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.

Posted by jack.taranto
Front end developer

Dated

Comments

Comment by Dian

Dated

Hi thanks for the post. I used the loop you dbsrcieed to get my FIELD_ID values, but when I try echo $row->{$view->field['field_product_short_desc']->field_alias};it just returns 1 , same with all the other fields.Do you know what might be up? Using D7 and views 3

Comment by jack.taranto

Dated

@Dian this post is specifically for adding custom fields to your node's "manage display" page, and doesn't relate back to views at all. I'm not sure which loop you are describing though?

Comment by Anonymous

Dated

Thanks Jack for these examples. They are handy!

Comment by Martin

Dated

Thanks for the example.

I'm trying to figure if it's possible to use standards formatters.

I use you first example with the footnote and I add formatters:

'properties' => array(
'formatters' => array(
'text_default' => t('Default'),
'text_plain' => t('Plain text'),
'text_trimmed' => t('Trimmed'),
),
),

The formatters are available within the UI but not their options. If I use Trimmed on a regular field, I have acces to the settings for defining the trim length. But with the "footnote" field, I do not have these options.

I want also to be able to use this technique to have an image field to have all options available. Image format with its settings (style and other), colorbox or any image formatter.

Is there a way?

Comment by jack.taranto

Dated

Hey Martin - take a look inside ds.ds_fields_info.inc that's inside the ds module. It has a tonne of examples of how to implement various formatting options, including image formatters.

Basically - the 'formatters' array is only used to pass values to your fields function - that you can access with $field['formatter'] - so you can manually adjust the display of your field.

Comment by nicky

Dated

Hi jack, great write up! But could you tell me the difference/advantages of using hook_ds_fields_info over hook_field_extra_fields?

Comment by jack.taranto

Dated

One is for Display suite, the other for Drupal core. The DS hook is a fair bit more powerful as well. Check the docs inside the ds api file to see everything it can do.

Comment by max

Dated

I guess one thing worse mentioning is, you need to enable a layout under manage display (at the bottom) in order to get your custom display suite fields to show up.

Comment by Fred

Dated

Hey there, great article thanks!

Has anyone else noticed that in the settings form if you save it with an empty string in there (or have an empty string as the default) the settings form will no longer show? Is there a way to get around this that anyone knows of?

Comment by Kyle

Dated

I have to say, this is a very thorough article on custom DS fields. Thanks so much!

Comment by Juho

Dated

This was some awesome sauce! Thanks man!

Comment by Selinav

Dated

Thanks for this great article.

How can we do to get value of an existing field ?

For example, I have a content type "product" with a file field "pdf file". I'd like to do a download button.

function cfds_ds_field_download($field) {
$path=?? //token or other to get the path of my file field
$text=t("Download");
$content = l($text, $path, array $options = array());
return $content;
}

Thank you for you help

Comment by kopeboy

Dated

How to render the author of the node with a custom view mode (defined from the UI)? Thanks..

Pagination