mailchimp.module in Mailchimp 7.4
Mailchimp module.
File
mailchimp.moduleView source
<?php
/**
* @file
* Mailchimp module.
*/
use Mailchimp\MailchimpLists;
define('MAILCHIMP_QUEUE_CRON', 'mailchimp');
define('MAILCHIMP_BATCH_QUEUE_CRON', 'mailchimp_batch');
define('MAILCHIMP_STATUS_SENT', 'sent');
define('MAILCHIMP_STATUS_SAVE', 'save');
define('MAILCHIMP_STATUS_PAUSED', 'paused');
define('MAILCHIMP_STATUS_SCHEDULE', 'schedule');
define('MAILCHIMP_STATUS_SENDING', 'sending');
/**
* Implements hook_libraries_info().
*/
function mailchimp_libraries_info() {
$libraries['mailchimp'] = array(
'name' => 'Mailchimp API',
'vendor url' => 'https://github.com/thinkshout/mailchimp-api-php',
'download url' => 'https://github.com/thinkshout/mailchimp-api-php/releases/download/v1.0.10/v1.0.10-package.zip',
'version arguments' => array(
'file' => 'composer.json',
'pattern' => '/"version": "([0-9a-zA-Z.-]+)"/',
),
'files' => array(
'php' => array(
'src/Mailchimp.php',
'src/MailchimpAPIException.php',
'src/MailchimpCampaigns.php',
'src/MailchimpConnectedSites.php',
'src/MailchimpLists.php',
'src/MailchimpReports.php',
'src/MailchimpTemplates.php',
'vendor/autoload.php',
),
),
);
return $libraries;
}
/**
* Implements hook_menu().
*/
function mailchimp_menu() {
$items = array();
$items['admin/config/services/mailchimp'] = array(
'title' => 'Mailchimp',
'description' => 'Manage Mailchimp Settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'mailchimp_admin_settings',
),
'access arguments' => array(
'administer mailchimp',
),
'file' => 'includes/mailchimp.admin.inc',
'type' => MENU_NORMAL_ITEM,
);
$items['admin/config/services/mailchimp/global'] = array(
'title' => 'Global Settings',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['admin/config/services/mailchimp/list_cache_clear'] = array(
'title' => 'Mailchimp webhooks endpoint',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'mailchimp_clear_list_cache_form',
),
'access callback' => 'mailchimp_apikey_ready_access',
'access arguments' => array(
'administer mailchimp',
),
'file' => 'includes/mailchimp.admin.inc',
'type' => MENU_CALLBACK,
);
$items['mailchimp/webhook'] = array(
'title' => 'Mailchimp webhooks endpoint',
'page callback' => 'mailchimp_process_webhook',
'access callback' => 'mailchimp_process_webhook_access',
'access arguments' => array(
2,
),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_permission().
*/
function mailchimp_permission() {
return array(
'administer mailchimp' => array(
'title' => t('administer mailchimp'),
'description' => t('Access the Mailchimp configuration options.'),
),
);
}
/**
* Access callback for mailchimp submodule menu items.
*/
function mailchimp_apikey_ready_access($permission) {
if (mailchimp_get_api_object() && user_access($permission)) {
return TRUE;
}
return FALSE;
}
/**
* Get an instance of the Mailchimp library.
*
* @param string $classname
* The Mailchimp library class to instantiate.
* @param string $api_key
* The Mailchimp api key to use if not the default.
*
* @return Mailchimp
* Instance of the Mailchimp library class. Can be overridden by $classname.
*/
function mailchimp_get_api_object($classname = 'Mailchimp', $api_key = NULL) {
// Set correct library class namespace depending on test mode.
if (variable_get('mailchimp_test_mode', FALSE)) {
$classname = '\\Mailchimp\\Tests\\' . $classname;
}
else {
$classname = '\\Mailchimp\\' . $classname;
}
$mailchimp =& drupal_static(__FUNCTION__);
if (!$api_key && isset($mailchimp) && $mailchimp instanceof $classname) {
return $mailchimp;
}
if (module_exists('libraries')) {
$library = libraries_load('mailchimp');
}
else {
$library = FALSE;
}
if (!$library['installed'] && !class_exists('Mailchimp\\Mailchimp')) {
$msg = t('Failed to load the Mailchimp PHP library. Please refer to the installation requirements.');
watchdog('mailchimp', $msg, array(), WATCHDOG_ERROR);
drupal_set_message($msg, 'error', FALSE);
return NULL;
}
if (!class_exists('\\GuzzleHttp\\Client')) {
$msg = t('The Mailchimp PHP library is missing the required GuzzleHttp library. Please check the installation notes in README.txt.');
watchdog('mailchimp', $msg, array(), WATCHDOG_ERROR);
drupal_set_message($msg, 'error', FALSE);
return NULL;
}
$context = array(
'api_class' => $classname,
);
if (!$api_key) {
$api_key = $default_api_key = variable_get('mailchimp_api_key', '');
// Allow modules to alter the default.
drupal_alter('mailchimp_api_key', $api_key, $context);
// Check to see if the key was altered.
if ($api_key !== $default_api_key) {
// Invalidate all caches because the key was altered.
mailchimp_cache_clear_all();
}
}
if (!strlen($api_key)) {
watchdog('mailchimp', 'Mailchimp Error: API Key cannot be blank.', array(), WATCHDOG_ERROR);
return NULL;
}
// Set the timeout to something that won't take down the Drupal site:
$http_options = [
'timeout' => 60,
];
$proxy_server = variable_get('proxy_server', '');
if ($proxy_server) {
$proxy_url = sprintf('tcp://%s:%d', $proxy_server, variable_get('proxy_port', 8080));
$http_options['proxy'] = [
'http' => $proxy_url,
'https' => $proxy_url,
];
if ($proxy_username = variable_get('proxy_username', '')) {
$proxy_password = variable_get('proxy_password', '');
$http_options['headers']['Proxy-Authorization'] = 'Basic ' . base64_encode($proxy_username . (!empty($proxy_password) ? ":" . $proxy_password : ''));
}
}
$http_options['headers']['User-Agent'] = _mailchimp_get_user_agent();
$mailchimp = new $classname($api_key, 'apikey', $http_options);
return $mailchimp;
}
/**
* Gets the user agent string for this installation of Mailchimp.
*
* @return string
* The user agent string.
*/
function _mailchimp_get_user_agent() {
$version = '7.x-4.x';
if (module_exists('system')) {
$info = system_get_info('module', 'mailchimp');
if (!empty($info['version'])) {
$version = $info['version'];
}
}
$user_agent = "DrupalMailchimp/{$version} " . \GuzzleHttp\default_user_agent();
return $user_agent;
}
/**
* Gets a single Mailchimp list by ID.
*
* @param string $list_id
* The unique ID of the list provided by Mailchimp.
* @param bool $use_interest_groups
* TRUE to load interest groups for the list.
* @param bool $reset
* TRUE to reset list cache and load from Mailchimp.
*
* @return object
* A Mailchimp list object.
*/
function mailchimp_get_list($list_id, $use_interest_groups = TRUE, $reset = FALSE) {
$cache = $reset ? NULL : cache_get('list-' . $list_id, 'cache_mailchimp');
if (!empty($cache)) {
// Use cached list only if interest group requirement is met.
if (!$use_interest_groups || $use_interest_groups && isset($cache->data->intgroups)) {
return $cache->data;
}
}
$list = NULL;
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot get list without Mailchimp API. Check API key has been entered.');
}
$list = $mc_lists
->getList($list_id);
if (!empty($list)) {
if ($use_interest_groups) {
// Add interest categories to the list.
$int_category_data = $mc_lists
->getInterestCategories($list->id, array(
'count' => 500,
));
if ($int_category_data->total_items > 0) {
$list->intgroups = array();
foreach ($int_category_data->categories as $interest_category) {
if (isset($interest_category->type) && $interest_category->type == 'hidden') {
continue;
}
$interest_data = $mc_lists
->getInterests($list->id, $interest_category->id, array(
'count' => 500,
));
if ($interest_data->total_items > 0) {
$interest_category->interests = $interest_data->interests;
}
$list->intgroups[] = $interest_category;
}
}
}
// Add mergefields to the list.
$mergefields = $mc_lists
->getMergeFields($list->id, array(
'count' => 500,
));
if ($mergefields->total_items > 0) {
$list->mergevars = $mergefields->merge_fields;
}
}
cache_set('list-' . $list_id, $list, 'cache_mailchimp', CACHE_PERMANENT);
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred requesting list information from Mailchimp. "%message"', array(
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
return $list;
}
/**
* Gets Mailchimp lists. Can be filtered by an array of list IDs.
*
* @param array $list_ids
* An array of list IDs to filter the results by.
* @param bool $use_interest_groups
* TRUE to load interest groups for the list.
* @param bool $reset
* TRUE to reset list cache and load from Mailchimp.
*
* @return array
* An array of Mailchimp list objects.
*/
function mailchimp_get_lists($list_ids = array(), $use_interest_groups = TRUE, $reset = FALSE) {
$cache = $reset ? NULL : cache_get('lists', 'cache_mailchimp');
// Return cached lists:
if ($cache) {
$lists = $cache->data;
}
else {
$lists = array();
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot get lists without Mailchimp API. Check API key has been entered.');
}
$result = $mc_lists
->getLists(array(
'count' => 500,
));
if ($result->total_items > 0) {
foreach ($result->lists as $list) {
if ($use_interest_groups) {
// Add interest categories to the list.
$int_category_data = $mc_lists
->getInterestCategories($list->id, array(
'count' => 500,
));
if ($int_category_data->total_items > 0) {
$list->intgroups = array();
foreach ($int_category_data->categories as $interest_category) {
if (isset($interest_category->type) && $interest_category->type == 'hidden') {
continue;
}
$interest_data = $mc_lists
->getInterests($list->id, $interest_category->id, array(
'count' => 500,
));
if ($interest_data->total_items > 0) {
$interest_category->interests = $interest_data->interests;
}
$list->intgroups[] = $interest_category;
}
}
}
$lists[$list->id] = $list;
// Add mergefields to the list.
$mergefields = $mc_lists
->getMergeFields($list->id, array(
'count' => 500,
));
if ($mergefields->total_items > 0) {
$lists[$list->id]->mergevars = $mergefields->merge_fields;
}
}
}
uasort($lists, '_mailchimp_list_cmp');
cache_set('lists', $lists, 'cache_mailchimp', CACHE_PERMANENT);
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred requesting list information from Mailchimp. "%message"', array(
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
}
// Filter by given ids:
if (!empty($list_ids)) {
$filtered_lists = array();
foreach ($list_ids as $id) {
if (array_key_exists($id, $lists)) {
$filtered_lists[$id] = $lists[$id];
}
}
return $filtered_lists;
}
else {
return $lists;
}
}
/**
* Helper function used by uasort() to sort lists alphabetically by name.
*
* @param array $a
* An array representing the first list.
* @param array $b
* An array representing the second list.
*
* @return int
* One of the values -1, 0, 1
*/
function _mailchimp_list_cmp($a, $b) {
if ($a->name == $b->name) {
return 0;
}
return $a->name < $b->name ? -1 : 1;
}
/**
* Wrapper around MailchimpLists->getMergeFields().
*
* @param array $list_ids
* Array of Mailchimp list IDs.
* @param bool $reset
* Set to TRUE if mergevars should not be loaded from cache.
*
* @return array
* Struct describing mergevars for the specified lists.
*/
function mailchimp_get_mergevars($list_ids, $reset = FALSE) {
$mergevars = array();
if (!$reset) {
foreach ($list_ids as $key => $list_id) {
$cache = cache_get($list_id . '-mergevars', 'cache_mailchimp');
// Get cached data and unset from our remaining lists to query.
if ($cache) {
$mergevars[$list_id] = $cache->data;
unset($list_ids[$key]);
}
}
}
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
try {
if (!$mc_lists) {
throw new MailchimpException('Cannot get merge vars without Mailchimp API. Check API key has been entered.');
}
// Get the uncached merge vars from Mailchimp.
foreach ($list_ids as $list_id) {
// Add default EMAIL merge var for all lists.
$mergevars[$list_id] = array(
(object) array(
'tag' => 'EMAIL',
'name' => t('Email Address'),
'type' => 'email',
'required' => TRUE,
'default_value' => '',
'public' => TRUE,
'display_order' => 1,
'options' => (object) array(
'size' => 25,
),
),
);
$result = $mc_lists
->getMergeFields($list_id, array(
'count' => 500,
));
if ($result->total_items > 0) {
$mergevars[$list_id] = array_merge($mergevars[$list_id], $result->merge_fields);
}
cache_set($list_id . '-mergevars', $mergevars[$list_id], 'cache_mailchimp', CACHE_TEMPORARY);
}
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred requesting mergevars for list @list. "%message"', array(
'@list' => $list_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
return $mergevars;
}
/**
* Get the Mailchimp member info for a given email address and list.
*
* Results are cached in the cache_mailchimp bin which is cleared by the
* Mailchimp web hooks system when needed.
*
* @param string $list_id
* The Mailchimp list ID to get member info for.
* @param string $email
* The Mailchimp user email address to load member info for.
* @param bool $reset
* Set to TRUE if member info should not be loaded from cache.
*
* @return object
* Member info object, empty if there is no valid info.
*/
function mailchimp_get_memberinfo($list_id, $email, $reset = FALSE) {
$cache = $reset ? NULL : cache_get($list_id . '-' . $email, 'cache_mailchimp');
// Return cached lists:
if ($cache) {
return $cache->data;
}
// Query lists from the MCAPI and store in cache:
$memberinfo = new stdClass();
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
try {
if (!$mc_lists) {
throw new MailchimpException('Cannot get member info without Mailchimp API. Check API key has been entered.');
}
try {
$memberinfo = $mc_lists
->getMemberInfo($list_id, $email);
cache_set($list_id . '-' . $email, $memberinfo, 'cache_mailchimp', CACHE_TEMPORARY);
} catch (Exception $e) {
// Throw exception only for errors other than member not found.
if ($e
->getCode() != 404) {
throw new Exception($e
->getMessage(), $e
->getCode(), $e);
}
}
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred requesting memberinfo for @email in list @list. "%message"', array(
'@email' => $email,
'@list' => $list_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
return $memberinfo;
}
/**
* Check if the given email is subscribed to the given list.
*
* Simple wrapper around mailchimp_get_memberinfo().
*
* @param string $list_id
* Unique string identifier for the list on your Mailchimp account.
* @param string $email
* Email address to check for on the identified Mailchimp List.
* @param bool $reset
* Set to TRUE to ignore the cache. (Used heavily in testing functions.)
*
* @return bool
* Indicates subscription status.
*/
function mailchimp_is_subscribed($list_id, $email, $reset = FALSE) {
$subscribed = FALSE;
$memberinfo = mailchimp_get_memberinfo($list_id, $email, $reset);
if (isset($memberinfo->status) && $memberinfo->status == 'subscribed') {
$subscribed = TRUE;
}
return $subscribed;
}
/**
* Subscribe a user to a Mailchimp list in real time or by adding to the queue.
*
* @see Mailchimp_Lists::subscribe()
*
* @return bool
* True on success.
*/
function mailchimp_subscribe($list_id, $email, $merge_vars = NULL, $interests = array(), $double_optin = FALSE, $format = 'html') {
if (variable_get('mailchimp_cron', FALSE)) {
$args = array(
'list_id' => $list_id,
'email' => $email,
'merge_vars' => $merge_vars,
'interests' => $interests,
'double_optin' => $double_optin,
'format' => $format,
);
return mailchimp_addto_queue('mailchimp_subscribe_process', $args);
}
return mailchimp_subscribe_process($list_id, $email, $merge_vars, $interests, $double_optin, $format);
}
/**
* Wrapper around MailchimpLists::addOrUpdateMember().
*
* @see MailchimpLists::addOrUpdateMember()
*
* @return object
* On success a result object will be returned from Mailchimp. On failure an
* object will be returned with the property success set to FALSE, the
* response code as a property, and the message as a property. To check for
* a failure, look for the property 'success' of the object returned to
* be set to FALSE.
*/
function mailchimp_subscribe_process($list_id, $email, $merge_vars = NULL, $interests = array(), $double_optin = FALSE, $format = 'html') {
$result = FALSE;
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot subscribe to list without Mailchimp API. Check API key has been entered.');
}
$parameters = array(
// If double opt-in is required, set member status to 'pending', but only
// if the user isn't already subscribed.
'status' => $double_optin && !mailchimp_is_subscribed($list_id, $email) ? \Mailchimp\MailchimpLists::MEMBER_STATUS_PENDING : \Mailchimp\MailchimpLists::MEMBER_STATUS_SUBSCRIBED,
'email_type' => $format,
);
// Set interests.
if (!empty($interests)) {
$parameters['interests'] = (object) $interests;
}
// Set merge fields.
if (!empty($merge_vars)) {
$parameters['merge_fields'] = (object) $merge_vars;
}
// Add member to list.
$result = $mc_lists
->addOrUpdateMember($list_id, $email, $parameters);
if (isset($result->id)) {
module_invoke_all('mailchimp_subscribe_user', $list_id, $email, $merge_vars);
// Clear user cache, just in case there's some cruft leftover:
mailchimp_cache_clear_member($list_id, $email);
watchdog('mailchimp', '@email was subscribed to list @list.', array(
'@email' => $email,
'@list' => $list_id,
), WATCHDOG_NOTICE);
}
else {
if (!variable_get('mailchimp_test_mode')) {
watchdog('mailchimp', 'A problem occurred subscribing @email to list @list.', array(
'@email' => $email,
'@list' => $list_id,
), WATCHDOG_WARNING);
}
}
} catch (Exception $e) {
if ($e
->getCode() == '400' && strpos($e
->getMessage(), 'Member In Compliance State') !== false && !$double_optin) {
watchdog('mailchimp', 'Detected "Member In Compliance State" subscribing @email to list @list. Trying again using double-opt in.', array(
'@email' => $email,
'@list' => $list_id,
), WATCHDOG_INFO);
return mailchimp_subscribe_process($list_id, $email, $merge_vars, $interests, TRUE, $format);
}
watchdog('mailchimp', 'An error occurred subscribing @email to list @list. Status code @code. "%message"', array(
'@email' => $email,
'@list' => $list_id,
'%message' => $e
->getMessage(),
'@code' => $e
->getCode(),
), WATCHDOG_ERROR);
$result = new stdClass();
$result->success = FALSE;
$result->status = $e
->getCode();
$result->message = $e
->getMessage();
}
if ($double_optin) {
drupal_set_message(t('Please check your email to confirm your subscription'), 'status', FALSE);
}
return $result;
}
/**
* Add a Mailchimp subscription task to the queue.
*
* @string $function
* The name of the function the queue runner should call.
* @array $args
* The list of args to pass to the function.
*
* @return bool
* Success or failure.
*/
function mailchimp_addto_queue($function, $args) {
$queue = DrupalQueue::get(MAILCHIMP_QUEUE_CRON);
$queue
->createQueue();
mailchimp_update_local_cache($function, $args);
return $queue
->createItem(array(
'function' => $function,
'args' => $args,
));
}
/**
* Updates the local cache for a user as though a queued request had been
* processed.
*
* If we don't do this, then users can make changes, but not have them shown on
* the site until cron runs, which is intensely confusing. See
* https://www.drupal.org/node/2503597
*
* @param string $function
* The name of the function that the queue runner will call when the update
* is processed.
* @param array $args
* The list of args that will be passed to the queue runner.
*
* @return bool
*/
function mailchimp_update_local_cache($function, $args) {
$list_id = isset($args['list_id']) ? $args['list_id'] : NULL;
$email = isset($args['email']) ? $args['email'] : NULL;
if (empty($list_id) || empty($email)) {
return FALSE;
}
$cache = mailchimp_get_memberinfo($list_id, $email);
if (empty($cache)) {
// Create a new entry.
cache_set($list_id . '-' . $email, (object) array(
'merge_fields' => new stdClass(),
), 'cache_mailchimp', CACHE_TEMPORARY);
$cache = cache_get($list_id . '-' . $email, 'cache_mailchimp');
$cache = $cache->data;
}
// Handle unsubscribes.
if ($function == 'mailchimp_unsubscribe_process') {
$cache->status = 'unsubscribed';
// Reset interests.
$cache->interests = new stdClass();
}
// Handle subscribes.
if ($function == 'mailchimp_subscribe_process') {
$cache->status = 'subscribed';
}
// Handle member updates.
if ($function == 'mailchimp_update_member_process' || $function == 'mailchimp_subscribe_process') {
// Update cached merge vars.
if (!isset($cache->merge_fields)) {
$cache->merge_fields = new stdClass();
}
foreach ($args['merge_vars'] as $key => $value) {
$cache->merge_fields->{$key} = $value;
}
// Update cached interests.
$cache->interests = new stdClass();
foreach ($args['interests'] as $interest_group => $interests) {
if (is_array($interests)) {
foreach ($interests as $interest_id => $value) {
if ($value !== 0) {
$cache->interests->{$interest_id} = TRUE;
}
}
}
elseif ($interests) {
$cache->interests->{$interest_group} = TRUE;
}
}
}
// Store the data back in the local cache.
cache_set($list_id . '-' . $email, $cache, 'cache_mailchimp', CACHE_TEMPORARY);
}
/**
* Update a members list subscription in real time or by adding to the queue.
*
* @see Mailchimp_Lists::updateMember()
*
* @return bool
* Success or failure.
*/
function mailchimp_update_member($list_id, $email, $merge_vars, $interests, $format = 'html', $double_optin = FALSE) {
if (variable_get('mailchimp_cron', FALSE)) {
$args = array(
'list_id' => $list_id,
'email' => $email,
'merge_vars' => $merge_vars,
'interests' => $interests,
'format' => $format,
'double_optin' => $double_optin,
);
return mailchimp_addto_queue('mailchimp_update_member_process', $args);
}
return mailchimp_update_member_process($list_id, $email, $merge_vars, $interests, $format, $double_optin);
}
/**
* Wrapper around MailchimpLists::updateMember().
*
* @see MailchimpLists::updateMember()
*
* @return bool
* Success or failure.
*/
function mailchimp_update_member_process($list_id, $email, $merge_vars, $interests, $format, $double_optin = FALSE) {
$result = FALSE;
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot update member without Mailchimp API. Check API key has been entered.');
}
$parameters = array(
'status' => $double_optin ? \Mailchimp\MailchimpLists::MEMBER_STATUS_PENDING : \Mailchimp\MailchimpLists::MEMBER_STATUS_SUBSCRIBED,
'email_type' => $format,
);
// Set interests.
if (!empty($interests)) {
$parameters['interests'] = (object) $interests;
}
// Set merge fields.
if (!empty($merge_vars)) {
$parameters['merge_fields'] = (object) $merge_vars;
}
// Update member.
$result = $mc_lists
->updateMember($list_id, $email, $parameters);
if (!empty($result) && isset($result->id)) {
watchdog('mailchimp', '@email was updated in list @list_id.', array(
'@email' => $email,
'@list' => $list_id,
), WATCHDOG_NOTICE);
// Clear user cache:
mailchimp_cache_clear_member($list_id, $email);
}
else {
watchdog('mailchimp', 'A problem occurred updating @email on list @list.', array(
'@email' => $email,
'@list' => $list_id,
), WATCHDOG_WARNING);
}
} catch (Exception $e) {
if ($e
->getCode() == '400' && strpos($e
->getMessage(), 'Member In Compliance State') !== false && !$double_optin) {
watchdog('mailchimp', 'Detected "Member In Compliance State" updating @email to list @list. Trying again using double-opt in.', array(
'@email' => $email,
'@list' => $list_id,
), WATCHDOG_INFO);
return mailchimp_update_member_process($list_id, $email, $merge_vars, $interests, $format, TRUE);
}
watchdog('mailchimp', 'An error occurred updating @email on list @list. "%message"', array(
'@email' => $email,
'@list' => $list_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
if ($double_optin) {
drupal_set_message(t('Please check your email to confirm your subscription'), 'status', FALSE);
}
return $result;
}
/**
* Retrieve all members of a given list with a given status.
*
* Note that this function can cause locking an is somewhat slow. It is not
* recommended unless you know what you are doing! See the MCAPI documentation.
*/
function mailchimp_get_members($list_id, $status = 'subscribed', $options = array()) {
$results = FALSE;
if (lock_acquire('mailchimp_get_members', 60)) {
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot get members without Mailchimp API. Check API key has been entered.');
}
$options['status'] = $status;
if (!isset($options['count']) || empty($options['count'])) {
$options['count'] = 500;
}
$results = $mc_lists
->getMembers($list_id, $options);
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred pulling member info for a list. "%message"', array(
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
lock_release('mailchimp_get_members');
}
return $results;
}
/**
* Wrapper around MailchimpLists->addOrUpdateMember().
*
* $batch is an array where each element is an array formatted thus:
* 'email' => 'example@example.com',
* 'email_type' => 'html' or 'text',
* 'merge_vars' => array('MERGEKEY' => 'value', 'MERGEKEY2' => 'value2'),
*/
function mailchimp_batch_update_members($list_id, $batch, $double_in = FALSE) {
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot batch subscribe to list without Mailchimp API. Check API key has been entered.');
}
if (!empty($batch)) {
// Create a new batch update operation for each member.
foreach ($batch as $batch_data) {
// TODO: Remove 'advanced' earlier? Needed at all?
unset($batch_data['merge_vars']['advanced']);
$parameters = array(
'email_type' => $batch_data['email_type'],
'merge_fields' => (object) $batch_data['merge_vars'],
);
$mc_lists
->addOrUpdateMember($list_id, $batch_data['email'], $parameters, TRUE);
}
// Process batch operations.
return $mc_lists
->processBatchOperations();
}
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred performing batch subscribe/update. "%message"', array(
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
}
/**
* Unsubscribe a member from a list.
*
* @param string $list_id
* A mailchimp list id.
* @param string $email
* Email address to be unsubscribed.
* @param bool $delete
* Indicates whether an email should be deleted or just unsubscribed.
* @param bool $goodbye
* Indicates whether to send the goodbye email to the email address.
* @param bool $notify
* Indicates whether to send the unsubscribe notification email to the address
* defined in the list email notification settings.
*
* @return bool
* Indicates whether unsubscribe was successful.
*/
function mailchimp_unsubscribe_member($list_id, $email, $delete = FALSE, $goodbye = FALSE, $notify = FALSE) {
$result = FALSE;
if (mailchimp_is_subscribed($list_id, $email)) {
if (variable_get('mailchimp_cron', FALSE)) {
$result = mailchimp_addto_queue('mailchimp_unsubscribe_process', array(
'list_id' => $list_id,
'email' => $email,
'delete' => $delete,
'goodbye' => $goodbye,
'notify' => $notify,
));
}
else {
$result = mailchimp_unsubscribe_process($list_id, $email, $delete, $goodbye, $notify);
}
}
return $result;
}
/**
* Unsubscribe a member from a list.
*
* @return bool
* Success or failure.
*/
function mailchimp_unsubscribe_process($list_id, $email, $delete, $goodbye, $notify) {
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot unsubscribe from list without Mailchimp API. Check API key has been entered.');
}
if ($delete) {
// Remove member from list.
$mc_lists
->removeMember($list_id, $email);
watchdog('mailchimp', '@email was removed from list @list_id.', array(
'@email' => $email,
'@list' => $list_id,
), WATCHDOG_INFO);
}
else {
// Unsubscribe member.
$parameters = array(
'status' => MailchimpLists::MEMBER_STATUS_UNSUBSCRIBED,
);
$mc_lists
->updateMember($list_id, $email, $parameters);
watchdog('mailchimp', '@email was unsubscribed from list @list_id.', array(
'@email' => $email,
'@list' => $list_id,
), WATCHDOG_INFO);
}
module_invoke_all('mailchimp_unsubscribe_user', $list_id, $email);
// Clear user cache:
mailchimp_cache_clear_member($list_id, $email);
return TRUE;
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred unsubscribing @email from list @list. "%message"', array(
'@email' => $email,
'@list' => $list_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
return FALSE;
}
}
/**
* Wrapper around MailchimpLists->getSegments().
*
* @param string $list_id
* A Mailchimp list id.
* @param bool $reset
* Set to TRUE if list segments should not be loaded from cache.
*
* @return array
* Array of segments details.
*/
function mailchimp_get_segments($list_id, $reset = NULL) {
$cache = $reset ? NULL : cache_get($list_id . '-segments', 'cache_mailchimp');
// Return cached lists:
if ($cache) {
return $cache->data;
}
// Query segments from the MCAPI and store in cache:
$segments = array();
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot get list segments without Mailchimp API. Check API key has been entered.');
}
$result = $mc_lists
->getSegments($list_id, array(
'count' => 500,
));
$segments = $result->total_items > 0 ? $result->segments : array();
cache_set($list_id . '-segments', $segments, 'cache_mailchimp', CACHE_TEMPORARY);
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred requesting list segment information from Mailchimp. "%message"', array(
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
return $segments;
}
/**
* Wrapper around MailchimpLists->addSegment().
*
* @param string $list_id
* A Mailchimp list id.
* @param string $name
* A label for the segment.
* @param string $type
* Can be 'static' or 'saved'.
* @param array $segment_options
* Array of options for 'saved' segments. See Mailchimp API docs.
*
* @return int
* ID of the new segment.
*/
function mailchimp_segment_create($list_id, $name, $type, $segment_options = NULL) {
$segment_id = FALSE;
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot add list segment without Mailchimp API. Check API key has been entered.');
}
$parameters = array(
'type' => $type,
);
if ($type == 'saved') {
$parameters['options'] = $segment_options;
}
$result = $mc_lists
->addSegment($list_id, $name, $parameters);
if (!empty($result->id)) {
$segment_id = $result->id;
}
// Clear the segment cache:
mailchimp_get_segments($list_id, TRUE);
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred creating segment @segment for list @list. "%message"', array(
'@segment' => $name,
'@list' => $list_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
return $segment_id;
}
/**
* Add a specific subscriber to a static segment of a list.
*
* @param string $list_id
* ID of a Mailchimp list.
* @param string $segment_id
* ID of a segment of the Mailchimp list.
* @param string $email
* Email address to add to the segment (does NOT subscribe to the list).
* @param bool $batch
* Whether to queue this for the batch processor. Defaults to TRUE.
* @param string $queue_id
* The ID of the queue to use in batch processing.
*
* @return bool
* Success boolean
*/
function mailchimp_segment_add_subscriber($list_id, $segment_id, $email, $batch = TRUE, $queue_id = MAILCHIMP_BATCH_QUEUE_CRON) {
$item = array(
'email' => $email,
);
if (!$batch) {
$batch = array(
$item,
);
$success = mailchimp_segment_batch_add_subscribers($list_id, $segment_id, $batch);
}
else {
$queue = DrupalQueue::get($queue_id);
$queue
->createQueue();
$success = $queue
->createItem(array(
'function' => 'mailchimp_segment_batch_add_subscribers',
'list_id' => $list_id,
'arg' => $segment_id,
'item' => $item,
));
if (!$success) {
watchdog('mailchimp', 'A problem occurred adding a Mailchimp segment subscribe to the queue. Email: @email List: @list Segment: @segment.', array(
'@email' => $email,
'@list' => $list_id,
'@segment' => $segment_id,
), WATCHDOG_WARNING);
}
}
return $success;
}
/**
* Add a batch of email addresses to a static segment of a list.
*
* @param string $list_id
* ID of a Mailchimp list.
* @param string $segment_id
* ID of a segment of the Mailchimp list.
* @param array $batch
* Batch of email addresses to add to the segment (does NOT subscribe new).
*
* @return int
* Successful subscribe count
*/
function mailchimp_segment_batch_add_subscribers($list_id, $segment_id, $batch) {
$count = 0;
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot batch add segment subscribers without Mailchimp API. Check API key has been entered.');
}
$segments_data = $mc_lists
->getSegments($list_id, array(
'count' => 500,
));
$matched_segment = NULL;
foreach ($segments_data->segments as $segment) {
if ($segment->id == $segment_id) {
$matched_segment = $segment;
continue;
}
}
if ($matched_segment != NULL) {
$parameters = array(
'static_segment' => $batch,
);
$result = $mc_lists
->updateSegment($list_id, $segment_id, $matched_segment->name, $parameters);
$count = isset($result->member_count) ? $result->member_count : 0;
}
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred on batch segment add. List: @list_id Segment: @segment_id. "%message"', array(
'@list_id' => $list_id,
'@segment_id' => $segment_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
return $count;
}
/**
* Wrapper around MailchimpCampaigns->getCampaign() to return data for a given
* campaign.
*
* Data is stored in the Mailchimp cache.
*
* @param string $campaign_id
* The ID of the campaign to get data for.
* @param bool $reset
* Set to TRUE if campaign data should not be loaded from cache.
*
* @return mixed
* Array of campaign data or FALSE if not found.
*/
function mailchimp_get_campaign_data($campaign_id, $reset = FALSE) {
$cache = $reset ? NULL : cache_get('campaign_' . $campaign_id, 'cache_mailchimp');
$campaign_data = FALSE;
// Return cached lists:
if ($cache) {
return $campaign_data = $cache->data;
}
try {
/* @var \Mailchimp\MailchimpCampaigns $mc_campaigns */
$mc_campaigns = mailchimp_get_api_object('MailchimpCampaigns');
if (!$mc_campaigns) {
throw new MailchimpException('Cannot get list without Mailchimp API. Check API key has been entered.');
}
$response = $mc_campaigns
->getCampaign($campaign_id);
if (!empty($response->id)) {
$campaign_data = $response;
cache_set('campaign_' . $campaign_id, $response, 'cache_mailchimp', CACHE_TEMPORARY);
}
else {
$campaign_data = FALSE;
}
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred retrieving campaign data for @campaign. "%message"', array(
'@campaign' => $campaign_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
return $campaign_data;
}
/**
* Wrapper around MailchimpLists->getListsForEmail()`.
*
* Returns all lists a given email address is currently subscribed to.
*
* @param string $email
* Email address to search.
*
* @return array
* Campaign structs containing id, web_id, name.
*/
function mailchimp_get_lists_for_email($email) {
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot get lists without Mailchimp API. Check API key has been entered.');
}
$lists = $mc_lists
->getListsForEmail($email);
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred retreiving lists data for @email. "%message"', array(
'@email' => $email,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
$lists = array();
}
return $lists;
}
/**
* Wrapper around MailchimpLists->getWebhooks().
*
* @param string $list_id
* Mailchimp API List ID.
*
* @return mixed
* Array of existing webhooks, or FALSE.
*/
function mailchimp_webhook_get($list_id) {
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot get webhook without Mailchimp API. Check API key has been entered.');
}
$result = $mc_lists
->getWebhooks($list_id);
return $result->total_items > 0 ? $result->webhooks : FALSE;
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred reading webhooks for list @list. "%message"', array(
'@list' => $list_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
return FALSE;
}
}
/**
* Wrapper around MailchimpLists->addWebhook().
*
* @return mixed
* New webhook ID if added, FALSE otherwise.
*/
function mailchimp_webhook_add($list_id, $url, $events = array(), $sources = array()) {
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot add webhook without Mailchimp API. Check API key has been entered.');
}
$parameters = array(
'events' => (object) $events,
'sources' => (object) $sources,
);
$result = $mc_lists
->addWebhook($list_id, $url, $parameters);
return $result->id;
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred adding webhook for list @list. "%message"', array(
'@list' => $list_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
return FALSE;
}
}
/**
* Wrapper around MailchimpLists->deleteWebhook().
*
* @return bool
* TRUE if deletion was successful, otherwise FALSE.
*/
function mailchimp_webhook_delete($list_id, $url) {
try {
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
if (!$mc_lists) {
throw new MailchimpException('Cannot delete webhook without Mailchimp API. Check API key has been entered.');
}
$result = $mc_lists
->getWebhooks($list_id);
if ($result->total_items > 0) {
foreach ($result->webhooks as $webhook) {
if ($webhook->url == $url) {
$mc_lists
->deleteWebhook($list_id, $webhook->id);
return TRUE;
}
}
}
return FALSE;
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred deleting webhook for list @list. "%message"', array(
'@list' => $list_id,
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
return FALSE;
}
}
/**
* Clear a mailchimp user memberinfo cache.
*
* @string $list_id
* @string $email
*/
function mailchimp_cache_clear_member($list_id, $email) {
cache_clear_all($list_id . '-' . $email, 'cache_mailchimp');
}
/**
* Clear a mailchimp activity cache.
*
* @string $list_id
*/
function mailchimp_cache_clear_list_activity($list_id) {
cache_clear_all('mailchimp_activity_' . $list_id, 'cache_mailchimp');
}
/**
* Clear a mailchimp activity cache.
*
* @string $list_id
*/
function mailchimp_cache_clear_campaign($campaign_id) {
cache_clear_all('mailchimp_campaign_' . $campaign_id, 'cache_mailchimp');
}
/**
* Clear all mailchimp caches.
*/
function mailchimp_cache_clear_all() {
cache_clear_all('*', 'cache_mailchimp', TRUE);
}
/**
* Implements hook_flush_caches().
*/
function mailchimp_flush_caches() {
return array(
'cache_mailchimp',
);
}
/**
* Access callback for mailchimp_process_webhook().
*
* @string $key
*/
function mailchimp_process_webhook_access($key) {
return $key == mailchimp_webhook_key();
}
/**
* Process a webhook post from Mailchimp.
*/
function mailchimp_process_webhook() {
if (empty($_POST)) {
return "Mailchimp Webhook Endpoint.";
}
$data = $_POST['data'];
$type = $_POST['type'];
switch ($type) {
case 'unsubscribe':
case 'profile':
case 'cleaned':
mailchimp_get_memberinfo($data['list_id'], $data['email'], TRUE);
break;
case 'upemail':
mailchimp_cache_clear_member($data['list_id'], $data['old_email']);
mailchimp_get_memberinfo($data['list_id'], $data['new_email'], TRUE);
break;
case 'campaign':
mailchimp_cache_clear_list_activity($data['list_id']);
mailchimp_cache_clear_campaign($data['id']);
break;
}
// Allow other modules to act on a webhook.
module_invoke_all('mailchimp_process_webhook', $type, $data);
// Log event:
watchdog('mailchimp', 'Webhook type @type has been processed.', array(
'@type' => $type,
), WATCHDOG_INFO);
return NULL;
}
/**
* Generate a key to include in the webhook url based on a hash.
*
* @string $list_id
*
* @return string
* The key.
*/
function mailchimp_webhook_key() {
return drupal_hash_base64($GLOBALS['base_url'] . drupal_get_private_key() . drupal_get_hash_salt());
}
/**
* Generate the webhook endpoint URL.
*
* @string $list_id
*
* @return string
* The endpoint URL.
*/
function mailchimp_webhook_url() {
return $GLOBALS['base_url'] . '/mailchimp/webhook/' . mailchimp_webhook_key();
}
/**
* Helper function to generate form elements for a list's interest groups.
*
* @param array $list
* Fully loaded array with mailchimp list settings as returned by
* mailchimp_get_list()
* @param array $defaults
* Array of default values to use if no group subscription values already
* exist at Mailchimp.
* @param string $email
* Optional email address to pass to the MCAPI and retrieve existing values
* for use as defaults.
*
* @return array
* A collection of form elements, one per interest group.
*/
function mailchimp_interest_groups_form_elements($list, $defaults = array(), $email = NULL) {
$return = array();
foreach ($list->intgroups as $group) {
if ($group->type == 'hidden') {
continue;
}
/* @var \Mailchimp\MailchimpLists $mc_lists */
$mc_lists = mailchimp_get_api_object('MailchimpLists');
$interest_data = $mc_lists
->getInterests($list->id, $group->id, array(
'count' => 500,
));
if (!empty($email)) {
$memberinfo = mailchimp_get_memberinfo($list->id, $email);
}
// Set the form field type:
switch ($group->type) {
case 'radio':
$field_type = 'radios';
break;
case 'dropdown':
$field_type = 'select';
break;
default:
$field_type = $group->type;
}
// Extract the field options:
$options = array();
$default_values = array();
// Set interest options and default values.
foreach ($interest_data->interests as $interest) {
$options[$interest->id] = $interest->name;
if (isset($memberinfo)) {
if (isset($memberinfo->interests->{$interest->id}) && $memberinfo->interests->{$interest->id} === TRUE) {
$default_values[$group->id][] = $interest->id;
}
}
elseif (!empty($defaults)) {
if (isset($defaults[$group->id][$interest->id]) && !empty($defaults[$group->id][$interest->id])) {
$default_values[$group->id][] = $interest->id;
}
}
}
$return[$group->id] = array(
'#type' => $field_type,
'#title' => $group->title,
'#options' => $options,
'#empty_option' => t('-- select --'),
'#default_value' => isset($default_values[$group->id]) ? $default_values[$group->id] : array(),
'#attributes' => array(
'class' => array(
'mailchimp-newsletter-interests-' . $list->id,
),
),
);
}
return $return;
}
/**
* Convert mailchimp form elements to Drupal Form API.
*
* @param array $mergevar
* The mailchimp-formatted form element to convert.
*
* @return array
* A properly formatted drupal form element.
*/
function mailchimp_insert_drupal_form_tag($mergevar, $placeholder) {
// Insert common FormAPI properties:
$input = array(
'#weight' => $mergevar->display_order,
'#required' => $mergevar->required,
'#default_value' => $mergevar->default_value,
);
$placeholder_req = $mergevar->required ? ' *' : '';
$title = t('@mergevar', array(
'@mergevar' => $mergevar->name,
));
// Check to see if we should set placeholder or #title attribute
if ($placeholder) {
$input['#attributes']['placeholder'] = $title . $placeholder_req;
}
else {
$input['#title'] = $title;
}
switch ($mergevar->type) {
case 'address':
// Sub-array of address elements according to Mailchimp specs.
// https://apidocs.mailchimp.com/api/2.0/lists/subscribe.php
$input['#type'] = 'container';
$input['#tree'] = TRUE;
$input['addr1'] = array(
'#type' => 'textfield',
);
$input['addr2'] = array(
'#type' => 'textfield',
);
$input['city'] = array(
'#type' => 'textfield',
);
$input['state'] = array(
'#type' => 'textfield',
'#size' => 2,
'#maxlength' => 2,
);
$input['zip'] = array(
'#type' => 'textfield',
'#size' => 6,
'#maxlength' => 6,
);
$input['country'] = array(
'#type' => 'textfield',
'#size' => 2,
'#maxlength' => 2,
);
if (!$placeholder) {
$input['addr1']['#title'] = t('Address 1');
$input['addr2']['#title'] = t('Address 2');
$input['city']['#title'] = t('City');
$input['state']['#title'] = t('State');
$input['zip']['#title'] = t('Zip');
$input['country']['#title'] = t('Country');
}
else {
$input['addr1']['#attributes']['placeholder'] = t('Address 1') . $placeholder_req;
$input['addr2']['#attributes']['placeholder'] = t('Address 2') . $placeholder_req;
$input['city']['#attributes']['placeholder'] = t('City') . $placeholder_req;
$input['state']['#attributes']['placeholder'] = t('State') . $placeholder_req;
$input['zip']['#attributes']['placeholder'] = t('Zip') . $placeholder_req;
$input['country']['#attributes']['placeholder'] = t('Country') . $placeholder_req;
}
break;
case 'dropdown':
// Dropdown is mapped to <select> element in Drupal Form API.
$input['#type'] = 'select';
// Creates options, we must delete array keys to have relevant information
// on Mailchimp.
$choices = array();
foreach ($mergevar->options->choices as $choice) {
$choices[$choice] = $choice;
}
$input['#options'] = $choices;
break;
case 'radio':
// Radio is mapped to <input type='radio' /> i.e. 'radios' element in
// Drupal Form API.
$input['#type'] = 'radios';
// Creates options, we must delete array keys to have relevant information
// on Mailchimp.
$choices = array();
foreach ($mergevar->options->choices as $choice) {
$choices[$choice] = $choice;
}
$input['#options'] = $choices;
break;
case 'email':
if (element_info_property('emailfield', '#type')) {
// Set to an HTML5 email type if 'emailfield' is supported:
$input['#type'] = 'emailfield';
}
else {
// Set to standard text type if 'emailfield' isn't defined:
$input['#type'] = 'textfield';
// Add validation - not necessary for emailfield type input because
// the "elements" module provides it for elements of type emailfield.
$input['#element_validate'] = array(
'mailchimp_validate_email',
);
}
$input['#size'] = isset($mergevar->options->size) ? $mergevar->options->size : 25;
break;
case 'phone':
$input['#type'] = 'textfield';
$input['#size'] = isset($mergevar->options->size) ? $mergevar->options->size : 25;
$input['#attributes'] = array(
'type' => 'tel',
);
break;
default:
// This is a standard input[type=text] or something we can't handle with
// Drupal FormAPI.
$input['#type'] = 'textfield';
$input['#size'] = isset($mergevar->options->size) ? $mergevar->options->size : 25;
break;
}
// Special cases for Mailchimp hidden defined fields:
if ($mergevar->public === FALSE) {
$input['#access'] = FALSE;
}
return $input;
}
/**
* Form element validation for email input of #type 'textfield'.
*
* Note: #maxlength and #required are validated by _form_validate() already.
*/
function mailchimp_validate_email(&$element, &$form_state) {
if ($element['#value'] && !valid_email_address($element['#value'])) {
form_error($element, t('"%mail" is not a valid email address.', array(
'%mail' => $element['#value'],
)));
}
}
/**
* Implements hook_cron().
*
* We don't use batch API calls currently as it would require sorting through
* a lot of options here. Instead, we will provide VBO functions to perform
* large unsubscribes and subscribes and specifically call the batch functions.
*/
function mailchimp_cron() {
$queue = DrupalQueue::get(MAILCHIMP_QUEUE_CRON);
$queue
->createQueue();
$queue_count = $queue
->numberOfItems();
if ($queue_count > 0) {
$batch_limit = variable_get('mailchimp_batch_limit', 100);
$batch_size = $queue_count < $batch_limit ? $queue_count : $batch_limit;
$count = 0;
while ($count < $batch_size) {
if ($item = $queue
->claimItem()) {
call_user_func_array($item->data['function'], $item->data['args']);
$queue
->deleteItem($item);
}
$count++;
}
}
}
/**
* Implements hook_variable_group_info().
*/
function mailchimp_variable_group_info() {
$groups['mailchimp'] = array(
'title' => t('Mailchimp'),
'description' => t('Settings related to Mailchimp.'),
'access' => 'administer mailchimp',
'path' => array(
'admin/config/services/mailchimp',
),
);
return $groups;
}
/**
* Implements hook_variable_info().
*/
function mailchimp_variable_info($options) {
$variable['mailchimp_api_key'] = array(
'title' => t('Mailchimp API Key', array(), $options),
'group' => 'mailchimp',
);
$variable['mailchimp_cron'] = array(
'title' => t('Use batch processing', array(), $options),
'type' => 'boolean',
'group' => 'mailchimp',
'default' => FALSE,
);
$variable['mailchimp_batch_limit'] = array(
'title' => t('Batch limit', array(), $options),
'type' => 'number',
'group' => 'mailchimp',
'default' => 100,
);
return $variable;
}
/**
* Replace an array of merge field placeholder tokens with their values.
*
* @param array $mergefields
* An array of merge fields and token place holders to be expanded. The key
* of the array is the Mailchimp field name, the value is the token that
* should be expanded.
* @param object $entity
* The entity that contains the values to use for token replacement.
* @param string $entity_type
* The entity type of the entity being used.
* @param string $list_id
*
* @return mixed
* Associative array of Mailchimp fields with values taken from the provided
* entity.
*/
function mailchimp_mergevars_populate($mergefields, $entity, $entity_type, $list_id = NULL) {
// Get mergevar settings from the list.
$list_mergevars = array();
if (!empty($list_id)) {
$list = mailchimp_get_list($list_id, FALSE);
if (!empty($list) && isset($list->mergevars)) {
// Create array of mergevars indexed by tag. Used to map to mergefields.
foreach ($list->mergevars as $list_mergevar) {
$list_mergevars[$list_mergevar->tag] = $list_mergevar;
}
}
}
$mergevars = drupal_static(__FUNCTION__, array());
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
if (!isset($mergevars[$bundle . ':' . $id])) {
foreach ($mergefields as $key => $token) {
$mergevar_value = token_replace($token, array(
$entity_type => $entity,
), array(
'clear' => TRUE,
));
if (isset($list_mergevars[$key])) {
if ($list_mergevars[$key]->type == 'date') {
$mergevar_value = mailchimp_format_date($mergevar_value);
}
elseif ($list_mergevars[$key]->type == 'phone') {
$mergevar_value = mailchimp_format_phone_number($mergevar_value);
}
}
if (!empty($mergevar_value)) {
$mergevars[$bundle . ':' . $id][$key] = $mergevar_value;
}
}
}
return $mergevars[$bundle . ':' . $id];
}
/**
* Formats a phone number string before sending to Mailchimp's API.
*
* Currently works only for USA and Canada phone numbers.
*
* @param string $input
* The input phone number.
*
* @return string
* The formatted phone number.
*
* @see http://kb.mailchimp.com/lists/growth/format-guidelines-for-your-import-file#phone
*/
function mailchimp_format_phone_number($input) {
$base_phone_number = preg_replace('/[^0-9]/s', '', $input);
// Only attempt to format ten-digit USA and Canada phone numbers.
if (strlen($base_phone_number) != 10) {
return $input;
}
// Convert phone number to format: "555-123-4567".
$formatted_number = substr($base_phone_number, 0, 3) . '-' . substr($base_phone_number, 3, 3) . '-' . substr($base_phone_number, 6);
return $formatted_number;
}
/**
* Formats a date string before sending to Mailchimp's API.
*
* @param string $input
* The input date.
*
* @return string
* The formatted date.
*
* @see http://kb.mailchimp.com/lists/growth/format-guidelines-for-your-import-file#date
*/
function mailchimp_format_date($input) {
// Attempt to convert date string to a timestamp.
// Remove time in standard Drupal date formats. It confuses strtotime().
$date = trim(preg_replace('/(- )?[0-9]+:[0-9]+/', '', $input));
$timestamp = strtotime($date);
if ($timestamp !== FALSE) {
// Return formatted date.
return date('Y-m-d', $timestamp);
}
else {
// Unable to parse the date string.
return NULL;
}
}
/**
* Implements hook_page_build().
*/
function mailchimp_page_build(&$page) {
// Insert JavaScript for Mailchimp Connected Sites, if enabled.
if (variable_get('mailchimp_enable_connected', FALSE) && mailchimp_get_api_object() && class_exists('\\Mailchimp\\MailchimpConnectedSites')) {
// Limit JavaScript embed to pre-configured paths.
$connected_site_paths = variable_get('mailchimp_connected_paths', FALSE);
$valid_paths = explode("\r\n", $connected_site_paths);
$path = current_path();
if (drupal_is_front_page() && in_array('<front>', $valid_paths) || in_array($path, $valid_paths)) {
$connected_site_id = variable_get('mailchimp_connected_id', FALSE);
if (!empty($connected_site_id)) {
try {
/* @var \Mailchimp\MailchimpConnectedSites $mc_connected */
$mc_connected = mailchimp_get_api_object('MailchimpConnectedSites');
// Verify Connected Site exists on the Mailchimp side and insert JS.
try {
$connected_site = $mc_connected
->getConnectedSite($connected_site_id);
if (!empty($connected_site)) {
$mcjs = array(
'#type' => 'markup',
'#markup' => $connected_site->site_script->fragment,
);
drupal_add_html_head($mcjs, 'mcjs');
}
} catch (Exception $e) {
// Throw exception only for errors other than member not found.
if ($e
->getCode() != 404) {
throw new Exception($e
->getMessage(), $e
->getCode(), $e);
}
}
} catch (Exception $e) {
watchdog('mailchimp', 'An error occurred requesting connected site information. "%message"', array(
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
}
}
}
}
}
Functions
Name | Description |
---|---|
mailchimp_addto_queue | Add a Mailchimp subscription task to the queue. |
mailchimp_apikey_ready_access | Access callback for mailchimp submodule menu items. |
mailchimp_batch_update_members | Wrapper around MailchimpLists->addOrUpdateMember(). |
mailchimp_cache_clear_all | Clear all mailchimp caches. |
mailchimp_cache_clear_campaign | Clear a mailchimp activity cache. |
mailchimp_cache_clear_list_activity | Clear a mailchimp activity cache. |
mailchimp_cache_clear_member | Clear a mailchimp user memberinfo cache. |
mailchimp_cron | Implements hook_cron(). |
mailchimp_flush_caches | Implements hook_flush_caches(). |
mailchimp_format_date | Formats a date string before sending to Mailchimp's API. |
mailchimp_format_phone_number | Formats a phone number string before sending to Mailchimp's API. |
mailchimp_get_api_object | Get an instance of the Mailchimp library. |
mailchimp_get_campaign_data | Wrapper around MailchimpCampaigns->getCampaign() to return data for a given campaign. |
mailchimp_get_list | Gets a single Mailchimp list by ID. |
mailchimp_get_lists | Gets Mailchimp lists. Can be filtered by an array of list IDs. |
mailchimp_get_lists_for_email | Wrapper around MailchimpLists->getListsForEmail()`. |
mailchimp_get_memberinfo | Get the Mailchimp member info for a given email address and list. |
mailchimp_get_members | Retrieve all members of a given list with a given status. |
mailchimp_get_mergevars | Wrapper around MailchimpLists->getMergeFields(). |
mailchimp_get_segments | Wrapper around MailchimpLists->getSegments(). |
mailchimp_insert_drupal_form_tag | Convert mailchimp form elements to Drupal Form API. |
mailchimp_interest_groups_form_elements | Helper function to generate form elements for a list's interest groups. |
mailchimp_is_subscribed | Check if the given email is subscribed to the given list. |
mailchimp_libraries_info | Implements hook_libraries_info(). |
mailchimp_menu | Implements hook_menu(). |
mailchimp_mergevars_populate | Replace an array of merge field placeholder tokens with their values. |
mailchimp_page_build | Implements hook_page_build(). |
mailchimp_permission | Implements hook_permission(). |
mailchimp_process_webhook | Process a webhook post from Mailchimp. |
mailchimp_process_webhook_access | Access callback for mailchimp_process_webhook(). |
mailchimp_segment_add_subscriber | Add a specific subscriber to a static segment of a list. |
mailchimp_segment_batch_add_subscribers | Add a batch of email addresses to a static segment of a list. |
mailchimp_segment_create | Wrapper around MailchimpLists->addSegment(). |
mailchimp_subscribe | Subscribe a user to a Mailchimp list in real time or by adding to the queue. |
mailchimp_subscribe_process | Wrapper around MailchimpLists::addOrUpdateMember(). |
mailchimp_unsubscribe_member | Unsubscribe a member from a list. |
mailchimp_unsubscribe_process | Unsubscribe a member from a list. |
mailchimp_update_local_cache | Updates the local cache for a user as though a queued request had been processed. |
mailchimp_update_member | Update a members list subscription in real time or by adding to the queue. |
mailchimp_update_member_process | Wrapper around MailchimpLists::updateMember(). |
mailchimp_validate_email | Form element validation for email input of #type 'textfield'. |
mailchimp_variable_group_info | Implements hook_variable_group_info(). |
mailchimp_variable_info | Implements hook_variable_info(). |
mailchimp_webhook_add | Wrapper around MailchimpLists->addWebhook(). |
mailchimp_webhook_delete | Wrapper around MailchimpLists->deleteWebhook(). |
mailchimp_webhook_get | Wrapper around MailchimpLists->getWebhooks(). |
mailchimp_webhook_key | Generate a key to include in the webhook url based on a hash. |
mailchimp_webhook_url | Generate the webhook endpoint URL. |
_mailchimp_get_user_agent | Gets the user agent string for this installation of Mailchimp. |
_mailchimp_list_cmp | Helper function used by uasort() to sort lists alphabetically by name. |