The theme was renamed Zibll/子比 → AKSRT → Jio, but upstream branding survived the sweeps in CSS classes, the SVG sprite prefix, a persisted widget field ID, JS events, admin Vue class names, test infrastructure and docblocks. Renames: - zib-widget / zib-widget-wrap / zib-slider → jio-widget-box / jio-widget-box-wrap / jio-slider-box (jio-widget is taken by the modern widget shell, jio-box-* by the card primitives) - zib-partners-scroll + zps-* → jio-partners-scroll + jps-* - zib-combo-info-card + zci-* → jio-combo-info-card + jci-* - zibsvg- → jiosvg-, including the exported picker helpers and the fa-zibsvg- family-prefix guard - zibpay_type → pay_type; the dual-read fallback in PostQuery collapses to a single key - [zibajax="submit"] dropped (no PHP emitter); zib_ajax.success → jio_ajax.success - aks-* admin Vue classes → jio-* - zib_palette() → palette() User-facing vendor traces are gone: the floating "more" button default no longer ships a zibll.com link or 子比主题 marketing copy, the notice widget ships no preset promo entries, and the four 官网教程 links are removed from the post-list admin schema. Test infrastructure renamed to neutral names (docker-compose.reference.yml, Caddyfile, article-baseline.json, modern-widgets-contract.test.cjs) with their DB/volume/env/slug identifiers following. Kept intentionally, documented in tests/fixtures/README.md: the golden fixture reference fingerprint (a SHA-256 record of an external directory, read by validate-widget-golden / generate-widget-golden-fixture / audit-widget-system), the doesNotMatch guards that prove the old tokens are gone, and the reference theme's own meta key in the visual fixtures. No backward-compat or data migration: saved widget configs holding old icon keys or the old field ID silently lose them, per the project's rewrite-over-compatibility rule. Verified: 132/132 node contract tests, php tests/widget-system/run.php (146 assertions), audit-admin-contracts, audit-psr4-paths and validate-widget-golden all green; tracked bundles regenerated and in sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
682 lines
27 KiB
PHP
682 lines
27 KiB
PHP
<?php
|
|
/**
|
|
* Unified comments composition (legacy-style closed surface).
|
|
*
|
|
* comments.php stays a thin mount point. Policy + sections live here.
|
|
*
|
|
* @package Jio
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
if (!function_exists('jio_comments_template_query_args')) :
|
|
/**
|
|
* Apply order / author-only filters to the comments template query.
|
|
*
|
|
* @param array<string,mixed> $args Comment query args.
|
|
* @return array<string,mixed>
|
|
*/
|
|
function jio_comments_template_query_args(array $args): array {
|
|
$order = isset($_GET['jio_comment_order'])
|
|
? sanitize_key((string) wp_unslash($_GET['jio_comment_order']))
|
|
: '';
|
|
if (!in_array($order, ['newest', 'hottest'], true)) {
|
|
$order = 'newest';
|
|
}
|
|
|
|
if ($order === 'hottest') {
|
|
$args['order'] = 'DESC';
|
|
$args['orderby'] = 'comment_date_gmt';
|
|
$args['jio_hottest_order'] = true;
|
|
} else {
|
|
$args['order'] = 'DESC';
|
|
$args['orderby'] = 'comment_date_gmt';
|
|
}
|
|
|
|
if (isset($_GET['jio_author_only']) && (int) wp_unslash($_GET['jio_author_only']) === 1) {
|
|
$post_id = (int) get_queried_object_id();
|
|
if ($post_id <= 0 && !empty($args['post_id'])) {
|
|
$post_id = (int) $args['post_id'];
|
|
}
|
|
$author_id = $post_id > 0 ? (int) get_post_field('post_author', $post_id) : 0;
|
|
if ($author_id > 0) {
|
|
$args['user_id'] = $author_id;
|
|
}
|
|
}
|
|
|
|
return $args;
|
|
}
|
|
endif;
|
|
|
|
add_filter('comments_template_query_args', static function ($args) {
|
|
if (!is_array($args)) {
|
|
$args = [];
|
|
}
|
|
return function_exists('jio_comments_template_query_args')
|
|
? jio_comments_template_query_args($args)
|
|
: $args;
|
|
});
|
|
|
|
add_filter('comments_clauses', static function (array $clauses, WP_Comment_Query $query): array {
|
|
if (empty($query->query_vars['jio_hottest_order'])) {
|
|
return $clauses;
|
|
}
|
|
|
|
global $wpdb;
|
|
$clauses['join'] .= " LEFT JOIN {$wpdb->commentmeta} AS jio_cm_hot ON ({$wpdb->comments}.comment_ID = jio_cm_hot.comment_id AND jio_cm_hot.meta_key = 'jio_comment_likes')";
|
|
$clauses['orderby'] = 'CAST(COALESCE(jio_cm_hot.meta_value, 0) AS UNSIGNED) DESC, ' . $wpdb->comments . '.comment_date_gmt DESC';
|
|
return $clauses;
|
|
}, 20, 2);
|
|
|
|
if (!function_exists('jio_comment_box_visible')) :
|
|
/**
|
|
* Whether the comment module may render for the current visitor.
|
|
*
|
|
* Mirrors the reference theme's comment_box_hide conditions.
|
|
*/
|
|
function jio_comment_box_visible(): bool {
|
|
$settings = class_exists('\Jio\Settings\Settings')
|
|
? \Jio\Settings\Settings::get_comment_display_settings()
|
|
: [];
|
|
$hide = sanitize_key((string) ($settings['box_hide'] ?? ''));
|
|
switch ($hide) {
|
|
case 'signin':
|
|
return is_user_logged_in();
|
|
case 'vip':
|
|
return function_exists('jio_is_vip') && jio_is_vip();
|
|
case 'vip_2':
|
|
return function_exists('jio_is_vip2') && jio_is_vip2();
|
|
case 'auth':
|
|
return function_exists('jio_current_user_is_verified') && jio_current_user_is_verified();
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_build_context')) :
|
|
/**
|
|
* Resolve comments runtime context once.
|
|
*
|
|
* @return array<string,mixed>
|
|
*/
|
|
function jio_comments_build_context(): array {
|
|
$settings = class_exists('\Jio\Settings\Settings')
|
|
? \Jio\Settings\Settings::get_comment_display_settings()
|
|
: [
|
|
'order' => 'desc',
|
|
'nested_depth' => 3,
|
|
'require_login' => false,
|
|
'avatar_size' => 48,
|
|
];
|
|
|
|
$order = isset($_GET['jio_comment_order'])
|
|
? sanitize_key((string) wp_unslash($_GET['jio_comment_order']))
|
|
: 'newest';
|
|
if (!in_array($order, ['newest', 'hottest'], true)) {
|
|
$order = 'newest';
|
|
}
|
|
|
|
$avatar_size = max(24, (int) ($settings['avatar_size'] ?? 48));
|
|
$toolbar = is_array($settings['toolbar'] ?? null)
|
|
? $settings['toolbar']
|
|
: ['code' => true, 'image' => true];
|
|
|
|
return [
|
|
'settings' => $settings,
|
|
'comment_count' => (int) get_comments_number(),
|
|
'is_logged_in' => is_user_logged_in(),
|
|
'current_user' => wp_get_current_user(),
|
|
'require_login' => !empty($settings['require_login']),
|
|
'order' => $order,
|
|
'author_only' => isset($_GET['jio_author_only']) && (int) $_GET['jio_author_only'] === 1,
|
|
'post_author_id' => (int) get_the_author_meta('ID'),
|
|
'avatar_size' => $avatar_size,
|
|
'max_depth' => max(1, (int) ($settings['nested_depth'] ?? 3)),
|
|
'toolbar' => $toolbar,
|
|
'upload_enabled' => !empty($toolbar['upload_img']),
|
|
'link_enabled' => !empty($toolbar['link']),
|
|
'user_url_enabled' => !empty($settings['user_url']),
|
|
'box_placeholder' => (string) ($settings['box_placeholder'] ?? __('说点什么吧...', 'jio')),
|
|
'submit_text' => (string) ($settings['submit_text'] ?? __('提交评论', 'jio')),
|
|
'title_text' => (string) ($settings['title'] ?? __('评论', 'jio')),
|
|
'corderby_enabled' => !empty($settings['corderby']) && !empty($settings['like_enabled']),
|
|
'close_comments' => !empty($settings['close_comments']),
|
|
'box_hidden' => !jio_comment_box_visible(),
|
|
'oauth_providers' => class_exists('\Jio\Auth\OAuth')
|
|
? \Jio\Auth\OAuth::get_instance()->get_auth_providers_data()
|
|
: [],
|
|
];
|
|
}
|
|
endif;
|
|
|
|
|
|
if (!function_exists('jio_comments_normalize_order')) :
|
|
/**
|
|
* Normalize comment order key.
|
|
*/
|
|
function jio_comments_normalize_order(string $order = ''): string {
|
|
$order = sanitize_key($order);
|
|
if (!in_array($order, ['newest', 'hottest'], true)) {
|
|
$order = 'newest';
|
|
}
|
|
return $order;
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_query_for_post')) :
|
|
/**
|
|
* Shared comment query for first paint / fragment / load-more.
|
|
*
|
|
* @return array{comments:array<int,\WP_Comment>,total:int,max_pages:int,page:int,order:string,author_only:bool,settings:array}
|
|
*/
|
|
function jio_comments_query_for_post(int $post_id, array $args = []): array {
|
|
$settings = class_exists('\Jio\Settings\Settings')
|
|
? \Jio\Settings\Settings::get_comment_display_settings()
|
|
: [];
|
|
$order = jio_comments_normalize_order((string) ($args['order'] ?? ''));
|
|
$author_only = !empty($args['author_only']);
|
|
$page = max(1, (int) ($args['page'] ?? 1));
|
|
$per_page = max(1, (int) ($args['per_page'] ?? get_option('comments_per_page', 10)));
|
|
$include_unapproved_for_user = (int) ($args['include_unapproved_user'] ?? 0);
|
|
|
|
$query_args = [
|
|
'post_id' => $post_id,
|
|
'status' => 'approve',
|
|
'number' => $per_page,
|
|
'offset' => ($page - 1) * $per_page,
|
|
'orderby' => 'comment_date_gmt',
|
|
'order' => 'DESC',
|
|
'hierarchical' => 'threaded',
|
|
];
|
|
|
|
if ($author_only) {
|
|
$author_id = (int) get_post_field('post_author', $post_id);
|
|
if ($author_id > 0) {
|
|
$query_args['user_id'] = $author_id;
|
|
$query_args['hierarchical'] = false;
|
|
}
|
|
}
|
|
|
|
if ($include_unapproved_for_user > 0) {
|
|
// WP_Comment_Query does not support mixed status easily; keep approve only for list fragment.
|
|
}
|
|
|
|
if ($order === 'hottest') {
|
|
$query_args['jio_hottest_order'] = true;
|
|
}
|
|
|
|
$comment_query = new WP_Comment_Query($query_args);
|
|
$comments = is_array($comment_query->comments) ? $comment_query->comments : [];
|
|
|
|
// Pin reorder for page 1 when not author-only.
|
|
if ($page === 1 && !$author_only && function_exists('jio_reorder_pinned_comments')) {
|
|
$comments = jio_reorder_pinned_comments($comments, $post_id);
|
|
}
|
|
|
|
$count_args = [
|
|
'post_id' => $post_id,
|
|
'status' => 'approve',
|
|
'count' => true,
|
|
];
|
|
if ($author_only) {
|
|
$author_id = (int) get_post_field('post_author', $post_id);
|
|
if ($author_id > 0) {
|
|
$count_args['user_id'] = $author_id;
|
|
}
|
|
}
|
|
$total = (int) get_comments($count_args);
|
|
$max_pages = (int) max(1, (int) ceil($total / $per_page));
|
|
|
|
return [
|
|
'comments' => $comments,
|
|
'total' => $total,
|
|
'max_pages' => $max_pages,
|
|
'page' => $page,
|
|
'order' => $order,
|
|
'author_only' => $author_only,
|
|
'settings' => $settings,
|
|
'per_page' => $per_page,
|
|
];
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_render_items_html')) :
|
|
/**
|
|
* Render comment list items HTML via canonical callback.
|
|
*
|
|
* @param array<int,\WP_Comment> $comments
|
|
* @param array<string,mixed> $settings
|
|
* @param string $order
|
|
*/
|
|
function jio_comments_render_items_html(array $comments, array $settings = [], string $order = 'newest'): string {
|
|
if (empty($comments) || !function_exists('jio_comment_callback')) {
|
|
return '';
|
|
}
|
|
set_query_var('jio_comment_settings', $settings);
|
|
set_query_var('jio_comment_order', jio_comments_normalize_order($order));
|
|
|
|
$avatar = max(24, (int) ($settings['avatar_size'] ?? 48));
|
|
$depth = max(1, (int) ($settings['nested_depth'] ?? 3));
|
|
$reverse = $order === 'newest';
|
|
|
|
ob_start();
|
|
wp_list_comments([
|
|
'callback' => 'jio_comment_callback',
|
|
'style' => 'ol',
|
|
'avatar_size' => $avatar,
|
|
'max_depth' => $depth,
|
|
], $comments);
|
|
return (string) ob_get_clean();
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_render_single_html')) :
|
|
/**
|
|
* Render one comment item HTML.
|
|
*/
|
|
function jio_comments_render_single_html(\WP_Comment $comment, array $settings = []): string {
|
|
$html = jio_comments_render_items_html([$comment], $settings, 'newest');
|
|
return $html;
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_render_list_fragment')) :
|
|
/**
|
|
* Fragment payload for order/author/page AJAX.
|
|
*
|
|
* @return array{html:string,items_html:string,count_text:string,total:int,max_pages:int,page:int,order:string,author_only:bool,empty:bool}
|
|
*/
|
|
function jio_comments_render_list_fragment(int $post_id, array $args = []): array {
|
|
$result = jio_comments_query_for_post($post_id, $args);
|
|
$settings = $result['settings'];
|
|
$order = $result['order'];
|
|
$author_only = !empty($result['author_only']);
|
|
$page = (int) $result['page'];
|
|
$max_pages = (int) $result['max_pages'];
|
|
$total = (int) $result['total'];
|
|
|
|
// Fake globals needed by pagination helpers when not on singular loop.
|
|
$GLOBALS['post'] = get_post($post_id);
|
|
setup_postdata($GLOBALS['post']);
|
|
set_query_var('cpage', $page);
|
|
set_query_var('jio_comment_order', $order);
|
|
set_query_var('jio_comment_settings', $settings);
|
|
|
|
$items_html = jio_comments_render_items_html($result['comments'], $settings, $order);
|
|
|
|
$ctx = [
|
|
'order' => $order,
|
|
'author_only' => $author_only,
|
|
'post_author_id' => (int) get_post_field('post_author', $post_id),
|
|
'corderby_enabled' => !empty($settings['corderby']) && !empty($settings['like_enabled']),
|
|
'comment_count' => $total,
|
|
];
|
|
|
|
ob_start();
|
|
echo '<div id="postcomments"><ol class="commentlist list-unstyled">';
|
|
if ($items_html === '') {
|
|
if (function_exists('jio_comments_render_empty')) {
|
|
jio_comments_render_empty($ctx);
|
|
}
|
|
echo '<div class="pagenav hide"><div class="next-page ajax-next"><a href="#"></a></div></div>';
|
|
} else {
|
|
if (function_exists('jio_comments_render_filter') && !empty($ctx['corderby_enabled'])) {
|
|
jio_comments_render_filter($ctx);
|
|
}
|
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- rendered comment markup.
|
|
echo $items_html;
|
|
if (function_exists('jio_render_comment_pagination') && $max_pages > 1) {
|
|
$pages_filter = static function () use ($max_pages) {
|
|
return $max_pages;
|
|
};
|
|
add_filter('get_comment_pages_count', $pages_filter);
|
|
jio_render_comment_pagination();
|
|
remove_filter('get_comment_pages_count', $pages_filter);
|
|
}
|
|
}
|
|
echo '</ol></div>';
|
|
$list_html = (string) ob_get_clean();
|
|
|
|
wp_reset_postdata();
|
|
|
|
return [
|
|
'html' => $list_html,
|
|
'items_html' => $items_html,
|
|
'count_text' => sprintf(__('共%s条', 'jio'), (string) $total),
|
|
'total' => $total,
|
|
'max_pages' => $max_pages,
|
|
'page' => $page,
|
|
'order' => $order,
|
|
'author_only' => $author_only,
|
|
'empty' => $items_html === '',
|
|
];
|
|
}
|
|
endif;
|
|
|
|
|
|
if (!function_exists('jio_comments_render_signarea')) :
|
|
/**
|
|
* Login-required gate.
|
|
*
|
|
* @param array<string,mixed> $ctx Comments context.
|
|
*/
|
|
function jio_comments_render_signarea(array $ctx): void {
|
|
$oauth_providers = is_array($ctx['oauth_providers'] ?? null) ? $ctx['oauth_providers'] : [];
|
|
$login_url = function_exists('jio_get_login_url') ? jio_get_login_url(get_permalink()) : wp_login_url(get_permalink());
|
|
?>
|
|
<div class="comment-signarea text-center box-body radius8">
|
|
<h3 class="text-muted em12 theme-box muted-3-color"><?php esc_html_e('请登录后发表评论', 'jio'); ?></h3>
|
|
<p>
|
|
<a href="javascript:;" data-login-url="<?php echo esc_url($login_url); ?>" class="signin-loader but c-blue padding-lg"><i class="fa fas fa-fw fa-sign-in-alt mr10" aria-hidden="true"></i><?php esc_html_e('登录', 'jio'); ?></a>
|
|
<?php if (get_option('users_can_register')) :
|
|
$register_url = function_exists('jio_get_register_url') ? jio_get_register_url() : wp_registration_url();
|
|
?>
|
|
<a href="javascript:;" data-register-url="<?php echo esc_url($register_url); ?>" class="signup-loader ml10 but c-yellow padding-lg"><?php echo jio_get_comment_icon('signup', 'icon mr10'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- 固定 sprite 标记。 ?><?php esc_html_e('注册', 'jio'); ?></a>
|
|
<?php endif; ?>
|
|
</p>
|
|
<?php if (!empty($oauth_providers)) : ?>
|
|
<p class="social-login-wrap">
|
|
<?php foreach ($oauth_providers as $provider) :
|
|
$provider_name = (string) ($provider['name'] ?? '');
|
|
$label = (string) ($provider['label'] ?? $provider_name);
|
|
$url = (string) ($provider['url'] ?? '#');
|
|
$icon = $provider['icon'] ?? '';
|
|
?>
|
|
<a href="<?php echo esc_url($url); ?>" class="social-login-item but hollow ml10 <?php echo esc_attr($provider_name); ?>" data-provider="<?php echo esc_attr($provider_name); ?>" title="<?php echo esc_attr($label); ?>">
|
|
<?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
|
<span><?php echo esc_html($label); ?></span>
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_render_form')) :
|
|
/**
|
|
* Comment respond form.
|
|
*
|
|
* @param array<string,mixed> $ctx Comments context.
|
|
*/
|
|
function jio_comments_render_form(array $ctx): void {
|
|
$is_logged_in = !empty($ctx['is_logged_in']);
|
|
$current_user = $ctx['current_user'] ?? null;
|
|
$require_name_email = (bool) get_option('require_name_email');
|
|
$comment_author = isset($_COOKIE['comment_author_' . COOKIEHASH])
|
|
? sanitize_text_field(wp_unslash((string) $_COOKIE['comment_author_' . COOKIEHASH]))
|
|
: '';
|
|
$comment_email = isset($_COOKIE['comment_author_email_' . COOKIEHASH])
|
|
? sanitize_text_field(wp_unslash((string) $_COOKIE['comment_author_email_' . COOKIEHASH]))
|
|
: '';
|
|
$comment_author_url = isset($_COOKIE['comment_author_url_' . COOKIEHASH])
|
|
? esc_url_raw(wp_unslash((string) $_COOKIE['comment_author_url_' . COOKIEHASH]))
|
|
: '';
|
|
$placeholder = (string) $ctx['box_placeholder'];
|
|
$post_id = (int) get_the_ID();
|
|
$can_comment = function_exists('jio_user_can')
|
|
? jio_user_can('comment_add', get_current_user_id(), $post_id)
|
|
: $is_logged_in;
|
|
|
|
if (!$can_comment) {
|
|
if (!$is_logged_in) {
|
|
jio_comments_render_signarea($ctx);
|
|
} else {
|
|
// 治理状态区分提示:禁封中/小黑屋/禁言显示状态徽章与查看入口,
|
|
// 而非笼统的无权限文案。
|
|
$ban_nocan = function_exists('jio_get_user_ban_nocan_html')
|
|
? jio_get_user_ban_nocan_html(get_current_user_id(), __('暂时无法发表评论', 'jio'))
|
|
: '';
|
|
if ($ban_nocan !== '') {
|
|
echo $ban_nocan; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- helper escapes internally.
|
|
} else {
|
|
echo '<p class="comments-permission-denied muted-2-color">' . esc_html__('当前账号没有发表评论的权限。', 'jio') . '</p>';
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (function_exists('jio_get_comment_virtual_input_html')) {
|
|
echo jio_get_comment_virtual_input_html($placeholder, '#respond'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
}
|
|
?>
|
|
<div id="respond" class="mobile-fixed">
|
|
<div class="fixed-body"></div>
|
|
<form id="commentform" method="post" action="<?php echo esc_url(site_url('/wp-comments-post.php')); ?>">
|
|
<div class="flex ac">
|
|
<div class="comt-title text-center flex0 mr10">
|
|
<?php if ($is_logged_in && $current_user instanceof WP_User) : ?>
|
|
<div class="comt-avatar mb10">
|
|
<?php echo jio_get_avatar_html($current_user->ID, 96, ['class' => 'avatar']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- canonical avatar helper escapes output. ?>
|
|
</div>
|
|
<p class="text-ellipsis muted-2-color"><?php echo function_exists('jio_get_vip_icon') ? jio_get_vip_icon($current_user->ID, 'em12 mr3') : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- VIP helper escapes output. ?><?php echo esc_html($current_user->display_name); ?></p>
|
|
<?php else : ?>
|
|
<div class="comt-avatar mb10">
|
|
<?php echo jio_get_avatar_html(0, 96, ['class' => 'avatar']); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- canonical avatar helper escapes output. ?>
|
|
</div>
|
|
<p class="" data-toggle-class="open" data-target="#comment-user-info" data-toggle="tooltip" title="<?php esc_attr_e('填写用户信息', 'jio'); ?>">
|
|
<?php echo $comment_author !== '' ? esc_html($comment_author) : esc_html__('昵称', 'jio'); ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="comt-box grow1">
|
|
<div class="action-text mb10 em09 muted-2-color" id="comment-reply-info" style="display:none;"></div>
|
|
<textarea placeholder="<?php echo esc_attr($placeholder); ?>" autoheight="true" maxheight="188" class="form-control grin" name="comment" id="comment" cols="100%" rows="4" tabindex="1"></textarea>
|
|
<?php if (function_exists('jio_is_captcha_enabled_for') && function_exists('jio_render_captcha') && jio_is_captcha_enabled_for('comment')) : ?>
|
|
<div style="width: 230px; margin-top: 8px;"><?php jio_render_captcha('comment'); ?></div>
|
|
<?php endif; ?>
|
|
<div class="comt-ctrl relative">
|
|
<div class="comt-tips">
|
|
<?php comment_id_fields(); ?>
|
|
<?php wp_nonce_field('jio_comment_nonce', '_jio_comment_nonce'); ?>
|
|
<?php do_action('comment_form', get_the_ID()); ?>
|
|
</div>
|
|
<div class="comt-tips-right pull-right">
|
|
<a class="but c-red" id="cancel-comment-reply-link" href="javascript:;" style="display:none;"><?php esc_html_e('取消', 'jio'); ?></a>
|
|
<button class="but c-blue pw-1em input-expand-submit comment-send" name="submit" id="submit" type="submit" tabindex="5"><?php echo esc_html((string) $ctx['submit_text']); ?></button>
|
|
</div>
|
|
<div class="comt-tips-left">
|
|
<?php if (!$is_logged_in) :
|
|
$req_mark = $require_name_email ? '(' . __('必填', 'jio') . ')' : '';
|
|
?>
|
|
<span class="dropup relative" id="comment-user-info"<?php echo $require_name_email ? ' require_name_email="true"' : ''; ?>>
|
|
<a class="but mr6" data-toggle-class="open" data-target="#comment-user-info" href="javascript:;"><i class="fa fas fa-fw fa-user" aria-hidden="true"></i><span class="hide-sm"><?php esc_html_e('昵称', 'jio'); ?></span></a>
|
|
<div class="dropdown-menu box-body" style="width:250px;">
|
|
<div class="mb20">
|
|
<p><?php esc_html_e('请填写用户信息:', 'jio'); ?></p>
|
|
<ul>
|
|
<li class="line-form mb10">
|
|
<input type="text" name="author" class="line-form-input" tabindex="1" value="<?php echo esc_attr($comment_author); ?>" placeholder="">
|
|
<div class="scale-placeholder"><?php echo esc_html__('昵称', 'jio') . esc_html($req_mark); ?></div>
|
|
<div class="abs-right muted-color"><i class="fa fas fa-fw fa-user" aria-hidden="true"></i></div>
|
|
<i class="line-form-line"></i>
|
|
</li>
|
|
<li class="line-form">
|
|
<input type="text" name="email" class="line-form-input" tabindex="2" value="<?php echo esc_attr($comment_email); ?>" placeholder="">
|
|
<div class="scale-placeholder"><?php echo esc_html__('邮箱', 'jio') . esc_html($req_mark); ?></div>
|
|
<div class="abs-right muted-color"><i class="fa far fa-fw fa-envelope" aria-hidden="true"></i></div>
|
|
<i class="line-form-line"></i>
|
|
</li>
|
|
<?php if (!empty($ctx['user_url_enabled'])) : ?>
|
|
<li class="line-form">
|
|
<input type="text" name="url" class="line-form-input" tabindex="3" value="<?php echo esc_attr($comment_author_url); ?>" placeholder="">
|
|
<div class="scale-placeholder"><?php esc_html_e('博客地址', 'jio'); ?></div>
|
|
<div class="abs-right muted-color"><i class="fa fas fa-fw fa-link" aria-hidden="true"></i></div>
|
|
<i class="line-form-line"></i>
|
|
</li>
|
|
<?php endif; ?>
|
|
</ul>
|
|
</div>
|
|
<?php
|
|
$oauth = is_array($ctx['oauth_providers'] ?? null) ? $ctx['oauth_providers'] : [];
|
|
if (!empty($oauth)) :
|
|
?>
|
|
<p class="social-login-wrap">
|
|
<?php foreach ($oauth as $provider) :
|
|
$label = (string) ($provider['label'] ?? $provider['name'] ?? '');
|
|
$url = (string) ($provider['url'] ?? '#');
|
|
?>
|
|
<a href="<?php echo esc_url($url); ?>" class="but hollow social-login-item ml10"><?php echo esc_html($label); ?></a>
|
|
<?php endforeach; ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
</div>
|
|
</span>
|
|
<?php endif; ?>
|
|
<?php if (function_exists('jio_render_comment_expand_toolbar')) { jio_render_comment_expand_toolbar($ctx); } ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<?php
|
|
}
|
|
endif;
|
|
|
|
|
|
if (!function_exists('jio_comments_render_filter')) :
|
|
/**
|
|
* Newest/hottest + author-only filter.
|
|
*
|
|
* @param array<string,mixed> $ctx Comments context.
|
|
*/
|
|
function jio_comments_render_filter(array $ctx): void {
|
|
if (empty($ctx['corderby_enabled'])) {
|
|
return;
|
|
}
|
|
$order = (string) $ctx['order'];
|
|
$author_only = !empty($ctx['author_only']);
|
|
$post_author_id = (int) $ctx['post_author_id'];
|
|
?>
|
|
<div class="comment-filter tab-nav-theme flex ac jsb" win-ajax-replace="comment-order-btn">
|
|
<ul class="list-inline comment-order-box" style="padding:0;">
|
|
<li class="mr6<?php echo $order === 'newest' ? ' active' : ''; ?>">
|
|
<a href="javascript:;" class="comment-orderby" data-order="newest" rel="nofollow"><?php esc_html_e('最新', 'jio'); ?></a>
|
|
</li>
|
|
<li class="<?php echo $order === 'hottest' ? 'active' : ''; ?>">
|
|
<a href="javascript:;" class="comment-orderby" data-order="hottest" rel="nofollow"><?php esc_html_e('最热', 'jio'); ?></a>
|
|
</li>
|
|
</ul>
|
|
<?php if ($post_author_id > 0) : ?>
|
|
<a href="javascript:;" class="but comment-orderby btn-only-author p2-10" data-author-only="<?php echo $author_only ? '0' : '1'; ?>" rel="nofollow">
|
|
<?php echo $author_only ? esc_html__('查看全部', 'jio') : esc_html__('只看作者', 'jio'); ?>
|
|
</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_get_comment_ajax_loader')) :
|
|
/**
|
|
* Hidden skeleton loader shown while AJAX pagination runs (legacy parity).
|
|
*
|
|
* @return string
|
|
*/
|
|
function jio_get_comment_ajax_loader(): string {
|
|
$item = '<ul class="list-inline flex"><div class="avatar-img placeholder radius"></div><li class="flex1"><div class="placeholder s1 mb6" style="width: 30%;"></div><div class="placeholder k2 mb10"></div><i class="placeholder s1 mb6"></i><i class="placeholder s1 mb6 ml10"></i></li></ul>';
|
|
// 显隐交给 modal-runtime.css 的 .is-loading,内联 display:none 会让骨架永远无法展开。
|
|
return '<div class="post_ajax_loader">' . $item . $item . $item . $item . '</div>';
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_render_empty')) :
|
|
/**
|
|
* Empty state (legacy: legacy('暂无评论内容', 40, 'null.svg', 'comment comment-null')).
|
|
*
|
|
* @param array<string,mixed> $ctx Comments context.
|
|
*/
|
|
function jio_comments_render_empty(array $ctx): void {
|
|
$text = __('暂无评论内容', 'jio');
|
|
if (function_exists('jio_get_null')) {
|
|
echo jio_get_null($text, 40, 'comment-null.svg', 'comment comment-null', 280); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
return;
|
|
}
|
|
echo '<div class="text-center comment comment-null" style="padding:40px 0;"><p class="em09 muted-3-color separator">' . esc_html($text) . '</p></div>';
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_render')) :
|
|
/**
|
|
* Compose the full comments surface.
|
|
*/
|
|
function jio_comments_render(): void {
|
|
if (post_password_required() || !comments_open()) {
|
|
return;
|
|
}
|
|
|
|
$ctx = jio_comments_build_context();
|
|
if (!empty($ctx['close_comments']) || !empty($ctx['box_hidden'])) {
|
|
return;
|
|
}
|
|
|
|
set_query_var('jio_comment_order', (string) $ctx['order']);
|
|
set_query_var('jio_comment_settings', $ctx['settings']);
|
|
|
|
$count = (int) $ctx['comment_count'];
|
|
$count_label = $count > 0
|
|
? sprintf(__('共%s条', 'jio'), (string) $count)
|
|
: __('抢沙发', 'jio');
|
|
?>
|
|
<div class="theme-box" id="comments" data-post-id="<?php echo esc_attr((string) get_the_ID()); ?>">
|
|
<div class="box-body notop">
|
|
<div class="title-theme"><?php echo esc_html((string) $ctx['title_text']); ?>
|
|
<?php echo '<small>' . esc_html($count_label) . '</small>'; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="no_webshot main-bg theme-box box-body radius8 main-shadow">
|
|
<?php if (!empty($ctx['require_login']) && empty($ctx['is_logged_in'])) : ?>
|
|
<?php jio_comments_render_signarea($ctx); ?>
|
|
<?php else : ?>
|
|
<?php jio_comments_render_form($ctx); ?>
|
|
<?php endif; ?>
|
|
|
|
<div id="postcomments">
|
|
<ol class="commentlist list-unstyled">
|
|
<?php
|
|
$show_filter = !empty($ctx['corderby_enabled']) && have_comments();
|
|
if ($show_filter) {
|
|
jio_comments_render_filter($ctx);
|
|
}
|
|
|
|
if (have_comments()) {
|
|
jio_comments_render_list_items($ctx);
|
|
} else {
|
|
jio_comments_render_empty($ctx);
|
|
echo '<div class="pagenav hide"><div class="next-page ajax-next"><a href="#"></a></div></div>';
|
|
}
|
|
?>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
endif;
|
|
|
|
if (!function_exists('jio_comments_render_list_items')) :
|
|
/**
|
|
* Render just the comment items + loader + pagination (inside ol.commentlist).
|
|
*
|
|
* @param array<string,mixed> $ctx Comments context.
|
|
*/
|
|
function jio_comments_render_list_items(array $ctx): void {
|
|
wp_list_comments([
|
|
'type' => 'comment',
|
|
'style' => 'ol',
|
|
'avatar_size' => (int) $ctx['avatar_size'],
|
|
'max_depth' => (int) $ctx['max_depth'],
|
|
'callback' => 'jio_comment_callback',
|
|
]);
|
|
echo jio_get_comment_ajax_loader(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
if (function_exists('jio_render_comment_pagination')) {
|
|
jio_render_comment_pagination();
|
|
}
|
|
}
|
|
endif;
|
|
|