PHPackages                             abderrahimghazali/sylius-popup-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. abderrahimghazali/sylius-popup-plugin

ActiveSylius-plugin

abderrahimghazali/sylius-popup-plugin
=====================================

Exit-intent &amp; engagement popup system for Sylius 2.x stores, fully managed from the admin panel.

01↑2900%PHPCI passing

Since Mar 27Pushed 1mo agoCompare

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

READMEChangelog (1)DependenciesVersions (1)Used By (0)

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

Sylius Popup Plugin
===================

[](#sylius-popup-plugin)

 Exit-intent &amp; engagement popup system for [Sylius 2.x](https://sylius.com) stores, fully managed from the admin panel.

 [![CI](https://github.com/abderrahimghazali/sylius-popup-plugin/actions/workflows/ci.yaml/badge.svg)](https://github.com/abderrahimghazali/sylius-popup-plugin/actions/workflows/ci.yaml) [![Latest Version](https://camo.githubusercontent.com/05ff90579ad8047d8768b4fdcbefbfd0abb97f8c65fdbdca45cee86cde6f8cf8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6162646572726168696d6768617a616c692f73796c6975732d706f7075702d706c7567696e2e737667)](https://packagist.org/packages/abderrahimghazali/sylius-popup-plugin) [![PHP Version](https://camo.githubusercontent.com/366f3a1319d5e900f4eb7fb8260544c388323ab749c4fab7597e1f3eea4fb059/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6162646572726168696d6768617a616c692f73796c6975732d706f7075702d706c7567696e2e737667)](https://packagist.org/packages/abderrahimghazali/sylius-popup-plugin) [![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE) [![Sylius 2.x](https://camo.githubusercontent.com/47390b9b61d6f22d062322df61d2d225ceaf33f7bb75b99592c7ba766049f3e5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f73796c6975732d322e782d677265656e2e737667)](https://packagist.org/packages/abderrahimghazali/sylius-popup-plugin) [![Symfony 7.x](https://camo.githubusercontent.com/fe777aec93f146d83db2752ebd66562c8d4d1be48fa4a1477c51c0dbab74e381/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f73796d666f6e792d372e782d626c61636b2e737667)](https://packagist.org/packages/abderrahimghazali/sylius-popup-plugin) [![PHPStan Level 5](https://camo.githubusercontent.com/0729e562e10fac943b16dbb271b4af26488f779a33fc82cc3eef1e37a432c0b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230352d627269676874677265656e2e737667)](https://camo.githubusercontent.com/0729e562e10fac943b16dbb271b4af26488f779a33fc82cc3eef1e37a432c0b4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230352d627269676874677265656e2e737667)

---

Screenshots
-----------

[](#screenshots)

### Admin — Campaign List

[](#admin--campaign-list)

[![Admin Grid](docs/images/admin-grid.png)](docs/images/admin-grid.png)

### Admin — Edit Campaign (Tabbed Form)

[](#admin--edit-campaign-tabbed-form)

[![Admin Form](docs/images/admin-form.png)](docs/images/admin-form.png)

### Shop — Modal Popup (Exit Intent)

[](#shop--modal-popup-exit-intent)

[![Popup Modal](docs/images/popup-modal.png)](docs/images/popup-modal.png)

Features
--------

[](#features)

- **Multiple popup campaigns** — create, enable/disable, and prioritize from the admin panel
- **4 trigger types:**
    - Exit intent (mouseleave detection)
    - Time on page (configurable delay in seconds)
    - Scroll depth (configurable percentage)
    - Cart abandonment (exit intent only when cart has items)
- **Smart frequency control** — show once per session, per 24h, or per 7 days (localStorage)
- **Page targeting** — all pages, product pages, cart, or checkout
- **Audience targeting** — everyone, guests only, or logged-in users only
- **2 popup styles** — centered modal with overlay, or fixed bottom bar
- **Discount codes** — display a copyable code with one-click copy (Clipboard API)
- **Email capture** — optional email field that POSTs to a dedicated API endpoint and dispatches a `sylius_popup.email_captured` event for 3rd-party integrations
- **Full design control** — background color, text color, button color (HTML color picker in admin)
- **Rate-limited API** — email subscribe endpoint limited to 3 requests/IP/hour
- **No external JS** — pure vanilla JS via Stimulus controller
- **Twig hooks** — auto-injects into the shop layout, no template overrides needed

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

[](#requirements)

- Sylius 2.1+
- Symfony 7.0+
- PHP 8.2+

Installation
------------

[](#installation)

1. Require the plugin:

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

2. Register the bundle in `config/bundles.php` (if not auto-discovered):

```
return [
    // ...
    Abderrahim\SyliusPopupPlugin\SyliusPopupPlugin::class => ['all' => true],
];
```

3. Import routes — create `config/routes/sylius_popup.yaml`:

```
sylius_popup:
    resource: '@SyliusPopupPlugin/config/routes.yaml'
```

4. Generate and run the migration:

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

5. Register the Stimulus controller in `assets/shop/controllers.json`:

```
{
    "controllers": {
        "@abderrahimghazali/sylius-popup-plugin": {
            "popup": {
                "enabled": true,
                "fetch": "eager"
            }
        }
    }
}
```

6. Symlink the plugin assets and rebuild:

```
# Create the symlink (from your project root)
mkdir -p node_modules/@abderrahimghazali
ln -s ../../vendor/abderrahimghazali/sylius-popup-plugin/assets node_modules/@abderrahimghazali/sylius-popup-plugin

# Rebuild assets
yarn encore dev
```

Usage
-----

[](#usage)

### Admin Panel

[](#admin-panel)

Navigate to **Marketing &gt; Popup Campaigns** in the Sylius admin sidebar.

Create a new campaign with three configuration tabs:

TabFields**Content**Name, title, body text, CTA button label &amp; URL, discount code, email capture toggle**Design**Style (modal/bar), background color, text color, button color**Targeting**Trigger type &amp; params, show frequency, target pages, target audience, priorityToggle campaigns on/off directly from the grid.

### Trigger Types

[](#trigger-types)

TriggerBehaviorConfigExit IntentFires when cursor leaves viewport (top edge)—Time on PageFires after N seconds`triggerDelay`Scroll DepthFires after X% page scroll`triggerScrollDepth`Cart AbandonmentExit intent, but only when cart has items—### Email Capture Event

[](#email-capture-event)

When a visitor submits their email, the plugin dispatches:

```
Event: sylius_popup.email_captured
Payload: { email, popupId }

```

Listen to this event to integrate with Mailchimp, Sendinblue, or any email service:

```
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\EventDispatcher\GenericEvent;

#[AsEventListener(event: 'sylius_popup.email_captured')]
final class EmailCapturedListener
{
    public function __invoke(GenericEvent $event): void
    {
        $email = $event->getArgument('email');
        $popupId = $event->getArgument('popupId');

        // Send to your email marketing platform
    }
}
```

### API Endpoint

[](#api-endpoint)

```
POST /api/v2/shop/popup/{id}/subscribe
Content-Type: application/json

{ "email": "visitor@example.com" }

→ 200 { "success": true }
→ 400 { "error": "Invalid email address." }
→ 429 { "error": "Too many requests. Please try again later." }

```

Rate limited to 3 requests per IP per hour.

Entity: PopupCampaign
---------------------

[](#entity-popupcampaign)

FieldTypeDescription`name`stringAdmin label (not shown to visitors)`enabled`booleanActive/inactive toggle`title`stringPopup heading`body`textPopup body content`ctaLabel`string?CTA button text`ctaUrl`string?CTA button link`discountCode`string?Copyable discount code`emailCaptureEnabled`booleanShow email input field`style`enum`modal` or `bar``backgroundColor`stringHex color (default `#ffffff`)`textColor`stringHex color (default `#111111`)`buttonColor`stringHex color (default `#000000`)`triggerType`enum`exit_intent`, `time_on_page`, `scroll_depth`, `cart_abandonment``triggerDelay`intSeconds (for time\_on\_page)`triggerScrollDepth`intPercentage (for scroll\_depth)`showFrequency`enum`session`, `day`, `week``targetPages`enum`all`, `product`, `cart`, `checkout``targetAudience`enum`everyone`, `guests`, `logged_in``priority`intHigher = shown firstArchitecture
------------

[](#architecture)

```
src/
├── Controller/
│   ├── Admin/PopupCampaignController.php    # CRUD + AJAX toggle
│   └── Shop/PopupSubscribeController.php    # Email capture API
├── DependencyInjection/
│   ├── Configuration.php
│   └── SyliusPopupExtension.php             # Prepends resources, grids, hooks
├── Entity/
│   ├── PopupCampaign.php
│   └── PopupCampaignInterface.php
├── Enum/                                     # 5 backed string enums
├── EventListener/AdminMenuListener.php       # Marketing menu item
├── Form/Type/PopupCampaignType.php          # Admin form with all fields
├── Repository/PopupCampaignRepository.php    # Targeting query
├── Service/PopupRenderer.php                 # Page/audience resolution
├── Twig/PopupRendererExtension.php          # Twig function bridge
└── SyliusPopupPlugin.php                    # Bundle class

assets/controllers/popup-controller.js        # Stimulus controller
templates/
├── admin/popup_campaign/                     # Tabbed create/update forms
└── shop/                                     # Modal + bar + renderer

```

Testing
-------

[](#testing)

```
vendor/bin/phpunit
```

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

###  Health Score

20

—

LowBetter than 14% of packages

Maintenance60

Regular maintenance activity

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 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.

### 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 (27 commits)")

---

Tags

exit-intentmarketingphppopupsyliussylius-pluginsymfony

### Embed Badge

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

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

PHPackages © 2026

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