Use toPage() on a string generated by pluck()

Hi there,

I’m currently using url parameters to filter posts in a blog by value of a category select field. Today I wanted to switch from hard-coded select options in the blog.yml to children of a new category page:
query: site.children.template('categories').children.listed

Before, I could easily fetch all categories from articles using pluck('category', ',', true), but now this outputs i.e "categories/article" instead of just "article", which of course breaks the URL. mypage.com/blog/category:categories/article redirects to the default page.

While looping over posts in the blog template, I’m able to use $article->category()->toPage()->title() but this doesn’t work anymore when creating the “tagcloud” of filtering options. In my posts controller, I have the following:

$categories = $articles->pluck('category', ',', true);

and in my posts.php template, I would like to do the following:

<?php foreach($categories as $category): ?>
    <a href="<?= url($page->url(), ['params' => ['category' => $category->toPage()->title()]]) ?>">
        <li class="link" data-category="<?= $category->toPage()->title(); ?>" style="background: <?= $category->toPage()->color(); ?>">
            <?= strtoupper(html($category->toPage()->title())); ?>
        </li>
    </a>
<?php endforeach ?> 

however, this breaks saying Error: Call to a member function toPage() on string. But Isn’t the toPage() method created for the purpose of converting exactly these values to a page object or am I missing something?

This returns an array, and each element of the array only outputs a string.

The toPage() method is a field method, so you can only call it on a field object. You can, however, fetch the page using the page helper

if ($page = page($category)) {
  // do stuff
}

By default, a select field stores the ID of a page. You can change that so that it only stores the slug.

3 Likes

This makes a lot of sense, thank you!

I’m using the page helper to get each category title and color value now:

<?php foreach($categories as $category): ?>
    <?php if ($cat = page($category)): ?>
        <a href="<?= url($page->url(), ['params' => ['category' => $cat->title()]]) ?>">
            <li class="link" data-category="<?= $cat->title(); ?>" style="background: <?= $cat->color(); ?>">
                <?= strtoupper(html($cat->title())); ?>
            </li>
        </a>
    <?php endif; ?>
<?php endforeach ?>

because like this I didn’t have to rewrite a lot.

The other option would have been to change the select field value in the blueprint to slug, in order to make less use of the page() helper, and using a generated stylesheet targeting the data- attributes instead of setting the background color inline. Do you think this would make sense in terms of performance?

1 Like

You mean inline styles vs. stylesheet? Or using the page helper?

both, since changing the field value would mean that I’d likely make much less use of the page helper AND would lose access to the color value of the category page in the template. I know using a stylesheet is preferable vs inline, but idk if it actually changes anything because it would be like 10 lines of css. No idea at all if there would be a noticeable increase in performance if less helper methods are used.

What is your reason for creating the categories as pages? Are they used for any other purpose apart from providing the category name and a color?

oh, right – i was planning on showing all articles with a certain category on their respective category page inside the panel. I couldn’t really figure out how i would filter this using the query language, so i postponed further confrontation but kept the categories as pages