From the official documentation https://developer.shopware.com/docs/guides/plugins/plugins/storefront/add-custom-sorting-product-listing.html it is clear enough how to add new custom sorting on PLP with Shopware.
But how to implement sorting by the reference price? This value is not stored in the database but calculated on fly, thus it is not possible to provide a field parameter at $myCustomSorting->setFields()
.
For example, we have two products with gross prices 10.00
and 15.00
and these products have selling units 0.5
and 0.9
respectively (for m2 in pack). We want to sort products based on reference price per m2 10 / 0.5 = 20.00
and 15 / 0.9 = 16.67
.
In the end, the problem was fixed with the following solution:
Shopware\Core\Content\Product\DataAbstractionLayer\CheapestPrice\CheapestPriceField
:class UnitPriceField extends CheapestPriceField
{
protected function getAccessorBuilderClass(): ?string
{
return UnitPriceFieldAccessorBuilder::class;
}
}
UnitPriceFieldAccessorBuilder
class which also extends Shopware\Core\Content\Product\DataAbstractionLayer\CheapestPrice\CheapestPriceAccessorBuilder
and recalculates result taking into account referenceUnit
and purchaseUnit
values:class UnitPriceFieldAccessorBuilder extends CheapestPriceAccessorBuilder
{
public function buildAccessor(string $root, Field $field, Context $context, string $accessor): ?string
{
$price = parent::buildAccessor($root, $field, $context, 'cheapestPrice');
return $price . ' * IFNULL(`product`.`reference_unit`, 1) / IFNULL(`product`.`purchase_unit`, 1)';
}
}
Shopware\Core\Content\Product\SalesChannel\SalesChannelProductDefinition
class to add new field:class SalesChannelProductDefinition extends ShopwareSalesChannelProductDefinition
{
protected function defineFields(): FieldCollection
{
$fields = parent::defineFields();
$fields->add(
(new UnitPriceField('unit_price', 'unitPrice'))
->addFlags(new Runtime())
);
return $fields;
}
}
product_sorting
table for url-keys price-asc
/price-desc
to use field product.unitPrice
instead of product.cheapestPrice
. Alternatively, just add a new sorting row here.