logo

额外区块类型 (EBT) - 全新的布局构建器体验❗

额外区块类型 (EBT) - 样式化、可定制的区块类型:幻灯片、标签页、卡片、手风琴等更多类型。内置背景、DOM Box、JavaScript 插件的设置。立即体验布局构建的未来。

演示 EBT 模块 下载 EBT 模块

❗额外段落类型 (EPT) - 全新的 Paragraphs 体验

额外段落类型 (EPT) - 类似的基于 Paragraph 的模块集合。

演示 EPT 模块 滚动

滚动

Hook_menu Drupal 7 通过模块创建页面

14/10/2025, by Ivan

在上一课中,我们学习了如何通过 Drupal API 从数据库中输出信息,具体来说使用了钩子 hook_block_info()hook_block_view()。在本课中,我们将学习如何输出页面,也就是使用钩子 hook_menu,将页面连接到 Drupal 的其他部分,如菜单、翻译模块、模板等。

我们从简单的开始,创建一个页面,用于输出最近 10 条新闻的标题和描述。这样就能得到一个简短的新闻列表。我们将使用 hook_menu()。以下是它的说明,之后我们会进行实际使用。

hook_menu()

定义菜单项并返回页面。

当模块中调用此钩子时,它会注册路径,并指定 Drupal 处理的顺序。路径既可以仅用于处理请求,也可以被添加到菜单中,例如导航菜单。路径及其相关信息称为 menu router item。此钩子只在特定情况下被调用(例如启用模块时),其结果会被缓存到数据库中。因此,在修改模块中的钩子后,通常需要清除缓存。

hook_menu() 返回一个关联数组,其中的键表示路径,值是另一个包含该路径属性的关联数组(这些属性在下面说明)。

每个路径的定义包括返回页面的回调函数,当该路径被请求时会调用此函数。如果没有其他路径与该 URL 匹配,钩子将返回页面。例如,您的模块可以注册路径 “abc/def”。

<?php   

function mymodule_menu() {
    $items['abc/def'] = array(
      'page callback' => 'mymodule_abc_view',
    );
    return $items;
}
function mymodule_abc_view($ghi = 0, $jkl = '') {
    // ...
}
?>

当请求路径 “abc/def” 且 URL 中没有更多内容时,不会传递额外参数。而当请求路径 “abc/def/1/Omsk” 时,页面会接收参数 “1” 和 “Omsk”。这在我们创建页面模板时非常有用。

路径中的附加参数可以定义为一个关联数组。参数列表可以包含简单的数值或复杂的值。当数字用于路径时,并且调用了回调函数(返回页面的函数),对应模块路径将被数字替换。例如,可以使用 arg(0) 调用第一个参数,arg(1) 调用第二个参数,依此类推。

<?php   

function mymodule_menu() {
    $items['abc/def'] = array(
      'page callback' => 'mymodule_abc_view',
      'page arguments' => array(1, 'foo'),
    );
    return $items;
}
?>

当访问路径 “abc/def” 时,返回的页面将接收 “def” 作为第一个参数,固定的 “foo” 作为第二个参数。钩子的完整说明可在此页面查看:http://api.drupal.org/api/drupal/modules--system--system.api.php/functio...

现在我们来创建一个简单的页面:

function sitemade_menu(){
    $items = array(); // 初始化菜单项数组
     
    $items['page_example'] = array(  // 添加路径 'page_example' 的页面
      'title' => '页面示例', // 页面标题
      'description' => '普通页面', // 页面描述
      'page callback' => '_page_example', // 返回页面内容的函数
      'access callback' => TRUE, // 允许所有人访问该页面
      'expanded' => TRUE,
    );    
     
    return $items; // 返回页面列表
}
 
function _page_example($content = NULL) {
    $content = ''; // 初始化内容为空
    $query = db_select('node_revision', 'n'); // 选择 node_revision 表,其中存储节点的修订版本
    $query->innerJoin('field_revision_body', 'b', 'b.revision_id = n.vid'); // 关联 field_revision_body 表(包含正文)
    $query->innerJoin('node', 'd', 'n.nid=d.nid'); // 关联 node 表(包含节点标题)
    $query->fields('n', array('title'), array('nid'), array('vid')); // 选择字段
    $query->fields('b', array('body_value'));
    $query->condition('d.type', 'news'); // 限制为内容类型 news
    $query->orderBy('n.timestamp', 'DESC'); // 按时间降序排列
    $query->range(0, 10); // 仅选择最近 10 条
    $result = $query->execute(); // 执行数据库查询
    while($nodes = $result->fetch()){ // 处理结果
        $content .= '<h3>' . $nodes->title . '</h3>'; // 输出标题
        $content .= $nodes->body_value; // 输出正文
    }
    return $content; // 返回内容
}

我们还可以使用钩子属性 type,将页面放入不同的菜单中,例如后台菜单或主菜单(main menu)。

让我们来试试:

function sitemade_menu(){
    $items = array(); // 初始化菜单项数组
     
    $items['page_example'] = array(  // 添加路径 'page_example' 的页面
      'title' => '页面示例', // 页面标题
      'description' => '普通页面', // 页面描述
      'page callback' => '_page_example', // 返回页面内容的函数
      'access callback' => TRUE, // 允许所有人访问该页面
      'expanded' => TRUE,
      'type' => MENU_NORMAL_ITEM,
      'menu_name' => 'main-menu',
    );    
    return $items; // 返回页面列表
}

刷新缓存后,该页面的链接就会出现在菜单中。

Add menu

除了普通菜单项外,还可以将页面显示在 Drupal 管理后台中:

function sitemade_menu(){
    $items = array(); // 初始化菜单项数组    
    $items['admin/config/content/page_example'] = array(  // 添加路径 'admin/config/content/page_example' 的页面
      'title' => '页面示例', // 页面标题
      'description' => '普通页面', // 页面描述
      'page callback' => '_page_example', // 返回页面内容的函数
      'access arguments' => array('administer site configuration'), // 仅限管理员访问
    );    
    return $items; // 返回页面列表
}

现在,该页面仅对管理员可见,并且可以在后台菜单中找到链接:

Drupal add menu page

该链接会出现在后台菜单中,因为 Drupal 会自动在路径 admin/config/content/* 下添加链接。如果我们将路径设置为 admin/config/people/*,那么链接会出现在“用户”部分(* 可替换为自定义名称,例如本例中的 page_example)。

现在我们已经学会了创建区块和页面,我认为这些是输出内容时最常用的钩子,它们将在您的模块中经常使用。

下一课我们将学习 hook_perm(),用于为用户创建新的访问权限。