Virtual route for a static tag

The page helper needs the id of a page. What you have to do is render the blog page with the tag value passed in the data array

I always get a 404 error (not found with this page(‘blog’).
Could the reason be my multi-language setup (EN & DE) + this config setting: ‘home’ => ‘blog’?

Then you better get the home page.

This doesn’t help, I always get a 404.
Could it be because of the multi-language setting?

      [
          'pattern' => 'test/',
          'action'  => function ($value) {
            $data = [
              'tag' => $value,
            ];
            if ($page = page('test/')) {
              return $page;
            } else {
              return page('home')->render($data);
            } 
          }
      ]

You can only use a variable here if your route contains a variable part

No trailing slash here.

Always a page not found error:

      [
          'pattern' => 'test/',
          'action'  => function () {
            if ($page = page('test')) {
              return $page;
            } else {
              return page('home');
            } 
          }
      ]


You probably also have to remove the trailing slash from here

I had to rename ‘home’ to ‘blog’ even if the page blog has been moved to home by the mentioned config to make it work.
Only with the following addition it doesn’t work:

return page('blog')->filterBy('tags', 'test', ',');

I was hoping that I would be able to filter all articles with a specific tag only by this.

No, as mentioned above, you have to pass the tag you want to filter by to the controller, then do your filtering there.

Calling filterBy() on a single page makes no sense at all, you can only filter a collection.

Probably my knowledge and understanding of PHP is far too low for this (and I really appreciate your constant support) but with this code all articles are displayed and not only the one with the tag “test”. Why is that?

config.php

      [
          'pattern' => '(test)',
          'action'  => function ($tag) {
            if ($page = page('test')) {
              return $page;
            } else {
              return page('blog')->render([
                'tag' => $tag
            ]);
            } 
          }
      ]

controllers/blog.php

<?php

return function($page, $tag) {

// fetch the basic set of pages
$articles = $page->children()->listed()->flip();

// fetch all tags
$tags = $articles->pluck('tags', ',', true);

// add the tag filter
if($tag = param('tag')) {
  $articles = $articles->filterBy('tags', $tag, ',');
}

// apply pagination
$articles   = $articles->paginate(5);
$pagination = $articles->pagination();

return compact('articles', 'tags', 'tag', 'pagination');

};

templates/blog.php

<?php snippet('header') ?>
<?php snippet('menu') ?>

<div class="blog">
<main class="blog" role="main">

  <h1><?= $page->title()->html() ?></h1>
  <?= $page->text()->kirbytext() ?>

  <?php foreach($page->children()->listed()->flip()->paginate() as $article): ?>

  <article>
    <h1><?= $article->title()->html() ?></h1>
    <?= $article->date()->toDate('%d.%m.%Y') ?>
    <?= $article->intro()->kirbytext() ?>
    <a href="<?= $article->url() ?>"><?php echo t('readmore', 'Weiterlesen…') ?></a>
  </article>

  <?php endforeach ?>

</main>

<!-- sidebar with tagcloud -->
<aside>
  <h1>Tags</h1>
  <ul class="tags">
    <?php foreach($tags as $tag): ?>
    <li>
      <a href="<?= url($page->url(), ['params' => ['tag' => $tag]]) ?>">
        <?= html($tag) ?>
      </a>
    </li>
    <?php endforeach ?>
  </ul>
  <a class="twitter-timeline" height="500px" data-chrome="nofooter transparent" href="https://twitter.com/MaluNoPeleke?ref_src=twsrc%5Etfw">Tweets by MaluNoPeleke</a> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</aside>

<!-- pagination -->
<nav class="pagination">
  <?php if($pagination->hasPrevPage()): ?>
  <a href="<?= $pagination->prevPageUrl() ?>"><<</a>
  <?php endif ?>

  <?php if($pagination->hasNextPage()): ?>
  <a href="<?= $pagination->nextPageUrl() ?>">>></a>
  <?php endif ?>
</nav>
</div>
<?php snippet('footer') ?>

Since there is no parameter set in this case, you just check for $tag, see the docs: Controllers | Kirby CMS


if($tag) {
  $articles = $articles->filterBy('tags', $tag, ',');
}
1 Like

But with none of the following blog.php controller code variations articles will be filtered by tags (I would expect to see only articles with the tag “test”):

<?php

return function($page, $tag) {

// fetch the basic set of pages
$articles = $page->children()->listed()->flip();

// fetch all tags
$tags = $articles->pluck('tags', ',', true);

// add the tag filter
if($tag = param('tag')) {
  $articles = $articles->filterBy('tags', 'test', ',');
}

// apply pagination
$articles   = $articles->paginate(5);
$pagination = $articles->pagination();

return compact('articles', 'tags', 'tag', 'pagination');

};
<?php

return function($page, $tag) {

// fetch the basic set of pages
$articles = $page->children()->listed()->flip();

// fetch all tags
$tags = $articles->pluck('tags', ',', true);

// add the tag filter
if($tag) {
  $articles = $articles->filterBy('tags', 'test', ',');
}

// apply pagination
$articles   = $articles->paginate(5);
$pagination = $articles->pagination();

return compact('articles', 'tags', 'tag', 'pagination');

};

Does filtering work if you simply use the tag as parameter in the url and filter by param(‘tag’)?

http://yourdomain.test/tag:test 

(or with language code in a multi-lang installation)

No, that doesn’t change anything either.
I followed the whole cookbook for the blog setup and created some articles with tags. What could be missing?

Is the field name correct? Feel free to send me a download link to the project. We are currently digging in the dark, it seems, although I’m sure it’s just a little thing.

Thanks a lot in advance, here is the download link: WeTransfer

The reason your filtering cannot possibly work is that you don’t use the $articles variable in your template, but

<?php foreach($page->children()->listed()->flip()->paginate() as $article): ?>

which should be

<?php foreach($articles as $article): ?>
1 Like

Thanks a lot, I didn’t look at that part anymore after I copied it from the example mentioned here: Creating a Kirby-powered blog | Kirby CMS

One question left: If I use the following code in the config.php to show only articles with the tag “test” on the virtual page “test” I still get all articles displayed:

      [
          'pattern' => 'test',
          'action'  => function () {
            if ($page = page('test')) {
              return $page;
            } else {
              return page('blog')->render([
                'tag' => 'test'
            ]);
            } 
          }
      ]

Why is that?

This question was already answered here: Virtual route for a static tag - #12 by pixelijn

Finally it works, thanks a lot!
I used the wrong order, now I can use the virtual page or the normal tag filter with this code in the blog.php controller:

  // add the tag filter
  if($tag) {
    $articles = $articles->filterBy('tags', $tag, ',');
  }
  if($tag = param('tag')) {
    $articles = $articles->filterBy('tags', $tag, ',');
  }

Initially I just pasted the mentioned code below the existing one.