I created a feature module containing only a view and a content type.
Right now my page-node-x.tpl.php
and my views-view-y.tpl.php
files lie in my themes directory.
Is it possible to move them into my feature module?
A module that implements hook_preprocess_page()
or hook_preprocess_node()
can suggest new template files by altering the variable $variables['theme_hook_suggestions']
.
The code contained in template_preprocess_page() that initialize that variable is the following.
// Populate the page template suggestions.
if ($suggestions = theme_get_suggestions(arg(), 'page')) {
$variables['theme_hook_suggestions'] = $suggestions;
}
Each theme suggestion needs to match with an entry returned by hook_theme().
In Views, there should be an equivalent preprocess function to use in the similar way, or a way that allows to hook_preprocess_page()
that allows to the function to understand if the page is associated with a view.
The solution to add the 'template file' key to hook_views_api()
does not appear to work in Drupal 7 yet. However, this works like a charm:
/**
* Implements hook_theme().
*/
function bigtexas_theme() {
return array(
'views_view_fields__slideshow' => array(
'variables' => array('view' => NULL, 'options' => NULL, 'row' => NULL),
'template' => 'views-view-fields--slideshow',
'base hook' => 'views_view_fields',
'path' => drupal_get_path('module', 'bigtexas') . '/theme',
),
);
}
The theme registry is where Drupal stores all sorts of info about what template files, theme functions etc to use. Messing with it can lead to WTF moments later on, as things will not work like default.
Anyways like all things drupal, there is a hook: hook_theme_registry_alter
you can use to alter the theme registry and this move your template files into a module. I wouldn't advise doing this, as it will make maintaining the site more complex. But if you want to do is, this is how it's done.
For views there is in theory a mechanism for views templates(perhaps it works for all templates).
You can set the key "template path" in your hook_views_api implementation of your custom module.
Once you have this views will scan your specified directory for template files. Sadly the simpletest currently fails, so this feature is probably not ported yet to drupal7, but if someone wants to get into it, see _views_find_module_templates() in views.module.
The easiest way is to use hook_theme_registry_alter()
and just add the path of your module to the theme paths:
function mymodule_theme_registry_alter(&$theme_registry) {
$theme_registry['[theme hook name, ie. page or views-view]']['theme paths'][] = drupal_get_path('module', 'mymodule');
}
theme()
implementation, it doesn't seem like theme path
can be an array. Are you sure this works? See api.drupal.org/api/drupal/includes%21theme.inc/function/theme/7
Commented
Oct 17, 2012 at 15:38
theme paths
used to work in Drupal 6, but Drupal 7 changed that behaviour in drupal.org/node/678714 It seems, from comments #29 and #31 in the mentioned issue, that theme suggestions from modules have to be declared in that module's hook_theme, but how to do that is left as an exercise to the reader :/
Commented
Oct 17, 2012 at 16:10
How about a slightly abstracted approach with Context Reaction Theme?
http://drupal.org/project/context_reaction_theme
Wrap up your context in Features and it's even exportable. But maybe this is actually a Drupal guru question looking to create something deeper and know the route.
I started with the answer of googletorp and built a generic function:
/**
* Overrides a third-party template file with a local copy.
*
* To be called from hook_theme_registry_alter():
* @code
* function mymodule_theme_registry_alter(&$theme_registry) {
* // Override variant of foo template using local copy.
* custom_override_template($theme_registry, 'foo--variant', drupal_get_path('module', 'mymodule') . '/templates');
* }
* @endcode
*
* @param array $theme_registry
* Theme registry array as passed to hook_theme_registry_alter().
* @param string $template
* Name of template file without '.tpl.php' extension. Example: 'foo--variant'.
* @param string $path
* Directory to load $template from.
* @param string $preprocess_function
* Optional preprocess function.
*/
function custom_override_template(&$theme_registry, $template, $path, $preprocess_function = NULL) {
if (strpos($template, '--') !== FALSE) {
$hook_name = array_shift(explode('--', $template));
}
else {
$hook_name = $template;
}
$hook_name = str_replace('-', '_', $hook_name);
if (isset($theme_registry[$hook_name])) {
// Copy hook info.
$hook_info = $theme_registry[$hook_name];
$hook_info['path'] = $path;
$hook_info['template'] = $template;
// Add to theme registry.
$new_hook = str_replace('-', '_', $template);
$theme_registry[$new_hook] = $hook_info;
// Add preprocess function.
if(!is_null($preprocess_function)){
$theme_registry[$new_hook]['preprocess functions'][] = $preprocess_function;
}
return $new_hook;
}
else {
throw new Exception(t('Unknown theme hook %hook.', array('%hook' => $hook_name)));
}
}
It allows not only to overwrite the position and name of node and view tpl files but also to provide a preprocess function for views.
So if you got your own module called mymodule
with a template file e.g sites/all/modules/mymodule/templates/foo--variant.tpl.php
you can now easily modify the theme registry to use your own template directory:
function mymodule_theme_registry_alter(&$theme_registry) {
// Override variant of foo template using local copy.
custom_override_template($theme_registry, 'foo--variant', drupal_get_path('module', 'mymodule') . '/templates');
}
As @jcsio said, the accepted answer on this page works, but the template cannot be overridden by a theme.
http://www.metachunk.com/blog/adding-module-path-drupal-7-theme-registry offers a solution that allows you to add the path of your module (and sub-folders) to be scanned for all kinds of .tpl.php files.
I slightly changed it, since it contained a 'theme paths' variable that seems not used by Drupal 7.
/**
* Implements hook_theme_registry_alter()
**/
function mymodule_theme_registry_alter(&$theme_registry) {
$mod_path = drupal_get_path('module', 'mymodule');
$theme_registry_copy = $theme_registry; // munge on a copy
_theme_process_registry($theme_registry_copy, 'phptemplate', 'theme_engine', 'pow', $mod_path);
$theme_registry += array_diff_key($theme_registry_copy, $theme_registry);
}
I tried both the accepted answer and this solution, the latter works for me so far!