Global variable (when a function is not an option)

Many have asked about global variables in Kirby but somehow I still can’t find the solution to my problem anywhere. Sorry if it’s out there and I’ve missed it.

I have an extended Page Model with a method that generates randomized content for my site. I need that content to be generated once per refresh, but to be accessed eventually more than once. Problem is I can’t simply call the same function (Page Method) twice cause it would output a newly randomized content, and that’s not what I want. Actually what I want is to generate the random content once, and be able to modify it from both whatever page or snippet.

What I do now is call the method in my template and store it in a (regular) variable:

<?php $hints = page('hints')->getHints() ?>

Then I pass that var on to my snippet:

<?php snippet( 'grid', [ 'hints' => $hints ] ) ?>

But when I modify the variable within the snippet:

<?php array_splice( $hints, 0, 1 ) ?>

the variable in my template is unaffected (I guess cause it’s passed on to the snippet and not just referenced). When in another snippet, later in the code, I want to access my random+modified variable, what I get if the initial value.

What would be the most elegant way to store my var globally?

Is a collection not enough? For example, on my portfolio pages, i generate a random list of current work, and exclude the page that is currently being viewed from it…

<?php
return function ($site) {

    $portfolio = $site->find('work')->children()->listed()->shuffle()->filterby('title', '!=', page()->title());

    return $portfolio;

};

You can read more about collections here:

https://getkirby.com/docs/guide/templates/collections

Filling the global scope with variables is considered a bad practice and could cause other issues.

You can achieve what you want inside the page model you are already using:

protected $hints = null;

public function getHints()
{
    if (! is_null($this->hints)) {
        return $this->hints;
    }

    return $this->hints = // generate hints
}

The first time you call the method getHints() it will store the result in the $hints property and return it on subsequent calls.

If you need to modify the $hints property elsewhere, add a setHints() method that takes an argument and modify it in there.

2 Likes

Yes! This is exactly what I needed. Thanks @pedroborges!

How would I implement this with a separate pagemodel?

I‘m using the modules plugin and need to test a field in the module pagemodel and be able to use the variable in the parent page template (parent to the module).

Would a shared Controller as in this cookbook article be an option?