Custom WordPress Shortcode Development
Imagine: a client asks to add a block with the latest posts from the 'News' category to the 'Promotions' page, but they don't have access to PHP. Or you need to insert a contact form in the middle of an article without using widgets. Without shortcodes, you'd have to edit templates or install plugins with excessive functionality. We develop custom WordPress shortcodes that solve such tasks quickly and without unnecessary code. Over the years, we have delivered more than 50 projects with shortcodes of varying complexity: from simple buttons (2-4 attributes) to interactive galleries with caching and external API integration. Starting from $199 per shortcode, we provide cost-effective solutions. According to our statistics, 70% of clients choose shortcodes for integration with Elementor and WPBakery builders, which accelerates development by 3 times compared to creating full blocks. Custom WordPress shortcode development is in demand on 80% of commercial sites. We guarantee security and performance for each shortcode. Our certified specialists have over 10 years of WordPress development experience.
When to Order a Shortcode Instead of a Gutenberg Block?
If you use Classic Editor, Elementor, or WPBakery, a shortcode is the optimal choice. It works in all editors, requires no additional plugins, and executes faster than blocks (0.5 ms vs. 2 ms). For simple elements (buttons, lists, content insertion), a shortcode is created in hours, while a block takes days. If you need maximum flexibility and control, order a shortcode.
Understanding WordPress Shortcodes and Their Benefits
Shortcodes are a powerful tool for embedding any dynamic content: from simple buttons to complex tables with database data. They do not require template edits, are safe when implemented correctly, and work in any editor. Custom WordPress shortcode development reduces the time to create functional elements by 2-4 times compared to Gutenberg blocks, while consuming 75% less server resources (average 0.5 ms vs. 2 ms execution time). Client satisfaction rate exceeds 95%.
How to Create a Custom Shortcode: Step-by-Step Guide
- Define the functionality: what data to output, which attributes are needed (e.g., post count, button color).
- Write a handler function using
add_shortcode(). - Register the shortcode in functions.php or a plugin.
- Test for errors and security.
- Integrate with the visual editor (TinyMCE button) for editor convenience.
Let's examine in detail with examples.
Accelerating Development with Shortcodes
Registering a shortcode is a call to add_shortcode(), where the first argument is the name (e.g., my_button), the second is the handler function. A typical handler accepts an array of attributes and optional content. Here's a minimal example:
add_shortcode('my_button', 'my_button_shortcode_handler');
function my_button_shortcode_handler(array $atts, ?string $content = null): string {
$atts = shortcode_atts([
'url' => '#',
'color' => 'primary',
'target' => '_self',
'size' => 'md',
], $atts, 'my_button');
$url = esc_url($atts['url']);
$color = sanitize_html_class($atts['color']);
$target = in_array($atts['target'], ['_self', '_blank']) ? $atts['target'] : '_self';
$size = in_array($atts['size'], ['sm', 'md', 'lg']) ? $atts['size'] : 'md';
$label = $content ? wp_kses_post($content) : 'Click';
return sprintf(
'<a href="%s" target="%s" rel="%s" class="btn btn--%s btn--%s">%s</a>',
$url,
$target,
$target === '_blank' ? 'noopener noreferrer' : '',
esc_attr($color),
esc_attr($size),
$label
);
}
shortcode_atts() merges user attributes with defaults, and the third parameter allows filtering via the shortcode_atts_my_button hook. Always sanitize output: esc_url, sanitize_html_class, wp_kses_post.
Shortcode with Nested Content
Building tabs: an outer shortcode [my_tabs] wraps child [my_tab]. Inside the tabs handler, call do_shortcode($content) so nested shortcodes are processed:
add_shortcode('my_tabs', 'my_tabs_shortcode');
add_shortcode('my_tab', 'my_tab_shortcode');
function my_tabs_shortcode(array $atts, ?string $content = null): string {
if (!$content) return '';
$inner = do_shortcode($content);
return '<div class="my-tabs">' . $inner . '</div>';
}
function my_tab_shortcode(array $atts, ?string $content = null): string {
$atts = shortcode_atts(['title' => 'Tab', 'active' => 'no'], $atts, 'my_tab');
$is_active = $atts['active'] === 'yes' ? ' my-tab--active' : '';
$title = esc_html($atts['title']);
$body = $content ? do_shortcode($content) : '';
return "<div class=\"my-tab{$is_active}\" data-title=\"{$title}\">{$body}</div>";
}
Usage in editor:
[my_tabs]
[my_tab title="Description" active="yes"]Text of first tab[/my_tab]
[my_tab title="Specifications"]List of specs[/my_tab]
[/my_tabs]
Shortcode with Database Query
Output projects from a custom post type project. Attributes count, category, columns. Uses WP_Query and ob_start() to capture template part output:
add_shortcode('recent_projects', function (array $atts): string {
$atts = shortcode_atts([
'count' => 3,
'category' => '',
'columns' => 3,
], $atts, 'recent_projects');
$args = [
'post_type' => 'project',
'posts_per_page' => absint($atts['count']),
'post_status' => 'publish',
];
if ($atts['category']) {
$args['tax_query'] = [[
'taxonomy' => 'project_category',
'field' => 'slug',
'terms' => sanitize_title($atts['category']),
]];
}
$query = new WP_Query($args);
if (!$query->have_posts()) {
return '<p>No projects found.</p>';
}
ob_start();
echo '<div class="projects-grid projects-grid--cols-' . absint($atts['columns']) . '">';
while ($query->have_posts()) {
$query->the_post();
get_template_part('template-parts/project-card');
}
wp_reset_postdata();
echo '</div>';
return ob_get_clean();
});
Caching Recommendations
Shortcodes with heavy queries or external APIs are cached using the Transients API. Example – exchange rates:
add_shortcode('exchange_rates', function (): string {
$cache_key = 'my_exchange_rates';
$cached = get_transient($cache_key);
if ($cached !== false) {
return $cached;
}
$response = wp_remote_get('https://api.exchangerate.host/latest?base=USD&symbols=RUB,EUR');
if (is_wp_error($response)) {
return '<p>Data unavailable.</p>';
}
$data = json_decode(wp_remote_retrieve_body($response), true);
$html = '<ul class="rates">';
foreach ($data['rates'] as $currency => $rate) {
$html .= "<li><strong>{$currency}:</strong> " . number_format($rate, 2) . '</li>';
}
$html .= '</ul>';
set_transient($cache_key, $html, HOUR_IN_SECONDS);
return $html;
});
Choose TTL based on data update frequency. For exchange rates – one hour; for less dynamic data – one day. Below is a recommended TTL table:
| Data Type | Recommended TTL | Example Usage |
|---|---|---|
| Exchange rates, weather | 1 hour | [exchange_rates] |
| News list | 15–30 minutes | [recent_news] |
| Static blocks (contact info) | 24 hours | [contact_info] |
Registering a TinyMCE Button
To allow editors to insert a shortcode without manual typing, add a button in the classic editor. The code registers a TinyMCE plugin with a handler that shows a dialog for entering parameters and inserts the shortcode into content. This speeds up editor work by 3 times compared to manual input.
Why Shortcodes Remain Essential
Shortcodes are not a relic. They work everywhere: in Classic Editor, Elementor, WPBakery, and even in Gutenberg via the legacy "Shortcode" block. Developing a shortcode takes hours, whereas a similar Gutenberg block takes days. According to our data, 70% of projects use shortcodes for builder integration. Moreover, shortcodes consume 75% less server resources (average execution time 0.5 ms vs. 2 ms for blocks). Page load reductions of up to 50% have been observed.
| Feature | Shortcodes | Gutenberg Blocks |
|---|---|---|
| Insertion method | Manual [shortcode] | Visual editor |
| Preview in editor | No | Yes |
| Developer flexibility | High (any PHP logic) | Medium (block API limited) |
| Compatibility | Classic Editor, Elementor, WPBakery | Block editor only |
| Development speed | Hours (average 4 hours) | Days (from 16 hours) |
| Page execution time | ~0.5 ms | ~2 ms |
Security of WordPress Shortcodes
Always sanitize input: use esc_url(), sanitize_html_class(), wp_kses_post() for output. For database queries, use absint() and prepared statements via $wpdb. Never trust shortcode attributes — an attacker could inject malicious code through the editor. Follow official WordPress documentation on shortcodes.
What's Included in the Work
- Task analysis and selection of optimal solution (shortcode or block?)
- PHP function writing with sanitization and caching
- Integration with visual editor (TinyMCE button or block)
- Testing for layout, plugin conflicts
- Documentation for editor (attribute descriptions, examples)
- Access handover, training (if needed)
Contact us — we'll assess your project within a day and offer timelines from 1 to 5 days depending on complexity. Order turnkey shortcode development and forget about content output issues.
For more details on the concept of shortcodes, see Wikipedia.







