创建一个区块:
在本例中,你将创建两个区块,它们使得内容修改更易于管理。首先,你将创建一个区块用于列出等待批准的评论,然后你将创建一个区块以列出未发布的节点。两个区块都提供了用于修改相应内容的编辑表单的链接。
让我们创建一个名为approval.module的模块。它将包含我们的区块代码。在路径sites/all/modules/custom下面创建一个名为approval的文件夹(如果modules和custom不存在的话,你需要创建它们)。
接下来,向文件中添加approval.info文件:
; $Id$
name = Approval
description = Blocks for facilitating pending content workflow.
version = "$name$"
然后,在添加approval.module文件:
<?php
// $Id$
/**
* @file
* Implements various blocks to improve pending content workflow.
*/
当你创建好这些文件后,在Administer ➤ Site building ➤
Modules下面启用该模块。你将继续使用approval.module,所以不要关闭文本编辑器。
接下来我们添加区块钩子方法并实现list操作,我们的区块将出现在区块管理页面的区块列表中(参看图9-5).
图9-5 在区块列表中,你可以看到你创建的区块了。
注意数组的键info不是区块启用时所展示给用户的区块标题。而是一个仅出现在管理员可以配置的区块列表页面的描述。你将在接下来的查看(view)情景中实现真正的区块标题。首先,你需要创建额外的配置选项,为了实现这一点,使用下面的代码来实现配置(configue)情景,你创建了一个新的表单字段,当你点击区块列表页面区块右边的配置链接时,即可看到它,如图9-6所示:
图9-6 带有区块定制字段的区块配置表单
当如图9-6所示的区块配置表单被提交后,它将触发下一步操作,这里是保存,你将使用它来保存表单字段值。
function approval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending comments');
return $blocks;
case 'configure':
$form['approval_block_num_posts'] = array(
'#type' => 'textfield',
'#title' => t('Number of pending comments to display'),
'#default_value' => variable_get('approval_block_num_posts', 5),
);
return $form;
case 'save':
variable_set('approval_block_num_posts',
(int) $edit['approval_block_num_posts']);
break;
}
}
通过使用Drupal自带的变量系统variable_set(),你将区块所展示的评论的数目保存了下来。注意这里使用了类型转换,将其转换为整数,目的是对数据进行清洁检查,最后添加查看操作,当区块显示时,返回一个待定评论的列表。
function approval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending comments');
return $blocks;
case 'configure':
$form['approval_block_num_posts'] = array(
'#type' => 'textfield',
'#title' => t('Number of pending comments to display'),
'#default_value' => variable_get('approval_block_num_posts', 5),
);
return $form;
case 'save':
variable_set('approval_block_num_posts', (int)
$edit['approval_block_num_posts']);
break;
case 'view':
if (user_access('administer comments')) {
// Retrieve the number of pending comments to display that
// we saved earlier in the 'save' op, defaulting to 5.
$num_posts = variable_get('approval_block_num_posts', 5);
// Query the database for unpublished comments.
$result = db_query_range('SELECT c.* FROM {comments} c WHERE
c.status = %d ORDER BY c.timestamp', COMMENT_NOT_PUBLISHED, 0,
$num_posts);
// Preserve our current location so user can return after editing.
$destination = drupal_get_destination();
$items = array();
while ($comment = db_fetch_object($result)) {
$items[] = l($comment->subject, 'node/'. $comment->nid, array(),
NULL, 'comment-'. $comment->cid). ' '.
l(t('[edit]'), 'comment/edit/'. $comment->cid, array(),
$destination);
}
$block['subject'] = t('Pending comments');
// We theme our array of links as an unordered list.
$block['content'] = theme('item_list', $items);
}
return $block;
}
}
这里我们通过对数据库进行查询来获得待定的评论,将评论的标题展示为链接,同时为每一个评论追加一个编辑链接,如图9-7所示
图9-7 “待定评论”列表区块在它启用后的情况。它展示了两个待定评论
在前面的代码中,注意我们是如何使用方法drupal_get_destination()的,这个方法将记住在你提交表单以前你所在的页面,所以当你更新一个评论以后(或者发布,或者删除),它将自动重定向到你原来所在的页面。
使用下面的代码,设置了区块的标题:
$block['subject'] = t('Pending comments');
现在待定区块已经完成,让我们在approval_block()钩子函数中定义另一个区块---它列出了所有未发布的节点,并提供了指向它们的编辑页面的链接。
function approval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending comments');
$blocks[1]['info'] = t('Unpublished nodes');
return $blocks;
}
}
注意这里是如何为每一个区块分配一个键值的($blocks[0], $blocks[1], . . . $blocks[n]
)。区块模块将最终使用这些键值作为$delta参数。这里我们将“待定评论”区块的$delta ID定义为0,“未发布节点”区块的$delta ID定义为1。在这里也可以使用“待定”和“未发布”作为键值。有程序员的习惯决定使用哪种键值,而键值不一定是数字形式。
下面是完整的例子,我们的新区块如图9-8所示:
function approval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending comments');
$blocks[1]['info'] = t('Unpublished nodes');
return $blocks;
case 'configure':
// Only in block 0 (the Pending comments block) can one
// set the number of comments to display.
if ($delta == 0) {
$form['approval_block_num_posts'] = array(
'#type' => 'textfield',
'#title' => t('Number of pending comments to display'),
'#default_value' => variable_get('approval_block_num_posts', 5),
);
}
return $form;
case 'save':
if ($delta == 0) {
variable_set('approval_block_num_posts', (int)
$edit['approval_block_num_posts']);
}
break;
case 'view':
if ($delta == 0 && user_access('administer comments')) {
// Retrieve the number of pending comments to display that
// we saved earlier in the 'save' op, defaulting to 5.
$num_posts = variable_get('approval_block_num_posts', 5);
// Query the database for unpublished comments.
$result = db_query_range('SELECT c.* FROM {comments} c WHERE c.status = %d
ORDER BY c.timestamp', COMMENT_NOT_PUBLISHED, 0, $num_posts);
$destination = drupal_get_destination();
$items = array();
while ($comment = db_fetch_object($result)) {
$items[] = l($comment->subject, 'node/'. $comment->nid, array(),
NULL, 'comment-'. $comment->cid). ' '.
l(t('[edit]'), 'comment/edit/'. $comment->cid, array(),
$destination);
}
$block['subject'] = t('Pending Comments');
// We theme our array of links as an unordered list.
$block['content'] = theme('item_list', $items);
}
elseif ($delta == 1 && user_access('administer nodes')) {
// Query the database for the 5 most recent unpublished nodes.
// Unpublished nodes have their status column set to 0.
$result = db_query_range('SELECT title, nid FROM {node} WHERE
status = 0 ORDER BY changed DESC', 0, 5);
$destination = drupal_get_destination();
while ($node = db_fetch_object($result)) {
$items[] = l($node->title, 'node/'. $node->nid). ' '.
l(t('[edit]'), 'node/'. $node->nid .'/edit', array(),
$destination);
}
$block['subject'] = t('Unpublished nodes');
// We theme our array of links as an unordered list.
$block['content'] = theme('item_list', $items);
}
return $block;
}
}
图9-8, 区块启用后,列出了未发布节点列表
由于你有多个区块,你查看操作下,你使用了if…elseif来构建。在每一种情况下,你检查被查看区块的$delta以决定你是否该运行该段代码。在脚本形式里,它看起来如下所示:
if ($delta == 0) {
// Do something to block 0
}
elseif ($delta == 1) {
// Do something to block 1
}
elseif ($delta == 2) {
// Do something to block 2
}
在“未发布节点”区块启用后,区块的最终结果如图9-8所示。
额外例子:添加一个“待定用户”区块
如果你想扩展approval.module,你可以添加另一个区块,以展示等待站点管理员批准的用户帐号。这将作为作业留给读者自己动手将其放到approval.module模块中去。这里展示了一个在假定的userapproval.module模块中的类似的例子:
function userapproval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending users');
return $blocks;
case 'view':
if (user_access('administer users')) {
$result = db_query_range('SELECT uid, name, created FROM {users}
WHERE uid != 0 AND status = 0 ORDER BY created DESC', 0, 5);
$destination = drupal_get_destination();
// Defensive coding: we use $u instead of $user to avoid potential namespace
// collision with global $user variable should this code be added to later.
while ($u = db_fetch_object($result)) {
$items[] = theme('username', $u). ' '.
l('[edit]', 'user/'. $u->uid. '/edit', array(), $destination);
}
$block['subject'] = t('Pending users');
$block['content'] = theme('item_list', $items);
}
return $block;
}
}
在安装模块时,启用一个区块
有时,你想在安装模块时,将一个区块自动展示出来。这非常直接,通过查询语句直接将区块的设置信息直接插入到blocks表中即可。查询放在钩子方法hook_install()中,钩子方法位于模块的.install文件中。下面是一个例子,当Drupal被安装时,用户模块启用了用户区块(参看modules/system/system.install):
db_query("INSERT INTO {blocks} (module, delta, theme, status) VALUES
('user', 0, '%s', 1)", variable_get('theme_default', 'garland'));
上面的数据库查询语句将区块插入到了区块表中,并将它的状态设置为1,所以它被启用了。
区块可视化例子
在区块管理接口里面,你可以在区块配置页面的“页面可视化配置”里面加入php代码片段。当一个页面被构建时,Drupal将运行php代码片段来决定区块是否被显示。一些常用的代码片段例子如下所示。每一段代码返回TRUE或FALSE来指示区块对于特定请求是否可见。
将区块仅展示给登录用户
当$user->id不为0时,返回TRUE
<?php
global $user;
return (bool) $user->uid;
?>
将区块仅展示给匿名用户
当$user->id为0时,返回TRUE
<?php
global $user;
return !(bool) $user->uid;
?>
小结
在本章,你学到了以下几点:
区块是什么以及它们与节点的区别
区块的可视化和位置配置是如何设定的
如何定义一个或多个区块
如何在默认情况下启用区块