Implement individual sorting
INFO
This document represents an architecture decision record (ADR) and has been mirrored from the ADR section in our Shopware 6 repository. You can find the original version here
Context
Shop owners should be able to define custom sorting options for product listings and search result pages out of the administration. It should be possible to define a system default sorting option for product listings. Top Results
will be the default on search pages and suggest route, which sorts products by _score
.
Currently, to define a custom sorting option, you need to define it as a service and tag it as shopware.sales_channel.product_listing.sorting
. This is somewhat tedious and makes it impossible to define individual sortings via the administration.
Decision
From now on, it is possible to define custom sortings via the administration.
Individual sortings will be stored in the database in the table product_sorting
and its translatable label in the product_sorting_translation
table.
It is possible to define a system default product listing sorting option, which is stored in system_default
.core.listing.defaultSorting
. This however has no influence on the default Top Results
sorting on search pages and the suggest route result.
To define custom sorting options via a plugin, you can either write a migration to store them in the database. This method is recommended, as the sortings can be managed via the administration.
The product_sorting
table looks like the following:
Column | Type | Notes |
---|---|---|
id | binary(16) | |
url_key | varchar(255) | Key (unique). Shown in url, when sorting is chosen |
priority | int unsigned | Higher priority means, the sorting will be sorted top |
active | tinyint(1) [1] | Inactive sortings will not be shown and will not sort |
locked | tinyint(1) [0] | Locked sortings can not be edited via the DAL |
fields | json | JSON of the fields by which to sort the listing |
created_at | datetime(3) | |
updated_at | datetime(3) |
The JSON for the fields column look like this:
[
{
"field": "product.name", // property to sort by (mandatory)
"order": "desc", // "asc" or "desc" (mandatory)
"priority": 0, // in which order the sorting is to applied (higher priority comes first) (mandatory)
"naturalSorting": 0
},
{
"field": "product.cheapestPrice",
"order": "asc",
"priority": 100,
"naturalSorting": 0
},
// ...
]
Otherwise, you can subscribe to the ProductListingCriteriaEvent
to add a ProductSortingEntity
as available sorting on the fly.
<?php
namespace Shopware\Core\Content\Product\SalesChannel\Sorting\Example;
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
use Shopware\Core\Content\Product\SalesChannel\Sorting\ProductSortingCollection;
use Shopware\Core\Content\Product\SalesChannel\Sorting\ProductSortingEntity;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ExampleListingSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents(): array
{
return [
ProductListingCriteriaEvent::class => ['addMyCustomSortingToStorefront', 500],
];
}
public function addMyCustomSortingToStorefront(ProductListingCriteriaEvent $event): void
{
/** @var ProductSortingCollection $availableSortings */
$availableSortings = $event->getCriteria()->getExtension('sortings') ?? new ProductSortingCollection();
$myCustomSorting = new ProductSortingEntity();
$myCustomSorting->setId(Uuid::randomHex());
$myCustomSorting->setActive(true);
$myCustomSorting->setTranslated(['label' => 'My Custom Sorting']);
$myCustomSorting->setKey('my-custom-sort');
$myCustomSorting->setPriority(5);
$myCustomSorting->setFields([
[
'field' => 'product.name',
'order' => 'desc',
'priority' => 1,
'naturalSorting' => 0,
],
]);
$availableSortings->add($myCustomSorting);
$event->getCriteria()->addExtension('sortings', $availableSortings);
}
}
Consequences
The old behaviour of defining the custom sorting as a tagged service is deprecated and will be removed in v6.4.0.