By tanc


2013-03-09 08:47:44 8 Comments

I'm writing a fairly simple module which allows the removal of colons from field output on a per field basis and I need to override the core field module's theme_field function in my module.

I can modify the theme registry with hook_theme_registry_alter() and change the field function to point to my custom function. Unfortunately once I do that I'm no longer able to override field.tpl.php in a theme.

The cascade I'd like to achieve is in order of template preference (most important first):

  1. Active theme's field.tpl.php
  2. My custom module's field.tpl.php (or custom_field theme function)
  3. Field module's theme_field function

Is this possible?

This answer comes close but requires a differently named template which I don't want. I'd like to keep things clean for the themer so if they override field.tpl.php in their theme the output is as expected, rather than having to copy a different tpl file from my custom module.

2 comments

@donquixote 2018-12-29 15:37:38

There are multiple ways to achieve this. I am just going to post from the top of my head.

Replacing the theme function

I can modify the theme registry with hook_theme_registry_alter() and change the field function to point to my custom function. Unfortunately once I do that I'm no longer able to override field.tpl.php in a theme.

You can use hook_theme_registry_alter() for this. You just need to make it conditional. Something like this:

function mymodule_theme_registry_alter(&$registry) {
  if (!isset($registry['field'])) {
    // Perhaps field module is not even enabled, or something else is wrong.
    return;
  }
  if (!isset($registry['field']['function'])
    || 'theme_field' !== $registry['field']['function']
    || isset($registry['field']['template']
  ) {
    // Apparently a theme has overridden the theme hook.
    return;
  }
  // Override with custom module-based template.
  $registry['field']['template'] = ...
}

This has a limitation if other modules or the theme itself also use hook_theme_registry_alter() to modify the same hook. But otherwise it should be ok.

You need to experiment a bit with the code above, I wrote this without any testing. Let me know if something can be corrected.

About the "cascade"

Some additional explanation.

The cascade I'd like to achieve is in order of template preference (most important first):

  • Active theme's field.tpl.php
  • My custom module's field.tpl.php (or custom_field theme function)
  • Field module's theme_field function

The good thing is that this cascade is rather "fixed". The theme registry is stored and calculated per theme, and within a theme the cascade always has the same outcome. The theme template either exists or not. The template in your custom module always exists. So the "Field module's theme_field function" is completely out of the picture.

It gets a bit more complicated if we are dealing with theme overrides like field--body.tpl.php, but we don't need to go into his territory here I think.

Alternative: Display suite field templates

I'm writing a fairly simple module which allows the removal of colons from field output on a per field basis and I need to override the core field module's theme_field function in my module.

I should point out that alternatives exist to what you attempt to achieve.

Display suite is an excellent module which provides settings for how a field should be rendered. Especially, if you enable ds_extras, go to admin/structure/ds/list/extras, and enable "Field Templates". This is a very powerful tool worth learning more about.

Renderkit has "field display processor" plugins, but this goes far beyond what you probably need.

@tko 2013-03-09 20:07:11

Think what you describe could work without falling back to the field module's function:

  1. Add <?php function MODULENAME_preprocess_field($variables) ?> and set a $colon variable with either ':' or ''
  2. Copy the theme_field function in your module and rename it <?php MODULENAME_field(&$variables) ?>
  3. Replace the code that renders the label with: <?php $output .= '<div class="field-label"' . $variables['title_attributes'] . '>' . $variables['label'] . $variables['colon'] . '&nbsp;</div>';?>

Might also just document for themers that in the template file they should use $colon for the module to work.

Related Questions

Sponsored Content

1 Answered Questions

[SOLVED] how to override module's theme function in a custom module?

  • 2019-01-08 07:34:09
  • richardson
  • 66 View
  • 0 Score
  • 1 Answer
  • Tags:   8 theming

1 Answered Questions

[SOLVED] How to get the correct 'base hook' to override a template file in a custom module?

  • 2018-12-02 06:05:35
  • Prestosaurus
  • 351 View
  • 1 Score
  • 1 Answer
  • Tags:   8 theming hooks

1 Answered Questions

[SOLVED] Is it possible to call a custom module function in the theme template file?

  • 2016-11-23 14:30:53
  • codestings
  • 1626 View
  • 2 Score
  • 1 Answer
  • Tags:   7 theming hooks

1 Answered Questions

[SOLVED] Getting the available template variables in a custom module

1 Answered Questions

1 Answered Questions

1 Answered Questions

[SOLVED] how can I override theme_image() on a custom node template, only

  • 2014-05-28 01:33:13
  • TopTomato
  • 166 View
  • 0 Score
  • 1 Answer
  • Tags:   7 theming

2 Answered Questions

[SOLVED] How to wrap field out put in custom markup?

  • 2014-11-15 13:44:15
  • josephleon
  • 824 View
  • 3 Score
  • 2 Answer
  • Tags:   7 hooks

1 Answered Questions

Sponsored Content