Would be great to have the ability to schedule a email campaign from the Campaign dashboard.

Comments

extrem94 created an issue. See original summary.

apmsooner’s picture

Status: Active » Needs review

Looks like the library doesn't include the function to schedule, can you consider adding this to the library at least assuming it looks good?

Here are schedule and unschedule public functions that should be added to the library file MailchimpCampaigns.php

  /**
   * Schedule a MailChimp campaign.
   *
   * @param string $campaign_id
   *   The ID of the campaign.
   * @param date_time $schedule_time
   *   The date and time in UTC to schedule the campaign for delivery.
   *   Campaigns may only be scheduled to send on the
   *   quarter-hour (:00, :15, :30, :45).
   * @param array $parameters
   *   Associative array of request parameters.
   * @param bool $batch
   *   TRUE to create a new pending batch operation.
   *
   * @return object
   *
   * @see http://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/#action-post_campaigns_campaign_id_actions_schedule
   */
  public function schedule($campaign_id, $schedule_time, $parameters = [], $batch = FALSE) {
    $tokens = [
      'campaign_id' => $campaign_id,
    ];

    $parameters += [
      'schedule_time' => $schedule_time,
    ];

    return $this->request('POST', '/campaigns/{campaign_id}/actions/schedule', $tokens, $parameters, NULL, $batch);
  }

  /**
   * Unschedule a MailChimp campaign.
   *
   * @param string $campaign_id
   *   The ID of the campaign.
   * @return object
   *
   * @see http://developer.mailchimp.com/documentation/mailchimp/reference/campaigns/#action-post_campaigns_campaign_id_actions_unschedule
   */
  public function unschedule($campaign_id) {
    $tokens = [
      'campaign_id' => $campaign_id,
    ];

    return $this->request('POST', '/campaigns/{campaign_id}/actions/unschedule', $tokens, NULL);
  }
apmsooner’s picture

The master branch of the library now includes functions to schedule and unschedule campaigns and also a function to check if campaign is ready to send. While I don't use the campaign functionality of the module, I have created a custom node type to serve as my campaign. In a custom module, I've created actions that attach to my view of campaigns as depicted here with example of how I'm making this work if anyone is interested in adapting to the mailchimp campaigns submodule as a patch.

Campaign history is normally stored in cache via the mailchimp module i believe so not sure the maintainers desire to implement similar functionality. I store all my campaign data in a custom table and it gets updated via mailchimp webhooks when the campaign is sent. The webhooks defined in the module would also need to be updated to allow campaign updates to get triggered. Anyhow... here's an example:

/**
 * Implements hook_action_info().
 */
function bei_campaign_action_info() {
  return array(
    'bei_campaign_send_campaign' => array(
      'type' => 'node',
      'label' => t('Send Campaign'),
      'configurable' => FALSE,
      'vbo_configurable' => FALSE,
      'triggers' => array('any'),
      'permissions' => array('send a campaign'),
    ),
    'bei_campaign_schedule_campaign' => array(
      'type' => 'node',
      'label' => t('Schedule Campaign'),
      'configurable' => TRUE,
      'vbo_configurable' => FALSE,
      'triggers' => array('any'),
      'permissions' => array('schedule a campaign'),
    ),
    'bei_campaign_unschedule_campaign' => array(
      'type' => 'node',
      'label' => t('Unschedule Campaign'),
      'configurable' => FALSE,
      'vbo_configurable' => FALSE,
      'triggers' => array('any'),
      'permissions' => array('unschedule a campaign'),
    ),
  );
}

/**
 * Helper function to build a schedule form for the schedule action.
 */
function bei_campaign_schedule_campaign_form($options) {
  $form = array();

  $form['bei_campaign_schedule'] = array(
    '#type' => 'date_popup',
    '#date_format' => 'Y-m-d h:i:sa',
    '#date_year_range' => '0:+1',
    '#date_timezone' => date_default_timezone(),
    '#title' => t('Schedule Date'),
    '#description' => t('Choose a time in which this campaign should be sent.'),
    '#required' => TRUE,
    '#default_value' => !empty($options['bei_campaign_schedule']) ? $options['bei_campaign_schedule'] : '',
    '#element_validate' => array('bei_campaign_schedule_date_validate'),
    '#datepicker_options' => array('minDate' => 0),
    '#date_increment' => 15,
  );

  return $form;
}
/**
 * Helper function to ensure schedule date is not in the past.
 */

function bei_campaign_schedule_date_validate($element, &$form_state, $form) {
  $now = strtotime('now');
  $schedule_date = strtotime($element['#value']['date'] . ' ' . $element['#value']['time']);
  if ($schedule_date <= $now) {
      form_error($element, t($element['#title'] . '  must be in the future.'));
  }
}

/**
 * Helper function to submit schedule form for the schedule action.
 */
function bei_campaign_schedule_campaign_submit($form, $form_state) {
  // This has to be returned as an array or it blows up. (Unsupported Operand)
  return array('time' => $form_state['values']['bei_campaign_schedule']);
}

/**
 * Action submit function to run an action's action!
 */
function bei_campaign_schedule_campaign($node, $context) {
   // Convert the time into GMT time.
   $date = new DateTime($context['time'], new DateTimeZone('America/Denver'));
   $date->setTimezone(new DateTimeZone('GMT'));
   $send_date = $date->format('Y-m-d H:i:s');
   $list_id = !empty($node->list_id) ? $node->list_id : NULL;
   $campaign_id = !empty($node->campaign_id) ? $node->campaign_id : NULL;
   if ($list_id && $campaign_id) {
      try {
         /* @var \Mailchimp\MailchimpCampaigns $mc_campaigns */
         $mc_campaigns = mailchimp_get_api_object('MailchimpCampaigns');
         if (!$mc_campaigns) {
           throw new MailchimpException('Cannot schedule campaigns without MailChimp API. Check API key has been entered.');
         }
         try {
            $checklist = $mc_campaigns->getSendChecklist($campaign_id);
            if (!$checklist->is_ready) {
               drupal_set_message(t('Campaign node @nid titled %title cannot be scheduled.', array(
                  '@nid' => $node->nid,
                  '%title' => $node->title,
                  )), 'warning');
               $errors = array();
               foreach ($checklist->items as $item) {
                 if ($item->type == 'error') {
                  $message = '<strong>' . $item->heading . '</strong>: ' . $item->details;
                  drupal_set_message(t($message), 'error');
                 }
               }
               watchdog('bei_campaign', 'Campaign node @nid is not ready to send.', array(
                  '@nid' => $node->nid,
                ), WATCHDOG_ERROR);
            }
            else {
               $mc_campaigns->schedule($campaign_id, $send_date, FALSE, FALSE);
               $campaign = $mc_campaigns->getCampaign($campaign_id);
               $node->campaign_status = $campaign->status;
               $node->schedule_date = strtotime($campaign->send_time);
               node_save($node);
            }
         }
         catch (Exception $e) {
            // Throw exception only for errors other than campaign not found.
            if ($e->getCode() != 404) {
              throw new Exception($e->getMessage(), $e->getCode(), $e);
            }
         }
      }
      catch (Exception $e) {
        watchdog('bei_campaign', 'An error occurred trying to schedule campaign node @nid. "%message"', array(
          '%message' => $e->getMessage(),
          '@nid' => $node->nid,
        ), WATCHDOG_ERROR);
      }
   }
}

/**
 * Action submit function to run an action's action!
 */
function bei_campaign_unschedule_campaign($node, $context) {
  // Send Mailchimp a request to unschedule a campaign.
  try {
      /* @var \Mailchimp\MailchimpCampaigns $mc_campaigns */
      $mc_campaigns = mailchimp_get_api_object('MailchimpCampaigns');
      if (!$mc_campaigns) {
        throw new MailchimpException('Cannot unschedule campaigns without MailChimp API. Check API key has been entered.');
      }
      if ($node->campaign_status !== 'schedule') {
         drupal_set_message(t('Cannot unschedule a campaign that is not scheduled.'), 'error');
      }
      else {
         $mc_campaigns->unschedule($node->campaign_id);
         $campaign = $mc_campaigns->getCampaign($node->campaign_id);
         $node->campaign_status = $campaign->status;
         unset($node->schedule_date);
         node_save($node);
         drupal_set_message(t('Unscheduled campaign @nid', array('@nid' => $node->nid)), 'status', FALSE);
      }
   }
   catch (Exception $e) {
     watchdog('bei_campaign', 'An error occurred trying to unschedule campaign node @nid. "%message"', array(
       '%message' => $e->getMessage(),
       '@nid' => $node->nid,
     ), WATCHDOG_ERROR);
   }
}

/**
 * Helper function that will run when send action is used.
 */
function bei_campaign_send_campaign($node, &$form_state) {
   $list_id = !empty($node->list_id) ? $node->list_id : NULL;
   $campaign_id = !empty($node->campaign_id) ? $node->campaign_id : NULL;
   if ($list_id && $campaign_id && $node->campaign_status == 'save') {
      try {
         /* @var \Mailchimp\MailchimpCampaigns $mc_campaigns */
         $mc_campaigns = mailchimp_get_api_object('MailchimpCampaigns');
         if (!$mc_campaigns) {
           throw new MailchimpException('Cannot send campaigns without MailChimp API. Check API key has been entered.');
         }
         try {
            $checklist = $mc_campaigns->getSendChecklist($campaign_id);
            if (!$checklist->is_ready) {
               drupal_set_message(t('Campaign node @nid titled %title cannot be sent.', array(
                  '@nid' => $node->nid,
                  '%title' => $node->title,
                  )), 'warning');
               $errors = array();
               foreach ($checklist->items as $item) {
                 if ($item->type == 'error') {
                  $message = '<strong>' . $item->heading . '</strong>: ' . $item->details;
                  drupal_set_message(t($message), 'error');
                 }
               }
               watchdog('bei_campaign', 'Campaign node @nid is not ready to send.', array(
                  '@nid' => $node->nid,
                ), WATCHDOG_ERROR);
            }
            else {
               $mc_campaigns->send($campaign_id);
               $campaign = $mc_campaigns->getCampaign($campaign_id);
               $node->campaign_status = $campaign->status;
               node_save($node);
            }
         }
         catch (Exception $e) {
            // Throw exception only for errors other than campaign not found.
            if ($e->getCode() != 404) {
              throw new Exception($e->getMessage(), $e->getCode(), $e);
            }
         }
      }
      catch (Exception $e) {
        watchdog('bei_campaign', 'An error occurred trying to send campaign node @nid. "%message"', array(
          '%message' => $e->getMessage(),
          '@nid' => $node->nid,
        ), WATCHDOG_ERROR);
      }
   }
}
samuel.mortenson’s picture

Status: Needs review » Closed (won't fix)

We’re in maintenance-mode for the Drupal 7 releases of Mailchimp, so only bug fixes can be committed going forward. Any new features should be developed for the Drupal 8 releases of Mailchimp. Thanks!