Back to top

Sort related content by Relevance (Drupal 8)

Related content sorted by Relevance

Many websites are tagging their content with more than one category term. Listing other content marked with the same term is a very common task in Drupal. But with a multi-valued field storing more than one Category on a single article things are a bit more complicated.

Complexity increases with the request to sort the list by relevance, showing the most relevant related content on top of the list (the articles that share more of the same tags).

This article lists the steps in Drupal 8 Views to create a list of related content titles sorted by the number of tags shared with the content currently viewed.

It's important to use the correct Contextual filtering strategy

The first thing to do when creating a list of relevant content is to create a block listing the desired content with contextual filters that restrict the results to nodes that are tagged with the same terms as the article that is currently being viewed.

No luck with Has taxonomy term ID

A very popular method of doing that is through Has taxonomy term ID contextual filter set to Provide default value of Taxonomy term ID from URL (with other options appropriately set as in this image).

The problem with this method, although it's working correctly to filter out relevant content (for both single-valued or multi-valued fields), is that I haven't been able to achieve the Sorting by relevancy with multi-valued fields. Perhaps someone can shed some light on this, whether and how it can be done.

But there is another method of filtering out only relevant content that is providing a good foundation to build Sorting by Relevancy on.

Introduce sibling nodes into View through Relationships

That other strategy relies on Relationships to introduce sibling nodes, and ID as contextual filters. That strategy is usually necessary to show sibling content when dealing with Entity references in general (as opposed to Taxonomy references that have some special filters that aren't there for all Entity references).

How to use Views Aggregation to sort related content by relevance in #Drupal8Tweet this

Once we have the list correctly filtering the relevant articles according to tags assigned to them, we can use Aggregation that is built into Views to count how many terms are shared between two articles, and use that count as the Sort criteria to show the most relevant articles at the top of the list.

List nodes tagged with the same Taxonomy terms through a multi-valued field

  1. Create a View of type Content, Filter it as usual to Content types, the taxonomy field Not empty (Is not empty (NOT NULL)) etc.
  2. Show fields Title and the field containing your terms (field_yourtags), show Multiple values in the same row although that won't matter later with Aggregation on, format as Table for readability, you can change it later.
  3. Add another field containing your terms (the same one as in the previous step field_yourtags), change the label to Nr. of shared Categories and also set it to Display all values in the same row under Multiple field settings.
    The first Categories field will be used to display tags of the related node, and the second one to count how many of them are shares with the node that is currently being viewed. These fields will have to configured further in future steps.

    Fields Title and Categories Twice

  4. Add a Relationship (search for your field name) Taxonomy term referenced from field_yourtags.

  5. Add another Relationship Content using field_yourtags,
    it will be set by default to use the Relationship from the previous step
  6. Add a Contextual filter ID (from Content Category) and set it to use the second Relationship (the one from the previous step, it will actually be the only choice next to "Do not use a Relationship") with other options:
    When the filter value is NOT available:
    Provide default value
    Content ID from URL
    When the filter value IS available or a default is provided
    Specify validation criteria (optional)
    Content
    [your appropriate types]
  7. Add another Contextual filter ID but this time Do not use a Relationship:
    When the filter value is NOT available:
    Provide default value
    Content ID from URL
    More: Exclude

    This second Contextual filter will exclude the node currently being viewed from the list.

    Taxonomy Relationships and Node Contextual filters

    To check the output in Views Preview at this point enter the same node ID both times, for example, to see what the block would output on node 24 enter 24/24:

    Views Preview with multiple Contextual filters

    Don't worry about the multiplicates in the results, we'll turn them to the best use with Aggregation ;) Notice they are listed the exact number of times that the tags match between them and the current node!

    Aggregate results according to common terms count

  8. Turn Aggregation on (Use aggregation option in the third column set to Aggregate), don't worry if you see a red message in Preview. All Fields and Filters now have Aggregation settings. Now is the time to change the settings on the two Categories fields:
  9. Click on Aggregation settings for the first "Content: Yourtags" field, keep the Group results together for the Aggregation type and change the Group column to Entity ID. This is important for keeping the multiple values of the Categories field to all show together on their node row, instead of causing the node to be listed multiple times, once for each Category it's tagged with.

    Aggregation settings for the first Categories field

  10. Click on Aggregation settings for the second "Content: Yourtags" field and change the Aggregation type to Count DISTINCT. Notice how that field is now showing numbers indicating how many common terms those nodes have with the current node!

  11. Now we just have to sort the View using this data: Add Sort criteria:
    Content: Yourtags
    Aggregation settings: Count DISTINCT
    Do not use a Relationship
    Sort descending

We now have the complete solution in our hands that is showing the related nodes sorted by how many tags they have in common with the node currently being viewed, we have the tags showing and the numbers used for sorting just so we can check that everything is working correctly.

Now Place your block in a Region and visit some nodes to check the block results, see if the count is correct. The nodes listed in the block will be sorted by the number of terms they share with the currently viewed content.

Related content sorted by the number of common taxonomy terms

An additional perk of this approach is that it won't list anything if the current node isn't tagged with any terms, while with the "Has taxonomy term ID" method you'd get all the results.

Cosmetic adjustments—Production sites

The two Categories fields we've added can be removed if you so wish, they aren't necessary for the filtering and sorting to work.

Or you may want to keep the tags listed. You can change the Views Format to Unformatted list and apply some other cosmetics:

Related content sorted by the number of common taxonomy terms

Or you may keep the Table Format (if for example you need to show some other information in addition to the Title and tags) and still make the tags appear below the Title. To do that you need to move the Categories field above the Title field (use the "Rearrange" from the drop-down next to the Fields heading), hide that field by ticking "Exclude from display", and "Rewrite results" of the Title field to output both:

Rewrite results of a field to output more fields

Conclusion—Views Aggregation FTW

How to use Views Aggregation to sort related content by relevance in #Drupal8Tweet this

When you need to sort a View list by some count, first create a list with the value to be counted available, then use Views Aggregation to turn that data into a number and use it a Sorting filter.

This is only one example of many about how to use Views Aggregation to manipulate your content and data in Drupal.

Need any help with this? Or with any other Drupal problem? Contact me for a friendly chat, share about your project and see how I can help you solve any issues you might have.