只要你在主题文件夹中覆写了页面元素所对应的代码,就等于修改了这个元素的呈现规则,Drupal系统会用这个新规则所定义的方式来呈现对应的元素——Drupal用这种被称之为“覆写”的机制来保证你永远不需要修改核心的东西。创建主题就是为了把默认的呈现规则变成你自己的规则,因为Drupal为你提供的HTML标记往往都是你不需要的。当你为所有需要修改的页面元素都添加了各自的规则的时候,你的主题就做好了。
2.3.1 模板的嵌套
关于页面的构成,Drupal官网上给出了一个很好的图示:
上图描述的Drupal7的情形。你可以在https://www.drupal.org/node/171194(link is external)这个页面看到这张图,也可以找到这张图的Drupal6版本。
从图中你可以看到,几个区块(block.tpl.php)可以组成一个区域(region.tpl.php),然后这些区域被嵌套进page.tpl.php和html.tpl.php中。这些小块不断嵌套,最终组成一个完整页面并呈现在浏览器上。
2.3.2 模板的命名
覆写模板文件的时候,你首先需要做的就是将对应的模板文件拷贝到你的主题文件夹中,然后你需要对它进行重命名,以便这个模板只在你需要的元素上起作用。比如在上图中,你可以看到很多个不同的区块,他们的默认模板文件都是block.tpl.php,因此如果你要覆写多个区块,你就需要用不同的名字来区分它们。模板覆写有自己的命名规则。你需要记住的一点是:模板文件的名字越短,则其作用域就越大。这里所说的名字长度并不是说字符串的长度,而是指名字中所包含的层级。比如node.tpl.php可以被应用于所有的节点,但是node--blog.tpl.php就只能被应用于内容类型为blog的节点。这里的node.tpl.php是第一级的,它在默认情况下作用于所有的节点,而node--blog.tpl.php是第二级的名称,它的作用域则要小得多。
你可以在官网的:https://www.drupal.org/node/1089656(link is external)和https://www.drupal.org/node/223440(link is external)页面中看到关于命名规则更详细的说明。我们在之后也会详细讲到。但是你应该记住的一点是Drupal6中的模板命名使用的是单横线(-),而Drupal7中使用的是双横线(--),由于Drupal6和Drupal7在模板机制上的相似性,网上总是有一些和主题有关的帖子没有标明其所针对的Drupal版本,这往往使初学者感到疑惑,经常出现的情况是他们用的单横线去命名Drupal7的模板,从而导致模板无法生效。至于Drupal8,由于使用了新的Twig引擎和其它更多的新特性的加入,我们将在以后单独讲述。
另一个容易忽略的事情是在views中,如果你用views生成了一个区块,而这个区块的名字太长了,程序会自动做一个HASH运算,将名字转变为包含32个字符的字符串,比如当你检查这个区块的代码时,你可能会在这个区块中看到类似这样的ID:block-views-c56a6974e1e747558c4a63b62b968376——如果你看到了不要奇怪。如果你要覆写这个区块模板的话,命名应该是这样的:block--views--c56a6974e1e747558c4a63b62b968376.tpl.php,当然你也可以把你的view的名字改短一点。
2.3.3 模板中的变量
另外,模板文件中除了HTML标记之外还包含PHP变量。你可以在Drupal默认的模板文件的注释中找到变量和它们对应的说明。你也可以在Drupal官网找到相应的说明,学习官网的API是学习Drupal的好办法,这里给出几个例子:
https://api.drupal.org/api/drupal/modules%21block%21block.tpl.php/7(link is external)
https://api.drupal.org/api/drupal/modules%21node%21node.tpl.php/7(link is external)
https://api.drupal.org/api/drupal/modules%21system%21page.tpl.php/7(link is external)
2.3.4 如何找到正确的原始代码
前面已经说过,覆写模板文件的时候,你首先需要做的就是将对应的模板文件拷贝到你的主题文件夹中。但是页面上的某个元素或者区块中的HTML到底是在哪里生成的?如何才能找到对应的需要覆写的代码?或者到底应该拷贝哪个文件?——这应该是对于初学者来说最著名的几大谜题之一了。
要正确的覆写代码,你应该知道两件事情:其一,这段代码是模板文件还是主题函数控制的;其二,这段代码是由哪个模块负责的。一般来说像一个节点或者一个区块这样大的元素都是由模板文件生成的,但是比如导航菜单,面包屑之类的东西,则是由主题函数控制的。另外,通过谷歌浏览器检查元素的方式你往往可以在CSS类名中找到这个元素是由哪个模块生成的信息。我一直以为这是一个笨办法,直到后来才发现原来大家都是这么干的。
如果代码是由模板文件控制的,你就应该尝试找到对应的文件。你可以在官网的:https://www.drupal.org/node/190815(link is external) 页面中找到关于核心默认模板的更详细的说明。
如果是由其他贡献模块生成的代码,那么你需要到对应的模块中找对应的.tpl.php文件。找到之后打开看看它的代码和页面中的代码是否一致,你也可以加一段自己的代码进去,看看是否会在刷新之后显示出来。如果是的,那说明你找到了。
如果你找不到对应的模板文件,那么说明这段代码是被定义在主题函数中的。你可以在官网的API文档页面(https://api.drupal.org/api/drupal(link is external))来搜索相关函数的信息和代码。一般来说你要找的函数都是由 theme_ 或者 template_preprocess_ 开头的。然后你可以和页面中需要覆写的代码进行比较。主题函数的覆写是在template.php文件中进行的。将你要覆写的函数代码复制到template.php文件中,并将theme_ 替换成你的主题的名字。比如,要覆写theme_breadcrumb(),你应该把对应的代码拷贝到template.php文件中,并将名字改为yourthemename_breadcrumb()。我将下一节讲述覆写主题函数相关的信息。
2.3.5 其它
还有一个好办法是使用Devel Themer模块,它能自动帮你完成上面的工作,让你可以很清楚的知道页面上的每个元素是由哪个模板文件或者哪个主题函数控制的。缺点是它可能让你的网站变得很慢,而且还可能报错。所以,我只在必要的时候才启用它。
还有,如果你在和views打交道的话,那你也可以在views的设置界面中找到相关的模板信息。
最后,也是最重要的,如果你新建了一个模板文件,请一定记住清空缓存。