欢迎莅临阿Q的项目

专业WP商业设计开发销售中心

[手册]Drupal 7 主题模板制作指南

Drupal是一个开源的内容管理系统(CMS) 平台,它是用PHP写成的。主要用于构造提供多种功能和服务的动态网站,这些功能包括用户管理(UserAdministration)、发布工作流 (Publishing Workflow)、讨论、新闻聚合(NewsAggregation)、元数据(Metadata)操作和用于内容共享的XML发布。Drupal有一个优秀的模块化结构,提供了许多模块,包括短消息、个性化书签、网站管理、Blog、日记、电子商务、电子出版、留言簿、Job、网上电影院、论坛、投票 等模块。并且Drupal模块的下载、安装、定制非常方便。

drupal中覆写可主题化的输出

原文:http://drupal.org/node/173880

译者:葛红儒,    Think in Drupal

只有当你需要修改默认输出时,你才需要阅读本节.如果你的显示层是完全有CSS样式表负责的,那么可以略过本节。

覆写主题输出,需要掌握3个方面。首先,你需要知道源头在哪里,其次你要进行覆写,最后你需理解它的类型。

注意,Drupal使用主题注册表(theme registry)来缓存主题数据覆写完成后,你必须清空缓存。

1. 寻找源头:

寻找主题输出的源头,是比较困难的,这是由于主题系统的多层级结构造成的,使得源头可能出现在系统的各个地方。

theme_tree

仅用来演示用。

大多数页面元素一般是由theme('page')拉进来的,在显示导航信息以后,它们被放置在page.tpl.php模板中。页面元素包括主菜单、区块区域元素,区域中的区块等等。通常通过一个主题钩子来引用每个大块的主题化数据。

注意:主题钩子现在包括主题函数和模板两部分。系统中的许多钩子都与主题无关。我们这里提到的钩子都是特定于主题的。

现在使用devel模块(devel module)可以很容易的追踪特定内容的源头。devel模块包含一个主题工具,可以方便的查勘任何输出的源头,类型以及其它主题相关数据。参看示范screencast(http://drupal.org/node/209561)。由于技术方面的限制,它只能应用到Drupal6以及更高版本中。

2. 覆写机制:

覆写机制有一个特定的级联顺序,当然也包含一些特殊情况。Drupal内核和模块使用主题钩子提供了一个合理的默认输出。如果默认输出不符合主题的需求的话,那么就可以对其进行覆写,从而避免使用默认输出。这样,默认的将被放到一边去,我们不再管它,而将所有的特定修改放到所用的主题目录下面。不要直接修改Drupal内核和模块,只在主题目录下面修改。

theme_overrides_0

如果传统的覆写不能满足你的需要的话,你可以使用主题注册表。

注意:尽管在Drupal 6中PHPTemplate.engine还存在,但它已不再覆写主题函数了。在Drupal5中,它允许使用模板来处理部分主题钩子。而现在则不必要这样了。

drupal主题函数 VS drupal模板

3.函数VS模板:

正如前面所说,实现特定的钩子有两种方式。通常的“函数”或者“模板”。根据要主题化的元素的特点,选用最合适的方式。drupal内核和模块可选用任何一种方式来构建输出。而上面的主题层,可以使用同样的方式来覆写,或者改变选用的方式。

theme_flow_6

使用函数来实现主题钩子,具有速度上的优势。通常比使用模板的快5倍,但是对们对于涉及者来说,就比较困难,通常涉及者都比较熟悉直接的xHTML,而不是php函数。通常,我们不需要考虑这样一点,而是根据钩子的特点和在一个页面中被调用的次数,来决定要选择的方式。

注意:在Drupal5及以前版本,内核和模块只能使用函数来实现主题钩子。想要使用模板的话,必须使用PHPTemplate来覆写钩子,并在引擎层中进行转换。

下面是覆写的两个例子,这里使用了devel themer.

函数方式:

主题函数theme_menu_local_tasks,是一个用来输出一级和二级标签的简单函数。这里的主题钩子就是"menu_local_tasks"。为了覆写它,可将函数名中的前缀"theme"替换为你主题的名字或者所用主题引擎的名字。最好使用主题的名字,这样可以避免潜在的与子主题(http://drupal.org/node/225125)的命名冲突。

function_override_example_2

本例中,Garland是使用引擎名来覆写的。如果你的主题是基于Garland的子主题,那么你必须使用你的主题名了。

将下面的代码放到主题的template.php,清空主题注册表缓存,这样就覆写了默认输出。注意,将"drop"改为你主题的名字。

 

[syntaxHighLighter brush="php"]

function drop_menu_local_tasks() {
    $output = '';

    if ($primary = menu_primary_local_tasks()) {
        $output .= "<ol class=\"tabs primary\">\n". $primary ."</ol>\n";
    }
    if ($secondary = menu_secondary_local_tasks()) {
        $output .= "<ol class=\"tabs secondary\">\n". $secondary ."</ol>\n";
    }

    return $output;
}

[/syntaxHighLighter]

这里所做的唯一修改就是将<ul>标签改为了<ol>。

api.drupal.org你可以找到所有的主题函数。

模板方式:

如果默认是使用模板实现的,那么你只需要简单得将模板源文件拷贝到主题下面,然后清空主题注册表,就完成了覆写。下面为search-theme-form.tpl.php的一个例子。注意在这里,主题钩子就是"search_theme_form",需要将连字符“-”替换为下划线“_”.

template_override_example_2

这就是你要做的。使用编辑器,打开拷贝的模板,对其进行修改。内核中的所有.tpl.php文件都带有注释。根据注释,你就可以做出具体的修改了。

注意:模板可以放在主题下面的任何目录中。这样便于管理,也避免了主题根目录下面的混乱。

相关页面:

  • 为了定制模板中的变量,参看自页面“预处理函数”(http://drupal.org/node/223430)。
  • 可以在子页面“核心模板和建议”(Core templates and suggestions)找到所有的主题模板。

将函数转化为模板

将一个主题函数转化为一个模板,开始是需要一点工作的,但一旦完成,便很好使用。如果你和设计者一同工作,那么转化为模板,将会使设计者更专注于设计,而不是编码。在内核中,已有了很多模板,而在将来的版本中,将有更多的主题函数转化为模板。第3方模块,为了与内核接轨,最好也使用模板。本部分是为那些还没有使用模板的主题钩子准备的。

Drupal以模板的方式识别主题钩子是自动完成的。下面是完成修改所需的所有必要条件:

  • 模板名必须与主题钩子匹配。
  • 主题钩子中的下划线必须改为连字符。
  • 模板文件必须使用扩展名".tpl.php"。(根据主题引擎的不同,扩展名会有所不同)

假如主题函数为theme_user_signature。这里的主题钩子就是"user_signature"。创建一个名为"user-signature.tpl.php"的文件,清空注册表,就会告诉Drupal现在钩子已改为模板方式了。现在该文件中的内容将替代相应的函数。这里的难点是,设置模板文件中用到的变量,这可以通过预处理函数来完成。

需要注意的一些点:

  • 可以在模板中直接放置代码,但这种方式不好。所有的复杂逻辑都应该从.tpl.php文件中分离出来。这样使得模板文件更干净,更便于管理。
  • 这也有安全方面的考虑。将逻辑与显示分离,可以避免潜在的恶意用户来创建内容,从而减小CSS(cross-site scripting)攻击的机会.当让你的设计者处理模板文价时,所有的输出都应该非常干净,这样设计者就不用考虑安全问题了。
  • 比较关于论坛的theming functions in 5template conversions in 6。你可以使用这个作为例子,来进行两种方式之间的转换。
  • 更多关于预处理函数的信息(http://drupal.org/node/223430)。

drupal主题注册表

原文:http://drupal.org/node/173880

译者:葛红儒, Think in Drupal,

Drupal的主体注册表维护了主题钩子相关的缓存数据,包含主题钩子和如何处理它们的信息。

对于大多数drupal主题开发者来说,都不需要直接与注册表打交道。只需要记住,当添加或者删除主题函数和模板时,要清空它。编辑已有的函数和模板时,则不需要清空。

清空主体注册表,有3方式:

  1. 位于"Administer > Site configuration > Performance"的clear按钮。
  2. 如果启用了devel区块(devel模块创建的),点击"Empty cache"连接。
  3. 使用API函数drupal_rebuild_theme_registry

drupal主题注册表是主题钩子相关信息的缓存数据,包括Drupal可用的主体钩子,勾子类型,即如何处理它们。在以前的版本中,所有的主题调用都是直接完成的。由于在底层需要进行大量的处理工作,而缓存可以加快这种处理,特别是对于模板而言。你主题用到的引擎应该为你自动的注册所有的主题钩子。

在一些特殊情况下,你需要直接与注册表打交道。如果你的drupal主题需要注册一个新的钩子,而该钩子不在底层中(内核,模块,引擎)。比如说一些表单,内核或者模块没有明确对其主体化,而仅仅使用了默认的表单输出。

  • 更多细节,参看子页面“特殊情况下的主题注册表”(The theme registry for special cases)。
  • 不要将主题注册表与主题的.info文件混淆了,两者都被缓存了。清空主题注册表的第1点和第2点,同时也清空了.info的缓存。
  • 预处理函数
  • 默认的基本变量
  • 特殊情况下的主题注册表
  • 使用模板建议(suggestions)
  • 核心模板和建议(suggestions)

drupal预处理函数

预处理函数仅适用于模板形式的主题钩子.它的主要作用是设置模板文件((.tpl.php)中所用到的变量。在预处理器(Preprocessor)中,一般涉及不到普通的主题函数。

注意:

  • 在提供模板建议(template suggestions)时也会用到预处理器。
  • 在drupal5中,函数_phptemplate_variables提供了同样的功能,在drupal6中,为了以后版本的兼容性,最好不要用这个函数。

对于单个主题钩子,可以有多个预处理器。内核,模块,引擎,主题,每层都可以有一个预处理器,来逐步的构建显示在模板文件中的变量集。通过将大部分逻辑放到这些预处理器中,可使得模板文件更加简洁,易于使用。

下面是预期的预处理器。当它们同时存在时,按照下面的顺序运行:

  1. template_preprocess
    -这个是由内核提供的,也是始终存在的。这里声称的变量在所有的模板钩子中都可以使用.
  2. template_preprocess_hook
    -实现了主题钩子的内核或者模块提供该处理器。特定于某个钩子的变量,通常首先在这里生成。
  3. moduleName_preprocess
    -不要将这个与前面的预处理器混淆了。对于那些最初没有实现钩子的模块,它允许影响变量集。它将在所有的钩子中运行。
  4. moduleName_preprocess_hook
    -和第3个一样,但是特定于某个钩子。
  5. engineName_engine_preprocess
    -主题引擎的预处理器。适用于所有的钩子。
  6. engineName_engine_preprocess_hook
    -主题引擎的另一个预处理器,特定于单个钩子。
  7. engineName_preprocess
    -这是第一个可以在主题内部使用的预处理器。命名方式为,主题所用引擎名称+预处理器名。适用于所有的钩子。
  8. engineName_preprocess_hook
    -这个和第7个一样,但是特定于单个钩子。
  9. themeName_preprocess
    -命名方式为:主题名+预处理器名。适用于所有的钩子。
  10. themeName_preprocess_hook
    -与前者一样,但是特定于单个钩子。

这里有多种方式可修改变量集。在大多数情况下,只有前两个预处理器存在。第一个,添加了所有的默认基本变量,而第2个添加了特定于该主题钩子的变量。第3方模块,如果用到了第3和第4个预处理器的话,需要添加注释对其进行详细说明。这里就不对此展开讨论了。

尽管可以这样做,但是默认的PHPTemplate没有对变量集进行修改。(5 & 6)

从列表中的第7个开始,所有的预处理器都是放置在主题中的。这个预处理器列表最多是可以超过10个的,那就是使用子主题,子主题是基于第9和第10个预处理的前缀主题名的,但是这种情况在实际中很少用到。

注意:

  • 一般推荐在基主题的预处理器中使用引擎名称(7 & 8)。这有利于代码在主题之间的迁移,同时有利于在Drupal.org上发布代码片断。
  • 而只有在子主题(sub-themes)中才使用主题名称(9 & 10)。这将减少潜在的重名冲突,在PHP中是不允许重名的。
  • 为了识别你主题的预处理器,与钩子相关联的模板必须位于主题内部。如果存在默认的模板的话,将其拷贝到你的主题下面,并清空注册表。如果你要将一个主题函数转化为一个模板,参看前面页面的“以模板方式注册钩子”(http://drupal.org/node/173880#convert-type)。

注意,这些函数中都没有返回值,所有的变量都是通过引用传递的,前面都有符号“&”,比如&$var。

由于这里适用的是引用方式,所以在前面设置的变量,在后面的预处理器中都会存在,所以你一定要小心,不要在这里出什么乱子。重置以前的变量是可以的,但重置以后,你总会疑神疑鬼,感情哪里会出漏子。

这个例子,来自于实现了钩子"foo"的模块:

[syntaxHighLighter brush="php"]

function template_preprocess_foo(&$variables) {
    $variables['foo_list'] = array(
        'list item 1',
        'list item 2',
        'list item 3',
    );
 }

[/syntaxHighLighter]
在主题的预处理器中添加变量集:
[syntaxHighLighter brush="php"]

function drop_preprocess_foo(&$variables) {
    // Do not do this unless you mean to:
    $variables['foo_list'] = array('list item 4');

    // Instead do this:
    $variables['foo_list'][] = 'list item 4';
}

[/syntaxHighLighter]
在模板文件中使用的变量,就是$variables的键。所以,在上面的例子中,在模板文件中可用的变量就是$foo_list。

原文:http://drupal.org/node/223430

译者:葛红儒, Think in Drupal,

如果喜欢本文,请分享给朋友们