跳转到主要内容
DrupalCMS 提交于 23 January 2013

改变Drupal生成的HTML或其它标签需要那些组成主题系统层次的知识。在本章中,我将教你主题系统怎样工作并且透露一些隐藏在Drupal核心中的最好的实践。首要问题是你在模块文件中不需要(或称不应该)编辑HTML来改变你的站点的视觉外观,要是那样做,你只是建立你自己私有的内容管理系统,并且因此失去了有社区支持的开源软件系统的内含的最大优势。一定记住:要覆写,而不是修改。

主题

用Drupal的话来说,主题就是制造出站点外观和感觉的文件的集合。你可以从http://drupal.org/project/themes下载预先构建好的主题,或者你学完这章后自己建一个。主题由下面一些东西组成,你期望看起来是web设计者:样式表、图片、javascript脚本等等,你需要注意Drupal主题和纯的HTML站点的不同是针对模板文件,模板文件典型包含大的HTML段和由动态内容如Drupal构造页面替换的特定的小片,你可以创建针对性模板文件来针对每一个Drupal内容的容器——诸如overall page、regions、blocks、nodes、comments甚至field。一会我们将遍历结构层模板文件的建立过程,但是先让我们从安装现成的Drupal.org的模板开始并测试构成主体的组成成分。

      安装现成的主题

有成百上千的Drupal主题可用,如果你寻求简单、快速地布置并运行一个站点,你可以考虑通过www.drupal.org/project/themes来浏览主题,确定选择了7.x,来只显示支持D7的主题。

------------------------------------------------------------------------------------------------------------------------------------------------ 注意:你必须挑选Drupal7版本的主题,因为主题结构的变化,D6及以前版本的主题不能运行于D7站点上。 ------------------------------------------------------------------------------------------------------------------------------------------------

在你浏览主题时,你通常能遇到所谓的“启动器主题”,启动器主题致力于提供构建一个新主题的实体基础。典型上,启动器主题包含一个丰富的在线文档和功能帮助。启动器主题的好处在于它提供了实体基础,可以在其上放置图片元素和颜色,而不用从一个空白页面开始。没有归类为启动器主题的主题已经是包含有图形效果(如图片、颜色、字体等等)应用并且可以通过少量修改来适应你的需要。 作为演示,我们将安装Pixture Reloaded主题,除了它已经可以在D7上运行之外,此主题没什么重要作用,浏览drupal.org的主题页面,复制pixture_reloaded主题下载连接的URL,返回你的站点,在页面顶部点击Appearance连接,在外观页面点击Install new theme连接,在上传新主题的表单上粘贴下载URL到标签为“Install form a URL”的文本框,然后点击Install按钮,Drupal将下载并保存主题到你的sites/all/themes目录,然后你可以通过浏览Appearance页面并点击“set default”连接激活主题并作为默认。 从drupal.org安装主题简单快速,你能通过上述方式下载任意数量的主题并在站点上测试他们,但是很可能有时你想建立自己所有的定制的主题,在下面的章节中,我将展示你怎样通过全新设计和白手起家来创建一个新主题。

      创建新主题

有几种方式来创建一个新主题,依赖于你开始的材料,假设你的设计师已经给你了站点的HTML和CSS,讲设计师的HTML和CSS转换到一个Drupal主题,相对来说是比较简单的。 通常建立一个新的Drupal主题有下列步骤:       + 1、建立或修改站点的一个HTML文件       + 2、建立或修改站点的一个CSS文件       + 3、建立一个.info文件告诉Drupal你的新主题       + 4、依据Drupal希望那样来标准化文件名       + 5、向你的模板中插入可用变量       + 6、给节点类型、区块等等分别建立附件的文件 我们以确定名字叫“Grayscale”开始来构建新主题——然后用相同的名字在sites/all/themes中建立目录(sites/all/themes/grayscale),下一步我们为此主题在目录中建立一个.info文件,我将建立grayscale.info文件,初始时包含合并到Drupal主题注册器中所需要的基本信息

name = Grayscale
core = 7.x
engine = phptemplate

一旦你保存了grayscale.info文件,你就能激活这个主题,通过点击页面顶部的Appearance连接,向下滚动,直到看见Grayscale主题,点击“enable and set default“连接将主题应用为站点默认主题,点击Home按钮浏览站点主页,你就有个新的Drupal主题(见图9-1),并且你所作的全部工作就是在.info文件中输入了3行。

Figure 9-1. The site rendered in the Grayscale theme

显然它不能够赢得任何创新奖,只是遍历了一下看看白手起家创建一个Drupal主题是多么简单。让我们给网站扩展一点东西,应用一些CSS重排和风格的东西,第一步在我们的主题Grayscale目录中建一个叫css的目录,虽然将所有css文件放到一个子目录中的做法不是必需的,但这样的好处在于别人不必挖掘你的主题目录来定位CSS文件。在css目录,建立一个style.css的文件,名字完全随意,但是多数Druapl主题用style.css来作为指定给主题的主.css文件名。 下面我们需要通知我们的主题应用style.css,要做到这些,我们更新grayscale.info文件,加入下面一行:

stylesheets[all][] = css/style.css

这个指定了站点在所有媒体(screen、projector、print)上显示都要应用style.css,你还可以讲样式表应用到指定的媒体,比如print,使用下面一行:

stylesheets[print][] = css/print.css

或者为screen和projector使用同一个样式表:

stylesheets[screen, projector] = theScreenProjectorStyle.css

我们的目的是将其应用到所有媒体。 下面我们实验Drupal用来渲染页面的结构,页面里我们能指定CSS的id和class来应用样式。如果你用firefox,我建议你下载并安装firebug,如果你用IE,我建议你下载并安装IE Developers Toolbar,或者如果你使用safari,请使用内建的web inspector,这3个工具都提供跟踪站点结构、简单标示CSS的id和class应用风格的能力,图9-2展示了firefox的firebug跟踪一个页面时显示的信息。

给你点时间下载这些工具,如果你还没有它们,一旦安装后,使用这个跟踪器选项去测试我们用Drupal生成的HTML和DIV。 下一步是为CSS的ID和class定义风格,开始这步之前,让我们查看站点的页面源代码来检视Drupal为我们新的站点的主页生成的HTML,焦点放到DIV标签的结构上,为简洁起见我们省略了DIV标签之间的HTML代码,如果你想去看页面的细节,你去浏览器窗口点击右键选择查看源文件。这里只展示<body></body>之间的DIV结构。

<body class="html front logged-in one-sidebar sidebar-first page-node toolbar tollbar-drawer">
  <div id="skip-link"> ... </div>
  <div class="region redion-page-top">..</div>
  <div id="page-wrapper">
    <div id="header">
      <div class="section clearfix">
        <a id="logo" ... ></a>
        <div id="name-and-slogan"></div>
      </div>
    </div>
    <div id="navigation">
      <div class="section">
        <ul id="main-menu"> ... </ul>
        <ul id="seconary-menu"> ... </ul>
      </div>
    </div>
    <div id="main-wraper">
      <div id="main">
        <div id="content"></div>
        <div id="sidebar-first" class="column sidebar"></div>
      </div>
    </div>
    <div id="footer"></div>
  </div>
</body>

可以注意到Div标签之间的更多内容,但是我们联系的重点是在于理解div结构使我们能定义风格到css/style.css。下面是为如图9-3那样的显示而定义的CSS。

body {
  background-color: #c6c6c6;
}
#page { 
  background-color: #c6c6c6;
}
#skip-link { 
   width: 960px;
   margin-right: auto;
   margin-left: auto;
   background-color: #c6c6c6;
}
 
#header { 
   width: 960px;
   background-color: #ffffff;
   margin-right: auto;
   margin-left: auto;
   margin-top: 10px;
   height: 40px;
   padding-top: 10px;
   border-top: 3px solid #000;
   border-bottom: 3px solid #0
}
 
#logo { 
   float: left;
   margin-left: 20px;
}

a#logo { 
   text-decoration: none;
}
 
#name-and-slogan { 
  float: left;
  margin-left: 100px;
}
 
#site-name a { 
  text-decoration: none;
}
 
#navigation { 
  width: 960px;
  margin-right: auto;
  margin-left: auto;
  background-color: #c6c6c6;
  height: 45px;
}
 
#navigation h2 { 
  display: none;
}
ul#main-menu { 
  background-color: #EEE;
  height: 25px;
}
 
ul#main-menu { 
  text-decoration: none;
  padding-top: 5px;
}
 
ul#main-menu li a { 
  text-decoration: none;
  padding-right: 10px;
}
 
ul#secondary-menu { 
  background-color: #333;
  height: 25px;
}
 
ul#secondary-menu li a { 
  text-decoration: none;
  color: #fff;
  padding-right: 10px;
  height: 25px;
  border-right: 1px solid #fff;
}
 
ul#secondary-menu a:hover { 
  color: #ff0000;
}
 
#main-wrapper {
  clear: both; 
  background-color: #ffffff;
  width: 960px;
  margin-right: auto;
  margin-left: auto;
}
 
#main { 
  width: 960px;
  margin: 5px auto;
}
 
#content { 
  width: 775px;
  float: right;
  padding-left: 15px;
}
#sidebar-first {
  float: left;
  width: 130px;
  margin:0;
  padding: 20px;
  background-col
}
 
#footer { 
  width: 920px;
  padding: 20px;
  margin-right:
  margin-left: a
  clear: both;
  min-height: 10
  background-col
  color: #fff;
}
 
#footer a { 
  color: #fff;
}

Figure 9-3. The site after applying the style sheet additions

保存完style.css之后,重新浏览站点主页,你看见的应该如图9-3。 只有4行的.info文件和几行的CSS,我们已经是有能力建立全新的Drupal主题,我们还没建立模板文件、HTML或碰到一行PHP代码,展示出来Drupal主题是如何的简单而强大。 建立Grayscale主题之所以如此简单是因为Drupal有一个预定义的模板文件集合,当一个主题自己没有提供文件作为自己的一部分是,它们就被应用到主题上。下一节中,我们说一说几个模板文件的细节。

.info文件

Grayscale主题的.info文件只有注册主题并使之在Appearance页面成为可选择所而必须的最少的信息,在大多数情况,你可能想定义你自己的的区域、包含附加的样式表、包含javascript文件来作为主题的一部分。让我们看一下怎样扩展.info文件来增加每一样属性。

      为主题增加区域

一个区域(region)本质上来说是站点页面上的一段。在我们构建Grayscale主题时,我们使用了Drupal自动为我们建立的标准区域:sidebar first,sidebar second, content, header,footer,highlighted, help, page_bottom, page_top。有许多你想划分主题到附加的区域情况,我们通过在.info文件中包含区域描述及在page.tpl.php中包含区域的结合来做到这些。 在.info中定义一个新的区域的语法是:

regions[alerts] = Alerts
regions[feature] = Featture Articles
regions[socialnetworks] = Social Networks

你可以在.info文件中定义许多你想要的区域,但是你应该在你的.info文件中包含page_botton、page_top、help以及content,作为核心需求区域来发挥正常功能。下一步要更新你的page.tpl.php文件来增加你新的区域,在页面上显示这个区域的流程如下:

<div id="alerts">
  <?php print render($page['alerts']); ?>
</div><!-- /alerts -->

      为主题增加CSS文件

当我们建立Grayscale主题时,我们增加了一个单个的CSS文件,它组合了我们完成我们设计目标所需要的所有风格。可能有这样情形,需要你组合多于一个的样式表,或你希望样式表基于浏览站点的设备,这两种方式都要通过下面的语法来完成(假设你所有的样式表都放在主题目录的css子目录中)。

;// add a style sheet that deals with colors for all mediums 
stylesheets[all][] = css/colors.css 
;// add a style sheet just for printing
stylesheets[print][] = css/print.css
;// add a style sheet just for projecting
stylesheets[projector][] = css/showtime.css
;// add a style sheet for screen
stylesheets[screen][] = css/style.css
;// add a style sheet for screen and projector
stylesheets[screen, projector] = css/showit.css

      为主题增加JavaScript文件

如果你的主题使用javascript,最好的实践是将javascript代码存储到外部文件中,要包含这些文件需要在你主题的.info文件中列出每个javascript文件,假设你把所有你的javascript文件放到主题的js子目录中,包含文件的语法如下:

scripts[] = js/jcarousel.js

      为主题增加设置

可能有这样情形,你希望你的主题不用动模板文件或CSS就能配置,如,你可能希望为站点管理员提供一个改变字体尺寸和样式的能力,我们通过提供设置来做到这些,要定义一个设置,我们组合这些定义到.info文件中,如下:

settings[font_family] = 'ff-sss'
settings[font_size] = 'fs-12'

用上面的设置更新你的grayscale.info文件,随后我们实现那些允许站点管理员能设置且你站点要使用该值的魔术片段。 下一步是提供站点管理员改变该值的手段,要做到这些,我们在主题目录中建立一个theme-settings.php的文件,并建立需要收集的字体族和字体大小的值的表单元素,在theme-settings.php中,我们使用hook_form_system_theme_settings_alter()函数去增加字段来设置字体族和字体大小。插入下面代码:

<?php

function grayscale_form_system_theme_settings_alter(&$form, &$form_state) {
  $form['style'] = array(
    '#type' => 'fieldset',
    '#title' => t('Style settings'),
    '#collapsible' => FALSE,
    '#collapsed' => FALSE,
  );

  $form['style']['font'] = array(
    '#type' => 'fieldset',
    '#title' => t('Font settings'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['style']['font']['font_family'] = array(
    '#type' => 'select',
    '#title' => 't('Font family'),
    '#default_value' => theme_get_setting('font_family'),
    '#options' => array(
      'ff-sss' => t('Helvetica Nueue, Trebuchet MS, Arial, Nimbus Sans L, FreeSans, sans-serif'),
      'ff-ssl' => t('Verdana, Geneva, Arial, Helvetica, sans-serif'),
      'ff-a'   => t('Arial, Helvetica, sans-serif'),
      'ff-ss'  => t('Garamond, Perpetua, Nimbus Roman No9 L, Times New Roman, serif'),
      'ff-sl'  => t('Baskerville, Georgia, Palatino, Palatino Linotype, Book Antiqua, URW Palladio L, serif'),
      'ff-m'   => t('Myriad Pro, Myriad, Arial, Helvetica, sans-serif'),
      'ff-l'   => t('Lucida Sans, Lucida Grande, Lucida Sans Unicode, Verdana, Geneva, sans-serif'),
    ),
  );
  $fomr['style']['font']['font_size'] = array(
    '#type' => 'select',
    '#title' => t('Font size'),
    '#default_value => theme_get_settings('font_size'),
    '#description' => t('Font sizes are always set in relative units - the sizes shown are the pixel value equivalent.'),
    '#options' => array(
      'fs-10' => t('10px'),
      'fs-11' => t('11px'),
      'fs-12' => t('12px'),
      'fs-13' => t('13px'),
      'fs-14' => t('14px'),
      'fs-15' => t('15px'),
      'fs-16' => t('16px'),
    ),
  );
}

保存文件之后浏览Appearance页面点击Grayscale主题的Settings连接。你应该能看见风格设置特性我们只加到了表单的底部,点击Font Settings连接展开这个表单,如图9-4.

Figure 9-4. The font settings options

流程的最终步骤是在主题中应用管理员选择了的值,我们通过在我们主题的$classes变量中增加字体族和字体大小的设置来完成这些。要增加这些值,我们需要建立template.php文件,这个文件用来做各式各样的主题处理,这个文件的细节我们在本章后面在细看,现在,我们在Grayscale目录中建立template.php文件,并加一个hook_process_HOOK()函数来将其参数增加到$classes变量。hook_process_HOOK()函数名叫grayscale_process_html(),这里grayscale是主题名,html是我们想覆写的.tpl.php文件的名字,我们还能用hook_process_HOOK()覆写任何其它的主题文件。

<?php

/**
 * Override or insert variables into the html template.
 */
function grayscale_process_html(&#vars) {
  // Add classes for the font styles.
  $classes = explode(' ', $vars['classes']);
  $classes[] = theme_get_setting('font_family');
  $classes[] = theme_get_setting('font_size');
  $vars['classes'] = trim(implode(' ', $classes));
}

设置完变量之后,它们将被应用到html.tpl.php文件中并通过$calsses变量应用到body标签上,html.tpl.php文件在modules/system目录中,是核心的一部分,本章后面我将给你展示怎样覆写核心模板包括这个html.tpl.php文件。

<body class="<?php print $classes; ?>" <?php print $attributes; ?>>

如果你列印了$calsses的值,你应该看到,如果你没改变字体族和字体大小的默认值,下面的值: html front logged-in one-sidebar sidebar-first page-node toolbar toolbar-drawer ff-sss fs-12 你能看到ff-sss和fs-12已经加到了$classes变量的结尾。剩下唯一的东西是为每个选项建立CSS,我们更新css/style.css文件来包含我们在先前建立的theme-settings.php文件中定义的每个选项的风格。

/* font family */
.ff-sss {font-family: "Helvetica Nueue", "Trebuchet MS", Arial, "Nimbus Sans L", FreeSans, sans-serif;}
.ff-ssl {font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;}
.ff-a {font-family: Arial, Helvetica, sans-serif;}
.ff-ss {font-family: Garamond, Perpetua, "Nimbus Roman No9 L", "Times New Roman", serif;}
.ff-sl {font-family: Baskerville, Georgia, Palatino, "Palatino Linotype", "Book Antiqua", "URW Palladio L", serif;}
.ff-m {font-family: "Myriad Pro", Myriad, Arial, Helvetica, sans-serif;}
.ff-l {font-family: "Lucida Sans", "Lucida Grande", "Lucida Sans Unicode", Verdana, Geneva, sans-serif;}
 
/* Base fontsize */
.fs-10 {font-size:0.833em}
.fs-11 {font-size:0.917em}
.fs-12 {font-size:1em}
.fs-13 {font-size:1.083em}
.fs-14 {font-size:1.167em}
.fs-15 {font-size:1.25em}
.fs-16 {font-size:1.333em}

试着访问Appearance页面并点击Grayscale主题的Settings连接,改变一下设置,看看变化。

理解模板文件

一些主题包含所有类型的模板文件,而另一些,就像我们的Grayscale主题,只有.info和.css文件,主题所需要的模板文件数量依赖于你想定制多少对应于标准Drupal模板的多样的组成部分。当你审视不同的模板文件,记住,如果你的主题没有提供一个这里所说的模板文件,Drupal自己讲使用包含在Drupal核心中的为每个内容(如page node comment field)分配的模板文件,我将在下面的章节讲述这些文件。

      重点

与给定的Drupal主题有联系的是几个tpl.php文件,一些主题只提供基本的html.tpl.php文件,你可以将它想象为包含所有传统的HTML站点的<body>之上的所有东西,而page.tpl.php你可以认为它包含着传统的基于HTML站点的<body>与</body>之间的每一样东西。有些主题利用Drupal的高级功能通过提供单独的主题文件来主题化独立的页面成分,例如下面       + node.tpl.php:此文件定义节点是如何在页面上渲染       + field.tpl.php:此文件定义字段是如何在页面上渲染       + block.tpl.php:此主题文件定义区块如何在页面上渲染 html.tpl.php是所有模板文件的祖父,为站点提供全部的页面布局,其它的模板文件嵌入page.tpl.php,如下面图9-5:

Figure 9-5. Other templates are inserted within the encompassing page.tpl.php file. html.tpl.php、page.tpl.php、block.tpl.php、node.tpl.php和field.tpl.php的嵌入在页面构建时由主题系统自动发生,如果你的主题没有包含一个或所有的上述文件,Drupal使用下表内的内核自带的模板文件:

---------------------------------------------------------------------------------------------------------------------------------------- Template file                 location                           Description ---------------------------------------------------------------------------------------------------------------------------------------- html.tpl.php                   modules/system               站点主模板文件,包含所有<head></head>之间的元素 page.tpl.php                  modules/system             定义包含在<body></body>之中,包括二者的所有东西,                                                                             当同主页面布局全部结构工作时要修改这个文件 region.tpl.php                dules/system                  定义站点上区域怎样布局和渲染 node.tpl.php                  modules/node                 定义站点上节点如何布局和渲染 block.tpl.php                 modules/block                 定义站点上区块如何布局和渲染 field.tpl.php                   modules/field/theme        定义站点上的字段如何布局和渲染 ---------------------------------------------------------------------------------------------------------------------------------------- 在为你的Grayscale主题建立这些模板文件的自定义版本之前,让我们简要介绍一下列出来的核心模板文件的结构和内容。

      html.tpl.php文件

这是在站点上显示基本的HTML结构的默认模板,这个主题文件的焦点在<html>标签和<body>标签之间的元素,在下面的代码中,你能看见html.tpl.php文件提供的元素,如DOCTYPE定义、RDF定义、HTML、少量DIV标签以及PHP代码片段,它打印分配给不同变量的内容,它们定义在表9-2中,虽然模板文件相对简单,但是它演示了Drupal主题的力量,和通过在运行时设置各种变量的值来显示动态内容及主题引擎用内容替换这些值的能力。这些变量的值可以通过内容如URL参数来设置,无论用户是匿名的还是已经登录的,用户规则是如果他登录进站点,其它内容,就是定义为应显示在站点上的帮助。我们将看见审视其它的模板文件,但是重要的是理解那一小片PHP代码的意义,你可以在这看到html.tpl.php的例子:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
  "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language; ?>"
  version="XHTML+RDFa 1.0" dir="<?php print $language->dir; ?>"<?php print $rdf_namespaces; ?>>

<head profile="<?php print $grddl_profile; ?>">
  <?php print $head; ?>
  <title><?php print $head_title; ?></title>
  <?php print $styles; ?>
  <?php print $scripts; ?>
</head>
<body class="<?php print $classes; ?>" <?php print $attaibutes; ?>>
  <div id="skip-link">
    <a href="#main-content"><?php print t('Skip to main content'); ?></a>
  </div>
  <?php print $page_top; ?>
  <?php print $page; ?>
  <?php print $page_bottom; ?>
</body>
</html>

表9-2列出了所有的通过不同模板的处理器和预处理器函数而可用于html.tpl.php文件的变量。如$css变量包含当前页面所有CSS文件的列表,这些CSS文件定义在.info文件中,用的是stylesheets[all]。

------------------------------------------------------------------------------------------------------------------------------------------------- 注意:为每个模板文件列出的变量表示这些变量可用于这个模板,你不需要在你的模板文件中使用全部的变量, 而只使用你的函数和技术需求所必需的,而在html.tpl.php中使用的变量是例外。 -------------------------------------------------------------------------------------------------------------------------------------------------

表9-2 Variables That Are Available for Use Within the  html.tpl.php File ------------------------------------------------------------------------------------------------------------------------------------------------- Variable                      Description of contents ------------------------------------------------------------------------------------------------------------------------------------------------- $css                          当前页面的CSS文件的数组 $language                     (对象)站点开始时使用的语言 $language->language           包含语言的文本化描述 $language->div                语言的方向,它是“ltr”或“rtl”之一 $rdf_namescapces              在此HTML文档中使用的所有RDF名称空间前缀 $grddl_profile                一个GRDDL的profile,允许代理扩展RDF数据 $head_title                   可修改的页面抬头,用于title标签 $head                         构造head段,包括meta标签、keyword标签等等 $styles                       style标签,页面导入所有必需的CSS文件 $scripts                      script标签,页面要加载的javascript文件和设置 $page_top                     初始化从任何改变页面的模块来的makeup,这个变量永远要首先输出,在所有                                        动态内容之前 $page                         渲染页面内容;Drupal用page.tpl.php的内容来替换$page $page_bottom                  最终关闭从任何改变页面的模块来的makeup,这个变量永远要最后输出,在所有                               动态内容之后 $classes                      CSS类字符串,默认的$classes字符串包含下面这些:html front logged-in                               one-sidebar sidebar-first page-node toolbar toolbar-drawer,其中的                               每一个都能用来作为DIV id和类的后缀 -----------------------------------------------------------------------------------------------------------------------------------------------

      page.tpl.php文件

下一个模板文件我们将讲page.tpl.php文件。这个模板文件注重的是那些显示在<body>和</body>标签之间元素和包含页面的HTML结构,包括DIV标签及php代码片段。如果我们回头看看html.tpl.php模板,你将看到<?php print $page; ?>这里的$page值就是page.tpl.php的内容。 这个模板文件定义显示给用户的页面结构,如果你回头看这本章开头的例子,所有我们在Grayscale主题中为其加风格的元素都是用page.tpl.php模板渲染的元素。在下面的代码中,你将看到这个页面上渲染的所有元素以及确定什么可以在页面上显示与页面怎样结构化的条件逻辑。就像html.tpl.php文件一样,page.tpl.php文件由HTML和php片段混合而成,这里的php片段包括条件逻辑来确定一个值是否设定和显示几个变量分配的值,这里的变量可以包含任何东西,从简单如“42”到复杂的HTML结构包括Javascript代码。一个例子是:page.tpl.php文件包含的第一个变量是$logo,这个值使HTML必须显示站点的logo,如果有,这就是为什么条件逻辑去测试是否提供了logo。 /modules/system中的page.tpl.php文件结构如下:

<div id="page-wrapper"><div id="page">
  <div id="page-header"><div class="section clearfix">
    <?php if ($logo): ?>
      <a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home" id="logo">
        <img src="<?php print $logo; ?>" alt="<?php print t('Home'); ?>" />
      </a>
    <?php endif; ?>

    <?php if ($site_name || $site_slogan): ?>
      <div id="name-and-slogan">
        <?php if ($site_name): ?>
          <?php if ($title): ?>
            <div id="site-name"><strong>
              <a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home"><span><?php print $site_name; ?></span></a>
            <strong></div>
          <?php else: ?>
            <h1 id="site-name">
              <a href="<?php print $front_page; ?>" title="<?php print t('Home'); ?>" rel="home"><span><?php print $site_name; ?></span></a>
            </h1>
          <?php endif; ?>
        <?php endif; ?>
        <?php if ($site_slogan): ?>
          <div id="site-slogan"><?php print $site_slogan; ?></div>
        <?php endif; ?>
      </div> <!-- #name-and-slogan -->
    <?php endif; ?>
    <?php print reader($page['header']); ?>
  </div></div> <!-- /.section, /#header -->

  <?php if ($main_menu || $secondary_menu): ?>
    <div id="navigation"><div class="section">
      <?php print theme('link__system_main_menu', array('links' => $main_menu,
      'attaibutes' => array('id' => 'main-menu', 'class' => array('links', 'clearfix')), 'heading' => t('Main_menu'))); ?>
      <?php print theme('link__system_secondary_menu', array('links' => $secondary_menu,
      'attributes' => array('id' => 'secondary-menu', 'class' => array('links', 'clearfix')), 'heading' => t('Secondary_menu'))); ?>
    </div> <!-- /.section, /#navigation -->
  <?php endif; ?>

  <?php if ($breadcrumb): ?>
    <div id="breadcrumb"><?php print $breadcrumb; ?></div>
  <?php endif; ?>

  <div id="main-wrapper"><div id="main" class="clearfix">
    <div id="content" class="column"><div class="section">
      <?php if ($page['highlighted']): ?><div id="highlighted">
        <?php print render($page['highlighted']); ?></div>
      <?php endif; ?>
      <a id="main-content"></a>
      <?php print render($title_prefix); ?>
      <?php if ($title): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?>
      <?php print render($title_suffix); ?>
      <?php if ($tabs): ?><div class="tabs"><?php print render($tabs); ?></div><?php endif; ?>
      <?php print render($page['help']); ?>
      <?php if ($action_links): ?><ul class="action-links"><?php print render($action_links); ?></ul><?php endif; ?>
      <?php print render($page['content']); ?>
      <?php print $feed_icons; ?>
    </div></div> <!-- /.section, /#content -->

    <?php if ($page['sidebar_first']): ?>
      <div id="sidebar-first" class="column sidebar"><div class="section">
        <?php print render($page['sidebar_first']); ?>
      </div></div> <!-- /.section /#sidebar-first -->
    <?php endif; ?>
    <?php if ($page['sidebar_secondary']): ?>
      <div id="sidebar-secondary" class="column sidebar"><div class="section">
        <?php print render($page['sidebar_secondary']); ?>
      </div></div> <!-- /.section /#sidebar-secondary -->
    <?php endif; ?>
  </div></div> <!-- /#main /#main-wrapper -->

  <div id="footer"><div class="section">
    <?php print render($page['footer']); ?>
  </div></div> <!-- /.section, /#footer -->
</div></div> <!-- /#page, /#page-wrapper -->

page.tpl.php文件中可用的默认变量见表9-3:

------------------------------------------------------------------------------------------------------------------------------------------------- Variable                      Description of contents ------------------------------------------------------------------------------------------------------------------------------------------------- $base_path                    Drupal安装的基本路径,最近这个路径总是默认为/ $directory                    模板所在路径,例如modules/system或theme/bartik $is_front                     如果当前页面是首页则为TRUE $logged_in                    如果用户注册并登录则为TRUE $is_admin                     如果用户有权限访问管理页面则为TRUE $front_page                   首页的URL,连接到首页时用它替代$base_path,它包括语言域或前缀 $logo                         logo图片的路径 $site_name                    站点名称,如果主题禁用则为空 $site_slogan                  站点口号,如果主题禁用则为空 $main_menu(array)             包含站点主菜单连接的数组 $secondary_menu(array) $breadcrumb $title_prefix                 包含模块的附加输出数组,准备去显示在呈现在模板中的主标题标签之前 $title                        页面标题 $title_suffix                 包含模块的附加输出数组,准备去显示在呈现在模板中的主标题标签之后 $message                      状态和错误信息 $tabs(array)                  选项卡连接到当前页面下的任一子页面 $action_links(array)          例如管理员界面的“Add menu” $feed_icons                   当前页面所有供稿图标的字符串 $node                         节点对象,如果这是自动载入的页面分配的节点,并且节点ID是页面路径的                               第二个参数(如node/123和node/123/revisions但不是comment/reply/123) -------------------------------------------------------------------------------------------------------------------------------------------------

变量$page['help'],$page['highlighted'],$page['content'],$page['sidebar_first'],$page['sidebar_second'],$page['header'],$page['footer']呈现为页面区域,一个区域呈现为一个物理容器,站点管理员能分配任何一个区块级元素到那里(例如logon表单、搜索区块、一个节点、一个视图或一个菜单)。如果在你的主题.info文件中没有特别指定任一个区域,你只能获得默认的区域,在后面的章节我将讲述建立附加的区域及怎样构建你的主题.info文件。

      region.tpl.php文件

此模板文件关注你的站点怎样显示区域(region),默认的region.tpl.php文件十分简单——基本上就是显示分配给一个区域的内容。

<?php if ($content): ?>
  <div class="<?php print $classes; ?>
    <?php print $content; ?>
  </div>
<?php endif; ?>

这个模板文件默认的可用变量见表9-4:

------------------------------------------------------------------------------------------------------------------------------------------------- Variable                      Description of contents ------------------------------------------------------------------------------------------------------------------------------------------------- $content                      区域的内容,典型的是区块 $classes                      可以用CSS进行风格化内容的类字符串,它能被预处理函数通过$classes变量操作                               典型的值是下面一个或多个:                               regions                               当前模板类型如"theming hook"                               region-[name]:就是将下划线的区域名称换成带横杠的,如page_top区域的类是region-page-top $region                       region变量的名字,就是定义在.info文件中的 $classes_array                HTML类属性的数组,它被平整化到变量$classes字符串中 $is_admin $is_front $logged_in -------------------------------------------------------------------------------------------------------------------------------------------------

      node.tpl.php文件

这个模板文件定义个体的节点如何在站点上显示,默认的node.tpl.php文件在目录modules/node中。在下面的列表中,你能看见元素类似前面讨论过的其它模板文件,明显地HTML和php片段执行条件逻辑并打印分配给变量的值,在node.tpl.php中你还能看到模板打印出分配给变量$content的值——这种情况下是独立的节点,你还能注意到模板使用“hide”来移除两个正常本应该在节点渲染时显示在页面上的元素——就是评论和分配给节点的连接,节点通过hide($content['comments'])和hide($content['links'])来完成这些,这么做的原因是我们通常想在节点显示时控制评论和连接在哪里渲染,通过先隐藏他们,然后再显示它们(使用print render($content['comments'])和print render(content['links']))。你能使用这种途径去隐藏任何本应该显示的东西的元素,使用hide()函数,如果你想在以后显示这些元素,你可以使用print render()函数。

<div id="node-<?php print $node->nid; ?>" class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
  <?php print $user_picture; ?>
  <?php print rebder($title_prefix); ?>
  <?php if (!page): ?>
    <h2<?php print $title_attributes; ?>><a href="<?php print $node_url; ?>"><?php print $title; ?></a></h2>
  <?php endif; ?>
  <?php print render($title_suffix); ?>

  <?php if ($display_submitted): ?>
    <div class="submitted">
      <?php
        print t('Submitted by !username on !datetime, array('!username' => $name, '!datetime' => $date));
      ?>
    </div>
  <?php endif; ?>

  <div class="content"<?php print $content_attributes; ?>>
    <?php
      // We hide thw comments and links now so that we can render them later.
      hide($content['comments']);
      hide($content['links']);
      print render($content);
    ?>
  </div>

  <?php print render($content['links']); ?>
  <?php print render($content['comments']; ?>
</div>

在模板文件node.tpl.php中可用的变量见表9-5

------------------------------------------------------------------------------------------------------------------------------------------------- Variable                           Description of contents ------------------------------------------------------------------------------------------------------------------------------------------------- $title                             标题的(消毒化)版本 $content(array)                    节点开始显示时产生的元素的数组,如果你要显示全部的节点内容                                    请使用render($content),或者像先前解释的用hide()和show()函数                                    来显示节点对象的单独元素 $user_picture                      节点作者的图片,来自user-picture-tpl.php $date                              格式化的创建时间,预处理函数可以用format_date()带$created参数来                                    重新格式化 $name                              由theme_username()主题化的所有者名称 $node_url                          当前节点的URL $display_submitted                 $classes                           CSS类字符串,它能在预处理函数中通过$classes_array来操作,默认的值                                    可以是下面一个或多个                                    node:当前模板类型,如“theming hook”                                    node-[type]:当前节点类型,例如,如果节点是Blog entry,它就应该是                                    “node-blog”                                    node-teaser:节点是预告表单                                    node-preview:酒店节点是预览模式                                    下面这些是通过节点发布选项控制                                    node-promoted:节点生到首页                                    node-sticky:在预告列表中节点始终在首位                                    node-unpubkished:未发布节点版本,只给管理员 $title_prefix(array)              $title_suffix(array) $node                              完整的node对象 $type                              节点的类型,如:story,page,blog等 $comment_count                     一个节点评论的数量 $uid                               节点作者的用户UID $created                           节点发布时的UNIX时间戳 $classes_array                     HTML类属性值的数组,它平整化进变量$classes字符串中 $zebra                             输出奇偶,用于预告列表的条纹化输出 $id                                节点的位置,每次输出的增量 $view_mode                         查看模式,如full或teaser $page                              全页状态标志(TRUE或FALSE) $promote                           提升到主页的状态标志(TRUE或FALSE) $sticky $status                            发布状态标志 $comment                           节点的评论设置状态 $readmode                          标志,如果预告内容不能显示完全部内容则设为TRUE,就是readmore $is_front $logged_in $is_admin -------------------------------------------------------------------------------------------------------------------------------------------------

      field.tpl.php文件

这个模板文件用来主题化字段,不像前面讲的模板,当渲染字段时它不被Drupal自动调用,你要想使用这个模板,就要将它从/module/fields/templates拷贝到你的主题目录下。

<div class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
  <?php if (!$label_hidden) : ?>
    <div class="field-label"<?php print $title_attributes; ?>>
      <?php print $label ?>:&nbsp;</div>
  <?php endif; ?>
  <div class="field-items"<?php print $content_attributes; ?>>
    <?php foreach ($items as $delta => $item) : ?>
      <div class="field-item <?php print $delta % 2 ? 'odd' : 'even'; ?>" <?php print $item_attributes[$delta]; ?>>
        <?php print render($item); ?>
      </div>
    <?php endforech; ?>
  </div>
</div>

模板文件field.tpl.php中可用的默认变量如下表: ------------------------------------------------------------------------------------------------------------------------------------------------- Variable                           Description of contents ------------------------------------------------------------------------------------------------------------------------------------------------- $items                             字段值数组;使用render()去输出他们 $label                             项目标签 $label_hidden                      一个标志,用于设置是否显示标签 $classes                           CSS类字符串,能通过CSS操作,能通过预处理函数的变量$classes数组操作                                    默认的值是以下一个或多个值                                    field:当前模板类型,如“theming hook”                                    field-name-[filed_name]:当前字段名。例如字段名是field_description,那么他就                                    应该是field-name-field-description                                    field-type-[field_type]:当前字段类型,如如果字段类型是text,那么它就应该是                                    field-type-text                                    field-label-[field_display]:当前标签位置,例如,如果标签位置是above,它就应该是                                    field-label-above $element['#object']                字段所附加到的实体 $element['#view_mode']             字段附加到的实体的查看模式,如full或teaser $element['#field_name']            字段名称 $element['#field_type']            字段类型 $element['#field_language']        字段语言 $element['#field_translatable']    字段是否可翻译 $element['#label_display']         标签显示的位置:inline,above,hidden $field_name_css                    CSS兼容的字段名 $field_type_css                    CSS兼容的字段类型 $classes_array                     HTML类属性值的数组,它平整化进变量$classes字符串中 -------------------------------------------------------------------------------------------------------------------------------------------------

      block.tpl.php文件

block层主题模板,block.tpl.php位于modules/block目录中,依据这一点,你应该看到一个明确的模式构建的模板文件

<div id="<?php print $block_html_id; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>>
  <?php print render($title_prefix); ?>
  <?php if ($block->subject) : ?>
    <h2<?php print $title_attributes; ?>><?php print $block->sybject ?></h2>
  <?php endif; ?>
  <?php print render($title_suffix); ?>
  <div class="content"<?php print $content_attributes; ?>>
    <?php print $content; ?>
  </div>
</div>

模板文件block.tpl.php中可用的默认变量见表9-7

------------------------------------------------------------------------------------------------------------------------------------------------- Variable                           Description of contents ------------------------------------------------------------------------------------------------------------------------------------------------- $block->subject                    区块标题 $content                           区块的内容 $block->module                     生成区块的模块 $block->delta                      block的ID,每个模块中唯一 $block->region                     封装当前区块的区域 $classes                           CSS类字符串,能通过CSS操作,能通过预处理函数的变量$classes数组操作                                    默认的值是以下一个或多个值                                    block:当前模板类型,如"theming hook"                                    block-[module]:生成区块的模块,例如,用户模块提供处理默认的用户导航区块,                                    这种情形下,它应该是block-user $title_prefix(array) $title_suffix(array) $classes_array(array)              HTML类属性值的数组,它平整化进变量$classes字符串中 $block_zebra $blcok_id                          依赖于每个区块的区域 $is_front $logged_in $is_admin $block_html_id                     生成的唯一的有效的HTML的ID -------------------------------------------------------------------------------------------------------------------------------------------------

      覆写模板文件

可能看到有时你需要修改page.tpl.php,node.tpl.php或其它任何一个标准模板文件来决定怎样在你的站点上显示元素,让我们回过头看一下Grayscale主题,自定义page.tpl.php文件使之在用户在主页浏览时显示一条欢迎信息,如果用户不在主页上,就不显示欢迎信息。开始的处理是将page.tpl.php文件从module/system目录拷贝到sites/all/themes/grayscale/templates目录,通过拷贝它到我们主题的目录,Drupal将使用我们版本的page.tpl.php,而不是modules/system下的那个。 修改起来相对简单,我们使用$is_front变量送给模板文件,通过条件解析,检查浏览者是不是在主页上,如果在,就显示“Welcome to My Site”,打开文件,找到下面一行:

<div id="content" class="column"><div class="section">

直接到这行后面,插入下面代码,它用变量$is_front检查浏览者是否在主页,如果是,则打印出一条欢迎信息:

<?php
  if ($is_front) : ?><div id="welcome_message">
    <?php print "Welcome to My Site"; ?></div>
<?php endif; ?>

结果是“Welcome to My Site”打印在第二个菜单之下,没什么激动人心的,但是它演示了标准page.tpl.php文件和自定义的杠杆作用概念。

---------------------------------------------------------------------------------------------------------------------------------------------------- 注意:如果你自定义的page.tpl.php文件没有效果,导航到admin/config/development/preformace并清除缓存 ----------------------------------------------------------------------------------------------------------------------------------------------------

你还能为站点特定的页面创建自定义的.tpl文件,例如,你能拷贝page.tpl.php并建立一个page--front.tpl.php文件,这个新模板只能应用到你站点的主页。你还能用node.tpl.php做同样的事情,比如你要给article节点做个与其它节点不同的主题形式,你可以从modules/node拷贝node.tpl.php文件到你的主题目录并重命名为node--article.tpl.php,如果节点是article,那么这个新的模板文件将覆写node.tpl.php,对于另外的细节,请浏览http://drupal.org/documentation/theme上的主题指南。

----------------------------------------------------------------------------------------------------------------------------------------------------- 注意:这里在node和article中间是两个横杠,Drupal要求两个横杠。 -----------------------------------------------------------------------------------------------------------------------------------------------------

      其它模板文件

通过浏览站点的模块和主题目录,你可以看到几个其它的模板文件,比如,comment模块使用comment.tpl.php来渲染评论,comment模块创建了几个变量,并将这些变量送进comment.tpl.php文件。comment.tpl.php文件的指定就如同评论的模板文件是通过以'template' => 'comment'为参数调用hook_theme()生成的一样,'template' => 'comment'是作为数组中的一个值(见下面代码),这里不需要指定.tpl.php扩展名,如同Drupal猜中你的意思一样。我将讲一些怎样去建立变量并将变量送到你的模板文件的具体细节。

/**
 * Implements hook_theme().
 */
function comment_theme() {
  return array(
    'comment_block' => array(
      'variables' => array(),
    ),
    'comment_preview' => array(
      'variables' => array('comment' => NULL),
    'comment' => array(
      'template' => 'comment',
      'render element' => 'elements',
    ),
    'comment_post_forbidden' => array(
      'variables' => array('node' => NULL),
    ),
    'comment_wrapper' => array(
      'template' => 'comment-wrapper',
      'render element' => 'content',
    ),
  );
}

      theme()函数简介

当Drupal想为一个可主题化项目(如一个节点、一个区块、一个面包屑踪迹、一个评论、或一个用户签名)生成某些HTML输出,它将查找将要为此项目生成输出的主题函数或模板文件。Drupal差不多所有部分都是可主题化的,这意味着你能你能覆写为此项目生成的实际的HTML,一会我们看看例子。

---------------------------------------------------------------------------------------------------------------------------------------------- Tip:Drupal的所有可主题化项目列表,请见http://api.drupal.org/group/themeable/7 ----------------------------------------------------------------------------------------------------------------------------------------------

      theme()工作流概览

这是一个简单的节点页面,如http://example.com/?q=node/3显示的时候发生的情况的高层概览:

      1. Drupal的菜单系统接收请求并将控制放手给node模块       2. 在建立了节点数据结构之后,theme('node', $wariables)被调用。它找到恰当的主题函数或模板文件          定义模板可用的变量,并且应用这个模板,结果是完成了节点的HTML(如果有多个节点要显示,那么这个          处理过程为每个节点来一次)       3. 一个HTML结构返回(你能在index.php中看到它是作为$return变量)并且再次传递给theme()函数,就像          theme('page', $return)       4. 在处理页面模板前,Drupal做一些预处理,诸如发现哪些区域是可用的及每个区域应该显示哪些区块,每          每个区块是通过调用theme('blocks', $region)来转换进HTML的,它定义变量并应用一个区块模板,你可          以在这里看见一些模式       5. 最终,Drupal为页面模板定义变量并应用页面模板

你可以从theme()处理流程看出,theme()函数对于Drupal是多么重要,它负责运行预处理函数来设置将在模板中应用的变量,并且安排一个主题调用恰当的函数或找出一个恰当的模板文件,结果是HTML。我们将在后面深层次看一下这个函数怎样工作,现在已足够理解当Drupal想去把节点转换进HTML时发生的事情:theme('node', $variables = array())被调用。依赖于是哪个主题被激活,theme_node()生成HTML或者用名字叫node.tpl.php的模板文件完成这些。 这个处理可以在许多层次被覆写,例如,主题能覆写内建的主题函数,那样的话,当theme('node', $variables = array())被调用,一个叫grayscale_node()的函数可以代替theme_node()来处理它。模板文件命名规则我们稍后再看,一个node--story.tpl.php的模板文件只能影响story类型的节点。

      覆写可主题化项目

正如你所见,可主题化项目是由它们的函数名来识别的,它们都以theme_开头,或者项目有一个模板文件(标准的可主题化项目见 http://api.drupal.org/api/group/themeable/7),命名规则使Drupal有能力为所有可主题化函数建立一个函数-覆写机制。设计者能指示Drupal去执行一个函数,优先于模块开发者指定的主题函数,或者覆盖Drupal的默认模板。让我们看看当构建站点面包屑时处理工作是怎样的。 打开includes/theme.inc,检查文件中的函数,这里许多函数都是以theme_开头,明显它们能被覆写,让我们检查下theme_breadcrumb()函数:

/**
 * Returns HTML for a breadcrumb trail.
 *
 * @param $variables
 *   An associative array containing:
 *   - breadcrumb: A array containing the breadcrumb links.
 */
function theme_breadcrumb($variables) {
  $breadcrumb = $variables['beradcrumb'];

  if (!empty($breadcrumb)) {
    // Provide a navigational heading to give context for breadcrumb links to
    // screen-reader users. Make the heading invisible with .element-invisible.
    $output = '<h2 class="element-invisible">' . t('You are here') . '</h2>';

    $output .= '<div class="breadcrumb">' . implode(' >> ', $breadcrumb) . '</div>';
  }
}

这个函数控制站点面包屑导航的HTML,一般来讲,它在每个面包屑踪迹之间增加一个右向的双箭头,假设你想把<div>标签改为<span>标签,同时用一个星号代替双箭头。该怎么做呢?有一种解决方案,编辑theme.inc中的这个函数,保存它,调用它。(不!不!,绝不要怎么做)这有更好的方案。 你曾经见过在核心中如何调用,你绝没有见过直接调用theme_breadcrumb(),作为替代,它总是封装进theme()助手函数,你希望函数如下面方式调用: theme_breadcrumb($variables) 其实不然,你将见到开发者这样调用 theme('breadcrumb', $variables); 通用的theme()函数为初始化主题层负责,并且在恰当的地方安排函数调用,给我们带来优雅的解决问题的方案。调用theme()函数使Drupal按下面的顺序查找breadcrumb函数。 假设你使用的主题是Grayscale,是以PHPTemplate为基础的主题,Drupal应按下面顺序查找(我们先忽略breadcrumb.tpl.php一下):

grayscale_breadcrumb()
sites/all/themes/grayscale/breadcrumb.tpl.php
them_breadcrumb()

你主题的template.php文件在这覆写Drupal默认的主题函数,并且拦截和建立自定义变量传递给模板文件。

---------------------------------------------------------------------------------------------------------------------------------------------------- 注意:在做这个例子时,不要使Bartik作为活动主题,因为Bartik已经有一个template.php文件 ----------------------------------------------------------------------------------------------------------------------------------------------------

要调整Drupal面包屑,建立(或更新,如果你在前面的例子中建了一个的话)一个sites/all/themes/grayscale/template.php文件,拷贝粘贴theme.inc中的theme_breadcrumb()函数,确保包括<?php标签,还有将theme_breadcrumb改为grayscale_breadcrumb,下一步,点击菜单的Modules连接,Drupal就会重建主题注册,发现你的新函数。

<?php

/**
 * Returns HTML for a breadcrumb trail.
 *
 * @param $variables
 *   An associative array containing:
 *   - breadcrumb: A array containing the breadcrumb links.
 */
function grayscale_breadcrumb($variables) {
  $breadcrumb = $variables['beradcrumb'];

  if (!empty($breadcrumb)) {
    // Provide a navigational heading to give context for breadcrumb links to
    // screen-reader users. Make the heading invisible with .element-invisible.
    $output = '<h2 class="element-invisible">' . t('You are here') . '</h2>';

    $output .= '<div class="breadcrumb">' . implode(' >> ', $breadcrumb) . '</div>';
  }
}

下面,如果你用Grayscale,在css/style.css中加入:

.breadcrumb {
  margin-top: 10px;
  clear: both;
  height: 15px;
  backgound-color: #fff;
  width: 960px;
  margin-right: auto;
  margin-left: auto;
}

下一时间Drupal去格式化面包屑踪迹,它首先找到你的函数并用它老代替默认的theme_breadcrumb()函数,面包屑将用星号来代替Drupal默认的双箭头。通过给theme()传递所有主题函数,Drupal总是检查当前的主题是否覆写任何一个theme_函数,有就调用它们。

-------------------------------------------------------------------------------------------------------------------------------------------------- 注意:你主题中任何输出HTML或XML的部分,都应包含进theme函数中,这样它们能被做主题的访问到来覆写它们。 --------------------------------------------------------------------------------------------------------------------------------------------------

      用Template文件覆写

如果你和一个设计师工作,告诉他“只要进入代码并找到可主题化函数并覆写”,这不是问题,幸运的是,有另外的方式来得到更容易的设计师方式,你能将可主题化项目放进他们自己的模板文件,我将利用手头的面包屑例子来做演示。

在我们开始之前,确认没有主题函数覆写了theme_breadcrumb(),如果我们在前面章节中在主题的template.php文件里建立了grayscale_breadcrumb()函数,请注释掉它,建立文件sites/all/themes/grayscale/breadcrumb.tpl.php,这是一个新的模板文件,因为我们想将<div>标签改成<span>标签,在文件中输入:

<?php if (!empty($breadcrumb)) : ?>
  <span class="breadcrumb"><?php print implode('!', $breadcrumb) ?></span>
<?php endif; ?>

这对设计师来说就足够简单了,现在你需要让Drupal知道在渲染breadcrumb时找到这个模板文件,为此,需要清空缓存,Drupal将发现你的breadcrumb.tpl.php文件,并且映射面包屑可主题化项目到这个模板文件。 现在你知道怎样在Drupal中以设计师的喜好来覆写任意的可主题化项目。

      增加和操作模板变量

在这个例子中,我们看一下操作或增加传递进页面或节点模板的变量,让我们继续前面的例子。修改sites/all/themes/grayscal/breadcrumb.tpl.php,用一个叫$breadcrumb_delimiter的变量来为面包屑定义分隔符。

<?php if (!empty($breadcrumb)) : ?>
  <span class="breadcrumb">
    <?php print implode(' ', $breadcrumb_delimiter . ' ' $breadcrumb); ?>
  </span>
<?php endif; ?>

要设置这个$breadcrumb_delimiter变量,一个选择是在模块中,我们建立一个sites/all/modules/crumbpicker.info:

name = Breadcrumb Picker
description = Provide a character for the breadcrumb trail delimiter.
package = Pro Drupal Development
core = 7.x

crumbpicker.module应该很小:

<?php
/**
 * @file
 * Provide a character for the breadcrumb trail delimiter.
 */

/**
 * Implements $modulename_preprocess_$hook().
 */
function crumbpicker_preprocess_breadcrumb(&$variables) {
  $variables['breadcrumb_delimiter'] = '/';
}

在激活这个模块后,你可以看到面包屑踪迹的分隔符变成了/。 这个预处理例子刻画出一个模块设置一个模板文件使用的变量,但是应该有一个比建立模块更简单的方式来每次设置一个变量,果然,template.php文件前来救驾,让我们写一个函数来设置面包屑分隔符,写到主题的template.php文件里:

/**
 * Implements $themeenginename_preprocess_$hook().
 * Variables we set here will be available to the breadcrumb template file.
 */
function grayscale_precess_breadcrumb(&$variables) {
  $variables['breadcrumb_delimiter'] = '#';
}

这比建立模块简单、直白,模块方法通常最适合使存在的模块去提供模板变量;模块通常不是单单为此目的而写。现在,我们有一个模块提供一个变量、template.php中函数提供一个变量,通常使用的是哪个? 通常预处理函数层级运行于一个特定的循序,它们每一个都潜在地覆写前一个预处理函数已经定义的变量。在上面的例子中,面包屑分隔符应该是#,因为phptemplate_preprocess_breadcrumb()将在crumbpicker_preprocess_breadcrumb()之后执行,因此它分配的变量$breadcrumb_delimiter将覆写原先分配的变量。 对于使用Grayscale主题来主题化面包屑,实际的预处理顺序(第一个调用和最后一个调用)将是这样:

template_preprocess() template_preprocess_breadcrumb() crumbpicker_preprocess() crumbpicker_preprocess_breadcrumb() phptemplate_preprocess() phptemplate_preprocess_breadcrumb() grayscale_preprocess() grayscale_preprocess_breadcrumb() template_process()

因此,grayscale_preprocess_breadcrumb()能覆写任何一设置的变量,它在变量呗模板文件处理前最后一个调用。当这些函数只有部分实现时就调用所有这些函数在你看来是浪费时间,那你是正确的,在主题注册时,Drupal就确定了那些函数已实现了,并只调用它们。

      使用主题开发模块

一个Drupal主题开发的宝贵资源是developer模块,它是devel.module的一部分,并且可以从http://drupal.org/project/devel_themer下载,主题开发者模块在页面上指定一个元素,并发现那个模板或主题函数是用来建立这个元素的以及此元素可用的变量(和它的值)。

小结

读完本章之后,你应该可以:

      + 建立模板文件       + 覆写主题函数       + 操作模板变量       + 为区块建立新的页面区域 Drupal 7 主题其它的细节请查看http://drupal.org/documentation/theme上的主题手册页面。