WordPress Shortcodes: A Complete Guide
WordPress shortcodes were introduced in version 2.5 and since then have proved to be one of the most useful features. The average user acting as editor has the ability to publish dynamic content using macros, without the need for programming skills.
When a shortcode is inserted in a WordPress post or page, it is replaced with some other content. In other words, we instruct WordPress to find the macro that is in square brackets ([]) and replace it with the appropriate dynamic content, which is produced by a PHP function.
The usage is pretty simple. Let’s say we want to show the most recent posts in a given post. We could use something like this:
[recent-posts]
For a more advanced shortcode, we could set the number of posts to display by setting a parameter:
[recent-posts posts="5"]
Going one step further, we could set a heading for the list of recent posts:
[recent-posts posts="5"]Posts Heading[/recent-posts]
Simple Shortcode
In the first part of this tutorial, we will create the code for this simple shortcode:
[recent-posts]
The creation process is simple and does not require any advanced PHP knowledge. The basic steps are:
- Create the function, which will be called by WordPress when it finds a shortcode.
- Register the shortcode by setting a unique name.
- Tie the registration function to a WordPress action.
All codes in this tutorial can be placed in functions.php or in a seperate PHP file that will be included in functions.php.
Create the Callback Function
When a shortcode is found, it is replaced by some piece of code, which is the callback function. So, let’s create a function that fetches recent posts from the database.
function recent_posts_function() {
query_posts(array('orderby' => 'date', 'order' => 'DESC' , 'showposts' => 1));
if (have_posts()) :
while (have_posts()) : the_post();
$return_string = '<a href="'.get_permalink().'">'.get_the_title().'</a>';
endwhile;
endif;
wp_reset_query();
return $return_string;
}
As shown, we’re querying the database to get the latest post and return a string with a link to it. Ιt is worth noting that the callback function does not print anything, but rather returns a string.
Register the Shortcode
Now, we tell WordPress that this function is a shortcode:
function register_shortcodes(){
add_shortcode('recent-posts', 'recent_posts_function');
}
Ιf a shortcode of [recent-posts] is found in a post’s content, then recent_posts_function() is called automatically. We should ensure that the shortocode’s name is unique in order to avoid conflicts.
Hook Into WordPress
In order to execute our register_shortcodes() function, we will tie it to WordPress’ initialization action:
add_action( 'init', 'register_shortcodes');
Test the Shortcode
Our simple shortcode is ready, and the next step is testing that it operates properly. Let’s create a new post (or open an existing one) and put the following line somewhere in the content:
[recent-posts]
Publish the post, and viewing it in a browser, you should see a link to the most recent post on your blog, as shown in this screenshot:
Advanced Shortcode
Shortcode Parameters
Shortcodes are flexible because they allow us to add parameteres in order to make them more functional. Let’s say we want to display a certain number of recent posts. To do this, we need to add an extra option to our shortcode that specifies how many recent posts to show.
We have to use two functions. The first one is WordPress’ built-in shortcode_atts() function, which combines user shortcode attributes with native attributes and fills in the defaults where needed. The second function is the extract() PHP function, which does what its name suggests: it extracts the shortcode attributes.
Extending our callback function, we add an argument, which is an array of attributes from which we extract the parameter for the number of posts. Then we query the database to get the desired number of posts and create an HTML list to show them.
function recent_posts_function($atts){
extract(shortcode_atts(array(
'posts' => 1,
), $atts));
$return_string = '<ul>';
query_posts(array('orderby' => 'date', 'order' => 'DESC' , 'showposts' => $posts));
if (have_posts()) :
while (have_posts()) : the_post();
$return_string .= '<li><a href="'.get_permalink().'">'.get_the_title().'</a></li>';
endwhile;
endif;
$return_string .= '</ul>';
wp_reset_query();
return $return_string;
}
If the user skips the option, 1 is the default value. In the same way, we can add more attributes, enabling the shortcodes to accept multiple parameteres. Thanks to this enhanced function, we can set how many posts to show:
[recent-posts posts="5"]
When viewing it in the browser, you should see links to the five most recent posts in the content:
Content in Shortcode
We can take our shortcode one step further and add the ability to pass some content as an argument, which in this case will be a heading for the list of recent posts. To do this, we use a second parameter, $content, in the callback function and add it as an h3 heading before the list. The new function is as follows:
function recent_posts_function($atts, $content = null) {
extract(shortcode_atts(array(
'posts' => 1,
), $atts));
$return_string = '<h3>'.$content.'</h3>';
$return_string .= '<ul>';
query_posts(array('orderby' => 'date', 'order' => 'DESC' , 'showposts' => $posts));
if (have_posts()) :
while (have_posts()) : the_post();
$return_string .= '<li><a href="'.get_permalink().'">'.get_the_title().'</a></li>';
endwhile;
endif;
$return_string .= '</ul>';
wp_reset_query();
return $return_string;
}
This kind of shortcode is similar to an HTML tag. We enclose the content in an opening and closing shortcode:
[recent-posts posts="5"]This is the list heading[/recent-posts]
The result is the same as the previous example, except for the new heading for the list of posts:
Shortcodes Anywhere, Anytime!
Enabling Shortcodes in Widgets
By default, shortcodes are ignored in WordPress sidebar widgets. Take the following as an example:
[recent-posts posts="5"]
If you type this shortcode into a widget, it would look something like this:

A shortcode in a widget before enabling the functionality
With WordPress, we can enable this functionality with a single line of code. To be able to add shortcodes in widgets, add the following:
add_filter('widget_text', 'do_shortcode');
Now, without having to change anything else, the shortcode will display properly in widgets:

A shortcode in a widget after enabling the functionality
Similarly, we can enable shortcodes in comments:
add_filter( 'comment_text', 'do_shortcode' );
And excerpts:
add_filter( 'the_excerpt', 'do_shortcode');
Shortcode TinyMCE Editor Button
While shortcodes are a handy way to add dynamic content to posts, the might be a bit confusing for the average user, especially when they get complicated, with multiple parameteres. Most users are not familiar with HTML-like syntax; and yet they have to remember the exact syntax and all available attributes of shortcodes, because even a minor syntax error could cause an undesirable result.
To resovle this, we can add a button to the TinyMCE editor`s interface, enabling the user to create a shortcode with a simple click. There are two basic steps to creating this button:
- Create the JavaScript file for the button.
- Register the button and the JavaScript file.
JavaScript File for the Button
The JavaScript file is used to register the TinyMCE plugin through the TinyMCE API. We create a new file named recent-posts.js in the js directory of our theme, and then we type the following piece of code:
(function() {
tinymce.create('tinymce.plugins.recentposts', {
init : function(ed, url) {
ed.addButton('recentposts', {
title : 'Recent posts',
image : url+'/recentpostsbutton.png',
onclick : function() {
var posts = prompt("Number of posts", "1");
var text = prompt("List Heading", "This is the heading text");
if (text != null && text != ''){
if (posts != null && posts != '')
ed.execCommand('mceInsertContent', false, '[recent-posts posts="'+posts+'"]'+text+'[/recent-posts]');
else
ed.execCommand('mceInsertContent', false, '[recent-posts]'+text+'[/recent-posts]');
}
else{
if (posts != null && posts != '')
ed.execCommand('mceInsertContent', false, '[recent-posts posts="'+posts+'"]');
else
ed.execCommand('mceInsertContent', false, '[recent-posts]');
}
}
});
},
createControl : function(n, cm) {
return null;
},
getInfo : function() {
return {
longname : "Recent Posts",
author : 'Konstantinos Kouratoras',
authorurl : 'http://www.kouratoras.gr',
infourl : 'http://wp.smashingmagazine.com',
version : "1.0"
};
}
});
tinymce.PluginManager.add('recentposts', tinymce.plugins.recentposts);
})();
As shown below, we create a new plugin, calling the tinymce.create() method, passing in the plugin’s name and the attributes. The most important part of this code is the init() function, where we define a name, an icon file and an event handler for the button using the onclick() function.<1/p>
In the first two lines of the onclick() function, the user is prompted to input the parameters for the number of posts and list heading of the shortcode. Then, depending of the values of these parameters, the appropriate shortcode form is inserted in the editor.
Finally, our TinyMCE plugin is added to the PluginManager using the add() function. Now we’ve successfully integrated the [recent-posts] shortcode into a WordPress theme.
Registering the Button and TinyMCE Plugin
After creating the JavaScript file, we need to register it and the shortcode button. So, we create two functions and tie them to the corresponding WordPress filters.
The first function is named register_button() and pushes the shortcode into the array of buttons, adding a divider between the new button and the existing ones:
function register_button( $buttons ) {
array_push( $buttons, "|", "recentposts" );
return $buttons;
}
The second function, add_plugin(), points to the path and name of the JavaScript file:
function add_plugin( $plugin_array ) {
$plugin_array['recentposts'] = get_template_directory_uri() . '/js/recentposts.js';
return $plugin_array;
}
The next step is to add a filter with the previous functions. The register_button() function is tied to the mce_buttons filter, which is executed when the editor loads the plugins, and add_plugin() is tied to mce_external_plugins filter, which is executed when the buttons are about to be loaded:
function my_recent_posts_button() {
if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') ) {
return;
}
if ( get_user_option('rich_editing') == 'true' ) {
add_filter( 'mce_external_plugins', 'add_plugin' );
add_filter( 'mce_buttons', 'register_button' );
}
}
The previous function takes no action if the user does not have permission to edit posts or pages or if the user is not in visual editor mode.
Finally, we hook the function into WordPress’ initialization action to execute this when a page loads:
add_action('init', 'my_recent_posts_button');
Button Usage
To check that the shortcode button functions properly, let’s create a new post or edit an existing one. A new button, with the icon that we set before, should have been added to the left of the first line of the TinyMCE buttons, as in this screenshot:

Shortcode TinyMCE editor button
When we press the shortcode button, a dialog appears that prompts us to type the shortcode parameter for the number of posts:

Shortcode TinyMCE editor button
After inserting the number of posts, a second dialog appears, prompting us to type in the heading of the list:

Shortcode TinyMCE editor button
If any parameter is left blank, it will not be included in the final shortcode.
Finally, the shortcode appears in the editor:

Shortcode TinyMCE editor button
Some Useful Shortcodes
This part of the tutorial provides the source code for some userful WordPress shortcodes that will take your blog one step up.
Link Button
One simple example is the link button shortcode:
function linkbutton_function( $atts, $content = null ) {
return '<button type="button">'.do_shortcode($content).'</button>';
}
add_shortcode('linkbutton', 'linkbutton_function');
Use this shortcode as follows:
[linkbutton]Click Me![/linkbutton]
Something like this should appear:
WordPress Menu
Let’s move on to a more complex shortcode, one that grabs a WordPress menu:
function menu_function($atts, $content = null) {
extract(
shortcode_atts(
array( 'name' => null, ),
$atts
)
);
return wp_nav_menu(
array(
'menu' => $name,
'echo' => false
)
);
}
add_shortcode('menu', 'menu_function');
When calling this shortcode, pass in the name of the menu you want to show:
[menu name="main-menu"]
The menu will appear in your content:
Google Maps
A Google Maps shortcode is really useful, because we can insert a map into our content without needing to edit the source code.
function googlemap_function($atts, $content = null) {
extract(shortcode_atts(array(
"width" => '640',
"height" => '480',
"src" => ''
), $atts));
return '<iframe width="'.$width.'" height="'.$height.'" src="'.$src.'&output=embed" ></iframe>';
}
add_shortcode("googlemap", "googlemap_function");
When typing the shortcode, pass in the width and height and the link from Google Maps as parameters:
[googlemap width="600" height="300" src="http://maps.google.com/maps?q=Heraklion,+Greece&hl=en&ll=35.327451,25.140495&spn=0.233326,0.445976& sll=37.0625,-95.677068&sspn=57.161276,114.169922& oq=Heraklion&hnear=Heraklion,+Greece&t=h&z=12"]
The result is the following:
Google Charts
Another useful service is Google Charts, because it is very customizable. Here is a shortcode example with multiple attributes:
function chart_function( $atts ) {
extract(shortcode_atts(array(
'data' => '',
'chart_type' => 'pie',
'title' => 'Chart',
'labels' => '',
'size' => '640x480',
'background_color' => 'FFFFFF',
'colors' => '',
), $atts));
switch ($chart_type) {
case 'line' :
$chart_type = 'lc';
break;
case 'pie' :
$chart_type = 'p3';
break;
default :
break;
}
$attributes = '';
$attributes .= '&chd=t:'.$data.'';
$attributes .= '&chtt='.$title.'';
$attributes .= '&chl='.$labels.'';
$attributes .= '&chs='.$size.'';
$attributes .= '&chf='.$background_color.'';
$attributes .= '&chco='.$colors.'';
return '<img title="'.$title.'" src="http://chart.apis.google.com/chart?cht='.$chart_type.''.$attributes.'" alt="'.$title.'" />';
}
add_shortcode('chart', 'chart_function');
To create a pie chart with four types of data, we insert the following line:
[chart type="pie" title="Example Pie Chart" data="41.12,32.35,21.52,5.01" labels="First+Label|Second+Label|Third+Label|Fourth+Label" background_color="FFFFFF" colors="D73030,329E4A,415FB4,DFD32F" size="450x180"]
The result is a pie like the following:
PDF embedding
We can use the Google Docs PDF viewer to embed a PDF on your website. Here is the shortcode to do this:
function pdf_function($attr, $url) {
extract(shortcode_atts(array(
'width' => '640',
'height' => '480'
), $attr));
return '<iframe src="http://docs.google.com/viewer?url=' . $url . '&embedded=true" style="width:' .$width. '; height:' .$height. ';">Your browser does not support iframes</iframe>';
}
add_shortcode('pdf', 'pdf_function');
To embed a PDF, type the shortcode [pdf], and pass in the URL as the content argument:
[pdf width="520px" height="700px"]http://static.fsf.org/common/what-is-fs-new.pdf[/pdf]
When viewing the page, the visitor will see a viewer with the PDF:
Shortcodes WordPress Plugins
Thanks to WordPress plugins, adding shortcode functionality to a website requires no source-code editing at all. If you look at the WordPress plugins directory, you’ll see a large number of such plugins with which to style posts and pages. In this section, we’ll recommend some of the best shortcode plugins (favoring the free ones) to satisfy your every need.
Shortcodes Ultimate
Without a doubt, this is the best shortcode plugin out there. It enables you to easily create buttons, tabs, boxes, sliders, tooltips and many more elements.
J Shortcodes
The J Shortcodes plugin is similar to Shortcodes Ultimate, offering a collection of useful elements to style a website, including buttons, boxes, tabs and accordions. J Shortcodes lets you set custom attributes on elements, such as color, size and shape, and define custom column layouts on any page or post.
Shortcodes Pro
Shortcodes Pro does not offer ready-to-use shortcodes. Instead, this plugin allows for quick and easy creation of WordPress shortcodes from inside WordPress’ administration panel.
Shortcode Exec PHP
Natively, WordPress does not provide functionality to execute pieces of PHP source code on posts or pages. Shortcode Exec PHP plugin enables you to execute PHP code in WordPress content using manually defined shortcodes.
Resources From Around the Web
Last but not least, here are some articles you might find useful.
- “Mastering WordPress Shortcodes,” Smashing Magazine
A great article that shows how to create and use shortcodes, providing some ready-to-use WordPress shortcodes. - “Getting Started with WordPress Shortcodes (+Examples),” SpeckyBoy
This tutorial is a good place to start messing with shortcodes. - “Getting Started With WordPress Shortcodes,” Tuts+
This gives a detailed explanation of the WordPress shortcode API, showing some useful examples of more advanced shortcodes. - “Shortcode API,” WordPress Codex
The official page of the API in the WordPress Codex. - “Shortcodes,” WordPress Support
Lists some useful built-in shorcodes.
(al)




















Danni
May 1st, 2012 12:56 pmWhat an amazing tutorial! I have been wanting to use shortcodes for a long time now, and this is the perfect opportunity!
Thanks a bunch!
Konstantin Kovshenin
May 2nd, 2012 12:21 amA complete guide you say?
You barely explained what
shortcode_attsis for and what exactlyextractdoes, other than just “extracts the shortcode attributes.” It’s almost as saying array_walk_recursive “recursively walks through an array.”The
shortcode_attsfunction is an important security measure. It takes a list of accepted (and default) shortcode attributes and makes sure that any extra attributes provided by the user are stripped, and the ones skipped, are defaulted. This is very important especially with a function likeextractaround. And you say “combines with native attributes,” huh??Dear Smashing Magazine, please don’t become like WPTuts+.
~ Konstantin
Jeff Starr
May 4th, 2012 1:20 pmHi Konstantin,
Absolutely, further info on
shortcode_attsandextractwould be useful, especially your point about the former playing an important role in WordPress security. It’s good to know that WordPressshortcode_attsfunction is operating securely behind the scenes. Also agree that “combines with native attributes” is a bit vague, but otherwise think the article does a good job of completely guiding the reader through the fun and rewarding world of WordPress shortcodes.Thanks for the feedback — and for holding us to a higher standard.
Alex Vallejo
July 2nd, 2012 7:30 amOne question on the Advanced Shortcodes part; Where is ‘$posts’ defined? You extract ‘posts’ from the attributes but they are never assigned the variable of $posts, even though you use the variable in defining the number of posts to display. Should you assign the entire extract function to the variable of $posts?
Sam Fresh
July 8th, 2012 2:39 pmHi Konstantin,
Your tone is critical and not complimentary to the efforts of the author of the article. If you have anything to add that can assist people further then please write your own article, expanding on the points you made, and give good illustrative examples. Then come back here and make a link to your contribution. In this way we assist and support one another, and take action on what we can offer.
Gabriel
May 2nd, 2012 1:24 pmThis was really helpful! Before I knew how to do this I had to create a custom page template that ran a function above or below the content region. This is a huge help! Thanks :)
Derry
May 12th, 2012 6:15 amNice roundup! Very useful ( and not too detailed as some would have it ). More detail can be found elsewhere and i would also suggest always wrapping related code inside a nice, portable class to be used as a plugin on any site! Cheers!
Sami Keijonen
May 13th, 2012 2:35 amJust made pullquote shortcode plugin with a help of this article. Thank you.
Martin
June 20th, 2012 11:59 pmThanks for the great Tutorial.
What if I wanted to include a shortcode in another shortcode?
Here is an example
function twitt() {
return ‘ID).’?trackid=” title=”Click to send this page to Twitter!” target=”_blank”>Share on Twitter‘;
}
add_shortcode(‘twitter’, ‘twitt’);
you will see that at the end of the post it relates to, we add a track ID
We have another shortcode already on our site that collects this data, so if someone sends us traffic, we know where its from as their link is cookied so we can see where the visitor goes.
example: person links to a site post like this http://www.samplesite.com/?trackid=juyh
We then know who referred to our site. Then when it gets retweeted, it still will tell us the originator because the new inbound link will include the original track id.
Hope that makes sense?
My issue is that the above code show the link with the track id part at the end, but how do I include the shortcode result of the originator :)
Thanks for your help.
Martin
Luka
June 29th, 2012 12:37 amGreat article! It was very helpful, thanks :).
sohail tariq
June 29th, 2012 9:37 pmall information is very useful.
Maor Barazany
July 5th, 2012 5:14 amIs there a way to add support for shorcodes in custom wp_editor?
It appears WP ignores shortcoded that placed in custom wp_editor .
Of course, do_shortcode($content) can be used, but it’s not the best way.\
I tried to add the filter, like in widgets and comments –
add_filter( 'the_editor_content', 'do_shortcode' );but it still ignores the shortcode. Any ideas?
Thanks
Global
July 17th, 2012 5:14 pmGreat article, really appreciate the real-world use cases with Google maps and charts.
There was one area that I would love to have had covered: the placeholder that WordPress generates for the gallery shortcode. Where to get further documentation on the placeholder and how to create placeholders for your own custom shortcodes.
But great article!
Dario Ferrer
October 2nd, 2012 8:03 amAmazing article… People!! This author saved my life today!!
PS.- Konstantin, i’ve read you too and let me say you: If you have a very basic knowledge of this stuff, you wont find any advantage in this guide. Maybe you wish to learn the first steps and come back again.
marcos
October 13th, 2012 2:38 pmGREAT ARTICLE. Thanks very much.
tosun
November 22nd, 2012 2:11 amHello,
Thank you for this valuable post.
My question is related to triggering shortcode not create a shortcode.
I use a flv mp4 player to show videos and have shortcodes for it.
I want to put small images to a page and when click small image, related shortcode ( video) is opened.
On the other hand, how can I activate shortcode by clicking an image or text?
Regards
Nicolas Vial
December 31st, 2012 1:32 pmHi,
Thanks for the guide: I’m new to wordpress and I have the same question than tosun,
I already have a shortcode from a plugin and what i try to do is to have a button in the MCE editor, and when I click on it it will insert the shortcode tags in the post like: [shortcode] [/shortcode]
As you said: Most users are not familiar with HTML-like syntax; and yet they have to remember the exact syntax, because even a minor syntax error could cause an undesirable result.
Thanks!
Davis Augi
November 22nd, 2012 3:29 amHow to add short code for Read More feature?
I am trying to add Read more in a theme but do not know how to do it. I am an amateur.
Konstantinos Kouratoras
November 22nd, 2012 5:34 amYou follow the Simple Shortcode example and in the main function you just return the permalink of the post using the get_permalink($post->ID).
Jason
November 23rd, 2012 3:36 pmThank you so much for this great tutorial
Bibhuti Bhushan Barman
December 11th, 2012 12:28 amThis is nice but I am looking for something else.
I want a shortcode to directly liked to a tag archive page. For example if I write [tag]Sometimg[/tag] this will auto liked to the Something tag page like Something
Please help me.
Konstantinos Kouratoras
December 13th, 2012 6:19 amYou follow the example with the parameter and in the main function you return the appropriate link, something like that:
get_bloginfo(‘url’).’/tag/’.$tag
Amel Hendrik Groos
December 25th, 2012 4:59 amSir,
Great short-codes review. Thank you very much. Can you help me with something else please? I once had this WordPress short-code that gave me the ability to split a WordPress page in multiple pages. I can’t find nor remember the short-code. The only thing I can remember it looked something like this: ”/- – -new_page- – -/” (only replaced by arrows). Please let me know if something comes to mind. Thank you.
Keisa
January 3rd, 2013 4:28 amThis article is great, but I get multiple errors with the Google Maps shortcode somethig about http and https…
How can I fix this ?
Keisa
January 14th, 2013 8:53 pmThe Recent Posts shortcode works, but even when using //
recent-posts posts=”5″
Only one post is listed…how can I fix this?
Ariful Islam
January 15th, 2013 12:51 pmReally useful tips for me. Great article. !!!!!
Dejan
March 13th, 2013 7:05 amThe tinyMCE button is not working as of march 2013, that part of the tutorial should be updated.
arick
March 21st, 2013 4:49 pmcan some body helpme…?
i will make recent-post shortcode from custom post type, how to make it…?
Jose
April 2nd, 2013 12:20 pmHi Konstantinos, I’m trying to put a shortcode that I’ve created to show the post title into a phrase located at the body message field of a Contact Form inserted like a text widget in my blog’s sidebar. It doesn’t run :(
Perhaphs you can help me.
If somebody knows another way to do that I’ll pleased about that!
If you answer me by mail I send you all the technical details.
Thanks, see you.
Konstantinos
April 10th, 2013 3:04 pmHi Jose, in order to enable shortcodes in widgets, you have to insert this line in your functions.php
add_filter(‘widget_text’, ‘do_shortcode’);
Skweekah
April 2nd, 2013 5:39 pmWhat about native, inbuilt wordpress shortcodes. Is there a list of these?
Great article. Very, very comprehensive.
Chaim Krause
May 5th, 2013 7:29 amYour article is the latest one I have checked this morning searching for an answer. Like the commenter above me, I am looking for a list of the shortcodes. My issue is that I can find the list of default shortcodes installed with WordPress, but I am unable to find an easy way to determine all of the shortcodes available to me on a particular WP installation based on the plugins that are installed. To me, an awesome plugin would be one that lists all of the shortcodes available and provides info on what plugin provides that shortcode.
ashfaq ahmed
June 6th, 2013 4:40 pmHi,
I have used read and use Advanced Shortcode into my site i am getting only 1 post. I set
extract( shortcode_atts( array(
‘posts’ => 1
), $atts ) )
$args = array(
‘post_type’ => ‘events’,
‘orderby’ => ‘post_date’,
‘showposts’ => $posts,
‘post_status’ => ‘publish’
)
and my shortcode is [location posts="10"] so it should need to display 10 post but it is only display 1 post can anyone help me. I actually want that whenever i change number in the shortcode it should change number of post at front end like if i put shortcode [location posts="5"] it show 5 posts and if i put [location posts="20"] it show 20 post etc etc thanks
David
June 15th, 2013 6:31 amBest article I’ve ever read in my entire unproductive life lol