WordPress Shortcode Tutorial: How to Create Shortcodes, and Why They’re Super-Useful

wordpress shortcode love

This article is an in-depth WordPress shortcode tutorial. We cover what shortcodes are, when to use them, and how to register your own, with full-code custom shortcode examples.

WordPress shortcodes are a very handy tool to do one thing: get custom PHP code to display anywhere on your site.

Once you understand WordPress shortcodes, they’re an extremely handy and easy-to-use tool to do one thing: get custom PHP code of any kind to display anywhere on your site, from your post content to your sidebars to your headers and footers. Even with Gutenberg, the WordPress block editor, solidly established in WordPress core, shortcodes remain one of my favorite programmable tools in WordPress—even though Gutenberg is designed explicitly to make shortcodes obsolete.

So before we dive into the code,  let’s examine why WordPress shortcodes continue to be useful, even in a Gutenberg era.

Gutenblocks vs. Shortcodes: Comparison and Tradeoffs

If there’s one thing Gutenberg is designed to kill, it’s shortcodes.

Our WordPress shortcode examples need to grapple with one fact: if there’s one thing Gutenberg is designed to kill, it’s the use of WordPress shortcodes in content creation.

It’s not hard to see why. 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.) The Gutenberg team use the disgusting but accurate term “mystery meat” for the exact kind of user experience that shortcodes give.

If “mystery meat” is the problem, Gutenberg’s live-previewing Blocks are the cure:

gutenberg vs shortcodes live table example
So should we stop registering custom shortcodes? Have I stopped using them in my work as a WordPress developer? Heck no! I find myself registering custom WordPress shortcodes on almost every personal or client site I build, and I don’t plan on slowing down.

Shortcodes are massively useful. What matters is what you use them for.

The truth is that WordPress shortcodes are massively useful. What matters is what you use them for. And that starts with knowing the relative advantages of registering WordPress shortcodes versus Gutenberg blocks for creating custom functionality on your WordPress site.

Advantages of Gutenblocks

We’ve already seen the advantages of Gutenberg blocks compared to shortcodes in the screenshots above:

  1. Everything in a Gutenblock is in a clean visual user interface—no [this_is_really_confusing right="yes"] pseudocode that most site owners will be rightly scared to touch.
  2. Gutenblocks are live-previewing—no mystery meat.

Gutenberg blocks are a better user experience than shortcodes.

In other words, Gutenberg blocks are a better user experience than shortcodes. If you’re building something that a user needs to be able to drop into post content and mess around with, custom Gutenblocks are a better bet.

Advantages of WordPress Shortcodes

What we haven’t discussed yet are the pros of WordPress shortcodes relative to Gutenblocks, and there are quite a few:

  1. Shortcodes can go anywhere: post content, yes, but also widget areas that could be anywhere on your site (header, sidebar, footer, …). You can even execute them literally anywhere—in a theme template file, in a plugin—with WordPress’s do_shortcode() function. Gutenblocks are restricted to only post content.
  2. Shortcodes are a heck of a lot easier to register than Gutenblocks. For one thing, they’re PHP-only, whereas Gutenblocks are PHP and JavaScript. Registering a simple shortcode is super-easy and takes just a single function, as you’ll see in the custom WordPress shortcode examples below.
  3. Shortcodes can be anything: just a tiny blip of inline text, or a massive block of PHP code execution. Gutenblocks have to stack on top of other Gutenblocks, so they can’t be inline.

Shortcodes are an awful experience for nontechnical users. But for developers, they’re super-useful because they get your code on the page with minimum effort.

In sum, the problem with shortcodes is that they’re an awful experience for users who don’t have technical knowledge. But for developers, they’re one of the most useful tools there is—both during the development process itself and in production sites—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 explore some examples that show how WordPress shortcodes are massively useful for all kinds of WordPress development needs.

One thing first. If you’re serious about learning WordPress development, we’ve written the best guide to it out there, our flagship course Up and Running:

Serious About Learning WordPress Development?

Get Up and Running Today

Up and Running is our complete “learn WordPress development” course. Now in its updated and expanded Third Edition, it’s helped hundreds of happy buyers learn WordPress development the fast, smart, and thorough way.

 

I think anyone interested in learning WordPress development NEEDS this course.

Before I purchased Up and Running, I had taught myself some WordPress code, but lacked direction. Watching the course’s videos was like a bunch of lights being turned on.

I went from being vaguely familiar with how themes, functions and WordPress itself worked to mastering these. Everything became much clearer.

I very happily recommend this course to anyone willing to listen.”

–Jason Robie, WordPress developer

Take the next step in your WordPress development journey!

Onward into this WordPress shortcode tutorial!

How to Create WordPress Shortcodes

As a WordPress developer, you will definitely want to know how to register your own custom shortcodes. The tutorials in this section walk you through that process.

How to Register 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 will return a text string that WordPress will then output onto the page. In this case, the function wpshout_sample_shortcode() simply returns “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.

How to Create 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:

  1. An array of attributes
  2. 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 option-rich as WordPress shortcodes get, so if you understand the shortcode tutorial 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?

Shortcode Examples: Outputting PHP Code During Development

Shortcodes let me get anything I’m doing in PHP directly onto the page.

One reason I love shortcodes is 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 shortcodes, 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:

The Many Uses of PHP Output Buffering in WordPress

Shortcode 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', 'wpshout_dump_query' );
function wpshout_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:

shortcode query test

Shortcode 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( 'get_recent_comments', 'wpshout_get_recent_comments' );
function wpshout_get_recent_comments() {
	$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 [get_recent_comments] on the page, that gives us:
recent comments shortcode

Shortcode 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', 'wpshout_rec_images_medium' );
function wpshout_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:

Shortcodes are Great for Just Getting Stuff on the Page

Shortcodes are one of the easiest and lightest-weight ways to get stuff to display onto the page during development.

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 so so on. 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.

Real-Life WordPress Shortcode Examples: Using Shortcodes in Production Sites

I use custom shortcodes on personal and client sites all the time.

Gutenberg or no, I still use shortcodes on client projects all the time.

As we’ve discussed above, shortcodes are ideal when the relevant section of the site will only be updated by a technical person. This is often the case on client sites: most clients want to be able to change their page and post content, but they’re much more likely to call you than to try to bang around in, say, their site footer changing stuff.

There are also numerous situations that come up in real-world WordPress site projects—like when you need your custom code inline (in the middle of the flow of a piece of text), or when you’re registering custom code to go both in page content and potentially in widget areas or elsewhere on the site—that a shortcode can do what a Gutenblock can’t.

It’s just for commercially released products, or projects that will be managed by many less-technical people, that shortcodes are not usually a good choice.

Below, we’ll look at some real-life examples of shortcodes on live production sites. You’ll see that shortcodes are still super-handy. It’s just for commercially released products, or projects that will be managed on one team but by large numbers of less technical people, that shortcodes are not a good choice.

Example of a WordPress Shortcode in Post Content on a Production Site

I help manage the website Writers.com, which sells online writing courses. At any given time, some courses are scheduled, and some aren’t, meaning that the call-to-action on each type of course page is different.

We wrote a shortcode to serve the right kind of call-to-action on the right kind of course page—including calling in a second shortcode that we used to register the HTML for the unscheduled courses. Here’s the code:

add_shortcode( 'conditional_enroll_button', 'writers_conditional_enroll_button' );
function writers_conditional_enroll_button() {
	global $post;
	
	// Get unix time of event
	$end_datetime = new DateTime(
		get_post_meta( get_the_ID(), '_event_end_date', true )
	);

	// A class should display until its end date has passed (is after yesterday)
	$class_is_joinable = $end_datetime > new DateTime( 'yesterday' );
	
	
	ob_start();
	
	if( $class_is_joinable ) : ?>
		<div class="enroll-button"><input type="button" style="padding: 5px;" onclick="location.href='https://www.writers.com/regform.html?course_id=<?php echo $post->ID; ?>'" value="Enroll »"></div>		
		
	<?php else :
		// See "Interested" plugin
		echo do_shortcode( '[single_unscheduled_interested]' );
	endif;
	
	return ob_get_clean();
}

Here’s the shortcode in post content:

shortcode example conditional enroll button

Here’s what it outputs on a scheduled course:
shortcode example conditional enroll button output two

And here’s what it outputs on a non-scheduled course:
shortcode example conditional enroll button output one

So is a shortcode the right interface for this functionality? Definitely, because:

  • We don’t need live-previewing or other Gutenberg features.
  • We just need a simple wrapper for our complex custom functionality.
  • There’s no specific “boundary” to hook into; the code needs to go in the middle of something, in this case in the middle of post content.
  • It’s only developers touching and making changes to this section, not untrained people.

Example of a WordPress Shortcode that Adds a Lot of Functionality

WordPress shortcodes are often small, but they can be huge—remember, they’re a way of adding any amount of arbitrary PHP onto the page. One real-life huge one is the wpshout_homepage_scroll shortcode we use on the WPShout homepage, which controls the entire “Recently Published” section of the homepage:

using wordpress shortcode with beaver builder

The code for this shortcode is a few hundred lines in length in our theme’s functions.php file:

shortcode example code

Since the page has complex custom layouts, we’re using the always-excellent Beaver Builder plugin. So the question is: how should we get all this complex custom code onto our homepage? There is absolutely no better answer than to use a shortcode, because, again:

  • We don’t need live-previewing or other Gutenberg features.
  • We just need a simple wrapper for our complex custom functionality.
  • There’s no specific “boundary” to hook into; the code needs to go in the middle of something, in this case in the middle of post content.
  • It’s only developers touching and making changes to this section, not untrained people.

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.

Cool, right? I hope that’s helpful. And if you want to gain a complete foundation in WordPress development, I again highly recommend that you take a look at our flagship course Up and Running:

The Best Way to Learn WordPress Development

Get Up and Running Today

Up and Running is our complete “learn WordPress development” course. Now in its updated and expanded Third Edition, it’s helped hundreds of happy buyers learn WordPress development the fast, smart, and thorough way.

Here’s what they have to say:

wordpress freelancer caroline “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

Up and Running really brought everything together for me. I already knew of some of the pieces, but the course filled in the gaps and provided a proper understanding of how WordPress really works.

I found it easy to follow, delivering just the right depth of knowledge in the right sequence.”

–Hugues, freelance web developer

Anything I missed? We’d love to hear from you in the comments below, or in our Facebook group.


8 Responses

Comments

  • Gagan says:

    Quite informative, there are short code plugins out there which make my work bit easier.

  • thanks, came here for something different, but loved the article. still, i am courious, what you think is a better way for clients / users. GUI and everything, that is not rechable through a GUI they should not touch? Hand them a page-builder and watch them messing up? or do you think there is no “one for all”?

    I always struggle a bit with client expectations, that wordpress means, the now can “change _everything_ on the site” themselves…

    • Fred Meyer says:

      Good question! I actually have had success training users in page builders (I use Beaver Builder), so I’d say that’s my closest thing to a recommendation. (Most good page builders will render shortcodes, by the way, so your users can at least live-preview shortcodes you write yourself.)

      Beyond that, I agree that it’s important to manage expectations around complex layout/data/functionality/etc. changes being a completely hands-off thing in WordPress.

      • Thanks for your answer. Most pagebuilders I found quite overload and in the end not suitable for customers, but if you can recommand beaver, I will have a look at it.

        In the end, I always ask the customers, how skilled and patient they are with.. let’s say styling a word document? Based on the answer I can judge, if they will be able or not. ^^

  • Diego says:

    Hello, thanks for post ! I have a function with html+css+js for a calendar with some math things. And i want to convert it into a shortcode, to not copy/paste code in differentes places. Is it posible have a example of a plugin using static content with a shortcode function.

    Thanks

  • Stevan says:

    Instead of result I get actual shortcode on my post, like this [rec_images_medium].

  • Cesar says:

    You could consider the use of a plugin. For example:
    https://wordpress.org/plugins/ultimate-shortcodes-creator/.
    You can inject whatever code through a custom shortcode, even ajax calls with php.

  • Riccardo says:

    Nice and complete article!

    Can you suggest, to developers that use a lot shortcodes in their code, the repository plugin Shortodes Finder (https://wordpress.org/plugins/shortcodes-finder/)?
    It gives you the possibility to find every shortcode inside your website, detect its php source, get information about parameters and test it.

Add a Comment

Your email address will not be published. Required fields are marked *