Add custom sorting for product listing

Overview

Individual sortings are groups of sorting options which you can use to sort product listings. The sortings are available in the storefront.
This guide will show you how to add individual sorting options using a migration (manageable) or at runtime (non-manageable).

Prerequisites

In order to add your own custom sorting for product listings for your plugin, you first need a plugin as base. Therefore, you can refer to the Plugin Base Guide.
You should also have a look at our Database migrations guide, as we use one in this guide.

Create individual sorting with migration

In order to make your sorting manageable in the administration by the user, you will need to migrate the data to the database.
Create a new Migration in your plugin:
Note: Do not change an existing migration if your plugin is already in use by someone. In that case, create a new Migration instead! This also means, that you have to re-install or update your plugin if you adjust the migration.
<plugin root>/src/Migration/Migration1615470599ExampleSorting.php
1
<?php declare(strict_types=1);
2
3
namespace Swag\BasicExample\Migration;
4
5
use Doctrine\DBAL\Connection;
6
use Shopware\Core\Content\Product\SalesChannel\Sorting\ProductSortingDefinition;
7
use Shopware\Core\Defaults;
8
use Shopware\Core\Framework\Migration\MigrationStep;
9
use Shopware\Core\Framework\Uuid\Uuid;
10
11
class Migration1615470599ExampleSorting extends MigrationStep
12
{
13
public function getCreationTimestamp(): int
14
{
15
return 1615470599;
16
}
17
18
public function update(Connection $connection): void
19
{
20
$myCustomSorting = [
21
'id' => Uuid::randomBytes(),
22
'url_key' => 'my-custom-sort', // shown in url - must be unique system wide
23
'priority' => 5, // the higher the priority, the further upwards it will be shown in the sortings dropdown in storefront
24
'active' => 1, // activate / deactivate the sorting
25
'locked' => 0, // you can lock the sorting here to prevent it from being edited in the administration
26
'fields' => json_encode([
27
[
28
'field' => 'product.name', // field to sort by
29
'order' => 'desc', // asc or desc
30
'priority' => 1, // in which order the sorting is to applied (higher priority comes first)
31
'naturalSorting' => 0 // apply natural sorting logic to this field
32
],
33
// ... more fields
34
]),
35
'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT),
36
];
37
38
// insert the product sorting
39
$connection->insert(ProductSortingDefinition::ENTITY_NAME, $myCustomSorting);
40
41
// insert the translation for the translatable label
42
// if you use multiple languages, you will need to update all of them
43
$connection->executeStatement(
44
'REPLACE INTO product_sorting_translation
45
(`language_id`, `product_sorting_id`, `label`, `created_at`)
46
VALUES
47
(:language_id, :product_sorting_id, :label, :created_at)',
48
[
49
'language_id' => Uuid::fromHexToBytes(Defaults::LANGUAGE_SYSTEM),
50
'product_sorting_id' => $myCustomSorting['id'],
51
'label' => 'My Custom Sorting',
52
'created_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT),
53
]
54
);
55
}
56
57
public function updateDestructive(Connection $connection): void
58
{
59
}
60
}
Copied!

Create individual sorting at runtime

You can subscribe to the ProductListingCriteriaEvent to add a ProductSortingEntity as available sorting on the fly. If you don't know how to do this, head over to our Listening to events guide.
While possible, it is not recommended adding an individual sorting at runtime. If you just wish for your individual sorting to be not editable by users in the administration, create a migration and set the parameter locked to be true.
Here's an example how your subscriber could look like:
<plugin root>/src/Subscriber/ExampleListingSubscriber.php
1
<?php declare(strict_types=1);
2
3
namespace Swag\BasicExample\Subscriber;
4
5
use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent;
6
use Shopware\Core\Content\Product\SalesChannel\Sorting\ProductSortingCollection;
7
use Shopware\Core\Content\Product\SalesChannel\Sorting\ProductSortingEntity;
8
use Shopware\Core\Framework\Uuid\Uuid;
9
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
10
11
class ExampleListingSubscriber implements EventSubscriberInterface
12
{
13
14
public static function getSubscribedEvents(): array
15
{
16
return [
17
// be sure to subscribe with high priority to add you sorting before the default shopware logic applies
18
// otherwise storefront will throw a ProductSortingNotFoundException
19
ProductListingCriteriaEvent::class => ['addMyCustomSortingToStorefront', 500],
20
];
21
}
22
23
public function addMyCustomSortingToStorefront(ProductListingCriteriaEvent $event): void
24
{
25
/** @var ProductSortingCollection $availableSortings */
26
$availableSortings = $event->getCriteria()->getExtension('sortings') ?? new ProductSortingCollection();
27
28
$myCustomSorting = new ProductSortingEntity();
29
$myCustomSorting->setId(Uuid::randomHex());
30
$myCustomSorting->setActive(true);
31
$myCustomSorting->setTranslated(['label' => 'My Custom Sorting at runtime']);
32
$myCustomSorting->setKey('my-custom-runtime-sort');
33
$myCustomSorting->setPriority(5);
34
$myCustomSorting->setFields([
35
[
36
'field' => 'product.name',
37
'order' => 'desc',
38
'priority' => 1,
39
'naturalSorting' => 0,
40
],
41
]);
42
43
$availableSortings->add($myCustomSorting);
44
45
$event->getCriteria()->addExtension('sortings', $availableSortings);
46
}
47
}
Copied!

Next steps

Are you interested to add a custom filter to your listing in the storefront, as well? Head over to the corresponding guide to learn more about that: