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:
<base>tag + generator metawindow.CMS_LANG(context-aware payload — see i18n) andCMS_TYPE_LABELSas inert JSON islands, thenassets/js/front-boot.js(not deferred — reads them, pluswindow.CMS_BASE_URLfromdocument.baseURI, before anything else runs)assets/css/synaptikCSS.php— a plain blocking<link>(unconditional), immediately followed byassets/css/shortcodes.cssand/orassets/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(), scanningglobal $pageContent— see Front-End Asset Registry). It used to load non-blocking via amedia="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.theme/{active}/css/style.cssassets/js/features/search.js(deferred) — always loaded, every page gets the search overlay- RSS
<link rel="alternate">, thentheme/child_theme/{active}/css/style.cssif present - highlight.js + language packs, only if the rendered page actually contains a code block
$headerScripts— whateverindex.phpcollected for this request (gallery CDN includes for the layout in use, JSON-LD schema, the#cms-appsettings-jsonisland, the admin-bar<style>block)theme/{active}/js/script.js(deferred, if the file exists), thentheme/child_theme/{active}/js/script.jsif present- Last, after everything above: whatever was queued via
enqueue_css()/enqueue_js()during rendering — in practiceassets/css/lightbox.css+assets/js/features/lightbox.js(enqueued byindex.phpwhen the page has a gallery) andassets/js/features/collapsibles.js(enqueued byrender_collapsibles_script()when$pageContentcontains ac-col/tab-groupmarker). 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).
Related items
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.
Search
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.
