You are here

simplenews_scheduler.module in Simplenews Scheduler 7

Simplenews Scheduler module allows a schedule to be set for sending (and resending) a Simplenews item.

File

simplenews_scheduler.module
View source
<?php

/**
 * @file
 * Simplenews Scheduler module allows a schedule to be set
 * for sending (and resending) a Simplenews item.
 */

/**
 * NEWSLETTER SEND COMMAND
 */
define('SIMPLENEWS_COMMAND_SEND_SCHEDULE', 4);
define('SIMPLENEWS_COMMAND_SEND_NONE', 5);

/**
 * Implements hook_permission().
 */
function simplenews_scheduler_permission() {
  return array(
    'overview scheduled newsletters' => array(
      'title' => t('View scheduled newsletters'),
      'description' => t('Access overview page for scheduled newsletters.'),
    ),
    'send scheduled newsletters' => array(
      'title' => t('Send scheduled newsletters'),
      'description' => t('Allows users to use scheduled newsletter sending option.'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function simplenews_scheduler_menu() {
  $items = array();
  $items["node/%node/editions"] = array(
    'title' => 'Newsletter Editions',
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
    'page callback' => 'simplenews_scheduler_node_page',
    'page arguments' => array(
      1,
    ),
    'access callback' => '_simplenews_scheduler_tab_permission',
    'access arguments' => array(
      1,
    ),
  );
  return $items;
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * @todo replace the "This newsletter has been sent" checkbox of simplenews module
 * by a message like "Last edition of this newsletter was sent at 12.12.2012"
 */
function simplenews_scheduler_form_simplenews_node_tab_send_form_alter(&$form, &$form_state) {
  global $user;

  // Add schedule settings to the send newsletter form.
  if (user_access('send scheduled newsletters')) {

    // Make sure that this is not an edition.
    $node = node_load($form['nid']['#value']);

    // Only add the schedule send options if the newsletter has not been sent,
    // in which case there is no send form element.
    if (isset($form['simplenews']['send']) && !isset($node->simplenews_scheduler_edition)) {

      // Set the default values.
      $form['#submit'][] = "simplenews_scheduler_submit";
      $scheduler = array();
      $record = db_select('simplenews_scheduler', 's')
        ->fields('s')
        ->condition('nid', $node->nid)
        ->execute()
        ->fetchAssoc();
      if (!empty($record)) {
        $scheduler = $record;
      }
      else {
        $scheduler['activated'] = 0;
      }
      $form_state['simplenews_scheduler'] = $scheduler;

      // Only show relevant options
      if ($scheduler['activated'] == 0) {
        $form['simplenews']['send']['#options'] += array(
          SIMPLENEWS_COMMAND_SEND_SCHEDULE => t('Send newsletter according to schedule'),
        );
      }
      else {
        $form['simplenews']['send']['#options'] += array(
          SIMPLENEWS_COMMAND_SEND_NONE => t("Stop newsletter schedule"),
        );
        drupal_set_message(t('Newsletter Schedule will send again on @next_run', array(
          '@next_run' => format_date($record['next_run']),
        )));
      }
      $form['simplenews']['send']['#default_value'] = $scheduler['activated'] == 1 ? SIMPLENEWS_COMMAND_SEND_SCHEDULE : variable_get('simplenews_send', SIMPLENEWS_COMMAND_SEND_NONE);
      $form['simplenews']['scheduler'] = array(
        '#type' => 'fieldset',
        '#title' => t('Schedule details'),
        '#attributes' => array(
          'class' => array(
            'schedule-info',
          ),
        ),
        '#collapsible' => TRUE,
        '#collapsed' => FALSE,
        '#states' => array(
          'visible' => array(
            ':input[name="simplenews[send]"]' => array(
              'value' => (string) SIMPLENEWS_COMMAND_SEND_SCHEDULE,
            ),
          ),
        ),
      );

      // If there is no default value, use the current time for start.
      $start_date = !empty($scheduler['start_date']) ? $scheduler['start_date'] : REQUEST_TIME;

      // and Today + 2 years for stop, that should be enough.
      $stop_date = !empty($scheduler['stop_date']) ? $scheduler['stop_date'] : REQUEST_TIME + 2 * 365 * 24 * 60 * 60;
      $form['simplenews']['scheduler']['start_date'] = array(
        '#type' => 'date_select',
        '#title' => t('Start sending on'),
        '#default_value' => date('Y-m-d H:i', $start_date),
        '#required' => TRUE,
        '#date_format' => 'Y-m-d H:i',
        '#date_label_position' => 'within',
        '#date_year_range' => '-0:+3',
        '#description' => t('Intervals work by creating a new node at the
          desired time and marking this to be sent, ensure
          you have your <a href="@site">site timezones</a>
          configured and <a href="@user">user timezone</a>
          configured.', array(
          '@site' => url('admin/config/date-time'),
          '@user' => url('user/' . $user->uid . '/edit'),
        )),
      );
      $intervals = array(
        'hour' => t('Hour'),
        'day' => t('Day'),
        'week' => t('Week'),
        'month' => t('Month'),
      );
      $form['simplenews']['scheduler']['interval'] = array(
        '#type' => 'select',
        '#title' => t('Sending interval'),
        '#options' => $intervals,
        '#description' => t('Interval to send at'),
        '#default_value' => !empty($scheduler['send_interval']) ? $scheduler['send_interval'] : 'week',
      );
      $form['simplenews']['scheduler']['frequency'] = array(
        '#type' => 'textfield',
        '#title' => t('Interval frequency'),
        '#size' => 5,
        '#default_value' => !empty($scheduler['interval_frequency']) ? $scheduler['interval_frequency'] : 1,
        '#description' => t('Set the number of Intervals between newsletter transmission.'),
      );
      $stoptypes = array(
        t('Never'),
        t('On a given date'),
        t('After a maximum number of editions'),
      );
      $form['simplenews']['scheduler']['stoptype'] = array(
        '#type' => 'radios',
        '#title' => t('Stop sending'),
        '#options' => $stoptypes,
        '#default_value' => !empty($scheduler['stop_type']) ? $scheduler['stop_type'] : 0,
        '#attributes' => array(
          'class' => array(
            'simplenews-command-stop',
          ),
        ),
      );
      $form['simplenews']['scheduler']['stop_edition'] = array(
        '#type' => 'textfield',
        '#default_value' => isset($scheduler['stop_edition']) ? $scheduler['stop_edition'] : 0,
        '#size' => 5,
        '#maxlength' => 5,
        '#required' => TRUE,
        '#description' => t('The maximum number of editions which should be sent.'),
        '#states' => array(
          'visible' => array(
            ':input[name="simplenews[scheduler][stoptype]"]' => array(
              'value' => (string) 2,
            ),
          ),
        ),
      );
      $form['simplenews']['scheduler']['stop_date'] = array(
        '#type' => 'date_select',
        '#title' => t('Stop sending on'),
        '#default_value' => date('Y-m-d H:i', $stop_date),
        '#required' => TRUE,
        '#date_format' => 'Y-m-d H:i',
        '#date_label_position' => 'within',
        '#date_year_range' => '-0:+3',
        '#description' => t('The date when the last sent newsletter will be sent.'),
        '#states' => array(
          'visible' => array(
            ':input[name="simplenews[scheduler][stoptype]"]' => array(
              'value' => (string) 1,
            ),
          ),
        ),
      );
      $form['simplenews']['scheduler']['php_eval'] = array(
        '#type' => 'textarea',
        '#title' => t('Additionally only create newsletter edition if the following code returns true'),
        '#default_value' => isset($scheduler['php_eval']) ? $scheduler['php_eval'] : '',
        '#required' => FALSE,
        '#description' => t('Additionally evaluate the following PHP code and only issue the newsletter edition if it returns true. Do not include &lt;?php ?&gt; tags.'),
        '#access' => user_access('use PHP for settings'),
      );
      $form['simplenews']['scheduler']['title'] = array(
        '#type' => 'textfield',
        '#title' => t('Title pattern for new edition nodes'),
        '#description' => t('New edition nodes will have their title set to the above string, with tokens replaced.'),
        '#required' => TRUE,
        '#default_value' => isset($scheduler['title']) ? $scheduler['title'] : '[node:title]',
      );
      $form['simplenews']['scheduler']['token_help'] = array(
        '#title' => t('Replacement patterns'),
        '#type' => 'fieldset',
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      );
      $form['simplenews']['scheduler']['token_help']['help'] = array(
        '#theme' => 'token_tree',
        '#token_types' => array(
          'node',
        ),
      );
      $form['simplenews']['scheduler']['activated'] = array(
        '#type' => 'value',
        '#value' => $scheduler['activated'],
      );
    }
    elseif (isset($node->simplenews_scheduler_edition)) {

      // This is a newsletter edition.
      $form['simplenews']['none']['#title'] = t('This node is part of a scheduled newsletter configuration. View the original newsletter <a href="@parent">here</a>.', array(
        '@parent' => url('node/' . $node->simplenews_scheduler_edition->pid),
      ));
    }
  }
}

/**
 * Additional submit handler for the node_tab_send_form of simplenews.
 */
function simplenews_scheduler_submit($form, &$form_state) {
  $scheduler = $form_state['simplenews_scheduler'];
  $nid = $form_state['values']['nid'];
  $node = node_load($nid);

  // Get Scheduler values from Simplenews.
  $send = $form_state['values']['simplenews']['send'];
  $stoptype = $form_state['values']['simplenews']['scheduler']['stoptype'];
  $start_date = strtotime($form_state['values']['simplenews']['scheduler']['start_date']);
  $stop_date = $stoptype == 1 ? strtotime($form_state['values']['simplenews']['scheduler']['stop_date']) : 0;
  $record = array(
    'nid' => $nid,
    'activated' => $send == SIMPLENEWS_COMMAND_SEND_SCHEDULE ? 1 : 0,
    'send_interval' => $form_state['values']['simplenews']['scheduler']['interval'],
    'interval_frequency' => $form_state['values']['simplenews']['scheduler']['frequency'],
    'start_date' => $start_date,
    'stop_type' => $stoptype,
    'stop_date' => $stop_date,
    'stop_edition' => $form_state['values']['simplenews']['scheduler']['stop_edition'],
    'php_eval' => $form_state['values']['simplenews']['scheduler']['php_eval'],
    'title' => $form_state['values']['simplenews']['scheduler']['title'],
  );

  // For a new scheduler, add the next_run time
  // and also for the old deactivated.
  if (!isset($scheduler['next_run']) || isset($scheduler['activated']) && $scheduler['activated'] == 0) {
    $record['next_run'] = $start_date;

    // reset last run, so next run will be calculated properly
    $record['last_run'] = 0;
  }

  // Update scheduler record.
  db_merge('simplenews_scheduler')
    ->key(array(
    'nid' => $nid,
  ))
    ->fields($record)
    ->execute();
  drupal_set_message(t('Newsletter Schedule preferences have been saved.'));
}

/**
 * Implements hook_node_load().
 */
function simplenews_scheduler_node_load($nodes, $types) {
  $nids = array_keys($nodes);
  $result = db_select('simplenews_scheduler', 's')
    ->fields('s')
    ->condition('nid', $nids, 'IN')
    ->execute()
    ->fetchAll();
  foreach ($result as $key => $record) {
    $nodes[$record->nid]->simplenews_scheduler = $record;
  }
  $result = db_select('simplenews_scheduler_editions', 's')
    ->fields('s')
    ->condition('eid', $nids, 'IN')
    ->execute()
    ->fetchAll();
  foreach ($result as $key => $record) {
    $nodes[$record->eid]->simplenews_scheduler_edition = $record;
    $nodes[$record->eid]->is_edition = TRUE;
    $nodes[$record->eid]->simplenews_edition_parent = $record->pid;
  }
}

/**
 * Implements hook_node_delete().
 */
function simplenews_scheduler_node_delete($node) {
  db_delete('simplenews_scheduler')
    ->condition('nid', $node->nid)
    ->execute();
  db_delete('simplenews_scheduler_editions')
    ->condition('eid', $node->nid)
    ->execute();
}

/**
 * Implements hook_node_view().
 */
function simplenews_scheduler_node_view($node) {
  if (isset($node->simplenews_scheduler_edition) && user_access('send scheduled newsletters')) {
    drupal_set_message(t('This is a newsletter edition. View the the master template of this newsletter <a href="!master_url">here</a>', array(
      '!master_url' => url('node/' . $node->simplenews_edition_parent),
    )));
  }
}

/**
 * Implements hook_cron().
 *
 * Essentially we are just checking against a status table
 * and cloning the node into edition nodes which will be sent.
 */
function simplenews_scheduler_cron() {

  // Get the newsletters that need to be sent at this time.
  $now_time = REQUEST_TIME;
  $newsletters_to_send = simplenews_scheduler_get_newsletters_due($now_time);
  foreach ($newsletters_to_send as $newsletter_parent_data) {
    $edition_time = simplenews_scheduler_calculate_edition_time($newsletter_parent_data, $now_time);

    // Create a new edition.
    $eid = _simplenews_scheduler_new_edition($newsletter_parent_data->nid, $edition_time);

    // Update the edition record.
    simplenews_scheduler_scheduler_update($newsletter_parent_data, $now_time);

    // Send it.
    _simplenews_scheduler_send_new_edition($edition_time, $newsletter_parent_data, $eid);
  }
}

/**
 * Updates a scheduler record with any housekeeping changes and saves it.
 *
 * This should be called once a new edition has been created. This sets the
 * next_run time on the scheduler.
 *
 * @todo: Make this a general API function for saving a new or existing scheduler?
 *
 * @param $newsletter_parent_data
 *   A row of data from {simplenews_scheduler}, as returned by
 *   simplenews_scheduler_get_newsletters_due().
 * @param $now_time
 *   The time of the operation.
 */
function simplenews_scheduler_scheduler_update($newsletter_parent_data, $now_time) {

  // Set the run time for the next edition.
  $newsletter_parent_data->next_run = simplenews_scheduler_calculate_next_run_time($newsletter_parent_data, $now_time);
  drupal_write_record('simplenews_scheduler', $newsletter_parent_data, 'nid');
}

/**
 * Calculates time for the current edition about to be created.
 *
 * Because cron may run after the scheduled timestamp, one or more scheduled
 * edition times may have been skipped. This calculates the most recent
 * possible time for an edition.
 *
 * @param $newsletter_parent_data
 *   A row of data from {simplenews_scheduler}, as returned by
 *   simplenews_scheduler_get_newsletters_due().
 * @param $now_time
 *   The time of the operation.
 *
 * @return
 *   The calculcated creation time of the newsletter edition.
 */
function simplenews_scheduler_calculate_edition_time($newsletter_parent_data, $now_time) {

  // Make an offset string of the format '+1 month'.
  $offset_string = _simplenews_scheduler_make_time_offset($newsletter_parent_data->send_interval, $newsletter_parent_data->interval_frequency);

  // Make a DateInterval object that represents this.
  $date_interval = DateInterval::createFromDateString($offset_string);

  // Take the last run time and add as many intervals as possible without going
  // past 'now'.
  // Create a date object to act as a pointer we'll advance and increment.
  if ($newsletter_parent_data->last_run) {

    // Generate a date string to initialize a DateTime() object, otherwise the
    // timezone is ignored.
    $start_date = date('Y-m-d H:i:s', $newsletter_parent_data->last_run);
  }
  else {
    $start_date = date('Y-m-d H:i:s', $newsletter_parent_data->start_date);
  }

  // Initialize the DateTime object using the configured ste timezone.
  $pointer_date = new DateTime($start_date);
  while ($pointer_date
    ->getTimestamp() <= $now_time) {

    // Get the last iteration's timestamp before we change the pointer.
    $timestamp_old = $pointer_date
      ->getTimestamp();

    // Add interval to the pointer time.
    $pointer_date
      ->add($date_interval);

    // Check if the pointer is now in the future.
    if ($pointer_date
      ->getTimestamp() > $now_time) {

      // If so, return the last iteration timestamp as the edition time.
      return $timestamp_old;
    }
  }
}

/**
 * Calculates time for the next edition to be sent.
 *
 * This is set in the {simplenews_scheduler} table when a new edition is run,
 * for subsequent cron runs to query against.
 *
 * The time is strictly in the future; that is, if the $now_time is a valid
 * edition time, a schedule interval is added to it. This is to allow for cron
 * runs that need to calculate the next run time at the time of the current
 * edition being sent.
 *
 * @param $newsletter_parent_data
 *   A row of data from {simplenews_scheduler}, as returned by
 *   simplenews_scheduler_get_newsletters_due().
 * @param $now_time
 *   The time of the operation.
 *
 * @return
 *   The calculcated run time for the next future edition.
 */
function simplenews_scheduler_calculate_next_run_time($newsletter_parent_data, $now_time) {

  // Make an offset string of the format '+1 month'.
  $offset_string = _simplenews_scheduler_make_time_offset($newsletter_parent_data->send_interval, $newsletter_parent_data->interval_frequency);

  // Make a DateInterval object that represents this.
  $date_interval = DateInterval::createFromDateString($offset_string);

  // Create a date object to act as a pointer we'll advance and increment.
  if ($newsletter_parent_data->last_run) {

    // Generate a date string to initialize a DateTime() object, otherwise the
    // timezone is ignored.
    $start_date = date('Y-m-d H:i:s', $newsletter_parent_data->last_run);
  }
  else {
    $start_date = date('Y-m-d H:i:s', $newsletter_parent_data->start_date);
  }

  // Initialize the DateTime object using the configured ste timezone.
  $pointer_date = new DateTime($start_date);

  // Add as many offsets as possible until we get into the future.
  while ($pointer_date
    ->getTimestamp() <= $now_time) {

    // Add interval to the pointer time.
    $pointer_date
      ->add($date_interval);
  }
  return $pointer_date
    ->getTimestamp();
}

/**
 * Helper to create a PHP time offset string.
 *
 * @param $interval
 *  A time interval. One of hour, day, week, month.
 * @param $frequency
 *  An integer that specifies how many of the $interval to create an offset for.
 *
 * @return
 *  A string representing a time offset that can be understood by strtotime(),
 *  eg '+1 month'.
 */
function _simplenews_scheduler_make_time_offset($interval, $frequency) {
  $offset_string = "+{$frequency} {$interval}";
  return $offset_string;
}

/**
 * Get the newsletters that need to have new editions sent.
 *
 * This is a helper function for hook_cron that has the current date abstracted
 * out so it can be tested.
 *
 * @param $timestamp
 *   A unix timestamp at which to determine which newsletters are due to be
 *   sent. In ordinary operation this should be the current time.
 *
 * @return
 *  An array of newsletter data arrays in the form of rows from the
 *  {simplenews_scheduler} table, keyed by newsletter nid.
 */
function simplenews_scheduler_get_newsletters_due($timestamp) {

  // Get all newsletters that need to be sent.
  $result = db_query("SELECT * FROM {simplenews_scheduler} WHERE activated = 1 AND next_run <= :now AND (stop_date > :now OR stop_date = 0)", array(
    ':now' => $timestamp,
  ));
  $newsletters = array();
  foreach ($result as $newsletter_parent_data) {

    // The node id of the parent node.
    $pid = $newsletter_parent_data->nid;

    // Check upon if sending should stop with a given edition number.
    $stop = $newsletter_parent_data->stop_type;
    $stop_edition = $newsletter_parent_data->stop_edition;
    $edition_count = db_query('SELECT COUNT(*) FROM {simplenews_scheduler_editions} WHERE pid = :pid', array(
      ':pid' => $pid,
    ))
      ->fetchField();

    // Don't create new edition if the edition number would exceed the given maximum value.
    if ($stop == 2 && $edition_count >= $stop_edition) {
      continue;
    }

    // does this newsletter have something to evaluate to check running condition?
    if (strlen($newsletter_parent_data->php_eval)) {
      $eval_result = eval($newsletter_parent_data->php_eval);
      if (!$eval_result) {
        continue;
      }
    }
    $newsletters[$pid] = $newsletter_parent_data;
  }
  return $newsletters;
}

/**
 * Helper for hook_cron() to send a new edition.
 *
 * @param $edition_time
 *  The time of the operation. Usually the current time unless testing.
 * @param $newsletter_parent_data
 *  A row of data from {simplenews_scheduler}, as returned by
 *  simplenews_scheduler_get_newsletters_due().
 * @param $eid
 *  The node id of the new edition to send. This should already have been
 *  created by _simplenews_scheduler_new_edition().
 */
function _simplenews_scheduler_send_new_edition($edition_time, $newsletter_parent_data, $eid) {
  $pid = $newsletter_parent_data->nid;

  // persist last_run
  db_update('simplenews_scheduler')
    ->fields(array(
    'last_run' => $edition_time,
  ))
    ->condition('nid', $pid)
    ->execute();

  // Send the newsletter edition to each subscriber of the parent newsletter.
  $node = node_load($eid);
  module_load_include('inc', 'simplenews', 'includes/simplenews.mail');
  simplenews_add_node_to_spool($node);
}

/**
 * Function clones a node from the given template newsletter node.
 */
function simplenews_scheduler_clone_node($node) {
  if (isset($node->nid)) {
    $clone = clone $node;
    $clone->nid = NULL;
    $clone->vid = NULL;
    $clone->tnid = NULL;
    $clone->created = NULL;
    $clone->book['mlid'] = NULL;
    $clone->path = NULL;

    //$clone->title = $original_node->title;

    // Add an extra property as a flag.
    $clone->clone_from_original_nid = $node->nid;
    node_save($clone);
    return $clone;
  }
}

/**
 * Menu callback to provide an overview page with the scheduled newsletters.
 *
 * @todo replace the output of this function with a default view that
 * will be provided by the views integration of this module. Code below
 * is ported from D6!
 */
function simplenews_scheduler_node_page($node) {
  drupal_set_title(t('Scheduled newsletter editions'));
  $nid = _simplenews_scheduler_get_pid($node);
  $output = '';
  $rows = array();
  if ($nid == $node->nid) {

    // This is the template newsletter.
    $output .= '<p>' . t('This is a newsletter template node of which all corresponding editions nodes are based on.') . '</p>';
  }
  else {

    // This is a newsletter edition.
    $output .= '<p>' . t('This node is part of a scheduled newsletter configuration. View the original newsletter <a href="@parent">here</a>.', array(
      '@parent' => url('node/' . $nid),
    )) . '</p>';
  }

  // Load the corresponding editions from the database to further process.
  $result = db_select('simplenews_scheduler_editions', 's')
    ->extend('PagerDefault')
    ->limit(20)
    ->fields('s')
    ->condition('s.pid', $nid)
    ->execute()
    ->fetchAll();
  foreach ($result as $row) {
    $node = node_load($row->eid);
    $rows[] = array(
      l($node->title, 'node/' . $row->eid),
      format_date($row->date_issued, 'custom', 'Y-m-d H:i'),
    );
  }

  // Display a table with all editions.
  $tablecontent = array(
    'header' => array(
      t('Edition Node'),
      t('Date sent'),
    ),
    'rows' => $rows,
    'attributes' => array(
      'class' => array(
        'schedule-history',
      ),
    ),
    'empty' => '<p>' . t('No scheduled newsletter editions have been sent.') . '</p>',
  );
  $output .= theme('table', $tablecontent);
  $output .= theme('pager', array(
    'tags' => 20,
  ));
  return $output;
}

/**
 * Check whether to display the Scheduled Newsletter tab.
 */
function _simplenews_scheduler_tab_permission($node) {

  // Check if this is a simplenews node type and permission.
  if (simplenews_check_node_types($node->type) && user_access('overview scheduled newsletters')) {

    // Check if this is either a scheduler newsletter or an edition.
    return !empty($node->simplenews_scheduler) || !empty($node->is_edition);
  }
}

/**
 * Find Full HTML input format.
 *
 * Use the Drupal API for finding the Full HTML input format, this is what the subsequent newsletter editions
 * need to be set to.
 */
function _simplenews_scheduler_get_full_html_format() {
  global $user;
  $formats = filter_formats($user);
  foreach ($formats as $index => $format) {
    if (stristr($format->name, 'Full HTML')) {
      return $index;
    }
  }
  return false;
}

/**
 * Create a new newsletter edition based on the master edition of this newsletter.
 *
 * This does no checking of whether a new edition should be made; it's up to
 * the caller to determine this first.
 *
 * @param $nid
 *   The node id of the parent newsletter node to use as a template.
 * @param $edition_time
 *   Desired edition creation time.
 *
 * @return
 *  The node id of the new edition node.
 */
function _simplenews_scheduler_new_edition($nid, $edition_time) {

  // Load the template node and clone an edition.
  $template_node = node_load($nid);
  $edition_node = simplenews_scheduler_clone_node($template_node);

  // Set the node's creation time as the given timestamp.
  $edition_node->created = $edition_time;

  // Run the title through token replacement.
  // Get title pattern from the scheduler record, not newsletter node.
  // $edition_node->title = token_replace($edition_node->title, array('node' => $edition_node));
  $schedrecord = db_select('simplenews_scheduler', 's')
    ->fields('s')
    ->condition('nid', $template_node->nid)
    ->execute()
    ->fetchAssoc();
  $edition_node->title = token_replace($schedrecord['title'], array(
    'node' => $template_node,
  ));

  // Invoke simplenews_scheduler_edition_node() to give installed modules a
  // chance to modify the cloned edition node if necessary before it gets saved.
  drupal_alter('simplenews_scheduler_edition_node', $edition_node, $template_node);

  // Save the changes of other modules
  node_save($edition_node);

  // Insert edition data.
  $values = array(
    'eid' => $edition_node->nid,
    'pid' => $template_node->nid,
    'date_issued' => $edition_time,
  );
  db_insert('simplenews_scheduler_editions')
    ->fields($values)
    ->execute();

  // Add a watchdog entry.
  $variables = array(
    '%title' => entity_label('node', $edition_node),
  );
  $uri = entity_uri('node', $edition_node);
  $link = l(t('view'), $uri['path'], $uri['options']);
  watchdog('simplenews_sched', 'Created a new newsletter edition %title', $variables, WATCHDOG_NOTICE, $link);

  // Prepare the correct status for Simplenews to pickup.
  simplenews_newsletter_update_sent_status($edition_node);
  return $edition_node->nid;
}

/**
 * Helper function to get the identifier of newsletter.
 *
 * @param $node
 *  The node object for the newsletter.
 *
 * @return
 *  If the node is a newsletter edition, the node id of its parent template
 *  newsletter; if the node is a template newsletter, its own node id; and
 *  FALSE if the node is not part of a scheduled newsletter set.
 */
function _simplenews_scheduler_get_pid($node) {

  // First assume this is a newsletter edition,
  if (isset($node->simplenews_scheduler_edition)) {
    return $node->simplenews_scheduler_edition->pid;
  }
  elseif (isset($node->simplenews_scheduler)) {
    return $node->nid;
  }
  return FALSE;
}

Functions

Namesort descending Description
simplenews_scheduler_calculate_edition_time Calculates time for the current edition about to be created.
simplenews_scheduler_calculate_next_run_time Calculates time for the next edition to be sent.
simplenews_scheduler_clone_node Function clones a node from the given template newsletter node.
simplenews_scheduler_cron Implements hook_cron().
simplenews_scheduler_form_simplenews_node_tab_send_form_alter Implements hook_form_FORM_ID_alter().
simplenews_scheduler_get_newsletters_due Get the newsletters that need to have new editions sent.
simplenews_scheduler_menu Implements hook_menu().
simplenews_scheduler_node_delete Implements hook_node_delete().
simplenews_scheduler_node_load Implements hook_node_load().
simplenews_scheduler_node_page Menu callback to provide an overview page with the scheduled newsletters.
simplenews_scheduler_node_view Implements hook_node_view().
simplenews_scheduler_permission Implements hook_permission().
simplenews_scheduler_scheduler_update Updates a scheduler record with any housekeeping changes and saves it.
simplenews_scheduler_submit Additional submit handler for the node_tab_send_form of simplenews.
_simplenews_scheduler_get_full_html_format Find Full HTML input format.
_simplenews_scheduler_get_pid Helper function to get the identifier of newsletter.
_simplenews_scheduler_make_time_offset Helper to create a PHP time offset string.
_simplenews_scheduler_new_edition Create a new newsletter edition based on the master edition of this newsletter.
_simplenews_scheduler_send_new_edition Helper for hook_cron() to send a new edition.
_simplenews_scheduler_tab_permission Check whether to display the Scheduled Newsletter tab.

Constants