diff --git a/scheduler.cron.inc b/scheduler.cron.inc
index 511e979..e5a19dc 100644
--- a/scheduler.cron.inc
+++ b/scheduler.cron.inc
@@ -35,8 +35,26 @@ function _scheduler_publish() {
   // Allow other modules to alter the list of nodes to be published.
   \Drupal::moduleHandler()->alter('scheduler_nid_list', $nids, $action);
 
+  $logger = \Drupal::logger('scheduler');
   $nodes = Node::loadMultiple($nids);
   foreach ($nodes as $nid => $node) {
+    $view_link = $node->link(t('View node'));
+    $nodetype_url = Url::fromRoute('entity.node_type.edit_form', array('node_type' => $node->getType()));
+    $nodetype_link = \Drupal::l(t('Settings'), $nodetype_url);
+    $logger_variables = array(
+      '@type' => $node->getType(),
+      '%title' => $node->getTitle(),
+      '%field' => $node->publish_on->label, // @todo this does not work. How to get the label text?
+      'link' => $nodetype_link . ' ' . $view_link,
+    );
+
+    // The above query and api calls can return nodes of types which are not
+    // enabled for this scheduler action. Do not process these.
+    if (!$node->type->entity->getThirdPartySetting('scheduler', $action . '_enable', FALSE)) {
+      $logger->warning('"%title" not published because @type node type is not enabled for Scheduler', $logger_variables);
+      continue;
+    }
+
     // Check that other modules allow the action on this node.
     if (!_scheduler_allow($node, $action)) {
       continue;
@@ -46,6 +64,13 @@ function _scheduler_publish() {
     // @todo For D8 move the 'pre' call to here.
     // See https://www.drupal.org/node/2311273
 
+    // Ensure we have a valid date to avoid a cron crash if third-party modules
+    // have altered the node list or node data via the API calls above.
+    if (empty($node->publish_on->value)) {
+      $logger->error('@type "%title" not published because %field field has no value', $logger_variables);
+      continue;
+    }
+
     // Update timestamps.
     $publish_on = $node->publish_on->value;
     $node->set('changed', $publish_on);
@@ -64,7 +89,7 @@ function _scheduler_publish() {
       ));
     }
     // Unset publish_on so the node will not get rescheduled by subsequent calls
-    // to $node->save(). Save the value for use when calling Rules.
+    // to $node->save().
     $node->publish_on->value = NULL;
 
     // Invoke scheduler API to allow modules to alter the node before it is
@@ -73,8 +98,7 @@ function _scheduler_publish() {
     _scheduler_scheduler_api($node, 'pre_' . $action);
 
     // Log the fact that a scheduled publication is about to take place.
-    $view_link = $node->link(t('View'));
-    \Drupal::logger('scheduler')->notice('@type: scheduled publishing of %title.', array('@type' => $node->getType(), '%title' => $node->getTitle(), 'link' => $view_link));
+    $logger->notice('@type: scheduled publishing of %title.', $logger_variables);
 
     // Use the actions system to publish the node.
     \Drupal::entityManager()->getStorage('action')->load('node_publish_action')->getPlugin()->execute($node);
@@ -117,8 +141,26 @@ function _scheduler_unpublish() {
   // Allow other modules to alter the list of nodes to be unpublished.
   \Drupal::moduleHandler()->alter('scheduler_nid_list', $nids, $action);
 
+  $logger = \Drupal::logger('scheduler');
   $nodes = Node::loadMultiple($nids);
   foreach ($nodes as $nid => $node) {
+    $view_link = $node->link(t('View node'));
+    $nodetype_url = Url::fromRoute('entity.node_type.edit_form', array('node_type' => $node->getType()));
+    $nodetype_link = \Drupal::l(t('Settings'), $nodetype_url);
+    $logger_variables = array(
+      '@type' => $node->getType(),
+      '%title' => $node->getTitle(),
+      '%field' => $node->unpublish_on->label,
+      'link' => $nodetype_link . ' ' . $view_link,
+    );
+
+    // The above query and api calls can return nodes of types which are not
+    // enabled for this scheduler action. Do not process these.
+    if (!$node->type->entity->getThirdPartySetting('scheduler', $action . '_enable', FALSE)) {
+      $logger->warning('"%title" not unpublished because @type node type is not enabled for Scheduler', $logger_variables);
+      continue;
+    }
+
     // Check that other modules allow the action on this node.
     if (!_scheduler_allow($node, $action)) {
       continue;
@@ -136,6 +178,13 @@ function _scheduler_unpublish() {
     // @todo For D8, move the 'pre' call to here.
     // See https://www.drupal.org/node/2311273
 
+    // Ensure we have a valid date to avoid cron crash if third-party modules
+    // have altered the node list or node data via the API calls above.
+    if (empty($node->unpublish_on->value)) {
+      $logger->error('@type "%title" not unpublished because %field field has no value', $logger_variables);
+      continue;
+    }
+
     // Update timestamps.
     $old_change_date = $node->getChangedTime();
     $unpublish_on = $node->unpublish_on->value;
@@ -160,8 +209,7 @@ function _scheduler_unpublish() {
     _scheduler_scheduler_api($node, 'pre_' . $action);
 
     // Log the fact that a scheduled unpublication is about to take place.
-    $view_link = $node->link(t('View'));
-    \Drupal::logger('scheduler')->notice('@type: scheduled unpublishing of %title.', array('@type' => $node->getType(), '%title' => $node->getTitle(), 'link' => $view_link));
+    $logger->notice('@type: scheduled unpublishing of %title.', $logger_variables);
 
     // Use the actions system to publish the node.
     \Drupal::entityManager()->getStorage('action')->load('node_unpublish_action')->getPlugin()->execute($node);
