Registering custom API variables in ProcessWire

Processwire API variables injected inside templates are defined in Fuel class in /wire/core/Fuel.php, which provides following variables as of Processwire 3.0:

VariableClass
$wireProcessWire
$sessionSession
$sanitizerSanitizer
$fieldsFields
$templatesTemplates
$pagesPages
$pagePage
$modulesModules
$permissionsPermissions
$rolesRoles
$usersUsers
$userUser
$cacheWireCache
$inputWireInput
$languagesLanguages
$configConfig

(Some variables are omitted. You can find the full list of variables and their functions on Processwire documentation)

Although the list is plenty, there might be some scenarios that require setting a new API variable to be consumed in templates; say you need one to store site-wide settings, like brand color, url to site logo, or one to store view settings, such as <body> classes, scripts or styles to include in the page.

API variables are handled with Wire::wire() (alternatively Wire::set()) method inside /wire/core/Wire.php. This method makes sure the correct Processwire instance is selected and returns or adds requested API variable. You can access this method anywhere inside the templates and modules, and create your own variable, but using /site/ready.php or /site/init.php is the suggested way of defining hooks or general behaviour as these files are included before any rendering is done, i.e. any template file is called. The difference between the two, however, is that init.php is called right after autoload modules have been initialized, but before the current page is set. This means you cannot access $page variable inside init.php, while inside ready.php all API variables including $page is set. For simple purposes, using any of the two would do the job, but with ready.php you have more tools under your belt. If these files do not exist, you can create them yourself.

To create a simple variable to store some data, you can do the following:

// /site/ready.php

// Wire::wire() method signature, setting $lock as true prevents overriding
public function wire($name = '', $value = null, $lock = false) { /* ... */ }

// an object to pack view data
$viewData = new \stdClass();
$this->wire('v', $viewData, true);

// alternative syntax
wire()->set('v', $viewData, true);

You can also use it for a custom class as well:

class Utils {
    public function renderMessage($message = '') {
        return "Message: " . $message;
    }
}

$this->wire('utils', new Utils(), true);

Now, you can use your custom API variables inside your templates. If you've configured an auto-prepend template with $config->prependTemplateFile, then you can:

// /site/templates/_init.php

// Use it to store body classes
$v->bodyClass = ["template--" . $page->template->name];
// and append new items
if ($page->isFeatured) $v->bodyClass[] = 'is-featured';

// Set some flags
$v->showFooterCopyright = false;

// Store some data
// Append site name to page title except home page
$v->seoTitle = $page->id !== 1 ? "$page->title - MySite" : "MySite";

// Use custom utility class
$v->message = $utils->renderMessage('hello');

// etc.

Then when building HTML, you can simply use:

<html>
    <head>
        <title><?= $v->seoTitle ?></title>
    </head>
    <body class="<?= join(' ', $v->bodyClass) ?>">
        <?= $v->message ?>
        <footer>
            <?php if($v->showFooterCopyright ?? true): ?>
                <p>© <?= date('Y') ?> - MySite</p>
            <?php endif; ?>
        </footer>
    </body>
</html>

Keep in mind that, as useful as having a custom API variable is, you should not go overboard with it since they will be included every TemplateFile instance (unless you implement some restrictions), which means plugging large objects as API variables may detoriorate performance.