Nine years after its inception (in plugin-years, that's like 108 human years), it's time to retire this plugin. I've created a Craft 4 version to ease the transition, but no new development will be done, and no support given. It's time for you to start looking for/creating alternatives.
Mailchimp Subscribe for Craft is a plugin for working with Mailchimp audiences.
This plugin requires Craft CMS 4.0.0 or later.
This is a minimum effort upgrade to Craft 4, no changes.
Too much, see the changelog for information.
- The plugin no longer is configurable from the control panel, you need to use a config file.
- The plugin handle used in the action input has changed from
mailchimpSubscribe
tomailchimp-subscribe
. - The redirect url now has to be hashed in the redirect input.
To install the plugin, either install it from the plugin store, or follow these instructions:
- Install with composer via
composer require aelvan/mailchimp-subscribe
from your project directory. - Install the plugin in the Craft Control Panel under Settings → Plugins, or from the command line via
./craft install/plugin mailchimp-subscribe
. - Eat a banana and continue reading!
Mailchimp Subscribe must be configured by creating a file named mailchimp-subscribe.php
in your Craft config
folder (usually /config
), and configure settings as needed.
Default: ''
The API key for your Mailchimp account. This setting is required.
Default: ''
The default audience ID you want users to subscribe to. You can also configure the audienceID by posting this
through your forms (see below).
Default: true
Indicates if double opt-in should be used when subscribing. If enabled, users will receive an email to
confirm their subscription before being added to the audience.
<?php
return [
'apiKey' => 'xxxxxxxxxxxxxxxxxxx-us2',
'audienceId' => '7fw6eq98ca',
'doubleOptIn' => true,
];
The plugin config also supports using different settings on a per-site basis. This works like Craft's general config does:
<?php
return [
'apiKey' => [
'siteHandleA' => 'xxxxxxxxxxxxxxxxxxx-us2',
'siteHandleB' => 'xxxxxxxxxxxxxxxxxxx-us2',
],
'audienceId' => [
'siteHandleA' => '7fw6eq98ca',
'siteHandleB' => '3fa8ew9fce',
],
'doubleOptIn' => [
'siteHandleA' => true,
'siteHandleB' => false,
],
];
Mailchimp Subscribe let's you subscribe, unsubscribe and delete members to/from Mailchimp audiences.
In it's simplest form, you can subscribe a user with a simple form with just an email input field:
<form class="newsletter-form" action="" method="post">
{{ csrfInput() }}
<input type="hidden" name="action" value="mailchimp-subscribe/audience/subscribe">
{% set subscribeResponse = mailchimpSubscribe is defined and mailchimpSubscribe.action == 'subscribe' ? mailchimpSubscribe : null %}
{% if subscribeResponse %}
{% if subscribeResponse.success %}
<p>Subscribed successfully!</p>
{% else %}
<p>An error occured: {{ subscribeResponse.message }}</p>
{% endif %}
{% endif %}
<div>
<label for="emailInput"{% if subscribeResponse and subscribeResponse.errorCode=='1000' %} class="error"{% endif %}>
Email:
</label>
<input id="emailInput" type="text" name="email"
{% if subscribeResponse and not subscribeResponse.success %}value="{{ subscribeResponse.values.email ?? '' }}"{% endif %}/>
</div>
<input type="submit" name="" value="Subscribe"/>
</form>
If you want to redirect the user upon success, you can supply a redirect parameter (like you would in any
craft front-end form). You can also set or override the audienceId
directly from the form:
<form class="newsletter-form" action="" method="post">
{{ csrfInput() }}
{{ redirectInput('thankyou') }}
<input type="hidden" name="action" value="mailchimp-subscribe/audience/subscribe">
<input type="hidden" name="audienceId" value="1fr4ew09qv">
{% set subscribeResponse = mailchimpSubscribe is defined and mailchimpSubscribe.action == 'subscribe' ? mailchimpSubscribe : null %}
{% if subscribeResponse %}
{% if not subscribeResponse.success %}
<p>An error occured: {{ subscribeResponse.message }}</p>
{% endif %}
{% endif %}
<div>
<label for="emailInput"{% if subscribeResponse and subscribeResponse.errorCode=='1000' %} class="error"{% endif %}>
Email:
</label>
<input id="emailInput" type="text" name="email"
{% if subscribeResponse and not subscribeResponse.success %}value="{{ subscribeResponse.values.email ?? '' }}"{% endif %}/>
</div>
<input type="submit" name="" value="Subscribe"/>
</form>
You can also set email_type
, merge_fields
, interests
, language
, vip
, marketing_permissions
and tags
as per the Mailchimp API documentation.
The following example shows all the options in play - obviously you should adapt this to your own needs:
<form class="newsletter-form" action="" method="post">
{{ csrfInput() }}
{{ redirectInput('thankyou') }}
<input type="hidden" name="action" value="mailchimp-subscribe/audience/subscribe">
<input type="hidden" name="audienceId" value="2a34d0978q">
<input type="hidden" name="email_type" value="text">
<input type="hidden" name="language" value="no">
<input type="hidden" name="vip" value="yes">
{% set subscribeResponse = mailchimpSubscribe is defined and mailchimpSubscribe.action == 'subscribe' ? mailchimpSubscribe : null %}
{% if subscribeResponse %}
{% if not subscribeResponse.success %}
<p>An error occured: {{ subscribeResponse.message }}</p>
{% endif %}
{% endif %}
<div>
<label for="emailInput"{% if subscribeResponse and subscribeResponse.errorCode=='1000' %} class="error"{% endif %}>
Email:
</label>
<input id="emailInput" type="text" name="email"
{% if subscribeResponse and not subscribeResponse.success %}value="{{ subscribeResponse.values.email ?? '' }}"{% endif %}/>
</div>
<div>
<label for="firstNameInput">First name:</label>
<input id="firstNameInput" type="text" name="merge_fields[FNAME]"
{% if subscribeResponse and not subscribeResponse.success %}value="{{ subscribeResponse.values.FNAME ?? '' }}"{% endif %}/>
</div>
<div>
<label for="lastNameInput">Last name:</label>
<input id="lastNameInput" type="text" name="merge_fields[LNAME]"
{% if subscribeResponse and not subscribeResponse.success %}value="{{ subscribeResponse.values.LNAME ?? '' }}"{% endif %}/>
</div>
<div>
<h4>Marketing permissions</h4>
<input type="hidden" name="marketing_permissions" value="">
<input type="checkbox" value="1c862d81f1" name="marketing_permissions[]">Weekly newsletter<br>
<input type="checkbox" value="46712a192a" name="marketing_permissions[]">Special offers<br>
<input type="checkbox" value="46acfd7a2b" name="marketing_permissions[]">Special offers from partners<br>
</div>
<div>
<h4>Tags</h4>
<input type="hidden" value="" name="tags">
<input type="checkbox" value="One tag" name="tags[]">One tag<br>
<input type="checkbox" value="Two tag" name="tags[]">Two tag<br>
<input type="checkbox" value="Three tag" name="tags[]">Three tag<br>
</div>
{% set interestGroups = craft.mailchimpSubscribe.getInterestGroups('2a34d0978q') %}
{% if interestGroups and (interestGroups | length > 0) %}
{% for group in interestGroups %}
<div>
<h4>{{ group.title }}</h4>
<input type="hidden" value="" name="interests[{{ group.title }}]">
{% if group.type=='checkboxes' %}
{% for interest in group.interests %}
<input type="checkbox" value="{{ interest.id }}" name="interests[{{ group.title }}][]">{{ interest.name }}<br>
{% endfor %}
{% endif %}
{% if group.type=='radio' %}
{% for interest in group.interests %}
<input type="radio" value="{{ interest.id }}" name="interests[{{ group.title }}][]">{{ interest.name }}<br>
{% endfor %}
{% endif %}
{% if group.type=='dropdown' %}
<select name="interests[{{ group.title }}][]">
{% for interest in group.interests %}
<option value="{{ interest.id }}">{{ interest.name }}</option>
{% endfor %}
</select>
{% endif %}
</div>
{% endfor %}
{% endif %}
<br>
<input type="submit" name="" value="Subscribe"/>
</form>
Please note:
-
You can get the interests connected to a list with the template variable
getInterestGroups
, as shown in the example. Mailchimp lets you create different types of groups, checkboxes, radio buttons, dropdown, etc, but doesn't actually limit the add functionality to the groups depending on the type. You have to do this based on the group type. -
If you want to override/reset any existing tags and marketing permissions, make sure you add the hidden inputs as shown above. Omit it if you want tags to be append only.
-
For more information about marketing permissions, see the GDPR section below.
-
You will not get an error message if you submit an email address that's already subscribed to your audience – this is intended behavior. If you want to check if an email is already in your audience, you can use the template variable
craft.mailchimpSubscribe.getMemberByEmail
or the controller actionmailchimp-subscribe/audience/get-member-by-email
, and check if the response isnull
, or what the status of the member is.
You can subscribe a user by submitting the email address to the unsubscribe controller action:
<form class="newsletter-form" action="" method="post">
{{ csrfInput() }}
<input type="hidden" name="action" value="mailchimp-subscribe/audience/unsubscribe">
{% set unsubscribeResponse = mailchimpSubscribe is defined and mailchimpSubscribe.action == 'unsubscribe' ? mailchimpSubscribe : null %}
{% if unsubscribeResponse %}
{% if unsubscribeResponse.success %}
<p>Unsubscribed successfully!</p>
{% else %}
<p>An error occured: {{ unsubscribeResponse.message }}</p>
{% endif %}
{% endif %}
<div class="field-line">
<label for="emailInput"{% if unsubscribeResponse and unsubscribeResponse.errorCode=='1000' %} class="error"{% endif %}>
Email:
</label>
<input id="emailInput" type="text" name="email"
{% if unsubscribeResponse and not unsubscribeResponse.success %}value="{{ unsubscribeResponse.values.email ?? '' }}"{% endif %}/>
</div>
<input type="submit" name="" value="Unsubscribe"/>
</form>
You can delete a user by submitting the email address to the unsubscribe controller action:
<form class="newsletter-form" action="" method="post">
{{ csrfInput() }}
<input type="hidden" name="action" value="mailchimp-subscribe/audience/delete">
{% set deleteResponse = mailchimpSubscribe is defined and mailchimpSubscribe.action == 'delete' ? mailchimpSubscribe : null %}
{% if deleteResponse %}
{% if deleteResponse.success %}
<p>Deleted successfully!</p>
{% else %}
<p>An error occured: {{ deleteResponse.message }}</p>
{% endif %}
{% endif %}
<div>
<label for="emailInput"{% if deleteResponse and deleteResponse.errorCode=='1000' %} class="error"{% endif %}>
Email:
</label>
<input id="emailInput" type="text" name="email"
{% if deleteResponse and not deleteResponse.success %}value="{{ deleteResponse.values.email ?? '' }}"{% endif %}/>
</div>
<div>
<label><input type="checkbox" name="permanent"/> Permanent</label>
</div>
<input type="submit" name="" value="Delete"/>
</form>
The permanent
parameter is optional, when enabled it creates a permanent/hard delete.
When unsubscribing a user from an audience, the status of that member is set to unsubscribed
. All information
about the member will be kept in Mailchimp, the data can be queried, you can see it in the Mailchimp
control panel, and the status can be changed back to subscribed
at a later point.
When (soft) deleting a user, it's mostly the same as an unsubscribe, except the member will have an empty status and will not be visible in the Mailchimp control panel.
When permanently (hard) deleting a user, all personally identifiable information related to the member is deleted, and the member is removed from the audience. This is the GDPR-compliant way of removing a member if requested. This will make it impossible to re-import or re-subscribe the member at a later point, the member can only resubscribe through a Mailchimp hosted, GDPR-compliant subscribe form.
If you need to get information about a member or an audience, you can use the craft.mailchimpSubscribe.getMemberByEmail
and craft.mailchimpSubscribe.getAudienceById
template variables, or the corresponding controller actions
mailchimp-subscribe/audience/get-member-by-email
and mailchimp-subscribe/audience/get-audience-by-id
(see documentation
below).
The returned data contains all the information directly from the Mailchimp API, as documented in the API documentation for members and audiences.
In the previous versions of Mailchimp Subscribe, there were template variables for checkIfInList
and checkIfSubscribed
.
These are now deprecated, you should instead get member information and check the status
of the member.
At the time of writing this (june 2019) it's still unclear if subscribing through the API is considered GDPR compliant by Mailchimp, so it's probably safest to assume not, and use their hosted forms, if you're serving EU customers.
The API supports updating marketing permissions, though, so feel free to experiment. The only way to create
and edit marketing permissions at the moment, is to create a new signup form from your GDPR enabled audience,
and edit the attached "Marketing permissions" block. To create the input checkboxes in your own form, you need
to get the ID's of each permission. The only way to do this at the moment, is to get information about a member
that's already subscribed to the list. So subscribe a user, then do (dump
is only available when devMode
is enabled):
{{ dump(craft.mailchimpSubscribe.getMarketingPermissionsByEmail('[email protected]')) }}
This will dump out an array of marketing permissions, where the important part is the marketing_permission_id
that you'll need to add to you form like this:
...
<input type="hidden" name="marketing_permissions" value="">
<input type="checkbox" value="1c862d81f1" name="marketing_permissions[]">Weekly newsletter<br>
<input type="checkbox" value="46712a192a" name="marketing_permissions[]">Special offers<br>
<input type="checkbox" value="46acfd7a2b" name="marketing_permissions[]">Special offers from partners<br>
...
Again, make sure your form actually is GDPR compliant, and don't blame me.
There are several events that enable the ability for you to trigger custom code. Right now we have events for the subscribe, unsubscribe and delete actions that occur. All events should be listened to using the MailchimpSubscribeService class, examples can be found below
The onAfterSubscribe event is triggered whenever a successful subscribe action has occurred. The SubscribeEvent class will contain the following properties:
- (string) email
- (string) audienceId
use aelvan\mailchimpsubscribe\events\SubscribeEvent;
use aelvan\mailchimpsubscribe\services\MailchimpSubscribeService;
Event::on(
MailchimpSubscribeService::class,
MailchimpSubscribeService::EVENT_AFTER_SUBSCRIBE,
function (SubscribeEvent $event) {
// custom logic
}
);
The onAfterSubscribe event is triggered whenever a successful unsubscribe action has occurred. The UnsubscribeEvent class will contain the following properties:
- (string) email
- (string) audienceId
use aelvan\mailchimpsubscribe\events\UnsubscribeEvent;
use aelvan\mailchimpsubscribe\services\MailchimpSubscribeService;
Event::on(
MailchimpSubscribeService::class,
MailchimpSubscribeService::EVENT_AFTER_UNSUBSCRIBE,
function (UnsubscribeEvent $event) {
// custom logic
}
);
The onAfterDelete event is triggered whenever a successful delete action has occurred. The DeleteEvent class will contain the following properties:
- (string) email
- (string) audienceId
- (bool) permanent
use aelvan\mailchimpsubscribe\events\DeleteEvent;
use aelvan\mailchimpsubscribe\services\MailchimpSubscribeService;
Event::on(
MailchimpSubscribeService::class,
MailchimpSubscribeService::EVENT_AFTER_DELETE,
function (DeleteEvent $event) {
// custom logic
}
);
All controller actions:
- Requires
POST
, so make sure to add a CSRF token to the request. - Returns JSON if the request was an ajax request/has the right headers.
- A variable named
mailchimpSubscribe
will be available in your templates if an error occurs, or if you return to the same template after success, without redirecting (see examples above).
Subscribes a member to an audience. The following variables can be submitted:
email (required): Email of member to subscribe.
redirect: Route to redirect to on success. If not set, the same route will be loaded with mailchimpSubscribe
variable set.
audienceId: ID of audience to subscribe the member to. If not set, the configured audienceId
will be used.
email_type: Email type the member prefers. Can be html
(default) or text
language: Preferred language for member (see documentation for possible language codes).
vip: Sets VIP status for member, accepted values are true
, yes
, 1
for true
, anything else is considered false
(default).
merge_fields: An array of additional fields defined in Mailchimp (Currently called "Audience fields and |MERGE| tags" in Mailchimp).
marketing_permissions: An array of marketing permissions that should be enabled for member.
interests: An array of group interests that should be enabled for member (you find these under "Manage Contacts" > "Groups" in Mailchimp).
tags: An array of tags that should be enabled for member (you find these under "Manage Contacts" > "Tags" in Mailchimp). New tags are automatically created in Mailchimp.
The action will return a SubscribeResponse with the action
property set to subscribe
.
Unsubscribes a member from an audience. The following variables can be submitted:
email (required): Email of member to unsubscribe.
redirect: Route to redirect to on success. If not set, the same route will be loaded with mailchimpSubscribe
variable set.
audienceId: ID of audience to unsubscribe the member from. If not set, the configured audienceId
will be used.
The action will return a SubscribeResponse with the action
property set to unsubscribe
.
Delete a member from an audience. The following variables can be submitted:
email (required): Email of member to delete.
redirect: Route to redirect to on success. If not set, the same route will be loaded with mailchimpSubscribe
variable set.
audienceId: ID of audience to delete the member from. If not set, the configured audienceId
will be used.
permanent: Set to true
if the member should be permanently deleted. See the "Differences between unsubscribe, delete and permanent delete" section above for more information on what this means.
The action will return a SubscribeResponse with the action
property set to delete
.
Gets information about a member in an audience by email. The following variables can be submitted:
email (required): Email to query.
redirect: Route to redirect to on success. If not set, the same route will be loaded with mailchimpSubscribe
variable set.
audienceId: ID of audience to unsubscribe the member to. If not set, the configured audienceId
will be used.
The action will return a MemberResponse with the action
property set to get-member
.
Gets information about an audience by its ID. The following variables can be submitted:
audienceId: ID of audience to get information on. If not set, the configured audienceId
will be used.
redirect: Route to redirect to on success. If not set, the same route will be loaded with mailchimpSubscribe
variable set.
The action will return a AudienceResponse with the action
property set to get-audience
.
In the definitions below, square brackets indicate parameters that are optional. If audience ID is not submitted, the id from the config file will be used.
All methods will return null
if an error occured, please refer to you logs/debug toolbar for the
error message.
Returns interest groups for an audience in the following structure:
[
0 => [
'title' => 'Job position'
'type' => 'radio'
'interests' => [
0 => [
'id' => '3ba93a1818'
'name' => 'Developer'
]
1 => [
'id' => '98a725d885'
'name' => 'Designer'
]
2 => [
'id' => 'e54cdea2b8'
'name' => 'Project Manager'
]
]
]
1 => [
'title' => 'Interests'
'type' => 'checkboxes'
'interests' => [
0 => [
'id' => '517e7129x5'
'name' => 'Donating'
]
1 => [
'id' => '15128d2daf'
'name' => 'Volunteering'
]
2 => [
'id' => 'f254817294'
'name' => 'Events'
]
]
]
]
Queries the Mailchimp API for an audience, and returns the response object in its entirety. Please refer to the API documentation for details.
Queries the Mailchimp API for a member, and returns the response object in its entirety. Please refer to the API documentation for details.
Queries the Mailchimp API for a member, and returns the marketing permissions for that member in the following structure:
[
0 => stdClass#1
(
[marketing_permission_id] => '0e963d96x1'
[text] => 'Weekly newsletter'
[enabled] => true
)
1 => stdClass#2
(
[marketing_permission_id] => '42723a122x'
[text] => 'Special offers'
[enabled] => false
)
2 => stdClass#3
(
[marketing_permission_id] => '36cxbd1a8b'
[text] => 'Special offers from partners'
[enabled] => false
)
]
You can also get this directly from the member, this method is just for convenience.
Queries the Mailchimp API for a member's tags, and returns them in the following structure:
[
0 => stdClass#1
(
[id] => 32608
[name] => 'One tag'
[date_added] => '2019-06-24T18:35:07+00:00'
)
1 => stdClass#2
(
[id] => 32611
[name] => 'Three tag'
[date_added] => '2019-06-24T18:35:07+00:00'
)
]
You can also get this directly from the member, this method is just for convenience.
You can access Mailchimp Subscribe's service methods from your own plugin or module, by doing something like this:
$msPlugin = Craft::$app->plugins->getPlugin('mailchimp-subscribe');
if ($msPlugin && $msPlugin instanceof \aelvan\mailchimpsubscribe\MailchimpSubscribe) {
$msPlugin->mailchimpSubscribe->subscribe('[email protected]', '2a34d0978q');
}
The available public methods are (again, square brackets indicate parameters that are optional):
Subscribes a member to an audience. The third, optional parameter, is an array of all the possible parameters documented in the subscribe controller action above. The response is always an SubscribeResponse, as documented below. Example:
$response = $msPlugin->mailchimpSubscribe->subscribe('[email protected]', '2a34d0978q', [
'email_type' => 'html',
'language' => 'no',
'merge_fields' => [
'FNAME' => 'Lorem',
'LNAME' => 'Ipsum'
]
]);
Unsubscribes a member from an audience. The response is always an SubscribeResponse, as documented below. Example:
$response = $msPlugin->mailchimpSubscribe->unsubscribe('[email protected]', '2a34d0978q');
Deletes a member from an audience. If the third parameter is true
, a hard delete is performed, see explanation
above for the differences between unsubscribe, delete, and hard delete. The response is always an SubscribeResponse,
as documented below. Example:
$response = $msPlugin->mailchimpSubscribe->delete('[email protected]', '2a34d0978q', true);
Gets information about a member from an audience. The response is null
if an error occured (see logs/debug toolbar
for error message), and a Collection object if the request was successful. The collection will have all the
information about the member, as
documented in the Mailchimp API.
Example:
$member = $msPlugin->mailchimpSubscribe->getMemberByEmail('[email protected]', '2a34d0978q');
Gets information about an audience. The response is null
if an error occured (see logs/debug toolbar
for error message), and a Collection object if the request was successful. The collection will have all the
information about the audience, as
documented in the Mailchimp API.
Example:
$member = $msPlugin->mailchimpSubscribe->getAudienceById('2a34d0978q');
Gets marketing permissions from a member. The response is null
if an error occured (see logs/debug toolbar
for error message), and an array if the request was successful. See the documentation for the corresponding
template variable for an example of the returned data.
Gets interests groups from an audience. The response is null
if an error occured (see logs/debug toolbar
for error message), and an array if the request was successful. See the documentation for the corresponding
template variable for an example of the returned data.
Gets tags from a member. The response is null
if an error occured (see logs/debug toolbar
for error message), and an array if the request was successful. See the documentation for the corresponding
template variable for an example of the returned data.
Returned by subscribe
, unsubscribe
and delete
controller actions. Has the following properties:
action: Indicates which of the actions where used to trigger the response. If you have more than one type of
form on a single template, this is how you differenciate which form was submitted.
success: Boolean indicating if the request was successful or not.
errorCode: If an error occured, the error code will be set. 1000
indicates an invalid email and 2000
an invalid API key or audienceId. For all other error codes, refer to the Mailchimp API documentation.
message: If an error occured, an error message will be returned.
values: The values that were submitted from the form.
response: The complete Mailchimp response that the request resulted in.
Returned by the get-member-by-email
controller actions. Has the following properties:
action: Indicates which of the actions where used to trigger the response, will always be 'get-member'
for this response.
success: Boolean indicating if the request was successful or not.
response: The complete Mailchimp response that the request resulted in.
Returned by the get-audience-by-id
controller actions. Has the following properties:
action: Indicates which of the actions where used to trigger the response, will always be 'get-audience'
for this response.
success: Boolean indicating if the request was successful or not.
response: The complete Mailchimp response that the request resulted in.
The plugin is released under the MIT license, meaning you can do what ever you want with it as long as you don't blame me. It's free, which means there is absolutely no support included.
See CHANGELOG.md.