如何告诉Drupal在模块目录中查找模板?


11

我想在我的模块中提供模板实现,并允许主题覆盖它。基本上,我通过以下简化代码添加建议:

function attach_preprocess_node(&$vars) {
  $vars['theme_hook_suggestions'][] = 'node__test';
}

(我不想使用hook_theme添加新主题,因为我想重用预处理节点功能。主题名称很尴尬,但我不想编写node_ attach _%以避免与节点类型混淆。)

然后,我使用hook_theme_registry_alter()添加模块路径:

function attach_theme_registry_alter(&$theme_registry) {
  $path = drupal_get_path('module', 'attach') . '/themes';
  $theme_registry_copy = $theme_registry;
  _theme_process_registry($theme_registry_copy, 'phptemplate', 'theme_engine', 'node', drupal_get_path('module', 'node'));
  $theme_registry += array_diff_key($theme_registry_copy, $theme_registry);
  if (!isset($theme_registry['node']['theme paths'])) {
    $theme_registry['node']['theme paths'] = array();
  }
  if (!isset($theme_registry['node']['theme paths'])) {
    $first_element = array_shift($theme_registry['node']['theme paths']);
    if ($first_element) {
      array_unshift($theme_registry['node']['theme paths'], $first_element, $path);
    }
    else {
      array_unshift($theme_registry['node']['theme paths'], $path);
    }
  }
}

但是,它不起作用。这意味着:不使用文件主题/节点--super.tpl.php。仅当我将其复制到主题文件夹时才使用。


澄清:我希望Drupal在模块目录(以及主题目录)中查找由代码定义的模板(此处为节点模板)。我不想定义一个新模板。
jcisio 2012年

Answers:


5

基本上,您可以通过实施hook_theme()而不是更改注册表来为自己省些麻烦。

我建议您看一下示例项目中的theming_example,该示例可在此API文档页面上轻松复制,也许在此页面上包含特别有用的代码。

function theming_example_list_page() {
  $items = array(
    t('First item'),
    t('Second item'),
    t('Third item'),
    t('Fourth item'),
  );

  // First we'll create a render array that simply uses theme_item_list.
  $title = t("A list returned to be rendered using theme('item_list')");
  $build['render_version'] = array(
    // We use #theme here instead of #theme_wrappers because theme_item_list()
    // is the classic type of theme function that does not just assume a
    // render array, but instead has its own properties (#type, #title, #items).
    '#theme' => 'item_list',
    // '#type' => 'ul',  // The default type is 'ul'
    // We can easily make sure that a css or js file is present using #attached. 
    '#attached' => array('css' => array(drupal_get_path('module', 'theming_example') . '/theming_example.css')), 
    '#title' => $title, 
    '#items' => $items, 
    '#attributes' => array('class' => array('render-version-list')),
  );

  // Now we'll create a render array which uses our own list formatter,
  // theme('theming_example_list').
  $title = t("The same list rendered by theme('theming_example_list')");
  $build['our_theme_function'] = array(
    '#theme' => 'theming_example_list', 
    '#attached' => array('css' => array(drupal_get_path('module', 'theming_example') . '/theming_example.css')), 
    '#title' => $title, 
    '#items' => $items,
  );
  return $build;
}

这一切都适用于Drupal 7。


正如我在问题中所说的那样,我不想使用hook_theme(),因为我想在节点模板中重用$ variables。这些变量是在许多模块的hook_(pre)过程中生成的,这些模块不知道主题的存在(如果我定义了主题)。
jcisio 2012年

定义主题的方法是使用hook_theme()。:-)您可以在hook_theme()中定义主题功能。给他们起任何名字。如果需要,可以设置匀场功能。API文档:“ hook_theme_HOOK()...仅应在模块需要为其未定义的主题挂钩重写或添加到主题预处理中时使用。”
paul-m

我不想定义一个主题。如果您定义主题“ mynode”而不是重用“ node”,则.tpl.php文件中没有任何变量。
jcisio 2012年

1
事实并非如此:主题调用是累积性的,因此实现hook_theme应为您提供一个$existing参数,使您可以修改事物,而不是覆盖它。如果不是这种情况,则可能是您遇到了错误。
Countzero 2012年

@Countzero声明主题node_attach时,新主题不会发生所有hook_preprocess_node函数。也就是说,您的node-attach.tpl.php中没有任何内容。
jcisio 2012年

5

也许这一作品:

/**
 * Implements hook_theme().
 */
function MODULE_theme($existing, $type, $theme, $path) {
  return array (
    'node__CONTENTTYPE' => array (
      'variables' => array( . . . ),
      'template' => 'node--CONTENTTYPE' ,
      'base hook' => 'node',
      'path' => drupal_get_path('module', 'MODULE'),
    ),
  );
}

这里重要的是键“ 基础钩子 ”。


这是为以下文件添加文档的问题base hookdrupal.org/node/2106635
Andy

+1赞成-这和我发现有效的来自batigotix的派生答案。谢谢。
therobyouknow 2015年

2

我喜欢dashohoxha的 hook_theme实现解决方案,但无法使其正常运行。经过更多的谷歌搜索后,我发现了一个对我来说很好的变体

/**
 * Implements hook_theme().
 */
function mymodule_theme($existing, $type, $theme, $path) {
  $theme = array();
  $theme['node__blog_post'] = array(
    'render element' => 'content',
    'base hook' => 'node',
    'template' => 'node--blog_post',
    'path' => drupal_get_path('module', 'mymodule') . '/templates',
   );
  return $theme;
}

注意:我的自定义模块称为“ mymodule”,而我的自定义内容类型称为“ blog_post”。我使用的tpl.php称为“ node--blog_post.tpl.php”,它位于模块的“ templates”子文件夹中。


+1谢谢,我发现这行得通。如果你还覆盖您的自定义模块内的template.php功能感兴趣的话,就来看看:snugug.com/musings/override-theme-functions-drupal-7-module -我发现这工作得很好
therobyouknow

2

这是我的片段,用于声明存储在“ custom_module”的“ template”文件夹中的视图模板:

/**
 * Implements hook_theme_registry_alter().
 */
function custom_module_theme_registry_alter(&$theme_registry) {
  $extension   = '.tpl.php';
  $module_path = drupal_get_path('module', 'custom_module');
  $files       = file_scan_directory($module_path . '/templates', '/' . preg_quote($extension) . '$/');

  foreach ($files as $file) {
    $template = drupal_basename($file->filename, $extension);
    $theme    = str_replace('-', '_', $template);
    list($base_theme, $specific) = explode('__', $theme, 2);

    // Don't override base theme.
    if (!empty($specific) && isset($theme_registry[$base_theme])) {
      $theme_info = array(
        'template'   => $template,
        'path'       => drupal_dirname($file->uri),
        'variables'  => $theme_registry[$base_theme]['variables'],
        'base hook'  => $base_theme,
        // Other available value: theme_engine.
        'type'       => 'module',
        'theme path' => $module_path,
      );

      $theme_registry[$theme] = $theme_info;
    }
  }
}

希望它可以帮助某人。


节省了我的时间。同样适用于d8,并且需要
Mykola Mykolayovich Dolynskyi

-1

我曾经在Stack Overflow上问过一次。基本上,您必须实现hook_theme_registry_alter()将路径添加到主题挂钩模板路径中。然后,在上hook_enable(),调用 drupal_theme_rebuild()清除主题注册表缓存并扫描路径以查找模板。


也许阻碍您前进的只是清除缓存。
Capi Etheriel 2012年

因此,基本相同的解决方案。我尝试了“ drush cc all”不少于50次,在新的安装站点等上进行了测试,但均未成功。我将修改我的代码并将其压缩到一个最小的模块中,以便每个人都可以测试。
jcisio 2012年

hook_enable()启用模块时调用;如果模块已启用,则必须先将其禁用,然后再启用。
kiamlaluno

@kiamlaluno:iḿ使用hook_enable清除缓存,如果已经安装,则用户可能只是手动清除缓存。
Capi Etheriel'3

,-1分。该解决方案太旧了(2009年),我什至不确定它是否适用于D7。虽然您的旧解决方案是针对Views量身定制的,但对于非Views场景(开发人员可能希望为其模块中的每个主题键打包超过1个默认模板)而言,它不是理想的选择。想象一下,为单个主题键实现100个动态主题建议的解决方案。在Views上下文之外应用我将您的解决方案称为反模式。
业余咖啡师
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.