如果你要覆写的主题函数不包含在基本列表中(block, box, comment, node, page),你需要将它告诉给PHPTemplate.
为了实现这一点,你需要在你主题目录下,创建一个template.php文件.这个文件以PHP开始标签<?php,但是这里不需要结束标签,推荐你不要使用结束标签.还有,在文件中,还需要包含用于主题覆写的存根(stubs),这些存根告诉引擎使用哪个模板文件,以及向其中传递哪些参数.
首先,你需要知道你要覆写哪个主题函数.你可以在Drupal API文档中找出一列这样的函数.我们在这里以theme_item_list()为例.
theme_item_list()大概是这样定义的:
<?php function theme_item_list($items = array(), $title = NULL) { ?>
现在,你需要在你主题的template.php文件中加一个存根,如下所示:
<?php
/**
* Catch the theme_item_list function, and redirect through the template api
*/
function phptemplate_item_list($items = array(), $title = NULL) {
// Pass to phptemplate, including translating the parameters to an associative array.
// The element names are the names that the variables
// will be assigned within your template.
return _phptemplate_callback('item_list', array('items' => $items, 'title' => $title));
}
?>
我们将函数名中的“theme”替换为了“phptemplate”,并调用函数_phptemplate_callback()以将参数($items和$title)传递给PHPTemplate。
现在,你可以在你主题目录下,创建一个item_list.tpl.php模板文件了,它将用来替代原有的theme_item_list()。这个函数,与原有的theme_item_list()相比,应该采用相同的逻辑。
注意,你需要访问[ Administer -> Site building -> Themes ],从而刷新PHPTemplate的缓存,以识别出新添加的文件。但是从drupal4.6开始,就不需要这一步了。
除了Drupal标准的主题函数以外(API中所包含的),你还可以使用主题函数来覆写Drupal表单的外观。例如,对于由表单构建器函数构建的一个核心表单,你可以使用form_id来对其进行覆写。详情可参看这个实例。
Drupal 6.x提供了一种内置的phptemplate方式,对站点离线后的维护页面进行主题化---参看http://drupal.org/node/195435.
在Drupal 5.x中,许多帖子建议通过修改内核为该页面定制主题,但是这种想法很臭,而且没有必要,当然最后的结果也不一定好.下面是由Nax(http://drupal.org/user/25511)提出的一些比较好的方式,每种方式都有自己的优点:
function phptemplate_maintenance_page($content, $messages = TRUE, $partial = FALSE) {
drupal_goto('path/to/your/site-offline.html');
}
参看http://drupal.org/node/58562#comment-281490
这两种方法都能工作,所以你可以根据你的情况选择一个适合自己的。
当开发你自定义的维护页面时,你需要注意几点:
如果你有什么建议或者更好的方法的话,可以在下面跟贴。
Drupal内置的CSS聚合工作原理是,在"files/css"文件夹下,创建一个聚合文件,可以创建多个这样的聚合文件,比如当一个css文件在特定页面不需要时,而在另一个页面则用得到,这时就会新建一个聚合文件,通过$styles变量将其输出到page.tpl.php中。然而,这种方式对于部分人是行不通的,例如,将drupal运行在多台前台终端服务器上,但是却没有共享的"files"文件夹(它们可以与主服务器进行同步,而编辑则向主服务器添加内容),并且启用了缓存。在这种情况下,在部分前台终端服务器上css就显示不出来了,这是由于返回的是缓存页面,而没有检查css文件是否存在。
这个问题的解决方案是,由template.php来负责css的聚合,并将css文件缓存在主题目录下(在服务器间同步时,通常将这个目录排除在外,即使你包含了这个目录,它仍然管用)。
每当用户访问一个前台终端服务器时,将会对文件名和最近修改时间应用md5函数从而创建一个字符串。如果存在了一个以该字符串为名的文件的话,将会使用这个文件,否则,将会创建一个这样的文件,并将其保存到'cache'目录下。
所以,首先在你的drupal主题下面创建一个名为'cache'的子目录,修改相应的权限,这样当代码执行时可以向该子目录写入文件。
如果你使用了Zen主题,那可可以向你子主题的template.php添加下面的代码(首先需要检查一下,这个函数是否已经存在,如果存在的话,你需要把函数声明去掉,将代码添加到函数的最底部),将STARTERKIT改为你主题的名字。
function STARTERKIT_preprocess_page(&$vars) {
$css = drupal_add_css();
$css_arr = array();
$modifiedDates = '';
$fileString = '';
foreach($css['all']['module'] as $css_module => $css_module_on) {
if(file_exists($_SERVER['DOCUMENT_ROOT'] . base_path() . $css_module)) {
$modifiedDates .= filemtime($_SERVER['DOCUMENT_ROOT'] . base_path() . $css_module);
$css_arr[] = $_SERVER['DOCUMENT_ROOT'] . base_path() . $css_module;
$fileString .= $css_module . ',';
}
}
foreach($css['all']['theme'] as $css_theme => $css_theme_on) {
if(file_exists($_SERVER['DOCUMENT_ROOT'] . base_path() . $css_theme)) {
$modifiedDates .= filemtime($_SERVER['DOCUMENT_ROOT'] . base_path() . $css_theme);
$css_arr[] = $_SERVER['DOCUMENT_ROOT'] . base_path() . $css_theme;
$fileString .= $css_theme . ',';
}
}
$combinedContent = '';
$fileName = base_path() . path_to_subtheme() . '/cache/' . md5($fileString . $modifiedDates) . '.css';
$file = $_SERVER['DOCUMENT_ROOT'] . $fileName;
if(!file_exists($file)) {
foreach($css_arr as $css_file) {
$combinedContent .= PHP_EOL.PHP_EOL.file_get_contents($css_file);
}
$fh = fopen($file, 'w');
fwrite($fh, $combinedContent);
fclose($fh);
}
$vars['styles_aggregated'] = '<style type="text/css" media="all">@import "' . $fileName . '";</style>';
}
如果你用的是一个普通的主题的话,你需要向你的template.php文件中添加以下代码(同样,存在函数已经存在的情况):
function _phptemplate_variables($hook, $vars) {
switch($hook) {
case 'page' :
$css = drupal_add_css();
$css_arr = array();
$modifiedDates = '';
$fileString = '';
foreach($css['all']['module'] as $css_module => $css_module_on) {
if(file_exists($_SERVER['DOCUMENT_ROOT'] . base_path() . $css_module)) {
$modifiedDates .= filemtime($_SERVER['DOCUMENT_ROOT'] . base_path() . $css_module);
$css_arr[] = $_SERVER['DOCUMENT_ROOT'] . base_path() . $css_module;
$fileString .= $css_module . ',';
}
}
foreach($css['all']['theme'] as $css_theme => $css_theme_on) {
if(file_exists($_SERVER['DOCUMENT_ROOT'] . base_path() . $css_theme)) {
$modifiedDates .= filemtime($_SERVER['DOCUMENT_ROOT'] . base_path() . $css_theme);
$css_arr[] = $_SERVER['DOCUMENT_ROOT'] . base_path() . $css_theme;
$fileString .= $css_theme . ',';
}
}
$combinedContent = '';
$fileName = base_path() . path_to_theme() . '/cache/' . md5($fileString . $modifiedDates) . '.css';
$file = $_SERVER['DOCUMENT_ROOT'] . $fileName;
if(!file_exists($file)) {
foreach($css_arr as $css_file) {
$combinedContent .= PHP_EOL.PHP_EOL.file_get_contents($css_file);
}
$fh = fopen($file, 'w');
fwrite($fh, $combinedContent);
fclose($fh);
}
$vars['styles_aggregated'] = '<style type="text/css" media="all">@import "' . $fileName . '";</style>';
break;
}
return $vars;
}
最后,在你的page.tpl.php中,注意将$styles替换为$styles_aggregated
下面这个例子,讲述了在drupal中,如何使用主题函数来隐藏元素.这个例子向你展示了如何隐藏节点创建页面生成的日志消息.它将永远的隐藏日志消息盒子(box),所以,如果你将来需要用到这个盒子的话,就不能使用这段代码了.
<?php
/**
* Override node form
*/
function phptemplate_node_form($form) {
// Remove 'Log message' text area
$form['log']['#access'] = FALSE;
return drupal_render($form);
}
?>
可以通过覆写theme_stylesheet_import()函数来忽略drupal.css文件.只需要向主题的template.php文件中添加以下代码:
<?php
/*
Do not include drupal's default style sheet in this theme !
*/
function phptemplate_stylesheet_import($stylesheet, $media = 'all') {
if (strpos($stylesheet, 'misc/drupal.css') == 0) {
return theme_stylesheet_import($stylesheet, $media);
}
}
?>
使用一个自定义.css文件来代替drupal.css:
<?php
function phptemplate_stylesheet_import($stylesheet, $media = 'all') {
if (strpos($stylesheet, 'misc/drupal.css') != 0) {
$stylesheet = str_replace('misc/drupal.css', 'misc/mysite.css', $stylesheet);
}
if (strpos($stylesheet, 'misc/drupal.css') == 0) {
return theme_stylesheet_import($stylesheet, $media);
}
}
?>
将这段代码放到主题的template.php文件中,这将drupal.css文件切换为一个自定义的.css文件。有些drupal站点,你想让它看不出来后台是用drupal做的话,你就需要替换这个drupal.css文件。在这个例子中,我们拷贝了原来的drupal.css文件,将其重命名为mysite.css,并将其保存到名为misc的目录下。
注意strpos的使用,来自于PHP.net:
警告—这个函数可能返回一个布尔值FALSE,但是也可能返回与FALSE等价的非布尔值,比如0或者""。更多信息可参看布尔值部分。在这个函数中使用===操作符来测试返回值。
最简单的方式是使用一个自定义图片来直接替换/misc/feed.png文件.如果不能这样做的话,你可以使用PHP来覆写默认的XML图标.
对于一个兼容PHPTemplate的主题,使用下面的步骤,你就可以轻松的将图标替换为你自己的(不仅仅是边栏区块中的,对于页面底部的也同样适用).本文基于如何覆写一个主题函数的步骤.
function phptemplate_feed_icon($url) {
$icon_url = 'path/to/new/icon';
if ($image = '<img src="'. $icon_url . '" alt="'. t('XML feed') .'" />') {
return '<span class="xml-icon"><a href="'. check_url($url) .'">'. $image .'</a></span>';
}
}