从Drupal 4.7开始,主题可以实现任意数量的区域,用于区块或者其它内容的显示。你可以到Drupal的区块管理页面(admin/build/block)看一下,你将看到,实际上区域本质上就是一个容器,你可以向里面添加区块。你也可以使用PHP向区域中添加非区块内容。什么是区域呢,一个比较好的例子就是边栏。
这些区域可以用于整个页面,或者其它的主题元素中,比如接电或者评论。
PHPTemplate引擎定义了5个默认的区域:left(左栏), right(右栏), content(内容), header(页首), 和footer(页脚)。为了实现这些区域,在drupal主题中,只需要在page.tpl.php模板文件中包含进变量$sidebar_left, $sidebar_right, $content, $header, 和$footer_message就可以了,比如,<?php print $header; ?>。
如何实现自定义区域
对于一个主题,如果你不想使用默认的区域,想自己定义一套的话,你可以使用_regions()钩子函数。在这种情况下,你的自定义区域,将会覆写PHPTemplate的默认区域。
如果在主题目录中还没有template.php文件的话,那么创建一个;如果有的话,就使用现有的。然后,打开template.php文件,向里面添加一个mytheme_regions()函数,用来定义你的区域。每个区域都需要一个名字(没有空格的字符串)和一个描述(展示给用户的文本,比如在区块管理页面)。在下面的代码中,我们为"mytheme"主题重新定义了除左栏以外的PHPTemplate的默认区域,还为它添加了两个新的区域。
<?php
function mytheme_regions() {
return array(
'right' => t('right sidebar'),
'content' => t('content'),
'header' => t('header'),
'footer' => t('footer'),
'floater' => t('floater'),
'inline1' => t('inline 1')
);
}
?>
注意:对于函数名,你需要注意几点:
如何向页面写入主题的区域变量。
如果你需要在page.tpl.php中使用你的区域的话,你不需要为你的区域去创建一个变量,然后再将内容指定给它;PHPTemplate已经自动帮你完成了。你所需要做的就是,通过编辑你主题的page.tpl.php文件,将变量写入到页面。对于你定义的每个新的区域,只需要在page.tpl.php中加一个print语句就可以了。对于前面定义的'floater'区域,可以这样调用:
<?php print $floater;?>.
当然,你可以使用HTML,CSS,PHP(这个可能用到)来为你的区域定制一个好看的外观。
默认情况下,所有定义的区域都传递给page.tpl.php。但是只需要额外的几步,你也可以将特定的区域应用到其它的模板文件中:node.tpl.php,comment.tpl.php等等。下面是如何实现的。
在你定义区域的template.php文件中,定义一个_phptemplate_variables()函数(如果已经存在的话,就使用已有的)。在这里,你要做的就是将区域内容指定到一个特定的主题调用中。当调用_phptemplate_variables()时,将会向$hook变量传递一个主题参数,比如'node'。所以,使用下面的代码,我们可以将区域指定到节点模板文件中:
<?php
function _phptemplate_variables($hook, $variables) {
// Load the node region only if we're not in a teaser view.
if ($hook == 'node' && !$vars['teaser']) {
// Load region content assigned via blocks.
foreach (array('inline1') as $region) {
$variables[$region] = theme('blocks', $region);
}
}
return $variables;
}
?>
注意,我们在这里做了检查,确保不是处于一个'teaser'视图中,这样只有当处于完整的节点视图中时,才加载内置区域。
现在,在你的节点模板中,你就可以把区域变量包含进来了。下面是标准的phptemplate node.tpl.php模板加进'inline1'区域后的样子:
<div class="node<?php if ($sticky) { print " sticky"; } ?><?php if (!$status) { print " node-unpublished"; } ?>">
<?php if ($picture) {
print $picture;
}?>
<?php if ($page == 0) { ?><h2 class="title"><a href="<?php print $node_url?>"><?php print $title?></a></h2><?php }; ?>
<span class="submitted"><?php print $submitted?></span>
<span class="taxonomy"><?php print $terms?></span>
<div class="content"><div class="floatleft"><?php print $inline1?></div><?php print $content?></div>
<?php if ($links) { ?><div class="links">» <?php print $links?></div><?php }; ?>
</div>
大多数情况下,你都会为你的区域添加一些样式,你可以像往常一样,通过主题的style.css文件来完成。例如,在这里,我们将让内置区域向左浮动:
div.floatleft {
float: left;
}
由于一个节点的变量传递给了其它的节点模板,所以你也可以在node-type模板中实现你的自定义外观。
这种方式还可以应用到其它的主题元素中。下面的例子将特定的区域指定到了节点和评论中:
<?php
function _phptemplate_variables($hook, $variables) {
// Load region content assigned via blocks.
// Load the node region only if we're not in a teaser view.
if ($hook == 'node' && !$variables['teaser']) {
foreach (array('node1', 'node2') as $region) {
$variables[$region] = theme('blocks', $region);
}
}
else if ($hook == 'commment') {
foreach (array('comment1', 'comment2') as $region) {
$variables[$region] = theme('blocks', $region);
}
}
return $variables;
}
?>
如果你想将内容指定到区域中,而又不通过区块来实现的话,你可以使用drupal_set_content()函数。这允许你绕过通常的区块机制,你可以尝试以下几点:
将内容设置到区域中
在你的模块代码中,将内容设置给区域。在这里,你可以使用themename_regions()数组中不存在的区域名。这样,这些区域对于区块来说就不可用,因此里面也就不会放置区块内容了。假定你的区域叫做'region1' 和'region2'。在你的模块中,可以这样做:
<?php
$output = 'whatever';
drupal_set_content('region1', $output);
?>
在template.php文件中,设置一个变量,并将区域内容指定给这个变量。
<?php
function _phptemplate_variables($hook, $variables) {
// Load region content assigned via drupal_set_content().
if ($hook == 'page') {
foreach (array('region1', 'region2') as $region) {
$variables[$region] = drupal_get_content($region);
}
}
return $variables;
}
?>
输出你的内容
在你的page.tpl.php文件中,在需要的地方输出区域:
<?php
print $region1;
?>