id_base = $id_base; } } class WP_Query { public array $posts = []; public int $found_posts = 0; public int $max_num_pages = 1; private int $cursor = 0; public function __construct(array $args = []) { $rows = array_values(array_filter($GLOBALS['tab_fixture_posts'], static function (array $post) use ($args): bool { $include = array_map('intval', (array) ($args['category__in'] ?? [])); $exclude = array_map('intval', (array) ($args['category__not_in'] ?? [])); foreach (array_filter(explode(',', (string) ($args['cat'] ?? ''))) as $cat) { if ((int) $cat > 0) $include[] = (int) $cat; if ((int) $cat < 0) $exclude[] = abs((int) $cat); } return (!$include || in_array($post['cat'], $include, true)) && !in_array($post['cat'], $exclude, true); })); $orderby = (string) ($args['orderby'] ?? 'date'); $order = strtoupper((string) ($args['order'] ?? 'DESC')) === 'ASC' ? 1 : -1; if ($orderby === 'rand') { usort($rows, static fn(array $a, array $b): int => $a['id'] <=> $b['id']); } else { usort($rows, static fn(array $a, array $b): int => $order * ($a[$orderby] <=> $b[$orderby])); } $this->found_posts = count($rows); $per_page = max(1, (int) ($args['posts_per_page'] ?? 6)); $this->max_num_pages = (int) ceil($this->found_posts / $per_page); $page = max(1, (int) ($args['paged'] ?? 1)); $this->posts = array_map(static fn(array $post): WP_Post => new WP_Post((int) $post['id']), array_slice($rows, ($page - 1) * $per_page, $per_page)); } public function have_posts(): bool { return $this->cursor < count($this->posts); } public function the_post(): void { $GLOBALS['tab_fixture_current_post'] = $this->posts[$this->cursor++]; $GLOBALS['post'] = $GLOBALS['tab_fixture_current_post']; } } } namespace AKSRT\Settings { final class Settings { public static function get_post_list_style_settings(): array { return $GLOBALS['tab_fixture_global_style'] ?? []; } public static function get_post_thumb_settings(): array { return ['thumb_catimg_s' => false]; } public static function get_post_page_settings(): array { return ['like_enabled' => true]; } public static function get_comment_display_settings(): array { return ['close_comments' => false]; } public static function get_paid_content_settings(): array { return $GLOBALS['tab_fixture_paid_settings'] ?? ['display' => ['currency_symbol' => '¥']]; } public static function get_payment_vip_settings(): array { return $GLOBALS['tab_fixture_vip_settings'] ?? ['levels' => []]; } } } namespace { $GLOBALS['tab_fixture_posts'] = []; foreach (range(1, 70) as $id) { $category = $id <= 36 ? 7 : ($id <= 48 ? 8 : 9); $GLOBALS['tab_fixture_posts'][] = ['id' => $id, 'cat' => $category, 'date' => 1000 + $id, 'modified' => 2000 + $id, 'views' => 71 - $id]; } $GLOBALS['tab_fixture_current_post'] = null; $GLOBALS['tab_fixture_global_style'] = []; $GLOBALS['tab_fixture_mobile'] = false; $GLOBALS['tab_fixture_avatar_calls'] = []; $GLOBALS['tab_fixture_pay_meta'] = []; $GLOBALS['tab_fixture_paid_settings'] = ['display' => ['currency_symbol' => '¥']]; $GLOBALS['tab_fixture_vip_settings'] = [ 'enabled' => true, 'levels' => [ 1 => ['enabled' => true, 'name' => '黄金会员', 'img_icon' => 'https://example.test/vip-1.svg'], 2 => ['enabled' => true, 'name' => '钻石会员', 'img_icon' => 'https://example.test/vip-2.svg'], ], ]; function __($text, $domain = null): string { return (string) $text; } function esc_html__($text, $domain = null): string { return esc_html((string) $text); } function esc_attr__($text, $domain = null): string { return esc_attr((string) $text); } function esc_html($value): string { return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } function esc_attr($value): string { return esc_html($value); } function esc_url($value): string { return esc_attr($value); } function esc_url_raw($value): string { return (string) $value; } function wp_kses_post($value): string { return strip_tags((string) $value, '

'); } function wp_kses($value, array $allowed): string { unset($allowed); return (string) $value; } function wp_parse_args($args, array $defaults = []): array { return array_merge($defaults, is_array($args) ? $args : []); } function sanitize_key($value): string { return preg_replace('/[^a-z0-9_-]/', '', strtolower((string) $value)) ?? ''; } function sanitize_html_class($value): string { return preg_replace('/[^A-Za-z0-9_-]/', '', (string) $value) ?? ''; } function sanitize_text_field($value): string { return trim(strip_tags((string) $value)); } function sanitize_textarea_field($value): string { return trim(strip_tags((string) $value)); } function absint($value): int { return abs((int) $value); } function wp_strip_all_tags($value): string { return trim(strip_tags((string) $value)); } function wp_trim_words($value, int $num_words = 55, string $more = '...'): string { return implode(' ', array_slice(preg_split('/\s+/', trim((string) $value)) ?: [], 0, $num_words)) . $more; } function wp_is_mobile(): bool { return (bool) $GLOBALS['tab_fixture_mobile']; } function aksrt_is_show_sidebar(): bool { return true; } function is_category(): bool { return false; } function is_search(): bool { return false; } function is_home(): bool { return false; } function is_front_page(): bool { return false; } function is_author(): bool { return true; } function is_tag(): bool { return false; } function get_the_ID(): int { return (int) ($GLOBALS['tab_fixture_current_post']->ID ?? 0); } function strip_shortcodes(string $value): string { return $value; } function get_the_category(int $id = 0): array { unset($id); return []; } function get_the_tags(int $id = 0): array { unset($id); return []; } function get_the_excerpt(int $id = 0): string { unset($id); return '首页通用文章列表的长摘要,这里只用于卡片和列表样式的内容渲染'; } function get_post_field(string $field, int $id = 0, string $context = 'display'): string { unset($id, $context); if ($field === 'post_author') return '5'; if ($field === 'post_content') return ''; return 'article body'; } function get_userdata(int $id): WP_User { return new WP_User($id); } function get_avatar_url(int $id, array $args = []): string { unset($args); return 'https://example.test/avatar/' . $id . '.png'; } function aksrt_get_avatar_box($subject, string $class = 'avatar-img', bool $link = true, bool $vip = true): string { $user_id = is_numeric($subject) ? (int) $subject : 0; $GLOBALS['tab_fixture_avatar_calls'][] = ['user_id' => $user_id, 'class' => $class, 'link' => $link, 'vip' => $vip]; $inner = 'VIP'; return $link && $user_id > 0 ? '' . $inner . '' : $inner; } function get_the_time(string $format = '', $post = null): string { unset($post); return $format === 'U' ? '1000' : '2026-01-01 00:00:00'; } function get_the_modified_time(string $format = '', $post = null): string { unset($post); return $format === 'U' ? '2000' : '2026-02-01 00:00:00'; } function current_time(string $type): int { unset($type); return 3000; } function human_time_diff(int $from, int $to): string { unset($to); return $from === strtotime('2026-01-01 00:00:00') ? '发布' : '修改'; } function get_permalink(int $id = 0): string { return 'https://example.test/post/' . $id; } function get_the_title(int $id = 0): string { return '真实文章 ' . $id; } function get_post_thumbnail_id(int $id = 0): int { return $id; } function get_post_meta(int $id, string $key = '', bool $single = false) { unset($id, $key, $single); return []; } function wp_get_attachment_image_url(int $id, string $size = 'medium'): string { unset($size); return 'https://example.test/image/' . $id . '.jpg'; } function attachment_url_to_postid(string $url): int { unset($url); return 0; } function get_post_format(int $id = 0): string|false { unset($id); return false; } function has_post_format($format, int $id = 0): bool { unset($format, $id); return false; } function get_comments_number(int $id = 0): int { return $id; } function comments_open(int $id = 0): bool { unset($id); return true; } function get_comments_link(int $id = 0): string { return 'https://example.test/post/' . $id . '#comments'; } function get_post_type(int $id = 0): string { unset($id); return 'post'; } function is_sticky(int $id = 0): bool { unset($id); return false; } function aksrt_resource_card_badge_text(int $id): string { return isset($GLOBALS['tab_fixture_pay_meta'][$id]) ? '旧版资源标签' : ''; } function aksrt_get_pay_meta($post = null): array { $post_id = $post instanceof WP_Post ? $post->ID : (int) $post; return $GLOBALS['tab_fixture_pay_meta'][$post_id] ?? ['pay_type' => 'no']; } function aksrt_get_pay_types(): array { return ['reading' => '付费阅读', 'download' => '付费下载', 'gallery' => '付费图片', 'video' => '付费视频']; } function aksrt_format_price($price): string { $value = number_format((float) $price, 2, '.', ''); return rtrim(rtrim($value, '0'), '.') ?: '0'; } function aksrt_get_post_views(int $id): int { return $id * 10; } function aksrt_get_post_likes(int $id): int { return $id * 2; } function aksrt_format_number(int $number): string { return (string) $number; } function aksrt_get_lazy_thumb(string $size = ''): string { unset($size); return 'https://example.test/placeholder.jpg'; } function aksrt_get_lazy_attr(string $key, string $url, string $class = '', string $lazy = ''): string { unset($key, $lazy); return ' class="' . esc_attr($class) . '" src="' . esc_url($url) . '"'; } function wp_reset_postdata(): void { $GLOBALS['tab_fixture_current_post'] = null; $GLOBALS['post'] = null; } function aksrt_widget_ajax_null(string $message = ''): string { return '

' . esc_html($message) . '
'; } function aksrt_render_placeholder(string $style, int $count): string { return '
'; } function get_template_directory(): string { return dirname(__DIR__, 2); } function get_template_directory_uri(): string { return 'https://example.test/theme'; } function rest_url(string $path): string { return 'https://example.test/wp-json/' . $path; } function wp_register_style(string $handle, string $src = '', array $deps = [], $version = false): bool { return true; } function wp_register_script(string $handle, string $src = '', array $deps = [], $version = false, $in_footer = false): bool { return true; } function wp_enqueue_style(string $handle): void {} function wp_enqueue_script(string $handle): void {} function wp_add_inline_script(string $handle, string $data, string $position = 'after'): void {} function wp_json_encode($value): string { return json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR); } require dirname(__DIR__, 2) . '/vendor/autoload.php'; require dirname(__DIR__, 2) . '/inc/helpers/aksrt-icons.php'; require dirname(__DIR__, 2) . '/inc/helpers/posts-renderer/config.php'; require dirname(__DIR__, 2) . '/inc/helpers/posts-renderer/post-data.php'; require dirname(__DIR__, 2) . '/inc/helpers/posts-renderer/markup.php'; $GLOBALS['tab_fixture_global_style'] = ['list_type' => 'card', 'list_show_type' => 'no_margin', 'list_list_option' => ['style' => 'style2'], 'list_card_option' => ['style' => 'style3'], 'list_orderby' => 'date', 'post_time_source' => 'modified', 'post_list_author' => true, 'post_list_time' => true]; $GLOBALS['tab_fixture_pay_meta'] = [ 70 => ['pay_type' => 'reading', 'pay_modo' => '0', 'price' => '12.50', 'points_price' => 0, 'pay_limit' => 0], 69 => ['pay_type' => 'download', 'pay_modo' => '0', 'price' => '12.00', 'points_price' => 0, 'pay_limit' => 0], 68 => ['pay_type' => 'gallery', 'pay_modo' => '0', 'price' => '8.60', 'points_price' => 0, 'pay_limit' => 0], 67 => ['pay_type' => 'video', 'pay_modo' => '0', 'price' => '5.00', 'points_price' => 0, 'pay_limit' => 0], 66 => ['pay_type' => 'reading', 'pay_modo' => '0', 'price' => '0.00', 'points_price' => 0, 'pay_limit' => 0], 65 => ['pay_type' => 'download', 'pay_modo' => '0', 'price' => '0.00', 'points_price' => 0, 'pay_limit' => 0], 64 => ['pay_type' => 'gallery', 'pay_modo' => 'points', 'price' => '0.00', 'points_price' => 0, 'pay_limit' => 0], 63 => ['pay_type' => 'video', 'pay_modo' => '0', 'price' => '0.00', 'points_price' => 0, 'pay_limit' => 1], 62 => ['pay_type' => 'reading', 'pay_modo' => 'points', 'price' => '0.00', 'points_price' => 125, 'pay_limit' => 0], 61 => ['pay_type' => 'download', 'pay_modo' => 'points', 'price' => '0.00', 'points_price' => 60, 'pay_limit' => 0], 60 => ['pay_type' => 'gallery', 'pay_modo' => 'points', 'price' => '0.00', 'points_price' => 500, 'pay_limit' => 0], 59 => ['pay_type' => 'video', 'pay_modo' => 'points', 'price' => '0.00', 'points_price' => 12, 'pay_limit' => 0], 58 => ['pay_type' => 'reading', 'pay_modo' => '0', 'price' => '12.50', 'points_price' => 0, 'pay_limit' => 1], 57 => ['pay_type' => 'download', 'pay_modo' => '0', 'price' => '12.50', 'points_price' => 0, 'pay_limit' => 2], 56 => ['pay_type' => 'gallery', 'pay_modo' => '0', 'price' => '8.75', 'points_price' => 0, 'pay_limit' => 1], 55 => ['pay_type' => 'reading', 'pay_modo' => '0', 'price' => '0.50', 'points_price' => 0, 'pay_limit' => 0], 54 => ['pay_type' => 'download', 'pay_modo' => '0', 'price' => '0.50', 'points_price' => 0, 'pay_limit' => 0], 53 => ['pay_type' => 'gallery', 'pay_modo' => '0', 'price' => '0.50', 'points_price' => 0, 'pay_limit' => 0], 52 => ['pay_type' => 'video', 'pay_modo' => '0', 'price' => '0.50', 'points_price' => 0, 'pay_limit' => 0], 51 => ['pay_type' => 'no', 'pay_modo' => '0', 'price' => '0.00', 'points_price' => 0, 'pay_limit' => 0], ]; $tabs = [ ['title' => '热门', 'cat' => '7', 'orderby' => 'date'], ['title' => '', 'cat' => '7'], ['title' => '最近', 'cat' => '8', 'orderby' => 'modified'], ]; $cases = []; $list_instance = []; foreach (['default', 'invalid', 'mini', 'list', 'card'] as $name) { $GLOBALS['tab_fixture_global_style']['list_type'] = $name === 'list' ? 'text' : 'card'; $instance = ['count' => 4, 'paginate' => 'number', 'mini_opt' => [], 'tabs' => $tabs]; if ($name === 'mini' || $name === 'list' || $name === 'card') $instance['style'] = $name; if ($name === 'invalid') $instance['style'] = 'unknown'; if ($name === 'default' || $name === 'invalid') { $cases['raw_' . $name] = [ 'tab_markup' => \AKSRT\WidgetSystem\Renderers\ContentRenderer::render('tab_posts', $instance, ['widget_id' => 'aksrt_widget_tab_posts-4']), 'first' => \AKSRT\WidgetSystem\PostRenderer::payload($instance, 'tab_posts', 1, '0')['html'], ]; } $instance = \AKSRT\WidgetSystem\FieldSchema::normalize(\AKSRT\WidgetSystem\WidgetSchemas::for('tab_posts'), $instance); if ($name === 'list') $list_instance = $instance; $avatar_start = count($GLOBALS['tab_fixture_avatar_calls']); $first_page = \AKSRT\WidgetSystem\PostRenderer::payload($instance, 'tab_posts', 1, '0'); $second_page = \AKSRT\WidgetSystem\PostRenderer::payload($instance, 'tab_posts', 2, '0'); $cases[$name] = [ 'instance_style' => $instance['style'], 'tab_markup' => \AKSRT\WidgetSystem\Renderers\ContentRenderer::render('tab_posts', $instance, ['widget_id' => 'aksrt_widget_tab_posts-4']), 'first' => $first_page['html'], 'second' => $second_page['html'], 'pagination' => $first_page['paginate_html'], 'last_pagination' => \AKSRT\WidgetSystem\PostRenderer::payload($instance, 'tab_posts', 9, '0')['paginate_html'], 'avatar_calls' => array_slice($GLOBALS['tab_fixture_avatar_calls'], $avatar_start), ]; } $mini_instance = ['style' => 'mini', 'mini_opt' => ['show_thumb', 'show_number', 'show_meta'], 'count' => 4, 'paginate' => 'number', 'tabs' => $tabs]; $mini_instance = \AKSRT\WidgetSystem\FieldSchema::normalize(\AKSRT\WidgetSystem\WidgetSchemas::for('tab_posts'), $mini_instance); $avatar_start = count($GLOBALS['tab_fixture_avatar_calls']); $mini_first = \AKSRT\WidgetSystem\PostRenderer::payload($mini_instance, 'tab_posts', 1, '0')['html']; $mini_second = \AKSRT\WidgetSystem\PostRenderer::payload($mini_instance, 'tab_posts', 2, '0')['html']; $cases['mini_all_options'] = [ 'first' => $mini_first, 'second' => $mini_second, 'avatar_calls' => array_slice($GLOBALS['tab_fixture_avatar_calls'], $avatar_start), ]; $cases['no_pagination_page'] = \AKSRT\WidgetSystem\PostRenderer::payload(array_merge($mini_instance, ['paginate' => '']), 'tab_posts', 2, '0'); foreach (['list', 'card', 'mini'] as $posts_style) { $posts_definition = \AKSRT\WidgetSystem\WidgetRegistry::get('posts'); foreach (['detail', 'ajax'] as $load_mode) { $posts_instance = $posts_definition->normalize(['style' => $posts_style, 'load_mode' => $load_mode, 'count' => 4, 'paginate' => 'number', 'title' => '文章列表']); $cases['posts_' . $posts_style . '_' . $load_mode] = \AKSRT\WidgetSystem\Renderers\ContentRenderer::render('posts', $posts_instance, ['widget_id' => 'aksrt_widget_posts-3']); } } $GLOBALS['tab_fixture_global_style']['post_list_author'] = false; $mini_time_instance = ['style' => 'mini', 'mini_opt' => ['show_meta'], 'count' => 4, 'paginate' => '', 'tabs' => $tabs]; $mini_time_instance = \AKSRT\WidgetSystem\FieldSchema::normalize(\AKSRT\WidgetSystem\WidgetSchemas::for('tab_posts'), $mini_time_instance); $cases['mini_time_source'] = ['html' => \AKSRT\WidgetSystem\PostRenderer::payload($mini_time_instance, 'tab_posts', 1, '0')['html']]; $GLOBALS['tab_fixture_global_style']['post_list_author'] = true; $ajax_instance = $instance; $ajax_instance['style'] = 'mini'; $ajax_instance['paginate'] = 'ajax'; $ajax_instance = \AKSRT\WidgetSystem\FieldSchema::normalize(\AKSRT\WidgetSystem\WidgetSchemas::for('tab_posts'), $ajax_instance); $cases['ajax_pagination'] = [ 'first' => \AKSRT\WidgetSystem\PostRenderer::payload($ajax_instance, 'tab_posts', 1, '0')['paginate_html'], 'last' => \AKSRT\WidgetSystem\PostRenderer::payload($ajax_instance, 'tab_posts', 9, '0')['paginate_html'], ]; $GLOBALS['tab_fixture_mobile'] = true; $cases['mobile_pagination'] = [ 'middle' => \AKSRT\WidgetSystem\PostRenderer::payload($list_instance, 'tab_posts', 5, '0')['paginate_html'], 'last' => \AKSRT\WidgetSystem\PostRenderer::payload($list_instance, 'tab_posts', 9, '0')['paginate_html'], ]; $GLOBALS['tab_fixture_mobile'] = false; $cases['context_margins'] = [ 'implicit' => \aksrt_renderer_config(['type' => 'list'])['no_margin'], 'explicit_false' => \aksrt_renderer_config(['type' => 'list', 'no_margin' => false])['no_margin'], ]; $definition = \AKSRT\WidgetSystem\WidgetRegistry::get('tab_posts'); $widget = new \AKSRT\WidgetSystem\SchemaWidget($definition); $widget->id = 'aksrt_widget_tab_posts-4'; $wrapper_instance = \AKSRT\WidgetSystem\FieldSchema::normalize($definition->fields(), [ 'title' => '参考标题', 'layout_pin_pc' => ['top' => 8, 'right' => 6, 'bottom' => 18, 'left' => 4], 'layout_pin_m' => ['top' => 3, 'right' => 2, 'bottom' => 10, 'left' => 2], 'layout_bg' => [ 'light' => ['color' => '#ffffff', 'image' => 'https://example.test/light.jpg'], 'dark' => ['color' => '#111111', 'image' => 'https://example.test/dark.jpg'], ], 'tabs' => $tabs, ]); ob_start(); \AKSRT\WidgetSystem\FrontendRenderer::render($definition, ['before_widget' => ''], $wrapper_instance, $widget); $cases['frontend_wrapper'] = (string) ob_get_clean(); $paid_instance = \AKSRT\WidgetSystem\FieldSchema::normalize(\AKSRT\WidgetSystem\WidgetSchemas::for('tab_posts'), [ 'style' => 'mini', 'mini_opt' => ['show_meta'], 'count' => 20, 'paginate' => '', 'tabs' => [['title' => '付费徽标用例', 'cat' => '9']], ]); $cases['pay_meta_right'] = \AKSRT\WidgetSystem\PostRenderer::payload($paid_instance, 'tab_posts', 1, '0')['html']; $paid_instance['mini_opt'] = []; $cases['pay_meta_hidden'] = \AKSRT\WidgetSystem\PostRenderer::payload($paid_instance, 'tab_posts', 1, '0')['html']; $paid_instance['mini_opt'] = ['show_meta']; $GLOBALS['tab_fixture_global_style']['post_list_author'] = false; $GLOBALS['tab_fixture_global_style']['post_list_time'] = false; $cases['pay_meta_left'] = \AKSRT\WidgetSystem\PostRenderer::payload($paid_instance, 'tab_posts', 1, '0')['html']; $GLOBALS['tab_fixture_global_style']['post_list_author'] = true; $GLOBALS['tab_fixture_global_style']['post_list_time'] = true; $GLOBALS['tab_fixture_paid_settings']['display']['currency_symbol'] = '€'; $cases['pay_meta_custom_currency'] = \AKSRT\WidgetSystem\PostRenderer::payload($paid_instance, 'tab_posts', 1, '0')['html']; $GLOBALS['tab_fixture_paid_settings']['display']['currency_symbol'] = '¥'; $GLOBALS['tab_fixture_vip_settings'] = [ 'enabled' => true, 'levels' => [ 1 => ['enabled' => true, 'name' => '黄金会员', 'img_icon' => 'https://example.test/vip-1.svg'], 2 => ['enabled' => false, 'name' => '钻石会员', 'img_icon' => 'https://example.test/vip-2.svg'], ], ]; $cases['pay_vip1_only'] = \AKSRT\WidgetSystem\PostRenderer::payload($paid_instance, 'tab_posts', 1, '0')['html']; $GLOBALS['tab_fixture_vip_settings'] = [ 'enabled' => true, 'levels' => [ 1 => ['enabled' => false, 'name' => '黄金会员', 'img_icon' => 'https://example.test/vip-1.svg'], 2 => ['enabled' => true, 'name' => '钻石会员', 'img_icon' => 'https://example.test/vip-2.svg'], ], ]; $cases['pay_vip2_only'] = \AKSRT\WidgetSystem\PostRenderer::payload($paid_instance, 'tab_posts', 1, '0')['html']; $GLOBALS['tab_fixture_vip_settings'] = [ 'enabled' => false, 'levels' => [ 1 => ['enabled' => false, 'name' => '黄金会员', 'img_icon' => 'https://example.test/vip-1.svg'], 2 => ['enabled' => false, 'name' => '钻石会员', 'img_icon' => 'https://example.test/vip-2.svg'], ], ]; $cases['pay_vip_disabled'] = \AKSRT\WidgetSystem\PostRenderer::payload($paid_instance, 'tab_posts', 1, '0')['html']; $cases['pay_empty'] = aksrt_renderer_compact_pay_badge([]); echo json_encode(['cases' => $cases], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR); }