In this blog, you are going to learn “How to add the custom listing in the storefront at the Shopware.”
I hope you know the directory structure of Shopware 6 plugin, if you don’t know, see here- https://docs.shopware.com/en/shopware-platform-dev-en/internals/directory-structure.
New product listing filters can be registered via the event \Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent
. This event will be fire when the Criteria object is creating for the listing. The event can use to respond to the request to add new filters or aggregations to the Criteria object. Afterward, it is important to register for the event \Shopware\Core\Content\Product\Events\ProductListingResultEvent
to add the filtered values to the result.
<?php namespace Shopware\Core\Content\Product\SalesChannel\Listing; use Shopware\Core\Content\Product\Events\ProductListingCriteriaEvent; use Shopware\Core\Content\Product\Events\ProductListingResultEvent; use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Metric\EntityAggregation; use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsAnyFilter; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; class ExampleListingSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ ProductListingCriteriaEvent::class => 'handleRequest', ProductListingResultEvent::class => 'handleResult', ]; } public function handleRequest(ProductListingCriteriaEvent $event) { $criteria = $event->getCriteria(); $request = $event->getRequest(); $criteria->addAggregation( new EntityAggregation('manufacturer', 'product.manufacturerId', 'product_manufacturer') ); $ids = $this->getManufacturerIds($request); if (empty($ids)) { return; } $criteria->addPostFilter(new EqualsAnyFilter('product.manufacturerId', $ids)); } public function handleResult(ProductListingResultEvent $event) { $event->getResult()->addCurrentFilter('manufacturer', $this->getManufacturerIds($event->getRequest())); } private function getManufacturerIds(Request $request): array { $ids = $request->query->get('manufacturer', ''); $ids = explode('|', $ids); return array_filter($ids); } }
The sorting in the product listing is controlled by the \Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingSortingRegistry
. All classes in this registry represent a selectable sort in the listing. The \Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingSorting
can easily be defined via DI-Container. By the container tag shopware.sales_channel.product_listing.sorting
these are then registered in the registry.
service.xml
<service id="product_listing.sorting.name_descending" class="Shopware\Core\Content\Product\SalesChannel\Listing\ProductListingSorting"> <argument>name-desc</argument> <argument>filter.sortByNameDescending</argument> <argument type="collection"> <argument key="product.name">desc</argument> </argument> <tag name="shopware.sales_channel.product_listing.sorting" /> </service>
$sorting = new ProductListingSorting( 'name-asc', 'filter.sortByNameDescending', [ 'product.name' => 'desc', 'product.id' => 'asc' ] );
Entity extension
If you’re wondering how to extend existing core entities, this ‘HowTo’ will have you covered. Do not confuse entity extensions with entities’ custom fields though, as they serve a different purpose. In short: Extensions are technical and not configurable by the admin user just like that. Also, they can deal with more complex types than scalar ones. Custom fields are, by default, configurable by the admin user in the administration and they mostly support scalar types, e.g. a text-field, a number field
Own entities can be integrated into the core via the corresponding entry in the services.xml
. To extend existing entities, the abstract class \Shopware\Core\Framework\DataAbstractionLayer\EntityExtension
is used. The EntityExtension must define which entity should extend in the method. Once this extension access in the system, the extension can add more fields to it:
<?php declare(strict_types=1); namespace Webkul\EntityExtension\Extension\Content\Product; use Shopware\Core\Content\Product\ProductDefinition; use Shopware\Core\Framework\DataAbstractionLayer\EntityExtension; use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Runtime; use Shopware\Core\Framework\DataAbstractionLayer\Field\ObjectField; use Shopware\Core\Framework\DataAbstractionLayer\FieldCollection; class CustomExtension extends EntityExtension { public function extendFields(FieldCollection $collection): void { $collection->add( (new ObjectField('custom_struct', 'customStruct'))->addFlags(new Runtime()) ); } public function getDefinitionClass(): string { return ProductDefinition::class; } }
This example adds another association named custom_struct
to the ProductDefinition
. The Runtime
flag tells the data abstraction layer, that you’re going to take care of the field’s content yourself. Have a look at our detailed list of flags and what their purpose is, or find out which field types are available in Shopware 6.
So, time to take care of the product entities’ new field yourself. You’re going to need a new subscriber for this. Have a look here to find out how to properly add your own subscriber class.
<?php declare(strict_types=1); namespace Webkul\EntityExtension\Subscriber; use Swag\EntityExtension\Struct\MyCustomStruct; use Shopware\Core\Content\Product\ProductEntity; use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Shopware\Core\Content\Product\ProductEvents; class MySubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ ProductEvents::PRODUCT_LOADED_EVENT => 'onProductsLoaded' ]; } public function onProductsLoaded(EntityLoadedEvent $event): void { /** @var ProductEntity $productEntity */ foreach ($event->getEntities() as $productEntity) { $productEntity->addExtension('custom_struct', new MyCustomStruct()); } } }
As you can see, the subscriber listens to the PRODUCT_LOADED
event, which is triggered every time a set of products is requested. The listener onProductsLoaded
then adds a custom struct into the new field.
service.xml
<?xml version="1.0" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="Webkul\EntityExtension\Extension\Content\Product\CustomExtension"> <tag name="shopware.entity.extension"/> </service> <service id="Webkul\EntityExtension\Subscriber\MySubscriber"> <tag name="kernel.event_subscriber" /> </service> </services> </container>
I hope it will help you. Thanks for reading. Happy Coding 🙂
Please explore our shopware development services and Quality shopware extensions.
Thank You.
Good job for the tutorials.