You are here

mailchimp_campaign.module in Mailchimp 7.3

Module file for mailchimp_campaign.

File

modules/mailchimp_campaign/mailchimp_campaign.module
View source
<?php

/**
 * @file
 * Module file for mailchimp_campaign.
 */

/**
 * Implements hook_entity_info().
 */
function mailchimp_campaign_entity_info() {
  $return = array(
    'mailchimp_campaign' => array(
      'label' => t('MailChimp Campaign'),
      'entity class' => 'MailChimpCampaign',
      'controller class' => 'MailChimpCampaignController',
      'base table' => 'mailchimp_campaigns',
      'uri callback' => 'entity_class_uri',
      'fieldable' => FALSE,
      'exportable' => FALSE,
      'entity keys' => array(
        'id' => 'mc_campaign_id',
      ),
      'token type' => 'mailchimp_campaign',
      'module' => 'mailchimp_campaign',
      'label callback' => 'entity_class_label',
      'view modes' => array(
        'full' => array(
          'label' => t('Full Campaign'),
          'custom settings' => FALSE,
        ),
      ),
    ),
  );
  return $return;
}

/**
 * Implements hook_permission().
 */
function mailchimp_campaign_permission() {
  return array(
    'administer mailchimp campaigns' => array(
      'title' => t('Administer MailChimp campaigns'),
      'description' => t('Create and send MailChimp campaigns.'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function mailchimp_campaign_menu() {
  $items['admin/config/services/mailchimp/campaigns'] = array(
    'title' => t('Campaigns'),
    'description' => t('Manage MailChimp Campaigns.'),
    'page callback' => 'mailchimp_campaign_overview_page',
    'access callback' => 'mailchimp_apikey_ready_access',
    'access arguments' => array(
      'administer mailchimp campaigns',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 10,
  );
  $items['admin/config/services/mailchimp/campaigns/add'] = array(
    'title' => t('Add a Campaign'),
    'description' => t('Add a new MailChimp campaign.'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'mailchimp_campaign_campaign_form',
    ),
    'access callback' => 'mailchimp_apikey_ready_access',
    'access arguments' => array(
      'administer mailchimp campaigns',
    ),
    'file' => 'includes/mailchimp_campaign.admin.inc',
    'type' => MENU_LOCAL_ACTION,
  );
  $items['admin/config/services/mailchimp/campaigns/%mailchimp_campaign'] = array(
    'title callback' => 'mailchimp_campaign_page_title',
    'title arguments' => array(
      5,
    ),
    'page callback' => 'mailchimp_campaign_view',
    'page arguments' => array(
      5,
    ),
    'access arguments' => array(
      'administer mailchimp campaigns',
    ),
    'load arguments' => array(
      5,
    ),
  );
  $items['admin/config/services/mailchimp/campaigns/%mailchimp_campaign/view'] = array(
    'title' => t('View'),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 0,
  );
  $items['admin/config/services/mailchimp/campaigns/%mailchimp_campaign/send'] = array(
    'title' => t('Send'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'mailchimp_campaign_send_form',
      5,
    ),
    'access callback' => 'mailchimp_campaign_access',
    'access arguments' => array(
      5,
      FALSE,
    ),
    'file' => 'includes/mailchimp_campaign.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
  );
  $items['admin/config/services/mailchimp/campaigns/%mailchimp_campaign/send-test'] = array(
    'title' => 'Send Test',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'mailchimp_campaign_send_test_form',
      5,
    ),
    'access callback' => 'mailchimp_campaign_access',
    'access arguments' => array(
      5,
      FALSE,
    ),
    'file' => 'includes/mailchimp_campaign.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
  );
  $items['admin/config/services/mailchimp/campaigns/%mailchimp_campaign/edit'] = array(
    'title' => t('Edit'),
    'description' => t('Edit a MailChimp campaign.'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'mailchimp_campaign_campaign_form',
      5,
    ),
    'access callback' => 'mailchimp_campaign_access',
    'access arguments' => array(
      5,
      FALSE,
    ),
    'file' => 'includes/mailchimp_campaign.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
  $items['admin/config/services/mailchimp/campaigns/%mailchimp_campaign/delete'] = array(
    'title' => t('Delete'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'mailchimp_campaign_delete_form',
      5,
    ),
    'access callback' => 'mailchimp_campaign_access',
    'access arguments' => array(
      5,
      FALSE,
    ),
    'file' => 'includes/mailchimp_campaign.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 3,
  );
  $items['admin/config/services/mailchimp/campaigns/%mailchimp_campaign/stats'] = array(
    'title' => t('Stats'),
    'page callback' => 'mailchimp_campaign_stats_page',
    'page arguments' => array(
      5,
    ),
    'access callback' => 'mailchimp_campaign_access',
    'access arguments' => array(
      5,
      TRUE,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 4,
  );
  $items['admin/config/services/mailchimp/campaigns/entities'] = array(
    'page callback' => 'mailchimp_campaign_entities_autocomplete_callback',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Callback for campaign template entity search field.
 *
 * @param string $type
 *   The entity type to limit search to.
 * @param string $string
 *   The string to search entity titles for.
 *
 * @return array
 *   Entities with titles matching search string.
 */
function mailchimp_campaign_entities_autocomplete_callback($type, $string = '') {
  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', $type)
    ->propertyCondition('title', $string, 'CONTAINS')
    ->range(0, 10);
  $entities = array();
  $result = $query
    ->execute();
  if (isset($result[$type])) {
    $entity_ids = array_keys($result[$type]);
    $entities_data = entity_load($type, $entity_ids);
    if (!empty($entities_data)) {
      foreach ($entities_data as $id => $entity) {
        $entities[$entity->title . ' [' . $id . ']'] = $entity->title;
      }
    }
  }
  drupal_json_output($entities);
}

/**
 * Title callback: Generate a title for a registration entity.
 *
 * Callback for hook_menu() within system_themes_page().
 *
 * @param MailChimpCampaign $campaign
 *   The MailChimp campaign instance.
 *
 * @return string
 *   The entity title.
 */
function mailchimp_campaign_page_title(MailChimpCampaign $campaign) {
  return $campaign
    ->label();
}

/**
 * Access callback for campaigns.
 *
 * Provides access to features based on whether or not a campaign has been sent.
 *
 * @param MailChimpCampaign $campaign
 *   The MailChimp campaign instance.
 * @param bool $sent
 *   Set to TRUE when a campaign has been sent.
 */
function mailchimp_campaign_access(MailChimpCampaign $campaign, $sent = TRUE) {
  $access = FALSE;

  // Only campaigns that haven't been sent can be changed.
  if (user_access('administer mailchimp campaigns') && ($campaign->mc_data['status'] === 'sent') === $sent) {
    $access = TRUE;
  }
  return $access;
}

/**
 * Page callback for showing a list of MailChimp Campaign entities.
 */
function mailchimp_campaign_overview_page() {
  $campaigns = mailchimp_campaign_load_multiple();
  $templates = mailchimp_campaign_list_templates();
  $rows = array();
  foreach ($campaigns as $campaign) {
    $actions = array();
    $actions[] = l(t('View Archive'), $campaign->mc_data['archive_url'], array(
      'attributes' => array(
        'target' => '_blank',
      ),
    ));
    $actions[] = l(t('View'), 'admin/config/services/mailchimp/campaigns/' . $campaign->mc_campaign_id);
    if ($campaign->mc_data['status'] == 'save') {
      $actions[] = l(t('Send'), 'admin/config/services/mailchimp/campaigns/' . $campaign->mc_campaign_id . '/send');
    }
    else {
      $actions[] = t('Sent');
    }
    $rows[] = array(
      l($campaign
        ->label(), 'admin/config/services/mailchimp/campaigns/' . $campaign->mc_campaign_id),
      $campaign->mc_data['subject'],
      $campaign->mc_data['status'],
      l($campaign->list['name'], 'https://admin.mailchimp.com/lists/dashboard/overview?id=' . $campaign->list['web_id'], array(
        'attributes' => array(
          'target' => '_blank',
        ),
      )),
      isset($templates[$campaign->mc_data['template_id']]) ? $templates[$campaign->mc_data['template_id']]['name'] : '',
      $campaign->mc_data['create_time'],
      implode(' | ', $actions),
    );
  }
  return array(
    '#theme' => 'table',
    '#header' => array(
      t('Title'),
      t('Subject'),
      t('Status'),
      t('MailChimp list'),
      t('MailChimp template'),
      t('Created'),
      t('Actions'),
    ),
    '#rows' => $rows,
  );
}

/**
 * Implements hook_theme().
 */
function mailchimp_campaign_theme($existing, $type, $theme, $path) {
  return array(
    'mailchimp_campaign_node_campaigns_list' => array(
      'variables' => array(
        'node_campaigns' => array(),
      ),
    ),
    'mailchimp_campaign_mclinks' => array(
      'variables' => array(
        'data' => NULL,
      ),
    ),
    'mailchimp_campaign_actions' => array(
      'variables' => array(
        'campaign' => NULL,
      ),
    ),
  );
}

/**
 * Save a campaign in MailChimp and as a Drupal entity.
 *
 * @param array $template
 *   Associative array of template content indexed by section IDs.
 * @param array $options
 *   Associative array of template values.
 * @param array $segment_options
 *   Associative array of list segment options.
 * @param string $campaign_id
 *   The ID of the campaign to save, if updating.
 *
 * @return string
 *   New or existing campaign ID.
 */
function mailchimp_campaign_save_campaign($template, $options, $segment_options = NULL, $campaign_id = NULL) {
  $mcapi = mailchimp_get_api_object();
  $options += array(
    'generate_text' => TRUE,
    'tracking' => array(
      'opens' => TRUE,
      'html_clicks' => TRUE,
      'text_clicks' => TRUE,
    ),
  );

  // Allow alter of template and options used in campaign
  drupal_alter('mailchimp_campaign', $options, $template, $campaign_id);

  // Convert template to content by running through formatter.
  if (isset($template['html'])) {
    $content = mailchimp_campaign_render_template($template);
  }
  else {
    $content = array(
      'sections' => mailchimp_campaign_render_template($template),
    );
  }

  // Test for valid list segment, if selected.
  if ($segment_options != NULL) {
    if (mailchimp_test_list_segment($options['list_id'], $segment_options['saved_segment_id']) === NULL) {
      return NULL;
    }
  }

  // Save campaign to MailChimp. (Only regular campaigns are supported).
  $is_new = empty($campaign_id);
  if ($is_new) {
    try {
      if (!$mcapi) {
        throw new MailchimpException('Cannot create campaign without Mailchimp API. Check API key has been entered.');
      }
      $result = $mcapi->campaigns
        ->create('regular', $options, $content, $segment_options);
    } catch (Mailchimp_Error $e) {
      drupal_set_message($e
        ->getMessage(), 'error');
      watchdog('mailchimp_campaign', 'An error occurred while creating this campaign: @msg', array(
        '@msg' => $e
          ->getMessage(),
      ), WATCHDOG_ERROR);
      return NULL;
    }
    if (isset($result['status']) && $result['status'] == 'save') {
      $campaign_id = $result['id'];
    }
  }
  else {

    // Updates must be sent one type at a time.
    try {
      if (!$mcapi) {
        throw new MailchimpException('Cannot update campaign without Mailchimp API. Check API key has been entered.');
      }
      $mcapi->campaigns
        ->update($campaign_id, 'options', $options);
      $mcapi->campaigns
        ->update($campaign_id, 'segment_opts', $segment_options);
      $mcapi->campaigns
        ->update($campaign_id, 'content', $content);
    } catch (Mailchimp_Error $e) {
      drupal_set_message($e
        ->getMessage(), 'error');
      watchdog('mailchimp_campaign', 'An error occurred while updating this campaign: @msg', array(
        '@msg' => $e
          ->getMessage(),
      ), WATCHDOG_ERROR);
      return NULL;
    }
  }
  if (isset($result['status']) && $result['status'] == 'error') {

    // Display and log error, if any.
    $message = 'MailChimp error. The campaign was not saved.';
    _mailchimp_campaign_mcapi_error_message($result, $message);
  }
  else {
    drupal_set_message(t('Campaign %name (%cid) was successfully saved.', array(
      '%name' => $options['title'],
      '%cid' => $campaign_id,
    )));

    // Save the campaign entity:
    $campaign = entity_create('mailchimp_campaign', array(
      'mc_campaign_id' => $campaign_id,
      'template' => $template,
      'is_new' => $is_new,
    ));
    mailchimp_campaign_save($campaign);

    // Clear cached data for this campaign.
    mailchimp_campaign_get_campaigns(array(
      $campaign_id,
    ), TRUE);
  }
  return $campaign_id;
}

/**
 * Send MailChimp campaign.
 */
function mailchimp_campaign_send_campaign(MailChimpCampaign $campaign) {
  $mcapi = mailchimp_get_api_object();

  // Send campaign.
  try {
    if (!$mcapi) {
      throw new MailchimpException('Cannot send campaign without Mailchimp API. Check API key has been entered.');
    }
    $result = $mcapi->campaigns
      ->send($campaign->mc_campaign_id);
  } catch (Mailchimp_Error $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
    watchdog('mailchimp_campaign', 'An error occurred while sending to this campaign: @msg', array(
      '@msg' => $e
        ->getMessage(),
    ), WATCHDOG_ERROR);
    return FALSE;
  }
  if (isset($result['complete']) && $result['complete'] === TRUE) {

    // Log action, and notify the user.
    watchdog('mailchimp_campaign', 'MailChimp campaign %name has been sent.', array(
      '%name' => $campaign
        ->label(),
    ));
    entity_get_controller('mailchimp_campaign')
      ->resetCache(array(
      $campaign
        ->identifier(),
    ));
    return TRUE;
  }
  elseif (isset($result['status']) && $result['status'] == 'error') {

    // Display and log error, if any.
    $message = 'MailChimp error. The campaign was not sent.';
    _mailchimp_campaign_mcapi_error_message($result, $message);
  }
  return FALSE;
}

/**
 * Send MailChimp campaign.
 */
function mailchimp_campaign_send_test_campaign(MailChimpCampaign $campaign, $recipients = array()) {
  $mcapi = mailchimp_get_api_object();

  // Send campaign.
  try {
    if (!$mcapi) {
      throw new MailchimpException('Cannot send campaign without Mailchimp API. Check API key has been entered.');
    }
    $result = $mcapi->campaigns
      ->sendTest($campaign->mc_campaign_id, $recipients);
  } catch (Mailchimp_Error $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
    watchdog('mailchimp_campaign', 'An error occurred while sending a test of this campaign: @msg', array(
      '@msg' => $e
        ->getMessage(),
    ), WATCHDOG_ERROR);
    return FALSE;
  }
  if (isset($result['complete']) && $result['complete'] === TRUE) {

    // Log action, and notify the user.
    watchdog('mailchimp_campaign', 'MailChimp test message for campaign %name has been sent to %recipients.', array(
      '%name' => $campaign
        ->label(),
      '%recipients' => implode(', ', $recipients),
    ));
    return TRUE;
  }
  elseif (isset($result['status']) && $result['status'] == 'error') {

    // Display and log error, if any.
    $message = 'MailChimp error. The campaign was not sent.';
    _mailchimp_campaign_mcapi_error_message($result, $message);
  }
  return FALSE;
}

/**
 * Delete a MailChimp campaign and the local entity.
 */
function mailchimp_campaign_delete_campaign($cid) {
  $mcapi = mailchimp_get_api_object();
  $result = NULL;

  // Delete campaign from MailChimp.
  try {
    if (!$mcapi) {
      throw new MailchimpException('Cannot delete campaign without Mailchimp API. Check API key has been entered.');
    }
    $result = $mcapi->campaigns
      ->delete($cid);
  } catch (Mailchimp_Error $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
    watchdog('mailchimp_campaign', 'An error occurred while deleting this campaign: @msg', array(
      '@msg' => $e
        ->getMessage(),
    ), WATCHDOG_ERROR);
    return FALSE;
  }
  if (isset($result['status']) && $result['status'] == 'error') {

    // Display and log error, if any.
    $message = 'MailChimp error. The campaign was not deleted.';
    _mailchimp_campaign_mcapi_error_message($result, $message);
  }
  elseif (isset($result['complete']) && $result['complete'] === TRUE) {

    // Delete campaign from the database.
    mailchimp_campaign_delete($cid);
    watchdog('mailchimp_campaign', 'MailChimp campaign %cid was deleted.', array(
      '%cid' => $cid,
    ));
    return TRUE;
  }
  return FALSE;
}

/**
 * Return all available user templates.
 *
 * @param bool $reset
 *   True if templates should not be loaded from cache.
 *
 * @return mixed
 *   Array listing existing Mailchimp templates by type.
 */
function mailchimp_campaign_list_templates($reset = FALSE) {
  $cache = $reset ? NULL : cache_get('templates', 'cache_mailchimp');
  $all_templates = array();

  // Return cached lists:
  if ($cache) {
    $all_templates = $cache->data;
  }
  else {
    if ($mcapi = mailchimp_get_api_object()) {
      $template_types = array(
        'user' => 1,
        'base' => 1,
        'gallery' => 1,
      );
      $response = $mcapi->templates
        ->getList($template_types);
      foreach ($template_types as $type => $chosen) {
        if ($chosen) {
          $all_templates[$type] = array();
          foreach ($response[$type] as $template) {
            $all_templates[$type][$template['id']] = $template;
          }
        }
      }
    }
    cache_set('templates', $all_templates, 'cache_mailchimp', CACHE_TEMPORARY);
  }
  return $all_templates;
}

/**
 * Return full details for a Mailchimp Template.
 *
 * @param string $template_id
 *   Optional template ID. Set to return a single MailChimp template.
 * @param bool $reset
 *   True if templates should not be loaded from cache.
 *
 * @return mixed
 *   An array with all configuration and content for a Mailchimp Template.
 */
function mailchimp_campaign_get_template($template_id, $reset = FALSE) {
  $all_templates = mailchimp_campaign_list_templates($reset);
  foreach ($all_templates as $type) {
    if (isset($type[$template_id])) {
      $template = $type[$template_id];

      // Get template details from cache or the MailChimp API.
      $cache = $reset ? NULL : cache_get('template_' . $template_id, 'cache_mailchimp');
      if ($cache) {
        $template['info'] = $cache->data;
      }
      else {
        if ($mcapi = mailchimp_get_api_object()) {
          $template['info'] = $mcapi->templates
            ->info($template_id);
          cache_set('template_' . $template_id, $template['info'], 'cache_mailchimp', CACHE_TEMPORARY);
        }
      }
      return $template;
    }
  }
  return NULL;
}

/**
 * Set and log error messages after MailChimp API errors.
 */
function _mailchimp_campaign_mcapi_error_message($result, $message, $variables = array()) {
  $mcapi_error_message = 'MailChimp error code: %errorCode, MailChimp error message: %errorMessage.';
  $mcapi_error_variables = array(
    '%errorCode' => $result['code'],
    '%errorMessage' => $result['message'],
  );
  $human = t($message, $variables) . ' ' . t($mcapi_error_message, $mcapi_error_variables);
  drupal_set_message($human, 'error');
  $watchdog = $message . ' ' . $mcapi_error_message;
  $variables = $variables + $mcapi_error_variables;
  watchdog('mailchimp_campaign', $watchdog, $variables, WATCHDOG_ERROR);
}

/**
 * Change the relative URLs to absolute ones in the message.
 */
function mailchimp_campaign_convert_url($text) {
  global $base_url;
  $matches = array();
  preg_match_all('/<(a|img).*?(href|src)="(.*?)"/', $text, $matches);
  foreach ($matches[3] as $key => $url) {
    if ($url[0] == '/') {
      $new_url = $base_url . $url;
      $new_match = str_replace($url, $new_url, $matches[0][$key]);
      $text = str_replace($matches[0][$key], $new_match, $text);
    }
  }
  return $text;
}

/**
 * Implements hook_filter_info().
 */
function mailchimp_campaign_filter_info() {
  $filters['mailchimp_campaign'] = array(
    'title' => t('MailChimp Campaign filter'),
    'description' => t('Add content and covert URLs for sending as MailChimp campaigns.'),
    'process callback' => 'mailchimp_campaign_filter_campaign_process',
    'tips callback' => 'mailchimp_campaign_filter_tips',
  );
  return $filters;
}

/**
 * Tips callback for mailchimp_campaign_filter_info().
 *
 * @param object $filter
 *   The filter object containing settings for the given format.
 * @param object $format
 *   The text format object assigned to the text to be filtered.
 * @param bool $long
 *   Set to TRUE to return a long tip, FALSE for short.
 *
 * @return string
 *   Translated text to display as a tip.
 */
function mailchimp_campaign_filter_tips($filter, $format, $long) {
  $tip = t('Converts content tokens in the format %pattern into the appropriate rendered content and makes all paths absolute. Use the "Insert Site Content" widget below to generate tokens.', array(
    '%pattern' => '[mailchimp_campaign|entity_type=node|entity_id=1|view_mode=teaser]',
  ));
  return $tip;
}

/**
 * Process callback for mailchimp_campaign_filter_info().
 *
 * @string $text
 *   The text string to be filtered.
 * @object object $filter
 *   The filter object containing settings for the given format.
 * @string $format
 *   The text format object assigned to the text to be filtered.
 * @string $langcode
 *   The language code of the text to be filtered.
 * @bool $cache
 *   A Boolean indicating whether the filtered text is going to be cached in
 *   {cache_filter}.
 * @int $cache_id
 *   The ID of the filtered text in {cache_filter}, if $cache is TRUE.
 *
 * @return string
 *   The filtered text.
 */
function mailchimp_campaign_filter_campaign_process($text, $filter, $format, $langcode, $cache, $cache_id) {

  // Replace node macros with entity content:
  $pattern = '/\\[mailchimp_campaign\\|entity_type=(\\w+)\\|entity_id=(\\d+)\\|view_mode=(\\w+)\\]/s';
  $text = preg_replace_callback($pattern, 'mailchimp_campaign_process_callback', $text);

  // Convert URL to absolute:
  $text = mailchimp_campaign_convert_url($text);
  return $text;
}

/**
 * Callback for preg_replace in mailchimp_campaign_filter_campaign_process().
 */
function mailchimp_campaign_process_callback($matches = array()) {
  $content = '';
  $entity_type = $entity_id = $view_mode = '';
  foreach ($matches as $key => $match) {
    switch ($key) {
      case 1:
        $entity_type = $match;
        break;
      case 2:
        $entity_id = $match;
        break;
      case 3:
        $view_mode = $match;
        break;
    }
  }
  $entities = entity_load($entity_type, array(
    $entity_id,
  ));
  if (!empty($entities)) {

    // Prevent session information from being rendered.
    drupal_save_session(FALSE);

    // Force the current user to anonymous to prevent access bypass.
    $original_user = $GLOBALS['user'];
    $GLOBALS['user'] = drupal_anonymous_user();

    // Render the entity.
    $render_array = entity_view($entity_type, $entities, $view_mode, NULL, TRUE);

    // Remove contextual links.
    _mailchimp_campaign_recursive_unset($render_array[$entity_type][$entity_id], '#contextual_links');
    $content = render($render_array);

    // Restore the user.
    $GLOBALS['user'] = $original_user;
    drupal_save_session(TRUE);
  }
  return $content;
}

/**
 * Helper function to recursively unset a given key from an array.
 *
 * Used here by mailchimp_campaign_process_callback() to remove all contextual
 * links, even from nested entity objects.
 *
 * @param array $array Array that needs keys removed.
 * @param string $unwanted_key Key that needs to be removed.
 */
function _mailchimp_campaign_recursive_unset(&$array, $unwanted_key) {

  // Remove key from top level of array.
  if (isset($array[$unwanted_key])) {
    unset($array[$unwanted_key]);
  }

  // Recurse through any remaining keys that may themselves be arrays.
  foreach ($array as &$value) {
    if (is_array($value)) {
      _mailchimp_campaign_recursive_unset($value, $unwanted_key);
    }
  }
}

/**
 * Page callback for a campaign's statistics.
 *
 * @param MailChimpCampaign $campaign
 *   The MailChimp campaign instance.
 *
 * @return array
 *   A renderable array for the campaign stats page.
 */
function mailchimp_campaign_stats_page(MailChimpCampaign $campaign) {
  $mcapi = mailchimp_get_api_object();
  try {
    if (!$mcapi) {
      throw new MailchimpException('Cannot get campaign stats without MailChimp API. Check API key has been entered.');
    }
    $response = $mcapi->reports
      ->summary($campaign->mc_campaign_id);
  } catch (Mailchimp_Error $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
    watchdog('mailchimp_campaign', 'An error occurred getting report data from MailChimp: @msg', array(
      '@msg' => $e
        ->getMessage(),
    ), WATCHDOG_ERROR);
  }
  if (empty($response)) {
    return t('The campaign stats are unavailable at this time.');
  }

  // Tabular summary:
  $rows = array();
  foreach ($response as $key => $stat) {
    if (is_array($stat)) {
      break;
    }
    $rows[] = array(
      $key,
      drupal_ucfirst(str_replace('_', ' ', $stat)),
    );
  }

  // Time series chart data:
  $settings = array();
  foreach ($response['timeseries'] as $series) {
    $settings['mailchimp_campaign']['stats'][] = array(
      'timestamp' => $series['timestamp'],
      'emails_sent' => isset($series['emails_sent']) ? $series['emails_sent'] : 0,
      'unique_opens' => $series['unique_opens'],
      'recipients_click' => $series['recipients_click'],
    );
  }
  $render = array(
    '#attached' => array(
      'js' => array(
        array(
          'data' => 'https://www.google.com/jsapi',
          'type' => 'external',
        ),
        drupal_get_path('module', 'mailchimp_campaign') . '/js/mailchimp_campaign.js',
        array(
          'data' => $settings,
          'type' => 'setting',
        ),
      ),
    ),
    'charts' => array(
      '#prefix' => '<h2>' . t('Hourly stats for the first 24 hours of the campaign') . '</h2>',
      '#markup' => '<div id="mailchimp-campaign-chart"></div>',
    ),
    'overview' => array(
      '#prefix' => '<h2>' . t('Other campaign metrics') . '</h2>',
      '#theme' => 'table',
      '#rows' => $rows,
      '#header' => array(
        t('Key'),
        t('Value'),
      ),
    ),
  );
  return $render;
}

/**
 * Convert an array of templates into rendered content.
 *
 * @param array $template
 *   Array keyed by the section name with a value of the template.
 *
 * @return array
 *   Array of template content indexed by section ID.
 */
function mailchimp_campaign_render_template($template) {
  $content = array();
  foreach ($template as $key => $part) {
    if (isset($part['format'])) {
      $content[$key] = check_markup($part['value'], $part['format']);
    }
  }
  return $content;
}

/**
 * Get MailChimp campaigns.
 *
 * @param array $mc_campaign_ids
 *   Array of MailChimp campaign IDs.
 * @param bool $reset
 *   Set to TRUE if campaigns should not be loaded from cache.
 *
 * @return array
 *   Associative array of MailChimp campaigns indexed by campaign ID.
 */
function mailchimp_campaign_get_campaigns($mc_campaign_ids, $reset = FALSE) {
  $mc_campaigns = array();
  $cached_campaigns = cache_get('campaigns', 'cache_mailchimp');
  foreach ($mc_campaign_ids as $id) {
    if (!isset($cached_campaigns->data[$id]) || $cached_campaigns->data[$id]['status'] == MAILCHIMP_STATUS_SENDING || $reset) {
      $to_refresh[] = $id;
    }
    else {
      $mc_campaigns[$id] = $cached_campaigns->data[$id];
    }
  }
  if (!empty($to_refresh)) {
    $mcapi = mailchimp_get_api_object();
    try {
      if (!$mcapi) {
        throw new MailchimpException('Cannot get list without MailChimp API. Check API key has been entered.');
      }
      $response = $mcapi->campaigns
        ->getList(array(
        'campaign_id' => implode(',', $to_refresh),
      ));
    } catch (Mailchimp_Error $e) {
      drupal_set_message($e
        ->getMessage(), 'error');
      watchdog('mailchimp_campaign', 'An error occurred while getting campaigns: @msg', array(
        '@msg' => $e
          ->getMessage(),
      ), WATCHDOG_ERROR);
      return NULL;
    }
    if (isset($response['total']) && $response['total'] > 0) {
      foreach ($response['data'] as $mc_campaign) {
        $mc_campaigns[$mc_campaign['id']] = $mc_campaign;
      }
    }
    cache_set('campaigns', $mc_campaigns, 'cache_mailchimp');
  }
  return $mc_campaigns;
}

/**
 * Gets an array of list segments for a given list ID.
 *
 * @param int $list_id
 *   The list ID.
 * @param string $type
 *   The segment type to get. "static" or "saved"
 *
 * @return array
 *   Array of MailChimp list segments.
 */
function mailchimp_campaign_get_list_segments($list_id, $type) {
  $mcapi = mailchimp_get_api_object();
  try {
    if (!$mcapi) {
      throw new MailchimpException('Cannot get list segments without MailChimp API. Check API key has been entered.');
    }
    $response = $mcapi->lists
      ->segments($list_id, $type);
  } catch (Mailchimp_Error $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
    watchdog('mailchimp_campaign', 'An error occurred getting list segments for list ID %list_id: @msg', array(
      '%list_id' => $list_id,
      '@msg' => $e
        ->getMessage(),
    ), WATCHDOG_ERROR);
    return NULL;
  }
  return $response[$type];
}

/**
 * Tests a list segment, returning the number of subscribers in the segment.
 *
 * @param string $list_id
 *   The list ID.
 * @param string $list_segment_id
 *   The list segment ID.
 *
 * @return int
 *   The number of subscribers contained in the segment.
 */
function mailchimp_test_list_segment($list_id, $list_segment_id) {
  $mcapi = mailchimp_get_api_object();
  try {
    if (!$mcapi) {
      throw new MailchimpException('Cannot get campaign list segment without MailChimp API. Check API key has been entered.');
    }
    $result = $mcapi->campaigns
      ->segmentTest($list_id, array(
      'saved_segment_id' => $list_segment_id,
    ));
  } catch (Mailchimp_Error $e) {
    drupal_set_message($e
      ->getMessage(), 'error');
    watchdog('mailchimp_campaign', 'An error occurred testing a list segment: @msg', array(
      '@msg' => $e
        ->getMessage(),
    ), WATCHDOG_ERROR);
    return NULL;
  }
  return $result['total'];
}

/**
 * Saves a campaign.
 */
function mailchimp_campaign_save(MailChimpCampaign $campaign) {
  $campaign->updated = REQUEST_TIME;

  // Set the creation timestamp if not set.
  if (!isset($campaign->created) || empty($campaign->created)) {
    $campaign->created = REQUEST_TIME;
  }
  return $campaign
    ->save();
}

/**
 * Load a campaign by ID.
 */
function mailchimp_campaign_load($cid, $reset = FALSE) {
  $campaign = mailchimp_campaign_load_multiple(array(
    $cid,
  ), array(), $reset);
  return $campaign ? $campaign[$cid] : FALSE;
}

/**
 * Loads multiple campaigns.
 */
function mailchimp_campaign_load_multiple($campaign_ids = array(), $conditions = array(), $reset = FALSE) {
  if (empty($campaign_ids)) {
    $campaign_ids = FALSE;
  }
  $campaigns = entity_load('mailchimp_campaign', $campaign_ids, $conditions, $reset);
  return $campaigns;
}

/**
 * Delete a campaign.
 */
function mailchimp_campaign_delete($cid) {
  return mailchimp_campaign_delete_multiple(array(
    $cid,
  ));
}

/**
 * Delete multiple campaigns.
 */
function mailchimp_campaign_delete_multiple($campaign_ids) {
  return entity_get_controller('mailchimp_campaign')
    ->delete($campaign_ids);
}

/**
 * Display a campaign.
 *
 * @param object $campaign
 *   A fully loaded campaign object.
 *
 * @return array
 *   Renderable elements.
 */
function mailchimp_campaign_view($campaign) {
  return $campaign
    ->view();
}

Functions

Namesort descending Description
mailchimp_campaign_access Access callback for campaigns.
mailchimp_campaign_convert_url Change the relative URLs to absolute ones in the message.
mailchimp_campaign_delete Delete a campaign.
mailchimp_campaign_delete_campaign Delete a MailChimp campaign and the local entity.
mailchimp_campaign_delete_multiple Delete multiple campaigns.
mailchimp_campaign_entities_autocomplete_callback Callback for campaign template entity search field.
mailchimp_campaign_entity_info Implements hook_entity_info().
mailchimp_campaign_filter_campaign_process Process callback for mailchimp_campaign_filter_info().
mailchimp_campaign_filter_info Implements hook_filter_info().
mailchimp_campaign_filter_tips Tips callback for mailchimp_campaign_filter_info().
mailchimp_campaign_get_campaigns Get MailChimp campaigns.
mailchimp_campaign_get_list_segments Gets an array of list segments for a given list ID.
mailchimp_campaign_get_template Return full details for a Mailchimp Template.
mailchimp_campaign_list_templates Return all available user templates.
mailchimp_campaign_load Load a campaign by ID.
mailchimp_campaign_load_multiple Loads multiple campaigns.
mailchimp_campaign_menu Implements hook_menu().
mailchimp_campaign_overview_page Page callback for showing a list of MailChimp Campaign entities.
mailchimp_campaign_page_title Title callback: Generate a title for a registration entity.
mailchimp_campaign_permission Implements hook_permission().
mailchimp_campaign_process_callback Callback for preg_replace in mailchimp_campaign_filter_campaign_process().
mailchimp_campaign_render_template Convert an array of templates into rendered content.
mailchimp_campaign_save Saves a campaign.
mailchimp_campaign_save_campaign Save a campaign in MailChimp and as a Drupal entity.
mailchimp_campaign_send_campaign Send MailChimp campaign.
mailchimp_campaign_send_test_campaign Send MailChimp campaign.
mailchimp_campaign_stats_page Page callback for a campaign's statistics.
mailchimp_campaign_theme Implements hook_theme().
mailchimp_campaign_view Display a campaign.
mailchimp_test_list_segment Tests a list segment, returning the number of subscribers in the segment.
_mailchimp_campaign_mcapi_error_message Set and log error messages after MailChimp API errors.
_mailchimp_campaign_recursive_unset Helper function to recursively unset a given key from an array.