chacadwa.com

Technical blog and writings by Micah Webner.

Adding fake Drupal 7 node fields with custom theme functions

This example takes the node creation date and renders it as a fake field. It also creates a theme_mysite_pseudo_field() function that could be used as a template for any renderable array.

For our example, our content type is podcast, and we want to add a pseudo-field called mysite_podcast_date. This is a pretty standard implementation of hook_node_view(), but we're going to specify our mysite_pseudo_field theme wrapper and specify that we want our label to be inline. This adds our fake field to our node's output.

/**
 * Implements hook_node_view().
 */

function mysite_node_view($node, $view_mode, $langcode) {
  switch ($node->type) {
    case 'podcast':
      $node->content['mysite_podcast_date'] = array(
        '#type' => 'item',
        '#field_name' => 'mysite_podcast_date',
        '#label' => t('Date:'),
        '#markup' => format_date($node->created, 'custom', 'l, F j, Y'),
        '#theme_wrappers' => array('mysite_pseudo_field'),
        '#label_display' => 'inline',
      );
      break;
  }
}

Next we want to add our field to hook_field_extra_fields(). This allows us to include our field in the manage fields display for our content type.

Note: While writing this, I've noticed that I hard-coded the #label_display in hook_node_view() above, and it cannot be set in the site's UI. I can't recall the details behind that, but I think it's related to #1471706 which is an open issue for Drupal 8 core.

/**
 * Implements hook_field_extra_fields().
 */

function mysite_field_extra_fields() {
  $extra['node']['podcast']['display'] = array(
    'mysite_podcast_date' => array(
      'label' => t('Sermon Date'),
      'description' => t('Display the node date like a field.'),
      'weight' => 0,
    ),
  );
  return $extra;
}

Now we invoke hook_theme() to add information about the mysite_pseudo_field theme wrapper.

Note: This is a fairly simple example using a theme function. Here's a better example that uses a template file and a template_preprocess() function.

/**
 * Implements hook_theme().
 */

function mysite_theme() {
  return array(
    'mysite_pseudo_field' => array(
      'render element' => 'element',
    ),
  );
}

Finally, we create our theme function, which more closely emulates Field API output than anything I've found (other than forging enough settings to use the actual field theming functions.)

/**
 * Theme output of a pseudo_field.
 *
 * @see http://drupal.org/node/1471706
 */

function theme_mysite_pseudo_field($variables) {
  $classes = array('clearfix', 'field');

  if (isset($variables['element']['#field_name'])) {
    $classes[] = 'field-name-' . strtr($variables['element']['#field_name'], '_', '-');
  }

  if (isset($variables['element']['#label_display'])) {
    $classes[] = 'field-label-' . $variables['element']['#label_display'];
  }

  $output = '<div class="' . implode(' ', $classes) . '">';
  if (isset($variables['element']['#title'])) {
    $output .= '<div class="field-label">' . $variables['element']['#title'] . '&nbsp;</div>';
  }
  $output .= '<div class="field-items">' . $variables['element']['#markup'] . '</div>';
  $output .= '</div>';
  return $output;
}

Acknowledgement

I combined several resources to figure this out. I learned about hook_node_view() from ComputerMinds: Add stuff to a node and configure it like fields.

Updates

  • April 24, 2013: Improved theme_mysite_pseudo_field() to add support for #field_name and streamline handling of #label_display, based on project collaboration with Donald Dille.
  • June 4, 2013: This commit on one of my current projects includes a template preprocess function and uses an external template file to generate the HTML for theming fake fields.
Topics: