PHPTemplate是由Adrian Rossouw编写的一个drupal主题引擎,Adrian Rossouw还是Drupal 4.5主题改革的幕后推动者。
它使用something.tpl.php模板文件来实现Drupal的theme_something()函数的功能。Drupal的主题化函数文档可参看Development Plumbing站点。每个模板文件都包含了一个HTML骨架,里面嵌入了一些简单的PHP语句,用来输出动态数据。因此,如果你仅仅了解一点PHP的话,那么PHPTemplate应该是你的很好的选择:使用一些基本的PHP代码片断,你可以很容易的创建高级的drupal主题。
如果你不了解PHP的话,那么PHPTemplate仍然是一个很好的选择,因为这里面仅涉及到了很少的代码,而且这些代码都是一个模式的。你可以复制粘贴这些代码就可以了。
一个扩展的论坛讨论提供了创建PHPTemplate背后的原因。
提示:输出可用的变量
输出变量数组
<?php
print '<pre>';
print_r(get_defined_vars());
print '</pre>';
?>
使用HTML标记输出变量数组
<?php
print '<pre>';
print htmlspecialchars(print_r(get_defined_vars(), TRUE), ENT_QUOTES);
print '</pre>';
?>
为了创建一个新的PHPTemplate主题,你需要在你的themes目录下,创建一个新的目录,例如themes/mytheme.接着,你需要在该目录下创建一个名为page.tpl.php的文件.或者你也可以拷贝一个已有主题,仅仅改一下名字.对于Drupal 5,你可以基于Zen 或者Blue breeze来构建自己的主题.
page.tpl.php是唯一的一个必须的文件.它将覆写theme('page')函数,用来输出页面的最终内容,包括各种修饰,比如页首、标签、面包屑、左右栏、和页脚等等。
You can create files to override the following functions:
你可以创建模板文件来覆写下面的函数
Themes/engines/phptemplate下面包含了这些模板文件的样板,对于page.tpl.php的例子可参看box_grey。简单的将这些模板文件拷贝到你的theme/mytheme目录下,然后编辑它们。注意,对于PHPTemplate主题,你需要通过访问administer > themes,来刷新它的缓存,从而识别出新的.tpl.php模板文件。
如果你要覆写的drupal主题函数,在这里没有列出来的话,你需要自己提供一个覆写。
用于输出区块中(页面的左右栏)的内容.这个模板是可选的,通过拷贝默认的模板文件,并修改它,就可以覆写这个模板.
模板可用的变量
$block对象包括:
$block->module
生成该区块的模块的名称.
$block->delta
区块在其模块中的id.
$block->subject
区块标题.
$block->content
区块的html内容
$block->status
区块的状态(0或者1).
$block->region
区域名称,默认可用的区域有'left', 'right', 'header' 和'footer'(左栏,右栏,页首,页脚).
$block->throttle:
节流阀设置.
其它变量:
$directory
主题所在的目录,比如themes/garland 或者themes/garland/minelli.
$is_front
如果当前页面为drupal站点首页的话,返回True。
$id
展示的区块的序列id,比如,第一个区块为1,第2个区块为2,等等。
$block_id
与$id一样,但是在左右栏中将被重置。
$zebra
'odd' 或者'even'。这对于使用css创建斑马线非常有用。
$block_zebra
与$zebra一样,但是在左右栏中将被重置。
默认模板
默认的block.tpl.php,位于themes/engines/phptemplate/block.tpl.php。
<div id="block-<?php print $block->module .'-'. $block->delta; ?>" class="block block-<?php print $block->module ?>">
<?php if ($block->subject): ?>
<h2><?php print $block->subject ?></h2>
<?php endif;?>
<div class="content"><?php print $block->content ?></div>
</div>
Drupal 4.6 vs. Drupal 4.7及更高版本
在Drupal 4.6中这些变量是不同的:
在drupal4.7及更高的版本中,除了默认的'left', 'right', 'header' 和'footer'以外,你还可以定义自己的区域。
推荐阅读:
我为客户创建过一些drupal站点,站点创建后由客户来维护,我发现客户对于节点、页面、区块这些drupal概念非常困惑,所以我在所有的自定义区块的底部都添加了一个链接“编辑这个区块”,而只有具有区块管理权限的用户才可以看到这个链接(同样,我对page.tpl.php也作了相应的修改,使得只有具有页面管理权限的用户才能看到页面右下角的编辑链接)。
<div class="<?php print "block block-$block->module" ?>" id="<?php print "block-$block->module-$block->delta"; ?>">
<?php print $block->subject ?>
<div class="content"><?php print $block->content ?>
<?php if ($block->module == "block"):?>
<?php if (user_access('administer blocks')) :?>
<br /><center><a href='/admin/block/edit/<?php print $block->delta;?>'>(edit this block)</a></center>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
注意编辑链接的路径在各个drupal版本下有所不同。
在Drupal5.0中,设计者可以基于特定的区块、区块所属的模块、以及区块所在的区域,为区块创建多个tpl.php文件。
drupal模板文件的查找顺序如下:
例如,用户登录区块的delta为0。假如你将它放在了左栏中,当它显示时,PHPTemplate将按照下面的顺序寻找模板文件:
通过查看页面的源文件,你可以找到区块所属的模块以及delta:每个区块的主DIV都使用了下面的类和ID:
<div class="block block-{module}" id="block-{module}-{delta}">
使用CSS自定义样式
你也可以使用这些类和IDs为区块添加CSS规则,可用于所有的区块,特定模块的区块,或者单个区块。(为了通过区域来自定义区块的样式,你需要在选择器中使用整个区域DIV的类或者ID)。
注意,delta一般是一个数字:模块中区块的排序,从0开始。在一些情况下,delta也可以是一个名字:为了给Views模块创建的区块定义外观,你可以使用block-views-[name of your block].tpl.php。
注意:在Drupal 5中,这更简单了。只需要像前文所讲的那样就可以了。
方法1
这里所讲的具有一些技巧性,它允许你为特定的区块创建一个单独的block.tpl.php模板。你可以使用区块名称或者区块ID进行控制。下面是一个修改后的block.tpl.php,在前面带了一个条件语句。你所要做的就是编辑module == '[模块名]' 和delta == '[区块名或id]'部分就可以了。
下面是我当前的block.tpl.php,条件里面的区块信息是我站点特有的。如果你想在你的drupal站点上使用它的话,你需要按照前面所说的对其进行修改。这个是在我的站点上,为两个区块加载一个自定义block.tpl.php,你可以根据需要用于,1个,6个等等。对于每个自定义模板,你都需要一个条件语句("if "部分)。
<?php
if ( ( $block->module == 'views' && $block->delta == 'Cool Block' ) || ( $block->module == 'node' && $block->delta == '0' ) ) {
include 'block-custom.tpl.php'; /*load a custom template for those two block IDs */
return; }
?>
<div class="<?php print "block block-$block->module" ?>" id="<?php print "block-$block->module-$block->delta"; ?>">
<div class="title"><h3><?php print $block->subject ?></h3></div>
<div class="content"><?php print $block->content ?></div>
</div>
你需要自己创建一个block-custom.tpl.php,根据需要你可以创建任意多个这样的模板文件。为了在你的Drupal站点上进行测试,你可以复制一份标准的区块模板,将其改名为block-custom.tpl.php,然后对其进行编辑,比如将标题放在最后面而不是最前面,然后查看效果。剩下的就是你的事儿了。你可以在模板中根据需要放置任何想要的东西。
这意味着所有的区块都可以拥有自定义的外观,这是很多人都热切希望的。将这个添加到新的区域功能中,你将拥有100%的自定义区块。
方法2
JohnAlbin写的
block.tpl.php的内容:
<?php
$block_module = $block->module;
// force delta to be alphanumeric
$block_name = $block_module . '-' . preg_replace('/[^\w]/', '', $block->delta);
switch ($block_name) {
case 'menu-2': // Primary links
case 'views-CoolBlock': // a custom Views block named "Cool Block"
if ( @include("block-$block_name.tpl.php") ) {
return;
}
break;
}
?>
<div class="block block-<?php print $block_module; ?>" id="block-<?php print $block_name; ?>">
<h2 class="title"><?php print $block->subject; ?></h2>
<div class="content"><?php print $block->content; ?></div>
</div>
这段代码就有下面的优势:
1. 在id属性中不会有奇怪的字符(比如空格)。
2. 如果没有"block-[module]-[delta].tpl.php"文件的话,也不会引起PHP警告,此时将会使用默认的block.tpl.php代码。
方法3
dman写的
在block.tpl.php的最顶部:
<?php
// allow for unique blocks to have their own phptemplate theme
if(!empty($block->subject))
$blockid = 'block-'.strtolower(preg_replace("/[^A-Za-z0-9]+/","-",$block->subject));
else
$blockid = 'block-'.$block->module.'-'.$block->delta;
if (file_exists(path_to_theme() . "/$blockid.tpl.php")) {
include path_to_theme() . "/$blockid.tpl.php";
return;
}
?>
现在你就可以实现block-block-7.tpl.php或者block-login.tpl.php等等模板文件了。
在一个页面元素周围输出一个简单的html盒子(box).唯一常用的例子是,在drupal的内核中的搜索结果和评论表单中用到了.在评论试图选项周围,就是用的box.tpl.php.
注意,这个模板很少用到,我专职的做过1年的drupal开发,从没有遇到过要修改这个模板的,它仅仅用于Drupal的内核中,除非你需要开发内核,否则你是不会需要修改这个模板的.
可用变量
$title
盒子的标题.
$content
盒子的内容.
$region
区域. Main(主), left(左) 或者 right(右).
默认模板
<div class="box">
<h2><?php print $title ?></h2>
<div class="content"><?php print $content ?></div>
</div>
定义一个评论区块所输出的HTML.没有对评论进行任何逻辑处理,仅仅用于输出实际的评论.
可用变量
$author
链接到作者的个人信息页面.
$comment (object)
评论对象,将传递给theme_comment函数.
$content
链接的内容.
$date
格式化的发布日期.
$directory
主题所在的目录,比如themes/garland or themes/garland/minelli.
$id
被展示评论的序列ID.
$is_front
如果当前页面为首页的话,返回true.
$links
位于评论下面的上下文链接.
$new
英文'new'的翻译文本,如果评论确实是新的,未读过的.
$picture
用户图片的HTML(包含<a>标签),如果展示被启用并且图片被设置了.
$submitted
翻译的发布信息字符串.
$title
链接到评论的标题上.
$zebra
斑马线,odd/even,二选一.
默认Drupal模板文件
<div class="comment<?php print ($comment->new) ? ' comment-new' : ''; print ($comment->status == COMMENT_NOT_PUBLISHED) ? ' comment-unpublished' : ''; ?> clear-block">
<?php print $picture ?>
<?php if ($comment->new) : ?>
<a id="new"></a>
<span class="new"><?php print $new ?></span>
<?php endif; ?>
<h3><?php print $title ?></h3>
<div class="submitted">
<?php print $submitted ?>
</div>
<div class="content">
<?php print $content ?>
</div>
<?php print $links ?>
</div>
这个模板文件控制着节点的输出,和节点摘要的输出.它仅能影响page.tpl.php中的$content变量。
可用变量
$content
节点内容,如果是摘要的话,就是节点的teaser。
$date
格式化的节点创建日期。
$directory
主题所在的目录,比如themes/garland or themes/garland/minelli。
$id
被展示节点,在列表中的序列ID。
$is_front
如果当前页面为首页的话,返回true。
$links
节点链接。
$main (drupal4.6)
如果节点出现在上下文中,比如首页,在这里只展示teaser,此时为true。在drupal4.7及以后版本中,不再使用这个变量了。
$name
格式化的作者名。
$node (object)
节点对象。为了查看当前节点对象的所有属性,将下面的代码放到你的node.tpl.php中:
<pre><?php print_r($node); ?></pre>
$node_url
指向节点的链接。
$page
如果节点单独展示在一个页面时,返回true。
$picture
如果启用的话,返回用户图片的HTML。
$sticky
如果节点是sticky(粘的)的话,返回true.
$submitted
如果为这个节点类型启用了节点信息的展示的话,它将包含作者和节点创建日期等信息。
$taxonomy (array)
一个展示分类术语的HTML链接数组。
$teaser
布尔值,用来指示是否需要返回teaser,而不是整个节点文本。
$terms
分类术语的HTML。
$title
节点标题
$zebra
斑马线,odd/even二选一。
提示:输出可用的变量。
输出变量数组:
<?php
print '<pre>';
print_r(get_defined_vars());
print '</pre>';
?>
输出带有HTML的变量数组:
<?php
print '<pre>';
print htmlspecialchars(print_r(get_defined_vars(), TRUE), ENT_QUOTES);
print '</pre>';
?>
Drupal5.x的默认模板文件
<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?> clear-block">
<?php print $picture ?>
<?php if ($page == 0): ?>
<h2><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
<?php endif; ?>
<div class="meta">
<?php if ($submitted): ?>
<span class="submitted"><?php print $submitted ?></span>
<?php endif; ?>
<?php if ($terms): ?>
<span class="terms"><?php print $terms ?></span>
<?php endif;?>
</div>
<div class="content">
<?php print $content ?>
</div>
<?php
if ($links) {
print $links;
}
?>
</div>
Drupal4.7的默认模板文件
<div class="node<?php if ($sticky) { print " sticky"; } ?><?php if (!$status) { print " node-unpublished"; } ?>">
<?php if ($page == 0): ?>
<h2><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
<?php endif; ?>
<?php print $picture ?>
<div class="info"><?php print $submitted ?><span class="terms"><?php print $terms ?></span></div>
<div class="content">
<?php print $content ?>
</div>
<?php if ($links): ?>
<?php if ($picture): ?>
<br class='clear' />
<?php endif; ?>
<div class="links"><?php print $links ?></div>
<?php endif; ?>
</div>
如果你打算使用$is_front来检查当前页面是不是展示的单个节点的话,这里有篇好的帖子(尤其是帖子下面的评论更值得一读),讨论了变量$page和$is_front的不同.
只有当你处在drupal站点的首页时,变量$is_front才被设置,也就是为真,而当你处在其它页面时,$is_front为假。对于普通的节点列表页面,比如当你点击一个drupal分类术语后所得到的节点列表页面,在这里$is_front就为假(false)。
对于所有的节点列表页面,包括特定的分类术语下面的节点列表页面,$page都等于0。
如果你想为一个drupal节点使用一个特定的node.tpl.php模板文件的话,你可以将下面的代码拷贝或者合并到你的template.php中:
<?php
function _phptemplate_variables($hook, $vars = array()) {
switch ($hook) {
case 'node':
$vars['template_files'] = array('node-'. $vars['nid']);
break;
}
return $vars;
}
?>
现在,比如对于节点34,你就可以专门为它创建一个主题,名为node-34.tpl.php的模板文件.
本文是基于我的实践经验所写,我的客户向我提出了一个要求,如何让CCK定义的节点类型拥有一个他想要的主题外观。当然,有多种方式可以实现这一点:1)仅用CSS(并不是所有情况下都有效);2)使用Contemplate模块,(是不是的会让我挠头);3)一个自定义模块(根据他的情况,也不是一个好办法);4)主题模板。
随着他的需求的日益明确,我觉得主题模板模板应该是最好的办法。当然,这也是能够传授给他的最简单的方法。
具体要求和环境
新的节点类型已经用CCK定义好了,当然它还可以更精简一些。节点类型的名字是“agency”。
这个Drupal站点使用的主题为Garland。
站长对于外观没有太明确的要求,她只是想让我给他一个简单的教程,这样将来他好自己修改。他熟悉CSS,也了解一点PHP。
解决方案
首先,让我们看一下由CCK定义的节点类型。
在这个图片中,我们看到"Name"(名称)和 "Type"(类型);注意这些字段下面的说明:
为了构建主题模板文件,我们需要"Type"。
我们还需要注意,在这里我们把"body"字段叫作了什么。我们称它为"Description"。
当我们来到"Manage fields"(管理字段集)页面时,我们看到上图所示的页面。其中,"Name"列是我们需要的。然而,这里需要注意一点:我们这里没有字段叫作"body filter",这是Drupal内核中的一个表单技术,将“body”名称为"body_filter".
好了,现在全部信息我们都有了,让我们开始为这个节点类新定制主题。
打开你的文本编辑器,新建一个文件。在这里,我们将使用HTML 和PHP。首先,先输入一些基本的东西,以供将来定义CSS时使用。
<div class="content agency">
</div>
<div class="clear-block clear"></div>
它的意思是说,“下面的是这个节点的内容,节点类型为'agency'”。这里我选择使用了机器可读的节点类型作为内容标识,你也可以使用自己的标识。"content"是Drupal的标准用法,所以你需要保留它。第2行仅仅是一个结束标签。第3行也不是必需的,但是由于我们的节点中包含了图片,图片的大小可能会有所不同,加上这一行,能让浏览器返回“起点处”,从而保持统一的外观。
那么,现在我假设你想输出一些实际的内容?
节点中包含了一个图片,这里我们用的是使用了ImageCache模块的CCK "Image"字段。我们想把图片放在左上方。实际上,如果把公司名(标题)放在图片上方的话,效果可能会好一些,至于标题和图片的位置问题,我们现在先不管它,首先要做的是将它们显示出来。我们将这些东西插入到第一个<div>标签中。
ImageCache模块提供了一个非常方便的主题函数,让我们来使用它。
[顺便说一句,'echo'函数比'print'函数稍微快一点,所以我使用'echo'。不过大多数主题制作者都使用'print'。两者都能工作。
]
<?php echo theme('imagecache', 'thumbnail', $node->field_logo[0]['filepath'], $node->title, $node->title, array('align' => 'left', 'hspace' => '10')); ?>
在这个函数中,首先使用"thumbnail"(可以改为你自己要用的)来设置图片的大小。对于数据字段("$node->field_logo[0]['filepath']"),我将在下面作出解释。接下来的两个"$node->title"参数,它是告诉函数,对于"alt" 和"title"属性,在这里都使用公司名称。最后,我们使用了一个数组,它告诉ImageCache向IMG标签中添加属性'align="left"' 和'hspace="10"'。
好了,我们把图片插进去了,现在轮到标题了。在Drupal中,最标准的做法是使用<h2>标签。这个取决于你的习惯,不过在这里我将遵循Drupal标准。整个节点对象在主题中都是可用的,按照Drupal标准的,它叫作"$node"。在节点对象内部的标题(在这种情况下,就是公司名称),它的叫法就有点奇怪了,叫做 "title",而不是“company_name”。因此我们可以使用"$node->title"来引用它。
<h2><?php echo l($node->title, 'node/'. $node->nid, array('title' => t('View agency')));?></h2>
另一个标准的Drupal做法是,在标题上加一个指向节点本身的链接,这样你就可以进入节点页面,如果有权限的话,可对其进行编辑。所以我在这里使用l()函数。关于这个函数的更多信息,可参看这里。
在我的例子中,我使用表格(table)来对数据进行格式化。你也可以这样做,或者你也可以使用<div>+CSS。有些主题制作者就喜欢使用后者。你可以自由的选用你喜欢的技术。但一定要小心,不要与你的主题冲突了。
在我的例子中,我使用了CCK_Address模块,由于它与其它的CCK字段有点区别,所以我将讲解一下它的字段是怎么命名的。地址模块允许使用多个地址;多个地址构成一个名为"field_address"的数组,所以第一个地址是0,第2个地址是1,以此类推。这个模块还提供了几个子字段,它们的标签不需要与编辑页面的保持一致。比如,显示的"Address"字段,在内部为"street1";"Address continued"在内部为"street2";而"Apt/suite number"则简记为"apt."
我没有能够为这些字段使用"content_format"函数来格式化它们的内容。不知这是好是坏,但是它能工作。而普通的CCK字段有一个安全的"view"元素可用。
<tr><th>Address</th><td>
<?php
echo $node->field_address[0]['street1'];
if ($node->field_address[0]['apt']) { echo '; '. $node->field_address[0]['apt']; }
if ($node->field_address[0]['street2']) { echo '<br/>'. $node->field_address[0]['street2']; }
echo '<br/>'. $node->field_address[0]['city'] .', '. $node->field_address[0]['state'] .' '. $node->field_address[0]['zip'];
if ($node->field_address[0]['country'] != 'US') { echo '<br/><big>'. $node->field_address[0]['country'] .'</big>'; }
?>
</td></tr>
注意,我这里加了一点逻辑,从而将城市,州,和邮政编码连在一起(采用美国的格式)。由于我就在美国,所以也没有显示"US",如果加上这个的话,这里的邮递员会觉得别扭的。
现在,除了"body"字段(也就是这里的"description")以外,到目前为止,所遇到的所有字段的处理方式都是一样的。如果你参考一下你的“管理字段集”("manage fields")页面的字段名称,现在仅有几点需要你了解。
和前面的"address"一样,CCK所有字段可以是单独的,也可以是多个的,所以需要使用数足来管理它们,数组名就为“管理字段集”页面的字段名。例如,我们把电话号码定义为"field_agency_telephone",这个和前面的一样,第一个元素为field_agency_telephone[0],第2个元素为field_agency_telephone[1],以此类推。在我们这种情况下,不需要多个电话号码,如果需要的话,使用一个简单的"foreach"循环就可以做到了。
CCK提供了一个内容格式化工具(content formatter),但是你用不到它。每一个字段数组,都有一个‘view’,这个就是内容格式化工具生成的,但它已经为你做好了。这是展示数据的安全方式。而对于电子邮件地址和超链接等字段内容,CCK已经对其进行了正确的格式化处理。
让我们归者一下,引用一个字段的最好的方式就是"$field_name[0]['view'],"其中field_name可从“管理字段集”页面找到。
<tr><th>Phone</th><td><?php echo $node->field_phone[0]['view'];?></td></tr>
<tr><th>Email</th><td><?php echo $node->field_email[0]['view'];?></td></tr>
<tr><th>Web site</th><td><?php echo $node->field_website[0]['view'];?></td></tr>
那么,现在基本上就快完工了;现在就剩下"description"(或者body)字段需要考虑了。这个与前面所讲的不一样,所以你必须要小心一点。这个字段是这样引用的,"$node->content['body']['#value']",我看到一些人在帖子中建议,"$node->description"也应该可以工作,但是现在还不能。
那么,让我们将整个例子正合到一起,希望我的讲解还算清晰明了:
<div class="content agency">
<?php echo theme('imagecache', 'thumbnail', $node->field_logo[0]['filepath'], $node->title, $node->title, array('align' => 'left', 'hspace' => '10')); ?>
<h2><big><?php echo l($node->title, 'node/'. $node->nid, array('title' => t('View agency')));?></big></h2><br/>
<table border="2" cellpadding="5">
<tr><th>Address</th><td>
<?php
echo $node->field_address[0]['street1'];
if ($node->field_address[0]['apt']) { echo '; '. $node->field_address[0]['apt']; }
if ($node->field_address[0]['street2']) { echo '<br/>'. $node->field_address[0]['street2']; }
echo '<br/>'. $node->field_address[0]['city'] .', '. $node->field_address[0]['state'] .' '. $node->field_address[0]['zip'];
if ($node->field_address[0]['country'] != 'US') { echo '<br/><big>'. $node->field_address[0]['country'] .'</big>'; }
?>
</td></tr>
<tr><th>Phone</th><td><?php echo $node->field_phone[0]['view'];?></td></tr>
<tr><th>Email</th><td><?php echo $node->field_email[0]['view'];?></td></tr>
<tr><th>Web site</th><td><?php echo $node->field_website[0]['view'];?></td></tr>
</table>
<?php
if ($node->content['body']['#value']) {
echo '<p><big>'. $node->content['body']['#value'] .'</big></p>';
}
?>
</div>
<div class="clear-block clear"></div>
While I initially developed this on the Bluemarine theme, it worked without change on the
这个模板文件,我最初是在Bluemarine主题下面开发的,当我把它放在Garland主题下时,只需要在我的CSS中加入".agency table {width: auto;}"就可以了。其它都不用修改。这是由于Garland主题忽略了我的"width"属性,并将其强制为100%的缘故。
最后…
现在将你的工作保存,并检查它是否正常工作。
将文件保存到你主题的文件夹下,取名为"node-content_type.tpl.php",其中content_type是你在第一步中给节点类型起的内部名字。
展示一列节点
站点已经安装了Views模块,这样我就可以使用这个模块来选择资源了,尽管我觉得这样运行效率低一些。
由于所有字段在主题中都列出来了,那么我在Views中需要做些什么呢?对于"teaser view",我发现所有要做的就是选择节点中的字段,比如标题等等,然后你就得到了想要的节点。你可能还想排个序,但是这已经不是本文讨论的范围了。
模板文件node.tpl.php适用于所有类型的节点的主题化.这个文件覆盖了所有的节点类型,你可以按照手册的node.tpl.php页面的说明,对这个文件进行修改.为了对单独的节点类型分别进行主题化,你需要在你的主题文件夹下面创建一个node-$type.tpl.php文件,其中$type是节点类型的名称,从而为每种类型按照需要自定义主题.一些例子:
在一般情况下,你可以将$type替换为任何节点类型的名称.一种特殊情况是, flexinode模块,它在内部使用数字对类型进行命名. Flexinodes的主题化可参看http://drupal.org/node/31646.还有,你也不能使用 node-admin.tpl.php仅仅对管理页面进行主题化.(译者注:实际上,是可以这样用的,但是你需要加点东西,在template.php中加个函数,但是这种用法不常见,文中所讲的应该是,不能直接这样用.)
创建了这个文件以后,将node.tpl.php的内容拷贝进取,然后按照要求进行修改. node.tpl.php列出的所有变量都可以使用.当Drupal展示该类型的节点时,就会使用你新创建的模板文件来代替默认的node.tpl.php.
对于由flexinode创建的节点类型,你给节点类型的命名(也就是展示的节点类型名)与系统内部使用的节点类型名不一样.在系统内部使用的节点类型名为"flexinode-1", "flexinode-2",等等.查看节点类型名的一种方式是,直接查看数据库表“node”的name列。
例如,如果你使用flexinode创建了一个名为"info"的节点类型,如果你查看数据库的话,你就会发现其内部名称为"flexinode-1"。所以,你为"info"创建的模板文件应该命名为"node-flexinode-1.tpl.php"。
你也可以通过访问admin>>content>>content types页面,点击所选的节点类型,来查看flexinode后面的数字。这个数字将出现在url(比如,node/types/edit_type/1就意味着flexinode-1)。
在你的节点模板中(比如node-flexinode-1.tpl.php),你可以这样引用flexinode的不同字段:
<?php print $node->flexinode_1 ?>
导航到admin>>content>>content types页面,点击编辑所选字段链接,查看相应的url(比如node/type/edit_field/1,就意味着$node->flexinode_1),你会发现不同的字段的引用方式是类似的。
这种方式适用于文本输入框,文本字段,日期/时间。对于图片你可以这样:
<img src="/<?php print $node->flexinode_1->filepath ?>" />.
如果需要输出对象的话,你需要研究一下代码了。你可以使用下面的输出命令:
<?php print serialize($node->flexinode_1)?>
它看起来有点怪,但它是一序列的变量和它们的内容。你可以找出满足你需要的那个。如果你找出了特定字段的工作方式的话,你可以将代码贴到这里来。
我看到很多人发帖询问如何为OG首页定制主题.我自己也想对drupal4.7版本的旧式OG首页进行升级,但是我还不能找到一种像样的方式。文档中(至少我看到的是)看起来仅仅告诉我们如何为实际的group(组)节点类型定制主题(例如node-og.tpl.php),或者在默认的og_ghp_ron主题加点过滤器。这些都不是本文要讨论的。(译者注,这里所讲的首页,是小组的首页,而不是站点的首页,一个站点可以有n多个小组,每个小组有一个自己的首页面)。
让我们假定你想为你的OG首页展示的所有帖子定制主题的话。你想让这些在OG展示的帖子与它们独立的节点页面以及teaser列表页面有所区别。而对于所有的小组首页采用相同的主题方式。这是我所要讲解的(如果你想让每个小组的首页都不同的话,你仍然可以使用这个代码,或者你还可以使用views)。我觉得应该有更好的方式,我也听到有人说,这很容易,但是没有看到过讲解如何去实现的帖子。所以我只能采用我的笨方法了。
在本教程中,我们将定你的og节点类型叫做'og'。如果你不知道你的叫做什么,可以访问admin/og/og,并点击"group home page"。这里所选的就是你的og节点类型。
还有,你需要先备份你的站点,这样当你觉得不对劲的时候,还可以恢复原貌。
我想使用一种通用的方式,因为我不想,当我添加一个新的小组时,需要更新我的节点文件。我也不想让小组的创建者为小组创建一个路径别名。(当然,如果只有一个人能够创建小组,而且小组的数量也不多的话,你也可以手工的在小组编辑表单页面设置小组的路径别名,而不用安装pathauto模块;这取决于你)。
我首先要做的是安装Pathauto模块。Pathauto允许你为你的任何内容创建用户友好的url路径。按照Pathauto模块的readme里面的说明,进行安装,完成以后,访问admin/settings/pathauto,点击"node path settings"。如果你仅仅想为你的小组添加别名的话,那么在节点部分的顶部,删除"Default path pattern (applies to all node types with blank patterns below)"(默认路径模式(适用于所有的节点类型,如果下面的模式为空的话))下面的东西。
如果你没有设置这一项的话,所有的内容都将采用默认路径模式来设置别名。Pathauto是一个非常方便的模块,如果你想采用默认的模式的话,我鼓励你好好的读一下配置页面的说明文字。对于本教程,就放心把它删除了吧。
现在,在同一部分里面,找到"Pattern for all og paths"(根据你的og节点类型名会有所不同)。在下面的输入框中,输入:groups/[title-raw]。
把页面往下拉,选中复选框"Bulk generate aliases for nodes that are not aliased"(为已有的没有别名的节点批量生成别名)。保存。现在你的所有小组首页面应该都有一个自动的用户友好的别名了。好极了。
现在,我们已经找到了一种方式,帮助节点识别我们是否处于小组首页面,现在就可以编辑我们的模板文件了。进入你的主题文件夹下面,编辑名为node.tpl.php的文件。
与普通的node.tpl.php文件唯一不同的是,我们需要检查pathauto别名,来看看我们是不是处在小组首页面上。然而,我们仅需要URL的第一个参数(也就是"groups"部分),所以我们还需要使用PHP字符串函数对别名进行截取。下面的是我写的代码片断,最后为完整的代码。下面是如何决定我们是否处于小组首页面:
<?php
if (arg(0) == 'node' && is_numeric(arg(1))) {
$url_alias = drupal_get_path_alias('node/'.arg(1));
} elseif (arg(0) == 'taxonomy' && arg(1) == 'term' && is_numeric(arg(2))) {
$url_alias = drupal_get_path_alias('taxonomy/term/'.arg(2));
}
// We need to only take the first argument of the aliased path, so define the separator
$slash = '/';
// find out if the separator exists in the returned alias
$pos = strpos($url_alias, $slash);
// if the separator is not present, then just look at the URL alias; if it is present, strip the first argument only
if ($pos === false) {
$string = $url_alias;
} else {
$string = substr($url_alias, 0, $pos);
}
// if the first argument of the aliased path == 'groups', then we know it's a group home page
if ($string == 'groups'){ ?>
接下来,我们将格式化小组首页面的节点。在这里,我仅需要一个带有链接的标题,以及作者,发表日期,所以代码如下:
<?php if ($page == 0) { ?>
<div class="content"><a href="<?php print $node_url; ?>"><?php print $title?></a><span class="submitted"><?php print " ".$user_name. " " . $date; ?></span></div>
<?php }; ?>
接下来,如果别名不是'groups'的话,我将提供一个普通的teaser视图(view):
<?php
// if the first argument of the aliased path wasn't 'groups', then it's a normal teaser view
}else{ ?>
<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"><?php print $content?></div>
<div class="clr">
<?php if ($links): ?>
<div class="links"><?php print $links; ?></div>
<?php endif; ?>
</div>
</div>
<?php } ?>
接着,让我们添加独立的节点视图(view),从而完成我们的node.tpl.php文件。
下面是完整的可用的代码
(你可以根据需要自己定制外观):
<?php if ($teaser): ?>
<?php
// we just get the drupal path args so that we can look up the path alias
if (arg(0) == 'node' && is_numeric(arg(1))) {
$url_alias = drupal_get_path_alias('node/'.arg(1));
} elseif (arg(0) == 'taxonomy' && arg(1) == 'term' && is_numeric(arg(2))) {
$url_alias = drupal_get_path_alias('taxonomy/term/'.arg(2));
}
// We need to only take the first argument of the aliased path, so define the separator
$slash = '/';
// find out if the separator exists in the returned alias
$pos = strpos($url_alias, $slash);
// if the separator is not present, then just look at the URL alias; if it is present, strip the first argument only
if ($pos === false) {
$string = $url_alias;
} else {
$string = substr($url_alias, 0, $pos);
}
// if the first argument of the aliased path == 'groups', then we know it's a group home page
if ($string == 'groups'){
// below this is where you need to put your node formatting for the og home page ?>
<?php if ($page == 0) { ?>
<div class="content"><a href="<?php print $node_url; ?>"><?php print $title?></a><span class="submitted"><?php print " ".$user_name. " " . $date; ?></span></div>
<?php }; ?>
<?php
// if the first argument of the aliased path wasn't 'groups', then it's a normal teaser view
}else{
// below this is where you need to put your normal node teaser formatting ?>
<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"><?php print $content?></div>
<div class="clr">
<?php if ($links): ?>
<div class="links"><?php print $links; ?></div>
<?php endif; ?>
</div>
</div>
<?php } ?>
<?php else:
// here is where your full node formatting goes ?>
<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?> clear-block">
<?php print $picture ?>
<?php if ($page == 0): ?>
<h2><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
<?php endif; ?>
<div class="meta">
<?php if ($submitted): ?>
<span class="submitted"><?php print $submitted ?></span>
<?php endif; ?>
<?php if ($terms): ?>
<span class="terms"><?php print $terms ?></span>
<?php endif;?>
</div>
<div class="content">
<?php print $content ?>
</div>
<?php
if ($links) {
print $links;
}
?>
</div>
<?php endif; ?>
Hopefully that will help save somebody time.
希望本文对读者能有所帮助。
你可以在drupal主题的node.tpl.php模板文件中使用下面的条件语句,来为摘要创建一个独特的外观:
<?php
if ($teaser) {
//if node is being displayed as a teaser
//Anything here will show up when the teaser of the post is viewed in your taxonomies or front page
} else {
//all other cases
//Anything here will show up when viewing your post at any other time, e.g. previews
?>
或者,你想在条件语句中使用HTML,例如使用模板创建两个完全不同的布局:
<?php if ($teaser): ?>
<!-- teaser template HTML here -->
<?php else: ?>
<!-- regular node view template HTML here -->
<?php endif; ?>
注意$page变量用来判断节点是不是单独处在一个页面中,这与是否是作为摘要(teaser)显示的是有区别的:在节点的编辑预览页面, $page都为true的.
这个模板文件定义了页面的骨架.
可用变量(按字母顺序)
$base_path
返回Drupal安装的URL基路径.最初,这将默认为/。
$breadcrumb
在页面顶部用于展示面包屑的breadcrumb。
$closure
需要放在页面的底部,在页面展示出来后,用于动态javascript的调用。
$content
由Drupal生成的要展示的HTML内容。
$css
一个数组,包含了当前页面的所有CSS文件。
$directory
主题所在的目录,比如themes/garland or themes/garland/minelli.
$feed_icons
一个字符串,表示当前页面的所有种子的图标。
$footer_message
在管理设置页面(admin/settings/site-information)定义的页脚信息。
$head
由drupal_get_html_head()生成的HTML。
$head_title
在页面标题中要展示的文本。
$help
动态帮助文本,主要用于drupal的后台管理页面。
$is_front
如果当前页面为首页的话返回true。一般和mission(使命)结合使用。
$language
Drupal站点当前使用的语言。
$layout
这个设置允许你为不同的布局('none', 'left', 'right' 或者'both')使用不同的样式,这以来于你的布局结构。
$logo
Logo图片的路径,可在主题配置页面中定义。
$messages
HTML状态信息和错误信息,展示在页面的顶部。
$mission
Drupal站点的使命文本,当在主题设置中禁用了的话,那么为空。
$node
(drupal5.x及更高版本)如果你要在page.tpl.php中展示一个单独的完整的节点页面视图的话,那么就可以在你的模板中使用$node变量.
$onload_attribute
(drupal4.7及以前版本)在<head>标签中,添加onload标签,从而允许附带脚本的自动执行。
$primary_links (array)
一个包含了链接的数组,可以在phptemplate特定的配置区块中定义这些链接。
$scripts
(drupal5.x及更高版本)用来加载JavaScript文件,并使得JS设置可用的HTML。在以前,javascript文件是硬编码到page.tpl.php中去的。
$search_box
如果启用了搜索框的话,返回true。
$search_button_text
(drupal4.7及以前版本)搜索按钮上的翻译了的文本。
$search_description
(drupal4.7及以前版本)搜索按钮的翻译了的描述。
$search_url
(drupal4.7及以前版本)搜索表单要提交到的URL。
$secondary_links (array)
一个包含了链接的数组,可以在phptemplate特定的配置区块中定义这些链接。
$sidebar_left
用于左栏的HTML内容。
$sidebar_right
用于右栏的HTML内容。
$site_name
Drupal站点的名字,当在主题设置中禁用了该项的话,那么为空。
$site_slogan
Drupal站点的口号,当在主题设置中禁用了该项的话,那么为空。
$styles
用于样式表的切换。这将输出所需要的样式标签。
$tabs
在页面顶部展示的HTML标签(tab)
$title
标题,与head_title是不同的,这个在大多数时候指的是节点标题。
默认模板
下面是Drupal 5的bluemarine主题的page.tpl.php模板,让你对页面模板文件有个实际的认识。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $language ?>" xml:lang="<?php print $language ?>">
<head>
<title><?php print $head_title ?></title>
<?php print $head ?>
<?php print $styles ?>
<?php print $scripts ?>
<script type="text/javascript"><?php /* Needed to avoid Flash of Unstyle Content in IE */ ?> </script>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" id="header">
<tr>
<td id="logo">
<?php if ($logo) { ?><a href="<?php print $base_path ?>" title="<?php print t('Home') ?>"><img src="<?php print $logo ?>" alt="<?php print t('Home') ?>" /></a><?php } ?>
<?php if ($site_name) { ?><h1 class='site-name'><a href="<?php print $base_path ?>" title="<?php print t('Home') ?>"><?php print $site_name ?></a></h1><?php } ?>
<?php if ($site_slogan) { ?><div class='site-slogan'><?php print $site_slogan ?></div><?php } ?>
</td>
<td id="menu">
<?php if (isset($secondary_links)) { ?><?php print theme('links', $secondary_links, array('class' =>'links', 'id' => 'subnavlist')) ?><?php } ?>
<?php if (isset($primary_links)) { ?><?php print theme('links', $primary_links, array('class' =>'links', 'id' => 'navlist')) ?><?php } ?>
<?php print $search_box ?>
</td>
</tr>
<tr>
<td colspan="2"><div><?php print $header ?></div></td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" id="content">
<tr>
<?php if ($sidebar_left) { ?><td id="sidebar-left">
<?php print $sidebar_left ?>
</td><?php } ?>
<td valign="top">
<?php if ($mission) { ?><div id="mission"><?php print $mission ?></div><?php } ?>
<div id="main">
<?php print $breadcrumb ?>
<h1 class="title"><?php print $title ?></h1>
<div class="tabs"><?php print $tabs ?></div>
<?php print $help ?>
<?php print $messages ?>
<?php print $content; ?>
<?php print $feed_icons; ?>
</div>
</td>
<?php if ($sidebar_right) { ?><td id="sidebar-right">
<?php print $sidebar_right ?>
</td><?php } ?>
</tr>
</table>
<div id="footer">
<?php print $footer_message ?>
</div>
<?php print $closure ?>
</body>
</html>
PHPTemplate在page.tpl.php中提供了一个变量,如果你知道怎么使用的话,它将非常强大.
Drupal 5 ($layout)
$layout包含一个字符串,用来告诉你页面的布局:
如果用的是左栏的话,则为left
如果用的是右栏的话,则为right
如果左右栏都用的话,则为both
Drupal 6 ($body_classes)
一个更强大的变量, $body_classes变量包含了一些由空格分隔的非常有用的信息,你可以在你的css类中使用它.
一些Drupal 5主题已经实现了这些类,比如Zen。
用它来增加你的优势
当你把这些变量放到类中的时候,这将使得你的主题更强大,扩展性也更强。这些变量的字符串,就是专门针对CSS类进行设计的。
使用drupal_add_css()函数可以将其它的样式表添加到样式表数组中去:
<?php
// Repeat this line for every CSS file added.
drupal_add_css(path_to_theme() . '/example.css', 'theme', 'all', TRUE);
// Reassemble the $styles snippet to include the new files.
$styles = drupal_get_css();
?>
在这个例子中,我们是从主题文件夹下取得的example.css文件.当然你也可以把样式表放到files目录下,这样就不用使用path_to_theme()函数了,此时你就可以直接这样用'files/subdirectory/example.css'.
drupal_add_css()函数的参数分析:
对于Drupal 4.7.x
<?php
print $head;
print theme('stylesheet_import', base_path() . path_to_theme() . '/your_extra.css');
print $styles;
?>
因此,这就是样式表的最终顺序:
样式表可以对前面的CSS规则进行覆写(例如,style.css可以覆写它前面的所有的CSS,除了用户CSS)。
在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;
}
// (...)
?>
这里的例子来自于Drupal的论坛讨论. $hook指的是变量可用的区域(比如,对于comment.tpl.php,它就是"comment").
这个函数需要定义在一个template.php文件中,这个文件放在主题目录下面(例如: themes/box_cleanslate/template.php).
<?php
function _phptemplate_variables($hook, $vars) {
switch($hook) {
case 'comment' :
$vars['newvar'] = 'new variable';
$vars['title'] = 'new title';
break;
}
return $vars;
}
?>
这个函数对phptemplate_comment返回的变量进行了处理,你在这里可以很方便的按照需求对变量进行调整.
现在,在你的comment.tpl.php文件中,可以使用一个新的名为$newvar的变量了.类似的, $title变量覆写了phptemplate_comment中该变量的值.
一个漂亮的技巧是用来计算每个钩子的调用次数,这样你可以传递过来另一个额外的参数了.如下所示:
<?php
function _phptemplate_variables($hook, $vars) {
static $count;
$count = is_array($count) ? $count : array();
$count[$hook] = is_int($count[$hook]) ? $count[$hook] : 1;
$vars['zebra'] = ($count[$hook] % 2) ?'odd' : 'even';
$vars['seqid'] = $count[$hook]++;
return $vars;
}
?>
如果为偶数的话,就是'even';奇数的话就是'odd'.这意味着你可以为每个节点/区块/评论/其它,实现一个斑马线样式(也就是:颜色间隔切换).
接着你就可以为class='$zebra'设置一些样式了,用来处理颜色的切换.
另一个例子就是,节点标记,用来判断我们查看的是不是节点.当有人查看一片文章时,使用这个变量就可以处理不同项目的显示了.
<?php
function _phptemplate_variables($hook, $vars) {
switch ($hook) {
case 'page':
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == '') {
$vars['content_is_node'] = TRUE;
}
break;
}
return $vars;
}
?>
注意,这里的切换有点老套,但是我还是这样用了,因为将来你可能需要添加更多的变量.在这种情况下,你就需要它了.
args()用来检查你的url是/node/NID/形式的,而不是/node/NID/edit或者/node形式的.如果找到了符合条件的,我们将这个标记设为TRUE.
从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;
?>
如果你要覆写的主题函数不包含在基本列表中(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>';
}
}
首先,将xtemplate.xtmpl改名为original.xtmpl,这样这个主题就不再是xtemplate主题了.
创建page.tpl.php
创建node.tpl.php
创建 comment.tpl.php
为了简洁起见,你可能想修改“new”的展示,只有当$new != ''时,才对其进行展示。
创建block.tpl.php
创建box.tpl.php