SyliusCon 2025
Early Bird Deal
LogoLogo
πŸ›£οΈ RoadmapπŸ’» Sylius DemoπŸ’¬ Community Slack
  • Sylius Documentation
  • Sylius Plugins
  • Sylius Stack
  • πŸ“–Sylius 2.0 Documentation
    • Organization
      • Release Cycle
      • Backwards Compatibility Promise
      • Sylius Team
      • Sylius Roadmap
  • 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
      • Catalog Promotions
      • Taxons
      • Inventory
      • βž•Multi-Source Inventory
      • Search
    • Carts & Orders
      • Orders
      • Cart flow
      • Taxation
      • Adjustments
      • Cart Promotions
      • Coupons
      • Payments
      • 🧩Invoices
      • Shipments
    • 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 Styles
    • Customizing Validation
    • Customizing Menus
    • Customizing Templates
    • 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?
  • 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. Create a New Promotion Rule Checker
  • 2. Add a Premium Field to the Customer Entity
  • 3. Extend the Customer Admin Form
  • 4. Create the Template Section for the Premium Field
  • 5. Create a Configuration Form Type (Optional)
  • 6. Register Services
  • βœ… Result

Was this helpful?

Edit on GitHub

How to add a custom cart promotion rule?

Adding custom promotion rules is a common need in real-world shops. For example, you might want to offer exclusive discounts to premium customers. To implement this, you'll create a new PromotionRule that checks whether a customer qualifies.


1. Create a New Promotion Rule Checker

Define a custom RuleChecker that determines rule eligibility:

<?php

namespace App\Promotion\Checker\Rule;

use Sylius\Component\Promotion\Checker\Rule\RuleCheckerInterface;
use Sylius\Component\Promotion\Model\PromotionSubjectInterface;

class PremiumCustomerRuleChecker implements RuleCheckerInterface
{
    public const TYPE = 'premium_customer';

    public function isEligible(PromotionSubjectInterface $subject, array $configuration): bool
    {
        return $subject->getCustomer()?->isPremium() === true;
    }
}

Ensure the getCustomer() method exists on your PromotionSubjectInterface.


2. Add a Premium Field to the Customer Entity

First, extend the Customer entity to include a premium boolean field:

<?php

// App\Entity\Customer\Customer

declare(strict_types=1);

namespace App\Entity\Customer;

use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Core\Model\Customer as BaseCustomer;

#[ORM\Entity]
#[ORM\Table(name: 'sylius_customer')]
class Customer extends BaseCustomer
{
    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $premium = false;

    public function isPremium(): bool
    {
        return $this->premium;
    }

    public function setPremium(bool $premium): void
    {
        $this->premium = $premium;
    }
}

Apply the Doctrine migration:

php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate

3. Extend the Customer Admin Form

Now, extend the customer form to allow editing the premium field in the Sylius admin:

<?php

// src/Form/Extension/CustomerTypeExtension.php

namespace App\Form\Extension;

use Sylius\Bundle\AdminBundle\Form\Type\CustomerType;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface;

final class CustomerTypeExtension extends AbstractTypeExtension
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->add('premium', CheckboxType::class, [
            'label' => 'Premium',
            'required' => false,
        ]);
    }

    public static function getExtendedTypes(): iterable
    {
        return [CustomerType::class];
    }
}

If your autowiring is disabled, you will need also to register your CustomerTypeExtension in config/services.yaml:

services:    
    App\Form\Extension\CustomerTypeExtension:
        tags:
            - { name: form.type_extension }

4. Create the Template Section for the Premium Field

Inspect the admin customer form to find the appropriate hook. The relevant section is sylius_admin.customer.update.content.form.sections.general.

Create a new Twig template for this field:

{# templates/admin/customer/form/sections/general/premium.html.twig #}

{{ form_row(hookable_metadata.context.form.premium) }}

Then configure the hook in your sylius.yaml:

# config/packages/_sylius.yaml

sylius_twig_hooks:
    hooks:
        'sylius_admin.customer.update.content.form.sections.general':
            premium:
                template: '/admin/customer/form/sections/general/premium.html.twig'
                priority: -50

5. Create a Configuration Form Type (Optional)

Even if no configuration is needed, Sylius expects a form type to exist for every rule.

<?php

// src/Form/Type/Rule/PremiumCustomerConfigurationType.php

namespace App\Form\Type\Rule;

use Symfony\Component\Form\AbstractType;

class PremiumCustomerConfigurationType extends AbstractType
{
    public function getBlockPrefix(): string
    {
        return 'app_promotion_rule_premium_customer_configuration';
    }
}

If your autowiring is disabled, you will need also to register your PremiumCustomerConfigurationType in config/services.yaml:

services:    
    App\Form\Extension\PremiumCustomerConfigurationType:
        tags:
            - { name: form.type_extension }

6. Register Services

Add both the rule checker and form type to your config/services.yaml:

# config/services.yaml
services:
    App\Promotion\Checker\Rule\PremiumCustomerRuleChecker:
        tags:
            - {
                name: sylius.promotion_rule_checker,
                type: premium_customer,
                form_type: App\Form\Type\Rule\PremiumCustomerConfigurationType,
                label: 'Premium customer'
              }

βœ… Result

You can now select the Premium customer rule type when creating or editing a cart promotion in the Sylius Admin panel.

To make this rule applicable, edit a customer and mark them as premium.

Promotions using this rule will now apply (or not) based on whether the customer is marked as premiumβ€” regardless of whether a coupon is used:


PreviousHow to add a custom cart promotion action?

Last updated 5 days ago

Was this helpful?

Learn more about twig hooks !

If your rule requires configuration fields (like thresholds or limits), see how it’s handled in .

here
ItemTotalConfigurationType