Kirby Starthook - Pass global data to your templates and snippets

With the starthook from your config.php or a plugin you can pass global data to your templates and snippets.

You have access to the current $page object, which you normally don’t have in the config.php file.

Usage example 1

kirby()->hook('starthook', function($page) {
  starthook::return(array(
    'foo' => 'my first template variable ' . $page->title(),
    'bar' => 'my second template variable'
  ));
});

Usage example 2

kirby()->hook('starthook', function($page) {
  if($page->title() == 'Project A') {
    go(page('projects'), 301);
  }
});
1 Like

For example 1, what is the difference between using starthook and using c::set()?

You have a point. In my example 1, I did not use the $page object. I updated my example to show the full potential of that example.

If taken the new updated example 1 and would have used c::set instead it would have been something like this:

$page = page();

c::set('starthook', array(
  'foo' => 'my first template variable ' . $page->title(),
  'bar' => 'my second template variable'
));

$page in the example above will not be defined so I need to set it to page() but it now contains home no matter on where we are. Therefor I need a hook to be able to have the correct $page object.

If no $page object is needed we could use c::set but as far as I know we almost always need the $page object. Therefor I don’t see a big benefit of supporting both a hook and c::set.

UPDATE

I will move to @lukasbestle solution instead. It’s quite the same idea but much better.

1 Like

Why do use hooks for this? What about this:

c::set('starthook', function($page) {
  return array(
    'foo' => 'my first template variable ' . $page->title(),
    'bar' => 'my second template variable'
  );
});

// In your plugin
$starthook = c::get('starthook');
if(is_callable($starthook)) $vars = call($starthook, $page);

It even supports return values. :wink:

2 Likes

Thanks! That’s brilliant! :slight_smile:

Version 0.2 released. Thanks to @lukasbestle this plugin was improved.

It now works just like that:

c::set('starthook', function($page) {
  return array(
    'foo' => 'my first template variable ' . $page->title(),
    'bar' => 'my second template variable'
  );
});

or

c::set('starthook', function($page) {
  if($page->title() == 'Project A') {
    go(page('projects'), 301);
  }
});

It’s not hooks anymore but I think I’ll keep the name Kirby Starthook. It still kind of hooks with the template component.

1 Like

While the current $page object may not be accessible from config.php, we do have kirby()->request()->path().

I tried to solve this problem by creating a simple getPage() function:

function getCurrentPage() {
	// Get the full request path
	$path = kirby()->request()->path();

	// Strip language prefix from path
	foreach (c::get('languages', []) as $l) {
		$prefix = substr($l['url'], 1);
		if ($prefix and strpos($path, $prefix) === 0) {
			$path = substr($path, str::length($prefix));
			continue;
		}
	}

	// Add homepage slug to path if it's blank
	if ($path == '') $path = c::get('home', '/');

	// Build page object
	$page = page($path);

	// If page doesn't exist, use error page
	if (!$page) $page = page('error');

	// Return the page object
	return $page;
}

I wonder what advantages your Starthook has over this method? I’m not familiar with Components.

It depends what you are going to do. I tried it and here are some disadvantages with your function that I see right now:

Config runs first

I can’t use getPage() in the config.php if the function is in a plugin, because the config runs first. Maybe you don’t want to run it in the config but if you do want it there you also need the function to be there and that is probably not the best way.

Template/Snippet

If I’m going to use getPage() to figure out if the page should redirect or not, it’s not very nice to put the code it in a template/snippet. That is one of the things I wanted to avoid, to keep the templates and snippets clean from logic.

Controller

If I put getPage() into a controller (I have not tried that) I need to put it in every controller which is what my plugin is ment to avoid in the first place.

Language

You remove the language prefix in your function, but the language slug can be different which this might not always work.

Advantages with Starthook

I don’t think it has any bottlenecks. I’ve tried to solve this very problem for a long time through other plugins like Init Controller, Pre Controller, Inherit Controller etc. At the end I wanted it to be even more simple and at the same time work with alternative ways to work for example with the Kirby Bricks plugin.

Instead of using a global controller with $site, $pages and $page I found out that only the $page object is really needed. The other two objects can be use with site() and site()->children() anyway.

I also found out that it should be in the config and not in a new kind of controller. Config is also the natural global place to set stuff.

1 Like

Thanks for the detailed answer :smiley: I see that your solution is a lot more robust than I thought at first glance.

You remove the language prefix in your function, but the language slug can be different which this might not always work.

This isn’t quite right, my function uses the 'url' key of each language, so it will match the slug.