Shortcodes
Create embeddable content with simple tags.
What are Shortcodes?
Shortcodes let users add dynamic content to posts using simple brackets:
[button text="Click me" url="/signup"]
[gallery columns="3"]
[alert type="warning"]Be careful![/alert]Registering Shortcodes
Basic Shortcode
sdk.shortcodes.register('year', () => {
return new Date().getFullYear().toString();
});
// Usage: The year is [year]
// Output: The year is 2024With Attributes
sdk.shortcodes.register('button', (attrs) => {
const {
text = 'Click',
url = '#',
color = 'primary'
} = attrs;
return `<a href="${url}" class="btn btn-${color}">${text}</a>`;
});
// Usage: [button text="Sign Up" url="/signup" color="green"]With Content
sdk.shortcodes.register('alert', (attrs, content) => {
const { type = 'info' } = attrs;
const icons = {
info: 'ℹ️',
warning: '⚠️',
success: '✅',
error: '❌'
};
return `
<div class="alert alert-${type}">
<span class="alert-icon">${icons[type] || ''}</span>
<div class="alert-content">${content}</div>
</div>
`;
});
// Usage: [alert type="warning"]Please read this![/alert]Async Shortcodes
For database queries or API calls:
sdk.shortcodes.register('latest-posts', async (attrs) => {
const { count = 5, category = '' } = attrs;
const filter = category ? { category } : {};
const posts = await sdk.content.getPosts({
filter,
limit: parseInt(count),
sort: { createdAt: -1 }
});
let html = '<ul class="latest-posts">';
posts.items.forEach(post => {
html += `<li><a href="${post.url}">${post.title}</a></li>`;
});
html += '</ul>';
return html;
});
// Usage: [latest-posts count="10" category="news"]Context Access
Access page context in shortcodes:
sdk.shortcodes.register('current-category', (attrs, content, context) => {
// context.post - current post (if on post page)
// context.category - current category (if on category page)
// context.user - logged in user
// context.request - request object
if (context.category) {
return context.category.name;
}
if (context.post && context.post.category) {
return context.post.category.name;
}
return 'Uncategorized';
});Attribute Types
Attributes are always strings. Convert as needed:
sdk.shortcodes.register('grid', (attrs) => {
// Convert to number
const columns = parseInt(attrs.columns) || 3;
// Convert to boolean
const showBorder = attrs.border === 'true';
// Handle arrays (comma-separated)
const items = (attrs.items || '').split(',').map(s => s.trim());
return `<div class="grid grid-${columns}" ${showBorder ? 'style="border: 1px solid #ccc"' : ''}>
${items.map(item => `<div>${item}</div>`).join('')}
</div>`;
});
// Usage: [grid columns="4" border="true" items="one,two,three,four"]Common Shortcode Examples
YouTube Embed
sdk.shortcodes.register('youtube', (attrs) => {
const { id, width = '560', height = '315' } = attrs;
if (!id) return '<p class="error">YouTube ID required</p>';
return `
<div class="video-container">
<iframe
width="${width}"
height="${height}"
src="https://www.youtube.com/embed/${id}"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
</div>
`;
});
// Usage: [youtube id="dQw4w9WgXcQ"]Accordion/Collapsible
sdk.shortcodes.register('accordion', (attrs, content) => {
const { title = 'Click to expand' } = attrs;
const id = 'acc-' + Math.random().toString(36).substr(2, 9);
return `
<div class="accordion">
<button class="accordion-toggle" aria-expanded="false" aria-controls="${id}">
${title}
<span class="accordion-icon">▼</span>
</button>
<div id="${id}" class="accordion-content" hidden>
${content}
</div>
</div>
`;
});
// Usage: [accordion title="Read more"]Hidden content here[/accordion]Tabs
// Store tabs temporarily
let currentTabs = [];
sdk.shortcodes.register('tabs', (attrs, content) => {
const tabs = [...currentTabs];
currentTabs = []; // Reset for next use
if (tabs.length === 0) return '';
const id = 'tabs-' + Math.random().toString(36).substr(2, 9);
let html = `<div class="tabs" id="${id}">`;
// Tab buttons
html += '<div class="tab-buttons">';
tabs.forEach((tab, i) => {
html += `<button class="tab-btn ${i === 0 ? 'active' : ''}" data-tab="${i}">${tab.title}</button>`;
});
html += '</div>';
// Tab panels
html += '<div class="tab-panels">';
tabs.forEach((tab, i) => {
html += `<div class="tab-panel ${i === 0 ? 'active' : ''}" data-panel="${i}">${tab.content}</div>`;
});
html += '</div></div>';
return html;
});
sdk.shortcodes.register('tab', (attrs, content) => {
currentTabs.push({
title: attrs.title || 'Tab',
content: content
});
return ''; // Content handled by parent
});
// Usage:
// [tabs]
// [tab title="First"]Content 1[/tab]
// [tab title="Second"]Content 2[/tab]
// [/tabs]Pricing Table
sdk.shortcodes.register('pricing', (attrs) => {
const {
name = 'Plan',
price = '$0',
period = 'month',
features = '',
cta = 'Sign Up',
url = '#',
featured = 'false'
} = attrs;
const featureList = features.split(',').map(f => f.trim());
const isFeatured = featured === 'true';
return `
<div class="pricing-card ${isFeatured ? 'pricing-featured' : ''}">
${isFeatured ? '<span class="pricing-badge">Popular</span>' : ''}
<h3 class="pricing-name">${name}</h3>
<div class="pricing-price">
<span class="price">${price}</span>
<span class="period">/${period}</span>
</div>
<ul class="pricing-features">
${featureList.map(f => `<li>✓ ${f}</li>`).join('')}
</ul>
<a href="${url}" class="pricing-cta">${cta}</a>
</div>
`;
});
// Usage: [pricing name="Pro" price="$29" features="Feature 1,Feature 2,Feature 3" featured="true"]Code Block
sdk.shortcodes.register('code', (attrs, content) => {
const { language = 'text', filename = '' } = attrs;
// Escape HTML
const escaped = content
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
return `
<div class="code-block">
${filename ? `<div class="code-filename">${filename}</div>` : ''}
<pre><code class="language-${language}">${escaped}</code></pre>
</div>
`;
});
// Usage: [code language="javascript" filename="app.js"]const x = 1;[/code]Testimonial
sdk.shortcodes.register('testimonial', (attrs, content) => {
const { name = '', title = '', image = '' } = attrs;
return `
<blockquote class="testimonial">
<p class="testimonial-content">"${content}"</p>
<footer class="testimonial-author">
${image ? `<img src="${image}" alt="${name}" class="testimonial-image">` : ''}
<div class="testimonial-info">
<cite class="testimonial-name">${name}</cite>
${title ? `<span class="testimonial-title">${title}</span>` : ''}
</div>
</footer>
</blockquote>
`;
});
// Usage: [testimonial name="John Doe" title="CEO, Company" image="/avatar.jpg"]Great product![/testimonial]Removing Shortcodes
sdk.shortcodes.unregister('oldShortcode');Check If Exists
if (sdk.shortcodes.exists('button')) {
console.log('Button shortcode is registered');
}Adding Styles
Include CSS for your shortcodes:
sdk.hooks.addAction('theme_head', () => {
return `
<style>
.alert {
padding: 15px;
border-radius: 4px;
margin: 15px 0;
display: flex;
gap: 10px;
}
.alert-info { background: #e3f2fd; border-left: 4px solid #2196f3; }
.alert-warning { background: #fff3e0; border-left: 4px solid #ff9800; }
.alert-success { background: #e8f5e9; border-left: 4px solid #4caf50; }
.alert-error { background: #ffebee; border-left: 4px solid #f44336; }
</style>
`;
});