Global `$site`, `$page`, `$pages` in route snippet

If you are not using routes, it’s in a template possible to call a snippet and inside that snippet write:

echo $page->title();

It magically works because $page is like a global object that I can use in any template or snippet.

Route

Here I call a snippet with a route. To make it aware of $site, $page and $pages I send it as arguments.

kirby()->routes(array( 
  array(
    'pattern' => 'my/pattern/(:any)',
    'action' => function ($uid) {
      snippet('a-snippet', array(
        'site' => site(),
        'page' => page('some/page'),
        'pages' => page('some/page')->children()
      ));
      return site()->visit('about', 'de');
    }
  )
));

The problem is that when I call a snippet from that snippet it does not remember these objects anymore.

Is there a good way to make them global? I tried a few things but could not make it work.

Snippets

Called from the route above.

a-snippet

<?php echo $page->title(); // Works ?>
<?php snippet('another-snippet'); ?>

another-snippet

<?php echo $page->title(); // Doesn't work ?>

How can I make $site, $page and $pages as global objects when a snippet is used in a route?

They’re not global per se, but added by the Template component when rendering a page:

    // merge and register the template data globally
    $tplData = tpl::$data;
    tpl::$data = array_merge(tpl::$data, $data);
    // load the template
    $result = tpl::load($file, null, $return);
    // reset the template data
    tpl::$data = $tplData;

(In this example $data contains 'site', 'page', 'kirby' and 'pages' keys with the corresponding objects.)

On the other hand, the snippet helper function will simply load existing data from tpl::$data.

This means that if you have a route that renders a snippet, and you’re not rendering a page (or a rendering a snippet before rendering a page and calling the Template component), tpl::$data will probably be empty. If that doesn’t work for you, you probably need to write your own rendering function that does the same thing as Kirby\Component\Template::render. Or see if you can retrieve an instance of Kirby\Component\Template (through the registry?) and use the render method to render a snippet (by giving the full path to the snippet PHP file as first argument).

By the way, it seems you’re feeding your snippet a $pages collection with a specific pages collection. I would avoid doing that, especially if you’re going to overwrite tpl::$data['pages'] with that specific value. Maybe use a different name? Or, if the logic in your snippet is to always use the children of the current page, maybe hardcode that in the snippet?

1 Like

I see. :slight_smile:

At the moment I will not extend the template component just for this. I have other solutions that will work ok. Good to know anyway. Thanks! :slight_smile:

This issue seems to be coming back to me from time to time. This time I need to use it to preview a snippet. For that I will need a route and somehow send arguments to the snippets. Because the snippet can use many other snippets which will probably use the $page object I will need to solve this issue.

Anyway I think your previous reply gave a few hints of how to solve it. Time will tell of how things goes.

It worked like you said it would. :slight_smile:

Class in a plugin:

<?php
class SnippetPreview extends Kirby\Component\Template {
	public function render($template, $data = [], $page = null) {
		$file = $template;
		$data = $this->data($page, $data);

		if(!file_exists($file)) {
			throw new Exception('The template could not be found');
		}

		$tplData = tpl::$data;
		tpl::$data = array_merge(tpl::$data, $data);
		$result = tpl::load($file, null);
		tpl::$data = $tplData;

		return $result;
	}
}

It’s been shorten down quite a bit to only contain what is really needed.

Inside a route, or just run it late:

$SnippetPreview = new SnippetPreview(kirby());

$path = 'some/path/to/snippet.php';
$data = array();
$page = page('about');

$data = $SnippetPreview->render($path, $data, $page);

echo $data;
  • $path to the snippet is required.
  • $data is optional data values for the template.
  • $page is needed to get values from, for example $page->title() .