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;
    }
}
circle-exclamation

2. Add a Premium Field to the Customer Entity

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

Apply the Doctrine migration:


3. Extend the Customer Admin Form

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

circle-exclamation

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:

Then configure the hook in your sylius.yaml:

circle-check

5. Create a Configuration Form Type (Optional)

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

circle-exclamation

6. Register Services

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


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


circle-check

Last updated

Was this helpful?