You are here

nd.module in Display Suite 6.3

Node displays.

File

modules/nd/nd.module
View source
<?php

/**
 * @file
 * Node displays.
 */

/**
 * Tell ctools where we keep default plugins
 */
function nd_ctools_plugin_directory($module, $plugin) {
  if ($module == 'ds' && !empty($plugin)) {
    return "plugins/{$plugin}";
  }
}

/**
 * Implementation of hook_init().
 */
function nd_init() {
  drupal_add_css(drupal_get_path('module', 'nd') . '/css/nd_regions.css');
}

/**
 * Implementation of hook_rules_event_info().
 */
function nd_rules_event_info() {
  return array(
    'nd_node_is_build' => array(
      'label' => t('DS has built the node display'),
      'module' => 'nd',
      'arguments' => array(
        'node' => array(
          'type' => 'node',
          'label' => t('Content'),
        ),
      ),
    ),
  );
}

/**
 * Implementation of hook_rules_action_info().
 */
function nd_rules_action_info() {
  return array(
    'nd_rules_disable_fields' => array(
      'label' => t('Do not show a ND field'),
      'arguments' => array(
        'node' => array(
          'type' => 'node',
          'label' => t('Content'),
        ),
      ),
      'module' => 'nd',
    ),
  );
}

/**
 * Implementation of hook_content_build_modes().
 */
function nd_content_build_modes() {
  $build_modes = array(
    'nd' => array(
      'title' => t('Node displays'),
      'build modes' => array(
        'full' => array(
          'title' => t('Full node'),
          'weight' => -1,
        ),
        'teaser' => array(
          'title' => t('Teaser'),
          'weight' => 1,
        ),
        'sticky' => array(
          'title' => t('Sticky'),
          'weight' => 2,
          'views style' => TRUE,
        ),
        NODE_BUILD_RSS => array(
          'title' => t('RSS'),
          'weight' => 3,
        ),
      ),
    ),
  );

  // Also add this here, so other modules (like views_attach)
  // can profit from custom build modes from the UI.
  $db_build_modes = variable_get('nd_build_modes', array());
  foreach ($db_build_modes as $key => $build_mode) {
    $build_modes[$key] = array(
      'title' => $build_mode,
      'build modes' => array(
        $key => array(
          'title' => $build_mode,
          'views style' => TRUE,
        ),
      ),
    );
  }
  return $build_modes;
}

/**
 * Implementation of hook_registry_alter().
 */
function nd_theme_registry_alter(&$registry) {
  $path = drupal_get_path('module', 'nd') . '/templates';
  array_unshift($registry['node']['theme paths'], $path);
}

/**
 * Implementation of hook_nodeapi().
 */
function nd_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  switch ($op) {

    // Add has body property.
    case 'load':
      $node->has_body = node_get_types('type', $node->type)->has_body;
      break;

    // Determine build mode.
    case 'view':
      if ($node->build_mode == NODE_BUILD_RSS) {

        // For the RSS build mode, we need to manipulate right now.
        _nd_nodeapi($node);
      }
      elseif ($node->build_mode == NODE_BUILD_PREVIEW) {
        $node->build_mode = $teaser ? 'teaser' : 'full';

        // Prepare taxonomy
        if (isset($node->taxonomy)) {
          foreach ($node->taxonomy as $tid => $term) {
            if (is_int($tid)) {
              $node->taxonomy[$tid] = db_fetch_object(db_query('SELECT * FROM {term_data} WHERE tid = %d', $tid));
            }
          }
        }
      }
      elseif ($node->build_mode === NODE_BUILD_NORMAL) {
        $build_mode = $teaser ? 'teaser' : 'full';
        $node->build_mode = $build_mode;
      }
      $node->has_body = node_get_types('type', $node->type)->has_body;
      if ($node->has_body == 1 && strlen($node->body) == 0) {
        $node->has_empty_body = 1;
      }
      drupal_alter('nd_build', $node);
      break;

    // Alter the node object for viewing.
    case 'alter':

      // We ignore the RSS build mode, which is handled in the view operation.
      if ($node->build_mode == NODE_BUILD_RSS) {
        return;
      }
      _nd_nodeapi($node);
      break;
  }
}

/**
 *  Implements hook_nd_build_alter
 */
function nd_nd_build_alter(&$node) {

  /**
   * Stickied Teasers
   *
   * Use of sticky as a stand-alone buildmode will be deprecated in 3.x,
   * where it will be replaced with custom variant selection.
   * For the time being, sticky can be ignored by setting
   * $conf['ds_ignore_sticky'] = TRUE
   * in settings.php
   */
  if (variable_get('ds_ignore_sticky', FALSE) != TRUE) {
    if ($node->build_mode == 'teaser' && $node->sticky == 1) {
      $node->build_mode = 'sticky';
    }
  }

  /**
   * Switch buildmode based on query string
   *
   * Build modes can be changed by setting ?build_mode=name in the query
   * string. Becuase this is potentially insecure, developers must enable
   * this for specific build modes by setting which modes allow switching
   * in a variable 'nd_parameter_switch_bm'.
   */
  $parameter_build_modes = variable_get('nd_parameter_switch_bm', array());
  if (isset($_GET['build_mode'])) {
    $switch = check_plain($_GET['build_mode']);
    if (in_array($switch, $parameter_build_modes)) {
      $node->build_mode = $switch;
    }
  }
}

/**
 * Implements hook_preprocess_page()
 */
function nd_preprocess_page(&$vars) {

  /**
   * Unset the node title
   *
   * Display Suite can display the node title where required. The default is to
   * use Drupal's default behaviour, however you may wish to hide the title and
   * let Display Suite take over.
   */
  if (isset($vars['node']) && variable_get('nd_ignore_title_' . $vars['node']->type, FALSE) == TRUE) {
    $vars['title'] = '';
  }
}

/**
 * Helper function to alter node properties
 *
 * @param stdClass $node The complete node object.
 */
function _nd_nodeapi(&$node) {

  // Attach a display to the node object
  ds_attach_display($node);
  $node->ds
    ->prepare($node);

  // Build fields and regions.

  //ds_build_fields_and_regions($node, 'nd');

  // Special support for RSS.
  if ($node->build_mode == NODE_BUILD_RSS && $node->render_by_ds == TRUE) {
    foreach (element_children($node->content) as $key => $field) {
      if (!isset($node->ds_fields[$field])) {
        $node->content[$field]['#access'] = FALSE;
      }
      $node->content[$field]['#weight'] = $node->ds_fields[$field]['weight'];
      unset($node->ds_fields[$field]);
    }
    foreach ($node->ds_fields as $key => $field) {
      $render_key = $key . '_rendered';
      $node->content[$key]['#value'] = theme('ds_field', $node->{$render_key}, $node->ds_fields[$key]);
      $node->content['#content_extra_fields'][$key]['weight'] = $node->ds_fields[$key]['weight'];
    }

    // Body and title are tricky ones since their weights are set
    // in #content_extra_fields, so update the value there!
    $node->content['#content_extra_fields']['body_field']['weight'] = $node->content['body']['#weight'];
    $node->content['#content_extra_fields']['title']['weight'] = $node->content['title']['#weight'];
  }
  if (function_exists('rules_invoke_event')) {
    rules_invoke_event('nd_node_is_build', array(
      'node' => &$node,
    ));
  }
}

/**
 * Implementation of moduleName_preprocess_hook().
 * The node data will be rendered in regions. This uses a helper function
 * so themers/developers can call that helper function from within
 * their preprocess_hooks if they are fiddling with some data. For information
 * about this decision see http://drupal.org/node/570592 (issue) and
 * http://drupal.org/node/572614 for information on howto implement.
 */
function nd_preprocess_node(&$vars, $hook) {
  if (!variable_get('nd_preprocess_override', FALSE)) {
    _nd_preprocess_node($vars, $hook);
  }
}

/**
 * Helper function used in either nd_preprocess_node or other preprocess function.
 */
function _nd_preprocess_node(&$vars, $hook) {
  $node = $vars['node'];

  // Break all the rendering if needed.
  if (!$node->render_by_ds) {
    return;
  }

  // Add nd-content_type-build_mode(-nid) template suggestion.
  $vars['template_files'][] = 'nd';
  $vars['template_files'][] = 'nd-' . $node->type;
  $vars['template_files'][] = 'nd-' . $node->type . '-' . $node->build_mode;
  $vars['template_files'][] = 'nd-' . $node->type . '-' . $node->build_mode . '-' . $node->nid;
  $vars['content'] = $node->ds
    ->render();
}

/**
 * Render the node object through the DS views plugin.
 *
 * @param array $vars The variables to manipulate.
 * @param string $build_mode The build mode to use on this object.
 */
function ds_views_row_node(&$vars, $build_mode) {
  nd_views_node_helper($vars, $build_mode);
}

/**
 * Render the apachesolr object through the DS views plugin.
 *
 * @param array $vars The variables to manipulate.
 * @param string $build_mode The build mode to use on this object.
 */
function ds_views_row_apachesolr(&$vars, $build_mode) {
  nd_views_node_helper($vars, $build_mode);
}

/**
 * Render the apachesolr node object through the DS views plugin.
 *
 * @param array $vars The variables to manipulate.
 * @param string $build_mode The build mode to use on this object.
 */
function ds_views_row_apachesolr_node(&$vars, $build_mode) {
  nd_views_node_helper($vars, $build_mode);
}

/**
 * Helper function for views node plugin.
 */
function nd_views_node_helper(&$vars, $build_mode) {
  $nid = $vars['row']->nid;
  if (!is_numeric($nid)) {
    return;
  }
  if (module_exists('object_cache')) {
    $node = object_cache_get('node', $nid);
  }
  else {
    $node = node_load($nid);
  }
  if (empty($node)) {
    return;
  }
  $node->build_mode = $build_mode;

  // Check the teaser flag and show_links flag.
  $teaser = $node->build_mode != 'full' ? TRUE : FALSE;
  $show_links = ds_show_field('nd', $node->type, $build_mode, 'links');

  // Build object.
  $vars['object'] = node_view($node, $teaser, FALSE, $show_links);
}

/**
 * Implementation of hook_theme().
 */
function nd_theme() {
  $theme_functions = array();

  // Single theming functions.
  $formatters = array(
    'nd_bodyfield',
    'nd_title_h1_nolink',
    'nd_title_h1_link',
    'nd_title_h2_nolink',
    'nd_title_h2_link',
    'nd_title_h2_block_nolink',
    'nd_title_h2_block_link',
    'nd_title_p_nolink',
    'nd_title_p_link',
    'nd_book_add_new_child',
    'nd_book_printer_version',
  );
  foreach ($formatters as $formatter) {
    $theme_functions[$formatter] = array(
      'arguments' => array(
        'node' => NULL,
      ),
    );
  }

  // Post date with Date API.
  if (variable_get('nd_use_date_api', TRUE)) {
    if (module_exists('date_api')) {
      $date_formats = date_get_format_types('', TRUE);
    }
    else {
      $date_formats = array(
        'small' => array(
          'title' => 'Small',
          'type' => 'small',
        ),
        'medium' => array(
          'title' => 'Medium',
          'type' => 'medium',
        ),
        'large' => array(
          'title' => 'Large',
          'type' => 'large',
        ),
      );
    }
    foreach ($date_formats as $formatter) {
      $theme_functions['nd_post_date_' . $formatter['type']] = array(
        'arguments' => array(
          'node' => NULL,
        ),
        'function' => 'theme_nd_post_date',
      );
    }
  }

  // Vocabulary.
  $vocab_formatters = array(
    'nd_terms_per_vocabulary_space',
    'nd_terms_per_vocabulary_linked_space',
    'nd_terms_per_vocabulary_comma',
    'nd_terms_per_vocabulary_linked_comma',
    'nd_terms_per_vocabulary_list',
    'nd_terms_per_vocabulary_linked_list',
  );
  foreach ($vocab_formatters as $formatter) {
    $theme_functions[$formatter] = array(
      'arguments' => array(
        'node' => NULL,
      ),
      'function' => 'nd_terms_per_vocabulary',
    );
  }
  return $theme_functions;
}

/**
 * Implementation of hook_ds_fields().
 */
function nd_ds_fields($type_name, $build_mode, $extra) {
  $fields = array(
    'title' => array(
      'title' => t('Title'),
      'type' => DS_FIELD_TYPE_THEME,
      'status' => DS_FIELD_STATUS_STATIC,
      'allow_formatters' => TRUE,
      'properties' => array(
        'formatters' => array(
          'nd_title_h1_nolink' => t('H1 title'),
          'nd_title_h1_link' => t('H1 title, linked to node'),
          'nd_title_h2_nolink' => t('H2 title'),
          'nd_title_h2_link' => t('H2 title, linked to node'),
          'nd_title_h2_block_nolink' => t('H2 block title'),
          'nd_title_h2_block_link' => t('H2 block title, linked to node'),
          'nd_title_p_nolink' => t('Paragraph title'),
          'nd_title_p_link' => t('Paragraph title, linked to node'),
        ),
      ),
    ),
    'author' => array(
      'title' => t('Author'),
      'type' => DS_FIELD_TYPE_THEME,
      'status' => DS_FIELD_STATUS_STATIC,
      'properties' => array(
        'formatters' => array(
          'ds_author_nolink' => t('Author'),
          'ds_author_link' => t('Author linked to profile'),
        ),
      ),
    ),
    'links' => array(
      'title' => t('Links'),
      'type' => DS_FIELD_TYPE_PREPROCESS,
      'status' => DS_FIELD_STATUS_STATIC,
    ),
    'read_more' => array(
      'title' => t('Read more'),
      'type' => DS_FIELD_TYPE_CODE,
      'status' => DS_FIELD_STATUS_DEFAULT,
      'properties' => array(
        'formatters' => array(
          'ds_eval_code' => t('Default'),
        ),
        'code' => '<?php echo l(t("Read more"), "node/$object->nid"); ?>',
      ),
    ),
  );

  // Updated and posted date formatters
  if (module_exists('date_api')) {
    $date_formats = date_get_format_types('', FALSE);
  }
  else {
    $date_formats = array(
      'small' => array(
        'title' => 'Small',
        'type' => 'small',
      ),
      'medium' => array(
        'title' => 'Medium',
        'type' => 'medium',
      ),
      'large' => array(
        'title' => 'Large',
        'type' => 'large',
      ),
    );
  }
  $date_formatters = array();
  foreach ($date_formats as $formatter) {
    $date_formatters['nd_post_date_' . $formatter['type']] = t($formatter['title']);
  }

  // Regression. People upgrading from 6.x-2.2 to 6.x-2.3 will lose
  // the post date PHP code field, we can't do that by default. The
  // update_2 will make the nd_use_date_api variable false, and
  // developers can set this variable to 1 in the variable table.
  if (variable_get('nd_use_date_api', TRUE)) {
    $fields['post_date'] = array(
      'title' => t('Post date'),
      'type' => DS_FIELD_TYPE_THEME,
      'status' => DS_FIELD_STATUS_STATIC,
      'properties' => array(
        'formatters' => $date_formatters,
      ),
    );
  }
  else {
    $fields['post_date'] = array(
      'title' => t('Post date'),
      'type' => DS_FIELD_TYPE_CODE,
      'status' => DS_FIELD_STATUS_DEFAULT,
      'properties' => array(
        'formatters' => array(
          'ds_eval_code' => t('Default'),
        ),
        'code' => '<?php echo format_date($object->created, "custom", "d/m/Y"); ?>',
      ),
    );
  }
  $fields['updated_date'] = array(
    'title' => t('Last updated date'),
    'type' => DS_FIELD_TYPE_THEME,
    'status' => DS_FIELD_STATUS_STATIC,
    'properties' => array(
      'formatters' => $date_formatters,
    ),
  );

  // Check for body.
  if (isset($extra['has_body']) && $extra['has_body'] == TRUE) {
    $fields['body'] = array(
      'title' => t('Body'),
      'type' => DS_FIELD_TYPE_THEME,
      'status' => DS_FIELD_STATUS_STATIC,
      'allow_formatters' => TRUE,
      'properties' => array(
        'formatters' => array(
          'nd_bodyfield' => t('Default'),
        ),
      ),
    );
  }

  // Taxonomy support.
  if (module_exists('taxonomy')) {
    $all = FALSE;

    // All vocabularies per content type.
    // We can't use taxonomy_get_vocabularies() here, see http://drupal.org/node/810352.
    $result = db_query("SELECT v.vid, v.*, n.type FROM {vocabulary} v LEFT JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", $type_name);
    while ($vocabulary = db_fetch_object($result)) {
      $all = TRUE;
      $fields['terms_' . $vocabulary->vid] = array(
        'title' => t('Taxonomy: @vocab', array(
          '@vocab' => $vocabulary->name,
        )),
        'type' => DS_FIELD_TYPE_THEME,
        'status' => DS_FIELD_STATUS_STATIC,
        'properties' => array(
          'css-class' => 'field-terms field-terms-' . $vocabulary->vid,
          'formatters' => array(
            'nd_terms_per_vocabulary_space' => t('Separated by space'),
            'nd_terms_per_vocabulary_linked_space' => t('Separated by space, linked to term'),
            'nd_terms_per_vocabulary_comma' => t('Separated by comma'),
            'nd_terms_per_vocabulary_linked_comma' => t('Separated by comma, linked to term'),
            'nd_terms_per_vocabulary_list' => t('Unordered list'),
            'nd_terms_per_vocabulary_linked_list' => t('Unordered list, linked to term'),
          ),
        ),
      );
    }
    if ($all) {

      // All terms.
      $fields['terms'] = array(
        'title' => t('Taxonomy: all terms'),
        'type' => DS_FIELD_TYPE_PREPROCESS,
        'status' => DS_FIELD_STATUS_STATIC,
      );
    }
  }

  // Upload support.
  if (module_exists('upload') && $build_mode != 'teaser' && variable_get("upload_{$type_name}", 1)) {
    $fields['files'] = array(
      'title' => t('Core upload'),
      'type' => DS_FIELD_TYPE_IGNORE,
      'status' => DS_FIELD_STATUS_STATIC,
    );
  }

  // Book support.
  if (module_exists('book') && book_type_is_allowed($type_name)) {
    $fields['book_navigation'] = array(
      'title' => t('Book navigation'),
      'type' => DS_FIELD_TYPE_FUNCTION,
      'status' => DS_FIELD_STATUS_STATIC,
      'properties' => array(
        'formatters' => array(
          'nd_book_navigation' => t('Book navigation'),
        ),
      ),
    );
    $fields['book_add_new_child'] = array(
      'title' => t('Book: add new child'),
      'type' => DS_FIELD_TYPE_THEME,
      'status' => DS_FIELD_STATUS_STATIC,
      'properties' => array(
        'formatters' => array(
          'nd_book_add_new_child' => t('Add new child'),
        ),
      ),
    );
    $fields['book_printer_version'] = array(
      'title' => t('Book: printer version'),
      'type' => DS_FIELD_TYPE_THEME,
      'status' => DS_FIELD_STATUS_STATIC,
      'properties' => array(
        'formatters' => array(
          'nd_book_printer_version' => t('Printer version'),
        ),
      ),
    );
  }
  return array(
    'nd' => $fields,
  );
}

/**
 * ND theming functions.
 */
function theme_nd_bodyfield($field) {
  return $field['object']->content['body']['#value'];
}
function theme_nd_title_h1_nolink($field) {
  return '<h1>' . check_plain($field['object']->title) . '</h1>';
}
function theme_nd_title_h1_link($field) {
  return '<h1>' . l($field['object']->title, 'node/' . $field['object']->nid) . '</h1>';
}
function theme_nd_title_h2_nolink($field) {
  return '<h2>' . check_plain($field['object']->title) . '</h2>';
}
function theme_nd_title_h2_link($field) {
  return '<h2>' . l($field['object']->title, 'node/' . $field['object']->nid) . '</h2>';
}
function theme_nd_title_h2_block_nolink($field) {
  return '<h2 class="block-title">' . check_plain($field['object']->title) . '</h2>';
}
function theme_nd_title_h2_block_link($field) {
  return '<h2 class="block-title">' . l($field['object']->title, 'node/' . $field['object']->nid) . '</h2>';
}
function theme_nd_title_p_nolink($field) {
  return '<p>' . check_plain($field['object']->title) . '</p>';
}
function theme_nd_title_p_link($field) {
  return '<p>' . l($field['object']->title, 'node/' . $field['object']->nid) . '</p>';
}

/**
 *  Post date formatter.
 */
function theme_nd_post_date($field) {
  $date_format = str_replace('nd_post_date_', '', $field['formatter']);
  if (module_exists('date_api')) {
    $datetime = date_make_date($field['object']->created, NULL, DATE_UNIX);
    $format = variable_get('date_format_' . $date_format, 'd/m/Y');
    return date_format_date($datetime, 'custom', $format);
  }
  else {
    return format_date($field['object']->created, $date_format);
  }
}

/**
 * Terms per vocabulary.
 */
function nd_terms_per_vocabulary($field) {
  $content = '';
  if (isset($field['object']->taxonomy) && !empty($field['object']->taxonomy)) {
    $terms = array();
    $linked = FALSE;
    $vid = end(explode('_', $field['key']));
    $formatter_explode = explode('_', $field['formatter']);
    $separators = array(
      'space' => ' ',
      'comma' => ', ',
    );
    $separator = $separators[end($formatter_explode)];
    $list = end($formatter_explode) == 'list' ? TRUE : FALSE;
    $linked = prev($formatter_explode);
    foreach ($field['object']->taxonomy as $tid => $term) {
      if ($term->vid == $vid) {
        $terms[] = $linked == 'linked' ? l($term->name, taxonomy_term_path($term)) : check_plain($term->name);
      }
    }
    if (!empty($terms)) {
      if ($separator) {
        $content = implode($separator, $terms);
      }
      elseif ($list) {
        $content = theme('item_list', $terms);
      }
    }
  }
  return $content;
}

/**
 * Book navigation theming.
 */
function nd_book_navigation($field) {
  $content = '';
  if (isset($field['object']->content['book_navigation'])) {
    if (isset($field['object']->content['book_navigation']['#value'])) {
      $content = $field['object']->content['book_navigation']['#value'];
    }
    elseif (isset($field['object']->book['bid']) && !empty($field['object']->book['bid'])) {
      $content = theme('book_navigation', $field['object']->book);
    }
  }
  else {
    if (isset($field['object']->book['bid']) && !empty($field['object']->book['bid'])) {
      $content = theme('book_navigation', $field['object']->book);
    }
  }
  return $content;
}

/**
 * Add new child for book.
 */
function theme_nd_book_add_new_child($field) {
  if (user_access('add content to books')) {
    $child = str_replace('_', '-', variable_get('book_child_type', 'book'));
    return l(t('Add child page'), 'node/add/' . $child, array(
      'query' => array(
        'parent' => $field['object']->book['mlid'],
      ),
    ));
  }
}

/**
 * Printer friendly version
 */
function theme_nd_book_printer_version($field) {
  return l(t('Printer-friendly version'), 'book/export/html/' . $field['object']->nid);
}

Functions

Namesort descending Description
ds_views_row_apachesolr Render the apachesolr object through the DS views plugin.
ds_views_row_apachesolr_node Render the apachesolr node object through the DS views plugin.
ds_views_row_node Render the node object through the DS views plugin.
nd_book_navigation Book navigation theming.
nd_content_build_modes Implementation of hook_content_build_modes().
nd_ctools_plugin_directory Tell ctools where we keep default plugins
nd_ds_fields Implementation of hook_ds_fields().
nd_init Implementation of hook_init().
nd_nd_build_alter Implements hook_nd_build_alter
nd_nodeapi Implementation of hook_nodeapi().
nd_preprocess_node Implementation of moduleName_preprocess_hook(). The node data will be rendered in regions. This uses a helper function so themers/developers can call that helper function from within their preprocess_hooks if they are fiddling with some data. For…
nd_preprocess_page Implements hook_preprocess_page()
nd_rules_action_info Implementation of hook_rules_action_info().
nd_rules_event_info Implementation of hook_rules_event_info().
nd_terms_per_vocabulary Terms per vocabulary.
nd_theme Implementation of hook_theme().
nd_theme_registry_alter Implementation of hook_registry_alter().
nd_views_node_helper Helper function for views node plugin.
theme_nd_bodyfield ND theming functions.
theme_nd_book_add_new_child Add new child for book.
theme_nd_book_printer_version Printer friendly version
theme_nd_post_date Post date formatter.
theme_nd_title_h1_link
theme_nd_title_h1_nolink
theme_nd_title_h2_block_link
theme_nd_title_h2_block_nolink
theme_nd_title_h2_link
theme_nd_title_h2_nolink
theme_nd_title_p_link
theme_nd_title_p_nolink
_nd_nodeapi Helper function to alter node properties
_nd_preprocess_node Helper function used in either nd_preprocess_node or other preprocess function.