What this is for#
WordPress + WooCommerce is the most common stack people connect to AcelleMail. There's no first-class AcelleMail plugin in the WordPress.org plugin directory — instead, you wire up the REST API from a few WordPress hooks. The good news: it's ~30 lines of PHP and works reliably.
This guide is the master overview with all three integration patterns explained. Each pattern has a dedicated deep-dive article linked at the end.
Three integration patterns#
| Pattern |
Use when |
Code goes in |
| User-register sync |
You want every WordPress account creation to add a subscriber |
functions.php or a custom mu-plugin, hooking user_register |
| WooCommerce purchase sync |
You want every paying customer added to a list (and possibly trigger automations) |
Same place, hooking woocommerce_order_status_completed |
| Embedded signup form |
You want a marketing-list signup form on a WP page (no PHP) |
Paste AcelleMail's form embed code into a Custom HTML block |
| Zapier |
You want point-and-click without writing PHP |
See Zapier Integration Guide |
Pick the one that matches your use case. Most stores end up using #2 + #3 together — purchase sync for paying customers + an embedded form for newsletter signups.
Prerequisites (all patterns)#
- A working AcelleMail install
- An AcelleMail API token — see Getting Started with the REST API Step 1
- An AcelleMail list (UID copied from Lists → Overview → click the list → URL contains the UID)
- WordPress 5.5+ (for the modern
wp_remote_post reliability)
Field name gotcha: AcelleMail's subscriber API uses UPPERCASE field names (EMAIL, FIRST_NAME, LAST_NAME, MAIL_LIST_UID) — not lowercase. Older guides get this wrong. The API accepts uppercase only.
Pattern 1 — Sync on WordPress user registration#
Detail in WordPress Subscriber Sync. Summary:
add_action('user_register', function ($user_id) {
$user = get_user_by('id', $user_id);
wp_remote_post('https://mail.example.com/api/v1/subscribers', [
'headers' => [
'Authorization' => 'Bearer ' . ACELLEMAIL_API_TOKEN,
'Accept' => 'application/json',
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'MAIL_LIST_UID' => 'YOUR_LIST_UID',
'EMAIL' => $user->user_email,
'FIRST_NAME' => $user->first_name ?: '',
'LAST_NAME' => $user->last_name ?: '',
]),
'timeout' => 10,
'blocking' => false, // fire and forget
]);
});
Define ACELLEMAIL_API_TOKEN in wp-config.php (not in the theme — credentials must not be in version control).
Pattern 2 — Sync on WooCommerce purchase#
Detail in WooCommerce Post-Purchase Emails. Summary:
add_action('woocommerce_order_status_completed', function ($order_id) {
$order = wc_get_order($order_id);
if (!$order) return;
$tags = [];
foreach ($order->get_items() as $item) {
$cats = get_the_terms($item->get_product_id(), 'product_cat');
if ($cats) foreach ($cats as $c) $tags[] = $c->slug;
}
wp_remote_post('https://mail.example.com/api/v1/subscribers', [
'headers' => [
'Authorization' => 'Bearer ' . ACELLEMAIL_API_TOKEN,
'Accept' => 'application/json',
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'MAIL_LIST_UID' => 'POST_PURCHASE_LIST_UID',
'EMAIL' => $order->get_billing_email(),
'FIRST_NAME' => $order->get_billing_first_name(),
'LAST_NAME' => $order->get_billing_last_name(),
'ORDER_TOTAL' => $order->get_total(),
'ORDER_ID' => $order_id,
'tags' => implode(',', array_unique($tags)),
]),
'timeout' => 10,
'blocking' => false,
]);
});
This subscribes the customer to the "post-purchase" list with the order context. Configure an automation in AcelleMail to send a welcome → review-request → upsell sequence — see the post-purchase emails article for the 4-step sequence template.
Pattern 3 — Embedded signup form#
Inside AcelleMail:
- Lists → Your list → Forms → Create new
- Customize fields shown (email + first name is typical for newsletters)
- Copy embed code — gives you either an
<iframe> snippet or a JS-rendered snippet
In WordPress:
- Edit the page where you want the form (homepage, footer widget, etc.)
- Insert a Custom HTML block
- Paste the embed code
- Save → the form renders inline
Trade-offs: the embedded form posts directly to AcelleMail — no WordPress code needed, no API token needed. Downside: limited styling (iframe constraints) and no opportunity to add extra logic on submit. For a simple newsletter signup, it's perfect.
For more customisation, build your own HTML form that POSTs to /api/v1/public/subscribers (the unauthenticated endpoint — see REST API reference).
Optional — sync unsubscribes back to WordPress#
When a subscriber unsubscribes from your AcelleMail list, you may want to update WordPress user metadata (e.g. clear a newsletter_subscribed flag, set a "do not contact" tag).
Two approaches:
A. Per-campaign webhook on campaign.unsubscribe#
Configure an AcelleMail webhook (Campaign → Webhooks) on the campaign.unsubscribe event, pointing to a custom REST endpoint in WordPress:
// In a plugin file
add_action('rest_api_init', function () {
register_rest_route('acellemail/v1', '/unsubscribe', [
'methods' => 'POST',
'callback' => function (\WP_REST_Request $req) {
// Verify auth (Bearer token or shared header — match what you set in AcelleMail webhook config)
$auth = $req->get_header('authorization');
if ($auth !== 'Bearer ' . WEBHOOK_SHARED_SECRET) {
return new \WP_REST_Response('Unauthorized', 401);
}
$email = $req->get_param('subscriber_email');
$user = get_user_by('email', $email);
if ($user) {
update_user_meta($user->ID, 'newsletter_subscribed', '0');
}
return new \WP_REST_Response(['ok' => true], 200);
},
'permission_callback' => '__return_true',
]);
});
The endpoint is at https://your-wp-site.com/wp-json/acellemail/v1/unsubscribe. Configure that URL in the AcelleMail webhook config (per webhook reference).
B. Periodic sync via REST API#
Run a daily cron in WordPress that fetches the list's current unsubscribed subscribers via the API and updates user meta:
add_action('acellemail_daily_sync', function () {
$response = wp_remote_get(
'https://mail.example.com/api/v1/subscribers?filter[list_uid]=YOUR_LIST_UID&filter[status]=unsubscribed&per_page=200',
['headers' => ['Authorization' => 'Bearer ' . ACELLEMAIL_API_TOKEN, 'Accept' => 'application/json']]
);
$data = json_decode(wp_remote_retrieve_body($response), true);
foreach (($data['data'] ?? []) as $sub) {
$user = get_user_by('email', $sub['email']);
if ($user) update_user_meta($user->ID, 'newsletter_subscribed', '0');
}
});
if (!wp_next_scheduled('acellemail_daily_sync')) {
wp_schedule_event(time(), 'daily', 'acellemail_daily_sync');
}
Pattern A is real-time but more setup; Pattern B is simpler but lags up to 24 hours. Pick based on your urgency.
Where to put the code#
Don't paste into functions.php unless you're 100% comfortable losing it on a theme switch. Better:
# Create a custom mu-plugin (must-use; auto-loaded; survives any theme change)
sudo mkdir -p /path/to/wp-content/mu-plugins
sudo tee /path/to/wp-content/mu-plugins/acellemail-integration.php <<'EOF'
<?php
/**
* Plugin Name: AcelleMail Integration
* Description: Sync WordPress + WooCommerce users to AcelleMail
*/
if (!defined('ACELLEMAIL_API_TOKEN') || !defined('ACELLEMAIL_LIST_UID')) {
return; // Skip if not configured (defined in wp-config.php)
}
// ... your add_action hooks here ...
EOF
Then in wp-config.php:
define('ACELLEMAIL_API_TOKEN', 'your-token-here');
define('ACELLEMAIL_LIST_UID', 'your-list-uid');
Testing the integration#
# Tail Acelle's app log + WP debug log simultaneously
sudo tail -f /var/www/acellemail/storage/logs/laravel.log \
/path/to/wp-content/debug.log
# Then in WordPress, register a test user OR place a test WC order
# You should see in Acelle's log: a subscribers.create API hit
# And in WP debug.log (if WP_DEBUG_LOG is on): the wp_remote_post response
If nothing happens:
- Verify
WP_DEBUG_LOG = true is set in wp-config.php to see PHP errors
- Verify the API token works via curl (see getting-started)
- Verify the
MAIL_LIST_UID is the list UID, not the campaign UID (common confusion)
Common issues#
| What you see |
Likely cause |
Fix |
| Subscriber appears but field values are empty |
Used lowercase field names (email, not EMAIL) |
Switch to uppercase per the API spec |
| API returns 422 "MAIL_LIST_UID required" |
Posted to /lists/{uid}/subscribers without the field, or posted to /subscribers without the field |
Use /api/v1/subscribers + include MAIL_LIST_UID in the body |
| WordPress page loads slowly after adding the hook |
Default wp_remote_post is blocking — adds 200-500ms per registration |
Add 'blocking' => false to make it fire-and-forget |
| Duplicate subscribers (1 in WP user, 1 in WooCommerce) |
Both user_register AND woocommerce_order_status_completed fired for the same email |
Acelle handles duplicates (upserts by email) — verify; or scope each hook to a different list |
| Embedded form doesn't render |
iframe blocked by Content-Security-Policy |
Add the AcelleMail domain to your CSP frame-src; or use the JS-rendered embed instead |
wp_remote_post returns WP_Error "cURL error 60" |
TLS verification failed (self-signed cert on dev install) |
Use ['sslverify' => false] for testing only; fix the cert before production |
| Unsubscribe webhook arrives but WP user not updated |
get_user_by('email') returned null — email mismatch |
Lowercase both sides before lookup (strtolower($email)) |
FAQ#
Is there an official AcelleMail WordPress plugin? Not on WordPress.org as of 2026. The hooks-based integration is the recommended pattern — small, transparent, no plugin-dependency risk.
Can I import existing WordPress users into AcelleMail? Yes — export the WP user list as CSV (via a plugin like User Import Export) and import into AcelleMail via Lists → Your list → Subscribers → Import. See Importing Contacts.
WooCommerce Subscriptions / Memberships? Same approach — hook the relevant event (woocommerce_subscription_status_active, wc_memberships_user_membership_status_changed) and POST to the AcelleMail API. Read the WC documentation for the exact hook names.
Can AcelleMail send transactional emails for WooCommerce (order confirmation, password reset)? Yes via the Amazon SES integration — both WooCommerce and AcelleMail can send through the same SES sending identity. Don't try to route WooCommerce transactional through AcelleMail's send-a-campaign API (wrong shape).
Performance impact on WP site? With 'blocking' => false added, < 1ms overhead per user-register / order completion. Without it, 200-500ms — measurable on busy sites.
Multi-site WordPress (WPMU)? Same hooks work network-wide. Use is_multisite() ? $blog_id : null to differentiate, or scope per-blog to different AcelleMail lists.
Can I push back to WordPress from AcelleMail? Yes via webhooks — see the "Optional — sync unsubscribes back" section above.
Related articles#