Short answer: to insert a shortcode in WordPress, type its tag in square brackets – like
or
[contact-form id="3"]
– into a Shortcode block (block editor) or directly into a paragraph. WordPress finds the tag when the page renders, runs the PHP function registered to it, and replaces the tag with whatever that function returns. To build your own, register a function with
add_shortcode()
in your theme’s
functions.php
or a plugin.
This guide covers both sides: inserting shortcodes that plugins and themes already provide, and writing your own with parameters and enclosed content. It also explains why block-based equivalents are quietly replacing shortcodes in modern WordPress.
What a shortcode actually is#
A shortcode is a small placeholder that stands in for a block of dynamic output. Instead of pasting raw PHP or complex HTML into a post, you write a short tag, and WordPress swaps it for the real content when the page loads.
The tag has one of two forms:
- Self-closing:
[tag]or[tag attribute="value"]– the shortcode generates its output entirely on its own. - Enclosing:
[tag]some content[/tag]– the shortcode wraps content you provide and can transform it.
WordPress ships with a handful of built-in shortcodes (
,
,
,
,
,
), and almost every major plugin registers its own. A contact form plugin gives you
[contact-form-7 id="..."]
; a table plugin gives you
[table id="..."]
. The plugin’s documentation tells you the tag and its attributes.
How to insert a shortcode in WordPress#
Where you type the shortcode depends on which editor you use.
In the block editor (Gutenberg)#
The block editor does not run a shortcode typed into a plain Paragraph block reliably – it may render as literal text. Use the dedicated Shortcode block instead:
- In the post or page, click the + to add a block.
- Search for Shortcode and select it.
- Type or paste the shortcode tag into the block, including its square brackets.
- Update or publish. The shortcode runs when a visitor views the page, not in the editor preview.
Many plugins now also provide their own block, which is the better choice when offered – it gives you a visual interface instead of remembering attributes. The shortcode still works; the block is just friendlier.
In the classic editor#
In the classic editor, a shortcode works in either the Visual or Text tab – just type the tag into the content where you want the output to appear. The classic editor processes shortcodes anywhere in the post body, which is part of why they were so widely adopted.
In widgets#
By default, text widgets and the Custom HTML widget do not process shortcodes. If you place
[my-shortcode]
in a widget and see the literal text, that is why. The fix is one line in
functions.php
:
add_filter( 'widget_text', 'do_shortcode' );
This tells WordPress to run shortcodes inside legacy text widgets. If you are building widgets yourself, you can call
do_shortcode()
directly inside the widget output – see how to create a custom WordPress widget for where that code lives.
Why a shortcode shows as plain text#
If a shortcode renders as literal
[tag]
text on the front end instead of producing output, one of these is the cause:
- The shortcode is not registered. The plugin or theme that defines it is deactivated, or you mistyped the tag. WordPress only replaces tags it knows; an unknown tag is left as-is.
- It is in a plain Paragraph block. Move it to a Shortcode block.
- It is in a widget without
widget_textfiltering. Add thedo_shortcodefilter shown above. - It is double-wrapped. Pasting a shortcode inside a Custom HTML block can escape the brackets. Use the Shortcode block.
A leftover
[tag]
after deactivating a plugin is normal – the content is still in your database, the plugin that interpreted it is just gone. Reactivate the plugin or remove the tag.
How to create your own shortcode#
A custom shortcode is a PHP function plus one registration call. The function returns a string;
add_shortcode()
ties it to a tag.
A basic shortcode#
This registers
[current_year]
, which prints the current year – handy for a footer copyright line that never goes stale:
function hostney_current_year_shortcode() {
return date( 'Y' );
}
add_shortcode( 'current_year', 'hostney_current_year_shortcode' );
Now
[current_year]
anywhere in a post outputs
2026
. The single most important rule: a shortcode callback must
return
its output, never
echo
it. A shortcode that echoes will dump its content at the top of the page instead of in place, because WordPress captures the return value and substitutes it into the content.
Shortcodes with attributes#
Attributes are how a shortcode is configured at the point of use. The callback receives them as an array;
shortcode_atts()
merges them with defaults so missing attributes do not break anything:
function hostney_button_shortcode( $atts ) {
$atts = shortcode_atts(
array(
'url' => '#',
'label' => 'Click here',
'style' => 'primary',
),
$atts,
'hostney_button'
);
return sprintf(
'<a href="%s" class="btn btn-%s">%s</a>',
esc_url( $atts['url'] ),
esc_attr( $atts['style'] ),
esc_html( $atts['label'] )
);
}
add_shortcode( 'hostney_button', 'hostney_button_shortcode' );
Used in a post as
[hostney_button url="/pricing" label="See plans" style="orange"]
, it renders a styled link. Any attribute left out falls back to the default. Note the escaping:
esc_url()
,
esc_attr()
, and
esc_html()
on every value, because attribute values come from the post content and must be treated as untrusted.
Enclosing shortcodes#
An enclosing shortcode wraps content between an opening and closing tag. The callback receives that inner content as its second parameter,
$content
:
function hostney_notice_shortcode( $atts, $content = null ) {
$atts = shortcode_atts(
array( 'type' => 'info' ),
$atts,
'hostney_notice'
);
return sprintf(
'<div class="notice notice-%s">%s</div>',
esc_attr( $atts['type'] ),
do_shortcode( $content )
);
}
add_shortcode( 'hostney_notice', 'hostney_notice_shortcode' );
Used as
[hostney_notice type="warning"]Back up before you upgrade.[/hostney_notice]
, it wraps the message in a styled box. The
do_shortcode( $content )
call is deliberate: it processes any shortcodes nested inside, so the enclosed content can itself contain shortcodes. Do not escape
$content
with
esc_html()
here – it is meant to contain markup; rely on WordPress’s own content filtering instead.
Using do_shortcode() in theme files#
Shortcodes only run automatically inside post and page content (anything that passes through the
the_content
filter). They do not run inside theme template files by default. If you want a shortcode’s output in
header.php
,
footer.php
, or a custom template, call
do_shortcode()
explicitly:
echo do_shortcode( '[hostney_button url="/contact" label="Get in touch"]' );
This is the standard way to reuse a shortcode’s output in a part of the site that is not post content. If you are working on template files, do it in a child theme so an update does not erase the change – the same principle covered in how to create a custom WordPress theme from scratch.
Where to put shortcode code#
Like any custom function, a shortcode lives in one of two places:
- The theme’s
functions.phpif the shortcode only makes sense with that theme – for example, a shortcode that outputs theme-specific markup. Use a child theme so updates do not wipe it. - A small plugin if the shortcode should survive a theme switch. Content authors will have typed
[my-shortcode]into dozens of posts; if that tag stops being registered when you change themes, every one of those posts shows raw[my-shortcode]text. A plugin keeps the shortcode alive regardless of the active theme. Packaging a shortcode as a plugin is the same one-file pattern described in how to install plugins in WordPress.
The plugin route is the safer default for any shortcode that authors will use in content. Tie a feature to a theme and you tie your content’s correctness to that theme.
Shortcodes and the block editor#
Shortcodes were designed for the classic editor, where the post body was a single text field. The block editor changes the picture. A block does everything a shortcode does – dynamic output, configuration, reusability – but with a visual interface, live preview, and structured attributes instead of a string of square brackets.
For new development, a block is usually the better choice:
- The editor shows the real output, not a
[tag]. - Attributes are set through controls in the block sidebar, not memorized.
- There is no “renders as literal text” failure mode.
Shortcodes are not deprecated and are not going away – the API is stable, plugins still ship them, and the Shortcode block exists precisely to keep them working. But the modern equivalent of “I need reusable dynamic content in posts” is increasingly a custom block rather than a shortcode. If your output is mostly static markup, a reusable block (synced pattern) or a Custom HTML block may be simpler still – the trade-offs are covered in how to add HTML to a WordPress post or page.
The practical rule: insert and use the shortcodes your plugins provide without hesitation, keep maintaining shortcodes that already exist, but reach for a block when building something new.
Common mistakes to avoid#
- Echoing instead of returning. A shortcode callback must
returna string. Anechodumps the output at the top of the page. - Forgetting to escape attributes. Attribute values come from post content. Run
esc_url(),esc_attr(), oresc_html()on every one. - Hyphen and underscore confusion. The tag in
add_shortcode()must exactly match what authors type.[my-tag]and[my_tag]are different shortcodes. - Expecting shortcodes to run in templates. They do not – use
do_shortcode()in theme files. - Putting the shortcode in the wrong block. Plain Paragraph and Custom HTML blocks do not reliably run shortcodes; the Shortcode block does.
- Defining a shortcode in a theme that content depends on. Switch themes and the tags break. Use a plugin for anything authors put in content.
How Hostney handles shortcode development#
Custom shortcodes are code, and code needs somewhere safe to develop. On Hostney every site runs in its own isolated container, so a shortcode callback with a fatal error affects only the site you are editing, never a neighbor. Full file access through SSH/SFTP, FTPS, or the built-in file manager lets you drop a child theme’s
functions.php
edit or a small shortcode plugin straight into place.
The file manager’s code editor flags PHP syntax errors before you save, which catches the most common shortcode bug – a missing brace or semicolon that would otherwise white-screen the site. And because the PHP environment is kept current,
add_shortcode()
,
shortcode_atts()
, and
do_shortcode()
behave exactly as the current WordPress documentation describes.
Summary#
A shortcode is a square-bracket placeholder that WordPress replaces with the output of a registered PHP function. To use one, type its tag into a Shortcode block or the classic editor; to build one, register a callback with
add_shortcode()
that returns its output, escapes its attributes, and optionally handles enclosed
$content
. Use
do_shortcode()
to run shortcodes in theme templates or widgets, keep shortcode code in a plugin when content depends on it, and reach for a custom block when building something new – blocks are the modern path, but shortcodes remain fully supported for everything already built on them.