SyliusCon 2025 in Lyon
Join Us!
LogoLogo
🛣️ Roadmap💻 Sylius Demo💬 Community Slack
  • Sylius Documentation
  • Sylius Plugins
  • Sylius Stack
  • 📖Sylius Documentation
  • Organization
    • Sylius Team
  • Release Cycle
    • Backwards Compatibility Promise
  • Getting Started with Sylius
    • Installation
    • Basic Configuration
    • Shipping & Payment
    • First Product
    • Customizing the Shop
    • Customizing Business Logic
    • Using API
    • Installing Plugins
    • Deployment
    • Summary
  • The Book
    • Introduction to Sylius
    • Installation
      • System Requirements
      • Sylius CE Installation
        • Sylius CE Installation with Docker
      • ➕Sylius Plus Installation
      • Upgrading Sylius CE
      • Upgrading Sylius Plus
    • Architecture
      • Architecture Overview
      • Architectural Drivers
      • Resource Layer
      • State Machine
      • Translations
      • E-Mails
      • Contact
      • Fixtures
      • Events
    • Configuration
      • Channels
      • Locales
      • Currencies
    • Customers
      • Customer & ShopUser
      • ➕Customer Pools
      • AdminUser
      • Addresses
        • Countries
        • Zones
        • Addresses
        • Address Book
    • Products
      • Products
      • Product Reviews
      • Product Associations
      • Attributes
      • Pricing
        • B2B Pricing Engine
      • Catalog Promotions
      • Taxons
      • Inventory
      • ➕Multi-Source Inventory
      • Search
    • Carts & Orders
      • Orders
      • Cart flow
      • Taxation
      • Adjustments
      • Cart Promotions
      • Coupons
      • Payments
      • 🧩Invoices
      • Shipments
    • 🎨Frontend & Themes
    • Support
    • Contributing
      • Contributing Code
        • Submitting a Patch
        • ⚠️Security Issues
        • Coding Standards
        • Conventions
        • Sylius License and Trademark
      • Contributing Translations
      • Key Contributors
  • The Customization Guide
    • Customizing Models
      • How to add a custom model?
      • How to add a custom translatable model?
    • Customizing Forms
      • How to add a live form for a custom model?
    • Customizing Templates
    • Customizing Styles
    • Customizing Dynamic Elements
    • Customizing Validation
    • Customizing Menus
    • Customizing Translations
    • Customizing Flashes
    • Customizing State Machines
    • Customizing Grids
    • Customizing Fixtures
    • Customizing API
    • Customizing Serialization of API
    • Customizing Payments
      • How to integrate a Payment Gateway as a Plugin?
  • 🧑‍🍳THE COOKBOOK
    • How to resize images?
  • How to add one image to an entity?
  • How to add multiple images to an entity?
  • How to add a custom cart promotion action?
  • How to add a custom cart promotion rule?
  • How to add a custom catalog promotion action?
  • How to add a custom catalog promotion scope?
  • How to customize catalog promotion labels?
  • How to improve the performance of the catalog promotions?
  • How to add a custom shipping method rule?
  • Sylius 1.X Documentation
    • 📓Sylius 1.x Documentation
Powered by GitBook
LogoLogo

Developer

  • Community
  • Online Course

About

  • Team

© 2025 Sylius. All Rights Reserved

On this page
  • 1. Implement a Custom Scope Checker
  • Register the Checker Service
  • Create the Checker Class
  • 2. Create the Configuration Form Type
  • Form Type Class and Service
  • Register the form type:
  • 4. Translations
  • 5. Custom Validation (Optional)
  • ✅ Result

Was this helpful?

Edit on GitHub

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)

Tip: For customizing validation rules (e.g., enforcing phrase constraints), refer to Sylius' Custom Validation Guide.


✅ 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.

If your catalog promotion is not active, make sure the Messenger worker is active:

php bin/console messenger:consume main
PreviousHow to add a custom catalog promotion action?NextHow to customize catalog promotion labels?

Last updated 2 days ago

Was this helpful?