Template Variables

4 Aufrufe Markdown

Everything a view can print arrives as a named variable. Each is written by one of three layers: the engine, the client page pack, or the theme's hooks file.

Overview

A theme does not query. The platform prepares the data and the view prints what it was given. Knowing which layer wrote a variable tells you where to look when it is missing, and whether a theme may change it.

The layers always run in the same order. The engine writes the display environment on every page. Then set_predefined_data("client") writes what every client page needs, and the theme's hooks.php adds the rest, the only layer the theme owns.

Structure

The Three Layers

LayerWritten byWhat belongs there
Display environmentView::render(), on every page including adminLanguage, writing direction, asset addresses, theme settings
Client contentset_predefined_data("client"), from every client controllerBranding, menus, currency, cart, session state, legal links
Theme datahooks.php, through filter:template.variablesAnything only this theme needs, derived from core values

Only the theme layer answers with a value, and that value replaces the whole set instead of merging into it. A listener returns the array it was handed, with its own keys added; a return that is not an array leaves the set untouched.

Page data sits on top of all three. The controller adds it with addData(), and only the page that asked for it gets it.

Reference

What the Engine Writes on Every Page

Assigned in the themed branch of the view layer, after the hook has run. A listener cannot remove them. The list is narrower on the plain PHP engine. There, $cookie_domain, $demo_mode and $demo_themes are written only on the tag-engine path. $template_dir resolves to a path built from the theme's name. A theme on that engine asks the theme object for its directory.

$template_dir Filesystem path of the active theme directory, with a trailing separator. Not an address: use it only to read files.
$tadress Address of the theme directory. Prefer https://dev.wisecp.com/templates/website/WCOM/assets/..., which points inside assets/ and adds a cache-busting stamp to CSS and JS.
$badress Base address of the installation, with a trailing slash. On a bound subdomain this is that host, not the main site.
$sadress Address of the shared resources directory (uploads, flags, plugin assets), owned by no theme.
$ui_lang Active language code, resolved when the page is built, so a late language switch is reflected.
$ui_dir ltr or rtl, from the language pack. Print it on the html element; do not hardcode a direction.
$cookie_domain The host scope this installation's cookies use, empty on a single-host install. Theme JavaScript writing a cookie uses the same scope.
$demo_mode · $demo_themes Demo chrome only. The theme list is computed only while demo mode is on.
$setting Every field of this theme's settings schema merged with its saved value, from Theme::allSettings(). Colour fields also expose a _rgb twin.

What Every Client Page Adds

$company_name Trading name, from the language pack's constants, falling back to the company information block.
$light_logo_link · $dark_logo_link Site logo per colour mode. The client panel and the invoice document carry their own pair ($client_logo_light_link, $invoice_logo_light_link and their dark twins). Each falls back to the site logo.
$favicon_link Square brand mark, for places a wordmark does not fit (a collapsed rail, an app icon).
$current_year Current year as a string, for the footer copyright line. Do not compute a date in a view.
$lang_list · $lang_count · $selected_lang_key Active languages with a ready link each, their number, and the selected code in upper case. The layout also prints them as alternate language links.
$currencies · $currencies_count · $selected_currency · $selected_currency_code Currencies offered to the visitor (hidden ones filtered out) and the active one. Switching is a server round trip: link to the same page with a currency parameter.
$currency_formats_json · $currency_ids_json · $currency_rates_json · $currency_default Ready JSON for the theme's money script. Each format is a sample string the script parses to learn that currency's separators.
$header_menu · $footer_menu · $mobile_menu The three operator-managed menu trees. The mobile tree falls back to the header tree when it is empty.
$social_links · $contact_email · $contact_phone Social profiles as a list, plus the first configured address and number as plain strings, for the header and footer strips.
$visibility_cart · $cart_count Whether the shop is on at all, and the live item count. The count is always set, so a badge can be revealed without a reload.
$login_enabled · $registration_enabled · $account_actions_enabled The operator's account switches. The third is false when neither signing in nor signing up is possible. That hides the account menu and the cart.
$affiliate_enabled · $reseller_enabled · $only_client_panel Program switches for the account menu, and portal-only mode, in which a theme drops its links back to the public website.
$is_logged_in · $client_id The canonical session flag and the signed-in identity. Every "signed in or guest" branch tests this flag.
$privacy_contract_link · $terms_contract_link · $cookie_contract_link Legal pages the operator mapped, empty when unmapped. Hide the link when it is empty instead of printing a dead one.
$cookie_notice The consent prompt as a finished payload, or an empty array when consent is off. Decided server side: the cookies are not readable from the browser.
$notification_count · $notification_count_text Bell counter and its pill text (capped beyond two digits). Always set, but only queried for a page that asked for the client shell.
$password_min_length · $password_special_chars · $default_country The operator's password rules for the suggestion button, and the site's default country as a last-resort fallback for phone and address fields.
$links · $meta · $breadcrumb · $local_l · $show_powered_by Page frame: the controller's link map, page metadata, the trail, the installation's default language, and whether the footer prints the platform credit.

What a Signed-In Page Adds

These exist only while a member is signed in. A public page must not read them without guarding on $is_logged_in.

$account_info · $user_info Display identity for the chrome (name, avatar, initials, formatted balance, support PIN, previous sign-in) and the raw account row behind it.
$announcements Operator notices for the account shell, already filtered by language and by the active account's country.
$show_services · $show_domains · $show_invoices · $show_support · $show_sms Section visibility: the granted sub-user permission AND the operator's feature switch. A section the visitor cannot open is never linked.
$is_self_account · $switch_accounts Whether the active account is the member's own, and the accounts they may switch to.
$client_badges · $client_badges_text Attention counters per section as raw numbers, plus their pill text. The raw numbers stay for accessible names, which say the real figure.
$order_service_link Where "buy a service" goes, empty when the sub-user may not order. A theme that disables the catalogue overrides this in its hooks file.
$dashboard_modal · $twofa_required · $password_required The dashboard gate chain. Only one modal opens per load, and the chosen one is named here rather than decided in the view.
$client_addon_links Client-area pages contributed by enabled addon modules, each with a name, an address and an icon.
$verification_required · $verify_link Set while the member owes identity verification. The banner belongs to the layout; the redirect for gated pages already happened before the view ran.

The Shape of the Composite Values

what the view actually receives
// $lang_list : one row per ACTIVE language, ranked, the installation default first.
$lang_list = [
    ['rank' => 1, 'local' => 1, 'selected' => true, 'key' => 'en', 'name' => 'English',
     'global-name' => 'English', 'link' => 'https://example.com/home',
     'cc' => 'gb', 'cname' => 'United Kingdom', 'pc' => '44', 'flag-img' => 'https://example.com/resources/assets/images/flags/gb.svg'],
];

// $currencies : active, non-hidden currency rows.
$currencies = [
    ['id' => 1, 'code' => 'USD', 'name' => 'US Dollar', 'prefix' => '$', 'suffix' => '',
     'rate' => '1.00000000', 'local' => 1, 'hidden' => 0],
];

// $social_links : one entry per configured profile.
$social_links = [
    ['name' => 'X', 'url' => 'https://x.com/example', 'icon' => 'bi bi-twitter-x'],
];

// $account_info : display identity, already formatted. `balance` is a STRING with its symbol.
$account_info = [
    'name' => 'Ada', 'surname' => 'Lovelace', 'full_name' => 'Ada Lovelace',
    'email' => '[email protected]', 'avatar' => '', 'initials' => 'AL',
    'balance' => '$120.00', 'support_pin' => '481625', 'two_factor' => true,
    'is_reseller' => false, 'last_login' => [], 'last_login_date' => '02/08/2026 - 11:40',
    'last_login_ip' => '203.0.113.9', 'last_login_country' => 'GB', 'last_login_city' => 'London',
    'dealership' => [],
];

// $client_badges : raw counts; $client_badges_text holds the same keys as pill strings.
$client_badges = ['invoices' => 2, 'support' => 1, 'domains' => 0, 'services' => 0];

// $cookie_notice : empty array when consent is off.
$cookie_notice = [
    'needs_prompt' => true, 'text' => 'We use cookies…', 'policy_link' => 'https://example.com/cookie-policy',
    'policy_label' => 'Cookie policy', 'accept' => 'Accept', 'reject' => 'Reject',
    'prefs' => 'Preferences', 'save' => 'Save', 'prefs_title' => 'Cookie preferences',
    'categories' => [
        ['key' => 'necessary', 'label' => 'Necessary', 'desc' => '…', 'locked' => true, 'granted' => true],
    ],
    'url' => 'https://example.com/cookie-consent',
];

Signatures

the methods that fill the array
// Controllers : the page and the pack.
public function set_predefined_data(string $type = 'client', array $meta = [], array $breadcrumbs = [], array $links = []): void;
public function addData($k = '', $v = ''): void;
public function getData($key);

// View : the render itself. $return_output = true returns the HTML instead of printing it.
public function chose($dir, $noTemplate = false): self;
public function render($_name = null, $data = [], $return_output = false, $source = false): mixed;

// Theme : the settings map behind $setting, and the context-free render used off-request.
public function allSettings(): array;
public function render(string $view, array $data = []): string;

Example

A client page and the view that reads it back. The controller adds only what belongs to this page.

the controller
public function page_overview(&$links, &$meta, &$breadcrumbs): string
{
    // Read INSIDE set_predefined_data, so it has to be set before the call.
    $this->addData("show_client_subnav", true);

    $this->set_predefined_data("client", $meta, $breadcrumbs, $links);

    // Page data on top of the pack. Set unconditionally: a key the view reads has to
    // exist on every render, empty or not, or the view falls into an undefined key.
    $this->addData("recent_orders", $this->model->recent_orders((int) $this->getData("client_id")));

    echo $this->view->chose("website")->render("account/overview", $this->data, true);

    return '';
}
the view, in the engine the manifest declared
{* Environment layer: direction and language come from the engine, never hardcoded. *}
<section dir="{$ui_dir}" lang="{$ui_lang}">

    {* Client layer: guard on the session flag before touching a signed-in-only value. *}
    {if $is_logged_in}
        <p>{$account_info.full_name} · {$account_info.balance}</p>
        {if $client_badges.invoices > 0}
        <span class="badge">{$client_badges_text.invoices}</span>
        {/if}
    {/if}

    {* Theme layer: a setting this theme declared, read straight off $setting. *}
    {if $setting.topbar_enabled}<div class="topbar">{$setting.topbar_text nofilter}</div>{/if}

    {* Page layer: default:[] so an empty page never costs a warning per row. *}
    {foreach $recent_orders|default:[] as $order}
        <a href="{link route='invoice-detail' p1=$order.id}">{$order.number}</a>
    {/foreach}
</section>

Pitfalls

A variable set inside a condition is missing on the pages that skipped it

Set every global unconditionally and decide visibility in the view. Absence is not "false": the view falls into an undefined key, and every one costs a log write. Inside a loop that is a measurable slowdown.

The variables hook replaces the array, it does not merge into it

A listener that returns something other than the array it was handed drops every key the platform collected. The layout then breaks on the first missing address. Start from the incoming array, add to it, return all of it.

A background page gets the environment, not the client pack

A view built from a scheduled task or a document generator goes through the theme object directly. No controller ran to fill the pack. Only the environment layer and the theme settings are there; anything else is passed as page data.

Addresses are built in the view, not passed as variables

The controller does not hand out ready links for pages the theme can address itself. Build them with the link function and a route key. A theme that renames a page then needs no controller change.

War das hilfreich?

Vielen Dank für Ihre Rückmeldung!

Brauchen Sie weitere Hilfe?

Unser Support-Team ist rund um die Uhr für Sie da, wenn Sie oben nicht fündig werden.