这个问题非常经典,因为 DedeCMS 的搜索页 search.php 默认的分页逻辑与列表页 list.php 是不同的,它不依赖于 arc.listview.class.php 这个文件,而是有自己的处理方式。
实现 DedeCMS 搜索分页主要分为两个步骤:
- 修改搜索页模板
search.htm:在模板中添加分页的代码标签。 - 修改搜索处理文件
search.php:在后台处理分页参数并传递给模板。
第一步:修改搜索页模板 search.htm
在您的搜索页模板文件中,您需要找到您希望显示分页的位置,然后插入 DedeCMS 的分页标签。
常用分页标签如下:
-
{dede:pagelist listitem="index,end,pre,next,pageno" listsize="5"}- 这是最常用的分页标签,它会显示一个包含首页、末页、上一页、下一页和页码的导航栏。
listitem:定义要显示的项,index是首页,end是末页,pre是上一页,next是下一页,pageno是当前页码。listsize:显示的页码数量,5表示当前页码左右各显示 2 个页码。
-
{dede:pagelist listitem="index,end,pre,next"}这个标签只显示首页、末页、上一页、下一页,不显示具体的页码列表。
-
{dede:pagelist listitem="pageno"}这个标签只显示页码列表。
示例 search.htm 代码:
假设您的搜索结果列表循环代码是 {dede:arclist},那么您可以在列表循环结束后添加分页标签。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">搜索结果</title>
</head>
<body>
<h1>搜索结果</h1>
<!-- 搜索表单 -->
<form name="formsearch" action="{dede:global.cfg_cmspath/}/search.php">
<input type="hidden" name="kwtype" value="0" />
<input type="text" name="q" id="q" value="{dede:global name='q'/}" />
<button type="submit">搜索</button>
</form>
<hr>
<!-- 搜索结果列表 -->
{dede:arclist titlelen='40' row='10'}
<li>
<a href="[field:arcurl/]">[field:title/]</a>
<p>[field:description function='cn_substr(@me,100)'/]...</p>
</li>
{/dede:arclist}
<!-- 分页导航代码 -->
<div class="dede_pages">
<ul class="pagelist">
{dede:pagelist listitem="index,end,pre,next,pageno" listsize="5"}
</ul>
</div>
</body>
</html>
注意:
{dede:arclist}中的row='10'表示每页显示 10 条结果,这个值与search.php中的pagesize变量相对应。{dede:global name='q'/}用于在搜索框中回显用户输入的关键词。
第二步:修改搜索处理文件 search.php
这是最关键的一步。search.php 文件负责接收搜索请求,从数据库中查询数据,然后调用 search.htm 模板并传递数据,我们需要修改它来支持分页。
请打开您的 search.php 文件,找到类似下面的代码块(通常在文件末尾):
//搜索结果分页
$pageno = isset($pageno) && is_numeric($pageno) ? intval($pageno) : 1;
$PageSize = 10; //每页显示多少条
$totalresult = $dsql->GetOne("SELECT COUNT(*) AS dd FROM `dede_archives` WHERE {$orwhere}");
$totalresult = $totalresult['dd'];
$totalpage = ceil($totalresult / $PageSize);
$limitstart = ($pageno - 1) * $PageSize;
$orderby = "id DESC";
$orwhere = " (title like '%$q%' OR body like '%$q%') ";
//执行查询
$query = "SELECT * FROM `dede_archives` WHERE {$orwhere} ORDER BY $orderby LIMIT $limitstart,$PageSize";
$rslist = '';
$dsql->SetQuery($query);
$dsql->Execute();
while($arr = $dsql->GetArray())
{
$rslist .= GetArcList($arr, $typeid, $innertext, $arcid, $flag, $ismake, $channelid, $imgwidth, $imgheight, $page, $order, $subday, $noself, $aid, $titlelen);
}
代码可能存在以下问题,需要进行优化和修正:
$dsql->SetQuery和Execute:直接执行SetQuery和Execute是不推荐的,应该使用dsql对象的Select()方法,它更安全、更高效。GetArcList函数:这个函数通常用于列表页,用于处理分页标签等复杂逻辑,在搜索页直接用它来循环数据可能会导致分页标签无法正常工作,更简单的方式是直接获取文章的基本信息并输出。
优化后的 search.php 关键代码:
请用以下代码替换掉 search.php 中处理分页和查询的部分。
// --- 开始替换 ---
// 1. 接收并处理分页参数
$pageno = isset($pageno) && is_numeric($pageno) ? intval($pageno) : 1;
$PageSize = 10; // 每页显示条数,请根据需要修改
// 2. 构建搜索条件 (注意:为了安全,建议对 $q 进行转义)
$q = addslashes($q); // 防止SQL注入
$orwhere = " (title like '%$q%' OR body like '%$q%') ";
// 3. 获取总记录数
$totalresult = $dsql->GetOne("SELECT COUNT(*) AS dd FROM `#@__archives` WHERE {$orwhere}");
$totalresult = $totalresult['dd'];
$totalpage = ceil($totalresult / $PageSize);
// 4. 计算当前页的偏移量
if($pageno > $totalpage) $pageno = $totalpage;
if($pageno < 1) $pageno = 1;
$limitstart = ($pageno - 1) * $PageSize;
// 5. 执行查询,获取当前页的数据
$query = "SELECT * FROM `#@__archives` WHERE {$orwhere} ORDER BY id DESC LIMIT $limitstart, $PageSize";
$rslist = '';
$dsql->Execute('al',$query); // 使用 'al' 作为别名,避免冲突
// 6. 循环处理查询结果,并生成列表HTML
while($arr = $dsql->GetArray('al'))
{
// 这里我们直接获取文章信息并拼接,也可以调用 {dede:arclist} 的相关逻辑,但直接拼接更简单直接
$arcurl = GetFileUrl($arr['id'], $arr['typeid'], $arr['senddate'], $arr['title'], $arr['ismake'], $arr['arcrank'], $arr['namerule'], $arr['typedir'], $arr['money'], $arr['filename'], $arr['moresite'], $arr['siteurl'], $arr['sitepath']);
$rslist .= "<li>\n";
$rslist .= " <a href='{$arcurl}' target='_blank'>".cn_substr($arr['title'], 40)."</a>\n";
$rslist .= " <p>".cn_substr(preg_replace('/<[^>]*>/', '', $arr['description']), 100)."...</p>\n";
$rslist .= "</li>\n";
}
// 7. 将必要的数据传递给模板
$parseTag = new DedeTagParse();
$parseTag->SetNameSpace('field', '[', ']');
$parseTag->LoadString($innertext);
$parseTag->SetVar('item', $rslist); // 将生成的列表HTML传递给模板的 [field:item] 标签
$parseTag->SetVar('totalresult', $totalresult); // 总结果数
$parseTag->SetVar('totalpage', $totalpage); // 总页数
$parseTag->SetVar('pageno', $pageno); // 当前页码
$parseTag->ParseDT();
// 将分页数据也传递给模板,供 {dede:pagelist} 使用
$dpages = '';
$dpages .= "<div class=\"dede_pages\">\n";
$dpages .= "<ul class=\"pagelist\">\n";
$prepage = ($pageno > 1) ? "<li><a href=\"search.php?q=".urlencode($q)."&pageno=".($pageno-1)."\">上一页</a></li>" : "";
$nextpage = ($pageno < $totalpage) ? "<li><a href=\"search.php?q=".urlencode($q)."&pageno=".($pageno+1)."\">下一页</a></li>" : "";
$dpages .= $prepage.$nextpage; // 这里简化处理,实际项目中应使用 {dede:pagelist} 标签
$dpages .= "</ul>\n";
$dpages .= "</div>\n";
$parseTag->SetVar('pagelist', $dpages);
// --- 结束替换 ---
// 引入模板文件
include(DEDETEMPLATE.'/search.htm');
对上述 search.php 修改的说明:
- 安全处理:使用
addslashes($q)对搜索关键词进行简单的转义,防止 SQL 注入。 - 获取总记录数:
$dsql->GetOne获取符合条件的文章总数,用于计算总页数。 - 计算偏移量:
$limitstart是 SQLLIMIT子句中第二个参数的值,用于定位到当前页的数据。 - 执行查询:
$dsql->Execute('al', $query)执行带分页的查询。'al'是一个查询别名,避免与其他查询冲突。 - 生成列表:循环查询结果,使用
GetFileUrl获取文章链接,并用cn_substr截取标题和描述,最终拼接成 HTML 字符串$rslist。 - 传递数据:这部分是核心,我们创建了一个
DedeTagParse对象,将生成的$rslist、$totalresult等变量传递给模板,这样,您在search.htm中就可以通过[field:item]来显示列表,[field:totalresult]来显示总数。 {dede:pagelist}的工作原理:{dede:pagelist}标签会自动寻找search.php传递过来的pageno和totalpage等变量,并生成相应的分页链接,您只需要在模板中放置标签即可,search.php中不需要手动生成<a>标签(虽然上面的代码也手动生成了作为示例,但实际项目中应完全依赖模板标签)。
更简单、推荐的方法(仅修改模板)
如果你的 DedeCMS 版本较新(如 5.7+),并且你的搜索需求比较简单(只搜索文章标题),那么你可能只需要修改模板,而完全不需要修改 search.php。
前提条件:
- 你没有修改过
search.php文件。 - 你的搜索范围仅限于
#@__archives表(即文章)。
操作步骤:
-
确保
search.php中的查询逻辑正确,默认的search.php代码已经包含了分页逻辑,只是可能没有在模板中调用分页标签。 -
修改
search.htm模板,将你的列表循环和分页标签改成下面这样:{dede:global name='keyword' function='RemoveXSS(@me)'/} <!-- 安全输出关键词 --> <div>共找到 <strong>[field:totalrecord/]</strong> 条结果</div> <!-- 使用 {dede:list} 标签来循环搜索结果,这是最关键的一步! --> {dede:list pagesize='10'} <li> <a href="[field:arcurl/]">[field:title/]</a> <span>[field:pubdate function='MyDate("Y-m-d",@me)'/]</span> <p>[field:description function='cn_substr(@me,200)'/]...</p> </li> {/dede:list} <!-- 分页标签,直接放在 {dede:list} 循环后面 --> <div class="dede_pages"> <ul class="pagelist"> {dede:pagelist listitem="index,end,pre,next,pageno" listsize="5"} </ul> </div>
为什么这个方法可行?
因为 DedeCMS 的 search.php 在检测到模板中使用了 {dede:list} 标签时,会自动切换到列表模式,并自动处理分页逻辑,将 totalpage, pageno 等变量传递给模板,{dede:pagelist} 标签就能正常工作了。
- 首选方法:尝试仅修改
search.htm模板,使用{dede:list}标签,这是最安全、最简单、最符合 DedeCMS 设计思想的方法。 - 备用方法:如果搜索逻辑非常复杂(例如需要联合多个表查询),或者默认的
search.php已被修改得面目全非,那么才需要按照第二步的方法,手动修改search.php文件,并自己构建列表和传递分页数据。
希望这个详细的教程能帮到您!
