Adding custom shortcodes to your WordPress website is useful, but putting every shortcode directly into your theme’s functions.php file can quickly become messy. Over time, that file can become hard to read, hard to maintain, and risky to edit.
A cleaner method is to place your shortcodes in separate PHP files and load those files from one central location. This makes your code easier to organize, easier to update, and less likely to break when you are working on your site.
WordPress shortcodes are created with the add_shortcode() function. This function connects a shortcode name, such as [custom_button], to a PHP function that generates the output. WordPress notes that each shortcode tag can only have one callback, so each shortcode name should be unique. (WordPress Developer Resources)
Why You Should Avoid Putting Every Shortcode in functions.php
The functions.php file is useful for theme-related code, but it is not always the best place for site-wide functionality. If you add many shortcodes directly into functions.php, the file can become crowded and harder to troubleshoot.
There is another important issue: if you switch themes, code inside your old theme’s functions.php file will no longer run. That means your shortcodes could stop working across your pages and posts. For that reason, the best long-term solution is usually to create a small custom plugin for your website shortcodes.
The Best Method: Create a Custom Shortcodes Plugin
The cleanest way to organize your shortcodes is to create a simple custom plugin. This keeps your shortcode functionality separate from your theme. It also means your shortcodes can keep working even if you change your WordPress theme later.
Create a new folder here:
wp-content/plugins/site-shortcodes/
Inside that folder, create this main plugin file:
wp-content/plugins/site-shortcodes/site-shortcodes.php
Add this code to site-shortcodes.php:
<?php
/**
* Plugin Name: Site Shortcodes
* Description: Custom shortcodes for this website.
* Version: 1.0.0
*/
if (!defined('ABSPATH')) {
exit;
}
require_once plugin_dir_path(__FILE__) . 'shortcodes/custom-button.php';
require_once plugin_dir_path(__FILE__) . 'shortcodes/feature-box.php';
require_once plugin_dir_path(__FILE__) . 'shortcodes/notice-box.php';
The plugin header at the top is what allows WordPress to recognize the file as a plugin. WordPress requires at least a plugin name in the plugin header for the plugin to appear properly in the admin area. (WordPress Developer Resources)
The plugin_dir_path(__FILE__) function helps WordPress find files relative to the current plugin file. WordPress recommends using its directory functions instead of hard-coding paths, because WordPress folders can be moved or renamed on some installations. (WordPress Developer Resources)
Create a Shortcodes Folder
Inside your plugin folder, create a new folder called shortcodes:
wp-content/plugins/site-shortcodes/shortcodes/
Your structure should now look like this:
site-shortcodes/
site-shortcodes.php
shortcodes/
custom-button.php
feature-box.php
notice-box.php
Each shortcode can now live in its own file.
Example Shortcode File
Create this file:
wp-content/plugins/site-shortcodes/shortcodes/custom-button.php
Add this code:
<?php
if (!defined('ABSPATH')) {
exit;
}
function site_custom_button_shortcode($atts) {
$atts = shortcode_atts(
array(
'text' => 'Click Here',
'url' => '#',
),
$atts,
'custom_button'
);
return '<a class="site-custom-button" href="' . esc_url($atts['url']) . '">' . esc_html($atts['text']) . '</a>';
}
add_shortcode('custom_button', 'site_custom_button_shortcode');
You can now use this shortcode inside a page, post, or shortcode block:
[custom_button text="Contact Us" url="/contact/"]
The shortcode_atts() function lets you define default shortcode attributes and merge them with the attributes entered by the user. Unsupported attributes are ignored. (WordPress Developer Resources)
Example Shortcode With Opening and Closing Tags
Some shortcodes are better when they wrap around content. For example:
[feature_box title="Important Notice"]
This is the content inside the box.
[/feature_box]
Create this file:
wp-content/plugins/site-shortcodes/shortcodes/feature-box.php
Add this code:
<?php
if (!defined('ABSPATH')) {
exit;
}
function site_feature_box_shortcode($atts, $content = null) {
$atts = shortcode_atts(
array(
'title' => 'Feature Box',
),
$atts,
'feature_box'
);
ob_start();
?>
<div class="site-feature-box">
<h3><?php echo esc_html($atts['title']); ?></h3>
<div class="site-feature-box-content">
<?php echo wp_kses_post(do_shortcode($content)); ?>
</div>
</div>
<?php
return ob_get_clean();
}
add_shortcode('feature_box', 'site_feature_box_shortcode');
This version uses output buffering with ob_start() and ob_get_clean(). That makes it easier to write larger blocks of HTML inside a shortcode while still returning the final output properly.
Activate the Plugin
After creating the files, go to:
WordPress Admin > Plugins
Find:
Site Shortcodes
Then click:
Activate
Once activated, your shortcodes should work anywhere WordPress processes shortcodes.
Alternative Method: Use a Shortcodes Folder in Your Child Theme
If you do not want to create a plugin, you can also organize shortcodes inside your child theme.
Create this folder:
wp-content/themes/your-child-theme/shortcodes/
Then place your shortcode files inside it:
wp-content/themes/your-child-theme/shortcodes/custom-button.php
wp-content/themes/your-child-theme/shortcodes/feature-box.php
wp-content/themes/your-child-theme/shortcodes/notice-box.php
In your child theme’s functions.php file, load those files like this:
<?php
require_once get_stylesheet_directory() . '/shortcodes/custom-button.php';
require_once get_stylesheet_directory() . '/shortcodes/feature-box.php';
require_once get_stylesheet_directory() . '/shortcodes/notice-box.php';
This is much cleaner than putting all shortcode code directly in functions.php. However, the shortcode files are still tied to your theme. If you switch themes, those shortcodes will stop loading unless you move them to the new theme or a plugin.
Automatically Load All Shortcode Files
If you have many shortcodes, you may not want to manually add a new require_once line every time. You can automatically load every PHP file from the shortcodes folder.
For a custom plugin, use this in your main plugin file:
<?php
/**
* Plugin Name: Site Shortcodes
* Description: Custom shortcodes for this website.
* Version: 1.0.0
*/
if (!defined('ABSPATH')) {
exit;
}
foreach (glob(plugin_dir_path(__FILE__) . 'shortcodes/*.php') as $shortcode_file) {
require_once $shortcode_file;
}
Then every file inside this folder will be loaded:
wp-content/plugins/site-shortcodes/shortcodes/
This makes the system easier to maintain. To add a new shortcode, you only need to create a new PHP file inside the shortcodes folder.
Naming Your Shortcodes Safely
Use unique shortcode names so they do not conflict with WordPress, your theme, or other plugins. For example, instead of this:
[button]
Use something more specific:
[site_button]
Or:
[aspen_button]
This matters because WordPress allows only one callback for a given shortcode tag. If another plugin or theme registers the same shortcode name, one shortcode can override the other. (WordPress Developer Resources)
Basic Security Rules
When creating shortcode output, always escape dynamic data before displaying it.
Use:
esc_html()
for normal text.
Use:
esc_url()
for links.
Use:
esc_attr()
for HTML attributes.
Use:
wp_kses_post()
when you want to allow safe post-style HTML.
For example:
return '<a href="' . esc_url($atts['url']) . '">' . esc_html($atts['text']) . '</a>';
This protects your site from unsafe output and keeps your shortcodes more reliable.
Recommended Final Structure
For most websites, the best setup looks like this:
wp-content/
plugins/
site-shortcodes/
site-shortcodes.php
shortcodes/
custom-button.php
feature-box.php
notice-box.php
Your main plugin file loads the shortcode files. Each shortcode file contains one shortcode. This keeps your project organized and makes future updates easier.
Conclusion
You do not need to put every WordPress shortcode inside functions.php. A much better approach is to move each shortcode into its own PHP file and load those files from one central plugin file.
For the most reliable setup, create a small custom plugin called something like Site Shortcodes. Inside it, create a shortcodes folder and place each shortcode in its own file. This keeps your code clean, protects your shortcodes from theme changes, and makes your website easier to maintain over time.