Sorting buttons on home page. (alphabetically, recently added)


I’m pretty new to PHP and Kirby - so I appreciate any time taken to answer a rather simple question :slight_smile:
I am looking for a solution on how I could implement 2 buttons on my homepage that allow the user to sort the project list alphabetically or by most recently added. I looked at the docs for sorting and grouping but it doesn’t seem to be talking about a user interaction - just pre-sorting the data. I am not looking to change the order of projects on load – I just want to allowthe user to sort the projects if they wish to.

Extra points for an async solution, but I’m grateful for any guidance :slight_smile:


There are two options:

Your buttons could be plain links, then filtering would work via the URL, similar to filtering by tags.

Or your buttons could trigger an AJAX request, that triggers a filter action on the server.

Or you go for a pure JavaScript solution, where the projects are only filtered on the frontend without a request to the server.

So it really depends on what you want to do here.

Ideally I would want the URL to remain the same regardless of the filtered choice, so I think I’m looking to implement the AJAX filtering action. A pure JS option is fine too.

If you want to go with the AJAX solution, the Ajax load more recipe could be a starting point. The principle is always the same, but of course, instead of sending a limit and an offset for loading more content, you would send a filter value. Then on the server (in your controller) you check the value and apply it to the filter (see the Filtering Compendium).

So the general outline would be like this:

  • in your controller define the default project collection
  • then set up a check if the call is an AJAX call
  • if yes, apply the sorting

In your JS

  • implement a click handler
  • send the value to the server
  • get response from server and inject it in the DOM

Might be a bit in over my head - what do you recommend for a pure JS version?

I linked to a pure JS sorting/filtering option above, another option would be Isotope. Shuffle.js is another one. This last one comes with an example of sorting by date and title.

What you have to do in your HTML is add the data attributes, e.g. data-title and data-created, then you can sort by these criteria.

Firstly, thank you for your guidance.

I have gotten the load more cookbook example working as a starting point. However, the new projects that load do not add to the current showcase layout – they start a new row separate from the showcase.

Before I ask any more questions about the filtering options – how can I make it so the newly loaded projects are are added within the current showcase layout?

see the issue here when clicking load more:

That is because you use a div wrapper inside your ul that shouldn’t be there in the first place. Your wrapper should be outside of the ul, otherwise you end up with invalid HTML anyway. And because you add the new elements to the ul, that’s what you get.

Thank you, I have corrected this.

I’m still unable to get the images to take up the full space of the element - in the showcase it would crop the image to the full width of the project element, and now it seems like its cropping the thumbnail differently, even though the newly loaded images have the same class as the showcase images.

Have a look in your dev tools. Your markup looks like this:

<div class="wrap wide">

    <ul class="projects showcase grid gutter-1" data-page="" data-limit="30">
      <!-- Loop through the projects -->
       <div class=""> <!-- this div here should be removed, together with its closing counterpart -->
          <li class="showcase-item column">
              <a href="" class="showcase-link">
                                  <img height="395" src="" alt="Thumbnail for Bitcoin (BTC)" class="showcase-image">
                                <div class="showcase-caption">
                  <h3 class="showcase-title">Bitcoin (BTC)</h3>

        <!--  more li -->
       </div><!-- end of div -->

<!-- new li set -->

<li class="project showcase-item column">
  <a href="" class="showcase-link">
    <!-- We want to get the first image of each project. We first check if it exists! -->
        <img src="" alt="" class="showcase-image">
        <div class="showcase-caption">
      <h2 class="showcase-title">Binance Coin (BNB)</h2>

  <!--  more li -->
  </div><!-- end of wrap wide-->

An ul element should only have li elements as direct children!

thanks - now thats fixed and the only direct children of the ul are li elements. unfortunately, the images are still showing differently than the pre-populated list.

there is no difference (that I can find) between the li elements and their children, other than the new li elements have the class “project” which has no styling attributed to it. the img elements both have the class ‘showcase-image’.

Not sure what I’m missing here.

The first set of li elements has image thumbs with a size of 600x600, the second set doesn’t.

Please use your dev tools to debug such things, you have to look at the inner elements as well. After all, this is first and foremost a Kirby support forum and we can’t possibly do this sort of HTML debugging for you…

Of course, and I appreciate your time. I’ve done everything you’ve reccommened so far. The error was a php variable error, i was using the $image var rather than the $thumb var.

My original goal was not to load more items, just to re-arrange the items already loaded based on the sorting option.

How can change the load-more functionality to say, a “sort by recently added” or another custom attribute?

You will have to make changes in the controller, the json template and in your JavaScript; you don’t need offset and limit variables here but something that indicates what you want to sort by. Then you need two buttons and their click handlers. It can of course be done, but if you are not so experienced, it might be a bit too much.

For example, the controller would probably look something like this:

return function($site, $pages, $page) {

  $projects = $page->children()->visible();

  // check if the request is an Ajax request 
  //  we could as an example, use a "type" variable with a value of either sorted or unsorted
  // if the value is sorted, we sort, otherwise we return the original collection
  if(r::ajax() && get('type') && get('type')) {

    // convert limit and offset values to integer
    $type = get('type');
    if($type == 'sorted'){
      // limit projects using offset and limit values
      $projects = $projects->sortBy('title', 'asc');
    } else {
      $projects = $projects;

  return compact('projects');


The json template would just return the projects:


$html = '';

foreach($projects as $project) {

  // reuse the project snippet to create the HTML for each project
  // we need to set the third parameter to true, to return the
  // snippet content instead of echoing it
  $html .= snippet('project', compact('project'), true);


// add $html and $more to the $data array
$data = $html;

// JSON encode the $data array
echo json_encode($data);

Then you need the script.

I think, for simple sorting purposes, client side sorting is the better option. The elements are all in the DOM anyway, all you have to do is sort them. This is both faster, because you don’t need the server to provide the logic. And it saves you all the coding.