← Back to Logbook
April 14, 2026 by Quartermaster

How to Create WordPress Shortcodes — The Complete add_shortcode() Tutorial

how to create wordpress shortcodes — pirate captain with shortcode scroll

You learn how to create WordPress shortcodes by writing a PHP callback function that returns your desired output, then registering it with add_shortcode() — and learning how to create WordPress shortcodes is one of the fastest ways to add reusable dynamic content anywhere on your site. This guide covers everything from basic self-closing shortcodes to advanced patterns with attributes, nesting, and real-world examples you can deploy today.

⚓ KEY TAKEAWAYS

  • Shortcodes are square-bracket macros WordPress replaces with PHP function output at render time
  • Register every shortcode with add_shortcode('tag', 'callback') — never echo, always return
  • Use shortcode_atts() to handle attributes with safe default values
  • Enclosing shortcodes receive a $content parameter — call do_shortcode($content) to support nesting
  • Always sanitize inputs and escape outputs — shortcode attributes are user-controlled data
  • Shortcodes still work in Gutenberg via the Shortcode block — they are not dead, they are pirates

What Are WordPress Shortcodes and How Do They Work?

A shortcode is a small macro wrapped in square brackets — think

or [current_year] — that WordPress replaces with the output of a registered PHP function when a page renders. The visitor never sees the bracket tag. That is the magic of knowing how to create WordPress shortcodes. They see whatever HTML your callback returns.

The Shortcode API landed in WordPress 2.5 back in 2008 and has been a core feature for 18 years. That is not legacy code — that is a battle-hardened weapon. Thousands of plugins including WooCommerce, Contact Form 7, and Yoast SEO ship shortcodes to this day.

📊 STAT BLOCK

WordPress powers 43.2% of all websites on the internet as of April 2026 — and the Shortcode API is baked into every single one of those installations. (W3Techs, April 2026)

WordPress ships several built-in shortcodes out of the box:

, , , , , and . The registration pattern for custom shortcodes works exactly the same way — which is also how WordPress hooks, actions, and filters are wired up under the hood.

Where to Add Your Shortcode Code (The Right Way)

Part of knowing how to create WordPress shortcodes is knowing where to put the code. Get this wrong and a theme update wipes everything overboard.

Using Your Child Theme’s functions.php

The quick way to learn how to create WordPress shortcodes is dropping your shortcode registration into your child theme’s functions.php file. It works fine for site-specific shortcodes that are tightly coupled to your theme. Never touch the parent theme’s functions.php — updates will delete your code without mercy.

For those serious about mastering how to create WordPress shortcodes, the cleaner approach is a site-specific plugin. Create a file at /wp-content/plugins/my-site-shortcodes/my-site-shortcodes.php with a plugin header, drop your code in, and activate it. This approach to how to create WordPress shortcodes means your shortcodes survive theme swaps, child theme rebuilds, and any chaos the corporate SaaS overlords throw at you.

For full context on how WordPress loads these files, see our guide on what wp-config.php is and how to edit it — understanding the file structure helps you place code like a seasoned deck hand.

How to Create a Basic Self-Closing Shortcode

Understanding how to create WordPress shortcodes with attributes lets users customize shortcode output without touching code — the whole point of learning how to create WordPress shortcodes with real flexibility. The callback receives an $atts array of whatever the user typed inside the brackets.

Using shortcode_atts() for Default Values

Never access $atts directly. Run it through shortcode_atts() to merge user-supplied values with your safe defaults. Any attribute not passed by the user falls back to your default — no undefined index notices, no broken layouts.

Practical Example — A Custom Button Shortcode

function aodn_button_shortcode( $atts ) {
    $atts = shortcode_atts(
        array(
            'url'   => '#',
            'color' => 'blue',
            'text'  => 'Click Me',
        ),
        $atts,
        'aodn_button'
    );

    $url   = esc_url( $atts['url'] );
    $color = sanitize_text_field( $atts['color'] );
    $text  = esc_html( $atts['text'] );

    return '' . $text . '';
}
add_shortcode( 'aodn_button', 'aodn_button_shortcode' );

Usage: [aodn_button url="https://aiordienow.com" color="red" text="Board the Ship"]. Every attribute is sanitized and escaped before output — notice the esc_url(), sanitize_text_field(), and esc_html() calls. More on that in the security section.

How to create custom shortcodes in WordPress — Kinsta

Creating Enclosing Shortcodes with Content

The next step in how to create WordPress shortcodes is enclosing tags. The next level of how to create WordPress shortcodes is enclosing tags. An enclosing shortcode wraps content between an opening and closing tag: [highlight]This text[/highlight]. WordPress passes everything between the tags into the callback’s $content parameter.

function aodn_highlight_shortcode( $atts, $content = null ) {
    $atts = shortcode_atts(
        array( 'color' => 'yellow' ),
        $atts,
        'aodn_highlight'
    );

    $color = sanitize_text_field( $atts['color'] );

    return '' 
        . do_shortcode( $content ) 
        . '';
}
add_shortcode( 'aodn_highlight', 'aodn_highlight_shortcode' );

The key move: call do_shortcode( $content ) on the inner content rather than outputting it raw. That single call is what makes nesting work — and it is why understanding how to create WordPress shortcodes with enclosing patterns is worth the extra five minutes.

// PULL QUOTE

“As a security precaution, running PHP inside WordPress content is forbidden; to allow dynamic interactions with the content, Shortcodes were presented in WordPress version 2.5.”

— WordPress Plugin Handbook, developer.wordpress.org

How to Nest Shortcodes in WordPress

An advanced step in learning how to create WordPress shortcodes is nesting. Advanced knowledge of how to create WordPress shortcodes includes nesting. Nesting works when the outer shortcode calls do_shortcode() on its $content — which is exactly what the enclosing example above does. The WordPress parser runs a single pass, so the outer tag must call do_shortcode() explicitly to trigger inner tag processing.

// Outer shortcode — wraps content in a styled box
function aodn_box_shortcode( $atts, $content = null ) {
    return '
' . do_shortcode( $content ) . '
'; } add_shortcode( 'aodn_box', 'aodn_box_shortcode' ); // Usage in content: // [aodn_box][aodn_button url="https://aiordienow.com" text="Board Now"][/aodn_box]

When you learn how to create WordPress shortcodes with nesting, there is one hard limitation: you cannot nest a shortcode inside itself. The WordPress parser cannot handle [box][box]inner[/box][/box] — the first closing tag ends the first opening tag, full stop. Use different tag names for every nesting level.

⚓ MID-SHIP CTA

Need the full arsenal of WordPress development tools? We’ve mapped out the best weapons for fighting the corporate SaaS machine.

⚔️ RAID THE ARSENAL →

3 Practical Shortcode Examples You Can Use Today

When learning how to create WordPress shortcodes with real utility, most tutorials give you [hello_world] and wave goodbye. Not here. These are production-ready patterns showing how to create WordPress shortcodes that actually solve problems that show the full power of how to create WordPress shortcodes that actually do something.

Alert Box Shortcode

function aodn_alert_shortcode( $atts, $content = null ) {
    $atts = shortcode_atts(
        array( 'type' => 'info' ),
        $atts,
        'aodn_alert'
    );

    $type = sanitize_html_class( $atts['type'] );

    return '
' . wp_kses_post( do_shortcode( $content ) ) . '
'; } add_shortcode( 'aodn_alert', 'aodn_alert_shortcode' ); // [aodn_alert type="warning"]Back up your database before editing theme files.[/aodn_alert]

Team Member Card Shortcode

function aodn_team_member_shortcode( $atts, $content = null ) {
    $atts = shortcode_atts(
        array(
            'name'  => 'Crew Member',
            'role'  => 'Deck Hand',
            'image' => '',
        ),
        $atts,
        'aodn_team_member'
    );

    $img = $atts['image'] ? '' . esc_attr( $atts['name'] ) . '' : '';

    return '
' . $img . '

' . esc_html( $atts['name'] ) . '

' . '

' . esc_html( $atts['role'] ) . '

' . '
' . wp_kses_post( do_shortcode( $content ) ) . '
' . '
'; } add_shortcode( 'aodn_team_member', 'aodn_team_member_shortcode' );

Dynamic Recent Posts Shortcode

function aodn_recent_posts_shortcode( $atts ) {
    $atts = shortcode_atts(
        array(
            'count'    => 5,
            'category' => '',
        ),
        $atts,
        'aodn_recent_posts'
    );

    $args = array(
        'posts_per_page'      => absint( $atts['count'] ),
        'category_name'       => sanitize_text_field( $atts['category'] ),
        'ignore_sticky_posts' => 1,
    );

    $query  = new WP_Query( $args );
    $output = '';
    return $output;
}
add_shortcode( 'aodn_recent_posts', 'aodn_recent_posts_shortcode' );

// [aodn_recent_posts count="5" category="tutorials"]

That last one integrates WP_Query directly — real WordPress API usage, not a toy example. This is the level of power you unlock when you fully understand how to create WordPress shortcodes with parameters.

Shortcodes vs Gutenberg Blocks — Which Should You Use?

how to create wordpress shortcodes — shortcodes vs blocks comparison

Blocks are the modern approach. Drag-and-drop, visual editing, no code required for end users. If you are building something purely for content formatting — a pull quote, a column layout — use a block. Read our full WordPress Block Editor guide for the deep dive.

Shortcodes win when you need: programmatic dynamic content (like that WP_Query example), backward compatibility with existing content, or placement in locations blocks cannot reach — like navigation menus, widget areas in classic themes, or email templates. They are not dead. They are deployed differently.

Decision framework: use blocks for content formatting, use shortcodes for dynamic functionality. When you know how to create WordPress shortcodes properly, you use them as precision tools — not a crutch, not a novelty. The Gutenberg editor includes a dedicated Shortcode block, so both coexist without drama.

Debugging WordPress Shortcodes

how to create wordpress shortcodes — debugging shortcode issues

Common Issues and Fixes

Shortcode displays as plain text — the most common issue when you learn how to create WordPress shortcodes is the tag is not registered. Check for a typo between your add_shortcode() tag name and what you typed in the editor. Also verify the file containing your registration code is actually being loaded.

Output appears above the page content — you used echo instead of return in your callback. PHP buffers the echo before WordPress can place it, so it floats to the top. Always return.

Attributes not working — check your shortcode_atts() defaults array. The keys must match what the user types in the bracket tag. Nested shortcode not processing — you forgot do_shortcode( $content ) in the outer callback.

Using WP_DEBUG to Find Errors

Enable WP_DEBUG in your wp-config.php and watch the error log. A silent PHP fatal error in your callback will cause the shortcode to vanish without a trace — WP_DEBUG exposes it immediately. For the full troubleshooting playbook, hit our WordPress debugging guide.

Shortcode Security Best Practices

how to create wordpress shortcodes — security best practices

Once you learn how to create WordPress shortcodes, remember that shortcode attributes are user input. Treat them like you would treat a stranger handing you a USB drive labelled “free doubloons.” Sanitize every attribute on the way in, escape every value on the way out.

Use sanitize_text_field() for plain text attributes, esc_url() for URLs, absint() for integers, and sanitize_html_class() for CSS class names. On output, use esc_html() for plain text, esc_attr() inside HTML attributes, and wp_kses_post() for content that needs to allow some HTML.

Prefix every tag name — aodn_button not button. If two plugins register the same shortcode tag, the last one registered wins and your content breaks silently. Namespacing costs you nothing and saves you a very bad day.

Frequently Asked Questions

What is a shortcode in WordPress?

A shortcode is a small piece of code wrapped in square brackets (like

) that acts as a placeholder for dynamic content. WordPress replaces it with the output of a PHP callback function when the page renders, letting you add complex functionality with a simple tag.

Where do I put my custom shortcode code?

Add shortcode code to a site-specific plugin or your child theme functions.php file. Never edit the parent theme directly — updates will overwrite your changes. A site-specific plugin is the recommended approach because it survives theme switches.

Can I use shortcodes inside widgets and menus?

Yes. WordPress supports shortcodes in text widgets by default since version 4.9. For navigation menus, you can enable shortcode processing by adding add_filter(“wp_nav_menu_items”, “do_shortcode”) to your theme or plugin.

What is the difference between self-closing and enclosing shortcodes?

A self-closing shortcode like [current_year] has no content between tags and simply outputs a value. An enclosing shortcode like [highlight]text[/highlight] wraps content and passes it to the callback function via the parameter for processing.

Can I nest shortcodes inside each other?

Yes, WordPress supports nested shortcodes, but the outer shortcode must call do_shortcode() on its content parameter. The inner and outer shortcodes must use different tag names — the WordPress parser cannot handle nested shortcodes of the same name.

Do shortcodes still work with the Block Editor (Gutenberg)?

Yes. The Block Editor includes a dedicated Shortcode block where you can paste any shortcode tag. You can also use shortcodes in any block that accepts HTML. Shortcodes and blocks coexist — blocks are newer but shortcodes remain fully supported.

Why is my shortcode showing as plain text instead of rendering?

This usually means the shortcode is not registered — check for typos in your add_shortcode() call and verify the code file is being loaded. It can also indicate a PHP error in your callback function. Enable WP_DEBUG to see the actual error message.

← How to Create Membership Site WordPress — Plugin, WooCommerce, and Code-Only Paths Why Every Business Needs WordPress — And Why the Alternatives Are a Trap →
The Quartermaster
> THE QUARTERMASTER
Identify yourself, pirate. What brings ye to the command deck?