The ProductSearch
class provides a powerful and flexible way to retrieve products based on various criteria.
It supports:
This guide walks you through setting up product listing, implementing filtering, and displaying individual product details.
The product listing page retrieves and displays all available products.
Controller:
namespace App\Http\Controllers;
use Vanilo\Foundation\Search\ProductSearch;
class ProductController extends Controller
{
private ProductSearch $productFinder;
public function __construct(ProductSearch $productFinder)
{
$this->productFinder = $productFinder;
}
public function index()
{
return view('product.index', [
'products' => $this->productFinder->getResults(),
]);
}
}
Route:
use App\Http\Controllers\ProductController;
Route::get('/product-list', [ProductController::class, 'index'])->name('product.index');
View:
@foreach($products as $product)
<a href="{{ route('product.show', $product->slug) }}"
<img
@if($product->hasImage())
src="{{ $product->getThumbnailUrl() }}"
@else
src="/images/no_image_placeholder.jpg"
@endif
alt="{{ $product->name }}"
>
<h5>{{ $product->name }}</h5>
<p>{{ format_price($product->price) }}</p>
</a>
@endforeach
Allows users to refine product results based on selected attributes like category, properties, etc.
Controller:
namespace App\Http\Controllers;
use App\Http\Requests\ProductIndexRequest;
use Vanilo\Properties\Models\PropertyProxy;
use Vanilo\Foundation\Search\ProductSearch;
class ProductController extends Controller
{
...
public function index(ProductIndexRequest $request)
{
$properties = PropertyProxy::get();
foreach ($request->filters($properties) as $property => $values) {
$this->productFinder->havingPropertyValuesByName($property, $values);
}
return view('product.index', [
'products' => $this->productFinder->getResults(),
'properties' => $properties,
'filters' => $request->filters($properties),
]);
}
}
ProductIndexRequest:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Collection;
class ProductIndexRequest extends FormRequest
{
public function filters(Collection $properties): array
{
$filters = [];
foreach ($this->query() as $propertySlug => $values) {
if ($properties->contains(function ($property) use ($propertySlug) {
return $property->slug === $propertySlug;
})) {
$filters[$propertySlug] = is_array($values) ? $values : [$values];
}
}
return $filters;
}
public function rules(): array
{
return [];
}
}
View:
<form action="{{ route('product.index') }}">
Filters
<ul>
@foreach($properties as $property)
<li>{{ $property->name }}:</li>
@foreach($property->values() as $propertyValue)
<li>
<label for="filter-{{$propertyValue->id}}">
<input type="checkbox"
name="{{ $property->slug }}[]"
value="{{ $propertyValue->value }}"
id="filter-{{$propertyValue->id}}"
@if(in_array($propertyValue->value, $filters)) checked="checked" @endif
>
{{ $propertyValue->title }}
</label>
</li>
@endforeach
@endforeach
</ul>
<button type="submit">Apply</button>
</form>
Enables users to filter products within a specific category while applying additional filters.
Controller:
namespace App\Http\Controllers;
use Vanilo\Category\Contracts\Taxon;
use App\Http\Requests\ProductIndexRequest;
use Vanilo\Properties\Models\PropertyProxy;
use Vanilo\Foundation\Search\ProductSearch;
class ProductController extends Controller
{
...
public function index(ProductIndexRequest $request, string $taxonomyName = null, Taxon $taxon = null)
{
$properties = PropertyProxy::get();
if ($taxon) {
$this->productFinder->withinTaxon($taxon);
}
foreach ($request->filters($properties) as $property => $values) {
$this->productFinder->havingPropertyValuesByName($property, $values);
}
return view('product.index', [
'products' => $this->productFinder->getResults(),
'properties' => $properties,
'filters' => $request->filters($properties),
'taxon' => $taxon,
]);
}
Route:
Route::get('/c/{taxonomyName}/{taxon}', [ProductController::class, 'index'])->name('taxon.show');
View:
<form action="{{ $taxon ? route('taxon.show', [$taxon->taxonomy->slug, $taxon]) : route('product.index') }}">
Filters
<ul>
@foreach($properties as $property)
<li>{{ $property->name }}:</li>
@foreach($property->values() as $propertyValue)
<li>
<label for="filter-{{$propertyValue->id}}">
<input type="checkbox"
name="{{ $property->slug }}[]"
value="{{ $propertyValue->value }}"
id="filter-{{$propertyValue->id}}"
@if(in_array($propertyValue->value, $filters)) checked="checked" @endif
>
{{ $propertyValue->title }}
</label>
</li>
@endforeach
@endforeach
</ul>
<button type="submit">Apply</button>
</form>
Once a user selects a product, they should be taken to the product details page.
Controller:
namespace App\Http\Controllers;
use Vanilo\Foundation\Search\ProductSearch;
class ProductController extends Controller
{
...
public function show(string $slug)
{
$product = $this->productFinder->findBySlug($slug);
if (! $product) {
abort(404);
}
return view('product.show', [
'product' => $product,
]);
}
}
Route:
use App\Http\Controllers\ProductController;
Route::get('/p/{slug}', [ProductController::class, 'show'])->name('product.show');
View:
<x-app-layout>
<img src="{{ $product->getImageUrl("square") }}">
<h1>{{ $product->name }}</h1>
<p>SKU: {{ $product->sku }}</p>
<p>{{ format_price($product->price) }}</p>
</x-app-layout>
Displaying Product Properties:
@foreach($product->propertyValues as $value)
{{ $value->property->name }}: {{ $value->title }}
@endforeach
For more details, check out the Vanilo.io documentation.