Merge pull request 'Worktree ux depth batch22 24' (#236) from worktree-ux-depth-batch22-24 into main
Reviewed-on: CYL/wordpress-theme-aksrt#236
This commit is contained in:
@@ -2296,3 +2296,86 @@ a.main-color > .icon-cover-card:hover,
|
||||
}
|
||||
.tag-cloud.aksrt-tag-cloud a { transition: transform .15s ease; }
|
||||
.tag-cloud.aksrt-tag-cloud a:hover { transform: translateY(-1px); }
|
||||
|
||||
|
||||
/* batch22-24 forum/user residual */
|
||||
.forum-posts.mini.aksrt-ftopic-mini,
|
||||
.forum-posts.detail.aksrt-ftopic-detail {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid var(--color-line-soft, #f0f1f3);
|
||||
}
|
||||
.forum-posts.mini.aksrt-ftopic-mini:last-child,
|
||||
.forum-posts.detail.aksrt-ftopic-detail:last-child { border-bottom: 0; }
|
||||
.forum-posts .forum-posts-header .avatar-img img,
|
||||
.forum-posts .avatar-img img {
|
||||
width: 28px; height: 28px; border-radius: 50%; object-fit: cover; display: block;
|
||||
}
|
||||
.forum-posts.detail .avatar-img img { width: 40px; height: 40px; }
|
||||
.forum-posts .forum-title { margin: 0; font-size: 14px; font-weight: 600; line-height: 1.4; }
|
||||
.forum-posts .forum-title a { color: inherit; text-decoration: none; }
|
||||
.forum-posts .forum-title a:hover { color: var(--theme-color, #f04494); }
|
||||
.forum-posts .item-meta { gap: 2px; }
|
||||
.forum-posts .forum-excerpt { line-height: 1.5; }
|
||||
.forum-posts badge.img-badge { z-index: 2; }
|
||||
|
||||
.plate-lists .plate-item,
|
||||
.aksrt-plate-lists .plate-item {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid var(--color-line-soft, #f0f1f3);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.plate-lists .plate-item:last-child { border-bottom: 0; }
|
||||
.plate-thumb,
|
||||
.aksrt-plate-item__thumb {
|
||||
width: 48px; height: 48px; border-radius: 10px; overflow: hidden;
|
||||
flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
|
||||
background: var(--surface-2, #f3f4f6); color: #999;
|
||||
}
|
||||
.plate-thumb img, .aksrt-plate-item__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.panel-plate.scroll-plate,
|
||||
.aksrt-plate-cards {
|
||||
display: flex; gap: 12px; overflow-x: auto; padding-bottom: 4px; scrollbar-width: thin;
|
||||
}
|
||||
.plate-card, .aksrt-plate-card {
|
||||
flex: 0 0 160px; width: 160px; text-decoration: none; color: inherit;
|
||||
}
|
||||
.plate-card .plate-thumb, .aksrt-plate-card__cover {
|
||||
width: 100%; aspect-ratio: 1; border-radius: 12px; overflow: hidden;
|
||||
background: var(--surface-2, #f3f4f6); display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.plate-card .plate-thumb img, .aksrt-plate-card__cover img { width: 100%; height: 100%; object-fit: cover; }
|
||||
|
||||
.moderator-box.aksrt-plate-mods__list,
|
||||
.aksrt-plate-mods__list { display: flex; flex-direction: column; gap: 12px; }
|
||||
.aksrt-plate-mods.style-grid .aksrt-plate-mods__list {
|
||||
display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px;
|
||||
}
|
||||
.aksrt-plate-mods__item { gap: 4px; }
|
||||
.aksrt-plate-mods__avatar { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; display: block; }
|
||||
.aksrt-plate-mods.style-grid .aksrt-plate-mods__item { text-align: center; }
|
||||
.aksrt-plate-mods.style-grid .aksrt-plate-mods__avatar { width: 48px; height: 48px; margin: 0 auto 6px; }
|
||||
|
||||
.user-ranking-box .user-ranking-item,
|
||||
.aksrt-user-ranking-box .user-ranking-item { position: relative; }
|
||||
.user-ranking-item .avatar-img img { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; display: block; }
|
||||
.user-ranking-item .badg { white-space: nowrap; }
|
||||
|
||||
.aksrt-category-recommend__card[data-aksrt-animate] { will-change: transform, opacity; }
|
||||
.aksrt-category-recommend__posts.posts-mini-wrap { margin-top: 8px; }
|
||||
|
||||
.aksrt-plate-info.plate-info-sidebar { overflow: hidden; }
|
||||
.aksrt-plate-info__cover.plate-thumb {
|
||||
width: 100%; height: 110px; border-radius: 12px; overflow: hidden;
|
||||
background: var(--surface-2, #f3f4f6); display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.aksrt-plate-info__cover.plate-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.aksrt-plate-info__stats.count-mates { gap: 8px; flex-wrap: wrap; }
|
||||
|
||||
.aksrt-ftag-list { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.aksrt-ftag-item.is-card { min-width: 120px; justify-content: space-between; }
|
||||
|
||||
@@ -32,6 +32,7 @@ require_once AKSRT_DIR . '/inc/helpers/aksrt-archive.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-archive-filters.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-comments.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-forum.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-forum-widgets.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-slider.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-vip.php';
|
||||
require_once AKSRT_DIR . '/inc/helpers/aksrt-auth-ui.php';
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
/**
|
||||
* Shared forum widget renderers (zibll BBS posts/plate mini parity).
|
||||
*
|
||||
* Used by WidgetForumTopicLists, WidgetForumTabTopics, WidgetForumPlateLists,
|
||||
* WidgetForumBoardList, WidgetForumPlateModerator.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_forum_topic_meta_flags')) :
|
||||
/**
|
||||
* @return array{topping:bool,essence:bool,views:int,replies:int,plate_id:int}
|
||||
*/
|
||||
function aksrt_forum_topic_meta_flags(int $post_id): array {
|
||||
return [
|
||||
'topping' => (string) get_post_meta($post_id, '_aksrt_topping', true) === '1'
|
||||
|| (string) get_post_meta($post_id, '_aksrt_is_top', true) === '1',
|
||||
'essence' => (string) get_post_meta($post_id, '_aksrt_essence', true) === '1',
|
||||
'views' => (int) get_post_meta($post_id, '_aksrt_views', true),
|
||||
'replies' => (int) get_comments_number($post_id),
|
||||
'plate_id' => (int) get_post_meta($post_id, '_aksrt_plate_id', true),
|
||||
];
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_forum_topic_badges_html')) :
|
||||
/**
|
||||
* Topping / essence badges for forum topic rows.
|
||||
*/
|
||||
function aksrt_forum_topic_badges_html(int $post_id, bool $show_topping = true): string {
|
||||
$flags = aksrt_forum_topic_meta_flags($post_id);
|
||||
$html = '';
|
||||
if ($show_topping && !empty($flags['topping'])) {
|
||||
$html .= '<badge class="img-badge left jb-red"><i>' . esc_html__('置顶', 'aksrt') . '</i></badge>';
|
||||
}
|
||||
if (!empty($flags['essence'])) {
|
||||
$html .= '<badge class="img-badge right jb-yellow"><i>' . esc_html__('精华', 'aksrt') . '</i></badge>';
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_render_forum_topic_mini')) :
|
||||
/**
|
||||
* Mini forum topic row (zibll zib_bbs_get_posts_mini_list parity).
|
||||
*
|
||||
* @param int|null $post_id Null = current post in loop.
|
||||
* @param string $class Extra classes on outer element.
|
||||
* @param bool $show_topping Whether to show topping badge.
|
||||
*/
|
||||
function aksrt_render_forum_topic_mini(?int $post_id = null, string $class = 'ajax-item', bool $show_topping = true): string {
|
||||
$post_id = $post_id ?: (int) get_the_ID();
|
||||
if ($post_id <= 0) {
|
||||
return '';
|
||||
}
|
||||
$post = get_post($post_id);
|
||||
if (!$post || $post->post_status !== 'publish') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$author_id = (int) $post->post_author;
|
||||
$flags = aksrt_forum_topic_meta_flags($post_id);
|
||||
$permalink = get_permalink($post_id);
|
||||
$title = get_the_title($post_id);
|
||||
|
||||
$avatar_url = function_exists('aksrt_get_avatar_url')
|
||||
? aksrt_get_avatar_url($author_id, ['size' => 48])
|
||||
: get_avatar_url($author_id, ['size' => 48]);
|
||||
$home = function_exists('aksrt_get_user_home_url')
|
||||
? aksrt_get_user_home_url($author_id)
|
||||
: get_author_posts_url($author_id);
|
||||
|
||||
$name = function_exists('aksrt_get_user_name')
|
||||
? aksrt_get_user_name([
|
||||
'id' => $author_id,
|
||||
'class' => 'flex ac flex1',
|
||||
'follow' => false,
|
||||
'medal' => false,
|
||||
'level' => false,
|
||||
])
|
||||
: '<a href="' . esc_url($home) . '">' . esc_html(get_the_author_meta('display_name', $author_id)) . '</a>';
|
||||
|
||||
// Prefer last reply time when available.
|
||||
$time_raw = (string) get_post_meta($post_id, '_aksrt_last_reply_time', true);
|
||||
if ($time_raw === '' || !strtotime($time_raw)) {
|
||||
$time_raw = (string) $post->post_date;
|
||||
}
|
||||
$time_txt = function_exists('aksrt_time_ago')
|
||||
? aksrt_time_ago($time_raw)
|
||||
: human_time_diff(strtotime($time_raw), current_time('timestamp')) . __('前', 'aksrt');
|
||||
|
||||
$views_txt = function_exists('aksrt_format_number')
|
||||
? aksrt_format_number($flags['views'])
|
||||
: (string) $flags['views'];
|
||||
|
||||
$cls = trim('forum-posts mini aksrt-ftopic-mini relative ' . $class);
|
||||
$html = '<posts class="' . esc_attr($cls) . '">';
|
||||
$html .= aksrt_forum_topic_badges_html($post_id, $show_topping);
|
||||
$html .= '<div class="forum-posts-header flex ac">';
|
||||
$html .= '<a class="avatar-img mr6" href="' . esc_url($home) . '"><img class="avatar aksrt-lazy lazyload" data-src="' . esc_url($avatar_url) . '" src="' . esc_url(get_template_directory_uri() . '/assets/img/placeholder.svg') . '" alt="" loading="lazy" width="28" height="28" /></a>';
|
||||
$html .= '<div class="flex1 min-w0">';
|
||||
$html .= '<div class="forum-title text-ellipsis"><a class="icon-circle" href="' . esc_url($permalink) . '">' . esc_html($title) . '</a></div>';
|
||||
$html .= '<div class="item-meta em09 muted-2-color flex ac flex-wrap">';
|
||||
$html .= '<span class="forum-user-name">' . $name . '</span>';
|
||||
$html .= '<span class="ml6">' . esc_html($time_txt) . '</span>';
|
||||
$html .= '<span class="ml6"><i class="fa fa-eye" aria-hidden="true"></i> ' . esc_html((string) $views_txt) . '</span>';
|
||||
if ($flags['replies'] > 0) {
|
||||
$html .= '<span class="ml6"><i class="fa fa-comment-o" aria-hidden="true"></i> ' . esc_html((string) $flags['replies']) . '</span>';
|
||||
}
|
||||
$html .= '</div></div></div></posts>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_render_forum_topic_detail')) :
|
||||
/**
|
||||
* Detail forum topic row (richer entry meta).
|
||||
*
|
||||
* @param int|null $post_id
|
||||
* @param string $class
|
||||
* @param bool $show_topping
|
||||
*/
|
||||
function aksrt_render_forum_topic_detail(?int $post_id = null, string $class = 'ajax-item', bool $show_topping = true): string {
|
||||
$post_id = $post_id ?: (int) get_the_ID();
|
||||
if ($post_id <= 0) {
|
||||
return '';
|
||||
}
|
||||
$post = get_post($post_id);
|
||||
if (!$post || $post->post_status !== 'publish') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$author_id = (int) $post->post_author;
|
||||
$flags = aksrt_forum_topic_meta_flags($post_id);
|
||||
$permalink = get_permalink($post_id);
|
||||
$title = get_the_title($post_id);
|
||||
$excerpt = wp_trim_words(wp_strip_all_tags((string) $post->post_content), 36, '…');
|
||||
|
||||
$avatar_url = function_exists('aksrt_get_avatar_url')
|
||||
? aksrt_get_avatar_url($author_id, ['size' => 64])
|
||||
: get_avatar_url($author_id, ['size' => 64]);
|
||||
$home = function_exists('aksrt_get_user_home_url')
|
||||
? aksrt_get_user_home_url($author_id)
|
||||
: get_author_posts_url($author_id);
|
||||
|
||||
$name = function_exists('aksrt_get_user_name')
|
||||
? aksrt_get_user_name([
|
||||
'id' => $author_id,
|
||||
'class' => 'flex ac',
|
||||
'follow' => false,
|
||||
'medal' => true,
|
||||
'level' => true,
|
||||
])
|
||||
: '<a href="' . esc_url($home) . '">' . esc_html(get_the_author_meta('display_name', $author_id)) . '</a>';
|
||||
|
||||
$time_raw = (string) get_post_meta($post_id, '_aksrt_last_reply_time', true);
|
||||
if ($time_raw === '' || !strtotime($time_raw)) {
|
||||
$time_raw = (string) $post->post_date;
|
||||
}
|
||||
$time_txt = function_exists('aksrt_time_ago')
|
||||
? aksrt_time_ago($time_raw)
|
||||
: human_time_diff(strtotime($time_raw), current_time('timestamp')) . __('前', 'aksrt');
|
||||
|
||||
$views_txt = function_exists('aksrt_format_number')
|
||||
? aksrt_format_number($flags['views'])
|
||||
: (string) $flags['views'];
|
||||
|
||||
// Optional plate name chip.
|
||||
$plate_chip = '';
|
||||
if ($flags['plate_id'] > 0) {
|
||||
$plate = get_post($flags['plate_id']);
|
||||
if ($plate instanceof WP_Post) {
|
||||
$plate_chip = '<a class="but p2-10 em09 mr6" href="' . esc_url(get_permalink($plate)) . '">' . esc_html(get_the_title($plate)) . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
$cls = trim('forum-posts detail aksrt-ftopic-detail relative ' . $class);
|
||||
$html = '<posts class="' . esc_attr($cls) . '">';
|
||||
$html .= aksrt_forum_topic_badges_html($post_id, $show_topping);
|
||||
$html .= '<div class="forum-posts-header flex ac">';
|
||||
$html .= '<a class="avatar-img mr10" href="' . esc_url($home) . '"><img class="avatar aksrt-lazy lazyload" data-src="' . esc_url($avatar_url) . '" src="' . esc_url(get_template_directory_uri() . '/assets/img/placeholder.svg') . '" alt="" loading="lazy" width="40" height="40" /></a>';
|
||||
$html .= '<div class="flex1 min-w0">' . $name . '<div class="em09 muted-2-color mt3">' . esc_html($time_txt) . '</div></div>';
|
||||
$html .= '</div>';
|
||||
$html .= '<h2 class="forum-title mt10"><a href="' . esc_url($permalink) . '">' . esc_html($title) . '</a></h2>';
|
||||
if ($excerpt !== '') {
|
||||
$html .= '<div class="forum-excerpt muted-2-color em09 mt6">' . esc_html($excerpt) . '</div>';
|
||||
}
|
||||
$html .= '<div class="item-meta flex ac flex-wrap mt10 em09 muted-2-color">';
|
||||
$html .= $plate_chip;
|
||||
$html .= '<span class="mr10"><i class="fa fa-eye" aria-hidden="true"></i> ' . esc_html((string) $views_txt) . '</span>';
|
||||
$html .= '<span class="mr10"><i class="fa fa-comment-o" aria-hidden="true"></i> ' . esc_html((string) $flags['replies']) . '</span>';
|
||||
$html .= '</div></posts>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_render_plate_thumb_html')) :
|
||||
/**
|
||||
* Shared plate thumb with lazy pattern.
|
||||
*/
|
||||
function aksrt_render_plate_thumb_html(int $plate_id, string $size = 'thumbnail'): string {
|
||||
$thumb = get_the_post_thumbnail_url($plate_id, $size);
|
||||
$icon = (string) get_post_meta($plate_id, '_aksrt_icon', true);
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
if ($thumb) {
|
||||
return '<span class="plate-thumb aksrt-plate-item__thumb"><img class="aksrt-lazy lazyload fit-cover" data-src="' . esc_url($thumb) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" width="48" height="48" /></span>';
|
||||
}
|
||||
if ($icon !== '') {
|
||||
return '<span class="plate-thumb aksrt-plate-item__thumb is-icon"><i class="' . esc_attr($icon) . '" aria-hidden="true"></i></span>';
|
||||
}
|
||||
return '<span class="plate-thumb aksrt-plate-item__thumb is-empty"><i class="fa fa-comments" aria-hidden="true"></i></span>';
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_render_plate_row')) :
|
||||
/**
|
||||
* Plate list row (zibll plate-item flex).
|
||||
*
|
||||
* @param WP_Post|int $plate
|
||||
*/
|
||||
function aksrt_render_plate_row($plate): string {
|
||||
$post = $plate instanceof WP_Post ? $plate : get_post((int) $plate);
|
||||
if (!$post instanceof WP_Post) {
|
||||
return '';
|
||||
}
|
||||
$id = (int) $post->ID;
|
||||
$url = get_permalink($id);
|
||||
$count = (int) get_post_meta($id, '_aksrt_posts_count', true);
|
||||
$follow = (int) get_post_meta($id, '_aksrt_follow_count', true);
|
||||
$desc = $post->post_excerpt !== '' ? $post->post_excerpt : wp_trim_words(wp_strip_all_tags((string) $post->post_content), 18);
|
||||
|
||||
$html = '<a class="plate-item flex aksrt-plate-item ajax-item" href="' . esc_url($url) . '">';
|
||||
$html .= aksrt_render_plate_thumb_html($id, 'thumbnail');
|
||||
$html .= '<div class="item-info flex1 aksrt-plate-item__body">';
|
||||
$html .= '<div class="info-header"><h2 class="forum-title aksrt-plate-item__title">' . esc_html(get_the_title($post)) . '</h2></div>';
|
||||
if ($desc !== '') {
|
||||
$html .= '<div class="muted-2-color em09 mt3 text-ellipsis aksrt-plate-item__desc">' . esc_html($desc) . '</div>';
|
||||
}
|
||||
$html .= '<div class="item-meta em09 muted-2-color mt3 aksrt-plate-item__meta">';
|
||||
$html .= '<span>' . esc_html(sprintf(/* translators: %d topic count */ __('%d 帖', 'aksrt'), $count)) . '</span>';
|
||||
if ($follow > 0) {
|
||||
$html .= '<span class="ml10">' . esc_html(sprintf(/* translators: %d follow count */ __('%d 关注', 'aksrt'), $follow)) . '</span>';
|
||||
}
|
||||
$html .= '</div></div></a>';
|
||||
return $html;
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_render_plate_card')) :
|
||||
/**
|
||||
* Plate card slide item.
|
||||
*
|
||||
* @param WP_Post|int $plate
|
||||
*/
|
||||
function aksrt_render_plate_card($plate): string {
|
||||
$post = $plate instanceof WP_Post ? $plate : get_post((int) $plate);
|
||||
if (!$post instanceof WP_Post) {
|
||||
return '';
|
||||
}
|
||||
$id = (int) $post->ID;
|
||||
$url = get_permalink($id);
|
||||
$thumb = get_the_post_thumbnail_url($id, 'medium');
|
||||
$count = (int) get_post_meta($id, '_aksrt_posts_count', true);
|
||||
$follow = (int) get_post_meta($id, '_aksrt_follow_count', true);
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
|
||||
$html = '<a class="plate-card aksrt-plate-card ajax-item" href="' . esc_url($url) . '">';
|
||||
$html .= '<div class="plate-thumb aksrt-plate-card__cover">';
|
||||
if ($thumb) {
|
||||
$html .= '<img class="aksrt-lazy lazyload fit-cover" data-src="' . esc_url($thumb) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" />';
|
||||
} else {
|
||||
$html .= '<span class="is-empty"><i class="fa fa-comments" aria-hidden="true"></i></span>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
$html .= '<div class="aksrt-plate-card__title forum-title mt10">' . esc_html(get_the_title($post)) . '</div>';
|
||||
$html .= '<div class="aksrt-plate-card__meta muted-2-color em09 mt6">';
|
||||
$html .= '<span>' . esc_html(sprintf(__('%d 帖', 'aksrt'), $count)) . '</span>';
|
||||
$html .= '<span class="ml10">' . esc_html(sprintf(__('%d 关注', 'aksrt'), $follow)) . '</span>';
|
||||
$html .= '</div></a>';
|
||||
return $html;
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_render_moderator_row')) :
|
||||
/**
|
||||
* Moderator identity row with optional follow.
|
||||
*
|
||||
* @param int $user_id
|
||||
* @param string $role author|super|moderator
|
||||
* @param bool $show_avatar
|
||||
* @param string $style list|grid
|
||||
*/
|
||||
function aksrt_render_moderator_row(int $user_id, string $role = 'moderator', bool $show_avatar = true, string $style = 'list'): string {
|
||||
if ($user_id <= 0) {
|
||||
return '';
|
||||
}
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user) {
|
||||
return '';
|
||||
}
|
||||
$avatar = function_exists('aksrt_get_avatar_url')
|
||||
? aksrt_get_avatar_url($user_id, ['size' => 64])
|
||||
: get_avatar_url($user_id, ['size' => 64]);
|
||||
$home = function_exists('aksrt_get_user_home_url')
|
||||
? aksrt_get_user_home_url($user_id)
|
||||
: get_author_posts_url($user_id);
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
|
||||
if ($role === 'author' || $role === 'super') {
|
||||
$role_label = __('超级版主', 'aksrt');
|
||||
} else {
|
||||
$role_label = __('版主', 'aksrt');
|
||||
}
|
||||
|
||||
$name = function_exists('aksrt_get_user_name')
|
||||
? aksrt_get_user_name([
|
||||
'id' => $user_id,
|
||||
'class' => 'flex ac flex1',
|
||||
'follow' => false,
|
||||
'medal' => true,
|
||||
'level' => true,
|
||||
])
|
||||
: '<a href="' . esc_url($home) . '">' . esc_html($user->display_name) . '</a>';
|
||||
|
||||
// Follow control (not for self).
|
||||
$follow_html = '';
|
||||
$cuid = get_current_user_id();
|
||||
if ($cuid > 0 && $cuid !== $user_id && class_exists('\AKSRT\User\Follow')) {
|
||||
$following = \AKSRT\User\Follow::get_instance()->is_following($cuid, $user_id);
|
||||
$label = $following ? __('已关注', 'aksrt') : __('关注', 'aksrt');
|
||||
$follow_html = '<button type="button" class="but hollow c-blue p2-10 em09 ml10 flex0' . ($following ? ' is-following' : '') . '" data-aksrt-follow="' . (int) $user_id . '">' . esc_html($label) . '</button>';
|
||||
}
|
||||
|
||||
if ($style === 'grid') {
|
||||
$html = '<div class="aksrt-plate-mods__item role-' . esc_attr($role) . ' is-grid">';
|
||||
if ($show_avatar) {
|
||||
$html .= '<a href="' . esc_url($home) . '"><img class="aksrt-plate-mods__avatar aksrt-lazy lazyload" data-src="' . esc_url($avatar) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" width="48" height="48" /></a>';
|
||||
}
|
||||
$html .= '<div class="aksrt-plate-mods__name">' . $name . '</div>';
|
||||
$html .= '<div class="aksrt-plate-mods__role muted-2-color em09">' . esc_html($role_label) . '</div>';
|
||||
$html .= $follow_html;
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
$html = '<div class="aksrt-plate-mods__item role-' . esc_attr($role) . ' flex ac">';
|
||||
if ($show_avatar) {
|
||||
$html .= '<a class="avatar-img mr10" href="' . esc_url($home) . '"><img class="aksrt-plate-mods__avatar aksrt-lazy lazyload" data-src="' . esc_url($avatar) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" width="40" height="40" /></a>';
|
||||
}
|
||||
$html .= '<div class="flex1 min-w0">';
|
||||
$html .= '<div class="aksrt-plate-mods__name">' . $name . '</div>';
|
||||
$html .= '<div class="aksrt-plate-mods__role muted-2-color em09">' . esc_html($role_label) . '</div>';
|
||||
$html .= '</div>';
|
||||
$html .= $follow_html;
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
}
|
||||
endif;
|
||||
@@ -215,25 +215,26 @@ if (!function_exists('aksrt_home_widget_render_post_grid')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback: simple sidebar list
|
||||
// Fallback: shared mini list (lazy thumbs + meta).
|
||||
if (function_exists('aksrt_render_mini_list')) {
|
||||
echo '<div class="widget-tab-posts__list widget-tab-posts__list--mini aksrt-home-widget__sidebar-list">';
|
||||
aksrt_render_mini_list($query, ['context' => 'sidebar', 'show_thumb' => true]);
|
||||
echo '</div>';
|
||||
return;
|
||||
}
|
||||
echo '<ul class="widget-tab-posts__list aksrt-home-widget__sidebar-list">';
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
?>
|
||||
<li class="widget-tab-posts__item">
|
||||
<?php if (has_post_thumbnail()) : ?>
|
||||
<a href="<?php the_permalink(); ?>" class="widget-tab-posts__thumb">
|
||||
<?php the_post_thumbnail('thumbnail', ['loading' => 'lazy', 'class' => 'fit-cover']); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<div class="widget-tab-posts__info">
|
||||
<a href="<?php the_permalink(); ?>" class="widget-tab-posts__title"><?php the_title(); ?></a>
|
||||
<span class="widget-tab-posts__meta">
|
||||
<?php echo esc_html(human_time_diff(get_the_time('U'), current_time('timestamp')) . __('前', 'aksrt')); ?>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<?php
|
||||
$thumb = get_the_post_thumbnail_url(get_the_ID(), 'thumbnail');
|
||||
echo '<li class="widget-tab-posts__item">';
|
||||
if ($thumb) {
|
||||
echo '<a href="' . esc_url(get_permalink()) . '" class="widget-tab-posts__thumb"><img class="fit-cover aksrt-lazy lazyload" data-src="' . esc_url($thumb) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" /></a>';
|
||||
}
|
||||
echo '<div class="widget-tab-posts__info">';
|
||||
echo '<a href="' . esc_url(get_permalink()) . '" class="widget-tab-posts__title">' . esc_html(get_the_title()) . '</a>';
|
||||
echo '<span class="widget-tab-posts__meta">' . esc_html(human_time_diff(get_the_time('U'), current_time('timestamp')) . __('前', 'aksrt')) . '</span>';
|
||||
echo '</div></li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
wp_reset_postdata();
|
||||
|
||||
@@ -48,56 +48,82 @@ class CategoryRecommendWidget extends \WP_Widget {
|
||||
ob_start();
|
||||
printf('<div class="aksrt-category-recommend__grid ajax-item" style="--aksrt-recommend-columns:%d;">', (int) $columns);
|
||||
foreach ($cards as $card) {
|
||||
?>
|
||||
<article class="aksrt-category-recommend__card">
|
||||
<div class="aksrt-category-recommend__hero">
|
||||
<a href="<?php echo esc_url($card['link']); ?>">
|
||||
<?php if ($lazy['enabled']) : ?>
|
||||
<span class="aksrt-skeleton"></span>
|
||||
<img class="aksrt-category-recommend__cover aksrt-lazy" data-src="<?php echo esc_url($card['cover']); ?>" src="<?php echo esc_url($lazy['placeholder_url']); ?>" alt="<?php echo esc_attr($card['name']); ?>">
|
||||
<?php else : ?>
|
||||
<img class="aksrt-category-recommend__cover" src="<?php echo esc_url($card['cover']); ?>" alt="<?php echo esc_attr($card['name']); ?>">
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
<span class="aksrt-category-recommend__badge"><?php echo esc_html(sprintf(_n('%d 篇文章', '%d 篇文章', $card['count'], 'aksrt'), $card['count'])); ?></span>
|
||||
<?php if ($show_views && $card['views'] > 0) : ?>
|
||||
<span class="aksrt-category-recommend__views">
|
||||
<i class="fas fa-eye" aria-hidden="true"></i>
|
||||
<?php echo esc_html(function_exists('aksrt_format_number') ? aksrt_format_number($card['views']) : number_format_i18n($card['views'])); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="aksrt-category-recommend__body">
|
||||
<div class="aksrt-category-recommend__meta">
|
||||
<h4 class="aksrt-category-recommend__name">
|
||||
<a href="<?php echo esc_url($card['link']); ?>"><?php echo esc_html($card['name']); ?></a>
|
||||
</h4>
|
||||
<?php if ($show_description && $card['description'] !== '') : ?>
|
||||
<p class="aksrt-category-recommend__desc"><?php echo esc_html($card['description']); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<ul class="aksrt-category-recommend__posts">
|
||||
<?php foreach ($card['posts'] as $post_item) : ?>
|
||||
<li class="aksrt-category-recommend__post">
|
||||
<a class="aksrt-category-recommend__post-link" href="<?php echo esc_url($post_item['link']); ?>">
|
||||
<?php echo esc_html($post_item['title']); ?>
|
||||
</a>
|
||||
<?php if ($show_dates && $post_item['date'] !== '') : ?>
|
||||
<span class="aksrt-category-recommend__date"><?php echo esc_html($post_item['date']); ?></span>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php if ($show_more) : ?>
|
||||
<div class="aksrt-home-widget__footer">
|
||||
<a class="aksrt-home-widget__more" href="<?php echo esc_url($card['link']); ?>">
|
||||
<?php esc_html_e('查看更多', 'aksrt'); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</article>
|
||||
<?php
|
||||
$cover = (string) ($card['cover'] ?? '');
|
||||
$link = (string) ($card['link'] ?? '');
|
||||
$name = (string) ($card['name'] ?? '');
|
||||
$badge = sprintf(_n('%d 篇文章', '%d 篇文章', (int) $card['count'], 'aksrt'), (int) $card['count']);
|
||||
$more = '';
|
||||
if ($show_views && (int) $card['views'] > 0) {
|
||||
$v = function_exists('aksrt_format_number') ? aksrt_format_number((int) $card['views']) : number_format_i18n((int) $card['views']);
|
||||
$more = '<span class="aksrt-category-recommend__views"><i class="fa fa-eye" aria-hidden="true"></i> ' . esc_html((string) $v) . '</span>';
|
||||
}
|
||||
echo '<article class="aksrt-category-recommend__card" data-aksrt-animate="fade-up">';
|
||||
if (function_exists('aksrt_graphic_card') && $cover !== '') {
|
||||
echo aksrt_graphic_card([ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
'type' => 'style-2',
|
||||
'class' => 'aksrt-category-recommend__hero mb10',
|
||||
'img' => $cover,
|
||||
'alt' => $name,
|
||||
'link' => ['url' => $link],
|
||||
'text1' => $name,
|
||||
'text2' => $show_description ? (string) $card['description'] : '',
|
||||
'text3' => $badge,
|
||||
'more' => $more,
|
||||
'lazy' => true,
|
||||
]);
|
||||
} else {
|
||||
echo '<div class="aksrt-category-recommend__hero">';
|
||||
echo '<a href="' . esc_url($link) . '">';
|
||||
if ($lazy['enabled']) {
|
||||
echo '<span class="aksrt-skeleton"></span>';
|
||||
echo '<img class="aksrt-category-recommend__cover aksrt-lazy" data-src="' . esc_url($cover) . '" src="' . esc_url($lazy['placeholder_url']) . '" alt="' . esc_attr($name) . '">';
|
||||
} else {
|
||||
echo '<img class="aksrt-category-recommend__cover" src="' . esc_url($cover) . '" alt="' . esc_attr($name) . '">';
|
||||
}
|
||||
echo '</a>';
|
||||
echo '<span class="aksrt-category-recommend__badge">' . esc_html($badge) . '</span>';
|
||||
echo $more; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '</div>';
|
||||
echo '<div class="aksrt-category-recommend__meta">';
|
||||
echo '<h4 class="aksrt-category-recommend__name"><a href="' . esc_url($link) . '">' . esc_html($name) . '</a></h4>';
|
||||
if ($show_description && $card['description'] !== '') {
|
||||
echo '<p class="aksrt-category-recommend__desc">' . esc_html((string) $card['description']) . '</p>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
echo '<div class="aksrt-category-recommend__body">';
|
||||
// Prefer shared mini list when post IDs available.
|
||||
if (!empty($card['post_ids']) && function_exists('aksrt_render_mini_list')) {
|
||||
$q = new \WP_Query([
|
||||
'post_type' => 'any',
|
||||
'post__in' => array_map('intval', (array) $card['post_ids']),
|
||||
'orderby' => 'post__in',
|
||||
'posts_per_page' => count((array) $card['post_ids']),
|
||||
'ignore_sticky_posts' => true,
|
||||
'no_found_rows' => true,
|
||||
]);
|
||||
echo '<div class="aksrt-category-recommend__posts posts-mini-wrap">';
|
||||
aksrt_render_mini_list($q, ['context' => 'widget', 'show_thumb' => true, 'show_meta' => $show_dates]);
|
||||
echo '</div>';
|
||||
wp_reset_postdata();
|
||||
} else {
|
||||
echo '<ul class="aksrt-category-recommend__posts">';
|
||||
foreach ($card['posts'] as $post_item) {
|
||||
echo '<li class="aksrt-category-recommend__post">';
|
||||
echo '<a class="aksrt-category-recommend__post-link" href="' . esc_url($post_item['link']) . '">' . esc_html($post_item['title']) . '</a>';
|
||||
if ($show_dates && $post_item['date'] !== '') {
|
||||
echo '<span class="aksrt-category-recommend__date">' . esc_html($post_item['date']) . '</span>';
|
||||
}
|
||||
echo '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
if ($show_more) {
|
||||
echo '<div class="aksrt-home-widget__footer">';
|
||||
echo '<a class="aksrt-home-widget__more" href="' . esc_url($link) . '">' . esc_html__('查看更多', 'aksrt') . '</a>';
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div></article>';
|
||||
}
|
||||
echo '</div>';
|
||||
return (string) ob_get_clean();
|
||||
|
||||
@@ -130,7 +130,7 @@ class CategoryTabsWidget extends \WP_Widget {
|
||||
if(showMore&&more){
|
||||
html+='<div class="aksrt-home-widget__footer"><a class="aksrt-home-widget__more" href="'+more+'">查看更多</a></div>';
|
||||
}
|
||||
panel.innerHTML=html||'<p class="widget-empty">暂无文章</p>';
|
||||
panel.innerHTML=html||'<div class="ajax-item widget-empty muted-2-color">暂无文章</div>';
|
||||
panel.setAttribute('data-loaded','1');
|
||||
panel.classList.remove('is-ajax-loading');
|
||||
}).catch(function(){panel.classList.remove('is-ajax-loading');});
|
||||
|
||||
@@ -57,27 +57,44 @@ class WidgetForumBoardList extends \WP_Widget {
|
||||
$plates = get_posts($query_args);
|
||||
if ($plates) {
|
||||
ob_start();
|
||||
echo '<ul class="aksrt-forum-widget__boards style-' . esc_attr($style) . ' ajax-item">';
|
||||
foreach ($plates as $plate) {
|
||||
$icon = (string) get_post_meta($plate->ID, '_aksrt_icon', true);
|
||||
$count = (int) get_post_meta($plate->ID, '_aksrt_posts_count', true);
|
||||
$thumb = get_the_post_thumbnail_url($plate->ID, 'thumbnail');
|
||||
echo '<li class="aksrt-forum-widget__board">';
|
||||
echo '<a href="' . esc_url(get_permalink($plate)) . '">';
|
||||
if ($style === 'mini' && $thumb) {
|
||||
echo '<img class="aksrt-forum-widget__thumb" src="' . esc_url($thumb) . '" alt="" width="28" height="28" loading="lazy" />';
|
||||
} elseif ($icon !== '') {
|
||||
echo '<i class="' . esc_attr($icon) . '"></i> ';
|
||||
if ($style === 'mini' && function_exists('aksrt_render_plate_row')) {
|
||||
// Compact mini still uses shared plate row for consistent DOM/lazy.
|
||||
echo '<div class="plate-lists aksrt-forum-widget__boards style-mini ajax-item">';
|
||||
foreach ($plates as $plate) {
|
||||
echo aksrt_render_plate_row($plate); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '<span class="aksrt-forum-widget__name">' . esc_html(get_the_title($plate)) . '</span>';
|
||||
echo '<span class="aksrt-forum-widget__count">' . esc_html((string) $count) . '</span>';
|
||||
echo '</a></li>';
|
||||
echo '</div>';
|
||||
} elseif (function_exists('aksrt_render_plate_row')) {
|
||||
echo '<div class="plate-lists aksrt-forum-widget__boards style-list ajax-item">';
|
||||
foreach ($plates as $plate) {
|
||||
echo aksrt_render_plate_row($plate); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<ul class="aksrt-forum-widget__boards style-' . esc_attr($style) . ' ajax-item">';
|
||||
foreach ($plates as $plate) {
|
||||
$icon = (string) get_post_meta($plate->ID, '_aksrt_icon', true);
|
||||
$count = (int) get_post_meta($plate->ID, '_aksrt_posts_count', true);
|
||||
$thumb = get_the_post_thumbnail_url($plate->ID, 'thumbnail');
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
echo '<li class="aksrt-forum-widget__board">';
|
||||
echo '<a href="' . esc_url(get_permalink($plate)) . '">';
|
||||
if ($style === 'mini' && $thumb) {
|
||||
echo '<img class="aksrt-forum-widget__thumb aksrt-lazy lazyload" data-src="' . esc_url($thumb) . '" src="' . esc_url($ph) . '" alt="" width="28" height="28" loading="lazy" />';
|
||||
} elseif ($icon !== '') {
|
||||
echo '<i class="' . esc_attr($icon) . '"></i> ';
|
||||
}
|
||||
echo '<span class="aksrt-forum-widget__name">' . esc_html(get_the_title($plate)) . '</span>';
|
||||
echo '<span class="aksrt-forum-widget__count">' . esc_html((string) $count) . '</span>';
|
||||
echo '</a></li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
echo '</ul>';
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Taxonomy fallback.
|
||||
$term_args = [
|
||||
'taxonomy' => 'aksrt_forum_board',
|
||||
|
||||
@@ -54,11 +54,12 @@ class WidgetForumPlateInfo extends \WP_Widget {
|
||||
: home_url('/');
|
||||
|
||||
ob_start();
|
||||
echo '<div class="aksrt-plate-info ajax-item">';
|
||||
echo '<div class="forum-header plate-info-sidebar aksrt-plate-info ajax-item">';
|
||||
if ($thumb) {
|
||||
echo '<div class="aksrt-plate-info__cover" style="background-image:url(' . esc_url($thumb) . ')"></div>';
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
echo '<div class="aksrt-plate-info__cover plate-thumb"><img class="aksrt-lazy lazyload fit-cover" data-src="' . esc_url($thumb) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" /></div>';
|
||||
} elseif ($icon !== '') {
|
||||
echo '<div class="aksrt-plate-info__cover is-icon"><i class="' . esc_attr($icon) . '" aria-hidden="true"></i></div>';
|
||||
echo '<div class="aksrt-plate-info__cover plate-thumb is-icon"><i class="' . esc_attr($icon) . '" aria-hidden="true"></i></div>';
|
||||
}
|
||||
echo '<div class="aksrt-plate-info__body">';
|
||||
echo '<a class="aksrt-plate-info__title" href="' . esc_url($url) . '">' . esc_html(get_the_title($plate)) . '</a>';
|
||||
@@ -66,7 +67,7 @@ class WidgetForumPlateInfo extends \WP_Widget {
|
||||
echo '<div class="aksrt-plate-info__desc">' . esc_html($desc) . '</div>';
|
||||
}
|
||||
if ($show_stats) {
|
||||
echo '<div class="aksrt-plate-info__stats">';
|
||||
echo '<div class="aksrt-plate-info__stats count-mates flex jsb">';
|
||||
echo '<span title="' . esc_attr__('帖子', 'aksrt') . '"><i class="fas fa-file-alt" aria-hidden="true"></i> ' . esc_html((string) $posts) . '</span>';
|
||||
echo '<span title="' . esc_attr__('回复', 'aksrt') . '"><i class="fas fa-comment" aria-hidden="true"></i> ' . esc_html((string) $reply) . '</span>';
|
||||
if ($views > 0) {
|
||||
|
||||
@@ -88,20 +88,27 @@ class WidgetForumPlateLists extends \WP_Widget {
|
||||
return '';
|
||||
}
|
||||
ob_start();
|
||||
$self = new self();
|
||||
if ($style === 'card') {
|
||||
echo '<div class="aksrt-plate-cards ajax-item">';
|
||||
echo '<div class="panel-plate scroll-plate aksrt-plate-cards">';
|
||||
foreach ($plates as $post) {
|
||||
if ($post instanceof \WP_Post) {
|
||||
$self->render_card($post);
|
||||
if (function_exists('aksrt_render_plate_card')) {
|
||||
echo aksrt_render_plate_card($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
} else {
|
||||
(new self())->render_card($post);
|
||||
}
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<div class="aksrt-plate-lists ajax-item">';
|
||||
echo '<div class="plate-lists aksrt-plate-lists">';
|
||||
foreach ($plates as $post) {
|
||||
if ($post instanceof \WP_Post) {
|
||||
$self->render_row($post);
|
||||
if (function_exists('aksrt_render_plate_row')) {
|
||||
echo aksrt_render_plate_row($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
} else {
|
||||
(new self())->render_row($post);
|
||||
}
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
@@ -154,42 +161,56 @@ class WidgetForumPlateLists extends \WP_Widget {
|
||||
}
|
||||
|
||||
public function render_row(\WP_Post $post): void {
|
||||
if (function_exists('aksrt_render_plate_row')) {
|
||||
echo aksrt_render_plate_row($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
$id = (int) $post->ID;
|
||||
$url = get_permalink($id);
|
||||
$thumb = get_the_post_thumbnail_url($id, 'thumbnail');
|
||||
$icon = (string) get_post_meta($id, '_aksrt_icon', true);
|
||||
$count = (int) get_post_meta($id, '_aksrt_posts_count', true);
|
||||
$desc = $post->post_excerpt !== '' ? $post->post_excerpt : wp_trim_words(wp_strip_all_tags($post->post_content), 18);
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
|
||||
echo '<a class="aksrt-plate-item" href="' . esc_url($url) . '">';
|
||||
echo '<div class="aksrt-plate-item__thumb">';
|
||||
echo '<a class="plate-item flex aksrt-plate-item" href="' . esc_url($url) . '">';
|
||||
echo '<div class="plate-thumb aksrt-plate-item__thumb">';
|
||||
if ($thumb) {
|
||||
echo '<img src="' . esc_url($thumb) . '" alt="" loading="lazy" />';
|
||||
echo '<img class="aksrt-lazy lazyload" data-src="' . esc_url($thumb) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" />';
|
||||
} elseif ($icon !== '') {
|
||||
echo '<i class="' . esc_attr($icon) . '" aria-hidden="true"></i>';
|
||||
} else {
|
||||
echo '<i class="fas fa-comments" aria-hidden="true"></i>';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '<div class="aksrt-plate-item__body">';
|
||||
echo '<div class="aksrt-plate-item__title">' . esc_html(get_the_title($post)) . '</div>';
|
||||
echo '<div class="item-info flex1 aksrt-plate-item__body">';
|
||||
echo '<div class="info-header"><div class="forum-title aksrt-plate-item__title">' . esc_html(get_the_title($post)) . '</div></div>';
|
||||
if ($desc !== '') {
|
||||
echo '<div class="aksrt-plate-item__desc">' . esc_html($desc) . '</div>';
|
||||
echo '<div class="aksrt-plate-item__desc muted-2-color em09">' . esc_html($desc) . '</div>';
|
||||
}
|
||||
echo '<div class="aksrt-plate-item__meta"><span>' . esc_html(sprintf(/* translators: %d topic count */ __('%d 帖', 'aksrt'), $count)) . '</span></div>';
|
||||
echo '</div></a>';
|
||||
}
|
||||
|
||||
public function render_card(\WP_Post $post): void {
|
||||
if (function_exists('aksrt_render_plate_card')) {
|
||||
echo aksrt_render_plate_card($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
$id = (int) $post->ID;
|
||||
$url = get_permalink($id);
|
||||
$thumb = get_the_post_thumbnail_url($id, 'medium');
|
||||
$count = (int) get_post_meta($id, '_aksrt_posts_count', true);
|
||||
$follow = (int) get_post_meta($id, '_aksrt_follow_count', true);
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
|
||||
echo '<a class="aksrt-plate-card" href="' . esc_url($url) . '">';
|
||||
echo '<div class="aksrt-plate-card__cover"' . ($thumb ? ' style="background-image:url(' . esc_url($thumb) . ')"' : '') . '></div>';
|
||||
echo '<div class="aksrt-plate-card__title">' . esc_html(get_the_title($post)) . '</div>';
|
||||
echo '<a class="plate-card aksrt-plate-card" href="' . esc_url($url) . '">';
|
||||
echo '<div class="plate-thumb aksrt-plate-card__cover">';
|
||||
if ($thumb) {
|
||||
echo '<img class="aksrt-lazy lazyload fit-cover" data-src="' . esc_url($thumb) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" />';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '<div class="aksrt-plate-card__title forum-title">' . esc_html(get_the_title($post)) . '</div>';
|
||||
echo '<div class="aksrt-plate-card__meta">';
|
||||
echo '<span>' . esc_html(sprintf(__('%d 帖', 'aksrt'), $count)) . '</span>';
|
||||
echo '<span>' . esc_html(sprintf(__('%d 关注', 'aksrt'), $follow)) . '</span>';
|
||||
|
||||
@@ -74,13 +74,17 @@ class WidgetForumPlateModerator extends \WP_Widget {
|
||||
}
|
||||
|
||||
ob_start();
|
||||
echo '<div class="aksrt-plate-mods style-' . esc_attr($style) . ' ajax-item">';
|
||||
echo '<div class="zib-widget moderator-box aksrt-plate-mods style-' . esc_attr($style) . ' ajax-item">';
|
||||
if ($title_text !== '') {
|
||||
echo '<div class="aksrt-plate-mods__head"><div class="title-theme">' . esc_html($title_text) . '</div></div>';
|
||||
echo '<div class="mb10 flex jsb ac aksrt-plate-mods__head"><div class="title-theme">' . esc_html($title_text) . '</div></div>';
|
||||
}
|
||||
echo '<div class="aksrt-plate-mods__list">';
|
||||
foreach ($people as $row) {
|
||||
$uid = (int) $row['id'];
|
||||
$uid = (int) $row['id'];
|
||||
if (function_exists('aksrt_render_moderator_row')) {
|
||||
echo aksrt_render_moderator_row($uid, (string) $row['role'], $show_avatar, $style); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
continue;
|
||||
}
|
||||
$user = get_userdata($uid);
|
||||
if (!$user) {
|
||||
continue;
|
||||
@@ -105,7 +109,7 @@ class WidgetForumPlateModerator extends \WP_Widget {
|
||||
echo '</a>';
|
||||
}
|
||||
echo '</div></div>';
|
||||
return ['html' => (string) ob_get_clean()];
|
||||
return ['html' => (string) ob_get_clean()];
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
|
||||
@@ -88,7 +88,7 @@ class WidgetForumTabTopics extends \WP_Widget {
|
||||
.then(function(r){return r.json()}).then(function(j){
|
||||
var d=(j&&j.data)||j||{};
|
||||
var html=d.html||'';
|
||||
panel.innerHTML=html||'<p class="aksrt-ftab__empty">暂无内容</p>';
|
||||
panel.innerHTML=html||'<div class="ajax-item aksrt-ftab__empty muted-2-color">暂无内容</div>';
|
||||
panel.setAttribute('data-loaded','1');
|
||||
panel.classList.remove('is-ajax-loading');
|
||||
}).catch(function(){panel.classList.remove('is-ajax-loading');});
|
||||
|
||||
@@ -79,26 +79,25 @@ class WidgetForumTopicLists extends \WP_Widget {
|
||||
if (!$q->have_posts()) {
|
||||
return '';
|
||||
}
|
||||
$list_class = $style === 'detail' ? 'aksrt-ftopic-list is-detail' : 'aksrt-ftopic-list is-mini';
|
||||
ob_start();
|
||||
echo '<ul class="' . esc_attr($list_class) . '">';
|
||||
echo $style === 'detail'
|
||||
? '<div class="forum-posts-lists aksrt-ftopic-list is-detail">'
|
||||
: '<div class="forum-posts-lists aksrt-ftopic-list is-mini">';
|
||||
while ($q->have_posts()) {
|
||||
$q->the_post();
|
||||
$views = (int) get_post_meta(get_the_ID(), '_aksrt_views', true);
|
||||
echo '<li class="aksrt-ftopic-list__item ajax-item">';
|
||||
echo '<a class="aksrt-ftopic-list__link" href="' . esc_url(get_permalink()) . '">' . esc_html(get_the_title()) . '</a>';
|
||||
if ($style === 'detail') {
|
||||
echo '<div class="aksrt-ftopic-list__meta">';
|
||||
echo '<span>' . esc_html(get_the_author()) . '</span>';
|
||||
echo '<span>' . esc_html(get_the_date()) . '</span>';
|
||||
echo '<span><i class="fas fa-eye"></i> ' . esc_html((string) $views) . '</span>';
|
||||
echo '</div>';
|
||||
if ($style === 'detail' && function_exists('aksrt_render_forum_topic_detail')) {
|
||||
echo aksrt_render_forum_topic_detail(null, 'ajax-item', true); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
} elseif (function_exists('aksrt_render_forum_topic_mini')) {
|
||||
echo aksrt_render_forum_topic_mini(null, 'ajax-item', true); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
} else {
|
||||
$views = (int) get_post_meta(get_the_ID(), '_aksrt_views', true);
|
||||
echo '<div class="aksrt-ftopic-list__item ajax-item">';
|
||||
echo '<a class="aksrt-ftopic-list__link" href="' . esc_url(get_permalink()) . '">' . esc_html(get_the_title()) . '</a>';
|
||||
echo '<span class="aksrt-ftopic-list__views">' . esc_html((string) $views) . '</span>';
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
echo '</div>';
|
||||
wp_reset_postdata();
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ class WidgetForumTopicTerms extends \WP_Widget {
|
||||
continue;
|
||||
}
|
||||
$icon = (string) get_term_meta($term->term_id, '_aksrt_icon', true);
|
||||
echo '<a class="aksrt-ftag-item" href="' . esc_url($link) . '">';
|
||||
echo '<a class="aksrt-ftag-item but p2-10' . ($style === 'card' ? ' is-card' : '') . '" href="' . esc_url($link) . '">';
|
||||
if ($icon !== '') {
|
||||
echo '<i class="' . esc_attr($icon) . '" aria-hidden="true"></i> ';
|
||||
}
|
||||
@@ -106,7 +106,7 @@ class WidgetForumTopicTerms extends \WP_Widget {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
// IAS-style wrap for remote refresh.
|
||||
echo '<div class="zib-widget padding-6 ajaxpager" data-aksrt-ajaxpager>';
|
||||
echo '<div class="zib-widget padding-6 aksrt-ftag-wrap">';
|
||||
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '</div>';
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
@@ -49,6 +49,13 @@ class WidgetProductTab extends \WP_Widget {
|
||||
$paginate = sanitize_key((string) ($instance['paginate'] ?? 'ajax'));
|
||||
$tabs = self::parse_tabs($tabs_raw);
|
||||
if (!$tabs) {
|
||||
if (current_user_can('manage_options')) {
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo function_exists('aksrt_get_widget_null')
|
||||
? aksrt_get_widget_null(__('请至少配置一个 TAB', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
: '<p class="widget-empty">' . esc_html__('请至少配置一个 TAB', 'aksrt') . '</p>';
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* User ranking lists (zibll zib_user_ranking_lists parity).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,314 +11,343 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class WidgetUserRanking extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_user_ranking',
|
||||
__('用户排行榜', 'aksrt'),
|
||||
['description' => __('按积分、文章数或粉丝数排行的用户列表。', 'aksrt')]
|
||||
);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_user_ranking',
|
||||
__('用户排行榜', 'aksrt'),
|
||||
[
|
||||
'description' => __('按积分、文章数或粉丝数排行的用户列表。', 'aksrt'),
|
||||
'classname' => 'widget_aksrt_user_ranking',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : __('排行榜', 'aksrt');
|
||||
$rank_by = !empty($instance['rank_by']) ? $instance['rank_by'] : 'credits';
|
||||
$count = max(1, min(20, (int) ($instance['count'] ?? 5)));
|
||||
$show_avatar = !empty($instance['show_avatar']);
|
||||
public function widget($args, $instance): void {
|
||||
$title = !empty($instance['title']) ? (string) $instance['title'] : __('排行榜', 'aksrt');
|
||||
$rank_by = !empty($instance['rank_by']) ? (string) $instance['rank_by'] : 'credits';
|
||||
$count = max(1, min(20, (int) ($instance['count'] ?? 5)));
|
||||
$show_avatar = !isset($instance['show_avatar']) || !empty($instance['show_avatar']);
|
||||
$desc_mode = sanitize_key((string) ($instance['desc'] ?? 'desc'));
|
||||
$top_badge = !empty($instance['top_badge']);
|
||||
$users = $this->get_ranking($rank_by, $count, $desc_mode);
|
||||
|
||||
$desc_mode = sanitize_key((string) ($instance['desc'] ?? 'desc'));
|
||||
$users = $this->get_ranking($rank_by, $count, $desc_mode);
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="zib-widget user-ranking-box aksrt-user-ranking-box">';
|
||||
if (!empty($instance['checkin_btn']) && is_user_logged_in() && function_exists('aksrt_header_user_checkin_btn')) {
|
||||
$cbtn = aksrt_header_user_checkin_btn(get_current_user_id());
|
||||
if ($cbtn !== '') {
|
||||
echo '<div class="aksrt-user-ranking__checkin mb10">' . $cbtn . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($instance['checkin_btn']) && is_user_logged_in() && function_exists('aksrt_header_user_checkin_btn')) {
|
||||
$cbtn = aksrt_header_user_checkin_btn(get_current_user_id());
|
||||
if ($cbtn !== '') {
|
||||
echo '<div class="aksrt-user-ranking__checkin mb10">' . $cbtn . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
if (empty($users)) {
|
||||
echo function_exists('aksrt_get_widget_null')
|
||||
? aksrt_get_widget_null(__('暂无排行数据', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
: '<p class="aksrt-user-ranking__empty muted-2-color">' . esc_html__('暂无排行数据', 'aksrt') . '</p>';
|
||||
echo '</div>';
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($users)) {
|
||||
echo '<p class="aksrt-user-ranking__empty muted-2-color">' . esc_html__('暂无排行数据', 'aksrt') . '</p>';
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
$rank = 0;
|
||||
foreach ($users as $user) {
|
||||
$rank++;
|
||||
$uid = (int) $user['id'];
|
||||
$user_url = function_exists('aksrt_get_user_home_url')
|
||||
? aksrt_get_user_home_url($uid)
|
||||
: get_author_posts_url($uid);
|
||||
|
||||
$top_badge = !empty($instance['top_badge']);
|
||||
$top_bagd = '';
|
||||
if ($top_badge && $rank <= 3) {
|
||||
$tone = $rank === 1 ? 'jb-red' : ($rank === 2 ? 'jb-yellow' : 'b-gray');
|
||||
$top_bagd = '<badge class="img-badge left hot ' . esc_attr($tone) . '"><i>TOP' . (int) $rank . '</i></badge>';
|
||||
}
|
||||
|
||||
echo '<ul class="aksrt-user-ranking">';
|
||||
$rank = 0;
|
||||
foreach ($users as $user) {
|
||||
$rank++;
|
||||
$rank_class = $rank <= 3 ? ' aksrt-user-ranking__item--top' : '';
|
||||
$user_url = function_exists('aksrt_get_user_home_url')
|
||||
? aksrt_get_user_home_url($user['id'])
|
||||
: get_author_posts_url($user['id']);
|
||||
$name_html = function_exists('aksrt_get_user_name')
|
||||
? aksrt_get_user_name([
|
||||
'id' => $uid,
|
||||
'class' => 'flex ac flex1',
|
||||
'follow' => false,
|
||||
'medal' => true,
|
||||
'level' => true,
|
||||
])
|
||||
: '<a class="font-bold" href="' . esc_url($user_url) . '">' . esc_html((string) $user['name']) . '</a>';
|
||||
|
||||
echo '<li class="aksrt-user-ranking__item relative' . esc_attr($rank_class) . '">';
|
||||
$avatar_html = '';
|
||||
if ($show_avatar) {
|
||||
$avatar_url = function_exists('aksrt_get_avatar_url')
|
||||
? aksrt_get_avatar_url($uid, ['size' => 42])
|
||||
: get_avatar_url($uid, ['size' => 42]);
|
||||
$avatar_html = '<a class="avatar-img" href="' . esc_url($user_url) . '"><img class="avatar aksrt-lazy lazyload" data-src="' . esc_url($avatar_url) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" width="36" height="36" /></a>';
|
||||
}
|
||||
|
||||
if ($top_badge && $rank <= 3) {
|
||||
$tone = $rank === 1 ? 'jb-red' : ($rank === 2 ? 'jb-yellow' : 'b-gray');
|
||||
echo '<badge class="img-badge left hot ' . esc_attr($tone) . '"><i>TOP' . (int) $rank . '</i></badge>';
|
||||
}
|
||||
$desc = (string) ($user['desc'] ?? '');
|
||||
$value_label = (string) ($user['value_label'] ?? $user['value'] ?? '');
|
||||
$value_icon = (string) ($user['value_icon'] ?? 'fa-trophy');
|
||||
$right_badge = '<span class="badg" title="' . esc_attr($value_label) . '"><i class="fa ' . esc_attr($value_icon) . '" aria-hidden="true"></i><span class="ml6">' . esc_html((string) ($user['value_num'] ?? $user['value'] ?? '')) . '</span></span>';
|
||||
|
||||
// 排名
|
||||
echo '<span class="aksrt-user-ranking__rank">' . esc_html((string) $rank) . '</span>';
|
||||
$mt = $rank > 1 ? ' mt20' : '';
|
||||
echo '<div class="user-ranking-item aksrt-user-ranking__item relative' . esc_attr($mt) . ($rank <= 3 ? ' is-top' : '') . '">';
|
||||
echo $top_bagd; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="user-info flex ac">';
|
||||
echo $avatar_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '<div class="user-right flex flex1 ac jsb ml10">';
|
||||
echo '<div class="flex1 min-w0">';
|
||||
echo '<div class="font-bold aksrt-user-ranking__name">' . $name_html . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
if ($desc !== '') {
|
||||
echo '<div class="mt3 em09 muted-color text-ellipsis aksrt-user-ranking__desc">' . esc_html($desc) . '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '<div class="ml20 flex0 aksrt-user-ranking__value">' . $right_badge . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo '</div></div></div>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
// 头像
|
||||
if ($show_avatar) {
|
||||
$avatar_url = function_exists('aksrt_get_avatar_url')
|
||||
? aksrt_get_avatar_url($user['id'], ['size' => 36])
|
||||
: get_avatar_url($user['id'], ['size' => 36]);
|
||||
echo '<a href="' . esc_url($user_url) . '" class="aksrt-user-ranking__avatar">';
|
||||
echo '<img src="' . esc_url($avatar_url) . '" alt=""' . (function_exists('aksrt_lazy_loading') ? aksrt_lazy_loading('avatar') : ' loading="lazy"') . ' width="36" height="36">';
|
||||
echo '</a>';
|
||||
}
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
// 昵称 + 可选签名/附加信息
|
||||
echo '<div class="aksrt-user-ranking__meta">';
|
||||
echo '<a href="' . esc_url($user_url) . '" class="aksrt-user-ranking__name">' . esc_html($user['name']) . '</a>';
|
||||
if (!empty($user['desc'])) {
|
||||
echo '<div class="aksrt-user-ranking__desc em09 muted-2-color">' . esc_html((string) $user['desc']) . '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
/**
|
||||
* @return list<array{id:int,name:string,value:string,value_num:string,value_label:string,value_icon:string,desc:string}>
|
||||
*/
|
||||
private function get_ranking(string $rank_by, int $count, string $desc_mode = 'desc'): array {
|
||||
$users = [];
|
||||
|
||||
// 数值
|
||||
echo '<span class="aksrt-user-ranking__value">' . esc_html($user['value']) . '</span>';
|
||||
switch ($rank_by) {
|
||||
case 'credits':
|
||||
global $wpdb;
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT user_id, meta_value as credits FROM {$wpdb->usermeta}
|
||||
WHERE meta_key = 'aksrt_credits'
|
||||
ORDER BY CAST(meta_value AS UNSIGNED) DESC
|
||||
LIMIT %d",
|
||||
$count
|
||||
), ARRAY_A);
|
||||
foreach ((array) $rows as $row) {
|
||||
$user = get_userdata((int) $row['user_id']);
|
||||
if ($user) {
|
||||
$num = (int) $row['credits'];
|
||||
$users[] = [
|
||||
'id' => (int) $row['user_id'],
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n($num) . ' 积分',
|
||||
'value_num' => (string) number_format_i18n($num),
|
||||
'value_label' => sprintf(__('积分:%s', 'aksrt'), number_format_i18n($num)),
|
||||
'value_icon' => 'fa-diamond',
|
||||
'desc' => $this->user_extra_desc((int) $row['user_id'], $user, $desc_mode),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
echo '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
case 'posts':
|
||||
$blog_users = get_users([
|
||||
'number' => $count,
|
||||
'orderby' => 'post_count',
|
||||
'order' => 'DESC',
|
||||
'who' => 'authors',
|
||||
]);
|
||||
foreach ($blog_users as $user) {
|
||||
$post_count = count_user_posts($user->ID, 'post', true);
|
||||
if ($post_count > 0) {
|
||||
$users[] = [
|
||||
'id' => $user->ID,
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n($post_count) . ' 篇',
|
||||
'value_num' => (string) number_format_i18n($post_count),
|
||||
'value_label' => sprintf(__('共%d篇文章', 'aksrt'), $post_count),
|
||||
'value_icon' => 'fa-file-text-o',
|
||||
'desc' => $this->user_extra_desc($user->ID, $user, $desc_mode),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
case 'checkin_all_day':
|
||||
$users = $this->meta_rank('aksrt_checkin_all_day', ['checkin_all_day'], $count, $desc_mode, 'fa-calendar-check-o', __('累计签到%d天', 'aksrt'), ' 天');
|
||||
break;
|
||||
|
||||
private function get_ranking(string $rank_by, int $count, string $desc_mode = 'desc'): array {
|
||||
$users = [];
|
||||
case 'checkin_continuous_day':
|
||||
$users = $this->meta_rank('aksrt_checkin_continuous_day', ['checkin_continuous_day'], $count, $desc_mode, 'fa-calendar-check-o', __('连续签到%d天', 'aksrt'), ' 天');
|
||||
break;
|
||||
|
||||
switch ($rank_by) {
|
||||
case 'credits':
|
||||
global $wpdb;
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT user_id, meta_value as credits FROM {$wpdb->usermeta}
|
||||
WHERE meta_key = 'aksrt_credits'
|
||||
ORDER BY CAST(meta_value AS UNSIGNED) DESC
|
||||
LIMIT %d",
|
||||
$count
|
||||
), ARRAY_A);
|
||||
foreach ((array) $rows as $row) {
|
||||
$user = get_userdata((int) $row['user_id']);
|
||||
if ($user) {
|
||||
$users[] = [
|
||||
'id' => (int) $row['user_id'],
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n((int) $row['credits']) . ' 积分',
|
||||
'desc' => $this->user_extra_desc((int) $row['user_id'], $user, $desc_mode),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'followers':
|
||||
if (class_exists('\AKSRT\User\Follow')) {
|
||||
global $wpdb;
|
||||
$follow_table = \AKSRT\Core\DBMigrator::table('follow');
|
||||
if ($follow_table) {
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT following_id, COUNT(*) as cnt
|
||||
FROM {$follow_table}
|
||||
GROUP BY following_id
|
||||
ORDER BY cnt DESC
|
||||
LIMIT %d",
|
||||
$count
|
||||
), ARRAY_A);
|
||||
foreach ((array) $rows as $row) {
|
||||
$user = get_userdata((int) $row['following_id']);
|
||||
if ($user) {
|
||||
$num = (int) $row['cnt'];
|
||||
$users[] = [
|
||||
'id' => (int) $row['following_id'],
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n($num) . ' 粉丝',
|
||||
'value_num' => (string) number_format_i18n($num),
|
||||
'value_label' => sprintf(__('共%d个粉丝', 'aksrt'), $num),
|
||||
'value_icon' => 'fa-heart',
|
||||
'desc' => $this->user_extra_desc((int) $row['following_id'], $user, $desc_mode),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'posts':
|
||||
$blog_users = get_users([
|
||||
'number' => $count,
|
||||
'orderby' => 'post_count',
|
||||
'order' => 'DESC',
|
||||
'who' => 'authors',
|
||||
]);
|
||||
foreach ($blog_users as $user) {
|
||||
$post_count = count_user_posts($user->ID, 'post', true);
|
||||
if ($post_count > 0) {
|
||||
$users[] = [
|
||||
'id' => $user->ID,
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n($post_count) . ' 篇',
|
||||
'desc' => $this->user_extra_desc($user->ID, $user, $desc_mode),
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
return $users;
|
||||
}
|
||||
|
||||
case 'checkin_all_day':
|
||||
global $wpdb;
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT user_id, meta_value as val FROM {$wpdb->usermeta}
|
||||
WHERE meta_key IN ('aksrt_checkin_all_day','checkin_all_day')
|
||||
ORDER BY CAST(meta_value AS UNSIGNED) DESC
|
||||
LIMIT %d",
|
||||
$count * 2
|
||||
), ARRAY_A);
|
||||
$seen = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$uid = (int) $row['user_id'];
|
||||
if (isset($seen[$uid])) continue;
|
||||
$seen[$uid] = true;
|
||||
$user = get_userdata($uid);
|
||||
if ($user) {
|
||||
$users[] = [
|
||||
'id' => $uid,
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n((int) $row['val']) . ' 天',
|
||||
'desc' => $this->user_extra_desc($uid, $user, $desc_mode),
|
||||
];
|
||||
}
|
||||
if (count($users) >= $count) break;
|
||||
}
|
||||
break;
|
||||
/**
|
||||
* @param list<string> $alt_keys
|
||||
* @return list<array{id:int,name:string,value:string,value_num:string,value_label:string,value_icon:string,desc:string}>
|
||||
*/
|
||||
private function meta_rank(string $primary_key, array $alt_keys, int $count, string $desc_mode, string $icon, string $label_tpl, string $suffix): array {
|
||||
global $wpdb;
|
||||
$keys = array_merge([$primary_key], $alt_keys);
|
||||
$in = implode(',', array_fill(0, count($keys), '%s'));
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$sql = $wpdb->prepare(
|
||||
"SELECT user_id, meta_value as val FROM {$wpdb->usermeta}
|
||||
WHERE meta_key IN ($in)
|
||||
ORDER BY CAST(meta_value AS UNSIGNED) DESC
|
||||
LIMIT %d",
|
||||
...array_merge($keys, [$count * 2])
|
||||
);
|
||||
$rows = $wpdb->get_results($sql, ARRAY_A);
|
||||
$seen = [];
|
||||
$users = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$uid = (int) $row['user_id'];
|
||||
if (isset($seen[$uid])) {
|
||||
continue;
|
||||
}
|
||||
$seen[$uid] = true;
|
||||
$user = get_userdata($uid);
|
||||
if (!$user) {
|
||||
continue;
|
||||
}
|
||||
$num = (int) $row['val'];
|
||||
$users[] = [
|
||||
'id' => $uid,
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n($num) . $suffix,
|
||||
'value_num' => (string) number_format_i18n($num),
|
||||
'value_label' => sprintf($label_tpl, $num),
|
||||
'value_icon' => $icon,
|
||||
'desc' => $this->user_extra_desc($uid, $user, $desc_mode),
|
||||
];
|
||||
if (count($users) >= $count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $users;
|
||||
}
|
||||
|
||||
case 'checkin_continuous_day':
|
||||
global $wpdb;
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT user_id, meta_value as val FROM {$wpdb->usermeta}
|
||||
WHERE meta_key IN ('aksrt_checkin_continuous_day','checkin_continuous_day')
|
||||
ORDER BY CAST(meta_value AS UNSIGNED) DESC
|
||||
LIMIT %d",
|
||||
$count * 2
|
||||
), ARRAY_A);
|
||||
$seen = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$uid = (int) $row['user_id'];
|
||||
if (isset($seen[$uid])) continue;
|
||||
$seen[$uid] = true;
|
||||
$user = get_userdata($uid);
|
||||
if ($user) {
|
||||
$users[] = [
|
||||
'id' => $uid,
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n((int) $row['val']) . ' 天',
|
||||
'desc' => $this->user_extra_desc($uid, $user, $desc_mode),
|
||||
];
|
||||
}
|
||||
if (count($users) >= $count) break;
|
||||
}
|
||||
break;
|
||||
private function user_extra_desc(int $user_id, $user, string $mode): string {
|
||||
switch ($mode) {
|
||||
case 'user_registered':
|
||||
if ($user && !empty($user->user_registered)) {
|
||||
$days = max(0, (int) floor((time() - strtotime($user->user_registered)) / DAY_IN_SECONDS));
|
||||
return sprintf(__('加入 %d 天', 'aksrt'), $days);
|
||||
}
|
||||
return '';
|
||||
case 'last_login':
|
||||
$t = (string) get_user_meta($user_id, 'aksrt_last_login', true);
|
||||
if ($t === '') {
|
||||
$t = (string) get_user_meta($user_id, 'last_login', true);
|
||||
}
|
||||
return $t !== '' ? sprintf(__('最近登录 %s', 'aksrt'), $t) : '';
|
||||
case 'last_checkin':
|
||||
$t = (string) get_user_meta($user_id, 'aksrt_last_checkin', true);
|
||||
if ($t === '') {
|
||||
$t = (string) get_user_meta($user_id, 'last_checkin', true);
|
||||
}
|
||||
return $t !== '' ? sprintf(__('最近签到 %s', 'aksrt'), $t) : '';
|
||||
case 'desc':
|
||||
default:
|
||||
$bio = get_user_meta($user_id, 'description', true);
|
||||
if (!is_string($bio) || $bio === '') {
|
||||
$bio = $user ? (string) $user->description : '';
|
||||
}
|
||||
return $bio !== '' ? wp_trim_words($bio, 12) : '';
|
||||
}
|
||||
}
|
||||
|
||||
case 'followers':
|
||||
if (class_exists('\AKSRT\User\Follow')) {
|
||||
global $wpdb;
|
||||
$follow_table = \AKSRT\Core\DBMigrator::table('follow');
|
||||
if ($follow_table) {
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT following_id, COUNT(*) as cnt
|
||||
FROM {$follow_table}
|
||||
GROUP BY following_id
|
||||
ORDER BY cnt DESC
|
||||
LIMIT %d",
|
||||
$count
|
||||
), ARRAY_A);
|
||||
foreach ((array) $rows as $row) {
|
||||
$user = get_userdata((int) $row['following_id']);
|
||||
if ($user) {
|
||||
$users[] = [
|
||||
'id' => (int) $row['following_id'],
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n((int) $row['cnt']) . ' 粉丝',
|
||||
'desc' => $this->user_extra_desc((int) $row['following_id'], $user, $desc_mode),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
public function form($instance): void {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : __('排行榜', 'aksrt');
|
||||
$rank_by = !empty($instance['rank_by']) ? $instance['rank_by'] : 'credits';
|
||||
$count = !empty($instance['count']) ? (int) $instance['count'] : 5;
|
||||
$show_avatar = !isset($instance['show_avatar']) || !empty($instance['show_avatar']);
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php esc_html_e('标题:', 'aksrt'); ?></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); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('rank_by')); ?>"><?php esc_html_e('排行依据:', 'aksrt'); ?></label>
|
||||
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('rank_by')); ?>" name="<?php echo esc_attr($this->get_field_name('rank_by')); ?>">
|
||||
<option value="credits" <?php selected($rank_by, 'credits'); ?>><?php esc_html_e('积分', 'aksrt'); ?></option>
|
||||
<option value="posts" <?php selected($rank_by, 'posts'); ?>><?php esc_html_e('文章数', 'aksrt'); ?></option>
|
||||
<option value="followers" <?php selected($rank_by, 'followers'); ?>><?php esc_html_e('粉丝数', 'aksrt'); ?></option>
|
||||
<option value="checkin_all_day" <?php selected($rank_by, 'checkin_all_day'); ?>><?php esc_html_e('累计签到', 'aksrt'); ?></option>
|
||||
<option value="checkin_continuous_day" <?php selected($rank_by, 'checkin_continuous_day'); ?>><?php esc_html_e('连续签到', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('count')); ?>"><?php esc_html_e('显示数量:', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('count')); ?>" name="<?php echo esc_attr($this->get_field_name('count')); ?>" type="number" value="<?php echo esc_attr((string) $count); ?>" min="1" max="20">
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_avatar')); ?>" name="<?php echo esc_attr($this->get_field_name('show_avatar')); ?>" value="1" <?php checked($show_avatar); ?>>
|
||||
<?php esc_html_e('显示头像', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('desc')); ?>"><?php esc_html_e('附加显示:', 'aksrt'); ?></label>
|
||||
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('desc')); ?>" name="<?php echo esc_attr($this->get_field_name('desc')); ?>">
|
||||
<option value="desc" <?php selected(($instance['desc'] ?? 'desc'), 'desc'); ?>><?php esc_html_e('用户签名', 'aksrt'); ?></option>
|
||||
<option value="user_registered" <?php selected(($instance['desc'] ?? ''), 'user_registered'); ?>><?php esc_html_e('加入天数', 'aksrt'); ?></option>
|
||||
<option value="last_login" <?php selected(($instance['desc'] ?? ''), 'last_login'); ?>><?php esc_html_e('最后登录', 'aksrt'); ?></option>
|
||||
<option value="last_checkin" <?php selected(($instance['desc'] ?? ''), 'last_checkin'); ?>><?php esc_html_e('最后签到', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" name="<?php echo esc_attr($this->get_field_name('checkin_btn')); ?>" value="1" <?php checked(!empty($instance['checkin_btn'])); ?>>
|
||||
<?php esc_html_e('顶部显示签到按钮', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" name="<?php echo esc_attr($this->get_field_name('top_badge')); ?>" value="1" <?php checked(!empty($instance['top_badge'])); ?>>
|
||||
<?php esc_html_e('前三名 TOP 角标', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
|
||||
private function user_extra_desc(int $user_id, $user, string $mode): string {
|
||||
switch ($mode) {
|
||||
case 'user_registered':
|
||||
if ($user && !empty($user->user_registered)) {
|
||||
$days = max(0, (int) floor((time() - strtotime($user->user_registered)) / DAY_IN_SECONDS));
|
||||
return sprintf(__('加入 %d 天', 'aksrt'), $days);
|
||||
}
|
||||
return '';
|
||||
case 'last_login':
|
||||
$t = (string) get_user_meta($user_id, 'aksrt_last_login', true);
|
||||
if ($t === '') {
|
||||
$t = (string) get_user_meta($user_id, 'last_login', true);
|
||||
}
|
||||
return $t !== '' ? sprintf(__('最近登录 %s', 'aksrt'), $t) : '';
|
||||
case 'last_checkin':
|
||||
$t = (string) get_user_meta($user_id, 'aksrt_last_checkin', true);
|
||||
if ($t === '') {
|
||||
$t = (string) get_user_meta($user_id, 'last_checkin', true);
|
||||
}
|
||||
return $t !== '' ? sprintf(__('最近签到 %s', 'aksrt'), $t) : '';
|
||||
case 'desc':
|
||||
default:
|
||||
$bio = get_user_meta($user_id, 'description', true);
|
||||
if (!is_string($bio) || $bio === '') {
|
||||
$bio = $user ? (string) $user->description : '';
|
||||
}
|
||||
return $bio !== '' ? wp_trim_words($bio, 12) : '';
|
||||
}
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : __('排行榜', 'aksrt');
|
||||
$rank_by = !empty($instance['rank_by']) ? $instance['rank_by'] : 'credits';
|
||||
$count = !empty($instance['count']) ? (int) $instance['count'] : 5;
|
||||
$show_avatar = !empty($instance['show_avatar']);
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php esc_html_e('标题:', 'aksrt'); ?></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); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('rank_by')); ?>"><?php esc_html_e('排行依据:', 'aksrt'); ?></label>
|
||||
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('rank_by')); ?>" name="<?php echo esc_attr($this->get_field_name('rank_by')); ?>">
|
||||
<option value="credits" <?php selected($rank_by, 'credits'); ?>><?php esc_html_e('积分', 'aksrt'); ?></option>
|
||||
<option value="posts" <?php selected($rank_by, 'posts'); ?>><?php esc_html_e('文章数', 'aksrt'); ?></option>
|
||||
<option value="followers" <?php selected($rank_by, 'followers'); ?>><?php esc_html_e('粉丝数', 'aksrt'); ?></option>
|
||||
<option value="checkin_all_day" <?php selected($rank_by, 'checkin_all_day'); ?>><?php esc_html_e('累计签到', 'aksrt'); ?></option>
|
||||
<option value="checkin_continuous_day" <?php selected($rank_by, 'checkin_continuous_day'); ?>><?php esc_html_e('连续签到', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('count')); ?>"><?php esc_html_e('显示数量:', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('count')); ?>" name="<?php echo esc_attr($this->get_field_name('count')); ?>" type="number" value="<?php echo esc_attr((string) $count); ?>" min="1" max="20">
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_avatar')); ?>" name="<?php echo esc_attr($this->get_field_name('show_avatar')); ?>" value="1" <?php checked($show_avatar); ?>>
|
||||
<?php esc_html_e('显示头像', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('desc')); ?>"><?php esc_html_e('附加显示:', 'aksrt'); ?></label>
|
||||
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('desc')); ?>" name="<?php echo esc_attr($this->get_field_name('desc')); ?>">
|
||||
<option value="desc" <?php selected(($instance['desc'] ?? 'desc'), 'desc'); ?>><?php esc_html_e('用户签名', 'aksrt'); ?></option>
|
||||
<option value="user_registered" <?php selected(($instance['desc'] ?? ''), 'user_registered'); ?>><?php esc_html_e('加入天数', 'aksrt'); ?></option>
|
||||
<option value="last_login" <?php selected(($instance['desc'] ?? ''), 'last_login'); ?>><?php esc_html_e('最后登录', 'aksrt'); ?></option>
|
||||
<option value="last_checkin" <?php selected(($instance['desc'] ?? ''), 'last_checkin'); ?>><?php esc_html_e('最后签到', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" name="<?php echo esc_attr($this->get_field_name('checkin_btn')); ?>" value="1" <?php checked(!empty($instance['checkin_btn'])); ?>>
|
||||
<?php esc_html_e('顶部显示签到按钮', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" name="<?php echo esc_attr($this->get_field_name('top_badge')); ?>" value="1" <?php checked(!empty($instance['top_badge'])); ?>>
|
||||
<?php esc_html_e('前三名 TOP 角标', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$instance = [];
|
||||
$instance['title'] = sanitize_text_field($new_instance['title'] ?? '');
|
||||
$instance['rank_by'] = in_array($new_instance['rank_by'] ?? '', ['credits', 'posts', 'followers', 'checkin_all_day', 'checkin_continuous_day'], true) ? $new_instance['rank_by'] : 'credits';
|
||||
$instance['count'] = max(1, min(20, (int) ($new_instance['count'] ?? 5)));
|
||||
$instance['show_avatar'] = !empty($new_instance['show_avatar']);
|
||||
$instance['checkin_btn'] = !empty($new_instance['checkin_btn']);
|
||||
$instance['top_badge'] = !empty($new_instance['top_badge']);
|
||||
$instance['desc'] = in_array($new_instance['desc'] ?? '', ['desc', 'user_registered', 'last_login', 'last_checkin'], true) ? $new_instance['desc'] : 'desc';
|
||||
return $instance;
|
||||
}
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$instance = [];
|
||||
$instance['title'] = sanitize_text_field($new_instance['title'] ?? '');
|
||||
$instance['rank_by'] = in_array($new_instance['rank_by'] ?? '', ['credits', 'posts', 'followers', 'checkin_all_day', 'checkin_continuous_day'], true) ? $new_instance['rank_by'] : 'credits';
|
||||
$instance['count'] = max(1, min(20, (int) ($new_instance['count'] ?? 5)));
|
||||
$instance['show_avatar'] = !empty($new_instance['show_avatar']) ? 1 : 0;
|
||||
$instance['checkin_btn'] = !empty($new_instance['checkin_btn']) ? 1 : 0;
|
||||
$instance['top_badge'] = !empty($new_instance['top_badge']) ? 1 : 0;
|
||||
$instance['desc'] = in_array($new_instance['desc'] ?? '', ['desc', 'user_registered', 'last_login', 'last_checkin'], true) ? $new_instance['desc'] : 'desc';
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user