PHPackages                             abderrahimghazali/sylius-loyalty-plugin - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. abderrahimghazali/sylius-loyalty-plugin

ActiveSylius-plugin[Utility &amp; Helpers](/categories/utility)

abderrahimghazali/sylius-loyalty-plugin
=======================================

Points-based loyalty and rewards system for Sylius 2.x

v2.0.0(1mo ago)110↑2600%MITPHPPHP ^8.2

Since Mar 24Pushed 1mo agoCompare

[ Source](https://github.com/abderrahimghazali/sylius-loyalty-plugin)[ Packagist](https://packagist.org/packages/abderrahimghazali/sylius-loyalty-plugin)[ RSS](/packages/abderrahimghazali-sylius-loyalty-plugin/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (4)Versions (2)Used By (0)

 [    ![Sylius Logo](https://camo.githubusercontent.com/ea9dddc934264aa7ec01cf3202c500f3d8b04448bce2571bdc74230efddda88f/68747470733a2f2f6d656469612e73796c6975732e636f6d2f73796c6975732d6c6f676f2d3830302e706e67)  ](https://sylius.com)

Sylius Loyalty Plugin
=====================

[](#sylius-loyalty-plugin)

 A points-based loyalty and rewards system for [Sylius 2.x](https://sylius.com) e-commerce stores.

 [![Latest Version](https://camo.githubusercontent.com/0091ef6655c451227de66647cd7d36d4a9261c82438f35172b26fb58dfd96eb5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6162646572726168696d6768617a616c692f73796c6975732d6c6f79616c74792d706c7567696e2e737667)](https://packagist.org/packages/abderrahimghazali/sylius-loyalty-plugin) [![PHP Version](https://camo.githubusercontent.com/ca0f2dd312ec89b2712bd39ad448d43ff78513b347c9869db08d6cc5fdf0aa23/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6162646572726168696d6768617a616c692f73796c6975732d6c6f79616c74792d706c7567696e2e737667)](https://packagist.org/packages/abderrahimghazali/sylius-loyalty-plugin) [![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE) [![Sylius 2.x](https://camo.githubusercontent.com/47390b9b61d6f22d062322df61d2d225ceaf33f7bb75b99592c7ba766049f3e5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f73796c6975732d322e782d677265656e2e737667)](https://packagist.org/packages/abderrahimghazali/sylius-loyalty-plugin) [![Symfony 7.x](https://camo.githubusercontent.com/fe777aec93f146d83db2752ebd66562c8d4d1be48fa4a1477c51c0dbab74e381/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f73796d666f6e792d372e782d626c61636b2e737667)](https://packagist.org/packages/abderrahimghazali/sylius-loyalty-plugin)

---

Overview
--------

[](#overview)

SyliusLoyaltyPlugin adds a complete loyalty program to any Sylius 2.x store. Customers earn points on purchases, redeem them as discounts at checkout, unlock tier-based multipliers, and receive bonus points for registration, birthdays, and first orders — all manageable from the admin panel.

### Key Features

[](#key-features)

- **Points earning** — Configurable points per currency unit on every order
- **Checkout redemption** — Spend points as a monetary discount with live total update (Stimulus)
- **Points expiry** — Automatic expiration with cron command + 30-day warnings
- **Bonus events** — Registration, birthday, and first-order bonuses (toggle on/off)
- **Tier system** — Bronze / Silver / Gold with earning multipliers (tiers only go up)
- **Admin panel** — Full management: accounts, transactions, manual adjustments, global config
- **Customer account** — Points balance, tier badge, transaction history with running balance
- **REST API** — Headless-ready endpoints for balance and checkout redemption
- **Workflow integration** — Points deducted on order complete, restored on cancel/refund

Requirements
------------

[](#requirements)

DependencyVersionPHP^8.2Sylius~2.1Symfony^7.0Installation
------------

[](#installation)

```
composer require abderrahimghazali/sylius-loyalty-plugin
```

### 1. Register the plugin

[](#1-register-the-plugin)

```
// config/bundles.php
return [
    // ...
    Abderrahim\SyliusLoyaltyPlugin\SyliusLoyaltyPlugin::class => ['all' => true],
];
```

### 2. Import configuration and routes

[](#2-import-configuration-and-routes)

```
# config/packages/sylius_loyalty.yaml
sylius_loyalty:
    points_per_currency_unit: 1   # 1 point per €1 spent
    redemption_rate: 100          # 100 points = €1 discount
    expiry_days: 365              # Points expire after 12 months
    bonus:
        registration: 100         # Welcome bonus
        first_order: 50           # First purchase bonus
        birthday: 200             # Annual birthday bonus
    tiers_enabled: true
```

```
# config/routes/sylius_loyalty.yaml
sylius_loyalty:
    resource: '@SyliusLoyaltyPlugin/config/routes.yaml'
```

### 3. Extend your Order entity

[](#3-extend-your-order-entity)

Add the loyalty trait to your Order entity so customers can redeem points at checkout:

```
// 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. Run migrations

[](#4-run-migrations)

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

### 5. Set up cron jobs

[](#5-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
------------

[](#architecture)

### Domain Model

[](#domain-model)

```
Customer ──1:1──▶ LoyaltyAccount ──1:N──▶ PointTransaction
                        │                    (earn/redeem/expire/adjust/bonus)
                        │
                        └───N:1──▶ LoyaltyTier
                                   (Bronze/Silver/Gold)

```

### Entities

[](#entities)

EntityPurpose`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`Single-row config table for admin-editable settings### Sylius Integration Points

[](#sylius-integration-points)

Extension PointWhat It Does`OrderProcessorInterface` (priority 5)Applies loyalty discount adjustment after taxes`sylius.order.post_complete` eventAwards earn points on order completion`sylius.order.post_cancel` eventRevokes earned points`sylius.customer.post_register` eventAwards 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` eventAdds menu items under Customers &amp; ConfigurationTwig hooksCheckout widget, customer show section, account menuShop Features
-------------

[](#shop-features)

### Checkout Redemption Widget

[](#checkout-redemption-widget)

At the checkout summary step, logged-in customers see their points balance and can enter how many points to redeem. The widget uses a **Stimulus controller** for live updates — no page reload needed.

- Input field with min/max validation
- "Use all points" button
- "Clear" button to remove redemption
- Live discount and total recalculation via API
- Automatic clamping: can't exceed balance or order total

### Customer Account — Loyalty Page

[](#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
- Transaction history table with running balance column

Admin Features
--------------

[](#admin-features)

### Loyalty Accounts

[](#loyalty-accounts)

Grid view of all customer loyalty accounts with balance, lifetime points, tier, and status. Click through to a detail page showing full transaction history.

### Manual Point Adjustment

[](#manual-point-adjustment)

From any loyalty account detail page, admins can add or deduct points with a required reason field. Creates an `Adjust` type transaction in the ledger.

### Tier Management

[](#tier-management)

Full CRUD for loyalty tiers under **Configuration &gt; Loyalty Tiers**:

FieldDescriptionCodeUnique identifier (e.g., `BRONZE`)NameDisplay name (e.g., "Bronze")Min PointsLifetime points threshold to reach this tierMultiplierEarning multiplier (e.g., 1.5x for Silver)ColorBadge color (hex, rendered in admin and shop)### Global Configuration

[](#global-configuration)

Under **Configuration &gt; Loyalty Configuration**:

- Points per currency unit
- Redemption rate (points per 1 currency unit)
- Expiry period in months
- Toggle and configure bonus events (registration, birthday, first order)

API Endpoints
-------------

[](#api-endpoints)

### Shop API

[](#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

[](#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
------------------

[](#edge-cases-handled)

- Points redemption cannot exceed available balance (clamped)
- 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)
- Points are reserved at checkout, deducted only on completion
- Cancelled/refunded orders restore redeemed points (idempotent)
- Birthday bonus awarded at most once per calendar year
- Tiers only upgrade, never demote (based on lifetime points)

Running Tests
-------------

[](#running-tests)

```
composer install
vendor/bin/phpunit
```

License
-------

[](#license)

This plugin is released under the [MIT License](LICENSE).

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance90

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

49d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e1be9cf8e271987c350c614aa618f0e68c7f7409634e51f8c8fe105490899b0f?d=identicon)[abderrahim.ghazali](/maintainers/abderrahim.ghazali)

---

Top Contributors

[![abderrahimghazali](https://avatars.githubusercontent.com/u/12643883?v=4)](https://github.com/abderrahimghazali "abderrahimghazali (29 commits)")

---

Tags

ecommerceloyaltyphpsyliussylius-pluginsymfony

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/abderrahimghazali-sylius-loyalty-plugin/health.svg)

```
[![Health](https://phpackages.com/badges/abderrahimghazali-sylius-loyalty-plugin/health.svg)](https://phpackages.com/packages/abderrahimghazali-sylius-loyalty-plugin)
```

###  Alternatives

[winzou/state-machine-bundle

Bundle for the very lightweight yet powerful PHP state machine

34010.4M15](/packages/winzou-state-machine-bundle)[stfalcon/tinymce-bundle

This Bundle integrates TinyMCE WYSIWYG editor into a Symfony2 project.

2692.9M24](/packages/stfalcon-tinymce-bundle)[sylius/taxonomy-bundle

Flexible categorization system for Symfony.

26388.2k7](/packages/sylius-taxonomy-bundle)[symfony/ai-bundle

Integration bundle for Symfony AI components

30282.3k6](/packages/symfony-ai-bundle)[sylius/inventory-bundle

Flexible inventory management for Symfony applications.

19176.7k4](/packages/sylius-inventory-bundle)[netgen/content-browser

Netgen Content Browser is a Symfony bundle that provides an interface which selects items from any kind of backend and returns the IDs of selected items back to the calling code.

14112.1k8](/packages/netgen-content-browser)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
