hook_theme()如何工作?

时间:2011-10-12 15:04:27

标签: drupal drupal-7 hook drupal-templates

我很难理解hook_theme()的作用。

我的理解是它与可以覆盖模板有关。

我在看:

  $theme_hooks = array(
    'poll_vote' => array(
      'template' => 'poll-vote',
      'render element' => 'form',
    ),
    'poll_choices' => array(
      'render element' => 'form',
    ),
    'poll_results' => array(
      'template' => 'poll-results',
      'variables' => array('raw_title' => NULL, 'results' => NULL, 'votes' => NULL, 'raw_links' => NULL, 'block' => NULL, 'nid' => NULL, 'vote' => NULL),
    ),
    'poll_bar' => array(
      'template' => 'poll-bar',
      'variables' => array('title' => NULL, 'votes' => NULL, 'total_votes' => NULL, 'vote' => NULL, 'block' => NULL),
    ),
  );

你能提供一个如何运作的例子吗?

2 个答案:

答案 0 :(得分:22)

它为模块提供了一个定义主题的位置,然后可以被任何其他模块/主题覆盖。它还将为任何模块提供使用mymodule_preprocess_theme_name之类的钩子来更改传递给最终主题函数或模板文件的变量的机会。

基本上有两种初始化主题功能的方法:

theme('poll_results', array('raw_title' => 'title', 'results' => $results, etc...));

$build = array(
  '#theme' => 'poll_results',
  '#raw_title' => 'title',
  '#results' => $results,
  etc...
); // Note the '#' at the beginning of the argument name, this tells Drupal's `render` function that this is an argument, not a child element that needs to be rendered.

$content = render($build); // Exact equivalent of calling the previous example now that you have a render array.

请记住,你应该避免直接调用theme()(根据theme.inc中的文档),因为它:

  • Circumvents缓存。
  • 绕过hook_element_info()中定义的类型的默认值,包括附加资产
  • 绕过pre_render和post_render阶段。
  • Circumvents JavaScript陈述信息。

在Drupal 8中,theme()是一个私有函数_theme()。有关详细信息,请参阅www.drupal.org/node/2173655

当您将上述两个元素与上面给出的示例中的poll_results元素进行比较时,您可以解决正在发生的事情......因为PHP不是强类型语言,Drupal通过以下方式提供“命名参数”传递给theme函数的键控数组,或渲染数组中的散列键。

就“渲染元素”而言,这基本上告诉主题系统将使用渲染数组调用此主题函数,其中一个命名参数(在本例中为{{1} })。代码看起来像这样:

form

这会将$build = array( '#theme' => 'poll_choices', '#form' => $form ); 变量中的任何内容传递给主题函数,因为它是唯一的参数。

关于$form密钥:

template

定义了一个名为'poll_vote' => array( 'template' => 'poll-vote', 'render element' => 'form', ) 的主题,该主题使用名为“poll-vote.tpl.php”的模板文件(因此为poll_vote键)(按照惯例)。通过使用实现它的模块的路径(例如modules / poll / poll-vote.tpl.php)可以找到该模板文件的路径,因此可以将模板文件放在主模块文件夹的子文件夹中

有两种方法可以实际返回主题函数的输出,方法是实现物理函数名称(在本例中为template)或使用模板文件。如果theme_poll_vote键为空,Drupal将假设您已实现了物理功能并将尝试调用它。

如果您要为主题输出相当多的HTML,或者您根本不喜欢在PHP中的字符串中编写HTML(我个人不这样做),那么模板文件是首选。但在任何一种情况下,调用主题时传递的变量(使用template或如上所述的渲染数组)本身都会传递给模板文件或主题函数。所以:

theme()

如果您使用模板文件代替同一方法,则变量将以function theme_poll_results(&$vars) { $raw_title = $vars['raw_title']; $results = $vars['results']; // etc... } $raw_title等方式提供,因为Drupal在$results上运行extract在解析模板文件之前。

我确信我在这里错过了很多,但如果你有任何更具体的问题请求,我会尽力帮忙。

答案 1 :(得分:0)

还有另一种方式:(可以在Bartik主题中找到)

这里的场景是我们已经创建了自己的模块,并希望覆盖默认输出,让我们说一个标题为'zzz'的节点。
我们不知道也不关心如何生成默认输出。我们所需要的只是告诉Drupal使用我们自己的自定义模板文件(node-custom-name.tpl.php)来呈现该特定节点。

这些是步骤:

  1. 告诉Drupal我们的模板文件在哪里。 (请记住,此功能仅在清除Drupal缓存后生效一次):

    // Implements hook_theme()
    function mymodulename_theme() { 
      $theme = array();
      $theme['node__custom__name'] = array(
        'render element' => 'node',
        'template' => 'path_from_mymodule_root/node__custom__name',
        );
      return $theme;
    }
    
  2. 告诉Drupal何时何地使用

    //Implements hook_preprocess_node()
    function mymodulename_preprocess_node($vars) {
        if($vars['node']->title == 'zzzz') {
            $vars['theme_hook_suggestions'][] = 'node__custom__name';
            ... your other code ...
         }
     }
    

    现在Drupal将仅针对该特定情况使用我们的模板文件,前提是'node-custom-name.tpl.php'文件位于声明的路径中,否则它将继续根据建议命名约定进行搜索后备模板。