I've reference this related thread but haven't found a working solution that supports pagination and will exclude entries that have multiple categories.

The code example will not include Category One, but when an entry has Category One and Category Two it will still display because Category Two is included in the cateogries array. Is there a way to still exclude the entry even if it's second category is included?

  {# Get all the categories you want to INCLUDE #}
  {% set categories = craft.categories({
      group: 'categories',
      slug: [
        'not category-one',
      limit: null,
    }).all() %}

  {# Get entries related to your desired categories #}
  {% set latestNews = craft.entries({
      section: 'news',
      relatedTo: categories,
      with: ([
        ['image', {
          withTransforms: ['medium']
      orderBy: 'postDate desc',
      limit: 4
    }).all() %}

1 Answer 1


Start by getting the category ID(s) you want to exclude:

{% set categoryIds = craft.categories()
    .ids() %}

Then get all the entry IDs that are related to them, which should be excluded:

{% set excludeIds = craft.entries()
        targetElement: categoryIds
    .ids() %}

Then run your main news query, excluding those entry IDs.

{% set latestNews = craft.entries()
        ['image', {
            withTransforms: ['medium']
    .orderBy('postDate desc')
    .all() %}
  • .id(['not']|merge(excludeIds)) It seems that it is only returning the entries that have category-one. I figured this would return the entries that didn't include category-one.
    – Michael
    Jan 10, 2019 at 20:06
  • @Michael it should give you all the news entries whose IDs are not in the excludeIds array. Support for 'not' as a first element in the id param array wasn’t added until Craft 3.0.21, so make sure you’re on at least that version. Jan 10, 2019 at 21:37
  • Do you have any insight on how the cache tag works with .id(['not']|merge(excludeIds))? I have a topic about it here
    – Michael
    Jan 12, 2019 at 4:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.