在Drupal 5.0中, PHPTemplate支持在一个主题下,使用多个页面模板.根据当前的url路径(例如node/1, taxonomy/term/2, 或者user/1),PHPTemplate会按照顺序寻找相应的模板,如果找不到的话,将会采用默认的page.tpl.php模板文件。
例如,如果你访问http://www.example.com/node/1/edit,PHPtemplate将按照降序寻找下面的模板:
page-node-edit.tpl.php
page-node-1.tpl.php
page-node.tpl.php
page.tpl.php
如果你访问的是http://www.example.com/tracker,PHPTemplate将寻找下面的模板:
page-tracker.tpl.php
page.tpl.php
这一规则还适用于用户和分类的url。当访问http://www.example.com/user/1时 ,PHPtemplate将按照降序寻找下面的模板:
page-user-1.tpl.php
page-user.tpl.php
page.tpl.php
注意,首页是个特殊的情况(它的URL是http://example.com,后面没有相对路径了)。对于这种情况,你可以使用下面的模板:
page-front.tpl.php
记住,这些模板建议是基于drupal的内部路径的。如果你使用了path 或者pathauto模块的话,那么你看到的将是路径的别名。但是对于这些模板来说,他们仍然是基于drupal内部路径的。如果你想基于URL别名使用模板的话,可参看基于URL别名的不同页面模板一文。
如果你需要基于其它的一些规则来切换页面模板文件的话(例如,登录用户的角色),你可以在你主题的template.php文件中实现phptemplate_variables()函数。$vars['template_files']变量存储了一个可能的tpl.php文件数组,使用先进后出的规则。
注意:对于Drupal 5,你可参看相应的文章http://drupal.org/node/104316。
你可以为单篇文章、URL路径、分类术语、章节、和你的首页定制主题。
对于节点、页面和其它的主题定制的更全面的例子,可参看手册的PHP Template Snippets >> Customising full page layouts and sections。
一种方式是使用sections module,来为你站点的不同部分使用不同的主题。然而,如果你的自定义主题或者模块拥有自己的主题模板文件的话,比如event(事件)模块,它需要许多重复的CSS和图片资源。
在一个Drupal站点上使用多个主题的关键是,由主题引擎决定当前你在站点中所处的位置。下面是我们可以从模板引擎中检查的一列条件。
$is_front phptemplate变量可用来检查当前是否处于首页。
<?php
if ($is_front) {
include('front.tpl.php');
return;
}
?>
Drupal的arg()函数用来得到路径中的参数。
arg(0)=="admin"// is /admin
arg(0) =="node"// is /node
arg(0)=="user" // is /user
arg(0)=="node"&&arg(1)=="add" // is /node/add
arg(0)=="node"&& arg(2)=="edit" // is /node/###/edit
arg(0)=="user"&&arg(1)=="add" // is /user/add
arg(0)=="admin"&&arg(1)="user"&&arg(2)=="create" // is /admin/user/create
arg(0)=="alias"&&arg(1)=="alias1" is /alias/alias1
arg(0)=="taxonomy"&&arg(1)=="term"&&arg(2)=="term#" // is /taxonomy/term/term#
//arg(1)=="comment"
//arg(2)=="reply"
一旦你知道了front_page的值,或者路径,那么我们就可以使用不同的主题模板,也可使用CSS文件,或者修改xHTML标签的CSS类了。本节将分成3个子页面。
<?php
if ($is_front) {
include 'front.tpl.php';
return;
}
elseif (arg(0)=="taxonomy"&&arg(1)=="term"&&arg(2)=="term#") { // add argument of choice
include 'term#.tpl.php';// add template of choice
return;
}
<?php
if ($is_front) {
include 'page_front.tpl.php';
return;
}
if ($node->type == 'nodetype') { // all pages on my site are 'nodetype'
$my_path = explode("/", drupal_get_path_alias('node/'.$node->nid)); // all pages have path like 'section/page'
$my_path = $my_path[0];
} else {
$my_path = arg(0);
}
switch ($my_path) {
case 'using':
$section = 1;
break;
case 'education':
$section = 2;
break;
case 'company':
$section = 3;
break;
case 'image':
$section = 4;
break;
case 'forum':
$section = 5;
break;
default:
$section = 0;
}
$css_section = 'section'.$section;
?>
PHPTemplate 主题:
在page.tpl.php的body标签中(来自于bluemarine):
<body <?php print $onload_attributes ?> >
将变为:
<body class=" <?php print arg(0); ?> " <?php print $onload_attributes ?> >
接着你就可以为管理页面使用.admin作为css父选择器了。
对于Smarty
在page.tpl的body标签中(来自于bluemarine_smarty):
<body{$onload_attributes}>
将变为:
<body class="{php} echo arg(0); {/php}"{$onload_attributes}>
当查看根节点时,这可能产生一个空的class属性值---可以在class中包含一个固定的前缀,从而阻止这种情况的发生。
下面的代码片断,用来检查当前节点是否匹配一个主菜单链接.这段代码假定主菜单链接的格式为'/somepage'.
<?php if (count($primary_links)) : ?>
<ul class="primary">
<?php foreach ($primary_links as $link): ?>
<?php preg_match("/<a\s*.*?href\s*=\s*['\"]([^\"'>]*).*?>(.*?)<\/a>/i", $link, $matches); ?>
<?php if (('/'.drupal_get_path_alias('node/'.$node->nid))==$matches[1]): /* if $node exists */ ?>
<li class="selected"><?php print $link?></li>
<?php elseif ('/'.arg(0)==$matches[1]): /* else try to use arg */ ?>
<li class="selected"><?php print $link?></li>
<?php elseif ((drupal_get_path_alias('node/'.$node->nid)=='node/') && (arg(0)=='node') && ($matches[1]=='/')): /* else if home */ ?>
<li class="selected"><?php print $link?></li>
<?php else: ?>
<li><?php print $link?></li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
<?php endif; ?>
在这段代码中,我们只使用了arg(0)进行检查,对于那些由drupal模块创建的类节点来说,可能并不适用.
这个代码将为你drupal站点上的每个页面的<body>标签生成一个类(class)和id。
在你主题的页面模板文件(page.tpl.php)中,将已存在的<body>标签替换为下面的代码:
<body<?php print phptemplate_body_attributes($is_front, $layout); ?>>
并在你主题的template.php文件中添加下面的代码:
/**
* Sets the body tag class and id attributes.
*
* From the Theme Developer's Guide, http://drupal.org/node/32077
*
* @param $is_front
* boolean Whether or not the current page is the front page.
* @param $layout
* string Which sidebars are being displayed.
* @return
* string The rendered id and class attributes.
*/
function phptemplate_body_attributes($is_front = false, $layout = 'none') {
if ($is_front) {
$body_id = $body_class = 'homepage';
}
else {
// Remove base path and any query string.
global $base_path;
list(,$path) = explode($base_path, $_SERVER['REQUEST_URI'], 2);
list($path,) = explode('?', $path, 2);
$path = rtrim($path, '/');
// Construct the id name from the path, replacing slashes with dashes.
$body_id = str_replace('/', '-', $path);
// Construct the class name from the first part of the path only.
list($body_class,) = explode('/', $path, 2);
}
$body_id = 'page-'. $body_id;
$body_class = 'section-'. $body_class;
// Use the same sidebar classes as
$sidebar_class = ($layout == 'both') ? 'sidebars' : "sidebar-$layout";
return " id=\"$body_id\" class=\"$body_class $sidebar_class\"";
}
注意:这里你需要启用简洁url,才能正常使用。
使用例子:
使用了这段代码后,当你访问news/archive/2007页面时,你将看到下面的<body>属性:
<body id="page-news-archive-2007" class="section-news sidebar-left">
现在你要做的就是为整个站点的新闻栏目创建一套新的CSS规则:
.content { background-image: url("background.png"); }
.section-news .content { background-image: url("news.png"); }
如果你启用了路径别名模块的话,并且花了功夫为你的页面创建了多层级的路径,这样你就很容易将站点分为做个栏目,然后为每个栏目使用一个完全不同的布局(背景图片,颜色,宽度等等)。
Drupal 5包含了一个非常有用的机制,可以为不同的页面、区块、节点等提供不同的模板。例如,你可以为'blog'节点类型添加一个模板node-blog.tpl.php,从而取代默认的node.tpl.php模板。对于页面模板,就更加方便了,所以你可以为特定节点创建特定的模板,可参看基于当前路径适用不同的页面模板一文。
通过_phptemplate_variables()函数,还可以编辑可能的"template suggestions"(模板建议)列表。例如,下面的代码片断就基于URL别名创建了额外的“suggestions”(建议)。这比使用内部Drupal路径的方法更强大。
<?php
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
case 'page':
// Add node template suggestions based on the aliased path.
// For instance, if the current page has an alias of about/history/early,
// we'll have templates of:
// node_about_history_early.tpl.php
// node_about_history.tpl.php
// node_about.tpl.php
// Whichever is found first is the one that will be used.
if (module_exists('path')) {
$alias = drupal_get_path_alias($_GET['q']);
if ($alias != $_GET['q']) {
$suggestions = array();
$template_filename = 'node';
foreach (explode('/', $alias) as $path_part) {
$template_filename = $template_filename . '_' . $path_part;
$suggestions[] = $template_filename;
}
}
$vars['template_files'] = $suggestions;
}
break;
}
return $vars;
}
?>
可以在你的template.php文件中修改一个模板的“模板建议”("template suggestions")列表。下面的代码片断,将根据当前页面的节点类型来添加页面模板建议。这样,你就可以为节点类型为新闻(news)的页面定义一个模板page-nodetype-news.tpl.php。
<?php
// Add additional template suggestions
function _phptemplate_variables($hook, $vars) {
switch ($hook) {
case 'page':
// Add page template suggestions based on node type, if we aren't editing the node.
if ($vars['node'] && arg(2) != 'edit') {
$vars['template_files'][] = 'page-nodetype-'. $vars['node']->type;
}
break;
}
return $vars;
}
?>
如果你使用的drupal主题为Zen的话,打开你的子主题的template.php文件,将SUBTHEME_preprocess_page()函数的注释去掉,并向其中添加以下代码(没有<?php 和?>标签):
<?php
// Add page template suggestions based on node type, if we aren't editing the node.
if ($vars['node'] && arg(2) != 'edit') {
$vars['template_files'][] = 'page-nodetype-'. $vars['node']->type;
}
?>
可以在你的template.php文件中修改一个模板的“模板建议”("template suggestions")列表。下面的代码片断,将根据当前页面的URL别名来添加页面模板建议。这样你就可以为'music'路径或者目录下面的页面定义一个page-music.tpl.php模板文件了。
Drupal 5版本:
<?php
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
case 'page':
// Add page template suggestions based on the aliased path.
// For instance, if the current page has an alias of about/history/early,
// we'll have templates of:
// page-about-history-early.tpl.php
// page-about-history.tpl.php
// page-about.tpl.php
// Whichever is found first is the one that will be used.
if (module_exists('path')) {
$alias = drupal_get_path_alias(str_replace('/edit','',$_GET['q']));
if ($alias != $_GET['q']) {
$suggestions = array();
$template_filename = 'page';
foreach (explode('/', $alias) as $path_part) {
$template_filename = $template_filename . '-' . $path_part;
$suggestions[] = $template_filename;
}
}
$vars['template_files'] = $suggestions;
}
break;
}
return $vars;
}
?>
Drupal 6版本:
<?php
function phptemplate_preprocess_page(&$vars) {
if (module_exists('path')) {
$alias = drupal_get_path_alias(str_replace('/edit','',$_GET['q']));
if ($alias != $_GET['q']) {
$suggestions = array();
$template_filename = 'page';
foreach (explode('/', $alias) as $path_part) {
$template_filename = $template_filename . '-' . $path_part;
$suggestions[] = $template_filename;
}
}
$vars['template_files'] = $suggestions;
}
}
?>
变通
下面的是这个方法的一些变通应用。
在一个页面模板中仅修改一个CSS类。适用于那些不需要创建一个新的模板,仅需要修改CSS的情况。
<?php
if (module_exists('path')) {
$alias = drupal_get_path_alias($_GET['q']);
$class = explode('/', $alias);
print '<div class="page page-'.$class[0].'">';
}
?>
对特定节点类型的修改限制:
<?php
// (...)
if(arg(0)=='node') {
$vars['template_files'] = 'page_' . $vars['node']->type;
}
// (...)
?>