Skip to content
WordPress

WordPress Shortcodes: Use, Create, and Secure Every Type

WordPress shortcodes let editors place complex functionality anywhere in content. This guide covers built-in shortcodes, plugin shortcodes, creating custom ones, template use, and security.

WordPress Shortcodes: Use, Create, and Secure Every Type

A shortcode is one of the most practical WordPress features for non-developers — a short text placeholder like

[ Shortcode-Identifier-Here ]

or

[ gallery Shortcode-Identifier-Here ]

that WordPress replaces with complex HTML output when the page is rendered. WordPress shortcodes bridge the gap between backend functionality and front-end placement, letting content editors insert dynamic content anywhere in the WordPress editor without touching PHP or HTML directly. This guide covers using built-in shortcodes, installing plugin shortcodes, and creating custom ones. For the bigger picture, our Complete Guide to WordPress How pulls everything together.

WordPress Shortcodes — Built-In and Plugin Shortcodes

WordPress ships with several built-in WordPress shortcodes that most users never discover.

creates an image gallery from attached media. wraps an image with a caption.

and

embed media files with the native HTML5 player.

creates an audio or video playlist from attached files.

forces WordPress to treat a URL as an oEmbed embed rather than a plain link. These built-in shortcodes work in post content, page content, text widgets, and anywhere else that runs the do_shortcode() filter.

Plugin-added WordPress shortcodes expand the system significantly. Contact Form 7 generates shortcodes for each form ([contact-form-7 id="1"]). WooCommerce provides [woocommerce_cart], [woocommerce_checkout], [products], and dozens more. WPForms creates a shortcode for each form. Page builders like Elementor and Divi disable shortcode-based placement in favour of their own drag-and-drop interface, but most other plugins still use shortcodes as their primary front-end placement mechanism. To use a plugin’s shortcodes, install and activate the plugin → look for shortcode documentation in the plugin’s settings or documentation → paste the shortcode into any post, page, or text widget — WordPress replaces it with the plugin’s output automatically.

The block editor handles WordPress shortcodes through the dedicated Shortcode block: click the “+” block inserter → search “Shortcode” → insert the block → paste the shortcode into the text field. The block editor does not render shortcode output in the editor view — it shows the shortcode text during editing but renders the correct output on the published front-end. For shortcodes that need to appear in multiple places across the site (a signup form, a CTA button, a product grid), using a Reusable Block containing the Shortcode block allows updating the shortcode parameters in one place and having the change propagate to every instance automatically. According to the WordPress developer documentation, shortcodes are processed by the do_shortcode() function which applies the the_content filter — shortcodes in the_content run automatically, while shortcodes in other contexts require explicit echo do_shortcode('[shortcode]'); calls in template files.

Creating Custom WordPress Shortcodes

Custom WordPress shortcodes allow any PHP functionality to be triggered from post content through a simple text placeholder. Creating a shortcode requires registering a callback function that returns the HTML output — never echoes it — using the add_shortcode() function.

A simple shortcode that outputs the current year (useful for copyright notices that should always show the current year):

add_shortcode('current_year', function($atts) {
    return date('Y');
});
// Usage: [current_year]

A shortcode with attributes — $atts receives an array of the attribute values passed in the shortcode tag. The shortcode_atts() function merges provided attributes with defaults, preventing undefined index errors:

add_shortcode('button', function($atts) {
    $a = shortcode_atts([
        'text' => 'Click Here',
        'url'  => '#',
        'color' => 'blue',
    ], $atts);
    return sprintf('<a href="%s" class="btn btn-%s">%s</a>',
        esc_url($a['url']),
        esc_attr($a['color']),
        esc_html($a['text'])
    );
});
// Usage: [button text="Get Started" url="/contact/" color="green"]

Add these to the child theme’s functions.php or a custom plugin. Custom WordPress shortcodes in a plugin rather than functions.php survive theme switches — if the theme changes, shortcodes in functions.php are lost and every instance of the shortcode in content shows the raw shortcode text rather than the rendered output. The Code Snippets plugin is an excellent alternative to a custom plugin for non-developers — it allows adding shortcode registration PHP as a snippet through the admin UI without FTP access or creating plugin files manually.

Shortcodes in Widgets, Templates, and PHP

WordPress shortcodes work automatically in post and page content because the_content filter includes do_shortcode processing. They do not automatically work in widget text, template files, or theme options — each of these contexts requires explicit shortcode processing.

Enable WordPress shortcodes in the Classic Text Widget: in older WordPress installations or sites still using the classic widget system, add add_filter('widget_text_content', 'do_shortcode'); to functions.php. In the block editor’s Widget screen, shortcodes in a Shortcode block work automatically. In a Custom HTML widget, shortcodes are not processed — use the Shortcode block or the Text widget instead. For sidebar widgets in custom widget PHP code, wrap the output: echo do_shortcode($instance['content']); — this processes any shortcodes in user-entered widget content before outputting it.

Process WordPress shortcodes directly in PHP template files by wrapping the shortcode string: echo do_shortcode('[contact-form-7 id="1"]'); — this outputs the shortcode’s rendered HTML directly in the template. This approach is useful for placing a specific form or content block in a template position where the Shortcode block cannot be used — the footer, the sidebar, above the content in a specific template. Use do_shortcode() rather than echo to maintain output buffering compatibility and to allow the shortcode to return rather than directly echo its content. For shortcodes that need to run in the_excerpt, the_title, or other filter chains that do not include do_shortcode by default, add the filter explicitly: add_filter('the_excerpt', 'do_shortcode');. Our guide on fixing WordPress excerpt not showing covers the excerpt filter chain where shortcode processing may need to be explicitly added for shortcode-heavy content types.

Shortcode Performance and Security

WordPress shortcodes execute on every page load for every post that contains them — there is no built-in caching for shortcode output. A complex shortcode that runs database queries, makes external API calls, or generates large HTML structures adds to every page’s PHP execution time. Understanding this performance characteristic guides when shortcodes are appropriate and when a different approach is better.

Cache expensive shortcode output using WordPress transients: wrap the shortcode callback’s database queries or API calls in get_transient/set_transient: $cached = get_transient('my_shortcode_output'); if (false === $cached) { $cached = generate_expensive_output(); set_transient('my_shortcode_output', $cached, HOUR_IN_SECONDS); } return $cached;. This caches the shortcode output for one hour, running the expensive operation only once per hour rather than on every page load. Combine with a page caching plugin — when the entire page is cached, the shortcode does not execute at all for cached requests, making the transient caching only necessary for non-cached page loads. For WordPress shortcodes that personalise output per user (showing different content to logged-in users), caching must account for the user state to avoid serving cached personalised content to the wrong user.

Security for custom WordPress shortcodes requires escaping all output and validating all attribute values before using them. Never output raw user-supplied attribute values directly — always wrap string output in esc_html() or esc_attr(), URL values in esc_url(), and integer values in intval(). Shortcode attributes that accept post IDs or user IDs should validate that the referenced object exists and is accessible to the current user before outputting its data. A shortcode that outputs post content based on an ID attribute without capability checking could expose private or password-protected content to any visitor who knows the right shortcode syntax. Applying the same security principles to shortcode development as to any other PHP WordPress development prevents common vulnerabilities in custom shortcode implementations. Reviews from the WordPress security community highlight unescaped shortcode attribute output as a common source of Cross-Site Scripting (XSS) vulnerabilities in custom WordPress plugins and themes. Our guide on preventing WordPress spam comments covers the broader security mindset that applies to shortcode security hardening alongside content submission security.

WordPress shortcodes support enclosing content between opening and closing tags, allowing the shortcode callback to receive and transform the content between the tags. Enclosing shortcodes use a closing tag: [highlight color="yellow"]This text gets highlighted[/highlight]. The callback receives the enclosed content as the third parameter: add_shortcode('highlight', function($atts, $content=null) { $a = shortcode_atts(['color'=>'yellow'], $atts); return '<mark style="background:' . esc_attr($a['color']) . '">' . do_shortcode($content) . '</mark>'; });. The do_shortcode($content) call inside the callback processes any nested shortcodes within the enclosed content — allowing shortcodes to be nested inside other shortcodes when both are registered as enclosing types. This nesting capability enables complex layout shortcodes like column systems: [row][column width="6"]Left content[/column][column width="6"]Right content[/column][/row].

Deprecating and migrating old WordPress shortcodes when a site’s functionality changes requires a transition plan to avoid breaking existing content. If a shortcode like [old-button] needs to be replaced with [button], keep the old shortcode registered but have it call the new shortcode’s callback: add_shortcode('old-button', function($atts, $content) { return call_user_func(get_shortcode_regex_callback('button'), $atts, $content, 'button'); });. Alternatively, register the old name as an alias that simply calls the new shortcode string: add_shortcode('old-button', function($atts) { return do_shortcode('[button ' . shortcode_unautop(shortcode_parse_atts_string($atts)) . ']'); });. This backward compatibility layer means existing content with the old shortcode continues to render correctly while new content uses the updated shortcode name, giving time to search-replace old shortcode instances across content without an emergency update under time pressure.

Removing unused WordPress shortcodes from content when a plugin is deactivated or a custom shortcode is retired prevents the raw shortcode text from appearing in published content. WordPress’s strip_shortcodes() function removes all registered shortcode tags from a string — useful in excerpt generation. For content cleanup, the Better Search Replace plugin can find and replace shortcode instances across the database: search for [old-shortcode → replace with the equivalent HTML that the shortcode was previously generating. This content-level migration converts shortcode-dependent content into direct HTML, making it portable and removing the dependency on the shortcode registration existing. Run the search-replace on a staging environment first to confirm the replacements are correct before applying to production.

The wp_kses() function and its variants are essential for securing WordPress shortcodes that accept HTML in their content or attributes. Rather than using esc_html() (which strips all HTML tags) when HTML is intentionally allowed, wp_kses_post() strips dangerous tags and attributes while preserving safe ones (paragraphs, links, strong, em, etc.) — matching the same HTML filtering applied to post content. For shortcodes that output HTML from user-provided attributes, this distinction matters: a testimonial shortcode that accepts a quote attribute should use wp_kses_post($a['quote']) rather than esc_html($a['quote']) if the quote may contain formatting like line breaks or emphasis. Applying the correct escaping function to each output type is the single most important security decision when creating custom WordPress shortcodes, and auditing existing shortcodes against these standards is a worthwhile security review step on any established WordPress site.

Block patterns in the block editor are the modern evolution of WordPress shortcodes for layout-based content — pre-built arrangements of blocks that editors can insert with one click, similar to how shortcodes insert pre-built HTML. For new WordPress development, block patterns are preferred over shortcodes for layout purposes because they are natively editable in the block editor (the editor renders them visually rather than showing shortcode text), are version-controlled in the theme as PHP files, and do not require PHP execution at render time. Register a block pattern in the child theme’s functions.php using register_block_pattern(). However, shortcodes remain indispensable for dynamic content — output that changes based on context, user state, or database queries — which block patterns cannot replicate since patterns are static HTML arrangements. The two systems coexist cleanly: use block patterns for reusable layout sections and WordPress shortcodes for dynamic functionality that varies at runtime.

Debugging WordPress shortcodes that are not rendering correctly starts with confirming the shortcode is registered at the time it is called. Add global $shortcode_tags; var_dump(isset($shortcode_tags['your-shortcode'])); to a template file temporarily — if it outputs false, the shortcode is not registered at all, indicating the add_shortcode() call is not being executed. Common causes: the plugin registering the shortcode is inactive, the functions.php code containing add_shortcode() has a PHP syntax error above it preventing execution, or the shortcode is being called before the init hook when it is registered. For shortcodes that show the raw text instead of rendered output, check whether the page is being served from a full-page cache that was built before the shortcode was registered — clear the cache and reload to confirm. The WP Shortcode Debug plugin provides a visual overlay on the front-end showing which shortcodes were found on the page and whether they were successfully processed, making shortcode debugging significantly faster than print_r debugging in templates.

Internationalising custom WordPress shortcodes makes them translation-ready for multilingual sites. Wrap any string literals in the shortcode callback output with WordPress translation functions: use __('Text', 'textdomain') for strings returned by a variable and _e('Text', 'textdomain') for strings echoed directly. Use the same text domain as the plugin or child theme containing the shortcode. With translation functions in place, WPML or Polylang can extract the shortcode’s output strings for translation, and the shortcode displays correctly in each active language without any changes to the shortcode registration code itself. This internationalisation step costs almost no extra development time when done during initial shortcode creation but is significantly more work to add retroactively across many established shortcodes later. Related: WordPress Translation.

Nikolas Lamprou

Nikolas Lamprou (MSc; GCFR, SC-200, Security+) has been working with computers professionally since 2009 — starting with web development and e-commerce, and moving into cybersecurity over the years. Based in Greece, he brings over 15 years of real-world IT experience to SolveTechToday, where he writes about Windows fixes, software reviews, security tools, and AI applications. His goal is straightforward: cut through the noise and give readers clear, honest guidance on the tech decisions that matter.

Stay Ahead

Fix your next problem before it starts

Get the week's best Windows fixes, software picks, and security guides delivered straight to your inbox. No noise, just solutions.

Press ESC to close · Try "Windows 11" or "Chrome"