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.