开启左侧

Drupal主题制作指南(v6) 主题化介绍

[复制链接]
发表于 2010-5-27 09:30:17 | 显示全部楼层 |阅读模式
主题化介绍

Drupal的强大和灵活性是众所周知, 如果你想一下子就完全掌握它的话,这将是一个难于登天的事情.解决主题化问题的方式有很多,但是不是每种方式都是值得推荐的.掌握"Drupal 的方式"可以精简你的代码,从而使其更易维护. 如果您选择打破规则,走自己的路,那么首先了解"Drupal 的方式",将会增大你的成功机会。

这并不意味着, 为了制作主题,你必须全面的掌握Drupal.你只需要掌握完成任务所必需的技能就可以了,但是,你的站点的设计越复杂,你越需要了解drupal的主题机制.

本手册的目的,,在于揭示drupal主题制作(theming)的所有方面。一些地方比较难,适用于技术高手,而一些地方则比较容易,适用于初学者。在下面的部分中,我们将对内容进行展开,从每个主题开发者都应该熟悉的总体概况,到更具体的细节,有时,需要更多的技术解释。

在继续阅读本文以前,你需要了解一下的相关知识:
•        了解xHTML 和CSS
•        如果你的主题需要脚本支持的话,JavaScript 和jQuery也是必备的
•        Drupal中所用到的术语(http://drupal.org/node/21951

在某些情况下,会用到PHP的知识,但是基于纯CSS的主题,可以完全避免使用PHP。

根据你主题目标的不同,它可能非常简单,也可能非常复杂。Drupal是非常灵活的,所以你必须仔细的考虑你要做什么。你首先要考虑的是网站的需求。制作一个特定需求的主题,与制作一个通用的主题相比,要容易很多。

如果你碰到了一个难题,请阅读疑难解答(http://drupal.org/node/37156),或者在论坛的主题制作版面或者IRC @ #drupal-themes上向别人请教。请阅读“如何高效利用IRC”(http://drupal.org/node/108355)一文。
平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 09:32:35 | 显示全部楼层
OG首页主题化

OG首页的主题化,我想修改一个OG首页的外观,但是不知道怎么实现,打算用panels,但是对这个模块还不是很熟,另外就是OG在Panels方面还不成熟.
OG首页就是一个节点类型的主题模板,因为一个小组就对应一个节点,从og\theme下面拷贝node-og-group.tpl.php到当前的主题目录下面,并不生效,因为我已经为该类型的节点创建俄一个模板,对该模板重命名,现在node-og-group.tpl.php起作用了.
       其实我想要的就是控制content中的group post节点的列表,在网上找了半天,都没有找到答案,有人和我遇到了同样的问题,而且没有人解答。how to theme og home page?? http://drupal.org/node/344484
       问题的关键点就是,这个$content把所有的东西都属出来,怎么分开显示呢?由于og首页的主题化是第一次实现,所以感觉有点神秘,因为它提供的默认模板node-og-group.tpl.php。
       没有办法,只好print_r了,一个一个的找,最后找到了$node->content[view]['#value'],现在再看这个问题,其实很简单,只是刚开始自己把它想复杂化了。那就是使用group的节点类型就可以了,和普通的CCK节点类型的主题化完全一样。

平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 09:37:35 | 显示全部楼层
主题化概述


在软件开发中,将逻辑层和表示层分开,是很常见的.其中原因很多,最明显的原因是,后台的业务逻辑层所需要的技能,与前台表示层所需要的技能相比,有很大的不同.作为一个主题开发者,你可以在许多方面控制用到的数据,但是它局限于输出和显示.而只有Drupal内核模块和其他模块才用来负责输入.例如,一个模块可以实现一个带有默认外观的表单,来处理用户输入,并将其保存到数据库中.而Drupal主题(theme)的作用是仅仅用来重写默认外观.

在Drual中,这一抽象层是通过theme(主题)函数实现的.主题函数就是一个管道,将逻辑层与表示层连在一起.在主题引擎(theme engines)之上,有一个一个可选的中间层,用来选择标记语言比如PHPTAL或者Smarty.它还允许主题控制所有表示层的标识字体.而主题引擎像标记语言一样,都是可选的. PHPTemplate是默认的主题引擎.从名字我们就可以看出,它在xHTML中输出变量时,使用PHP作为标记语言.

从Drupal6开始,创建主题引擎的需求已被充分的淡化。


从上图可以看出,逻辑层和主题层(表示层)都可以为输出实现一个主题化的外观,(存在极个别例外情况)只有主题层才能对底层进行覆写。主题引擎(Theme engine)可以覆写内核模块和可选模块中的主题输出,而主题(图中最上方的theme一层)对下面的每一层都可以进行覆写。

注意,PHPTemplate引擎并没有覆写任何输出,但是其他主题引擎可以这样。也存在特殊情况,一个模块可以影响输出,或者对任何东西都可以覆写,但是他只用在非常特殊的情况下,而在大多数情况下,都遇不到这种情形。例如,devel的主题者模块(themer module)就属于这种特例,它是用来帮助主题开发的。更多细节将在接下来的章节中展开。

如果你的主题是由CSS完全控制的,也就是纯CSS主题,那么这里所讲的大部分内容你都不需要关心,但是当需要修改标记文本时,理解如何找到输出的源头,对于你的工作来讲,是非常有帮助的。

•         注意,Drupal的内核和第3方模块,总是使用可主题化的函数和模板文件来输出表示层的文本的。千万不要在这些模块里面直接对主题进行修改,如果这样做的话,当你需要升级时,情况就会变得复杂起来。这样做就是所谓的“分支”("forking")。开源的强大之处在于,让开源社区来负责修正臭虫(bug)和添加新的特性。一旦你建立了一个分支,也就意味着你创建了一个封闭的系统,这样你就脱离了社区。Drupal提供了各种功能,用来覆写表示层。如果你必须要在模块中直接对主题进行修改的话,要么是你做错了,要么是你发现了一个臭虫。如果是后者的话,请填一个臭虫报告。如果提供一个补丁来修正该问题的话,那是最好不过的了。

•        对于那些熟悉drupal以前版本的PHPTemplate引擎朋友来说,在Drupal6中,PHPTemplate引擎中的大部分函数都被移到了更底层的内核中。现在PHPTemplate仅仅用来 发现主题函数和该主题函数用到的模板文件。与其说它是一个主题引擎,不如说是一个主题帮助函数。PHPTemplate是最初由Adrian Rossouw为Drupal4.7编写的。Drupal6中的修改是由Earl Miles完成的。论坛中的一个帖子(http://drupal.org/node/7133)提供了最初创建引擎的原因,而在http://drupal.org/node/130987 则提供了Drupal6中的问题列表。
平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 10:17:03 | 显示全部楼层
对一个Drupal主题的剖析


phptemplate theme:

                               
登录/注册后可看大图
.info (必须)
".info"文件是必须的,当Drupal 寻找你的主题时,要用到这个文件.在这里可以定义:元数据,样式表, JavaScripts,(区块)区域,以及其它.而其它文件则是可选的.
主题的内部名称也是由该文件衍生出来的.例如,如果它名为”drop.info”的话,那么在Drupal中,"drop"就是主题的名字。而在Drupal5以及更早的版本中,Drupal使用主题文件夹名作为主题的名字。
Info文件是Drupal6引入的新的特性。在Drupal5中,.info文件仅适用于模块。

模板文件(.tpl.php)http://drupal.org/node/190815
这些模板文件,都是由xHTML和PHP变量构成的。在一些情况下,它们也可以输出其它的数据类型——比如xml rss。每个.tpl.php文件负责特定一块数据的输出,有时,根据suggestions (建议),它可以处理多个.tpl.php文件。模板文件是可选的,如果在你的主题中不存在的话,那末就会使用默认输出。注意,在这些文件中,不要包含复杂的业务逻辑。一般情况下,只需要包含xHTML标签和PHP变量。在内核和可选模块所在的目录中,存在着一些模板文件。将它们拷贝到你的主题目录下面,Drupal将会使用主题目录下的模板文件来代替模块里面的。
注意:theme registry(主题注册表)对可用主题数据信息进行了缓存。当你在你的drupal主题中添加或者删除模板文件(或者主题函数)时,你需要重置主题注册表,以清空缓存。

template.php
可将输出时所用到的所有条件逻辑和数据处理,都放到template.php文件中。该文件不是必需的,但是它能使.tpl.php文件保持整洁,在这里,可以对.tpl.php文件中的PHP变量进行预处理。定制函数,覆写的主题函数或者其它对原始输出的外观定制函数,都可以放到这里。这个文件开头必须是PHP开始标签"<?php",但是结束标签不是必须的,最好将其忽略。

Sub-themes (子主题)
在表面上,子主题和其它主题是一样的。唯一的区别是,它们继承了父主题的资源。为了创建一个子主题,在.info文件中必须包含"base theme"项。这样它就可以继承来自于父主题的资源了。继承可以是多重的;一个子主题可以是另一个子主题的父主题。对此没有进行限制,可以一直继承下去。
Drupal 5以及更低版本中,子主题需要位于父主题下面的子目录里面。Drupal6中则没有这一限制。

其它
  • Logo和截图并不是必需的,但它是推荐使用的,特别是你想把你的主题贡献到Drupal资源库中时。截图应该展示主题的特色,比如包含管理页面和用户帐号设置,它可在设置了适当权限后来选择主题。
  • 当你需要管理UI设置或者logo、搜索、使命(mission)等等以外的“特性”时,可以使用"theme-settings.php"文件。这是一个高级特性。更多信息,可参看用户手册的高级设置(http://drupal.org/node/177868)。
  • 对于颜色模块(color module)的支持,需要一个"color"目录,里面放置"color.inc"文件,以及其它各种支持文件。


  • 如果你想将你的主题基于核心主题,可以使用子主题(http://drupal.org/node/225125),或者拷贝主题并将其重命名。直接修改Garland或者Minnelli是非常非常不好的,这是由于安装和升级过程中都要用到他们。
  • 所有主题都应该放在"sites/all/themes"目录下,以将其与核心文件区分开来。参看多站点安装(http://drupal.org/node/43816),可以了解到所有可以放置主题的目录。


  • 子主题,它们的结构和继承



平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 10:28:27 | 显示全部楼层
子主题,它们的结构和继承
子主题(Sub-theme)和其它主题一样,唯一不同之处在于:它们继承来自于父主题的资源.对于多重继承,则没有限制.一个子主题可以是另一个子主题的子主题,允许存在分支和层级结构,只要你觉得合适就可以了.这使得子主题具有巨大的潜力.

                               
登录/注册后可看大图


假如开始我们用基主题(base theme)勾画出主题的轮廓,那么在子主题中我们要做的就是描绘出所有的细节。接着,从同一基主题出发,创建另一个子主题分支,用来尝试另一种设计。如果你要建立的是多站点的话,但是你想要一个统一的外观,那该怎么办呢?使用子主题,就可以在各个自站点中分享共同的设计资源。子站点相关的修改放在子主题里,而共享的设计资源则可以放在基主题中,这样一旦修改了之后,就可以应用到所有的子站点中了。如果仔细规划,那么就具有无限的可能。

为了声明一个父主题或者“基主题”("base theme"),那么在子主题的.info文件中设置下面一项,其中" themeName"(“主题名”)为父主题在Drupal内部的名字:
base theme = themeName

下面的将被继承:
  • 所有在父主题中定义的样式表(http://drupal.org/node/171209),但可以进行选择(http://drupal.org/node/171209#styles-override-parent),所以这是可以控制的。
  • 所有在父主题中定义的JavaScripts
  • 所有的模板文件(.tpl.php)。
  • "template.php"文件中定义的所有东西。包括覆写的主题函数,预处理器,或者其它东西。每个子主题都包含它自己的template.php文件和其父主题的template.php文件。
  • 如果子主题中.info文件和父主题的设置相同的话,父主题的截图(Screen shot)也是可以继承的。

下面的不能被继承:
  • 主题的logo.png。不包括上传的logo,因为这是总被用到的。
  • .info文件中的一些设置。包括区域。如果你没有使用默认区域的话,那么子主题的"page.tpl.php"文件中用到的区域,一定要在.info文件中定义过。每个基主题和子主题都可以拥有自己的区域设置。
  • 在高级主题设置(http://drupal.org/node/177868)中,"theme-settings.php"文件中的所有东西。
注意,子主题可以放在基主题目录的外面,也可放在里面。而在Drupal6以前的版本中,它们只能放在父主题目录的里面。



平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 11:02:06 | 显示全部楼层
主题的.info文件
.info配置文件是在Drupal6中新赠的,每个主题都必须有一个.info文件.该文件应该放在你主题的目录下面.如果没有该文件的话,Drupal就找不到你的主题. .info文件的后缀名必须为".info".

主题在Drupal内部的名字源自于这个文件.例如,如果文件名为drop.info",那么在Drupal内部,主题名字就为"drop".名字里面不要包含奇怪的字符,这是由于在Drupal中,许多PHP函数都是以主题名打头的,所以主题名和函数名存在同样的限制。起始字符必须为alphabetic字母,不能包含空格,标点等字符。可以包含下划线,但是不能包含连字符。数字字符也是允许的,但不能出现在首位。

注意:
  • 警告!模块的内部名称如果与主题的内部名称重名的话,那么你的站点将不能工作。因为可能会造成同名函数的存在,这在PHP中是非法的。每个安装了的部件(模块或者主题)都必须有一个唯一的名字。
  • .info文件中的内容是缓存在数据库中的,所以对它的修改不会在Drupal中立马生效。(不要与主题注册表的缓存相混淆了。)为了清除缓存,须这样做:
    • 导航到"Administer > Site configuration > Performance",点击"clear"按钮。
    • 如果启用了devel区块(安装了devel模块的话),点击"Empty cache"(“清空缓存”)链接。
    • 然后导航到主题选择页面"Administer > Site building > Themes"



语法与INIhttp://en.wikipedia.org/wiki/INI_file)文件类似。.info文件就是一个用来配置主题的的静态文本文件。文本文件的每一个行就是一个键值对(key-value),其中键位于左边,值位于右边,而中间则有一个等号。(例如:key = value)。分号是用来注释的。有些键使用了特殊的语法,带有中括号[],用来构建一列关联值,也就是我们常说的“数组”.如果你不熟悉数组的话,模仿Drupal默认.info文件中的例子,根据例子中的解释,完全可以依葫芦画瓢,得到自己的数组了。
Drupal可以识别下面所列的键。如果.info文件没有设置的话,Drupal将为其使用默认值(http://drupal.org/node/171206)。可参看核心主题中的例子(http://drupal.org/node/171205#example#example)。


主题的.info文件(1)

name (required)  名字(必须)
这是用户可读的名字,与主题的Drupal内部名字可以分开单独进行设置.这在这里,字符的限制则很少.
name = Un tema nombre de fantasia

description (recommended)  描述(推荐)
主题的简短描述.你可以在页面"Administer > Site building > themes"看到主题的描述.
description = Tableless multi-column theme designed for blogs.

screenshot 截图
截图键时可选的,它告诉Drupal主题的缩略图在哪里,在选择主题页面(admin/build/themes)里用到了缩略图.如果.info文件中忽略了该键,那么Drupal就会使用主题目录下面的"screenshot.png"文件.
只有当你的缩略图不叫"screenshot.png",或者你不想把它放到你主题的根目录(比如,screenshot = images/screenshot.png)下面时,才使用该键。
screenshot = screenshot.png

version (recommended) 版本(推荐)
当发布一个新的版本时,drupal.org会自动为其添加一个版本号。当你为Drupal贡献主题时,你可以忽略该值。如果你的主题没有放到drupal.org上的话,你可以为你的主题指定任意一个版本号。
version = 1.0
core (required)  内核(必须)
从Drupal 6.x开始,模块和主题的.info文件都必须指明它们兼容的Drupal内核主版本号。这里设的值将与DRUPAL_CORE_COMPATIBILITY常量相比较。如果不匹配的话,那么主题将被禁用。
core = 6.xdrupal.org的打包脚本,将根据每个发布版本的Drupal内核兼容性设置,自动设置该值。所以从drupal.org下载下来的主题,设置总是正确的。然而,对于直接通过CVS部署的Drupal站点来说,如果你将这一修改提交到你主题的.info文件中去的话,将会很有帮助。它也能够非常方便的帮用户指出,主题兼容CVS的HEAD中的哪些内核版本。

engine (recommended) 引擎(推荐)
主题引擎,供主题使用。如果没有提供引擎的话,那么主题就是独立的,比如,实现一个".theme"文件。大多数主题都使用"phptemplate"作为默认引擎。
PHPTemplate负责查找主题用到的主题函数和模板。只有当你理解你在做什么的时候,你才可以忽略这一设置。
engine = phptemplate
base theme 基主题
子主题可以声明一个基主题。这允许主题的继承,也就是说基主题中的资源将被传递下来并在子主题中使用。子主题可以声明别的子主题作为其基主题,也就是允许多重继承的存在。基主题的名字为其在Drupal内部的名字。下面是Garland的子主题Minnelli的相应设置。
base theme = garland更多细节可参看子主题,它们的结构和继承(http://drupal.org/node/225125)。
regions 区域
我们这样定义主题中的区域,声明键'regions',紧跟着“[”,接下来是内部名字,接着是“]”,然后是一个等号,右边是用户可读的区域名字。例如,regions[theRegion] = The region name.
如果没有定义区域的话,那么使用下面的默认值。你可以根据自己的需要覆写这些值。

regions[left] = Left sidebarregions[right] = Right sidebarregions[content] = Contentregions[header] = Headerregions[footer] = Footer更多细节可参看,“区块,内容和它们的区域”(http://drupal.org/node/171224)。

features  特性
许多由主题控制输出的页面元素,可以在主题的配置页面启用或者禁用. "features"键控制着出现在主题配置页面上的复选框.对于一个主题,如果你不想为其定义某个复选框时,着非常有用.为了删去某个复选框,只需要在"features"中将其删除即可.如果一个也没有定义的话,那么会输出所有默认的复选框.
下面的例子列出了所有由features键控制的元素.通过注释掉primary_links和secondary_links元素,那么站点管理员就不会看到这两个复选框了.
features[] = logofeatures[] = namefeatures[] = sloganfeatures[] = missionfeatures[] = node_user_picturefeatures[] = comment_user_picturefeatures[] = searchfeatures[] = favicon; These last two disabled by redefining the; above defaults with only the needed features.; features[] = primary_links; features[] = secondary_links更多信息参看”定制主题设置”(http://drupal.org/node/221905).
stylesheets 样式表
传统方式,主题可自动的使用默认的style.css,并且可以在它们的template.php文件中通过调用drupal_add_css()来添加其它样式表。从Drupal6开始,主题也可以通过.info文件来添加样式表。
stylesheets[all][] = theStyle.css更多信息可参看“样式表”一节(http://drupal.org/node/171209)。
scripts 脚本
传统方式,主题通过在template.php文件中调用drupal_add_js()来添加javascripts脚本。从Drupal6开始,主题也可以通过.info文件来添加javascripts了:
scripts[] = script.js更多信息参看  JavaScript & jQuery一节。

php
这个定义了主题支持的PHP最低版本。其默认值源自DRUPAL_MINIMUM_PHP常量,它是Drupal内核所需要的php最低版本。对于一个新的版本,如果需要的话,可以对其进行重新定义。而对于大多数的主题,都不应该添加这一项。
php = 4.3.3


Drupal核心主题中的.info文件例子
Garland: ; $Id: garland.info,v 1.5 2007/07/01 23:27:32 goba Exp $name = Garlanddescription = Tableless, recolorable, multi-column, fluid width theme (default).version = VERSIONcore = 6.xengine = phptemplatestylesheets[all][] = style.cssstylesheets[print][] = print.css; Information added by drupal.org packaging script on 2008-02-13version = "6.0"project = "drupal"datestamp = "1202913006"
Minnelli sub-theme of Garland.:
; $Id: minnelli.info,v 1.7 2007/12/04 20:58:44 goba Exp $name = Minnellidescription = Tableless, recolorable, multi-column, fixed width theme.version = VERSIONcore = 6.xbase theme = garlandstylesheets[all][] = minnelli.css; Information added by drupal.org packaging script on 2008-02-13version = "6.0"project = "drupal"datestamp = "1202913006"
注意,从行“; Information added by drupal.org packaging script on 2008-02-13”开始直到结束,这都是由drupal.org的打包脚本自动添加的。你一定不要手工添加project(项目)和datestamp(时间戳)键。手工添加version(版本)键(第一个),那么就可以允许直接从CVS建立起来的站点使用你的主题了。

.info的默认值
下面是假定的默认值。如果它们没有被定义的话,主题将自动使用这些值。
注意:这些默认值是作为一个组来共同起作用的。换句话说,仅仅使用regions[sub_header] = Sub-header来覆写一个区域的话,将会造成其它默认区域的消失。为了使用它们必须对它们进行重新定义。对于"stylesheets"也是一样的。尽管从技术的角度来看,它不是一个组,定义另外一个样式表,除非你重新对"style.css"进行定义,否则是找不到它的。
regions  regions[left] = Left sidebar
  regions[right] = Right sidebar
  regions[content] = Content
  regions[header] = Header
  regions[footer] = Footer
   
features  features[] = logo
  features[] = name
  features[] = slogan
  features[] = mission
  features[] = node_user_picture
  features[] = comment_user_picture
  features[] = search
  features[] = favicon
  features[] = primary_links
  features[] = secondary_links
   
stylesheets  stylesheets[all][] = style.css
   
scripts  scripts[] = script.js
   
screenshot  screenshot = screenshot.png
   
php (minimum support) (支持的最低版本)DRUPAL_MINIMUM_PHP是一个常量。它指出了运行Drupal所需php的最低版本。  php = DRUPAL_MINIMUM_PHP












平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 11:06:18 | 显示全部楼层
覆写可主题化的输出
只有当你需要修改默认输出时,你才需要阅读本节.如果你的显示层是完全有CSS样式表负责的,那么可以略过本节。
覆写主题输出,需要掌握3个方面。首先,你需要知道源头在哪里,其次你要进行覆写,最后你需理解它的类型。
注意,Drupal使用主题注册表(theme registry)来缓存主题数据覆写完成后,你必须清空缓存。
1.       寻找源头:
寻找主题输出的源头,是比较困难的,这是由于主题系统的多层级结构造成的,使得源头可能出现在系统的各个地方。
仅用来演示用。
大多数页面元素一般是由theme('page')拉进来的,在显示导航信息以后,它们被放置在page.tpl.php模板中。页面元素包括主菜单、区块区域元素,区域中的区块等等。通常通过一个主题钩子来引用每个大块的主题化数据。
注意:主题钩子现在包括主题函数和模板两部分。系统中的许多钩子都与主题无关。我们这里提到的钩子都是特定于主题的。
现在使用devel模块([url=http://drupal.org/project/devel]devel module)可以很容易的追踪特定内容的源头。devel模块包含一个主题工具,可以方便的查勘任何输出的源头,类型以及其它主题相关数据。参看示范screencast(http://drupal.org/node/209561)。由于技术方面的限制,它只能应用到Drupal6以及更高版本中。
2.       覆写机制:
覆写机制有一个特定的级联顺序,当然也包含一些特殊情况。Drupal内核和模块使用主题钩子提供了一个合理的默认输出。如果默认输出不符合主题的需求的话,那么就可以对其进行覆写,从而避免使用默认输出。这样,默认的将被放到一边去,我们不再管它,而将所有的特定修改放到所用的主题目录下面。不要直接修改Drupal内核和模块,只在主题目录下面修改。

                               
登录/注册后可看大图
如果传统的覆写不能满足你的需要的话,你可以使用主题注册表。
注意:尽管在Drupal 6中PHPTemplate.engine还存在,但它已不再覆写主题函数了。在Drupal5中,它允许使用模板来处理部分主题钩子。而现在则不必要这样了。



平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 11:23:09 | 显示全部楼层
函数VS模板
3.函数VS模板:
正如前面所说,实现特定的钩子有两种方式。通常的“函数”或者“模板”。根据要主题化的元素的特点,选用最合适的方式。内核和模块可选用任何一种方式来构建输出。而上面的主题层,可以使用同样的方式来覆写,或者改变选用的方式。
主题函数[url=http://api.drupal.org/api/function/theme_menu_local_tasks/6]theme_menu_local_tasks,是一个用来输出一级和二级标签的简单函数。这里的主题钩子就是"menu_local_tasks"。为了覆写它,可将函数名中的前缀"theme"替换为你主题的名字或者所用主题引擎的名字。最好使用主题的名字,这样可以避免潜在的与子主题(http://drupal.org/node/225125)的命名冲突。

                               
登录/注册后可看大图
本例中,Garland是使用引擎名来覆写的。如果你的主题是基于Garland的子主题,那么你必须使用你的主题名了。
将下面的代码放到主题的template.php,清空主题注册表缓存,这样就覆写了默认输出。注意,将"drop"改为你主题的名字。
<?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;
}
?>
这里所做的唯一修改就是将<ul>标签改为了<ol>。
api.drupal.org你可以找到所有的主题函数。
模板方式:
如果默认是使用模板实现的,那么你只需要简单得将模板源文件拷贝到主题下面,然后清空主题注册表,就完成了覆写。下面为search-theme-form.tpl.php的一个例子。注意在这里,主题钩子就是"search_theme_form",需要将连字符“-”替换为下划线“_”.

                               
登录/注册后可看大图
这就是你要做的。使用编辑器,打开拷贝的模板,对其进行修改。内核中的所有.tpl.php文件都带有注释。根据注释,你就可以做出具体的修改了。
注意:模板可以放在主题下面的任何目录中。这样便于管理,也避免了主题根目录下面的混乱。
相关页面:
将函数转化为模板
将一个主题函数转化为一个模板,开始是需要一点工作的,但一旦完成,便很好使用。如果你和设计者一同工作,那么转化为模板,将会使设计者更专注于设计,而不是编码。在内核中,已有了很多模板,而在将来的版本中,将有更多的主题函数转化为模板。第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)。



平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 11:26:23 | 显示全部楼层
主题注册表
Drupal的主体注册表维护了主题钩子相关的缓存数据,包含主题钩子和如何处理它们的信息。
对于大多数主题开发者来说,都不需要直接与注册表打交道。只需要记住,当添加或者删除主题函数和模板时,要清空它。编辑已有的函数和模板时,则不需要清空。
清空主体注册表,有3方式:
  • 位于"Administer > Site configuration > Performance"的clear按钮。
  • 如果启用了devel区块(devel模块创建的),点击"Empty cache"连接。
  • 使用API函数drupal_rebuild_theme_registry
主题注册表是主题钩子相关信息的缓存数据,包括Drupal可用的主体钩子,勾子类型,即如何处理它们。在以前的版本中,所有的主题调用都是直接完成的。由于在底层需要进行大量的处理工作,而缓存可以加快这种处理,特别是对于模板而言。你主题用到的引擎应该为你自动的注册所有的主题钩子。
在一些特殊情况下,你需要直接与注册表打交道。如果你的主题需要注册一个新的钩子,而该钩子不在底层中(内核,模块,引擎)。比如说一些表单,内核或者模块没有明确对其主体化,而仅仅使用了默认的表单输出。
  • 更多细节,参看子页面“特殊情况下的主题注册表”(The theme registry for special cases)。
  • 不要将主题注册表与主题的.info文件混淆了,两者都被缓存了。清空主题注册表的第1点和第2点,同时也清空了.info的缓存。
  
  • 预处理函数
  • 默认的基本变量
  • 特殊情况下的主题注册表
  • 使用模板建议(suggestions)
  • 核心模板和建议(suggestions)




预处理函数
    预处理函数仅适用于模板形式的主题钩子.它的主要作用是设置模板文件((.tpl.php)中所用到的变量。在预处理器(Preprocessor)中,一般涉及不到普通的主题函数。
注意:
  • 在提供模板建议(template suggestions)时也会用到预处理器。
  • 在drupal5中,函数_phptemplate_variables提供了同样的功能,在drupal6中,为了以后版本的兼容性,最好不要用这个函数。
对于单个主题钩子,可以有多个预处理器。内核,模块,引擎,主题,每层都可以有一个预处理器,来逐步的构建显示在模板文件中的变量集。通过将大部分逻辑放到这些预处理器中,可使得模板文件更加简洁,易于使用。
       下面是预期的预处理器。当它们同时存在时,按照下面的顺序运行:
  • template_preprocess
    -这个是由内核提供的,也是始终存在的。这里声称的变量在所有的模板钩子中都可以使用.
  • template_preprocess_hook
    -实现了主题钩子的内核或者模块提供该处理器。特定于某个钩子的变量,通常首先在这里生成。
  • moduleName_preprocess
    -不要将这个与前面的预处理器混淆了。对于那些最初没有实现钩子的模块,它允许影响变量集。它将在所有的钩子中运行。
  • moduleName_preprocess_hook
    -和第3个一样,但是特定于某个钩子。
  • engineName_engine_preprocess
    -主题引擎的预处理器。适用于所有的钩子。
  • engineName_engine_preprocess_hook
    -主题引擎的另一个预处理器,特定于单个钩子。
  • engineName_preprocess
    -这是第一个可以在主题内部使用的预处理器。命名方式为,主题所用引擎名称+预处理器名。适用于所有的钩子。
  • engineName_preprocess_hook
    -这个和第7个一样,但是特定于单个钩子。
  • themeName_preprocess
    -命名方式为:主题名+预处理器名。适用于所有的钩子。
  • 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"的模块:
<?php
function template_preprocess_foo(&$variables) {
  $variables['foo_list'] = array(
    'list item 1',
    'list item 2',
    'list item 3',
  );
}
?>

在主题的预处理器中添加变量集:
<?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';
}
?>

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







平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
 楼主| 发表于 2010-5-27 11:29:58 | 显示全部楼层
默认的基本变量

下面是在所有的模板文件(http://drupal.org/node/190815)中都可以使用的基本变量。它们是通过预处理器函数(http://drupal.org/node/223430),template_preprocess生成的。特定于模板文件的变量,其相关说明位于模板文件中。
$id
模板的编码。模板每被调用一次,它增1。
$zebra
"odd" 或者 "even"。两者随着模板的适用交替改变。
$directory
主题的相对路径,相对于安装路径。例如:"sites/all/themes/myTheme"
$is_admin
布尔值。当访问者为站点管理员(user 1)时返回TRUE;
$is_front
布尔值。当当前页面为首页时,返回TRUE;
$logged_in
布尔值。访问者为站点会员,登陆并通过验证时,返回TRUE;
$db_is_active
布尔值。当数据库可用时,返回TRUE。这只在“维护模式下的主题化”(http://drupal.org/node/195435)中有用,此时站点可能会遇到数据库问题。
$user
当前访问者的用户对象。把数据放到这里可能不大安全。对于可疑字符串,一定要用check_plain


特殊情况下的主题注册表
        在继续阅读本节以前,你首先要熟悉主题注册表的目的(http://drupal.org/node/173880#theme-registry)。这里的指导,将覆盖如何手动的注册一个主题钩子,并解释如何才能手动操作。 大部分需要手动注册主题的情景,是与表单相关联的。表单元素可以主题化,但是它们的主题化是以另一种方式进行的。对于基本元素,比如复选框,单选框,提交按钮,下拉菜单,等等。这些元素都是可以主题化的,对它们的覆写不需要手动的去注册与之相关联的钩子。对于一些定制表单,每个元素都以非常特别的方式来放置,这时就需要手动的去注册了。对于那些,已经设计好,主体化过的,并且注册过的表单,就不需要手动注册了。对于那些没有主题化的表单将使用默认方式显示它们(http://api.drupal.org/api/file/developer/topics/forms_api.html/6)。 表单注册例子:在下面这个例子中,search.module注册了两个搜索表单,搜索框和搜索区块。每个表单都有一个唯一的Id与之相关联。即可充当注册编号,又可充当主题钩子。在这里,它是"search_theme_form" 和"search_block_form"。 <?php
function search_theme() {
  return array(
    'search_theme_form' => array(
      'arguments' => array('form' => NULL),
      'template' => 'search-theme-form',
    ),
    'search_block_form' => array(
      'arguments' => array('form' => NULL),
      'template' => 'search-block-form',
    ),
    ...
  );
}
?>表单API将它的显示控制权交给了注册钩子的处理器。在这个例子中,它注册了默认参数('arguments')和模板类型('template')。只有当主题层(see image)下面的层次中已注册了主题钩子时,Drupal才能自动找到钩子。  注册一个未被注册的表单:另一个搜索表单还没有被注册过。它的id为"search_form",用在主搜索页面。表单的数据是在一个函数中构建的(http://api.drupal.org/api/function/search_form/6),这和其它表单一样,但它需要表单API根据它的数据结构来处理它的显示。我们可通过覆写来对其进行扩展,你需要在你的主题中使用hook_theme对其进行注册。将下面的代码放到你主题的template.php文件中,将"drop"前缀改为你主题的名字。主题钩子就是表单的id: <?php
function drop_theme() {
  return array(
    'search_form' => array(
      'arguments' => array('form' => NULL),
    ),
  );
}
?>主题化过的表单都有一个参数"form"。由于这里没有声明模板(template),那么钩子将作为主题函数的形式存在,而不是一个模板。主题函数必须使用它的主题名作为前缀。这里不能使用phptemplate_*。所以,根据上面的信息,那么主题函数应该是这样的:<?php
function drop_search_form($form) {
  $simple = '';
  foreach (element_children($form) as $element) {
    if ($element == 'advanced') {
      $advanced = drupal_render($form[$element]);
    }
    else {
      $simple .= drupal_render($form[$element]);
    }
  }
  return $advanced . $simple;
}
?> 这里所做的唯一修改就是高级搜索表单的位置。
  • 子主题中覆写了一个表单,如果这个表单在基表单中已经注册过的话,那么就不需要手动的再为这个表单进行注册了。记住,底层注册过了的,上层都不需要再注册了,对于基主题来说,子主题就是它上面的一层。
  • 在将来的版本中,这将会更加自动化。开发者知道主题者(themers)的负担。
手动操作主题注册表的手动操作,使一个高级特性。如果你安装了devel模块的话,点击区块中的"Theme registry"(主题注册表)可阅读进一步的详细信息。也可参看http://api.drupal.org/api/function/theme_get_registry/6

使用模板建议(template suggestions)
       模板建议是基于已有.tpl.php文件的可选模板文件。当满足特定的条件,并且相应的文件存在时,就使用这些建议。每一层次,包括内核、模块、主题引擎、主题,都可以提供相应的建议。你可以把它们当作“命名提示”(naming hints),来告诉系统根据合适的环境选择合适的模板。这种想法很简单,但是这一特性却非常强大,它使得在模板层上也能进行定制。 Devel模块展示了“页面”模板的可用的模板建议。

                               
登录/注册后可看大图
内核的所有建议的列表可参看“内核模板和建议”。 这些命名建议是在预处理函数中设置的。内核已经提供了大量的建议。如果你需要进一步的扩展它,你需要在你的主题下面的template.php文件中为相应的钩子添加一个预处理器。本例中,我们为"page"主题钩子添加了扩展建议。这里的钩子可以为任何模板钩子。 前缀"drop"应改为你主题的名字。<?php
function drop_preprocess_page(&$variables) {
  global $user;
  
  // Add a single suggestion.
  if (module_invoke('throttle', 'status') && isset($user->roles[1])) {
    $variables['template_file'] = 'page-busy';
  }  // Add multiple suggestions.
  if (!empty($user->roles)) {
    foreach ($user->roles as $role) {
      $filter = '![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s';
      $string_clean = preg_replace($filter, '-', drupal_strtolower($role));
      $variables['template_files'][] =  'page-'. $string_clean;
    }
  }}
?>有两种方式添加这些建议。
  •        1,键'template_file'接收一个单独的建议,并具有优先级。如果条件满足,并且文件存在的话,将会使用这个建议,忽略其它的建议。
  •        2,键'template_files' (复数)可以接受一个建议数组。它们按照先进后出的顺序进行处理。所以,首先应该向里面添加最一般的,然后逐步添加相对特殊一些的,这样就可以根据特殊性选择相应的建议了。
在上面的例子中,当达到了节流上限时,并且访问用户为匿名时,Drupal将尝试使用名为"page-busy.tpl.php"的文件。而其它代码,则告诉Drupal根据当前用户角色选择相应的模板,比如"page-authenticated-user.tpl.php"。如果找不到的话,就使用基模板"page.tpl.php"。这是非常简单的例子。你可以根据你可用的数据来自己设置上下文。 一些注意点:
  • 当向'template_files'也就是数组中添加建议时。不要对其进行重置,因为变量是使用饮用传递的。如果重置的话,所有在内核和模块中进行的设置将全部丢失。
<?php
  // Do not do this:
  $variables['template_files'] = array('hook-suggestion');
  
  // Instead do this:
  $variables['template_files'][] = 'hook-suggestion';
?>
  • 建议前面使用与之相连的钩子作为前缀。这样更加干净,并将文件聚到了一块。同时还减小了Drupal将该模板注册为其它钩子的风险。
  • 使用连字符来代替下划线。主模板都不使用下划线的。
  • 建议只有和基模板放在一块时,才起作用。模板可以放在主题下面的恶任意子目录下,但是必须将其放到一块。
  • 建议的修改添加删除,不需要清空主题注册表。只有基模板注册时才需要。而Drupal可以自动识别建议的。









平度网:www.pingdu.co 平度论坛:bbs.pingdu.co
您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

 
QQ在线咨询
售前咨询热线
0532-88371356
售后服务微信
pingduwangzhan
快速回复 返回顶部 返回列表