nacha's avatar
Level 2

how to make checkbox work for product filters?

I want when check one or multiple category,brand,size,color,... with checkbox display the products related to the categories(product filters) (for exemple check dress and basket display products of dress and basket) and also for brand,size,... I mean: On the category page, you can load the product attributes such as color or size and make a filtering section

how to change this code to display products? thank you

category.blade.php:

                              <h6 class="title">By Category </h6>
                            </a>
                        </header>
                        <div class="filter-content collapse show" id="collapse44">
                            <div class="card-body">
                                <form>
                                <form method="get" action="{{ route('category.show', $category->slug) }}"> 
                                
                @foreach ($categories as $category)
                
                                    <label class="form-check">
                                    <input class="form-check-input" name="category[]" value="{{ $category->slug }}" type="checkbox">
                                    
                                        <span class="form-check-label">
                    <span class="float-right badge badge-light round"></span> {{ $category->name }}
                                        </span>
                                    </label>
                                    
                                    
                                    
            
                                    
            @endforeach 
            <button type="submit">apply filter</button>
                                    </form>
                                    

By Brand

 <div class="filter-content collapse show" id="collapse45">
                    @foreach($brands as $brand)
                        <div class="card-body">
                        
                            <form>
                            
                                <label for="brand_id" class="form-check">
                                
                                    <input class="form-check-input" id="brand_id" value="{{$brand->id}}" type="checkbox">
                                    <span class="form-check-label">
                                  {{ $brand->name }}
                                    </span>
             by brand
                         <h6 class="title">By Brand </h6>
                     </a>
                 </header>
                 <form method="get" action="{{ route('category.show', $category->slug) }}"> 
                 <div class="filter-content collapse show" id="collapse48">
             
                                     <select name="brand_id" id="brand_id" class="form-control @error('brand_id') is-invalid @enderror">
                                         <option value="0">Select a brand</option>
                                         @foreach($brands as $brand)
                                             <option @if(request()->brand) selected @endif value="{{$brand->id}}">{{ $brand->name }}</option>
                                         @endforeach
                                     </select>
                                     </div>
                
                                     <button type="submit">apply filter</button>

by size

    <div class="filter-content collapse show" id="collapse46">
                        <div class="card-body">
                        @foreach($products as $product)
                          @foreach($product->attributes as $attributeValue)
                          @if ($attributeValue->attribute_id == 1)
                            <form>
                                <label for="size" class="form-check">
                                    <input class="form-check-input" id="attribute" value="{{$attributeValue->value}}" type="checkbox">
                                    <span class="form-check-label">
                                  {{ $attributeValue->value }}
                                  
                                    </span>

by color

      <h6 class="title">By color </h6>
                          </a>
                      </header>
                     
                      
                      <div class="filter-content collapse show" id="collapse47">
                          <div class="card-body">
                          @foreach($products as $product)
                          @foreach($product->attributes as $attribute)
                          @foreach($product->attributes as $attributeValue)
                         
                          @if ($attribute->id == 2)
                              <form>
                                  <label for="color" class="form-check">
                                      <input class="form-check-input" id="{{$attributeValue->id}}" value="{{$attributeValue->value}}" type="checkbox">
                                      <span class="form-check-label">
                                    {{ $attributeValue->value}}
                                    
                                      </span>

category controller:

<?php

namespace App\Http\Controllers\Site;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Contracts\CategoryContract;
use App\Models\Product;
use App\Models\Category;
use App\Models\Brand;

class CategoryController extends Controller
{
    protected $categoryRepository;

    public function __construct(CategoryContract $categoryRepository)
    {
        $this->categoryRepository = $categoryRepository;
    }
public function show($slug)
    {
        $category = $this->categoryRepository->findBySlug($slug);
        $pagination = 2;
        
        
       
        if (request()->category) { 
            $products = Product::with('categories')->whereHas('categories', function ($query) {
                $query->whereIn('id', request('category'));
             });
            };
            
     
        if (request()->brand) {
            $products = Product::when($brand, function ($query, $brand) {
                return $query->where('brand_id', $brand);
            });
           
            
            };
      
      
                if (request()->size) {
                    $products = ProductAttribute::where('id','=',1)->where('id', request('size'))->OrderBy('id', 'desc')->paginate($pagination);
                    
                    };
                    if (request()->color) {
                        $products = ProductAttribute::where('id','=',2)->where('id', request('color'))->OrderBy('id', 'desc')->paginate($pagination);
                        
                        };
        if (request()->sort == 'low_high') {
            $products = Product::orderBy('price')->paginate($pagination);
        } elseif (request()->sort == 'high_low') {
            $products = Product::orderBy('price', 'desc')->paginate($pagination);
        } 
           
        
        
   
    
       
        return view('site.pages.category', compact('category'));
    }
}

0 likes
18 replies
automica's avatar

@nacha should this bit

  @foreach($products as $product)
                          @foreach($product->attributes as $attribute)
                          @foreach($product->attributes as $attributeValue)
                         

actually be?

  @foreach($products as $product)
                          @foreach($product->attributes as $attribute)
                          @foreach($attribute as $attributeValue)
                         
nacha's avatar
Level 2

thank you @automica but the problem is with checkbox when I click for exemple color:red nothing change still the same page and the same products so I want when check for exemple brand:zara and color:red with checkbox display all products related to zara and red how to do it thank you

automica's avatar

@nacha so when you check the checkbox, you then save and the result isn't being filtered?

btw

no need to do:

where('id','=',2)

you don't need the equals, if the comparison is =

eg

where('id',2)

also, for your filters, it would be cleaner (and more Laravel) to make them as queryScopes

see

https://laravel.com/docs/7.x/eloquent#query-scopes

nacha's avatar
Level 2

thank you @automica very much but when I choose robe(category) display products of robe that's okay and in category page I have the filter section so when I choose sandal with checkbox and click apply filter return the same page with the products of robe and not for sandal and the link like this

http://localhost/site/public/category/robe?category%5B%5D=sandal

how to fix that thank you

automica's avatar

@nacha when you pass a filter in your request, you are filling an $products variable with an array.

What you aren’t doing is pass it into the blade, so that’s why you aren’t seeing any changes when you apply a filter.

If you append this

Eg

return view('site.pages.category', compact('category‘,‘products'));

You’ll then be able to access it’s values.

nacha's avatar
Level 2

thank you @automica very much I made some changes but nothing change still the same problem so if you suggest any change or give me an exemple to change some code (sorry sorry but I'm beginner and try to improve my self) maybe you find a fault and you know how to change the code and thank you very much

automica's avatar

@nacha if you can post your updated controller method, I’ll give it another look for you.

nacha's avatar
Level 2

thank you @automica I tried this

  if (request()->category) {
            $products = Product::where('slug', request('category'))->OrderBy('id', 'desc');
                    
        };
      $products = Product::orderBy('id', 'desc')->paginate(10);
        return view('site.pages.category', compact('category','products'));
    }

and this

 if (request()->category) {
            $products = Product::with('categories')->whereHas('categories', function ($query) {
                $query->where('slug', request()->category);
            });

nothing change

automica's avatar

@nacha can you show the bit in your blade file that uses the $products array?

automica's avatar

@nacha in here:

  if (request()->category) {
            $products = Product::where('slug', request('category'))->OrderBy('id', 'desc');
                    
        };
      $products = Product::orderBy('id', 'desc')->paginate(10);
        return view('site.pages.category', compact('category','products'));
    }

you are immediately overwriting $products with

   $products = Product::orderBy('id', 'desc')->paginate(10);

I would suspect you want to do the following:

$products = Product::all();

if (request('category')) {
    $products = $products->where('slug', request('category'));
};
$products = $products->orderBy('id', 'desc')->paginate(10);

return view('site.pages.category', compact('category', 'products'));
}

That will get all products, then apply the filter if request('category');

The above bit doesn't make sense, surely this should be where the products category slug = request('category'), not the products slug.

and then orderBy and paginate.

I think you need to stop for a moment and describe what you are trying to do.

your route suggests you are already in a category page.

From what I gather, you have a list of products for a given category, and you wish to filter them by either:

  • category
  • brand
  • size
  • color

You then appear to be passing in a category in your request, but are also passing in a slug to set the category.

Are you then looking at filtering the products in the slugs category by another category?

nacha's avatar
Level 2

thank you @automica I did it like this

    @foreach($products as $product)              
                @foreach ($product->categories as $category)
                @foreach ($category->products as $category)

I just try it and nothing change

automica's avatar

@nacha this doesn't make any sense, and isn't what I wrote further comments back.

@foreach($products as $product)              
                @foreach ($product->categories as $category)
                @foreach ($category->products as $category)

are you wanting to get all the categories a product is in and then list all the products for those categories?

if so should be

@foreach($products as $product)              
        @foreach ($product->categories as $category)
                @foreach ($category->products as $product)
{{$product->title}}
		@endforeach;
	@endforeach;
@endforeach;
nacha's avatar
Level 2

thank you @automica but it give me this error

BadMethodCallException
Method Illuminate\Database\Eloquent\Collection::orderBy does not exist.

but when I change this

$products = $products->orderBy('id', 'desc')->paginate(10);

to this

$products = Product::orderBy('id', 'desc')->paginate(10);

there's no error and nothing change I did

  <form method="get" action="{{ route('category.show', $category->slug) }}"> 
                                
                @foreach ($categories as $category)
                
                                    <label class="form-check">
                                    <input class="form-check-input" name="category[]" value="{{ $category->slug }}" type="checkbox">
                                    
                                        <span class="form-check-label">
                    <span class="float-right badge badge-light round"></span> {{ $category->name }}
                                        </span>
                                    </label>
                                    
                                    
                                    
            
                                    
            @endforeach 
            <button type="submit">apply filter</button>

and this code to display products by category and the categories in navbar

  @forelse($category->products as $product)
                    <div class="col-md-3">
                        <figure class="card card-product">
                            @if ($product->images->count() > 0)
                                <div class="img-wrap padding-y"><img src="{{ asset('storage/'.$product->images->first()->full) }}" alt=""></div>
                            @else
                                <div class="img-wrap padding-y"><img src="https://via.placeholder.com/176" alt=""></div>
                            @endif
                            <figcaption class="info-wrap">
                                <h4 class="title"><a href="{{ route('product.show', $product->slug) }}">{{ $product->name }}</a></h4>
                            </figcaption>
                            <div class="bottom-wrap">
                                <a href="{{ route('product.show', $product->slug) }}" class="btn btn-sm btn-success float-right">View Details</a>
                                @if ($product->sale_price != 0)
                                    <div class="price-wrap h5">
                                        <span class="price"> {{ config('settings.currency_symbol').$product->sale_price }} </span>
                                        <del class="price-old"> {{ config('settings.currency_symbol').$product->price }}</del>
                                    </div>
                                @else
                                    <div class="price-wrap h5">
                                        <span class="price"> {{ config('settings.currency_symbol').$product->price }} </span>
                                    </div>
                                @endif
                            </div>
                        </figure>
                    </div>
                  
                @empty
                    <p>No Products found in {{ $category->name }}.</p>
                    
                @endforelse
                
            </div>
automica's avatar

@nacha

Looking at your view, you aren't even using $products instead looking through $category->products.

are you using any of the other filters on this page still?

Can you scroll up to my long message and explain in words what you are trying to do. I'm sure there is a simple way to do this but if we keep exchanging code this way its making it really complicated.

nacha's avatar
Level 2

thank you @automica ok I will explain with image

when I make a filter section just "by category" and click the link of robe in 'by category' the products of robe display and there's no problem like this

https://i.imgur.com/7yH6ARy.png

and this is the code in category.blade.php:

<h3>By Category</h3>
            <ul>
                @foreach ($categories as $category)
               @if ($category->id!=1)
                    <li class=""><a href="{{ route('category.show', $category->slug) }}">{{ $category->name }}</a></li>
                @endif
                @endforeach
            </ul>

and in header there's the search bar , it works :

if i write bask in search bar it display all products in their name bask like bask, basket like this search: https://i.imgur.com/YmP1lXW.png

result: https://i.imgur.com/mWVA24H.png

and if write x: https://i.imgur.com/f0qI4yK.png result : search failed please try again with all products https://i.imgur.com/RG70Coa.png

and I made a filter section by price low_high high_low: productcontroller:

     if (request()->sort == 'low_high') {
            $products = Product::where('status', '1')->orderBy('price')->paginate($pagination);
        } elseif (request()->sort == 'high_low') {
            $products = Product::where('status', '1')->orderBy('price', 'desc')->paginate($pagination);
        } else {
           
       
       
       $products = Product::where('status', '1')->OrderBy('name', 'asc')->paginate($pagination);
    }
        return view('site.pages.products', compact('products','categories' ));
       
}

products.blade.php:

   <div>
                    <strong>Price: </strong>
                    <a href="{{ route('products.index', [ 'sort' => 'low_high']) }}">Low to High</a> |
                    <a href="{{ route('products.index', [ 'sort' => 'high_low']) }}">High to Low</a>

                </div>

image:high_low: https://i.imgur.com/b2F49BK.png image :low_high: https://i.imgur.com/Z0cYgjt.png

and this is code: header.blade.php:

<div class="col-lg-6 col-sm-6">
                    <form action="{{ url('products') }}" class="search-wrap" method="post" >
                    @csrf
                        <div class="input-group">
                            <input type="text" name="q" id="q" class="form-control" placeholder="Search">
                            <div class="input-group-append">
                                <button class="btn btn-primary" type="submit">
                                    <i class="fa fa-search"></i>
                                </button>
                            </div>
                        </div>
                    </form>
                </div>

products.blade.php:

@extends('site.app')
@section('title', 'products')
@section('content')
<section class="section-content bg padding-y">
    <div class="container">
    <div class="row">
    <aside class="col-sm-3">
    <div class="card card-filter">
   
                    
                    <div class="container">
        @if (session()->has('success_message'))
            <div class="alert alert-success">
                {{ session()->get('success_message') }}
            </div>
        @endif

        @if(count($errors) > 0)
            <div class="alert alert-danger">
                <ul>
                    @foreach ($errors->all() as $error)
                        <li>{{ $error }}</li>
                    @endforeach
                </ul>
            </div>
        @endif
    </div>
   
        <div>
            <div class="products-header">
                <h1 class="stylish-heading"></h1>
                <div>
                    <strong>Price: </strong>
                    <a href="{{ route('products.index', [ 'sort' => 'low_high']) }}">Low to High</a> |
                    <a href="{{ route('products.index', [ 'sort' => 'high_low']) }}">High to Low</a>

                </div>
            </div>
                    <!-- card-group-item.// -->
                  
                  
                </div>
                <!-- card.// -->
                
            </aside>
                    
                    <main class="col-sm-9">
        <div id="code_prod_complex">
        @if( session('status'))
                        <div class="alert alert-info">
                            {{ session('status')}}
                        </div>
                    @endif
                    <div class="container">
            <div class="row">
            
           
            @forelse($products as $product)
                    <div class="col-md-3">
                    <figure class="card card-product">
                            @if ($product->images->count() > 0)
                                <div class="img-wrap padding-y"><img src="{{ asset('storage/'.$product->images->first()->full) }}" alt=""></div>
                            @else
                                <div class="img-wrap padding-y"><img src="https://via.placeholder.com/176" alt=""></div>
                            @endif
                            <figcaption class="info-wrap">
                                <h4 class="title"><a href="{{ route('product.show', $product->slug) }}">{{ $product->name }}</a></h4>
                            </figcaption>
                           
                            <div class="bottom-wrap">
                                <a href="{{ route('product.show', $product->slug) }}" class="btn btn-sm btn-success float-right">View Details</a>
                               
                                
                                @if ($product->sale_price != 0)
                                    <div class="price-wrap h5">
                                        <span class="price"> {{ config('settings.currency_symbol').$product->sale_price }} </span>
                                        <del class="price-old"> {{ config('settings.currency_symbol').$product->price }}</del>
                                    </div>
                                @else
                                    <div class="price-wrap h5">
                                        <span class="price"> {{ config('settings.currency_symbol').$product->price }} </span>
                                    </div>
                                @endif
                  
                            </div>
                         
                        </figure>
                    </div>
                     
                        
                   
                    @empty
                    <p>No Products found </p>
                @endforelse
            </div>
            {{$products->links()}} 
        </div>
        </main>
        
    </div>
   
</section>
@stop

productcontroller:

public function search( Request $request) {
    $request->validate([
        'q' => 'required'
    ]);
    $q = $request->q;
   
    $products = Product::where('name', 'like', '%' . $q . '%')->where('status', '1')->paginate(15);
    if ($products->count()) {
        return view('site.pages.products')->with(
            'products' ,  $products
        );
    } else {
        
        return redirect('/products')->with(
            'status' , 'search failed ,, please try again'
  );
    }
    
}

route:

Route::view('/', 'site.pages.homepage');
Route::get('/category/{slug}', 'Site\CategoryController@show')->name('category.show');

Route::get('/product/{slug}', 'Site\ProductController@show')->name('product.show');
Route::get('/products', 'Site\ProductController@index')->name('products.index');
Route::post('/products', 'Site\ProductController@search')->name('products.search');

when I click men->basket in navbar it works and I made the filter section (by category,by brand,...) with checkbox and select (it doesn't work and this is the problem) and this is the image https://i.imgur.com/eoQsXzA.png

https://i.imgur.com/pyR2s13.png so what I have to do now I want to make this work and organize it step by step thank you very much

nacha's avatar
Level 2

thank you @automica

I tried some code but it's wrong and there's an error :

BadMethodCallException
Method Illuminate\Database\Eloquent\Collection::whereHas does not exist.

productcontroller

 public function index( Request $request)
    {   
       
      
        $categories = Category::all();

        
        $products = Product::all();
        
        
        

if (request('category')) {
 

        $products = $products->where('slug', request('category'))->whereHas('categories', 
		function($query) use ($categories) {
            		$query->where('category_id', $categories);
        	
        })->get();
    }

        $products=$products->where('status','1');
        
        return view('site.pages.products', compact('products','categories'));
       
}

products.blade.php

<p>Categories</p>
<form method="get" action="{{ route('products.index') }}"> 
@foreach ($categories as $category)
@if ($category->id!=1)
    <label>
        <input
            name="category" type="checkbox" value="{{ $category->id }}"
            @if (in_array($category->id, explode(',', request()->input('category'))))
                checked
            @endif
        >
        {{ $category->name }}
    </label>
    @endif
@endforeach

<button type="submit">apply filter</button>

Please or to participate in this conversation.