Mediawiki的CommentStreams扩展在某个版本删除了最近评论的功能,之前建站用AI弄了个扩展,服务器要过期了,先在这里备份下代码,晚点存github
结构
RecentComments/
├── extension.json
├── i18n/
│ ├── en.json
│ └── zh.json
└── includes/
├── RecentComments.alias.php
└── SpecialRecentComments.php
代码
extension.json
{
"manifest_version": 2,
"name": "RecentComments",
"version": "1.1.0",
"author": "H_W(使用AI辅助)",
"url": "https://lostmediawiki.cn/wiki/Special:最近评论",
"descriptionmsg": "尝试修复CommentStreams在9.0.0版本移除所有评论的诡异操作",
"license-name": "GPL-2.0-or-later",
"type": "specialpage",
"SpecialPages": {
"RecentComments": "MediaWiki\\Extension\\RecentComments\\SpecialRecentComments"
},
"ExtensionMessagesFiles": {
"RecentCommentsAlias": "i18n/RecentComments.alias.php"
},
"MessagesDirs": {
"RecentComments": "i18n"
},
"AutoloadClasses": {
"MediaWiki\\Extension\\RecentComments\\SpecialRecentComments": "includes/SpecialRecentComments.php"
}
}
SpecialRecentComments.php
<?php
namespace MediaWiki\Extension\RecentComments;
use MediaWiki\MediaWikiServices;
use MediaWiki\SpecialPage\SpecialPage;
use MediaWiki\Extension\CommentStreams\ICommentStreamsStore;
use MediaWiki\Extension\CommentStreams\AbstractComment;
use MediaWiki\Extension\CommentStreams\Comment; // 新增:用于获取评论标题
use MediaWiki\Title\Title;
use MediaWiki\Parser\ParserOptions;
use MediaWiki\Html\Html;
class SpecialRecentComments extends SpecialPage {
public function __construct() {
parent::__construct( 'RecentComments' );
}
public function execute( $subPage ) {
$this->setHeaders();
$out = $this->getOutput();
$request = $this->getRequest();
$out->setPageTitleMsg( $this->msg( 'recentcomments-title' ) );
$limit = 20;
$offset = max( 0, (int)$request->getInt( 'offset', 0 ) );
$services = MediaWikiServices::getInstance();
/** @var ICommentStreamsStore $store */
$store = $services->get( 'CommentStreamsStore' );
$result = $store->getCommentPages( $limit, $offset );
$comments = [];
foreach ( $result as $row ) {
$pageId = (int)$row->page_id;
$comment = $store->getComment( $pageId ) ?? $store->getReply( $pageId );
if ( $comment instanceof AbstractComment ) {
$comments[] = $comment;
}
}
if ( empty( $comments ) ) {
$out->addWikiMsg( 'recentcomments-no-comments' );
return;
}
// === 卡片样式(你原来的设置 + 小优化)===
$out->addHTML( '<style>
.recent-comment-card {
background-color: var(--background-color-neutral-subtle, #f8f9fa);
border: 1px solid var(--color-subtle, #54595d);
border-radius: 5px;
padding: 5px;
margin-bottom: 24px;
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}
.recent-comment-card .header-title {
font-size: 1.5em;
font-weight: 600;
}
.recent-comment-card .meta{
height:4.5em;
}
.recent-comment-card .meta .sp-avatar-wrapper img{
width:3em !important;
height:3em !important;
}
.recent-comment-card .meta a[title*="用户"]{
font-size: 1.2em;
}
.recent-comment-card hr {
border: none;
border-top: 1px solid var(--color-subtle, #54595d);
}
.recent-comment-card .page-title {
font-size: 1.1em;
color: var(--color-emphasized, #101418);
margin-bottom: 12px;
}
</style>' );
$parserFactory = $services->getParserFactory();
$parserOptions = ParserOptions::newFromContext( $this->getContext() );
$linkRenderer = $this->getLinkRenderer();
foreach ( $comments as $comment ) {
$associatedTitle = $comment->getAssociatedPage();
if ( !$associatedTitle || !$associatedTitle->exists() ) {
continue;
}
$pageLink = $associatedTitle
? $linkRenderer->makeKnownLink( $associatedTitle, $associatedTitle->getPrefixedText() )
: '(未知页面)';
$author = $comment->getAuthor();
$authorLink = $author
? $linkRenderer->makeKnownLink( Title::makeTitle( NS_USER, $author->getName() ), $author->getName() )
: '(匿名)';
//$time = $comment->getCreated()->format( 'Y-m-d H:i' );
$created = $comment->getCreated();
// 固定中文日期:2026年3月25日 12:45
$dateStr = $created->format('Y年n月j日 H:i');
// 计算时间差(秒)
$diff = time() - $created->getTimestamp();
// 极简4档判断(秒/分/时/天)
if ($diff < 60) {
$relative = $diff . '秒前';
} elseif ($diff < 3600) {
$relative = intval($diff / 60) . '分钟前';
} elseif ($diff < 86400) {
$relative = intval($diff / 3600) . '小时前';
} else {
$relative = intval($diff / 86400) . '天前';
}
// 最终拼接
$time = $dateStr . '(' . $relative . ')';
// === 新增:获取评论标题(主评论才有)===
$commentTitle = $comment instanceof Comment
? $comment->getTitle()
: '回复';
// 评论固定链接(用于点击标题跳转)
$permalink = '';
if ( $associatedTitle ) {
$anchor = 'cs-comment-' . $comment->getId();
$permalink = $associatedTitle->getFullURL() . '#' . $anchor;
}
$wikitext = $store->getWikitext( $comment );
$parser = $parserFactory->create();
//$parseResult = $parser->parse( $wikitext, $associatedTitle ?? $this->getTitle(), $parserOptions );
$parseResult = $parser->parse( $wikitext, $associatedTitle ?? $this->getPageTitle(), $parserOptions );
$transformed = $parseResult->runOutputPipeline( $parserOptions, [ 'unwrap' => true ] );
$contentHtml = $transformed->getContentHolderText();
// 输出卡片
$out->addHTML( '<div class="recent-comment-card">' );
// 1. 评论标题(可点击跳转)
$headerContent = $permalink
? Html::element( 'a', [ 'href' => $permalink ], htmlspecialchars( $commentTitle ) )
: htmlspecialchars( $commentTitle );
$out->addHTML( '<div class="header-title">' . $headerContent . '</div> <div class="page-title">' . $pageLink . '</div>' );
$out->addHTML( '<hr>' );
// 2. 用户 + 时间
$out->addHTML( '<div class="meta">' . $authorLink . ' · ' . htmlspecialchars( $time ) . '</div>' );
// 4. 评论正文
$out->addHTML( '<div>' . $contentHtml . '</div>' );
$out->addHTML( '</div>' );
}
// 分页(保持不变)
$prevOffset = $offset - $limit;
$nextOffset = $offset + $limit;
$hasPrev = $offset > 0;
$hasNext = count( $comments ) >= $limit;
if ( $hasPrev || $hasNext ) {
$out->addHTML( '<div style="margin-top:2em;text-align:center;">' );
if ( $hasPrev ) {
$url = $this->getPageTitle()->getLocalURL( [ 'offset' => $prevOffset ] );
$out->addHTML( Html::element( 'a', [ 'href' => $url ], $this->msg( 'recentcomments-prev', $limit )->text() ) . ' | ' );
}
if ( $hasNext ) {
$url = $this->getPageTitle()->getLocalURL( [ 'offset' => $nextOffset ] );
$out->addHTML( Html::element( 'a', [ 'href' => $url ], $this->msg( 'recentcomments-next', $limit )->text() ) );
}
$out->addHTML( '</div>' );
}
}
}
RecentComments.alias.php
<?php
$specialPageAliases = [];
/** English */
$specialPageAliases['en'] = [
'RecentComments' => [ 'RecentComments' ]
];
/** Chinese (Simplified) */
$specialPageAliases['zh'] = [
'RecentComments' => [ '最近评论' ]
];
$specialPageAliases['zh-hans'] = [
'RecentComments' => [ '最近评论' ]
];
zh.json
{
"recentcomments-desc": "提供一个显示 CommentStreams 全站最近评论的特殊页面。",
"recentcomments-title": "最近评论",
"recentcomments-no-comments": "暂无评论。",
"recentcomments-prev": "上一页($1 条)",
"recentcomments-next": "下一页($1 条)",
"recentcomments-page": "所在页面",
"recentcomments-author": "发布者",
"recentcomments-time": "发布时间",
"recentcomments-permalink": "固定链接",
"recentcomments-content": "评论内容"
}
en.json
{
"recentcomments-desc": "提供一个显示 CommentStreams 全站最近评论的特殊页面。",
"recentcomments-title": "最近评论",
"recentcomments-no-comments": "暂无评论。",
"recentcomments-prev": "上一页($1 条)",
"recentcomments-next": "下一页($1 条)",
"recentcomments-page": "所在页面",
"recentcomments-author": "发布者",
"recentcomments-time": "发布时间",
"recentcomments-permalink": "固定链接",
"recentcomments-content": "评论内容"
}

Comments NOTHING