Popups
Create lightboxes, floating bars and inline messages with WordPress blocks.
Quick start
- Go to XPAC → Popups → All Popups.
- Click Add New Popup.
- Build the popup with normal WordPress blocks.
- Open Display Rules in the editor sidebar.
- Add a rule: choose Lightbox, add an Everywhere page condition, and select Time on Page → is immediate as the opening trigger.
- Save the rule, then publish the popup. Visit a matching page to check it.
A popup with no rule will not open by itself. You can still open it with a Popup Selector block.
Popup types
| Type | What it does |
|---|---|
| Lightbox | Opens over the page with a dimmed background. |
| Floating Bar | Stays at the top or bottom of the window. |
| Inline | Prints inside the page before the header or after the footer. |
Display rules
Every rule answers three questions:
- Where? Choose the pages, posts, URLs or query strings.
- When? Choose a trigger.
- How? Choose the popup type, position, animation and close button.
You can add more than one rule to a popup. A rule must be enabled and inside its start/end dates.
Inline popups need a page condition but do not need a trigger. Combine conditions with any (OR) or all (AND). Keep the first rule simple and add targeting after confirming it opens. Dates use the WordPress site timezone; an end date includes that whole day. Leave either date blank for an open-ended schedule.
Frequency
For lightboxes and floating bars, under How often, set Dismiss for to a waiting period and choose whether to count opens or closes. Set both the delay and the count. For example, 7 days if popup closed 1 times waits seven days after the visitor closes it before showing it automatically again. Clear both numeric fields to remove the frequency limit.
Frequency is remembered in this browser using local storage. A visitor who clears site data, blocks storage or uses another browser can see the popup again.
Triggers
| Trigger | Opens when |
|---|---|
| Exit Intent | The pointer leaves through the top of the window. |
| Time on Page | The page opens or a timer ends. |
| Scroll Distance | The visitor reaches a percentage or pixel depth. |
| HTML Element | A selector is clicked, hovered or receives a custom event. |
| Inactivity | The visitor is idle for the chosen time. |
| Page Views | The visitor reaches the chosen page count in this session. |
Exit intent requires a mouse or similar pointer and does not provide a touch gesture. Use another trigger for touch devices. Inactivity resets when the visitor interacts with the page. Page-view and visit limits use tab-session storage; they are not counts of unique people across devices. Page Views includes earlier pages in the same tab, including pages where the popup is not shown.
Closing
- Close button, Close on Escape and Close on click outside (lightbox only) can each be switched off.
- A lightbox keeps at least one of the three on. The last one left can't be switched off, unless a button in the content closes the popup.
- A button or link with class
xpac-popup-cta-closecloses its popup. - Escape closes the active popup. With stacked popups, it dismisses one at a time. It closes an inline popup only while focus is inside it.
Popup Selector block
Use the Popup Selector block when a visitor should choose to open a popup.
- Add the block to a post or template.
- Select a published popup.
- Put a button, image or other blocks inside it.
The inner content becomes the opener. Use a Button or link for an opener that is naturally keyboard accessible. The block can open published content without automatic display rules. It bypasses automatic frequency and visit limits because the visitor requested it; Pause all popups and excluded paths still apply.
Opening the same popup as a lightbox and then as a floating bar switches its presentation and keeps any form entries. Different popups can remain open together; keyboard focus stays in the active lightbox.
Site settings
Go to XPAC → Popups → Settings. These settings apply to the whole site. Use the popup editor for an individual popup's design and display rules. Changes take effect after Save Changes; Discard restores the last saved values.
| Setting | Meaning |
|---|---|
| Pause all popups | Stops popups without deleting rules. |
| Most popups on one page | Maximum automatic popups eligible on a page, from 1 to 20. 0 means unlimited. |
| Most popups in one visit | Maximum distinct automatic popups per tab session, from 1 to 20. 0 means unlimited. Reopening the same popup does not consume another slot. |
| Count how popups perform | Turns anonymous counters on or off. |
| Never show popups on these paths | Disables popups on exact paths or path prefixes. |
The per-page limit includes inline popups. Per-visit and repeat-appearance limits apply to lightboxes and floating bars; inline content is rendered with the page.
Path examples:
/checkout
/account/*/checkout matches one path, with or without a trailing slash. /account/*
matches /account and its descendants, but does not match /accounting.
Only a trailing wildcard is supported. Matching ignores query strings. On a
site installed at /blog, enter paths relative to that installation, such as
/checkout for /blog/checkout.
Clear your full-page cache after changing settings, rules or schedules. Cached pages can contain the previous popup configuration until they are refreshed.
Statistics
The Overview shows four counts:
- Could have opened — the popup was available on the page.
- Opened — the popup appeared.
- Closed — the visitor dismissed it.
- Clicked — the visitor clicked an eligible link, button or submit control inside it; close controls are excluded.
Each count is recorded at most once per popup per page view. Editors are not counted. Popup-level totals and per-rule breakdowns are counted separately; adding the rule rows together does not give a popup's total.
Counts are sent when the page is hidden or left. Browser/network failures and content blockers can prevent delivery. These are engagement counts, not confirmed purchases or an audit log. The stats table stores daily aggregates by popup, rule and device bucket, without visitor identities. Turning counting off stops new counts without deleting existing totals.
Styling
A popup's content sits in a Popup box block. Select it to set the popup's width (Small, Medium, Large, Auto or a custom size) and its background, padding, border, radius and shadow. The editor shows the box as visitors see it.
- A lightbox opens at the box's width, never wider than the screen.
- A floating bar or inline popup stays full width. The box's background fills the bar and the content is centred at the box's width.
- Auto keeps the popup's default width, the theme's content size.
Until you change the box, popups use the active theme's theme.json values
for the surface, text, content size, spacing and shadow. Blocks inside the
popup keep their normal WordPress styles.
The plugin only supplies the popup frame, placement, overlay and close button. It does not force a brand palette or font.
Add a class under Advanced → Additional CSS Class(es) in the popup editor sidebar when one popup needs a custom look:
.sale-popup {
--xpac-pp-width: 38rem;
--xpac-pp-container-padd: 3rem;
--xpac-pp-shadow: var(--wp--preset--shadow--deep);
}Useful variables:
| Variable | Controls |
|---|---|
--xpac-pp-width | Lightbox width. |
--xpac-pp-space-x | Space from the left and right edges. |
--xpac-pp-space-y | Space from the top and bottom edges. |
--xpac-pp-container-bg | Popup surface color. |
--xpac-pp-container-color | Popup text/close color. |
--xpac-pp-container-padd | Inner padding. |
--xpac-pp-overlay-bg | Lightbox overlay color. |
--xpac-pp-shadow | Popup shadow. |
Use WordPress preset variables where possible. This keeps the popup correct when the site switches styles or color schemes.
Accessibility
- Lightboxes use a modal dialog, move focus inside and trap Tab until closed.
- Closing returns focus to the element that opened the popup.
- Floating and inline popups use a named region and do not trap focus.
- Background content becomes inert only while a lightbox is open.
- Reduced-motion preferences replace movement with a short fade.
Import and export
Use Export as JSON from the popup list. Use Import to preview a file before creating anything.
Published popups become drafts on import; draft, pending and private statuses are preserved. Review their page IDs, URLs, content and enabled display rules on the destination site before publishing. JSON transfers content and configuration; it does not copy media files or statistics between sites.
Troubleshooting
The popup never opens
Check these in order:
- The popup is published.
- The rule is enabled.
- The rule has a page condition.
- A lightbox or floating bar has a trigger.
- The schedule includes today.
- Popups are not paused.
- The current path is not excluded.
- The automatic page/visit limit or the rule's frequency limit has not been reached. Try a fresh private tab to check this.
- The full-page cache has been cleared and the trigger matches the device.
In the Overview and popup list, review the rule status and any setup problems. For a popup opened only by a Popup Selector, test its actual opener.
The popup looks different from the editor
Put background, text and spacing styles on a Group or Cover block inside the
popup. Check whether theme CSS targets only .wp-site-blocks; popup markup is
added directly to the document body.
Inline content is missing
Try After Footer first. Before Header needs the theme to call
wp_body_open().
For developers
See the Popups hook reference for every public action and filter.
PHP extensions
Register add-on schema and configuration filters during xpac_popups_init.
For example, to disable the built-in counts for requests where your own consent
check has not granted permission:
add_filter('xpac_popups_count_visitor', function ($count, $enabled) {
return $enabled && $count && my_site_allows_popup_analytics();
}, 10, 2);my_site_allows_popup_analytics() is your site's consent check. Keep the
$enabled and $count checks to honor the global switch and editor exclusion.
Sites with full-page caching
must make sure personalized consent decisions are not shared between visitors.
Use xpac_popups_settings_updated to connect global changes to your cache purge.
Browser lifecycle events
The runtime dispatches these DOM events on document and on the popup template:
| Event | Timing |
|---|---|
xpac-popup-pre-open | Before opening the popup. |
xpac-popup-post-open | After the popup is visible and focus is set. |
xpac-popup-pre-close | Before removing the open popup. |
xpac-popup-post-close | After removal and focus restoration. |
On document, event.detail contains template and the active rule.
The post-open event also includes requested: true for an explicit block
opener. Events are notifications, are not cancelable, and are dispatched
separately on the template and document rather than bubbling. Listen on one
target to avoid handling the same transition twice.
document.addEventListener('xpac-popup-post-open', (event) => {
const { template, rule, requested } = event.detail;
const { id } = template.xpacPopup.getSettings();
// Connect id, rule.id and requested to your integration here.
});These events describe runtime lightboxes and floating bars. Server-rendered
inline regions have no template interface and do not emit this lifecycle.
JavaScript filters such as xpac-popups-triggers use @wordpress/hooks and
must be registered before the popup runtime initializes. Consult the generated
reference for each filter's parameters and return contract.