Before we look at how to register WordPress custom shortcodes, let’s be clear: If there’s one thing Gutenberg is about to kill, it’s the use of WordPress shortcodes in content creation.
The Gutenberg team use the disgusting but accurate term “mystery meat” for the exact kind of user experience shortcodes give. Quick, what does the following code, in your post editing screen, look like on the front end of your site?
No idea. (That’s an actual shortcode here on WPShout, by the way.) When Gutenberg’s live-previewing Blocks land in WordPress Core, they’ll immediately make shortcodes feel like the horrible choice for post editing that they actually are.
Shortcodes are massively useful. What matters is what you use them for.
So am I planning to stop using shortcodes in my work as a WordPress developer? Heck no! I’ve written new shortcodes on client projects maybe 5 times this week so far, and I don’t plan on slowing down.
Shortcodes are massively useful. What matters is what you use them for.
Silly End User, Shortcodes are For Developers
Shortcodes are an awful experience for users. But for developers, they’re among the easiest and most useful testing tools in WordPress.
The problem with shortcodes, again, is that they’re an awful experience for users. But for developers, they’re just about the most useful testing tool there is, because they help you get your code on the page with an absolute minimum of effort.
In this article, we’ll make sure you know how to use add_shortcode()
to register custom WordPress shortcodes, with passed-in arguments and content if necessary. Then we’ll dive into some examples that show how WordPress shortcodes are massively useful for all kinds of WordPress development needs.
One quick thing before we dive in. If you’re looking to learn WordPress development, we’ve written the best guide to it out there:
The Best Way to Learn WordPress Development
Get Up and Running Today

Here’s what they have to say:
“Other courses I’ve tried nearly always lack clear explanations for why WordPress does things a certain way, or how things work together. Up and Running does all of this, and everything is explained clearly and in easy-to-understand language.” -Caroline, WordPress freelancer
How to Create WordPress Shortcodes
The first step in using shortcodes effectively as a WordPress developer is knowing how to register your own custom shortcodes. This section walks you through that process.
Registering a Custom Shortcode: the Most Basic Example
David recorded a great video Quick Guide covering the most basic possible use of add_shortcode()
to register a custom shortcode. That tutorial also covers how to register a plugin to hold the custom shortcode itself (which is better than using your theme’s functions.php
). Without that plugin boilerplate at the top, the code example looks like this:
add_shortcode( 'wpshout_sample_shortcode', 'wpshout_sample_shortcode' );
function wpshout_sample_shortcode() {
return 'hi!';
}
Notice a few things:
- You use
add_shortcode()
to register a new shortcode. - You name your shortcode whatever you want using the first argument of
add_shortcode()
. You’d put the shortcode we just registered onto the page with[wpshout_sample_shortcode]
. - With the second argument of
add_shortcode()
, you name a shortcode handler function. This function will be used to “handle” the shortcode: what that means is that it willreturn
a text string that WordPress will then output onto the page. In this case, the functionwpshout_sample_shortcode()
simplyreturn
s “hi!”—which is what will appear on the page anytime[wpshout_sample_shortcode]
is called.
This very simple shortcode setup is most of what we’ll be using in the examples below, but for completeness it’s also important to show you how to create shortcodes with content, and shortcodes that take passed-in arguments.
Creating a Custom Shortcode with Content and Passed-in Attributes
It’s also good to know how to create WordPress shortcodes that accept user-specified data. Here’s a shortcode with two new elements: a user-definable align
attribute, and user-defined content inside the shortcode itself.
[pullquote_shortcode align="left"]This is the text that should
go inside my pullquote[/pullquote_shortcode]
What do we “do with” this new data? By default, the shortcode handler function can take two arguments:
- An array of attributes
- The text content inside the shortcode.
Adding these to our handler function lets us work with them, as in this example:
// $attributes is an array of passed-in attributes. It would look like
// [ 'align' => 'left' ].
// $content is a string of passed-in shortcode content. It would look like
// 'This is the text that should go inside my pullquote'.
function pqsc_process_shortcode( $attributes, $content = null ) {
// Save each attribute's value to its own variable.
// This creates a variable $align with a value of 'left'.
extract( shortcode_atts( array(
'align' => ''
), $attributes ) );
// Return a string to display on the page
return '<blockquote class="pullquote align' . $align . '">' . $content . '</blockquote>';
}
The trickiest thing here is the combination of PHP’s default extract
function extract()
and WordPress’s shortcode_atts()
PHP function.
shortcode_atts()
shortcode_atts()
is a WordPress-provided function that combines an array of defaults with the array of attributes passed into the function itself. So by itself, it says that the align
attribute has a default value of ''
, an empty string—and that that default can be overwritten by whatever is actually the value for the align
element in the passed-in $attributes
array. For us, that value is 'left'
.
extract()
extract()
is a PHP function which takes each element of an array and makes a similarly-named variable out of it. So in the example above, we end up with $align
now being a variable of type string with a value of 'left'
. If we had other passed-in attributes, they’d become variables too.
Use
extract()
with care because of the danger of duplicate variable names.
By the way, make sure your extract()
function doesn’t let multiple variables take the same name! So don’t name one of your shortcode arguments, say, post
if you plan to use extract()
. Because of these potential confusions, extract()
isn’t the most secure PHP function overall, but boy is it convenient in this case. So fair warning.
That’s a Fancy Shortcode
That’s about as intricate as shortcodes get, so if you understand the example above, you’re pretty much set on the tech side for registering your own custom shortcodes. Now, what can we, as WordPress developers, do with WordPress shortcodes?
Why Shortcodes Are So Handy for a WordPress Developer (with Demos)
Shortcodes let me get anything I’m doing in PHP directly onto the page.
I love shortcodes for one reason: because they let me get anything I’m doing in PHP directly onto the page. They’re great for testing code, understanding what a function or variable is doing, and all kinds of other getting-visibility jobs. And once you’re used to registering and using them they take perhaps less setup than any other sensible way of displaying your code.
Below are some examples to make the point. Note that in these examples, I’m using PHP output buffering: see David’s excellent article on why output buffering is so handy for shortcodes.
Example: Using a Shortcode to Test a WP_Query
Let’s say I’m writing a WP_Query
and I want to know what it’s outputting:
add_shortcode( 'dump_query', 'dump_query' );
function dump_query() {
// Write query
$args = array(
'posts_per_page' => 1
);
$query = new WP_Query( $args );
// Return output
ob_start();
var_dump( $query );
return ob_get_clean();
}
Then I just write [dump_query]
anywhere, in any sample post or page on my site:
And I get something—an error, an array, or whatever—right in the page content:
Example: Searching Comment Text
Let’s say I want to do a word search through the site’s ten most recent approved comments:
add_shortcode( 'try_markup', 'try_markup' );
function try_markup() {
$args = array(
'status' => 'approve',
'number' => '10'
);
$comments = get_comments($args);
ob_start();
foreach($comments as $comment) :
echo $comment->comment_content . '<hr>';
endforeach;
return ob_get_clean();
}
With [try_markup]
on the page, that gives us:
Example: Display All Recent Medium-Sized Images
Wait, I need to look through (and maybe save into a folder) the “medium” image size of each of my last 50 image uploads:
add_shortcode( 'rec_images_medium', 'rec_images_medium' );
function rec_images_medium() {
$query_images_args = array(
'post_type' => 'attachment',
'post_mime_type' => 'image',
'post_status' => 'inherit',
'posts_per_page' => 50,
);
$query_images = new WP_Query( $query_images_args );
ob_start();
foreach( $query_images->posts as $image ) :
echo wp_get_attachment_image( $image->ID, 'medium' );
echo '<hr>';
endforeach;
return ob_get_clean();
}
The result with [rec_images_medium]
on the page:
The Pattern Here: Getting Stuff Onto the Page
Shortcodes are one of the easiest and lightest-weight ways to get stuff to display onto the page.
Do you see what I like about shortcodes? These use cases are the type of random need that can come up on the PHP side of any WordPress project, and in each case registering a shortcode was a very simple, easy way to turn my PHP code into something visual I could work with and get feedback from. In general, shortcodes are one of the easiest and lightweight-iest ways for a WordPress developer to get stuff—any stuff—to display onto the page, so you can use it, debug it, test it, tweak it, and what have you. And you know exactly where to expect it on the page, because you’ve placed the shortcode yourself.
So if you don’t know how to get your code onto the page, don’t reach for custom page templates, the_content
filters, or anything else. Reach for a shortcode.
Still Good for Individual Client Use
I’ll still be using shortcodes for private client projects where they’ll only have one or a few users.
I’ll put in one more plug for shortcodes: Gutenberg or no, I’ll still be using shortcodes for individual client projects until registering a Gutenblock is way easier than registering a shortcode. I’m guessing that day may never come.
As an example, I’ve got a client right now who needs to be able to insert an HTML quiz in his post content. I’m happy to train him, individually, in using the ugly UI of a shortcode, because wrapping HTML into a shortcode is so easy (as we’ve seen) and registering a whole Gutenblock will probably be overkill even when Gutenberg actually arrives.
It’s just for commercially released products, or products that will be used on one team but by large numbers of people, that shortcodes are nearing a dead end.
WordPress Shortcodes: Good For What They’re Good For
Shortcodes are not great for users, but man do I find them handy as a developer. I hope you better understand how to create custom WordPress shortcodes—with or without user-defined data—and why and when to use them in your WordPress development work.
Anything I missed? We’d love to hear from you in the comments below.