feat(frontend): replace article system with Zibll 9.0
This commit is contained in:
+9
-15
@@ -160,22 +160,16 @@ $has_filter = $current_orderby !== 'date' || $current_price !== 'all' || $price_
|
||||
|
||||
<?php if (have_posts()) : ?>
|
||||
<?php
|
||||
$render_config = function_exists('aksrt_resolve_post_list_render_config')
|
||||
? aksrt_resolve_post_list_render_config([
|
||||
'context' => 'archive',
|
||||
'overrides' => ['mode' => 'card'],
|
||||
])
|
||||
: ['context' => 'archive', 'mode' => 'card'];
|
||||
$render_config = aksrt_resolve_post_list_render_config([
|
||||
'context' => 'archive',
|
||||
'overrides' => ['type' => 'card'],
|
||||
]);
|
||||
|
||||
if (function_exists('aksrt_render_post_list')) {
|
||||
aksrt_render_post_list(null, array_merge($render_config, ['wrapper_class' => 'content-stream__list']));
|
||||
}
|
||||
if (function_exists('aksrt_render_pagination')) {
|
||||
aksrt_render_pagination(null, [
|
||||
'query_context' => 'archive',
|
||||
'render_config' => $render_config,
|
||||
]);
|
||||
}
|
||||
aksrt_render_post_list(array_merge($render_config, ['wrapper_class' => 'content-stream__list']));
|
||||
aksrt_render_pagination(null, [
|
||||
'query_context' => 'archive',
|
||||
'render_config' => $render_config,
|
||||
]);
|
||||
?>
|
||||
<?php else : ?>
|
||||
<div class="no-results">
|
||||
|
||||
@@ -359,6 +359,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fieldset (single nested object) -->
|
||||
<div v-else-if="schema.type === 'fieldset'" class="aksrt-field__fieldset">
|
||||
<AksField
|
||||
v-for="field in (schema.fields || [])"
|
||||
:key="field.key"
|
||||
:schema="field"
|
||||
:model-value="fieldsetValue(field)"
|
||||
@update:model-value="updateFieldsetValue(field.key, $event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Repeater (array of objects) — inline expand (default) -->
|
||||
<div v-else-if="schema.type === 'repeater' && schema.ui !== 'list-modal'" class="aksrt-field__repeater">
|
||||
<div
|
||||
@@ -529,7 +540,7 @@
|
||||
* AksField — renders a single form field based on its schema definition.
|
||||
*
|
||||
* Supported types: switch, input/text, textarea, number, select, radio,
|
||||
* checkbox, color, icon, media, slider, code, alert, repeater (inline|list-modal), custom (slot).
|
||||
* checkbox, color, icon, media, slider, code, alert, fieldset, repeater (inline|list-modal), custom (slot).
|
||||
*/
|
||||
import { computed, ref, onMounted, watch } from 'vue'
|
||||
import FaIcon from './FaIcon.vue'
|
||||
@@ -553,6 +564,20 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
function fieldsetValue(field) {
|
||||
const current = props.modelValue && typeof props.modelValue === 'object' && !Array.isArray(props.modelValue)
|
||||
? props.modelValue
|
||||
: {}
|
||||
return Object.prototype.hasOwnProperty.call(current, field.key) ? current[field.key] : field.default
|
||||
}
|
||||
|
||||
function updateFieldsetValue(key, value) {
|
||||
const current = props.modelValue && typeof props.modelValue === 'object' && !Array.isArray(props.modelValue)
|
||||
? props.modelValue
|
||||
: {}
|
||||
emit('update:modelValue', { ...current, [key]: value })
|
||||
}
|
||||
|
||||
/** Normalize options: support both string[] and {label, value}[] */
|
||||
const normalizedOptions = computed(() => {
|
||||
const opts = props.schema.options || []
|
||||
@@ -974,6 +999,13 @@ function confirmRepeaterModal() {
|
||||
}
|
||||
|
||||
/* Repeater */
|
||||
.aksrt-field__fieldset {
|
||||
padding: 14px;
|
||||
border: 1px solid #eef1f6;
|
||||
border-radius: 8px;
|
||||
background: #fafbfc;
|
||||
}
|
||||
|
||||
.aksrt-field__repeater {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
|
||||
<template #header><strong>列表显示</strong></template>
|
||||
<n-alert type="info" :show-icon="false">
|
||||
首页文章列表/卡片模式、样式变体与缩略图比例已统一到「文章&列表 → 文章列表」设置(对齐 Zibll 全局 list_type / list_card_home)。此处不再单独维护 homepage_card_style / 默认视图。
|
||||
首页文章列表/卡片模式、样式变体与缩略图比例统一由「文章&列表 → 文章列表」中的 Zibll 全局字段控制。
|
||||
</n-alert>
|
||||
</n-card>
|
||||
|
||||
@@ -224,11 +224,7 @@ const form = reactive({
|
||||
home_exclude_posts: [],
|
||||
home_exclude_cats: [],
|
||||
home_lists: [],
|
||||
homepage_card_style: 'default',
|
||||
homepage_multi_thumb_enabled: true,
|
||||
homepage_multi_thumb_min_images: 3,
|
||||
homepage_sidebar_mini_enabled: true,
|
||||
homepage_default_view: 'list',
|
||||
homepage_sort_ajax_enabled: true,
|
||||
homepage_sticky_tabs_enabled: true,
|
||||
home_list_sort_dropdown: false,
|
||||
@@ -294,11 +290,7 @@ async function loadSettings() {
|
||||
form.home_exclude_posts = Array.isArray(d.home_exclude_posts) ? d.home_exclude_posts : []
|
||||
form.home_exclude_cats = Array.isArray(d.home_exclude_cats) ? d.home_exclude_cats : []
|
||||
form.home_lists = Array.isArray(d.home_lists) ? d.home_lists : []
|
||||
form.homepage_card_style = d.homepage_card_style || 'default'
|
||||
form.homepage_multi_thumb_enabled = d.homepage_multi_thumb_enabled !== false
|
||||
form.homepage_multi_thumb_min_images = d.homepage_multi_thumb_min_images || 3
|
||||
form.homepage_sidebar_mini_enabled = d.homepage_sidebar_mini_enabled !== false
|
||||
form.homepage_default_view = d.homepage_default_view || 'list'
|
||||
form.homepage_sort_ajax_enabled = d.homepage_sort_ajax_enabled !== false
|
||||
form.homepage_sticky_tabs_enabled = d.homepage_sticky_tabs_enabled !== false
|
||||
form.home_list_sort_dropdown = !!d.home_list_sort_dropdown
|
||||
|
||||
@@ -313,7 +313,7 @@ export const pageDisplaySchemas = {
|
||||
user_home_tabs_mobile_hide: '',
|
||||
user_home_sidebar: false,
|
||||
user_home_cover: true,
|
||||
user_home_route_identifier: 'nicename',
|
||||
user_home_route_identifier: 'nicename',
|
||||
user_home_follow: true,
|
||||
user_home_posts_per_page: 10,
|
||||
user_home_avatar: true,
|
||||
@@ -333,7 +333,7 @@ export const pageDisplaySchemas = {
|
||||
icon: 'fas fa-th-large',
|
||||
fields: [
|
||||
{ key: 'user_home_cover', label: '封面区域', type: 'switch', default: true, help: '用户主页顶部封面图' },
|
||||
{ key: 'user_home_route_identifier', label: '主页 URL 标识', type: 'select', default: 'nicename', options: [{ label: '用户名 URL slug', value: 'nicename' }, { label: '数字用户 ID', value: 'uid' }] },
|
||||
{ key: 'user_home_route_identifier', label: '主页 URL 标识', type: 'select', default: 'nicename', options: [{ label: '用户名 URL slug', value: 'nicename' }, { label: '数字用户 ID', value: 'uid' }] },
|
||||
{ key: 'user_home_sidebar', label: '侧边栏(已弃用)', type: 'switch', default: false, help: '公开主页为通栏布局(对齐 Zibll author);运行时强制关闭。交易服务请去用户中心。' },
|
||||
{ key: 'user_home_follow', label: '关注按钮', type: 'switch', default: true },
|
||||
{ key: 'user_home_posts_per_page', label: '每页文章数', type: 'number', default: 10, min: 5, max: 50 },
|
||||
@@ -929,15 +929,11 @@ export const pageDisplaySchemas = {
|
||||
key: 'page_display.homepage',
|
||||
title: '首页配置',
|
||||
icon: 'fas fa-home',
|
||||
description: '配置首页主列表、分类 Tab、卡片样式与首页交互。实际编辑界面在 HomepageSettings.vue(customPage),此处补齐 page_display 的 schema 契约。',
|
||||
description: '配置首页主列表、分类 Tab 与首页交互。文章列表视觉统一由文章列表设置控制。',
|
||||
defaults: {
|
||||
homepage_tabs: [],
|
||||
homepage_card_style: 'default',
|
||||
homepage_multi_thumb_enabled: false,
|
||||
homepage_multi_thumb_min_images: 3,
|
||||
homepage_sidebar_mini_enabled: true,
|
||||
homepage_default_sort: 'date',
|
||||
homepage_default_view: 'list',
|
||||
homepage_sort_ajax_enabled: true,
|
||||
homepage_sticky_tabs_enabled: true,
|
||||
home_posts_list_s: true,
|
||||
@@ -986,34 +982,9 @@ export const pageDisplaySchemas = {
|
||||
},
|
||||
{
|
||||
key: 'cards-sidebar',
|
||||
title: '卡片与侧栏',
|
||||
title: '侧栏与交互',
|
||||
icon: 'fas fa-columns',
|
||||
fields: [
|
||||
{
|
||||
key: 'homepage_card_style',
|
||||
label: '卡片风格(已弃用)',
|
||||
type: 'radio',
|
||||
default: 'default',
|
||||
options: [
|
||||
{ label: '默认', value: 'default' },
|
||||
{ label: '风格 2', value: 'style2' },
|
||||
{ label: '风格 3', value: 'style3' },
|
||||
],
|
||||
help: '已弃用:请改用「文章列表」中的列表/卡片样式设置。',
|
||||
},
|
||||
{ key: 'homepage_multi_thumb_enabled', label: '多图卡片(已弃用)', type: 'switch', default: true, help: '请改用文章列表缩略图/多图设置。' },
|
||||
{ key: 'homepage_multi_thumb_min_images', label: '最少图片数(已弃用)', type: 'number', default: 3, min: 2, max: 4 },
|
||||
{
|
||||
key: 'homepage_default_view',
|
||||
label: '默认视图(已弃用)',
|
||||
type: 'radio',
|
||||
default: 'list',
|
||||
options: [
|
||||
{ label: '列表', value: 'list' },
|
||||
{ label: '卡片', value: 'card' },
|
||||
],
|
||||
help: 'SSR 以文章列表全局设置为准;此字段仅作兼容保留。',
|
||||
},
|
||||
{ key: 'homepage_sidebar_mini_enabled', label: '迷你侧栏列表', type: 'switch', default: true },
|
||||
{ key: 'homepage_sort_ajax_enabled', label: '排序栏 AJAX', type: 'switch', default: true },
|
||||
],
|
||||
|
||||
@@ -1,237 +1,104 @@
|
||||
/**
|
||||
* Post list — list section (Zibll-aligned admin contract).
|
||||
* Keys match PHP AKSRT_Admin_Schema_Post_List_List / Zibll option IDs.
|
||||
*/
|
||||
|
||||
/** Zibll 9.0 article-list settings. */
|
||||
export const listSchema = {
|
||||
key: 'post_list.list',
|
||||
title: '文章列表',
|
||||
icon: 'fas fa-list',
|
||||
description: '对齐 Zibll 文章列表:默认排序、置顶范围、翻页模式(数字/AJAX/自动加载)与列表显示部件。',
|
||||
description: '文章列表模式、UI、标签和翻页行为。',
|
||||
defaults: {
|
||||
list_orderby: 'modified',
|
||||
post_time_source: 'modified',
|
||||
sticky_s: ['home', 'cat'],
|
||||
target_blank: false,
|
||||
item_heading_bold: false,
|
||||
post_list_author: true,
|
||||
post_list_time: true,
|
||||
list_meta_show: 'like',
|
||||
list_badge_show: ['pay', 'tag', 'cat'],
|
||||
list_badge_show: ['pay', 'cat', 'tag'],
|
||||
list_show_type: 'separate',
|
||||
list_type: 'thumb',
|
||||
list_card_home: false,
|
||||
list_card_tag: false,
|
||||
list_card_author: false,
|
||||
list_card_cat: [],
|
||||
list_list_option: { style: 'null', img_position: 'left', scale: 70 },
|
||||
list_card_option: { style: 'null', scale: 70 },
|
||||
mult_thumb_cat: [],
|
||||
paging_ajax_s: '1',
|
||||
paging_ajax_ias_s: true,
|
||||
ias_max: 3,
|
||||
ajax_trigger: '加载更多',
|
||||
ajax_nomore: '没有更多了',
|
||||
post_card_style: 'thumb',
|
||||
post_excerpt_length: 120,
|
||||
post_list_per_page: 12,
|
||||
list_show_type: 'separate',
|
||||
list_list_style: '',
|
||||
list_list_img_position: 'left',
|
||||
list_list_scale: 70,
|
||||
list_card_style: '',
|
||||
list_card_scale: 70,
|
||||
list_card_home: false,
|
||||
list_card_cat: [],
|
||||
list_card_tag: false,
|
||||
list_card_author: false,
|
||||
ajax_trigger: '<i class="fa fa-angle-right"></i>加载更多',
|
||||
ajax_nomore: '没有更多内容了',
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
key: 'order',
|
||||
title: '默认排序与置顶',
|
||||
icon: 'fas fa-sort',
|
||||
fields: [
|
||||
{
|
||||
key: 'list_orderby',
|
||||
label: '默认排序方式',
|
||||
type: 'radio',
|
||||
default: 'modified',
|
||||
options: [
|
||||
{ label: '发布时间', value: 'date' },
|
||||
{ label: '更新时间', value: 'modified' },
|
||||
{ label: 'WP默认', value: 'default' },
|
||||
],
|
||||
help: '文章列表全局默认排序(Zibll list_orderby)',
|
||||
},
|
||||
{
|
||||
key: 'sticky_s',
|
||||
label: '显示置顶文章',
|
||||
type: 'checkbox',
|
||||
default: ['home', 'cat'],
|
||||
options: [
|
||||
{ label: '首页', value: 'home' },
|
||||
{ label: '分类页', value: 'cat' },
|
||||
{ label: '标签页', value: 'tag' },
|
||||
],
|
||||
},
|
||||
key: 'order', title: '默认排序与置顶', icon: 'fas fa-sort', fields: [
|
||||
{ key: 'list_orderby', label: '默认排序方式', type: 'radio', default: 'modified', options: [
|
||||
{ label: '发布时间', value: 'date' }, { label: '更新时间', value: 'modified' }, { label: 'WP默认', value: 'default' },
|
||||
] },
|
||||
{ key: 'post_time_source', label: '时间显示数据源', type: 'radio', default: 'modified', options: [
|
||||
{ label: '发布时间', value: 'date' }, { label: '更新时间', value: 'modified' },
|
||||
] },
|
||||
{ key: 'sticky_s', label: '显示置顶文章', type: 'checkbox', default: ['home', 'cat'], options: [
|
||||
{ label: '首页', value: 'home' }, { label: '分类页', value: 'cat' }, { label: '标签页', value: 'tag' },
|
||||
] },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'display',
|
||||
title: '列表显示',
|
||||
icon: 'fas fa-eye',
|
||||
fields: [
|
||||
key: 'display', title: '列表显示', icon: 'fas fa-eye', fields: [
|
||||
{ key: 'target_blank', label: '新窗口打开文章', type: 'switch', default: false },
|
||||
{ key: 'item_heading_bold', label: '列表标题粗体显示', type: 'switch', default: false },
|
||||
{ key: 'post_list_author', label: '显示文章作者', type: 'switch', default: true },
|
||||
{
|
||||
key: 'post_list_time',
|
||||
label: '显示文章时间',
|
||||
type: 'switch',
|
||||
default: true,
|
||||
help: '建议作者与时间至少开启一项',
|
||||
},
|
||||
{
|
||||
key: 'list_meta_show',
|
||||
label: '列表小部件(移动端优先)',
|
||||
type: 'radio',
|
||||
default: 'like',
|
||||
options: [
|
||||
{ label: '阅读量', value: 'view' },
|
||||
{ label: '点赞数', value: 'like' },
|
||||
{ label: '评论', value: 'comm' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'list_badge_show',
|
||||
label: '列表徽章',
|
||||
type: 'checkbox',
|
||||
default: ['pay', 'tag', 'cat'],
|
||||
options: [
|
||||
{ label: '付费', value: 'pay' },
|
||||
{ label: '分类', value: 'cat' },
|
||||
{ label: '标签', value: 'tag' },
|
||||
],
|
||||
},
|
||||
{ key: 'post_list_time', label: '显示文章时间', type: 'switch', default: true },
|
||||
{ key: 'list_meta_show', label: '列表小部件(移动端优先)', type: 'radio', default: 'like', options: [
|
||||
{ label: '阅读量', value: 'view' }, { label: '点赞数', value: 'like' }, { label: '评论', value: 'comm' },
|
||||
] },
|
||||
{ key: 'list_badge_show', label: '显示列表标签', type: 'checkbox', default: ['pay', 'cat', 'tag'], options: [
|
||||
{ label: '付费信息', value: 'pay' }, { label: '分类', value: 'cat' }, { label: '标签', value: 'tag' },
|
||||
] },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'paging',
|
||||
title: '列表翻页',
|
||||
icon: 'fas fa-ellipsis-h',
|
||||
fields: [
|
||||
{
|
||||
key: 'paging_ajax_s',
|
||||
label: '列表翻页模式',
|
||||
type: 'radio',
|
||||
default: '1',
|
||||
options: [
|
||||
{ label: 'AJAX 追加列表翻页', value: '1' },
|
||||
{ label: '数字翻页按钮', value: '0' },
|
||||
],
|
||||
help: '对齐 Zibll paging_ajax_s',
|
||||
},
|
||||
{
|
||||
key: 'paging_ajax_ias_s',
|
||||
label: 'AJAX 自动加载',
|
||||
type: 'switch',
|
||||
default: true,
|
||||
dependsOn: { key: 'paging_ajax_s', value: '1' },
|
||||
help: '滚动到列表尽头时自动加载下一页',
|
||||
},
|
||||
{
|
||||
key: 'ias_max',
|
||||
label: '自动加载页数',
|
||||
type: 'number',
|
||||
default: 3,
|
||||
min: 0,
|
||||
max: 10,
|
||||
dependsOn: { key: 'paging_ajax_s', value: '1' },
|
||||
help: '0 表示不限制',
|
||||
},
|
||||
{
|
||||
key: 'ajax_trigger',
|
||||
label: '加载更多文案',
|
||||
type: 'input',
|
||||
default: '加载更多',
|
||||
dependsOn: { key: 'paging_ajax_s', value: '1' },
|
||||
},
|
||||
{
|
||||
key: 'ajax_nomore',
|
||||
label: '没有更多文案',
|
||||
type: 'input',
|
||||
default: '没有更多了',
|
||||
dependsOn: { key: 'paging_ajax_s', value: '1' },
|
||||
},
|
||||
key: 'layout', title: '列表模式与 UI', icon: 'fas fa-th-large', fields: [
|
||||
{ key: 'list_show_type', label: '列表样式', type: 'radio', default: 'separate', options: [
|
||||
{ label: '分离', value: 'separate' }, { label: '无间距', value: 'no_margin' },
|
||||
] },
|
||||
{ key: 'list_type', label: '默认列表模式', type: 'radio', default: 'thumb', options: [
|
||||
{ label: '列表文字模式', value: 'text' },
|
||||
{ label: '列表图文模式', value: 'thumb' },
|
||||
{ label: '列表自动图文模式', value: 'thumb_if_has' },
|
||||
{ label: '卡片模式', value: 'card' },
|
||||
], help: '文字、自动图文和多图模式仅在开启侧栏的页面有效。' },
|
||||
{ key: 'list_card_home', label: '首页列表卡片模式', type: 'switch', default: false, dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_card_tag', label: '标签页列表卡片模式', type: 'switch', default: false, dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_card_author', label: '用户页列表卡片模式', type: 'switch', default: false, dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_card_cat', label: '分类页自定义卡片模式', type: 'taxonomy_select', taxonomy: 'category', multiple: true, default: [], dependsOn: { key: 'list_type', not: true, value: 'card' } },
|
||||
{ key: 'list_list_option', label: '列表模式 UI 配置', type: 'fieldset', default: { style: 'null', img_position: 'left', scale: 70 }, fields: [
|
||||
{ key: 'style', label: '列表样式', type: 'radio', default: 'null', options: [
|
||||
{ label: '默认', value: 'null' }, { label: '样式 2', value: 'style2' },
|
||||
] },
|
||||
{ key: 'img_position', label: '缩略图位置', type: 'radio', default: 'left', options: [
|
||||
{ label: '靠左', value: 'left' }, { label: '靠右', value: 'right' },
|
||||
] },
|
||||
{ key: 'scale', label: '缩略图长宽比例(%)', type: 'number', default: 70, min: 50, max: 200, step: 5 },
|
||||
] },
|
||||
{ key: 'list_card_option', label: '卡片模式 UI 配置', type: 'fieldset', default: { style: 'null', scale: 70 }, fields: [
|
||||
{ key: 'style', label: '卡片样式', type: 'radio', default: 'null', options: [
|
||||
{ label: '默认', value: 'null' }, { label: '样式 3', value: 'style3' },
|
||||
] },
|
||||
{ key: 'scale', label: '缩略图长宽比例(%)', type: 'number', default: 70, min: 20, max: 200, step: 5 },
|
||||
] },
|
||||
{ key: 'mult_thumb_cat', label: '列表多图显示分类', type: 'taxonomy_select', taxonomy: 'category', multiple: true, default: [], help: '文章格式为图片或画廊时默认显示 4 张缩略图;卡片模式或无侧栏时无效。' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'card',
|
||||
title: '卡片与布局',
|
||||
icon: 'fas fa-th-large',
|
||||
fields: [
|
||||
{
|
||||
key: 'post_card_style',
|
||||
label: '默认列表模式',
|
||||
type: 'select',
|
||||
default: 'thumb',
|
||||
options: [
|
||||
{ label: '列表图文模式', value: 'thumb' },
|
||||
{ label: '列表文字模式', value: 'text' },
|
||||
{ label: '列表自动图文', value: 'thumb_if_has' },
|
||||
{ label: '卡片模式', value: 'card' },
|
||||
{ label: '紧凑列表', value: 'compact' },
|
||||
{ label: '大图列表', value: 'large_thumb' },
|
||||
{ label: '多图列表', value: 'multi_thumb' },
|
||||
],
|
||||
help: '对齐 Zibll list_type:thumb/text/thumb_if_has 为列表,card 为卡片网格。首页可用下方「首页卡片模式」单独强制卡片。',
|
||||
},
|
||||
{ key: 'post_excerpt_length', label: '摘要长度', type: 'number', default: 120, min: 20, max: 500 },
|
||||
{ key: 'post_list_per_page', label: '每页文章数', type: 'number', default: 12, min: 4, max: 48 },
|
||||
{
|
||||
key: 'list_show_type',
|
||||
label: '列表间距样式',
|
||||
type: 'radio',
|
||||
default: 'separate',
|
||||
options: [
|
||||
{ label: '分隔卡片', value: 'separate' },
|
||||
{ label: '无间距', value: 'no_margin' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'list_list_style',
|
||||
label: '列表样式变体',
|
||||
type: 'radio',
|
||||
default: '',
|
||||
options: [
|
||||
{ label: '默认', value: '' },
|
||||
{ label: '样式2', value: 'style2' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'list_list_img_position',
|
||||
label: '列表缩略图位置',
|
||||
type: 'radio',
|
||||
default: 'left',
|
||||
options: [
|
||||
{ label: '左侧', value: 'left' },
|
||||
{ label: '右侧', value: 'right' },
|
||||
],
|
||||
},
|
||||
{ key: 'list_list_scale', label: '列表缩略图比例 (%)', type: 'number', default: 70, min: 50, max: 200 },
|
||||
{
|
||||
key: 'list_card_style',
|
||||
label: '卡片样式变体',
|
||||
type: 'radio',
|
||||
default: '',
|
||||
options: [
|
||||
{ label: '默认', value: '' },
|
||||
{ label: '样式3', value: 'style3' },
|
||||
],
|
||||
},
|
||||
{ key: 'list_card_scale', label: '卡片缩略图比例 (%)', type: 'number', default: 70, min: 20, max: 200 },
|
||||
{ key: 'list_card_home', label: '首页卡片模式', type: 'switch', default: false, help: '当默认模式不为卡片时,单独将首页列表强制为卡片(Zibll list_card_home)', dependsOn: { key: 'post_card_style', operator: '!=', value: 'card' } },
|
||||
{
|
||||
key: 'list_card_cat',
|
||||
label: '分类卡片模式',
|
||||
type: 'taxonomy_select',
|
||||
taxonomy: 'category',
|
||||
multiple: true,
|
||||
default: [],
|
||||
},
|
||||
{ key: 'list_card_tag', label: '标签页卡片模式', type: 'switch', default: false },
|
||||
{ key: 'list_card_author', label: '用户页卡片模式', type: 'switch', default: false },
|
||||
key: 'paging', title: '列表翻页', icon: 'fas fa-ellipsis-h', fields: [
|
||||
{ key: 'paging_ajax_s', label: '列表翻页模式', type: 'radio', default: '1', options: [
|
||||
{ label: 'AJAX 追加列表翻页', value: '1' }, { label: '数字翻页按钮', value: '0' },
|
||||
] },
|
||||
{ key: 'paging_ajax_ias_s', label: 'AJAX 自动加载', type: 'switch', default: true, dependsOn: { key: 'paging_ajax_s', value: '1' } },
|
||||
{ key: 'ias_max', label: '自动加载页数', type: 'number', default: 3, min: 0, max: 10, dependsOn: { key: 'paging_ajax_s', value: '1' } },
|
||||
{ key: 'ajax_trigger', label: '翻页按钮文字', type: 'textarea', default: '<i class="fa fa-angle-right"></i>加载更多' },
|
||||
{ key: 'ajax_nomore', label: '列表全部加载完毕文案', type: 'textarea', default: '没有更多内容了' },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -19,14 +19,11 @@ export const pageSchema = {
|
||||
post_lightbox_full: true,
|
||||
post_lightbox_down: false,
|
||||
post_lightbox_play: false,
|
||||
post_related_enabled: true,
|
||||
post_related_count: 6,
|
||||
// Display style (Zibll img/list/text). Legacy post_related_type may still hold source or style.
|
||||
post_related_style: 'img',
|
||||
post_related_source: 'category',
|
||||
post_related_type: 'category',
|
||||
post_related_s: true,
|
||||
post_related_type: 'img',
|
||||
related_title: '相关推荐',
|
||||
post_related_n: 6,
|
||||
post_related_orderby: 'views',
|
||||
post_related_title: '相关推荐',
|
||||
breadcrumbs_single_text: true,
|
||||
post_copyright_enabled: true,
|
||||
post_copyright_text: '',
|
||||
@@ -116,26 +113,23 @@ export const pageSchema = {
|
||||
title: '相关推荐',
|
||||
icon: 'fas fa-random',
|
||||
fields: [
|
||||
{ key: 'post_related_enabled', label: '显示相关推荐', type: 'switch', default: true },
|
||||
{ key: 'post_related_count', label: '推荐数量', type: 'number', default: 6, min: 1, max: 20, dependsOn: { key: 'post_related_enabled', value: true } },
|
||||
{ key: 'post_related_style', label: '展示样式', type: 'radio', default: 'img', options: [
|
||||
{ key: 'post_related_s', label: '显示相关推荐', type: 'switch', default: true },
|
||||
{ key: 'post_related_type', label: '展示样式', type: 'radio', default: 'img', options: [
|
||||
{ label: '图文卡片', value: 'img' },
|
||||
{ label: '列表', value: 'list' },
|
||||
{ label: '纯文字', value: 'text' },
|
||||
], dependsOn: { key: 'post_related_enabled', value: true }, help: '对齐 Zibll 相关文章三种样式' },
|
||||
{ key: 'post_related_source', label: '推荐来源', type: 'radio', default: 'category', options: [
|
||||
{ label: '同分类/标签', value: 'category' },
|
||||
{ label: '同标签', value: 'tag' },
|
||||
{ label: '随机', value: 'random' },
|
||||
], dependsOn: { key: 'post_related_enabled', value: true } },
|
||||
], dependsOn: { key: 'post_related_s', value: true }, help: '对齐 Zibll 相关文章三种样式' },
|
||||
{ key: 'related_title', label: '推荐标题', type: 'input', default: '相关推荐', dependsOn: { key: 'post_related_s', value: true } },
|
||||
{ key: 'post_related_n', label: '推荐数量', type: 'number', default: 6, min: 4, max: 12, step: 2, dependsOn: { key: 'post_related_s', value: true } },
|
||||
{ key: 'post_related_orderby', label: '推荐排序', type: 'select', default: 'views', options: [
|
||||
{ label: '浏览量', value: 'views' },
|
||||
{ label: '随机', value: 'rand' },
|
||||
{ label: '相关度', value: 'relevance' },
|
||||
{ label: '时间', value: 'date' },
|
||||
{ label: '更新时间', value: 'modified' },
|
||||
], dependsOn: { key: 'post_related_enabled', value: true } },
|
||||
{ key: 'post_related_title', label: '推荐标题', type: 'input', default: '相关推荐', dependsOn: { key: 'post_related_enabled', value: true } },
|
||||
{ label: '发布时间', value: 'date' },
|
||||
{ label: '浏览量', value: 'views' },
|
||||
{ label: '点赞量', value: 'like' },
|
||||
{ label: '评论量', value: 'comment_count' },
|
||||
{ label: '收藏数量', value: 'favorite' },
|
||||
{ label: '随机', value: 'rand' },
|
||||
], dependsOn: { key: 'post_related_s', value: true } },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/** Zibll 9.0 list-thumbnail settings. */
|
||||
const themeRoot = typeof window !== 'undefined' && window.aksrtAdminData?.themeUri
|
||||
? String(window.aksrtAdminData.themeUri).replace(/\/$/, '')
|
||||
: ''
|
||||
const spareThumbnailDefault = [{ img: `${themeRoot}/assets/img/thumbnail.svg` }]
|
||||
|
||||
export const thumbSchema = {
|
||||
key: 'post_list.thumb',
|
||||
title: '列表缩略图',
|
||||
icon: 'fas fa-images',
|
||||
description: '配置缩略图来源优先级、尺寸、占位图和多图模式。',
|
||||
description: '缩略图获取优先级:文章特色图像 > 外链特色图像 > 文章首图 > 分类封面图 > 备用缩略图 > 懒加载预载图。',
|
||||
defaults: {
|
||||
thumb_priority: 'featured,attachment,resource,custom',
|
||||
thumb_fallback: 'placeholder',
|
||||
thumb_spare_images: [],
|
||||
thumb_aspect_ratio: '16:9',
|
||||
list_thumb_fit: 'cover',
|
||||
thumb_multi_enabled: false,
|
||||
thumb_multi_count: 3,
|
||||
list_thumb_slides_s: true,
|
||||
list_thumb_video_s: true,
|
||||
list_thumb_video_mute_s: true,
|
||||
thumb_postfirstimg_s: true,
|
||||
thumb_catimg_s: true,
|
||||
mult_thumb_cat: [],
|
||||
list_thumb_fit: '',
|
||||
thumb_postfirstimg_size: 'medium',
|
||||
spare_thumbnail: spareThumbnailDefault,
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
@@ -24,44 +25,24 @@ export const thumbSchema = {
|
||||
title: '图片来源',
|
||||
icon: 'fas fa-image',
|
||||
fields: [
|
||||
{ key: 'thumb_priority', label: '图片优先级', type: 'input', default: 'featured,attachment,resource,custom', help: '逗号分隔: featured(特色图), attachment(附件), resource(资源封面), custom(自定义), post_first_img(文章首图), category_cover(分类封面)' },
|
||||
{ key: 'thumb_fallback', label: '无图时处理', type: 'radio', default: 'placeholder', options: [
|
||||
{ label: '显示占位图', value: 'placeholder' },
|
||||
{ label: '隐藏缩略图', value: 'hide' },
|
||||
{ label: '随机封面', value: 'random' },
|
||||
]},
|
||||
{ key: 'thumb_spare_images', label: '备用缩略图', type: 'gallery', default: [], help: '当无图处理选择"随机封面"时从此图库随机选取', dependsOn: { key: 'thumb_fallback', value: 'random' } },
|
||||
{ key: 'thumb_aspect_ratio', label: '图片比例', type: 'select', default: '16:9', options: [
|
||||
{ label: '16:9 宽屏', value: '16:9' },
|
||||
{ label: '4:3 标准', value: '4:3' },
|
||||
{ label: '1:1 正方形', value: '1:1' },
|
||||
{ label: '自适应', value: 'auto' },
|
||||
]},
|
||||
{ key: 'list_thumb_fit', label: '缩略图填充方式', type: 'radio', default: 'cover', options: [
|
||||
{ label: '填充裁剪', value: 'cover' },
|
||||
{ label: '完整显示', value: 'contain' },
|
||||
]},
|
||||
{ key: 'list_thumb_slides_s', label: '幻灯片缩略图', type: 'switch', default: true, help: '允许幻灯片作为列表缩略图' },
|
||||
{ key: 'list_thumb_video_s', label: '视频缩略图', type: 'switch', default: true, help: '鼠标悬停时自动播放视频缩略图' },
|
||||
{ key: 'list_thumb_video_mute_s', label: '视频缩略图静音', type: 'switch', default: true, dependsOn: { key: 'list_thumb_video_s', value: true }, help: '视频缩略图播放时静音' },
|
||||
{ key: 'thumb_postfirstimg_s', label: '自动获取文章首图', type: 'switch', default: true, help: '自动从文章内容中提取第一张图片作为缩略图' },
|
||||
{ key: 'thumb_postfirstimg_size', label: '首图尺寸', type: 'select', default: 'medium', options: [
|
||||
{ label: '缩略图', value: 'thumbnail' },
|
||||
{ label: '中等', value: 'medium' },
|
||||
{ label: '大', value: 'large' },
|
||||
{ label: '原始', value: 'full' },
|
||||
], dependsOn: { key: 'thumb_postfirstimg_s', value: true }, help: '自动获取文章首图时使用的 WP 图片尺寸' },
|
||||
{ key: 'thumb_catimg_s', label: '自动获取分类封面', type: 'switch', default: true, help: '无特色图时使用分类封面图作为缩略图' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'multi',
|
||||
title: '多图模式',
|
||||
icon: 'fas fa-images',
|
||||
fields: [
|
||||
{ key: 'thumb_multi_enabled', label: '多图卡片', type: 'switch', default: false, help: '当文章有多张图片时,在列表中展示多图预览' },
|
||||
{ key: 'thumb_multi_count', label: '最多显示几张', type: 'number', default: 3, min: 2, max: 6, dependsOn: { key: 'thumb_multi_enabled', value: true } },
|
||||
{ key: 'mult_thumb_cat', label: '按分类多图显示', type: 'taxonomy_select', taxonomy: 'category', multiple: true, default: [], help: '选择的分类下所有文章自动显示多张缩略图' },
|
||||
{ key: 'list_thumb_slides_s', label: '幻灯片缩略图', type: 'switch', default: true, help: '允许设置幻灯片为列表缩略图' },
|
||||
{ key: 'list_thumb_video_s', label: '视频缩略图', type: 'switch', default: true, help: '鼠标移动到列表上自动播放' },
|
||||
{ key: 'list_thumb_video_mute_s', label: '视频缩略图静音播放', type: 'switch', default: true, dependsOn: { key: 'list_thumb_video_s', value: true }, help: '部分手机浏览器无法实现静音播放' },
|
||||
{ key: 'thumb_postfirstimg_s', label: '自动获取文章首图', type: 'switch', default: true },
|
||||
{ key: 'thumb_catimg_s', label: '自动获取分类封面', type: 'switch', default: true },
|
||||
{ key: 'list_thumb_fit', label: '缩略图填充方式', type: 'radio', default: '', options: [
|
||||
{ label: 'cover 铺满', value: '' },
|
||||
{ label: 'contain 等比例缩放', value: 'contain' },
|
||||
] },
|
||||
{ key: 'thumb_postfirstimg_size', label: '缩略图大小', type: 'radio', default: 'medium', options: [
|
||||
{ label: '小尺寸', value: 'thumbnail' },
|
||||
{ label: '中尺寸', value: 'medium' },
|
||||
{ label: '大尺寸', value: 'large' },
|
||||
{ label: '原图', value: 'full' },
|
||||
] },
|
||||
{ key: 'spare_thumbnail', label: '备用缩略图', type: 'repeater', default: spareThumbnailDefault, addText: '添加备用缩略图', fields: [
|
||||
{ key: 'img', label: '图片', type: 'media', default: '' },
|
||||
], help: '添加多张图片时自动随机获取' },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -78,8 +78,6 @@ export const MODULE_LIBRARY = [
|
||||
options: [
|
||||
{ label: '卡片', value: 'card' },
|
||||
{ label: '列表', value: 'list' },
|
||||
{ label: '瀑布流', value: 'masonry' },
|
||||
{ label: '资源网格', value: 'grid-cms' },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -89,7 +87,7 @@ export const MODULE_LIBRARY = [
|
||||
label: '分类 Tabs',
|
||||
icon: 'switcher',
|
||||
desc: '多分类 Tab 切换',
|
||||
defaultConfig: { cat_ids: [], count: 8, layout: 'grid-cms', title: '' },
|
||||
defaultConfig: { cat_ids: [], count: 8, layout: 'card', title: '' },
|
||||
fields: [
|
||||
{ key: 'title', type: 'text', label: '标题' },
|
||||
{ key: 'cat_ids', type: 'cats', label: '分类列表' },
|
||||
@@ -99,8 +97,6 @@ export const MODULE_LIBRARY = [
|
||||
options: [
|
||||
{ label: '卡片', value: 'card' },
|
||||
{ label: '列表', value: 'list' },
|
||||
{ label: '瀑布流', value: 'masonry' },
|
||||
{ label: '资源网格', value: 'grid-cms' },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -138,8 +134,6 @@ export const MODULE_LIBRARY = [
|
||||
options: [
|
||||
{ label: '卡片', value: 'card' },
|
||||
{ label: '列表', value: 'list' },
|
||||
{ label: '瀑布流', value: 'masonry' },
|
||||
{ label: '资源网格', value: 'grid-cms' },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -460,8 +454,8 @@ export const PRESET_TEMPLATES = [
|
||||
desc: 'Hero(固定骨架)+ Tabs + 最新文章 + 下载排行',
|
||||
modules: [
|
||||
{ type: 'hero', config: {} },
|
||||
{ type: 'tabs', config: { count: 8, layout: 'grid-cms' } },
|
||||
{ type: 'recent', config: { count: 8, layout: 'grid-cms' } },
|
||||
{ type: 'tabs', config: { count: 8, layout: 'card' } },
|
||||
{ type: 'recent', config: { count: 8, layout: 'card' } },
|
||||
{ type: 'ranking', config: { metric: 'downloads', count: 6 } },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -418,11 +418,9 @@ html.dark .post-card,
|
||||
html.dark .widget,
|
||||
html.dark .aksrt-theme-box,
|
||||
html.dark .theme-box,
|
||||
html.dark .posts-item,
|
||||
body.dark-theme .post-card,
|
||||
body.dark-theme .widget,
|
||||
body.dark-theme .aksrt-theme-box,
|
||||
body.dark-theme .theme-box,
|
||||
body.dark-theme .posts-item {
|
||||
body.dark-theme .theme-box {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
@@ -41,26 +41,6 @@
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list {
|
||||
padding: 15px;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .item-thumbnail {
|
||||
width: 160px;
|
||||
min-width: 160px;
|
||||
padding-bottom: calc(160px * 0.7);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .thumb-items > span {
|
||||
width: calc(33.333% - 6px);
|
||||
padding-bottom: calc(var(--posts-list-scale, 70%) / 3);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .thumb-items > span:nth-child(4) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
@@ -73,41 +53,6 @@
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list {
|
||||
padding: 12px;
|
||||
gap: 12px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .item-thumbnail {
|
||||
width: 120px;
|
||||
min-width: 120px;
|
||||
padding-bottom: calc(120px * 0.7);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-heading {
|
||||
font-size: 15px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-excerpt {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Zibll keeps article cards in two columns throughout the mobile range. */
|
||||
.aksrt-homepage__posts[data-view="card"] {
|
||||
margin: -5px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item {
|
||||
width: calc(50% - 10px);
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
/* Tab skeleton: smaller thumb */
|
||||
.aksrt-homepage__tab-skeleton-thumb {
|
||||
width: 120px;
|
||||
@@ -158,44 +103,6 @@
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list {
|
||||
padding: 10px;
|
||||
gap: 10px;
|
||||
border-radius: var(--radius, 8px);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .item-thumbnail {
|
||||
width: 96px;
|
||||
min-width: 96px;
|
||||
padding-bottom: calc(96px * 0.7);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-heading {
|
||||
font-size: 15px;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-tags .badge {
|
||||
font-size: 11px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-meta {
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-avatar {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-item {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Tab skeleton: adapt */
|
||||
.aksrt-homepage__tab-skeleton-thumb {
|
||||
width: 96px;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
.aksrt-homepage__view-btn.is-active {
|
||||
color: var(--color-primary, var(--color-primary));
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.aksrt-homepage__view-btn svg {
|
||||
@@ -9,10 +8,6 @@
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
7. TITLE THEME (sidebar section headers)
|
||||
================================================================ */
|
||||
|
||||
.title-theme {
|
||||
position: relative;
|
||||
padding-left: 1.2em;
|
||||
@@ -23,14 +18,14 @@
|
||||
|
||||
.title-theme::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 4px;
|
||||
background: var(--color-primary, var(--color-primary));
|
||||
top: 10%;
|
||||
left: 2px;
|
||||
bottom: 10%;
|
||||
left: 2px;
|
||||
width: 4px;
|
||||
content: "";
|
||||
background: var(--color-primary);
|
||||
border-radius: 5px;
|
||||
box-shadow: 1px 1px 3px -1px var(--color-primary, var(--color-primary));
|
||||
box-shadow: 1px 1px 3px -1px var(--color-primary);
|
||||
}
|
||||
|
||||
.aksrt-homepage__page-indicator {
|
||||
@@ -40,29 +35,18 @@
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
8. PANELS
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__panel[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panels {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.home-tab-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel[hidden],
|
||||
.index-tab-main .tab-pane[hidden],
|
||||
.home-tab-content .tab-pane[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panels,
|
||||
.home-tab-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__panel {
|
||||
/* Inactive panes start transparent; active pane must be fully visible. */
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
@@ -72,18 +56,15 @@
|
||||
.aksrt-homepage__panel.fade.in,
|
||||
.aksrt-homepage__panel.tab-pane.active,
|
||||
#index-tab-main.aksrt-homepage__panel,
|
||||
#index-tab-main.posts-row,
|
||||
.home-tab-content .tab-pane.is-active,
|
||||
.home-tab-content .tab-pane.show,
|
||||
.home-tab-content .tab-pane.active,
|
||||
.aksrt-homepage__panel.is-active,
|
||||
.aksrt-homepage__panel.show {
|
||||
opacity: 1 !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
/* Beat Bootstrap .fade:not(.show){opacity:0} if fade class remains */
|
||||
.home-tab-content .tab-pane.fade.is-active,
|
||||
.home-tab-content .tab-pane.fade.show,
|
||||
.home-tab-content .tab-pane.fade.active,
|
||||
@@ -95,430 +76,26 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts.post-grid--home {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
|
||||
.aksrt-homepage__posts {
|
||||
display: block;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* List cards: wrapped (.aksrt-homepage__posts) OR direct panel children (skip_wrapper). */
|
||||
.aksrt-homepage__posts > .posts-item.list,
|
||||
.posts-row.ajaxpager > .posts-item.list,
|
||||
#index-tab-main > .posts-item.list {
|
||||
width: 100%;
|
||||
margin: 15px 0;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
min-width: 0;
|
||||
background: var(--surface-1, #fff);
|
||||
border: none;
|
||||
border-radius: var(--main-radius, var(--radius, 8px));
|
||||
box-shadow: var(--shadow-sm);
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.2s ease;
|
||||
font-size: 1rem;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list:last-child,
|
||||
.posts-row.ajaxpager > .posts-item.list:last-child,
|
||||
#index-tab-main > .posts-item.list:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list:hover,
|
||||
.posts-row.ajaxpager > .posts-item.list:hover,
|
||||
#index-tab-main > .posts-item.list:hover {
|
||||
box-shadow: var(--shadow);
|
||||
transform: none;
|
||||
}
|
||||
|
||||
html.dark .aksrt-homepage__posts > .posts-item.list:hover,
|
||||
html.dark .posts-row.ajaxpager > .posts-item.list:hover,
|
||||
html.dark #index-tab-main > .posts-item.list:hover {
|
||||
box-shadow: 0 4px 16px rgba(24, 24, 24, 0.22);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .item-thumbnail {
|
||||
position: relative;
|
||||
width: 190px;
|
||||
min-width: 190px;
|
||||
height: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: calc(190px * 0.7);
|
||||
border-radius: var(--radius, 8px);
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .item-thumbnail > a {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .item-thumbnail img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list:hover .item-thumbnail img {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .item-thumbnail .img-badge {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .thumb-items {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .item-thumbnail {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .thumb-items {
|
||||
display: block;
|
||||
margin: 0 -3px 6px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .thumb-items > span {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: calc(25% - 6px);
|
||||
height: 0;
|
||||
margin: 0 3px;
|
||||
padding-bottom: calc(var(--posts-list-scale, 70%) / 4);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .thumb-items.contain > span {
|
||||
overflow: hidden;
|
||||
background: var(--color-line, rgba(50, 50, 50, 0.06));
|
||||
border-radius: var(--radius, 8px);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .thumb-items > span > img {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .thumb-items > span > img {
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb:hover .thumb-items > span > img {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list.mult-thumb .item-body {
|
||||
width: 100%;
|
||||
padding: 2px 0 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts > .posts-item.list .item-body,
|
||||
.posts-row.ajaxpager > .posts-item.list .item-body,
|
||||
#index-tab-main > .posts-item.list .item-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding: 2px 0;
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-heading,
|
||||
#index-tab-main .item-heading,
|
||||
.posts-row.ajaxpager .item-heading {
|
||||
margin: 0 0 2px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
min-height: 0;
|
||||
max-height: 2.8em;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
color: var(--color-ink);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-heading a,
|
||||
#index-tab-main .item-heading a,
|
||||
.posts-row.ajaxpager .item-heading a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-heading a:hover,
|
||||
#index-tab-main .item-heading a:hover,
|
||||
.posts-row.ajaxpager .item-heading a:hover {
|
||||
color: var(--color-primary, var(--color-primary));
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-excerpt,
|
||||
#index-tab-main .item-excerpt,
|
||||
.posts-row.ajaxpager .item-excerpt {
|
||||
margin: 0;
|
||||
color: var(--main-color, #4e5358);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-tags,
|
||||
#index-tab-main .item-tags,
|
||||
.posts-row.ajaxpager .item-tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 0;
|
||||
margin-bottom: 0;
|
||||
gap: 5px;
|
||||
flex-wrap: wrap;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-tags .badge {
|
||||
min-height: auto;
|
||||
margin-right: 0;
|
||||
padding: 2px 5px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .item-meta,
|
||||
#index-tab-main .item-meta,
|
||||
.posts-row.ajaxpager .item-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
padding-top: 0;
|
||||
border-top: 0;
|
||||
font-size: 13px;
|
||||
color: var(--color-ink-3, #777);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-author,
|
||||
.aksrt-homepage__posts .meta-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-name {
|
||||
color: var(--color-ink);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-dot {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 999px;
|
||||
background: var(--color-ink-4, #b1b1b1);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
color: var(--color-ink-3, #777);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts .meta-item i {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
10. POST CARDS — CARD MODE (3-column grid)
|
||||
================================================================ */
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] {
|
||||
display: block;
|
||||
margin: -8px;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item {
|
||||
width: calc(33.333% - 16px);
|
||||
margin: 8px;
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
font-size: 1rem;
|
||||
background: var(--surface-1, #fff);
|
||||
border: none;
|
||||
border-radius: var(--main-radius, var(--radius, 8px));
|
||||
box-shadow: var(--shadow-sm);
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item:hover {
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style2 {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style2:hover {
|
||||
background: var(--surface-1, #fff);
|
||||
box-shadow: 0 0 10px var(--shadow, rgba(116, 116, 116, 0.08));
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style3 {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-thumbnail {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: var(--posts-card-scale, 70%);
|
||||
min-width: unset;
|
||||
border-radius: var(--radius, 8px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-thumbnail > a {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-thumbnail img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item:hover .item-thumbnail img {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.mult-thumb .thumb-items {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.mult-thumb .item-thumbnail {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style3 .item-thumbnail,
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style3 .item-thumbnail img {
|
||||
border-radius: var(--radius, 8px) var(--radius, 8px) 0 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-body {
|
||||
width: 100%;
|
||||
margin: 10px 0 0;
|
||||
padding: 0;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style3 .item-body {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-heading {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
min-height: 2.8em;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-excerpt {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-meta {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .meta-right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* ================================================================
|
||||
VISIBILITY LOCK — homepage post stream must always paint
|
||||
================================================================ */
|
||||
posts.posts-item,
|
||||
article.posts-item,
|
||||
#index-tab-main > .posts-item,
|
||||
.home-tab-content .posts-item {
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
color: var(--color-ink, #333);
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
|
||||
#index-tab-main > .posts-item.list,
|
||||
.home-tab-content .posts-item.list {
|
||||
.flex {
|
||||
display: flex !important;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Minimal flex utilities used by post cards (zibll-style helpers) */
|
||||
.flex { display: flex !important; }
|
||||
.flex.xx,
|
||||
.xx { flex-direction: column; }
|
||||
.xx {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex1,
|
||||
.flex-1 { flex: 1 1 auto; min-width: 0; }
|
||||
.jsb { justify-content: space-between; }
|
||||
.ac { align-items: center; }
|
||||
.jb { justify-content: space-between; }
|
||||
.flex-1 {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.jsb,
|
||||
.jb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.ac {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -1,55 +1,3 @@
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.mult-thumb .thumb-items {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.mult-thumb .item-thumbnail {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style3 .item-thumbnail,
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style3 .item-thumbnail img {
|
||||
border-radius: var(--radius, 8px) var(--radius, 8px) 0 0;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item:hover .item-thumbnail img {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-body {
|
||||
width: 100%;
|
||||
margin: 10px 0 0;
|
||||
padding: 0;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item.style3 .item-body {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-heading {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
min-height: 2.8em;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-excerpt {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .item-meta {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.aksrt-homepage__posts[data-view="card"] > .posts-item .meta-right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
11. PAGINATION
|
||||
================================================================ */
|
||||
|
||||
@@ -231,7 +231,4 @@
|
||||
padding: 0.7em;
|
||||
}
|
||||
|
||||
.posts-item .item-thumbnail {
|
||||
width: 138px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Post Card · CMS (grid-cms layout)
|
||||
*/
|
||||
|
||||
.post-grid--grid-cms {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.post-grid--grid-cms .posts-item.card.posts-item--cms {
|
||||
height: 100%;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.post-grid--grid-cms .posts-item--cms .item-body {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.post-grid--grid-cms .posts-item--cms .item-excerpt {
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.post-grid--grid-cms .posts-item--cms .item-cms-strip {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.post-grid--grid-cms .posts-item--cms .item-cms-strip li {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 24px;
|
||||
padding: 0 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-2);
|
||||
color: var(--color-ink-4);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.post-grid--grid-cms .posts-item--cms .item-cms-strip li::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.post-grid--grid-cms {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 380px) {
|
||||
.post-grid--grid-cms {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
+516
-567
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,102 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function renderGradientBackground(container) {
|
||||
if (!container || container.dataset.aksrtGradientState || typeof window.Grade !== "function") return;
|
||||
|
||||
var source = container.querySelector("img");
|
||||
if (!source || (!source.classList.contains("lazyloaded") && !(source.complete && source.naturalWidth > 0))) return;
|
||||
|
||||
container.dataset.aksrtGradientState = "loading";
|
||||
window.Grade(container, null, function (result) {
|
||||
var gradientData = result && result[0];
|
||||
var colors = gradientData && gradientData.gradientData;
|
||||
if (!gradientData || !colors || !colors[0] || !colors[1]) {
|
||||
delete container.dataset.aksrtGradientState;
|
||||
return;
|
||||
}
|
||||
|
||||
var opacity = container.getAttribute("data-opacity");
|
||||
var colorName = opacity ? "rgba" : "rgb";
|
||||
var alpha = opacity ? "," + opacity : "";
|
||||
var color1 = colorName + "(" + colors[0].rgba.slice(0, 3).join(",") + alpha + ") 10%";
|
||||
var color2 = colorName + "(" + colors[1].rgba.slice(0, 3).join(",") + alpha + ") 80%";
|
||||
|
||||
gradientData.element.classList.add("gradient-bg-loaded");
|
||||
gradientData.element.style.backgroundImage = "linear-gradient(135deg, " + color1 + ", " + color2 + ")";
|
||||
container.dataset.aksrtGradientState = "loaded";
|
||||
});
|
||||
}
|
||||
|
||||
function initGradientBackgrounds(root) {
|
||||
var scope = root || document;
|
||||
if (scope.nodeType === 1 && scope.matches(".gradient-bg")) {
|
||||
renderGradientBackground(scope);
|
||||
}
|
||||
scope.querySelectorAll(".gradient-bg").forEach(renderGradientBackground);
|
||||
}
|
||||
|
||||
document.addEventListener("lazyloaded", function (event) {
|
||||
if (!(event.target instanceof Element) || !event.target.matches(".gradient-bg img")) return;
|
||||
renderGradientBackground(event.target.closest(".gradient-bg"));
|
||||
}, true);
|
||||
|
||||
function initPostThumbMedia(root) {
|
||||
var scope = root || document;
|
||||
|
||||
scope.querySelectorAll("[data-post-thumb-slider]").forEach(function (el) {
|
||||
if (el.dataset.aksrtThumbSliderBound === "1" || typeof Swiper === "undefined") return;
|
||||
el.dataset.aksrtThumbSliderBound = "1";
|
||||
new Swiper(el, {
|
||||
slidesPerView: 1,
|
||||
loop: el.querySelectorAll(".swiper-slide").length > 1,
|
||||
pagination: {
|
||||
el: el.querySelector(".swiper-pagination"),
|
||||
clickable: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
scope.querySelectorAll("[data-post-thumb-video]").forEach(function (box) {
|
||||
if (box.dataset.aksrtThumbVideoBound === "1") return;
|
||||
box.dataset.aksrtThumbVideoBound = "1";
|
||||
var video = box.querySelector("video");
|
||||
if (!video) return;
|
||||
|
||||
function loadVideo() {
|
||||
if (!video.getAttribute("src") && video.dataset.src) {
|
||||
video.setAttribute("src", video.dataset.src);
|
||||
video.load();
|
||||
}
|
||||
}
|
||||
|
||||
function playVideo() {
|
||||
loadVideo();
|
||||
var result = video.play();
|
||||
var postItem = box.closest(".posts-item");
|
||||
if (postItem) postItem.classList.add("thumb-dplayer-playing");
|
||||
if (result && typeof result.catch === "function") result.catch(function () {});
|
||||
}
|
||||
|
||||
function pauseVideo() {
|
||||
video.pause();
|
||||
var postItem = box.closest(".posts-item");
|
||||
if (postItem) postItem.classList.remove("thumb-dplayer-playing");
|
||||
}
|
||||
|
||||
var item = box.closest(".item-thumbnail") || box;
|
||||
item.addEventListener("mouseenter", playVideo);
|
||||
item.addEventListener("mouseleave", pauseVideo);
|
||||
item.addEventListener("focusin", playVideo);
|
||||
item.addEventListener("focusout", pauseVideo);
|
||||
});
|
||||
}
|
||||
|
||||
window.AksrtFrontend.register("aksrt-post-thumb-media", function (root) {
|
||||
initPostThumbMedia(root);
|
||||
initGradientBackgrounds(root);
|
||||
});
|
||||
|
||||
function initRelatedSwiper() {
|
||||
var el = document.querySelector(".related-swiper[data-swiper-config]");
|
||||
if (!el || typeof Swiper === "undefined") return;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
}
|
||||
|
||||
function initAjaxPagination(root) {
|
||||
var containers = (root || document).querySelectorAll(".aksrt-pagination-ajax, .ajax-pagination");
|
||||
var containers = (root || document).querySelectorAll("[data-aksrt-pagination], .aksrt-comment-pagination");
|
||||
if (!containers.length) return;
|
||||
|
||||
var triggerText = (window.aksrtData && aksrtData.ajaxTrigger) || "加载更多";
|
||||
@@ -29,8 +29,9 @@
|
||||
var commentOrder = container.dataset.commentOrder || "newest";
|
||||
var loading = false;
|
||||
var failed = false;
|
||||
var loadMoreBtn = container.querySelector(".aksrt-load-more-btn, .ajax-next");
|
||||
var indicator = container.querySelector(".aksrt-loading-indicator");
|
||||
var clickTarget = container.querySelector(".next-page.ajax-next, .ias-btn") || container;
|
||||
var loadMoreBtn = container.querySelector("[data-aksrt-load-more]") || clickTarget;
|
||||
var indicator = container.querySelector(".post_ajax_loader");
|
||||
var successfulAutoLoads = 0;
|
||||
var iasMax = isComment
|
||||
? ((window.aksrtData && typeof aksrtData.commentIasMax !== "undefined") ? parseInt(aksrtData.commentIasMax, 10) : 0)
|
||||
@@ -68,13 +69,19 @@
|
||||
function stopInfinite(markNomore) {
|
||||
container.classList.remove("ias-pending");
|
||||
if (markNomore && loadMoreBtn) {
|
||||
loadMoreBtn.textContent = nomoreText;
|
||||
loadMoreBtn.innerHTML = nomoreText;
|
||||
loadMoreBtn.classList.remove("is-loading");
|
||||
loadMoreBtn.classList.add("ajax-nomore");
|
||||
var nextWrap = loadMoreBtn.closest(".next-page");
|
||||
if (nextWrap) nextWrap.classList.add("no-more");
|
||||
loadMoreBtn.style.pointerEvents = "none";
|
||||
} else if (loadMoreBtn && !loadMoreBtn.classList.contains("ajax-nomore")) {
|
||||
loadMoreBtn.classList.remove("is-loading");
|
||||
loadMoreBtn.textContent = failed ? errorText : triggerText;
|
||||
if (failed) {
|
||||
loadMoreBtn.textContent = errorText;
|
||||
} else {
|
||||
loadMoreBtn.innerHTML = triggerText;
|
||||
}
|
||||
loadMoreBtn.style.pointerEvents = "";
|
||||
}
|
||||
}
|
||||
@@ -164,7 +171,7 @@
|
||||
target.appendChild(newItems[0]);
|
||||
}
|
||||
}
|
||||
if (isComment && window.AksrtFrontend) {
|
||||
if (window.AksrtFrontend) {
|
||||
AksrtFrontend.rehydrate(target, "ajax");
|
||||
}
|
||||
nextPage++;
|
||||
@@ -191,13 +198,16 @@
|
||||
if (indicator) indicator.style.display = "none";
|
||||
if (loadMoreBtn && !loadMoreBtn.classList.contains("ajax-nomore") && !failed) {
|
||||
loadMoreBtn.classList.remove("is-loading");
|
||||
loadMoreBtn.textContent = triggerText;
|
||||
loadMoreBtn.innerHTML = triggerText;
|
||||
if (mode === "infinite") {
|
||||
var lazyTrigger = clickTarget.closest(".next-page") || clickTarget;
|
||||
if (iasMax > 0 && successfulAutoLoads >= iasMax) {
|
||||
stopInfinite(true);
|
||||
container.classList.remove("ias-pending");
|
||||
lazyTrigger.classList.remove("lazyload", "lazyloaded", "lazyloading");
|
||||
lazyTrigger.removeAttribute("lazyload-action");
|
||||
} else {
|
||||
loadMoreBtn.classList.remove("lazyloaded", "lazyloading");
|
||||
loadMoreBtn.classList.add("lazyload");
|
||||
lazyTrigger.classList.remove("lazyloaded", "lazyloading");
|
||||
lazyTrigger.classList.add("lazyload");
|
||||
if (window.lazySizes && lazySizes.loader) {
|
||||
lazySizes.loader.checkElems();
|
||||
}
|
||||
@@ -208,7 +218,7 @@
|
||||
}
|
||||
|
||||
if (loadMoreBtn) {
|
||||
loadMoreBtn.addEventListener("click", function(e) {
|
||||
clickTarget.addEventListener("click", function(e) {
|
||||
e.preventDefault();
|
||||
if (loadMoreBtn.dataset.jumpComments === "1") {
|
||||
var jumpInput = container.querySelector(".jump-input");
|
||||
@@ -228,14 +238,14 @@
|
||||
var archiveMax = parseInt(archiveJumpInput.dataset.maxPages || String(maxPages), 10) || maxPages;
|
||||
archiveTargetPage = Math.max(1, Math.min(archiveMax, archiveTargetPage));
|
||||
var archiveUrl = new URL(window.location.href);
|
||||
archiveUrl.searchParams.set("paged", String(archiveTargetPage));
|
||||
archiveUrl.searchParams.set(loadMoreBtn.dataset.pageVar || "paged", String(archiveTargetPage));
|
||||
window.location.href = archiveUrl.toString();
|
||||
return;
|
||||
}
|
||||
var fromAuto = loadMoreBtn.dataset.lazyAuto === "1";
|
||||
delete loadMoreBtn.dataset.lazyAuto;
|
||||
var fromAuto = clickTarget.dataset.lazyAuto === "1";
|
||||
delete clickTarget.dataset.lazyAuto;
|
||||
if (fromAuto && iasMax > 0 && successfulAutoLoads >= iasMax) {
|
||||
stopInfinite(true);
|
||||
container.classList.remove("ias-pending");
|
||||
return;
|
||||
}
|
||||
// Manual click can recover from a previous auto-load failure.
|
||||
@@ -246,8 +256,9 @@
|
||||
|
||||
if (mode === "infinite") {
|
||||
if ((isComment && window.aksrtData && aksrtData.commentIasAuto === false) || !hasAjaxConfig()) {
|
||||
loadMoreBtn.classList.remove("lazyload");
|
||||
loadMoreBtn.removeAttribute("lazyload-action");
|
||||
var autoTrigger = clickTarget.closest(".next-page") || clickTarget;
|
||||
autoTrigger.classList.remove("lazyload");
|
||||
autoTrigger.removeAttribute("lazyload-action");
|
||||
return;
|
||||
}
|
||||
container.classList.add("ias-pending");
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
(function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Grade=e()}})(function(){return function e(t,n,r){function i(o,s){if(!n[o]){if(!t[o]){var u="function"==typeof require&&require;if(!s&&u)return u(o,!0);if(a)return a(o,!0);var c=new Error("Cannot find module '"+o+"'");throw c.code="MODULE_NOT_FOUND",c}var g=n[o]={exports:{}};t[o][0].call(g.exports,function(e){var n=t[o][1][e];return i(n||e)},g,g.exports,e,t,n,r)}return n[o].exports}for(var a="function"==typeof require&&require,o=0;o<r.length;o++)i(r[o]);return i}({1:[function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var i=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),a=["webkit"],o=function(){function e(t,n,i){r(this,e),this.callback=i||null,this.container=t;var a=this.container.querySelector(n||"img");if(this.gradientData=[],a&&this.container){this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.imageData=[];var o=this;o.image=new Image,o.image.crossOrigin="Anonymous",o.image.src=a.getAttribute("data-src")||a.getAttribute("src"),o.image.onload=function(){o.readImage()}}}return i(e,[{key:"readImage",value:function(){this.imageDimensions={width:100,height:100},this.render()}},{key:"getImageData",value:function(){var e=this.ctx.getImageData(0,0,this.imageDimensions.width,this.imageDimensions.height).data;this.imageData=Array.from(e)}},{key:"getChunkedImageData",value:function(){var e=4,t=this.imageData.reduce(function(t,n,r){var i=Math.floor(r/e);return t[i]||(t[i]=[]),t[i].push(n),t},[]),n=t.filter(function(e){var t=e[0],n=e[1],r=e[2],i=Math.max(Math.abs(t-n),Math.abs(t-r),Math.abs(n-r));return i>20});return(!n||n.length<2)&&(n=t.filter(function(e){return e.slice(0,2).every(function(e){return e<245})&&e.slice(0,2).every(function(e){return e>10})})),n}},{key:"getRGBAGradientValues",value:function(e){return e.map(function(e,t){return"rgb("+e.rgba.slice(0,3).join(",")+") "+(0==t?"0%":"75%")}).join(",")}},{key:"getCSSGradientProperty",value:function(e){var t=this.getRGBAGradientValues(e);return a.map(function(e){return"background-image: -"+e+"-linear-gradient(\n 135deg,\n "+t+"\n )"}).concat(["background-image: linear-gradient(\n 135deg,\n "+t+"\n )"]).join(";")}},{key:"getMiddleRGB",value:function(e,t){var n=0,r=(n+1)/2,i=1-r,a=[parseInt(e[0]*r+t[0]*i),parseInt(e[1]*r+t[1]*i),parseInt(e[2]*r+t[2]*i)];return a}},{key:"getSortedValues",value:function(e){var t=Object.keys(e).map(function(t){var n=t,r=t.split("|"),i=(299*r[0]+587*r[1]+114*r[2])/1e3;return{rgba:n.split("|"),occurs:e[t],brightness:i}}).sort(function(e,t){return e.occurs-t.occurs}).reverse().slice(0,10);return t.sort(function(e,t){return e.brightness-t.brightness}).reverse()}},{key:"getTextProperty",value:function(e){var t=this.getMiddleRGB(e[0].rgba.slice(0,3),e[1].rgba.slice(0,3)),n=Math.round((299*parseInt(t[0])+587*parseInt(t[1])+114*parseInt(t[2]))/1e3);return n>125?"color: #000":"color: #fff"}},{key:"getTopValues",value:function(e){var t=this.getSortedValues(e);return[t[0],t[t.length-1]]}},{key:"getUniqValues",value:function(e){return e.reduce(function(e,t){var n=t.join("|");return e[n]?(e[n]=++e[n],e):(e[n]=1,e)},{})}},{key:"renderGradient",value:function(){var e=window.localStorage,t="grade-"+this.image.getAttribute("src"),n=null;if(e&&e.getItem(t)&&(n=JSON.parse(e.getItem(t))),!n||!n[0]){var r=this.getChunkedImageData();n=this.getTopValues(this.getUniqValues(r)),e&&e.setItem(t,JSON.stringify(n))}if(this.callback)return this.gradientData=n,void this.callback([{element:this.container,gradientData:n}]);var i=this.getCSSGradientProperty(n),a=this.getTextProperty(n),o=(this.container.getAttribute("style")||"")+"; "+i+"; "+a;this.container.setAttribute("style",o)}},{key:"render",value:function(){this.canvas.width=this.imageDimensions.width,this.canvas.height=this.imageDimensions.height,this.ctx.drawImage(this.image,0,0,this.imageDimensions.width,this.imageDimensions.height),this.getImageData(),this.renderGradient()}}]),e}();t.exports=function(e,t,n){var r=function(e,t,n){var r=new o(e,t,n),i=r.gradientData;return i.length?{element:e,gradientData:i}:null},i=(NodeList.prototype.isPrototypeOf(e)?Array.from(e).map(function(e){return r(e,t,n)}):[r(e,t,n)]).filter(Boolean);if(i.length)return n(i)}},{}]},{},[1])(1)});
|
||||
+5
-110
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Homepage Fixed - Interactive Layer (v2.0 Zibll-aligned)
|
||||
*
|
||||
* Unified AJAX protocol for homepage tabs, sort, pagination, and view toggle.
|
||||
* Unified AJAX protocol for homepage tabs, sort, and pagination.
|
||||
* Uses Zibll-style ajaxpager DOM conventions and custom event flow:
|
||||
* post_ajax.before → fetch → post_ajax.ed → aksrt:posts:rendered
|
||||
*
|
||||
@@ -11,34 +11,18 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var STORAGE_KEY = 'aksrt_homepage_view_mode';
|
||||
var SORT_QUERY_KEY = 'home_sort';
|
||||
var DEFAULT_SORT = 'modified';
|
||||
var DEFAULT_VIEW = 'list';
|
||||
var REST_PATH = '/wp-json/aksrt/v1/homepage/tab-posts';
|
||||
|
||||
/* ============================================================
|
||||
* Utilities
|
||||
* ============================================================ */
|
||||
|
||||
function safeLocalStorage() {
|
||||
try { return window.localStorage; } catch (e) { return null; }
|
||||
}
|
||||
|
||||
function getViewMode() {
|
||||
var store = safeLocalStorage();
|
||||
if (store) {
|
||||
var saved = store.getItem(STORAGE_KEY);
|
||||
if (saved === 'card' || saved === 'list') return saved;
|
||||
}
|
||||
return getDefaultView();
|
||||
}
|
||||
|
||||
function setViewMode(mode) {
|
||||
var store = safeLocalStorage();
|
||||
if (store) { try { store.setItem(STORAGE_KEY, mode); } catch (e) { /* */ } }
|
||||
}
|
||||
|
||||
function getRenderedPostCount(scope) {
|
||||
if (!scope) return 0;
|
||||
return scope.querySelectorAll('.posts-item, .posts-mini').length;
|
||||
@@ -63,8 +47,8 @@
|
||||
}
|
||||
|
||||
function getDefaultView() {
|
||||
var configured = window.aksrtData && aksrtData.homepageDefaultView;
|
||||
return configured === 'card' || configured === 'list' ? configured : DEFAULT_VIEW;
|
||||
var panel = document.querySelector('[data-home-tab-panel][data-view]');
|
||||
return panel && panel.getAttribute('data-view') === 'card' ? 'card' : 'list';
|
||||
}
|
||||
|
||||
function isSortAjaxEnabled(sortbar) {
|
||||
@@ -119,8 +103,8 @@
|
||||
}
|
||||
|
||||
function getStreamViewMode(stream) {
|
||||
var activeBtn = stream.querySelector('.aksrt-homepage__view-btn.is-active');
|
||||
return (activeBtn && activeBtn.getAttribute('data-view-mode')) || getViewMode();
|
||||
var panel = getActivePanel(stream);
|
||||
return panel && panel.getAttribute('data-view') === 'card' ? 'card' : 'list';
|
||||
}
|
||||
|
||||
function getActivePanel(stream) {
|
||||
@@ -153,7 +137,6 @@
|
||||
'&page=' + encodeURIComponent(options.page || 1) +
|
||||
'&per_page=' + encodeURIComponent(options.perPage || 10) +
|
||||
'&sort=' + encodeURIComponent(options.sort || getDefaultSort()) +
|
||||
'&view_mode=' + encodeURIComponent(options.viewMode || getDefaultView()) +
|
||||
'&page_url=' + encodeURIComponent(options.pageUrl || window.location.href) +
|
||||
'&panel=' + encodeURIComponent(options.panel || 'latest') +
|
||||
'&source=' + encodeURIComponent(options.source || 'home') +
|
||||
@@ -731,93 +714,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* View Mode Toggle
|
||||
* ============================================================ */
|
||||
|
||||
function applyViewMode(buttons, postsContainers, mode) {
|
||||
buttons.forEach(function (btn) {
|
||||
var btnMode = btn.getAttribute('data-view-mode');
|
||||
var isActive = btnMode === mode;
|
||||
btn.classList.toggle('is-active', isActive);
|
||||
btn.setAttribute('aria-pressed', isActive ? 'true' : 'false');
|
||||
});
|
||||
Array.prototype.forEach.call(postsContainers, function (container) {
|
||||
container.setAttribute('data-view', mode);
|
||||
container.querySelectorAll('.posts-item').forEach(function (item) {
|
||||
item.classList.toggle('card', mode === 'card');
|
||||
item.classList.toggle('list', mode === 'list');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initViewToggle() {
|
||||
var toggles = document.querySelectorAll('[data-aksrt-view-toggle]');
|
||||
|
||||
toggles.forEach(function (toggle) {
|
||||
var buttons = toggle.querySelectorAll('.aksrt-homepage__view-btn');
|
||||
var stream = toggle.closest('.aksrt-homepage__stream');
|
||||
if (!stream) return;
|
||||
|
||||
function getPostsContainers() {
|
||||
return stream.querySelectorAll('[data-home-tab-panel]');
|
||||
}
|
||||
|
||||
function getActiveMode() {
|
||||
var activeBtn = toggle.querySelector('.aksrt-homepage__view-btn.is-active');
|
||||
return (activeBtn && activeBtn.getAttribute('data-view-mode')) || getViewMode();
|
||||
}
|
||||
|
||||
var initialMode = getViewMode();
|
||||
var activePanel = getActivePanel(stream);
|
||||
var renderedMode = activePanel ? activePanel.getAttribute('data-view') : '';
|
||||
applyViewMode(buttons, getPostsContainers(), initialMode);
|
||||
|
||||
// The persisted preference may differ from the server-rendered mode.
|
||||
// Class toggling alone leaves list-only markup and its `.flex` utility in
|
||||
// place, which forces a supposed card to occupy a full row. Fetch the
|
||||
// matching renderer immediately so DOM and visual mode stay atomic.
|
||||
if (activePanel && renderedMode !== initialMode) {
|
||||
requestHomepagePanel(activePanel, {
|
||||
termId: getPanelTermId(activePanel),
|
||||
page: 1,
|
||||
perPage: getHomepagePerPage(activePanel),
|
||||
sort: getCurrentSort(stream),
|
||||
viewMode: initialMode,
|
||||
panel: activePanel.getAttribute('data-home-tab-panel') || 'latest',
|
||||
source: 'home',
|
||||
tabOrderby: getPanelTabOrderby(activePanel)
|
||||
});
|
||||
}
|
||||
|
||||
buttons.forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var mode = btn.getAttribute('data-view-mode') || getDefaultView();
|
||||
var activePanel = getActivePanel(stream);
|
||||
if (!activePanel || mode === getActiveMode()) return;
|
||||
|
||||
setViewMode(mode);
|
||||
applyViewMode(buttons, getPostsContainers(), mode);
|
||||
requestHomepagePanel(activePanel, {
|
||||
termId: getPanelTermId(activePanel),
|
||||
page: 1,
|
||||
perPage: getHomepagePerPage(activePanel),
|
||||
sort: getCurrentSort(stream),
|
||||
viewMode: mode,
|
||||
panel: activePanel.getAttribute('data-home-tab-panel') || 'latest',
|
||||
source: 'home',
|
||||
tabOrderby: getPanelTabOrderby(activePanel)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Re-apply view mode after AJAX content renders
|
||||
stream.addEventListener('aksrt:posts:rendered', function () {
|
||||
applyViewMode(buttons, getPostsContainers(), getActiveMode());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Init
|
||||
* ============================================================ */
|
||||
@@ -827,7 +723,6 @@
|
||||
initSortbarDropdown();
|
||||
initSortbar();
|
||||
initStickyTabs();
|
||||
initViewToggle();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
|
||||
+3
-20
@@ -36,7 +36,6 @@ if (!$term instanceof WP_Term) {
|
||||
$archive_settings = class_exists('\AKSRT\Core\TermMeta')
|
||||
? \AKSRT\Core\TermMeta::resolve_archive_settings($term)
|
||||
: [
|
||||
'layout_mode' => 'card',
|
||||
'header_style' => 'cover',
|
||||
'show_sidebar' => true,
|
||||
'show_cover' => false,
|
||||
@@ -44,7 +43,6 @@ $archive_settings = class_exists('\AKSRT\Core\TermMeta')
|
||||
'filter_bar' => true,
|
||||
'cover_url' => '',
|
||||
'description' => (string) $term->description,
|
||||
'card_style' => 'standard',
|
||||
];
|
||||
|
||||
$has_sidebar = function_exists('aksrt_archive_has_sidebar')
|
||||
@@ -52,8 +50,6 @@ $has_sidebar = function_exists('aksrt_archive_has_sidebar')
|
||||
: (!empty($archive_settings['show_sidebar']) && is_active_sidebar('cat_sidebar'));
|
||||
$description = !empty($archive_settings['show_desc']) ? wp_kses_post((string) $archive_settings['description']) : '';
|
||||
$header_style = (string) $archive_settings['header_style'];
|
||||
$layout_mode = (string) $archive_settings['layout_mode'];
|
||||
$card_style = (string) ($archive_settings['card_style'] ?? 'standard');
|
||||
$filter_settings = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_filter_settings()
|
||||
: ['enabled' => false, 'sort' => false, 'ajax_enabled' => false];
|
||||
@@ -68,20 +64,9 @@ $custom_dimensions = is_array($cat_filter_config['dimensions'] ?? null) ? $cat_f
|
||||
$sort_state = function_exists('aksrt_archive_get_sort_state') ? aksrt_archive_get_sort_state() : ['current' => 'latest', 'links' => []];
|
||||
$current_sort = $sort_state['current'];
|
||||
$sort_links = $sort_state['links'];
|
||||
$render_overrides = [
|
||||
'context' => 'category',
|
||||
];
|
||||
// Term meta layout_mode is authoritative only when explicitly set (non-empty preset).
|
||||
$layout_preset = (string) ($archive_settings['layout_preset'] ?? '');
|
||||
if ($layout_preset !== '' && in_array((string) $layout_mode, ['list', 'card', 'mini', 'grid-cms'], true)) {
|
||||
$render_overrides['mode'] = (string) $layout_mode;
|
||||
if (!empty($card_style)) {
|
||||
$render_overrides['card_style'] = (string) $card_style;
|
||||
}
|
||||
}
|
||||
$render_config = function_exists('aksrt_archive_get_render_config')
|
||||
? aksrt_archive_get_render_config($render_overrides)
|
||||
: array_merge(['context' => 'category', 'mode' => 'list'], $render_overrides);
|
||||
$render_config = function_exists('aksrt_archive_get_render_config')
|
||||
? aksrt_archive_get_render_config(['context' => 'category'])
|
||||
: ['context' => 'category'];
|
||||
|
||||
$filter_terms = [];
|
||||
$filter_all_url = get_category_link($term->term_id);
|
||||
@@ -226,8 +211,6 @@ if (function_exists('aksrt_archive_open_shell')) {
|
||||
'ajax' => $ajax_filter,
|
||||
'ajax_archive' => 'category',
|
||||
'term_id' => (int) $term->term_id,
|
||||
'layout_mode' => $layout_mode,
|
||||
'card_style' => $card_style,
|
||||
'aria_label' => __('分类筛选', 'aksrt'),
|
||||
'meta_text' => sprintf(_n('%d 篇文章', '%d 篇文章', (int) $term->count, 'aksrt'), (int) $term->count),
|
||||
'groups' => $filter_groups,
|
||||
|
||||
@@ -130,8 +130,6 @@ if (!function_exists('aksrt_archive_render_filter_bar')) :
|
||||
'ajax' => false,
|
||||
'ajax_archive' => '',
|
||||
'term_id' => 0,
|
||||
'layout_mode' => 'card',
|
||||
'card_style' => 'standard',
|
||||
'aria_label' => '',
|
||||
'meta_text' => '',
|
||||
'groups' => [],
|
||||
@@ -157,8 +155,6 @@ if (!function_exists('aksrt_archive_render_filter_bar')) :
|
||||
data-ajax-archive="<?php echo esc_attr((string) $args['ajax_archive']); ?>"
|
||||
data-term-id="<?php echo (int) $args['term_id']; ?>"
|
||||
data-query-context="archive"
|
||||
data-render-mode="<?php echo esc_attr((string) $args['layout_mode']); ?>"
|
||||
data-card-style="<?php echo esc_attr((string) $args['card_style']); ?>"
|
||||
<?php endif; ?>
|
||||
>
|
||||
<?php foreach ($groups as $group) : ?>
|
||||
|
||||
+21
-176
@@ -16,45 +16,15 @@ if (!function_exists('aksrt_archive_get_list_style_settings')) :
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
function aksrt_archive_get_list_style_settings(): array {
|
||||
$settings = class_exists('\AKSRT\Settings\Settings')
|
||||
return class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_list_style_settings()
|
||||
: [];
|
||||
|
||||
return [
|
||||
'list_type' => (string) ($settings['list_type'] ?? 'thumb'),
|
||||
'render_mode' => (string) ($settings['render_mode'] ?? 'list'),
|
||||
'list_type_token' => (string) ($settings['list_type_token'] ?? ($settings['list_type'] ?? 'thumb')),
|
||||
'list_style' => (string) ($settings['list_style'] ?? ''),
|
||||
'card_variant' => (string) ($settings['card_variant'] ?? ''),
|
||||
// Back-compat: older callers expected card_style as list_type token.
|
||||
'card_style' => (string) ($settings['list_type'] ?? ($settings['card_style'] ?? 'thumb')),
|
||||
'card_cat_ids' => is_array($settings['card_cat_ids'] ?? null) ? array_map('intval', $settings['card_cat_ids']) : [],
|
||||
'card_home' => !empty($settings['card_home']),
|
||||
'card_tag' => !empty($settings['card_tag']),
|
||||
'card_author' => !empty($settings['card_author']),
|
||||
'list_show_type' => (string) ($settings['list_show_type'] ?? 'separate'),
|
||||
'list_img_position'=> (string) ($settings['list_img_position'] ?? 'left'),
|
||||
'show_author' => !isset($settings['show_author']) || !empty($settings['show_author']),
|
||||
'show_date' => !isset($settings['show_date']) || !empty($settings['show_date']),
|
||||
'show_views' => !isset($settings['show_views']) || !empty($settings['show_views']),
|
||||
'show_comments' => !empty($settings['show_comments']),
|
||||
'show_likes' => !empty($settings['show_likes']),
|
||||
'target_blank' => !empty($settings['target_blank']),
|
||||
'heading_bold' => !empty($settings['heading_bold']),
|
||||
'badge_show' => !isset($settings['badge_show']) || !empty($settings['badge_show']),
|
||||
'excerpt_length' => (int) ($settings['excerpt_length'] ?? 120),
|
||||
];
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_resolve_post_list_render_config')) :
|
||||
/**
|
||||
* Zibll-aligned list/card resolver for all surfaces.
|
||||
*
|
||||
* Decision order mirrors zib_mian_posts_while():
|
||||
* 1) explicit override mode/type
|
||||
* 2) global list_type (post_card_style): only "card" is card grid; thumb/text/thumb_if_has are list
|
||||
* 3) surface card switches (home/tag/author/cat IDs)
|
||||
* Build the Zibll-shaped arguments used by every list surface.
|
||||
*
|
||||
* @param array<string,mixed> $args {
|
||||
* @type string $context home|category|tag|author|search|archive
|
||||
@@ -66,16 +36,10 @@ if (!function_exists('aksrt_resolve_post_list_render_config')) :
|
||||
function aksrt_resolve_post_list_render_config(array $args = []): array {
|
||||
$args = wp_parse_args($args, [
|
||||
'context' => '',
|
||||
'term_id' => 0,
|
||||
'overrides' => [],
|
||||
]);
|
||||
|
||||
$overrides = is_array($args['overrides']) ? $args['overrides'] : [];
|
||||
if (!empty($args['context']) && empty($overrides['context'])) {
|
||||
// keep context on root for merge below
|
||||
}
|
||||
|
||||
$context = sanitize_key((string) ($args['context'] !== '' ? $args['context'] : ($overrides['context'] ?? '')));
|
||||
$context = sanitize_key((string) ($args['context'] ?: ($overrides['context'] ?? '')));
|
||||
if ($context === '') {
|
||||
if (function_exists('is_front_page') && (is_front_page() || is_home())) {
|
||||
$context = 'home';
|
||||
@@ -91,125 +55,20 @@ if (!function_exists('aksrt_resolve_post_list_render_config')) :
|
||||
$context = 'archive';
|
||||
}
|
||||
}
|
||||
|
||||
$term_id = (int) ($args['term_id'] ?? 0);
|
||||
if ($term_id <= 0) {
|
||||
$term_id = (int) get_queried_object_id();
|
||||
}
|
||||
|
||||
$list = aksrt_archive_get_list_style_settings();
|
||||
$list_type = sanitize_key((string) ($list['list_type'] ?? 'thumb'));
|
||||
if ($list_type === '' || $list_type === 'standard') {
|
||||
$list_type = 'thumb';
|
||||
}
|
||||
|
||||
// Explicit caller mode wins (term meta, AJAX view toggle, etc.).
|
||||
$forced_mode = '';
|
||||
if (isset($overrides['mode']) && is_string($overrides['mode']) && $overrides['mode'] !== '') {
|
||||
$forced_mode = sanitize_key($overrides['mode']);
|
||||
} elseif (isset($overrides['type']) && sanitize_key((string) $overrides['type']) === 'card') {
|
||||
$forced_mode = 'card';
|
||||
} elseif (!empty($overrides['is_card'])) {
|
||||
$forced_mode = 'card';
|
||||
}
|
||||
|
||||
$mode = $forced_mode !== ''
|
||||
? $forced_mode
|
||||
: (($list_type === 'card') ? 'card' : 'list');
|
||||
|
||||
// Surface card overrides (only when not already card from list_type / force).
|
||||
if ($mode !== 'card' && $forced_mode === '') {
|
||||
if ($context === 'home' && !empty($list['card_home'])) {
|
||||
$mode = 'card';
|
||||
} elseif ($context === 'tag' && !empty($list['card_tag'])) {
|
||||
$mode = 'card';
|
||||
} elseif ($context === 'author' && !empty($list['card_author'])) {
|
||||
$mode = 'card';
|
||||
} elseif ($term_id > 0 && !empty($list['card_cat_ids']) && in_array($term_id, array_map('intval', (array) $list['card_cat_ids']), true)) {
|
||||
$mode = 'card';
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_array($mode, ['list', 'card', 'mini', 'grid-cms'], true)) {
|
||||
$mode = 'list';
|
||||
}
|
||||
|
||||
// Visual variant: list → style2; card → style3 (Zibll fieldsets).
|
||||
$style = '';
|
||||
if ($mode === 'card') {
|
||||
$style = sanitize_key((string) ($list['card_variant'] ?? ''));
|
||||
if (!in_array($style, ['', 'style3'], true)) {
|
||||
$style = '';
|
||||
}
|
||||
} else {
|
||||
$style = sanitize_key((string) ($list['list_style'] ?? ''));
|
||||
if (!in_array($style, ['', 'style2'], true)) {
|
||||
$style = '';
|
||||
}
|
||||
}
|
||||
if (isset($overrides['style']) && is_string($overrides['style'])) {
|
||||
$style = sanitize_key($overrides['style']);
|
||||
if (in_array($style, ['default', 'null'], true)) {
|
||||
$style = '';
|
||||
}
|
||||
}
|
||||
|
||||
$excerpt_words = max(8, (int) round(((int) ($list['excerpt_length'] ?? 120)) / 4));
|
||||
|
||||
$config = [
|
||||
'context' => $context,
|
||||
'mode' => $mode,
|
||||
// list_type token for text / thumb_if_has hooks (renderer card_style key).
|
||||
'card_style' => $list_type,
|
||||
'style' => $style === 'default' ? '' : $style,
|
||||
'list_show_type' => (string) ($list['list_show_type'] ?? 'separate'),
|
||||
'list_img_position' => (string) ($list['list_img_position'] ?? 'left'),
|
||||
'thumb_if_has' => ($list_type === 'thumb_if_has'),
|
||||
'show_thumb' => ($list_type !== 'text'),
|
||||
'show_author' => !empty($list['show_author']),
|
||||
'show_date' => !empty($list['show_date']),
|
||||
'show_views' => !empty($list['show_views']),
|
||||
'show_comments' => !empty($list['show_comments']),
|
||||
'show_likes' => !empty($list['show_likes']),
|
||||
'target_blank' => !empty($list['target_blank']),
|
||||
'heading_bold' => !empty($list['heading_bold']),
|
||||
'badge_show' => !empty($list['badge_show']),
|
||||
'show_excerpt' => $mode !== 'card',
|
||||
'excerpt_words' => $excerpt_words,
|
||||
'context' => $context,
|
||||
'is_home' => $context === 'home',
|
||||
'is_category' => $context === 'category',
|
||||
'is_tag' => $context === 'tag',
|
||||
'is_author' => $context === 'author',
|
||||
'is_search' => $context === 'search',
|
||||
];
|
||||
|
||||
// Multi-thumb from global thumb settings + category allowlist.
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$thumb_settings = \AKSRT\Settings\Settings::get_post_thumb_settings();
|
||||
if (!empty($thumb_settings['multi_enabled'])) {
|
||||
$config['multi_thumb_enabled'] = true;
|
||||
$config['multi_thumb_limit'] = (int) ($thumb_settings['multi_count'] ?? 4);
|
||||
$config['multi_thumb_min'] = 3;
|
||||
}
|
||||
if ($context === 'category' && !empty($thumb_settings['mult_thumb_cat_ids']) && $term_id > 0) {
|
||||
if (in_array($term_id, array_map('intval', (array) $thumb_settings['mult_thumb_cat_ids']), true)) {
|
||||
$config['multi_thumb_enabled'] = true;
|
||||
$config['multi_thumb_limit'] = (int) ($thumb_settings['multi_count'] ?? 4);
|
||||
$config['multi_thumb_min'] = 3;
|
||||
}
|
||||
foreach (['type', 'no_author', 'no_margin', 'is_mult_thumb', 'is_no_thumb', 'is_card', 'highlight_query', 'wrapper_class', 'skip_wrapper'] as $key) {
|
||||
if (array_key_exists($key, $overrides)) {
|
||||
$config[$key] = $overrides[$key];
|
||||
}
|
||||
}
|
||||
|
||||
// Merge remaining overrides last (except mode/style already handled carefully).
|
||||
foreach ($overrides as $key => $value) {
|
||||
if (in_array($key, ['mode', 'type', 'is_card', 'style', 'context'], true)) {
|
||||
continue;
|
||||
}
|
||||
$config[$key] = $value;
|
||||
}
|
||||
// Re-apply forced mode after merge if present.
|
||||
if ($forced_mode !== '' && in_array($forced_mode, ['list', 'card', 'mini', 'grid-cms'], true)) {
|
||||
$config['mode'] = $forced_mode;
|
||||
}
|
||||
$config['context'] = $context;
|
||||
$config['style'] = $style === 'default' ? '' : $style;
|
||||
|
||||
return $config;
|
||||
return aksrt_renderer_config($config);
|
||||
}
|
||||
endif;
|
||||
|
||||
@@ -222,18 +81,9 @@ if (!function_exists('aksrt_archive_get_render_config')) :
|
||||
*/
|
||||
function aksrt_archive_get_render_config(array $overrides = []): array {
|
||||
$context = sanitize_key((string) ($overrides['context'] ?? ''));
|
||||
$term_id = isset($overrides['term_id']) ? (int) $overrides['term_id'] : 0;
|
||||
|
||||
// Only treat explicit mode as override; empty string means follow global resolver.
|
||||
$resolver_overrides = $overrides;
|
||||
if (isset($resolver_overrides['mode']) && $resolver_overrides['mode'] === '') {
|
||||
unset($resolver_overrides['mode']);
|
||||
}
|
||||
|
||||
return aksrt_resolve_post_list_render_config([
|
||||
'context' => $context,
|
||||
'term_id' => $term_id,
|
||||
'overrides' => $resolver_overrides,
|
||||
'overrides' => $overrides,
|
||||
]);
|
||||
}
|
||||
endif;
|
||||
@@ -351,15 +201,14 @@ if (!function_exists('aksrt_archive_render_stream')) :
|
||||
$classes[] = 'is-ajax-enabled';
|
||||
}
|
||||
|
||||
$mode = (string) ($render_config['mode'] ?? 'card');
|
||||
$card_style = (string) ($render_config['card_style'] ?? 'standard');
|
||||
$mode = (string) ($render_config['mode'] ?? 'list');
|
||||
$has_posts = $query instanceof WP_Query ? $query->have_posts() : have_posts();
|
||||
?>
|
||||
<div
|
||||
class="<?php echo esc_attr(implode(' ', array_unique($classes))); ?>"
|
||||
data-page-kind="<?php echo esc_attr((string) $args['page_kind']); ?>"
|
||||
data-render-mode="<?php echo esc_attr($mode); ?>"
|
||||
data-card-style="<?php echo esc_attr($card_style); ?>"
|
||||
data-list-type="<?php echo esc_attr((string) ($render_config['list_type'] ?? 'thumb')); ?>"
|
||||
<?php if (!empty($args['ajax_enabled'])) : ?>
|
||||
data-ajax-wrap
|
||||
data-query-context="<?php echo esc_attr((string) $args['query_context']); ?>"
|
||||
@@ -372,18 +221,14 @@ if (!function_exists('aksrt_archive_render_stream')) :
|
||||
|
||||
<?php if ($has_posts) : ?>
|
||||
<?php
|
||||
if (function_exists('aksrt_render_post_list')) {
|
||||
aksrt_render_post_list($query, array_merge($render_config, ['wrapper_class' => 'content-stream__list']));
|
||||
}
|
||||
aksrt_render_post_list(array_merge($render_config, ['wrapper_class' => 'content-stream__list']), $query);
|
||||
?>
|
||||
<div class="content-stream__footer">
|
||||
<?php
|
||||
if (function_exists('aksrt_render_pagination')) {
|
||||
aksrt_render_pagination($query, [
|
||||
'query_context' => (string) $args['query_context'],
|
||||
'render_config' => $render_config,
|
||||
]);
|
||||
}
|
||||
aksrt_render_pagination($query, [
|
||||
'query_context' => (string) $args['query_context'],
|
||||
'render_config' => $render_config,
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
|
||||
@@ -1,44 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* AKSRT Flow Helper
|
||||
*
|
||||
* v4 起主题统一为 CMS / 资源站形态,不再提供 blog 形态分流。
|
||||
* 历史 helper 全部保留签名以保证兼容,但实际行为已收敛:
|
||||
*
|
||||
* aksrt_get_site_profile() 始终返回 'cms'
|
||||
* aksrt_get_term_flow() 始终返回 'inherit'(不再读取 term meta)
|
||||
* aksrt_is_resource_post() 仍按 _aksrt_is_resource meta 判定
|
||||
* aksrt_get_post_flow() 始终返回 'cms'
|
||||
* aksrt_is_cms_mode() 始终返回 true
|
||||
* aksrt_flow_layout_for() 始终返回 'grid-cms'
|
||||
* Resource-post predicate.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_get_site_profile')) {
|
||||
/**
|
||||
* @deprecated v4 起恒为 'cms',保留仅为向后兼容。
|
||||
* @return string 'cms'
|
||||
*/
|
||||
function aksrt_get_site_profile(): string {
|
||||
return 'cms';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_get_term_flow')) {
|
||||
/**
|
||||
* @deprecated v4 起恒为 'inherit',term meta 不再生效。
|
||||
* @param int $term_id
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_get_term_flow(int $term_id): string {
|
||||
unset($term_id);
|
||||
return 'inherit';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_is_resource_post')) {
|
||||
/**
|
||||
* 是否为资源帖:普通 post + _aksrt_is_resource meta。
|
||||
@@ -52,42 +20,5 @@ if (!function_exists('aksrt_is_resource_post')) {
|
||||
return false;
|
||||
}
|
||||
return (bool) get_post_meta($p->ID, '_aksrt_is_resource', true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_get_post_flow')) {
|
||||
/**
|
||||
* @deprecated v4 起恒为 'cms'。
|
||||
*
|
||||
* @param int|WP_Post|null $post
|
||||
* @return string 'cms'
|
||||
*/
|
||||
function aksrt_get_post_flow($post = null): string {
|
||||
unset($post);
|
||||
return 'cms';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_is_cms_mode')) {
|
||||
/**
|
||||
* 当前请求是否处在 CMS 形态。v4 起全站统一 CMS。
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function aksrt_is_cms_mode(): bool {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_flow_layout_for')) {
|
||||
/**
|
||||
* @deprecated v4 起恒为 'grid-cms'。
|
||||
*
|
||||
* @param string $flow
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_flow_layout_for(string $flow): string {
|
||||
unset($flow);
|
||||
return 'grid-cms';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +77,6 @@ if (!function_exists('aksrt_resolve_single_post_display_settings')) :
|
||||
'related_enabled' => true,
|
||||
'related_count' => 6,
|
||||
'related_style' => 'img',
|
||||
'related_source' => 'category',
|
||||
'related_type' => 'category',
|
||||
'related_orderby' => 'views',
|
||||
'related_title' => '',
|
||||
'breadcrumbs_single_text' => true,
|
||||
@@ -130,17 +128,6 @@ if (!function_exists('aksrt_resolve_single_post_display_settings')) :
|
||||
if (!array_key_exists('authordesc', $settings) && array_key_exists('authordesc_s', $settings)) {
|
||||
$settings['authordesc'] = !empty($settings['authordesc_s']);
|
||||
}
|
||||
// related_style / related_source (legacy related_type held either).
|
||||
if (!array_key_exists('related_style', $settings) || !in_array((string) $settings['related_style'], ['img', 'list', 'text'], true)) {
|
||||
$legacy = sanitize_key((string) ($settings['related_type'] ?? ''));
|
||||
$settings['related_style'] = in_array($legacy, ['img', 'list', 'text'], true) ? $legacy : 'img';
|
||||
}
|
||||
if (!array_key_exists('related_source', $settings) || !in_array((string) $settings['related_source'], ['category', 'tag', 'random'], true)) {
|
||||
$legacy = sanitize_key((string) ($settings['related_type'] ?? ''));
|
||||
$settings['related_source'] = in_array($legacy, ['category', 'tag', 'random'], true) ? $legacy : 'category';
|
||||
}
|
||||
// Keep related_type as source alias for older callers.
|
||||
$settings['related_type'] = (string) $settings['related_source'];
|
||||
$meta = class_exists('\AKSRT\Core\PostMetaBox') ? \AKSRT\Core\PostMetaBox::get_meta($post->ID) : [];
|
||||
// show_toc new route: '' follow | '1' on | '0' off
|
||||
if (array_key_exists('show_toc', $meta) && $meta['show_toc'] !== '' && $meta['show_toc'] !== null) {
|
||||
@@ -398,7 +385,7 @@ if (!function_exists('aksrt_render_mini_post_item')) :
|
||||
/**
|
||||
* Render a compact sidebar post item for homepage widgets.
|
||||
*
|
||||
* Thin wrapper over the unified shared renderer (mode=mini).
|
||||
* Render the dedicated Zibll mini-list item.
|
||||
*
|
||||
* @param int|WP_Post|null $post
|
||||
* @param array<string, mixed> $args
|
||||
@@ -408,72 +395,15 @@ if (!function_exists('aksrt_render_mini_post_item')) :
|
||||
if (!($post instanceof WP_Post)) {
|
||||
return;
|
||||
}
|
||||
// Set up the global post so the shared renderer works
|
||||
global $wp_query;
|
||||
$original_post = isset($wp_query->post) ? $wp_query->post : null;
|
||||
$wp_query->post = $post;
|
||||
setup_postdata($post);
|
||||
if (function_exists('aksrt_render_post')) {
|
||||
$config = [
|
||||
'mode' => 'mini',
|
||||
'context' => 'sidebar',
|
||||
'show_thumb' => true,
|
||||
'show_meta' => !isset($args['show_views']) || !empty($args['show_views']),
|
||||
];
|
||||
if (!empty($args['class']) && is_string($args['class'])) {
|
||||
$config['extra_class'] = $args['class'];
|
||||
}
|
||||
echo aksrt_render_post($config); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
} else {
|
||||
// Fallback: self-contained mini rendering
|
||||
$post_id = (int) $post->ID;
|
||||
$title = get_the_title($post_id);
|
||||
$permalink = get_permalink($post_id);
|
||||
$thumb_url = has_post_thumbnail($post_id)
|
||||
? (string) get_the_post_thumbnail_url($post_id, 'medium')
|
||||
: '';
|
||||
if ($thumb_url === '' && function_exists('aksrt_get_first_content_image_url')) {
|
||||
$thumb_url = (string) aksrt_get_first_content_image_url($post_id);
|
||||
}
|
||||
$placeholder_url = get_template_directory_uri() . '/assets/img/placeholder.svg';
|
||||
$view_count = function_exists('aksrt_get_post_views') ? (int) aksrt_get_post_views($post_id) : 0;
|
||||
$show_views = !isset($args['show_views']) || !empty($args['show_views']);
|
||||
$date_text = function_exists('aksrt_time_ago')
|
||||
? aksrt_time_ago((string) $post->post_date)
|
||||
: get_the_date('Y-m-d', $post_id);
|
||||
$classes = ['posts-mini'];
|
||||
if (!empty($args['class']) && is_string($args['class'])) {
|
||||
foreach (preg_split('/\s+/', trim($args['class'])) as $extra_class) {
|
||||
$extra_class = sanitize_html_class($extra_class);
|
||||
if ($extra_class !== '') {
|
||||
$classes[] = $extra_class;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<article class="<?php echo esc_attr(implode(' ', array_unique($classes))); ?>">
|
||||
<a href="<?php echo esc_url($permalink); ?>" class="item-thumbnail" aria-label="<?php echo esc_attr($title); ?>">
|
||||
<img<?php echo aksrt_get_lazy_attr('lazy_posts_thumb', (string) ($thumb_url !== '' ? $thumb_url : $placeholder_url), 'fit-cover'); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> alt="<?php echo esc_attr($title); ?>">
|
||||
</a>
|
||||
<div class="posts-mini-con">
|
||||
<h4 class="item-heading">
|
||||
<a href="<?php echo esc_url($permalink); ?>"><?php echo esc_html($title); ?></a>
|
||||
</h4>
|
||||
<div class="item-meta">
|
||||
<span class="meta-item"><?php echo esc_html($date_text); ?></span>
|
||||
<?php if ($show_views) : ?>
|
||||
<span class="meta-dot" aria-hidden="true"></span>
|
||||
<span class="meta-item">
|
||||
<i class="fas fa-eye" aria-hidden="true"></i>
|
||||
<?php echo esc_html(function_exists('aksrt_format_number') ? aksrt_format_number($view_count) : (string) $view_count); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<?php
|
||||
$config = aksrt_renderer_config([]);
|
||||
$data = aksrt_renderer_collect_post_data($config);
|
||||
if ($data) {
|
||||
echo aksrt_renderer_mini($data, $config); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
// Restore original post
|
||||
if ($original_post instanceof WP_Post) {
|
||||
$wp_query->post = $original_post;
|
||||
setup_postdata($original_post);
|
||||
|
||||
@@ -130,19 +130,6 @@ if (!function_exists('aksrt_homepage_get_tab_posts_per_page')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_get_default_view_mode')) {
|
||||
/**
|
||||
* Default homepage view mode.
|
||||
*/
|
||||
function aksrt_homepage_get_default_view_mode(): string {
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
return \AKSRT\Settings\Settings::homepage_default_view();
|
||||
}
|
||||
|
||||
return 'list';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_sticky_tabs_enabled')) {
|
||||
/**
|
||||
* Whether homepage tabs should stick below the primary nav.
|
||||
@@ -373,21 +360,6 @@ if (!function_exists('aksrt_homepage_render_sortbar')) {
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
$view_mode = 'list';
|
||||
if (function_exists('aksrt_resolve_post_list_render_config')) {
|
||||
$home_view_cfg = aksrt_resolve_post_list_render_config(['context' => 'home']);
|
||||
$view_mode = (($home_view_cfg['mode'] ?? 'list') === 'card') ? 'card' : 'list';
|
||||
}
|
||||
?>
|
||||
<div class="aksrt-homepage__view-toggle" data-aksrt-view-toggle>
|
||||
<button type="button" class="aksrt-homepage__view-btn<?php echo $view_mode === 'list' ? ' is-active' : ''; ?>" data-view-mode="list" aria-label="<?php esc_attr_e('列表视图', 'aksrt'); ?>">
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M1 3h14v2H1V3zm0 4h14v2H1V7zm0 4h14v2H1v-2z"/></svg>
|
||||
</button>
|
||||
<button type="button" class="aksrt-homepage__view-btn<?php echo $view_mode === 'card' ? ' is-active' : ''; ?>" data-view-mode="card" aria-label="<?php esc_attr_e('卡片视图', 'aksrt'); ?>">
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M1 1h4v4H1V1zm5 0h4v4H6V1zm5 0h4v4h-4V1zM1 6h4v4H1V6zm5 0h4v4H6V6zm5 0h4v4h-4V6zM1 11h4v4H1v-4zm5 0h4v4H6v-4zm5 0h4v4h-4v-4z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -127,8 +127,8 @@ if (!function_exists('aksrt_get_win_runtime_config')) :
|
||||
'signup_url' => $signup,
|
||||
'ajax_url' => admin_url('admin-ajax.php'),
|
||||
'ajaxpager' => '1',
|
||||
'ajax_trigger' => (string) ($list_style['ajax_trigger_text'] ?? __('加载更多', 'aksrt')),
|
||||
'ajax_nomore' => (string) ($list_style['ajax_nomore_text'] ?? __('没有更多了', 'aksrt')),
|
||||
'ajax_trigger' => (string) ($list_style['ajax_trigger'] ?? '<i class="fa fa-angle-right"></i>加载更多'),
|
||||
'ajax_nomore' => (string) ($list_style['ajax_nomore'] ?? __('没有更多内容了', 'aksrt')),
|
||||
'qj_loading' => __('加载中...', 'aksrt'),
|
||||
'is_mobile' => $is_mobile ? '1' : '',
|
||||
'is_logged_in' => is_user_logged_in() ? '1' : '',
|
||||
|
||||
@@ -481,15 +481,13 @@ if (!function_exists('aksrt_render_related_graphic_card')) :
|
||||
* Minimal Zibll style-3 related thumb card.
|
||||
*/
|
||||
function aksrt_render_related_graphic_card(WP_Post $post): string {
|
||||
$title = get_the_title($post);
|
||||
$subtitle = class_exists('\AKSRT\Core\PostMetaBox')
|
||||
? (string) \AKSRT\Core\PostMetaBox::get_meta_value($post->ID, 'subtitle', '')
|
||||
: '';
|
||||
$title = get_the_title($post) . $subtitle;
|
||||
$url = get_permalink($post);
|
||||
$thumb = get_the_post_thumbnail_url($post, 'medium_large');
|
||||
if (!$thumb) {
|
||||
$thumb = get_theme_file_uri('assets/img/thumbnail-lg.svg');
|
||||
if (!file_exists(get_theme_file_path('assets/img/thumbnail-lg.svg'))) {
|
||||
$thumb = includes_url('images/media/default.png');
|
||||
}
|
||||
}
|
||||
$media = aksrt_renderer_resolve_images($post->ID, aksrt_renderer_config(['type' => 'card']));
|
||||
$thumb = (string) $media['primary'];
|
||||
$time = human_time_diff((int) get_the_time('U', $post), (int) current_time('timestamp'));
|
||||
$views = function_exists('aksrt_get_post_views') ? (int) aksrt_get_post_views($post->ID) : 0;
|
||||
$views_label = function_exists('aksrt_format_number') ? aksrt_format_number($views) : number_format_i18n($views);
|
||||
|
||||
@@ -568,12 +568,8 @@ if (!function_exists('aksrt_single_related_query_args')) :
|
||||
*/
|
||||
function aksrt_single_related_query_args(int $post_id, array $settings): array {
|
||||
$count = max(1, min(12, (int) ($settings['related_count'] ?? 6)));
|
||||
$type = sanitize_key((string) ($settings['related_source'] ?? ($settings['related_type'] ?? 'category')));
|
||||
if (!in_array($type, ['category', 'tag', 'random'], true)) {
|
||||
$type = 'category';
|
||||
}
|
||||
$orderby = sanitize_key((string) ($settings['related_orderby'] ?? 'views'));
|
||||
if (!in_array($orderby, ['rand', 'relevance', 'date', 'views', 'modified'], true)) {
|
||||
if (!in_array($orderby, ['modified', 'date', 'views', 'like', 'comment_count', 'favorite', 'rand'], true)) {
|
||||
$orderby = 'views';
|
||||
}
|
||||
|
||||
@@ -587,39 +583,22 @@ if (!function_exists('aksrt_single_related_query_args')) :
|
||||
'order' => 'DESC',
|
||||
];
|
||||
|
||||
if ($type === 'random') {
|
||||
$args['orderby'] = 'rand';
|
||||
return $args;
|
||||
}
|
||||
|
||||
$tax_query = ['relation' => 'OR'];
|
||||
if ($type === 'tag') {
|
||||
$tag_ids = wp_get_post_terms($post_id, 'post_tag', ['fields' => 'ids']);
|
||||
if (!empty($tag_ids) && !is_wp_error($tag_ids)) {
|
||||
$tax_query[] = [
|
||||
'taxonomy' => 'post_tag',
|
||||
'field' => 'term_id',
|
||||
'terms' => array_map('intval', $tag_ids),
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// category (default): OR across category + tags.
|
||||
$cat_ids = wp_get_post_terms($post_id, 'category', ['fields' => 'ids']);
|
||||
if (!empty($cat_ids) && !is_wp_error($cat_ids)) {
|
||||
$tax_query[] = [
|
||||
'taxonomy' => 'category',
|
||||
'field' => 'term_id',
|
||||
'terms' => array_map('intval', $cat_ids),
|
||||
];
|
||||
}
|
||||
$tag_ids = wp_get_post_terms($post_id, 'post_tag', ['fields' => 'ids']);
|
||||
if (!empty($tag_ids) && !is_wp_error($tag_ids)) {
|
||||
$tax_query[] = [
|
||||
'taxonomy' => 'post_tag',
|
||||
'field' => 'term_id',
|
||||
'terms' => array_map('intval', $tag_ids),
|
||||
];
|
||||
}
|
||||
$cat_ids = wp_get_post_terms($post_id, 'category', ['fields' => 'ids']);
|
||||
if (!empty($cat_ids) && !is_wp_error($cat_ids)) {
|
||||
$tax_query[] = [
|
||||
'taxonomy' => 'category',
|
||||
'field' => 'term_id',
|
||||
'terms' => array_map('intval', $cat_ids),
|
||||
];
|
||||
}
|
||||
$tag_ids = wp_get_post_terms($post_id, 'post_tag', ['fields' => 'ids']);
|
||||
if (!empty($tag_ids) && !is_wp_error($tag_ids)) {
|
||||
$tax_query[] = [
|
||||
'taxonomy' => 'post_tag',
|
||||
'field' => 'term_id',
|
||||
'terms' => array_map('intval', $tag_ids),
|
||||
];
|
||||
}
|
||||
|
||||
if (count($tax_query) > 1) {
|
||||
@@ -636,6 +615,17 @@ if (!function_exists('aksrt_single_related_query_args')) :
|
||||
case 'modified':
|
||||
$args['orderby'] = 'modified';
|
||||
break;
|
||||
case 'like':
|
||||
$args['meta_key'] = '_aksrt_like_count';
|
||||
$args['orderby'] = ['meta_value_num' => 'DESC', 'date' => 'DESC'];
|
||||
break;
|
||||
case 'favorite':
|
||||
$args['meta_key'] = '_aksrt_favorite_count';
|
||||
$args['orderby'] = ['meta_value_num' => 'DESC', 'date' => 'DESC'];
|
||||
break;
|
||||
case 'comment_count':
|
||||
$args['orderby'] = 'comment_count';
|
||||
break;
|
||||
case 'views':
|
||||
$args['meta_query'] = [
|
||||
'relation' => 'OR',
|
||||
@@ -651,10 +641,8 @@ if (!function_exists('aksrt_single_related_query_args')) :
|
||||
];
|
||||
$args['orderby'] = ['views_value' => 'DESC', 'date' => 'DESC'];
|
||||
break;
|
||||
case 'relevance':
|
||||
default:
|
||||
// Prefer date when no search relevance context.
|
||||
$args['orderby'] = 'date';
|
||||
$args['orderby'] = 'modified';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -695,74 +683,54 @@ if (!function_exists('aksrt_single_render_related')) :
|
||||
];
|
||||
|
||||
$query = new WP_Query($args);
|
||||
if (!$query->have_posts()) {
|
||||
wp_reset_postdata();
|
||||
$empty_wrap = 'theme-box relates' . ($style === 'img' ? ' relates-thumb' : '');
|
||||
?>
|
||||
<div class="<?php echo esc_attr($empty_wrap); ?>">
|
||||
<div class="box-body notop">
|
||||
<div class="title-theme"><?php echo esc_html($title); ?></div>
|
||||
</div>
|
||||
<div class="zib-widget">
|
||||
<?php echo function_exists('aksrt_get_null') ? aksrt_get_null(__('暂无相关文章', 'aksrt'), 40, 'null.svg', 'related-null', 220) : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return;
|
||||
}
|
||||
|
||||
$wrap_class = 'theme-box relates' . ($style === 'img' ? ' relates-thumb' : '');
|
||||
$posts_html = '';
|
||||
$mini_cfg = aksrt_renderer_config([
|
||||
'type' => 'list',
|
||||
'show_number' => false,
|
||||
]);
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$post = get_post();
|
||||
if (!($post instanceof WP_Post)) {
|
||||
continue;
|
||||
}
|
||||
if ($style === 'list') {
|
||||
$data = aksrt_renderer_collect_post_data($mini_cfg);
|
||||
if ($data) {
|
||||
$posts_html .= aksrt_renderer_mini($data, $mini_cfg);
|
||||
}
|
||||
} elseif ($style === 'img' && function_exists('aksrt_render_related_graphic_card')) {
|
||||
$posts_html .= aksrt_render_related_graphic_card($post);
|
||||
} else {
|
||||
$subtitle = class_exists('\AKSRT\Core\PostMetaBox')
|
||||
? (string) \AKSRT\Core\PostMetaBox::get_meta_value($post->ID, 'subtitle', '')
|
||||
: '';
|
||||
$posts_html .= '<li><a class="icon-circle" href="' . esc_url(get_permalink($post)) . '">' . esc_html(get_the_title($post) . $subtitle) . '</a></li>';
|
||||
}
|
||||
}
|
||||
wp_reset_postdata();
|
||||
if ($posts_html === '') {
|
||||
$posts_html = '<li>' . esc_html__('暂无相关文章', 'aksrt') . '</li>';
|
||||
}
|
||||
?>
|
||||
<div class="<?php echo esc_attr($wrap_class); ?>">
|
||||
<div class="box-body notop">
|
||||
<div class="title-theme"><?php echo esc_html($title); ?></div>
|
||||
</div>
|
||||
<div class="zib-widget">
|
||||
<?php if ($style === 'list' && function_exists('aksrt_render_post_list')) : ?>
|
||||
<?php
|
||||
// New route: single query only.
|
||||
aksrt_render_post_list($query, [
|
||||
'context' => 'related',
|
||||
'mode' => 'mini',
|
||||
'show_thumb' => true,
|
||||
'show_meta' => true,
|
||||
'show_number' => false,
|
||||
]);
|
||||
?>
|
||||
<?php if ($style === 'img') : ?>
|
||||
<div class="swiper-container swiper-scroll">
|
||||
<div class="swiper-wrapper"><?php echo $posts_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
||||
<div class="swiper-button-prev"></div>
|
||||
<div class="swiper-button-next"></div>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
$posts_html = '';
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$p = get_post();
|
||||
if (!($p instanceof WP_Post)) {
|
||||
continue;
|
||||
}
|
||||
if ($style === 'img' && function_exists('aksrt_render_related_graphic_card')) {
|
||||
$posts_html .= aksrt_render_related_graphic_card($p);
|
||||
} else {
|
||||
$posts_html .= '<li><a class="icon-circle" href="' . esc_url(get_permalink($p)) . '">' . esc_html(get_the_title($p)) . '</a></li>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php if ($style === 'img') : ?>
|
||||
<div class="swiper-container swiper-scroll">
|
||||
<div class="swiper-wrapper">
|
||||
<?php echo $posts_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
<div class="swiper-button-prev"></div>
|
||||
<div class="swiper-button-next"></div>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<ul class="no-thumb">
|
||||
<?php echo $posts_html !== '' ? $posts_html : '<li>' . esc_html__('暂无相关文章', 'aksrt') . '</li>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
<ul class="no-thumb"><?php echo $posts_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></ul>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
wp_reset_postdata();
|
||||
}
|
||||
endif;
|
||||
|
||||
|
||||
@@ -206,12 +206,7 @@ if (!function_exists('aksrt_homepage_get_latest_panel_contract')) {
|
||||
|
||||
unset($query_vars['paged'], $query_vars['page']);
|
||||
|
||||
$render_config = function_exists('aksrt_resolve_post_list_render_config')
|
||||
? aksrt_resolve_post_list_render_config(['context' => 'home'])
|
||||
: [
|
||||
'mode' => 'list',
|
||||
'context' => 'home',
|
||||
];
|
||||
$render_config = aksrt_resolve_post_list_render_config(['context' => 'home']);
|
||||
$render_config['skip_wrapper'] = true;
|
||||
|
||||
return [
|
||||
@@ -364,57 +359,17 @@ if (!function_exists('aksrt_get_post_gallery_images')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_render_post_card')) {
|
||||
/**
|
||||
* Render a homepage post card inline.
|
||||
*/
|
||||
function aksrt_homepage_render_post_card(): void {
|
||||
if (!function_exists('aksrt_render_post')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config = function_exists('aksrt_resolve_post_list_render_config')
|
||||
? aksrt_resolve_post_list_render_config(['context' => 'home'])
|
||||
: [
|
||||
'mode' => 'list',
|
||||
'context' => 'home',
|
||||
];
|
||||
|
||||
echo aksrt_render_post($config); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_homepage_render_posts_grid')) {
|
||||
/**
|
||||
* Render a list block for the fixed homepage.
|
||||
*/
|
||||
function aksrt_homepage_render_posts_grid(?WP_Query $query = null, bool $with_pagination = false): void {
|
||||
$query = $query instanceof WP_Query ? $query : aksrt_homepage_get_latest_query();
|
||||
$config = function_exists('aksrt_resolve_post_list_render_config')
|
||||
? aksrt_resolve_post_list_render_config(['context' => 'home'])
|
||||
: [
|
||||
'mode' => 'list',
|
||||
'context' => 'home',
|
||||
];
|
||||
$config = aksrt_resolve_post_list_render_config(['context' => 'home']);
|
||||
$config['skip_wrapper'] = true;
|
||||
$view = (($config['mode'] ?? 'list') === 'card') ? 'card' : 'list';
|
||||
|
||||
if (function_exists('aksrt_render_post_list')) {
|
||||
// Panel already provides posts-row.ajaxpager; avoid nested wrapper.
|
||||
aksrt_render_post_list($query, $config, true);
|
||||
} else {
|
||||
if (!$query->have_posts()) {
|
||||
echo '<div class="no-results"><p>' . esc_html__('暂无文章', 'aksrt') . '</p></div>';
|
||||
} else {
|
||||
echo '<div class="posts-row aksrt-homepage__posts" data-view="' . esc_attr($view) . '">';
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
aksrt_homepage_render_post_card();
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
// Panel already provides posts-row.ajaxpager; avoid nested wrapper.
|
||||
aksrt_render_post_list($config, $query, true);
|
||||
|
||||
if ($with_pagination) {
|
||||
aksrt_homepage_render_pagination($query);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Shared post renderer helpers for archive, widget, and related lists.
|
||||
*
|
||||
* Centralizes card/list/mini rendering to avoid duplicating DOM contracts
|
||||
* across category.php, search.php, widgets, and home modules.
|
||||
* Zibll 9.0 article-list configuration and image resolution.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
@@ -11,355 +8,249 @@
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_renderer_defaults')) {
|
||||
/**
|
||||
* Base renderer config defaults.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
/** @return array<string,mixed> */
|
||||
function aksrt_renderer_defaults(): array {
|
||||
return [
|
||||
'context' => 'archive',
|
||||
'mode' => 'list',
|
||||
'columns' => 1,
|
||||
'style' => 'default',
|
||||
'card_style' => 'standard',
|
||||
'heading_bold' => true,
|
||||
'show_excerpt' => true,
|
||||
'excerpt_words' => 36,
|
||||
'show_meta' => true,
|
||||
'show_author' => true,
|
||||
'show_date' => true,
|
||||
'show_views' => true,
|
||||
'show_comments' => true,
|
||||
'show_likes' => false,
|
||||
'show_badges' => true,
|
||||
'show_tags' => true,
|
||||
'tag_limit' => 3,
|
||||
'category_limit' => 1,
|
||||
'show_thumb' => true,
|
||||
'thumb_ratio' => '4:3',
|
||||
'thumb_fit' => 'cover',
|
||||
'thumb_if_has' => false,
|
||||
'target_blank' => false,
|
||||
'title_html' => '',
|
||||
'excerpt_html' => '',
|
||||
'badge_show' => true,
|
||||
'show_resource_badge' => true,
|
||||
'multi_thumb_enabled' => true,
|
||||
'multi_thumb_limit' => 4,
|
||||
'multi_thumb_min' => 2,
|
||||
'list_show_type' => 'separate',
|
||||
'list_img_position' => 'left',
|
||||
'number_offset' => 0,
|
||||
'show_number' => false,
|
||||
'extra_class' => '',
|
||||
'highlight_query' => '',
|
||||
'type' => 'auto',
|
||||
'no_author' => false,
|
||||
'no_margin' => false,
|
||||
'is_mult_thumb' => false,
|
||||
'is_no_thumb' => false,
|
||||
'is_card' => false,
|
||||
'is_category' => is_category(),
|
||||
'is_search' => is_search(),
|
||||
'is_home' => is_home() || is_front_page(),
|
||||
'is_author' => is_author(),
|
||||
'is_tag' => is_tag(),
|
||||
'highlight_query' => '',
|
||||
'wrapper_class' => '',
|
||||
'skip_wrapper' => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_config')) {
|
||||
/**
|
||||
* Merge renderer config with context-aware defaults.
|
||||
* Resolve the one canonical Zibll list/card decision matrix.
|
||||
*
|
||||
* @param array<string,mixed> $config User config.
|
||||
* @param array<string,mixed> $args Caller arguments.
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
function aksrt_renderer_config(array $config = []): array {
|
||||
$cfg = wp_parse_args($config, aksrt_renderer_defaults());
|
||||
function aksrt_renderer_config(array $args = []): array {
|
||||
$args = wp_parse_args($args, aksrt_renderer_defaults());
|
||||
$list = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_list_style_settings()
|
||||
: [];
|
||||
$thumb = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_thumb_settings()
|
||||
: [];
|
||||
|
||||
$cfg['mode'] = in_array($cfg['mode'], ['list', 'card', 'mini', 'grid-cms'], true)
|
||||
? $cfg['mode']
|
||||
: 'list';
|
||||
|
||||
$cfg['columns'] = max(1, min(6, (int) $cfg['columns']));
|
||||
$cfg['excerpt_words'] = max(0, (int) $cfg['excerpt_words']);
|
||||
$cfg['tag_limit'] = max(0, (int) $cfg['tag_limit']);
|
||||
$cfg['category_limit'] = max(0, (int) $cfg['category_limit']);
|
||||
$cfg['multi_thumb_limit'] = max(1, min(6, (int) $cfg['multi_thumb_limit']));
|
||||
$cfg['multi_thumb_min'] = max(1, min(6, (int) $cfg['multi_thumb_min']));
|
||||
|
||||
if ($cfg['mode'] === 'mini') {
|
||||
$cfg['show_excerpt'] = false;
|
||||
$cfg['show_badges'] = false;
|
||||
$cfg['show_tags'] = false;
|
||||
$cfg['show_author'] = false;
|
||||
$cfg['show_comments'] = false;
|
||||
$list_type = sanitize_key((string) ($list['list_type'] ?? 'thumb'));
|
||||
$forced_type = sanitize_key((string) $args['type']);
|
||||
$is_forced = in_array($forced_type, ['list', 'card'], true);
|
||||
$is_card = $forced_type === 'card' || (!$is_forced && !empty($args['is_card']));
|
||||
if (!$is_forced && !$is_card && $list_type === 'card') {
|
||||
$is_card = true;
|
||||
}
|
||||
if (!$is_forced && !$is_card) {
|
||||
$is_card = (!empty($args['is_tag']) && !empty($list['list_card_tag']))
|
||||
|| (!empty($args['is_home']) && !empty($list['list_card_home']))
|
||||
|| (!empty($args['is_author']) && !empty($list['list_card_author']));
|
||||
}
|
||||
if (!$is_forced && !$is_card) {
|
||||
$term_id = (int) get_queried_object_id();
|
||||
$is_card = $term_id > 0 && in_array($term_id, (array) ($list['list_card_cat'] ?? []), true);
|
||||
}
|
||||
|
||||
if (in_array((string) $cfg['style'], ['default', 'null'], true)) {
|
||||
$cfg['style'] = '';
|
||||
$list_option = (array) ($list['list_list_option'] ?? []);
|
||||
$card_option = (array) ($list['list_card_option'] ?? []);
|
||||
$style = sanitize_key((string) (($is_card ? $card_option : $list_option)['style'] ?? 'null'));
|
||||
if (!in_array($style, ['style2', 'style3'], true)) {
|
||||
$style = '';
|
||||
}
|
||||
$cfg['list_img_position'] = in_array(sanitize_key((string) ($cfg['list_img_position'] ?? 'left')), ['left', 'right'], true)
|
||||
? sanitize_key((string) ($cfg['list_img_position'] ?? 'left'))
|
||||
: 'left';
|
||||
$cfg['list_show_type'] = in_array(sanitize_key((string) ($cfg['list_show_type'] ?? 'separate')), ['separate', 'no_margin'], true)
|
||||
? sanitize_key((string) ($cfg['list_show_type'] ?? 'separate'))
|
||||
: 'separate';
|
||||
|
||||
return $cfg;
|
||||
}
|
||||
}
|
||||
$args['mode'] = $is_card ? 'card' : 'list';
|
||||
$args['list_type'] = $list_type;
|
||||
$args['style'] = $style;
|
||||
$args['img_position'] = sanitize_key((string) ($list_option['img_position'] ?? 'left')) === 'right' ? 'right' : 'left';
|
||||
$args['list_scale'] = max(50, min(200, (int) ($list_option['scale'] ?? 70)));
|
||||
$args['card_scale'] = max(20, min(200, (int) ($card_option['scale'] ?? 70)));
|
||||
$args['no_margin'] = !empty($args['no_margin']) || (($list['list_show_type'] ?? 'separate') === 'no_margin');
|
||||
$args['no_author'] = !empty($args['no_author']) || !empty($args['is_author']);
|
||||
$args['target_blank'] = !empty($list['target_blank']);
|
||||
$args['heading_bold'] = !empty($list['item_heading_bold']);
|
||||
$args['show_author'] = !empty($list['post_list_author']);
|
||||
$args['show_time'] = !empty($list['post_list_time']);
|
||||
$args['time_source'] = (string) ($list['post_time_source'] ?? 'modified');
|
||||
$args['list_orderby'] = (string) ($list['list_orderby'] ?? 'modified');
|
||||
$args['mobile_meta'] = (string) ($list['list_meta_show'] ?? 'like');
|
||||
$args['badge_types'] = (array) ($list['list_badge_show'] ?? ['pay', 'cat', 'tag']);
|
||||
$args['mult_thumb_cat'] = (array) ($list['mult_thumb_cat'] ?? []);
|
||||
$args['thumb'] = $thumb;
|
||||
$args['allow_conditional_layout'] = aksrt_is_show_sidebar() || wp_is_mobile();
|
||||
$page = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_page_settings()
|
||||
: [];
|
||||
$comments = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_comment_display_settings()
|
||||
: [];
|
||||
$args['show_like'] = !array_key_exists('like_enabled', $page) || !empty($page['like_enabled']);
|
||||
$args['close_comments'] = !empty($comments['close_comments']);
|
||||
|
||||
if (!function_exists('aksrt_renderer_sanitize_inline_html')) {
|
||||
/**
|
||||
* Sanitize small inline HTML snippets used by render config overrides.
|
||||
*
|
||||
* @param string $html Raw HTML.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_sanitize_inline_html(string $html): string {
|
||||
return wp_kses($html, [
|
||||
'span' => ['class' => true, 'aria-hidden' => true],
|
||||
'em' => ['class' => true],
|
||||
'strong' => ['class' => true],
|
||||
'i' => ['class' => true, 'aria-hidden' => true],
|
||||
'small'=> ['class' => true],
|
||||
]);
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_highlight_text')) {
|
||||
/**
|
||||
* Highlight plain text query matches using a safe span wrapper.
|
||||
*
|
||||
* @param string $text Plain text.
|
||||
* @param string $query Highlight query.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_highlight_text(string $text, string $query): string {
|
||||
$text = wp_strip_all_tags($text);
|
||||
$query = trim($query);
|
||||
|
||||
if ($query === '' || $text === '') {
|
||||
return esc_html($text);
|
||||
}
|
||||
|
||||
$words = preg_split('/\s+/u', $query) ?: [];
|
||||
$words = array_values(array_unique(array_filter(array_map('trim', $words), static function ($word) {
|
||||
return $word !== '' && mb_strlen($word) >= 2;
|
||||
})));
|
||||
|
||||
if (empty($words)) {
|
||||
$words = array_values(array_unique(array_filter(preg_split('/\s+/u', $query) ?: [])));
|
||||
if (!$words) {
|
||||
return esc_html($text);
|
||||
}
|
||||
|
||||
$pattern = '/' . implode('|', array_map(static function ($word) {
|
||||
return preg_quote($word, '/');
|
||||
}, $words)) . '/iu';
|
||||
|
||||
$escaped = esc_html($text);
|
||||
return (string) preg_replace($pattern, '<span class="focus-color">$0</span>', $escaped);
|
||||
$pattern = '/' . implode('|', array_map(static fn(string $word): string => preg_quote($word, '/'), $words)) . '/iu';
|
||||
return (string) preg_replace($pattern, '<span class="focus-color">$0</span>', esc_html($text));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_title_markup')) {
|
||||
/**
|
||||
* Resolve title markup, supporting highlighted search terms.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_title_markup(array $data, array $cfg): string {
|
||||
if (!empty($cfg['title_html'])) {
|
||||
return aksrt_renderer_sanitize_inline_html((string) $cfg['title_html']);
|
||||
$title = aksrt_renderer_highlight_text((string) $data['title'], (string) ($cfg['highlight_query'] ?? ''));
|
||||
if ((string) ($data['subtitle'] ?? '') !== '') {
|
||||
$title .= '<span class="focus-color"> ' . esc_html((string) $data['subtitle']) . '</span>';
|
||||
}
|
||||
|
||||
$title = aksrt_renderer_highlight_text((string) $data['title'], (string) $cfg['highlight_query']);
|
||||
$subtitle = trim((string) ($data['subtitle'] ?? ''));
|
||||
if ($subtitle !== '') {
|
||||
$title .= '<span class="focus-color"> ' . esc_html($subtitle) . '</span>';
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_excerpt_markup')) {
|
||||
/**
|
||||
* Resolve excerpt markup, supporting highlighted search terms.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_excerpt_markup(array $data, array $cfg): string {
|
||||
if (!empty($cfg['excerpt_html'])) {
|
||||
return aksrt_renderer_sanitize_inline_html((string) $cfg['excerpt_html']);
|
||||
}
|
||||
|
||||
return aksrt_renderer_highlight_text((string) $data['excerpt'], (string) $cfg['highlight_query']);
|
||||
return aksrt_renderer_highlight_text((string) $data['excerpt'], (string) ($cfg['highlight_query'] ?? ''));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_curated_images')) {
|
||||
/**
|
||||
* Resolve curated cover images from post meta.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param int $limit Maximum items.
|
||||
* @return string[]
|
||||
*/
|
||||
function aksrt_renderer_curated_images(int $post_id, int $limit = 6): array {
|
||||
/** @return string[] */
|
||||
function aksrt_renderer_curated_images(int $post_id, string $size, int $limit = 8): array {
|
||||
$raw = class_exists('\AKSRT\Core\PostMetaBox')
|
||||
? (string) \AKSRT\Core\PostMetaBox::get_meta_value($post_id, 'featured_slide', '')
|
||||
: '';
|
||||
$images = [];
|
||||
$limit = max(1, min(8, $limit));
|
||||
|
||||
if (!class_exists('\AKSRT\Core\PostMetaBox')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cover_images = (string) \AKSRT\Core\PostMetaBox::get_meta_value($post_id, 'cover_images', '');
|
||||
if ($cover_images === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$cover_ids = array_filter(array_map('absint', preg_split('/[\s,]+/', $cover_images) ?: []));
|
||||
foreach ($cover_ids as $attachment_id) {
|
||||
$url = (string) wp_get_attachment_image_url($attachment_id, 'medium_large');
|
||||
if ($url !== '') {
|
||||
$images[] = esc_url_raw($url);
|
||||
foreach (array_filter(preg_split('/[\s,]+/', $raw) ?: []) as $token) {
|
||||
$image = aksrt_renderer_sized_image((string) $token, $size);
|
||||
if ($image !== '') {
|
||||
$images[] = $image;
|
||||
}
|
||||
}
|
||||
|
||||
return array_slice(array_values(array_unique($images)), 0, $limit);
|
||||
return array_slice($images, 0, $limit);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_attachment_images')) {
|
||||
/**
|
||||
* Resolve gallery/content images for list cards.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param int $limit Maximum items.
|
||||
* @return string[]
|
||||
*/
|
||||
function aksrt_renderer_attachment_images(int $post_id, int $limit = 6): array {
|
||||
$images = [];
|
||||
$limit = max(1, min(8, $limit));
|
||||
|
||||
if (function_exists('aksrt_get_post_gallery_images')) {
|
||||
$images = aksrt_get_post_gallery_images($post_id, $limit);
|
||||
}
|
||||
|
||||
if (function_exists('aksrt_get_first_content_image_url')) {
|
||||
$first_content_image = (string) aksrt_get_first_content_image_url($post_id);
|
||||
if ($first_content_image !== '') {
|
||||
$images[] = esc_url_raw($first_content_image);
|
||||
}
|
||||
}
|
||||
|
||||
return array_slice(array_values(array_unique(array_filter($images))), 0, $limit);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_random_fallback_image')) {
|
||||
/**
|
||||
* Pick a deterministic fallback image when "random cover" is enabled.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_random_fallback_image(int $post_id): string {
|
||||
$candidates = [
|
||||
get_template_directory_uri() . '/assets/img/person_background.png',
|
||||
get_template_directory_uri() . '/assets/img/placeholder.svg',
|
||||
];
|
||||
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$thumb = \AKSRT\Settings\Settings::get_post_thumb_settings();
|
||||
$spare = $thumb['spare_images'] ?? [];
|
||||
if (is_array($spare) && !empty($spare)) {
|
||||
foreach ($spare as $url) {
|
||||
if (is_string($url) && $url !== '') {
|
||||
array_unshift($candidates, $url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$candidates = array_values(array_unique(array_filter(array_map('esc_url_raw', $candidates))));
|
||||
if (empty($candidates)) {
|
||||
if (!function_exists('aksrt_renderer_sized_image')) {
|
||||
function aksrt_renderer_sized_image(string $image, string $size): string {
|
||||
$image = trim($image);
|
||||
if ($image === '') {
|
||||
return '';
|
||||
}
|
||||
$attachment_id = ctype_digit($image) ? (int) $image : 0;
|
||||
if ($attachment_id === 0) {
|
||||
$lookup_url = (string) preg_replace('/\?.*$/', '', $image);
|
||||
$attachment_id = attachment_url_to_postid($lookup_url);
|
||||
if ($attachment_id === 0) {
|
||||
$full_url = (string) preg_replace('/-\d+x\d+(?=\.[^.]+$)/', '', $lookup_url);
|
||||
$attachment_id = attachment_url_to_postid($full_url);
|
||||
}
|
||||
}
|
||||
if ($attachment_id > 0) {
|
||||
$sized = wp_get_attachment_image_url($attachment_id, $size);
|
||||
if (is_string($sized) && $sized !== '') {
|
||||
return esc_url_raw($sized);
|
||||
}
|
||||
}
|
||||
return esc_url_raw($image);
|
||||
}
|
||||
}
|
||||
|
||||
$index = $post_id % count($candidates);
|
||||
return $candidates[$index] ?? $candidates[0];
|
||||
if (!function_exists('aksrt_renderer_content_images')) {
|
||||
/** @return string[] */
|
||||
function aksrt_renderer_content_images(int $post_id, string $size): array {
|
||||
$content = strip_shortcodes((string) get_post_field('post_content', $post_id, 'raw'));
|
||||
if ($content === '' || !preg_match_all('/<img.*?(?: |\t|\r|\n)?src=[\'\"]?(.+?)[\'\"]?(?:(?: |\t|\r|\n)+.*?)?>/sim', $content, $matches)) {
|
||||
return [];
|
||||
}
|
||||
$images = [];
|
||||
foreach ((array) ($matches[1] ?? []) as $image) {
|
||||
$sized = aksrt_renderer_sized_image((string) $image, $size);
|
||||
if ($sized !== '') {
|
||||
$images[] = $sized;
|
||||
}
|
||||
}
|
||||
return $images;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_category_image')) {
|
||||
function aksrt_renderer_category_image(int $post_id, string $size): string {
|
||||
foreach ((array) get_the_category($post_id) as $category) {
|
||||
$attachment_id = (int) get_term_meta((int) $category->term_id, 'aksrt_category_cover_id', true);
|
||||
if ($attachment_id > 0) {
|
||||
return aksrt_renderer_sized_image((string) $attachment_id, $size);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_spare_image')) {
|
||||
function aksrt_renderer_spare_image(array $thumb): string {
|
||||
$images = array_values(array_filter((array) ($thumb['spare_thumbnail'] ?? [])));
|
||||
return $images ? (string) $images[array_rand($images)] : '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_resolve_images')) {
|
||||
/**
|
||||
* Resolve primary + gallery images for a post based on card settings.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return array{primary:string,gallery:string[],has_thumb:bool,has_real:bool}
|
||||
*/
|
||||
/** @return array{primary:string,gallery:string[],slides:string[],has_real:bool,is_slide:bool,video_url:string} */
|
||||
function aksrt_renderer_resolve_images(int $post_id, array $cfg): array {
|
||||
$thumb_url = get_the_post_thumbnail_url($post_id, 'medium_large');
|
||||
$curated_images = !empty($cfg['thumb_if_has']) || !empty($cfg['multi_thumb_enabled'])
|
||||
? aksrt_renderer_curated_images($post_id, max(4, (int) $cfg['multi_thumb_limit']))
|
||||
: [];
|
||||
$content_images = !empty($cfg['multi_thumb_enabled'])
|
||||
? aksrt_renderer_attachment_images($post_id, max(4, (int) $cfg['multi_thumb_limit']))
|
||||
: [];
|
||||
$thumb = (array) ($cfg['thumb'] ?? []);
|
||||
$size = (string) ($thumb['thumb_postfirstimg_size'] ?? 'medium');
|
||||
$slides = aksrt_renderer_curated_images($post_id, $size);
|
||||
$gallery = aksrt_renderer_content_images($post_id, $size);
|
||||
$video_url = class_exists('\AKSRT\Core\PostMetaBox')
|
||||
? esc_url_raw((string) \AKSRT\Core\PostMetaBox::get_meta_value($post_id, 'featured_video', ''))
|
||||
: '';
|
||||
|
||||
$gallery = [];
|
||||
if (!empty($curated_images)) {
|
||||
$gallery = array_merge($gallery, $curated_images);
|
||||
$thumbnail_id = (int) get_post_thumbnail_id($post_id);
|
||||
$primary = $thumbnail_id > 0 ? aksrt_renderer_sized_image((string) $thumbnail_id, $size) : '';
|
||||
if ($primary === '') {
|
||||
$primary = class_exists('\AKSRT\Core\PostMetaBox')
|
||||
? esc_url_raw((string) \AKSRT\Core\PostMetaBox::get_meta_value($post_id, 'thumbnail_url', ''))
|
||||
: '';
|
||||
}
|
||||
if (!empty($content_images)) {
|
||||
$gallery = array_merge($gallery, $content_images);
|
||||
if ($primary === '' && !empty($thumb['thumb_postfirstimg_s']) && !empty($gallery[0])) {
|
||||
$primary = (string) $gallery[0];
|
||||
}
|
||||
if ($primary === '' && !empty($thumb['thumb_catimg_s'])) {
|
||||
$primary = aksrt_renderer_category_image($post_id, $size);
|
||||
}
|
||||
$gallery = array_values(array_unique(array_filter($gallery)));
|
||||
|
||||
$primary = is_string($thumb_url) && $thumb_url !== '' ? esc_url_raw($thumb_url) : '';
|
||||
$has_real = $primary !== '';
|
||||
|
||||
if ($primary === '' && !empty($curated_images[0])) {
|
||||
$primary = $curated_images[0];
|
||||
$has_real = true;
|
||||
if ($primary === '') {
|
||||
$primary = aksrt_renderer_spare_image($thumb);
|
||||
}
|
||||
if ($primary === '' && !empty($content_images[0])) {
|
||||
$primary = $content_images[0];
|
||||
$has_real = true;
|
||||
}
|
||||
|
||||
$thumb_settings = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_thumb_settings() : [];
|
||||
$fallback = sanitize_key((string) ($thumb_settings['fallback'] ?? 'placeholder'));
|
||||
if ($primary === '' && empty($cfg['thumb_if_has'])) {
|
||||
if ($fallback === 'random') {
|
||||
$primary = aksrt_renderer_random_fallback_image($post_id);
|
||||
} elseif ($fallback === 'placeholder') {
|
||||
$primary = aksrt_get_lazy_thumb();
|
||||
}
|
||||
if ($primary === '') {
|
||||
$primary = (string) aksrt_get_lazy_thumb();
|
||||
}
|
||||
|
||||
return [
|
||||
'primary' => $primary,
|
||||
'gallery' => $gallery,
|
||||
'has_thumb' => $primary !== '',
|
||||
'has_real' => $has_real,
|
||||
'primary' => esc_url_raw($primary),
|
||||
'gallery' => $gallery,
|
||||
'slides' => $slides,
|
||||
'has_real' => $has_real,
|
||||
'is_slide' => !empty($thumb['list_thumb_slides_s']) && count($slides) > 0,
|
||||
'video_url' => $video_url,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_thumb_ratio_value')) {
|
||||
/**
|
||||
* Convert ratio tokens like 4:3 to CSS aspect ratio values.
|
||||
*
|
||||
* @param string $ratio Ratio token.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_thumb_ratio_value(string $ratio): string {
|
||||
$ratio = trim($ratio);
|
||||
if (preg_match('/^(\d+)\s*:\s*(\d+)$/', $ratio, $matches)) {
|
||||
$w = max(1, (int) $matches[1]);
|
||||
$h = max(1, (int) $matches[2]);
|
||||
return $w . ' / ' . $h;
|
||||
}
|
||||
|
||||
return '4 / 3';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Shared post renderer helpers.
|
||||
* Zibll 9.0 article-list DOM contract.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
@@ -8,351 +8,206 @@
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_renderer_list')) {
|
||||
/**
|
||||
* Render a horizontal list card.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_list(array $data, array $cfg): string {
|
||||
$classes = ['posts-item', 'list', 'ajax-item', 'flex', 'posts-item--' . ($cfg['card_style'] ?: 'standard')];
|
||||
|
||||
if ($cfg['style'] !== '' && $cfg['style'] !== 'default') {
|
||||
$classes[] = $cfg['style'];
|
||||
}
|
||||
if ($cfg['style'] === 'style2') {
|
||||
$classes[] = 'xx';
|
||||
$classes = ['posts-item', 'list', 'ajax-item'];
|
||||
if ((string) ($cfg['style'] ?? '') !== '') {
|
||||
$classes[] = (string) $cfg['style'];
|
||||
}
|
||||
if (!empty($data['is_mult_thumb'])) {
|
||||
$classes[] = 'mult-thumb';
|
||||
}
|
||||
if ($cfg['context'] === 'home') {
|
||||
$classes[] = 'posts-item--home-list';
|
||||
}
|
||||
if (empty($data['has_img'])) {
|
||||
if (!empty($data['is_no_thumb'])) {
|
||||
$classes[] = 'no-thumb';
|
||||
}
|
||||
if (($cfg['list_show_type'] ?? 'separate') === 'no_margin') {
|
||||
$classes[] = 'no-margin';
|
||||
if (!empty($cfg['no_margin'])) {
|
||||
$classes[] = 'no_margin';
|
||||
}
|
||||
$classes[] = ($cfg['style'] ?? '') === 'style2' ? 'flex xx' : 'flex';
|
||||
|
||||
$title = '<h2 class="item-heading' . (!empty($cfg['heading_bold']) ? ' font-bold' : '') . '"><a' . (!empty($cfg['target_blank']) ? ' target="_blank"' : '') . ' href="' . esc_url((string) $data['permalink']) . '">' . aksrt_renderer_title_markup($data, $cfg) . '</a></h2>';
|
||||
$excerpt_class = ($cfg['style'] ?? '') === 'style2' ? 'text-ellipsis-2' : 'text-ellipsis';
|
||||
$excerpt = '<div class="item-excerpt muted-color ' . $excerpt_class . ' mb6">' . aksrt_renderer_excerpt_markup($data, $cfg) . '</div>';
|
||||
$thumb = aksrt_renderer_thumb($data, $cfg);
|
||||
$mult = aksrt_renderer_mult_thumb($data);
|
||||
if (!empty($data['is_mult_thumb'])) {
|
||||
// Zibll's multi-image mode replaces the primary graphic; both must
|
||||
// never be emitted for the same list item.
|
||||
$thumb = '';
|
||||
$mult = aksrt_renderer_mult_thumb($data, $cfg);
|
||||
$graphic = '';
|
||||
if ($thumb !== '' && empty($data['is_mult_thumb'])) {
|
||||
$graphic = '<div class="post-graphic' . (($cfg['img_position'] ?? 'left') === 'right' ? ' order1' : '') . '">' . $thumb . '</div>';
|
||||
}
|
||||
|
||||
if ($cfg['card_style'] === 'text' || ($cfg['card_style'] === 'thumb_if_has' && empty($data['has_img']))) {
|
||||
$thumb = '';
|
||||
$mult = '';
|
||||
$classes[] = 'no-thumb';
|
||||
$classes[] = 'posts-item--text';
|
||||
}
|
||||
$title_markup = aksrt_renderer_title_markup($data, $cfg);
|
||||
$excerpt_markup = aksrt_renderer_excerpt_markup($data, $cfg);
|
||||
$badges = aksrt_renderer_badges($data, $cfg);
|
||||
$meta = aksrt_renderer_meta($data, $cfg);
|
||||
|
||||
$target_attr = !empty($cfg['target_blank']) ? ' target="_blank"' : '';
|
||||
$heading_cls = !empty($cfg['heading_bold']) ? 'item-heading item-heading--bold' : 'item-heading';
|
||||
$title_html = '<h2 class="' . $heading_cls . '"><a href="' . esc_url($data['permalink']) . '" rel="bookmark"' . $target_attr . '>' . $title_markup . '</a></h2>';
|
||||
$excerpt_html = $cfg['show_excerpt'] && $excerpt_markup !== ''
|
||||
? '<p class="item-excerpt">' . $excerpt_markup . '</p>'
|
||||
: '';
|
||||
|
||||
$html = '<article ' . aksrt_renderer_article_attrs($classes, $data) . '>';
|
||||
|
||||
if ($cfg['style'] === 'style2') {
|
||||
$html .= $title_html;
|
||||
$html .= '<div class="flex">';
|
||||
$html .= $thumb;
|
||||
$html .= '<div class="item-body flex xx flex1 jsb">';
|
||||
$html .= $mult ?: $excerpt_html;
|
||||
$html .= $badges;
|
||||
$html .= $meta;
|
||||
$html .= '</div></div>';
|
||||
$meta = aksrt_renderer_meta($data, $cfg, false);
|
||||
$html = '<posts class="' . esc_attr(implode(' ', $classes)) . '">';
|
||||
if (($cfg['style'] ?? '') === 'style2') {
|
||||
$html .= $title . '<div class="flex">' . $graphic . '<div class="item-body flex xx flex1 jsb">';
|
||||
$html .= $mult !== '' ? $mult : $excerpt;
|
||||
$html .= $badges . $meta . '</div></div>';
|
||||
} else {
|
||||
$html .= $thumb;
|
||||
$html .= '<div class="item-body flex xx flex1 jsb">';
|
||||
$html .= $title_html;
|
||||
$html .= $mult ?: $excerpt_html;
|
||||
$html .= '<div>' . $badges . $meta . '</div>';
|
||||
$html .= '</div>';
|
||||
$html .= $graphic . '<div class="item-body flex xx flex1 jsb">' . $title;
|
||||
$html .= $mult !== '' ? $mult : $excerpt;
|
||||
$html .= '<div>' . $badges . $meta . '</div></div>';
|
||||
}
|
||||
|
||||
$html .= '</article>';
|
||||
return $html;
|
||||
return $html . '</posts>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_card')) {
|
||||
/**
|
||||
* Render a vertical card or CMS resource card.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_card(array $data, array $cfg): string {
|
||||
$classes = ['posts-item', 'card', 'ajax-item', 'posts-item--' . ($cfg['card_style'] ?: 'standard')];
|
||||
|
||||
if ($cfg['style'] !== '' && $cfg['style'] !== 'default') {
|
||||
$classes[] = $cfg['style'];
|
||||
}
|
||||
if ($cfg['context'] === 'home') {
|
||||
$classes[] = 'posts-item--home';
|
||||
}
|
||||
if ($cfg['mode'] === 'grid-cms') {
|
||||
$classes[] = 'posts-item--cms';
|
||||
}
|
||||
if (!empty($data['is_mult_thumb'])) {
|
||||
$classes[] = 'mult-thumb';
|
||||
}
|
||||
if (empty($data['has_img'])) {
|
||||
$classes[] = 'no-thumb';
|
||||
$classes = ['posts-item', 'card', 'ajax-item'];
|
||||
if ((string) ($cfg['style'] ?? '') !== '') {
|
||||
$classes[] = (string) $cfg['style'];
|
||||
}
|
||||
$title = '<h2 class="item-heading' . (!empty($cfg['heading_bold']) ? ' font-bold' : '') . '"><a' . (!empty($cfg['target_blank']) ? ' target="_blank"' : '') . ' href="' . esc_url((string) $data['permalink']) . '">' . aksrt_renderer_title_markup($data, $cfg) . '</a></h2>';
|
||||
|
||||
$thumb = aksrt_renderer_thumb($data, $cfg);
|
||||
$badges = aksrt_renderer_badges($data, $cfg);
|
||||
$resource_strip = aksrt_renderer_resource_strip($data);
|
||||
$meta = aksrt_renderer_meta($data, $cfg);
|
||||
$title_markup = aksrt_renderer_title_markup($data, $cfg);
|
||||
$html = '<article ' . aksrt_renderer_article_attrs($classes, $data) . '>';
|
||||
$html .= $thumb;
|
||||
$html .= '<div class="item-body">';
|
||||
$target_attr = !empty($cfg['target_blank']) ? ' target="_blank"' : '';
|
||||
$heading_cls = !empty($cfg['heading_bold']) ? 'item-heading item-heading--bold' : 'item-heading';
|
||||
$html .= '<h2 class="' . $heading_cls . '"><a href="' . esc_url($data['permalink']) . '" rel="bookmark"' . $target_attr . '>' . $title_markup . '</a></h2>';
|
||||
|
||||
$html .= $badges;
|
||||
|
||||
if ($cfg['mode'] === 'grid-cms') {
|
||||
$html .= $resource_strip;
|
||||
}
|
||||
|
||||
$html .= $meta;
|
||||
$html .= '</div></article>';
|
||||
|
||||
return $html;
|
||||
$html = '<posts class="' . esc_attr(implode(' ', $classes)) . '">';
|
||||
$html .= aksrt_renderer_thumb($data, $cfg);
|
||||
$html .= '<div class="item-body">' . $title;
|
||||
$html .= aksrt_renderer_badges($data, $cfg);
|
||||
$html .= aksrt_renderer_meta($data, $cfg, true);
|
||||
return $html . '</div></posts>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_mini')) {
|
||||
/**
|
||||
* Render a compact mini card.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_mini(array $data, array $cfg): string {
|
||||
$classes = ['posts-mini'];
|
||||
if (!empty($cfg['extra_class'])) {
|
||||
$classes[] = $cfg['extra_class'];
|
||||
function aksrt_renderer_mini(array $data, array $cfg = []): string {
|
||||
$target = !empty($cfg['target_blank']) ? ' target="_blank"' : '';
|
||||
$thumb = '';
|
||||
$show_thumb = !array_key_exists('show_thumb', $cfg) || !empty($cfg['show_thumb']);
|
||||
$show_meta = !array_key_exists('show_meta', $cfg) || !empty($cfg['show_meta']);
|
||||
if ($show_thumb && (string) $data['primary'] !== '') {
|
||||
$default_attr = empty($data['has_real']) ? ' data-thumb="default"' : '';
|
||||
$thumb = '<div class="mr10"><div class="item-thumbnail"><a' . $target . ' href="' . esc_url((string) $data['permalink']) . '"><img' . $default_attr . aksrt_get_lazy_attr('lazy_posts_thumb', (string) $data['primary'], 'fit-cover radius8') . ' alt="' . esc_attr((string) $data['title']) . '"></a></div></div>';
|
||||
}
|
||||
if (empty($data['has_img'])) {
|
||||
$classes[] = 'posts-mini--no-thumb';
|
||||
$number = '';
|
||||
if (!empty($cfg['show_number'])) {
|
||||
$number_value = max(1, (int) ($cfg['number_offset'] ?? 1));
|
||||
$colors = ['c-red', 'c-yellow', 'c-purple', 'c-blue', 'c-green'];
|
||||
$number_class = $colors[$number_value - 1] ?? '';
|
||||
$number = '<span class="badg badg-sm mr3 ' . esc_attr($number_class) . '">' . $number_value . '</span>';
|
||||
}
|
||||
|
||||
$number_html = '';
|
||||
if ($cfg['show_number'] && $cfg['number_offset'] > 0) {
|
||||
$badge_colors = ['c-red', 'c-yellow', 'c-orange', 'c-blue', 'c-green'];
|
||||
$index = $cfg['number_offset'] - 1;
|
||||
$color = $badge_colors[$index] ?? '';
|
||||
$number_html = '<span class="badg badg-sm mr3 ' . esc_attr($color) . '">' . (int) $cfg['number_offset'] . '</span>';
|
||||
$title_class = $show_thumb ? ' text-ellipsis-2' : ' text-ellipsis' . (!$show_meta && empty($cfg['show_number']) ? ' icon-circle' : '');
|
||||
$title = esc_html((string) $data['title']);
|
||||
if ((string) ($data['subtitle'] ?? '') !== '') {
|
||||
$title .= '<span class="focus-color">' . esc_html((string) $data['subtitle']) . '</span>';
|
||||
}
|
||||
|
||||
$thumb_html = '';
|
||||
$target_attr = !empty($cfg['target_blank']) ? ' target="_blank"' : '';
|
||||
if ($cfg['show_thumb'] && !empty($data['has_img'])) {
|
||||
$fit_class = !empty($cfg['thumb_fit']) && $cfg['thumb_fit'] === 'contain' ? 'fit-contain' : 'fit-cover';
|
||||
$thumb_attr = aksrt_get_lazy_attr('lazy_posts_thumb', (string) $data['img_url'], $fit_class);
|
||||
$thumb_img = '<img' . $thumb_attr . ' alt="' . esc_attr($data['title']) . '">';
|
||||
|
||||
$thumb_html = '<a href="' . esc_url($data['permalink']) . '" class="item-thumbnail" aria-label="' . esc_attr($data['title']) . '"' . $target_attr . '>' . $thumb_img . '</a>';
|
||||
$meta = '';
|
||||
if ($show_meta) {
|
||||
$show_time = !empty($cfg['show_time']);
|
||||
if (!empty($cfg['show_author'])) {
|
||||
$author_value = $show_time ? (string) $data['time_ago'] : (string) $data['author_name'];
|
||||
$meta_left = '<item class="meta-author flex ac"><img class="avatar-mini" src="' . esc_url((string) $data['avatar_url']) . '" alt="" width="20" height="20"><span class="ml6">' . esc_html($author_value) . '</span></item>';
|
||||
} else {
|
||||
$meta_left = $show_time ? '<item title="' . esc_attr((string) $data['time_title']) . '" class="icon-circle mln3">' . esc_html((string) $data['time_ago']) . '</item>' : '';
|
||||
}
|
||||
$pay = aksrt_renderer_pay_badge($data, true);
|
||||
if ($meta_left === '') {
|
||||
$meta_left = $pay;
|
||||
$pay = '';
|
||||
}
|
||||
if ($meta_left === '') {
|
||||
$meta_left = '<item></item>';
|
||||
}
|
||||
$meta_right = $pay . '<item class="meta-view">' . aksrt_renderer_svg_icon('view') . esc_html(aksrt_renderer_meta_number((int) $data['views'])) . '</item>';
|
||||
$meta = '<div class="item-meta muted-2-color flex jsb ac' . (!$show_thumb ? ' mt6' : '') . '">' . $meta_left . '<div class="meta-right">' . $meta_right . '</div></div>';
|
||||
}
|
||||
|
||||
$heading_class = 'item-heading' . (!empty($cfg['heading_bold']) ? ' item-heading--bold' : '') . (!empty($data['has_img']) ? ' text-ellipsis-2' : ' text-ellipsis');
|
||||
$title_html = '<h2 class="' . esc_attr($heading_class) . '">' . $number_html . '<a href="' . esc_url($data['permalink']) . '"' . $target_attr . '>' . aksrt_renderer_title_markup($data, $cfg) . '</a></h2>';
|
||||
|
||||
$html = '<div class="' . esc_attr(implode(' ', array_unique($classes))) . '">';
|
||||
$html .= $thumb_html;
|
||||
$html .= '<div class="posts-mini-con flex xx flex1 jsb">';
|
||||
$html .= $title_html;
|
||||
$html .= aksrt_renderer_meta($data, $cfg);
|
||||
$html .= '</div></div>';
|
||||
|
||||
return $html;
|
||||
$class = trim('posts-mini ' . (string) ($cfg['class'] ?? ''));
|
||||
return '<div class="' . esc_attr($class) . '">' . $thumb . '<div class="posts-mini-con flex xx flex1 jsb"><h2 class="item-heading' . esc_attr($title_class) . '">' . $number . '<a' . $target . ' href="' . esc_url((string) $data['permalink']) . '">' . $title . '</a></h2>' . $meta . '</div></div>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_render_post')) {
|
||||
/**
|
||||
* Render one post item inside a loop.
|
||||
*
|
||||
* @param array<string,mixed> $config Renderer config overrides.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_render_post(array $config = []): string {
|
||||
$cfg = aksrt_renderer_config($config);
|
||||
function aksrt_render_post(array $args = []): string {
|
||||
$cfg = aksrt_renderer_config($args);
|
||||
$data = aksrt_renderer_collect_post_data($cfg);
|
||||
|
||||
if (empty($data)) {
|
||||
if (!$data) {
|
||||
return '';
|
||||
}
|
||||
|
||||
switch ($cfg['mode']) {
|
||||
case 'card':
|
||||
case 'grid-cms':
|
||||
return aksrt_renderer_card($data, $cfg);
|
||||
case 'mini':
|
||||
return aksrt_renderer_mini($data, $cfg);
|
||||
case 'list':
|
||||
default:
|
||||
return aksrt_renderer_list($data, $cfg);
|
||||
}
|
||||
return ($cfg['mode'] ?? 'list') === 'card'
|
||||
? aksrt_renderer_card($data, $cfg)
|
||||
: aksrt_renderer_list($data, $cfg);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_render_post_list')) {
|
||||
/**
|
||||
* Render a query loop with the unified renderer.
|
||||
* Render the canonical article stream.
|
||||
*
|
||||
* @param WP_Query|null $query Posts query. Falls back to global loop.
|
||||
* @param array<string,mixed> $config Renderer config overrides.
|
||||
* @param bool $echo Whether to echo output.
|
||||
* @return string
|
||||
* @param array<string,mixed> $args Zibll-shaped list arguments.
|
||||
* @param WP_Query|null $query Optional custom query.
|
||||
*/
|
||||
function aksrt_render_post_list(?WP_Query $query = null, array $config = [], bool $echo = true): string {
|
||||
$cfg = aksrt_renderer_config($config);
|
||||
$wrapper_classes = ['posts-row', 'ajaxpager'];
|
||||
|
||||
if ($cfg['context'] === 'home') {
|
||||
$wrapper_classes[] = 'aksrt-homepage__posts';
|
||||
$wrapper_classes[] = 'post-grid';
|
||||
$wrapper_classes[] = 'post-grid--home';
|
||||
} elseif ($cfg['mode'] !== 'mini') {
|
||||
$wrapper_classes[] = 'post-grid';
|
||||
$wrapper_classes[] = 'post-grid--' . $cfg['mode'];
|
||||
function aksrt_render_post_list(array $args = [], ?WP_Query $query = null, bool $echo = true): string {
|
||||
$cfg = aksrt_renderer_config($args);
|
||||
$has_posts = $query instanceof WP_Query ? $query->have_posts() : have_posts();
|
||||
if (!$has_posts) {
|
||||
$html = aksrt_get_null(__('暂无内容', 'aksrt'), 100, 'null-post.svg');
|
||||
if ($echo) {
|
||||
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return '';
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
if (!empty($config['wrapper_class']) && is_string($config['wrapper_class'])) {
|
||||
foreach (preg_split('/\s+/', trim($config['wrapper_class'])) as $extra_class) {
|
||||
$extra_class = sanitize_html_class($extra_class);
|
||||
if ($extra_class !== '') {
|
||||
$wrapper_classes[] = $extra_class;
|
||||
}
|
||||
$classes = ['posts-row', 'ajaxpager'];
|
||||
foreach (preg_split('/\s+/', trim((string) ($cfg['wrapper_class'] ?? ''))) ?: [] as $class) {
|
||||
$class = sanitize_html_class($class);
|
||||
if ($class !== '') {
|
||||
$classes[] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
$wrapper_attr = 'class="' . esc_attr(implode(' ', array_unique($wrapper_classes))) . '"';
|
||||
if ($cfg['columns'] > 1) {
|
||||
$wrapper_attr .= ' style="--aksrt-widget-columns:' . (int) $cfg['columns'] . '"';
|
||||
}
|
||||
|
||||
$data_view = in_array($cfg['mode'], ['card', 'grid-cms'], true) ? 'card' : $cfg['mode'];
|
||||
// Homepage panel already provides .posts-row.ajaxpager — allow callers to skip nesting.
|
||||
$skip_wrapper = !empty($config['skip_wrapper']);
|
||||
$html = '';
|
||||
$html = empty($cfg['skip_wrapper'])
|
||||
? '<div class="' . esc_attr(implode(' ', array_unique($classes))) . '" data-view="' . esc_attr((string) $cfg['mode']) . '">'
|
||||
: '';
|
||||
|
||||
if ($query instanceof WP_Query) {
|
||||
if (!$query->have_posts()) {
|
||||
$html = '<div class="no-results"><p>' . esc_html__('暂无文章', 'aksrt') . '</p></div>';
|
||||
} else {
|
||||
if (!$skip_wrapper) {
|
||||
$html .= '<div ' . $wrapper_attr . ' data-view="' . esc_attr($data_view) . '">';
|
||||
}
|
||||
$number = $cfg['number_offset'];
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
if ($cfg['mode'] === 'mini' && $cfg['show_number']) {
|
||||
$number++;
|
||||
$config['number_offset'] = $number;
|
||||
$cfg = aksrt_renderer_config($config);
|
||||
}
|
||||
$html .= aksrt_render_post($cfg);
|
||||
}
|
||||
if (!$skip_wrapper) {
|
||||
$html .= '</div>';
|
||||
}
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$html .= aksrt_render_post($cfg);
|
||||
}
|
||||
wp_reset_postdata();
|
||||
} else {
|
||||
if (!have_posts()) {
|
||||
$html = '<div class="no-results"><p>' . esc_html__('暂无文章', 'aksrt') . '</p></div>';
|
||||
} else {
|
||||
if (!$skip_wrapper) {
|
||||
$html .= '<div ' . $wrapper_attr . ' data-view="' . esc_attr($data_view) . '">';
|
||||
}
|
||||
while (have_posts()) {
|
||||
the_post();
|
||||
$html .= aksrt_render_post($cfg);
|
||||
}
|
||||
if (!$skip_wrapper) {
|
||||
$html .= '</div>';
|
||||
}
|
||||
while (have_posts()) {
|
||||
the_post();
|
||||
$html .= aksrt_render_post($cfg);
|
||||
}
|
||||
}
|
||||
if (empty($cfg['skip_wrapper'])) {
|
||||
$html .= '</div>';
|
||||
}
|
||||
|
||||
if ($echo) {
|
||||
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return '';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_render_mini_list')) {
|
||||
/**
|
||||
* Convenience wrapper for mini lists.
|
||||
*
|
||||
* @param WP_Query $query Posts query.
|
||||
* @param array<string,mixed> $config Renderer config overrides.
|
||||
* @param bool $echo Whether to echo output.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_render_mini_list(WP_Query $query, array $config = [], bool $echo = true): string {
|
||||
$config['mode'] = 'mini';
|
||||
return aksrt_render_post_list($query, $config, $echo);
|
||||
function aksrt_render_mini_list(WP_Query $query, array $args = [], bool $echo = true): string {
|
||||
$cfg = aksrt_renderer_config($args);
|
||||
$html = '';
|
||||
$number = max(0, (int) ($args['number_offset'] ?? 0));
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$data = aksrt_renderer_collect_post_data($cfg);
|
||||
if (!$data) {
|
||||
continue;
|
||||
}
|
||||
$number++;
|
||||
$html .= aksrt_renderer_mini($data, array_merge($cfg, ['number_offset' => $number]));
|
||||
}
|
||||
wp_reset_postdata();
|
||||
if ($echo) {
|
||||
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return '';
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_render_placeholder')) {
|
||||
/**
|
||||
* Render skeleton placeholders for loading states.
|
||||
*
|
||||
* @param string $mode list|card|mini.
|
||||
* @param int $count Number of placeholders.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_render_placeholder(string $mode = 'list', int $count = 3): string {
|
||||
$count = max(1, min(12, $count));
|
||||
$html = '';
|
||||
|
||||
if ($mode === 'card') {
|
||||
$item = '<div class="posts-item card"><div class="item-thumbnail"><div class="radius8 item-thumbnail placeholder"></div></div>'
|
||||
. '<div class="item-body"><h2 class="item-excerpt placeholder t1 item-heading"></h2>'
|
||||
. '<p class="mt10 placeholder k2"></p>'
|
||||
. '<i class="flex jsb"><i class="placeholder s1"></i><i class="placeholder s1 ml10"></i></i></div></div>';
|
||||
$html = str_repeat($item, $count);
|
||||
} elseif ($mode === 'mini') {
|
||||
$item = '<div class="posts-mini"><div class="item-thumbnail"><div class="radius8 placeholder"></div></div>'
|
||||
. '<div class="posts-mini-con"><div class="placeholder t1"></div>'
|
||||
. '<div class="placeholder k2 mt6"></div></div></div>';
|
||||
$html = str_repeat($item, $count);
|
||||
} else {
|
||||
$item = '<div class="posts-item list flex"><div class="post-graphic"><div class="radius8 item-thumbnail placeholder"></div></div>'
|
||||
. '<div class="item-body flex xx flex1 jsb"><p class="placeholder t1"></p>'
|
||||
. '<h4 class="item-excerpt placeholder k1"></h4><p class="placeholder k2"></p>'
|
||||
. '<i><i class="placeholder s1"></i><i class="placeholder s1 ml10"></i></i></div></div>';
|
||||
$html = str_repeat($item, $count);
|
||||
}
|
||||
|
||||
return $html;
|
||||
$class = $mode === 'card' ? 'posts-item card' : 'posts-item list flex';
|
||||
$item = '<posts class="' . esc_attr($class) . '"><div class="post-graphic"><div class="item-thumbnail placeholder"></div></div><div class="item-body flex xx flex1 jsb"><div class="placeholder t1"></div><div class="placeholder k2"></div><div class="placeholder s1"></div></div></posts>';
|
||||
return str_repeat($item, $count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Shared post renderer helpers.
|
||||
* Zibll 9.0 article-list data and markup fragments.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
@@ -8,12 +8,7 @@
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_renderer_collect_post_data')) {
|
||||
/**
|
||||
* Aggregate the runtime data needed by all renderer modes.
|
||||
*
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
/** @return array<string,mixed> */
|
||||
function aksrt_renderer_collect_post_data(array $cfg): array {
|
||||
$post_id = (int) get_the_ID();
|
||||
if ($post_id <= 0) {
|
||||
@@ -21,278 +16,264 @@ if (!function_exists('aksrt_renderer_collect_post_data')) {
|
||||
}
|
||||
|
||||
$images = aksrt_renderer_resolve_images($post_id, $cfg);
|
||||
$gallery_images = array_slice($images['gallery'], 0, $cfg['multi_thumb_limit']);
|
||||
$is_mult_thumb = !empty($cfg['multi_thumb_enabled'])
|
||||
&& count($gallery_images) >= (int) $cfg['multi_thumb_min']
|
||||
&& $cfg['mode'] === 'list';
|
||||
|
||||
$author_id = (int) get_post_field('post_author', $post_id);
|
||||
$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;
|
||||
}
|
||||
|
||||
$custom_excerpt = class_exists('\AKSRT\Core\PostMetaBox')
|
||||
? (string) \AKSRT\Core\PostMetaBox::get_meta_value($post_id, 'custom_excerpt', '')
|
||||
: '';
|
||||
$custom_subtitle = (string) get_post_meta($post_id, '_subtitle', true);
|
||||
$excerpt_source = $custom_excerpt !== '' ? $custom_excerpt : (string) get_the_excerpt($post_id);
|
||||
if ($excerpt_source === '') {
|
||||
$excerpt_source = (string) get_post_field('post_content', $post_id, 'raw');
|
||||
$excerpt = $custom_excerpt !== '' ? $custom_excerpt : (string) get_the_excerpt($post_id);
|
||||
if ($excerpt === '') {
|
||||
$excerpt = (string) get_post_field('post_content', $post_id, 'raw');
|
||||
}
|
||||
$excerpt = wp_trim_words(wp_strip_all_tags($excerpt_source), $cfg['excerpt_words'], '...');
|
||||
$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);
|
||||
|
||||
$resource_meta = function_exists('aksrt_get_resource_meta') ? aksrt_get_resource_meta($post_id) : [];
|
||||
$resource_strip = function_exists('aksrt_resource_meta_strip') ? aksrt_resource_meta_strip($resource_meta) : [];
|
||||
$subtitle = class_exists('\AKSRT\Core\PostMetaBox')
|
||||
? (string) \AKSRT\Core\PostMetaBox::get_meta_value($post_id, 'subtitle', '')
|
||||
: '';
|
||||
$pay_meta = aksrt_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' => $custom_subtitle,
|
||||
'excerpt' => $excerpt,
|
||||
'img_url' => $images['primary'],
|
||||
'has_img' => !empty($images['has_thumb']),
|
||||
'has_real_img' => !empty($images['has_real']),
|
||||
'gallery_images' => $gallery_images,
|
||||
'is_mult_thumb' => $is_mult_thumb,
|
||||
'is_video_cover' => !empty(get_post_meta($post_id, '_aksrt_featured_video', true)) || !empty(get_post_meta($post_id, '_video_url', true)),
|
||||
'author_id' => $author_id,
|
||||
'avatar_url' => get_avatar_url($author_id, ['size' => 40]),
|
||||
'author_name' => get_the_author(),
|
||||
'categories' => $categories,
|
||||
'tags' => $tags,
|
||||
'comment_count' => (int) get_comments_number($post_id),
|
||||
'views' => function_exists('aksrt_get_post_views') ? (int) aksrt_get_post_views($post_id) : 0,
|
||||
'likes' => function_exists('aksrt_get_post_likes') ? (int) aksrt_get_post_likes($post_id) : 0,
|
||||
'time_ago' => human_time_diff((int) get_the_time('U', $post_id), current_time('timestamp')),
|
||||
'resource_badge' => function_exists('aksrt_resource_card_badge_text') ? (string) aksrt_resource_card_badge_text($post_id) : '',
|
||||
'resource_strip' => $resource_strip,
|
||||
'is_resource' => function_exists('aksrt_is_resource_post') ? aksrt_is_resource_post($post_id) : false,
|
||||
'is_sticky' => is_sticky($post_id),
|
||||
'thumb_ratio_css' => aksrt_renderer_thumb_ratio_value((string) $cfg['thumb_ratio']),
|
||||
'thumb_ratio_key' => (string) $cfg['thumb_ratio'],
|
||||
'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_slice((array) $images['slides'], 0, 8),
|
||||
'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 : '',
|
||||
'avatar_url' => get_avatar_url($author_id, ['size' => 40]),
|
||||
'time_title' => $time_value,
|
||||
'time_ago' => human_time_diff($time_timestamp, current_time('timestamp')) . __('前', 'aksrt'),
|
||||
'views' => (int) aksrt_get_post_views($post_id),
|
||||
'likes' => (int) aksrt_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) aksrt_resource_card_badge_text($post_id),
|
||||
'pay_type' => sanitize_key((string) ($pay_meta['pay_type'] ?? 'no')),
|
||||
'pay_limit' => (int) ($pay_meta['pay_limit'] ?? 0),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_article_attrs')) {
|
||||
/**
|
||||
* Build the article wrapper attributes.
|
||||
*
|
||||
* @param string[] $classes CSS classes.
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_article_attrs(array $classes, array $data): string {
|
||||
$classes[] = 'thumb-ratio--' . str_replace(':', '-', (string) $data['thumb_ratio_key']);
|
||||
|
||||
return sprintf(
|
||||
'class="%s" style="%s"',
|
||||
esc_attr(implode(' ', array_unique(array_filter($classes)))),
|
||||
esc_attr('--aksrt-thumb-ratio:' . $data['thumb_ratio_css'])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_thumb')) {
|
||||
/**
|
||||
* Render the primary thumbnail.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_thumb(array $data, array $cfg): string {
|
||||
if (!$cfg['show_thumb'] || empty($data['has_img'])) {
|
||||
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;
|
||||
|
||||
$img = (string) $data['img_url'];
|
||||
$title = (string) $data['title'];
|
||||
$href = (string) $data['permalink'];
|
||||
$is_sticky = !empty($data['is_sticky']);
|
||||
$has_real_img = !empty($data['has_real_img']);
|
||||
|
||||
$fit_class = !empty($cfg['thumb_fit']) && $cfg['thumb_fit'] === 'contain' ? 'fit-contain' : 'fit-cover';
|
||||
$img_attr = aksrt_get_lazy_attr('lazy_posts_thumb', $img, $fit_class);
|
||||
$img_html = '<img' . $img_attr . ' alt="' . esc_attr($title) . '">';
|
||||
|
||||
$sticky_html = ($is_sticky && !empty($cfg['badge_show']))
|
||||
? '<badge class="img-badge left jb-red">' . esc_html__('置顶', 'aksrt') . '</badge>'
|
||||
: '';
|
||||
|
||||
$format_badge = '';
|
||||
if (!empty($data['is_mult_thumb']) && !empty($data['gallery_images'])) {
|
||||
$format_badge = '<badge class="b-black opacity8 abs-right">' . esc_html(count($data['gallery_images'])) . '</badge>';
|
||||
} elseif (!empty($data['is_video_cover'])) {
|
||||
$format_badge = '<badge class="b-black opacity8 abs-right"><i class="fas fa-play-circle" aria-hidden="true"></i></badge>';
|
||||
}
|
||||
|
||||
$empty_class = $has_real_img ? '' : ' item-thumbnail--fallback';
|
||||
$target_attr = !empty($cfg['target_blank']) ? ' target="_blank"' : '';
|
||||
|
||||
if ($cfg['mode'] === 'list') {
|
||||
$graphic_class = 'post-graphic';
|
||||
if (($cfg['list_img_position'] ?? 'left') === 'right') {
|
||||
$graphic_class .= ' order1';
|
||||
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') . '" data-post-thumb-video>';
|
||||
$content .= '<div class="img-thumb"><img' . $default_attr . aksrt_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 class="dplayer dplayer-thumb"><video playsinline loop preload="none"' . ($muted ? ' muted' : '') . ' data-src="' . esc_url((string) $data['video_url']) . '"></video></div></div></div>';
|
||||
$format_icon = '<i class="fa fa-play-circle em12 mt6 c-white opacity8" aria-hidden="true"></i>';
|
||||
} elseif ($has_slides) {
|
||||
$content .= '<div class="relative zib-slider"><div class="new-swiper item-thumbnail' . ($is_contain ? ' gradient-background' : '') . '" data-loop="true" data-effect="slide" data-autoplay="1" data-post-thumb-slider><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' . aksrt_get_lazy_attr('lazy_posts_thumb', (string) $image, 'radius8') . ' alt="' . esc_attr((string) $data['title']) . '"></a></div>';
|
||||
}
|
||||
$content .= '</div><div class="swiper-pagination kaoyou"></div></div></div>';
|
||||
$format_icon = '<badge class="b-black opacity8 mt6"><i class="fa 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 . aksrt_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 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 fa-image mr3" aria-hidden="true"></i>' . (int) $data['gallery_count'] . '</badge>';
|
||||
} elseif ($format === 'video') {
|
||||
$format_icon = '<i class="fa fa-play-circle em12 mr6 mt6 c-white opacity8" aria-hidden="true"></i>';
|
||||
}
|
||||
return '<div class="' . esc_attr($graphic_class) . '"><div class="item-thumbnail' . esc_attr($empty_class) . '"><a href="' . esc_url($href) . '" rel="bookmark"' . $target_attr . '>'
|
||||
. $img_html . '</a>' . $sticky_html . $format_badge . '</div></div>';
|
||||
}
|
||||
|
||||
return '<div class="item-thumbnail' . esc_attr($empty_class) . '"><a href="' . esc_url($href) . '" rel="bookmark"' . $target_attr . '>'
|
||||
. $img_html . '</a>' . $sticky_html . $format_badge . '</div>';
|
||||
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__('置顶', 'aksrt') . '</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('aksrt_renderer_mult_thumb')) {
|
||||
/**
|
||||
* Render the multi-image strip used by list cards.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_mult_thumb(array $data): string {
|
||||
if (empty($data['is_mult_thumb']) || empty($data['gallery_images'])) {
|
||||
function aksrt_renderer_mult_thumb(array $data, array $cfg): string {
|
||||
if (empty($data['is_mult_thumb'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$html = '<a class="thumb-items contain" href="' . esc_url($data['permalink']) . '" aria-label="' . esc_attr($data['title']) . '">';
|
||||
|
||||
foreach (array_slice($data['gallery_images'], 0, 4) as $image) {
|
||||
$html .= '<span>';
|
||||
$html .= '<img' . aksrt_get_lazy_attr('lazy_posts_thumb', (string) $image, 'fit-cover') . ' alt="">';
|
||||
$html .= '</span>';
|
||||
$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 fa-image mr3" aria-hidden="true"></i>+' . ((int) $data['gallery_count'] - 4) . '</badge></div>';
|
||||
}
|
||||
$html .= '<span>' . $badge . '<img' . aksrt_get_lazy_attr('lazy_posts_thumb', (string) $image, 'fit-cover radius8') . ' alt=""></span>';
|
||||
}
|
||||
return $html . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
$html .= '</a>';
|
||||
return $html;
|
||||
if (!function_exists('aksrt_renderer_pay_badge')) {
|
||||
function aksrt_renderer_pay_badge(array $data, bool $compact = false): string {
|
||||
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('aksrt_get_pay_types') ? aksrt_get_pay_types() : [];
|
||||
$title = (string) ($type_labels[(string) ($data['pay_type'] ?? '')] ?? __('付费内容', 'aksrt'));
|
||||
$icon = $is_vip ? aksrt_renderer_vip_icon($vip_level) : '';
|
||||
if ($compact) {
|
||||
return '<item class="meta-pay badg badg-sm mr6 ' . esc_attr($class) . '" data-toggle="tooltip" title="' . esc_attr($title) . '">' . $icon . esc_html((string) $data['resource_badge']) . '</item>';
|
||||
}
|
||||
$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('aksrt_renderer_vip_icon')) {
|
||||
function aksrt_renderer_vip_icon(int $level): string {
|
||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
||||
return '<i class="fas fa-crown mr3" aria-hidden="true"></i>';
|
||||
}
|
||||
$settings = \AKSRT\Settings\Settings::get_payment_vip_settings();
|
||||
$url = esc_url((string) ($settings['levels'][$level]['img_icon'] ?? ''));
|
||||
return $url !== ''
|
||||
? '<img class="mr3" src="' . $url . '" alt="" aria-hidden="true">'
|
||||
: '<i class="fas fa-crown mr3" aria-hidden="true"></i>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_badges')) {
|
||||
/**
|
||||
* Render taxonomy and resource badges.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_badges(array $data, array $cfg): string {
|
||||
$items = [];
|
||||
|
||||
if (!empty($cfg['show_resource_badge']) && $data['resource_badge'] !== '') {
|
||||
$items[] = '<a href="' . esc_url($data['permalink']) . '#posts-pay" class="meta-pay but jb-yellow">' . esc_html($data['resource_badge']) . '</a>';
|
||||
}
|
||||
|
||||
if (!empty($cfg['show_badges']) && !empty($cfg['badge_show']) && $cfg['category_limit'] > 0) {
|
||||
foreach (array_slice($data['categories'], 0, $cfg['category_limit']) as $category) {
|
||||
$items[] = '<a href="' . esc_url(get_category_link($category->term_id)) . '" class="but"><i class="far fa-folder-open" aria-hidden="true"></i> ' . esc_html($category->name) . '</a>';
|
||||
$types = (array) ($cfg['badge_types'] ?? []);
|
||||
if (in_array('pay', $types, true)) {
|
||||
$pay = aksrt_renderer_pay_badge($data);
|
||||
if ($pay !== '') {
|
||||
$items[] = $pay;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($cfg['show_tags']) && $cfg['tag_limit'] > 0) {
|
||||
foreach (array_slice($data['tags'], 0, $cfg['tag_limit']) as $tag) {
|
||||
$items[] = '<a href="' . esc_url(get_tag_link($tag->term_id)) . '" class="but">#' . esc_html($tag->name) . '</a>';
|
||||
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__('查看更多分类文章', 'aksrt') . '" href="' . esc_url(get_category_link($category->term_id)) . '"><i class="fa fa-folder-open-o" aria-hidden="true"></i>' . esc_html($category->name) . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data['is_resource'])) {
|
||||
$items[] = '<span class="but jb-vip">VIP</span>';
|
||||
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__('查看此标签更多文章', 'aksrt') . '" href="' . esc_url(get_tag_link($tag->term_id)) . '"># ' . esc_html($tag->name) . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($items)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<div class="item-tags scroll-x no-scrollbar">' . implode('', $items) . '</div>';
|
||||
return $items ? '<div class="item-tags scroll-x no-scrollbar mb6">' . implode('', $items) . '</div>' : '';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_resource_strip')) {
|
||||
/**
|
||||
* Render compact resource meta chips.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_resource_strip(array $data): string {
|
||||
if (empty($data['resource_strip']) || !is_array($data['resource_strip'])) {
|
||||
return '';
|
||||
}
|
||||
if (!function_exists('aksrt_renderer_meta_number')) {
|
||||
function aksrt_renderer_meta_number(int $number): string {
|
||||
return (string) aksrt_format_number($number);
|
||||
}
|
||||
}
|
||||
|
||||
$html = '<ul class="item-cms-strip">';
|
||||
foreach ($data['resource_strip'] as $item) {
|
||||
$html .= '<li>' . esc_html((string) $item) . '</li>';
|
||||
}
|
||||
$html .= '</ul>';
|
||||
|
||||
return $html;
|
||||
if (!function_exists('aksrt_renderer_svg_icon')) {
|
||||
function aksrt_renderer_svg_icon(string $name): string {
|
||||
return '<svg class="icon" aria-hidden="true"><use xlink:href="#icon-' . esc_attr($name) . '"></use></svg>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('aksrt_renderer_meta')) {
|
||||
/**
|
||||
* Render the meta bar.
|
||||
*
|
||||
* @param array<string,mixed> $data Collected post data.
|
||||
* @param array<string,mixed> $cfg Renderer config.
|
||||
* @return string
|
||||
*/
|
||||
function aksrt_renderer_meta(array $data, array $cfg): string {
|
||||
if (!$cfg['show_meta']) {
|
||||
return '';
|
||||
function aksrt_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 = '<img class="avatar-mini" src="' . esc_url((string) $data['avatar_url']) . '" alt="" width="20" height="20">';
|
||||
$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>';
|
||||
}
|
||||
|
||||
$format_number = function_exists('aksrt_format_number') ? 'aksrt_format_number' : 'strval';
|
||||
|
||||
if ($cfg['mode'] === 'mini') {
|
||||
$items = [];
|
||||
if (!empty($cfg['show_date'])) {
|
||||
$items[] = '<span class="meta-item">' . esc_html($data['time_ago']) . '</span>';
|
||||
}
|
||||
if (!empty($cfg['show_views'])) {
|
||||
$items[] = '<span class="meta-item"><i class="fas fa-eye" aria-hidden="true"></i> ' . esc_html($format_number($data['views'])) . '</span>';
|
||||
}
|
||||
|
||||
if (empty($items)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<div class="item-meta">' . implode('<span class="meta-dot" aria-hidden="true"></span>', $items) . '</div>';
|
||||
$right = '';
|
||||
if (!empty($data['comments_open']) && empty($cfg['close_comments'])) {
|
||||
$right .= '<item class="meta-comm"><a rel="nofollow" data-toggle="tooltip" title="' . esc_attr__('去评论', 'aksrt') . '" href="' . esc_url((string) $data['comments_link']) . '">' . aksrt_renderer_svg_icon('comment') . esc_html((string) $data['comments']) . '</a></item>';
|
||||
}
|
||||
$right .= '<item class="meta-view">' . aksrt_renderer_svg_icon('view') . esc_html(aksrt_renderer_meta_number((int) $data['views'])) . '</item>';
|
||||
if (!empty($cfg['show_like']) && (string) ($data['post_type'] ?? '') === 'post') {
|
||||
$right .= '<item class="meta-like">' . aksrt_renderer_svg_icon('like') . esc_html(aksrt_renderer_meta_number((int) $data['likes'])) . '</item>';
|
||||
}
|
||||
|
||||
$left = [];
|
||||
if (!empty($cfg['show_author'])) {
|
||||
$left[] = '<item class="meta-author flex ac"><img' . aksrt_get_lazy_attr('lazy_avatar', (string) $data['avatar_url'], 'avatar-mini', aksrt_get_lazy_thumb('sm')) . ' alt="" width="20" height="20"><name class="meta-name">' . esc_html($data['author_name']) . '</name></item>';
|
||||
}
|
||||
if (!empty($cfg['show_date'])) {
|
||||
$left[] = '<item class="meta-time">' . esc_html($data['time_ago']) . '</item>';
|
||||
}
|
||||
|
||||
$right = [];
|
||||
if (!empty($cfg['show_comments'])) {
|
||||
$right[] = '<item class="meta-view"><i class="fas fa-comment" aria-hidden="true"></i> ' . esc_html((string) $data['comment_count']) . '</item>';
|
||||
}
|
||||
if (!empty($cfg['show_views'])) {
|
||||
$right[] = '<item class="meta-view"><i class="fas fa-eye" aria-hidden="true"></i> ' . esc_html($format_number($data['views'])) . '</item>';
|
||||
}
|
||||
if (!empty($cfg['show_likes'])) {
|
||||
$right[] = '<item class="meta-view"><i class="fas fa-thumbs-up" aria-hidden="true"></i> ' . esc_html($format_number($data['likes'])) . '</item>';
|
||||
}
|
||||
|
||||
if (empty($left) && empty($right)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$html = '<div class="item-meta muted-2-color flex jsb ac">';
|
||||
if (!empty($left)) {
|
||||
$html .= '<div class="meta-author-group flex ac">' . implode('<span class="meta-dot" aria-hidden="true"></span>', $left) . '</div>';
|
||||
}
|
||||
if (!empty($right)) {
|
||||
$html .= '<div class="meta-right">' . implode('', $right) . '</div>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
return '<div class="item-meta muted-2-color flex jsb ac">' . $meta_left . '<div class="meta-right">' . $right . '</div></div>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,38 +24,51 @@ if (!function_exists('aksrt_render_pagination')) {
|
||||
* }
|
||||
*/
|
||||
function aksrt_render_pagination(?WP_Query $query = null, array $args = []): void {
|
||||
global $wp_query;
|
||||
$q = $query ?? $wp_query;
|
||||
if (!($q instanceof WP_Query)) {
|
||||
return;
|
||||
}
|
||||
$page_var = sanitize_key((string) ($args['page_var'] ?? 'paged')) ?: 'paged';
|
||||
$current_page = isset($args['current_page'])
|
||||
? max(1, (int) $args['current_page'])
|
||||
: max(1, (int) $q->get('paged'), (int) get_query_var('paged'), (int) get_query_var('page'));
|
||||
$max_pages = (int) $q->max_num_pages;
|
||||
|
||||
$pagination_mode = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_pagination_mode()
|
||||
: 'numbered';
|
||||
|
||||
if ($pagination_mode === 'numbered') {
|
||||
global $wp_query;
|
||||
$q = $query ?? $wp_query;
|
||||
if (!($q instanceof WP_Query) || $q->max_num_pages <= 1) {
|
||||
if ($max_pages <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current_page = max(1, (int) $q->get('paged'), (int) get_query_var('paged'), (int) get_query_var('page'));
|
||||
$max_pages = (int) $q->max_num_pages;
|
||||
$links = paginate_links([
|
||||
$paginate_args = [
|
||||
'total' => $max_pages,
|
||||
'current' => $current_page,
|
||||
'mid_size' => 2,
|
||||
'prev_text' => '<span aria-hidden="true">‹</span>',
|
||||
'next_text' => '<span aria-hidden="true">›</span>',
|
||||
'type' => 'plain',
|
||||
]);
|
||||
];
|
||||
if ($page_var !== 'paged') {
|
||||
$big = 999999999;
|
||||
$paginate_args['base'] = str_replace((string) $big, '%#%', esc_url_raw(add_query_arg($page_var, $big)));
|
||||
$paginate_args['format'] = '';
|
||||
}
|
||||
$links = paginate_links($paginate_args);
|
||||
|
||||
if (empty($links)) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<div class="pagenav ajax-pag aksrt-pagination content-stream__footer-nav">';
|
||||
echo '<div class="pagenav ajax-pag" data-aksrt-pagination data-mode="numbered" data-page-var="' . esc_attr($page_var) . '" data-max-pages="' . esc_attr((string) $max_pages) . '">';
|
||||
echo wp_kses_post($links);
|
||||
if ($max_pages > 8) {
|
||||
echo '<span class="pag-jump">';
|
||||
echo '<input type="number" class="jump-input" min="1" max="' . esc_attr((string) $max_pages) . '" value="' . esc_attr((string) $current_page) . '" data-max-pages="' . esc_attr((string) $max_pages) . '" />';
|
||||
echo '<button type="button" class="ajax-next order-ajax-next" data-jump-archive="1">' . esc_html__('跳转', 'aksrt') . '</button>';
|
||||
echo '<button type="button" class="ajax-next order-ajax-next" data-jump-archive="1" data-page-var="' . esc_attr($page_var) . '">' . esc_html__('跳转', 'aksrt') . '</button>';
|
||||
echo '</span>';
|
||||
}
|
||||
echo '</div>';
|
||||
@@ -63,14 +76,6 @@ if (!function_exists('aksrt_render_pagination')) {
|
||||
}
|
||||
|
||||
// load_more / infinite 模式
|
||||
global $wp_query;
|
||||
$q = $query ?? $wp_query;
|
||||
if (!($q instanceof WP_Query)) {
|
||||
return;
|
||||
}
|
||||
$max_pages = (int) $q->max_num_pages;
|
||||
$current_page = max(1, (int) $q->get('paged'), (int) get_query_var('paged'), (int) get_query_var('page'));
|
||||
|
||||
if ($current_page >= $max_pages) {
|
||||
return;
|
||||
}
|
||||
@@ -95,29 +100,31 @@ if (!function_exists('aksrt_render_pagination')) {
|
||||
? $args['render_config']
|
||||
: [];
|
||||
|
||||
$trigger_text = __('加载更多', 'aksrt');
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$list_settings = \AKSRT\Settings\Settings::get_post_list_style_settings();
|
||||
if (!empty($list_settings['ajax_trigger_text'])) {
|
||||
$trigger_text = (string) $list_settings['ajax_trigger_text'];
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="text-center theme-pagination ajax-pag ajax-pagination aksrt-pagination-ajax content-stream__footer-nav"
|
||||
data-mode="<?php echo esc_attr($pagination_mode); ?>"
|
||||
data-next-page="<?php echo esc_attr((string) ($current_page + 1)); ?>"
|
||||
data-max-pages="<?php echo esc_attr((string) $max_pages); ?>"
|
||||
$trigger_text = __('加载更多', 'aksrt');
|
||||
$ias_max = 3;
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$list_settings = \AKSRT\Settings\Settings::get_post_list_style_settings();
|
||||
if (!empty($list_settings['ajax_trigger'])) {
|
||||
$trigger_text = (string) $list_settings['ajax_trigger'];
|
||||
}
|
||||
$ias_max = max(0, (int) ($list_settings['ias_max'] ?? 3));
|
||||
}
|
||||
$auto_load = $pagination_mode === 'infinite' && ($ias_max === 0 || $current_page <= $ias_max);
|
||||
?>
|
||||
<div class="text-center theme-pagination ajax-pag"
|
||||
data-aksrt-pagination
|
||||
data-mode="<?php echo esc_attr($pagination_mode); ?>"
|
||||
data-next-page="<?php echo esc_attr((string) ($current_page + 1)); ?>"
|
||||
data-max-pages="<?php echo esc_attr((string) $max_pages); ?>"
|
||||
data-page-var="<?php echo esc_attr($page_var); ?>"
|
||||
data-query-context="<?php echo esc_attr($query_context); ?>"
|
||||
data-query-vars="<?php echo esc_attr(wp_json_encode($query_vars)); ?>"
|
||||
data-render-config="<?php echo esc_attr(wp_json_encode($render_config)); ?>">
|
||||
<div class="next-page ajax-next aksrt-load-more-btn<?php echo $pagination_mode === 'infinite' ? ' lazyload' : ''; ?>"<?php echo $pagination_mode === 'infinite' ? ' lazyload-action="ias"' : ''; ?> role="button" tabindex="0">
|
||||
<?php echo esc_html($trigger_text); ?>
|
||||
</div>
|
||||
<div class="aksrt-loading-indicator" style="display:none;" aria-hidden="true">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
<span><?php esc_html_e('加载中…', 'aksrt'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="next-page ajax-next<?php echo $auto_load ? ' lazyload' : ''; ?>"<?php echo $auto_load ? ' lazyload-action="ias"' : ''; ?>>
|
||||
<a href="<?php echo esc_url(add_query_arg($page_var, $current_page + 1)); ?>" data-aksrt-load-more><?php echo wp_kses_post($trigger_text); ?></a>
|
||||
</div>
|
||||
<div class="post_ajax_loader" style="display:none;" aria-hidden="true"><?php echo function_exists('aksrt_render_placeholder') ? aksrt_render_placeholder('list', 2) : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,13 +29,11 @@ $has_sidebar = function_exists('aksrt_is_show_sidebar') ? aksrt_is_show_sidebar(
|
||||
<div class="content-wrap">
|
||||
<div class="content-layout">
|
||||
<?php
|
||||
$render_config = function_exists('aksrt_resolve_post_list_render_config')
|
||||
? aksrt_resolve_post_list_render_config(['context' => 'archive'])
|
||||
: ['context' => 'archive', 'mode' => 'list'];
|
||||
$render_config = aksrt_resolve_post_list_render_config(['context' => 'archive']);
|
||||
?>
|
||||
|
||||
<?php if (have_posts()) : ?>
|
||||
<?php aksrt_render_post_list(null, $render_config); ?>
|
||||
<?php aksrt_render_post_list($render_config); ?>
|
||||
<?php aksrt_render_pagination(); ?>
|
||||
<?php else : ?>
|
||||
<div class="no-results">
|
||||
|
||||
+3
-6
@@ -29,9 +29,6 @@ $hot_keywords = function_exists('aksrt_get_search_hot_keywords') ? aksrt_get_sea
|
||||
$filter_settings = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_filter_settings()
|
||||
: ['enabled' => false, 'categories' => true, 'tags' => false, 'sort' => true];
|
||||
$list_settings = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_list_style_settings()
|
||||
: ['render_mode' => 'card', 'card_style' => 'standard'];
|
||||
$other_page_settings = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_other_page_settings()
|
||||
: ['page_search_sidebar' => true];
|
||||
@@ -150,7 +147,7 @@ if (function_exists('aksrt_archive_open_shell')) {
|
||||
]);
|
||||
?>
|
||||
|
||||
<section class="content-stream content-stream--search content-stream--archive" data-page-kind="search" data-render-mode="<?php echo esc_attr((string) $render_config['mode']); ?>" data-card-style="<?php echo esc_attr((string) $render_config['card_style']); ?>">
|
||||
<section class="content-stream content-stream--search content-stream--archive" data-page-kind="search" data-render-mode="<?php echo esc_attr((string) $render_config['mode']); ?>" data-list-type="<?php echo esc_attr((string) $render_config['list_type']); ?>">
|
||||
<form role="search" method="get" class="search-hero-form search-page-form" action="<?php echo esc_url(home_url('/')); ?>" data-aksrt-search-form="search-page" data-default-search-type="<?php echo esc_attr($search_type); ?>" data-default-category="<?php echo esc_attr((string) $current_category); ?>">
|
||||
<input type="hidden" name="aksrt_search_type" value="<?php echo esc_attr($search_type); ?>">
|
||||
<?php if ($search_category_enabled) : ?>
|
||||
@@ -275,8 +272,8 @@ if (function_exists('aksrt_archive_open_shell')) {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($loop_query->have_posts() && function_exists('aksrt_render_post_list')) : ?>
|
||||
<?php aksrt_render_post_list($loop_query, array_merge($render_config, ['wrapper_class' => 'content-stream__list'])); ?>
|
||||
<?php if ($loop_query->have_posts()) : ?>
|
||||
<?php aksrt_render_post_list(array_merge($render_config, ['wrapper_class' => 'content-stream__list']), $loop_query); ?>
|
||||
<div class="content-stream__footer">
|
||||
<?php aksrt_render_pagination($loop_query, ['query_context' => 'search', 'render_config' => $render_config]); ?>
|
||||
</div>
|
||||
|
||||
+44
-60
@@ -203,7 +203,9 @@ class Admin {
|
||||
public static function sanitize_public_query_vars(array $vars): array {
|
||||
$allowed = [
|
||||
'post_type', 'post_status', 'posts_per_page', 'paged', 'orderby', 'order',
|
||||
'cat', 'tag', 'tag_id', 'category_name', 's', 'post__not_in', 'category__not_in',
|
||||
'cat', 'tag', 'tag_id', 'category_name', 's', 'author', 'author_name', 'offset',
|
||||
'post__in', 'post__not_in', 'category__in', 'category__not_in', 'tag__in',
|
||||
'tag__not_in', 'tag_slug__in', 'ignore_sticky_posts',
|
||||
];
|
||||
$clean = [];
|
||||
foreach ($allowed as $key) {
|
||||
@@ -223,15 +225,28 @@ class Admin {
|
||||
if (isset($clean['paged'])) {
|
||||
$clean['paged'] = max(1, (int) $clean['paged']);
|
||||
}
|
||||
foreach (['author', 'cat', 'tag_id', 'offset'] as $int_key) {
|
||||
if (isset($clean[$int_key])) {
|
||||
$clean[$int_key] = max(0, (int) $clean[$int_key]);
|
||||
}
|
||||
}
|
||||
foreach (['post__in', 'post__not_in', 'category__in', 'category__not_in', 'tag__in', 'tag__not_in'] as $ids_key) {
|
||||
if (isset($clean[$ids_key])) {
|
||||
$clean[$ids_key] = array_values(array_filter(array_map('absint', (array) $clean[$ids_key])));
|
||||
}
|
||||
}
|
||||
if (isset($clean['ignore_sticky_posts'])) {
|
||||
$clean['ignore_sticky_posts'] = !empty($clean['ignore_sticky_posts']);
|
||||
}
|
||||
return $clean;
|
||||
}
|
||||
|
||||
public static function sanitize_public_render_config(array $config): array {
|
||||
$clean = [];
|
||||
if (isset($config['mode'])) {
|
||||
$mode = sanitize_key((string) $config['mode']);
|
||||
if (in_array($mode, ['list', 'card', 'mini', 'grid-cms'], true)) {
|
||||
$clean['mode'] = $mode;
|
||||
if (isset($config['type'])) {
|
||||
$type = sanitize_key((string) $config['type']);
|
||||
if (in_array($type, ['auto', 'list', 'card'], true)) {
|
||||
$clean['type'] = $type;
|
||||
}
|
||||
}
|
||||
if (isset($config['context'])) {
|
||||
@@ -240,44 +255,18 @@ class Admin {
|
||||
if (isset($config['query_context'])) {
|
||||
$clean['query_context'] = sanitize_key((string) $config['query_context']);
|
||||
}
|
||||
if (isset($config['style'])) {
|
||||
$style = sanitize_key((string) $config['style']);
|
||||
if (in_array($style, ['', 'style2', 'style3'], true)) {
|
||||
$clean['style'] = $style;
|
||||
}
|
||||
}
|
||||
if (isset($config['card_style'])) {
|
||||
$card_style = sanitize_key((string) $config['card_style']);
|
||||
$allowed = ['thumb', 'text', 'thumb_if_has', 'card', 'compact', 'large_thumb', 'multi_thumb', 'standard'];
|
||||
if (in_array($card_style, $allowed, true)) {
|
||||
$clean['card_style'] = $card_style;
|
||||
}
|
||||
}
|
||||
if (isset($config['list_show_type'])) {
|
||||
$v = sanitize_key((string) $config['list_show_type']);
|
||||
if (in_array($v, ['separate', 'no_margin'], true)) {
|
||||
$clean['list_show_type'] = $v;
|
||||
}
|
||||
}
|
||||
if (isset($config['list_img_position'])) {
|
||||
$v = sanitize_key((string) $config['list_img_position']);
|
||||
if (in_array($v, ['left', 'right'], true)) {
|
||||
$clean['list_img_position'] = $v;
|
||||
}
|
||||
}
|
||||
foreach (['thumb_if_has', 'show_thumb', 'show_author', 'show_date', 'show_views', 'show_comments', 'show_likes', 'show_excerpt', 'heading_bold', 'target_blank', 'badge_show', 'multi_thumb_enabled', 'skip_wrapper'] as $bool_key) {
|
||||
if (array_key_exists($bool_key, $config)) {
|
||||
$clean[$bool_key] = !empty($config[$bool_key]);
|
||||
}
|
||||
}
|
||||
if (isset($config['multi_thumb_limit'])) {
|
||||
$clean['multi_thumb_limit'] = max(1, min(6, (int) $config['multi_thumb_limit']));
|
||||
}
|
||||
if (isset($config['multi_thumb_min'])) {
|
||||
$clean['multi_thumb_min'] = max(1, min(6, (int) $config['multi_thumb_min']));
|
||||
}
|
||||
if (isset($config['excerpt_words'])) {
|
||||
$clean['excerpt_words'] = max(0, min(200, (int) $config['excerpt_words']));
|
||||
foreach (['no_author', 'no_margin', 'is_card', 'skip_wrapper'] as $bool_key) {
|
||||
if (array_key_exists($bool_key, $config)) {
|
||||
$clean[$bool_key] = !empty($config[$bool_key]);
|
||||
}
|
||||
}
|
||||
foreach (['is_mult_thumb', 'is_no_thumb'] as $layout_key) {
|
||||
if (array_key_exists($layout_key, $config)) {
|
||||
$clean[$layout_key] = $config[$layout_key] === 'disable' ? 'disable' : !empty($config[$layout_key]);
|
||||
}
|
||||
}
|
||||
if (isset($config['highlight_query'])) {
|
||||
$clean['highlight_query'] = sanitize_text_field((string) $config['highlight_query']);
|
||||
}
|
||||
return $clean;
|
||||
}
|
||||
@@ -294,18 +283,15 @@ class Admin {
|
||||
$render_config = json_decode(wp_unslash((string) ($_POST['render_config'] ?? '{}')), true);
|
||||
$query_vars = is_array($query_vars) ? self::sanitize_public_query_vars($query_vars) : [];
|
||||
$render_config = is_array($render_config) ? self::sanitize_public_render_config($render_config) : [];
|
||||
// Prefer server-side resolution so AJAX matches SSR styles even if client config is slim.
|
||||
if (function_exists('aksrt_resolve_post_list_render_config')) {
|
||||
$context = sanitize_key((string) ($render_config['context'] ?? 'archive'));
|
||||
if ($context === '') {
|
||||
$context = 'archive';
|
||||
}
|
||||
$resolved = aksrt_resolve_post_list_render_config([
|
||||
'context' => $context,
|
||||
'overrides' => $render_config,
|
||||
]);
|
||||
$render_config = array_merge($resolved, $render_config);
|
||||
}
|
||||
$context = sanitize_key((string) ($render_config['context'] ?? 'archive'));
|
||||
if ($context === '') {
|
||||
$context = 'archive';
|
||||
}
|
||||
$resolved = aksrt_resolve_post_list_render_config([
|
||||
'context' => $context,
|
||||
'overrides' => $render_config,
|
||||
]);
|
||||
$render_config = array_merge($resolved, $render_config, ['skip_wrapper' => true]);
|
||||
$query_vars['paged'] = $page;
|
||||
if (empty($query_vars['post_status'])) {
|
||||
$query_vars['post_status'] = 'publish';
|
||||
@@ -314,11 +300,9 @@ class Admin {
|
||||
$query_vars['post_type'] = 'post';
|
||||
}
|
||||
|
||||
$query = new \WP_Query($query_vars);
|
||||
ob_start();
|
||||
if (function_exists('aksrt_render_post_list')) {
|
||||
aksrt_render_post_list($query, $render_config, true);
|
||||
}
|
||||
$query = new \WP_Query($query_vars);
|
||||
ob_start();
|
||||
aksrt_render_post_list($render_config, $query, true);
|
||||
$html = (string) ob_get_clean();
|
||||
|
||||
wp_send_json_success([
|
||||
|
||||
@@ -129,7 +129,6 @@ class GlobalController extends ControllerBase {
|
||||
'page' => ['type' => 'integer', 'default' => 1, 'sanitize_callback' => 'absint'],
|
||||
'per_page' => ['type' => 'integer', 'default' => 10, 'sanitize_callback' => 'absint'],
|
||||
'sort' => ['type' => 'string', 'default' => 'modified', 'sanitize_callback' => 'sanitize_text_field'],
|
||||
'view_mode' => ['type' => 'string', 'default' => 'list', 'sanitize_callback' => 'sanitize_text_field'],
|
||||
'page_url' => ['type' => 'string', 'default' => '', 'sanitize_callback' => 'esc_url_raw'],
|
||||
'panel' => ['type' => 'string', 'default' => 'latest', 'sanitize_callback' => 'sanitize_key'],
|
||||
'source' => ['type' => 'string', 'default' => 'home', 'sanitize_callback' => 'sanitize_key'],
|
||||
@@ -239,7 +238,6 @@ class GlobalController extends ControllerBase {
|
||||
$page = max(1, (int) $request->get_param('page'));
|
||||
$per_page = min(50, max(1, (int) $request->get_param('per_page')));
|
||||
$sort = sanitize_key($request->get_param('sort') ?: 'modified');
|
||||
$view_mode = sanitize_key($request->get_param('view_mode') ?: 'list');
|
||||
$tab_orderby = sanitize_key($request->get_param('tab_orderby') ?: '');
|
||||
$panel = sanitize_key($request->get_param('panel') ?: 'latest');
|
||||
|
||||
@@ -294,32 +292,11 @@ class GlobalController extends ControllerBase {
|
||||
|
||||
$query = new \WP_Query($args);
|
||||
|
||||
$mode = in_array($view_mode, ['card', 'list'], true) ? $view_mode : '';
|
||||
$html = '';
|
||||
if (function_exists('aksrt_render_post_list')) {
|
||||
$overrides = ['context' => 'home'];
|
||||
if ($mode !== '') {
|
||||
$overrides['mode'] = $mode;
|
||||
}
|
||||
$render_config = function_exists('aksrt_resolve_post_list_render_config')
|
||||
? aksrt_resolve_post_list_render_config([
|
||||
'context' => 'home',
|
||||
'overrides' => $overrides,
|
||||
])
|
||||
: array_merge(['mode' => ($mode !== '' ? $mode : 'list'), 'context' => 'home'], $overrides);
|
||||
$render_config['skip_wrapper'] = true;
|
||||
$html = aksrt_render_post_list($query, $render_config, false);
|
||||
} elseif ($query->have_posts()) {
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
if (function_exists('aksrt_homepage_render_post_card')) {
|
||||
ob_start();
|
||||
aksrt_homepage_render_post_card();
|
||||
$html .= ob_get_clean();
|
||||
}
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
$render_config = aksrt_resolve_post_list_render_config([
|
||||
'context' => 'home',
|
||||
]);
|
||||
$render_config['skip_wrapper'] = true;
|
||||
$html = aksrt_render_post_list($render_config, $query, false);
|
||||
|
||||
$has_more = $page < (int) $query->max_num_pages;
|
||||
|
||||
|
||||
@@ -62,26 +62,9 @@ trait HomepageSettingsRest {
|
||||
$settings['home_lists'] = $this->sanitize_home_lists($params['home_lists'], $allowed_sorts);
|
||||
}
|
||||
|
||||
// --- AKSRT presentation extras (optional, not Zibll dual-write) ---
|
||||
if (isset($params['homepage_card_style'])) {
|
||||
$settings['homepage_card_style'] = in_array($params['homepage_card_style'], ['default', 'style2', 'style3'], true)
|
||||
? $params['homepage_card_style']
|
||||
: 'default';
|
||||
}
|
||||
if (array_key_exists('homepage_multi_thumb_enabled', $params)) {
|
||||
$settings['homepage_multi_thumb_enabled'] = !empty($params['homepage_multi_thumb_enabled']);
|
||||
}
|
||||
if (isset($params['homepage_multi_thumb_min_images'])) {
|
||||
$settings['homepage_multi_thumb_min_images'] = max(2, min(4, (int) $params['homepage_multi_thumb_min_images']));
|
||||
}
|
||||
if (array_key_exists('homepage_sidebar_mini_enabled', $params)) {
|
||||
$settings['homepage_sidebar_mini_enabled'] = !empty($params['homepage_sidebar_mini_enabled']);
|
||||
}
|
||||
if (isset($params['homepage_default_view'])) {
|
||||
$settings['homepage_default_view'] = in_array($params['homepage_default_view'], ['list', 'card'], true)
|
||||
? $params['homepage_default_view']
|
||||
: 'list';
|
||||
}
|
||||
if (array_key_exists('homepage_sort_ajax_enabled', $params)) {
|
||||
$settings['homepage_sort_ajax_enabled'] = !empty($params['homepage_sort_ajax_enabled']);
|
||||
}
|
||||
|
||||
@@ -9,265 +9,121 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class SchemaPostListList {
|
||||
|
||||
public static function build(): array {
|
||||
return [
|
||||
'key' => 'list',
|
||||
'title' => '文章列表',
|
||||
'version' => '2.0.0',
|
||||
'option_key' => 'aksrt_settings',
|
||||
'groups' => [
|
||||
[
|
||||
'key' => 'order',
|
||||
'title' => '默认排序与置顶',
|
||||
'fields' => [
|
||||
[
|
||||
'key' => 'list_orderby',
|
||||
'label' => '默认排序方式',
|
||||
'type' => 'radio',
|
||||
'default' => 'modified',
|
||||
'options' => [
|
||||
['label' => '发布时间', 'value' => 'date'],
|
||||
['label' => '更新时间', 'value' => 'modified'],
|
||||
['label' => 'WP默认', 'value' => 'default'],
|
||||
],
|
||||
'help' => '文章列表全局默认排序(对齐 Zibll list_orderby)',
|
||||
],
|
||||
[
|
||||
'key' => 'sticky_s',
|
||||
'label' => '显示置顶文章',
|
||||
'type' => 'checkbox',
|
||||
'default' => ['home', 'cat'],
|
||||
'options' => [
|
||||
['label' => '首页', 'value' => 'home'],
|
||||
['label' => '分类页', 'value' => 'cat'],
|
||||
['label' => '标签页', 'value' => 'tag'],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'display',
|
||||
'title' => '列表显示',
|
||||
'fields' => [
|
||||
[
|
||||
'key' => 'target_blank',
|
||||
'label' => '新窗口打开文章',
|
||||
'type' => 'switch',
|
||||
'default' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'item_heading_bold',
|
||||
'label' => '列表标题粗体显示',
|
||||
'type' => 'switch',
|
||||
'default' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'post_list_author',
|
||||
'label' => '显示文章作者',
|
||||
'type' => 'switch',
|
||||
'default' => true,
|
||||
],
|
||||
[
|
||||
'key' => 'post_list_time',
|
||||
'label' => '显示文章时间',
|
||||
'type' => 'switch',
|
||||
'default' => true,
|
||||
'help' => '建议作者与时间至少开启一项',
|
||||
],
|
||||
[
|
||||
'key' => 'list_meta_show',
|
||||
'label' => '列表小部件(移动端优先)',
|
||||
'type' => 'radio',
|
||||
'default' => 'like',
|
||||
'options' => [
|
||||
['label' => '阅读量', 'value' => 'view'],
|
||||
['label' => '点赞数', 'value' => 'like'],
|
||||
['label' => '评论', 'value' => 'comm'],
|
||||
],
|
||||
'help' => '移动端空间不足时始终保留的部件',
|
||||
],
|
||||
[
|
||||
'key' => 'list_badge_show',
|
||||
'label' => '列表徽章',
|
||||
'type' => 'checkbox',
|
||||
'default' => ['pay', 'tag', 'cat'],
|
||||
'options' => [
|
||||
['label' => '付费', 'value' => 'pay'],
|
||||
['label' => '分类', 'value' => 'cat'],
|
||||
['label' => '标签', 'value' => 'tag'],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'paging',
|
||||
'title' => '列表翻页',
|
||||
'fields' => [
|
||||
[
|
||||
'key' => 'paging_ajax_s',
|
||||
'label' => '列表翻页模式',
|
||||
'type' => 'radio',
|
||||
'default' => '1',
|
||||
'options' => [
|
||||
['label' => 'AJAX 追加列表翻页', 'value' => '1'],
|
||||
['label' => '数字翻页按钮', 'value' => '0'],
|
||||
],
|
||||
'help' => '对齐 Zibll paging_ajax_s;单页数量仍受 WP 阅读设置影响',
|
||||
],
|
||||
[
|
||||
'key' => 'paging_ajax_ias_s',
|
||||
'label' => 'AJAX 自动加载',
|
||||
'type' => 'switch',
|
||||
'default' => true,
|
||||
'dependsOn' => ['key' => 'paging_ajax_s', 'value' => '1'],
|
||||
'help' => '滚动到列表尽头时自动加载下一页(Zibll paging_ajax_ias_s)',
|
||||
],
|
||||
[
|
||||
'key' => 'ias_max',
|
||||
'label' => '自动加载页数',
|
||||
'type' => 'number',
|
||||
'default' => 3,
|
||||
'min' => 0,
|
||||
'max' => 10,
|
||||
'dependsOn' => ['key' => 'paging_ajax_s', 'value' => '1'],
|
||||
'help' => '0 表示不限制,直到加载完全部列表',
|
||||
],
|
||||
[
|
||||
'key' => 'ajax_trigger',
|
||||
'label' => '加载更多文案',
|
||||
'type' => 'input',
|
||||
'default' => '加载更多',
|
||||
'dependsOn' => ['key' => 'paging_ajax_s', 'value' => '1'],
|
||||
],
|
||||
[
|
||||
'key' => 'ajax_nomore',
|
||||
'label' => '没有更多文案',
|
||||
'type' => 'input',
|
||||
'default' => '没有更多了',
|
||||
'dependsOn' => ['key' => 'paging_ajax_s', 'value' => '1'],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'card',
|
||||
'title' => '卡片与布局',
|
||||
'fields' => [
|
||||
[
|
||||
'key' => 'post_card_style',
|
||||
'label' => '默认列表模式',
|
||||
'type' => 'select',
|
||||
'default' => 'thumb',
|
||||
'options' => [
|
||||
['label' => '列表图文模式', 'value' => 'thumb'],
|
||||
['label' => '紧凑卡', 'value' => 'compact'],
|
||||
['label' => '大图卡', 'value' => 'large_thumb'],
|
||||
['label' => '多图卡', 'value' => 'multi_thumb'],
|
||||
['label' => '列表文字模式', 'value' => 'text'],
|
||||
['label' => '列表自动图文', 'value' => 'thumb_if_has'],
|
||||
['label' => '卡片模式', 'value' => 'card'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'post_excerpt_length',
|
||||
'label' => '摘要长度',
|
||||
'type' => 'number',
|
||||
'default' => 120,
|
||||
'min' => 20,
|
||||
'max' => 500,
|
||||
],
|
||||
[
|
||||
'key' => 'post_list_per_page',
|
||||
'label' => '每页文章数',
|
||||
'type' => 'number',
|
||||
'default' => 12,
|
||||
'min' => 4,
|
||||
'max' => 48,
|
||||
],
|
||||
[
|
||||
'key' => 'list_show_type',
|
||||
'label' => '列表间距样式',
|
||||
'type' => 'radio',
|
||||
'default' => 'separate',
|
||||
'options' => [
|
||||
['label' => '分隔卡片', 'value' => 'separate'],
|
||||
['label' => '无间距', 'value' => 'no_margin'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'list_list_style',
|
||||
'label' => '列表样式变体',
|
||||
'type' => 'radio',
|
||||
'default' => '',
|
||||
'options' => [
|
||||
['label' => '默认', 'value' => ''],
|
||||
['label' => '样式2', 'value' => 'style2'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'list_list_img_position',
|
||||
'label' => '列表缩略图位置',
|
||||
'type' => 'radio',
|
||||
'default' => 'left',
|
||||
'options' => [
|
||||
['label' => '左侧', 'value' => 'left'],
|
||||
['label' => '右侧', 'value' => 'right'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'list_list_scale',
|
||||
'label' => '列表缩略图比例 (%)',
|
||||
'type' => 'number',
|
||||
'default' => 70,
|
||||
'min' => 50,
|
||||
'max' => 200,
|
||||
],
|
||||
[
|
||||
'key' => 'list_card_style',
|
||||
'label' => '卡片样式变体',
|
||||
'type' => 'radio',
|
||||
'default' => '',
|
||||
'options' => [
|
||||
['label' => '默认', 'value' => ''],
|
||||
['label' => '样式3', 'value' => 'style3'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'list_card_scale',
|
||||
'label' => '卡片缩略图比例 (%)',
|
||||
'type' => 'number',
|
||||
'default' => 70,
|
||||
'min' => 20,
|
||||
'max' => 200,
|
||||
],
|
||||
[
|
||||
'key' => 'list_card_home',
|
||||
'label' => '首页卡片模式',
|
||||
'type' => 'switch',
|
||||
'default' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'list_card_cat',
|
||||
'label' => '分类卡片模式',
|
||||
'type' => 'taxonomy_select',
|
||||
'taxonomy' => 'category',
|
||||
'multiple' => true,
|
||||
'default' => [],
|
||||
],
|
||||
[
|
||||
'key' => 'list_card_tag',
|
||||
'label' => '标签页卡片模式',
|
||||
'type' => 'switch',
|
||||
'default' => false,
|
||||
],
|
||||
[
|
||||
'key' => 'list_card_author',
|
||||
'label' => '用户页卡片模式',
|
||||
'type' => 'switch',
|
||||
'default' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
public static function build(): array {
|
||||
return [
|
||||
'key' => 'list',
|
||||
'title' => '文章列表',
|
||||
'version' => '9.0.0',
|
||||
'option_key' => 'aksrt_settings',
|
||||
'groups' => [
|
||||
[
|
||||
'key' => 'order',
|
||||
'title' => '默认排序与置顶',
|
||||
'fields' => [
|
||||
['key' => 'list_orderby', 'label' => '默认排序方式', 'type' => 'radio', 'default' => 'modified', 'options' => [
|
||||
['label' => '发布时间', 'value' => 'date'],
|
||||
['label' => '更新时间', 'value' => 'modified'],
|
||||
['label' => 'WP默认', 'value' => 'default'],
|
||||
]],
|
||||
['key' => 'post_time_source', 'label' => '时间显示数据源', 'type' => 'radio', 'default' => 'modified', 'options' => [
|
||||
['label' => '发布时间', 'value' => 'date'],
|
||||
['label' => '更新时间', 'value' => 'modified'],
|
||||
]],
|
||||
['key' => 'sticky_s', 'label' => '显示置顶文章', 'type' => 'checkbox', 'default' => ['home', 'cat'], 'options' => [
|
||||
['label' => '首页', 'value' => 'home'],
|
||||
['label' => '分类页', 'value' => 'cat'],
|
||||
['label' => '标签页', 'value' => 'tag'],
|
||||
]],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'display',
|
||||
'title' => '列表显示',
|
||||
'fields' => [
|
||||
['key' => 'target_blank', 'label' => '新窗口打开文章', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'item_heading_bold', 'label' => '列表标题粗体显示', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'post_list_author', 'label' => '显示文章作者', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'post_list_time', 'label' => '显示文章时间', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'list_meta_show', 'label' => '列表小部件(移动端优先)', 'type' => 'radio', 'default' => 'like', 'options' => [
|
||||
['label' => '阅读量', 'value' => 'view'],
|
||||
['label' => '点赞数', 'value' => 'like'],
|
||||
['label' => '评论', 'value' => 'comm'],
|
||||
]],
|
||||
['key' => 'list_badge_show', 'label' => '显示列表标签', 'type' => 'checkbox', 'default' => ['pay', 'cat', 'tag'], 'options' => [
|
||||
['label' => '付费信息', 'value' => 'pay'],
|
||||
['label' => '分类', 'value' => 'cat'],
|
||||
['label' => '标签', 'value' => 'tag'],
|
||||
]],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'layout',
|
||||
'title' => '列表模式与 UI',
|
||||
'fields' => [
|
||||
['key' => 'list_show_type', 'label' => '列表样式', 'type' => 'radio', 'default' => 'separate', 'options' => [
|
||||
['label' => '分离', 'value' => 'separate'],
|
||||
['label' => '无间距', 'value' => 'no_margin'],
|
||||
]],
|
||||
['key' => 'list_type', 'label' => '默认列表模式', 'type' => 'radio', 'default' => 'thumb', 'options' => [
|
||||
['label' => '列表文字模式', 'value' => 'text'],
|
||||
['label' => '列表图文模式', 'value' => 'thumb'],
|
||||
['label' => '列表自动图文模式', 'value' => 'thumb_if_has'],
|
||||
['label' => '卡片模式', 'value' => 'card'],
|
||||
], 'help' => '文字、自动图文和多图模式仅在开启侧栏的页面有效。'],
|
||||
['key' => 'list_card_home', 'label' => '首页列表卡片模式', 'type' => 'switch', 'default' => false, 'dependsOn' => ['key' => 'list_type', 'not' => true, 'value' => 'card']],
|
||||
['key' => 'list_card_tag', 'label' => '标签页列表卡片模式', 'type' => 'switch', 'default' => false, 'dependsOn' => ['key' => 'list_type', 'not' => true, 'value' => 'card']],
|
||||
['key' => 'list_card_author', 'label' => '用户页列表卡片模式', 'type' => 'switch', 'default' => false, 'dependsOn' => ['key' => 'list_type', 'not' => true, 'value' => 'card']],
|
||||
['key' => 'list_card_cat', 'label' => '分类页自定义卡片模式', 'type' => 'taxonomy_select', 'taxonomy' => 'category', 'multiple' => true, 'default' => [], 'dependsOn' => ['key' => 'list_type', 'not' => true, 'value' => 'card']],
|
||||
[
|
||||
'key' => 'list_list_option',
|
||||
'label' => '列表模式 UI 配置',
|
||||
'type' => 'fieldset',
|
||||
'sanitize_type' => 'array',
|
||||
'default' => ['style' => 'null', 'img_position' => 'left', 'scale' => 70],
|
||||
'fields' => [
|
||||
['key' => 'style', 'label' => '列表样式', 'type' => 'radio', 'default' => 'null', 'options' => [
|
||||
['label' => '默认', 'value' => 'null'],
|
||||
['label' => '样式 2', 'value' => 'style2'],
|
||||
]],
|
||||
['key' => 'img_position', 'label' => '缩略图位置', 'type' => 'radio', 'default' => 'left', 'options' => [
|
||||
['label' => '靠左', 'value' => 'left'],
|
||||
['label' => '靠右', 'value' => 'right'],
|
||||
]],
|
||||
['key' => 'scale', 'label' => '缩略图长宽比例(%)', 'type' => 'number', 'default' => 70, 'min' => 50, 'max' => 200, 'step' => 5],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'list_card_option',
|
||||
'label' => '卡片模式 UI 配置',
|
||||
'type' => 'fieldset',
|
||||
'sanitize_type' => 'array',
|
||||
'default' => ['style' => 'null', 'scale' => 70],
|
||||
'fields' => [
|
||||
['key' => 'style', 'label' => '卡片样式', 'type' => 'radio', 'default' => 'null', 'options' => [
|
||||
['label' => '默认', 'value' => 'null'],
|
||||
['label' => '样式 3', 'value' => 'style3'],
|
||||
]],
|
||||
['key' => 'scale', 'label' => '缩略图长宽比例(%)', 'type' => 'number', 'default' => 70, 'min' => 20, 'max' => 200, 'step' => 5],
|
||||
],
|
||||
],
|
||||
['key' => 'mult_thumb_cat', 'label' => '列表多图显示分类', 'type' => 'taxonomy_select', 'taxonomy' => 'category', 'multiple' => true, 'default' => [], 'help' => '文章格式为图片或画廊时默认显示 4 张缩略图;卡片模式或无侧栏时无效。'],
|
||||
],
|
||||
],
|
||||
[
|
||||
'key' => 'paging',
|
||||
'title' => '列表翻页',
|
||||
'fields' => [
|
||||
['key' => 'paging_ajax_s', 'label' => '列表翻页模式', 'type' => 'radio', 'default' => '1', 'options' => [
|
||||
['label' => 'AJAX 追加列表翻页', 'value' => '1'],
|
||||
['label' => '数字翻页按钮', 'value' => '0'],
|
||||
]],
|
||||
['key' => 'paging_ajax_ias_s', 'label' => 'AJAX 自动加载', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'paging_ajax_s', 'value' => '1']],
|
||||
['key' => 'ias_max', 'label' => '自动加载页数', 'type' => 'number', 'default' => 3, 'min' => 0, 'max' => 10, 'dependsOn' => ['key' => 'paging_ajax_s', 'value' => '1']],
|
||||
['key' => 'ajax_trigger', 'label' => '翻页按钮文字', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '<i class="fa fa-angle-right"></i>加载更多'],
|
||||
['key' => 'ajax_nomore', 'label' => '列表全部加载完毕文案', 'type' => 'textarea', 'sanitize_type' => 'html', 'default' => '没有更多内容了'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,43 +18,28 @@ class SchemaPostList {
|
||||
'thumb' => [
|
||||
'key' => 'thumb',
|
||||
'title' => '列表缩略图',
|
||||
'version' => '1.0.0',
|
||||
'version' => '9.0.0',
|
||||
'option_key' => 'aksrt_settings',
|
||||
'groups' => [
|
||||
['key' => 'source', 'title' => '图片来源', 'fields' => [
|
||||
['key' => 'thumb_priority', 'label' => '图片优先级', 'type' => 'input', 'default' => 'featured,attachment,resource,custom'],
|
||||
['key' => 'thumb_fallback', 'label' => '无图时处理', 'type' => 'radio', 'default' => 'placeholder', 'options' => [
|
||||
['label' => '显示占位图', 'value' => 'placeholder'],
|
||||
['label' => '隐藏缩略图', 'value' => 'hide'],
|
||||
['label' => '随机封面', 'value' => 'random'],
|
||||
]],
|
||||
['key' => 'thumb_spare_images', 'label' => '备用缩略图', 'type' => 'gallery', 'default' => [], 'dependsOn' => ['key' => 'thumb_fallback', 'value' => 'random'], 'description' => '当 thumb_fallback 为 random 时从此图库随机选取'],
|
||||
['key' => 'thumb_aspect_ratio', 'label' => '图片比例', 'type' => 'select', 'default' => '16:9', 'options' => [
|
||||
['label' => '16:9 宽屏', 'value' => '16:9'],
|
||||
['label' => '4:3 标准', 'value' => '4:3'],
|
||||
['label' => '1:1 正方形', 'value' => '1:1'],
|
||||
['label' => '自适应', 'value' => 'auto'],
|
||||
]],
|
||||
['key' => 'list_thumb_fit', 'label' => '缩略图填充方式', 'type' => 'radio', 'default' => 'cover', 'options' => [
|
||||
['label' => '填充裁剪', 'value' => 'cover'],
|
||||
['label' => '完整显示', 'value' => 'contain'],
|
||||
]],
|
||||
['key' => 'source', 'title' => '图片来源', 'description' => '缩略图获取优先级:文章特色图像 > 外链特色图像 > 文章首图 > 分类封面图 > 备用缩略图 > 懒加载预载图。', 'fields' => [
|
||||
['key' => 'list_thumb_slides_s', 'label' => '幻灯片缩略图', 'type' => 'switch', 'default' => true, 'description' => '允许幻灯片作为列表缩略图'],
|
||||
['key' => 'list_thumb_video_s', 'label' => '视频缩略图', 'type' => 'switch', 'default' => true, 'description' => '鼠标悬停时自动播放视频缩略图'],
|
||||
['key' => 'list_thumb_video_mute_s', 'label' => '视频缩略图静音', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'list_thumb_video_s', 'value' => true], 'description' => '视频缩略图播放时静音'],
|
||||
['key' => 'thumb_postfirstimg_s', 'label' => '自动获取文章首图', 'type' => 'switch', 'default' => true, 'description' => '自动从文章内容中提取第一张图片作为缩略图'],
|
||||
['key' => 'thumb_catimg_s', 'label' => '自动获取分类封面', 'type' => 'switch', 'default' => true, 'description' => '无特色图时使用分类封面图作为缩略图'],
|
||||
['key' => 'list_thumb_fit', 'label' => '缩略图填充方式', 'type' => 'radio', 'default' => '', 'options' => [
|
||||
['label' => 'cover 铺满', 'value' => ''],
|
||||
['label' => 'contain 等比例缩放', 'value' => 'contain'],
|
||||
]],
|
||||
['key' => 'thumb_postfirstimg_size', 'label' => '首图尺寸', 'type' => 'radio', 'default' => 'medium', 'dependsOn' => ['key' => 'thumb_postfirstimg_s', 'value' => true], 'options' => [
|
||||
['label' => '缩略图', 'value' => 'thumbnail'],
|
||||
['label' => '中等', 'value' => 'medium'],
|
||||
['label' => '大', 'value' => 'large'],
|
||||
['label' => '原始', 'value' => 'full'],
|
||||
], 'description' => '自动获取文章首图时使用的 WP 图片尺寸'],
|
||||
]],
|
||||
['key' => 'multi', 'title' => '多图模式', 'fields' => [
|
||||
['key' => 'thumb_multi_enabled', 'label' => '多图卡片', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'thumb_multi_count', 'label' => '最多显示几张', 'type' => 'number', 'default' => 3, 'min' => 2, 'max' => 6, 'dependsOn' => ['key' => 'thumb_multi_enabled', 'value' => true]],
|
||||
['key' => 'mult_thumb_cat', 'label' => '按分类多图显示', 'type' => 'taxonomy_select', 'taxonomy' => 'category', 'multiple' => true, 'default' => [], 'dependsOn' => ['key' => 'thumb_multi_enabled', 'value' => true]],
|
||||
['key' => 'spare_thumbnail', 'label' => '备用缩略图', 'type' => 'repeater', 'sanitize_type' => 'array', 'default' => [['img' => get_template_directory_uri() . '/assets/img/thumbnail.svg']], 'addText' => '添加备用缩略图', 'fields' => [
|
||||
['key' => 'img', 'label' => '图片', 'type' => 'media', 'default' => ''],
|
||||
]],
|
||||
]],
|
||||
],
|
||||
],
|
||||
@@ -102,34 +87,25 @@ class SchemaPostList {
|
||||
['key' => 'post_lightbox_down', 'label' => '灯箱下载', 'type' => 'switch', 'default' => false],
|
||||
['key' => 'post_lightbox_play', 'label' => '灯箱播放', 'type' => 'switch', 'default' => false],
|
||||
]],
|
||||
['key' => 'related', 'title' => '相关推荐', 'fields' => [
|
||||
['key' => 'post_related_enabled', 'label' => '显示相关推荐', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'post_related_count', 'label' => '推荐数量', 'type' => 'number', 'default' => 6, 'min' => 1, 'max' => 20],
|
||||
['key' => 'post_related_style', 'label' => '展示样式', 'type' => 'radio', 'default' => 'img', 'options' => [
|
||||
['label' => '图文卡片', 'value' => 'img'],
|
||||
['label' => '列表', 'value' => 'list'],
|
||||
['label' => '纯文字', 'value' => 'text'],
|
||||
], 'description' => '对齐 Zibll 相关文章三种样式'],
|
||||
['key' => 'post_related_source', 'label' => '推荐来源', 'type' => 'radio', 'default' => 'category', 'options' => [
|
||||
['label' => '同分类/标签', 'value' => 'category'],
|
||||
['label' => '同标签', 'value' => 'tag'],
|
||||
['label' => '随机', 'value' => 'random'],
|
||||
]],
|
||||
// Legacy alias kept so old saved values still round-trip.
|
||||
['key' => 'post_related_type', 'label' => '推荐方式(兼容)', 'type' => 'radio', 'default' => 'category', 'options' => [
|
||||
['label' => '同分类', 'value' => 'category'],
|
||||
['label' => '同标签', 'value' => 'tag'],
|
||||
['label' => '随机', 'value' => 'random'],
|
||||
]],
|
||||
['key' => 'post_related_orderby', 'label' => '推荐排序', 'type' => 'select', 'default' => 'views', 'options' => [
|
||||
['label' => '浏览量', 'value' => 'views'],
|
||||
['label' => '随机', 'value' => 'rand'],
|
||||
['label' => '相关度', 'value' => 'relevance'],
|
||||
['label' => '时间', 'value' => 'date'],
|
||||
['label' => '更新时间', 'value' => 'modified'],
|
||||
]],
|
||||
['key' => 'post_related_title', 'label' => '推荐标题', 'type' => 'input', 'default' => '相关推荐'],
|
||||
]],
|
||||
['key' => 'related', 'title' => '相关推荐', 'fields' => [
|
||||
['key' => 'post_related_s', 'label' => '显示相关推荐', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'post_related_type', 'label' => '展示样式', 'type' => 'radio', 'default' => 'img', 'options' => [
|
||||
['label' => '图文卡片', 'value' => 'img'],
|
||||
['label' => '列表', 'value' => 'list'],
|
||||
['label' => '纯文字', 'value' => 'text'],
|
||||
]],
|
||||
['key' => 'related_title', 'label' => '推荐标题', 'type' => 'input', 'default' => '相关推荐'],
|
||||
['key' => 'post_related_n', 'label' => '推荐数量', 'type' => 'number', 'default' => 6, 'min' => 4, 'max' => 12, 'step' => 2],
|
||||
['key' => 'post_related_orderby', 'label' => '推荐排序', 'type' => 'select', 'default' => 'views', 'options' => [
|
||||
['label' => '更新时间', 'value' => 'modified'],
|
||||
['label' => '发布时间', 'value' => 'date'],
|
||||
['label' => '浏览量', 'value' => 'views'],
|
||||
['label' => '点赞量', 'value' => 'like'],
|
||||
['label' => '评论量', 'value' => 'comment_count'],
|
||||
['label' => '收藏数量', 'value' => 'favorite'],
|
||||
['label' => '随机', 'value' => 'rand'],
|
||||
]],
|
||||
]],
|
||||
['key' => 'interactions', 'title' => '互动功能', 'fields' => [
|
||||
['key' => 'post_like_enabled', 'label' => '点赞', 'type' => 'switch', 'default' => true],
|
||||
['key' => 'post_favorite_enabled', 'label' => '收藏', 'type' => 'switch', 'default' => true],
|
||||
|
||||
@@ -71,7 +71,6 @@ class DomainModel {
|
||||
return [
|
||||
'cover_images' => '',
|
||||
'custom_excerpt' => '',
|
||||
'layout_override' => '',
|
||||
'header_image_mode' => '',
|
||||
'show_toc' => '',
|
||||
'show_reading_progress' => '',
|
||||
@@ -105,7 +104,6 @@ class DomainModel {
|
||||
return [
|
||||
'cover_url' => '',
|
||||
'description' => '',
|
||||
'layout_mode' => '',
|
||||
'show_sidebar' => '',
|
||||
'show_header' => true,
|
||||
'show_featured' => false,
|
||||
|
||||
@@ -214,7 +214,7 @@ class HomeModules {
|
||||
return [
|
||||
['type' => 'hero', 'config' => []],
|
||||
['type' => 'tabs', 'config' => ['count' => 8]],
|
||||
['type' => 'recent', 'config' => ['count' => 8, 'layout' => 'grid-cms']],
|
||||
['type' => 'recent', 'config' => ['count' => 8, 'layout' => 'card']],
|
||||
['type' => 'ranking', 'config' => ['metric' => 'downloads', 'count' => 6]],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -163,14 +163,6 @@ class PostMetaBox {
|
||||
<small class="description"><?php esc_html_e('用于列表多图模式,填写附件 ID(逗号分隔)。', 'aksrt'); ?></small>
|
||||
</p>
|
||||
|
||||
<p><strong><?php esc_html_e('列表布局覆盖', 'aksrt'); ?></strong></p>
|
||||
<select name="aksrt_post_meta[layout_override]" class="widefat">
|
||||
<option value="" <?php selected($meta['layout_override'], ''); ?>><?php esc_html_e('跟随全局', 'aksrt'); ?></option>
|
||||
<option value="card" <?php selected($meta['layout_override'], 'card'); ?>><?php esc_html_e('卡片', 'aksrt'); ?></option>
|
||||
<option value="list" <?php selected($meta['layout_override'], 'list'); ?>><?php esc_html_e('列表', 'aksrt'); ?></option>
|
||||
<option value="mini" <?php selected($meta['layout_override'], 'mini'); ?>><?php esc_html_e('迷你', 'aksrt'); ?></option>
|
||||
</select>
|
||||
|
||||
<p><strong><?php esc_html_e('侧栏布局(Zibll show_layout)', 'aksrt'); ?></strong></p>
|
||||
<?php
|
||||
$show_layout = (string) get_post_meta($post->ID, '_aksrt_show_layout', true);
|
||||
@@ -251,9 +243,9 @@ class PostMetaBox {
|
||||
<p><strong><?php esc_html_e('副标题', 'aksrt'); ?></strong></p>
|
||||
<input type="text" name="aksrt_post_meta[subtitle]" value="<?php echo esc_attr($meta['subtitle']); ?>" class="widefat" placeholder="<?php esc_attr_e('可选,显示在标题下方', 'aksrt'); ?>">
|
||||
|
||||
<p><strong><?php esc_html_e('外链特色图', 'aksrt'); ?></strong></p>
|
||||
<input type="url" name="aksrt_post_meta[thumbnail_url]" value="<?php echo esc_url($meta['thumbnail_url']); ?>" class="widefat" placeholder="<?php esc_attr_e('外部图片 URL(覆盖特色图片)', 'aksrt'); ?>">
|
||||
<small class="description"><?php esc_html_e('填入外部图片 URL 将替代特色图片。', 'aksrt'); ?></small>
|
||||
<p><strong><?php esc_html_e('外链特色图', 'aksrt'); ?></strong></p>
|
||||
<input type="url" name="aksrt_post_meta[thumbnail_url]" value="<?php echo esc_url($meta['thumbnail_url']); ?>" class="widefat" placeholder="<?php esc_attr_e('外部图片 URL(覆盖特色图片)', 'aksrt'); ?>">
|
||||
<small class="description"><?php esc_html_e('未设置文章特色图片时使用此外链图片。', 'aksrt'); ?></small>
|
||||
|
||||
<p><strong><?php esc_html_e('幻灯片封面', 'aksrt'); ?></strong></p>
|
||||
<input type="text" name="aksrt_post_meta[featured_slide]" value="<?php echo esc_attr($meta['featured_slide']); ?>" class="widefat" placeholder="<?php esc_attr_e('图片 URL,逗号分隔', 'aksrt'); ?>">
|
||||
@@ -359,7 +351,7 @@ class PostMetaBox {
|
||||
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
|
||||
if (!current_user_can('edit_post', $post_id)) return;
|
||||
|
||||
// Zibll show_layout (independent of list layout_override).
|
||||
// Zibll show_layout.
|
||||
$show_layout = isset($_POST['aksrt_show_layout']) ? sanitize_key((string) wp_unslash($_POST['aksrt_show_layout'])) : '';
|
||||
if (!in_array($show_layout, ['no_sidebar', 'sidebar_left', 'sidebar_right'], true)) {
|
||||
$show_layout = '';
|
||||
@@ -391,7 +383,6 @@ class PostMetaBox {
|
||||
$sanitized = [
|
||||
'cover_images' => isset($raw['cover_images']) ? sanitize_text_field($raw['cover_images']) : '',
|
||||
'custom_excerpt' => isset($raw['custom_excerpt']) ? sanitize_textarea_field($raw['custom_excerpt']) : '',
|
||||
'layout_override' => isset($raw['layout_override']) ? sanitize_key($raw['layout_override']) : '',
|
||||
'header_image_mode' => isset($raw['header_image_mode']) ? sanitize_key($raw['header_image_mode']) : '',
|
||||
// New route: '' follow | '1' force on | '0' force off.
|
||||
'show_toc' => isset($raw['show_toc']) && in_array((string) $raw['show_toc'], ['', '0', '1'], true) ? (string) $raw['show_toc'] : '',
|
||||
@@ -417,11 +408,6 @@ class PostMetaBox {
|
||||
'maxheight' => isset($raw['maxheight']) ? max(0, (int) $raw['maxheight']) : 0,
|
||||
];
|
||||
|
||||
$valid_modes = ['', 'card', 'list', 'mini', 'grid-cms'];
|
||||
if (!in_array($sanitized['layout_override'], $valid_modes, true)) {
|
||||
$sanitized['layout_override'] = '';
|
||||
}
|
||||
|
||||
$valid_header_modes = ['', 'featured', 'auto', 'none'];
|
||||
if (!in_array($sanitized['header_image_mode'], $valid_header_modes, true)) {
|
||||
$sanitized['header_image_mode'] = '';
|
||||
@@ -476,10 +462,9 @@ class PostMetaBox {
|
||||
echo esc_html($views > 0 ? (string) $views : '—');
|
||||
} elseif ($column === 'aksrt_likes') {
|
||||
$likes = (int) ($meta['likes'] ?? 0);
|
||||
$layout = esc_attr($meta['layout_override'] ?? '');
|
||||
$toc = esc_attr($meta['show_toc'] ?? '');
|
||||
$mh = (int) ($meta['maxheight'] ?? 0);
|
||||
echo '<span class="aksrt-col-data" data-views="' . (int) ($meta['views'] ?? 0) . '" data-likes="' . $likes . '" data-layout="' . $layout . '" data-toc="' . $toc . '" data-maxheight="' . $mh . '">' . esc_html($likes > 0 ? (string) $likes : '—') . '</span>';
|
||||
echo '<span class="aksrt-col-data" data-views="' . (int) ($meta['views'] ?? 0) . '" data-likes="' . $likes . '" data-toc="' . $toc . '" data-maxheight="' . $mh . '">' . esc_html($likes > 0 ? (string) $likes : '—') . '</span>';
|
||||
} elseif ($column === 'aksrt_sales') {
|
||||
$this->render_sales_column($post_id);
|
||||
}
|
||||
@@ -631,17 +616,6 @@ class PostMetaBox {
|
||||
<span class="title"><?php esc_html_e('点赞数', 'aksrt'); ?></span>
|
||||
<input type="number" name="aksrt_qe_likes" min="0" step="1" value="" class="aksrt-qe-likes">
|
||||
</label>
|
||||
<label class="alignleft">
|
||||
<span class="title"><?php esc_html_e('布局', 'aksrt'); ?></span>
|
||||
<select name="aksrt_qe_layout" class="aksrt-qe-layout">
|
||||
<option value="-1"><?php esc_html_e('— 不更改 —', 'aksrt'); ?></option>
|
||||
<option value=""><?php esc_html_e('跟随全局', 'aksrt'); ?></option>
|
||||
<option value="card"><?php esc_html_e('卡片', 'aksrt'); ?></option>
|
||||
<option value="list"><?php esc_html_e('列表', 'aksrt'); ?></option>
|
||||
<option value="mini"><?php esc_html_e('迷你', 'aksrt'); ?></option>
|
||||
<option value="grid-cms"><?php esc_html_e('CMS网格', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="alignleft">
|
||||
<span class="title"><?php esc_html_e('目录树', 'aksrt'); ?></span>
|
||||
<select name="aksrt_qe_toc" class="aksrt-qe-toc">
|
||||
@@ -771,14 +745,6 @@ class PostMetaBox {
|
||||
? max(0, (int) $_POST['aksrt_qe_likes'])
|
||||
: (int) ($existing['likes'] ?? 0);
|
||||
|
||||
$layout = $existing['layout_override'] ?? '';
|
||||
if (isset($_POST['aksrt_qe_layout']) && $_POST['aksrt_qe_layout'] !== '-1') {
|
||||
$layout = sanitize_key((string) $_POST['aksrt_qe_layout']);
|
||||
if (!in_array($layout, ['', 'card', 'list', 'mini', 'grid-cms'], true)) {
|
||||
$layout = $existing['layout_override'] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
$toc = $existing['show_toc'] ?? '';
|
||||
if (isset($_POST['aksrt_qe_toc']) && $_POST['aksrt_qe_toc'] !== '-1') {
|
||||
$toc_v = sanitize_key((string) $_POST['aksrt_qe_toc']);
|
||||
@@ -791,7 +757,6 @@ class PostMetaBox {
|
||||
|
||||
$existing['views'] = $views;
|
||||
$existing['likes'] = $likes;
|
||||
$existing['layout_override'] = $layout;
|
||||
$existing['show_toc'] = $toc;
|
||||
$existing['maxheight'] = $mh;
|
||||
|
||||
@@ -835,7 +800,6 @@ class PostMetaBox {
|
||||
|
||||
var v = data.getAttribute('data-views') || '';
|
||||
var l = data.getAttribute('data-likes') || '';
|
||||
var layout = data.getAttribute('data-layout') || '';
|
||||
var toc = data.getAttribute('data-toc') || '';
|
||||
var mh = data.getAttribute('data-maxheight') || '';
|
||||
|
||||
@@ -844,8 +808,6 @@ class PostMetaBox {
|
||||
if (qv) qv.value = v;
|
||||
if (ql) ql.value = l;
|
||||
|
||||
var qLayout = form.querySelector('.aksrt-qe-layout');
|
||||
if (qLayout) qLayout.value = layout;
|
||||
var qToc = form.querySelector('.aksrt-qe-toc');
|
||||
if (qToc) qToc.value = toc;
|
||||
var qMh = form.querySelector('.aksrt-qe-maxheight');
|
||||
|
||||
@@ -316,7 +316,7 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
|
||||
|| is_page_template('templates/pages/page-user-home.php');
|
||||
$is_fixed_homepage = function_exists('aksrt_is_fixed_homepage_request') && aksrt_is_fixed_homepage_request();
|
||||
|
||||
// CMS 形态判定(可能在博客流页面也需要 grid-cms 卡片样式)
|
||||
// CMS route detection.
|
||||
$is_cms_mode = function_exists('aksrt_is_cms_mode') ? aksrt_is_cms_mode() : false;
|
||||
// 首页/归档/搜索:卡片 + 侧栏
|
||||
if ($is_home_or_archive) {
|
||||
@@ -755,10 +755,8 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
|
||||
$enqueue_module('pages');
|
||||
}
|
||||
|
||||
// grid-cms 卡片样式
|
||||
// Resource archives use the canonical Zibll article-card stylesheet.
|
||||
if ($is_resource_archive || $is_single_resource || ($is_cms_mode && ($is_home_or_archive || $is_static_page) && !$is_fixed_homepage)) {
|
||||
$enqueue_module('post-card-cms');
|
||||
// 确保 post-card 基础样式也加载(若上面分支未加)
|
||||
if (!$is_home_or_archive && !$is_single_post && !$is_static_page) {
|
||||
$enqueue_module('post-card');
|
||||
}
|
||||
@@ -797,7 +795,6 @@ $hmb_js = get_template_directory() . '/assets/js/header-newadd.js';
|
||||
$enqueue_module('home-modules');
|
||||
$enqueue_module('post-card'); // 模块内复用
|
||||
$enqueue_module('header-components'); // header components 模块依赖
|
||||
$enqueue_module('post-card-cms'); // grid-cms 卡片依赖
|
||||
|
||||
wp_enqueue_script(
|
||||
'aksrt-cms-home-modules',
|
||||
|
||||
@@ -72,8 +72,9 @@ trait ScriptsPart1c {
|
||||
|
||||
// ===== 7. JS =====
|
||||
|
||||
// Swiper.js(首页/归档/CMS 模块/单篇文章页加载)
|
||||
$needs_swiper = $is_home_or_archive || $is_single_post || $is_single_resource;
|
||||
// Swiper.js(文章列表媒体及单篇资源页加载)
|
||||
$needs_post_list_media = wp_style_is('aksrt-post-card', 'enqueued');
|
||||
$needs_swiper = $needs_post_list_media || $is_home_or_archive || $is_single_post || $is_single_resource;
|
||||
if ($needs_swiper) {
|
||||
wp_enqueue_style(
|
||||
'aksrt-swiper',
|
||||
@@ -119,6 +120,17 @@ trait ScriptsPart1c {
|
||||
true
|
||||
);
|
||||
|
||||
if ($needs_post_list_media) {
|
||||
$grade_js = get_template_directory() . '/assets/js/grade.min.js';
|
||||
wp_enqueue_script(
|
||||
'aksrt-grade',
|
||||
$base_uri . '/assets/js/grade.min.js',
|
||||
[],
|
||||
file_exists($grade_js) ? (string) filemtime($grade_js) : $version,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
$notyf_js = get_template_directory() . '/assets/js/notyf.js';
|
||||
wp_enqueue_script(
|
||||
'aksrt-notyf',
|
||||
@@ -173,6 +185,8 @@ trait ScriptsPart1c {
|
||||
$deps = ['aksrt-rehydrate', 'aksrt-runtime'];
|
||||
if ($handle === 'aksrt-core-slider') {
|
||||
$deps = array_merge($deps, $needs_swiper ? ['aksrt-swiper'] : []);
|
||||
} elseif ($handle === 'aksrt-core-misc' && $needs_post_list_media) {
|
||||
$deps[] = 'aksrt-grade';
|
||||
} elseif ($handle === 'aksrt-core-modal-runtime') {
|
||||
$deps = array_merge($deps, [
|
||||
'aksrt-core-modal-telemetry',
|
||||
@@ -558,15 +572,14 @@ trait ScriptsPart1c {
|
||||
'commentPaginationMode' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_comment_pagination_mode() : 'numbered',
|
||||
'homepagePostsPerPage' => function_exists('aksrt_homepage_get_tab_posts_per_page') ? aksrt_homepage_get_tab_posts_per_page() : (int) get_option('posts_per_page'),
|
||||
'homepageDefaultSort' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::homepage_default_sort() : 'modified',
|
||||
'homepageDefaultView' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::homepage_default_view() : 'list',
|
||||
'homepageSortAjax' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::homepage_sort_ajax_enabled() : true,
|
||||
'homepageStickyTabs' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::homepage_sticky_tabs_enabled() : true,
|
||||
'homePostsListEnabled' => !class_exists('\AKSRT\Settings\Settings') || \AKSRT\Settings\Settings::home_posts_list_enabled(),
|
||||
'homeListSortEnabled' => !class_exists('\AKSRT\Settings\Settings') || \AKSRT\Settings\Settings::home_list_sort_enabled(),
|
||||
'homeListSortDropdown' => class_exists('\AKSRT\Settings\Settings') && \AKSRT\Settings\Settings::home_list_sort_dropdown(),
|
||||
// AJAX 翻页文案
|
||||
'ajaxTrigger' => (class_exists('\AKSRT\Settings\Settings') && ($t = \AKSRT\Settings\Settings::get_post_list_style_settings()['ajax_trigger_text'] ?? '') !== '') ? $t : __('加载更多', 'aksrt'),
|
||||
'ajaxNomore' => (class_exists('\AKSRT\Settings\Settings') && ($n = \AKSRT\Settings\Settings::get_post_list_style_settings()['ajax_nomore_text'] ?? '') !== '') ? $n : __('没有更多了', 'aksrt'),
|
||||
'ajaxTrigger' => (class_exists('\AKSRT\Settings\Settings') && ($t = \AKSRT\Settings\Settings::get_post_list_style_settings()['ajax_trigger'] ?? '') !== '') ? $t : '<i class="fa fa-angle-right"></i>加载更多',
|
||||
'ajaxNomore' => (class_exists('\AKSRT\Settings\Settings') && ($n = \AKSRT\Settings\Settings::get_post_list_style_settings()['ajax_nomore'] ?? '') !== '') ? $n : __('没有更多内容了', 'aksrt'),
|
||||
'ajaxLoading' => __('正在加载...', 'aksrt'),
|
||||
'iasMax' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['ias_max'] : 3,
|
||||
'commentIasAuto' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_comment_display_settings()['paging_ajax_ias'] : true,
|
||||
@@ -585,10 +598,10 @@ trait ScriptsPart1c {
|
||||
'identity' => true,
|
||||
'badge' => true,
|
||||
],
|
||||
'stickyEnabled' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['sticky_enabled'] : true,
|
||||
'stickyPages' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['sticky_pages'] : ['home', 'cat'],
|
||||
'badgeShow' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['badge_show'] : true,
|
||||
'badgeTypes' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['badge_types'] : ['pay', 'tag', 'cat'],
|
||||
'stickyEnabled' => class_exists('\AKSRT\Settings\Settings') ? !empty(\AKSRT\Settings\Settings::get_post_list_style_settings()['sticky_s']) : true,
|
||||
'stickyPages' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['sticky_s'] : ['home', 'cat'],
|
||||
'badgeShow' => class_exists('\AKSRT\Settings\Settings') ? !empty(\AKSRT\Settings\Settings::get_post_list_style_settings()['list_badge_show']) : true,
|
||||
'badgeTypes' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['list_badge_show'] : ['pay', 'tag', 'cat'],
|
||||
'search' => [
|
||||
'mode' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::search_mode() : 'default',
|
||||
'placeholder' => function_exists('aksrt_get_search_placeholder') ? aksrt_get_search_placeholder() : __('开启精彩搜索...', 'aksrt'),
|
||||
|
||||
@@ -274,10 +274,6 @@ class Shortcodes {
|
||||
* 用统一渲染器输出文章列表,避免内容里手写卡片循环。
|
||||
*/
|
||||
public function render_posts(array $atts = [], string $content = ''): string {
|
||||
if (!function_exists('aksrt_render_post_list')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$a = shortcode_atts([
|
||||
'count' => 6,
|
||||
'cat' => '',
|
||||
@@ -309,10 +305,13 @@ class Shortcodes {
|
||||
$mode = in_array($a['mode'], ['card', 'list', 'mini'], true) ? $a['mode'] : 'card';
|
||||
|
||||
$query = new \WP_Query($query_args);
|
||||
$html = aksrt_render_post_list($query, [
|
||||
'context' => 'widget',
|
||||
'mode' => $mode,
|
||||
], false);
|
||||
if ($mode === 'mini') {
|
||||
$html = aksrt_render_mini_list($query, [], false);
|
||||
} else {
|
||||
$html = aksrt_render_post_list([
|
||||
'type' => $mode === 'card' ? 'card' : 'list',
|
||||
], $query, false);
|
||||
}
|
||||
wp_reset_postdata();
|
||||
|
||||
return '<div class="aksrt-shortcode-posts">' . $html . '</div>';
|
||||
|
||||
@@ -66,7 +66,6 @@ class TermMeta {
|
||||
'header_style' => 'cover',
|
||||
'cover_enabled' => true,
|
||||
'desc_enabled' => true,
|
||||
'list_mode' => 'grid',
|
||||
'filter_bar' => true,
|
||||
'sidebar' => true,
|
||||
'per_page' => 12,
|
||||
@@ -77,25 +76,6 @@ class TermMeta {
|
||||
$saved = [];
|
||||
}
|
||||
|
||||
// Empty term layout_mode means follow global post-list settings (Zibll).
|
||||
// Do not fall back to page-display list_mode=grid which forced card everywhere.
|
||||
$layout_preset = isset($saved['layout_mode']) ? sanitize_key((string) $saved['layout_mode']) : '';
|
||||
if ($layout_preset === '') {
|
||||
$resolved_layout = ['mode' => '', 'card_style' => ''];
|
||||
$layout_mode = '';
|
||||
} else {
|
||||
$layout_mode = $layout_preset;
|
||||
$layout_map = [
|
||||
'grid' => ['mode' => 'card', 'card_style' => 'thumb'],
|
||||
'card' => ['mode' => 'card', 'card_style' => 'thumb'],
|
||||
'list' => ['mode' => 'list', 'card_style' => 'thumb'],
|
||||
'compact' => ['mode' => 'list', 'card_style' => 'compact'],
|
||||
'mini' => ['mode' => 'mini', 'card_style' => 'thumb'],
|
||||
'grid-cms' => ['mode' => 'grid-cms', 'card_style' => 'thumb'],
|
||||
];
|
||||
$resolved_layout = $layout_map[$layout_mode] ?? ['mode' => 'list', 'card_style' => 'thumb'];
|
||||
}
|
||||
|
||||
$header_style = (string) ($global['header_style'] ?? 'simple');
|
||||
if (!in_array($header_style, ['cover', 'simple', 'none'], true)) {
|
||||
$header_style = 'simple';
|
||||
@@ -126,9 +106,6 @@ class TermMeta {
|
||||
|
||||
return [
|
||||
'taxonomy' => $taxonomy,
|
||||
'layout_mode' => $resolved_layout['mode'],
|
||||
'card_style' => $resolved_layout['card_style'],
|
||||
'layout_preset' => $layout_mode,
|
||||
'header_style' => $header_style,
|
||||
'show_sidebar' => $sidebar_enabled,
|
||||
'show_cover' => $header_style === 'cover' && !empty($global['cover_enabled']) && $cover_url !== '',
|
||||
@@ -191,15 +168,6 @@ class TermMeta {
|
||||
<input type="url" name="aksrt_term_meta[cover_url]" id="aksrt_term_cover_url" value="" placeholder="https://...">
|
||||
<p class="description"><?php esc_html_e('分类/标签页顶部封面图,留空则不显示。', 'aksrt'); ?></p>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="aksrt_term_layout"><?php esc_html_e('列表布局', 'aksrt'); ?></label>
|
||||
<select name="aksrt_term_meta[layout_mode]" id="aksrt_term_layout">
|
||||
<option value=""><?php esc_html_e('跟随全局设置', 'aksrt'); ?></option>
|
||||
<option value="card"><?php esc_html_e('卡片模式', 'aksrt'); ?></option>
|
||||
<option value="list"><?php esc_html_e('列表模式', 'aksrt'); ?></option>
|
||||
<option value="mini"><?php esc_html_e('迷你模式', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -223,17 +191,6 @@ class TermMeta {
|
||||
<p class="description"><?php esc_html_e('覆盖默认的分类/标签描述。', 'aksrt'); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="form-field">
|
||||
<th scope="row"><label for="aksrt_term_layout"><?php esc_html_e('列表布局', 'aksrt'); ?></label></th>
|
||||
<td>
|
||||
<select name="aksrt_term_meta[layout_mode]" id="aksrt_term_layout">
|
||||
<option value="" <?php selected($meta['layout_mode'], ''); ?>><?php esc_html_e('跟随全局设置', 'aksrt'); ?></option>
|
||||
<option value="card" <?php selected($meta['layout_mode'], 'card'); ?>><?php esc_html_e('卡片模式', 'aksrt'); ?></option>
|
||||
<option value="list" <?php selected($meta['layout_mode'], 'list'); ?>><?php esc_html_e('列表模式', 'aksrt'); ?></option>
|
||||
<option value="mini" <?php selected($meta['layout_mode'], 'mini'); ?>><?php esc_html_e('迷你模式', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="form-field">
|
||||
<th scope="row"><?php esc_html_e('显示设置', 'aksrt'); ?></th>
|
||||
<td>
|
||||
@@ -269,18 +226,11 @@ class TermMeta {
|
||||
$sanitized = [
|
||||
'cover_url' => isset($raw['cover_url']) ? esc_url_raw($raw['cover_url']) : '',
|
||||
'description' => isset($raw['description']) ? sanitize_textarea_field($raw['description']) : '',
|
||||
'layout_mode' => isset($raw['layout_mode']) ? sanitize_key($raw['layout_mode']) : '',
|
||||
'show_sidebar' => isset($raw['show_sidebar']) ? '1' : '',
|
||||
'show_header' => isset($raw['show_header']) ? true : false,
|
||||
'show_featured' => isset($raw['show_featured']) ? true : false,
|
||||
];
|
||||
|
||||
// Only allow valid layout modes
|
||||
$valid_modes = ['', 'card', 'list', 'mini', 'grid-cms'];
|
||||
if (!in_array($sanitized['layout_mode'], $valid_modes, true)) {
|
||||
$sanitized['layout_mode'] = '';
|
||||
}
|
||||
|
||||
update_term_meta($term_id, self::META_KEY, $sanitized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +77,8 @@ class InlineStyleBuilder {
|
||||
'--aksrt-logo-width' => $logo_width . 'px',
|
||||
'--nav-height' => '60px',
|
||||
'--single-cover-scale' => '35%',
|
||||
'--posts-list-scale' => (class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['list_scale'] ?? 70 : 70) . '%',
|
||||
'--posts-card-scale' => (class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_post_list_style_settings()['card_scale'] ?? 70 : 70) . '%',
|
||||
'--posts-list-scale' => (class_exists('\AKSRT\Settings\Settings') ? (\AKSRT\Settings\Settings::get_post_list_style_settings()['list_list_option']['scale'] ?? 70) : 70) . '%',
|
||||
'--posts-card-scale' => (class_exists('\AKSRT\Settings\Settings') ? (\AKSRT\Settings\Settings::get_post_list_style_settings()['list_card_option']['scale'] ?? 70) : 70) . '%',
|
||||
];
|
||||
|
||||
echo '<style id="aksrt-runtime-vars">:root{';
|
||||
@@ -106,6 +106,15 @@ class InlineStyleBuilder {
|
||||
}
|
||||
echo '}</style>' . "\n";
|
||||
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$list_settings = \AKSRT\Settings\Settings::get_post_list_style_settings();
|
||||
$mobile_meta = sanitize_key((string) ($list_settings['list_meta_show'] ?? 'like'));
|
||||
if (!in_array($mobile_meta, ['view', 'like', 'comm'], true)) {
|
||||
$mobile_meta = 'like';
|
||||
}
|
||||
echo '<style id="aksrt-post-list-mobile-meta">@media (max-width:640px){.meta-right .meta-' . esc_attr($mobile_meta) . '{display:unset!important}}</style>' . "\n";
|
||||
}
|
||||
|
||||
// Zibll header_theme_custom → --header-bg / --header-color on .header.
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$ht = \AKSRT\Settings\Settings::get_header_theme_config();
|
||||
|
||||
@@ -170,55 +170,8 @@ trait DisplayPageGroups {
|
||||
$filter = self::get_post_filter_settings();
|
||||
|
||||
return [
|
||||
'list' => [
|
||||
'post_card_style' => $list['list_type'] ?? $list['card_style'] ?? 'thumb',
|
||||
'post_list_author' => $list['show_author'],
|
||||
'post_show_date' => $list['show_date'],
|
||||
'post_show_views' => $list['show_views'],
|
||||
'post_show_category' => $list['show_category'],
|
||||
'post_show_comments' => $list['show_comments'],
|
||||
'post_show_likes' => $list['show_likes'],
|
||||
'post_excerpt_length' => $list['excerpt_length'],
|
||||
'paging_ajax_s' => PostDisplay::is_list_paging_ajax() ? '1' : '0',
|
||||
'paging_ajax_ias_s' => PostDisplay::is_list_paging_ajax_ias(),
|
||||
'post_pagination_mode' => self::get_post_pagination_mode(),
|
||||
'render_mode' => $list['render_mode'],
|
||||
'sticky_s' => $list['sticky_pages'],
|
||||
'list_badge_show' => $list['badge_types'],
|
||||
'target_blank' => $list['target_blank'],
|
||||
'item_heading_bold' => $list['heading_bold'],
|
||||
'list_meta_show' => $list['mobile_meta'],
|
||||
'list_show_type' => $list['list_show_type'],
|
||||
'ias_max' => $list['ias_max'],
|
||||
'ajax_trigger' => $list['ajax_trigger_text'],
|
||||
'ajax_nomore' => $list['ajax_nomore_text'],
|
||||
'ajax_nomore_text' => $list['ajax_nomore_text'],
|
||||
'post_list_columns' => $list['columns'],
|
||||
'post_list_per_page' => $list['per_page'],
|
||||
'list_list_style' => $list['list_style'],
|
||||
'list_list_img_position' => $list['list_img_position'],
|
||||
'list_list_scale' => $list['list_scale'],
|
||||
'list_card_style' => $list['card_variant'] ?? '',
|
||||
'list_card_scale' => $list['card_scale'],
|
||||
'list_card_home' => $list['card_home'],
|
||||
'list_card_cat' => $list['card_cat_ids'] ?? [],
|
||||
'list_card_tag' => $list['card_tag'],
|
||||
'list_card_author' => $list['card_author'],
|
||||
],
|
||||
'thumb' => [
|
||||
'thumb_priority' => implode(',', $thumb['priority']),
|
||||
'thumb_fallback' => $thumb['fallback'],
|
||||
'thumb_spare_images' => $thumb['spare_images'],
|
||||
'thumb_aspect_ratio' => $thumb['aspect_ratio'],
|
||||
'thumb_multi_enabled' => $thumb['multi_enabled'],
|
||||
'thumb_multi_count' => $thumb['multi_count'],
|
||||
'list_thumb_fit' => $thumb['fit'],
|
||||
'list_thumb_slides_s' => $thumb['slides_s'],
|
||||
'list_thumb_video_s' => $thumb['video_s'],
|
||||
'list_thumb_video_mute_s' => $thumb['video_mute_s'],
|
||||
'thumb_postfirstimg_s' => $thumb['postfirstimg_s'],
|
||||
'thumb_catimg_s' => $thumb['catimg_s'],
|
||||
],
|
||||
'list' => $list,
|
||||
'thumb' => $thumb,
|
||||
'filter' => [
|
||||
'filter_enabled' => $filter['enabled'],
|
||||
'filter_categories' => $filter['categories'],
|
||||
|
||||
@@ -259,13 +259,11 @@ trait FacadeBulk {
|
||||
'reading_progress' => !isset($settings['post_reading_progress']) || !empty($settings['post_reading_progress']),
|
||||
'breadcrumbs' => !isset($settings['breadcrumbs_single_s']) || !empty($settings['breadcrumbs_single_s']),
|
||||
'breadcrumbs_home' => trim((string) ($settings['breadcrumbs_home_text'] ?? '')) ?: __('首页', 'aksrt'),
|
||||
'related_enabled' => !isset($settings['post_related_enabled']) || !empty($settings['post_related_enabled']),
|
||||
'related_count' => max(1, min(20, (int) ($settings['post_related_count'] ?? 6))),
|
||||
'related_style' => 'img',
|
||||
'related_source' => 'category',
|
||||
'related_type' => 'category',
|
||||
'related_orderby' => 'views',
|
||||
'related_title' => sanitize_text_field((string) ($settings['post_related_title'] ?? '相关推荐')),
|
||||
'related_enabled' => !isset($settings['post_related_s']) || !empty($settings['post_related_s']),
|
||||
'related_count' => max(4, min(12, (int) ($settings['post_related_n'] ?? 6))),
|
||||
'related_style' => in_array(($settings['post_related_type'] ?? 'img'), ['img', 'list', 'text'], true) ? (string) $settings['post_related_type'] : 'img',
|
||||
'related_orderby' => 'views',
|
||||
'related_title' => sanitize_text_field((string) ($settings['related_title'] ?? '相关推荐')),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -212,12 +212,7 @@ class HomeCms {
|
||||
'home_exclude_cats' => $exclude_cats,
|
||||
'home_lists' => self::normalize_homepage_tabs($tabs_raw),
|
||||
|
||||
// AKSRT presentation extras.
|
||||
'homepage_card_style' => isset($s['homepage_card_style']) ? sanitize_key((string) $s['homepage_card_style']) : 'default',
|
||||
'homepage_multi_thumb_enabled' => !empty($s['homepage_multi_thumb_enabled']),
|
||||
'homepage_multi_thumb_min_images' => (int) ($s['homepage_multi_thumb_min_images'] ?? 3),
|
||||
'homepage_sidebar_mini_enabled' => !isset($s['homepage_sidebar_mini_enabled']) || !empty($s['homepage_sidebar_mini_enabled']),
|
||||
'homepage_default_view' => isset($s['homepage_default_view']) ? sanitize_key((string) $s['homepage_default_view']) : 'list',
|
||||
'homepage_sort_ajax_enabled' => !isset($s['homepage_sort_ajax_enabled']) || !empty($s['homepage_sort_ajax_enabled']),
|
||||
'homepage_sticky_tabs_enabled' => !isset($s['homepage_sticky_tabs_enabled']) || !empty($s['homepage_sticky_tabs_enabled']),
|
||||
'home_list_sort_dropdown' => !empty($s['home_list_sort_dropdown']),
|
||||
@@ -227,16 +222,6 @@ class HomeCms {
|
||||
'homepage_module_banner_enabled' => !isset($s['homepage_module_banner_enabled']) || !empty($s['homepage_module_banner_enabled']),
|
||||
];
|
||||
|
||||
if (!in_array($settings['homepage_card_style'], ['default', 'style2', 'style3'], true)) {
|
||||
$settings['homepage_card_style'] = 'default';
|
||||
}
|
||||
|
||||
$settings['homepage_multi_thumb_min_images'] = max(2, min(4, $settings['homepage_multi_thumb_min_images']));
|
||||
|
||||
if (!in_array($settings['homepage_default_view'], ['list', 'card'], true)) {
|
||||
$settings['homepage_default_view'] = 'list';
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
@@ -259,21 +244,6 @@ class HomeCms {
|
||||
return self::homepage_tabs();
|
||||
}
|
||||
|
||||
public static function homepage_card_style(): string {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['homepage_card_style'];
|
||||
}
|
||||
|
||||
public static function homepage_multi_thumb_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['homepage_multi_thumb_enabled']);
|
||||
}
|
||||
|
||||
public static function homepage_multi_thumb_min_images(): int {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return (int) $settings['homepage_multi_thumb_min_images'];
|
||||
}
|
||||
|
||||
public static function homepage_sidebar_mini_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['homepage_sidebar_mini_enabled']);
|
||||
@@ -284,11 +254,6 @@ class HomeCms {
|
||||
return $settings['home_list1_orderby_option']['orderby'] ?? 'date';
|
||||
}
|
||||
|
||||
public static function homepage_default_view(): string {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return $settings['homepage_default_view'];
|
||||
}
|
||||
|
||||
public static function homepage_sort_ajax_enabled(): bool {
|
||||
$settings = self::get_homepage_fixed_settings();
|
||||
return !empty($settings['homepage_sort_ajax_enabled']);
|
||||
|
||||
@@ -54,29 +54,6 @@ trait HomepageReader {
|
||||
return HomeCms::homepage_tabs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Homepage card view variant.
|
||||
*
|
||||
* @return string default|style2|style3
|
||||
*/
|
||||
public static function homepage_card_style(): string {
|
||||
return HomeCms::homepage_card_style();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether homepage list cards should switch to the multi-thumb layout.
|
||||
*/
|
||||
public static function homepage_multi_thumb_enabled(): bool {
|
||||
return HomeCms::homepage_multi_thumb_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimum image count required to trigger the multi-thumb layout.
|
||||
*/
|
||||
public static function homepage_multi_thumb_min_images(): int {
|
||||
return HomeCms::homepage_multi_thumb_min_images();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether homepage sidebar widgets should use the compact mini list style.
|
||||
*/
|
||||
@@ -91,13 +68,6 @@ trait HomepageReader {
|
||||
return HomeCms::homepage_default_sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default homepage view mode.
|
||||
*/
|
||||
public static function homepage_default_view(): string {
|
||||
return HomeCms::homepage_default_view();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the homepage sortbar should refresh through AJAX.
|
||||
*/
|
||||
|
||||
+93
-227
@@ -11,177 +11,92 @@ class PostDisplay {
|
||||
|
||||
public static function get_post_list_style_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
// post_card_style storage key mirrors Zibll list_type.
|
||||
$list_type = sanitize_key((string) ($settings['post_card_style'] ?? 'thumb'));
|
||||
$allowed_list_types = ['thumb', 'compact', 'large_thumb', 'multi_thumb', 'text', 'thumb_if_has', 'card', 'standard'];
|
||||
|
||||
if (!in_array($list_type, $allowed_list_types, true)) {
|
||||
$list_type = sanitize_key((string) ($settings['list_type'] ?? 'thumb'));
|
||||
if (!in_array($list_type, ['text', 'thumb', 'thumb_if_has', 'card'], true)) {
|
||||
$list_type = 'thumb';
|
||||
}
|
||||
// Historical aliases → Zibll list_type tokens.
|
||||
if ($list_type === 'standard') {
|
||||
$list_type = 'thumb';
|
||||
}
|
||||
// Non-Zibll extras stay list-mode variants (never force card grid).
|
||||
if (in_array($list_type, ['compact', 'large_thumb', 'multi_thumb'], true)) {
|
||||
// Keep token for CSS hooks; render as list.
|
||||
}
|
||||
|
||||
// Zibll: only list_type=card is card mode; thumb/text/thumb_if_has are list.
|
||||
$render_mode_map = [
|
||||
'thumb' => 'list',
|
||||
'compact' => 'list',
|
||||
'large_thumb' => 'list',
|
||||
'multi_thumb' => 'list',
|
||||
'text' => 'list',
|
||||
'thumb_if_has' => 'list',
|
||||
'card' => 'card',
|
||||
];
|
||||
$list_option = is_array($settings['list_list_option'] ?? null) ? $settings['list_list_option'] : [];
|
||||
$list_style = sanitize_key((string) ($list_option['style'] ?? 'null'));
|
||||
$list_style = $list_style === 'style2' ? 'style2' : 'null';
|
||||
$list_position = sanitize_key((string) ($list_option['img_position'] ?? 'left'));
|
||||
$list_position = $list_position === 'right' ? 'right' : 'left';
|
||||
|
||||
$sticky_pages_raw = $settings['sticky_s'] ?? null;
|
||||
if (is_array($sticky_pages_raw)) {
|
||||
$allowed_pages = ['home', 'cat', 'tag'];
|
||||
$sticky_pages = array_values(array_intersect(array_map('sanitize_key', $sticky_pages_raw), $allowed_pages));
|
||||
} else {
|
||||
$sticky_pages = ['home', 'cat'];
|
||||
}
|
||||
$card_option = is_array($settings['list_card_option'] ?? null) ? $settings['list_card_option'] : [];
|
||||
$card_style = sanitize_key((string) ($card_option['style'] ?? 'null'));
|
||||
$card_style = $card_style === 'style3' ? 'style3' : 'null';
|
||||
|
||||
$badge_types_raw = $settings['list_badge_show'] ?? null;
|
||||
if (is_array($badge_types_raw)) {
|
||||
$allowed_types = ['pay', 'cat', 'tag'];
|
||||
$badge_types = array_values(array_intersect(array_map('sanitize_key', $badge_types_raw), $allowed_types));
|
||||
} else {
|
||||
$badge_types = ['pay', 'cat', 'tag'];
|
||||
}
|
||||
$sticky_pages = is_array($settings['sticky_s'] ?? null)
|
||||
? array_values(array_intersect(array_map('sanitize_key', $settings['sticky_s']), ['home', 'cat', 'tag']))
|
||||
: ['home', 'cat'];
|
||||
$badge_types = is_array($settings['list_badge_show'] ?? null)
|
||||
? array_values(array_intersect(array_map('sanitize_key', $settings['list_badge_show']), ['pay', 'cat', 'tag']))
|
||||
: ['pay', 'cat', 'tag'];
|
||||
$card_cat_ids = is_array($settings['list_card_cat'] ?? null)
|
||||
? array_values(array_filter(array_map('intval', $settings['list_card_cat'])))
|
||||
: [];
|
||||
|
||||
$show_author = array_key_exists('post_list_author', $settings)
|
||||
? !empty($settings['post_list_author'])
|
||||
: (!isset($settings['post_show_author']) || !empty($settings['post_show_author']));
|
||||
|
||||
$show_date = array_key_exists('post_list_time', $settings)
|
||||
? !empty($settings['post_list_time'])
|
||||
: (!isset($settings['post_show_date']) || !empty($settings['post_show_date']));
|
||||
|
||||
$target_blank = array_key_exists('target_blank', $settings)
|
||||
? !empty($settings['target_blank'])
|
||||
: !empty($settings['post_target_blank']);
|
||||
|
||||
$ajax_trigger = '';
|
||||
if (array_key_exists('ajax_trigger', $settings)) {
|
||||
$ajax_trigger = sanitize_text_field((string) $settings['ajax_trigger']);
|
||||
} elseif (array_key_exists('ajax_trigger_text', $settings)) {
|
||||
$ajax_trigger = sanitize_text_field((string) $settings['ajax_trigger_text']);
|
||||
}
|
||||
|
||||
$ajax_nomore = '';
|
||||
if (array_key_exists('ajax_nomore', $settings)) {
|
||||
$ajax_nomore = sanitize_text_field((string) $settings['ajax_nomore']);
|
||||
} elseif (array_key_exists('ajax_nomore_text', $settings)) {
|
||||
$ajax_nomore = sanitize_text_field((string) $settings['ajax_nomore_text']);
|
||||
}
|
||||
|
||||
$list_style = sanitize_key((string) ($settings['list_list_style'] ?? ''));
|
||||
if (!in_array($list_style, ['', 'style2'], true)) {
|
||||
$list_style = '';
|
||||
}
|
||||
|
||||
$card_variant = sanitize_key((string) ($settings['list_card_style'] ?? ''));
|
||||
if (!in_array($card_variant, ['', 'style3'], true)) {
|
||||
$card_variant = '';
|
||||
}
|
||||
|
||||
$card_cat_ids = [];
|
||||
if (is_array($settings['list_card_cat'] ?? null)) {
|
||||
$card_cat_ids = array_values(array_filter(array_map('intval', $settings['list_card_cat'])));
|
||||
}
|
||||
$time_source = sanitize_key((string) ($settings['post_time_source'] ?? 'modified'));
|
||||
$mobile_meta = sanitize_key((string) ($settings['list_meta_show'] ?? 'like'));
|
||||
$list_show_type = sanitize_key((string) ($settings['list_show_type'] ?? 'separate'));
|
||||
$list_orderby = sanitize_key((string) ($settings['list_orderby'] ?? 'modified'));
|
||||
|
||||
return [
|
||||
// Zibll list_type (storage: post_card_style).
|
||||
'list_type' => $list_type,
|
||||
// Base mode from list_type only (surface card overrides applied by resolver).
|
||||
'render_mode' => $render_mode_map[$list_type] ?? 'list',
|
||||
// List item subtype token for text/thumb_if_has class hooks (not card variant).
|
||||
'list_type_token' => $list_type,
|
||||
// List mode visual variant (Zibll list_list_option.style).
|
||||
'list_style' => $list_style,
|
||||
// Card mode visual variant (Zibll list_card_option.style).
|
||||
'card_variant' => $card_variant,
|
||||
// Back-compat aliases used by older callers (prefer list_type / card_variant).
|
||||
'card_style' => $list_type,
|
||||
'show_author' => $show_author,
|
||||
'show_date' => $show_date,
|
||||
'show_views' => !isset($settings['post_show_views']) || !empty($settings['post_show_views']),
|
||||
'show_category' => !isset($settings['post_show_category']) || !empty($settings['post_show_category']),
|
||||
'show_comments' => !isset($settings['post_meta_comments']) || !empty($settings['post_meta_comments']),
|
||||
'show_likes' => !isset($settings['post_meta_likes']) || !empty($settings['post_meta_likes']),
|
||||
'badge_types' => $badge_types,
|
||||
'badge_show' => !empty($badge_types),
|
||||
'sticky_pages' => $sticky_pages,
|
||||
'sticky_enabled' => !empty($sticky_pages),
|
||||
'target_blank' => $target_blank,
|
||||
'heading_bold' => !empty($settings['item_heading_bold']),
|
||||
'mobile_meta' => in_array(sanitize_key((string) ($settings['list_meta_show'] ?? 'like')), ['view', 'like', 'comm'], true) ? sanitize_key((string) ($settings['list_meta_show'] ?? 'like')) : 'like',
|
||||
'list_show_type' => in_array(sanitize_key((string) ($settings['list_show_type'] ?? 'separate')), ['separate', 'no_margin'], true) ? sanitize_key((string) ($settings['list_show_type'] ?? 'separate')) : 'separate',
|
||||
'excerpt_length' => max(20, min(500, (int) ($settings['post_excerpt_length'] ?? 120))),
|
||||
'ias_max' => max(0, min(10, (int) ($settings['ias_max'] ?? 3))),
|
||||
'paging_ajax' => self::is_list_paging_ajax($settings),
|
||||
'paging_ajax_ias' => self::is_list_paging_ajax_ias($settings),
|
||||
'ajax_trigger_text' => $ajax_trigger,
|
||||
'ajax_nomore_text' => $ajax_nomore,
|
||||
'list_orderby' => in_array(sanitize_key((string) ($settings['list_orderby'] ?? 'modified')), ['modified', 'date', 'default'], true) ? sanitize_key((string) ($settings['list_orderby'] ?? 'modified')) : 'modified',
|
||||
'columns' => max(1, min(3, (int) ($settings['post_list_columns'] ?? 1))),
|
||||
'per_page' => max(4, min(48, (int) ($settings['post_list_per_page'] ?? 12))),
|
||||
'list_img_position' => in_array(sanitize_key((string) ($settings['list_list_img_position'] ?? 'left')), ['left', 'right'], true) ? sanitize_key((string) ($settings['list_list_img_position'] ?? 'left')) : 'left',
|
||||
'list_scale' => max(50, min(200, (int) ($settings['list_list_scale'] ?? 70))),
|
||||
'card_scale' => max(20, min(200, (int) ($settings['list_card_scale'] ?? 70))),
|
||||
'card_home' => !empty($settings['list_card_home']),
|
||||
'card_cat' => !empty($card_cat_ids),
|
||||
'card_cat_ids' => $card_cat_ids,
|
||||
'card_tag' => !empty($settings['list_card_tag']),
|
||||
'card_author' => !empty($settings['list_card_author']),
|
||||
'list_type' => $list_type,
|
||||
'list_orderby' => in_array($list_orderby, ['date', 'modified', 'default'], true) ? $list_orderby : 'modified',
|
||||
'post_time_source' => $time_source === 'date' ? 'date' : 'modified',
|
||||
'sticky_s' => $sticky_pages,
|
||||
'target_blank' => !empty($settings['target_blank']),
|
||||
'item_heading_bold' => !empty($settings['item_heading_bold']),
|
||||
'post_list_author' => !array_key_exists('post_list_author', $settings) || !empty($settings['post_list_author']),
|
||||
'post_list_time' => !array_key_exists('post_list_time', $settings) || !empty($settings['post_list_time']),
|
||||
'paging_ajax_s' => (string) ($settings['paging_ajax_s'] ?? '1') === '1',
|
||||
'paging_ajax_ias_s' => !array_key_exists('paging_ajax_ias_s', $settings) || !empty($settings['paging_ajax_ias_s']),
|
||||
'ias_max' => max(0, min(10, (int) ($settings['ias_max'] ?? 3))),
|
||||
'list_meta_show' => in_array($mobile_meta, ['view', 'like', 'comm'], true) ? $mobile_meta : 'like',
|
||||
'list_badge_show' => $badge_types,
|
||||
'list_show_type' => in_array($list_show_type, ['separate', 'no_margin'], true) ? $list_show_type : 'separate',
|
||||
'list_card_home' => !empty($settings['list_card_home']),
|
||||
'list_card_tag' => !empty($settings['list_card_tag']),
|
||||
'list_card_author' => !empty($settings['list_card_author']),
|
||||
'list_card_cat' => $card_cat_ids,
|
||||
'list_list_option' => [
|
||||
'style' => $list_style,
|
||||
'img_position' => $list_position,
|
||||
'scale' => max(50, min(200, (int) ($list_option['scale'] ?? 70))),
|
||||
],
|
||||
'list_card_option' => [
|
||||
'style' => $card_style,
|
||||
'scale' => max(20, min(200, (int) ($card_option['scale'] ?? 70))),
|
||||
],
|
||||
'mult_thumb_cat' => is_array($settings['mult_thumb_cat'] ?? null) ? array_values(array_filter(array_map('intval', $settings['mult_thumb_cat']))) : [],
|
||||
'ajax_trigger' => wp_kses_post((string) ($settings['ajax_trigger'] ?? '<i class="fa fa-angle-right"></i>加载更多')),
|
||||
'ajax_nomore' => wp_kses_post((string) ($settings['ajax_nomore'] ?? '没有更多内容了')),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_post_thumb_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$priority_raw = (string) ($settings['thumb_priority'] ?? 'featured,attachment,resource,custom');
|
||||
$priority = preg_split('/[\s,]+/', strtolower($priority_raw)) ?: [];
|
||||
$priority = array_values(array_unique(array_filter(array_map('sanitize_key', $priority))));
|
||||
$allowed_sources = ['featured', 'attachment', 'resource', 'custom', 'category_cover', 'post_first_img'];
|
||||
$priority = array_values(array_filter($priority, static function (string $source) use ($allowed_sources): bool {
|
||||
return in_array($source, $allowed_sources, true);
|
||||
}));
|
||||
|
||||
if (empty($priority)) {
|
||||
$priority = ['featured', 'attachment', 'resource', 'custom'];
|
||||
public static function get_post_thumb_settings(): array {
|
||||
$settings = Settings::get_all();
|
||||
$spare_settings = array_key_exists('spare_thumbnail', $settings)
|
||||
? (array) $settings['spare_thumbnail']
|
||||
: [['img' => get_template_directory_uri() . '/assets/img/thumbnail.svg']];
|
||||
$spare = [];
|
||||
foreach ($spare_settings as $item) {
|
||||
$url = is_array($item) ? (string) ($item['img'] ?? '') : '';
|
||||
if ($url !== '') {
|
||||
$spare[] = esc_url_raw($url);
|
||||
}
|
||||
}
|
||||
|
||||
$fallback = sanitize_key((string) ($settings['thumb_fallback'] ?? 'placeholder'));
|
||||
if (!in_array($fallback, ['placeholder', 'hide', 'random'], true)) {
|
||||
$fallback = 'placeholder';
|
||||
}
|
||||
|
||||
$aspect_ratio = (string) ($settings['thumb_aspect_ratio'] ?? '16:9');
|
||||
if (!in_array($aspect_ratio, ['16:9', '4:3', '1:1', 'auto'], true)) {
|
||||
$aspect_ratio = '16:9';
|
||||
}
|
||||
|
||||
$fit = sanitize_key((string) ($settings['list_thumb_fit'] ?? ''));
|
||||
return [
|
||||
'priority' => $priority,
|
||||
'fallback' => $fallback,
|
||||
'spare_images' => is_array($settings['thumb_spare_images'] ?? null) ? $settings['thumb_spare_images'] : [],
|
||||
'aspect_ratio' => $aspect_ratio,
|
||||
'multi_enabled' => !empty($settings['thumb_multi_enabled']),
|
||||
'multi_count' => max(2, min(6, (int) ($settings['thumb_multi_count'] ?? 3))),
|
||||
'fit' => in_array(sanitize_key((string) ($settings['list_thumb_fit'] ?? 'cover')), ['cover', 'contain'], true) ? sanitize_key((string) ($settings['list_thumb_fit'] ?? 'cover')) : 'cover',
|
||||
'slides_s' => !isset($settings['list_thumb_slides_s']) || !empty($settings['list_thumb_slides_s']),
|
||||
'video_s' => !isset($settings['list_thumb_video_s']) || !empty($settings['list_thumb_video_s']),
|
||||
'video_mute_s' => !isset($settings['list_thumb_video_mute_s']) || !empty($settings['list_thumb_video_mute_s']),
|
||||
'postfirstimg_s' => !isset($settings['thumb_postfirstimg_s']) || !empty($settings['thumb_postfirstimg_s']),
|
||||
'catimg_s' => !isset($settings['thumb_catimg_s']) || !empty($settings['thumb_catimg_s']),
|
||||
'postfirstimg_size'=> in_array(sanitize_key((string) ($settings['thumb_postfirstimg_size'] ?? 'medium')), ['thumbnail', 'medium', 'large', 'full'], true) ? sanitize_key((string) ($settings['thumb_postfirstimg_size'] ?? 'medium')) : 'medium',
|
||||
'mult_thumb_cat_ids' => is_array($settings['mult_thumb_cat'] ?? null) ? array_map('intval', $settings['mult_thumb_cat']) : [],
|
||||
'list_thumb_slides_s' => !array_key_exists('list_thumb_slides_s', $settings) || !empty($settings['list_thumb_slides_s']),
|
||||
'list_thumb_video_s' => !array_key_exists('list_thumb_video_s', $settings) || !empty($settings['list_thumb_video_s']),
|
||||
'list_thumb_video_mute_s' => !array_key_exists('list_thumb_video_mute_s', $settings) || !empty($settings['list_thumb_video_mute_s']),
|
||||
'thumb_postfirstimg_s' => !array_key_exists('thumb_postfirstimg_s', $settings) || !empty($settings['thumb_postfirstimg_s']),
|
||||
'thumb_catimg_s' => !array_key_exists('thumb_catimg_s', $settings) || !empty($settings['thumb_catimg_s']),
|
||||
'list_thumb_fit' => $fit === 'contain' ? 'contain' : '',
|
||||
'thumb_postfirstimg_size' => in_array(sanitize_key((string) ($settings['thumb_postfirstimg_size'] ?? 'medium')), ['thumbnail', 'medium', 'large', 'full'], true) ? sanitize_key((string) ($settings['thumb_postfirstimg_size'] ?? 'medium')) : 'medium',
|
||||
'spare_thumbnail' => $spare,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -262,30 +177,15 @@ class PostDisplay {
|
||||
$maxheight = 1000;
|
||||
}
|
||||
|
||||
// Related: split Zibll display style (img/list/text) from query source (category/tag/random).
|
||||
// Legacy post_related_type held either style (img|list|text) or source (category|tag|random).
|
||||
$raw_related_type = sanitize_key((string) ($settings['post_related_type'] ?? ''));
|
||||
$raw_related_style = sanitize_key((string) ($settings['post_related_style'] ?? ''));
|
||||
$raw_related_source = sanitize_key((string) ($settings['post_related_source'] ?? ''));
|
||||
$related_style = sanitize_key((string) ($settings['post_related_type'] ?? 'img'));
|
||||
if (!in_array($related_style, ['img', 'list', 'text'], true)) {
|
||||
$related_style = 'img';
|
||||
}
|
||||
|
||||
$related_style = 'img';
|
||||
if (in_array($raw_related_style, ['img', 'list', 'text'], true)) {
|
||||
$related_style = $raw_related_style;
|
||||
} elseif (in_array($raw_related_type, ['img', 'list', 'text'], true)) {
|
||||
$related_style = $raw_related_type;
|
||||
}
|
||||
|
||||
$related_source = 'category';
|
||||
if (in_array($raw_related_source, ['category', 'tag', 'random'], true)) {
|
||||
$related_source = $raw_related_source;
|
||||
} elseif (in_array($raw_related_type, ['category', 'tag', 'random'], true)) {
|
||||
$related_source = $raw_related_type;
|
||||
}
|
||||
|
||||
$related_orderby = sanitize_key((string) ($settings['post_related_orderby'] ?? 'views'));
|
||||
if (!in_array($related_orderby, ['rand', 'relevance', 'date', 'views', 'modified'], true)) {
|
||||
$related_orderby = 'views';
|
||||
}
|
||||
$related_orderby = sanitize_key((string) ($settings['post_related_orderby'] ?? 'views'));
|
||||
if (!in_array($related_orderby, ['modified', 'date', 'views', 'like', 'comment_count', 'favorite', 'rand'], true)) {
|
||||
$related_orderby = 'views';
|
||||
}
|
||||
|
||||
return [
|
||||
'toc_enabled' => !isset($settings['post_toc_enabled']) || !empty($settings['post_toc_enabled']),
|
||||
@@ -317,15 +217,11 @@ class PostDisplay {
|
||||
'lightbox_full' => !isset($settings['post_lightbox_full']) || !empty($settings['post_lightbox_full']),
|
||||
'lightbox_down' => !empty($settings['post_lightbox_down']),
|
||||
'lightbox_play' => !empty($settings['post_lightbox_play']),
|
||||
'related_enabled' => !isset($settings['post_related_enabled']) || !empty($settings['post_related_enabled']),
|
||||
'related_count' => max(1, min(20, (int) ($settings['post_related_count'] ?? 6))),
|
||||
// Display style (Zibll img/list/text) + query source (category/tag/random).
|
||||
'related_style' => $related_style,
|
||||
'related_source' => $related_source,
|
||||
// Legacy alias: older code treated related_type as source.
|
||||
'related_type' => $related_source,
|
||||
'related_orderby' => $related_orderby,
|
||||
'related_title' => sanitize_text_field((string) ($settings['post_related_title'] ?? '相关推荐')),
|
||||
'related_enabled' => !isset($settings['post_related_s']) || !empty($settings['post_related_s']),
|
||||
'related_count' => max(4, min(12, (int) ($settings['post_related_n'] ?? 6))),
|
||||
'related_style' => $related_style,
|
||||
'related_orderby' => $related_orderby,
|
||||
'related_title' => sanitize_text_field((string) ($settings['related_title'] ?? '相关推荐')),
|
||||
'like_enabled' => !isset($settings['post_like_enabled']) || !empty($settings['post_like_enabled']),
|
||||
'favorite_enabled' => !isset($settings['post_favorite_enabled']) || !empty($settings['post_favorite_enabled']),
|
||||
// Canonical + legacy share.
|
||||
@@ -534,42 +430,21 @@ class PostDisplay {
|
||||
}
|
||||
|
||||
public static function apply_list_per_page($query): void {
|
||||
if (is_admin() || !$query->is_main_query()) {
|
||||
return;
|
||||
}
|
||||
if (!$query->is_archive() && !$query->is_search() && !$query->is_home()) {
|
||||
return;
|
||||
}
|
||||
$s = Settings::get_all();
|
||||
$per_page = max(4, min(48, (int) ($s['post_list_per_page'] ?? 12)));
|
||||
if ($per_page !== 12) {
|
||||
$query->set('posts_per_page', $per_page);
|
||||
}
|
||||
unset($query);
|
||||
}
|
||||
|
||||
public static function get_archive_layout(): string {
|
||||
$settings = self::get_post_list_style_settings();
|
||||
return $settings['render_mode'];
|
||||
return ($settings['list_type'] ?? 'thumb') === 'card' ? 'card' : 'list';
|
||||
}
|
||||
|
||||
public static function get_post_pagination_mode(): string {
|
||||
$settings = Settings::get_all();
|
||||
|
||||
// Zibll: paging_ajax_s '1' = ajax append, '0' = numeric buttons.
|
||||
if (array_key_exists('paging_ajax_s', $settings)) {
|
||||
$ajax = self::is_list_paging_ajax($settings);
|
||||
if (!$ajax) {
|
||||
return 'numbered';
|
||||
}
|
||||
return self::is_list_paging_ajax_ias($settings) ? 'infinite' : 'load_more';
|
||||
if (!self::is_list_paging_ajax($settings)) {
|
||||
return 'numbered';
|
||||
}
|
||||
|
||||
// Temporary bridge for installs still holding the previous schema key only.
|
||||
$mode = (string) ($settings['post_pagination_mode'] ?? 'numbered');
|
||||
if ($mode === 'numeric') {
|
||||
$mode = 'numbered';
|
||||
}
|
||||
return in_array($mode, ['numbered', 'load_more', 'infinite'], true) ? $mode : 'numbered';
|
||||
return self::is_list_paging_ajax_ias($settings) ? 'infinite' : 'load_more';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -579,12 +454,7 @@ class PostDisplay {
|
||||
*/
|
||||
public static function is_list_paging_ajax(?array $settings = null): bool {
|
||||
$settings = $settings ?? Settings::get_all();
|
||||
if (!array_key_exists('paging_ajax_s', $settings)) {
|
||||
// Fallback from previous 3-mode key.
|
||||
$mode = (string) ($settings['post_pagination_mode'] ?? 'numbered');
|
||||
return in_array($mode, ['load_more', 'infinite', 'ajax'], true);
|
||||
}
|
||||
$raw = $settings['paging_ajax_s'];
|
||||
$raw = $settings['paging_ajax_s'] ?? '1';
|
||||
if (is_bool($raw)) {
|
||||
return $raw;
|
||||
}
|
||||
@@ -601,11 +471,7 @@ class PostDisplay {
|
||||
if (!self::is_list_paging_ajax($settings)) {
|
||||
return false;
|
||||
}
|
||||
if (!array_key_exists('paging_ajax_ias_s', $settings)) {
|
||||
$mode = (string) ($settings['post_pagination_mode'] ?? '');
|
||||
return $mode === 'infinite';
|
||||
}
|
||||
return !empty($settings['paging_ajax_ias_s']);
|
||||
return !array_key_exists('paging_ajax_ias_s', $settings) || !empty($settings['paging_ajax_ias_s']);
|
||||
}
|
||||
|
||||
public static function get_comment_pagination_mode(): string {
|
||||
|
||||
@@ -646,9 +646,9 @@ class Settings {
|
||||
|
||||
|
||||
/**
|
||||
* Post-list card style and meta display settings.
|
||||
*
|
||||
* @return array{card_style:string,render_mode:string,show_author:bool,show_date:bool,show_views:bool,show_category:bool,show_comments:bool,show_likes:bool,excerpt_length:int}
|
||||
* Zibll 9.0 post-list display settings.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_post_list_style_settings(): array {
|
||||
return PostDisplay::get_post_list_style_settings();
|
||||
@@ -659,7 +659,7 @@ class Settings {
|
||||
/**
|
||||
* Post-list thumbnail policy settings.
|
||||
*
|
||||
* @return array{priority:string[],fallback:string,aspect_ratio:string,multi_enabled:bool,multi_count:int,lazy:bool}
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public static function get_post_thumb_settings(): array {
|
||||
return PostDisplay::get_post_thumb_settings();
|
||||
@@ -949,10 +949,7 @@ class Settings {
|
||||
/**
|
||||
* 获取归档布局模式。
|
||||
*
|
||||
* 从 post_list.list schema 的 render_mode 字段读取。
|
||||
* 后台可在 /post-list/list 页面配置。
|
||||
*
|
||||
* @return string grid-cms|list|compact
|
||||
* @return string card|list
|
||||
*/
|
||||
public static function get_archive_layout(): string {
|
||||
return PostDisplay::get_archive_layout();
|
||||
|
||||
@@ -31,48 +31,49 @@ final class PostRenderer {
|
||||
$style = (string) ($instance['style'] ?? 'card');
|
||||
$mode = in_array($style, ['list', 'card', 'mini'], true) ? $style : 'card';
|
||||
$config = [
|
||||
'mode' => $mode,
|
||||
'context' => 'widget',
|
||||
'columns' => $mode === 'card' ? 3 : 1,
|
||||
'show_thumb' => $slug !== 'hot_posts' || !empty($instance['show_thumbnail']),
|
||||
'show_meta' => $mode !== 'mini',
|
||||
'show_excerpt' => $mode === 'list',
|
||||
'show_author' => false,
|
||||
'show_comments' => true,
|
||||
'show_likes' => true,
|
||||
'show_tags' => false,
|
||||
'show_badges' => true,
|
||||
'type' => $mode === 'card' ? 'card' : 'list',
|
||||
'show_number' => $slug === 'hot_posts',
|
||||
'show_thumb' => $slug !== 'hot_posts' || !array_key_exists('show_thumbnail', $instance) || !empty($instance['show_thumbnail']),
|
||||
'show_meta' => true,
|
||||
'number_offset' => ($page - 1) * max(1, (int) ($instance['count'] ?? 8)),
|
||||
'wrapper_class' => 'aksrt-widget-posts aksrt-widget-posts--' . $slug,
|
||||
'widget_style' => $mode,
|
||||
];
|
||||
if ($slug === 'oneline_posts') {
|
||||
return self::oneline($query, $config, !empty($instance['autoplay']));
|
||||
}
|
||||
if (function_exists('aksrt_render_post_list')) {
|
||||
return aksrt_render_post_list($query, $config, false);
|
||||
if ($mode === 'mini') {
|
||||
return aksrt_render_mini_list($query, $config, false);
|
||||
}
|
||||
|
||||
$html = '<div class="aksrt-widget-posts aksrt-widget-posts--fallback">';
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$html .= '<article><a href="' . esc_url(get_permalink()) . '">' . get_the_post_thumbnail(get_the_ID(), 'medium') . '<strong>' . esc_html(get_the_title()) . '</strong></a></article>';
|
||||
}
|
||||
wp_reset_postdata();
|
||||
return $html . '</div>';
|
||||
return aksrt_render_post_list($config, $query, false);
|
||||
}
|
||||
|
||||
private static function oneline(\WP_Query $query, array $config, bool $autoplay): string {
|
||||
$slides = '';
|
||||
$items = '';
|
||||
$style = in_array(($config['widget_style'] ?? 'card'), ['list', 'card', 'mini'], true)
|
||||
? (string) $config['widget_style']
|
||||
: 'card';
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$item = function_exists('aksrt_render_post')
|
||||
? aksrt_render_post(array_merge($config, ['skip_wrapper' => true]))
|
||||
: '<a href="' . esc_url(get_permalink()) . '">' . esc_html(get_the_title()) . '</a>';
|
||||
$slides .= '<div class="swiper-slide">' . $item . '</div>';
|
||||
if ($style === 'mini') {
|
||||
$data = aksrt_renderer_collect_post_data($config);
|
||||
$items .= $data ? aksrt_renderer_mini($data, array_merge($config, [
|
||||
'class' => 'posts-item',
|
||||
'show_thumb' => true,
|
||||
'show_meta' => true,
|
||||
'show_number' => false,
|
||||
])) : '';
|
||||
} else {
|
||||
$items .= aksrt_render_post(array_merge($config, [
|
||||
'type' => $style === 'card' ? 'card' : 'list',
|
||||
'is_mult_thumb' => 'disable',
|
||||
'is_no_thumb' => 'disable',
|
||||
]));
|
||||
}
|
||||
}
|
||||
wp_reset_postdata();
|
||||
return '<div class="swiper aksrt-widget-swiper aksrt-widget-oneline" data-aksrt-swiper="scroll" data-autoplay="' . ($autoplay ? '1' : '0') . '"><div class="swiper-wrapper">' . $slides . '</div><button class="swiper-button-prev" type="button" aria-label="' . esc_attr__('上一组', 'aksrt') . '"></button><button class="swiper-button-next" type="button" aria-label="' . esc_attr__('下一组', 'aksrt') . '"></button></div>';
|
||||
$autoplay_attr = $autoplay ? ' data-autoplay="true"' : '';
|
||||
return '<div class="widget-main-post mb20 style-' . esc_attr($style) . '"><div class="swiper-container swiper-scroll" data-slideClass="posts-item"' . $autoplay_attr . '><div class="swiper-wrapper">' . $items . '</div><div class="swiper-button-prev"></div><div class="swiper-button-next"></div></div></div>';
|
||||
}
|
||||
|
||||
private static function pagination(array $instance, int $page, int $max_pages): string {
|
||||
|
||||
@@ -18,14 +18,12 @@ if (!$term instanceof WP_Term) {
|
||||
$archive_settings = class_exists('\AKSRT\Core\TermMeta')
|
||||
? \AKSRT\Core\TermMeta::resolve_archive_settings($term)
|
||||
: [
|
||||
'layout_mode' => 'card',
|
||||
'header_style' => 'simple',
|
||||
'show_sidebar' => true,
|
||||
'show_cover' => false,
|
||||
'show_desc' => !empty($term->description),
|
||||
'cover_url' => '',
|
||||
'description' => (string) $term->description,
|
||||
'card_style' => 'standard',
|
||||
];
|
||||
|
||||
$has_sidebar = function_exists('aksrt_archive_has_sidebar')
|
||||
@@ -33,8 +31,6 @@ $has_sidebar = function_exists('aksrt_archive_has_sidebar')
|
||||
: (!empty($archive_settings['show_sidebar']) && is_active_sidebar('tag_sidebar'));
|
||||
$description = !empty($archive_settings['show_desc']) ? wp_kses_post((string) $archive_settings['description']) : '';
|
||||
$header_style = (string) $archive_settings['header_style'];
|
||||
$layout_mode = (string) $archive_settings['layout_mode'];
|
||||
$card_style = (string) ($archive_settings['card_style'] ?? 'standard');
|
||||
$filter_settings = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_post_filter_settings()
|
||||
: ['enabled' => false, 'sort' => false, 'ajax_enabled' => false];
|
||||
@@ -45,20 +41,9 @@ $ajax_filter = !empty($filter_settings['ajax_enabled']) && !empty($filter_settin
|
||||
$sort_state = function_exists('aksrt_archive_get_sort_state') ? aksrt_archive_get_sort_state() : ['current' => 'latest', 'links' => []];
|
||||
$current_sort = $sort_state['current'];
|
||||
$sort_links = $sort_state['links'];
|
||||
$render_overrides = [
|
||||
'context' => 'tag',
|
||||
];
|
||||
// Term meta layout_mode is authoritative only when explicitly set (non-empty preset).
|
||||
$layout_preset = (string) ($archive_settings['layout_preset'] ?? '');
|
||||
if ($layout_preset !== '' && in_array((string) $layout_mode, ['list', 'card', 'mini', 'grid-cms'], true)) {
|
||||
$render_overrides['mode'] = (string) $layout_mode;
|
||||
if (!empty($card_style)) {
|
||||
$render_overrides['card_style'] = (string) $card_style;
|
||||
}
|
||||
}
|
||||
$render_config = function_exists('aksrt_archive_get_render_config')
|
||||
? aksrt_archive_get_render_config($render_overrides)
|
||||
: array_merge(['context' => 'tag', 'mode' => 'list'], $render_overrides);
|
||||
$render_config = function_exists('aksrt_archive_get_render_config')
|
||||
? aksrt_archive_get_render_config(['context' => 'tag'])
|
||||
: ['context' => 'tag'];
|
||||
|
||||
$cat_filter_terms = [];
|
||||
$current_filter_cat = sanitize_text_field((string) get_query_var('aksrt_filter_cat', ''));
|
||||
@@ -132,8 +117,6 @@ if (function_exists('aksrt_archive_open_shell')) {
|
||||
'ajax' => $ajax_filter,
|
||||
'ajax_archive' => 'tag',
|
||||
'term_id' => (int) $term->term_id,
|
||||
'layout_mode' => $layout_mode,
|
||||
'card_style' => $card_style,
|
||||
'aria_label' => __('标签工具条', 'aksrt'),
|
||||
'meta_text' => sprintf(_n('%d 篇文章', '%d 篇文章', (int) $term->count, 'aksrt'), (int) $term->count),
|
||||
'groups' => $filter_groups,
|
||||
|
||||
@@ -52,11 +52,7 @@ if (function_exists('aksrt_archive_open_shell')) {
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<?php
|
||||
if (function_exists('aksrt_render_pagination')) {
|
||||
aksrt_render_pagination($query);
|
||||
} else {
|
||||
echo '<div class="aksrt-pagination">' . paginate_links(['total' => $query->max_num_pages]) . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
aksrt_render_pagination($query);
|
||||
wp_reset_postdata();
|
||||
?>
|
||||
<?php else : ?>
|
||||
|
||||
@@ -8,24 +8,4 @@
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
$args = isset($args) && is_array($args) ? $args : [];
|
||||
$forced_layout = (string) get_query_var('aksrt_post_card_layout', '');
|
||||
$mode = 'card';
|
||||
|
||||
if (in_array($forced_layout, ['card', 'list', 'grid-cms'], true)) {
|
||||
$mode = $forced_layout;
|
||||
} elseif (!empty($args['mode']) && in_array($args['mode'], ['card', 'list', 'grid-cms', 'mini'], true)) {
|
||||
$mode = (string) $args['mode'];
|
||||
} elseif (function_exists('aksrt_get_post_flow') && aksrt_get_post_flow(get_the_ID()) === 'cms') {
|
||||
$mode = 'grid-cms';
|
||||
} elseif (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$archive_layout = \AKSRT\Settings\Settings::get_archive_layout();
|
||||
$mode = in_array($archive_layout, ['card', 'list', 'grid-cms'], true) ? $archive_layout : 'card';
|
||||
}
|
||||
|
||||
$scene = (string) get_query_var('aksrt_post_card_scene', '');
|
||||
$context = ($scene === 'home' || is_front_page() || (is_home() && !is_paged())) ? 'home' : 'archive';
|
||||
|
||||
echo aksrt_render_post(array_merge($args, [
|
||||
'mode' => $mode,
|
||||
'context' => $context,
|
||||
])); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo aksrt_render_post($args); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
@@ -15,7 +15,7 @@ $layout = (string) ($cfg['layout'] ?? 'card');
|
||||
$columns = max(1, min(6, (int) ($cfg['columns'] ?? 4)));
|
||||
$title = (string) ($cfg['title'] ?? '');
|
||||
|
||||
if (!in_array($layout, ['card', 'list', 'masonry', 'grid-cms'], true)) {
|
||||
if (!in_array($layout, ['card', 'list'], true)) {
|
||||
$layout = 'card';
|
||||
}
|
||||
|
||||
@@ -53,15 +53,13 @@ $more_link = $cat_id > 0 ? get_category_link($cat_id) : '';
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
|
||||
<div class="post-grid post-grid--<?php echo esc_attr($layout); ?>" style="--cols:<?php echo (int) $columns; ?>;">
|
||||
<div class="posts-row ajaxpager">
|
||||
<?php
|
||||
set_query_var('aksrt_post_card_layout', $layout);
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
get_template_part('templates/parts/content', 'post-card');
|
||||
}
|
||||
set_query_var('aksrt_post_card_layout', '');
|
||||
wp_reset_postdata();
|
||||
aksrt_render_post_list([
|
||||
'type' => $layout === 'card' ? 'card' : 'list',
|
||||
'is_home' => true,
|
||||
'skip_wrapper' => true,
|
||||
], $query);
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -16,7 +16,7 @@ $count = max(1, min(20, (int) ($cfg['count'] ?? 6)));
|
||||
$layout = (string) ($cfg['layout'] ?? 'card');
|
||||
$title = (string) ($cfg['title'] ?? '');
|
||||
|
||||
if (!in_array($layout, ['card', 'list', 'masonry', 'grid-cms'], true)) {
|
||||
if (!in_array($layout, ['card', 'list'], true)) {
|
||||
$layout = 'card';
|
||||
}
|
||||
|
||||
@@ -49,16 +49,13 @@ $archive_link = get_permalink(get_option('page_for_posts'));
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
|
||||
<div class="post-grid post-grid--<?php echo esc_attr($layout); ?>">
|
||||
<div class="posts-row ajaxpager">
|
||||
<?php
|
||||
set_query_var('aksrt_post_card_layout', $layout);
|
||||
set_query_var('aksrt_post_card_scene', 'home');
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
get_template_part('templates/parts/content', 'post-card');
|
||||
}
|
||||
set_query_var('aksrt_post_card_layout', '');
|
||||
set_query_var('aksrt_post_card_scene', '');
|
||||
aksrt_render_post_list([
|
||||
'type' => $layout === 'card' ? 'card' : 'list',
|
||||
'is_home' => true,
|
||||
'skip_wrapper' => true,
|
||||
], $query);
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -16,11 +16,11 @@ if (!is_array($cfg)) $cfg = [];
|
||||
$cat_ids = isset($cfg['cat_ids']) && is_array($cfg['cat_ids']) ? array_map('intval', $cfg['cat_ids']) : [];
|
||||
$cat_ids = array_filter($cat_ids, fn($x) => $x > 0);
|
||||
$count = max(1, min(20, (int) ($cfg['count'] ?? 8)));
|
||||
$layout = (string) ($cfg['layout'] ?? 'grid-cms');
|
||||
$layout = (string) ($cfg['layout'] ?? 'card');
|
||||
$title = (string) ($cfg['title'] ?? '');
|
||||
|
||||
if (!in_array($layout, ['card', 'list', 'masonry', 'grid-cms'], true)) {
|
||||
$layout = 'grid-cms';
|
||||
if (!in_array($layout, ['card', 'list'], true)) {
|
||||
$layout = 'card';
|
||||
}
|
||||
|
||||
if (empty($cat_ids)) {
|
||||
@@ -86,15 +86,11 @@ $active_id = $tabs[0]['id'];
|
||||
<?php if ($query->have_posts()) : ?>
|
||||
<div class="posts-row ajaxpager tab-content">
|
||||
<?php
|
||||
set_query_var('aksrt_post_card_layout', $layout === 'list' ? 'list' : 'card');
|
||||
set_query_var('aksrt_post_card_scene', 'home');
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
get_template_part('templates/parts/content', 'post-card');
|
||||
}
|
||||
set_query_var('aksrt_post_card_layout', '');
|
||||
set_query_var('aksrt_post_card_scene', '');
|
||||
wp_reset_postdata();
|
||||
aksrt_render_post_list([
|
||||
'type' => $layout === 'card' ? 'card' : 'list',
|
||||
'is_home' => true,
|
||||
'skip_wrapper' => true,
|
||||
], $query);
|
||||
?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
|
||||
@@ -43,15 +43,22 @@ if (!$query->have_posts()) {
|
||||
<header class="resource-related__header">
|
||||
<h2 class="resource-related__title"><?php esc_html_e('相关资源', 'aksrt'); ?></h2>
|
||||
</header>
|
||||
<div class="resource-related__grid post-grid post-grid--card">
|
||||
<?php
|
||||
set_query_var('aksrt_post_card_layout', 'card');
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
get_template_part('templates/parts/content', 'post-card');
|
||||
}
|
||||
set_query_var('aksrt_post_card_layout', '');
|
||||
wp_reset_postdata();
|
||||
?>
|
||||
<div class="resource-related__grid zib-widget">
|
||||
<div class="swiper-container swiper-scroll">
|
||||
<div class="swiper-wrapper">
|
||||
<?php
|
||||
while ($query->have_posts()) {
|
||||
$query->the_post();
|
||||
$post = get_post();
|
||||
if ($post instanceof WP_Post) {
|
||||
echo aksrt_render_related_graphic_card($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
wp_reset_postdata();
|
||||
?>
|
||||
</div>
|
||||
<div class="swiper-button-prev"></div>
|
||||
<div class="swiper-button-next"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -20,29 +20,18 @@ extract($args, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_ext
|
||||
'post_status' => 'publish',
|
||||
'paged' => $posts_page,
|
||||
'no_found_rows' => false,
|
||||
'update_post_meta_cache' => false,
|
||||
]);
|
||||
if ($author_posts->have_posts()) :
|
||||
?>
|
||||
<div class="profile-list">
|
||||
<?php while ($author_posts->have_posts()) : $author_posts->the_post(); ?>
|
||||
<?php
|
||||
get_template_part('templates/parts/content', 'profile-list-item', [
|
||||
'action' => [
|
||||
'type' => 'view',
|
||||
'url' => get_permalink(),
|
||||
'label' => __('阅读', 'aksrt'),
|
||||
],
|
||||
]);
|
||||
?>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<?php
|
||||
aksrt_render_profile_pagination((int) $author_posts->max_num_pages, $posts_page, 'posts_page');
|
||||
wp_reset_postdata();
|
||||
else :
|
||||
aksrt_render_profile_empty($svg_empty_post, __('TA 还没有发布文章', 'aksrt'));
|
||||
endif;
|
||||
$author_render_config = aksrt_resolve_post_list_render_config([
|
||||
'context' => 'author',
|
||||
]);
|
||||
aksrt_render_post_list(array_merge($author_render_config, ['wrapper_class' => 'profile-list']), $author_posts);
|
||||
aksrt_render_pagination($author_posts, [
|
||||
'query_context' => 'author',
|
||||
'render_config' => $author_render_config,
|
||||
'page_var' => 'posts_page',
|
||||
'current_page' => $posts_page,
|
||||
]);
|
||||
wp_reset_postdata();
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
+31
-7
@@ -8,16 +8,40 @@ $env:ZIBLL_THEME_PATH='C:\Users\Xing\Desktop\zibll'
|
||||
docker compose -f tests/visual/docker-compose.zibll.yml up -d
|
||||
docker compose -f tests/visual/docker-compose.zibll.yml run --rm wp core install --url=https://localhost:9443 --title='Zibll Reference' --admin_user=visual_admin --admin_password='AKSRT-Visual-2026!' --admin_email=visual@example.test --skip-email
|
||||
docker compose -f tests/visual/docker-compose.zibll.yml run --rm wp theme activate zibll
|
||||
docker compose -f tests/visual/docker-compose.zibll.yml run --rm wp eval-file /visual-fixtures/article-fixtures.php create
|
||||
~~~
|
||||
|
||||
Create or clean AKSRT fixtures inside its WordPress container:
|
||||
Run the same theme-neutral article generator inside the AKSRT WordPress
|
||||
container. Mount `tests/visual/` read-only at `/visual-fixtures` in that stack:
|
||||
|
||||
~~~powershell
|
||||
wp eval-file wp-content/themes/AKSRT-theme/tools/wp-cli-visual-fixtures.php create
|
||||
wp eval-file wp-content/themes/AKSRT-theme/tools/wp-cli-visual-fixtures.php cleanup
|
||||
wp eval-file /visual-fixtures/article-fixtures.php create
|
||||
wp eval-file /visual-fixtures/article-fixtures.php cleanup
|
||||
~~~
|
||||
|
||||
Use tests/fixtures/widget-golden-v1.json for the 222 component captures and
|
||||
tests/fixtures/page-visual-matrix-v1.json for page-level captures. Remove
|
||||
the reference stack with docker compose down -v only after fixture cleanup
|
||||
and screenshot verification.
|
||||
The shared generator creates the same authors, category, tag, dates, images,
|
||||
featured/no-image/multi-image/first-image/external-cover posts, slide and video
|
||||
metadata, pay/VIP states, sticky state, and interaction counters in both sites.
|
||||
Fixture-only Zibll and AKSRT metadata are written together so the rendered
|
||||
business state is identical without adding compatibility code to either theme.
|
||||
|
||||
Use `tests/visual/article-visual-matrix-v1.json` for the article-only captures.
|
||||
Every reference/candidate pair must record the screenshot, DOM, computed styles,
|
||||
bounding boxes, console messages, and failed network requests. The matrix pins
|
||||
1440, 1024, 768, 767, 641, 640, and 390 widths across light/dark,
|
||||
sidebar/no-sidebar, list/card modes, media states, and all pagination states.
|
||||
|
||||
The acceptance gate is at most 1 CSS px geometry delta and 1.5% pixel
|
||||
difference, with no visible mismatch, console error, unexpected failed request,
|
||||
or critical/serious accessibility issue.
|
||||
|
||||
Clean the reference fixture before removing its volumes:
|
||||
|
||||
~~~powershell
|
||||
docker compose -f tests/visual/docker-compose.zibll.yml run --rm wp eval-file /visual-fixtures/article-fixtures.php cleanup
|
||||
docker compose -f tests/visual/docker-compose.zibll.yml down -v
|
||||
~~~
|
||||
|
||||
The older `tools/wp-cli-visual-fixtures.php`, widget golden file, and broad page
|
||||
matrix remain dedicated to non-article component regression tests and are not
|
||||
the truth source for this replacement.
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
<?php
|
||||
/**
|
||||
* Theme-neutral article fixtures shared by the Zibll and AKSRT visual sites.
|
||||
*
|
||||
* Usage: wp eval-file /visual-fixtures/article-fixtures.php create|cleanup
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!defined('WP_CLI') || !WP_CLI) {
|
||||
return;
|
||||
}
|
||||
|
||||
$action = sanitize_key((string) ($args[0] ?? ''));
|
||||
$manifest_key = 'zibll_article_visual_fixture_v1';
|
||||
$prefix = 'zibll_article_v1_';
|
||||
|
||||
if (!in_array($action, ['create', 'cleanup'], true)) {
|
||||
WP_CLI::error('Expected create or cleanup.');
|
||||
}
|
||||
|
||||
$cleanup = static function (array $manifest) use ($manifest_key): void {
|
||||
require_once ABSPATH . 'wp-admin/includes/user.php';
|
||||
foreach (array_reverse((array) ($manifest['posts'] ?? [])) as $post_id) {
|
||||
unstick_post((int) $post_id);
|
||||
wp_delete_post((int) $post_id, true);
|
||||
}
|
||||
foreach (array_reverse((array) ($manifest['attachments'] ?? [])) as $attachment_id) {
|
||||
wp_delete_attachment((int) $attachment_id, true);
|
||||
}
|
||||
$upload = wp_upload_dir();
|
||||
$upload_root = wp_normalize_path((string) ($upload['basedir'] ?? ''));
|
||||
foreach (array_reverse((array) ($manifest['files'] ?? [])) as $file) {
|
||||
$file = wp_normalize_path((string) $file);
|
||||
if ($upload_root !== '' && str_starts_with($file, trailingslashit($upload_root)) && is_file($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
foreach (array_reverse((array) ($manifest['terms'] ?? [])) as $term) {
|
||||
wp_delete_term((int) $term['id'], (string) $term['taxonomy']);
|
||||
}
|
||||
foreach (array_reverse((array) ($manifest['users'] ?? [])) as $user_id) {
|
||||
wp_delete_user((int) $user_id);
|
||||
}
|
||||
foreach ((array) ($manifest['options'] ?? []) as $name => $state) {
|
||||
if (!empty($state['exists'])) {
|
||||
update_option((string) $name, $state['value'], false);
|
||||
} else {
|
||||
delete_option((string) $name);
|
||||
}
|
||||
}
|
||||
delete_option($manifest_key);
|
||||
};
|
||||
|
||||
$existing = get_option($manifest_key, []);
|
||||
if ($action === 'cleanup') {
|
||||
if (!is_array($existing) || !$existing) {
|
||||
WP_CLI::success('No article visual fixtures found.');
|
||||
return;
|
||||
}
|
||||
$cleanup($existing);
|
||||
WP_CLI::success('Article visual fixtures removed.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($existing) && $existing) {
|
||||
WP_CLI::error('Fixtures already exist. Run cleanup first.');
|
||||
}
|
||||
|
||||
$manifest = [
|
||||
'created_at' => gmdate('c'),
|
||||
'users' => [],
|
||||
'terms' => [],
|
||||
'attachments' => [],
|
||||
'posts' => [],
|
||||
'files' => [],
|
||||
'options' => [],
|
||||
];
|
||||
foreach (['aksrt_settings', 'zibll_options'] as $option_name) {
|
||||
$manifest['options'][$option_name] = [
|
||||
'exists' => get_option($option_name, null) !== null,
|
||||
'value' => get_option($option_name),
|
||||
];
|
||||
}
|
||||
update_option($manifest_key, $manifest, false);
|
||||
|
||||
try {
|
||||
$visual_options = [
|
||||
'list_type' => 'thumb',
|
||||
'list_show_type' => 'separate',
|
||||
'list_list_option' => ['style' => 'null', 'img_position' => 'left', 'scale' => 70],
|
||||
'list_card_option' => ['style' => 'null', 'scale' => 70],
|
||||
'post_list_author' => true,
|
||||
'post_list_time' => true,
|
||||
'post_time_source' => 'modified',
|
||||
'list_meta_show' => 'like',
|
||||
'list_badge_show' => ['pay', 'cat', 'tag'],
|
||||
'list_thumb_slides_s' => true,
|
||||
'list_thumb_video_s' => true,
|
||||
'list_thumb_video_mute_s' => true,
|
||||
'thumb_postfirstimg_s' => true,
|
||||
'thumb_catimg_s' => true,
|
||||
'list_thumb_fit' => '',
|
||||
'paging_ajax_s' => '1',
|
||||
'paging_ajax_ias_s' => true,
|
||||
'ias_max' => 3,
|
||||
'post_related_s' => true,
|
||||
'post_related_type' => 'img',
|
||||
'post_related_n' => 6,
|
||||
'post_related_orderby' => 'views',
|
||||
'related_title' => '相关推荐',
|
||||
];
|
||||
foreach (['aksrt_settings', 'zibll_options'] as $option_name) {
|
||||
$current = get_option($option_name, []);
|
||||
update_option($option_name, array_merge(is_array($current) ? $current : [], $visual_options), false);
|
||||
}
|
||||
|
||||
$authors = [
|
||||
['login' => $prefix . 'author_a', 'name' => '视觉作者甲'],
|
||||
['login' => $prefix . 'author_b', 'name' => '视觉作者乙'],
|
||||
];
|
||||
$author_ids = [];
|
||||
foreach ($authors as $author) {
|
||||
$user_id = wp_insert_user([
|
||||
'user_login' => $author['login'],
|
||||
'user_pass' => 'AKSRT-Visual-2026!',
|
||||
'user_email' => $author['login'] . '@example.test',
|
||||
'display_name' => $author['name'],
|
||||
'description' => '固定作者简介,用于文章卡片视觉对比。',
|
||||
'role' => 'author',
|
||||
]);
|
||||
if (is_wp_error($user_id)) {
|
||||
throw new RuntimeException($user_id->get_error_message());
|
||||
}
|
||||
$author_ids[] = (int) $user_id;
|
||||
$manifest['users'][] = (int) $user_id;
|
||||
}
|
||||
|
||||
$category = wp_insert_term('视觉文章', 'category', ['slug' => 'zibll-article-fixture']);
|
||||
$tag = wp_insert_term('视觉标签', 'post_tag', ['slug' => 'zibll-visual-tag']);
|
||||
if (is_wp_error($category) || is_wp_error($tag)) {
|
||||
throw new RuntimeException('Unable to create article fixture terms.');
|
||||
}
|
||||
$category_id = (int) $category['term_id'];
|
||||
$tag_id = (int) $tag['term_id'];
|
||||
$manifest['terms'][] = ['id' => $category_id, 'taxonomy' => 'category'];
|
||||
$manifest['terms'][] = ['id' => $tag_id, 'taxonomy' => 'post_tag'];
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
$upload = wp_upload_dir();
|
||||
if (!empty($upload['error'])) {
|
||||
throw new RuntimeException((string) $upload['error']);
|
||||
}
|
||||
$attachment_ids = [];
|
||||
$colors = [
|
||||
[240, 68, 148],
|
||||
[58, 134, 255],
|
||||
[92, 191, 147],
|
||||
[255, 175, 56],
|
||||
[126, 87, 194],
|
||||
];
|
||||
foreach ($colors as $index => $rgb) {
|
||||
$filename = $prefix . 'image-' . ($index + 1) . '.jpg';
|
||||
$filepath = trailingslashit($upload['path']) . $filename;
|
||||
if (function_exists('imagecreatetruecolor')) {
|
||||
$image = imagecreatetruecolor(1200, 800);
|
||||
$background = imagecolorallocate($image, $rgb[0], $rgb[1], $rgb[2]);
|
||||
$foreground = imagecolorallocate($image, 255, 255, 255);
|
||||
imagefill($image, 0, 0, $background);
|
||||
imagestring($image, 5, 48, 48, 'Zibll 9.0 Article Fixture ' . ($index + 1), $foreground);
|
||||
imagejpeg($image, $filepath, 92);
|
||||
imagedestroy($image);
|
||||
} else {
|
||||
$pixel = base64_decode('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAP//////////////////////////////////////////////////////////////////////////////////////2wBDAf//////////////////////////////////////////////////////////////////////////////////////wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAX/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAEf/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPwF//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPwF//8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQAGPwJ//8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQABPyF//9oADAMBAAIAAwAAABAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAwEBPxB//8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAgBAgEBPxB//8QAFBABAAAAAAAAAAAAAAAAAAAAAP/aAAgBAQABPxB//9k=', true);
|
||||
file_put_contents($filepath, $pixel);
|
||||
}
|
||||
$attachment_id = wp_insert_attachment([
|
||||
'post_mime_type' => 'image/jpeg',
|
||||
'post_title' => '视觉图片 ' . ($index + 1),
|
||||
'post_status' => 'inherit',
|
||||
], $filepath);
|
||||
if (is_wp_error($attachment_id)) {
|
||||
throw new RuntimeException($attachment_id->get_error_message());
|
||||
}
|
||||
$attachment_id = (int) $attachment_id;
|
||||
wp_update_attachment_metadata($attachment_id, wp_generate_attachment_metadata($attachment_id, $filepath));
|
||||
$attachment_ids[] = $attachment_id;
|
||||
$manifest['attachments'][] = $attachment_id;
|
||||
}
|
||||
|
||||
$image_urls = array_map(static fn(int $id): string => (string) wp_get_attachment_image_url($id, 'full'), $attachment_ids);
|
||||
$video_path = trailingslashit($upload['path']) . $prefix . 'fixture-video.mp4';
|
||||
file_put_contents($video_path, '');
|
||||
$manifest['files'][] = $video_path;
|
||||
$video_url = trailingslashit($upload['url']) . basename($video_path);
|
||||
$term_other = (array) get_term_meta($category_id, 'zib_other_data', true);
|
||||
$term_other['cover_image'] = $image_urls[4];
|
||||
update_term_meta($category_id, 'zib_other_data', $term_other);
|
||||
update_term_meta($category_id, 'cover_image', $image_urls[4]);
|
||||
update_term_meta($category_id, 'aksrt_category_cover_id', $attachment_ids[4]);
|
||||
|
||||
$scenarios = [
|
||||
['slug' => 'featured', 'title' => '特色图文章:标准列表与卡片基线', 'featured' => 0],
|
||||
['slug' => 'no-image', 'title' => '无图长标题文章用于检查纯文字模式与两行截断', 'no_image' => true],
|
||||
['slug' => 'multi', 'title' => '多图文章:四张真实内容图片', 'featured' => 1, 'gallery' => true],
|
||||
['slug' => 'external', 'title' => '自定义外链封面文章', 'external' => 2],
|
||||
['slug' => 'slides', 'title' => '幻灯片封面文章', 'featured' => 3, 'slides' => true],
|
||||
['slug' => 'video', 'title' => '视频悬停封面文章', 'featured' => 4, 'video' => true],
|
||||
['slug' => 'paid', 'title' => '付费阅读文章价格徽章', 'featured' => 0, 'pay' => 'reading'],
|
||||
['slug' => 'vip', 'title' => '会员专属文章 VIP 徽章', 'featured' => 1, 'pay' => 'vip'],
|
||||
['slug' => 'first-image', 'title' => '文章首图作为缩略图', 'first_image' => 3],
|
||||
];
|
||||
foreach ($scenarios as $index => $scenario) {
|
||||
$content = '<p>固定摘要正文,用于 Zibll 与 AKSRT 的文章列表逐像素比较。</p>';
|
||||
if (!empty($scenario['gallery'])) {
|
||||
$content .= implode('', array_map(static fn(string $url): string => '<img src="' . esc_url($url) . '" alt="">', array_slice($image_urls, 0, 4)));
|
||||
} elseif (isset($scenario['first_image'])) {
|
||||
$content .= '<img src="' . esc_url($image_urls[(int) $scenario['first_image']]) . '" alt="">';
|
||||
}
|
||||
$post_id = wp_insert_post([
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish',
|
||||
'post_author' => $author_ids[$index % 2],
|
||||
'post_title' => $scenario['title'],
|
||||
'post_name' => $prefix . $scenario['slug'],
|
||||
'post_excerpt' => '固定文章摘要用于检查字号、行高、留白和截断。',
|
||||
'post_content' => $content,
|
||||
'post_date' => gmdate('Y-m-d H:i:s', strtotime('2026-07-01 08:00:00') + ($index * DAY_IN_SECONDS)),
|
||||
'post_date_gmt' => gmdate('Y-m-d H:i:s', strtotime('2026-07-01 00:00:00') + ($index * DAY_IN_SECONDS)),
|
||||
], true);
|
||||
if (is_wp_error($post_id)) {
|
||||
throw new RuntimeException($post_id->get_error_message());
|
||||
}
|
||||
$post_id = (int) $post_id;
|
||||
$manifest['posts'][] = $post_id;
|
||||
wp_set_post_terms($post_id, [$category_id], 'category');
|
||||
wp_set_post_terms($post_id, [$tag_id], 'post_tag');
|
||||
if (isset($scenario['featured'])) {
|
||||
set_post_thumbnail($post_id, $attachment_ids[(int) $scenario['featured']]);
|
||||
}
|
||||
if (!empty($scenario['gallery'])) {
|
||||
set_post_format($post_id, 'gallery');
|
||||
}
|
||||
|
||||
$post_meta = [
|
||||
'subtitle' => ' · 固定副标题',
|
||||
];
|
||||
$zib_meta = (array) get_post_meta($post_id, 'zib_other_data', true);
|
||||
$zib_meta['subtitle'] = $post_meta['subtitle'];
|
||||
if (isset($scenario['external'])) {
|
||||
$post_meta['thumbnail_url'] = $image_urls[(int) $scenario['external']];
|
||||
$zib_meta['thumbnail_url'] = $post_meta['thumbnail_url'];
|
||||
}
|
||||
if (!empty($scenario['slides'])) {
|
||||
$post_meta['featured_slide'] = implode(',', array_slice($attachment_ids, 0, 4));
|
||||
$zib_meta['featured_slide'] = $post_meta['featured_slide'];
|
||||
}
|
||||
if (!empty($scenario['video'])) {
|
||||
$post_meta['featured_video'] = $video_url;
|
||||
$zib_meta['featured_video'] = $video_url;
|
||||
}
|
||||
$zib_meta['views'] = 1200 + ($index * 137);
|
||||
$zib_meta['like'] = 30 + ($index * 7);
|
||||
update_post_meta($post_id, 'zib_other_data', $zib_meta);
|
||||
update_post_meta($post_id, 'aksrt_post_meta', $post_meta);
|
||||
update_post_meta($post_id, 'aksrt_post_views', $zib_meta['views']);
|
||||
update_post_meta($post_id, '_aksrt_like_count', $zib_meta['like']);
|
||||
update_post_meta($post_id, '_aksrt_favorite_count', 10 + $index);
|
||||
|
||||
$pay_type = (string) ($scenario['pay'] ?? 'no');
|
||||
$pay_limit = $pay_type === 'vip' ? 2 : 0;
|
||||
$pay_price = $pay_type === 'reading' ? 19.9 : 0;
|
||||
update_post_meta($post_id, '_aksrt_pay', [
|
||||
'pay_type' => $pay_type,
|
||||
'pay_modo' => '0',
|
||||
'price' => $pay_price,
|
||||
'pay_limit' => $pay_limit,
|
||||
]);
|
||||
update_post_meta($post_id, 'posts_zibpay', [
|
||||
'pay_type' => $pay_type,
|
||||
'pay_modo' => '0',
|
||||
'pay_price' => $pay_price,
|
||||
'pay_limit' => $pay_limit,
|
||||
]);
|
||||
}
|
||||
if ($manifest['posts']) {
|
||||
stick_post((int) $manifest['posts'][0]);
|
||||
}
|
||||
update_option($manifest_key, $manifest, false);
|
||||
WP_CLI::success('Created identical Zibll/AKSRT article fixtures.');
|
||||
} catch (Throwable $error) {
|
||||
$cleanup($manifest);
|
||||
WP_CLI::error('Fixture creation rolled back: ' . $error->getMessage());
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"schema": "aksrt.zibll-article-visual-matrix.v1",
|
||||
"reference": "https://localhost:9443",
|
||||
"candidate": "https://localhost",
|
||||
"fixture": "/visual-fixtures/article-fixtures.php",
|
||||
"viewports": [
|
||||
{ "id": "desktop-wide", "width": 1440, "height": 1100 },
|
||||
{ "id": "desktop", "width": 1024, "height": 1000 },
|
||||
{ "id": "tablet", "width": 768, "height": 1000 },
|
||||
{ "id": "breakpoint-767", "width": 767, "height": 1000 },
|
||||
{ "id": "breakpoint-641", "width": 641, "height": 960 },
|
||||
{ "id": "breakpoint-640", "width": 640, "height": 960 },
|
||||
{ "id": "mobile", "width": 390, "height": 844 }
|
||||
],
|
||||
"colorSchemes": ["light", "dark"],
|
||||
"layouts": ["sidebar", "no-sidebar"],
|
||||
"listModes": ["thumb", "text", "thumb_if_has", "card"],
|
||||
"styles": ["default", "style2", "style3"],
|
||||
"routes": [
|
||||
{ "id": "home", "path": "/", "states": ["default", "hover", "loading", "error"] },
|
||||
{ "id": "archive", "path": "/?post_type=post", "states": ["default", "numbered", "load-more", "infinite", "no-more"] },
|
||||
{ "id": "category", "path": "/category/zibll-article-fixture/", "states": ["default", "empty"] },
|
||||
{ "id": "tag", "path": "/tag/zibll-visual-tag/", "states": ["default", "empty"] },
|
||||
{ "id": "search", "path": "/?s=视觉", "states": ["default", "empty"] },
|
||||
{ "id": "author-a", "path": "/author/zibll_article_v1_author_a/", "states": ["default", "numbered", "load-more"] },
|
||||
{ "id": "single-related", "path": "/zibll_article_v1_featured/", "states": ["img", "list", "text"] }
|
||||
],
|
||||
"postScenarios": ["featured", "no-image", "multi", "external", "slides", "video", "paid", "vip", "first-image"],
|
||||
"capture": {
|
||||
"selector": ".posts-row, .profile-list, .relates",
|
||||
"artifacts": ["screenshot", "dom", "computed-style", "bounding-box", "console", "network"],
|
||||
"computedProperties": [
|
||||
"display", "position", "width", "height", "margin", "padding", "gap", "font-size", "line-height",
|
||||
"border-radius", "box-shadow", "background-color", "color", "object-fit"
|
||||
]
|
||||
},
|
||||
"acceptance": {
|
||||
"dimensionDeltaPxMax": 1,
|
||||
"pixelDifferencePercentMax": 1.5,
|
||||
"consoleErrorsMax": 0,
|
||||
"unexpectedNetworkFailuresMax": 0,
|
||||
"a11yCriticalMax": 0,
|
||||
"a11ySeriousMax": 0
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,10 @@ services:
|
||||
source: ${ZIBLL_THEME_PATH}
|
||||
target: /var/www/html/wp-content/themes/zibll
|
||||
read_only: true
|
||||
- type: bind
|
||||
source: .
|
||||
target: /visual-fixtures
|
||||
read_only: true
|
||||
|
||||
caddy:
|
||||
image: caddy:2.8-alpine
|
||||
@@ -62,6 +66,10 @@ services:
|
||||
source: ${ZIBLL_THEME_PATH}
|
||||
target: /var/www/html/wp-content/themes/zibll
|
||||
read_only: true
|
||||
- type: bind
|
||||
source: .
|
||||
target: /visual-fixtures
|
||||
read_only: true
|
||||
entrypoint: ["wp"]
|
||||
|
||||
volumes:
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"schema": "aksrt.zibll-article-baseline.v1",
|
||||
"referencePath": "C:\\Users\\Xing\\Desktop\\zibll",
|
||||
"theme": "Zibll",
|
||||
"version": "9.0",
|
||||
"capturedAt": "2026-08-18",
|
||||
"files": {
|
||||
"style.css": {
|
||||
"bytes": 927,
|
||||
"sha256": "4e9e319d92cea3862aefd520d5519b81ea22f9147b203b77eafedd0447148aea"
|
||||
},
|
||||
"css/main.css": {
|
||||
"bytes": 292331,
|
||||
"sha256": "87ff1aeaf78369934c875422ab3ebc13ad65f30de78f6caabf091c780a27a158"
|
||||
},
|
||||
"inc/functions/zib-posts-list.php": {
|
||||
"bytes": 34255,
|
||||
"sha256": "ced813182c0b0fc5847ca5c04a57fa4379581ace13a6d40dfb7dfabb55e13ae4"
|
||||
},
|
||||
"inc/options/admin-options.php": {
|
||||
"bytes": 700302,
|
||||
"sha256": "3d2cf89bc01a1ec98297d16c14023a820170568e716daedf421fd0386b38486b"
|
||||
},
|
||||
"js/main.min.js": {
|
||||
"bytes": 74446,
|
||||
"sha256": "0fdd02246a5b68480d11ced1dfd2bfa19788fef16ba069eb021fcfb5cfaf60f9"
|
||||
},
|
||||
"js/libs/grade.min.js": {
|
||||
"bytes": 4833,
|
||||
"sha256": "8d74bf6ab34f4c44203766cc639818c4daf0a7c1978ddefb4ebfde9daaa16040"
|
||||
}
|
||||
},
|
||||
"excluded": [
|
||||
"topics taxonomy",
|
||||
"single article body",
|
||||
"comments",
|
||||
"header and footer"
|
||||
]
|
||||
}
|
||||
@@ -7,79 +7,258 @@ const test = require('node:test');
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
||||
const join = (files) => files.map(read).join('\n');
|
||||
|
||||
test('post list DOM follows the Zibll flex and multi-image contract', () => {
|
||||
const articleFiles = [
|
||||
'src/Settings/PostDisplay.php',
|
||||
'src/Admin/Schema/PostList/SchemaPostListList.php',
|
||||
'src/Admin/Schema/SchemaPostList.php',
|
||||
'assets/admin/src/schema/sections/post-list/list.js',
|
||||
'assets/admin/src/schema/sections/post-list/thumb.js',
|
||||
'assets/admin/src/schema/sections/post-list/page.js',
|
||||
'inc/helpers/posts-renderer/config.php',
|
||||
'inc/helpers/posts-renderer/post-data.php',
|
||||
'inc/helpers/posts-renderer/markup.php',
|
||||
'inc/helpers/aksrt-archive.php',
|
||||
'inc/helpers/aksrt-single-render.php',
|
||||
];
|
||||
|
||||
test('the article stream exposes only the new typed renderer contract', () => {
|
||||
const markup = read('inc/helpers/posts-renderer/markup.php');
|
||||
const consumers = join([
|
||||
'index.php',
|
||||
'category.php',
|
||||
'tag.php',
|
||||
'search.php',
|
||||
'archive-resources.php',
|
||||
'src/Admin/Admin.php',
|
||||
'src/Admin/GlobalController.php',
|
||||
'src/Core/Shortcodes.php',
|
||||
'src/WidgetSystem/PostRenderer.php',
|
||||
'inc/helpers/homepage/content.php',
|
||||
'templates/parts/user-home/panels-core.php',
|
||||
]);
|
||||
|
||||
assert.match(markup, /function aksrt_render_post_list\(array \$args = \[\], \?WP_Query \$query = null, bool \$echo = true\): string/);
|
||||
assert.doesNotMatch(consumers, /function_exists\(['"]aksrt_render_post_list/);
|
||||
assert.doesNotMatch(consumers, /aksrt_render_post_list\(\s*\$query\s*,/);
|
||||
assert.doesNotMatch(consumers, /content-post-card|aksrt_homepage_render_post_card/);
|
||||
});
|
||||
|
||||
test('settings use Zibll list modes, grouped options, and destructive related keys', () => {
|
||||
const source = join(articleFiles);
|
||||
const listSchema = read('assets/admin/src/schema/sections/post-list/list.js');
|
||||
const pageSchema = read('assets/admin/src/schema/sections/post-list/page.js');
|
||||
const legacyKeys = [
|
||||
'post_card_style',
|
||||
'list_list_style',
|
||||
'list_card_style',
|
||||
'grid-cms',
|
||||
'large_thumb',
|
||||
'multi_thumb',
|
||||
'layout_override',
|
||||
'homepage_card_style',
|
||||
'homepage_multi_thumb',
|
||||
'homepage_default_view',
|
||||
'post_related_enabled',
|
||||
'post_related_count',
|
||||
'post_related_style',
|
||||
'post_related_source',
|
||||
'post_related_title',
|
||||
];
|
||||
|
||||
assert.match(listSchema, /list_type: 'thumb'/);
|
||||
for (const value of ['text', 'thumb', 'thumb_if_has', 'card']) {
|
||||
assert.match(listSchema, new RegExp(`value: '${value}'`));
|
||||
}
|
||||
assert.match(listSchema, /list_list_option: \{ style: 'null', img_position: 'left', scale: 70 \}/);
|
||||
assert.match(listSchema, /list_card_option: \{ style: 'null', scale: 70 \}/);
|
||||
assert.match(pageSchema, /post_related_s: true/);
|
||||
assert.match(pageSchema, /post_related_type: 'img'/);
|
||||
assert.match(pageSchema, /related_title: '相关推荐'/);
|
||||
assert.match(pageSchema, /post_related_n: 6/);
|
||||
assert.match(pageSchema, /post_related_orderby: 'views'/);
|
||||
for (const key of legacyKeys) {
|
||||
assert.equal(source.includes(key), false, `legacy article key remains: ${key}`);
|
||||
}
|
||||
assert.doesNotMatch(source, /list_card_topics|is_topics|\btopics\b/);
|
||||
});
|
||||
|
||||
test('forced mode wins and thumb_if_has ignores spare and lazy placeholders', () => {
|
||||
const config = read('inc/helpers/posts-renderer/config.php');
|
||||
const data = read('inc/helpers/posts-renderer/post-data.php');
|
||||
|
||||
const forced = config.indexOf("$is_forced = in_array($forced_type, ['list', 'card'], true)");
|
||||
const globalCard = config.indexOf("$list_type === 'card'");
|
||||
const contextCard = config.indexOf("$list['list_card_tag']");
|
||||
const categoryCard = config.indexOf("$list['list_card_cat']");
|
||||
assert.ok(forced >= 0 && forced < globalCard && globalCard < contextCard && contextCard < categoryCard);
|
||||
assert.match(config, /\$is_card = \$forced_type === 'card' \|\| \(!\$is_forced/);
|
||||
|
||||
const hasReal = config.indexOf("$has_real = $primary !== '';");
|
||||
const spareCall = config.lastIndexOf('aksrt_renderer_spare_image($thumb)');
|
||||
const lazy = config.lastIndexOf('aksrt_get_lazy_thumb');
|
||||
assert.ok(hasReal >= 0 && hasReal < spareCall && spareCall < lazy);
|
||||
assert.match(data, /'thumb_if_has' && empty\(\$images\['has_real'\]\)/);
|
||||
assert.match(data, /count\(\$gallery\) > 2/);
|
||||
assert.match(data, /has_post_format\(\['image', 'gallery'\]/);
|
||||
});
|
||||
|
||||
test('image resolution counts only content images and applies the configured WordPress size', () => {
|
||||
const config = read('inc/helpers/posts-renderer/config.php');
|
||||
const data = read('inc/helpers/posts-renderer/post-data.php');
|
||||
const thumbSchema = read('assets/admin/src/schema/sections/post-list/thumb.js');
|
||||
const phpSchema = read('src/Admin/Schema/SchemaPostList.php');
|
||||
|
||||
assert.match(config, /function aksrt_renderer_content_images\(int \$post_id, string \$size\)/);
|
||||
assert.match(config, /strip_shortcodes\(\(string\) get_post_field\('post_content'/);
|
||||
assert.match(config, /\$slides = aksrt_renderer_curated_images\(\$post_id, \$size\);\s*\$gallery = aksrt_renderer_content_images\(\$post_id, \$size\);/);
|
||||
assert.match(config, /get_post_thumbnail_id\(\$post_id\).*aksrt_renderer_sized_image\(\(string\) \$thumbnail_id, \$size\)/s);
|
||||
assert.match(config, /aksrt_renderer_category_image\(\$post_id, \$size\)/);
|
||||
assert.doesNotMatch(config, /aksrt_get_post_gallery_images|cover_images|featured_video_episode|_aksrt_featured_video|_video_url|_aksrt_thumbnail_url|_thumbnail_url/);
|
||||
assert.doesNotMatch(config, /\['aksrt_category_cover_id',/);
|
||||
assert.match(data, /'gallery_count'\s*=>\s*count\(\$content_images\)/);
|
||||
assert.match(data, /\(int\) \$data\['gallery_count'\] - 4/);
|
||||
assert.match(thumbSchema, /spareThumbnailDefault = \[\{ img: `\$\{themeRoot\}\/assets\/img\/thumbnail\.svg` \}\]/);
|
||||
assert.match(phpSchema, /'spare_thumbnail'.*'default' => \[\['img' => get_template_directory_uri\(\) \. '\/assets\/img\/thumbnail\.svg'\]\]/);
|
||||
});
|
||||
|
||||
test('list, card, media, badge and Mini DOM follow dedicated Zibll structures', () => {
|
||||
const markup = read('inc/helpers/posts-renderer/markup.php');
|
||||
const data = read('inc/helpers/posts-renderer/post-data.php');
|
||||
const cardStart = markup.indexOf('function aksrt_renderer_card');
|
||||
const miniStart = markup.indexOf('function aksrt_renderer_mini');
|
||||
const card = markup.slice(cardStart, miniStart);
|
||||
const card = markup.slice(markup.indexOf('function aksrt_renderer_card'), markup.indexOf('function aksrt_renderer_mini'));
|
||||
const mini = markup.slice(markup.indexOf('function aksrt_renderer_mini'), markup.indexOf('function aksrt_render_post'));
|
||||
|
||||
assert.match(markup, /\['posts-item', 'list', 'ajax-item', 'flex'/);
|
||||
assert.match(markup, /if \(!empty\(\$data\['is_mult_thumb'\]\)\)[\s\S]*?\$thumb = '';/);
|
||||
assert.doesNotMatch(card, /item-excerpt|renderer_excerpt_markup/);
|
||||
assert.match(data, /&& \$cfg\['mode'\] === 'list'/);
|
||||
assert.match(data, /<a class=\"thumb-items contain\"/);
|
||||
assert.match(markup, /\['posts-item', 'list', 'ajax-item'\]/);
|
||||
assert.match(markup, /\$classes\[\] = .*'flex xx'.*'flex'/s);
|
||||
assert.match(markup, /<posts class=/);
|
||||
assert.match(markup, /<div class="post-graphic/);
|
||||
assert.match(markup, /<div class="item-body flex xx flex1 jsb/);
|
||||
assert.doesNotMatch(card, /item-excerpt|renderer_excerpt_markup|thumb-items/);
|
||||
assert.match(data, /<div class="item-thumbnail/);
|
||||
assert.match(data, /relative zib-slider.*new-swiper item-thumbnail/s);
|
||||
assert.match(data, /swiper-slide.*gradient-bg.*data-opacity="0\.2"/s);
|
||||
assert.match(data, /\$fit = \$is_contain && !\$has_slides \? ' contain gradient-bg' : ''/);
|
||||
assert.match(data, /video-thumb-box.*data-post-thumb-video/s);
|
||||
assert.match(data, /class="thumb-items/);
|
||||
assert.match(data, /empty\(\$cfg\['is_category'\]\).*in_array\('cat'/s);
|
||||
assert.match(data, /empty\(\$cfg\['is_tag'\]\).*in_array\('tag'/s);
|
||||
assert.doesNotMatch(data, /meta-mobile-show/);
|
||||
|
||||
assert.match(mini, /<div class="mr10"><div class="item-thumbnail"><a/);
|
||||
assert.match(mini, /posts-mini-con flex xx flex1 jsb/);
|
||||
assert.match(mini, /\['c-red', 'c-yellow', 'c-purple', 'c-blue', 'c-green'\]/);
|
||||
assert.match(mini, /aksrt_renderer_pay_badge\(\$data, true\)/);
|
||||
assert.match(data, /meta-pay badg badg-sm mr6/);
|
||||
assert.doesNotMatch(mini, /posts-mini-row/);
|
||||
|
||||
assert.doesNotMatch(markup, /--posts-(?:list|card)-scale|<posts[^>]+style=/);
|
||||
assert.match(data, /\['c-blue', 'c-yellow', 'c-green', 'c-purple', 'c-red'\]/);
|
||||
assert.match(data, /查看更多分类文章/);
|
||||
assert.match(data, /usort\(\$tags,.*->count.*->count/s);
|
||||
assert.match(data, /查看此标签更多文章/);
|
||||
|
||||
const commentMeta = data.indexOf("aksrt_renderer_svg_icon('comment')");
|
||||
const viewMeta = data.indexOf("aksrt_renderer_svg_icon('view')", commentMeta);
|
||||
const likeMeta = data.indexOf("aksrt_renderer_svg_icon('like')", viewMeta);
|
||||
assert.ok(commentMeta >= 0 && commentMeta < viewMeta && viewMeta < likeMeta);
|
||||
assert.match(data, /comments_open.*close_comments/s);
|
||||
assert.match(data, /show_like.*post_type.*=== 'post'/s);
|
||||
assert.match(data, /<use xlink:href="#icon-/);
|
||||
});
|
||||
|
||||
test('homepage card mode keeps the Zibll inline-block three-column flow', () => {
|
||||
const css = read('assets/css/frontend/homepage-fixed/base-2.css');
|
||||
const responsive = read('assets/css/frontend/homepage-fixed/ajax-tab-error-state.css');
|
||||
const homepageScript = read('assets/js/homepage-fixed.js');
|
||||
const scripts = read('src/Core/ScriptsPart1b.php');
|
||||
const cardModeStart = css.indexOf('.aksrt-homepage__posts[data-view="card"] {');
|
||||
const cardItemStart = css.indexOf('.aksrt-homepage__posts[data-view="card"] > .posts-item {');
|
||||
const cardMode = css.slice(cardModeStart, cardItemStart);
|
||||
const cardItem = css.slice(cardItemStart, css.indexOf('\n}', cardItemStart) + 2);
|
||||
const visibilityStart = css.indexOf('VISIBILITY LOCK');
|
||||
const visibilityEnd = css.indexOf('/* Minimal flex utilities', visibilityStart);
|
||||
const visibility = css.slice(visibilityStart, visibilityEnd);
|
||||
test('post-card CSS owns the exact desktop and 767/640 responsive matrix', () => {
|
||||
const css = read('assets/css/frontend/post-card.css');
|
||||
const mobile767 = css.slice(css.indexOf('@media (max-width: 767px)'), css.indexOf('@media (max-width: 640px)'));
|
||||
const mobile640 = css.slice(css.indexOf('@media (max-width: 640px)'));
|
||||
|
||||
assert.match(cardMode, /display:\s*block/);
|
||||
assert.match(cardMode, /font-size:\s*0/);
|
||||
assert.match(cardItem, /width:\s*calc\(33\.333% - 16px\)/);
|
||||
assert.match(cardItem, /display:\s*inline-block/);
|
||||
assert.doesNotMatch(visibility, /\.posts-item[\s\S]*?display:\s*block\s*!important/);
|
||||
assert.match(scripts, /\$homepage_style_parts\s*=\s*\[/);
|
||||
assert.match(scripts, /filemtime\(\$part_path\)/);
|
||||
assert.doesNotMatch(scripts, /wp_enqueue_style\(\s*'aksrt-homepage-fixed',\s*\$base_uri\s*\.\s*'\/assets\/css\/frontend\/homepage-fixed\.css'/);
|
||||
|
||||
const tabletStart = responsive.indexOf('@media (max-width: 991.98px)');
|
||||
const mobileStart = responsive.indexOf('@media (max-width: 767px)');
|
||||
const smallMobileStart = responsive.indexOf('@media (max-width: 640px)');
|
||||
const tablet = responsive.slice(tabletStart, mobileStart);
|
||||
const mobile = responsive.slice(mobileStart, smallMobileStart);
|
||||
const smallMobile = responsive.slice(smallMobileStart);
|
||||
|
||||
assert.doesNotMatch(tablet, /data-view="card"/);
|
||||
assert.match(mobile, /data-view="card"[\s\S]*?width:\s*calc\(50% - 10px\)/);
|
||||
assert.match(mobile, /data-view="card"[\s\S]*?margin:\s*-5px/);
|
||||
assert.doesNotMatch(smallMobile, /data-view="card"[\s\S]*?width:\s*100%/);
|
||||
|
||||
assert.match(homepageScript, /var initialMode = getViewMode\(\)/);
|
||||
assert.match(homepageScript, /var renderedMode = activePanel \? activePanel\.getAttribute\('data-view'\)/);
|
||||
assert.match(homepageScript, /renderedMode !== initialMode[\s\S]*?requestHomepagePanel\(activePanel/);
|
||||
assert.match(css, /\.posts-row\s*\{[^}]*margin-right:\s*-8px;[^}]*margin-left:\s*-8px;/s);
|
||||
assert.match(css, /\.posts-item\.card\s*\{[^}]*width:\s*calc\(33\.333% - 16px\)/s);
|
||||
assert.match(css, /\.fluid-widget-wrap \.posts-item\.card,[\s\S]*?\.site-layout-1 \.posts-item\.card\s*\{[^}]*width:\s*calc\(25% - 16px\)/);
|
||||
assert.match(css, /\.site-layout-1 \.posts-item:not\(\.card\)\s*\{[^}]*width:\s*calc\(50% - 16px\)/s);
|
||||
assert.match(mobile767, /\.posts-item\.card\s*\{[^}]*width:\s*calc\(50% - 10px\)/s);
|
||||
assert.doesNotMatch(mobile767, /\.posts-mini\s*\{[^}]*width:\s*100%/s);
|
||||
assert.match(mobile640, /\.posts-mini\s*\{[^}]*width:\s*100%/s);
|
||||
assert.match(mobile640, /\.posts-item:not\(\.no-thumb\) \.meta-right item\s*\{[^}]*display:\s*none/s);
|
||||
assert.doesNotMatch(css, /\.aksrt-|post-card-cms|grid-cms/);
|
||||
});
|
||||
|
||||
test('site shell has one float owner and fluid zones sit outside main', () => {
|
||||
const layout = read('assets/css/frontend/layout.css');
|
||||
const archive = read('inc/helpers/aksrt-archive.php');
|
||||
const shell = layout.slice(layout.indexOf('Site shell'), layout.indexOf('页面标题区'));
|
||||
test('related posts, author page and widgets use their dedicated renderers', () => {
|
||||
const related = read('inc/helpers/aksrt-single-render.php');
|
||||
const relatedCard = read('inc/helpers/aksrt-single-components.php');
|
||||
const resourceRelated = read('templates/parts/resource-related.php');
|
||||
const author = read('templates/parts/user-home/panels-core.php');
|
||||
const authorPosts = author.slice(author.indexOf("in_array('posts'"), author.indexOf("in_array('comments'"));
|
||||
const widgets = read('src/WidgetSystem/PostRenderer.php');
|
||||
|
||||
assert.doesNotMatch(shell, /display:\s*grid/);
|
||||
assert.match(shell, /width:\s*var\(--sidebar-width, 311px\)/);
|
||||
assert.match(shell, /calc\(var\(--sidebar-width, 311px\) \+ 15px\)/);
|
||||
assert.ok(archive.indexOf("$args['top_fluid']") < archive.indexOf('<main id="main-content"'));
|
||||
assert.ok(archive.lastIndexOf("$args['bottom_fluid']") > archive.indexOf('</main>'));
|
||||
assert.match(related, /\['img', 'list', 'text'\]/);
|
||||
assert.match(related, /aksrt_renderer_mini\(\$data, \$mini_cfg\)/);
|
||||
assert.match(related, /aksrt_render_related_graphic_card\(\$post\)/);
|
||||
assert.match(related, /<li><a class="icon-circle"/);
|
||||
assert.doesNotMatch(related, /topics|post_related_source/);
|
||||
assert.match(relatedCard, /aksrt_renderer_resolve_images/);
|
||||
assert.match(resourceRelated, /swiper-container swiper-scroll/);
|
||||
assert.match(resourceRelated, /aksrt_render_related_graphic_card/);
|
||||
assert.doesNotMatch(resourceRelated, /aksrt_render_post_list/);
|
||||
assert.match(authorPosts, /aksrt_render_post_list/);
|
||||
assert.match(authorPosts, /aksrt_render_pagination/);
|
||||
assert.match(authorPosts, /'page_var'\s*=>\s*'posts_page'/);
|
||||
assert.doesNotMatch(authorPosts, /aksrt_render_profile_pagination/);
|
||||
assert.match(widgets, /aksrt_render_mini_list/);
|
||||
assert.match(widgets, /swiper-container swiper-scroll/);
|
||||
});
|
||||
|
||||
test('widget shell uses Zibll wrappers without overriding post link colors', () => {
|
||||
const renderer = read('src/WidgetSystem/FrontendRenderer.php');
|
||||
const css = read('assets/widgets/frontend.css');
|
||||
test('AJAX pagination can recover, caps auto loading and rehydrates appended media', () => {
|
||||
const php = read('inc/helpers/template-tags/pagination-permissions.php');
|
||||
const admin = read('src/Admin/Admin.php');
|
||||
const js = read('assets/js/core/pagination.js');
|
||||
const media = read('assets/js/core/misc.js');
|
||||
|
||||
assert.match(renderer, /'zib-widget-wrap'/);
|
||||
assert.match(renderer, /\$classes\[\] = 'zib-widget'/);
|
||||
assert.match(renderer, /aksrt-widget__inner container/);
|
||||
assert.doesNotMatch(css, /\.aksrt-widget a\s*\{[^}]*color:\s*inherit/);
|
||||
assert.match(css, /\.aksrt-widget\.zib-widget\s*\{/);
|
||||
assert.match(php, /class="text-center theme-pagination ajax-pag"/);
|
||||
assert.match(php, /class="next-page ajax-next/);
|
||||
assert.match(php, /lazyload-action="ias"/);
|
||||
assert.match(php, /class="post_ajax_loader"/);
|
||||
assert.match(php, /data-page-var/);
|
||||
assert.match(admin, /'author', 'author_name'/);
|
||||
assert.match(admin, /'category__in'.*'tag__in'/s);
|
||||
assert.match(admin, /\$query_vars\['paged'\] = \$page/);
|
||||
assert.match(js, /failed = false;\s*loadNextPage\(fromAuto\)/);
|
||||
assert.match(js, /successfulAutoLoads >= iasMax/);
|
||||
assert.match(js, /AksrtFrontend\.rehydrate\(target, "ajax"\)/);
|
||||
assert.match(js, /classList\.add\("lazyload"\)/);
|
||||
assert.match(media, /thumb-dplayer-playing/);
|
||||
assert.match(media, /data-post-thumb-slider/);
|
||||
assert.match(media, /data-post-thumb-video/);
|
||||
assert.match(media, /window\.Grade\(container/);
|
||||
assert.match(media, /linear-gradient\(135deg/);
|
||||
assert.match(media, /aksrtGradientState/);
|
||||
assert.match(read('src/Core/ScriptsPart1c.php'), /'aksrt-grade'/);
|
||||
});
|
||||
|
||||
test('the pinned Zibll baseline records all source checksums', () => {
|
||||
const baseline = JSON.parse(read('tests/visual/zibll-9.0-article-baseline.json'));
|
||||
assert.equal(baseline.theme, 'Zibll');
|
||||
assert.equal(baseline.version, '9.0');
|
||||
const files = Object.values(baseline.files);
|
||||
assert.ok(files.length >= 6);
|
||||
for (const file of files) {
|
||||
assert.match(file.sha256, /^[a-f0-9]{64}$/);
|
||||
}
|
||||
});
|
||||
|
||||
test('article visual matrix pins every breakpoint, state and strict threshold', () => {
|
||||
const matrix = JSON.parse(read('tests/visual/article-visual-matrix-v1.json'));
|
||||
assert.deepEqual(matrix.viewports.map((item) => item.width), [1440, 1024, 768, 767, 641, 640, 390]);
|
||||
assert.deepEqual(matrix.colorSchemes, ['light', 'dark']);
|
||||
assert.deepEqual(matrix.layouts, ['sidebar', 'no-sidebar']);
|
||||
assert.deepEqual(matrix.listModes, ['thumb', 'text', 'thumb_if_has', 'card']);
|
||||
assert.deepEqual(matrix.styles, ['default', 'style2', 'style3']);
|
||||
assert.ok(matrix.routes.some((route) => route.id === 'author-a'));
|
||||
assert.ok(matrix.routes.some((route) => route.states.includes('infinite')));
|
||||
assert.ok(matrix.postScenarios.includes('no-image'));
|
||||
assert.ok(matrix.postScenarios.includes('multi'));
|
||||
assert.ok(matrix.postScenarios.includes('video'));
|
||||
assert.ok(matrix.postScenarios.includes('slides'));
|
||||
assert.equal(matrix.acceptance.dimensionDeltaPxMax, 1);
|
||||
assert.equal(matrix.acceptance.pixelDifferencePercentMax, 1.5);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user