How to create custom sorting logic for Drupal views

May 16, 2024
default author headshot Ashraf Abed
Share this post:

Drupal websites sometimes have a need to implement more advanced sorting logic than what's available out of the box.

One of our career-changing Drupal training course alumni asked me how to handle this today. After answering them, I decided to copy the answer into a blogpost.

The views module creates dynamic queries for us based on the configuration options we select. The UI essentially allows us to use any field for sorting in ascending (smallest to largest) or descending (largest to smallest) order. This is extremely helpful and covers the vast majority of use cases - date sorting, alphabetical sorting, and numeric sorting are all supported - but we sometimes run into limitations when we have more complicated requirements.

Some examples of these scenarios include:

  • Sorting by field(s) which may sometimes be empty (or null)
  • More complex sorting logic

How to sort results in Drupal views

Before moving on to the more advanced scenarios, let's get the simplest out of the way: How do you sort results in a Drupal view?

Views admin UI. "Sort Criteria" section with "Add" button/link.
Click "Add" next to "Sort Criteria" to add an additional field for sorting the query (view) results.

The sort in the top of that list is the "primary" sort, the next sort is the "secondary" (think "tie-breaker") sort, and so on.

So, just add all the fields you want to sort by and call it a day! ...Right? Not always.

How to sort a view when a field is NULL?

Fields used for sorting can be in one of 3 states:

  • Populated with a value
  • Empty
  • NULL

Empty and NULL are similar but not identical. For example in PHP, a number that is "empty" is 0. A number that is NULL is... NULL. It doesn't just have an "empty" value, it has no value at all.

These 3 value possibilities need to be taken into account when using a field for sorting.

If you sort in ascending order, views will sometimes sort results in this order:

  1. NULL
  2. Empty
  3. Populated (in ascending order)

And that's rarely what you want.

This isn't really a problem caused by Drupal - it's the standard behavior for some database queries, and the views module is writing queries for you.

Normally, you would want an ascending sort to show results in the following order:

  1. Populated (in ascending order)
  2. Empty or NULL

One solution to this problem is to use the contrib module "views sort null field":

How to implement more complex sorting logic in views?

Let's say we have more complicated sorting logic, for example:

  1. Primary sort: field_published_date
  2. When field_published date is empty, use created date as the primary sort instead

This isn't quite the same as the out of the box behavior of "Primary sort Published Date, secondary sort created date". We are not sorting by published date first, and created date second (as the 'tiebreaker'); but rather we are using both fields as the 'primary' sort depending on field_published_date's value.

There are two different solutions to this issue:

  1. Alter the query using a hook
    • Pro: Potential to be more efficient (depending on how it's implemented)
    • Con: More advanced (requires proficiency in writing custom DB queries)
  2. Store the "sort" value in a dedicated field
    • Pro: Easier to debug
    • Pro: Easier to implement, especially for more complex logic
    • Con: Creates an additional DB table (or two)

We are going to walk through the second option - storing the "sort" value in a dedicated field.

How do I create a custom module to override Drupal views sorting?

This solution often surprises people in its (relative) simplicity. It's often much easier to store the sort value in a dedicated field than it is to alter the views' query directly.

At a high-level, here's how it's done:

  1. Create a sort field on your content type(s) (e.g. field_sort)
    • Typically either an integer or a date field, depending on what will be stored
  2. Hide the field from both the front end (via "Manage display") and the backend (via "Manage Form Display")
  3. Use the field (field_sort) as the primary sort in your view
  4. Create a custom module to populate the sort field (as described below)

For this example, we will make the following assumptions:

  • You named your "sort value" field field_sort
  • You want to use field_published_date as the source for the 'primary' sort value
  • When field_published_date is empty, you want to use the value from the "created" field instead
  • field_published_date, field_sort, and created fields are all stored in the database using the same format (a timestamp)
    • If this isn't the case, you would need to normalize the values (convert to the same type) before storing them

Next up, it's time to create a custom module to auto-populate the sort field! For this example, we'll name the module debug_academy_custom_sort

  1. At a minimum, custom modules consists of:
    1. A folder: docroot/modules/custom/debug_academy_custom_sort/
    2. An info file: docroot/modules/custom/debug_academy_custom_sort/ containing e.g.:
      • name: Autopopulate Custom Sort
        type: module
        core_version_requirement: ^9 || ^10 || ^11
  2. In your custom module, create a MODULENAME.module file, e.g.:
    • docroot/modules/custom/debug_academy_custom_sort/debug_academy_custom_sort.module
  3. I'll assume your field's machine name is field_sort . Replace field_sort in the following code with your date field's machine name!
  4. Within debug_academy_custom_sort.module , write:

     * Implements hook_node_presave().
     * Auto-populate field_sort.
    function debug_academy_custom_sort_node_presave(\Drupal\Core\Entity\EntityInterface $entity) {
      // If node being saved has "field_sort" field.
      if ($entity instanceof \Drupal\Core\Entity\FieldableEntityInterface) {
        // Only autopopulate for nodes which have both field_sort and field_published_date fields.
        if ($entity->hasField('field_sort') && $entity->hasField('field_published_date')) {
          if ($entity->get('field_published_date')->isEmpty()) {
            // field_published_date is empty. Store the "created" date in the sort field.
            $entity->set('field_sort', $entity->get('created')->value);
          } else {
            // field_published_date is not empty. Store its value in the sort field.
            $entity->set('field_sort', $entity->get('field_published_date')->value);
  5. Save your files, enable the module (via Manage > Extend), and clear your site's cache.
  6. Because the code above only runs when a node is being saved, you will need to re-save your nodes once to populate field_sort. Going forward, field_sort will continue to be autopopulated.

That's it! You can use the same technique for more complicated sorting logic as well.

Become a skilled Web Developer with Tailored, Hands-On Training: Debug Academy

There's more to the picture and we would love to share it with you. If you’re serious about learning the skills required for web developer and want to speed up the process, you can trust Debug Academy. We’ll teach you the web developer required skills in a structured manner that helps you hit the ground running fast - and most importantly, with confidence!

Our approach blends structured learning with hands-on, real-world projects, guided by experienced professionals. Whether you're a beginner or looking to upgrade your skills, our comprehensive curriculum covers everything from fundamental coding principles to advanced web technologies. 

With personalized mentorship, collaborative projects, and a supportive community, Debug Academy is committed to transforming you into a proficient, job-ready web developer. 

Experience the most efficient and effective path to a successful career in web development with Debug Academy. We have free Drupal training to help you get a sense of what’s possible in this field along with a more advanced curriculum. Learn about our Drupal certification trainingDrupal migration services, and all the other Drupal courses we have to offer today!

Ready To Launch Your Career?

Take the first step to launching the career you've always wanted. Explore Debug Academy classes today!

Explore Classes Contact Us