Shortcodes

Shortcodes are tags inserted in page or article content and resolved server-side at render time. All shortcodes are parsed inside render_content_html() in template-functions.php.


Parsing order

  1. [gallery id="X"]renderGallery()
  2. [toc] → injects id anchors on <h2>/</h2><h3> + table of contents
  3. [callout type="…"]…[/callout]
  4. [quote author="…"]…[/quote]
  5. [button …]
  6. [recent_articles …]
  7. [recent_projects …]
  8. [articles_by_tag …]
  9. [contact_form]

Each parser is conditional — if the shortcode string is not found in the HTML, the regex is never executed.


Self-closing shortcodes

[toc]

Auto-generated table of contents from all </h3><h2> and </h2><h3> in the content.


[button url="…" label="…" style="…"]

AttributeValuesRequired
urlAny URLYes
labelButton textYes
styleprimary \secondary \outlineNo (defaults to primary)
[button url="/contact" label="Get in touch" style="primary"]

[recent_articles limit="3" tag="slug" category="slug"]

Renders a grid of recent articles. Optionally filtered by tag or category.

AttributeDescriptionRequired
limitNumber of articles to showNo (default: 3)
tagFilter by tag slugNo
categoryFilter by category slugNo

🚫

This shortcode reads from slloadindex('article') directly — never from $GLOBALS['data']. On single-item pages, $GLOBALS['data']['article'] only contains the current item; using it would return empty results.


[recent_projects limit="3"]

AttributeDescriptionRequired
limitNumber of projects to showNo (default: 3)

[articles_by_tag tag="slug" limit="5"]

Alias of [recent_articles] with a mandatory tag filter.


[contact_form]

Renders the full contact form with CSRF protection, honeypot field, rate limiting, and optional hCaptcha. Automatically injects contact.css once per page.


Wrapping shortcodes

[callout type="info"]…[/callout]

TypeColour
infoBlue
warningOrange
tipGreen
dangerRed

[quote author="Name"]…[/quote]

Styled blockquote with attribution.


Adding a custom shortcode

  1. Add the parser in render_content_html() after existing parsers, before the final return $html.
  2. Add a render function if needed.
  3. Use sl_load_index($type) to query data — never $GLOBALS['data'].
  4. Add styles in the theme's shortcodes.css with sc-* prefixed classes.
  5. Add the entry in the editor shortcode picker (editor.js).
if (strpos($html, '[myshortcode') !== false) {
    $html = preg_replace_callback(
        '/\[myshortcode([^\]]*)\]/i',
        function ($m) {
            $attrs = _shortcode_parse_attrs($m[1]);
            return '<div class="sc-myshortcode">…</div>';
        },
        $html
    );
}