isOpen() generates an error if the page is in draft mode

<?php e($item->isOpen(), 'text-red', 'text-green') ?>
I use this function to add a CSS class to a navigation. This also works perfectly.
However, if I open a page that is in draft mode, I get an error message:

Call to a member function isOpen() on null

In the example, I don’t see that an additional query is required for the status of the page.

Is this a Kirby related error or an :man_technologist: programmer error?

Hm, I’m missing some context here. Guess it’s related to the subsubmenu you mentioned in an earlier topic?

And when exactly does this happen?

Yes, it’s about this topic, where you’ve already helped me:

And when exactly does this happen?

When I open the draft from the panel, the error message appears.
With status listed and unlisted don’t generate an error.

<?php e($item->isOpen(), 'text-red', 'text-green') ?>

Since this includes already an if/else query, I don’t understand why an error message appears. Or do I need another if/else query for the if/else query? :sunglasses: That would only make the construct more complex.

The error is only displayed in draft mode. But explain that to a customer who wants to check their prepared article in the frontend. Then my phone will be ringing off the hook :wink:

Before I look for a solution, my question is: Kirby error or user error?

It still a mystery, what $item refers to in this context. Could you please post or otherwise provide the complete template with all included snippets (if applicable). And please also post the stack trace of the error.

1 Like

After a few tests, I was able to solve the problem.

Before:

<?php foreach($items as $item): ?>
<?php e($item->isOpen(), 'text-red', 'text-green') ?>
<?php endforeach ?>

After:

<?php foreach($items as $item): ?>
<?php if ($item): ?>
<?php e($item->isOpen(), 'text-red', 'text-green') ?>
<?php endif ?>
<?php endforeach ?>

I am using the code to list all children and move the active page to the first position. I could eliminate the error message by additionally checking that $item is not null before trying to access its properties. (I have omitted irrelevant elements for a better overview.)

Hm, but I think the issue happens actually somewhere before. If $items is a collection of pages as it should be, there shouldn’t be a need to check if the current item in the collection is a page. And that’s why I was asking for the context.

So yes, you can solve it like this, but I have a feeling that something else is not ok.

Thank you for wanting to go into more depth.
I am, of course, also in favor of efficient code, but I don’t want to create too much complexity.
This is the complete code area that creates the navigation. Do you already recognize the problem area here? Or do you need further information?

<?php
$items = false;
if ($root1 = $pages->findBy('isOpen', true)) {
if ($root2 = $root1->children()->findOpen()) {
$unopened = $root2->children()->listed()->not($root2->children()->findOpen());
$first = $root2->children()->findOpen();
$items = $unopened->prepend($first);
}
}
if ($items and $items->isNotEmpty()): ?>
<ul>
<?php foreach ($items as $item): ?>
<?php if ($item): ?>
<li class="position-relative pb-5px pt-5px border-bottom">
<a class="<?php e($item->isOpen(), 'text-red fw-900 text-uppercase', 'text-dark-gray') ?>" href="<?= $item->url() ?>"><?= $item->title()->html() ?></a>
<i class="fa-sharp <?php e($item->isOpen(), 'fa-solid fa-angles-right text-red', 'fa-regular fa-plus') ?>"></i>
</li>
<?php endif; ?>
<?php endforeach ?>
</ul>
<?php endif ?>

The problem seems to be here, where you don’t check if $first is even a page object before you prepend it to the collection, so you are likely to add a NULL item.

On a side note, it is best practice to use && instead of and in this line.

Thanks for the tip. Good that you have found a weak point.
At which position must the query take place? I have only worked with collections once.

$items = $first ? $unopened->prepend($first) : $unopended;
1 Like

Top! Thank you. :clap:
And again, the Kirby world has gotten better with your help.