Merge pull request 'fix(header): wire multi-function page-type enable like zibll' (#169) from worktree-header-multifunc-page-types into main

Reviewed-on: CYL/wordpress-theme-aksrt#169
This commit is contained in:
2026-07-15 17:15:19 +08:00
12 changed files with 445 additions and 285 deletions
@@ -86,16 +86,6 @@ export const pageDisplaySection = {
desc: '首页内容模型、主列表、分类 Tab 与首页交互配置。',
component: 'HomepageSettings',
}),
schemaPage({
key: 'page-display-float-btn',
name: 'PageDisplayFloatBtn',
label: '悬浮按钮',
route: '/page-display/float-btn',
title: '悬浮按钮',
desc: '悬浮按钮的显示规则、样式与滚动隐藏设置。',
canonicalDomain: 'page_display',
section: 'float-btn',
}),
schemaPage({
key: 'page-display-category',
name: 'PageDisplayCategory',
+5 -46
View File
@@ -5,21 +5,13 @@
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header>
<div class="aksrt-card-header-row">
<strong>Hero 显示开关</strong>
<n-button size="small" secondary @click="goHeaderComponents">顶部多功能组件(搜索/卡片/轮播参数)</n-button>
<strong>显示范围</strong>
<n-button size="small" secondary @click="goHeaderComponents">顶部多功能组件(页面类型/搜索/卡片)</n-button>
</div>
</template>
<n-form label-placement="left" label-width="160" class="aksrt-form">
<n-form-item label="显示首页 Hero">
<div class="aksrt-inline-setting">
<n-switch v-model:value="heroEnabled" :disabled="settingsLoading || settingsSaving" />
<span class="aksrt-inline-setting__hint">关闭后,首页 Hero 区块将不再渲染。</span>
</div>
</n-form-item>
</n-form>
<div class="aksrt-inline-setting__actions">
<n-button type="primary" :loading="settingsSaving" :disabled="settingsLoading" @click="saveHeroSettings">保存 Hero 开关</n-button>
</div>
<p class="aksrt-inline-setting__hint" style="margin:0;">
幻灯片内容在此维护。页面类型启用、设备规则、搜索覆盖层与图标卡片请到「顶部多功能组件」配置;全不选页面类型即为关闭。
</p>
</n-card>
<n-spin :show="loading" style="width:100%; min-height:200px;">
@@ -216,10 +208,7 @@ function goHeaderComponents() {
}
const loading = ref(true)
const saving = ref(false)
const settingsLoading = ref(false)
const settingsSaving = ref(false)
const slides = ref([])
const heroEnabled = ref(true)
const modalShow = ref(false)
const editing = ref(emptyForm())
@@ -348,36 +337,7 @@ async function loadSlides() {
}
}
async function loadHeroSettings() {
settingsLoading.value = true
try {
const res = await api.getHomepageSettings()
const data = res?.data || {}
heroEnabled.value = data.homepage_module_hero_enabled !== false
} catch (e) {
message.error(e.message || '加载 Hero 开关失败')
} finally {
settingsLoading.value = false
}
}
async function saveHeroSettings() {
settingsSaving.value = true
try {
const res = await api.saveHomepageSettings({
homepage_module_hero_enabled: heroEnabled.value,
})
if (res?.code === 'success') {
message.success('Hero 开关已保存')
return
}
throw new Error(res?.message || '保存 Hero 开关失败')
} catch (e) {
message.error(e.message || '保存 Hero 开关失败')
} finally {
settingsSaving.value = false
}
}
function openCreate() {
editing.value = emptyForm()
@@ -495,7 +455,6 @@ function handleDelete(row) {
onMounted(() => {
loadSlides()
loadHeroSettings()
})
</script>
@@ -626,14 +626,17 @@ export const pageDisplaySchemas = {
{ key: 'header_components_cards_enabled', label: '启用图标卡片', type: 'switch', default: false, help: '在顶部组件区域显示图标卡片入口' },
{ key: 'header_components_show_on', label: '按页面类型启用', type: 'checkbox', default: ['home'], options: [
{ label: '首页', value: 'home' },
{ label: '文章', value: 'single' },
{ label: '页面', value: 'page' },
{ label: '分类', value: 'category' },
{ label: '标签', value: 'tag' },
{ label: '搜索', value: 'search' },
{ label: '归档', value: 'archive' },
{ label: '专题', value: 'special' },
], help: '选择哪些页面类型显示顶部组件,不选则关闭' },
{ label: '专题页', value: 'topics' },
{ label: '分类页', value: 'category' },
{ label: '标签页', value: 'tag' },
{ label: '用户页', value: 'author' },
{ label: '文章页', value: 'single' },
{ label: '搜索页', value: 'search' },
{ label: '[论坛]首页', value: 'forum_home' },
{ label: '[论坛]板块页面', value: 'forum_plate' },
{ label: '[论坛]帖子页面', value: 'forum_post' },
{ label: '其它页面', value: 'page' },
], help: '选择启用顶部多功能组件的页面类型,一个都不选则为关闭此功能' },
{ key: 'header_components_device_visibility', label: '设备显示规则', type: 'radio', default: '', options: [
{ label: '全部', value: '' },
{ label: '仅电脑', value: 'only_pc' },
@@ -742,74 +745,6 @@ export const pageDisplaySchemas = {
],
},
/**
* Floating button settings
*/
'float-btn': {
key: 'page_display.float-btn',
title: '悬浮按钮',
icon: 'fas fa-circle-chevron-up',
description: '配置页面悬浮按钮的显示规则、样式和滚动隐藏行为。',
defaults: {
float_btn_style: 'round',
float_btn_position: 'bottom',
float_btn_scroll_hide: false,
float_btn_scroll_down_hide: true,
float_btn_max: 5,
float_btn_size: 44,
float_btn_spacing: 10,
float_btn_shadow: true,
float_btn_animation: true,
float_btn_opacity: 100,
float_btn_active_color: '',
float_btn_bg_color: '',
float_btn_pc_s: true,
float_btn_m_s: true,
float_btn_filter_css: '',
},
groups: [
{
key: 'basic',
title: '悬浮按钮设置',
icon: 'fas fa-circle-notch',
fields: [
{
key: 'float_btn_style',
label: '按钮风格',
type: 'radio',
default: 'round',
options: [
{ label: '圆形', value: 'round' },
{ label: '方形', value: 'square' },
],
},
{
key: 'float_btn_position',
label: '按钮位置',
type: 'radio',
default: 'bottom',
options: [
{ label: '底部', value: 'bottom' },
{ label: '居中', value: 'center' },
],
},
{ key: 'float_btn_scroll_hide', label: '滚动时隐藏', type: 'switch', default: false },
{ key: 'float_btn_scroll_down_hide', label: '下滑时隐藏', type: 'switch', default: true },
{ key: 'float_btn_max', label: '最大显示数', type: 'number', default: 5, min: 1, max: 10 },
{ key: 'float_btn_size', label: '按钮尺寸', type: 'number', default: 44, min: 32, max: 64 },
{ key: 'float_btn_spacing', label: '按钮间距', type: 'number', default: 10, min: 4, max: 24 },
{ key: 'float_btn_shadow', label: '显示阴影', type: 'switch', default: true },
{ key: 'float_btn_animation', label: '悬停动画', type: 'switch', default: true },
{ key: 'float_btn_opacity', label: '按钮透明度', type: 'number', default: 100, min: 30, max: 100 },
{ key: 'float_btn_active_color', label: '激活颜色', type: 'color', default: '' },
{ key: 'float_btn_bg_color', label: '背景颜色', type: 'color', default: '' },
{ key: 'float_btn_pc_s', label: 'PC端显示', type: 'switch', default: true },
{ key: 'float_btn_m_s', label: '移动端显示', type: 'switch', default: true },
{ key: 'float_btn_filter_css', label: '过滤 CSS', type: 'textarea', default: '' },
],
},
],
},
footer: {
key: 'page_display.footer',
title: '底部页脚',
+103 -72
View File
@@ -157,85 +157,116 @@
return null;
}
function collectActionButtons(scope, selector) {
scope = scope || document;
var list = [];
if (!scope) return list;
if (scope.nodeType === 1 && scope.matches && scope.matches(selector)) {
list.push(scope);
}
if (typeof scope.querySelectorAll === "function") {
var found = scope.querySelectorAll(selector);
for (var i = 0; i < found.length; i++) list.push(found[i]);
} else if (scope.nodeType === 9) {
var all = document.querySelectorAll(selector);
for (var j = 0; j < all.length; j++) list.push(all[j]);
}
// also keep legacy id hooks
var legacyId = selector.indexOf("action-like") >= 0 ? "action-like" : (selector.indexOf("action-favorite") >= 0 ? "action-favorite" : "");
if (legacyId) {
var legacy = findInScope(scope, legacyId);
if (legacy && list.indexOf(legacy) === -1) list.push(legacy);
}
return list;
}
function initInteractionBar(root) {
var scope = root || document;
// Element roots (AJAX rehydrate) do not implement getElementById
var likeBtn = findInScope(scope, "action-like");
var favBtn = findInScope(scope, "action-favorite");
// Bind all like/favorite controls (in-content + footer tabbar extend).
var likeBtns = collectActionButtons(scope, ".action-like[data-post-id]");
var favBtns = collectActionButtons(scope, ".action-favorite[data-post-id]");
if (likeBtn && likeBtn.dataset.aksrtInteractionBound) return;
if (favBtn && favBtn.dataset.aksrtInteractionBound) return;
if (likeBtn) {
var likePostId = likeBtn.dataset.postId ? String(likeBtn.dataset.postId) : "";
function applyLikeState(isActive, count) {
likeBtn.dataset.initialActive = isActive ? "1" : "0";
likeBtn.classList.toggle("is-active", isActive);
var likeIcon = likeBtn.querySelector("i");
if (likeIcon) {
likeIcon.className = isActive ? "fas fa-heart" : "far fa-heart";
}
if ("number" === typeof count && !isNaN(count)) {
setBaseStatCount("likes", count);
} else {
updateStatCounts("likes", getBaseStatCount("likes"));
}
}
applyLikeState(likeBtn.dataset.initialActive === "1", getBaseStatCount("likes"));
likeBtn.addEventListener("click", function () {
if (!likePostId || likeBtn.disabled) return;
var nextState = likeBtn.dataset.initialActive !== "1";
setButtonBusy(likeBtn, true);
requestInteraction("aksrt_toggle_like", likePostId, nextState).then(function (data) {
applyLikeState(!!data.active, parseInt(data.count, 10) || 0);
showToast(data.active ? "感谢你的点赞" : "已取消点赞", "success");
}).catch(function (error) {
showToast(error && error.message ? error.message : "点赞失败", "error");
}).finally(function () {
setButtonBusy(likeBtn, false);
});
});
function paintLike(btn, isActive) {
btn.dataset.initialActive = isActive ? "1" : "0";
btn.classList.toggle("is-active", isActive);
var icon = btn.querySelector("i");
if (icon) icon.className = isActive ? "fas fa-heart" : "far fa-heart";
}
if (favBtn) {
var favoritePostId = favBtn.dataset.postId ? String(favBtn.dataset.postId) : "";
function applyFavoriteState(isActive, count) {
favBtn.dataset.initialActive = isActive ? "1" : "0";
favBtn.classList.toggle("is-active", isActive);
var favoriteIcon = favBtn.querySelector("i");
if (favoriteIcon) {
favoriteIcon.className = isActive ? "fas fa-star" : "far fa-star";
}
if ("number" === typeof count && !isNaN(count)) {
setBaseStatCount("favorites", count);
} else {
updateStatCounts("favorites", getBaseStatCount("favorites"));
}
}
applyFavoriteState(favBtn.dataset.initialActive === "1", getBaseStatCount("favorites"));
favBtn.addEventListener("click", function () {
if (!favoritePostId || favBtn.disabled) return;
var nextState = favBtn.dataset.initialActive !== "1";
setButtonBusy(favBtn, true);
requestInteraction("aksrt_toggle_favorite", favoritePostId, nextState).then(function (data) {
applyFavoriteState(!!data.active, parseInt(data.count, 10) || 0);
showToast(data.active ? "收藏成功" : "已取消收藏", "success");
}).catch(function (error) {
showToast(error && error.message ? error.message : "收藏失败", "error");
}).finally(function () {
setButtonBusy(favBtn, false);
});
});
function paintFavorite(btn, isActive) {
btn.dataset.initialActive = isActive ? "1" : "0";
btn.classList.toggle("is-active", isActive);
var icon = btn.querySelector("i");
if (icon) icon.className = isActive ? "fas fa-star" : "far fa-star";
}
if (likeBtn) likeBtn.dataset.aksrtInteractionBound = "1";
if (favBtn) favBtn.dataset.aksrtInteractionBound = "1";
function applyLikeState(isActive, count) {
for (var i = 0; i < likeBtns.length; i++) paintLike(likeBtns[i], isActive);
if ("number" === typeof count && !isNaN(count)) {
setBaseStatCount("likes", count);
} else {
updateStatCounts("likes", getBaseStatCount("likes"));
}
}
function applyFavoriteState(isActive, count) {
for (var i = 0; i < favBtns.length; i++) paintFavorite(favBtns[i], isActive);
if ("number" === typeof count && !isNaN(count)) {
setBaseStatCount("favorites", count);
} else {
updateStatCounts("favorites", getBaseStatCount("favorites"));
}
}
if (likeBtns.length) {
var seedLike = likeBtns[0];
if (!seedLike.dataset.aksrtInteractionBound) {
applyLikeState(seedLike.dataset.initialActive === "1", getBaseStatCount("likes"));
likeBtns.forEach(function (likeBtn) {
if (likeBtn.dataset.aksrtInteractionBound) return;
likeBtn.dataset.aksrtInteractionBound = "1";
likeBtn.addEventListener("click", function () {
var postId = likeBtn.dataset.postId ? String(likeBtn.dataset.postId) : "";
if (!postId || likeBtn.disabled) return;
var nextState = likeBtn.dataset.initialActive !== "1";
setButtonBusy(likeBtn, true);
requestInteraction("aksrt_toggle_like", postId, nextState).then(function (data) {
applyLikeState(!!data.active, parseInt(data.count, 10) || 0);
showToast(data.active ? "感谢你的点赞" : "已取消点赞", "success");
}).catch(function (error) {
showToast(error && error.message ? error.message : "点赞失败", "error");
}).finally(function () {
setButtonBusy(likeBtn, false);
});
});
});
}
}
if (favBtns.length) {
var seedFav = favBtns[0];
if (!seedFav.dataset.aksrtInteractionBound) {
applyFavoriteState(seedFav.dataset.initialActive === "1", getBaseStatCount("favorites"));
favBtns.forEach(function (favBtn) {
if (favBtn.dataset.aksrtInteractionBound) return;
favBtn.dataset.aksrtInteractionBound = "1";
favBtn.addEventListener("click", function () {
var postId = favBtn.dataset.postId ? String(favBtn.dataset.postId) : "";
if (!postId || favBtn.disabled) return;
var nextState = favBtn.dataset.initialActive !== "1";
setButtonBusy(favBtn, true);
requestInteraction("aksrt_toggle_favorite", postId, nextState).then(function (data) {
applyFavoriteState(!!data.active, parseInt(data.count, 10) || 0);
showToast(data.active ? "收藏成功" : "已取消收藏", "success");
}).catch(function (error) {
showToast(error && error.message ? error.message : "收藏失败", "error");
}).finally(function () {
setButtonBusy(favBtn, false);
});
});
});
}
}
}
window.AksrtFrontend.register("aksrt-search-clear", function () { initSearchClear(); });
+12 -1
View File
@@ -123,8 +123,9 @@
}
function initShareDropdown() {
var trigger = document.getElementById('action-share-trigger');
var dropdown = document.getElementById('share-dropdown');
var triggers = Array.prototype.slice.call(document.querySelectorAll('#action-share-trigger, .action-share[data-type="share"], .footer-tabbar .action-share')).filter(function (el, idx, arr) { return arr.indexOf(el) === idx; });
var trigger = triggers[0] || null;
if (!trigger || !dropdown || dropdown.dataset.aksrtShareBound === '1') return;
dropdown.dataset.aksrtShareBound = '1';
@@ -160,6 +161,16 @@
toggleDropdown();
});
triggers.slice(1).forEach(function (extraTrigger) {
extraTrigger.addEventListener('click', function (event) {
event.preventDefault();
event.stopPropagation();
// Reuse primary trigger click semantics by synthetic toggle
trigger.click();
});
});
document.addEventListener('click', function (event) {
if (!trigger.contains(event.target) && !dropdown.contains(event.target)) {
closeDropdown();
+27 -16
View File
@@ -471,27 +471,38 @@ if ($floating_enabled) :
</div>
<?php endif; ?>
<?php if ($tabbar_enabled) : ?>
<?php if ($tabbar_enabled) :
$tabbar_use_single_extend = function_exists('aksrt_should_use_footer_tabbar_single_extend')
&& aksrt_should_use_footer_tabbar_single_extend();
?>
<div class="footer-tabbar-placeholder" aria-hidden="true"></div>
<nav id="footer-tabbar" class="footer-tabbar<?php echo !empty($tabbar_settings['animation']) ? ' has-animation' : ''; ?><?php echo !empty($tabbar_settings['scroll_down_hide']) ? ' scroll-down-hide' : ''; ?><?php echo empty($tabbar_settings['border']) ? ' no-border' : ''; ?><?php echo empty($tabbar_settings['shadow']) ? ' no-shadow' : ''; ?>" aria-label="<?php esc_attr_e('底部导航', 'aksrt'); ?>">
<?php foreach ($tabbar_items as $tab_item) :
$tab_type = sanitize_key((string) ($tab_item['type'] ?? 'custom'));
$tab_text = (string) ($tab_item['text'] ?? '');
$tab_icon = (string) ($tab_item['icon'] ?? 'fas fa-circle');
$tab_href = home_url('/');
if ($tab_type === 'category') {
$tab_href = get_post_type_archive_link('post') ?: home_url('/');
} elseif ($tab_type === 'auth') {
$tab_href = is_user_logged_in() ? aksrt_get_user_center_url() : aksrt_get_login_url();
} elseif ($tab_type === 'search') {
$tab_href = home_url('/');
}
?>
<nav id="footer-tabbar" class="footer-tabbar<?php echo !empty($tabbar_settings['animation']) ? ' has-animation' : ''; ?><?php echo !empty($tabbar_settings['scroll_down_hide']) ? ' scroll-down-hide' : ''; ?><?php echo empty($tabbar_settings['border']) ? ' no-border' : ''; ?><?php echo empty($tabbar_settings['shadow']) ? ' no-shadow' : ''; ?><?php echo $tabbar_use_single_extend ? ' footer-tabbar--single-extend' : ''; ?>" aria-label="<?php esc_attr_e('底部导航', 'aksrt'); ?>">
<?php if ($tabbar_use_single_extend && function_exists('aksrt_render_footer_tabbar_single_extend')) :
aksrt_render_footer_tabbar_single_extend(!empty($tabbar_settings['show_text']));
else :
foreach ($tabbar_items as $tab_item) :
$tab_type = sanitize_key((string) ($tab_item['type'] ?? 'custom'));
$tab_text = (string) ($tab_item['text'] ?? '');
$tab_icon = (string) ($tab_item['icon'] ?? 'fas fa-circle');
$tab_href = home_url('/');
if ($tab_type === 'category') {
$tab_href = get_post_type_archive_link('post') ?: home_url('/');
} elseif ($tab_type === 'auth') {
$tab_href = is_user_logged_in() ? aksrt_get_user_center_url() : aksrt_get_login_url();
} elseif ($tab_type === 'search') {
$tab_href = home_url('/');
} elseif ($tab_type === 'custom' && !empty($tab_item['link'])) {
$tab_href = (string) $tab_item['link'];
} elseif ($tab_type === 'home') {
$tab_href = home_url('/');
}
?>
<a href="<?php echo esc_url($tab_href); ?>" class="tabbar-item" data-type="<?php echo esc_attr($tab_type); ?>">
<i class="<?php echo esc_attr($tab_icon); ?>" aria-hidden="true"></i>
<?php if (!empty($tabbar_settings['show_text'])) : ?><span><?php echo esc_html($tab_text); ?></span><?php endif; ?>
</a>
<?php endforeach; ?>
<?php endforeach;
endif; ?>
</nav>
<?php endif; ?>
@@ -78,13 +78,16 @@ class AKSRT_Admin_Schema_Page_Display {
['key' => 'header_components_cards_enabled', 'label' => '启用图标卡片', 'type' => 'switch', 'default' => false],
['key' => 'header_components_show_on', 'label' => '按页面类型启用', 'type' => 'checkbox', 'default' => ['home'], 'options' => [
['label' => '首页', 'value' => 'home'],
['label' => '文章', 'value' => 'single'],
['label' => '页面', 'value' => 'page'],
['label' => '分类', 'value' => 'category'],
['label' => '标签', 'value' => 'tag'],
['label' => '搜索', 'value' => 'search'],
['label' => '归档', 'value' => 'archive'],
['label' => '专题', 'value' => 'special'],
['label' => '专题页', 'value' => 'topics'],
['label' => '分类页', 'value' => 'category'],
['label' => '标签页', 'value' => 'tag'],
['label' => '用户页', 'value' => 'author'],
['label' => '文章页', 'value' => 'single'],
['label' => '搜索页', 'value' => 'search'],
['label' => '[论坛]首页', 'value' => 'forum_home'],
['label' => '[论坛]板块页面', 'value' => 'forum_plate'],
['label' => '[论坛]帖子页面', 'value' => 'forum_post'],
['label' => '其它页面', 'value' => 'page'],
]],
['key' => 'header_components_device_visibility', 'label' => '设备显示规则', 'type' => 'radio', 'default' => '', 'options' => [
['label' => '全部', 'value' => ''],
@@ -494,37 +497,6 @@ class AKSRT_Admin_Schema_Page_Display {
]],
],
],
'float-btn' => [
'key' => 'float-btn',
'title' => '悬浮按钮',
'version' => '1.1.0',
'option_key' => 'aksrt_settings',
'groups' => [
['key' => 'basic', 'title' => '悬浮按钮设置', 'fields' => [
['key' => 'float_btn_style', 'label' => '按钮风格', 'type' => 'radio', 'default' => 'round', 'options' => [
['label' => '圆形', 'value' => 'round'],
['label' => '方形', 'value' => 'square'],
]],
['key' => 'float_btn_position', 'label' => '按钮位置', 'type' => 'radio', 'default' => 'bottom', 'options' => [
['label' => '底部', 'value' => 'bottom'],
['label' => '居中', 'value' => 'center'],
]],
['key' => 'float_btn_scroll_hide', 'label' => '滚动时隐藏', 'type' => 'switch', 'default' => false],
['key' => 'float_btn_scroll_down_hide', 'label' => '下滑时隐藏', 'type' => 'switch', 'default' => true],
['key' => 'float_btn_max', 'label' => '最大显示数', 'type' => 'number', 'default' => 5, 'min' => 1, 'max' => 10],
['key' => 'float_btn_size', 'label' => '按钮尺寸', 'type' => 'number', 'default' => 44, 'min' => 32, 'max' => 64],
['key' => 'float_btn_spacing', 'label' => '按钮间距', 'type' => 'number', 'default' => 10, 'min' => 4, 'max' => 24],
['key' => 'float_btn_shadow', 'label' => '显示阴影', 'type' => 'switch', 'default' => true],
['key' => 'float_btn_animation', 'label' => '悬停动画', 'type' => 'switch', 'default' => true],
['key' => 'float_btn_opacity', 'label' => '按钮透明度', 'type' => 'number', 'default' => 100, 'min' => 30, 'max' => 100],
['key' => 'float_btn_active_color', 'label' => '激活颜色', 'type' => 'color', 'default' => ''],
['key' => 'float_btn_bg_color', 'label' => '背景颜色', 'type' => 'color', 'default' => ''],
['key' => 'float_btn_pc_s', 'label' => 'PC端显示', 'type' => 'switch', 'default' => true],
['key' => 'float_btn_m_s', 'label' => '移动端显示', 'type' => 'switch', 'default' => true],
['key' => 'float_btn_filter_css', 'label' => '过滤CSS', 'type' => 'textarea', 'default' => ''],
]],
],
],
],
];
}
@@ -177,15 +177,19 @@ trait AKSRT_Scripts_Part_1b {
// CMS 形态判定(可能在博客流页面也需要 grid-cms 卡片样式)
$is_cms_mode = function_exists('aksrt_is_cms_mode') ? aksrt_is_cms_mode() : false;
// 首页/归档/搜索:卡片 + 顶部多功能组件 + 侧栏
// 首页/归档/搜索:卡片 + 侧栏
if ($is_home_or_archive) {
$enqueue_module('header-components');
$enqueue_module('post-card');
$enqueue_module('widgets');
$enqueue_module('sidebar');
$enqueue_module('breadcrumb');
}
// 顶部多功能组件:按 page-type 启用结果入队(对齐 zibll,不绑死首页)
if (function_exists('aksrt_header_slide_is_show') && aksrt_header_slide_is_show()) {
$enqueue_module('header-components');
}
// 单篇文章:所有 single 相关样式
if ($is_single_post) {
$enqueue_module('single-post');
@@ -51,7 +51,24 @@ trait AKSRT_Settings_Display_Page_Groups {
*/
public static function get_header_components_settings(): array {
$s = self::get_all();
$allowed_page_types = [
'home',
'topics',
'category',
'tag',
'author',
'single',
'search',
'forum_home',
'forum_plate',
'forum_post',
'page',
];
$show_on = isset($s['header_components_show_on']) ? (array) $s['header_components_show_on'] : ['home'];
$show_on = array_values(array_intersect(
array_map('sanitize_key', $show_on),
$allowed_page_types
));
$show_type = $s['header_components_device_visibility'] ?? '';
if (!in_array($show_type, ['', 'only_pc', 'only_sm'], true)) {
$show_type = '';
@@ -60,7 +77,7 @@ trait AKSRT_Settings_Display_Page_Groups {
'search_enabled' => self::header_components_search_enabled(),
'search_config' => self::get_header_components_search_config(),
'cards_enabled' => self::header_components_cards_enabled(),
'show_on_pages' => array_values(array_filter(array_map('sanitize_key', $show_on))),
'show_on_pages' => $show_on,
'show_type' => $show_type,
'filter_blur' => isset($s['header_components_filter_blur_devices']) ? array_values(array_intersect(array_map('sanitize_key', (array) $s['header_components_filter_blur_devices']), ['pc', 'mobile'])) : [],
'card_show' => isset($s['header_components_card_show_devices']) ? array_values(array_intersect(array_map('sanitize_key', (array) $s['header_components_card_show_devices']), ['pc', 'mobile'])) : ['pc', 'mobile'],
+145 -7
View File
@@ -822,27 +822,165 @@ if (!function_exists('aksrt_homepage_render_section')) {
}
}
if (!function_exists('aksrt_header_components_page_type_keys')) {
/**
* Allowed page-type keys for header multi-function (zibll CFS_Module::page_type).
*
* @return list<string>
*/
function aksrt_header_components_page_type_keys(): array {
return [
'home',
'topics',
'category',
'tag',
'author',
'single',
'search',
'forum_home',
'forum_plate',
'forum_post',
'page',
];
}
}
if (!function_exists('aksrt_header_slide_excluded_page_templates')) {
/**
* Page templates excluded from the generic "page" type (zibll parity).
*
* @return list<string>
*/
function aksrt_header_slide_excluded_page_templates(): array {
return [
'templates/pages/page-sign.php',
'templates/pages/page-login.php',
'templates/pages/page-register.php',
'templates/pages/page-reset-password.php',
'templates/pages/page-bind-account.php',
'templates/pages/page-verify-email.php',
'templates/pages/page-download.php',
'templates/pages/page-download-file.php',
'templates/pages/page-forums.php',
];
}
}
if (!function_exists('aksrt_header_slide_match_page_type')) {
/**
* Whether the current main query matches a header-slider page-type key.
*
* Mirrors zibll zib_header_slide_is_show() matching rules.
*/
function aksrt_header_slide_match_page_type(string $type): bool {
global $wp_query;
$type = sanitize_key($type);
if ($type === '' || !($wp_query instanceof WP_Query)) {
return false;
}
$raw_post_type = $wp_query->get('post_type');
if (is_array($raw_post_type)) {
$post_type = (string) reset($raw_post_type);
} else {
$post_type = (string) $raw_post_type;
}
// Special keys that are not plain is_{$type} flags.
if ($type === 'topics') {
return is_tax('topics');
}
if ($type === 'forum_home') {
return is_page_template('templates/pages/page-forums.php');
}
if ($type === 'forum_plate') {
return is_singular('aksrt_forum_plate') || $post_type === 'aksrt_forum_plate';
}
if ($type === 'forum_post') {
return is_singular('aksrt_forum_topic') || $post_type === 'aksrt_forum_topic';
}
// Generic WP_Query is_* flags (home/category/tag/author/single/search/page).
$query_flag = 'is_' . $type;
if (empty($wp_query->{$query_flag})) {
return false;
}
if ($type === 'single') {
// Only ordinary posts; CPTs use dedicated keys.
return $post_type === '' || $post_type === 'post';
}
if ($type === 'page') {
foreach (aksrt_header_slide_excluded_page_templates() as $template) {
if (is_page_template($template)) {
return false;
}
}
return true;
}
return true;
}
}
if (!function_exists('aksrt_header_slide_is_show')) {
/**
* Whether the header multi-function slider should render (zibll header-slider contract).
*
* Master switch: non-empty header_components_show_on + current page-type match.
* Device rule: header_components_device_visibility (only_pc / only_sm).
*/
function aksrt_header_slide_is_show(): bool {
if (is_admin()) {
global $wp_query;
if (is_admin() || !($wp_query instanceof WP_Query)) {
return false;
}
// Match zibll: only first page of the posts index / front page.
if (!(is_front_page() || is_home())) {
// Not on paginated views (zibll: query_vars['paged'] non-empty).
$paged = (int) $wp_query->get('paged');
if ($paged > 1) {
return false;
}
if (function_exists('aksrt_homepage_get_current_page') && aksrt_homepage_get_current_page() > 1) {
return false;
}
return function_exists('aksrt_homepage_module_hero_enabled')
? aksrt_homepage_module_hero_enabled()
: true;
$settings = class_exists('AKSRT_Settings')
? AKSRT_Settings::get_header_components_settings()
: [];
$show_on = isset($settings['show_on_pages']) ? (array) $settings['show_on_pages'] : [];
$allowed = array_values(array_intersect(
array_map('sanitize_key', $show_on),
aksrt_header_components_page_type_keys()
));
// Empty selection = feature off (zibll header_slider_show).
if ($allowed === []) {
return false;
}
// Device visibility (zibll header_slider_show_type).
$show_type = (string) ($settings['show_type'] ?? '');
if ($show_type === 'only_pc' && wp_is_mobile()) {
return false;
}
if ($show_type === 'only_sm' && !wp_is_mobile()) {
return false;
}
foreach ($allowed as $type) {
if (aksrt_header_slide_match_page_type($type)) {
return true;
}
}
return false;
}
}
+101
View File
@@ -1283,3 +1283,104 @@ add_action('save_post_aksrt_banner', 'aksrt_flush_banner_cache');
add_action('deleted_post', 'aksrt_flush_banner_cache');
add_action('trashed_post', 'aksrt_flush_banner_cache');
endif;
if (!function_exists('aksrt_should_use_footer_tabbar_single_extend')) :
/**
* Whether single-post extended footer tabbar should replace the default items.
* Zibll: footer_tabbar_single.s === extend && is_single(post).
*/
function aksrt_should_use_footer_tabbar_single_extend(): bool {
if (!is_singular('post')) {
return false;
}
if (!class_exists('AKSRT_Settings') || !method_exists('AKSRT_Settings', 'get_footer_tabbar_single')) {
return false;
}
return AKSRT_Settings::get_footer_tabbar_single() === 'extend';
}
endif;
if (!function_exists('aksrt_render_footer_tabbar_single_extend')) :
/**
* Render single-post extended footer tabbar actions (like / favorite / share / comment).
*
* @param bool $show_text Whether to show text labels under icons.
*/
function aksrt_render_footer_tabbar_single_extend(bool $show_text = true): void {
$post_id = (int) get_the_ID();
if ($post_id <= 0) {
return;
}
$settings = function_exists('aksrt_resolve_single_post_display_settings')
? aksrt_resolve_single_post_display_settings($post_id)
: [];
$like_on = !isset($settings['like_enabled']) || !empty($settings['like_enabled']);
$favorite_on = !isset($settings['favorite_enabled']) || !empty($settings['favorite_enabled']);
$share_on = !isset($settings['share_enabled']) || !empty($settings['share_enabled']);
$comments_open = comments_open($post_id)
&& !(function_exists('aksrt_are_comments_closed') && aksrt_are_comments_closed());
$like_count = function_exists('aksrt_get_post_likes') ? (int) aksrt_get_post_likes($post_id) : 0;
$favorite_count = function_exists('aksrt_get_post_favorites') ? (int) aksrt_get_post_favorites($post_id) : 0;
$is_liked = function_exists('aksrt_is_post_liked') ? aksrt_is_post_liked($post_id) : false;
$is_favorited = function_exists('aksrt_is_post_favorited') ? aksrt_is_post_favorited($post_id) : false;
$comment_count = (int) get_comments_number($post_id);
if ($like_on) :
?>
<button type="button"
class="tabbar-item single-action-tabbar action-like<?php echo $is_liked ? ' is-active' : ''; ?>"
data-type="like"
data-post-id="<?php echo esc_attr((string) $post_id); ?>"
data-initial-active="<?php echo $is_liked ? '1' : '0'; ?>"
aria-label="<?php esc_attr_e('点赞', 'aksrt'); ?>">
<i class="<?php echo $is_liked ? 'fas' : 'far'; ?> fa-heart" aria-hidden="true"></i>
<?php if ($show_text) : ?><span data-stat-count="likes" data-base-count="<?php echo esc_attr((string) $like_count); ?>"><?php echo esc_html((string) $like_count); ?></span><?php endif; ?>
</button>
<?php
endif;
if ($favorite_on) :
?>
<button type="button"
class="tabbar-item single-action-tabbar action-favorite<?php echo $is_favorited ? ' is-active' : ''; ?>"
data-type="favorite"
data-post-id="<?php echo esc_attr((string) $post_id); ?>"
data-initial-active="<?php echo $is_favorited ? '1' : '0'; ?>"
aria-label="<?php esc_attr_e('收藏', 'aksrt'); ?>">
<i class="<?php echo $is_favorited ? 'fas' : 'far'; ?> fa-star" aria-hidden="true"></i>
<?php if ($show_text) : ?><span data-stat-count="favorites" data-base-count="<?php echo esc_attr((string) $favorite_count); ?>"><?php echo esc_html((string) $favorite_count); ?></span><?php endif; ?>
</button>
<?php
endif;
if ($share_on) :
?>
<button type="button"
class="tabbar-item single-action-tabbar action-share"
data-type="share"
aria-haspopup="true"
aria-expanded="false"
aria-label="<?php esc_attr_e('分享', 'aksrt'); ?>">
<i class="fas fa-share-alt" aria-hidden="true"></i>
<?php if ($show_text) : ?><span><?php esc_html_e('分享', 'aksrt'); ?></span><?php endif; ?>
</button>
<?php
endif;
if ($comments_open) :
?>
<a href="#comments"
class="tabbar-item single-action-tabbar"
data-type="comment"
aria-label="<?php esc_attr_e('评论', 'aksrt'); ?>">
<i class="far fa-comment" aria-hidden="true"></i>
<?php if ($show_text) : ?><span><?php echo esc_html((string) $comment_count); ?></span><?php endif; ?>
</a>
<?php
endif;
}
endif;
+7 -16
View File
@@ -7,22 +7,8 @@
*/
defined('ABSPATH') || exit;
if (class_exists('AKSRT_Settings') && !AKSRT_Settings::homepage_module_hero_enabled()) {
return;
}
// Device visibility gate: header_components_device_visibility ('' = all, 'only_pc' = PC only, 'only_sm' = mobile only)
$_hero_show_type = '';
if (class_exists('AKSRT_Settings')) {
$_hero_slider_cfg = AKSRT_Settings::get_header_components_settings();
$_hero_show_type = $_hero_slider_cfg['show_type'] ?? '';
}
if ($_hero_show_type === 'only_pc' && wp_is_mobile()) {
return;
}
if ($_hero_show_type === 'only_sm' && !wp_is_mobile()) {
return;
}
// Visibility (page type + device) is decided by aksrt_header_slide_is_show().
// This partial only renders content when already gated by aksrt_header_slide().
$cfg = get_query_var('aksrt_module_config', []);
if (!is_array($cfg)) {
@@ -171,6 +157,11 @@ $render_icon_cards = static function () use ($show_cards, $icon_cards, $card_bg_
if (!empty($hero_banners)) :
$slider_cfg = function_exists('aksrt_get_slider_config') ? aksrt_get_slider_config() : [];
$_nav_color_for_header = sanitize_hex_color((string) ($slider_cfg['nav_color'] ?? '')) ?: '';
if ($_nav_color_for_header !== '' && strtolower($_nav_color_for_header) !== '#ffffff') {
echo '<style id="aksrt-header-slider-nav-color">.header.show-slide{--header-color:' . esc_attr($_nav_color_for_header) . ';}</style>';
}
$swiper_config = [
'effect' => $slider_cfg['effect'] ?? 'fade',
'loop' => $slide_count > 1 && ($slider_cfg['loop'] ?? true),