根据您之前的讨论和DokuWiki的代码结构,我将为您实现一个按日期排序并分页显示命名空间下页面的功能。这个功能可以通过两种方式实现:自定义action方法或自定义语法插件。
最佳实现方式:自定义Action方法
对于这种功能,自定义Action方法是更合适的选择,原因如下:
- 这是一个页面级别的功能,需要处理整个页面的显示
- 需要处理URL参数(如页码、命名空间等)
- 与DokuWiki的现有分页机制更容易集成
实现步骤
1. 创建插件目录结构
首先,创建一个名为datepages
的动作插件:
lib/plugins/datepages/
├── action.php
├── syntax.php (可选,如果需要语法标记)
└── style.css (可选,用于样式)
2. 实现Action插件
以下是action.php
的实现代码:
<?php
/**
* DokuWiki Plugin datepages (Action Component)
*
* @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
* @author Your Name
*/
class action_plugin_datepages extends DokuWiki_Action_Plugin {
/**
* 注册事件处理器
*/
public function register(Doku_Event_Handler $controller) {
$controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleDatepages');
$controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'handleDisplay');
}
/**
* 处理datepages动作
*/
public function handleDatepages(Doku_Event $event, $param) {
if($event->data != 'datepages') return;
// 标记为已处理
$event->preventDefault();
}
/**
* 显示按日期排序的页面列表
*/
public function handleDisplay(Doku_Event $event, $param) {
global $ACT, $INPUT, $INFO, $conf;
if($ACT != 'datepages') return;
// 阻止默认处理
$event->preventDefault();
// 获取参数
$ns = $INPUT->str('ns', getNS($INFO['id']));
$offset = $INPUT->int('offset', 0);
$limit = $INPUT->int('limit', 10); // 默认每页10项
// 获取并显示页面
$this->showDateSortedPages($ns, $offset, $limit);
}
/**
* 获取按日期排序的页面并显示
*/
private function showDateSortedPages($ns, $offset, $limit) {
global $conf, $lang;
// 方法1: 使用search函数
$pages = array();
search($pages, $conf['datadir'], 'search_allpages', array('ns' => $ns), '', 'date');
// 应用权限过滤
$filtered = array();
foreach($pages as $page) {
if(auth_quickaclcheck($page['id']) >= AUTH_READ && !isHiddenPage($page['id'])) {
$filtered[] = $page;
}
}
// 计算分页信息
$total = count($filtered);
$hasNext = ($offset + $limit < $total);
$hasPrev = ($offset > 0);
// 获取当前页的数据
$currentPageData = array_slice($filtered, $offset, $limit);
// 输出HTML
echo '<div class="datepages">';
echo '<h1>' . sprintf($lang['datepages_title'] ?? 'Pages in namespace "%s" sorted by date', hsc($ns)) . '</h1>';
if(count($currentPageData) > 0) {
echo '<ul class="datepages-list">';
foreach($currentPageData as $item) {
$date = dformat($item['mtime']);
echo '<li>';
echo '<div class="datepages-date">' . $date . '</div>';
echo '<div class="datepages-page">' . html_wikilink($item['id']) . '</div>';
echo '</li>';
}
echo '</ul>';
// 分页导航
echo '<div class="datepages-pagination">';
if($hasPrev) {
$prevOffset = max(0, $offset - $limit);
echo '<a href="' . wl($INFO['id'], array('do' => 'datepages', 'ns' => $ns, 'offset' => $prevOffset, 'limit' => $limit)) . '" class="datepages-prev">' . $lang['btn_newer'] . '</a>';
}
if($hasNext) {
$nextOffset = $offset + $limit;
echo '<a href="' . wl($INFO['id'], array('do' => 'datepages', 'ns' => $ns, 'offset' => $nextOffset, 'limit' => $limit)) . '" class="datepages-next">' . $lang['btn_older'] . '</a>';
}
echo '</div>';
} else {
echo '<div class="nothing">' . $lang['nothingfound'] . '</div>';
}
echo '</div>';
}
}
3. 可选:添加语法插件支持
如果您希望通过语法标记来调用此功能,可以添加syntax.php
:
<?php
/**
* DokuWiki Plugin datepages (Syntax Component)
*
* @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
* @author Your Name
*/
class syntax_plugin_datepages extends DokuWiki_Syntax_Plugin {
public function getType() {
return 'substition';
}
public function getPType() {
return 'block';
}
public function getSort() {
return 155;
}
public function connectTo($mode) {
$this->Lexer->addSpecialPattern('{{datepages(?:\?[^}]*)?}}', $mode, 'plugin_datepages');
}
public function handle($match, $state, $pos, Doku_Handler $handler) {
$match = substr($match, 11, -2); // 去除 {{datepages 和 }}
// 解析参数
$params = array();
if(substr($match, 0, 1) == '?') {
$match = substr($match, 1);
parse_str($match, $params);
}
return $params;
}
public function render($mode, Doku_Renderer $renderer, $data) {
if($mode != 'xhtml') return false;
global $INFO;
// 设置默认参数
$ns = $data['ns'] ?? getNS($INFO['id']);
$limit = (int)($data['limit'] ?? 10);
$offset = (int)($data['offset'] ?? 0);
// 获取页面
$pages = array();
search($pages, $GLOBALS['conf']['datadir'], 'search_allpages', array('ns' => $ns), '', 'date');
// 应用权限过滤
$filtered = array();
foreach($pages as $page) {
if(auth_quickaclcheck($page['id']) >= AUTH_READ && !isHiddenPage($page['id'])) {
$filtered[] = $page;
}
}
// 计算分页信息
$total = count($filtered);
$hasNext = ($offset + $limit < $total);
$hasPrev = ($offset > 0);
// 获取当前页的数据
$currentPageData = array_slice($filtered, $offset, $limit);
// 输出HTML
$renderer->doc .= '<div class="datepages">';
if(count($currentPageData) > 0) {
$renderer->doc .= '<ul class="datepages-list">';
foreach($currentPageData as $item) {
$date = dformat($item['mtime']);
$renderer->doc .= '<li>';
$renderer->doc .= '<div class="datepages-date">' . $date . '</div>';
$renderer->doc .= '<div class="datepages-page">';
$renderer->internallink($item['id']);
$renderer->doc .= '</div>';
$renderer->doc .= '</li>';
}
$renderer->doc .= '</ul>';
// 分页导航
$renderer->doc .= '<div class="datepages-pagination">';
if($hasPrev) {
$prevOffset = max(0, $offset - $limit);
$params = array('ns' => $ns, 'offset' => $prevOffset, 'limit' => $limit);
$renderer->doc .= '<a href="' . wl($INFO['id'], array('do' => 'datepages') + $params) . '" class="datepages-prev">' . $lang['btn_newer'] . '</a>';
}
if($hasNext) {
$nextOffset = $offset + $limit;
$params = array('ns' => $ns, 'offset' => $nextOffset, 'limit' => $limit);
$renderer->doc .= '<a href="' . wl($INFO['id'], array('do' => 'datepages') + $params) . '" class="datepages-next">' . $lang['btn_older'] . '</a>';
}
$renderer->doc .= '</div>';
} else {
$renderer->doc .= '<div class="nothing">' . $lang['nothingfound'] . '</div>';
}
$renderer->doc .= '</div>';
return true;
}
}
4. 添加样式(可选)
创建style.css
文件:
.datepages {
margin: 1em 0;
}
.datepages-list {
list-style: none;
padding: 0;
}
.datepages-list li {
margin-bottom: 0.5em;
padding: 0.5em;
border-bottom: 1px solid #eee;
display: flex;
}
.datepages-date {
flex: 0 0 150px;
color: #666;
}
.datepages-page {
flex: 1;
}
.datepages-pagination {
margin-top: 1em;
display: flex;
justify-content: space-between;
}
使用方法
方法1:通过URL参数
访问以下URL来查看按日期排序的页面:
https://your-wiki.com/doku.php?do=datepages&ns=namespace&offset=0&limit=10
方法2:通过语法标记(如果实现了syntax.php)
在wiki页面中添加以下语法:
{{datepages?ns=namespace&limit=10&offset=0}}
使用索引器的替代实现
如果您希望使用索引器来提高性能,可以替换showDateSortedPages
方法中的页面获取部分:
private function showDateSortedPages($ns, $offset, $limit) {
global $conf, $lang;
// 使用索引器获取页面
$Indexer = idx_get_indexer();
$allPages = $Indexer->getPages();
// 过滤命名空间
$nsPages = array();
foreach($allPages as $id => $title) {
if(getNS($id) == $ns) {
$nsPages[$id] = $title;
}
}
// 按修改时间排序
$pageIds = array_keys($nsPages);
usort($pageIds, 'ft_pagemtimesorter');
// 应用权限过滤
$filtered = array();
foreach($pageIds as $id) {
if(auth_quickaclcheck($id) >= AUTH_READ && !isHiddenPage($id) && page_exists($id)) {
$meta = p_get_metadata($id);
$filtered[] = array(
'id' => $id,
'title' => $nsPages[$id],
'mtime' => filemtime(wikiFN($id))
);
}
}
// 计算分页信息
$total = count($filtered);
$hasNext = ($offset + $limit < $total);
$hasPrev = ($offset > 0);
// 获取当前页的数据
$currentPageData = array_slice($filtered, $offset, $limit);
// 输出HTML
// ... 与之前相同 ...
}
结论
对于按日期排序并分页显示命名空间下页面的功能,自定义action方法是最合适的实现方式。这种方法可以:
- 处理URL参数和分页
- 提供更灵活的页面展示
- 与DokuWiki的现有机制更好地集成
如果您希望在页面内嵌入此功能,可以同时实现语法插件部分。两种方法可以共存,为用户提供更多的使用选择。
Notes
这个实现基于DokuWiki的核心功能,包括search()
函数和索引器。对于大型wiki站点,建议使用索引器方法以提高性能。代码中的分页逻辑参考了DokuWiki的Recent
类的实现方式,确保与系统的其他部分保持一致的用户体验。
如果您需要更复杂的排序或过滤功能,可以扩展此插件,添加更多参数和选项。