EVOLUTION-NINJA
Edit File: mailchimp.module
<?php /** * @file * Mailchimp module. */ 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 MCAPI', 'vendor url' => 'http://apidocs.mailchimp.com/api/2.0', 'download url' => 'https://bitbucket.org/mailchimp/mailchimp-api-php/get/2.0.4.zip', 'path' => 'src', 'version arguments' => array( 'file' => 'composer.json', // Version 2.0.4 'pattern' => '/\"version": \"((\d+)\.(\d+)\.(\d+))\",/', ), 'files' => array( 'php' => array('Mailchimp.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 a Mailchimp API object for communication with the mailchimp server. * * @return DrupalMailchimp * The default return value is an instance of DrupalMailchimp, although that * can be overridden. */ function mailchimp_get_api_object() { $mailchimp = &drupal_static(__FUNCTION__); if (isset($mailchimp)) { return $mailchimp; } // We allow the class name to be overridden, following the example of core's // mailsystem, in order to use alternate MailChimp classes. The bundled tests // use this approach to extend the MailChimp class with a test server. $classname = variable_get('mailchimp_api_classname', 'DrupalMailchimp'); $library = libraries_load('mailchimp'); if (!$library['installed'] && ($classname != 'MailChimpTest')) { $msg = t('Failed to load MailChimp PHP library. Please refer to the installation requirements.'); watchdog('mailchimp', $msg, NULL, WATCHDOG_ERROR); drupal_set_message($msg, 'error'); return NULL; } $api_key = variable_get('mailchimp_api_key', ''); if (!strlen($api_key)) { watchdog('mailchimp', 'Mailchimp Error: API Key cannot be blank.', NULL, WATCHDOG_ERROR); return NULL; } // Set the timeout to something that won't take down the Drupal site: $options = array('timeout' => 60); $mailchimp = new $classname($api_key, $options); return $mailchimp; } /** * Wrapper around mailchimp_get_lists() to return a single list. * * @param string $list_id * The unique ID of the list provided by MailChimp. * * @return array * A list array formatted as indicated in the MailChimp API documentation. */ function mailchimp_get_list($list_id) { $lists = mailchimp_get_lists(array($list_id)); return reset($lists); } /** * Return all MailChimp lists for a given key. Lists are stored in the cache. * * @param array $list_ids * An array of list IDs to filter the results by. * @param bool $reset * Force a cache reset. * * @return array * An array of list arrays. */ function mailchimp_get_lists($list_ids = array(), $reset = FALSE) { $cache = $reset ? NULL : cache_get('lists', 'cache_mailchimp'); $lists = array(); // Return cached lists: if ($cache) { $lists = $cache->data; } // Query lists from the MCAPI and store in cache: else { try { $mcapi = mailchimp_get_api_object(); $result = $mcapi->lists->getList(array(), 0, 100); if ($result['total'] > 0) { foreach ($result['data'] as $list) { if ($list['stats']['group_count']) { // Append interest groups: $list['intgroups'] = $mcapi->lists->interestGroupings($list['id']); } $lists[$list['id']] = $list; } // Append mergefields: $mergevar_settings = $mcapi->lists->mergeVars($list_ids); foreach ($mergevar_settings['data'] as $mergevars) { $lists[$mergevars['id']]['mergevars'] = $mergevars['merge_vars']; } } uasort($lists, '_mailchimp_list_cmp'); cache_set('lists', $lists, 'cache_mailchimp', CACHE_TEMPORARY); } 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 MCAPI->Lists->mergeVars. * * @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]); } } } // Get the uncached merge vars from MailChimp. if (count($list_ids)) { $mcapi = mailchimp_get_api_object(); $last_list_id = NULL; try { $result = $mcapi->lists->mergeVars($list_ids); if ($result['success_count']) { foreach ($result['data'] as $list_mergevars) { $last_list_id = $list_mergevars['id']; $mergevars[$last_list_id] = $list_mergevars; cache_set($last_list_id . '-mergevars', $list_mergevars, 'cache_mailchimp', CACHE_TEMPORARY); } } } catch (Exception $e) { watchdog('mailchimp', 'An error occurred requesting mergevars for list @list. "%message"', array( '@list' => $last_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 array * Member info array, 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 = array(); $mcapi = mailchimp_get_api_object(); try { $result = $mcapi->lists->memberInfo($list_id, array(array('email' => $email))); if ($result['success_count']) { $memberinfo = reset($result['data']); cache_set($list_id . '-' . $email, $memberinfo, 'cache_mailchimp', CACHE_TEMPORARY); } } 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, $double_optin = FALSE, $confirm = TRUE, $format = 'html', $update_existing = TRUE, $replace_interests = TRUE) { if (variable_get('mailchimp_cron', FALSE)) { $args = array( 'list_id' => $list_id, 'email' => $email, 'merge_vars' => $merge_vars, 'format' => $format, 'double_optin' => $double_optin, 'update_existing' => $update_existing, 'replace_interests' => $replace_interests, 'confirm' => $confirm, ); return mailchimp_addto_queue('mailchimp_subscribe_process', $args); } return mailchimp_subscribe_process($list_id, $email, $merge_vars, $double_optin, $format, $update_existing, $replace_interests, $confirm); } /** * Wrapper around Mailchimp_Lists::subscribe(). * * @see Mailchimp_Lists::subscribe() * * @return bool * True on success. */ function mailchimp_subscribe_process($list_id, $email, $merge_vars = NULL, $double_optin = FALSE, $format = 'html', $update_existing = TRUE, $replace_interests = TRUE, $confirm = TRUE) { $result = FALSE; try { $mcapi = mailchimp_get_api_object(); $result = $mcapi->lists->subscribe($list_id, array('email' => $email), $merge_vars, $format, $double_optin, $update_existing, $replace_interests, $confirm); if (isset($result['email'])) { 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' => $merge_vars['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) { watchdog('mailchimp', 'An error occurred subscribing @email to list @list. "%message"', array( '@email' => $email, '@list' => $list_id, '%message' => $e->getMessage(), ), WATCHDOG_ERROR); } 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(); return $queue->createItem(array( 'function' => $function, 'args' => $args, )); } /** * 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, $format = '', $replace_interests = TRUE) { if (variable_get('mailchimp_cron', FALSE)) { $args = array( 'list_id' => $list_id, 'email' => $email, 'merge_vars' => $merge_vars, 'format' => $format, 'replace_interests' => $replace_interests, ); return mailchimp_addto_queue('mailchimp_update_member_process', $args); } return mailchimp_update_member_process($list_id, $email, $merge_vars, $format, $replace_interests); } /** * Wrapper around Mailchimp_Lists::updateMember(). * * @see Mailchimp_Lists::updateMember() * * @return bool * Success or failure. */ function mailchimp_update_member_process($list_id, $email, $merge_vars, $format, $replace_interests) { $result = FALSE; try { $mcapi = $mcapi = mailchimp_get_api_object(); $result = $mcapi->lists->updateMember($list_id, array('email' => $email), $merge_vars, $format, $replace_interests); if (isset($result['email'])) { 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) { watchdog('mailchimp', 'An error occurred updating @email on list @list. "%message"', array( '@email' => $email, '@list' => $list_id, '%message' => $e->getMessage(), ), WATCHDOG_ERROR); } 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 { $mcapi = mailchimp_get_api_object(); $results = $mcapi->lists->members($list_id, $status, $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 MCAPI->lists->batch-subscribe. * * $batch is an array where each element is an array formatted thus: * 'email' => array('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, $update_existing = FALSE, $replace_interests = TRUE) { $results = FALSE; try { $mcapi = mailchimp_get_api_object(); $results = $mcapi->lists->batchSubscribe($list_id, $batch, $double_in, $update_existing, $replace_interests); } catch (Exception $e) { watchdog('mailchimp', 'An error occurred performing batch subscribe/update. "%message"', array( '%message' => $e->getMessage(), ), WATCHDOG_ERROR); } return $results; } /** * 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. * @param object $mcapi * Mailchimp API object if one is already loaded. * @param bool $allow_async * Set to TRUE to allow asynchronous processing using DrupalQueue. * * @return bool * Indicates whether unsubscribe was successful. */ function mailchimp_unsubscribe($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; } /** * Wrapper around Mailchimp_Lists::unsubscribe(). * * @see Mailchimp_Lists::unsubscribe() * * @return bool * Success or failure. */ function mailchimp_unsubscribe_process($list_id, $email, $delete, $goodbye, $notify) { $result = FALSE; try { $mcapi = mailchimp_get_api_object(); $result = $mcapi->lists->unsubscribe($list_id, array('email' => $email), $delete, $goodbye, $notify); if ($result) { module_invoke_all('mailchimp_unsubscribe_user', $list_id, $email); } // Clear user cache: mailchimp_cache_clear_member($list_id, $email); } 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 $result; } /** * Wrapper around MCAPI->lists->segments. * * @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 { $mcapi = mailchimp_get_api_object(); $segments = $mcapi->lists->segments($list_id); 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 MCAPI->lists->segmentAdd. * * @param string $list_id * A MailChimp list id. * @param string $name * A label for the segment. * @param string $type * '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 { $mcapi = mailchimp_get_api_object(); $options = array( 'type' => $type, 'name' => $name, ); if ($type == 'saved') { $options['segment_opts'] = $segment_options; } $segment_id = $mcapi->lists->segmentAdd($list_id, $options); // 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 { $mcapi = mailchimp_get_api_object(); $results = $mcapi->lists->staticSegmentMembersAdd($list_id, $segment_id, $batch); $count = isset($results['success_count']) ? $results['success_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 MCAPI->campaigns->getList 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 { $mcapi = mailchimp_get_api_object(); $filters = array( 'campaign_id' => $campaign_id, ); $results = $mcapi->campaigns->getList($filters, 0, 1); if (isset($results['total']) && $results['total']) { $campaign_data = $results['data'][0]; cache_set('campaign_' . $campaign_id, $campaign_data, '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 MCAPI->helper->campaignsForEmail(). * * Returns all IDs of campaigns that have included a given email address. * * @param string $email * Email address to search. * * @return array * Campaign structs containing id, title, subject, send_time, type. */ function mailchimp_get_campaigns_for_email($email) { try { $mcapi = mailchimp_get_api_object(); $campaign_list = $mcapi->helper->campaignsForEmail(array('email' => $email)); } catch (Exception $e) { watchdog('mailchimp', 'An error occurred retreiving campaign data for @email. "%message"', array( '@email' => $email, '%message' => $e->getMessage(), ), WATCHDOG_ERROR); $campaign_list = array(); } return $campaign_list; } /** * Wrapper around MCAPI->helper->listsForEmail(). * * 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 { $mcapi = mailchimp_get_api_object(); $lists = $mcapi->helper->listsForEmail(array('email' => $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 MCAPI->lists->webhooks(). * * @param string $list_id * Mailchimp API List ID. * * @return mixed * Array of existing webhooks, or FALSE. */ function mailchimp_webhook_get($list_id) { try { $mcapi = mailchimp_get_api_object(); $result = $mcapi->lists->webhooks($list_id); } 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; } return $result; } /** * Wrapper around MCAPI->lists->webhookAdd(). * * @return bool * TRUE if deletion was successful, otherwise FALSE. */ function mailchimp_webhook_add($list_id, $url, $actions = array(), $sources = array()) { try { $mcapi = mailchimp_get_api_object(); $result = $mcapi->lists->webhookAdd($list_id, $url, $actions, $sources); } 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; } return $result['id']; } /** * Wrapper around MCAPI->lists->webhookDel(). * * @return bool * TRUE if deletion was successful, otherwise FALSE. */ function mailchimp_webhook_delete($list_id, $url) { try { $mcapi = mailchimp_get_api_object(); $result = $mcapi->lists->webhookDel($list_id, $url); } 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; } return $result['complete']; } /** * 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'); } /** * 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 (!isset($_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 $mc_list * Fully loaded array with mailchimp list settings as returned by * mailchimp_get_list() * @param array $default_values * 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($mc_list, $default_values = array(), $email = NULL) { $return = array(); foreach ($mc_list['intgroups'] as $group) { if ($group['form_field'] == 'hidden') { continue; } // Set the form field type: switch ($group['form_field']) { case 'radio': $field_type = 'radios'; break; case 'dropdown': $field_type = 'select'; break; default: $field_type = $group['form_field']; } // Extract the field options: $options = array(); if ($field_type == 'select') { $options[''] = '-- select --'; } foreach ($group['groups'] as $option) { $options[$option['name']] = $option['name']; } // Grab the default values for this group: if ($email) { $memberinfo = mailchimp_get_memberinfo($mc_list['id'], $email); if (isset($memberinfo['merges']['GROUPINGS'])) { $default_values = array(); foreach ($memberinfo['merges']['GROUPINGS'] as $membergroup) { if ($membergroup['id'] == $group['id']) { foreach ($membergroup['groups'] as $option) { if ($option['interested']) { $default_values[$group['id']][] = $option['name']; } } break; } } } } $return[$group['id']] = array( '#type' => $field_type, '#title' => $group['name'], '#options' => $options, '#default_value' => isset($default_values[$group['id']]) ? $default_values[$group['id']] : array(), '#attributes' => array('class' => array('mailchimp-newsletter-interests-' . $mc_list['id'])), ); } return $return; } /** * Helper function to make an API-ready array from an interest group form. */ function mailchimp_reformat_groupings($interest_groups) { $groupings = array(); foreach ($interest_groups as $key => $groups) { if (is_array($groups)) { $groups = array_filter($groups); $groupings[] = array('id' => $key, 'groups' => $groups); } else { $groupings[] = array('id' => $key, 'groups' => array($groups => $groups)); } } return $groupings; } /** * 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) { // Insert common FormAPI properties: $input = array( '#title' => t('@mergevar', array('@mergevar' => $mergevar['name'])), '#weight' => $mergevar['order'], '#required' => $mergevar['req'], '#default_value' => $mergevar['default'], ); switch ($mergevar['field_type']) { 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['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['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'; }; $input['#size'] = $mergevar['size']; break; default: // This is a standard input[type=text] or something we can't handle with // Drupal FormAPI. $input['#type'] = 'textfield'; $input['#size'] = $mergevar['size']; break; } // Special cases for MailChimp hidden defined fields: if ($mergevar['public'] == FALSE) { $input['#type'] = 'hidden'; } return $input; } /** * 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++; } } }