View source  
  <?php
function node_recur_menu() {
  $items = array();
  $items['node/%node/recur'] = array(
    'title' => 'Repeat',
    'title callback' => 'node_recur_menu_title_callback',
    'title arguments' => array(
      1,
    ),
    'description' => 'Set recurring rules on this node',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'node_recur_node_recur_form',
      1,
    ),
    'access callback' => 'node_recur_node_recur_form_access',
    'access arguments' => array(
      1,
    ),
    'file' => 'node_recur.pages.inc',
    'type' => MENU_LOCAL_ACTION,
    'weight' => 1,
  );
  return $items;
}
function node_recur_permission() {
  return array(
    'recur own nodes' => array(
      'title' => t('Recur own nodes'),
      'description' => t('Can recur nodes that the user is an author of.'),
    ),
    'recur all nodes' => array(
      'title' => t('Recur all nodes'),
      'description' => t('Can recur all published nodes.'),
    ),
  );
}
function node_recur_form_node_type_form_alter(&$form, &$form_state) {
  $type = $form['#node_type']->type;
  
  $fields = array();
  $instances = field_info_instances();
  if (isset($instances['node'][$type])) {
    foreach ($instances['node'][$type] as $name => $field) {
      if ($field['widget']['module'] == 'date') {
        $fields[$name] = $field['label'] . ' (' . $name . ')';
      }
    }
  }
  $form['node_recur'] = array(
    '#type' => 'fieldset',
    '#title' => t('Node recurring'),
    '#group' => 'additional_settings',
  );
  if (!empty($fields)) {
    $form['node_recur']['node_recur_enabled_node_type'] = array(
      '#type' => 'checkbox',
      '#title' => t('Enable recurring for this node type'),
      '#default_value' => node_recur_recurring_enabled($type) ? 1 : 0,
      '#description' => t('If checked, users with permission can create recurring copies of these nodes.'),
    );
    $form['node_recur']['node_recur_date_field_node_type'] = array(
      '#type' => 'select',
      '#title' => t('Date field'),
      '#options' => $fields,
      '#default_value' => node_recur_get_date_field_name($type),
      '#description' => t('Select the date field that will be used to base the recurrences on.'),
    );
  }
  else {
    $form['node_recur']['node_recur_null'] = array(
      '#markup' => t('There are no date fields available for this node type.'),
    );
  }
}
function node_recur_node_recur_form_access($node) {
  global $user;
  $access = FALSE;
  
  if (node_recur_recurring_enabled($node->type) && node_recur_get_date_field_name($node->type)) {
    
    $recur_access = user_access('recur all nodes') || user_access('recur own nodes') && $node->uid == $user->uid;
    if ($recur_access && node_access('create', $node->type)) {
      
      $access = TRUE;
    }
    
    drupal_alter('node_recur_access', $access, $node);
  }
  return $access;
}
function node_recur_recurring_enabled($type) {
  return variable_get("node_recur_enabled_node_type_{$type}", FALSE);
}
function node_recur_get_date_field_name($type) {
  if ($field_name = variable_get("node_recur_date_field_node_type_{$type}", FALSE)) {
    
    if (field_info_field($field_name)) {
      return $field_name;
    }
  }
  return NULL;
}
function node_recur_menu_title_callback($node) {
  return t('Repeat this !type', array(
    '!type' => strtolower(node_type_get_name($node)),
  ));
}
function node_recur_node_batch_start($node, $dates) {
  
  $operations = array();
  if (!empty($dates)) {
    foreach ($dates as $date) {
      $operations[] = array(
        'node_recur_node_batch_create_node',
        array(
          $node,
          $date,
        ),
      );
    }
    
    $batch = array(
      'title' => t('Generating items'),
      'operations' => $operations,
      'finished' => 'node_recur_node_batch_finished',
      'file' => drupal_get_path('module', 'node_recur') . '/node_recur.batch.inc',
    );
    batch_set($batch);
    batch_process("node/{$node->nid}");
  }
}
function node_recur_node_batch_create_node($node, $date, &$context) {
  $field_name = node_recur_get_date_field_name($node->type);
  $view = field_view_value('node', $node, $field_name, $date);
  
  $context['message'] = t('Date: !date', array(
    '!date' => $view['#markup'],
  ));
  
  $clone = node_load($node->nid, $node->vid, TRUE);
  
  unset($clone->{$field_name}[LANGUAGE_NONE]);
  $clone->{$field_name}[LANGUAGE_NONE][] = $date;
  
  $context['results'][] = $date;
  
  if (module_exists('clone')) {
    $context = [
      'method' => 'node_recur',
      'prefix_title' => FALSE,
      'original_node' => $node,
    ];
    clone_action_clone($clone, $context);
  }
  else {
    $clone->clone_from_original_nid = $node->nid;
    unset($clone->nid);
    unset($clone->created);
    unset($clone->changed);
    unset($clone->vid);
    node_save($clone);
  }
}
function node_recur_node_batch_finished($success, $results, $operations) {
  if ($success) {
    $count = count($results);
    drupal_set_message(t('%count %items have been generated.', array(
      '%count' => $count,
      '%items' => format_plural($count, 'item', 'items'),
    )));
  }
  else {
    drupal_set_message(t('An error occurred. Please try again.'), 'error');
  }
}