Undefined variable in snippet

I am building a page with a project thumbs section.

The home page looks like this:

<?php snippet('home-header') ?>

    <?php snippet('projects') ?>

<?php snippet('home-footer') ?>

The projects snippet looks like this:

<?php $n = 0; foreach($page->children()->visible()->flip() as $project): $n++; ?>

        <?php snippet(r($n%2==0, 'project-even', 'project-odd')) ?>

<?php endforeach ?>

And the individual snippets the odd even snippets look like this:

<section class="project-section">

      <figure class="project-side project-side-left">
        <?php if($image = $project->image('home-page.jpg')): ?>
          <img src="<?php echo $image->url() ?>" alt="<?php echo $project->title()->html() ?>">
        <?php endif ?>
      </figure>

      <article class="project-side project-side-right">
          <h2><?php echo $project->title()->html() ?></h2>
          <p><?php echo kirbytext($project->intro()) ?></p>
          <ul>
            <?php foreach($project->tags()->split() as $tag): ?>
                <li><?php echo $tag ?></li>
            <?php endforeach ?>
          </ul>
          <a href="<?php echo $project->url() ?>" class="project-section-button">View project</a>
      </article>

    </section>

The error I’m getting is

PHP Notice:  Undefined variable: project in project-odd.php line 5
PHP Fatal error:  Call to a member function image() on a non-object in project-odd.php line5

Following this example http://getkirby.com/docs/cheatsheet/page/children I don’t see how $project is not defined

The snippet doesn’t know the variable $project, which is only defined in the template. You need to hand it over from the template to the snippet, I’m not quite sure how it works with the short notation above, but usually it is works like this:

<?php snippet('project-odd', array('project' => $project)); ?>

where $project is the variable defined in the template, ‘project’ the name by which you want to refer to it in the snippet.

2 Likes

I see! so this is how it is fixed now:

<?php
        $n = 0;
        foreach($page->children() as $project): $n++; ?>
      <?php
        if($n%2 == 0) {
          snippet('project-even', array('project' => $project));} // code as above, i.e. with article first
        else {
          snippet('project-odd', array('project' => $project)); //.i.e. with image first
        } ?>
      <?php endforeach ?>

Ok, and here the short version:

<?php $n = 0; foreach($page->children() as $project): $n++; ?>
        <?php snippet(r($n%2==0, 'project-even', 'project-odd'), array('project' => $project)) ?>
<?php endforeach ?>
1 Like

So, what happens if I want to call this variable in the template after modifying it in the snippet. Let’s say I want to do something like this:

<?php $color = "used to be black"; ?>
<?php snippet('palette', array('color' => $color)); ?>
<?php echo $color; ?>

Where my ‘palette’ snippet contains this:

<?php $color = "now is red"; ?>

I want the echo in the template to return “now is red”, but it keeps on giving me “used to be black”. I tried using global before variables in many different ways, but I couldn’t succeed.

this should work:

in your snippet:

<?php $GLOBALS['color'] = "now is red"; ?>

in your template:

<?php echo $GLOBALS['color'] ?>
2 Likes

Hola, thats quite an old post, but i would like to know, if this is still the way to go, to get variables from snippets in templates in Kirby V3? The following is working, but i was wondering, if there is another solution?
i need the variable $images from my snippet into a template for a json-output.
Thanks!

// example-template.php
<?php
snippet('cover');
$data = [
  'coverImages' => $GLOBALS['coverImages'],
  'h1' => $page->h1()->text()->value(),
];
echo \Kirby\Data\Json::encode($data);
?>
// cover.php
<?php
$quality = 80;
$images = [];

if($imageMobile = $page->coverMobile()->toFile()) {
  $images["mobile"] = $imageMobile->crop(768, 768, $quality)->url();
}
if($imageDesktop = $page->coverDesktop()->toFile()) {
  $images["desktop1920"] = $imageDesktop->crop(1920, 768, $quality)->url();
}
$GLOBALS['coverImages'] = $images;
?>

Why do you define the variables in the snippet instead of in the controller?

hmm, i think i would like to avoid having a controller for each template using a cover.
apart from that i just tried your proposal, but unfortunately the snippet could also not access the variable from the controller (why not?). it also only works with a globals variable :frowning:
did i make a mistake?

/* controllers/home.php */

<?php 

return function ($page) {

    $images = [];
    $images["testfromcontroller"] = 'testfromcontroller';

    return [
        'images' => $images
    ];
};
/* templates/home.php */

<?php
snippet('cover');

$data = [
  'images' => $images,
  'globalImages' => $GLOBALS['globalImages'],
];
echo \Kirby\Data\Json::encode($data);
?>
/* snippets/cover.php */

<?php

$quality = 80;
$images['testfromsnippet'] = "testfromsnippet";

if($imageMobile = $page->coverMobile()->toFile()) {
  $images["mobile"] = $imageMobile->crop(768, 768, $quality)->url();
}
if($imageDesktop = $page->coverDesktop()->toFile()) {
  $images["desktop1920"] = $imageDesktop->crop(1920, 768, $quality)->url();
}

$GLOBALS['globalImages'] = $images;
?>

The whole idea was to get get rid of the snippet and move the logic to a different place, either a controller or to a page method, so that you don’t have to move your variables back and forth from the snippet.

If you need this code in all templates, then the method approach is of course the better option.

Your JSON template would then look like this:

<?php
$data = [
  'coverImages' => $page->getImageThumbs(),
  'h1'          => $page->h1()->text()->value(),
];
echo \Kirby\Data\Json::encode($data);

With your getImageThumbs() method defined in a plugin.

If you want to make the method more versatile, you could extend it with arguments you can pass to it (e.g. thumb sizes).

1 Like

Page Methods works like a charm!
Thank you! @texnixe @pixelijn

<?php

Kirby::plugin('my/page-methods', [
    'pageMethods' => [
        'getCover' => function () {
            $quality = option('my.cover.quality', 80);
            $images = [];
            if($imageMobile = $this->coverMobile()->toFile()) {
                $images["mobile"] = $imageMobile->crop(768, 768, $quality)->url();
            }
            if($imageDesktop = $this->coverDesktop()->toFile())
                $images["desktop1920"] = $imageDesktop->crop(1920, 768, $quality)->url();
            }
            return $images;
        }
    ]
]);
<?php

$data = [
  'cover' => $page->getCover(),
  'h1' => $page->h1()->text()->value(),
];
echo \Kirby\Data\Json::encode($data);

?>