Sort by a tag from a tags field

I have a status “tags field” which has some statuses such as “new” or “best seller” in it.

I would like to sort pages based on a value in this field. E.g. show all pages sorted with the “new” first. How can I accomplish this?

Thanks!

Since sort() only allows you to sort by a particular field, which does not make sense for the tags field, I’d use group() with a callback. Here is an example:

<?php
$callback = function($p) {
  $tags = $p->tags()->split(',');
  if(in_array('new', $tags)) {
    return 'new';
  }
  return 'not new';
  };

$articles = $page->children()->visible()->group($callback);

foreach($articles as $tagName => $articles) {
  if($tagName === 'new') {
    foreach($articles as $article) {
      echo $article->title() . '<br>';
    }
  }
}
?>

Thanks for your reply @texnixe.

I can now group them, but how can I print them in a list sorted by new first in the template?
As far as I understand it, you have now “filtered” them into 2 groups instead of “sorted” them by “new” first?

Well, yes, now there are two groups, of course you can output the second group as well and optionally sort them within each group (here by title), or optionally output the category name:

<?php
$callback = function($p) {
  $tags = $p->tags()->split(',');
  if(in_array('new', $tags)) {
    return 'new';
  }
  return 'not new';
  };
$articles = $page->children()->visible()->group($callback);

foreach($articles as $tagName => $articles) {
  if($tagName === 'new') {
    echo $tagName . '<br>';
    foreach($articles->sortBy('title') as $article) {
      echo $article->title() . '<br>';
    }
  } elseif($tagName === 'not new') {
    echo $tagName . '<br>';
      foreach($articles->sortBy('title') as $article) {
        echo $article->title() . '<br>';
      }
  }
}
?>

Of course, you can also build other groups, depending on what you need.

Another option would indeed by to filter your pages; have a first group filtered by tag “new”, and a second one filtered by “not new”, usingfilter($callback), but I think that doesn’t really make a difference and grouping() probably needs less code.

For reference; I did it like this in the controller.

I’m not sure if this is the best / fastest way, but it seems to do the trick for now. I’m all ears for improvements :slight_smile:

$newProds = new Pages();
$otherProds = new Pages();
$sortedProds = new Pages();

$callback = function($p) {
    $tags = $p->status()->split(',');
    if(in_array('New', $tags)) {
        return 'New';
    }
    return 'not New';
};

$articles = $page->children()->visible()->group($callback);

foreach($articles as $status => $articleList) {
    if ($status === "New") {
        $newProds->add($articleList);
    } elseif ($status === "not New") {
        $otherProds->add($articleList);
    }
}
// Add the "New" products first to a new sortedproducts collection
$sortedProds->add($newProds)->add($otherProds);

Thanks for the help @texnixe !