Skip to main content

Creating custom display suite fields or how I learned to stop worrying and use hook_ds_fields_info()

Display Suite is one of those modules that should exist in every themer's toolkit. It gives us tremendous power to get away from template files and assign layouts for just about anything via a UI. It also provides a lovely little hook that makes it very easy to add custom fields via a module.

by jack.taranto /

hook_ds_fields_info() lets you define a variety of different fields that are available to be placed via the manage display screens for all entity types. This is useful for a variety of cases: say you have a footnote that you need to add to all articles, or you may want to repeat the article's published date somewhere within it's display. Display Suite makes this easy, and allows you to keep it in code via this handy hook.

Our first example will show a field declaration for a function field that's going to print some static text. This hook is often best implemented inside the feature which contains the content type or entity that you are adding the fields to.

/**
 * Implements hook_ds_fields_info().
 */
function article_ds_fields_info($entity_type) {
  $fields = array();

  $fields['node']['article_footnote'] = array(
    'title' => t('Article footnote'),
    'field_type' => DS_FIELD_TYPE_FUNCTION,
    'function' => 'article_ds_field_article_footnote',
  );

  if (isset($fields[$entity_type])) {
    return array($entity_type => $fields[$entity_type]);
  }
  return;
}

Above I have setup the article_footnote field for node entities with a readable title and the field type of DS_FIELD_TYPE_FUNCTION which lets us define a custom function to provide the output for the field. The last few lines of the hook will allow us to specify fields for different entity types through the same function. That's enough to get us started. All we need to do now is provide the function which will return the fields output.

/**
 * Render the article footnote field.
 */
function article_ds_field_article_footnote($field) {
  $content = 'All articles are composed in a permanent state of coffee frenzy.';
  return $content;
}

By using simple functions like this we can print any custom output we like and place it into a display.

Lets step it up a notch and print out some node data. I'll start by declaring another field via our field info hook:

  $fields['node']['article_date_2'] = array(
    'title' => t('Article date 2'),
    'field_type' => DS_FIELD_TYPE_FUNCTION,
    'function' => 'article_ds_field_article_date_2',
  );

Keeping it simple for now, below you can see how we're able to access the node (or entity) object via the $field array.

/**
 * Render the article's created date.
 */ function article_ds_field_article_date_2($field, $title = NULL) {
  $date = $field['entity']->created;
  return format_date($date,'medium');
}

Static fields are nice and simple, but a little configuration never hurt anyone, lets add Drupal's default date format's as formatter options to our field declaration:

  $fields['node']['article_date_2'] = array(
    'title' => t('Article date 2'),
    'field_type' => DS_FIELD_TYPE_FUNCTION,
    'function' => 'article_ds_field_article_date_2',
    'properties' => array(
      'formatters' => array(
        'article_date_short' => t('Short'),
        'article_date_medium' => t('Medium'),
        'article_date_long' => t('Long'),
      ),
    ),
  );

Now our field will have some formatter options. We can then rework our function slightly so it's taking the value of the selected formatter to render the date field:

function article_ds_field_article_date_2($field, $title = NULL) {
  $date_format = str_replace('article_date_', '', $field['formatter']);
  $date = $field['entity']->created;
  return format_date($date,$date_format);
}

Seeing as we are able to specify our own values for the formatters, we can use this to create multiple different outputs for our field's function using if statements. Like below:

function article_ds_field_article_footnote($field, $title = NULL) {
  if ($field['formatter']=='article_footnote_short_version') {
    $content = 'We love coffee!';
  }
  elseif ($field['formatter']=='article_footnote_long_version') {
    $content = 'All articles are composed in a state of permanent coffee frenzy.';
  }
  return $content;
}

To take this a step further and add a little more customisation for the manage display screens, we can add settings forms for our field. First we need to define the settings inside our field declaration:

  $fields['node']['article_date_2'] = array(
    'title' => t('Article date'),
    'field_type' => DS_FIELD_TYPE_FUNCTION,
    'function' => 'article_ds_field_article_date_2',
    'properties' => array(
      'formatters' => array(
        'article_date_short' => t('Short'),
        'article_date_medium' => t('Medium'),
        'article_date_long' => t('Long'),
        'article_date_custom' => t('Custom'),
      ),
      'settings' => array(
        'custom_date_format' => array(
          'type' => 'textfield',
          'description' => t('Specify a custom format to display the date')
        ),
      ),
      'default' => array(
        'custom_date_format' => 'j F Y',
      ),
    ),
  );

You'll see I have defined a settings & default key which hold information about the field type, a description & default values for the form. Sadly that's not quite enough though. We also need to implement two additional hooks: hook_ds_field_settings_form() & hook_ds_field_format_summary(). These will define the settings form & the summary information that's shown. Fortunately however the creators of Display Suite have already written these for us inside ds.field_ui.inc so all we need to do is call them from within our module:

/**
 * Implements hook_ds_field_settings_form().
 */
function article_ds_field_settings_form($field) {
  return ds_ds_field_settings_form($field);
}

/**
 * Implements hook_ds_field_format_summary().
 */
function article_ds_field_format_summary($field) {
  return ds_ds_field_format_summary($field);
}

And just a quick modification to the function thats printing the date:

function mymodule_ds_field_article_date($field) {
  $custom_format = '';
  if ($field['formatter']=='article_date_custom') {
    $date_format = 'custom';
    $custom_format = $field['formatter_settings']['custom_date_format'];
  }
  else {
    $date_format = str_replace('article_date_', '', $field['formatter']);
  }
  $date = $field['entity']->created;
  return format_date($date,$date_format,$custom_format);
}

Now, if the date's format is set to "Custom", the settings form value will be used to format the date.

The examples shown here can be built upon to create a host of field options from within display suite that are configurable via the UI. For further reading, the files within the Display Suite module itself are an excellent resource. Check out ds.api.php for a detailed explanation of the above hooks, and see ds.ds_fields_info.inc for numerous examples of field declarations.