WP Manifestindependent plugin directory
manifest / content / whimsical-promo

Whimsical Promo

Editor-managed promo cards (newsletter, app, custom CTAs) rendered at theme hooks or on exit intent, with client-side chaining, cookies, and dataLayer/gtag tracking.

by XWP · github.com/xwp/whimsical-promo · website

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/xwp/whimsical-promo/archive/refs/heads/main.zip

Readme

Whimsical Promo

Editor-managed promo cards — newsletter sign-ups, app pitches, any CTA — rendered after the post body, at a theme hook of your choosing, or on exit intent: the cursor leaving the window on desktop, and optionally the end of the article on a coarse-pointer device. Copy, design and targeting all live in the block editor, so changes ship without a deployment.

Activate per site from the Plugins screen. Deactivating is the kill switch: no promo markup, no assets.

What it looks like

Both of these are the same plugin, authored entirely in the block editor — the copy, the button and the design are editor settings, not code.

An inline promo card below an article body: a small sparkle divider, the heading "Everything here, in your pocket", two paragraphs of copy and a "Download the app" button, on a bordered off-white card

Inline placement: the card renders at a theme hook inside the post, in the content column. A paragraph holding only a link becomes the button.

An exit-intent panel over an article: a rounded white panel with a pink gradient along its top edge, a close control, the heading "One email. Every Friday. Nothing else." and a black "Sign me up" pill button

Exit-intent placement with the slide-down presentation: it arrives when the cursor leaves the top of the window on desktop, and closes with the ×. Same authoring, different placement and style.

Installation

The plugin lives at github.com/xwp/whimsical-promo and installs with Composer. From the site repo root:

composer config repositories.whimsical-promo vcs https://github.com/xwp/whimsical-promo
composer require xwp/whimsical-promo:dev-main

composer/installers reads the repo's installer-paths and drops it in the plugins directory — plugins/whimsical-promo/ in the VIP Go mirror. There is no build step, so nothing needs compiling afterwards.

Without Composer, clone the repo into wp-content/plugins/whimsical-promo/.

Requires PHP 8.1+.

Upgrading to 1.2

Nothing to do, and nothing to rewrite. Two behaviour changes worth knowing about before you see them in the numbers:

  • Overlays are now rate-limited site-wide. After any exit-intent promo opens, none opens again for 15 minutes. On a site running a single overlay this is close to invisible; on a site running two it is the difference between a fallback and a nuisance. See The quiet period.
  • Exit-intent chain order has a control of its own, Show this one first, instead of depending on Order and publication date. Existing promos are unflagged, so their order is exactly what it was.

Upgrading from 1.0

1.1 renames what the plugin puts on the page, at the client's request, so that nothing in the rendered document reads as advertising:

1.0 1.1
whim-promo, whim-promo__card, whim-promo--… whim-bogo, whim-bogo__card, whim-bogo--…
#whim-promo-<id> #whim-bogo-<id>
whimsical_promo event, promo_* parameters whimsical_bogo event, bogo_* parameters
window.whimPromoCfg window.whimBogoCfg

Nothing is rewritten for you, deliberately. Any Custom CSS stored on a promo, and any theme CSS targeting .whim-promo…, has to be updated by hand — search for whim-promo and replace with whim-bogo. A promo whose Custom CSS still uses the old prefix keeps rendering, but with promo-base.css and nothing else — Custom CSS replaces the selected style rather than adding to it, so once its selectors stop matching there is no design left underneath. The damage is obvious rather than silent, which is the point. (An automatic rewrite was tried and dropped: telling a selector from a value that merely contains the same word means parsing the CSS, and getting that wrong corrupts a working stylesheet — url("#whim-promo-filter") is a value, not a selector.)

Analytics is not migrated either — rename the variables, trigger and parameters in GTM/GA4 to match. The data-whim-* attributes and the whim_seen_<slug> cookies are unchanged, so nobody's frequency capping resets.

The plugin directory and its asset filenames still say whimsical-promo, since those are the repository's name. If the word has to disappear from request paths too, that is a repo rename and a Composer package rename — say so and it can be done as its own change.

How a promo works

  1. Create Promos → Add New. The title is for the admin list only; the body is the card content, edited with regular blocks.
  2. Fill in Promo Settings (below the editor).
  3. Publish. Drafts, pending and scheduled promos never render.

Promos on the same hook form a chain. The first promo the visitor has not already interacted with wins; the rest stay hidden. So the "already subscribed?" fallback is simply the next promo in the chain.

Chain order comes from the Order field (Page Attributes), and promos left on the same Order — which is all of them until you change it — queue newest first. Every exit-intent promo shares one chain regardless of hook, and for those there is a plainer control: tick Show this one first and that promo leads, whatever the dates say (see below).

A promo with Stop showing once the visitor clicks or submits unticked is always visible: it wins as soon as the chain reaches it, whatever the cookies say, and nothing after it can ever show. That is how you build a permanent fallback — and why it has to be last.

Promos on different hooks are not a chain. They are independent slots and all of them render, which is the usual reason a hand-off appears not to work.

Promo Settings reference

Field What it does
Placement Inline renders at a theme hook. Exit intent renders in the footer and appears when the cursor leaves the top of the window (desktop). To turn a promo off, set its status back to Draft — only published promos are placed on the site.
Preview The whim_preview=<slug> query string for this promo, with a Copy button. Add it to any page the promo appears on to open it on demand (see below).
Hook name whim_after_content — the default — appends the promo to the post body, so a fresh install needs no theme work. Otherwise any action hook your theme fires inside the post. Suggestions come from the whimsical_promo_hooks filter and a new promo starts on the first one, so a theme that filters its own hooks to the front sets the default. A few hooks are refused (see below).
Show on these post types Public post types the promo may appear on. Nothing checked = never renders.
Stop showing once the visitor clicks or submits Sets a whim_seen_<slug> cookie, which hands off to the next promo in the chain on later visits. Inline promos set it on click or submit; exit-intent promos set it as soon as they open (see below). Unchecked = shows every visit, never hands off.
Remember for (days) How long an interaction is remembered, counted from it. Only shown while the box above is ticked; emptying it or setting 0 unticks that box, which is how a promo becomes always-visible. Default 30.
Show this one first Moves this promo to the front of the exit-intent queue, so a promoted overlay goes ahead of a campaign that runs all year without either being unpublished. Only one promo can hold it: ticking the box unticks it everywhere else. Exit intent only, off by default (see below).
Exit-intent presentation slide-down, slide-up or modal (only modal dims the page). Exit intent only.
Also trigger on mobile… Opens the promo when the reader reaches the end of the article, since a phone has no cursor to leave the page. Exit intent only, off by default (see below).
Animation slide-up-spring, slide-down-spring, fade-rise or none. The spring pair differ only in which way the card travels — pick the one that matches the edge it enters from. Readers who ask for reduced motion always get a plain crossfade.
Style The design this promo ships with (see below). Defaults to basic-1.
Custom CSS This promo's CSS, replacing the style's own. Administrators only. Empty means the selected style ships as designed.
Colour and shape overrides Any CSS value per token — hex, rgba(), var(--your-token), gradients. These land in the wrapper's style attribute, so they beat both the style and Custom CSS.

Override values containing ;, {, }, <, >, @, \, url(, expression(, a comment marker, a control character, or more than 200 bytes are rejected on save: an admin notice names the fields, and the previous value is kept.

Hooks that are refused

wp_head, wp_footer, shutdown, template_redirect, wp_enqueue_scripts, the_content, the_title and the_excerpt are cleared on save, and dropped from the suggestion list even if a theme adds them. Each one breaks the page rather than the promo: wp_head puts a card in <head>, wp_footer is where the exit-intent chain already renders, shutdown prints after </html>, the two early actions print before the document opens, and the three filters print above the value they filter rather than after it. Use whim_after_content instead of the_content.

Every other name is allowed, including one your theme has not fired yet. A hook that never fires renders nothing, and a name that turns out to be a filter is handed its value back untouched — so a typo can cost you the promo, never the page.

Read the full README on GitHub →

Releases

TagPublished
1.3 Aug 13, 2026
1.2 Aug 6, 2026
1.1 Aug 6, 2026
1.0 Aug 4, 2026

These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.