Files
wordpress-theme-aksrt/src/AKSRT/Widgets/WidgetOnelinePosts.php
T
kate522 a770ff2591 feat(widgets): comments CPT, tag scale, oneline filters + CSS
RecentComments uses aksrt_forum_topic/product + lazy avatars; TagCloud
scale works; OnelinePosts topics/pay_type; batch34-36 residual CSS.
2026-07-21 12:16:57 +08:00

283 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
/**
* Horizontal one-line posts scroller (zibll zib_widget_ui_oneline_posts).
*
* Uses shared post renderer + slider.js Type A (.swiper-scroll).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
defined('ABSPATH') || exit;
class WidgetOnelinePosts extends \WP_Widget {
public function __construct() {
parent::__construct(
'aksrt_oneline_posts',
esc_html__('AKSRT 横向文章', 'aksrt'),
[
'description' => esc_html__('横向滚动的文章卡片/迷你列表(共享 swiper-scroll)。', 'aksrt'),
'classname' => 'widget_aksrt_oneline_posts',
]
);
}
/**
* @param array<string,mixed> $instance
* @return array<string,mixed>
*/
public static function build_query_args(array $instance): array {
$count = max(1, min(20, (int) ($instance['count'] ?? 8)));
$orderby = sanitize_key((string) ($instance['orderby'] ?? 'date'));
$cat = (int) ($instance['cat'] ?? 0);
$limit_day = max(0, (int) ($instance['limit_day'] ?? 0));
$query = [
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => $count,
'ignore_sticky_posts' => true,
'no_found_rows' => true,
];
if ($cat > 0) {
$query['cat'] = $cat;
}
if ($limit_day > 0) {
$query['date_query'] = [['after' => $limit_day . ' days ago']];
}
switch ($orderby) {
case 'views':
$query['meta_key'] = 'aksrt_post_views';
$query['orderby'] = 'meta_value_num';
$query['order'] = 'DESC';
break;
case 'comments':
$query['orderby'] = 'comment_count';
$query['order'] = 'DESC';
break;
case 'rand':
$query['orderby'] = 'rand';
break;
default:
$query['orderby'] = 'date';
$query['order'] = 'DESC';
}
$topics_raw = trim((string) ($instance['topics'] ?? ''));
if ($topics_raw !== '' && taxonomy_exists('topics')) {
$topic_ids = array_values(array_filter(array_map('intval', preg_split('/[,,\s]+/', $topics_raw) ?: [])));
if ($topic_ids) {
$query['tax_query'] = [[
'taxonomy' => 'topics',
'field' => 'term_id',
'terms' => $topic_ids,
]];
}
}
$pay_type = sanitize_key((string) ($instance['pay_type'] ?? ''));
if ($pay_type !== '' && $pay_type !== '0' && $pay_type !== 'no') {
if ($pay_type === 'any' || $pay_type === 'paid') {
$query['meta_query'] = [
'relation' => 'OR',
['key' => '_aksrt_pay_price', 'value' => 0, 'compare' => '>', 'type' => 'NUMERIC'],
['key' => '_aksrt_pay_type', 'value' => ['reading', 'download', 'gallery', 'video', 'vip'], 'compare' => 'IN'],
['key' => '_aksrt_visibility', 'value' => ['pay', 'credits'], 'compare' => 'IN'],
];
} else {
$query['meta_query'] = [['key' => '_aksrt_pay_type', 'value' => $pay_type]];
}
}
return $query;
}
/**
* @param array<string,mixed> $instance
*/
public static function render_html(array $instance): string {
$style = sanitize_key((string) ($instance['style'] ?? 'card'));
if (!in_array($style, ['card', 'mini', 'list'], true)) {
$style = 'card';
}
$q = new \WP_Query(self::build_query_args($instance));
if (!$q->have_posts()) {
wp_reset_postdata();
return function_exists('aksrt_get_ajax_null')
? aksrt_get_ajax_null(__('暂无文章', 'aksrt'))
: '<p class="widget-empty ajax-item">' . esc_html__('暂无文章', 'aksrt') . '</p>';
}
$mode = $style === 'mini' ? 'mini' : ($style === 'list' ? 'list' : 'card');
$cfg = [
'mode' => $mode,
'context' => 'widget',
'show_thumb' => true,
'show_meta' => $style !== 'mini',
'show_excerpt' => false,
'show_author' => false,
'show_comments' => false,
'show_likes' => false,
'show_tags' => false,
'show_badges' => $style === 'card',
'skip_wrapper' => true,
'extra_class' => 'posts-item',
];
$slides = '';
if (function_exists('aksrt_render_post')) {
while ($q->have_posts()) {
$q->the_post();
$item = aksrt_render_post($cfg);
if ($item === '') {
continue;
}
// Ensure freeMode width calc has a posts-item root when renderer wraps differently.
if (strpos($item, 'posts-item') === false && strpos($item, 'posts-mini') === false) {
$item = '<div class="posts-item">' . $item . '</div>';
}
$slides .= '<div class="swiper-slide ajax-item">' . $item . '</div>';
}
wp_reset_postdata();
} else {
// Fallback: bare thumb+title (should rarely hit).
while ($q->have_posts()) {
$q->the_post();
$thumb = get_the_post_thumbnail_url(get_the_ID(), $style === 'card' ? 'medium' : 'thumbnail');
$slides .= '<div class="swiper-slide ajax-item"><a class="posts-item aksrt-oneline-fallback" href="' . esc_url(get_permalink()) . '">';
if ($thumb) {
$slides .= '<div class="item-thumbnail"><img src="' . esc_url($thumb) . '" alt="" loading="lazy" /></div>';
}
$slides .= '<div class="item-body"><div class="item-heading">' . esc_html(get_the_title()) . '</div></div></a></div>';
}
wp_reset_postdata();
}
if ($slides === '') {
return function_exists('aksrt_get_ajax_null')
? aksrt_get_ajax_null(__('暂无文章', 'aksrt'))
: '<p class="widget-empty ajax-item">' . esc_html__('暂无文章', 'aksrt') . '</p>';
}
// zibll: .widget-main-post.style-{card|mini|list} + .swiper-container.swiper-scroll data-slideClass="posts-item".
ob_start();
echo '<div class="widget-main-post style-' . esc_attr($style) . ' aksrt-oneline-posts ajax-item">';
echo '<div class="swiper-container swiper-scroll aksrt-oneline-swiper" data-slideClass="posts-item">';
echo '<div class="swiper-wrapper">';
echo $slides; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</div>';
echo '<div class="swiper-button-prev" aria-label="' . esc_attr__('上一页', 'aksrt') . '"></div>';
echo '<div class="swiper-button-next" aria-label="' . esc_attr__('下一页', 'aksrt') . '"></div>';
echo '</div></div>';
return (string) ob_get_clean();
}
/**
* @param array<string,mixed> $args
* @param array<string,mixed> $instance
*/
public function widget($args, $instance): void {
$html = self::render_html($instance);
if ($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
}
$rest = rest_url('aksrt/v1/widgets/oneline-posts');
echo '<div class="ajaxpager" data-aksrt-ajaxpager data-aksrt-ajax-url="' . esc_url($rest) . '">';
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* @param array<string,mixed> $instance
*/
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'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('数量', 'aksrt'); ?>
<input class="tiny-text" type="number" min="1" max="20" name="<?php echo esc_attr($this->get_field_name('count')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['count'] ?? 8))); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('样式', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('style')); ?>">
<option value="card" <?php selected(($instance['style'] ?? 'card'), 'card'); ?>><?php esc_html_e('卡片', 'aksrt'); ?></option>
<option value="mini" <?php selected(($instance['style'] ?? ''), 'mini'); ?>><?php esc_html_e('迷你', 'aksrt'); ?></option>
<option value="list" <?php selected(($instance['style'] ?? ''), 'list'); ?>><?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('orderby')); ?>">
<option value="date" <?php selected(($instance['orderby'] ?? 'date'), 'date'); ?>><?php esc_html_e('时间', 'aksrt'); ?></option>
<option value="views" <?php selected(($instance['orderby'] ?? ''), 'views'); ?>><?php esc_html_e('浏览', 'aksrt'); ?></option>
<option value="comments" <?php selected(($instance['orderby'] ?? ''), 'comments'); ?>><?php esc_html_e('评论', 'aksrt'); ?></option>
<option value="rand" <?php selected(($instance['orderby'] ?? ''), 'rand'); ?>><?php esc_html_e('随机', 'aksrt'); ?></option>
</select>
</label>
</p>
<p>
<label><?php esc_html_e('分类 ID(0=全部)', 'aksrt'); ?>
<input class="tiny-text" type="number" min="0" name="<?php echo esc_attr($this->get_field_name('cat')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['cat'] ?? 0))); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('限制最近 N 天(0=不限)', 'aksrt'); ?>
<input class="tiny-text" type="number" min="0" name="<?php echo esc_attr($this->get_field_name('limit_day')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['limit_day'] ?? 0))); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('专题 topics ID(逗号)', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('topics')); ?>" value="<?php echo esc_attr((string) ($instance['topics'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('付费类型', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('pay_type')); ?>">
<option value="" <?php selected(($instance['pay_type'] ?? ''), ''); ?>><?php esc_html_e('不限', 'aksrt'); ?></option>
<option value="paid" <?php selected(($instance['pay_type'] ?? ''), 'paid'); ?>><?php esc_html_e('任意付费', 'aksrt'); ?></option>
<option value="reading" <?php selected(($instance['pay_type'] ?? ''), 'reading'); ?>><?php esc_html_e('付费阅读', 'aksrt'); ?></option>
<option value="download" <?php selected(($instance['pay_type'] ?? ''), 'download'); ?>><?php esc_html_e('付费下载', 'aksrt'); ?></option>
</select>
</label>
</p>
<?php
}
/**
* @param array<string,mixed> $new_instance
* @param array<string,mixed> $old_instance
* @return array<string,mixed>
*/
public function update($new_instance, $old_instance): array {
$style = sanitize_key((string) ($new_instance['style'] ?? 'card'));
if (!in_array($style, ['card', 'mini', 'list'], true)) {
$style = 'card';
}
$orderby = sanitize_key((string) ($new_instance['orderby'] ?? 'date'));
if (!in_array($orderby, ['date', 'views', 'comments', 'rand'], true)) {
$orderby = 'date';
}
return [
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'count' => max(1, min(20, (int) ($new_instance['count'] ?? 8))),
'style' => $style,
'orderby' => $orderby,
'cat' => max(0, (int) ($new_instance['cat'] ?? 0)),
'limit_day' => max(0, (int) ($new_instance['limit_day'] ?? 0)),
'topics' => sanitize_text_field((string) ($new_instance['topics'] ?? '')),
'pay_type' => sanitize_key((string) ($new_instance['pay_type'] ?? '')),
];
}
}