Help with filtering via routes

Hi all

I would like to filter my blog content per category. I’ve been following the filtering by routes guide and I can’t get it to work…

Any help is appreciated!

This is my code

article contains field

----

Category: Sport

----

route in config.php

'routes' => [
    [
        'pattern' => 'magazin/category/(:any)',
        'action'  => function ($category) {

            return Page::factory([
                'slug'     => $category,
                'template' => 'category',
                'model'    => 'category',
                'content'  => [
                    'title' => 'Results for ' . ucfirst($category),
                ]
            ]);

        }
    ]
]

link to page

<a href="<?= $site->url() . '/magazin/category/' . urlencode($article->category()->slug()) ?>"><?= $article->category() ?></a>

controller category.php

<?php
return function($kirby, $site, $pages, $page) {


    $shared = $kirby->controller('site' , compact('page', 'pages', 'site', 'kirby'));
    
    $category = urldecode($page->slug());
    $articles = page('magazin')->children()->filterBy('category', $category, ',');

    return A::merge($shared , compact('category', 'articles'));
    
};
?>

template category.php contains

                    <?php if ($articles->isNotEmpty()) : ?>
                        <?php foreach ($articles as $article) : ?>
                            <article>
                                <h2><?= $article->title()->html() ?></h2>
                                <?= $article->text()->kt() ?>
                                <ul>
                                <?php foreach ($article->category()->split(',') as $category) : ?>
                                    <li><a href="<?= page('magazin')->url() . '/magazin/' . esc($category, 'url') ?>"><?= $category ?></a></li>
                                <?php endforeach ?>
                                </ul>
                            </article>
                        <?php endforeach ?>
                    <?php else : ?>    
                        <div>No results for category <?= $category ?></div>
                    <?php endif ?>

So what I want to achieve is to filter content by category and the url to be website.com/blog/sport, not website.com/blog/category/sport (my blog is called ‘magazin’). Currently when I open that url, I get the text ‘No results for sport’.

What am I doing wrong?

Your link and your pattern point to website.com/magazin/category/sport not website.com/magazin/sport, but that’s probably not the issue?

Don’t know why you are passing $category here, because you are not using this parameter anywhere.

I wouldn’t do both here, sluggify and urlencode, and that’s probably the issue, because your categories seem to have uppercase, while if you sluggify, all will be lowercase.

1 Like

Hi Sonja

Yeah, the link and the pattern are not the problem. I can get to that later - still have to figure out how to remove the ‘category’ from the url using pattern…

I’ve removed the $category from the controller, and updated the template code. I updated the code in my original post to reflect.

I’m still getting the ‘No results for category sport’ but I do have an article with category sport.

So each article only has one category assigned, is that okay?

So, what does the link with the sport category that does not return a result actually look like?

And just on a side note: If the category field only ever has one category assigned, this foreach statement (and the ul element) is superflous.

 <?php foreach ($article->category()->split(',') as $category) : ?>
                                    <li><a href="<?= page('magazin')->url() . '/magazin/' . esc($category, 'url') ?>"><?= $category ?></a></li>
                                <?php endforeach ?>

Replace with

<a href="<?= page('magazin')->url() . '/magazin/' . esc($page->category(), 'url') ?>"><?= $category ?></a>

Okay I’ve replaced the foreach statement. Still the same result.

So when I open the page localhost:8888/magazin/category/sport I get the following result.

"Results for Sport

No results for category sport"

So originally on my magazin page, I had the category listed under each article, and that category was linked to magazin/category/$category - but I removed that until I get the displaying of articles under the category right.

So I just tried going into the article.txt of the article that is under category ‘Sport’ and I change the category from ‘Sport’ to ‘sport’- so all lowercase and refreshed the page.

The result went from

“No results for category sport”

to

“sport”

So it actually displayed the category.

Feel free to send me a download link to your project if you don’t figure it out, and I will have a look later.

Got it working. So my categories in article.txt have the first letter in uppercase. So I edited the slug part of the route to be

'slug'     => ucfirst($category)

Not sure if that’s the most efficient way but it worked.

Not my next question is, how do I amend the route to remove the ‘category’ from the url path. Do I need a new route for that or can I amend the current route.

'routes' => [
    [
        'pattern' => 'magazin/category/(:any)',
        'action'  => function ($category) {

            return Page::factory([
                'slug'     => ucfirst($category),
                'template' => 'category',
                'model'    => 'category',
                'content'  => [
                    'title' => 'Results for ' . ucfirst($category),
                ]
            ]);

        }
    ]
  ],

];

If you remove the category part from the url, you have to handle two cases:

  1. The url part after magazin is a child page
  2. The url part is not a page
[
        'pattern' => 'magazin/(:any)',
        'action'  => function ($slug) {

            if ($page = page('magazin/' . $slug) {
              return $page;
            }
            return Page::factory([
                'slug'     => ucfirst($slug),
                'template' => 'category',
                'model'    => 'category',
                'content'  => [
                    'title' => 'Results for ' . ucfirst($slug),
                ]
            ]);

        }
    ]

BTW: There isn’t really a need for a separate category controller/template, you could actually handle this in the magazin controller/template, unless that is somehow different.

Thanks Sonja, will this route have an effect on the tags? Tags are the usual patern ‘magazin/tag:soccer’ or will the tags work fine?

I will have a go at combining the code with magazin controller/template. I was following the filtering by route and tags so I created separate files.

No, the route ignores url parameters.

Hi Sonja

I’ve tried this code and it doesn’t work. I keep getting an error.

This page is currently offline due to an unexpected error. We are very sorry for the inconvenience and will fix it as soon as possible.

Advice for developers and administrators:
Enable debug mode to get further information about the error.

However, I do have the debugger enabled…

Then you probably have an error in your config.php. Check if your IDE shows any errors in that file and if you can’t find it, post the code here.

This is my code, so basically copy paste what you sent.

return [
    'debug' => true,
    'sgkirby.commentions.templatesWithComments' => ['article'],
    'sgkirby.commentions.templatesWithWebmentions' => [''],
    'sgkirby.commentions.defaultstatus' => 'approved',
    'sgkirby.commentions.commentfields' => [
        'name' => true,  // include name field and mark as required
      ],

    'hooks' => [
      'commentions.add:after' => function ($page, $data) {
        try {
          kirby()->email([
            'from' => 'webserver@radioritamsrca.com',
            'to' => 'mkolundzic@gmail.com',
            'subject' => 'New comment on ' . $page->title(),
            'body'=> print_r($data, true),
          ]);
        } catch (Exception $error) {
          echo $error;
        }
      }
    ],


'routes' => [
    [
        'pattern' => 'magazin/(:any)',
        'action'  => function ($slug) {

            if ($page = page('magazin/' . $slug) {
              return $page;
            }
            return Page::factory([
                'slug'     => ucfirst($slug),
                'template' => 'category',
                'model'    => 'category',
                'content'  => [
                    'title' => 'Results for ' . ucfirst($slug),
                ]
            ]);

        }
    ]
  ],

];
         if ($page = page('magazin/' . $slug) {
              return $page;
            }

[/quote]

There is a closing parenthesis missing, should be

   if ($page = page('magazin/' . $slug)) {
              return $page;
   }

Your IDE should show you such errors. Which one are you using?

1 Like

That worked!

I’m using MAMP - is that what you mean by IDE?

It usually shows errors - but this one showed that message I posted above. Also - with this error, the whole site wasn’t working, where as if it’s a page specific error the debugger usually shows what it is.

No, I mean the code editor.

Example using VS Code with IntelliSense extension:

Oh, I’m using VS Code, but didn’t have IntelliSense extension. I was meaning to install some of these extensions, but didn’t know which ones to get… I’ll get the IntelliSense one now… any others you recommend?

Ah, sorry, I have the Intelephense plugin installed in VS Code. Not so familiar with the extensions, because my goto IDE is PHPStorm.

But I’d also use a plugin to enforce coding style standards, see

1 Like

Thank you! I’ll have a read of that.