Files
wordpress-theme-aksrt/src/AKSRT/Widgets/WidgetForumPlateLists.php
T
kate522 80991d8347 fix(widgets): strip remaining decorative forum/oneline ajaxpagers
Board list, plate lists, topic terms and oneline posts no longer wrap
static SSR in inert ajaxpager attributes without a real pager.
2026-07-21 13:13:07 +08:00

280 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Forum plate list (zibll zib_bbs_widget_ui_plate_lists + ajax).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
defined('ABSPATH') || exit;
class WidgetForumPlateLists extends \WP_Widget {
public function __construct() {
parent::__construct(
'aksrt_forum_plate_lists',
esc_html__('论坛 - 版块列表(Plate)', 'aksrt'),
[
'description' => esc_html__('展示论坛 plate 版块列表,支持排序/卡片/AJAX。', 'aksrt'),
'classname' => 'widget_aksrt_forum_plate_lists',
]
);
}
/**
* @return array
*/
public static function build_query_args(array $instance): array {
$limit = max(1, min(30, (int) ($instance['showposts'] ?? 8)));
$orderby = sanitize_key((string) ($instance['orderby'] ?? 'menu_order'));
$filter = sanitize_key((string) ($instance['filter'] ?? ''));
$cat_raw = (string) ($instance['cat'] ?? '');
$cat_ids = array_values(array_filter(array_map('intval', preg_split('/[\s,]+/', $cat_raw) ?: [])));
$query_args = [
'post_type' => 'aksrt_forum_plate',
'post_status' => 'publish',
'posts_per_page' => $limit,
'order' => 'ASC',
'no_found_rows' => true,
];
switch ($orderby) {
case 'date':
$query_args['orderby'] = 'date';
$query_args['order'] = 'DESC';
break;
case 'posts':
$query_args['meta_key'] = '_aksrt_posts_count';
$query_args['orderby'] = 'meta_value_num';
$query_args['order'] = 'DESC';
break;
case 'views':
$query_args['meta_key'] = '_aksrt_views';
$query_args['orderby'] = 'meta_value_num';
$query_args['order'] = 'DESC';
break;
case 'follow':
$query_args['meta_key'] = '_aksrt_follow_count';
$query_args['orderby'] = 'meta_value_num';
$query_args['order'] = 'DESC';
break;
default:
$query_args['orderby'] = 'menu_order title';
}
if ($cat_ids) {
$query_args['tax_query'] = [[
'taxonomy' => 'aksrt_plate_cat',
'field' => 'term_id',
'terms' => $cat_ids,
]];
}
if ($filter === 'is_hot') {
$query_args['meta_query'] = [[
'key' => '_aksrt_is_hot',
'value' => '1',
'compare' => '=',
]];
}
return $query_args;
}
public static function render_items_html(array $plates, string $style = 'default'): string {
if (!$plates) {
return '';
}
ob_start();
if ($style === 'card') {
echo '<div class="panel-plate scroll-plate aksrt-plate-cards">';
foreach ($plates as $post) {
if ($post instanceof \WP_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="plate-lists aksrt-plate-lists">';
foreach ($plates as $post) {
if ($post instanceof \WP_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>';
}
return (string) ob_get_clean();
}
/**
* @return array{html:string}
*/
public static function query_payload(array $instance): array {
if (!post_type_exists('aksrt_forum_plate')) {
return ['html' => ''];
}
$style = sanitize_key((string) ($instance['style'] ?? 'default'));
$plates = get_posts(self::build_query_args($instance));
$html = self::render_items_html($plates ?: [], $style === 'card' ? 'card' : 'default');
if ($html === '') {
$html = function_exists('aksrt_get_ajax_null')
? aksrt_get_ajax_null(__('暂无版块', 'aksrt'))
: '<p class="aksrt-plate-empty ajax-item">' . esc_html__('暂无版块', 'aksrt') . '</p>';
}
return ['html' => $html];
}
public function widget($args, $instance): void {
if (!post_type_exists('aksrt_forum_plate')) {
return;
}
$style = sanitize_key((string) ($instance['style'] ?? 'default'));
$payload = self::query_payload($instance);
if ($payload['html'] === '') {
return;
}
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
if ($title !== '') {
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
echo '<div class="widget-plate-lists mb20">';
echo $payload['html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
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="plate-item flex aksrt-plate-item" href="' . esc_url($url) . '">';
echo '<div class="plate-thumb aksrt-plate-item__thumb">';
if ($thumb) {
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="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 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="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>';
echo '</div></a>';
}
public function form($instance): void {
?>
<p>
<label><?php esc_html_e('标题', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? __('版块列表', 'aksrt'))); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('数量', 'aksrt'); ?>
<input class="tiny-text" type="number" min="1" max="30" name="<?php echo esc_attr($this->get_field_name('showposts')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['showposts'] ?? 8))); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('排序', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('orderby')); ?>">
<option value="menu_order" <?php selected(($instance['orderby'] ?? 'menu_order'), 'menu_order'); ?>><?php esc_html_e('菜单顺序', 'aksrt'); ?></option>
<option value="date" <?php selected(($instance['orderby'] ?? ''), 'date'); ?>><?php esc_html_e('创建时间', 'aksrt'); ?></option>
<option value="posts" <?php selected(($instance['orderby'] ?? ''), 'posts'); ?>><?php esc_html_e('帖子数', 'aksrt'); ?></option>
<option value="views" <?php selected(($instance['orderby'] ?? ''), 'views'); ?>><?php esc_html_e('浏览量', 'aksrt'); ?></option>
<option value="follow" <?php selected(($instance['orderby'] ?? ''), 'follow'); ?>><?php esc_html_e('关注数', 'aksrt'); ?></option>
</select>
</label>
</p>
<p>
<label><?php esc_html_e('样式', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('style')); ?>">
<option value="default" <?php selected(($instance['style'] ?? 'default'), 'default'); ?>><?php esc_html_e('列表', 'aksrt'); ?></option>
<option value="card" <?php selected(($instance['style'] ?? ''), 'card'); ?>><?php esc_html_e('卡片', 'aksrt'); ?></option>
</select>
</label>
</p>
<p>
<label><?php esc_html_e('筛选', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('filter')); ?>">
<option value="" <?php selected(($instance['filter'] ?? ''), ''); ?>><?php esc_html_e('全部', 'aksrt'); ?></option>
<option value="is_hot" <?php selected(($instance['filter'] ?? ''), 'is_hot'); ?>><?php esc_html_e('仅热门', 'aksrt'); ?></option>
</select>
</label>
</p>
<p>
<label><?php esc_html_e('版块分类 term ID(逗号)', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('cat')); ?>" value="<?php echo esc_attr((string) ($instance['cat'] ?? '')); ?>">
</label>
</p>
<?php
}
public function update($new_instance, $old_instance): array {
$orderby = sanitize_key((string) ($new_instance['orderby'] ?? 'menu_order'));
if (!in_array($orderby, ['menu_order', 'date', 'posts', 'views', 'follow'], true)) {
$orderby = 'menu_order';
}
return [
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'showposts' => max(1, min(30, (int) ($new_instance['showposts'] ?? 8))),
'orderby' => $orderby,
'style' => ($new_instance['style'] ?? '') === 'card' ? 'card' : 'default',
'filter' => ($new_instance['filter'] ?? '') === 'is_hot' ? 'is_hot' : '',
'cat' => sanitize_text_field((string) ($new_instance['cat'] ?? '')),
];
}
}