skip to Main Content

have a "courses" collection that contains two taxonomies: "courses_levels" and "courses_categories". Currently, I use the following loop to iterate over all courses by level. However, I would now like to apply a filter based on the second taxonomy "courses_categories".

{{ taxonomy:courses_levels }}
    {{ entries query_scope="filter_by_categories_and_levels" }}
        {{ partial:courses.preview }}
    {{ /entries }}
{{ /taxonomy:courses_levels }}

Honestly, I have no idea how to do this. I was thinking of using a query_scope, provided I could retrieve the URL parameters. I have already set up a form that generates a URL that looks like this: http://url.test/formations/niveaux-et-categories?animalieres=1&artisanat=1.

How can I filter the entries using the second taxonomy?

Note: I am not looking for a JavaScript solution at this stage. I am working on my fallback solution without JS.

<?php

namespace AppScopes;

use StatamicQueryScopesScope;

class FilterByCategoriesAndLevels extends Scope
{
    /**
     * Apply the scope.
     *
     * @param StatamicQueryBuilder $query
     * @param array $values
     * @return void
     */
    public function apply($query, $values)
    {
       // HELP NEEDED HERE
    }
}

2

Answers


  1. Create a single query scope for both levels and categories may not be a good idea. Also, global scopes, like that FilterByCategoriesAndLevels class that you proposed, do not accept parameters.

    I would create two local scopes in the Course class for each of those relationships.

    class Course extends Model
    {
        public function level()
        {
            return $this->belongsTo(Level::class);
        }
    
        public function categories()
        {
            return $this->belongsToMany(Level::class);
        }
    
        public function scopeAtLevel($query, $levelId)
        {
            return $query->whereRelation('level', 'id', $levelId);
        }
    
        public function scopeHavingCategory($query, $categoryId)
        {
            return $query->whereRelation('categories', 'id', $categoryId);
        }
    }
    

    Then you can retrieve the results by doing:

    Course::atLevel(request('level_id'))
        ->havingCategory(request('category_id'))
        ->get();
    

    I hope I understand you correctly. Pls clarify if it is not.

    Login or Signup to reply.
  2. Statamic comes with a query builder, which you can utilize for this.

    Now I do recommend you cache the result, cause (for our use-case at least, not sure how much content you have) it was quite slow.

    For this, you would need to get all entries from X collection, and then filter on the appropriate taxonomy.

    We have one setup for products, which looks as follows. (Keep in mind we have a lot of enums and stuff setup)

    return Cache::remember(
        "products:{$contentType->value}:{$locale->value}",
        config('custom.caching.ttl'),
        function () use ($contentType, $locale) {
            /** @var EntryQueryBuilder $qb */
            $qb = EntryFacade::query();
    
            $qb
                ->where('collection', Collection::PRODUCTS->value)
                ->where('published', true)
                ->where('status', 'published')
                ->where('locale', $locale->value);
    
            if ($contentType === 'somevalue') {
                $qb
                    ->whereJsonContains('tags', 'tags::sale')
                    ->orWhereJsonContains('tags', 'tags::reduced');
            } else {
                $qb
                    ->whereJsonDoesntContain('tags', 'tags::sale')
                    ->whereJsonDoesntContain('tags', 'tags::reduced');
            }
    
            return $qb->get()->sortBy('order');
        }
    );
    

    If we apply that to your setup, it could look something like below. Where you use a whereJsonContains to check if something is present in the JSON, of course below will not be a working example of how to fix your problem, but it should be a nudge in the right direction.

    Of course, dd’ing to see what data you are working with will be a great help to solve this problem 🙂

    $qb = EntryFacade::query();
    
    $qb
        ->where('collection', 'courses')
        ->where('published', true)
        ->where('status', 'published')
        ->where('locale', $locale->value)
        ->whereJsonContains('courses_categories', 'courses_categories::category_name');
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search