Group by date and sort by clicks

Hey Guys,

I have a blog with articles sorted by date (today, this week, this month and all). All articles have a clicks field.
Is there a way to sort all articles by clicks and by date? I was thinking on grouping the articles by date and sort them by clicks after? But I can’t get that to work.

Hope someone can help me with this?

Thanks,
— Giel

Yes, you can pass more than one option to the sortBy() method, see the docs: https://getkirby.com/docs/cheatsheet/pages/sort-by

Edit; oh, sorry, you wanted to group them with the groupBy() method? Then you should be able to string together the groupBy() and sortBy() methods. How do you group them? Simply by date?

Well, now I do something like this (see code below) to group articles in the right date range. But inside the date range I want to sort by clicks.

`// Variables
$parent = page("blog");
$children = $parent->children();
$blog = $children->visible()->sortBy('date', 'desc');

// Paginate
$blog = $blog->paginate(10);
$pagination = $blog->pagination();

// Arrays
$today = array();
$week = array();
$month = array();
$others = array();

// Push arrays with data per date
foreach ($blog as $article) {

    // today
    if (date('Y-m-d') == date('Y-m-d', $article->date())) {
        $today[] = $article;
        continue;
    }

    // week
    else if( $article->date() > strtotime('-7 day') ) {
        $week[] = $article;
        continue;
    }

    // month
    else if ( $article->date() > strtotime('-1 month') ) {
        $month[] = $article;
        continue;
    }

    // everything else
    else {
        $others[] = $article;
        continue;
    }

}

`

If you want to first group and then sort them (inside the group), you can sort them in your output loop:

<?php foreach($page->children()->groupBy('date') as $date => $items): ?>
  <h2><?php echo $date ?></h2>
  
  <?php foreach($items->sortBy('clicks', 'desc') as $item): ?>
    ...
  <?php endforeach ?>
<?php endforeach ?>

You can sort your individual collections after creating them:

$today->sortBy('clicks', 'desc');
etc.

@lukasbestle: But how can I group them by: today, this week, this month and others?

@texnixe: When I do that I get this error:
Fatal error: Call to a member function sortBy() on array ...

Oops, of course; you would need collections to use the sortBy() option. So $today etc. need to be collections instead of arrays. You can use the append() method to add an item to a collection: https://getkirby.com/docs/cheatsheet/pages/append

Sorry, I didn’t see your other post while writing mine.

Kirby 2.3 will support grouping by callback, which allows for something like this (if you use the Kirby 2.3 beta):

$groups = $page->children()->visible()->group(function($article) {
  if($article->date('Y-m-d') == date('Y-m-d')) return 'today';
  if($article->date() > strtotime('-7 day'))   return 'this week';
  if($article->date() > strtotime('-1 month')) return 'this month';
  return 'older articles';
});

<?php foreach($groups as $description => $items): ?>
  <h2><?php echo $description ?></h2>
  
  <?php foreach($items->sortBy('clicks', 'desc') as $item): ?>
    ...
  <?php endforeach ?>
<?php endforeach ?>

You can change the return values to whatever you need. They will become the descriptions of the groups.

1 Like

@lukasbestle: I think this is what I was looking for. Thank you! :grin:
So one more thing: how does pagination work with these groups?

Hm…
Paginating before grouping doesn’t really make much sense because it will be quite random. So you might need to paginate inside the groups, but that means that there are 4 paginations on the page.

What kind of pagination did you have planned?

Hmm… well maybe 4 paginations isn’t that bad. Then I can do it like Product Hunt does showing “more posts” per group right?

But how does pagination inside a group work?

Edit, I have something like this:

<?php foreach($groups as $description => $items): ?
    <?php
        $items = $items->paginate(10);
        $pagination = $items->pagination();
    ?>
    <div class="section <?php echo $description ?>">
        <div class="title">
            <span class="line"></span>
            <h2><?php echo $description ?></h2>
        </div>
        <?php foreach($items->sortBy('clicks', 'desc') as $item): ?>
            <?php snippet("bookmark", array("bookmark" => $item)); ?>
        <?php endforeach ?>
    </div>
    <?php if($pagination->hasNextPage()): ?>
        <a class="next" href="<?php echo $pagination->nextPageUrl() ?>">load more posts</a>
    <?php endif ?>
<?php endforeach ?>

but nextPageUrl() is not going to show the next articles inside the group.

If you have more than one pagination on a page, you need different param names for them:

$items = $items->paginate(10, array('variable' => str::slug($description)));

This is perfect. Thank you!! :grinning:

1 Like

Hi @lukasbestle,

So I thought everything worked perfect but it doesn’t because all the articles are stored by clicks per page. If I click on the next page (2) inside a group (this month for example) the first article can have more clicks than the last article on page 1. Is there anything I can do about that?

Thanks again.

Then you should first sort and then paginate:

<?php foreach($groups as $description => $items): ?
    <?php
        $items = $items->sortBy('clicks', 'desc')->paginate(10, array('variable' => str::slug($description)));
        $pagination = $items->pagination();
    ?>
    <div class="section <?php echo $description ?>">
        <div class="title">
            <span class="line"></span>
            <h2><?php echo $description ?></h2>
        </div>
        <?php foreach($items as $item): ?>
            <?php snippet("bookmark", array("bookmark" => $item)); ?>
        <?php endforeach ?>
    </div>
    <?php if($pagination->hasNextPage()): ?>
        <a class="next" href="<?php echo $pagination->nextPageUrl() ?>">load more posts</a>
    <?php endif ?>
<?php endforeach ?>
1 Like