'scheduler/cron', 'type' => MENU_CALLBACK, 'callback' => '_scheduler_run_cron', 'access' => TRUE, ); $items[] = array( 'path' => 'scheduler/timecheck', 'type' => MENU_CALLBACK, 'callback' => '_scheduler_timecheck', 'access' => user_access('schedule (un)publishing of nodes'), ); } return $items; } /** * Implementation of hook_form_alter(). */ function scheduler_form_alter($form_id, &$form) { //allow scheduling on a per-node-type basis if ('node_type_form' == $form_id) { $form['workflow']['scheduler'] = array( '#type' => 'checkbox', '#title' => t('Enable scheduled (un)publishing'), '#default_value' => variable_get('scheduler_'. $form['#node_type']->type, 0), '#description' => t('Check this box to enable scheduled (un)publishing for this node type.') ); } // is this a node form? else if (isset($form['type']['#value']) && $form['type']['#value'] .'_node_form' == $form_id) { if (user_access('schedule (un)publishing of nodes')) { // if scheduling has been enabled for this node type if (variable_get('scheduler_'. $form['type']['#value'], 0) == 1) { //use JScalendar picker for dates if the module exists and is enabled $jscalendar = FALSE; if (module_exists('jscalendar')) { $jscalendar = TRUE; // Show 24-hour clock for JScalendar //$form['#jscalendar_timeFormat'] = '24'; // Use only year, month, and day in textfield. $form['#jscalendar_ifFormat'] = '%Y-%m-%d'; // Don't show time. $form['#jscalendar_showsTime'] = 'false'; } $node = $form['#node']; //only load the values if we are viewing an existing node if ($node->nid > 0) { $defaults = db_fetch_object(db_query('SELECT publish_on, unpublish_on, timezone FROM {scheduler} WHERE nid = %d', $node->nid)); } else { // init standard values $defaults = new StdClass; $defaults->publish_on = $defaults->unpublish_on = NULL; } // We add the additional validation function this way to preserve any existing validation function $form['#validate']['_scheduler_form_validate' ] = array(); //note don't use format_date() because drupal automatically formats the date to the user's timezone //this will show the wrong time because scheduler can set nodes to be published in different timezones $form['scheduler_settings'] = array( '#type' => 'fieldset', '#title' => t('Scheduling options'), '#collapsible' => TRUE, '#collapsed' => ($defaults->publish_on != 0 || $defaults->unpublish_on != 0) ? FALSE: FALSE, '#weight' => 35 ); $form['scheduler_settings']['publish_on'] = array( '#type' => 'textfield', '#title' => t('Publish on'), '#maxlength' => 25, //we subtract the time zone to show the user the correct time they entered //and below that we show the timezone to adjust this time by //we store the adjusted timezone value in the database for cron '#default_value' => $defaults->publish_on ? date('d.m.Y', $defaults->publish_on - $defaults->timezone) : date('d.m.Y'), '#description' => t('Format: %time. Default is set to publish now.', array('%time' => date('d.m.Y'))), '#attributes' => $jscalendar ? array('class' => 'jscalendar') : array(), // Use only year, month, and day in textfield. // '#jscalendar_ifFormat' => $jscalendar ? '%Y-%m-%d' : array(), '#jscalendar_ifFormat' => $jscalendar ? '%d.%m.%Y' : array(), // Don't show time. '#jscalendar_showsTime' => $jscalendar ? 'false' : array(), // Show 24-hour clock. '#jscalendar_timeFormat' => $jscalendar ? '24' : '', ); $form['scheduler_settings']['unpublish_on'] = array( '#type' => 'textfield', '#title' => t('Unpublish on'), '#maxlength' => 25, //we subtract the time zone to show the user the correct time they entered //and below that we show the timezone to adjust this time by //we store the adjusted timezone value in the database for cron // If no value is found in the database, we set the default unpublish date to be in one week. (604800 sec) '#default_value' => $defaults->unpublish_on ? date('d.m.Y', $defaults->unpublish_on - $defaults->timezone) : date('d.m.Y', time()+604800), '#description' => t('Format: %time.', array('%time' => date('d.m.Y'))), '#required' => TRUE, '#attributes' => $jscalendar ? array('class' => 'jscalendar') : array(), // Use only year, month, and day in textfield. // '#jscalendar_ifFormat' => $jscalendar ? '%Y-%m-%d' : array(), '#jscalendar_ifFormat' => $jscalendar ? '%d.%m.%Y' : array(), // Don't show time. '#jscalendar_showsTime' => $jscalendar ? 'false' : array(), // Show 24-hour clock. '#jscalendar_timeFormat' => $jscalendar ? '24' : '', ); //default to user timezone, if not specified, default to system wide timezone global $user; $zones = _system_zonelist(); $form['scheduler_settings']['timezone'] = array( // Changed from 'select' to 'hidden' because we don't want this field to be shown to the user '#type' => 'hidden', '#title' => t('Time zone'), '#default_value' => $defaults->timezone ? $defaults->timezone : (strlen($user->timezone) ? $user->timezone : variable_get('date_default_timezone', 0)), '#options' => $zones, '#description' => t('Select the time zone to (un)publish in.') ); } } } } /** * Implementation of hook_nodeapi(). */ function scheduler_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { if (user_access('schedule (un)publishing of nodes')) { switch ($op) { case 'load': if ($node->nid) { $result = db_query('SELECT * FROM {scheduler} WHERE nid = %d', $node->nid); if ($result && db_num_rows($result) > 0) { $row = db_fetch_array($result); $row['published'] = $row['publish_on'] ? date(variable_get('date_format_long', 'l, F j, Y - H:i'), $row['publish_on']) : NULL; $row['unpublished'] = $row['unpublish_on'] ? date(variable_get('date_format_long', 'l, F j, Y - H:i'), $row['unpublish_on']) : NULL; $node->scheduler = $row; } } break; case 'submit': // right before we save the node, we need to check if a "publish on" value has been set // if it has been set, we want to make sure the node is unpublished // since it will be published at a later date if ($node->publish_on != '') { $node->status = 0; } //adjust the entered times for timezone consideration $node->publish_on = $node->publish_on ? strtotime($node->publish_on) + $node->timezone : NULL; $node->unpublish_on = $node->unpublish_on ? strtotime($node->unpublish_on) + $node->timezone : NULL; break; case 'insert': //only insert into database if we need to (un)publish this node at some date if ($node->publish_on != NULL || $node->unpublish_on != NULL) { db_query('INSERT INTO {scheduler} (nid, publish_on, unpublish_on, timezone) VALUES (%d, %d, %d, %d)', $node->nid, $node->publish_on, $node->unpublish_on, $node->timezone); } break; case 'update': $exists = db_result(db_query('SELECT nid FROM {scheduler} WHERE nid = %d', $node->nid)); //if this node has already been scheduled, update its record if ($exists) { //only update database if we need to (un)publish this node at some date //otherwise the user probably cleared out the (un)publish dates so we should remove the record if ($node->publish_on != NULL || $node->unpublish_on != NULL) { db_query('UPDATE {scheduler} SET publish_on = %d, unpublish_on = %d, timezone = %d WHERE nid = %d', $node->publish_on, $node->unpublish_on, $node->timezone, $node->nid); } else { db_query('DELETE FROM {scheduler} WHERE nid = %d', $node->nid); } } //node doesn't exist, create a record only if the (un)publish fields are blank else if ($node->publish_on != NULL || $node->unpublish_on != NULL) { db_query('INSERT INTO {scheduler} (nid, publish_on, unpublish_on, timezone) VALUES (%d, %d, %d, %d)', $node->nid, $node->publish_on, $node->unpublish_on, $node->timezone); } break; case 'delete': db_query('DELETE FROM {scheduler} WHERE nid = %d', $node->nid); break; } } } /** * Implementation of hook_cron(). */ function scheduler_cron() { $clear_cache = FALSE; //if the time now is greater than the time to publish a node, publish it $nodes = db_query('SELECT *, (publish_on - timezone) AS utc_publish_on FROM {scheduler} s LEFT JOIN {node} n ON s.nid = n.nid WHERE n.status = 0 AND s.publish_on > 0 AND s.publish_on < %d + s.timezone', time()); while ($node = db_fetch_object($nodes)) { $node = node_load($node->nid); $node->changed = $node->utc_publish_on; $node->status = 1; node_save($node); //if this node is not to be unpublished, then we can delete the record if ($node->unpublish_on == 0) { db_query('DELETE FROM {scheduler} WHERE nid = %d', $node->nid); } //we need to unpublish this node at some time so clear the publish on since it's been published else { db_query('UPDATE {scheduler} SET publish_on = 0 WHERE nid = %d', $node->nid); } //invoke scheduler API _scheduler_scheduler_api($node, 'publish'); watchdog('content', t('@type: scheduled publishing of %title.', array('@type' => $node->type, '%title' => $node->title)), WATCHDOG_NOTICE, l(t('view'), 'node/'. $node->nid)); $clear_cache = TRUE; } //if the time is greater than the time to unpublish a node, unpublish it $nodes = db_query('SELECT *, (unpublish_on - timezone) AS utc_unpublish_on FROM {scheduler} s LEFT JOIN {node} n ON s.nid = n.nid WHERE n.status = 1 AND s.unpublish_on > 0 AND s.unpublish_on < %d + s.timezone', time()); while ($node = db_fetch_object($nodes)) { //if this node is to be unpublished, we can update the node and remove the record since it can't be republished $node = node_load($node->nid); $node->changed = $node->utc_publish_on; $node->status = 0; node_save($node); db_query('DELETE FROM {scheduler} WHERE nid = %d', $node->nid); //invoke scheduler API _scheduler_scheduler_api($node, 'unpublish'); watchdog('content', t('@type: scheduled unpublishing of %title.', array('@type' => $node->type, '%title' => $node->title)), WATCHDOG_NOTICE, l(t('view'), 'node/'. $node->nid)); $clear_cache = TRUE; } if ($clear_cache) { // clear the cache so an anonymous poster can see the node being published or unpublished cache_clear_all(); } } function _scheduler_run_cron() { scheduler_cron(); if (ob_get_level() > 0) { ob_clean(); } exit(); } /** * Scheduler API to perform actions when nodes are (un)published * * @param $node * The node object * @param $action * The action being performed, either "publish" or "unpublish" */ function _scheduler_scheduler_api($node, $action) { foreach (module_implements('scheduler_api') as $module) { $function = $module .'_scheduler_api'; $function($node, $action); } } function _scheduler_timecheck() { $now = time(); return theme('scheduler_timecheck', $now); } function theme_scheduler_timecheck($now) { drupal_set_title(t('Scheduler OS time check')); $t = localtime($now, TRUE); $lt = ($t['tm_year']+1900) .'-'. ($t['tm_mon']+1) .'-'. $t['tm_mday'] .' '. $t['tm_hour'] .':'. $t['tm_min'] .':'. $t['tm_sec']; $t_options = array( '%time' => date("Y-m-d H:i:s", $now), '%lt' => $lt, ); return t('Your server reports the UTC time as %time and "localtime" as %lt.', $t_options) . '

'. t('If all is well with your server\'s time configuration UTC should match UTC London Time and the localtime should be the time where you are.') . '

'. t('If this is not the case please have your Unix System Administrator fix your servers time/date configuration.'); } /** * Implementation of hook_form_validate() * Validate the input of the publish and unpublish date fields. Uses the helper function 'timediff_date' (or alternatively 'timediff_timestamp') to make sure that the actual or a future date is entered. */ function _scheduler_form_validate($form_id, $form_values) { $publishtime =''; $unpublishtime = ''; if (is_array($form_values) && isset($form_values['publish_on'])) { $publishtime = strtotime($form_values['publish_on']); $timediff_pub = timediff_date($form_values['publish_on']); if ($publishtime === false) { form_set_error('publish_on', t('The entered publication date is invalid.')); } else if ($timediff_pub < 0) { form_set_error('publish_on', t('The entered publication date occurs in the past.')); } } if (is_array($form_values) && isset($form_values['unpublish_on'])) { $unpublishtime = strtotime($form_values['unpublish_on']); $timediff_unpub = timediff_date($form_values['unpublish_on']); if ($unpublishtime === false) { form_set_error('unpublish_on', t('The entered expiration date is invalid.')); } else if ($timediff_unpub < 0) { form_set_error('unpublish_on', t('The entered expiration date occurs in the past.')); } else if (isset($form_values['publish_on']) && $unpublishtime < $publishtime) { form_set_error('unpublish_on', t('The expiration date can\'t lie ahead of the publication date.')); } } } /** * Function checks the time difference between a specified date to now in days. * @param $date * @return Positive value for number of days in the future, negative value for number of days in the past. * A date in standard english format 'Y-m-d'. */ function timediff_date($date){ $date_diff = round( (strtotime($date)-strtotime(date('Y-m-d'))) / 86400, 0 ); return $date_diff; } /** * Function checks the time difference between a specified timestamp to now in days. * @param $date * @return Positive value for number of days in the future, negative value for number of days in the past. * A timestamp. */ function timediff_timestamp($timestamp){ $date_diff = round( ($timestamp-strtotime(date('Y-m-d'))) / 86400, 0 ); return $date_diff; }