# WordPress Subscriber Sync

> Wire up the WordPress user_register hook to push every new account into an AcelleMail list. Twenty lines of PHP, no plugin dependency, real-time. This guide covers the production-ready snippet (with timeout / async / error handling) and the four common gotchas — field-name case, secrets in version control, slow page loads, duplicate subscribers.

- Canonical URL: https://acellesend.com/kb/articles/wordpress-subscriber-sync
- Author: Tom Becker, Developer Editor
- Category: Integrations — Stripe, PayPal, WordPress, WooCommerce, Zapier, webhooks, API
- Content type: tutorial · Difficulty: intermediate
- Tags: Acellemail
- Published: 2026-03-12 · Last updated: 2026-08-15
- Reading time: 7 min
- Publisher: AcelleMail Knowledge Base, https://acellesend.com/kb

---

## What this is for

The simplest WordPress ↔ AcelleMail integration: **when someone registers on your WordPress site, add them to an AcelleMail list.** Twenty lines of PHP, no plugin dependency, real-time.

This article is Pattern 1 from the [WordPress + WooCommerce integration overview](https://acellesend.com/kb/articles/integrating-acellemail-with-wordpress-and-woocommerce). If you're connecting WooCommerce purchases (not just user registrations), see [WooCommerce Post-Purchase Emails](https://acellesend.com/kb/articles/woocommerce-post-purchase-emails) instead.

## Prerequisites

- A working AcelleMail install
- An [AcelleMail API token](https://acellesend.com/kb/articles/getting-started-with-the-acellemail-rest-api#step-1--get-your-api-token)
- The UID of the list you want to add subscribers to (in AcelleMail: **Lists → Overview → click the list → URL contains the UID**)
- WordPress 5.5+ (we'll use `wp_remote_post` + `wp_json_encode`)

## Step 1 — Store credentials in `wp-config.php`

Never put API tokens in your theme. Put them in `wp-config.php` so they're outside the version-controlled theme code:

```php
// /path/to/wp-config.php
define('ACELLEMAIL_BASE_URL',  'https://mail.example.com');
define('ACELLEMAIL_API_TOKEN', 'your-token-here');
define('ACELLEMAIL_LIST_UID',  'your-list-uid-here');
```

## Step 2 — Create a must-use plugin

Don't paste into `functions.php` — it'll vanish on theme switch. Create a must-use plugin instead (`wp-content/mu-plugins/` auto-loads every plugin in that directory regardless of theme):

```bash
# WordPress doesn't create mu-plugins/ by default; mkdir it if needed
sudo mkdir -p /path/to/wp-content/mu-plugins
sudo nano /path/to/wp-content/mu-plugins/acellemail-subscriber-sync.php
```

```php
<?php
/**
 * Plugin Name: AcelleMail Subscriber Sync
 * Description: Push new WP user_register events to AcelleMail
 * Version:     1.0.0
 */

if (!defined('ACELLEMAIL_API_TOKEN') ||
    !defined('ACELLEMAIL_LIST_UID') ||
    !defined('ACELLEMAIL_BASE_URL')) {
    return; // Constants not set in wp-config.php; skip silently
}

add_action('user_register', function ($user_id) {
    $user = get_user_by('id', $user_id);
    if (!$user || !is_email($user->user_email)) return;

    $response = wp_remote_post(ACELLEMAIL_BASE_URL . '/api/v1/subscribers', [
        'headers' => [
            'Authorization' => 'Bearer ' . ACELLEMAIL_API_TOKEN,
            'Accept'        => 'application/json',
            'Content-Type'  => 'application/json',
        ],
        'body' => wp_json_encode([
            'MAIL_LIST_UID' => ACELLEMAIL_LIST_UID,
            'EMAIL'         => $user->user_email,
            'FIRST_NAME'    => $user->first_name ?: '',
            'LAST_NAME'     => $user->last_name ?: '',
        ]),
        'timeout'  => 10,
        'blocking' => false,   // fire and forget — don't slow down user signup
    ]);

    // With blocking => false, $response is always WP_Error-ish + we never see status.
    // Use blocking => true + WP_DEBUG_LOG for first-time setup, then flip back.
});
```

## Step 3 — Test it

Register a test user via **WordPress Admin → Users → Add New**. Check AcelleMail:

- **Lists → your list → Subscribers** should show the test user within 5 seconds
- If WP_DEBUG_LOG is on, `wp-content/debug.log` should not show any PHP errors
- AcelleMail's `storage/logs/laravel.log` should not show any 422/500 errors

If the subscriber doesn't appear:

```php
// Temporarily flip 'blocking' => true and 'timeout' => 30, then log the response
$body = wp_remote_retrieve_body($response);
error_log("[AcelleMail sync] HTTP " . wp_remote_retrieve_response_code($response) . " — $body");
```

Common debug results:

- `401 Unauthenticated` → wrong API token in `wp-config.php`
- `422 The MAIL_LIST_UID is invalid` → wrong list UID
- `cURL error 60: SSL` → self-signed cert on AcelleMail; either fix the cert or temporarily `'sslverify' => false`

## Step 4 — Field mapping

Acelle subscriber fields are stored per-list. The default fields every list has:

| AcelleMail field | WordPress source |
|---|---|
| `EMAIL` | `$user->user_email` |
| `FIRST_NAME` | `$user->first_name` (from user_meta) |
| `LAST_NAME` | `$user->last_name` (from user_meta) |

If your AcelleMail list has additional custom fields, add them to the body:

```php
'COMPANY'        => get_user_meta($user_id, 'company_name', true),
'SIGNUP_SOURCE'  => 'wordpress',
'WP_ROLE'        => implode(',', $user->roles),
```

Custom field keys are **UPPERCASE** matching what you defined in AcelleMail (**Lists → your list → Fields**).

## Step 5 — Differentiate by role / signup source

A common refinement: subscribers from different sources go to different lists.

```php
add_action('user_register', function ($user_id) {
    $user = get_user_by('id', $user_id);
    if (!$user) return;

    // Customers go to "Newsletter — Customers"; everyone else to "Newsletter — General"
    $list_uid = in_array('customer', $user->roles, true)
        ? CUSTOMER_LIST_UID
        : GENERAL_LIST_UID;

    wp_remote_post(/* ... use $list_uid instead of constant ... */);
});
```

## Optional — opt-in checkbox at registration

Don't auto-subscribe everyone — many compliance regimes (GDPR, CASL, etc.) require explicit consent. Add a checkbox to the WP registration form:

```php
add_action('register_form', function () {
    ?>
    <p>
        <label>
            <input type="checkbox" name="newsletter_optin" value="1" />
            Subscribe to our newsletter
        </label>
    </p>
    <?php
});

add_action('user_register', function ($user_id) {
    if (empty($_POST['newsletter_optin'])) {
        // User didn't opt in — skip
        return;
    }
    // ... your wp_remote_post call ...
});
```

Combine with [double opt-in](https://acellesend.com/kb/articles/double-opt-in-vs-single-opt-in-which-to-choose) at the AcelleMail list level for maximum compliance — Acelle then sends its own confirmation email after the WP signup.

## Optional — handle subscription updates

When a user updates their email in WordPress, push the change to AcelleMail:

```php
add_action('profile_update', function ($user_id, $old_user_data) {
    $user = get_user_by('id', $user_id);
    if ($user->user_email === $old_user_data->user_email) return; // no email change

    // Update AcelleMail subscriber's email
    // First, find by old email:
    $find = wp_remote_get(
        ACELLEMAIL_BASE_URL . '/api/v1/subscribers/email/' . urlencode($old_user_data->user_email),
        ['headers' => ['Authorization' => 'Bearer ' . ACELLEMAIL_API_TOKEN, 'Accept' => 'application/json']]
    );

    $sub = json_decode(wp_remote_retrieve_body($find), true);
    if (!$sub || empty($sub['id'])) return;

    wp_remote_request(
        ACELLEMAIL_BASE_URL . '/api/v1/subscribers/' . $sub['id'],
        [
            'method' => 'PATCH',
            'headers' => ['Authorization' => 'Bearer ' . ACELLEMAIL_API_TOKEN, 'Accept' => 'application/json', 'Content-Type' => 'application/json'],
            'body' => wp_json_encode(['EMAIL' => $user->user_email]),
        ]
    );
}, 10, 2);
```

## Common issues

| What you see | Likely cause | Fix |
|---|---|---|
| Subscriber created but FIRST_NAME / LAST_NAME empty | WP doesn't auto-fill these on registration — they're empty meta | Either skip the fields, or fetch from `$_POST['first_name']` if your registration form collects them |
| Page load slow after adding the hook | `'blocking' => true` (default) waits for the API response | Add `'blocking' => false` to make it fire-and-forget |
| Subscriber missing after deploying | Theme switch removed `functions.php` snippet | Use mu-plugin (Step 2) instead of functions.php |
| API token visible in error log | `error_log()` dumped the full request headers | Sanitize before logging; never log the full Authorization header |
| Double subscriptions during retry | Plugin runs again after a transient failure | API is idempotent per email — duplicates are de-duped automatically |
| User confirmed email but AcelleMail shows "pending" | List has double opt-in enabled | Either disable double opt-in on the list, or accept the confirmation email flow |
| `wp_remote_post` returns "blocked by firewall" | Server's outbound firewall blocks the AcelleMail URL | Whitelist the AcelleMail hostname in your hosting provider's firewall |

## FAQ

**Will this work with BuddyPress / bbPress / membership plugins?** Yes — their account-creation hooks fire `user_register` automatically. Test against your specific plugin to confirm.

**Can I delete subscribers from AcelleMail when a WP user is deleted?** Yes — hook `delete_user` and POST to `DELETE /api/v1/subscribers/{id}` (or use the `/by-email` lookup variant). For GDPR right-to-erasure compliance, this is recommended.

**What if a user already exists in AcelleMail?** The API treats the request as upsert — the existing subscriber is updated with the new field values. No duplicate created.

**Performance at scale?** Each `wp_remote_post('blocking' => false)` returns in < 1ms. Even 10,000 registrations per hour is negligible WP overhead. The AcelleMail side handles the writes via its queue.

**HTTPS-only?** Yes, always. Plain HTTP for the API call exposes your token. AcelleMail should be on HTTPS anyway per [hardening checklist](https://acellesend.com/kb/articles/post-install-hardening-checklist).

## Related articles

- [Integrating AcelleMail with WordPress and WooCommerce](https://acellesend.com/kb/articles/integrating-acellemail-with-wordpress-and-woocommerce) — the master overview (this is Pattern 1)
- [WooCommerce Post-Purchase Emails](https://acellesend.com/kb/articles/woocommerce-post-purchase-emails) — for purchase events instead of user registration
- [Getting Started with the AcelleMail REST API](https://acellesend.com/kb/articles/getting-started-with-the-acellemail-rest-api) — token + API fundamentals
- [REST API Authentication and Endpoints](https://acellesend.com/kb/articles/rest-api-authentication-and-endpoints) — full subscriber API reference
- [Double Opt-In vs Single Opt-In](https://acellesend.com/kb/articles/double-opt-in-vs-single-opt-in-which-to-choose) — compliance decision
- [Importing Contacts](https://acellesend.com/kb/articles/importing-contacts-csv-best-practices-and-field-mapping) — for bulk-importing existing WP users
- [Zapier Integration Guide](https://acellesend.com/kb/articles/zapier-integration-guide) — no-code alternative
- [GDPR Compliance Guide for Email Marketing](https://acellesend.com/kb/articles/gdpr-compliance-guide-for-email-marketing) — consent requirements

---

## Related articles

- [Connecting Stripe for Subscription Billing](https://acellesend.com/kb/articles/connecting-stripe-for-subscription-billing): AcelleMail's Cashier ships Stripe as the first-class subscription gateway. This guide walks the connection end-to-end: API key configuration, the four webhook events that must be subscribed, the webhook URL location, and test-vs-live mode discipline. Covers both subscription billing (for SaaS operators) and one-off payment use cases.
- [Integrating AcelleMail with WordPress and WooCommerce](https://acellesend.com/kb/articles/integrating-acellemail-with-wordpress-and-woocommerce): WordPress + WooCommerce is the most common stack people connect to AcelleMail. There's no first-class plugin — instead, you wire up the REST API from a few WordPress hooks. This guide walks the three integration patterns (user registration, WooCommerce purchase, optional unsubscribe sync) end-to-end, plus the choice of "API from theme/plugin" vs "embedded signup form" vs "third-party Zapier".
- [Zapier Integration Guide for AcelleMail](https://acellesend.com/kb/articles/zapier-integration-guide): AcelleMail doesn't ship a native Zapier app, but the REST API + webhook system gives you everything you need to wire AcelleMail to the 7,000+ apps on Zapier. This guide walks both directions — AcelleMail as a Zapier action (POST to API), and AcelleMail as a Zapier trigger (webhook → Zap). Plus 6 production-tested Zap recipes.
- [WooCommerce Post-Purchase Emails](https://acellesend.com/kb/articles/woocommerce-post-purchase-emails): The window right after a WooCommerce purchase is the highest-engagement moment a customer ever has with you. A well-timed thank-you / usage-tips / review-request / cross-sell sequence quietly increases LTV without any additional ad spend. This guide walks the hook setup, the 4-step sequence template, the product-category tagging trick, and the AcelleMail automation that ties it all together.
- [BIMI with VMC — Cost, Process, and Whether It's Worth It](https://acellesend.com/kb/articles/bimi-with-vmc-cost-walkthrough): VMC (Verified Mark Certificate) costs $1,500/yr per domain and takes 4-8 weeks to obtain. This guide walks the cost math, the trademark requirements, the alternative paths, and a decision framework for whether VMC is right for your sending program.
