Shortcodes API
Shortcodes allow users to embed dynamic content using simple tags in their posts.
Registering Shortcodes
sdk.shortcodes.register(name, handler)
Register a new shortcode.
// Simple shortcode
sdk.shortcodes.register('year', () => {
return new Date().getFullYear().toString();
});
// Usage: [year] → 2024// Shortcode with attributes
sdk.shortcodes.register('button', (attrs) => {
const { text = 'Click Me', url = '#', color = 'blue' } = attrs;
return `
<a href="${url}" class="btn btn-${color}">
${text}
</a>
`;
});
// Usage: [button text="Sign Up" url="/signup" color="green"]// Shortcode with content
sdk.shortcodes.register('note', (attrs, content) => {
const { type = 'info' } = attrs;
return `
<div class="note note-${type}">
${content}
</div>
`;
});
// Usage: [note type="warning"]Be careful![/note]Async Shortcodes
Shortcodes can be async for database queries or API calls:
sdk.shortcodes.register('recent-posts', async (attrs) => {
const { count = 5 } = attrs;
const posts = await sdk.content.getLatestPosts(parseInt(count));
let html = '<ul class="recent-posts">';
posts.forEach(post => {
html += `<li><a href="${post.url}">${post.title}</a></li>`;
});
html += '</ul>';
return html;
});
// Usage: [recent-posts count="10"]Attribute Types
Attributes are passed as strings. Convert them as needed:
sdk.shortcodes.register('gallery', async (attrs) => {
// Convert types
const columns = parseInt(attrs.columns) || 3;
const showCaptions = attrs.showCaptions === 'true';
const limit = parseInt(attrs.limit) || 20;
// ... render gallery
});
// Usage: [gallery columns="4" showCaptions="true" limit="12"]Context Access
The handler receives context as a third parameter:
sdk.shortcodes.register('author-info', async (attrs, content, context) => {
// context.post - current post (if on post page)
// context.category - current category (if on category page)
// context.user - current user (if logged in)
if (context.post && context.post.author) {
const author = context.post.author;
return `
<div class="author-box">
<img src="${author.avatar}" alt="${author.name}">
<strong>${author.name}</strong>
<p>${author.bio}</p>
</div>
`;
}
return '';
});Built-in Shortcodes
These shortcodes are available by default:
| Shortcode | Description | Example |
|---|---|---|
[year] | Current year | [year] → 2024 |
[sitename] | Site name | [sitename] |
[current_url] | Current page URL | [current_url] |
[if_logged_in]...[/if_logged_in] | Show if user logged in | [if_logged_in]Welcome![/if_logged_in] |
Common Shortcode Examples
Embed YouTube Video
sdk.shortcodes.register('youtube', (attrs) => {
const { id, width = '560', height = '315' } = attrs;
if (!id) return '<p>YouTube ID required</p>';
return `
<div class="video-container">
<iframe
width="${width}"
height="${height}"
src="https://www.youtube.com/embed/${id}"
frameborder="0"
allowfullscreen>
</iframe>
</div>
`;
});
// Usage: [youtube id="dQw4w9WgXcQ"]Callout Box
sdk.shortcodes.register('callout', (attrs, content) => {
const { type = 'info', title = '' } = attrs;
const icons = {
info: 'ℹ️',
warning: '⚠️',
success: '✅',
error: '❌'
};
return `
<div class="callout callout-${type}">
<span class="callout-icon">${icons[type] || ''}</span>
${title ? `<strong class="callout-title">${title}</strong>` : ''}
<div class="callout-content">${content}</div>
</div>
`;
});
// Usage: [callout type="warning" title="Important"]Read this carefully[/callout]Accordion
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-header" onclick="this.classList.toggle('active'); document.getElementById('${id}').classList.toggle('open')">
${title}
<span class="accordion-icon">▼</span>
</button>
<div id="${id}" class="accordion-content">
${content}
</div>
</div>
`;
});
// Usage: [accordion title="FAQ: How does this work?"]Explanation here...[/accordion]Card Grid
sdk.shortcodes.register('card', (attrs, content) => {
const { title = '', image = '', link = '' } = attrs;
let html = '<div class="card">';
if (image) {
html += `<img src="${image}" class="card-image" alt="${title}">`;
}
html += '<div class="card-body">';
if (title) {
if (link) {
html += `<h3 class="card-title"><a href="${link}">${title}</a></h3>`;
} else {
html += `<h3 class="card-title">${title}</h3>`;
}
}
html += `<div class="card-content">${content}</div>`;
html += '</div></div>';
return html;
});
sdk.shortcodes.register('cards', (attrs, content) => {
const { columns = '3' } = attrs;
return `
<div class="cards-grid" style="
display: grid;
grid-template-columns: repeat(${columns}, 1fr);
gap: 20px;
">
${content}
</div>
`;
});
// Usage:
// [cards columns="3"]
// [card title="Card 1" image="/img1.jpg"]Description[/card]
// [card title="Card 2" image="/img2.jpg"]Description[/card]
// [card title="Card 3" image="/img3.jpg"]Description[/card]
// [/cards]Pricing Table
sdk.shortcodes.register('pricing', (attrs) => {
const { name, price, 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' : ''}">
<h3 class="pricing-name">${name}</h3>
<div class="pricing-price">
<span class="price-amount">${price}</span>
<span class="price-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="Unlimited posts, Priority support, API access" featured="true"]Removing Shortcodes
sdk.shortcodes.unregister('year');Checking Existence
if (sdk.shortcodes.exists('gallery')) {
// Shortcode already registered
}