How to add a custom catalog promotion scope?

Catalog promotions in Sylius allow you to apply discounts automatically to selected product variants based on defined scopes. In this guide, we'll walk you through adding a custom scope that filters variants by checking if their name contains a specific phrase.


1. Implement a Custom Scope Checker

The scope checker determines if a given ProductVariant is within the scope.

Register the Checker Service

# config/services.yaml

services:
    App\CatalogPromotion\Checker\Variant\InByPhraseScopeChecker:
        arguments:
            - '@sylius.repository.product_variant'
        tags:
            - { name: 'sylius.catalog_promotion.variant_checker', type: 'by_phrase' }

Note: The type in the tag must match your scope's type key. It connects your logic to the scope configuration.

Create the Checker Class

<?php

// src/CatalogPromotion/Checker/Variant/InByPhraseScopeChecker.php

namespace App\CatalogPromotion\Checker\Variant;

use Sylius\Bundle\CoreBundle\CatalogPromotion\Checker\VariantInScopeCheckerInterface;
use Sylius\Component\Core\Model\ProductVariantInterface;
use Sylius\Component\Promotion\Model\CatalogPromotionScopeInterface;
use Webmozart\Assert\Assert;

final class InByPhraseScopeChecker implements VariantInScopeCheckerInterface
{
    public const TYPE = 'by_phrase';

    public function inScope(CatalogPromotionScopeInterface $scope, ProductVariantInterface $productVariant): bool
    {
        $configuration = $scope->getConfiguration();
        Assert::keyExists($configuration, 'phrase');

        return str_contains($productVariant->getName(), $configuration['phrase']);
    }
}

Configure parameter with the correct scope type:

# config/packages/_sylius.yaml

parameters:
    sylius.catalog_promotion.scope.by_phrase: !php/const App\CatalogPromotion\Checker\Variant\InByPhraseScopeChecker::TYPE

2. Create the Configuration Form Type

This allows admins to configure your custom scope via the UI.

Form Type Class and Service

<?php

// src/Form/Type/CatalogPromotionScope/ByPhraseScopeConfigurationType.php

namespace App\Form\Type\CatalogPromotionScope;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\NotBlank;

final class ByPhraseScopeConfigurationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add('phrase', TextType::class, [
            'label' => 'Phrase',
            'constraints' => [
                new NotBlank(['groups' => ['sylius']]),
            ],
        ]);
    }

    public function getBlockPrefix(): string
    {
        return 'sylius_catalog_promotion_scope_by_phrase_configuration';
    }
}

Register the form type:

# config/services.yaml

services:
    App\Form\Type\CatalogPromotionScope\ByPhraseScopeConfigurationType:
        tags:
            - { name: 'sylius.catalog_promotion.scope_configuration_type', key: '%sylius.catalog_promotion.scope.by_phrase%' }
            - { name: 'sylius_admin.catalog_promotion.scope_configuration_type', key: '%sylius.catalog_promotion.scope.by_phrase%'}
            - { name: 'form.type' }

4. Translations

For the admin UI to show your scope’s label, define this key in your translation file:

# translations/messages.en.yaml

sylius:
    ui:
        by_phrase: 'Phrase'

5. Custom Validation (Optional)


✅ Result

You can now select "By phrase" as a scope type when creating or editing catalog promotions. All product variants whose names contain the given phrase will be eligible for the promotion.

Last updated

Was this helpful?