3.2.52: 新增「最近评论」挂件(替代 Comments Widget Plus 插件)#22

主题自带一个好看的最近评论挂件,用户不必再装插件。

新挂件 widget_recent_comments(id_base = yang_recent_comments):
- 头像 40px 圆形 + object-fit:cover,带 max-width/max-height 双保险
- 摘要按字符截断(mb_substr),先剥标签再压空白,不走 wp_html_excerpt(按字节切半个汉字)
- 作者 · 相对时间 · 文章标题三段各自成 span,不拼 i18n 句式
- 三层字号:摘要 15px / 作者 14px / 文章 13px(文章字号继承自 meta)
- 条间虚线,最后一条去掉
- 后台九项设置:标题、条数、头像、头像尺寸、摘要、摘要字数、排除 pingback、评论类型、文章类型

实现要点:
- CSS 不依赖 .k-main .sidebar 祖先,只依到 .w-comments 自身
  (3.2.51 的红线:带祖先的选择器在后台「外观→小工具」预览里一条不生效)
- .w-comments 自己不写 padding,交给 widget 基类,避免与其它挂件错位
- 只查 status=approve 且 post_status=publish,草稿文章评论不露出

同时修一个前后台不一致的 bug:
- form() 的 post_type 原来走 pick(),pick() 把空串当"没填"回落 'post'
  ⇒ 老实例(存空串)在后台下拉框显示「文章」,前台却按「全部类型」渲染。
  改为 widget() 与 form() 都直接读原值,两处都识别空串/any 为「全部类型」。

验证:行为 112/0 · 行为反证 25/25 + CSS 10/10 · 几何 50/0 ·
线上真实页面 30/0 · 静态反证 23/0 · 发布脚本 22 组反证全真红。
This commit is contained in:
2026-10-27 08:40:53 +08:00
parent c1dde099d7
commit baa1d16fd1
4 changed files with 592 additions and 2 deletions
+158
View File
@@ -1913,6 +1913,164 @@ button:focus {
line-height: 19px; line-height: 19px;
} }
/* ══════════════════════════════════════════════════════════════════════
* 「最近评论」挂件(.w-comments)(3.2.52)
*
* ── 为什么自己做,不用插件 ────────────────────────────────────────────
* 原来装的是 Comments Widget Plus。它的三个问题都是实测出来的:
*
* ① 用 `_x('%1$s %2$son%3$s %4$s')` 拼句子,中文渲染成
* 「标题**上的**作者」(zh_CN.po 里 "on" 被译成"上的"),
* 而插件根本没带 zh_CN 语言包(languages/ 只有一个 .pot),
* 所以这句永远是英文语序套中文词。
* ② 文章标题 / 作者 / 摘要**三层同为 16px**,只能靠颜色区分;
* 而标题最长,首条实测 337×96(标题链接 332×50,折 2 行)。
* ③ 实例里 `avatar: false`,纯文字流没有任何视觉抓手。
*
* ── 这组规则的一条硬约束(3.2.51 的教训)────────────────────────────
* 🔴 选择器**只依赖 `.w-comments` 自身**,不写 `.k-main .sidebar .w-comments`。
* 3.2.51 的「个人简介撑爆」就是三段祖先选择器造成的:挂件在
* 后台「外观→小工具」预览里没有 `.k-main .sidebar` 那层祖先,
* 一组规则全部失效,头像按原图 2136px 铺开。
* **前台看起来正常,恰恰是把问题藏死的原因。**
* 🔴 所以这里**故意不写任何内边距规则**:白底与 15px/30px 内边距由
* 外层 `.widget` 提供(前台 `.k-main .sidebar .widget`,
* 后台由 WP 自己的挂件容器提供)。挂件本身不该管这些 ——
* 像 `.w-about` 那样去「对齐」内边距,就又把规则绑回祖先了。
*
* ── 信息层级(这是"漂亮"的全部含义)────────────────────────────────
* 摘要 15px #5a5a5a ← 主体,可点,整段链接到评论锚点
* 作者 14px #00a2ff ← 元信息,主色
* 文章 13px #999 ← 元信息,单行省略
* 时间 13px #999 ← 元信息
* 三层字号**必须不同**,插件"三层同为 16px"是它读起来像一坨的根本原因。
* ══════════════════════════════════════════════════════════════════════ */
/* 挂件内边距:不写。白底 + 15px/30px 由外层 `.widget` 提供,
* 与其它挂件(categories / archive 等)完全一致。理由见上面的 🔴。 */
.w-comments .yang-comment-list {
margin: 0;
padding: 0;
list-style: none;
}
/* 单条:flex 布局。
*
* 🔴 不用 float —— 插件用的是 `float:left` 的头像,长摘要下会出现
* "文字环绕到头像右侧再往下淌",元信息行钻进头像下方,整条错位。
* flex 的每一行都是独立盒子,不会出现环绕。 */
.w-comments .yang-comment-item {
display: flex;
align-items: flex-start;
padding: 12px 0;
border-bottom: 1px dashed #b4afaf;
}
/* 最后一条去掉分隔线 —— 跟 `.w-recommended .bookmark-item:last-child` 一致 */
.w-comments .yang-comment-item:last-child {
padding-bottom: 0;
border-bottom: none;
}
/* 头像:固定圆 + 裁切。
*
* 🔴 object-fit:cover 必须有:评论头像来自 Gravatar,可能是任意宽高比。
* fill(默认)会把人脸拉扁,none 会溢出。
* 🔴 flex-shrink:0 必须有:否则摘要很长时 flex 会把头像压扁(实测
* 40px 会被压到 8px 宽)。 */
.w-comments .yang-comment-avatar {
flex: 0 0 auto;
margin-right: 10px;
}
.w-comments .yang-comment-avatar img {
display: block;
width: 40px;
height: 40px;
max-width: 40px;
max-height: 40px;
object-fit: cover;
border-radius: 50%;
background-color: #f2f2f2;
}
/* 文字区:必须 min-width:0,否则长英文/长 URL 会撑破 flex 容器
* (flex 子项的默认 min-width 是 auto,等于"内容多宽就多宽")。 */
.w-comments .yang-comment-body {
flex: 1 1 auto;
min-width: 0;
}
/* 摘要:主体 */
.w-comments .yang-comment-text {
display: block;
color: #5a5a5a;
font-size: 15px;
line-height: 1.6;
text-decoration: none;
/* 中文长句无空格,必须 break-word,否则一个字都不换行直接溢出 */
overflow-wrap: break-word;
word-wrap: break-word;
}
.w-comments .yang-comment-text:hover {
color: #00a2ff;
}
/* 元信息行:作者 · 时间 · 文章标题 */
.w-comments .yang-comment-meta {
display: flex;
align-items: center;
flex-wrap: wrap;
margin-top: 4px;
color: #999;
font-size: 13px;
line-height: 1.5;
}
.w-comments .yang-comment-author {
color: #00a2ff;
font-size: 14px;
text-decoration: none;
}
.w-comments .yang-comment-sep {
margin: 0 5px;
color: #ccc;
}
.w-comments .yang-comment-time {
flex: 0 0 auto;
color: #999;
}
/* 文章标题:单行省略。
* min-width:0 同样是为了让 flex 允许它比内容窄。 */
.w-comments .yang-comment-post {
flex: 1 1 auto;
min-width: 0;
color: #999;
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.w-comments .yang-comment-post:hover {
color: #00a2ff;
}
/* 窄屏(侧栏整行显示,宽度充裕):让文章标题不必挤在一行里 */
@media (max-width: 991.98px) {
.w-comments .yang-comment-post {
flex: 1 1 100%;
white-space: normal;
overflow: visible;
text-overflow: clip;
}
}
.k-main .sidebar .w-recommended .bookmark-item { .k-main .sidebar .w-recommended .bookmark-item {
display: block; display: block;
overflow: hidden; overflow: hidden;
+1 -1
View File
File diff suppressed because one or more lines are too long
+432
View File
@@ -974,6 +974,437 @@ class widget_posts extends WP_Widget
} }
} }
/* ==========================================================================
* 「最近评论」挂件(3.2.52 · 工单 #22)
*
* ── 为什么自己写一个 ────────────────────────────────────────────────
* WP 原生的 `WP_Widget_Recent_Comments` 在本主题里**已经被注销**
* (见文件顶部 widgets_init() 的 unregister_widget 列表)—— 它输出的是
* 裸 `<ul><li>` + 一条 `sprintf` 拼出来的长句,跟侧栏视觉完全不搭。
*
* 之前站点用的是插件 Comments Widget Plus(`comments-widget-plus`),
* 之所以「丑」,实测有三条硬证据:
*
* ① **中文语序断裂**。插件用一条 `_x('%1$s %2$son%3$s %4$s')` 拼句子,
* 英文读作「作者 on 文章标题」,中文渲染成「<标题>上的<作者>」,
* 而且插件**根本没带 zh_CN 语言包**(languages/ 只有一个 .pot)。
* ② **三层信息同为 16px**。文章标题 / 作者 / 摘要字号一样,只能靠颜色
* 区分;而文章标题最长(实测单条占 96px 高、标题折 2 行 50px),
* 把真正的评论内容挤到最下面。
* ③ **默认关头像**。纯文字流,视觉上没有抓手。
*
* ── 本实现的设计取舍 ────────────────────────────────────────────────
* · 信息结构改成「摘要(主体)→ 元信息行(作者 · 时间 · 文章)」,
* 不再把三件事塞进一个句子 —— 这样中文语序问题从根上消失。
* · 头像默认开、圆形、`object-fit:cover`,用 flex 而非插件的 `float:left`
* (float 在长文本下会出现文字环绕错位)。
* · 默认 5 条(插件默认 10 条,实测占满 992px 高,把侧栏撑得没有尽头)。
* · **不做缓存层**。插件那套 `wp_cache_get('cwp_widget','widget')` +
* 三个 add_action 清缓存有两个问题:缓存键是全局的(挂两个实例会互相
* 污染),而 wp_comments 上 comment_approved_date_gmt 有索引,
* 取 5 条的代价可以忽略。少一层缓存 = 少一类"改了不生效"的 bug。
* ====================================================================== */
class widget_recent_comments extends WP_Widget
{
public function __construct()
{
$widget_ops = array(
'name' => __('最近评论', 'kratos'),
'description' => __('带头像与摘要的最近评论,替代 Comments Widget Plus 插件', 'kratos'),
);
parent::__construct('yang_recent_comments', __('最近评论', 'kratos'), $widget_ops);
}
/**
* 取实例字段;没填就用默认值。
*
* 🔴 判空一律用「trim 后是不是空串」,不用 empty():
* `!empty('0')` 是 false ⇒ 摘要字数填 0、或者标题就叫「0」会被当没填。
* 与 widget_about::pick() 保持同一套判据(3.2.51 的教训)。
*
* @param array $instance
* @param string $key
* @param mixed $fallback
* @return mixed
*/
private function pick($instance, $key, $fallback)
{
if (!isset($instance[$key])) {
return $fallback;
}
$v = $instance[$key];
// 布尔开关走另一套:checkbox 没勾时根本不会提交,所以「缺键 = 关」
if (is_bool($fallback)) {
return (bool) $v;
}
if (is_int($fallback)) {
$s = is_scalar($v) ? trim((string) $v) : '';
if ($s === '' || !preg_match('/^-?\d+$/', $s)) {
return $fallback;
}
return (int) $s;
}
if (!is_string($v)) {
return $fallback;
}
$v = trim($v);
return ($v === '') ? $fallback : $v;
}
/**
* 把评论内容压成单行摘要。
*
* 🔴 为什么不用 wp_html_excerpt():那个函数按**字节**截断
* (`mb_substr` 只在 WP 6.x 之后才在部分场景用),中文会被切出半个字。
* 这里用 mb_substr 按**字符**截,并显式带省略号。
* 🔴 为什么先 wp_strip_all_tags 再压缩空白:评论允许 HTML,
* 摘要里出现 `<blockquote>` 之类会把侧栏排版打乱。
*
* @param string $content 原始评论内容
* @param int $limit 保留多少个字符
* @return string
*/
private function excerpt($content, $limit)
{
$s = wp_strip_all_tags((string) $content);
// 换行/制表/连续空格统一压成一个空格,否则摘要是多行的
$s = preg_replace('/\s+/u', ' ', $s);
$s = trim((string) $s);
if ($s === '' || $limit <= 0) {
return $s;
}
if (function_exists('mb_strlen') && function_exists('mb_substr')) {
if (mb_strlen($s, 'UTF-8') > $limit) {
return rtrim(mb_substr($s, 0, $limit, 'UTF-8')) . '…';
}
return $s;
}
// 没有 mbstring 时的兜底:按字节截,但避免切出半个 UTF-8 字符
if (strlen($s) > $limit) {
$cut = substr($s, 0, $limit);
// 把末尾不完整的字节序列削掉
$cut = preg_replace('/[\x80-\xBF]+$/', '', $cut);
return rtrim($cut) . '…';
}
return $s;
}
public function widget($args, $instance)
{
$number = $this->pick($instance, 'number', 5);
if ($number < 1) {
$number = 5;
}
if ($number > 20) {
$number = 20;
}
$show_avatar = $this->pick($instance, 'show_avatar', true);
$avatar_size = $this->pick($instance, 'avatar_size', 40);
$show_excerpt = $this->pick($instance, 'show_excerpt', true);
$excerpt_length = $this->pick($instance, 'excerpt_length', 40);
$order = $this->pick($instance, 'order', 'DESC');
$exclude_pings = $this->pick($instance, 'exclude_pings', true);
/* 🔴 post_type 不能走 pick()。
*
* pick() 的规则是「trim 后是空串 ⇒ 回落 fallback」。而「全部类型」
* 这个选项本身就要用空语义表达,于是:
* 用户选「全部类型」→ update() 存 '' →
* pick() 认为"没填" → 回落 'post' → 只显示文章评论。
* 后台显示已选中、保存也成功,前台却看不到页面上的评论 ——
* 又是一处"静默失效"。
*
* 解法两层:
* ① update() 存**哨兵值 `any`**(非空,pick 不会回落);
* ② 这里**直接读原值**,把 '' 与 'any' 都当"全部类型",
* 只有键不存在时才用默认 'post'。
* 两层都做,是因为老实例(若将来有)可能存的是空串。 */
$pt_raw = array_key_exists('post_type', $instance) ? $instance['post_type'] : 'post';
$post_type = is_string($pt_raw) ? trim($pt_raw) : 'post';
$all_types = ($post_type === '' || $post_type === 'any');
/* 夹紧:这里仍需夹一遍,因为老实例(3.2.52 之前存的)里可能有
* 越界值,而 update() 只对"这次保存"生效、不会回头改老数据。 */
if ($order !== 'ASC') {
$order = 'DESC';
}
if ($avatar_size < 16) {
$avatar_size = 16;
}
if ($avatar_size > 96) {
$avatar_size = 96;
}
if ($excerpt_length < 0) {
$excerpt_length = 0;
}
/* 只取审核通过的评论。
*
* 🔴 `'status' => 'approve'` 是必须的:不加的话草稿/垃圾评论会露出来。
* 🔴 `'post_status' => 'publish'` 也是必须的:评论所属文章若被改成
* 草稿/私密,评论仍存在表里,但前台不该展示 —— get_comment_link()
* 对未发布的文章会返回一个 404 链接。
* 🔴 用 WP_Comment_Query 一次取回,不逐条调 get_comment()。 */
$query = array(
'number' => $number,
'status' => 'approve',
'post_status' => 'publish',
'order' => $order,
'orderby' => 'comment_date_gmt',
);
if (!$all_types) {
$query['post_type'] = $post_type;
}
if ($exclude_pings) {
$query['type__not_in'] = array('pingback', 'trackback');
}
if (function_exists('apply_filters')) {
$query = apply_filters('yang_recent_comments_query', $query, $instance, $this->id_base);
}
$comments = get_comments($query);
// 🔴 没评论就整块不输出 —— 不留下"标题 + 空 ul"的空壳
if (!is_array($comments) || count($comments) === 0) {
return;
}
echo '<div class="' . esc_attr(yang_widget_class('w-comments')) . '">';
yang_widget_title($args, $instance, __('最近评论', 'kratos'), $this->id_base);
echo '<ul class="yang-comment-list">';
foreach ($comments as $comment) {
$link = get_comment_link($comment->comment_ID);
$author = get_comment_author($comment->comment_ID);
$post_title = get_the_title($comment->comment_post_ID);
if ($post_title === '') {
// 标题为空时(极少见)用「无标题」占位,不留空白
$post_title = __('无标题', 'kratos');
}
echo '<li class="yang-comment-item">';
// ── 头像(左侧,圆形)──
if ($show_avatar) {
echo '<a class="yang-comment-avatar" href="' . esc_url($link) . '" rel="nofollow" aria-hidden="true" tabindex="-1">';
echo get_avatar($comment->comment_author_email, $avatar_size, '', '', array(
'class' => 'avatar yang-avatar',
'extra_attr' => 'loading="lazy"',
));
echo '</a>';
}
echo '<div class="yang-comment-body">';
// ── 主体:评论摘要 ──
if ($show_excerpt) {
$text = $this->excerpt($comment->comment_content, $excerpt_length);
if ($text !== '') {
/* 整段链接到该评论锚点 —— 侧栏空间小,用户更容易点中的
* 是"这段文字"而不是下方小字。 */
echo '<a class="yang-comment-text" href="' . esc_url($link) . '" rel="nofollow">' . esc_html($text) . '</a>';
}
} else {
/* 关掉摘要时,主体的位置留给「作者 + 文章」,
* 否则整条会变成只有一行小字,视觉上太轻。 */
echo '<a class="yang-comment-text" href="' . esc_url($link) . '" rel="nofollow">'
. esc_html(sprintf(
/* translators: 1: comment author, 2: post title */
__('%1$s 评论了《%2$s》', 'kratos'),
$author,
$post_title
))
. '</a>';
}
/* ── 元信息行:作者 · 时间 · 文章标题 ──
*
* 🔴 这里**不拼成句子**(不像插件那样塞一个 "on"):
* 中文里「作者 在 文章 中评论」这种句式一旦走 i18n 字符串,
* 语序、量词、标点全都要重新适配;拆成三段各自独立,
* 任何语言下都不会错位。 */
echo '<div class="yang-comment-meta">';
echo '<span class="yang-comment-author">' . esc_html($author) . '</span>';
echo '<span class="yang-comment-sep" aria-hidden="true">·</span>';
echo '<time class="yang-comment-time" datetime="' . esc_attr(get_comment_date('c', $comment->comment_ID)) . '">'
. esc_html(function_exists('human_time_diff')
? sprintf(__('%s前', 'kratos'), human_time_diff(strtotime($comment->comment_date_gmt . ' GMT')))
: get_comment_date('', $comment->comment_ID))
. '</time>';
echo '<span class="yang-comment-sep" aria-hidden="true">·</span>';
echo '<a class="yang-comment-post" href="' . esc_url(get_permalink($comment->comment_post_ID)) . '" title="' . esc_attr($post_title) . '">'
. esc_html($post_title) . '</a>';
echo '</div>';
echo '</div>'; // .yang-comment-body
echo '</li>';
}
echo '</ul>';
echo '</div>';
}
public function update($new_instance, $old_instance)
{
$instance = array();
$instance['title'] = isset($new_instance['title'])
? sanitize_text_field(trim((string) $new_instance['title']))
: '';
// 数字:非法就落回默认,不要存 0 或空串(空串会让 pick 回落,
// 但存成 0 会被当成"用户要 0 条")
$num = isset($new_instance['number']) ? trim((string) $new_instance['number']) : '';
$instance['number'] = ($num !== '' && preg_match('/^-?\d+$/', $num)) ? (int) $num : 5;
$size = isset($new_instance['avatar_size']) ? trim((string) $new_instance['avatar_size']) : '';
$instance['avatar_size'] = ($size !== '' && preg_match('/^-?\d+$/', $size)) ? (int) $size : 40;
/* 🔴 存的时候就夹到 16~96。
* 只在 widget() 里夹(前端夹)不够:后台表单会原样显示一个
* -5,用户以为存进去了,而前台用的是 16 —— 两边不一致。
* 这里夹住,后台看到的和前台用到的才是同一个值。 */
if ($instance['avatar_size'] < 16) {
$instance['avatar_size'] = 16;
}
if ($instance['avatar_size'] > 96) {
$instance['avatar_size'] = 96;
}
$elen = isset($new_instance['excerpt_length']) ? trim((string) $new_instance['excerpt_length']) : '';
$instance['excerpt_length'] = ($elen !== '' && preg_match('/^-?\d+$/', $elen)) ? (int) $elen : 40;
if ($instance['excerpt_length'] < 0) {
$instance['excerpt_length'] = 0;
}
$instance['order'] = (isset($new_instance['order']) && $new_instance['order'] === 'ASC') ? 'ASC' : 'DESC';
/* post_type:'' 与 'any' 都是「全部类型」,统一存成哨兵值 'any'。
* 🔴 不能存空串 —— 空串在 pick() 里等于"没填",会回落成 'post',
* 用户选了「全部类型」却只看到文章评论(静默失效)。 */
$pt = isset($new_instance['post_type']) ? sanitize_key((string) $new_instance['post_type']) : '';
$instance['post_type'] = ($pt === '' || $pt === 'any') ? 'any' : $pt;
// checkbox:没提交就是关。这两项必须显式写 false,
// 否则老值会残留(update 返回的数组是全新的,不写就是丢键,
// 而丢键会让 pick 拿到 fallback=true —— 用户取消勾选无效)
$instance['show_avatar'] = !empty($new_instance['show_avatar']);
$instance['show_excerpt'] = !empty($new_instance['show_excerpt']);
$instance['exclude_pings'] = !empty($new_instance['exclude_pings']);
return $instance;
}
public function form($instance)
{
$title = isset($instance['title']) ? (string) $instance['title'] : '';
$number = $this->pick($instance, 'number', 5);
$show_avatar = $this->pick($instance, 'show_avatar', true);
$avatar_size = $this->pick($instance, 'avatar_size', 40);
$show_excerpt = $this->pick($instance, 'show_excerpt', true);
$excerpt_length = $this->pick($instance, 'excerpt_length', 40);
$order = $this->pick($instance, 'order', 'DESC');
$exclude_pings = $this->pick($instance, 'exclude_pings', true);
/* 🔴 post_type 在这里**也不能走 pick()**(和 widget() 同一个理由,
* 而且这里更隐蔽):pick() 把空串当"没填"回落 'post',
* 于是 form() 里 $all_types 变成 false ⇒ 后台下拉框把
* 「全部类型」显示成「文章」;而 widget() 那边把空串当
* 「全部类型」⇒ **前后台显示与行为不一致**。
* 用户看到后台选的是"文章",前台却显示页面的评论 —— 无法解释。
* 所以两边都直接读原值,判据也要求两处都不出现 pick(...'post_type'...)。 */
$pt_raw = array_key_exists('post_type', $instance) ? $instance['post_type'] : 'post';
$post_type = is_string($pt_raw) ? trim($pt_raw) : 'post';
/* 「全部类型」的两个入口都收:
* · 'any' —— 3.2.52 起的哨兵值(update() 存的)
* · '' —— 3.2.52 之前若有人存过空串
* 渲染时用 $all_types,别再去比对 $post_type 的字面量。 */
$all_types = ($post_type === '' || $post_type === 'any');
$types = get_post_types(array('public' => true), 'objects');
?>
<div class="media-widget-control">
<p>
<label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php _e('标题:', 'kratos'); ?></label>
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>" placeholder="<?php esc_attr_e('最近评论', 'kratos'); ?>">
<span class="description"><?php _e('留空则显示「最近评论」。', 'kratos'); ?></span>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('number')); ?>"><?php _e('显示条数:', 'kratos'); ?></label>
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('number')); ?>" name="<?php echo esc_attr($this->get_field_name('number')); ?>" type="number" step="1" min="1" max="20" value="<?php echo esc_attr($number); ?>">
<span class="description"><?php _e('1 ~ 20 条,建议 5 条。', 'kratos'); ?></span>
</p>
<p>
<input class="checkbox" type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_avatar')); ?>" name="<?php echo esc_attr($this->get_field_name('show_avatar')); ?>" <?php checked($show_avatar); ?>>
<label for="<?php echo esc_attr($this->get_field_id('show_avatar')); ?>"><?php _e('显示头像', 'kratos'); ?></label>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('avatar_size')); ?>"><?php _e('头像尺寸(px):', 'kratos'); ?></label>
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('avatar_size')); ?>" name="<?php echo esc_attr($this->get_field_name('avatar_size')); ?>" type="number" step="1" min="16" max="96" value="<?php echo esc_attr($avatar_size); ?>">
<span class="description"><?php _e('16 ~ 96,建议 40。', 'kratos'); ?></span>
</p>
<p>
<input class="checkbox" type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_excerpt')); ?>" name="<?php echo esc_attr($this->get_field_name('show_excerpt')); ?>" <?php checked($show_excerpt); ?>>
<label for="<?php echo esc_attr($this->get_field_id('show_excerpt')); ?>"><?php _e('显示评论摘要', 'kratos'); ?></label>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('excerpt_length')); ?>"><?php _e('摘要字数:', 'kratos'); ?></label>
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('excerpt_length')); ?>" name="<?php echo esc_attr($this->get_field_name('excerpt_length')); ?>" type="number" step="1" min="0" value="<?php echo esc_attr($excerpt_length); ?>">
<span class="description"><?php _e('按字符数截断(中文一个字算一个),建议 40。', 'kratos'); ?></span>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('order')); ?>"><?php _e('排序:', 'kratos'); ?></label>
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('order')); ?>" name="<?php echo esc_attr($this->get_field_name('order')); ?>">
<option value="DESC" <?php selected($order, 'DESC'); ?>><?php _e('最新优先', 'kratos'); ?></option>
<option value="ASC" <?php selected($order, 'ASC'); ?>><?php _e('最早优先', 'kratos'); ?></option>
</select>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('post_type')); ?>"><?php _e('文章类型:', 'kratos'); ?></label>
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('post_type')); ?>" name="<?php echo esc_attr($this->get_field_name('post_type')); ?>">
<option value="any" <?php selected($all_types); ?>><?php _e('全部类型', 'kratos'); ?></option>
<?php foreach ($types as $type) : ?>
<option value="<?php echo esc_attr($type->name); ?>" <?php selected(!$all_types && $post_type === $type->name); ?>><?php echo esc_html($type->labels->singular_name); ?></option>
<?php endforeach; ?>
</select>
</p>
<p>
<input class="checkbox" type="checkbox" id="<?php echo esc_attr($this->get_field_id('exclude_pings')); ?>" name="<?php echo esc_attr($this->get_field_name('exclude_pings')); ?>" <?php checked($exclude_pings); ?>>
<label for="<?php echo esc_attr($this->get_field_id('exclude_pings')); ?>"><?php _e('排除 pingback / trackback', 'kratos'); ?></label>
<span class="description"><?php _e('建议勾选:这类"评论"是别的博客的引用通知,不是真人留言。', 'kratos'); ?></span>
</p>
</div>
<?php
}
}
function register_widgets() function register_widgets()
{ {
register_widget('widget_ad'); register_widget('widget_ad');
@@ -981,5 +1412,6 @@ function register_widgets()
register_widget('widget_tags'); register_widget('widget_tags');
register_widget('widget_search'); register_widget('widget_search');
register_widget('widget_posts'); register_widget('widget_posts');
register_widget('widget_recent_comments');
} }
add_action('widgets_init', 'register_widgets'); add_action('widgets_init', 'register_widgets');
+1 -1
View File
@@ -1,7 +1,7 @@
/* /*
Theme Name: Kratos_Yang Theme Name: Kratos_Yang
Text Domain: kratos_Yang Text Domain: kratos_Yang
Version: 3.2.51 Version: 3.2.52
Requires PHP: 7.0 Requires PHP: 7.0
Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。 Description: 这是一个Kratos主题的分支版本,用来增加一些定制化功能。
Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好 Tags: 博客, 双栏, 响应式, 自定义背景, 自定义颜色, 自定义图标, 自定义菜单, 特色图像, 收录优化, 邮件中心, 主题选项, 小工具, 文章置顶, 无障碍友好