Discuz! 的模板引擎是一个 “PHP 模板引擎”,它的工作核心思想是 “逻辑与表现分离”

discuz 模板输出php
(图片来源网络,侵删)
  • 逻辑:指 PHP 代码,负责数据处理、数据库查询、业务逻辑判断等。
  • 表现:指 HTML 模板文件,负责页面的最终展示,包含 HTML、CSS 和一些特殊的模板标签。

模板引擎就像一个“翻译官”,它读取模板文件,将其中特殊的模板标签“翻译”成最终的 PHP 代码,然后执行这些代码,并将 PHP 变量的值填充到相应位置,最终生成用户浏览器可以直接解析的 HTML 代码。


核心流程:从 PHP 到 HTML

整个过程可以分为三个主要步骤:

  1. PHP 端:准备数据

    • 在 PHP 文件中,你通过常规的 PHP 代码(如数据库查询 DB::query()、数组处理等)获取需要展示的数据。
    • 将这些数据赋值给一个或多个 PHP 变量。
  2. 交接:调用模板引擎

    discuz 模板输出php
    (图片来源网络,侵删)
    • PHP 端使用 include template('模板名称'); 这个函数来请求输出一个模板。
    • 这个函数会触发 Discuz! 的模板引擎。
  3. 模板端:展示数据

    • 模板引擎找到并加载 template/当前风格/模板名称.htm 文件。
    • 引擎解析这个 .htm 文件,遇到模板标签时,会用 PHP 端准备好的变量值进行替换。
    • 解析完成后,生成一个临时的 PHP 文件(通常在 data/template/ 目录下)。
    • 服务器执行这个临时 PHP 文件,将最终的 HTML 输出到浏览器。

模板语法详解

Discuz! 的模板语法非常直观,它使用花括号 来包裹其特殊指令。

变量输出

这是最基本的功能,用于显示 PHP 传递过来的变量。

  • 简单变量

    // PHP 代码中
    $username = '张三';
    $age = 25;
    // 模板代码中
    欢迎您,{$_G[username]}!您的年龄是:{$age}
  • 数组/对象变量: 使用 来访问数组的元素或对象的属性。

    // PHP 代码中
    $userInfo = array(
        'name' => '李四',
        'profile' => array(
            'city' => '北京',
            'job'  => '工程师'
        )
    );
    // 模板代码中
    用户名:{$userInfo.name}
    城市:{$userInfo.profile.city}
  • 全局变量 $_G$_G 是 Discuz! 中最重要的全局变量数组,包含了当前用户、站点设置、会话信息等所有全局数据。

    站点名称:{$_G['site']['name']}
    当前用户UID:{$_G['uid']}

条件判断 if

if 标签用于根据条件来决定是否输出某部分内容。

<!-- 基本用法 -->
{if $age > 18}
    您已成年。
{else}
    您未成年。
{/if}
<!-- 多重条件 -->
{if $usergroup == 'admin'}
    您是管理员。
{elseif $usergroup == 'mod'}
    您是版主。
{else}
    您是普通用户。
{/if}
<!-- 判断变量是否存在或为空 -->
{if !empty($post['message'])}
    帖子内容:{$post['message']}
{/if}

循环遍历 loop

loop 标签用于遍历一个数组,对数组中的每一个元素重复执行一段代码。

这是在列表页(如帖子列表、用户列表)中最常用的标签。

<!-- 假设 $threadlist 是一个包含多个主题信息的数组 -->
<!-- {loop $threadlist $thread} -->
    <!-- 循环开始,$thread 是当前循环到的元素,相当于 PHP 中的 $thread -->
    <li>
        <a href="forum.php?mod=viewthread&tid={$thread['tid']}">
            {$thread['subject']}
        </a>
        <span>作者:{$thread['author']}</span>
        <span>回复:{$thread['replies']}</span>
    </li>
<!-- {/loop} -->

语法解析{loop $array $key => $value}

  • $array: 要遍历的数组。
  • $key: 可选,当前元素的键名。
  • $value: 当前元素的值。

示例

{loop $userlist $uid $user}
    用户ID: {$uid}, 用户名: {$user['username']}
{/loop}

引入子模板 template

在一个模板文件中,可以引入另一个模板文件,用于实现模块化,例如页头、页脚、侧边栏等。

<!-- 在 forumdisplay.htm 中 -->
{template header}      <!-- 引入头部模板 template/default/header.htm -->
{template forumlist}   <!-- 引入版块列表模板 -->
<!-- 主要内容区 -->
{loop $threadlist $thread}
    ...
{/loop}
{template footer}      <!-- 引入底部模板 template/default/footer.htm -->

注释

在模板文件中,使用 包裹的内容会被引擎忽略,不会输出到 HTML 中,非常适合写注释。

{这是一个模板注释,不会在源代码中看到}

实践示例:修改帖子列表的标题颜色

假设我们想把置顶帖子的标题显示为红色。

第1步:找到对应的 PHP 文件

帖子列表通常在 forum/forumdisplay.php 文件中处理,打开它,找到生成 $threadlist 数组的核心代码段。

第2步:在 PHP 中添加判断逻辑

forumdisplay.php 中,找到处理 $threadlist 的循环(通常在 while($thread = DB::fetch($query)) 循环里),添加一个变量来标记帖子是否为置顶。

// ... 在 forumdisplay.php 的循环中 ...
while($thread = DB::fetch($query)) {
    // 原有的代码...
    // 添加我们的逻辑
    if($thread['displayorder'] > 0) {
        $thread['title_color'] = 'red'; // 如果是置顶(displayorder > 0),设置颜色变量
    } else {
        $thread['title_color'] = '#333'; // 否则使用默认颜色
    }
    // ... 继续原有的代码 ...
}

第3步:找到并修改对应的模板文件

帖子列表的模板文件通常是 template/default/forum/forumdisplay.htm

第4步:在模板中使用新变量

打开 forumdisplay.htm,找到显示帖子标题的代码,将原来的 {$thread['subject']} 修改为带有样式的版本。

<!-- 原来的代码可能是这样的 -->
<a href="forum.php?mod=viewthread&tid={$thread['tid']}">{$thread['subject']}</a>
<!-- 修改为如下代码 -->
<a href="forum.php?mod=viewthread&tid={$thread['tid']}" style="color: {$thread['title_color']};">
    {if $thread['displayorder'] > 0}[置顶] {/if}
    {$thread['subject']}
</a>

第5步:清空缓存并刷新

模板修改后,需要清空 Discuz! 的缓存,否则可能看不到效果。 进入 后台 -> 工具 -> 更新缓存,更新“模板缓存”,然后刷新论坛页面,你就会看到置顶帖子的标题变成了红色。


进阶技巧与注意事项

  1. 模板缓存: Discuz! 会将解析后的模板编译成 PHP 文件存放在 data/template/ 目录下,以提高访问速度,当你修改了模板文件后,必须更新缓存才能生效。

  2. eval 函数: 有时你需要在模板中执行一小段复杂的 PHP 代码,可以使用 eval

    {eval $hello = 'Hello from eval!';}
    {echo $hello}

    注意:滥用 eval 会破坏“逻辑与表现分离”的原则,使模板难以维护,应尽量避免。

  3. 函数调用: 你可以在模板中直接调用一些 PHP 函数来处理变量。

    {date('Y-m-d', $timestamp)}  <!-- 调用 date 函数格式化时间戳 -->
    {strtoupper($username)}      <!-- 调用 strtoupper 函数将用户名转为大写 -->

    可用的函数是有限的,主要是为了安全考虑。

  4. 继承与区块({block}: 在较新版本的 Discuz! 中,支持类似 PHP 面向对象中“继承”的模板机制,父模板可以定义一个 {block} 区块,子模板可以 {block}name 属性来覆盖父模板中的内容,这为制作主题提供了极大的灵活性。

通过掌握以上内容,你就可以对 Discuz! 的前台显示进行几乎任何你想要的修改了,核心就是 “PHP 准备数据 -> include template 调用 -> 模板语法展示” 这个流程。