Cross-category navigation between articles, ordered by date

I am a bit confused about how to build the navigation through my website, due to my poor PHP skills. Maybe someone could help me with this.

Background is this: My website is like a scrap book or a collection of unordered pages. Let’s say I found a bunch of loose papers and I bind them into a book, one after another. Later I detect that they all belong to different projects, and I put them into an order in an index. Maybe I want to list them in one of those index folders later. But the order of pages in the book must remain the same.

I have a page structure like that (my „index"), with certain time stamps:

Home
The sea/
   The guests vanish, date 09.01.2014/
   At the platform, date 06.04.2014/
   A ship arrives, date 03.07.2015/
The land suveyor/
   Flora and fauna, date 07.03.2014/
   Deepest cellar, date 05.05.2015/
   The burning exit, date 01.09.2016/
The fourteen Holy Helpers/
   Vitus, date 08.02.2014/
   Barbara, date 04.06.2015/
   Christoph, date 02.08.2016/
About
Contact

This structure is mirrored in the menu navigation, as sort of an index.

My intention is

  1. to show ALL the pages, one after another, irrespective of their category („The sea“, "The land surveyor“, "The fourteen Holy Helpers“), ordered by their time stamp, with the newest published page on/as the home page (a flipped page order).

  2. But if I navigate to the category, I want to display each page of only this category in chronological order, with the oldest as starting point.

  3. So the unordered page order would be:
    „The burning exit“ (home page) -> „Christoph“ -> „A ship arrives“ -> „Barbara“ -> „The deepest cellar“, and so on.

  4. The category page order would be like in my index, but only one category.

The home page is like this:

<?php $article = $site->index()->visible()->sortBy('date', 'desc')->first() ?>
<article>
<div><?php echo $article->parent()->title()->html() ?></div>
<div><?php echo $article->date('d. m. Y') ?></div>
<h1><?php echo html($article->title()) ?></h1>
<?php echo $article->text()->kirbytext() ?>
</article>

But how do I set up the page navigation? I guess it must be two setups, with an if-expression, one of those being

<nav role="navigation">
<?php if($prev = $page->prevVisible()): ?>
<a href="<?php echo $prev->url() ?>">&larr; previous</a>
<?php endif ?>
<?php if($next = $page->nextVisible()): ?>
<a href="<?php echo $next->url() ?>">next &rarr;</a>
<?php endif ?>
</nav>

Could someone help me with this if-expression and the alternative navigation?

How to differentiate between page types:

You could use different template names. For instance category.txt for the category page and article.txt for the article page. Then these conditions should work;

if ($page->isHomePage()) {
  // Navigation for home page
}
elseif ($page->intendedTemplate() == 'category') {
  // Navigation for category pages
}
elseif ($page->intendedTemplate() == 'article') {
  // Navigation for article pages
}

That’s one way to do it. Note that I’m using intendedTemplate() and not template() because if you don’t actually create category.php, home.php and article.php templates but instead rely on having every page rendered by a default.php, the template() method will return 'default' (but the intendedTemplate() method will return the name of the content file).

Now for retrieving the right list of articles depending on context:

// Lists all articles in the site
$articles = $site->index()
    ->filterBy('intendedTemplate', 'article')
    ->orderBy('date', 'desc');

// Lists child articles for the current category
$articles = $page->children()
    ->filterBy('intendedTemplate', 'article')
    ->orderBy('date', 'desc');

// Lists sibling articles
// Lists child articles for the current category
$articles = $page->parent()->children()
    ->filterBy('intendedTemplate', 'article')
    ->orderBy('date', 'desc');

You could combine these examples with the conditions above.

These are just some pointers, I have sadly not read your exact requirements in details so they’re probably not 100% of the answer but they should get you closer.

2 Likes

Hm, I don’t know whether I expressed myself well.

Here I am speaking of the next/prev-navigation.

I think I made a thinking mistake. How can an article page “know” whether I want it to proceed to the next page by date or by its own category? I suppose this might cause a paradox, no? So I must provide both options at the same time (next “page in my scrap book”+ next category article). My first idea was to simply fetch all the belonging pages by tags and have only one category. Then I can easily move from one page to the following one. But in the long run the list of articles will be too long and I will get lost in the amount of data.

So I think I should focus on that scrap book idea, to achieve a list of articles sorted by date only (not by category), but I still did not find out how to do that. I would like to keep the categories for organization’s sake, but then only in a menu navigation and with tags.

You can pass a sort option to the prev-next navigation, see the docs: https://getkirby.com/docs/cheatsheet/page/next

Thank you textnixe. I tried this but again I got only the category pages.

Is there a way to write something like this?

   <?php if($next = $site->index()->filterBy('template', 'article')->next('date', 'desc')): ?>
    <a class="float-right" href="<?php echo $next->url() ?>">next page  &rarr;</a>
    <?php endif ?>

This does not work, so there is still a mistake, but if I go back to the very root and then call all pages that are based on the template “article”, I should get something?

Check out this post if you want to navigate within a filtered collection: Navigate into a collection with hasNext/hasPrev

Could it not be simpler?

<?php
$articles = $site->index()
  ->filterBy('intendedTemplate', 'article')
  ->sortBy('date', 'desc');
$index = $articles->indexOf($page);
$last = $articles->count() - 1;
$prev = $index > 0 ? $articles->nth($index - 1) : null;
$next = $index < $last ? $articles->nth($index + 1) : null;
?>

<?php if ($prev): ?>
  <a href="<?= $prev->url() ?>"><?= $prev->title() ?></a>
<?php endif ?>
<?php if ($next): ?>
  <a href="<?= $next->url() ?>"><?= $next->title() ?></a>
<?php endif ?>
3 Likes

Great, thanks so much @fvsch ! That did the job. Only a little typo here:

$next = $index < $last ? : $articles->nth($index + 1) : null;

The first colon must be deleted.