Skip to content

Theme reference: variables and helpers

5 min read

A quick-lookup page for theme authors. For the concepts, start with Theme development.

Variables every template gets

VariableContents
$baseURL prefix of the install: '' at a domain root, /blog in a subfolder
$site_title, $taglineFrom the Customizer (Site identity)
$logo_url, $favicon_urlImage URLs, or empty
$footer_textFooter text from the Customizer, or empty
$primary_menu, $footer_menuMenu trees for the primary and footer locations, ready for menu_html()
$seoThis page's title, description and so on, for showing (a breadcrumb, a share link). Core prints the tags itself
$current_urlThe request path
$custom_cssThe site's custom CSS (already printed by bh_head())
$is_hometrue on the front page
$is_previewtrue when an editor is previewing a draft

Per template

TemplateVariables
index.php$posts (rows for this page), $meta (pagination)
single.php$post, $terms (its categories and tags), $comments (approved), $comments_count, $comments_open
page.php$post
archive.php$posts, $meta, $archive_type (category, tag or author), $term (for categories and tags), $author (for authors), $title
search.php$posts, $meta, $query

Note: On single.php and page.php, $page holds the same row as $post, not a page number. Read pagination from $meta['page'].

When the front page is set to a static page, core renders page.php for it with $is_home = true.

$meta (pagination)

['page' => 2, 'per_page' => 10, 'total' => 57, 'last_page' => 6]

A post row ($post, items of $posts)

FieldNotes
id, uuid, slug, typetype is post or page
title, excerptPlain text; escape when printing
contentFinished HTML on single and page templates. Print as is
content_formatblocks, markdown or html: how it was written, not how it arrives
statuspublished, or draft/pending in a preview
published_at, created_at, updated_atUTC, Y-m-d H:i:s. Show with bh_date()
author_id, author_name, author_avatar_urlThe author
featured_url, featured_alt, featured_width, featured_height, featured_sizesFeatured image; use bh_post_image()
comment_statusopen or closed
view_countViews counted by core

A term row ($terms, $term)

id, name, slug, description, parent_id, count, and on $terms also taxonomy_slug (category or tag). Link a term with:

<?php $prefix = $t['taxonomy_slug'] === 'tag' ? '/tag/' : '/category/'; ?>
<a href="<?= htmlspecialchars(link_to($prefix . $t['slug'])) ?>"><?= htmlspecialchars($t['name']) ?></a>

A comment row ($comments)

id, parent_id (empty for a top-level comment), author_name, author_url, content (plain text: escape it), created_at (UTC).

Page structure

HelperUse
bh_head()Echo inside <head>. Required
bh_footer()Echo before </body>. Required
bh_body_class($extra)Classes for <body>: is-home or is-inner, the theme slug, preview state, plus $extra
bh_ajax_client()Load Basehim.ajax on the public site. Call before bh_head()
bh_is_preview()true inside the Customizer's preview frame
HelperReturns
link_to($path)$path with the install's base path, e.g. link_to('/search')
\App\Core\Helpers::postUrl($post)A post's or page's path under the current permalink setting (prefix with $base)
theme_asset($file, $version = true)URL of a file in this theme's assets/, with ?v=
icon($name, $class)A Heroicon as inline SVG, e.g. icon('magnifying-glass', 'w-4 h-4')
HelperUse
menu_html($items, $opts)Nested <ul> with dropdowns to three levels. $opts: class (default bh-menu; keep bh-menu in it for the built-in styles), aria, depth
menu_at($location)Items for any location declared in theme.json
menu_has_children($items)Whether any item has children
menu_assets()Dropdown CSS and behaviour; echo once in <head>
<?= menu_html($primary_menu, ['class' => 'bh-menu site-nav', 'aria' => 'Primary']) ?>
<?= menu_html(menu_at('utility')) ?>

Widgets

HelperUse
widget_area($key)Rendered widgets of an area, or ''
has_widget_area($key)Whether the area has any widgets
<?php if (has_widget_area('sidebar')): ?>
    <aside><?= widget_area('sidebar') ?></aside>
<?php endif; ?>

Comments

HelperUse
bh_comment_form($post, $args)Core's comment form: CSRF token, honeypot, replies, no page reload. Returns the "closed" text when comments are off
bh_comment_count($post)Approved comments on a post

Mark a count so the form updates it after a new comment:

<span data-bh-comment-count="<?= (int) $post['id'] ?>"><?= (int) $comments_count ?></span>

Any element with data-bh-reply data-id="…" data-name="…" turns the form into a reply to that comment. Style hooks and options (class, button_class, label_submit, styles => false…) are listed in Customizer, menus and widgets.

Authors

HelperReturns
bh_author_box($post, $args)The author box (avatar, name, bio, link). Empty when Settings → Reading → Author box on posts is off
bh_author($post)Public profile: display_name, bio, slug, url, avatar_url, post_count
bh_author_url($post)Path to the author's archive, or '' when archives are off or the author has no posts
bh_avatar($userOrPost, $size)An avatar <img>, or initials

Images

HelperReturns
bh_post_image($post, $size, $attrs)Responsive <img> of the featured image (srcset, width, height, lazy loading), or ''
bh_image_url($post, $size)One size's URL; falls back to the original
bh_image_sizes($post)All sizes, smallest first: name => [url, width, height]

Sizes: thumbnail (square), medium, large, full (original).

Dates and times

Stored times are UTC. These show them in the site's timezone and formats:

HelperExample output
bh_date($t, $format = null)October 10, 2026
bh_time($t, $format = null)1:32 pm
bh_datetime($t, $format = null)October 10, 2026 1:32 pm
bh_time_ago($t, $maxDays = 7)5 minutes ago
bh_time_tag($t, $format = null, $relative = false)<time datetime="2026-10-10T13:32:00+05:00">…</time>
bh_iso8601($t)2026-10-10T13:32:00+05:00
bh_local_time($t)DateTimeImmutable in the site timezone
bh_to_utc($local)A time typed in the site timezone, as UTC to store
bh_now()Now, UTC, for storing
bh_timezone()e.g. Asia/Karachi

Settings and options

HelperReturns
bh_theme_option($key, $default)A Customizer option of this theme, preview-aware
bh_setting($group, $key, $default)A site setting, e.g. bh_setting('reading', 'posts_per_page', 10)

SEO

HelperUse
bh_seo()This page's SEO head: set(), get(), addJsonLd(), disable(), handOff()
bh_seo_value($key)Read one value back, e.g. bh_seo_value('title')

See SEO, dates and images.

AI agents (WebMCP)

HelperUse
bh_webmcp_form($name, $description, $opts)Attributes that describe a form to in-browser agents
bh_webmcp_param($description)Describes one form field

Both return '' while WebMCP is off, so they are safe to leave in. See AI discovery.

Keep building

More guides, or jump straight into the API reference.

Discussion

Leave a comment