From 6c354fb0866ea484a7eaa2e26fa05d7b7e0a7571 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Jul 2026 12:44:09 +0800 Subject: [PATCH] fix(single): restore Zibll float dual-column and article chrome Align single-post layout/visuals with Zibll: fix sidebar-over-content float geometry (position:unset, 311px token, kill Bootstrap/container padding and the 280px sidebar override), demote theme-box to spacing- only, unify breadcrumb/cover/graphic utilities, and split aksrt-single render helpers under the file-size limit. --- assets/css/core/tokens.css | 2 +- assets/css/frontend/base.css | 77 +- assets/css/frontend/breadcrumb.css | 81 +- assets/css/frontend/card-primitives.css | 38 +- assets/css/frontend/layout.css | 80 +- assets/css/frontend/sidebar.css | 9 +- .../frontend/single-post/author-actions.css | 16 +- assets/css/frontend/single-post/content.css | 29 + assets/css/frontend/single-post/cover.css | 79 +- assets/css/frontend/single-post/shell.css | 7 +- assets/css/frontend/zibll-utilities.css | 126 +++ inc/bootstrap.php | 1 + inc/helpers/aksrt-single-render.php | 812 ++++++++++++++++++ inc/helpers/aksrt-single.php | 803 ----------------- templates/parts/single-author-bar.php | 4 +- 15 files changed, 1189 insertions(+), 975 deletions(-) create mode 100644 inc/helpers/aksrt-single-render.php diff --git a/assets/css/core/tokens.css b/assets/css/core/tokens.css index 34964f6e..ab73d485 100644 --- a/assets/css/core/tokens.css +++ b/assets/css/core/tokens.css @@ -103,7 +103,7 @@ --container-wide: 1440px; --container-read: 760px; --container-page: 880px; - --sidebar-width: 300px; + --sidebar-width: 311px; --content-gap: 24px; --section-gap: 24px; --sidebar-bp: 992px; diff --git a/assets/css/frontend/base.css b/assets/css/frontend/base.css index ebc1807f..6c289d27 100644 --- a/assets/css/frontend/base.css +++ b/assets/css/frontend/base.css @@ -72,22 +72,83 @@ a[href] { flex: 1; } -.container { +/* Zibll dual-column float math expects a padding-free main.container. + * Bootstrap 5 also defines .container (max-width ladder + padding-x). + * Force Zibll geometry after Bootstrap so negative-margin sidebars land correctly. */ +.container, +main.container, +.site-main.container { width: 100%; - max-width: var(--container); - margin: 0 auto; - padding: 0 16px; + max-width: var(--container, var(--mian-max-width, 1200px)); + margin-right: auto; + margin-left: auto; + padding-right: 0; + padding-left: 0; + /* Kill Bootstrap 5 --bs-gutter-x padding model on site shells */ + --bs-gutter-x: 0; + --bs-gutter-y: 0; +} + +@media (min-width: 576px) { + .container, + main.container { + max-width: var(--container, var(--mian-max-width, 1200px)); + } } @media (min-width: 768px) { - .container { - padding: 0 24px; + .container, + main.container { + max-width: var(--container, var(--mian-max-width, 1200px)); + } +} + +@media (min-width: 992px) { + .container, + main.container { + max-width: var(--container, var(--mian-max-width, 1200px)); } } @media (min-width: 1200px) { - .container { - padding: 0 32px; + .container, + main.container { + max-width: var(--container, var(--mian-max-width, 1200px)); + } +} + +@media (min-width: 1240px) { + .container, + main.container, + .fluid-widget-wrap .widget-container { + width: auto; + max-width: var(--container, var(--mian-max-width, 1200px)); + } +} + +@media (min-width: 1400px) { + .container, + main.container { + max-width: var(--container, var(--mian-max-width, 1200px)); + } +} + +/* Soft pad only when the float dual-column is collapsed */ +@media (max-width: 991.98px) { + .container, + main.container { + padding-right: 10px; + padding-left: 10px; + } +} + +@media (max-width: 767px) { + .container, + main.container { + width: 100%; + max-width: 100%; + padding-right: 10px; + padding-left: 10px; } } diff --git a/assets/css/frontend/breadcrumb.css b/assets/css/frontend/breadcrumb.css index f00800a9..43d855da 100644 --- a/assets/css/frontend/breadcrumb.css +++ b/assets/css/frontend/breadcrumb.css @@ -1,12 +1,17 @@ -/* ========== 面包屑导航 — 对齐 zibll breadcrumb ========== */ -.breadcrumb-nav, +/* ========== 面包屑导航 — 对齐 zibll .breadcrumb (main.css) ========== */ +/* Single source for breadcrumb chrome. Do not re-define in layout.css. */ + +.breadcrumb, ul.breadcrumb, +.breadcrumb-nav, .breadcrumbs-wrap { + background: transparent; font-size: 13px; padding: 0 8px; - margin-bottom: 12px; + margin: 0 0 12px; opacity: 0.6; line-height: 1.8; + list-style: none; } .breadcrumb-nav ol, @@ -16,90 +21,98 @@ ul.breadcrumb, list-style: none; margin: 0; padding: 0; - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 0; + display: block; } -.breadcrumb-nav li, +/* Zibll uses flat li + li:before separators (not flex-gap nodes) */ +.breadcrumb > li, ul.breadcrumb > li, +.breadcrumb-nav li, .breadcrumbs.breadcrumb > li { - display: inline-flex; - align-items: center; + display: inline; } -/* Zibll flat ul.breadcrumb inserts parents with "
  • " — separators via content */ -.breadcrumb-nav li + li::before, -ul.breadcrumb > li + li::before { - content: '/'; - padding: 0 6px 0 6px; +.breadcrumb > li + li:before, +ul.breadcrumb > li + li:before, +.breadcrumb-nav li + li:before { + content: "/"; + padding: 0 0 0 6px; opacity: 0.6; } +/* Archive/nav variant may still stamp sep nodes — keep neutral */ .breadcrumbs.breadcrumb .breadcrumbs__sep { padding: 0 6px; opacity: 0.6; } -.breadcrumb-nav a, +.breadcrumb a, ul.breadcrumb a, +.breadcrumb-nav a, .breadcrumbs a { - color: var(--color-ink-4, #999); + color: var(--muted-2-color, var(--color-ink-4, #999)); text-decoration: none; transition: color 0.2s; } -.breadcrumb-nav a:hover, +.breadcrumb a:hover, ul.breadcrumb a:hover, +.breadcrumb-nav a:hover, .breadcrumbs a:hover { - color: var(--color-primary, #f04494); + color: var(--focus-color, var(--color-primary, #f04494)); } -.breadcrumb-nav .current, +.breadcrumb > li:last-child, ul.breadcrumb > li:last-child, +.breadcrumb-nav .current, .breadcrumbs__item.is-current { - color: var(--color-ink-2, #4e5358); - font-weight: 500; + color: var(--main-color, var(--color-ink-2, #4e5358)); } -.single-cover-con .breadcrumb-nav, +/* Cover / video footer breadcrumb — Zibll single-cover-con / single-video */ .single-cover-con .breadcrumb, .single-cover-con ul.breadcrumb, -.post-breadcrumbs .breadcrumb { +.single-cover-con .breadcrumb-nav, +.post-breadcrumbs .breadcrumb, +.single-video .breadcrumb { font-size: 13px; margin: 5px 0 0 -6px; opacity: unset; padding: 0; + background: transparent; } -/* 封面内面包屑 */ -.single-cover-con .breadcrumb-nav, +.single-video .breadcrumb { + padding: 0; +} + +.single-cover-con .breadcrumb, .single-cover-con ul.breadcrumb, -.single-cover-con .breadcrumb { +.single-cover-con .breadcrumb-nav { color: rgba(255, 255, 255, 0.85); } -.single-cover-con .breadcrumb-nav a, +.single-cover-con .breadcrumb a, .single-cover-con ul.breadcrumb a, -.single-cover-con .breadcrumb a { +.single-cover-con .breadcrumb-nav a { color: rgba(255, 255, 255, 0.85); } -.single-cover-con .breadcrumb-nav a:hover, -.single-cover-con ul.breadcrumb a:hover { +.single-cover-con .breadcrumb a:hover, +.single-cover-con ul.breadcrumb a:hover, +.single-cover-con .breadcrumb-nav a:hover { color: #fff; } -.single-cover-con .breadcrumb-nav .current, +.single-cover-con .breadcrumb > li:last-child, .single-cover-con ul.breadcrumb > li:last-child { color: #fff; } -/* 移动端 */ @media (max-width: 767px) { - .breadcrumb-nav, + .breadcrumb, ul.breadcrumb, + .breadcrumb-nav, .breadcrumbs-wrap { font-size: 12px; } diff --git a/assets/css/frontend/card-primitives.css b/assets/css/frontend/card-primitives.css index 351837a0..b7bc4c1d 100644 --- a/assets/css/frontend/card-primitives.css +++ b/assets/css/frontend/card-primitives.css @@ -73,22 +73,17 @@ /* ============================================================ * Zibll 兼容别名 * ============================================================ */ -.theme-box { - background: var(--surface-1); - border: none; - border-radius: var(--radius, 8px); - box-shadow: var(--shadow-sm); +/* Zibll .theme-box is ONLY a spacing utility (margin-bottom: 20px). + * Background/shadow live on .main-bg / .main-shadow / .box-bg / .zib-widget. + * Do NOT turn every theme-box into a card — article-header also uses it. */ +.theme-box, +.mb20 { margin-bottom: 20px; - transition: box-shadow 0.2s ease; -} - -.theme-box:hover { - box-shadow: var(--shadow); } .box-bg { - background-color: var(--surface-1); - box-shadow: var(--shadow-sm); + background-color: var(--main-bg-color, var(--surface-1)); + box-shadow: 0 0 10px var(--main-shadow, rgba(116, 116, 116, 0.08)); } .box-body { @@ -109,7 +104,11 @@ } .main-shadow { - box-shadow: var(--shadow); + box-shadow: 0 0 10px var(--main-shadow, rgba(116, 116, 116, 0.08)); +} + +.main-bg { + background: var(--main-bg-color, var(--surface-1)); } .muted-box { @@ -123,26 +122,21 @@ * ============================================================ */ html.dark .aksrt-theme-box, body.dark-theme .aksrt-theme-box, -html.dark .theme-box, -body.dark-theme .theme-box, html.dark .box-bg, body.dark-theme .box-bg { border-color: transparent; - box-shadow: var(--shadow-sm); + box-shadow: 0 0 10px var(--main-shadow, rgba(0, 0, 0, 0.2)); } html.dark .aksrt-theme-box:hover, -body.dark-theme .aksrt-theme-box:hover, -html.dark .theme-box:hover, -body.dark-theme .theme-box:hover { - box-shadow: var(--shadow); +body.dark-theme .aksrt-theme-box:hover { + box-shadow: 0 0 10px var(--main-shadow, rgba(0, 0, 0, 0.28)); } /* ============================================================ * 卡片 hover 动效 * ============================================================ */ -.aksrt-theme-box, -.theme-box { +.aksrt-theme-box { transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease); } diff --git a/assets/css/frontend/layout.css b/assets/css/frontend/layout.css index fb94e5b7..730151d4 100644 --- a/assets/css/frontend/layout.css +++ b/assets/css/frontend/layout.css @@ -1,63 +1,4 @@ -/* ========== 面包屑 — 对齐 zibll .breadcrumb ========== */ -.breadcrumbs-wrap { - margin-bottom: 18px; -} - -.breadcrumbs { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 0; - margin: 0; - padding: 0; - list-style: none; - font-size: 13px; - color: var(--muted-2-color, #999); - opacity: 0.8; -} - -.breadcrumbs__item { - display: inline-flex; - align-items: center; - min-width: 0; -} - -.breadcrumbs__item a, -.breadcrumbs__item span { - display: inline-flex; - align-items: center; - gap: 6px; -} - -.breadcrumbs a { - color: var(--muted-2-color, #999); -} - -.breadcrumbs a:hover { - color: var(--focus-color, #f04494); -} - -.breadcrumbs__sep { - margin: 0 0 0 6px; - opacity: 0.6; -} - -@media (max-width: 767px) { - .breadcrumbs { - font-size: 12px; - } - - .breadcrumbs-wrap { - margin-bottom: 14px; - } -} - -/* 封面内面包屑 */ -.single-cover-con .breadcrumbs { - font-size: 13px; - margin: 5px 0 0 -6px; - opacity: unset; -} +/* Breadcrumb chrome lives in breadcrumb.css (single source). */ /* ========== 主布局 ========== */ .content-main { @@ -149,8 +90,16 @@ main.content-shell::after, max-width: 100%; } -.content-layout__aside, +/* Base sidebar column (Zibll .sidebar defaults) — layout variants override below */ .sidebar { + float: left; + width: var(--sidebar-width, 311px); + min-width: 0; + position: relative; + box-sizing: border-box; +} + +.content-layout__aside { min-width: 0; } @@ -171,7 +120,7 @@ body.site-layout-1 .content-layout--no-sidebar { margin-right: 0 !important; } -/* Sidebar RIGHT (layout 2) — Zibll default */ +/* Sidebar RIGHT (layout 2) — Zibll main.css 1:1 */ body.site-layout-2 .content-layout { margin-right: calc(var(--sidebar-width, 311px) + 15px); margin-left: 0; @@ -181,10 +130,11 @@ body.site-layout-2 .sidebar { float: left; width: var(--sidebar-width, 311px); margin-left: calc(0px - var(--sidebar-width, 311px)); - position: relative; + /* Zibll uses position:unset so sticky children aren't trapped */ + position: unset; } -/* Sidebar LEFT (layout 3) */ +/* Sidebar LEFT (layout 3) — Zibll main.css 1:1 */ body.site-layout-3 .content-layout { margin-left: calc(var(--sidebar-width, 311px) + 15px); margin-right: unset; @@ -194,7 +144,7 @@ body.site-layout-3 .sidebar { float: left; width: var(--sidebar-width, 311px); margin-left: -100%; - position: relative; + position: unset; } /* Sticky widgets inside sidebar */ diff --git a/assets/css/frontend/sidebar.css b/assets/css/frontend/sidebar.css index 0fa51c46..bad458dd 100644 --- a/assets/css/frontend/sidebar.css +++ b/assets/css/frontend/sidebar.css @@ -156,13 +156,8 @@ margin-bottom: 12px; } -/* 侧边栏响应式 */ -@media (max-width: 1200px) { - .sidebar { - width: 280px; - } -} - +/* 侧边栏响应式 — width/float 由 layout.css 的 --sidebar-width + site-layout-* 拥有。 + * 禁止在这里硬编码 280px(会与 content-layout gutter 失配导致叠层/空隙)。 */ @media (max-width: 991px) { .sidebar { display: none; diff --git a/assets/css/frontend/single-post/author-actions.css b/assets/css/frontend/single-post/author-actions.css index 5ee72529..f7f465ef 100644 --- a/assets/css/frontend/single-post/author-actions.css +++ b/assets/css/frontend/single-post/author-actions.css @@ -457,10 +457,14 @@ html.dark .post-drop-meta__item:hover { width: 100%; } +.article-avatar .avatar-img { + --this-size: 42px; +} + .article-avatar .avatar-img img, .article-avatar .avatar { - width: 42px; - height: 42px; + width: 100%; + height: 100%; border-radius: 50%; object-fit: cover; } @@ -472,6 +476,8 @@ html.dark .post-drop-meta__item:hover { .article-header .article-avatar .relative { margin-top: 20px; + position: relative; + min-height: 1px; } .single-metabox { @@ -514,11 +520,9 @@ html.dark .post-drop-meta__item:hover { --body-bg-color: rgba(0, 0, 0, 0.3); } -.line-form-line { +/* line-form-line owned by zibll-utilities.css — only context here */ +.article-avatar .line-form-line { display: block; - height: 1px; - background: var(--main-border-color, rgba(50,50,50,.06)); - margin: 12px 0 0; } .post-actions { diff --git a/assets/css/frontend/single-post/content.css b/assets/css/frontend/single-post/content.css index 17ee09d5..bbf616d0 100644 --- a/assets/css/frontend/single-post/content.css +++ b/assets/css/frontend/single-post/content.css @@ -1,9 +1,34 @@ /* ========== Single Post ========== */ + +/* Zibll .article — card body padding wins over .box-body (main.css order) */ +.article, +article.article.box-body, +.article.main-bg.box-body { + padding: 0 30px; + overflow: hidden; +} + +@media (max-width: 767px) { + .article, + article.article.box-body, + .article.main-bg.box-body { + padding: 0 15px; + } + + .article-header .article-title { + font-size: 18px; + } +} + .entry-header, .article-header { margin-bottom: 10px; padding-bottom: 0; border-bottom: none; + /* theme-box is spacing only — never paint a nested card here */ + background: transparent; + box-shadow: none; + border-radius: 0; } /* 标题 — 对齐 zibll: 22px, bold, line-height 1.4 */ @@ -17,6 +42,10 @@ color: var(--key-color, var(--color-ink)); } +.article-title > a:hover { + color: inherit; +} + .article-header .article-title { font-size: 22px; font-weight: bold; diff --git a/assets/css/frontend/single-post/cover.css b/assets/css/frontend/single-post/cover.css index f37a4a2f..eb863168 100644 --- a/assets/css/frontend/single-post/cover.css +++ b/assets/css/frontend/single-post/cover.css @@ -3,14 +3,20 @@ * The cover stays inside the content column with a fixed aspect ratio box. * ============================================================ */ -/* ===== Cover (in-column ratio box) ===== */ +/* ===== Cover (in-column ratio box) — Zibll .single-cover ===== */ .single-cover { position: relative; overflow: hidden; - border-radius: var(--radius-2xl, 16px); - box-shadow: var(--shadow-sm); + border-radius: var(--main-radius, var(--radius, 8px)); + box-shadow: 0 0 10px var(--main-shadow, rgba(116, 116, 116, 0.08)); margin-bottom: 20px; - padding-bottom: var(--single-cover-scale, 35%); + /* Zibll: padding-bottom: calc(var(--single-cover-scale) + 50px) */ + padding-bottom: calc(var(--single-cover-scale, 35%) + 50px); +} + +.single-cover-slide { + padding-bottom: calc(var(--scale-height, var(--single-cover-scale, 35%)) + 50px); + border-radius: var(--main-radius, var(--radius, 8px)); } .single-cover > .fit-cover, @@ -22,6 +28,25 @@ object-fit: cover; } +.single-cover-con { + color: #fff; + padding: 15px 15px 10px 15px; + border-radius: 0 0 var(--main-radius, var(--radius, 8px)) var(--main-radius, var(--radius, 8px)); + background-image: linear-gradient(0deg, rgba(29, 41, 49, 0.5), rgba(255, 255, 255, 0)); + padding-top: 2em; +} + +.single-cover-con a { + color: #fff; +} + +.single-video .article-title, +.single-cover-con .article-title { + font-size: 18px; + font-weight: 700; +} + +/* Legacy overlay helpers (kept for non-zibll markup) */ .single-cover__overlay { position: absolute; inset: 0; @@ -40,7 +65,7 @@ right: 0; padding: 24px; color: #fff; - border-radius: 0 0 var(--radius-2xl, 16px) var(--radius-2xl, 16px); + border-radius: 0 0 var(--main-radius, var(--radius, 8px)) var(--main-radius, var(--radius, 8px)); } .single-cover__title, @@ -155,23 +180,13 @@ position: relative; } -.article-avatar .line-form-line, -.article-avatar .line-form-line::before { - position: absolute; - top: 50%; - left: calc(52px + 16px); - right: 120px; - height: 1px; - transform: translateY(-50%); - background: var(--color-line); -} - -.article-avatar .line-form-line::before { - content: ""; - right: auto; - width: 42px; - background: var(--color-primary, #f04494); - opacity: 0.3; +/* line-form-line geometry owned by zibll-utilities.css (absolute full-width bottom). + * Here only ensure the meta row has height so the rule sits correctly. */ +.article-header .article-avatar .relative { + margin-top: 20px; + position: relative; + min-height: 1px; + padding-bottom: 1px; } /* ===== Article Card ===== */ @@ -253,11 +268,11 @@ .single-cover-slide-wrap { position: relative; overflow: hidden; - border-radius: var(--radius-2xl, 16px); + border-radius: var(--main-radius, var(--radius, 8px)); } .single-cover-slide-wrap .abs-center.left-bottom { z-index: 2; - padding: 18px 20px; + padding: 15px 15px 10px 15px; color: #fff; } .article-avatar name.flex { @@ -277,11 +292,23 @@ /* Slide cover overlay (injected by aksrt_render_slider overlay_html) */ .aksrt-slider-wrapper--has-overlay, -.aksrt-slider-wrapper--scale { position: relative; overflow: hidden; border-radius: var(--radius-2xl, 16px); } +.aksrt-slider-wrapper--scale { + position: relative; + overflow: hidden; + border-radius: var(--main-radius, var(--radius, 8px)); +} .aksrt-slider-wrapper--scale .new-swiper { position: absolute; inset: 0; width: 100%; height: 100%; } .aksrt-slider-wrapper--scale .swiper-slide img.fit-cover { width: 100%; height: 100%; object-fit: cover; } .aksrt-slider-overlay { position: absolute; inset: 0; z-index: 3; pointer-events: none; } -.aksrt-slider-overlay .abs-center.left-bottom { pointer-events: none; padding: 18px 20px; color: #fff; } +.aksrt-slider-overlay .abs-center.left-bottom { + pointer-events: none; + padding: 15px 15px 10px 15px; + color: #fff; + background-image: linear-gradient(0deg, rgba(29, 41, 49, 0.5), rgba(255, 255, 255, 0)); + padding-top: 2em; + width: 100%; + box-sizing: border-box; +} .aksrt-slider-overlay .article-title, .aksrt-slider-overlay .article-title.title-h-left { color: #fff; text-shadow: 0 1px 4px rgba(0,0,0,.45); } .aksrt-slider-overlay .breadcrumb a, diff --git a/assets/css/frontend/single-post/shell.css b/assets/css/frontend/single-post/shell.css index 359b6e04..27349db9 100644 --- a/assets/css/frontend/single-post/shell.css +++ b/assets/css/frontend/single-post/shell.css @@ -25,7 +25,7 @@ body.single main.container .content-layout > .breadcrumbs-wrap { padding-top: 2px; } -/* Sticky TOC widget in sidebar */ +/* Sticky TOC widget in sidebar — parent .sidebar is position:unset like Zibll */ body.single .sidebar .posts-nav-box.toc-widget { position: sticky; top: calc(var(--nav-height, 60px) + 16px); @@ -35,3 +35,8 @@ body.single .sidebar .zib-widget, body.single .sidebar .widget { margin-bottom: 15px; } + +/* Geometry owned by base/layout — keep single shell free of float overrides. */ +body.single main.container { + box-sizing: border-box; +} diff --git a/assets/css/frontend/zibll-utilities.css b/assets/css/frontend/zibll-utilities.css index c913eff9..1bf25ea2 100644 --- a/assets/css/frontend/zibll-utilities.css +++ b/assets/css/frontend/zibll-utilities.css @@ -49,6 +49,132 @@ transform: translate(-50%, -50%); } +/* Zibll abs-center position variants (main.css) */ +.abs-center.left-bottom, +.abs-center.right-bottom, +.abs-center.conter-bottom { + top: auto; + transform: unset; + bottom: 0; +} + +.abs-center.left-bottom { + left: 0; + right: auto; + text-align: left; +} + +.abs-center.right-bottom, +.abs-center.right-conter { + left: auto; + right: 0; + text-align: right; +} + +/* Graphic ratio box (cover / related thumbs) — Zibll .graphic */ +.graphic, +.page-cover { + text-shadow: 0 0 5px rgba(0, 0, 0, 0.2); + --main-color: #fff; + color: #fff; + position: relative; + overflow: hidden; + box-shadow: 0 0 10px var(--main-shadow, rgba(116, 116, 116, 0.08)); + padding: 0; + padding-bottom: 70%; + border-radius: var(--main-radius, var(--radius, 8px)); +} + +.graphic > .fit-cover, +.graphic > img.fit-cover { + position: absolute; + width: 100%; + height: 100%; + object-fit: cover; + inset: 0; +} + +.fit-cover { + object-fit: cover; + max-width: 100%; +} + +/* title-h-left underline bar (Zibll) */ +.title-h-left { + position: relative; + padding-bottom: 8px; +} + +.title-h-left:before { + transition: 0.4s; + transform-origin: left; + position: absolute; + content: ""; + width: 40px; + height: 3px; + background: var(--theme-color, var(--focus-color, #f04494)); + left: 0; + bottom: 3px; + border-radius: 5px; + box-shadow: 1px 1px 3px -1px var(--theme-color, var(--focus-color, #f04494)); +} + +/* line-form-line — Zibll absolute bottom rule (author meta separator) */ +.line-form-line, +.line-form-line:before { + position: absolute; + bottom: 0; + left: 0; + height: 1px; + width: 100%; + transition: 0.8s; + background: var(--main-border-color, rgba(50, 50, 50, 0.06)); +} + +.line-form-line:before { + content: ""; + width: 0; + background: var(--focus-color, #f04494); +} + +/* Avatar size primitive */ +.avatar-img { + position: relative; + display: inline-block; + flex-shrink: 0; + --this-size: 38px; + width: var(--this-size); + height: var(--this-size); +} + +.avatar-img .avatar, +.avatar-img img { + width: 100%; + height: 100%; + border-radius: 50%; + object-fit: cover; +} + +.avatar-lg { + --this-size: 80px; +} + +.avatar-md { + --this-size: 55px; +} + +.avatar-mini { + --this-size: 20px; +} + +.shrink0 { + flex-shrink: 0; +} + +.opacity8 { + opacity: 0.8; +} + /* Typography / color helpers */ .muted-color { color: var(--muted-color, var(--color-ink-3)); } .muted-2-color { color: var(--muted-2-color, var(--color-ink-4)); } diff --git a/inc/bootstrap.php b/inc/bootstrap.php index 73278505..7571b587 100644 --- a/inc/bootstrap.php +++ b/inc/bootstrap.php @@ -29,6 +29,7 @@ require_once AKSRT_DIR . '/inc/helpers/aksrt-flow.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-homepage.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-single-components.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-single.php'; +require_once AKSRT_DIR . '/inc/helpers/aksrt-single-render.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-archive.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-archive-filters.php'; require_once AKSRT_DIR . '/inc/helpers/aksrt-comments.php'; diff --git a/inc/helpers/aksrt-single-render.php b/inc/helpers/aksrt-single-render.php new file mode 100644 index 00000000..3de983cf --- /dev/null +++ b/inc/helpers/aksrt-single-render.php @@ -0,0 +1,812 @@ + $ctx Single context. + */ + function aksrt_single_render_cover(array $ctx): void { + if (empty($ctx['show_cover']) || $ctx['cover_url'] === '') { + return; + } + + $type = (string) $ctx['cover_type']; + $badge = (string) $ctx['status_badge']; + $crumbs = (string) $ctx['breadcrumbs_html']; + $meta_box = (string) ($ctx['meta_box_html'] ?? ''); + $img_scale = max(10, min(100, (int) $ctx['img_scale'])); + $video_scale = max(20, min(100, (int) $ctx['video_scale'])); + $episode = (int) $ctx['episode_count']; + $slides = is_array($ctx['slide_images'] ?? null) ? $ctx['slide_images'] : []; + $poster = (string) ($ctx['video_poster'] ?? ''); + $title_html = (string) ($ctx['title_html'] ?? esc_html(get_the_title())); + + if ($type === 'video') : + ?> +
    +
    +
    +
    style="position:absolute;inset:0;width:100%;height:100%;">
    +
    + +
    +
    + (string) $slide_url, + 'alt' => wp_strip_all_tags(get_the_title()), + ]; + } + $overlay = '
    ' + . '

    ' . $title_html . '

    ' + . ($crumbs !== '' ? $crumbs : '') + . $badge + . '
    ' + . ($meta_box !== '' ? str_replace('abs-right', 'cover-meta abs-right', $meta_box) : ''); + $slider_html = ''; + if (function_exists('aksrt_render_slider')) { + $slider_html = aksrt_render_slider([ + 'slides' => $slide_items, + 'scale_height' => true, + 'scale_ratio' => $img_scale / 100, + 'wrapper_class' => 'mb20 single-cover-slide imgbox-container', + 'slider_class' => 'single-cover single-cover--slide', + 'show_nav' => true, + 'show_pagination' => true, + 'loop' => count($slide_items) > 1, + 'autoplay' => count($slide_items) > 1, + 'overlay_html' => $overlay, + ]); + } + ?> +
    + + + +
    + $slide_url) : ?> + + + +
    + +
    + +
    +
    + alt=""> +
    +

    + + + + +
    + + + +
    +
    + $ctx Single context. + */ + function aksrt_single_render_box_header(array $ctx): void { + $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; + ?> +
    + + +

    + + + true, + 'show_time' => empty($settings['hide_time']), + 'meta_html' => empty($ctx['show_cover']) ? (string) ($ctx['meta_box_html'] ?? '') : '', + ]); + ?> +
    + $ctx Single context. + */ + function aksrt_single_render_actions(array $ctx): void { + $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; + $post_id = (int) $ctx['post_id']; + $like_count = (int) $ctx['like_count']; + $favorite_count = (int) $ctx['favorite_count']; + $is_liked = !empty($ctx['is_liked']); + $is_favorited = !empty($ctx['is_favorited']); + ?> +
    +
    +
    + + + + + + + + + + + + + + + +
    + + + + +
    + + + + + $ctx Single context. + */ + function aksrt_single_render_content_footer(array $ctx): void { + $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; + $post_id = (int) $ctx['post_id']; + ?> + +
    + + + +
    +
    ©
    + +
    + + +
    THE END
    + + $ctx Single context. + */ + function aksrt_single_render_author_card(array $ctx): void { + $author_id = (int) get_the_author_meta('ID'); + if ($author_id <= 0) { + return; + } + $author_url = get_author_posts_url($author_id); + $author_name = get_the_author(); + $bio = trim((string) get_the_author_meta('description')); + $vip_badge = function_exists('aksrt_render_vip_badge') ? aksrt_render_vip_badge($author_id, 'sm') : ''; + $signals = []; + if (class_exists('AKSRT_User_Home')) { + $signals = AKSRT_User_Home::get_instance()->get_profile_signals($author_id); + } + $avatar = function_exists('aksrt_get_avatar_html') + ? aksrt_get_avatar_html($author_id, 80, ['class' => 'avatar avatar-lg']) + : get_avatar($author_id, 80, '', esc_attr($author_name), ['class' => 'avatar avatar-lg']); + $recent = get_posts([ + 'author' => $author_id, + 'post_type' => 'post', + 'post_status' => 'publish', + 'posts_per_page' => 6, + 'orderby' => 'date', + 'order' => 'DESC', + 'no_found_rows' => true, + ]); + ?> +
    +
    +
    +
    + +
    + +
    +
      + + +
    • + + +
    +
    + +
    +
    + $ctx Single context. + */ + function aksrt_single_render_prevnext(array $ctx = []): void { + $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; + $enabled = array_key_exists('prevnext', $settings) + ? !empty($settings['prevnext']) + : (!array_key_exists('prevnext_s', $settings) || !empty($settings['prevnext_s'])); + if (!$enabled) { + return; + } + + // Zibll: constrain to current category when available. + $in_same_term = !empty(get_the_category()); + $prev = get_previous_post($in_same_term, '', 'category'); + $next = get_next_post($in_same_term, '', 'category'); + if (!$prev && !$next) { + // Fallback: any post. + $prev = get_previous_post(); + $next = get_next_post(); + } + if (!$prev && !$next) { + return; + } + + $prev_title = $prev ? get_the_title($prev) : __('无更多文章', 'aksrt'); + $next_title = $next ? get_the_title($next) : __('无更多文章', 'aksrt'); + $prev_href = $prev ? get_permalink($prev) : 'javascript:;'; + $next_href = $next ? get_permalink($next) : 'javascript:;'; + ?> +
    + +
    + $settings Single display settings. + * @return array + */ + 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)) { + $orderby = 'views'; + } + + $args = [ + 'post_type' => get_post_type($post_id) ?: 'post', + 'post_status' => 'publish', + 'post__not_in' => [$post_id], + 'posts_per_page' => $count, + 'ignore_sticky_posts' => true, + 'no_found_rows' => true, + '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 + topics like Zibll. + $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 (taxonomy_exists('topics')) { + $topic_ids = wp_get_post_terms($post_id, 'topics', ['fields' => 'ids']); + if (!empty($topic_ids) && !is_wp_error($topic_ids)) { + $tax_query[] = [ + 'taxonomy' => 'topics', + 'field' => 'term_id', + 'terms' => array_map('intval', $topic_ids), + ]; + } + } + } + + if (count($tax_query) > 1) { + $args['tax_query'] = $tax_query; + } + + switch ($orderby) { + case 'rand': + $args['orderby'] = 'rand'; + break; + case 'date': + $args['orderby'] = 'date'; + break; + case 'modified': + $args['orderby'] = 'modified'; + break; + case 'views': + $args['meta_key'] = 'aksrt_post_views'; + $args['orderby'] = 'meta_value_num'; + break; + case 'relevance': + default: + // Prefer date when no search relevance context. + $args['orderby'] = 'date'; + break; + } + + return $args; + } +endif; + +if (!function_exists('aksrt_single_render_related')) : + /** + * Related posts — Zibll-like list + optional shared mini renderer. + * + * @param array $ctx Single context. + */ + function aksrt_single_render_related(array $ctx): void { + $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; + if (empty($settings['related_enabled'])) { + return; + } + + $post_id = (int) $ctx['post_id']; + $title = (string) ($settings['related_title'] ?? ''); + if ($title === '') { + $title = __('相关推荐', 'aksrt'); + } + $style = sanitize_key((string) ($settings['related_style'] ?? 'img')); + if (!in_array($style, ['img', 'list', 'text'], true)) { + $style = 'img'; + } + + $args = function_exists('aksrt_single_related_query_args') + ? aksrt_single_related_query_args($post_id, $settings) + : [ + 'post_type' => get_post_type($post_id) ?: 'post', + 'post_status' => 'publish', + 'post__not_in' => [$post_id], + 'posts_per_page' => max(1, min(12, (int) ($settings['related_count'] ?? 6))), + 'ignore_sticky_posts' => true, + ]; + + $query = new WP_Query($args); + if (!$query->have_posts()) { + wp_reset_postdata(); + return; + } + + $wrap_class = 'theme-box relates' . ($style === 'img' ? ' relates-thumb' : ''); + ?> +
    +
    +
    +
    +
    + + 'related', + 'mode' => 'mini', + 'show_thumb' => true, + 'show_meta' => true, + 'show_number' => false, + ]); + ?> + + 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 .= '
  • ' . esc_html(get_the_title($p)) . '
  • '; + } + } + ?> + +
    +
    + +
    +
    +
    +
    + + + + + + + $ctx Single context. + */ + function aksrt_single_render_pay_box(array $ctx = []): void { + if ($ctx === []) { + $ctx = function_exists('aksrt_single_build_context') ? aksrt_single_build_context() : []; + } + if (empty($ctx['show_pay_box'])) { + return; + } + $allow = $ctx['allow_view'] ?? null; + if (is_array($allow) && empty($allow['allow'])) { + return; + } + + $post_id = (int) ($ctx['post_id'] ?? get_the_ID()); + $post = get_post($post_id); + if (!($post instanceof WP_Post)) { + return; + } + + $pay_type = (string) ($ctx['pay_type'] ?? 'no'); + if (!empty($ctx['has_download']) || $pay_type === 'download') { + echo '
    '; + get_template_part('templates/parts/resource-download-box'); + echo '
    '; + return; + } + + if (!function_exists('aksrt_get_pay_meta')) { + return; + } + + $has_access = function_exists('aksrt_has_paid_access') ? aksrt_has_paid_access($post) : false; + $paid_class = $has_access ? 'paid-box' : 'pay-box'; + echo '
    '; + if ($has_access) { + if ($pay_type === 'gallery' && function_exists('aksrt_render_paid_gallery')) { + echo aksrt_render_paid_gallery($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } elseif ($pay_type === 'video' && function_exists('aksrt_render_paid_video')) { + echo aksrt_render_paid_video($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } else { + echo '
    ' . esc_html__('已解锁', 'aksrt') . '' . esc_html(get_the_title($post)) . '
    '; + } + } elseif (function_exists('aksrt_get_paywall_html')) { + echo aksrt_get_paywall_html($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + echo '
    '; + } +endif; + +if (!function_exists('aksrt_single_pay_box_matches')) : + /** + * @param array $ctx + */ + function aksrt_single_pay_box_matches(array $ctx, string $slot): bool { + if (empty($ctx['show_pay_box'])) { + return false; + } + $allow = $ctx['allow_view'] ?? null; + if (is_array($allow) && empty($allow['allow'])) { + return false; + } + return (string) ($ctx['paid_box_position'] ?? 'top') === $slot; + } +endif; + +if (!function_exists('aksrt_single_render_article')) : + /** + * Main article box (Zibll zib_single_content order). + * + * @param array $ctx Single context. + */ + function aksrt_single_render_article(array $ctx): void { + $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; + $maxheight = (int) $ctx['content_maxheight']; + ?> +
    > + + +
    + +
    + + + + + + + + + +
    + + +
    0 ? ' style="max-height:' . esc_attr((string) $maxheight) . 'px;"' : ''; ?> + + data-maxheight=" 0 ? max(0, $maxheight - 80) : 0)); ?>" + data-aksrt-toc="" + data-aksrt-toc-depth="" + > + + '

    ', + 'after' => '

    ', + ]); + ?> + + + +
    + + + + + + +
    + + +
    + $ctx Single context. + */ + function aksrt_single_render_after_box(array $ctx): void { + $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; + + if (!empty($settings['yiyan_box'])) { + ?> +
    + $ctx Single context. + */ + function aksrt_single_render_aside(array $ctx): void { + if (empty($ctx['show_aside']) || wp_is_mobile()) { + return; + } + ?> + + $ctx Single context. - */ - function aksrt_single_render_cover(array $ctx): void { - if (empty($ctx['show_cover']) || $ctx['cover_url'] === '') { - return; - } - - $type = (string) $ctx['cover_type']; - $badge = (string) $ctx['status_badge']; - $crumbs = (string) $ctx['breadcrumbs_html']; - $meta_box = (string) ($ctx['meta_box_html'] ?? ''); - $img_scale = max(10, min(100, (int) $ctx['img_scale'])); - $video_scale = max(20, min(100, (int) $ctx['video_scale'])); - $episode = (int) $ctx['episode_count']; - $slides = is_array($ctx['slide_images'] ?? null) ? $ctx['slide_images'] : []; - $poster = (string) ($ctx['video_poster'] ?? ''); - $title_html = (string) ($ctx['title_html'] ?? esc_html(get_the_title())); - - if ($type === 'video') : - ?> -
    -
    -
    -
    style="position:absolute;inset:0;width:100%;height:100%;">
    -
    - -
    -
    - (string) $slide_url, - 'alt' => wp_strip_all_tags(get_the_title()), - ]; - } - $overlay = '
    ' - . '

    ' . $title_html . '

    ' - . ($crumbs !== '' ? $crumbs : '') - . $badge - . '
    ' - . ($meta_box !== '' ? str_replace('abs-right', 'cover-meta abs-right', $meta_box) : ''); - $slider_html = ''; - if (function_exists('aksrt_render_slider')) { - $slider_html = aksrt_render_slider([ - 'slides' => $slide_items, - 'scale_height' => true, - 'scale_ratio' => $img_scale / 100, - 'wrapper_class' => 'mb20 single-cover-slide imgbox-container', - 'slider_class' => 'single-cover single-cover--slide', - 'show_nav' => true, - 'show_pagination' => true, - 'loop' => count($slide_items) > 1, - 'autoplay' => count($slide_items) > 1, - 'overlay_html' => $overlay, - ]); - } - ?> -
    - - - -
    - $slide_url) : ?> - - - -
    - -
    - -
    -
    - alt=""> -
    -

    - - - - -
    - - - -
    -
    - $ctx Single context. - */ - function aksrt_single_render_box_header(array $ctx): void { - $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; - ?> -
    - - -

    - - - true, - 'show_time' => empty($settings['hide_time']), - 'meta_html' => empty($ctx['show_cover']) ? (string) ($ctx['meta_box_html'] ?? '') : '', - ]); - ?> -
    - $ctx Single context. - */ - function aksrt_single_render_actions(array $ctx): void { - $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; - $post_id = (int) $ctx['post_id']; - $like_count = (int) $ctx['like_count']; - $favorite_count = (int) $ctx['favorite_count']; - $is_liked = !empty($ctx['is_liked']); - $is_favorited = !empty($ctx['is_favorited']); - ?> -
    -
    -
    - - - - - - - - - - - - - - - -
    - - - - -
    - - - - - $ctx Single context. - */ - function aksrt_single_render_content_footer(array $ctx): void { - $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; - $post_id = (int) $ctx['post_id']; - ?> - -
    - - - -
    -
    ©
    - -
    - - -
    THE END
    - - $ctx Single context. - */ - function aksrt_single_render_author_card(array $ctx): void { - $author_id = (int) get_the_author_meta('ID'); - if ($author_id <= 0) { - return; - } - $author_url = get_author_posts_url($author_id); - $author_name = get_the_author(); - $bio = trim((string) get_the_author_meta('description')); - $vip_badge = function_exists('aksrt_render_vip_badge') ? aksrt_render_vip_badge($author_id, 'sm') : ''; - $signals = []; - if (class_exists('AKSRT_User_Home')) { - $signals = AKSRT_User_Home::get_instance()->get_profile_signals($author_id); - } - $avatar = function_exists('aksrt_get_avatar_html') - ? aksrt_get_avatar_html($author_id, 80, ['class' => 'avatar avatar-lg']) - : get_avatar($author_id, 80, '', esc_attr($author_name), ['class' => 'avatar avatar-lg']); - $recent = get_posts([ - 'author' => $author_id, - 'post_type' => 'post', - 'post_status' => 'publish', - 'posts_per_page' => 6, - 'orderby' => 'date', - 'order' => 'DESC', - 'no_found_rows' => true, - ]); - ?> -
    -
    -
    -
    - -
    - -
    -
      - - -
    • - - -
    -
    - -
    -
    - $ctx Single context. - */ - function aksrt_single_render_prevnext(array $ctx = []): void { - $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; - $enabled = array_key_exists('prevnext', $settings) - ? !empty($settings['prevnext']) - : (!array_key_exists('prevnext_s', $settings) || !empty($settings['prevnext_s'])); - if (!$enabled) { - return; - } - - // Zibll: constrain to current category when available. - $in_same_term = !empty(get_the_category()); - $prev = get_previous_post($in_same_term, '', 'category'); - $next = get_next_post($in_same_term, '', 'category'); - if (!$prev && !$next) { - // Fallback: any post. - $prev = get_previous_post(); - $next = get_next_post(); - } - if (!$prev && !$next) { - return; - } - - $prev_title = $prev ? get_the_title($prev) : __('无更多文章', 'aksrt'); - $next_title = $next ? get_the_title($next) : __('无更多文章', 'aksrt'); - $prev_href = $prev ? get_permalink($prev) : 'javascript:;'; - $next_href = $next ? get_permalink($next) : 'javascript:;'; - ?> -
    - -
    - $settings Single display settings. - * @return array - */ - 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)) { - $orderby = 'views'; - } - - $args = [ - 'post_type' => get_post_type($post_id) ?: 'post', - 'post_status' => 'publish', - 'post__not_in' => [$post_id], - 'posts_per_page' => $count, - 'ignore_sticky_posts' => true, - 'no_found_rows' => true, - '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 + topics like Zibll. - $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 (taxonomy_exists('topics')) { - $topic_ids = wp_get_post_terms($post_id, 'topics', ['fields' => 'ids']); - if (!empty($topic_ids) && !is_wp_error($topic_ids)) { - $tax_query[] = [ - 'taxonomy' => 'topics', - 'field' => 'term_id', - 'terms' => array_map('intval', $topic_ids), - ]; - } - } - } - - if (count($tax_query) > 1) { - $args['tax_query'] = $tax_query; - } - - switch ($orderby) { - case 'rand': - $args['orderby'] = 'rand'; - break; - case 'date': - $args['orderby'] = 'date'; - break; - case 'modified': - $args['orderby'] = 'modified'; - break; - case 'views': - $args['meta_key'] = 'aksrt_post_views'; - $args['orderby'] = 'meta_value_num'; - break; - case 'relevance': - default: - // Prefer date when no search relevance context. - $args['orderby'] = 'date'; - break; - } - - return $args; - } -endif; - -if (!function_exists('aksrt_single_render_related')) : - /** - * Related posts — Zibll-like list + optional shared mini renderer. - * - * @param array $ctx Single context. - */ - function aksrt_single_render_related(array $ctx): void { - $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; - if (empty($settings['related_enabled'])) { - return; - } - - $post_id = (int) $ctx['post_id']; - $title = (string) ($settings['related_title'] ?? ''); - if ($title === '') { - $title = __('相关推荐', 'aksrt'); - } - $style = sanitize_key((string) ($settings['related_style'] ?? 'img')); - if (!in_array($style, ['img', 'list', 'text'], true)) { - $style = 'img'; - } - - $args = function_exists('aksrt_single_related_query_args') - ? aksrt_single_related_query_args($post_id, $settings) - : [ - 'post_type' => get_post_type($post_id) ?: 'post', - 'post_status' => 'publish', - 'post__not_in' => [$post_id], - 'posts_per_page' => max(1, min(12, (int) ($settings['related_count'] ?? 6))), - 'ignore_sticky_posts' => true, - ]; - - $query = new WP_Query($args); - if (!$query->have_posts()) { - wp_reset_postdata(); - return; - } - - $wrap_class = 'theme-box relates' . ($style === 'img' ? ' relates-thumb' : ''); - ?> -
    -
    -
    -
    -
    - - 'related', - 'mode' => 'mini', - 'show_thumb' => true, - 'show_meta' => true, - 'show_number' => false, - ]); - ?> - - 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 .= '
  • ' . esc_html(get_the_title($p)) . '
  • '; - } - } - ?> - -
    -
    - -
    -
    -
    -
    - -
      - ' . esc_html__('暂无相关文章', 'aksrt') . ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> -
    - - -
    -
    - $ctx Single context. - */ - function aksrt_single_render_pay_box(array $ctx = []): void { - if ($ctx === []) { - $ctx = function_exists('aksrt_single_build_context') ? aksrt_single_build_context() : []; - } - if (empty($ctx['show_pay_box'])) { - return; - } - $allow = $ctx['allow_view'] ?? null; - if (is_array($allow) && empty($allow['allow'])) { - return; - } - - $post_id = (int) ($ctx['post_id'] ?? get_the_ID()); - $post = get_post($post_id); - if (!($post instanceof WP_Post)) { - return; - } - - $pay_type = (string) ($ctx['pay_type'] ?? 'no'); - if (!empty($ctx['has_download']) || $pay_type === 'download') { - echo '
    '; - get_template_part('templates/parts/resource-download-box'); - echo '
    '; - return; - } - - if (!function_exists('aksrt_get_pay_meta')) { - return; - } - - $has_access = function_exists('aksrt_has_paid_access') ? aksrt_has_paid_access($post) : false; - $paid_class = $has_access ? 'paid-box' : 'pay-box'; - echo '
    '; - if ($has_access) { - if ($pay_type === 'gallery' && function_exists('aksrt_render_paid_gallery')) { - echo aksrt_render_paid_gallery($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } elseif ($pay_type === 'video' && function_exists('aksrt_render_paid_video')) { - echo aksrt_render_paid_video($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } else { - echo '
    ' . esc_html__('已解锁', 'aksrt') . '' . esc_html(get_the_title($post)) . '
    '; - } - } elseif (function_exists('aksrt_get_paywall_html')) { - echo aksrt_get_paywall_html($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - } - echo '
    '; - } -endif; - -if (!function_exists('aksrt_single_pay_box_matches')) : - /** - * @param array $ctx - */ - function aksrt_single_pay_box_matches(array $ctx, string $slot): bool { - if (empty($ctx['show_pay_box'])) { - return false; - } - $allow = $ctx['allow_view'] ?? null; - if (is_array($allow) && empty($allow['allow'])) { - return false; - } - return (string) ($ctx['paid_box_position'] ?? 'top') === $slot; - } -endif; - -if (!function_exists('aksrt_single_render_article')) : - /** - * Main article box (Zibll zib_single_content order). - * - * @param array $ctx Single context. - */ - function aksrt_single_render_article(array $ctx): void { - $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; - $maxheight = (int) $ctx['content_maxheight']; - ?> -
    > - - -
    - -
    - - - - - - - - - -
    - - -
    0 ? ' style="max-height:' . esc_attr((string) $maxheight) . 'px;"' : ''; ?> - - data-maxheight=" 0 ? max(0, $maxheight - 80) : 0)); ?>" - data-aksrt-toc="" - data-aksrt-toc-depth="" - > - - '

    ', - 'after' => '

    ', - ]); - ?> - - - -
    - - - - - - -
    - - -
    - $ctx Single context. - */ - function aksrt_single_render_after_box(array $ctx): void { - $settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : []; - - if (!empty($settings['yiyan_box'])) { - ?> -
    - $ctx Single context. - */ - function aksrt_single_render_aside(array $ctx): void { - if (empty($ctx['show_aside']) || wp_is_mobile()) { - return; - } - ?> - - - 'avatar avatar-id-' . $author_id]); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> + 'avatar avatar-id-' . $author_id]); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> - 'avatar avatar-id-' . $author_id]); ?> + 'avatar avatar-id-' . $author_id]); ?>