abderrahimghazali/sylius-loyalty-plugin
Composer 安装命令:
composer require abderrahimghazali/sylius-loyalty-plugin
包简介
Points-based loyalty and rewards system for Sylius 2.x
README 文档
README
Sylius Loyalty Plugin
A points-based loyalty and rewards system for Sylius 2.x e-commerce stores.
Overview
SyliusLoyaltyPlugin adds a complete loyalty program to any Sylius 2.x store. Customers earn points on purchases, redeem them as discounts on the cart page, unlock tier-based multipliers, and receive bonus points for registration, birthdays, and first orders — all configurable per channel from the admin panel.
Key Features
- Multi-channel — Each channel has independent earning rates, redemption rates, expiry, and bonus settings
- Loyalty rules — Override earning rates for specific products with per-rule points configuration and multi-channel support
- Points earning — Configurable default points per currency unit on every order
- Cart redemption — Spend points as a monetary discount on the cart page
- Points expiry — Automatic expiration with cron command + 30-day warnings
- Bonus events — Registration, birthday, and first-order bonuses (toggle on/off per channel)
- Tier system — Bronze / Silver / Gold with earning multipliers (tiers only go up)
- Admin panel — Full management: accounts, transactions, manual adjustments, per-channel config
- Customer account — Points balance, tier badge, paginated transaction history with running balance
- REST API — Headless-ready endpoints for balance and redemption
- Workflow integration — Points deducted on order complete, restored on cancel/refund
- Translations — English, French, German, Spanish, Polish, Portuguese
Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.2 |
| Sylius | ~2.1 |
| Symfony | ^7.0 |
Installation
composer require abderrahimghazali/sylius-loyalty-plugin
1. Register the plugin
// config/bundles.php return [ // ... Abderrahim\SyliusLoyaltyPlugin\SyliusLoyaltyPlugin::class => ['all' => true], ];
2. Import routes
# config/routes/sylius_loyalty.yaml sylius_loyalty: resource: '@SyliusLoyaltyPlugin/config/routes.yaml'
3. Extend your Order entity
Add the loyalty trait to your Order entity so customers can redeem points on the cart page:
// src/Entity/Order/Order.php namespace App\Entity\Order; use Abderrahim\SyliusLoyaltyPlugin\Entity\Order\LoyaltyOrderInterface; use Abderrahim\SyliusLoyaltyPlugin\Entity\Order\LoyaltyOrderTrait; use Sylius\Component\Core\Model\Order as BaseOrder; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ORM\Table(name: 'sylius_order')] class Order extends BaseOrder implements LoyaltyOrderInterface { use LoyaltyOrderTrait; // ...existing code... }
4. Register the Stimulus controller (for the cart widget)
Add the plugin JS dependency to your package.json:
{
"dependencies": {
"@abderrahimghazali/sylius-loyalty-plugin": "file:vendor/abderrahimghazali/sylius-loyalty-plugin/assets"
}
}
Register the controller in assets/shop/controllers.json:
{
"controllers": {
"@abderrahimghazali/sylius-loyalty-plugin": {
"loyalty-redemption": {
"enabled": true,
"fetch": "eager"
}
}
}
}
Then rebuild assets:
npm install npm run build
5. Run migrations
php bin/console doctrine:migrations:diff php bin/console doctrine:migrations:migrate
6. Seed the default configuration
php bin/console loyalty:install
This creates a default loyalty configuration for each channel. You can then customize settings per channel from the admin panel under Configuration > Loyalty configuration.
7. Set up cron jobs
# Expire old points (run daily) php bin/console loyalty:expire-points # Award birthday bonuses (run daily) php bin/console loyalty:birthday-bonus
Architecture
Domain Model
Channel ──1:1──▶ LoyaltyConfiguration
(earning rate, redemption rate, expiry, bonuses)
Channel ──N:M──▶ LoyaltyRule ──N:M──▶ Product
(name, enabled, points rate per product)
Customer ──1:1──▶ LoyaltyAccount ──1:N──▶ PointTransaction
│ (earn/redeem/expire/adjust/bonus)
│
└───N:1──▶ LoyaltyTier
(Bronze/Silver/Gold)
Points are shared across channels (one account per customer), while earning/redemption rates are configured per channel.
Entities
| Entity | Purpose |
|---|---|
LoyaltyAccount |
Per-customer account with balance, lifetime points, tier |
PointTransaction |
Ledger entry — signed points, type, optional order link, expiry |
LoyaltyTier |
Tier with min-points threshold, earning multiplier, color |
LoyaltyConfiguration |
Per-channel config: earning rate, redemption rate, expiry, bonuses |
LoyaltyRule |
Per-product earning rate override, multi-channel |
Sylius Integration Points
| Extension Point | What It Does |
|---|---|
OrderProcessorInterface (priority 5) |
Applies loyalty discount adjustment after taxes |
sylius.order.post_complete event |
Awards earn points + first-order bonus on order completion |
sylius.order.post_cancel event |
Revokes earned points |
sylius.customer.post_register event |
Awards registration bonus |
workflow.sylius_order_checkout.completed.complete |
Deducts redeemed points from balance |
workflow.sylius_order.completed.cancel |
Restores redeemed points |
workflow.sylius_payment.completed.refund |
Restores redeemed points on refund |
sylius.menu.admin.main event |
Adds menu items under Customers, Marketing & Configuration |
| Twig hooks | Cart widget, cart/checkout summary, customer show section, account menu |
Multi-Channel Support
Each Sylius channel can have its own loyalty configuration:
| Setting | US Store | EU Store | B2B Store |
|---|---|---|---|
| Earning rate | 1 pt / $1 | 2 pts / €1 | Disabled |
| Redemption rate | 100 pts = $1 | 50 pts = €1 | N/A |
| Registration bonus | 100 pts | 200 pts | 0 |
| Birthday bonus | 200 pts | 500 pts | 0 |
| Tiers enabled | Yes | Yes | No |
Points are shared across channels — a customer earns on one store and redeems on another. Rates are applied based on the order's channel.
Manage per-channel settings at Configuration > Loyalty configuration in the admin panel.
Shop Features
Cart Redemption Widget
On the cart page, logged-in customers can redeem points as a discount. The widget uses Symfony UX Live Components for seamless interaction without page reloads.
- Input field with placeholder showing available balance
- "Apply points" button (triggers Live Component re-render)
- Applied state shows a badge with points count, discount value, and a remove button
- Loyalty discount line appears in the cart summary and throughout the checkout sidebar
- Automatic clamping: can't exceed balance or order total
Customer Account — Loyalty Page
Accessible from the account sidebar menu:
- Current balance + redeemable monetary value
- Tier badge with multiplier info
- Expiry warning for points expiring within 30 days
- Paginated transaction history table with running balance column
Admin Features
Loyalty Accounts
Grid view of all customer loyalty accounts with balance, lifetime points, tier, and status. Click through to a detail page showing paginated transaction history.
Manual Point Adjustment
From any loyalty account detail page, admins can add or deduct points with a required reason field. Positive values create an Adjust (credit) transaction, negative values create a Deduct (debit) transaction.
Tier Management
Full CRUD for loyalty tiers under Marketing > Loyalty tiers. Code and position are auto-generated from the tier name.
| Field | Description |
|---|---|
| Name | Display name (e.g., "Bronze") — code is auto-generated |
| Min Points | Lifetime points threshold to reach this tier |
| Multiplier | Earning multiplier (e.g., 1.5x for Silver) |
| Color | Badge color (hex, rendered in admin and shop) |
Per-Channel Configuration
Under Configuration > Loyalty configuration, admins see a table of all channels and can configure each independently:
- Points per currency unit
- Redemption rate (points per 1 currency unit)
- Expiry period in days
- Enable/disable tier system
- Toggle and configure bonus events (registration, birthday, first order)
Settings are stored in the database and take effect immediately without redeployment.
Loyalty Rules
Under Marketing > Loyalty rules, admins can override the default earning rate for specific products. Each rule has:
- Name — descriptive label for the rule
- Products — select one or more products via autocomplete
- Points per currency unit — custom earning rate (set to 0 to exclude products from earning)
- Channels — select which channels the rule applies to
- Enabled — toggle the rule on/off
When a product in an order matches a loyalty rule for that channel, the rule's rate is used instead of the channel's default rate.
Example rules:
| Rule | Products | Rate | Channels |
|---|---|---|---|
| Double on gift sets | Gift Set A, Gift Set B | 2 pts/€1 | All |
| No points on gift cards | Gift Card | 0 pts/€1 | All |
| Premium bonus | Limited Edition Watch | 10 pts/€1 | Fashion Web Store |
API Endpoints (Headless)
For headless/SPA storefronts, the plugin provides REST endpoints. All shop endpoints verify the authenticated user owns the order.
Shop API
POST /api/v2/shop/orders/{tokenValue}/loyalty-redemption
Body: { "pointsToRedeem": 500 }
→ { "pointsRedeemed": 500, "discountAmount": 500, "orderTotal": 9500 }
DELETE /api/v2/shop/orders/{tokenValue}/loyalty-redemption
→ { "pointsRedeemed": 0, "discountAmount": 0, "orderTotal": 10000 }
GET /api/v2/shop/loyalty/account
→ Balance, lifetime points, tier info
Admin API
GET /api/v2/admin/loyalty/accounts
GET /api/v2/admin/loyalty/accounts/{id}
PATCH /api/v2/admin/loyalty/accounts/{id}
Edge Cases Handled
- Pessimistic DB locking prevents double-spend on concurrent checkouts, cancellations, and refunds
- API endpoints require
ROLE_USERand verify the authenticated user owns the order - Balance cannot go negative (clamped in service layer + guard in entity)
- Points redemption cannot exceed available balance (clamped, validated in cart form and API)
- Discount cannot exceed order total (capped, points recalculated)
- Guest checkouts cannot use loyalty points (guarded)
- Disabled accounts are excluded from earning and redemption
- Duplicate point awards are prevented (idempotent per order)
- Duplicate revocations are prevented (idempotent per order)
- First-order bonus awarded only once (idempotent)
- Points are reserved at cart, deducted only on order completion
- Cancelled/refunded orders restore redeemed points (idempotent, locked)
- Birthday bonus awarded at most once per calendar year per channel
- Tiers only upgrade, never demote (based on lifetime points)
- CSRF protection on all admin forms
- Admin point adjustment descriptions are sanitized
- Expire points command uses batched processing for large datasets
Translations
The plugin ships with translations for:
| Language | File |
|---|---|
| English | messages.en.yaml |
| French | messages.fr.yaml |
| German | messages.de.yaml |
| Spanish | messages.es.yaml |
| Polish | messages.pl.yaml |
| Portuguese | messages.pt.yaml |
Running Tests
composer install vendor/bin/phpunit
71 unit tests covering entities, services, order processing, and all event listeners.
Screenshots
Cart — Redeem points
Customer Account — Loyalty points & transaction history
Admin — Loyalty tiers management
License
This plugin is released under the MIT License.
abderrahimghazali/sylius-loyalty-plugin 适用场景与选型建议
abderrahimghazali/sylius-loyalty-plugin 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 48 次下载、GitHub Stars 达 2, 最近一次更新时间为 2026 年 03 月 24 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「ecommerce」 「sylius」 「rewards」 「loyalty」 「points」 「sylius-plugin」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 abderrahimghazali/sylius-loyalty-plugin 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 abderrahimghazali/sylius-loyalty-plugin 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 abderrahimghazali/sylius-loyalty-plugin 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Implementation of the Omnibus Directive for Sylius application.
Bulk export of sylius resources
Sylius plugin that integrates Addwish
Nevogate Payment Gateway SDK
Setono example plugin for Sylius.
Will translate fragments of text automatically
统计信息
- 总下载量: 48
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 2
- 点击次数: 28
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-03-24


