Sync WordPress User Profile Updates to Mailchimp and Vice Versa
In this tutorial we are going to work with both Mailchimp API and its webhooks. You can also find basic guides on how to work with the API and also a basic guide about webhooks on my website.
In the first part of the tutorial we are going to update user first and last name in WordPress profile and sync the changes with Mailchimp audience fields. Then we are going to update the merge tags directly in Mailchimp and configure the syncing with WP profiles.
Also I can recommend you my Simple Mailchimp Sync plugin that allows to sync users between WordPress and Mailchimp automatically.
Sync User Profile Update with Mailchimp Merge Tags
This part of the tutorial is the simplest, because all we need to do is to create a function connected to profile_update
action hook and a Mailchimp API call.
add_action( 'profile_update', 'rudr_upd_user', 25, 3 );
function rudr_upd_user( $user_id, $old_userdata, $userdata ) {
$list_id = 'YOUR AUDIENCE ID';
$api = 'YOUR API KEY';
// user data
$email = $old_userdata->user_email;
$first_name = $userdata->first_name;
$last_name = $userdata->last_name;
wp_remote_request(
'https://' . substr($api,strpos($api,'-')+1) . '.api.mailchimp.com/3.0/lists/' . $list_id . '/members/' . md5(strtolower($email)),
array(
'method' => 'PATCH',
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( 'user:'. $api )
),
'body' => json_encode(
array(
'merge_fields' => array( 'FNAME' => $first_name, 'LNAME' => $last_name )
)
)
)
);
}
Here is also where to get API key and audience ID.
Sync Audience Fields Updates with WordPress User Profile
Create a webhook in Mailchimp
First of all go to your Mailchimp dashboard, select an audience you would like to configure the syncing, then Settings > Webhooks.
When creating a webhook check a checkbox Profile updates.

Update user profiles automatically
In case you do not know where to insert the below code, I recommend you this guide.
add_action( 'template_redirect', 'misha_user_update_webhook' );
function misha_user_update_webhook(){
// exit the function in case it is not our hook
if( empty( $_GET[ 'process-webhook' ] ) || 'anything123' !== $_GET[ 'delete-users' ] ) {
return;
}
// check the action
if( empty( $_POST[ 'type' ] ) || 'profile' !== $_POST[ 'type' ] ) {
return;
}
// we can check the list ID to improve the security of a webhook
// if( empty( $_POST[ 'data' ][ 'list_id' ] ) || 'abcdef12345' !== $_POST[ 'data' ][ 'list_id' ] ) {
// return;
// }
// do the thing
$user = get_user_by( 'email', $_POST[ 'data' ][ 'email' ] );
if( $user ) {
wp_update_user(
array(
'ID' => $user->ID,
'first_name' => $_POST[ 'data' ][ 'merges' ][ 'FNAME' ],
'last_name' => $_POST[ 'data' ][ 'merges' ][ 'LNAME' ],
'display_name' => $_POST[ 'data' ][ 'merges' ][ 'FNAME' ] . ' ' . $_POST[ 'data' ][ 'merges' ][ 'LNAME' ]
)
);
// you can also use update_post_meta()
// update_user_meta( $user->ID, 'first_name', $_POST[ 'data' ][ 'merges' ][ 'FNAME' ] );
}
exit;
}

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Hi,
The whole posts serie on Mailchimp Webhooks and API 3 is exactly what I was looking for and really didactic. Great job!!
However one specific question:
Everything’s fine if Mailchimp user change fname/lname OR email.
Unfortunatly if both fields are update together, profile AND upemail webhooks must be processed.
No problem if profile webhook is first then upemail webhook.
But if upemail webhook start first, user’s email is change and profile webhook can’t get the userID by email.
Any tips or trick to resolve this?
Thanks ;-)
Hey,
While updating from
upemail
I recommend to store an old email somewhere in user meta. So, when the profile webhook will be fired, check if user exists, if it doesn’t exist, try to find the user by a email we stored in user meta 🙃Correct answer but I’ve just realised that my question was completely wrong (in fact it’s just the opposite problem :D )
When modifying both email and fname/lname,
profile
is send with the new email and no reference to old one. So ifupemail
has not already been fired first to update the old email,profile
is unable to find any reference of the new email.The only solution I could find up to now is to resend
profile
datas after theupemail
with something like this:wp_schedule_single_event( time() + 1, 'resend_profile_datas', array( $datas ) );
But this seems to me to be an ugly process…
I got lost, 😁
Let’s try from the beginning – where you modify email and first/last names? On the website?
P.S. You can use
<code>
tag in comments 🙃Sorry, I start myself to loose my mind with this full 2 way sync.
When a Mailchimp user updates his email and first/last names at the same time, 2 webhooks are sent,
profile
andupemail
.upemail
contains old and new emails andprofile
contains new first/last names and new email.My webhook listener is not always receiving both webhooks in same order.
Good case : If
upemail
is fired first, my webhook listener can updates my user email first so whenprofile
is then fired, the listener can find the related user with the new email.Bad case : If
profile
is fired first, the webhook listener is unable to find the related user as it is still using the old email while theprofile
webhook contains only the new email. Theget_user_by( 'email', $_POST['data']['email'] );
is not returning any valid WP_user object.My new idea to resolve this bad case is, when receiving the
profile
webhook to create a temporary user with new data fromprofile
and adding atemporary
user meta (thanks for the idea).So after when receiving
upemail
, I can first check if I can find a user with new email and thetemporary
user meta (meaning thatprofile
has been fired first) and getting new first/last names from this user before deleting him.Not a completely clean solution (a lot of efforts for basic result) but at least I get rid of the
wp_schedule_single_event
I didn’t trust so much.Thanks for time and posts serie!
Now that I have my Mailchimp to WordPress sync, I will try to set up the other way sync…
Sebastien,
This solution #comment-4188 should fit perfectly for what you’ve just described.
Sorry, I must be dumb.
What would be the use of storing the old email when Upemail as Profile webhook only contains new email?
Just when
upemail
is fired, useupdate_user_meta()
to store the old email somewhere in user meta.When
profile
is fired afterupemail
check if there is a user with a email passed in the hook. If there is not such user, get it by the specific meta key you stored the old email into.