⌘K

Rendering Functions

All functions below return a string — always echo them; none print output directly except where noted.

Content

render_content_html(string $html, array $item = null): string

Full rich content rendering: complete shortcode parsing (galleries, TOC, callouts, quotes, buttons, recent_articles, recent_projects, contact_form…). When $item['content_format'] === 'markdown', converts Markdown to HTML first, then runs the shortcode pipeline.

🚫

Never display $item['content'] directly — always pass it through this function.

echo render_content_html($item['content'] ?? '', $item);

render_site_logo(array $settings, string $class = '', string $alt = ''): string

<img> tag for the configured site logo. Empty string if none is set.

If a -light and -dark variant of the configured logo both exist on disk (e.g. site_logo is files/logo.webp and files/logo-light.webp + files/logo-dark.webp are also present), both <img> tags are rendered (classes snk-logo-dark / snk-logo-light) along with a small inline <style> block — emitted once per request even if the function is called more than once — that toggles visibility via the [data-theme] attribute a theme's dark/light switch sets on <html>. Pure CSS, no extra JS, no flash on switch. Falls back to the single configured logo when either variant is missing.

render_site_favicon(array $settings): string

<link rel="icon"> for the configured favicon, MIME-typed from the file extension (ico, svg, png, gif, webp).

render_site_title(array $settings, string $pageTitle): string

Site title string, respecting show_site_title_in_header.

render_content_title(array $item): string

<h1> title block. Empty string if show_title is false.

render_meta_tags(array $settings, string $metaTitle, string $metaDescription, array $pageData = null): string

All SEO tags: description, Open Graph, canonical URL, JSON-LD schema.org markup.

render_header_scripts(array $headerScripts): string

Injects every <head> asset. Call once, in header.php. Actual injection order:

  1. <base> tag + generator meta
  2. window.CMS_LANG (context-aware payload — see i18n) and CMS_TYPE_LABELS as inert JSON islands, then assets/js/front-boot.js (not deferred — reads them, plus window.CMS_BASE_URL from document.baseURI, before anything else runs)
  3. assets/css/synaptikCSS.php — a plain blocking <link> (unconditional), immediately followed by assets/css/shortcodes.css and/or assets/css/gallery-layout.css, each only emitted when the fully-rendered page HTML actually contains that stylesheet's marker classes (sl_content_needs_shortcode_assets()/sl_content_needs_gallery_assets(), scanning global $pageContent — see Front-End Asset Registry). It used to load non-blocking via a media="print" swap script, removed: the file is a few KB, gzipped, cached for a year — the swap script's own fragility (it's what caused a real production bug once) cost more than the swap ever saved on an HTTP/2 connection.
  4. theme/{active}/css/style.css
  5. assets/js/features/search.js (deferred) — always loaded, every page gets the search overlay
  6. RSS <link rel="alternate">, then theme/child_theme/{active}/css/style.css if present
  7. highlight.js + language packs, only if the rendered page actually contains a code block
  8. $headerScripts — whatever index.php collected for this request (gallery CDN includes for the layout in use, JSON-LD schema, the #cms-appsettings-json island, the admin-bar <style> block)
  9. theme/{active}/js/script.js (deferred, if the file exists), then theme/child_theme/{active}/js/script.js if present
  10. Last, after everything above: whatever was queued via enqueue_css()/enqueue_js() during rendering — in practice assets/css/lightbox.css + assets/js/features/lightbox.js (enqueued by index.php when the page has a gallery) and assets/js/features/collapsibles.js (enqueued by render_collapsibles_script() when $pageContent contains a c-col/tab-group marker). See Front-End Asset Registry for exactly how that detection works — it checks rendered CSS classes, not raw Markdown/shortcode source, precisely so a collapsible block with no gallery still gets styled.

Steps 5, 7, 8 and 10 used to be a single always-loaded assets/js/main.js bundling search, lightbox, collapsibles/tabs, and page transitions together. It's been split into one file per feature, each loaded only on the pages that actually need it.

There is no core-level "page transitions" file anymore, either — its fade-in/pagination-fade behavior wasn't actually used by most catalogue themes (no .fade-in CSS rule, or pagination markup under a different class than .pagination), so loading it unconditionally on every theme cost more than it was worth. The handful of themes that do use it (axion, blueish, darkish, myelin, nihonium, nova, prism, synaptik-cms, synaptik-docs) now carry that same behavior directly in their own step-10 script.js (or equivalent) — no separate request, and no code shipped to a theme that never used it.

See Front-End Loading Pipeline for what front-boot.js and css-async.js actually do and why each is a separate cached file rather than an inline script.

render_featured_image(array $item): string

<div class="featured-image"> block. Empty string if no image or show_featured_image is false.

render_content_date(array $item): string

Publication date if show_date is true, formatted per date_format.

render_content_category(array $item): string

Category badge link. Empty string if no category.

render_content_tags(array $item): string

Tag links block. Empty string if no tags.

render_content_gallery(array $item): string

Legacy gallery block from $item['gallery']. For inline galleries in $item['galleries'], use [gallery id="N"] in content instead.

render_footer_content(): string

Footer text (supports {year}) and social links.


Cards

render_article_card(array $article): string / render_project_card(array $project): string

Delegate to theme/{active}/partials/article-card.php / project-card.php if present; built-in default otherwise.

get_article_summary(array $article, int $length = 150): string

$article['summary'] if set, otherwise an auto-generated clean excerpt. Loads the full item on demand if content is absent (index-mode context).


render_related_items(array $item, int $limit = 5): string

Empty string unless $item['show_related_items'] is true. Manual mode: resolves the exact {type, slug} references in $item['related_items']. Auto mode (when that array is empty): scores every other item by shared tags (+1 each) and matching category (+2), index-only — no full item files read.


Homepage sections

render_home_articles(array $data, array $settings): string

Article grid with pagination, respecting show_articles_on_homepage, articles_per_page, per-article show_on_homepage.

render_home_projects(array $data, array $settings): string

Same, for projects (show_projects_on_homepage, projects_per_page).


Custom fields

render_item_custom_fields(array $item, string $type): string

Renders custom fields in schema order with their configured labels — URL fields as links, checkboxes as checkmarks, text/number with nl2br. Empty string if no schema or no values.

get_custom_field(array $item, string $key, mixed $default = ''): mixed

Single field's value, or $default.


render_search_ui(): string

Full search overlay markup (#search-overlay). Always generated, regardless of show_search_icon, so Ctrl+K keeps working. Call before </body>.

render_search_icon(): string

Nav bar search <li>. Empty string if show_search_icon is false.


Galleries

renderGallery(array $galleryItems, string $layout = 'grid'): string

Dispatches to the matching renderer. Layouts: grid, masonry, justified, carousel — each with lightbox support except carousel (prev/next controls instead).

getGalleryScripts(string $galleryLayout): string

Inline JS/CSS a given layout needs.


Navigation

renderHierarchicalMenu(array $settings, array $data): string

The single entry point for menu rendering — internally falls back to renderDefaultMenu() when use_custom_menu is off or main_menu is empty, otherwise builds and renders the custom menu tree (passed through the menu_tree filter — see Filters — before rendering). Emits bare <ul><li><a> for the custom-menu path — no CSS classes, style it yourself.

renderDefaultMenu(array $data): string

Auto-menu from content marked show_in_menu, sorted by default_menu_order. Always reloads fresh indices via sl_load_index(), never reads $data directly.


Contact form

render_contact_form_html(): string

Full form: CSRF, honeypot, rate limiting, optional hCaptcha. Injects its CSS once per page. Callable directly or via [contact_form].


Breadcrumbs

getBreadcrumbs(string $type, string $slug = '', string $title = '', string $category = ''): string

HTML breadcrumbs for any page type; category links resolve the full hierarchical path.