abderrahimghazali / sylius-popup-plugin
Exit-intent & engagement popup system for Sylius 2.x stores, fully managed from the admin panel.
Package info
github.com/abderrahimghazali/sylius-popup-plugin
Type:sylius-plugin
pkg:composer/abderrahimghazali/sylius-popup-plugin
Requires
- php: ^8.2
- doctrine/orm: ^2.17 || ^3.0
- sylius/sylius: ^2.1
- symfony/framework-bundle: ^7.0
- symfony/rate-limiter: ^7.0
- symfony/stimulus-bundle: ^2.0
Requires (Dev)
- phpunit/phpunit: ^10.0
- symfony/test-pack: ^1.0
This package is auto-updated.
Last update: 2026-03-28 00:10:37 UTC
README
Sylius Popup Plugin
Exit-intent & engagement popup system for Sylius 2.x stores, fully managed from the admin panel.
Screenshots
Admin — Campaign List
Admin — Edit Campaign (Tabbed Form)
Shop — Modal Popup (Exit Intent)
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_capturedevent 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
- Sylius 2.1+
- Symfony 7.0+
- PHP 8.2+
Installation
- Require the plugin:
composer require abderrahimghazali/sylius-popup-plugin
- Register the bundle in
config/bundles.php(if not auto-discovered):
return [ // ... Abderrahim\SyliusPopupPlugin\SyliusPopupPlugin::class => ['all' => true], ];
- Import routes — create
config/routes/sylius_popup.yaml:
sylius_popup: resource: '@SyliusPopupPlugin/config/routes.yaml'
- Generate and run the migration:
bin/console doctrine:migrations:diff bin/console doctrine:migrations:migrate
- Register the Stimulus controller in
assets/shop/controllers.json:
{
"controllers": {
"@abderrahimghazali/sylius-popup-plugin": {
"popup": {
"enabled": true,
"fetch": "eager"
}
}
}
}
- 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
Admin Panel
Navigate to Marketing > Popup Campaigns in the Sylius admin sidebar.
Create a new campaign with three configuration tabs:
| Tab | Fields |
|---|---|
| Content | Name, title, body text, CTA button label & URL, discount code, email capture toggle |
| Design | Style (modal/bar), background color, text color, button color |
| Targeting | Trigger type & params, show frequency, target pages, target audience, priority |
Toggle campaigns on/off directly from the grid.
Trigger Types
| Trigger | Behavior | Config |
|---|---|---|
| Exit Intent | Fires when cursor leaves viewport (top edge) | — |
| Time on Page | Fires after N seconds | triggerDelay |
| Scroll Depth | Fires after X% page scroll | triggerScrollDepth |
| Cart Abandonment | Exit intent, but only when cart has items | — |
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
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
| Field | Type | Description |
|---|---|---|
name |
string | Admin label (not shown to visitors) |
enabled |
boolean | Active/inactive toggle |
title |
string | Popup heading |
body |
text | Popup body content |
ctaLabel |
string? | CTA button text |
ctaUrl |
string? | CTA button link |
discountCode |
string? | Copyable discount code |
emailCaptureEnabled |
boolean | Show email input field |
style |
enum | modal or bar |
backgroundColor |
string | Hex color (default #ffffff) |
textColor |
string | Hex color (default #111111) |
buttonColor |
string | Hex color (default #000000) |
triggerType |
enum | exit_intent, time_on_page, scroll_depth, cart_abandonment |
triggerDelay |
int | Seconds (for time_on_page) |
triggerScrollDepth |
int | Percentage (for scroll_depth) |
showFrequency |
enum | session, day, week |
targetPages |
enum | all, product, cart, checkout |
targetAudience |
enum | everyone, guests, logged_in |
priority |
int | Higher = shown first |
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
vendor/bin/phpunit
License
MIT. See LICENSE.


