You are here

mailchimp.module in Mailchimp 7.2

Mailchimp module.

File

mailchimp.module
View source
<?php

/**
 * @file
 * Mailchimp module.
 */

/**
 * Implements hook_libraries_info().
 */
function mailchimp_libraries_info() {
  $libraries['mailchimp'] = array(
    'name' => 'MailChimp MCAPI',
    'vendor url' => 'http://apidocs.mailchimp.com/api/1.3',
    'download url' => 'http://apidocs.mailchimp.com/api/downloads/mailchimp-api-class.zip',
    'version arguments' => array(
      'file' => 'MCAPI.class.php',
      // Version 1.3
      'pattern' => '/\\$version = \\"((\\d+)\\.(\\d+))\\"/',
    ),
    'files' => array(
      'php' => array(
        'MCAPI.class.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['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('TODO Add a description for administer mailchimp'),
    ),
  );
}

/**
 * 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 given list.
 */
function mailchimp_subscribe_user($list, $email, $merge_vars, $message = TRUE, $mcapi = NULL) {
  $success = FALSE;
  if ($mcapi || ($mcapi = mailchimp_get_api_object())) {
    $double_optin = $list->settings['doublein'];
    $success = $mcapi
      ->listSubscribe($list->mc_list_id, $email, $merge_vars, 'html', $double_optin, TRUE);
    if ($message && $success && $double_optin) {
      drupal_set_message(t('You have chosen to subscribe to %list. An email will be sent to your address. Click the link in the email to confirm the subscription.', array(
        '%list' => $list->label,
      )));
    }
    elseif ($message && $success) {
      drupal_set_message(t('You have subscribed to %list.', array(
        '%list' => $list->label,
      )));
    }

    // Clear user cache, just in case there's some cruft leftover:
    mailchimp_cache_clear_user($list->mc_list_id, $email);
    if ($success) {
      module_invoke_all('mailchimp_subscribe_user', $list, $email, $merge_vars);
      watchdog('mailchimp', '@email was subscribed to list @list.', array(
        '@email' => $merge_vars['EMAIL'],
        '@list' => $list->label,
      ), WATCHDOG_NOTICE);
    }
    else {
      watchdog('mailchimp', 'A problem occurred subscribing @email to list @list. Message: @msg', array(
        '@email' => $merge_vars['EMAIL'],
        '@list' => $list->label,
        '@msg' => $mcapi->errorMessage,
      ), WATCHDOG_WARNING);
    }
  }
  return $success;
}

/**
 * Update a user in a given list.
 */
function mailchimp_update_user($list, $email, $merge_vars, $message = TRUE, $mcapi = NULL) {
  $success = FALSE;
  if ($mcapi || ($mcapi = mailchimp_get_api_object())) {
    $success = $mcapi
      ->listUpdateMember($list->mc_list_id, $email, $merge_vars);
    if ($success && $message) {
      drupal_set_message(t('You have updated your settings in %list.', array(
        '%list' => $list->label,
      )));
    }

    // Clear user cache:
    mailchimp_cache_clear_user($list->mc_list_id, $email);
    if ($success) {
      watchdog('mailchimp', '@email was updated in list @list.', array(
        '@email' => $merge_vars['EMAIL'],
        '@list' => $list->label,
      ), WATCHDOG_NOTICE);
    }
    else {
      watchdog('mailchimp', 'A problem occurred subscribing @email to list @list. Message: @msg', array(
        '@email' => $merge_vars['EMAIL'],
        '@list' => $list->label,
        '@msg' => $mcapi->errorMessage,
      ), WATCHDOG_WARNING);
    }
  }
  return $success;
}

/**
 * Unsubscribe a user from the given list.
 *
 * @param stdclass $list
 *   A mailchimp lists entity.
 * @param string $email
 *   Email address to be unsubscribed.
 * @param bool $message
 *   Whether or not to display a message in the web interface.
 * @param object $mcapi
 *   Mailchimp API object if one is already loaded.
 * @param bool $delete
 *   Indicates whether an email should be deleted or just unsubscribed.
 *
 * @return bool
 *   Indicates whether unsubscribe was successful.
 */
function mailchimp_unsubscribe_user($list, $email, $message = TRUE, $mcapi = NULL, $delete = FALSE) {
  $success = FALSE;
  if ($mcapi || ($mcapi = mailchimp_get_api_object())) {
    if (mailchimp_is_subscribed($list->mc_list_id, $email)) {
      $success = $mcapi
        ->listUnsubscribe($list->mc_list_id, $email, $delete, FALSE, FALSE);
      if ($success) {
        module_invoke_all('mailchimp_unsubscribe_user', $list, $email);
        if ($message) {
          drupal_set_message(t('You have unsubscribed from %list.', array(
            '%list' => $list->label,
          )));
        }
      }

      // Clear user cache:
      mailchimp_cache_clear_user($list->mc_list_id, $email);
    }
  }
  return $success;
}

/**
 * Get a Mailchimp API object for communication with the mailchimp server.
 *
 * @return MCAPI|NULL
 *   A valid MCAPI implementation or NULL if no one found.
 */
function mailchimp_get_api_object() {
  $library = libraries_load('mailchimp');
  if (!$library['installed']) {
    $msg = 'Failed to load MailChimp PHP library. Please refer to the installation requirements.';
    watchdog('mailchimp', $msg, array(), WATCHDOG_ERROR);
    drupal_set_message(t($msg), 'error');
    return NULL;
  }
  $api_key = variable_get('mailchimp_api_key', '');

  // 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', 'MailChimp');
  $q = new $classname($api_key);

  // Set the timeout to something that won't take down the Drupal site:
  $q
    ->setTimeout(60);

  // Specify if a secure connection should be used with the API:
  $q
    ->useSecure(variable_get('mailchimp_use_secure', TRUE));
  if ($q->errorCode) {
    watchdog('mailchimp', 'MCAPI Error: %errmsg', array(
      '%errmsg' => $q->errorMessage,
    ), WATCHDOG_ERROR);
    return NULL;
  }
  return $q;
}

/**
 * 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('mailchimp_lists');
  $lists = array();

  // Return cached lists:
  if ($cache) {
    $lists = $cache->data;
  }
  else {
    if ($q = mailchimp_get_api_object()) {
      $result = $q
        ->lists(array(), 0, 100);
      if ($result['total'] > 0) {
        foreach ($result['data'] as $list) {

          // Append mergefields:
          $list['mergevars'] = $q
            ->listMergeVars($list['id']);

          // Append interest groups:
          $list['intgroups'] = $q
            ->listInterestGroupings($list['id']);
          $lists[$list['id']] = $list;
        }
      }
    }
    uasort($lists, '_mailchimp_list_cmp');
    cache_set('mailchimp_lists', $lists, 'cache', CACHE_TEMPORARY);
  }

  // Filter by given ids:
  if (!empty($list_ids)) {
    foreach ($lists as $key => $list) {
      if (!in_array($key, $list_ids)) {
        unset($lists[$key]);
      }
    }
  }
  return $lists;
}

/**
 * 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);
}

/**
 * Get the MailChimp memberinfo for a given email address and list.
 *
 * Results are cached in the cache_mailchimp_user bin which is cleared by the MC
 * web hooks system when needed.
 *
 * @param string $list_id
 * @param string $email
 * @param bool $reset
 *
 * @return array
 *   memberinfo array.
 */
function mailchimp_get_memberinfo($list_id, $email, $reset = FALSE) {
  $cache = $reset ? NULL : cache_get($list_id . '-' . $email, 'cache_mailchimp_user');
  $memberinfo = array();

  // Return cached lists:
  if ($cache) {
    $memberinfo = $cache->data;
  }
  else {
    if ($q = mailchimp_get_api_object()) {
      $result = $q
        ->listMemberInfo($list_id, array(
        $email,
      ));
      if ($result['success']) {
        $memberinfo = reset($result['data']);
      }
    }
    cache_set($list_id . '-' . $email, $memberinfo, 'cache_mailchimp_user', CACHE_PERMANENT);
  }
  return $memberinfo;
}

/**
 * Sets the member info in the cache.
 *
 * @param string $list_id
 * @param string $email
 */
function mailchimp_set_memberinfo($list_id, $email) {
  mailchimp_get_memberinfo($list_id, $email, TRUE);
}

/**
 * Clear a mailchimp user memberinfo cache.
 *
 * @param string $list_id
 * @param  $email
 */
function mailchimp_cache_clear_user($list_id, $email) {
  cache_clear_all($list_id . '-' . $email, 'cache_mailchimp_user');
}

/**
 * Clear a mailchimp activity cache.
 */
function mailchimp_cache_clear_list_activity($list_id) {
  cache_clear_all('mailchimp_activity_' . $list_id, 'cache');
}

/**
 * Clear a mailchimp activity cache.
 */
function mailchimp_cache_clear_campaign($campaign_id) {
  cache_clear_all('mailchimp_campaign_' . $campaign_id, 'cache');
}

/**
 * Implements hook_flush_caches().
 */
function mailchimp_flush_caches() {
  return array(
    'cache_mailchimp_user',
  );
}

/**
 * Access callback for mailchimp_process_webhook().
 */
function mailchimp_process_webhook_access($key) {
  return $key == mailchimp_webhook_key();
}

/**
 * Process a webhook post from MailChimp.
 */
function mailchimp_process_webhook() {
  $data = $_POST['data'];
  $type = $_POST['type'];
  switch ($type) {
    case 'unsubscribe':
    case 'profile':
    case 'cleaned':
      mailchimp_cache_clear_user($data['list_id'], $data['email']);
      mailchimp_set_memberinfo($data['list_id'], $data['email']);
      break;
    case 'upemail':
      mailchimp_cache_clear_user($data['list_id'], $data['old_email']);
      mailchimp_set_memberinfo($data['list_id'], $data['new_email']);
      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);
}

/**
 * Generate a key to include in the webhook url based on a hash.
 *
 * @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.
 *
 * @return string
 *   The endpoint URL.
 */
function mailchimp_webhook_url() {
  return $GLOBALS['base_url'] . '/mailchimp/webhook/' . mailchimp_webhook_key();
}

/**
 * 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::campaigns() to return data for a given campaign.
 *
 * Data is stored in the temporary cache.
 *
 * @param string $campaign_id
 * @param bool $reset
 *
 * @return mixed
 *   Array of campaign data or NULL if not found.
 */
function mailchimp_get_campaign_data($campaign_id, $reset = FALSE) {
  $cache = $reset ? NULL : cache_get('mailchimp_campaign_' . $campaign_id);

  // Return cached lists:
  if ($cache) {
    $campaign_data = $cache->data;
  }
  else {
    $q = mailchimp_get_api_object();
    $filters = array(
      'campaign_id' => $campaign_id,
    );
    $result_sandwich = $q
      ->campaigns($filters);
    $campaign_data = $result_sandwich['data'][0];
    cache_set('mailchimp_campaign_' . $campaign_id, $campaign_data, 'cache', CACHE_TEMPORARY);
  }
  return $campaign_data;
}

/**
 * Wrapper around MCAPI::campaignsForEmail().
 *
 * Returns all IDs of campaigns that have included a given email address.
 *
 * @param string $email
 *
 * @return array
 *   campaign IDs.
 */
function mailchimp_get_campaigns_for_email($email) {
  $q = mailchimp_get_api_object();
  $campaign_list = $q
    ->campaignsForEmail($email);
  return $campaign_list;
}

/**
 * Returns an array of lists that the user has been a member of.
 *
 * Includes a value indicating whether they are currently a subscribed or not.
 *
 * @param string $email
 *
 * @return array
 *   Containing 2 arrays -- one ('lists') of all lists that have made use of
 * this email address (list_id -> list_data[]). One ('campaigns') of all
 * campaigns that have included this email (campaign_id -> campaign_data[])
 *
 * We include the campaign data because we need it to get accurate list
 * activity history anyway, and we want to keep the data handy to avoid
 * excessive API calls.
 */
function mailchimp_get_lists_by_email($email) {
  $campaign_ids = mailchimp_get_campaigns_for_email($email);
  $lists = mailchimp_get_lists();
  $filtered_lists = array();
  if ($campaign_ids) {

    // Iterate through campaigns, add each campaign's list as array index/value.
    foreach ($campaign_ids as $campaign_id) {
      $campaign_data = mailchimp_get_campaign_data($campaign_id);
      $filtered_lists['lists'][$campaign_data['list_id']] = $lists[$campaign_data['list_id']];
      $filtered_lists['campaigns'][$campaign_id] = $campaign_data;
    }
  }
  return $filtered_lists;
}

Functions

Namesort descending Description
mailchimp_cache_clear_campaign Clear a mailchimp activity cache.
mailchimp_cache_clear_list_activity Clear a mailchimp activity cache.
mailchimp_cache_clear_user Clear a mailchimp user memberinfo cache.
mailchimp_flush_caches Implements hook_flush_caches().
mailchimp_get_api_object Get a Mailchimp API object for communication with the mailchimp server.
mailchimp_get_campaigns_for_email Wrapper around MCAPI::campaignsForEmail().
mailchimp_get_campaign_data Wrapper around MCAPI::campaigns() to return data for a given campaign.
mailchimp_get_list Wrapper around mailchimp_get_lists() to return a single list.
mailchimp_get_lists Return all MailChimp lists for a given key. Lists are stored in the cache.
mailchimp_get_lists_by_email Returns an array of lists that the user has been a member of.
mailchimp_get_memberinfo Get the MailChimp memberinfo for a given email address and list.
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_permission Implements hook_permission().
mailchimp_process_webhook Process a webhook post from MailChimp.
mailchimp_process_webhook_access Access callback for mailchimp_process_webhook().
mailchimp_set_memberinfo Sets the member info in the cache.
mailchimp_subscribe_user Subscribe a user to a given list.
mailchimp_unsubscribe_user Unsubscribe a user from the given list.
mailchimp_update_user Update a user in a given list.
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_list_cmp Helper function used by uasort() to sort lists alphabetically by name.