The theme was renamed Zibll/子比 → AKSRT → Jio, but upstream branding survived the sweeps in CSS classes, the SVG sprite prefix, a persisted widget field ID, JS events, admin Vue class names, test infrastructure and docblocks. Renames: - zib-widget / zib-widget-wrap / zib-slider → jio-widget-box / jio-widget-box-wrap / jio-slider-box (jio-widget is taken by the modern widget shell, jio-box-* by the card primitives) - zib-partners-scroll + zps-* → jio-partners-scroll + jps-* - zib-combo-info-card + zci-* → jio-combo-info-card + jci-* - zibsvg- → jiosvg-, including the exported picker helpers and the fa-zibsvg- family-prefix guard - zibpay_type → pay_type; the dual-read fallback in PostQuery collapses to a single key - [zibajax="submit"] dropped (no PHP emitter); zib_ajax.success → jio_ajax.success - aks-* admin Vue classes → jio-* - zib_palette() → palette() User-facing vendor traces are gone: the floating "more" button default no longer ships a zibll.com link or 子比主题 marketing copy, the notice widget ships no preset promo entries, and the four 官网教程 links are removed from the post-list admin schema. Test infrastructure renamed to neutral names (docker-compose.reference.yml, Caddyfile, article-baseline.json, modern-widgets-contract.test.cjs) with their DB/volume/env/slug identifiers following. Kept intentionally, documented in tests/fixtures/README.md: the golden fixture reference fingerprint (a SHA-256 record of an external directory, read by validate-widget-golden / generate-widget-golden-fixture / audit-widget-system), the doesNotMatch guards that prove the old tokens are gone, and the reference theme's own meta key in the visual fixtures. No backward-compat or data migration: saved widget configs holding old icon keys or the old field ID silently lose them, per the project's rewrite-over-compatibility rule. Verified: 132/132 node contract tests, php tests/widget-system/run.php (146 assertions), audit-admin-contracts, audit-psr4-paths and validate-widget-golden all green; tracked bundles regenerated and in sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
316 lines
16 KiB
PHP
316 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* legacy 9.0 article-list data and markup fragments.
|
|
*
|
|
* @package Jio
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
if (!function_exists('jio_renderer_collect_post_data')) {
|
|
/** @return array<string,mixed> */
|
|
function jio_renderer_collect_post_data(array $cfg): array {
|
|
$post_id = (int) get_the_ID();
|
|
if ($post_id <= 0) {
|
|
return [];
|
|
}
|
|
|
|
$images = jio_renderer_resolve_images($post_id, $cfg);
|
|
$categories = get_the_category($post_id) ?: [];
|
|
$tags = get_the_tags($post_id) ?: [];
|
|
$content_images = (array) $images['gallery'];
|
|
$gallery = array_slice($content_images, 0, 4);
|
|
$allow_conditional = !empty($cfg['allow_conditional_layout']) && ($cfg['mode'] ?? 'list') === 'list';
|
|
$is_mult_thumb = false;
|
|
$is_no_thumb = false;
|
|
|
|
if ($allow_conditional) {
|
|
if (($cfg['is_no_thumb'] ?? false) !== 'disable'
|
|
&& (($cfg['list_type'] ?? 'thumb') === 'text'
|
|
|| (($cfg['list_type'] ?? 'thumb') === 'thumb_if_has' && empty($images['has_real'])))) {
|
|
$is_no_thumb = true;
|
|
} elseif (($cfg['is_mult_thumb'] ?? false) !== 'disable' && count($gallery) > 2) {
|
|
$is_mult_thumb = has_post_format(['image', 'gallery'], $post_id);
|
|
if (!$is_mult_thumb) {
|
|
foreach ($categories as $category) {
|
|
if (in_array((int) $category->term_id, array_map('intval', (array) ($cfg['mult_thumb_cat'] ?? [])), true)) {
|
|
$is_mult_thumb = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (($cfg['is_no_thumb'] ?? false) === true) {
|
|
$is_no_thumb = true;
|
|
$is_mult_thumb = false;
|
|
}
|
|
if (($cfg['is_mult_thumb'] ?? false) === true && count($gallery) > 2 && !$is_no_thumb) {
|
|
$is_mult_thumb = true;
|
|
}
|
|
|
|
$excerpt = (string) get_the_excerpt($post_id);
|
|
if ($excerpt === '') {
|
|
$excerpt = (string) get_post_field('post_content', $post_id, 'raw');
|
|
}
|
|
$author_id = (int) get_post_field('post_author', $post_id);
|
|
$author = get_userdata($author_id);
|
|
$time_value = ($cfg['time_source'] ?? 'modified') === 'date'
|
|
? (string) get_the_time('Y-m-d H:i:s', $post_id)
|
|
: (string) get_the_modified_time('Y-m-d H:i:s', $post_id);
|
|
$time_timestamp = strtotime($time_value) ?: (int) get_the_time('U', $post_id);
|
|
|
|
$subtitle = class_exists('\Jio\Core\PostMetaBox')
|
|
? (string) \Jio\Core\PostMetaBox::get_meta_value($post_id, 'subtitle', '')
|
|
: '';
|
|
$pay_meta = jio_get_pay_meta($post_id);
|
|
if (!is_array($pay_meta)) {
|
|
$pay_meta = [];
|
|
}
|
|
|
|
return [
|
|
'post_id' => $post_id,
|
|
'permalink' => get_permalink($post_id),
|
|
'title' => get_the_title($post_id),
|
|
'subtitle' => $subtitle,
|
|
'excerpt' => wp_trim_words(wp_strip_all_tags($excerpt), 30, '...'),
|
|
'primary' => (string) $images['primary'],
|
|
'has_real' => !empty($images['has_real']),
|
|
'gallery' => $gallery,
|
|
'gallery_count' => count($content_images),
|
|
'slides' => (array) $images['slides'],
|
|
'is_slide' => !empty($images['is_slide']),
|
|
'video_url' => (string) $images['video_url'],
|
|
'is_mult_thumb' => $is_mult_thumb,
|
|
'is_no_thumb' => $is_no_thumb,
|
|
'categories' => $categories,
|
|
'tags' => $tags,
|
|
'author_id' => $author_id,
|
|
'author_name' => $author instanceof WP_User ? $author->display_name : '',
|
|
'time_title' => $time_value,
|
|
'time_ago' => human_time_diff($time_timestamp, current_time('timestamp')) . __('前', 'jio'),
|
|
'views' => (int) jio_get_post_views($post_id),
|
|
'likes' => (int) jio_get_post_likes($post_id),
|
|
'comments' => (int) get_comments_number($post_id),
|
|
'comments_open' => comments_open($post_id),
|
|
'comments_link' => get_comments_link($post_id),
|
|
'post_type' => (string) get_post_type($post_id),
|
|
'is_sticky' => is_sticky($post_id),
|
|
'resource_badge' => (string) jio_resource_card_badge_text($post_id),
|
|
'pay_meta' => $pay_meta,
|
|
'pay_type' => sanitize_key((string) ($pay_meta['pay_type'] ?? 'no')),
|
|
'pay_limit' => (int) ($pay_meta['pay_limit'] ?? 0),
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_thumb')) {
|
|
function jio_renderer_thumb(array $data, array $cfg): string {
|
|
if (!empty($data['is_no_thumb']) || (string) $data['primary'] === '') {
|
|
return '';
|
|
}
|
|
$is_contain = (($cfg['thumb']['list_thumb_fit'] ?? '') === 'contain');
|
|
$target = !empty($cfg['target_blank']) ? ' target="_blank"' : '';
|
|
$content = '';
|
|
$format_icon = '';
|
|
$default_attr = empty($data['has_real']) ? ' data-thumb="default"' : '';
|
|
$has_video_thumb = (string) $data['video_url'] !== '' && !empty($cfg['thumb']['list_thumb_video_s']);
|
|
$has_slides = !$has_video_thumb && !empty($data['is_slide']) && count((array) $data['slides']) > 0;
|
|
|
|
if ($has_video_thumb) {
|
|
$muted = !empty($cfg['thumb']['list_thumb_video_mute_s']);
|
|
$content .= '<div class="video-thumb-box" video-url="' . esc_url((string) $data['video_url']) . '" data-volume="' . ($muted ? 'none' : '100') . '">';
|
|
$content .= '<div class="img-thumb"><img' . $default_attr . jio_get_lazy_attr('lazy_posts_thumb', (string) $data['primary'], 'fit-cover radius8') . ' alt="' . esc_attr((string) $data['title']) . '"></div>';
|
|
$content .= '<div class="video-thumb"></div></div>';
|
|
$format_icon = '<i class="fa fas fa-play-circle em12 mt6 c-white opacity8" aria-hidden="true"></i>';
|
|
} elseif ($has_slides) {
|
|
$single_slide = count((array) $data['slides']) === 1;
|
|
$slide_image_class = 'radius8' . (jio_is_lazy('lazy_sider') ? ' swiper-lazy' : '');
|
|
$content .= '<div class="relative jio-slider"><div class="new-swiper item-thumbnail' . ($is_contain ? ' gradient-background' : '') . ($single_slide ? ' swiper-container-initialized' : '') . '" data-loop="true" data-effect="slide" data-autoplay="1" data-interval="4000"><div class="swiper-wrapper">';
|
|
foreach ((array) $data['slides'] as $image) {
|
|
$content .= '<div class="swiper-slide' . ($is_contain ? ' gradient-bg' : '') . '"' . ($is_contain ? ' data-opacity="0.2"' : '') . '><a' . $target . ' href="' . esc_url((string) $data['permalink']) . '"><img' . jio_get_lazy_attr('lazy_sider', (string) $image, $slide_image_class) . ' alt="' . esc_attr((string) $data['title']) . '"></a></div>';
|
|
}
|
|
$content .= '</div>' . ($single_slide ? '' : '<div class="swiper-pagination kaoyou"></div>') . '</div></div>';
|
|
$format_icon = '<badge class="b-black opacity8 mt6"><i class="fa fas fa-image mr3" aria-hidden="true"></i>' . count((array) $data['slides']) . '</badge>';
|
|
} else {
|
|
$content .= '<a' . $target . ' href="' . esc_url((string) $data['permalink']) . '"><img' . $default_attr . jio_get_lazy_attr('lazy_posts_thumb', (string) $data['primary'], 'fit-cover radius8') . ' alt="' . esc_attr((string) $data['title']) . '"></a>';
|
|
$format = get_post_format((int) $data['post_id']);
|
|
if ((string) $data['video_url'] !== '') {
|
|
$format_icon = '<i class="fa fas fa-play-circle em12 mt6 c-white opacity8" aria-hidden="true"></i>';
|
|
} elseif (in_array($format, ['image', 'gallery'], true) && (int) $data['gallery_count'] > 0) {
|
|
$format_icon = '<badge class="b-black opacity8 mr6 mt6"><i class="fa fas fa-image mr3" aria-hidden="true"></i>' . (int) $data['gallery_count'] . '</badge>';
|
|
} elseif ($format === 'video') {
|
|
$format_icon = '<i class="fa fas fa-play-circle em12 mr6 mt6 c-white opacity8" aria-hidden="true"></i>';
|
|
}
|
|
}
|
|
|
|
if ($format_icon !== '') {
|
|
$content .= '<div class="abs-center right-top">' . $format_icon . '</div>';
|
|
}
|
|
if (!empty($data['is_sticky'])) {
|
|
$content .= '<badge class="img-badge left jb-red">' . esc_html__('置顶', 'jio') . '</badge>';
|
|
}
|
|
|
|
$fit = $is_contain && !$has_slides ? ' contain gradient-bg' : '';
|
|
$opacity = $is_contain && !$has_slides ? ' data-opacity="0.2"' : '';
|
|
return '<div class="item-thumbnail' . $fit . '"' . $opacity . '>' . $content . '</div>';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_mult_thumb')) {
|
|
function jio_renderer_mult_thumb(array $data, array $cfg): string {
|
|
if (empty($data['is_mult_thumb'])) {
|
|
return '';
|
|
}
|
|
$fit = (($cfg['thumb']['list_thumb_fit'] ?? '') === 'contain') ? ' contain' : '';
|
|
$target = !empty($cfg['target_blank']) ? ' target="_blank"' : '';
|
|
$html = '<a' . $target . ' class="thumb-items' . $fit . '" href="' . esc_url((string) $data['permalink']) . '">';
|
|
foreach (array_slice((array) $data['gallery'], 0, 4) as $index => $image) {
|
|
$badge = '';
|
|
if ($index === 3 && (int) ($data['gallery_count'] ?? 0) > 4) {
|
|
$badge = '<div class="abs-center right-top"><badge class="b-black mr6 mt6 em09"><i class="fa fas fa-image mr3" aria-hidden="true"></i>+' . ((int) $data['gallery_count'] - 4) . '</badge></div>';
|
|
}
|
|
$html .= '<span>' . $badge . '<img' . jio_get_lazy_attr('lazy_posts_thumb', (string) $image, 'fit-cover radius8') . ' alt=""></span>';
|
|
}
|
|
return $html . '</a>';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_pay_badge')) {
|
|
function jio_renderer_pay_badge(array $data, bool $compact = false): string {
|
|
if ($compact) {
|
|
return jio_renderer_compact_pay_badge((array) ($data['pay_meta'] ?? []));
|
|
}
|
|
if ((string) $data['resource_badge'] === '') {
|
|
return '';
|
|
}
|
|
$is_vip = (int) ($data['pay_limit'] ?? 0) > 0 || (string) ($data['pay_type'] ?? '') === 'vip';
|
|
$vip_level = max(1, min(2, (int) ($data['pay_limit'] ?? 1)));
|
|
$class = $is_vip ? 'jb-vip' . $vip_level : 'c-yellow';
|
|
$type_labels = function_exists('jio_get_pay_types') ? jio_get_pay_types() : [];
|
|
$title = (string) ($type_labels[(string) ($data['pay_type'] ?? '')] ?? __('付费内容', 'jio'));
|
|
$icon = $is_vip ? jio_renderer_vip_icon($vip_level) : '';
|
|
$tooltip = $is_vip ? ' data-toggle="tooltip" title="' . esc_attr($title) . '"' : '';
|
|
return '<a rel="nofollow" href="' . esc_url((string) $data['permalink']) . '#posts-pay"' . $tooltip . ' class="meta-pay but ' . esc_attr($is_vip ? $class : 'jb-yellow') . '">' . $icon . esc_html((string) $data['resource_badge']) . '</a>';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_compact_pay_badge')) {
|
|
/** Compact article meta uses the published price and a type icon, not the large tag's text. */
|
|
function jio_renderer_compact_pay_badge(array $meta): string {
|
|
$types = [
|
|
'reading' => [__('付费阅读', 'jio'), 'fa fas fa-book'],
|
|
'download' => [__('付费资源', 'jio'), 'fa fas fa-download'],
|
|
'gallery' => [__('付费图片', 'jio'), 'fa far fa-file-image'],
|
|
'video' => [__('付费视频', 'jio'), 'fa fas fa-play-circle'],
|
|
];
|
|
$type = (string) ($meta['pay_type'] ?? 'no');
|
|
if (!isset($types[$type])) {
|
|
return '';
|
|
}
|
|
[$title, $type_icon] = $types[$type];
|
|
$points = ($meta['pay_modo'] ?? '0') === 'points';
|
|
$price = $points ? (string) max(0, (int) ($meta['points_price'] ?? 0)) : jio_format_price((string) ($meta['price'] ?? '0.00'));
|
|
$icon = jio_icon_markup($type_icon, 'mr3');
|
|
$class = 'c-yellow';
|
|
if ($price === '0') {
|
|
$title = str_replace(__('付费', 'jio'), __('免费', 'jio'), $title);
|
|
$label = esc_html__('免费', 'jio');
|
|
} else {
|
|
$level = max(0, min(2, (int) ($meta['pay_limit'] ?? 0)));
|
|
$vip = \Jio\Settings\Settings::get_payment_vip_settings();
|
|
if ($level > 0 && !empty($vip['enabled'])) {
|
|
$class = 'jb-vip' . $level;
|
|
$icon = jio_renderer_vip_icon($level);
|
|
$label = esc_html__('会员专属', 'jio');
|
|
} else {
|
|
$display = \Jio\Settings\Settings::get_paid_content_settings()['display'];
|
|
$mark = $points ? jio_icon_markup('jiosvg-points', 'points-mark') : esc_html((string) ($display['currency_symbol'] ?? '¥'));
|
|
$label = '<span class="em09">' . $mark . '</span>' . esc_html($price);
|
|
}
|
|
}
|
|
return '<item class="meta-pay badg badg-sm mr6 ' . esc_attr($class) . '" data-toggle="tooltip" title="' . esc_attr($title) . '">' . $icon . $label . '</item>';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_vip_icon')) {
|
|
function jio_renderer_vip_icon(int $level): string {
|
|
$settings = \Jio\Settings\Settings::get_payment_vip_settings();
|
|
$url = (string) ($settings['levels'][$level]['img_icon'] ?? '');
|
|
if ($url === '') {
|
|
$url = get_template_directory_uri() . '/assets/img/user/vip/vip-' . $level . '.svg';
|
|
}
|
|
$name = (string) ($settings['levels'][$level]['name'] ?? 'VIP');
|
|
return '<img' . jio_get_lazy_attr('lazy_other', $url, 'img-icon mr3') . ' data-toggle="tooltip" title="' . esc_attr($name) . '" alt="' . esc_attr($name) . '">';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_badges')) {
|
|
function jio_renderer_badges(array $data, array $cfg): string {
|
|
$items = [];
|
|
$types = (array) ($cfg['badge_types'] ?? []);
|
|
if (in_array('pay', $types, true)) {
|
|
$pay = jio_renderer_pay_badge($data);
|
|
if ($pay !== '') {
|
|
$items[] = $pay;
|
|
}
|
|
}
|
|
if (empty($cfg['is_category']) && in_array('cat', $types, true)) {
|
|
$colors = ['c-blue', 'c-yellow', 'c-green', 'c-purple', 'c-red'];
|
|
foreach (array_slice((array) $data['categories'], 0, 3) as $index => $category) {
|
|
$items[] = '<a class="but ' . esc_attr($colors[$index % count($colors)]) . '" title="' . esc_attr__('查看更多分类文章', 'jio') . '" href="' . esc_url(get_category_link($category->term_id)) . '"><i class="fa fas fa-folder-open" aria-hidden="true"></i>' . esc_html($category->name) . '</a>';
|
|
}
|
|
}
|
|
if (empty($cfg['is_tag']) && in_array('tag', $types, true)) {
|
|
$tags = (array) $data['tags'];
|
|
usort($tags, static fn($left, $right): int => (int) $right->count <=> (int) $left->count);
|
|
foreach (array_slice($tags, 0, 3) as $tag) {
|
|
$items[] = '<a class="but" title="' . esc_attr__('查看此标签更多文章', 'jio') . '" href="' . esc_url(get_tag_link($tag->term_id)) . '"># ' . esc_html($tag->name) . '</a>';
|
|
}
|
|
}
|
|
return $items ? '<div class="item-tags scroll-x no-scrollbar mb6">' . implode('', $items) . '</div>' : '';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_meta_number')) {
|
|
function jio_renderer_meta_number(int $number): string {
|
|
return (string) jio_format_number($number);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_svg_icon')) {
|
|
function jio_renderer_svg_icon(string $name): string {
|
|
return jio_icon_markup('jiosvg-' . $name);
|
|
}
|
|
}
|
|
|
|
if (!function_exists('jio_renderer_meta')) {
|
|
function jio_renderer_meta(array $data, array $cfg, bool $is_card = false): string {
|
|
$show_time = !empty($cfg['show_time']);
|
|
$meta_left = '';
|
|
if (empty($cfg['no_author']) && !empty($cfg['show_author'])) {
|
|
$name = (!$is_card || !$show_time) && (string) $data['author_name'] !== ''
|
|
? '<span class="' . ($show_time ? 'hide-sm ' : '') . 'ml6">' . esc_html((string) $data['author_name']) . '</span>'
|
|
: '';
|
|
$time = $show_time
|
|
? '<span title="' . esc_attr((string) $data['time_title']) . '" class="' . ($is_card ? 'ml6' : 'icon-circle') . '">' . esc_html((string) $data['time_ago']) . '</span>'
|
|
: '';
|
|
$avatar = jio_get_avatar_box((int) $data['author_id'], 'avatar-mini');
|
|
$meta_left = '<item class="meta-author flex ac">' . $avatar . $name . $time . '</item>';
|
|
} elseif ($show_time) {
|
|
$meta_left = '<item title="' . esc_attr((string) $data['time_title']) . '" class="icon-circle mln3">' . esc_html((string) $data['time_ago']) . '</item>';
|
|
}
|
|
|
|
$right = '';
|
|
if (!empty($data['comments_open']) && empty($cfg['close_comments'])) {
|
|
$right .= '<item class="meta-comm"><a rel="nofollow" data-toggle="tooltip" title="' . esc_attr__('去评论', 'jio') . '" href="' . esc_url((string) $data['comments_link']) . '">' . jio_renderer_svg_icon('comment') . esc_html(jio_renderer_meta_number((int) $data['comments'])) . '</a></item>';
|
|
}
|
|
$right .= '<item class="meta-view">' . jio_renderer_svg_icon('view') . esc_html(jio_renderer_meta_number((int) $data['views'])) . '</item>';
|
|
if (!empty($cfg['show_like']) && (string) ($data['post_type'] ?? '') === 'post') {
|
|
$right .= '<item class="meta-like">' . jio_renderer_svg_icon('like') . esc_html(jio_renderer_meta_number((int) $data['likes'])) . '</item>';
|
|
}
|
|
|
|
return '<div class="item-meta muted-2-color flex jsb ac">' . $meta_left . '<div class="meta-right">' . $right . '</div></div>';
|
|
}
|
|
}
|