Emerge Campaigns

Description

Emerge Campaigns turns WordPress into a self-hosted email-marketing tool. Build contact lists from your existing WordPress audience, group them into static or dynamic segments, author HTML emails in the block editor, schedule one-off or recurring campaigns, and track opens, clicks, and unsubscribes — all without leaving wp-admin.

Sends dispatch through WordPress’s standard wp_mail() function, so the plugin works with whatever mail transport your site is already configured for — host SMTP, a transactional service plugin, or PHP’s default mail.

Key features

  • Contacts from your existing WordPress audience — daily background sync pulls in WordPress users, comment authors, WooCommerce customers, Easy Digital Downloads customers, Jetpack contact form submissions, Jetpack Subscriptions, MailPoet subscribers, Newsletter Plugin subscribers, Contact Form 7 (via Flamingo) submissions, and Gravity Forms entries. Each source is opt-in from the settings screen. Manual add is supported from the Contacts screen.
  • Static and dynamic segments — static segments are manually-curated lists. Dynamic segments are rule-based (status, source, subscribed-at) and re-evaluated at send time, so membership stays current as new contacts arrive.
  • Block-editor email templates — author emails using Gutenberg, including Query Loop blocks to pull recent posts into newsletters. Mustache-style merge tags ({{first_name}}, {{email}}, {{site_name}}, {{unsubscribe_url}}, {{view_in_browser_url}}) substituted at send time. Starter newsletter and receipt block patterns included in a dedicated email category.
  • Broadcasts and Newsletters — two dedicated surfaces over the same engine. Broadcasts are one-time sends: draft scheduled sending sent / paused / cancelled, with schedule-for-later, pause/resume in-flight, and duplicate-as-draft. Newsletters are recurring series: pick a daily / weekly / monthly cadence and a send time, and a background sweeper spawns each issue automatically, picking up template and segment changes on the parent.
  • Newsletter issue log & smart resend — every newsletter keeps a read-only Issues log (the original send plus each recurring issue, numbered to match the subject line), with pause/stop controls for an issue that’s mid-send. An opt-in “send only if content changed” gate re-renders the template each run and skips the send when nothing meaningful changed — nonces, per-render ids, and insignificant whitespace are normalized out so only genuine content changes trigger a new issue.
  • Background batched sending — Action Scheduler chained batches with a configurable per-minute throttle (default 2/min ≈ 120/hour) to stay within mail-provider rate limits. Action Scheduler is bundled — no separate install required.
  • Resilient failure handling — syntactically invalid email addresses are skipped per-recipient rather than failing the whole campaign. When the underlying mail transport breaks (N consecutive wp_mail() failures, configurable in Settings Sending), the campaign auto-pauses and resets failed sends back to pending so they aren’t lost.
  • Retry failed sends — one-click button on the campaign edit screen re-queues transport failures once delivery is healthy again. Legitimate skips (unsubscribed, missing contact, invalid address) are not re-queued.
  • Emerge Subscribe — public-facing signup form — accept new subscribers in three interchangeable ways: a [emerge_campaigns_subscribe] shortcode, an “Emerge Subscribe” block in the block editor, or an “Emerge Subscribe” classic widget. Same configuration shape across all three (heading, description, button label, optional first/last name fields, optional consent text). Submissions are tagged with the emerge_subscribe source and recorded with explicit consent so they’re identifiable in segment rules.
  • Progressive-enhancement AJAX submit — the subscribe form posts to a REST endpoint via vanilla JavaScript and renders the result inline with no page reload. Falls back cleanly to a classic POST + redirect path when JavaScript is disabled or fails to load. Same nonce, same validation, only the transport differs.
  • Spam controls on the subscribe form — nonce verification, hidden honeypot field, and a per-IP rate limit (default 5/hour, filterable).
  • Test sends and preview — send a test to any address from the campaign edit screen with full merge-tag substitution. Preview templates in the browser before assigning them to a campaign.
  • Per-recipient tokens — every send gets a unique token used for unsubscribe, view-in-browser, open-pixel, and click-tracking URLs. No shared secrets, no guessable URLs.
  • RFC 8058 one-click unsubscribeList-Unsubscribe-Post headers so Gmail and Apple Mail show a native unsubscribe button.
  • Built-in analytics — open pixel, click redirect, and unsubscribe events recorded locally in your own database. Per-campaign stats (sent, opens, unique opens, clicks, unique clicks, unsubscribes, rates) and per-contact send history visible inside wp-admin.
  • Privacy-conscious tracking — IP addresses are stored as a salted SHA-256 hash, never in the clear. Open pixel is opt-out via the wrapper filter.
  • Bounce & complaint handling — when the companion Emerge Mail plugin is active, Emerge Campaigns consumes its emerge_mail_bounce_received events and reflects them onto contacts: hard bounces and complaints are suppressed (dropped from the mailable audience and hidden from the default Contacts view), soft bounces are marked but kept mailable. Optional, guarded cleanup on a hard bounce can delete a linked WordPress user (reassigning their content) and reassign the address’s anonymous comments to a fallback user.
  • Authenticated subscribe webhook — besides the public form, an API-key-protected REST endpoint (POST /wp-json/emerge-campaigns/v1/webhook/subscribe, x-api-key header) lets external systems add contacts programmatically. Generate or revoke the key from Settings; webhook signups are tagged with the webhook source.

How it works

When you activate the plugin, it creates its own custom database tables for contacts, segments, campaigns, sends, and events. A daily background job populates your contacts from whichever sources you’ve enabled under Settings.

You author email templates in the block editor. When you build a campaign, you pick a template and a segment; on send, the segment is snapshotted into per-recipient send records (one per recipient, idempotent so re-runs never duplicate). A background worker picks up batches of pending sends, renders the template with each recipient’s merge context, dispatches via wp_mail(), and records the result.

Recurring campaigns are driven by a small sweep job: at each interval (daily / weekly / monthly), the sweeper duplicates the parent campaign as a fresh child and queues it for send. The parent stays editable, so changes to the template or segment propagate to the next occurrence.

Public signups via the subscribe shortcode / block / widget are inserted directly into the contacts table with explicit consent and the source emerge_subscribe, so they show up in the Contacts list table and can be targeted by segment rules.

Tracking is opt-out via the wrapper filter. By default, every email includes a 1×1 pixel that hits ?emerge_open=<token> when loaded, and rewritten link targets that hit ?emerge_click=<token>&url=<encoded> before redirecting to the real destination.

What this is not

  • Not a SaaS — nothing is hosted off your site. All data, including tracking events, lives in your database.
  • Not an SMTP plugin — Emerge Campaigns hands sends to WordPress’s wp_mail() and lets your existing mail configuration take it from there.
  • Not a transactional-only tool — wp_mail() calls from other plugins (password resets, order receipts) are not intercepted. This plugin is for outbound campaigns you compose and send yourself.

External services

Emerge Campaigns does not contact any external service. All sending, tracking, and storage stays on your WordPress site.

Sends are dispatched via WordPress’s wp_mail() function. Whatever delivery mechanism your site is configured for — PHP’s default mail, host SMTP, or another plugin that hooks wp_mail — handles the actual transport. Emerge Campaigns does not call any third-party API directly.

Blocks

This plugin provides 1 block.

  • Emerge Subscribe Email subscription form. Submissions are added to Emerge Campaigns as contacts.

Installation

  1. Upload the emerge-campaigns folder to /wp-content/plugins/, or install via the Plugins screen.
  2. Activate the plugin from the Plugins menu.
  3. Action Scheduler is bundled — no separate install is needed for reliable background sending.
  4. Visit Emerge Campaigns Settings and pick which contact sources to sync from. Then visit Emerge Campaigns Contacts — the first sync runs an hour after activation; click Sync now to populate immediately.
  5. Author your first template under Emerge Campaigns Templates and build a campaign under Emerge Campaigns Campaigns.
  6. To accept public signups, drop the [emerge_campaigns_subscribe] shortcode on a page, add the “Emerge Subscribe” block in the editor, or add the “Emerge Subscribe” widget to a sidebar.

FAQ

How do sends actually get delivered?

Emerge Campaigns dispatches every send via WordPress’s wp_mail() function — the same function any other WordPress plugin uses to send email. Whatever transport your site is already configured for (host SMTP, a transactional-email plugin, or PHP’s default mail) handles the actual delivery. Deliverability depends on that configuration.

Where do contacts come from?

A daily background sync pulls from whichever sources you enable in Settings: WordPress users, comment authors, WooCommerce customers, Easy Digital Downloads customers, Jetpack contact form submissions, Jetpack Subscriptions, MailPoet subscribers, Newsletter Plugin subscribers, Contact Form 7 submissions (via Flamingo), and Gravity Forms entries. You can also add contacts manually from the Contacts screen, and accept self-signups via the Emerge Subscribe form (shortcode, block, or widget).

What’s the difference between static and dynamic segments?

A static segment is a manually-curated list — pick the contacts you want, save the segment, those contacts are members until you remove them. A dynamic segment is a rule definition (e.g. “source = woocommerce AND subscribed_at >= 2026-01-01”) evaluated at send time, so membership stays current as new contacts arrive.

What’s the difference between a Broadcast and a Newsletter?

A Broadcast is a one-time send — compose it, pick an audience, and send now or schedule it for later. A Newsletter is a recurring series: you choose a daily / weekly / monthly cadence and a time of day, and a background sweep spawns each issue automatically. Newsletters have their own menu and a read-only Issues log showing every issue that’s gone out. Both are built on the same engine; they’re just separated so the one-off and ongoing workflows stay uncluttered.

Can I send recurring newsletters?

Yes — that’s what the Newsletter surface is for. Set a daily, weekly, or monthly cadence with a send time; a background sweep job spawns the next issue as a fresh child campaign at each interval. The parent stays editable, so changes to the template or segment propagate forward. By default a new issue is only spawned when the rendered content has actually changed since the last one (an opt-out “send only if content changed” checkbox) — ideal for newsletters that pull dynamic content like recent posts. You can pause or stop the series at any time.

What happens when an address bounces or reports spam?

If the companion Emerge Mail plugin is delivering your mail, it reports bounces and complaints back to Emerge Campaigns. A hard bounce or spam complaint suppresses the contact — it’s dropped from the mailable audience and hidden from the default Contacts view — while a soft bounce is marked but kept mailable. On a hard bounce you can optionally (off by default) delete a linked WordPress user, reassigning their content, and reassign the bounced address’s anonymous comments to a fallback user. Without Emerge Mail, this is simply inactive.

Can I use Query Loop blocks in email templates?

Yes. Templates render through the same the_content filter pipeline as front-end posts, so Query Loop and any other block that works in posts works in emails. This is especially useful for newsletter templates that pull in recent posts dynamically.

How do I add a subscribe form to my site?

Three ways, all interchangeable: drop the [emerge_campaigns_subscribe] shortcode anywhere on a post or page; add the “Emerge Subscribe” block in the block editor; or add the “Emerge Subscribe” widget to a sidebar or block-based widget area. All three render the same form, accept the same options (heading, description, button label, optional first/last name fields, optional consent line), and submit to the same endpoint. Submissions land in the Contacts table with source emerge_subscribe.

Does the subscribe form work without JavaScript?

Yes. With JavaScript enabled, submissions go through a small vanilla-JS module that posts to a REST endpoint and renders the result inline with no page reload. With JavaScript disabled or blocked, the same form falls back to a classic POST + redirect that surfaces the same result inline on the next render. Same nonce, same validation, only the transport differs.

How does unsubscribe work?

Every send has a unique token. The token is used to build a per-recipient unsubscribe URL placed in both the email body ({{unsubscribe_url}}) and the List-Unsubscribe header. Mail clients that support RFC 8058 (Gmail, Apple Mail) show a native one-click unsubscribe button that POSTs to the URL without a browser round-trip.

How are opens and clicks tracked?

Opens are tracked via an invisible 1×1 pixel placed at the bottom of every email. Clicks are tracked by rewriting <a href> targets to a redirect URL on your site, which records the click and 302-redirects to the real destination. Tracking can be disabled site-wide by replacing the wrapper template via the emerge_campaigns_email_wrapper filter.

How is recipient privacy protected?

IP addresses are never stored in the clear. When a recipient opens an email or clicks a link, their IP is salted (with wp_salt('auth')) and SHA-256 hashed before it’s recorded with the event. The hash is stable per-site (so we can count unique recipients) but the raw IP can’t be recovered. User agents are stored verbatim for delivery diagnostics, capped at 255 characters.

What happens if a send fails?

The send row is marked failed with the error stored alongside it. Failed sends show on the campaign edit screen with recipient email and error reason — up to the 50 most recent. The campaign keeps sending; one failure doesn’t pause the whole batch.

Syntactically invalid email addresses and per-recipient bounces are recorded as terminal failures (invalid_email, recipient_bounced) and skipped — they don’t pause the campaign. But if N consecutive wp_mail() calls return false from the same transport (default 10, configurable in Settings Sending, set to 0 to disable), the campaign auto-pauses and the burst of failures is reset to pending so nothing is lost. A Retry failed sends button on the campaign edit screen lets you re-queue them once delivery is healthy.

Can I throttle sends to stay within mail-provider rate limits?

Yes. Set Maximum sends per minute on Emerge Campaigns Settings. The send worker clamps each batch to the remaining budget and defers to the start of the next minute when exhausted. Default is 2 (≈ 120/hour); set to 0 for unlimited. Smaller per-minute batches keep each Action Scheduler dispatch short and resilient to provider latency spikes.

Is `wp_mail` modified or replaced by this plugin?

No. Campaigns are dispatched via wp_mail() like any other plugin’s email, so transactional wp_mail() calls from elsewhere in WordPress are unaffected.

How do I remove all data on uninstall?

Deleting the plugin from the Plugins screen runs uninstall.php, which drops all six custom tables, deletes plugin options, and clears all scheduled jobs.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“Emerge Campaigns” is open source software. The following people have contributed to this plugin.

Contributors

Translate “Emerge Campaigns” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

1.0.0

First public release.

  • Contacts table with daily background sync from WordPress users, comment authors, WooCommerce customers, Easy Digital Downloads customers, Jetpack contact form submissions, Jetpack Subscriptions, MailPoet subscribers, Newsletter Plugin subscribers, Contact Form 7 (Flamingo) submissions, and Gravity Forms entries. Each source toggleable from settings; manual add supported.
  • Static segments (manual contact picker) and dynamic segments (rule builder over status / source / subscribed_at), re-evaluated at send time.
  • Email templates authored as custom posts in the block editor, with merge tags, starter block patterns (newsletter + receipt), test-send, and preview.
  • Broadcasts — one-time sends with the full draft / scheduled / sending / sent / paused / cancelled lifecycle, schedule-for-later, pause/resume in-flight, and duplicate-as-draft.
  • Newsletters — recurring series on a daily / weekly / monthly cadence with a send time, spawned automatically by a background sweep. Read-only per-series Issues log with pause/stop controls for an in-flight issue, and an opt-in “send only if content changed” gate that uses normalized-render hashing so nonces, per-render ids, and whitespace never trigger spurious issues.
  • Background batched send worker via bundled Action Scheduler, with a settings-configured per-minute throttle (default 2/min ≈ 120/hour).
  • Per-recipient skip codes (invalid_email, recipient_bounced) so per-contact data problems don’t pause healthy campaigns.
  • Dead-end auto-pause: when N consecutive transport failures occur (default 10, configurable), the campaign auto-pauses and the burst of failures resets back to pending. One-click “Retry failed sends” re-queues transport failures once delivery is healthy.
  • Bounce & complaint handling: consumes the companion Emerge Mail plugin’s emerge_mail_bounce_received events — hard bounces and complaints suppress the contact, soft bounces are marked but kept mailable — with optional, guarded hard-bounce cleanup (delete a linked WordPress user with content reassignment; reassign the address’s anonymous comments to a fallback user).
  • Per-recipient send tokens for unsubscribe, view-in-browser, open-pixel, and click-tracking URLs. RFC 8058 List-Unsubscribe / List-Unsubscribe-Post headers for native one-click unsubscribe in Gmail and Apple Mail.
  • Open-pixel + click-redirect tracking recorded in your own database; IPs stored only as salted SHA-256 hashes. Per-campaign stats (sent, opens, unique opens, clicks, unique clicks, unsubscribes, rates) and per-contact send history on the admin screens.
  • Emerge Subscribe: public signup form available three ways — [emerge_campaigns_subscribe] shortcode, “Emerge Subscribe” block, and classic widget — all sharing identical output and configuration, with progressive-enhancement AJAX submit and a no-JS POST + redirect fallback. Spam controls: nonce verification, hidden honeypot, and a per-IP rate limit (default 5/hour, filterable).
  • Authenticated subscribe webhook: API-key-protected REST endpoint (POST /wp-json/emerge-campaigns/v1/webhook/subscribe, x-api-key header) for adding contacts programmatically; webhook signups tagged with the webhook source.
  • Extension points for integrators: emerge_campaigns_subscribed, emerge_campaigns_bounce_recorded, emerge_campaigns_dead_end_paused, and emerge_campaigns_email_wrapper.