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.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 " </li><li> " — 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)); }
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -0,0 +1,812 @@
|
||||
<?php
|
||||
/**
|
||||
* Single post render helpers (Zibll-style composition pieces).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
if (!function_exists('aksrt_single_render_cover')) :
|
||||
/**
|
||||
* Cover / slide / video header (Zibll single-head-cover).
|
||||
*
|
||||
* @param array<string,mixed> $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') :
|
||||
?>
|
||||
<div class="single-head-cover">
|
||||
<div class="single-video">
|
||||
<div class="graphic single-cover single-cover--video imgbox-container" style="padding-bottom:<?php echo esc_attr((string) $video_scale); ?>%;">
|
||||
<div class="aksrt-video single-cover__player" data-aksrt-video data-src="<?php echo esc_url($ctx['cover_url']); ?>"<?php echo $poster !== '' ? ' data-poster="' . esc_url($poster) . '"' : ''; ?> style="position:absolute;inset:0;width:100%;height:100%;"></div>
|
||||
</div>
|
||||
<div class="single-video-footer dplayer-featured">
|
||||
<div class="flex jsb at">
|
||||
<?php if ($crumbs !== '') : ?>
|
||||
<div class="post-breadcrumbs"><?php echo $crumbs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($meta_box !== '') : ?>
|
||||
<?php echo str_replace('abs-right', 'mb10 ml10 shrink0', $meta_box); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<h1 class="article-title">
|
||||
<?php
|
||||
$episodes = is_array($ctx['video_episodes'] ?? null) ? $ctx['video_episodes'] : [];
|
||||
if ($episodes === [] && !empty($ctx['cover_url'])) {
|
||||
$episodes = [['url' => (string) $ctx['cover_url'], 'title' => '']];
|
||||
}
|
||||
$ep_count = count($episodes);
|
||||
if ($ep_count > 1) : ?>
|
||||
<span class="badg badg-sm b-theme mr6"><i class="fa fa-play-circle mr3" aria-hidden="true"></i><?php printf(esc_html__('共%d集', 'aksrt'), $ep_count); ?></span>
|
||||
<?php else : ?>
|
||||
<i class="fa fa-play-circle-o mr6 opacity8" aria-hidden="true"></i>
|
||||
<?php endif; ?>
|
||||
<?php echo $title_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</h1>
|
||||
<?php echo $badge; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php if ($ep_count > 0) : ?>
|
||||
<div class="featured-video-episode mt10">
|
||||
<?php foreach ($episodes as $idx => $ep) :
|
||||
$ep_url = (string) ($ep['url'] ?? '');
|
||||
if ($ep_url === '') { continue; }
|
||||
$ep_title = trim((string) ($ep['title'] ?? ''));
|
||||
if ($ep_title === '') {
|
||||
$ep_title = sprintf(__('第%d集', 'aksrt'), $idx + 1);
|
||||
}
|
||||
?>
|
||||
<a href="javascript:;" class="switch-video text-ellipsis<?php echo $idx === 0 ? ' active' : ''; ?>" data-index="<?php echo (int) ($idx + 1); ?>" data-src="<?php echo esc_url($ep_url); ?>">
|
||||
<span class="mr6 badg badg-sm"><?php echo (int) ($idx + 1); ?></span><i class="episode-active-icon"></i><?php echo esc_html($ep_title); ?>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return;
|
||||
endif;
|
||||
|
||||
if ($type === 'slide' && !empty($slides)) :
|
||||
$slide_items = [];
|
||||
foreach ($slides as $slide_url) {
|
||||
$slide_items[] = [
|
||||
'image' => (string) $slide_url,
|
||||
'alt' => wp_strip_all_tags(get_the_title()),
|
||||
];
|
||||
}
|
||||
$overlay = '<div class="abs-center left-bottom single-cover-con">'
|
||||
. '<h1 class="article-title title-h-left">' . $title_html . '</h1>'
|
||||
. ($crumbs !== '' ? $crumbs : '')
|
||||
. $badge
|
||||
. '</div>'
|
||||
. ($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,
|
||||
]);
|
||||
}
|
||||
?>
|
||||
<div class="single-head-cover">
|
||||
<?php if ($slider_html !== '') : ?>
|
||||
<?php echo $slider_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php else : ?>
|
||||
<div class="graphic mb20 single-cover single-cover--slide imgbox-container" style="padding-bottom:calc(<?php echo esc_attr((string) $img_scale); ?>% + 50px);">
|
||||
<?php foreach ($slides as $idx => $slide_url) : ?>
|
||||
<img src="<?php echo esc_url($slide_url); ?>" alt="" class="fit-cover" style="<?php echo $idx === 0 ? '' : 'display:none;'; ?>" loading="<?php echo $idx === 0 ? 'eager' : 'lazy'; ?>">
|
||||
<?php endforeach; ?>
|
||||
<?php echo $overlay; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return;
|
||||
endif;
|
||||
|
||||
// Image cover (default).
|
||||
$img_attrs = function_exists('aksrt_lazy_img_attrs')
|
||||
? aksrt_lazy_img_attrs((string) $ctx['cover_url'], 'cover', 'fit-cover')
|
||||
: 'class="fit-cover" src="' . esc_url((string) $ctx['cover_url']) . '" loading="eager"';
|
||||
?>
|
||||
<div class="single-head-cover">
|
||||
<div class="graphic mb20 single-cover imgbox-container" style="padding-bottom:calc(<?php echo esc_attr((string) $img_scale); ?>% + 50px);">
|
||||
<img <?php echo $img_attrs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> alt="<?php echo esc_attr(wp_strip_all_tags(get_the_title())); ?>">
|
||||
<div class="abs-center left-bottom single-cover-con">
|
||||
<h1 class="article-title title-h-left"><?php echo $title_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></h1>
|
||||
<?php if ($crumbs !== '') : ?>
|
||||
<?php echo $crumbs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif; ?>
|
||||
<?php echo $badge; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
<?php if ($meta_box !== '') : ?>
|
||||
<?php echo str_replace('abs-right', 'cover-meta abs-right', $meta_box); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_box_header')) :
|
||||
/**
|
||||
* Title + author bar (when no cover).
|
||||
*
|
||||
* @param array<string,mixed> $ctx Single context.
|
||||
*/
|
||||
function aksrt_single_render_box_header(array $ctx): void {
|
||||
$settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : [];
|
||||
?>
|
||||
<div class="article-header theme-box clearfix relative">
|
||||
<?php if (empty($ctx['show_cover'])) : ?>
|
||||
<?php echo (string) $ctx['status_badge']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<h1 class="article-title"><a href="<?php the_permalink(); ?>"><?php echo (string) ($ctx['title_html'] ?? esc_html(get_the_title())); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></a></h1>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
// Author bar always shows in header (Zibll zib_single_box_header).
|
||||
// `authordesc` only controls the after-box author card.
|
||||
aksrt_single_render_author_bar([
|
||||
'show_actions' => true,
|
||||
'show_time' => empty($settings['hide_time']),
|
||||
'meta_html' => empty($ctx['show_cover']) ? (string) ($ctx['meta_box_html'] ?? '') : '',
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_actions')) :
|
||||
/**
|
||||
* Like / reward / share / favorite row.
|
||||
*
|
||||
* @param array<string,mixed> $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']);
|
||||
?>
|
||||
<div class="text-center muted-3-color box-body em09"><?php echo esc_html($settings['button_toptext'] ?? __('喜欢就支持一下吧', 'aksrt')); ?></div>
|
||||
<div class="post-actions-wrap relative">
|
||||
<div class="text-center post-actions">
|
||||
<?php if (!empty($settings['like_enabled'])) : ?>
|
||||
<button type="button" class="action action-like<?php echo $is_liked ? ' is-active' : ''; ?>" id="action-like" data-post-id="<?php echo esc_attr((string) $post_id); ?>" data-initial-active="<?php echo $is_liked ? '1' : '0'; ?>">
|
||||
<i class="<?php echo $is_liked ? 'fas' : 'far'; ?> fa-heart" aria-hidden="true"></i>
|
||||
<span class="action-btn__count" data-stat-count="likes" data-base-count="<?php echo esc_attr((string) $like_count); ?>"><?php echo esc_html((string) $like_count); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['rewards_enabled']) && !empty($settings['rewards_image'])) : ?>
|
||||
<button type="button" class="action action-rewards" id="action-reward">
|
||||
<i class="fas fa-gift" aria-hidden="true"></i>
|
||||
<span class="action-btn__label"><?php echo esc_html($settings['rewards_btn_text'] ?? __('赞赏', 'aksrt')); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['share_enabled'])) : ?>
|
||||
<button type="button" class="action action-share" id="action-share-trigger" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-share-alt" aria-hidden="true"></i>
|
||||
<span class="action-btn__label"><?php esc_html_e('分享', 'aksrt'); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['favorite_enabled'])) : ?>
|
||||
<button type="button" class="action action-favorite<?php echo $is_favorited ? ' is-active' : ''; ?>" id="action-favorite" data-post-id="<?php echo esc_attr((string) $post_id); ?>" data-initial-active="<?php echo $is_favorited ? '1' : '0'; ?>">
|
||||
<i class="<?php echo $is_favorited ? 'fas' : 'far'; ?> fa-star" aria-hidden="true"></i>
|
||||
<span class="action-btn__count" data-stat-count="favorites" data-base-count="<?php echo esc_attr((string) $favorite_count); ?>"><?php echo esc_html((string) $favorite_count); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($settings['share_enabled'])) : ?>
|
||||
<div class="share-dropdown" id="share-dropdown" aria-hidden="true">
|
||||
<div class="share-dropdown__grid">
|
||||
<button type="button" class="share-item" data-platform="qq"><i class="fab fa-qq"></i><span>QQ</span></button>
|
||||
<button type="button" class="share-item" data-platform="weibo"><i class="fab fa-weibo"></i><span>微博</span></button>
|
||||
<button type="button" class="share-item" data-platform="twitter"><i class="fab fa-x-twitter"></i><span>X</span></button>
|
||||
<button type="button" class="share-item" data-platform="wechat"><i class="fab fa-weixin"></i><span>微信</span></button>
|
||||
<button type="button" class="share-item" data-platform="copy"><i class="fas fa-link"></i><span><?php esc_html_e('复制链接', 'aksrt'); ?></span></button>
|
||||
</div>
|
||||
<div id="share-qrcode-box" aria-hidden="true"><img id="share-qrcode-image" src="" alt="QR Code"></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($settings['rewards_enabled']) && !empty($settings['rewards_image'])) : ?>
|
||||
<div class="reward-modal" id="reward-modal" aria-hidden="true">
|
||||
<div class="reward-modal__overlay"></div>
|
||||
<div class="reward-modal__dialog">
|
||||
<button type="button" class="reward-modal__close" aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>"><i class="fas fa-times" aria-hidden="true"></i></button>
|
||||
<div class="reward-modal__content">
|
||||
<h3><?php echo esc_html((string) ($settings['rewards_text'] ?? '')); ?></h3>
|
||||
<div class="reward-modal__qrcode">
|
||||
<img src="<?php echo esc_url((string) $settings['rewards_image']); ?>" alt="<?php esc_attr_e('打赏二维码', 'aksrt'); ?>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_content_footer')) :
|
||||
/**
|
||||
* Copyright + THE END + tags.
|
||||
*
|
||||
* @param array<string,mixed> $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'];
|
||||
?>
|
||||
<?php if (!empty($settings['yiyan_footer'])) : ?>
|
||||
<div class="article-yiyan yiyan-box aksrt-yiyan yiyan--footer" data-aksrt-yiyan data-type="hitokoto"></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['copyright_enabled'])) : ?>
|
||||
<div class="em09 muted-3-color">
|
||||
<div><span>©</span> <?php esc_html_e('版权声明', 'aksrt'); ?></div>
|
||||
<div class="posts-copyright"><?php echo esc_html((string) $ctx['copyright_text']); ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="text-center theme-box muted-3-color box-body separator em09">THE END</div>
|
||||
<?php
|
||||
if (function_exists('aksrt_get_single_article_tags_html')) {
|
||||
echo aksrt_get_single_article_tags_html($post_id); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_author_card')) :
|
||||
/**
|
||||
* Compact author card used in the after-box stack.
|
||||
*
|
||||
* @param array<string,mixed> $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,
|
||||
]);
|
||||
?>
|
||||
<div class="user-card author zib-widget">
|
||||
<div class="card-content mt10 relative">
|
||||
<div class="user-content">
|
||||
<div class="user-avatar"><?php echo $avatar; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
||||
<div class="user-info mt20 mb10">
|
||||
<div class="user-name flex jc">
|
||||
<a class="display-name" href="<?php echo esc_url($author_url); ?>"><?php echo esc_html($author_name); ?></a>
|
||||
<?php echo $vip_badge; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php foreach ($signals as $signal) : ?>
|
||||
<span class="badg badg-sm ml3 aksrt-identity-chip aksrt-identity-chip--<?php echo esc_attr((string) ($signal['tone'] ?? 'info')); ?>">
|
||||
<i class="fa fa-<?php echo esc_attr((string) ($signal['icon'] ?? 'check')); ?>" aria-hidden="true"></i>
|
||||
<?php echo esc_html((string) ($signal['label'] ?? '')); ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($bio !== '') : ?>
|
||||
<div class="user-desc mt10 muted-2-color em09"><?php echo esc_html($bio); ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="user-btns mt20">
|
||||
<a class="but pw-1em mr6 jb-blue" href="<?php echo esc_url($author_url); ?>"><?php esc_html_e('个人主页', 'aksrt'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!empty($recent)) : ?>
|
||||
<div class="user-card-posts mt10">
|
||||
<ul class="no-thumb">
|
||||
<?php foreach ($recent as $rp) : ?>
|
||||
<?php if ($rp instanceof WP_Post) : ?>
|
||||
<li><a class="icon-circle" href="<?php echo esc_url(get_permalink($rp)); ?>"><?php echo esc_html(get_the_title($rp)); ?></a></li>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_prevnext')) :
|
||||
/**
|
||||
* Previous / next navigation (Zibll .article-nav).
|
||||
*
|
||||
* @param array<string,mixed> $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:;';
|
||||
?>
|
||||
<div class="theme-box" style="height:99px">
|
||||
<nav class="article-nav">
|
||||
<div class="main-bg box-body radius8 main-shadow">
|
||||
<a href="<?php echo $prev ? esc_url($prev_href) : 'javascript:;'; ?>">
|
||||
<p class="muted-2-color"><i class="fa fa-angle-left em12" aria-hidden="true"></i><i class="fa fa-angle-left em12 mr6" aria-hidden="true"></i><?php esc_html_e('上一篇', 'aksrt'); ?></p>
|
||||
<div class="text-ellipsis-2"><?php echo esc_html($prev_title); ?></div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="main-bg box-body radius8 main-shadow">
|
||||
<a href="<?php echo $next ? esc_url($next_href) : 'javascript:;'; ?>">
|
||||
<p class="muted-2-color"><?php esc_html_e('下一篇', 'aksrt'); ?><i class="fa fa-angle-right em12 ml6" aria-hidden="true"></i><i class="fa fa-angle-right em12" aria-hidden="true"></i></p>
|
||||
<div class="text-ellipsis-2"><?php echo esc_html($next_title); ?></div>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_related_query_args')) :
|
||||
/**
|
||||
* Build related-posts WP_Query args (Zibll-like multi-tax OR + orderby).
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param array<string,mixed> $settings Single display settings.
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
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<string,mixed> $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' : '');
|
||||
?>
|
||||
<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 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; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
wp_reset_postdata();
|
||||
}
|
||||
endif;
|
||||
|
||||
|
||||
if (!function_exists('aksrt_single_render_pay_box')) :
|
||||
/**
|
||||
* Unified single pay module (Zibll zibpay_posts_pay_content equivalent).
|
||||
*
|
||||
* @param array<string,mixed> $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 '<div class="zib-widget pay-box pay-type-download" id="posts-pay">';
|
||||
get_template_part('templates/parts/resource-download-box');
|
||||
echo '</div>';
|
||||
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 '<div class="zib-widget ' . esc_attr($paid_class) . ' pay-type-' . esc_attr($pay_type) . '" id="posts-pay">';
|
||||
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 '<div class="box-body"><span class="badg c-green hollow badg-sm mr6">' . esc_html__('已解锁', 'aksrt') . '</span><b>' . esc_html(get_the_title($post)) . '</b></div>';
|
||||
}
|
||||
} elseif (function_exists('aksrt_get_paywall_html')) {
|
||||
echo aksrt_get_paywall_html($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_pay_box_matches')) :
|
||||
/**
|
||||
* @param array<string,mixed> $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<string,mixed> $ctx Single context.
|
||||
*/
|
||||
function aksrt_single_render_article(array $ctx): void {
|
||||
$settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : [];
|
||||
$maxheight = (int) $ctx['content_maxheight'];
|
||||
?>
|
||||
<article <?php post_class('article main-bg theme-box box-body radius8 main-shadow'); ?>>
|
||||
<?php aksrt_single_render_box_header($ctx); ?>
|
||||
|
||||
<div class="article-content">
|
||||
<?php if (!empty($settings['yiyan_header'])) : ?>
|
||||
<div class="article-yiyan yiyan-box aksrt-yiyan yiyan--header theme-box text-center radius8 main-shadow" data-aksrt-yiyan data-type="hitokoto"></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php do_action('aksrt_single_content_before', get_post()); ?>
|
||||
|
||||
<?php if (function_exists('aksrt_single_pay_box_matches') && aksrt_single_pay_box_matches($ctx, 'top')) : ?>
|
||||
<?php aksrt_single_render_pay_box($ctx); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($ctx['front_content'] !== '') : ?>
|
||||
<div class="post_front_content theme-box box-body"><?php echo wp_kses_post((string) $ctx['front_content']); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="theme-box wp-posts-content<?php echo $maxheight > 0 ? ' limit-height' : ''; ?>"
|
||||
<?php echo $maxheight > 0 ? ' style="max-height:' . esc_attr((string) $maxheight) . 'px;"' : ''; ?>
|
||||
<?php echo !empty($ctx['show_toc']) ? ' data-nav="posts"' : ''; ?>
|
||||
data-maxheight="<?php echo esc_attr((string) ($maxheight > 0 ? max(0, $maxheight - 80) : 0)); ?>"
|
||||
data-aksrt-toc="<?php echo !empty($ctx['show_toc']) ? '1' : '0'; ?>"
|
||||
data-aksrt-toc-depth="<?php echo esc_attr((string) ((int) ($settings['toc_depth'] ?? 3))); ?>"
|
||||
<?php echo !empty($settings['lightbox']) ? ' data-aksrt-lightbox="1"' : ''; ?>>
|
||||
<?php the_content(); ?>
|
||||
<?php
|
||||
wp_link_pages([
|
||||
'before' => '<p class="text-center post-nav-links radius8 padding-6">',
|
||||
'after' => '</p>',
|
||||
]);
|
||||
?>
|
||||
<?php if ($ctx['after_content'] !== '') : ?>
|
||||
<?php echo wp_kses_post((string) $ctx['after_content']); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (function_exists('aksrt_single_pay_box_matches') && aksrt_single_pay_box_matches($ctx, 'bottom')) : ?>
|
||||
<?php aksrt_single_render_pay_box($ctx); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php aksrt_single_render_content_footer($ctx); ?>
|
||||
</div>
|
||||
|
||||
<?php aksrt_single_render_actions($ctx); ?>
|
||||
</article>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_after_box')) :
|
||||
/**
|
||||
* After-article stack: yiyan box / author card / prevnext / related.
|
||||
*
|
||||
* @param array<string,mixed> $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'])) {
|
||||
?>
|
||||
<div class="yiyan-box main-bg theme-box text-center box-body radius8 main-shadow aksrt-yiyan" data-aksrt-yiyan data-type="hitokoto"></div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// Accept both `authordesc` (Settings DTO) and legacy `authordesc_s`.
|
||||
$show_author = array_key_exists('authordesc', $settings)
|
||||
? !empty($settings['authordesc'])
|
||||
: !empty($settings['authordesc_s']);
|
||||
if ($show_author) {
|
||||
aksrt_single_render_author_card($ctx);
|
||||
}
|
||||
|
||||
aksrt_single_render_prevnext($ctx);
|
||||
aksrt_single_render_related($ctx);
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_aside')) :
|
||||
/**
|
||||
* Page-owned single aside (not a generic sidebar prepend hack).
|
||||
*
|
||||
* @param array<string,mixed> $ctx Single context.
|
||||
*/
|
||||
function aksrt_single_render_aside(array $ctx): void {
|
||||
if (empty($ctx['show_aside']) || wp_is_mobile()) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="sidebar" role="complementary" aria-label="<?php esc_attr_e('侧栏', 'aksrt'); ?>">
|
||||
<?php if (!empty($ctx['has_download'])) : ?>
|
||||
<?php get_template_part('templates/parts/resource-meta-box'); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($ctx['show_toc'])) : ?>
|
||||
<div class="zib-widget toc-widget posts-nav-box" data-title="<?php echo esc_attr((string) $ctx['toc_title']); ?>">
|
||||
<h3><?php echo esc_html((string) $ctx['toc_title']); ?></h3>
|
||||
<ol class="toc-list"></ol>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (is_active_sidebar('all_sidebar_top')) : ?>
|
||||
<?php dynamic_sidebar('all_sidebar_top'); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (is_active_sidebar('sidebar-article')) : ?>
|
||||
<?php dynamic_sidebar('sidebar-article'); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (is_active_sidebar('all_sidebar_bottom')) : ?>
|
||||
<?php dynamic_sidebar('all_sidebar_bottom'); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
@@ -173,809 +173,6 @@ if (!function_exists('aksrt_single_render_author_bar')) :
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_cover')) :
|
||||
/**
|
||||
* Cover / slide / video header (Zibll single-head-cover).
|
||||
*
|
||||
* @param array<string,mixed> $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') :
|
||||
?>
|
||||
<div class="single-head-cover">
|
||||
<div class="single-video">
|
||||
<div class="graphic single-cover single-cover--video imgbox-container" style="padding-bottom:<?php echo esc_attr((string) $video_scale); ?>%;">
|
||||
<div class="aksrt-video single-cover__player" data-aksrt-video data-src="<?php echo esc_url($ctx['cover_url']); ?>"<?php echo $poster !== '' ? ' data-poster="' . esc_url($poster) . '"' : ''; ?> style="position:absolute;inset:0;width:100%;height:100%;"></div>
|
||||
</div>
|
||||
<div class="single-video-footer dplayer-featured">
|
||||
<div class="flex jsb at">
|
||||
<?php if ($crumbs !== '') : ?>
|
||||
<div class="post-breadcrumbs"><?php echo $crumbs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($meta_box !== '') : ?>
|
||||
<?php echo str_replace('abs-right', 'mb10 ml10 shrink0', $meta_box); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<h1 class="article-title">
|
||||
<?php
|
||||
$episodes = is_array($ctx['video_episodes'] ?? null) ? $ctx['video_episodes'] : [];
|
||||
if ($episodes === [] && !empty($ctx['cover_url'])) {
|
||||
$episodes = [['url' => (string) $ctx['cover_url'], 'title' => '']];
|
||||
}
|
||||
$ep_count = count($episodes);
|
||||
if ($ep_count > 1) : ?>
|
||||
<span class="badg badg-sm b-theme mr6"><i class="fa fa-play-circle mr3" aria-hidden="true"></i><?php printf(esc_html__('共%d集', 'aksrt'), $ep_count); ?></span>
|
||||
<?php else : ?>
|
||||
<i class="fa fa-play-circle-o mr6 opacity8" aria-hidden="true"></i>
|
||||
<?php endif; ?>
|
||||
<?php echo $title_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</h1>
|
||||
<?php echo $badge; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php if ($ep_count > 0) : ?>
|
||||
<div class="featured-video-episode mt10">
|
||||
<?php foreach ($episodes as $idx => $ep) :
|
||||
$ep_url = (string) ($ep['url'] ?? '');
|
||||
if ($ep_url === '') { continue; }
|
||||
$ep_title = trim((string) ($ep['title'] ?? ''));
|
||||
if ($ep_title === '') {
|
||||
$ep_title = sprintf(__('第%d集', 'aksrt'), $idx + 1);
|
||||
}
|
||||
?>
|
||||
<a href="javascript:;" class="switch-video text-ellipsis<?php echo $idx === 0 ? ' active' : ''; ?>" data-index="<?php echo (int) ($idx + 1); ?>" data-src="<?php echo esc_url($ep_url); ?>">
|
||||
<span class="mr6 badg badg-sm"><?php echo (int) ($idx + 1); ?></span><i class="episode-active-icon"></i><?php echo esc_html($ep_title); ?>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return;
|
||||
endif;
|
||||
|
||||
if ($type === 'slide' && !empty($slides)) :
|
||||
$slide_items = [];
|
||||
foreach ($slides as $slide_url) {
|
||||
$slide_items[] = [
|
||||
'image' => (string) $slide_url,
|
||||
'alt' => wp_strip_all_tags(get_the_title()),
|
||||
];
|
||||
}
|
||||
$overlay = '<div class="abs-center left-bottom single-cover-con">'
|
||||
. '<h1 class="article-title title-h-left">' . $title_html . '</h1>'
|
||||
. ($crumbs !== '' ? $crumbs : '')
|
||||
. $badge
|
||||
. '</div>'
|
||||
. ($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,
|
||||
]);
|
||||
}
|
||||
?>
|
||||
<div class="single-head-cover">
|
||||
<?php if ($slider_html !== '') : ?>
|
||||
<?php echo $slider_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php else : ?>
|
||||
<div class="graphic mb20 single-cover single-cover--slide imgbox-container" style="padding-bottom:<?php echo esc_attr((string) $img_scale); ?>%;">
|
||||
<?php foreach ($slides as $idx => $slide_url) : ?>
|
||||
<img src="<?php echo esc_url($slide_url); ?>" alt="" class="fit-cover" style="<?php echo $idx === 0 ? '' : 'display:none;'; ?>" loading="<?php echo $idx === 0 ? 'eager' : 'lazy'; ?>">
|
||||
<?php endforeach; ?>
|
||||
<?php echo $overlay; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
return;
|
||||
endif;
|
||||
|
||||
// Image cover (default).
|
||||
$img_attrs = function_exists('aksrt_lazy_img_attrs')
|
||||
? aksrt_lazy_img_attrs((string) $ctx['cover_url'], 'cover', 'fit-cover')
|
||||
: 'class="fit-cover" src="' . esc_url((string) $ctx['cover_url']) . '" loading="eager"';
|
||||
?>
|
||||
<div class="single-head-cover">
|
||||
<div class="graphic mb20 single-cover imgbox-container" style="padding-bottom:<?php echo esc_attr((string) $img_scale); ?>%;">
|
||||
<img <?php echo $img_attrs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> alt="<?php echo esc_attr(wp_strip_all_tags(get_the_title())); ?>">
|
||||
<div class="abs-center left-bottom single-cover-con">
|
||||
<h1 class="article-title title-h-left"><?php echo $title_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></h1>
|
||||
<?php if ($crumbs !== '') : ?>
|
||||
<?php echo $crumbs; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif; ?>
|
||||
<?php echo $badge; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</div>
|
||||
<?php if ($meta_box !== '') : ?>
|
||||
<?php echo str_replace('abs-right', 'cover-meta abs-right', $meta_box); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_box_header')) :
|
||||
/**
|
||||
* Title + author bar (when no cover).
|
||||
*
|
||||
* @param array<string,mixed> $ctx Single context.
|
||||
*/
|
||||
function aksrt_single_render_box_header(array $ctx): void {
|
||||
$settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : [];
|
||||
?>
|
||||
<div class="article-header theme-box clearfix relative">
|
||||
<?php if (empty($ctx['show_cover'])) : ?>
|
||||
<?php echo (string) $ctx['status_badge']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<h1 class="article-title"><a href="<?php the_permalink(); ?>"><?php echo (string) ($ctx['title_html'] ?? esc_html(get_the_title())); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></a></h1>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
// Author bar always shows in header (Zibll zib_single_box_header).
|
||||
// `authordesc` only controls the after-box author card.
|
||||
aksrt_single_render_author_bar([
|
||||
'show_actions' => true,
|
||||
'show_time' => empty($settings['hide_time']),
|
||||
'meta_html' => empty($ctx['show_cover']) ? (string) ($ctx['meta_box_html'] ?? '') : '',
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_actions')) :
|
||||
/**
|
||||
* Like / reward / share / favorite row.
|
||||
*
|
||||
* @param array<string,mixed> $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']);
|
||||
?>
|
||||
<div class="text-center muted-3-color box-body em09"><?php echo esc_html($settings['button_toptext'] ?? __('喜欢就支持一下吧', 'aksrt')); ?></div>
|
||||
<div class="post-actions-wrap relative">
|
||||
<div class="text-center post-actions">
|
||||
<?php if (!empty($settings['like_enabled'])) : ?>
|
||||
<button type="button" class="action action-like<?php echo $is_liked ? ' is-active' : ''; ?>" id="action-like" data-post-id="<?php echo esc_attr((string) $post_id); ?>" data-initial-active="<?php echo $is_liked ? '1' : '0'; ?>">
|
||||
<i class="<?php echo $is_liked ? 'fas' : 'far'; ?> fa-heart" aria-hidden="true"></i>
|
||||
<span class="action-btn__count" data-stat-count="likes" data-base-count="<?php echo esc_attr((string) $like_count); ?>"><?php echo esc_html((string) $like_count); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['rewards_enabled']) && !empty($settings['rewards_image'])) : ?>
|
||||
<button type="button" class="action action-rewards" id="action-reward">
|
||||
<i class="fas fa-gift" aria-hidden="true"></i>
|
||||
<span class="action-btn__label"><?php echo esc_html($settings['rewards_btn_text'] ?? __('赞赏', 'aksrt')); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['share_enabled'])) : ?>
|
||||
<button type="button" class="action action-share" id="action-share-trigger" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fas fa-share-alt" aria-hidden="true"></i>
|
||||
<span class="action-btn__label"><?php esc_html_e('分享', 'aksrt'); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['favorite_enabled'])) : ?>
|
||||
<button type="button" class="action action-favorite<?php echo $is_favorited ? ' is-active' : ''; ?>" id="action-favorite" data-post-id="<?php echo esc_attr((string) $post_id); ?>" data-initial-active="<?php echo $is_favorited ? '1' : '0'; ?>">
|
||||
<i class="<?php echo $is_favorited ? 'fas' : 'far'; ?> fa-star" aria-hidden="true"></i>
|
||||
<span class="action-btn__count" data-stat-count="favorites" data-base-count="<?php echo esc_attr((string) $favorite_count); ?>"><?php echo esc_html((string) $favorite_count); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($settings['share_enabled'])) : ?>
|
||||
<div class="share-dropdown" id="share-dropdown" aria-hidden="true">
|
||||
<div class="share-dropdown__grid">
|
||||
<button type="button" class="share-item" data-platform="qq"><i class="fab fa-qq"></i><span>QQ</span></button>
|
||||
<button type="button" class="share-item" data-platform="weibo"><i class="fab fa-weibo"></i><span>微博</span></button>
|
||||
<button type="button" class="share-item" data-platform="twitter"><i class="fab fa-x-twitter"></i><span>X</span></button>
|
||||
<button type="button" class="share-item" data-platform="wechat"><i class="fab fa-weixin"></i><span>微信</span></button>
|
||||
<button type="button" class="share-item" data-platform="copy"><i class="fas fa-link"></i><span><?php esc_html_e('复制链接', 'aksrt'); ?></span></button>
|
||||
</div>
|
||||
<div id="share-qrcode-box" aria-hidden="true"><img id="share-qrcode-image" src="" alt="QR Code"></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($settings['rewards_enabled']) && !empty($settings['rewards_image'])) : ?>
|
||||
<div class="reward-modal" id="reward-modal" aria-hidden="true">
|
||||
<div class="reward-modal__overlay"></div>
|
||||
<div class="reward-modal__dialog">
|
||||
<button type="button" class="reward-modal__close" aria-label="<?php esc_attr_e('关闭', 'aksrt'); ?>"><i class="fas fa-times" aria-hidden="true"></i></button>
|
||||
<div class="reward-modal__content">
|
||||
<h3><?php echo esc_html((string) ($settings['rewards_text'] ?? '')); ?></h3>
|
||||
<div class="reward-modal__qrcode">
|
||||
<img src="<?php echo esc_url((string) $settings['rewards_image']); ?>" alt="<?php esc_attr_e('打赏二维码', 'aksrt'); ?>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_content_footer')) :
|
||||
/**
|
||||
* Copyright + THE END + tags.
|
||||
*
|
||||
* @param array<string,mixed> $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'];
|
||||
?>
|
||||
<?php if (!empty($settings['yiyan_footer'])) : ?>
|
||||
<div class="article-yiyan yiyan-box aksrt-yiyan yiyan--footer" data-aksrt-yiyan data-type="hitokoto"></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($settings['copyright_enabled'])) : ?>
|
||||
<div class="em09 muted-3-color">
|
||||
<div><span>©</span> <?php esc_html_e('版权声明', 'aksrt'); ?></div>
|
||||
<div class="posts-copyright"><?php echo esc_html((string) $ctx['copyright_text']); ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="text-center theme-box muted-3-color box-body separator em09">THE END</div>
|
||||
<?php
|
||||
if (function_exists('aksrt_get_single_article_tags_html')) {
|
||||
echo aksrt_get_single_article_tags_html($post_id); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_author_card')) :
|
||||
/**
|
||||
* Compact author card used in the after-box stack.
|
||||
*
|
||||
* @param array<string,mixed> $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,
|
||||
]);
|
||||
?>
|
||||
<div class="user-card author zib-widget">
|
||||
<div class="card-content mt10 relative">
|
||||
<div class="user-content">
|
||||
<div class="user-avatar"><?php echo $avatar; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
||||
<div class="user-info mt20 mb10">
|
||||
<div class="user-name flex jc">
|
||||
<a class="display-name" href="<?php echo esc_url($author_url); ?>"><?php echo esc_html($author_name); ?></a>
|
||||
<?php echo $vip_badge; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php foreach ($signals as $signal) : ?>
|
||||
<span class="badg badg-sm ml3 aksrt-identity-chip aksrt-identity-chip--<?php echo esc_attr((string) ($signal['tone'] ?? 'info')); ?>">
|
||||
<i class="fa fa-<?php echo esc_attr((string) ($signal['icon'] ?? 'check')); ?>" aria-hidden="true"></i>
|
||||
<?php echo esc_html((string) ($signal['label'] ?? '')); ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php if ($bio !== '') : ?>
|
||||
<div class="user-desc mt10 muted-2-color em09"><?php echo esc_html($bio); ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="user-btns mt20">
|
||||
<a class="but pw-1em mr6 jb-blue" href="<?php echo esc_url($author_url); ?>"><?php esc_html_e('个人主页', 'aksrt'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!empty($recent)) : ?>
|
||||
<div class="user-card-posts mt10">
|
||||
<ul class="no-thumb">
|
||||
<?php foreach ($recent as $rp) : ?>
|
||||
<?php if ($rp instanceof WP_Post) : ?>
|
||||
<li><a class="icon-circle" href="<?php echo esc_url(get_permalink($rp)); ?>"><?php echo esc_html(get_the_title($rp)); ?></a></li>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_prevnext')) :
|
||||
/**
|
||||
* Previous / next navigation (Zibll .article-nav).
|
||||
*
|
||||
* @param array<string,mixed> $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:;';
|
||||
?>
|
||||
<div class="theme-box" style="height:99px">
|
||||
<nav class="article-nav">
|
||||
<div class="main-bg box-body radius8 main-shadow">
|
||||
<a href="<?php echo $prev ? esc_url($prev_href) : 'javascript:;'; ?>">
|
||||
<p class="muted-2-color"><i class="fa fa-angle-left em12" aria-hidden="true"></i><i class="fa fa-angle-left em12 mr6" aria-hidden="true"></i><?php esc_html_e('上一篇', 'aksrt'); ?></p>
|
||||
<div class="text-ellipsis-2"><?php echo esc_html($prev_title); ?></div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="main-bg box-body radius8 main-shadow">
|
||||
<a href="<?php echo $next ? esc_url($next_href) : 'javascript:;'; ?>">
|
||||
<p class="muted-2-color"><?php esc_html_e('下一篇', 'aksrt'); ?><i class="fa fa-angle-right em12 ml6" aria-hidden="true"></i><i class="fa fa-angle-right em12" aria-hidden="true"></i></p>
|
||||
<div class="text-ellipsis-2"><?php echo esc_html($next_title); ?></div>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_related_query_args')) :
|
||||
/**
|
||||
* Build related-posts WP_Query args (Zibll-like multi-tax OR + orderby).
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param array<string,mixed> $settings Single display settings.
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
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<string,mixed> $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' : '');
|
||||
?>
|
||||
<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 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; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
wp_reset_postdata();
|
||||
}
|
||||
endif;
|
||||
|
||||
|
||||
if (!function_exists('aksrt_single_render_pay_box')) :
|
||||
/**
|
||||
* Unified single pay module (Zibll zibpay_posts_pay_content equivalent).
|
||||
*
|
||||
* @param array<string,mixed> $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 '<div class="zib-widget pay-box pay-type-download" id="posts-pay">';
|
||||
get_template_part('templates/parts/resource-download-box');
|
||||
echo '</div>';
|
||||
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 '<div class="zib-widget ' . esc_attr($paid_class) . ' pay-type-' . esc_attr($pay_type) . '" id="posts-pay">';
|
||||
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 '<div class="box-body"><span class="badg c-green hollow badg-sm mr6">' . esc_html__('已解锁', 'aksrt') . '</span><b>' . esc_html(get_the_title($post)) . '</b></div>';
|
||||
}
|
||||
} elseif (function_exists('aksrt_get_paywall_html')) {
|
||||
echo aksrt_get_paywall_html($post); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_pay_box_matches')) :
|
||||
/**
|
||||
* @param array<string,mixed> $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<string,mixed> $ctx Single context.
|
||||
*/
|
||||
function aksrt_single_render_article(array $ctx): void {
|
||||
$settings = is_array($ctx['settings'] ?? null) ? $ctx['settings'] : [];
|
||||
$maxheight = (int) $ctx['content_maxheight'];
|
||||
?>
|
||||
<article <?php post_class('article main-bg theme-box box-body radius8 main-shadow'); ?>>
|
||||
<?php aksrt_single_render_box_header($ctx); ?>
|
||||
|
||||
<div class="article-content">
|
||||
<?php if (!empty($settings['yiyan_header'])) : ?>
|
||||
<div class="article-yiyan yiyan-box aksrt-yiyan yiyan--header theme-box text-center radius8 main-shadow" data-aksrt-yiyan data-type="hitokoto"></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php do_action('aksrt_single_content_before', get_post()); ?>
|
||||
|
||||
<?php if (function_exists('aksrt_single_pay_box_matches') && aksrt_single_pay_box_matches($ctx, 'top')) : ?>
|
||||
<?php aksrt_single_render_pay_box($ctx); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($ctx['front_content'] !== '') : ?>
|
||||
<div class="post_front_content theme-box box-body"><?php echo wp_kses_post((string) $ctx['front_content']); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="theme-box wp-posts-content<?php echo $maxheight > 0 ? ' limit-height' : ''; ?>"
|
||||
<?php echo $maxheight > 0 ? ' style="max-height:' . esc_attr((string) $maxheight) . 'px;"' : ''; ?>
|
||||
<?php echo !empty($ctx['show_toc']) ? ' data-nav="posts"' : ''; ?>
|
||||
data-maxheight="<?php echo esc_attr((string) ($maxheight > 0 ? max(0, $maxheight - 80) : 0)); ?>"
|
||||
data-aksrt-toc="<?php echo !empty($ctx['show_toc']) ? '1' : '0'; ?>"
|
||||
data-aksrt-toc-depth="<?php echo esc_attr((string) ((int) ($settings['toc_depth'] ?? 3))); ?>"
|
||||
<?php echo !empty($settings['lightbox']) ? ' data-aksrt-lightbox="1"' : ''; ?>>
|
||||
<?php the_content(); ?>
|
||||
<?php
|
||||
wp_link_pages([
|
||||
'before' => '<p class="text-center post-nav-links radius8 padding-6">',
|
||||
'after' => '</p>',
|
||||
]);
|
||||
?>
|
||||
<?php if ($ctx['after_content'] !== '') : ?>
|
||||
<?php echo wp_kses_post((string) $ctx['after_content']); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (function_exists('aksrt_single_pay_box_matches') && aksrt_single_pay_box_matches($ctx, 'bottom')) : ?>
|
||||
<?php aksrt_single_render_pay_box($ctx); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php aksrt_single_render_content_footer($ctx); ?>
|
||||
</div>
|
||||
|
||||
<?php aksrt_single_render_actions($ctx); ?>
|
||||
</article>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_after_box')) :
|
||||
/**
|
||||
* After-article stack: yiyan box / author card / prevnext / related.
|
||||
*
|
||||
* @param array<string,mixed> $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'])) {
|
||||
?>
|
||||
<div class="yiyan-box main-bg theme-box text-center box-body radius8 main-shadow aksrt-yiyan" data-aksrt-yiyan data-type="hitokoto"></div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// Accept both `authordesc` (Settings DTO) and legacy `authordesc_s`.
|
||||
$show_author = array_key_exists('authordesc', $settings)
|
||||
? !empty($settings['authordesc'])
|
||||
: !empty($settings['authordesc_s']);
|
||||
if ($show_author) {
|
||||
aksrt_single_render_author_card($ctx);
|
||||
}
|
||||
|
||||
aksrt_single_render_prevnext($ctx);
|
||||
aksrt_single_render_related($ctx);
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single_render_aside')) :
|
||||
/**
|
||||
* Page-owned single aside (not a generic sidebar prepend hack).
|
||||
*
|
||||
* @param array<string,mixed> $ctx Single context.
|
||||
*/
|
||||
function aksrt_single_render_aside(array $ctx): void {
|
||||
if (empty($ctx['show_aside']) || wp_is_mobile()) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="sidebar" role="complementary" aria-label="<?php esc_attr_e('侧栏', 'aksrt'); ?>">
|
||||
<?php if (!empty($ctx['has_download'])) : ?>
|
||||
<?php get_template_part('templates/parts/resource-meta-box'); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($ctx['show_toc'])) : ?>
|
||||
<div class="zib-widget toc-widget posts-nav-box" data-title="<?php echo esc_attr((string) $ctx['toc_title']); ?>">
|
||||
<h3><?php echo esc_html((string) $ctx['toc_title']); ?></h3>
|
||||
<ol class="toc-list"></ol>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (is_active_sidebar('all_sidebar_top')) : ?>
|
||||
<?php dynamic_sidebar('all_sidebar_top'); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (is_active_sidebar('sidebar-article')) : ?>
|
||||
<?php dynamic_sidebar('sidebar-article'); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (is_active_sidebar('all_sidebar_bottom')) : ?>
|
||||
<?php dynamic_sidebar('all_sidebar_bottom'); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
endif;
|
||||
|
||||
if (!function_exists('aksrt_single')) :
|
||||
/**
|
||||
* Compose header + article + after-box (Zibll zib_single equivalent).
|
||||
|
||||
@@ -60,11 +60,11 @@ if (class_exists('AKSRT_User_Home')) {
|
||||
<div class="user-info flex ac">
|
||||
<?php if (function_exists('aksrt_get_avatar_html')) : ?>
|
||||
<a class="avatar-img" href="<?php echo esc_url($author_url); ?>">
|
||||
<?php echo aksrt_get_avatar_html($author_id, 52, ['class' => 'avatar avatar-id-' . $author_id]); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php echo aksrt_get_avatar_html($author_id, 42, ['class' => 'avatar avatar-id-' . $author_id]); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
</a>
|
||||
<?php else : ?>
|
||||
<a class="avatar-img" href="<?php echo esc_url($author_url); ?>">
|
||||
<?php echo get_avatar($author_id, 52, '', esc_attr($author_name), ['class' => 'avatar avatar-id-' . $author_id]); ?>
|
||||
<?php echo get_avatar($author_id, 42, '', esc_attr($author_name), ['class' => 'avatar avatar-id-' . $author_id]); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<div class="user-right flex flex1 ac jsb ml10">
|
||||
|
||||
Reference in New Issue
Block a user