Stuck - Collections of albums

Based on the blueprint + model for album in Starterkit,

My aim is to have three separate pages - portfolio pieces, perspectives, and life (news) - and inside each of those would be any number of individual album-like pages.

I have created blueprints for the page and section for portfolio pieces, and a blueprint for portfolio. They have have adapted directly from the Starterkit album files. This much appears to be working as expected.

On the template for home.php, I can call the individual portfolio pages into the front-end. All of the object data appears to be well-formed and intact.

When I attempt to copy and adapt the album model for portfolio, I’m getting really stuck.
My aim is to adapt the Cover method so each portfolio object automatically renders out the selected cover file as an image. But I’m not sure what I’m overlooking.

Any thoughts…?

→ models\portfolio.php

class PortfolioPage extends Page{
public function coverPortfolio() {
// need to verify whether $this refers to the correct context for my purposes
return $this->content()->get(‘cover’)->toFile() ?? $this->image();
}
}

Full code base is available on Git - GitHub - 2inchesofwater/2inchesofwater-2019: Rebuild of the 2 Inches of Water home page

That is the same method as in the album.php model, only named differently.

If you want to render that as an image tag in your template, you can do it like this.

<?= $page->coverPortfolio() ?>

I wouldn’t return HTML from the model.

Thanks so much for your answer, Texnixe

I might be confused about the example shown in album’s model, then?

Why would it work (but my re-named version not work), and why would it be okay for that example to return HTML from its model?

Both models return an image object (if it exists), if you echo an image object, it returns the HTML (I corrected my example above).

The reason for this is the magic __toString() method that creates an image tag for an image file in a string context:

The __toString() method allows a class to decide how it will react when it is treated like a string. For example, what echo $obj; will print. This method must return a string, as otherwise a fatal E_RECOVERABLE_ERROR level error is emitted.

This is the method (in FileFoundation.php)

 public function __toString(): string
    {
        if ($this->type() === 'image') {
            return $this->html();
        }

        return $this->url();
    }

Anything thoughts on how I can diagnose why I’m seeing different results?
In the attached screen capture, both the album and the portfolio objects are being printed using PHP, and the respective cover and coverPortfolio models called.

The album cover is being returned as a fully-formed piece of HTML, but the portfolio coverPortfolio only returns the filename…

[live update] ahh - just saw your edit, Texnixe

A new line of thinking… is it possible/correct to call coverPortfolio from any page within a Kirby site?

Could things be breaking because I’m trying to call it from index.php [correction: templates/home.php], rather than one of the individual pages?

No, coverPortfolio() is a page model, so it only refers to pages that use the portfolio blueprint.

Instead of creating multiple models, you can define a custom page method that you can then use anywhere.

You have to put your code into the templates, not into index.php.

1 Like

Sorry - yes - the temporary code is in templates/home.php

Cool - I think this might be the insight I need. Will delve into it in the morning. Thanks so much for your help, Texnixe!

But what is your code in home.php?

Good night, then. It’s morning in my part of the world…

In templates/home.php, I currently have this -

<?php if ($coverPortfolio = $child->cover()): ?>

Cover:
<?= $coverPortfolio ?>

<?php endif ?>

But taking on board your advice regarding Page Models, I can see why the call to coverPortfolio would not be connecting to the actual coverPortfolio method.

It’s Australia over here, so everything is upside down :sweat_smile:

But here you call cover() not coverPortfolio()

I think that was a misunderstanding: You can call these methods everywhere in your project, but only for the pages that use corresponding model.

An expanded view of templates/home.php -

 <?php foreach (page('portfolio')->children()->listed() as $child): ?>
    <?= $child->headline()->html() ?>
    <?php if ($coverPortfolio = $child->coverPortfolio()): ?>
    <p>Cover: <br/><?= $coverPortfolio ?></p>
    <?php endif ?>

If this code appears inside home.php, is it enough that we’re calling in page(‘portfolio’) as the parent object? Will Kirby make the connection between page(‘portfolio’) and models/portfolio.php?

Yes, that should work (endforeach missing in above code snippet, though). Does it not? If not, what is the result/error?

Appears that I’ve got a working solution -

templates/home.php

<?php foreach (page('portfolio')->children()->listed() as $child): ?>
  <?php if ($coverPortfolio = $child->coverPortfolio()): ?> 
  <?= $coverPortfolio ?>
  <?php endif ?>
<?php endforeach ?>

Which pairs across to -
site/models/portfolio

class PortfolioPage extends Page {
  public function coverPortfolio() {
    return $this->content()->get('cover')->toFile() ?? $this->image();
  }
}