WordPress is one of the most versatile content management systems available, and part of its flexibility lies in how plugins integrate with it. One of the most useful mechanisms plugins rely on is the shortcode: a bracketed tag that lets you drop in complex functionality without touching PHP. This guide covers what shortcodes actually are, how plugins use them, how to build your own, and where they tend to cause problems.
What Are Shortcodes in WordPress?
A shortcode is a small placeholder, written in square brackets like [shortcode], that WordPress swaps out for a block of dynamic output when the page renders. They were introduced back in WordPress 2.5, and they became the standard way for plugin developers to expose functionality to people who don’t write code.
Instead of hand-coding a gallery, a form, or a pricing table into HTML, you drop in a shortcode and WordPress does the rest at render time. A basic example:
That single tag inserts a full image gallery pulling from attachment ID 123, displayed at medium size, without you writing a line of markup.
How the Mechanism Actually Works
Under the hood, a shortcode is just a PHP function registered with add_shortcode(), tied to a specific tag name. When WordPress processes post content through the do_shortcode() filter (which happens automatically as part of the_content()), it scans for anything matching [tagname …] and replaces it with whatever that function returns. This is why pasting a shortcode into a text widget sometimes does nothing: older widget areas didn’t run content through do_shortcode() by default, so the raw brackets showed up on the page instead of the expected output. Modern WordPress fixed this for the default Text widget, but the gap still trips people up in custom theme areas that echo content directly without that filter applied.
It’s also worth understanding that shortcode parsing happens late in the content pipeline, after post_content has already been retrieved from the database. That’s why a shortcode’s output can react to the current logged-in user, the time of day, or query parameters in the URL: the actual rendering happens at request time, not at save time. A gallery shortcode saved in 2022 still pulls whatever images are currently attached, because the shortcode itself is just a marker. The real work happens fresh on every page load.
Examples of Popular Plugins That Use Shortcodes
Contact Form 7
After building a form, Contact Form 7 generates a shortcode like this:
[contact-form-7 id="1234" title="Contact form 1"]
Paste that anywhere on the site, and the form renders in place.
WooCommerce
WooCommerce ships with several shortcodes for embedding store elements outside the standard shop templates. To display products in a grid:
[products columns="4" limit="8"]
This pulls products into a 4-column grid, capped at 8 items. WooCommerce also ships shortcodes for a single product ([product id=”123″]), a cart page ([woocommerce_cart]), and checkout ([woocommerce_checkout]), which is how the core store pages get built without hardcoded templates.
Slider Plugins
Slider plugins like Slider Revolution use a shortcode to drop a configured slider anywhere on a page:
[rev_slider alias="homepage_slider"]
Yoast SEO
Yoast offers a breadcrumb shortcode for manual placement in templates or content where the automatic breadcrumb function isn’t already wired in:
Benefits of Using Shortcodes in Plugins
The appeal comes down to a few things. They’re simple to use, since copying a generated shortcode into a post requires no technical knowledge at all. Many accept parameters, so a gallery shortcode might let you set columns, image size, or which category of images to pull, without needing a different shortcode for every configuration. They’re reusable everywhere content lives, posts, pages, or widgets, so the same feature can appear in a dozen places without duplicating markup. And they’re broadly compatible: a well-built shortcode works regardless of which theme is active, since it’s not tied to any particular template file.
How to Add Shortcodes to Posts and Pages
Using an existing shortcode is straightforward in either editor WordPress offers.
In the Block Editor (Gutenberg)
- Open the post or page where the shortcode should appear.
- Add a new block and search for the Shortcode block specifically. It’s a plain-text block that doesn’t try to interpret or format the shortcode before rendering.
- Paste the shortcode into the block.
Note that pasting a shortcode into a regular Paragraph block usually works too, since do_shortcode() still processes it on render, but the dedicated Shortcode block avoids any interference from the paragraph block’s own formatting logic.
In the Classic Editor
Paste the shortcode directly into the content area at the point where the functionality should render. No special block or wrapping required.
In Widgets
- Go to Appearance > Widgets.
- Add a Text or Custom HTML widget to the target sidebar or footer area.
- Paste the shortcode into the widget content.
As mentioned above, this generally works fine in current WordPress versions, but if a shortcode outputs raw brackets instead of rendering, that’s the do_shortcode() filter gap to check first.
In Theme Files
If you’re comfortable editing theme code directly, you can hard-code a shortcode’s output into a template:
<?php echo do_shortcode('[shortcode]'); ?>
This is useful for embedding a shortcode’s functionality at a fixed location in a template, like a shop’s homepage banner, without relying on someone remembering to paste the shortcode into page content every time the design changes.
How to Create Custom Shortcodes
Beyond using plugin-provided shortcodes, you can register your own. This is worth doing when you find yourself repeating the same block of markup or logic across multiple pages.
A Basic Shortcode
Add this to your theme’s functions.php file, or better, a site-specific plugin so it survives a theme change:
function custom_greeting_shortcode() {
return 'Hello, welcome to my website!';
}
add_shortcode('greeting', 'custom_greeting_shortcode');
That registers [greeting], which outputs the given text wherever it’s placed.
Shortcodes With Parameters
Real-world shortcodes usually need to accept configuration. Here’s a button shortcode with customizable text and a target URL:
function custom_button_shortcode($atts) {
$atts = shortcode_atts(array(
'text' => 'Click Me',
'url' => '#',
), $atts);
return '<a class="button" href="' . esc_url($atts['url']) . '">' . esc_html($atts['text']) . '</a>';
}
add_shortcode('button', 'custom_button_shortcode');
Used like this:
[button text="Learn More" url="https://example.com"]
Two details in that example matter more than they look. shortcode_atts() merges user-supplied attributes with sensible defaults, so [button] alone (with no attributes) still renders something reasonable instead of breaking. And esc_url() plus esc_html() escape the output before it hits the page, which is not optional. A shortcode that echoes raw user input straight into HTML is a stored XSS vulnerability waiting to happen, particularly if the shortcode ever gets used inside a form submission or a field editable by non-admin users.
Shortcodes That Wrap Content
Some shortcodes need to wrap content between an opening and closing tag, rather than just outputting something on their own, similar to how … works in WordPress core. That requires a second parameter in the callback function:
function custom_highlight_shortcode($atts, $content = null) {
return '<mark>' . do_shortcode($content) . '</mark>';
}
add_shortcode('highlight', 'custom_highlight_shortcode');
Used as [highlight]this text gets marked[/highlight]. Wrapping the inner content with do_shortcode() before returning it is worth doing deliberately, since it allows other shortcodes to be nested inside yours, though it’s also a decision to make consciously rather than by default, since nested shortcode processing can get unpredictable if you’re not controlling both sides of it.
Potential Challenges With Shortcodes
Shortcodes are flexible, but they come with a few recurring headaches.
Plugin dependency is the big one. A shortcode only exists because a plugin registered it. Deactivate that plugin, and every instance of that shortcode across your site starts printing raw, ugly bracket text instead of quietly disappearing. If you’re removing or replacing a plugin, search your content for its shortcodes first, not after visitors start reporting broken pages.
Some shortcodes carry a genuinely large number of parameters, and remembering the exact attribute names without checking documentation gets old fast. This is less of a technical problem and more a documentation and discoverability one, which is part of why the block editor’s shift toward dedicated blocks, rather than shortcode tags, has been a welcome change for a lot of non-technical users.
Visual representation is limited. A shortcode in the editor is just text in brackets until you preview or publish. Complex layouts built from several nested or adjacent shortcodes are genuinely hard to visualize while editing, which is one of the reasons blocks have largely replaced shortcodes as the preferred mechanism for anything visually complex, even though shortcodes remain fully supported and widely used for simpler, single-purpose insertions.
Shortcodes vs. Blocks: Which Should You Use Now?
Since the block editor became the default in WordPress 5.0, a fair question is whether shortcodes still make sense to build new functionality around. The honest answer is that both have a place. Blocks give a visual, in-editor preview and fit naturally into the editing experience, which makes them the better choice for anything a user needs to configure visually. Shortcodes remain simpler to build for a single, narrow purpose. They work identically in the Classic Editor and in widgets, and drop straight into template files without any extra registration overhead. And they’re still the format most contact form and payment plugins default to, since a single bracketed tag is easier to document and support than a full custom block.
If you’re building something new for a client and expect them to configure it visually, lean toward a block. If it’s a narrow, single-purpose insertion (a form, a specific pricing table, a single embed), a shortcode is often still the pragmatic choice, and plenty of well-maintained plugins keep shipping them for exactly that reason.
Shortcodes in BuddyPress and Community Plugins
Community-focused plugins lean on shortcodes for exactly the kind of embed use case they’re best at: dropping a specific dynamic block, a member directory, an activity stream, a groups list, onto a regular page rather than relying entirely on the plugin’s own template files. This matters because BuddyPress components are normally tied to their own dedicated pages (the members directory, the groups directory), but a shortcode lets you place that same functionality inside a custom landing page, a widget area, or anywhere else content can go. If you’re building a custom homepage that needs to show, say, a small preview of recent group activity alongside marketing copy, a shortcode-driven embed is usually a cleaner solution than trying to override core BuddyPress templates just to relocate one component.
The same logic applies to bbPress forums and most membership plugins: the core functionality lives on dedicated pages, but shortcodes give you an escape hatch for surfacing a slice of that functionality wherever you actually need it.
Security Considerations Beyond Basic Escaping
The escaping shown in the button example earlier (esc_url(), esc_html()) is the baseline, not the whole story. A few other things are worth building the habit of checking.
If a shortcode attribute controls a database query, sanitize it before it ever touches SQL. shortcode_atts() merges defaults with user input, but it doesn’t sanitize anything on its own. That’s still your job inside the callback function.
If a shortcode is going to be usable by non-administrator users (a common setup on membership or community sites where members can post content that goes through the same content pipeline), think carefully about what that shortcode can actually do. A shortcode that reads arbitrary file paths, or executes arbitrary PHP passed as an attribute, is a serious vulnerability if a lower-privilege user can trigger it. Most well-built plugin shortcodes avoid this by design, but any custom shortcode you build yourself needs the same scrutiny.
Finally, don’t trust do_shortcode() to sanitize its own output automatically. It’s a text substitution mechanism, not a security layer. The security work happens inside each individual shortcode’s callback function, which means a plugin with 40 registered shortcodes has 40 separate places where that discipline needs to hold.
Debugging a Broken Shortcode
When a shortcode shows raw bracket text on the front end instead of rendering, work through this in order.
First, confirm the plugin that registers it is actually active. This sounds obvious, but it’s the single most common cause, especially after a bulk plugin update or a migration where something silently failed to reactivate.
Second, check for a typo in the tag name or an attribute. Shortcodes fail silently on typos rather than throwing a visible error. [galery id=”123″] with a misspelled tag name just outputs the raw bracket text, with nothing in the browser telling you why.
Third, verify the shortcode is being placed somewhere that actually runs do_shortcode(). Post content and page content run it automatically. Custom template areas, some widget types, and certain page builder text fields don’t always, depending on how that specific plugin or theme handles output.
Fourth, check whether the theme or another plugin is filtering post content in a way that strips or escapes bracket characters before the shortcode parser gets to run. That last one is rare, but it happens with some security or sanitization plugins configured aggressively, and it’s worth temporarily disabling suspect plugins one at a time if the first three checks come up clean.
Frequently Asked Questions
Can I use two different plugins’ shortcodes on the same page? Yes, as long as both plugins are active. Shortcodes don’t conflict with each other unless two different plugins happen to register the exact same tag name, which is uncommon but not impossible with poorly namespaced plugin code.
Why does my shortcode show up as plain text instead of rendering? Almost always one of three things: the plugin that registers it isn’t active, there’s a typo in the tag name, or it’s placed somewhere that doesn’t run content through do_shortcode().
Can shortcodes accept multiple values for one attribute? Yes, though it takes some custom handling. A common pattern is accepting a comma-separated string as one attribute value, then exploding it into an array inside the shortcode function.
Do shortcodes slow down a page? A single shortcode adds negligible overhead. Where it adds up is when a shortcode runs its own database query, and a page stacks several of those shortcodes together, each one running independently. A product grid shortcode and a related-posts shortcode on the same page, for instance, are two separate queries that could potentially be combined or cached if performance becomes a real issue.
Can I disable a specific shortcode without deactivating the whole plugin? Yes, with a bit of code. remove_shortcode(‘tagname’) unregisters a specific shortcode, which is useful if a plugin ships a shortcode you don’t want active but you still need the rest of the plugin’s functionality.
Is there a way to see every shortcode registered on my site? There’s no built-in WordPress screen for this, but you can list them with a small snippet: global $shortcode_tags; print_r(array_keys($shortcode_tags)); dropped into a template temporarily, or wrapped in a WP-CLI command for a cleaner one-off check.
Conclusion
Plugins in WordPress lean on shortcodes constantly, offering a simple way to add dynamic functionality without writing code. Contact forms, product grids, and breadcrumbs (sliders too) are all a bracketed tag away from working. For anyone building custom functionality, shortcodes remain a legitimate, well-supported option even in a block-editor-first WordPress, particularly for anything narrow and single-purpose that doesn’t need a full visual block interface.
Learning to build your own, with proper escaping and sensible defaults, is one of the more useful small skills a WordPress developer can pick up. It’s a small amount of PHP that unlocks a lot of reusable functionality, and it’s usually the fastest path from “I keep pasting the same block of HTML into every page” to a single tag that does the job everywhere it’s needed.