Merge pull request 'Worktree ux depth batch5' (#223) from worktree-ux-depth-batch5 into main
Reviewed-on: CYL/wordpress-theme-aksrt#223
This commit is contained in:
@@ -0,0 +1,554 @@
|
||||
/**
|
||||
* Batch5: user card guest/login depth, main posts, term aggregation.
|
||||
*/
|
||||
|
||||
.aksrt-user-card {
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-line, #e5e7eb);
|
||||
background: var(--surface-1, #fff);
|
||||
text-align: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.aksrt-user-card__cover {
|
||||
height: 90px;
|
||||
background: linear-gradient(135deg, #93c5fd, #c4b5fd) center/cover no-repeat;
|
||||
}
|
||||
.aksrt-user-card__cover.is-empty {
|
||||
background: linear-gradient(135deg, #e2e8f0, #f8fafc);
|
||||
}
|
||||
.aksrt-user-card__body { padding: 0 14px 16px; position: relative; }
|
||||
.aksrt-user-card__checkin {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 8px;
|
||||
z-index: 2;
|
||||
max-width: 48%;
|
||||
}
|
||||
.aksrt-user-card__checkin .but {
|
||||
padding: 4px 8px !important;
|
||||
font-size: 12px !important;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.aksrt-user-card__checkin .aksrt-header-checkin-details { display: none; }
|
||||
.aksrt-user-card__avatar {
|
||||
display: inline-block;
|
||||
margin-top: -36px;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 3px solid var(--surface-1, #fff);
|
||||
background: var(--surface-2, #eee);
|
||||
}
|
||||
.aksrt-user-card__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.aksrt-user-card__name {
|
||||
margin: 10px 0 0;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.aksrt-user-card__name a { color: inherit; text-decoration: none; }
|
||||
.aksrt-user-card__bio,
|
||||
.aksrt-user-card__guest-title {
|
||||
margin: 8px 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--muted-2-color, #888);
|
||||
line-height: 1.5;
|
||||
}
|
||||
.aksrt-user-card__guest-title { font-size: 14px; font-weight: 600; color: inherit; }
|
||||
.aksrt-user-card__stats {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 18px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.aksrt-user-card__stat-value {
|
||||
display: block;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.aksrt-user-card__stat-label {
|
||||
font-size: 11px;
|
||||
color: var(--muted-2-color, #999);
|
||||
}
|
||||
.aksrt-user-card__actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
.aksrt-user-card__btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 96px;
|
||||
padding: 7px 14px;
|
||||
border-radius: 999px;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
.aksrt-user-card__btn--primary {
|
||||
background: var(--color-primary, #3b82f6);
|
||||
color: #fff !important;
|
||||
}
|
||||
.aksrt-user-card__btn--ghost {
|
||||
background: var(--surface-2, #f3f4f6);
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
/* Main posts */
|
||||
.aksrt-main-posts { display: flex; flex-direction: column; gap: 10px; }
|
||||
.aksrt-main-posts.style-card {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
@media (max-width: 575.98px) {
|
||||
.aksrt-main-posts.style-card { grid-template-columns: 1fr; }
|
||||
}
|
||||
.aksrt-main-posts__card {
|
||||
display: block;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--color-line, #e5e7eb);
|
||||
background: var(--surface-1, #fff);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
.aksrt-main-posts__thumb {
|
||||
height: 110px;
|
||||
background: var(--surface-2, #f3f4f6);
|
||||
overflow: hidden;
|
||||
}
|
||||
.aksrt-main-posts__thumb.mini {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.aksrt-main-posts__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.aksrt-main-posts__thumb.is-empty { background: linear-gradient(135deg, #e2e8f0, #f8fafc); }
|
||||
.aksrt-main-posts__body { padding: 10px 12px 12px; min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 4px; }
|
||||
.aksrt-main-posts__title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.aksrt-main-posts__meta {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
font-size: 11px;
|
||||
color: var(--muted-2-color, #999);
|
||||
}
|
||||
.aksrt-main-posts__row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
padding: 4px 0;
|
||||
border-bottom: 1px dashed var(--color-line, #e5e7eb);
|
||||
}
|
||||
.aksrt-main-posts__row:last-child { border-bottom: 0; }
|
||||
.aksrt-main-posts__num {
|
||||
width: 20px;
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--color-primary, #3b82f6);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Term aggregation */
|
||||
.aksrt-term-agg {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--aksrt-ta-cols, 1), minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
.aksrt-term-agg__card {
|
||||
border: 1px solid var(--color-line, #e5e7eb);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: var(--surface-1, #fff);
|
||||
}
|
||||
.aksrt-term-agg__head {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
position: relative;
|
||||
}
|
||||
.aksrt-term-agg__cover {
|
||||
height: 96px;
|
||||
background: var(--surface-2, #f3f4f6) center/cover no-repeat;
|
||||
}
|
||||
.aksrt-term-agg__cover.is-empty {
|
||||
background: linear-gradient(135deg, #dbeafe, #eff6ff);
|
||||
}
|
||||
.aksrt-term-agg__name {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
bottom: 10px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,.45);
|
||||
}
|
||||
.aksrt-term-agg__count {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
background: rgba(0,0,0,.45);
|
||||
color: #fff;
|
||||
}
|
||||
.aksrt-term-agg__posts {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 8px 12px 10px;
|
||||
}
|
||||
.aksrt-term-agg__posts li {
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px dashed var(--color-line, #eee);
|
||||
}
|
||||
.aksrt-term-agg__posts li:last-child { border-bottom: 0; }
|
||||
.aksrt-term-agg__posts a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
/* Icon cover cards */
|
||||
.aksrt-icon-cover {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--aksrt-icc-pc, 2), minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
--aksrt-icc-icon: 25px;
|
||||
}
|
||||
@media (max-width: 575.98px) {
|
||||
.aksrt-icon-cover {
|
||||
grid-template-columns: repeat(var(--aksrt-icc-m, 1), minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
.aksrt-icon-cover__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--color-line, #e5e7eb);
|
||||
background: var(--surface-1, #fff);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
.aksrt-icon-cover__icon {
|
||||
width: calc(var(--aksrt-icc-icon) + 18px);
|
||||
height: calc(var(--aksrt-icc-icon) + 18px);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: var(--aksrt-icc-icon);
|
||||
color: var(--color-primary, #3b82f6);
|
||||
background: var(--surface-2, #f3f4f6);
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.aksrt-icon-cover.is-radius .aksrt-icon-cover__icon { border-radius: 10px; }
|
||||
.aksrt-icon-cover__icon img { width: 70%; height: 70%; object-fit: contain; }
|
||||
.aksrt-icon-cover__title { font-weight: 700; font-size: 14px; }
|
||||
.aksrt-icon-cover__desc { font-size: 12px; color: var(--muted-2-color, #888); margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
|
||||
/* Bookmark links */
|
||||
.aksrt-bookmark-links {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
.aksrt-bookmark-links.has-box {
|
||||
padding: 10px;
|
||||
border: 1px solid var(--color-line, #e5e7eb);
|
||||
border-radius: 12px;
|
||||
}
|
||||
.aksrt-bookmark-links.style-simple {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.aksrt-bookmark-links__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
border-radius: 10px;
|
||||
background: var(--surface-2, #f8fafc);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
min-width: 0;
|
||||
}
|
||||
.aksrt-bookmark-links__img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 8px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.aksrt-bookmark-links__text { min-width: 0; display: flex; flex-direction: column; }
|
||||
.aksrt-bookmark-links__name { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.aksrt-bookmark-links__desc { font-size: 11px; color: var(--muted-2-color, #999); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
|
||||
|
||||
/* Search keywords */
|
||||
.aksrt-search-widget__keywords { margin-top: 10px; }
|
||||
.aksrt-search-widget__kw-title {
|
||||
font-size: 12px;
|
||||
color: var(--muted-2-color, #888);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.aksrt-search-widget__kw-list { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.aksrt-search-widget__kw {
|
||||
display: inline-block;
|
||||
padding: 3px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-2, #f3f4f6);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
.aksrt-search-widget__more { margin-top: 8px; text-align: right; font-size: 12px; }
|
||||
.aksrt-search-widget__more a { color: var(--color-primary, #3b82f6); text-decoration: none; }
|
||||
|
||||
/* Scroll notice */
|
||||
.aksrt-scroll-notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 14px;
|
||||
border-radius: 10px;
|
||||
background: #eff6ff;
|
||||
color: #1d4ed8;
|
||||
margin-bottom: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.aksrt-scroll-notice.is-radius { border-radius: 999px; }
|
||||
.aksrt-scroll-notice.color-c-green { background: #ecfdf5; color: #047857; }
|
||||
.aksrt-scroll-notice.color-c-yellow { background: #fffbeb; color: #b45309; }
|
||||
.aksrt-scroll-notice.color-c-red { background: #fef2f2; color: #b91c1c; }
|
||||
.aksrt-scroll-notice.color-c-purple { background: #f5f3ff; color: #6d28d9; }
|
||||
.aksrt-scroll-notice__icon { flex-shrink: 0; }
|
||||
.aksrt-scroll-notice__viewport { position: relative; flex: 1; min-width: 0; height: 1.4em; }
|
||||
.aksrt-scroll-notice__item {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
transition: opacity .35s ease, transform .35s ease;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.aksrt-scroll-notice__item.is-active {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
.aksrt-scroll-notice__item a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.aksrt-scroll-notice__item i { margin-right: 6px; opacity: .85; }
|
||||
|
||||
.hot-post-item { display: flex; align-items: center; gap: 10px; }
|
||||
.hot-post-item__thumb {
|
||||
width: 48px; height: 48px; border-radius: 8px; overflow: hidden; flex-shrink: 0;
|
||||
background: var(--surface-2, #eee);
|
||||
}
|
||||
.hot-post-item__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.aksrt-cover-card__bg.is-video video {
|
||||
width: 100%; height: 100%; object-fit: cover; display: block;
|
||||
}
|
||||
|
||||
.widget-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--btn-gap, 10px);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.widget-buttons--vertical { flex-direction: column; }
|
||||
.widget-buttons.align-center { justify-content: center; }
|
||||
.widget-buttons.align-left { justify-content: flex-start; }
|
||||
.widget-buttons.align-right { justify-content: flex-end; }
|
||||
.widget-buttons__btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
background: var(--color-primary, #3b82f6);
|
||||
color: #fff !important;
|
||||
}
|
||||
.widget-buttons.is-radius .widget-buttons__btn { border-radius: 999px; }
|
||||
.widget-buttons.is-hollow .widget-buttons__btn {
|
||||
background: transparent;
|
||||
color: var(--color-primary, #3b82f6) !important;
|
||||
border: 1px solid currentColor;
|
||||
}
|
||||
.widget-buttons__btn--secondary { background: #64748b; }
|
||||
.widget-buttons__btn--outline {
|
||||
background: transparent;
|
||||
color: inherit !important;
|
||||
border: 1px solid var(--color-line, #ddd);
|
||||
}
|
||||
.widget-buttons__btn--text {
|
||||
background: transparent;
|
||||
color: var(--color-primary, #3b82f6) !important;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.widget-buttons__btn--pink { background: #ec4899; }
|
||||
.widget-buttons__btn--blue { background: #3b82f6; }
|
||||
.widget-buttons__btn--green { background: #22c55e; }
|
||||
|
||||
.aksrt-video-widget {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #111;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.aksrt-video-widget iframe,
|
||||
.aksrt-video-widget video {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
.aksrt-video-widget.controller-hide video::-webkit-media-controls {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.widget-recent-comments__post {
|
||||
margin-top: 2px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.widget-recent-comments__post a {
|
||||
color: var(--muted-2-color, #999);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.widget-icon-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--ic-columns, 2), minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
@media (max-width: 575.98px) {
|
||||
.widget-icon-cards {
|
||||
grid-template-columns: repeat(var(--ic-m-columns, 2), minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
.widget-icon-cards.is-bare .widget-icon-cards__item {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
.widget-icon-cards__item.is-vertical {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
padding: 16px 10px;
|
||||
}
|
||||
.widget-icon-cards__item.is-vertical .widget-icon-cards__icon {
|
||||
margin: 0 auto 10px;
|
||||
width: calc(var(--ic-icon, 28px) + 20px);
|
||||
height: calc(var(--ic-icon, 28px) + 20px);
|
||||
font-size: var(--ic-icon, 28px);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--surface-2, #f3f4f6);
|
||||
color: var(--color-primary, #3b82f6);
|
||||
}
|
||||
.aksrt-tag-cloud.tag-cloud {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.aksrt-tag-cloud .but {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: var(--surface-2, #f3f4f6);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
.aksrt-tag-cloud .c-blue { background: #dbeafe; color: #1d4ed8; }
|
||||
.aksrt-tag-cloud .c-green { background: #dcfce7; color: #15803d; }
|
||||
.aksrt-tag-cloud .c-yellow { background: #fef3c7; color: #b45309; }
|
||||
.aksrt-tag-cloud .c-purple { background: #ede9fe; color: #6d28d9; }
|
||||
.aksrt-tag-cloud .c-red { background: #fee2e2; color: #b91c1c; }
|
||||
.aksrt-tag-cloud.fixed-width a { min-width: 72px; justify-content: center; }
|
||||
.aksrt-cat-list .count {
|
||||
float: right;
|
||||
color: var(--muted-2-color, #999);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.aksrt-user-card__oauth {
|
||||
margin-top: 14px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px dashed var(--color-line, #e5e7eb);
|
||||
}
|
||||
.aksrt-user-card__oauth .social-login-divider {
|
||||
font-size: 12px;
|
||||
color: var(--muted-2-color, #999);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.aksrt-user-card__oauth .social-login-item,
|
||||
.aksrt-user-card__oauth a {
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
.aksrt-author-card__follow {
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
margin-right: 6px;
|
||||
background: #ef4444;
|
||||
color: #fff !important;
|
||||
}
|
||||
.aksrt-author-card__follow.is-following {
|
||||
background: var(--surface-2, #e5e7eb);
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.aksrt-author-card__badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-top: 8px;
|
||||
padding: 2px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 12px;
|
||||
background: #fef3c7;
|
||||
color: #b45309;
|
||||
}
|
||||
.aksrt-author-card__badge img { border-radius: 50%; }
|
||||
@@ -8,3 +8,4 @@
|
||||
@import url("widget-batch3d.css");
|
||||
@import url("widget-batch3e.css");
|
||||
@import url("widget-batch3f.css");
|
||||
@import url("widget-batch5.css");
|
||||
|
||||
@@ -140,6 +140,9 @@ if (get_option('aksrt_flushed_version') !== AKSRT_VERSION) {
|
||||
if (class_exists('\AKSRT\Auth\WeixinGzh')) {
|
||||
\AKSRT\Auth\WeixinGzh::get_instance()->init();
|
||||
}
|
||||
if (class_exists('\AKSRT\Frontend\WeChatShare')) {
|
||||
\AKSRT\Frontend\WeChatShare::get_instance()->init();
|
||||
}
|
||||
|
||||
// 初始化代理登录(根据配置模式选择性加载)
|
||||
$aksrt_proxy_mode = \AKSRT\Settings\Settings::oauth_proxy_mode();
|
||||
@@ -171,6 +174,12 @@ if (class_exists('\AKSRT\User\Restriction')) {
|
||||
if (class_exists('\AKSRT\User\Center')) {
|
||||
\AKSRT\User\Center::get_instance()->init();
|
||||
}
|
||||
if (class_exists('\AKSRT\User\Badges')) {
|
||||
\AKSRT\User\Badges::get_instance()->init();
|
||||
}
|
||||
if (class_exists('\AKSRT\User\BadgeAutoAward')) {
|
||||
\AKSRT\User\BadgeAutoAward::get_instance()->init();
|
||||
}
|
||||
if (class_exists('\AKSRT\User\Home')) {
|
||||
\AKSRT\User\Home::get_instance()->init();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,16 @@ defined('ABSPATH') || exit;
|
||||
/**
|
||||
* Register custom widgets.
|
||||
*/
|
||||
function aksrt_unregister_default_widgets(): void {
|
||||
unregister_widget('WP_Widget_RSS');
|
||||
unregister_widget('WP_Widget_Recent_Posts');
|
||||
unregister_widget('WP_Widget_Recent_Comments');
|
||||
unregister_widget('WP_Widget_Pages');
|
||||
unregister_widget('WP_Widget_Search');
|
||||
unregister_widget('WP_Widget_Calendar');
|
||||
}
|
||||
add_action('widgets_init', 'aksrt_unregister_default_widgets', 1);
|
||||
|
||||
function aksrt_register_widgets() {
|
||||
register_widget('\AKSRT\Widgets\AboutWidget');
|
||||
register_widget('\AKSRT\Widgets\CategoriesWidget');
|
||||
@@ -74,6 +84,10 @@ function aksrt_register_widgets() {
|
||||
register_widget('\AKSRT\Widgets\WidgetAuthorCard');
|
||||
register_widget('\AKSRT\Widgets\WidgetOnelinePosts');
|
||||
register_widget('\AKSRT\Widgets\WidgetTiltCases');
|
||||
register_widget('\AKSRT\Widgets\WidgetMainPosts');
|
||||
register_widget('\AKSRT\Widgets\WidgetTermAggregation');
|
||||
register_widget('\AKSRT\Widgets\WidgetIconCoverCards');
|
||||
register_widget('\AKSRT\Widgets\WidgetBookmarkLinks');
|
||||
|
||||
|
||||
// Forum widgets
|
||||
|
||||
@@ -407,11 +407,15 @@ trait SetupPart1 {
|
||||
|
||||
// ── Shop widget areas (§6.9) ──
|
||||
$shop_widgets = [
|
||||
'shop_home_top_fluid' => ['商城首页 · 顶部通栏', '商城首页顶部全宽区域。'],
|
||||
'shop_home_sidebar' => ['商城首页 · 侧栏', '商城首页侧栏区域。'],
|
||||
'shop_product_top_fluid' => ['商品详情页 · 顶部通栏', '商品详情页顶部全宽区域。'],
|
||||
'shop_product_sidebar' => ['商品详情页 · 侧栏', '商品详情页侧栏区域(PC 端)。'],
|
||||
'shop_product_bottom_fluid' => ['商品详情页 · 底部通栏', '商品详情页底部全宽区域。'],
|
||||
'shop_cart_top_fluid' => ['购物车页 · 顶部通栏', '购物车页顶部全宽区域。'],
|
||||
'shop_cart_bottom_fluid' => ['购物车页 · 底部通栏', '购物车页底部全宽区域。'],
|
||||
'shop_order_top_fluid' => ['订单页 · 顶部通栏', '订单中心顶部全宽。'],
|
||||
'shop_order_bottom_fluid' => ['订单页 · 底部通栏', '订单中心底部全宽。'],
|
||||
];
|
||||
foreach ($shop_widgets as $sid => $meta) {
|
||||
register_sidebar([
|
||||
|
||||
@@ -159,8 +159,16 @@ class Signin {
|
||||
// Keep lightweight meta for header/badge consumers (zibll checkin_all_day).
|
||||
update_user_meta($user_id, 'aksrt_signin_' . $today_str, 1);
|
||||
$all_day = (int) get_user_meta($user_id, 'aksrt_checkin_all_day', true);
|
||||
update_user_meta($user_id, 'aksrt_checkin_all_day', $all_day + 1);
|
||||
if ($all_day <= 0) {
|
||||
// Fallback to zibll key if migrated users only have that meta.
|
||||
$all_day = (int) get_user_meta($user_id, 'checkin_all_day', true);
|
||||
}
|
||||
$all_day = $all_day + 1;
|
||||
update_user_meta($user_id, 'aksrt_checkin_all_day', $all_day);
|
||||
update_user_meta($user_id, 'checkin_all_day', $all_day); // zibll alias
|
||||
update_user_meta($user_id, 'aksrt_checkin_continuous_day', $new_streak);
|
||||
update_user_meta($user_id, 'checkin_continuous_day', $new_streak); // zibll alias
|
||||
do_action('aksrt_checkin_done', $user_id);
|
||||
|
||||
return new \WP_REST_Response([
|
||||
'success' => true,
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
/**
|
||||
* WeChat JS-SDK share signature (zibll ZibWeChatShare parity).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Frontend;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class WeChatShare {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
/** @var array{wechat_enabled:bool,wechat_appid:string,wechat_app_secret:string,only_logo:bool} */
|
||||
private $config = [];
|
||||
|
||||
public static function get_instance(): self {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function init(): void {
|
||||
$this->config = class_exists('\AKSRT\Settings\Settings')
|
||||
? \AKSRT\Settings\Settings::get_share_settings()
|
||||
: [];
|
||||
|
||||
if (empty($this->config['wechat_enabled'])) {
|
||||
return;
|
||||
}
|
||||
if (empty($this->config['wechat_appid']) || empty($this->config['wechat_app_secret'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action('wp_enqueue_scripts', [$this, 'enqueue_sdk'], 20);
|
||||
add_action('wp_footer', [$this, 'print_share_date'], 99);
|
||||
}
|
||||
|
||||
public function enqueue_sdk(): void {
|
||||
// Only needed in WeChat browser, but enqueue lightly for all (script is external CDN).
|
||||
wp_enqueue_script(
|
||||
'aksrt-jweixin',
|
||||
'https://res.wx.qq.com/open/js/jweixin-1.6.0.js',
|
||||
[],
|
||||
'1.6.0',
|
||||
true
|
||||
);
|
||||
// Ensure our bridge runs after jweixin.
|
||||
if (wp_script_is('aksrt-weixin-share', 'registered') || wp_script_is('aksrt-weixin-share', 'enqueued')) {
|
||||
wp_script_add_data('aksrt-weixin-share', 'group', 1);
|
||||
}
|
||||
}
|
||||
|
||||
public function print_share_date(): void {
|
||||
$url = $this->current_url();
|
||||
$sign = $this->get_sign($url);
|
||||
if (!$sign) {
|
||||
return;
|
||||
}
|
||||
$img = $this->resolve_image();
|
||||
$title = wp_get_document_title();
|
||||
$desc = '';
|
||||
if (is_singular()) {
|
||||
$post = get_post();
|
||||
if ($post) {
|
||||
$desc = wp_strip_all_tags(get_the_excerpt($post));
|
||||
}
|
||||
}
|
||||
if ($desc === '') {
|
||||
$desc = (string) get_bloginfo('description');
|
||||
}
|
||||
$payload = [
|
||||
'appId' => $sign['appId'],
|
||||
'timestamp' => (string) $sign['timestamp'],
|
||||
'nonceStr' => $sign['nonceStr'],
|
||||
'signature' => $sign['signature'],
|
||||
'url' => $url,
|
||||
'title' => $title,
|
||||
'img' => $img,
|
||||
'desc' => $desc,
|
||||
];
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
window.WeChatShareDate = <?php echo wp_json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); ?>;
|
||||
(function () {
|
||||
function applyConfig() {
|
||||
if (!window.wx || typeof window.wx.config !== 'function' || !window.WeChatShareDate) return;
|
||||
var e = window.WeChatShareDate;
|
||||
try {
|
||||
window.wx.config({
|
||||
debug: false,
|
||||
appId: e.appId,
|
||||
timestamp: e.timestamp,
|
||||
nonceStr: e.nonceStr,
|
||||
signature: e.signature,
|
||||
jsApiList: ['updateTimelineShareData', 'updateAppMessageShareData']
|
||||
});
|
||||
window.wx.ready(function () {
|
||||
var title = e.title || document.title;
|
||||
var link = e.url || window.location.href;
|
||||
var desc = e.desc || ((document.querySelector('meta[name="description"]') || {}).content || '');
|
||||
var img = e.img || '';
|
||||
if (typeof window.wx.updateTimelineShareData === 'function') {
|
||||
window.wx.updateTimelineShareData({ title: title, link: link, imgUrl: img });
|
||||
}
|
||||
if (typeof window.wx.updateAppMessageShareData === 'function') {
|
||||
window.wx.updateAppMessageShareData({ title: title, desc: desc, link: link, imgUrl: img });
|
||||
}
|
||||
});
|
||||
} catch (err) {}
|
||||
}
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function () { setTimeout(applyConfig, 50); });
|
||||
} else {
|
||||
setTimeout(applyConfig, 50);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{appId:string,nonceStr:string,timestamp:int,signature:string}|null
|
||||
*/
|
||||
public function get_sign(string $url): ?array {
|
||||
$ticket = $this->get_jsapi_ticket();
|
||||
if ($ticket === '') {
|
||||
return null;
|
||||
}
|
||||
$timestamp = time();
|
||||
$nonce = $this->nonce_string();
|
||||
$raw = "jsapi_ticket={$ticket}&noncestr={$nonce}×tamp={$timestamp}&url={$url}";
|
||||
return [
|
||||
'appId' => (string) $this->config['wechat_appid'],
|
||||
'nonceStr' => $nonce,
|
||||
'timestamp' => $timestamp,
|
||||
'signature' => sha1($raw),
|
||||
];
|
||||
}
|
||||
|
||||
private function current_url(): string {
|
||||
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|
||||
|| (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443)
|
||||
|| (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
|
||||
$protocol = $https ? 'https://' : 'http://';
|
||||
$host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash((string) $_SERVER['HTTP_HOST'])) : wp_parse_url(home_url('/'), PHP_URL_HOST);
|
||||
$uri = isset($_SERVER['REQUEST_URI']) ? (string) wp_unslash($_SERVER['REQUEST_URI']) : '/';
|
||||
// Drop hash fragment if any (should not be present in REQUEST_URI).
|
||||
return $protocol . $host . $uri;
|
||||
}
|
||||
|
||||
private function resolve_image(): string {
|
||||
$only_logo = !empty($this->config['only_logo']);
|
||||
$default = '';
|
||||
if (!empty($this->config['share_img'])) {
|
||||
$default = (string) $this->config['share_img'];
|
||||
} elseif (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$default = (string) (\AKSRT\Settings\Settings::get_value('favicon', '') ?: \AKSRT\Settings\Settings::get_value('iconpng', ''));
|
||||
}
|
||||
if ($only_logo) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$pic = '';
|
||||
if (is_singular()) {
|
||||
$post_id = get_queried_object_id();
|
||||
if ($post_id && has_post_thumbnail($post_id)) {
|
||||
$pic = (string) get_the_post_thumbnail_url($post_id, 'full');
|
||||
}
|
||||
} elseif (is_author()) {
|
||||
$author = get_queried_object();
|
||||
if ($author && !empty($author->ID)) {
|
||||
$pic = (string) get_user_meta((int) $author->ID, 'custom_avatar', true);
|
||||
if ($pic === '') {
|
||||
$pic = get_avatar_url((int) $author->ID, ['size' => 300]);
|
||||
}
|
||||
}
|
||||
} elseif (is_category() || is_tag() || is_tax()) {
|
||||
$term = get_queried_object();
|
||||
if ($term && !empty($term->term_id)) {
|
||||
$img_id = (int) get_term_meta((int) $term->term_id, 'thumbnail_id', true);
|
||||
if ($img_id) {
|
||||
$pic = (string) (wp_get_attachment_image_url($img_id, 'full') ?: '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pic !== '' ? $pic : $default;
|
||||
}
|
||||
|
||||
private function get_jsapi_ticket(): string {
|
||||
$opt = get_option('aksrt_wechatshare_ticket', []);
|
||||
$now = time() + 300;
|
||||
if (is_array($opt) && !empty($opt['ticket']) && !empty($opt['expiration_time']) && (int) $opt['expiration_time'] > $now) {
|
||||
return (string) $opt['ticket'];
|
||||
}
|
||||
|
||||
$token = $this->get_access_token();
|
||||
if ($token === '') {
|
||||
return '';
|
||||
}
|
||||
$url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . rawurlencode($token) . '&type=jsapi';
|
||||
$res = $this->http_json($url);
|
||||
if (empty($res['ticket'])) {
|
||||
return '';
|
||||
}
|
||||
$res['expiration_time'] = time() + max(60, (int) ($res['expires_in'] ?? 7200));
|
||||
update_option('aksrt_wechatshare_ticket', $res, false);
|
||||
return (string) $res['ticket'];
|
||||
}
|
||||
|
||||
private function get_access_token(): string {
|
||||
// Prefer shared GZH token cache when present.
|
||||
$opt = get_option('aksrt_weixingzh_access_token', []);
|
||||
$now = time() + 300;
|
||||
if (is_array($opt) && !empty($opt['access_token']) && !empty($opt['expiration_time']) && (int) $opt['expiration_time'] > $now) {
|
||||
return (string) $opt['access_token'];
|
||||
}
|
||||
|
||||
$appid = (string) $this->config['wechat_appid'];
|
||||
$secret = (string) $this->config['wechat_app_secret'];
|
||||
$url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . rawurlencode($appid) . '&secret=' . rawurlencode($secret);
|
||||
$res = $this->http_json($url);
|
||||
if (empty($res['access_token'])) {
|
||||
return '';
|
||||
}
|
||||
$res['expiration_time'] = time() + max(60, (int) ($res['expires_in'] ?? 7200));
|
||||
update_option('aksrt_weixingzh_access_token', $res, false);
|
||||
return (string) $res['access_token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
private function http_json(string $url): array {
|
||||
$response = wp_remote_get($url, [
|
||||
'timeout' => 8,
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
]);
|
||||
if (is_wp_error($response)) {
|
||||
return [];
|
||||
}
|
||||
$body = (string) wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
private function nonce_string(int $length = 16): string {
|
||||
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$str = '';
|
||||
$max = strlen($chars) - 1;
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$str .= $chars[random_int(0, $max)];
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
/**
|
||||
* Auto-grant medals from catalog thresholds (zibll zib_auto_add_user_medal lite).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\User;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class BadgeAutoAward {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
public static function get_instance(): self {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function init(): void {
|
||||
// Run after login / current user bootstrap.
|
||||
add_action('wp_login', [$this, 'on_login'], 20, 2);
|
||||
add_action('wp', [$this, 'maybe_for_current_user'], 30);
|
||||
// Cheap hooks for common counters.
|
||||
add_action('publish_post', [$this, 'on_content_change'], 20, 1);
|
||||
add_action('comment_post', [$this, 'on_content_change'], 20, 1);
|
||||
add_action('aksrt_user_followed', [$this, 'on_follow'], 20, 2);
|
||||
add_action('aksrt_checkin_done', [$this, 'on_checkin'], 20, 1);
|
||||
}
|
||||
|
||||
public function on_login($user_login, $user): void {
|
||||
if ($user instanceof \WP_User) {
|
||||
$this->evaluate((int) $user->ID);
|
||||
}
|
||||
}
|
||||
|
||||
public function maybe_for_current_user(): void {
|
||||
if (!is_user_logged_in() || is_admin()) {
|
||||
return;
|
||||
}
|
||||
// Throttle: once per 10 minutes per user.
|
||||
$uid = get_current_user_id();
|
||||
$key = 'aksrt_badge_auto_' . $uid;
|
||||
if (get_transient($key)) {
|
||||
return;
|
||||
}
|
||||
set_transient($key, 1, 10 * MINUTE_IN_SECONDS);
|
||||
$this->evaluate($uid);
|
||||
}
|
||||
|
||||
public function on_content_change($arg = null): void {
|
||||
$uid = get_current_user_id();
|
||||
if ($uid > 0) {
|
||||
$this->evaluate($uid);
|
||||
}
|
||||
}
|
||||
|
||||
public function on_follow(int $follower_id, int $following_id): void {
|
||||
if ($following_id > 0) {
|
||||
$this->evaluate($following_id);
|
||||
}
|
||||
if ($follower_id > 0) {
|
||||
$this->evaluate($follower_id);
|
||||
}
|
||||
}
|
||||
|
||||
public function on_checkin(int $user_id): void {
|
||||
if ($user_id > 0) {
|
||||
$this->evaluate($user_id);
|
||||
}
|
||||
}
|
||||
|
||||
public function evaluate(int $user_id): void {
|
||||
if ($user_id <= 0 || !class_exists('\AKSRT\User\Badges') || !Badges::enabled()) {
|
||||
return;
|
||||
}
|
||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
||||
return;
|
||||
}
|
||||
$identity = \AKSRT\Settings\Settings::get_user_identity_settings();
|
||||
$medal = is_array($identity['medal'] ?? null) ? $identity['medal'] : [];
|
||||
$items = is_array($medal['items_by_slug'] ?? null) ? $medal['items_by_slug'] : [];
|
||||
if (!$items) {
|
||||
// Fall back to badge dictionary without thresholds.
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($items as $slug => $item) {
|
||||
$get_type = sanitize_key((string) ($item['get_type'] ?? 'manually_add'));
|
||||
if ($get_type === 'manually_add' || $get_type === '') {
|
||||
continue;
|
||||
}
|
||||
$need = max(0, (int) ($item['get_val'] ?? 0));
|
||||
if ($need <= 0) {
|
||||
continue;
|
||||
}
|
||||
$val = $this->metric($user_id, $get_type);
|
||||
if ($val >= $need) {
|
||||
Badges::grant($user_id, (string) $slug, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function metric(int $user_id, string $type): int {
|
||||
switch ($type) {
|
||||
case 'registration_time':
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user) {
|
||||
return 0;
|
||||
}
|
||||
$reg = strtotime((string) $user->user_registered);
|
||||
if ($reg <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return max(0, (int) floor((time() - $reg) / DAY_IN_SECONDS));
|
||||
|
||||
case 'checkin_all_day':
|
||||
$v = (int) get_user_meta($user_id, 'aksrt_checkin_all_day', true);
|
||||
if ($v <= 0) {
|
||||
$v = (int) get_user_meta($user_id, 'checkin_all_day', true);
|
||||
}
|
||||
return $v;
|
||||
|
||||
case 'new_post':
|
||||
return (int) count_user_posts($user_id, 'post', true);
|
||||
|
||||
case 'bbs_post':
|
||||
return post_type_exists('aksrt_forum_topic')
|
||||
? (int) count_user_posts($user_id, 'aksrt_forum_topic', true)
|
||||
: 0;
|
||||
|
||||
case 'comment':
|
||||
return (int) get_comments(['user_id' => $user_id, 'count' => true, 'status' => 'approve']);
|
||||
|
||||
case 'followed':
|
||||
if (class_exists('\AKSRT\User\Follow')) {
|
||||
return (int) Follow::get_instance()->get_follower_count($user_id);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'like':
|
||||
return (int) get_user_meta($user_id, 'aksrt_like_count', true)
|
||||
?: (int) get_user_meta($user_id, 'like-posts', true);
|
||||
|
||||
case 'views':
|
||||
return (int) get_user_meta($user_id, 'aksrt_user_views', true);
|
||||
|
||||
case 'pay_income':
|
||||
return (int) get_user_meta($user_id, 'aksrt_pay_income', true);
|
||||
|
||||
case 'pay_rebate':
|
||||
return (int) get_user_meta($user_id, 'aksrt_pay_rebate', true);
|
||||
|
||||
default:
|
||||
/**
|
||||
* Allow extensions to provide metric values.
|
||||
*
|
||||
* @param int $value
|
||||
* @param int $user_id
|
||||
* @param string $type
|
||||
*/
|
||||
return (int) apply_filters('aksrt_badge_metric_value', 0, $user_id, $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,9 +185,14 @@ class Badges {
|
||||
}
|
||||
$wear = sanitize_key((string) get_user_meta($user_id, self::META_WEAR, true));
|
||||
if ($wear === '') {
|
||||
return '';
|
||||
// zibll alias.
|
||||
$wear = sanitize_key((string) get_user_meta($user_id, 'wear_medal', true));
|
||||
}
|
||||
$owned = self::get_owned($user_id);
|
||||
if ($wear === '') {
|
||||
// Default to newest/first owned badge when unset (zibll behavior).
|
||||
return $owned[0] ?? '';
|
||||
}
|
||||
return in_array($wear, $owned, true) ? $wear : '';
|
||||
}
|
||||
|
||||
@@ -211,6 +216,7 @@ class Badges {
|
||||
return new \WP_Error('aksrt_badge_not_owned', __('尚未获得该徽章', 'aksrt'), ['status' => 403]);
|
||||
}
|
||||
update_user_meta($user_id, self::META_WEAR, $slug);
|
||||
update_user_meta($user_id, 'wear_medal', $slug); // zibll alias
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,8 +99,13 @@ class AboutWidget extends \WP_Widget {
|
||||
$avatar = get_avatar_url(0, ['size' => 160, 'default' => 'mystery']);
|
||||
|
||||
$oauth_html = '';
|
||||
if (function_exists('\AKSRT\Auth\OAuth') && method_exists(\AKSRT\Auth\OAuth::get_instance(), 'get_login_buttons')) {
|
||||
$oauth_html = \AKSRT\Auth\OAuth::get_instance()->get_login_buttons();
|
||||
if (class_exists('\AKSRT\Auth\OAuth')) {
|
||||
$oauth = \AKSRT\Auth\OAuth::get_instance();
|
||||
if (method_exists($oauth, 'render_social_buttons')) {
|
||||
$oauth_html = (string) $oauth->render_social_buttons(__('社交账号登录', 'aksrt'));
|
||||
} elseif (method_exists($oauth, 'get_login_buttons')) {
|
||||
$oauth_html = (string) $oauth->get_login_buttons();
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="aksrt-user-card">
|
||||
@@ -120,9 +125,9 @@ class AboutWidget extends \WP_Widget {
|
||||
</div>
|
||||
|
||||
<div class="aksrt-user-card__btns">
|
||||
<a class="aksrt-user-card__btn aksrt-user-card__btn--primary" href="<?php echo esc_url($login_url); ?>"><?php esc_html_e('登 录', 'aksrt'); ?></a>
|
||||
<a class="aksrt-user-card__btn aksrt-user-card__btn--primary signin-loader" href="<?php echo esc_url($login_url); ?>"><?php esc_html_e('登 录', 'aksrt'); ?></a>
|
||||
<?php if (get_option('users_can_register')) : ?>
|
||||
<a class="aksrt-user-card__btn aksrt-user-card__btn--outline" href="<?php echo esc_url($register_url); ?>"><?php esc_html_e('注 册', 'aksrt'); ?></a>
|
||||
<a class="aksrt-user-card__btn aksrt-user-card__btn--outline signup-loader" href="<?php echo esc_url($register_url); ?>"><?php esc_html_e('注 册', 'aksrt'); ?></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Custom buttons group (zibll zib_widget_ui_buttons lite).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,106 +11,169 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class ButtonsWidget extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_buttons', esc_html__('AKSRT 按钮组', 'aksrt'), [
|
||||
'description' => esc_html__('显示一组自定义按钮', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_buttons', esc_html__('AKSRT 按钮组', 'aksrt'), [
|
||||
'description' => esc_html__('显示一组自定义按钮,支持外链跳转与样式。', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget'];
|
||||
$title = apply_filters('widget_title', $instance['title'] ?? '', $instance, $this->id_base);
|
||||
$buttons = isset($instance['buttons']) && is_array($instance['buttons']) ? $instance['buttons'] : [];
|
||||
$layout = sanitize_key($instance['layout'] ?? 'vertical');
|
||||
public function widget($args, $instance): void {
|
||||
$buttons = isset($instance['buttons']) && is_array($instance['buttons']) ? $instance['buttons'] : [];
|
||||
$layout = sanitize_key((string) ($instance['layout'] ?? 'horizontal'));
|
||||
if (!in_array($layout, ['vertical', 'horizontal'], true)) {
|
||||
$layout = 'horizontal';
|
||||
}
|
||||
$align = sanitize_key((string) ($instance['align'] ?? 'center'));
|
||||
if (!in_array($align, ['left', 'center', 'right'], true)) {
|
||||
$align = 'center';
|
||||
}
|
||||
$radius = !empty($instance['radius']);
|
||||
$hollow = !empty($instance['hollow']);
|
||||
$go_link = !empty($instance['go_link']);
|
||||
$gap = max(4, min(30, (int) ($instance['gap'] ?? 10)));
|
||||
|
||||
if ($title) echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
$items = [];
|
||||
foreach ($buttons as $btn) {
|
||||
if (!is_array($btn)) {
|
||||
continue;
|
||||
}
|
||||
$text = sanitize_text_field((string) ($btn['text'] ?? ''));
|
||||
$url = esc_url_raw(trim((string) ($btn['url'] ?? '')));
|
||||
if ($text === '') {
|
||||
continue;
|
||||
}
|
||||
if ($url !== '' && $go_link && function_exists('aksrt_go_link')) {
|
||||
$url = aksrt_go_link($url, true);
|
||||
}
|
||||
$items[] = [
|
||||
'text' => $text,
|
||||
'url' => $url,
|
||||
'style' => sanitize_key((string) ($btn['style'] ?? 'primary')),
|
||||
'icon' => sanitize_text_field((string) ($btn['icon'] ?? $btn['icon_left'] ?? '')),
|
||||
'icon_right' => sanitize_text_field((string) ($btn['icon_right'] ?? '')),
|
||||
'new_window' => !empty($btn['new_window']) || !empty($btn['target']),
|
||||
];
|
||||
}
|
||||
if (!$items) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($buttons)) : ?>
|
||||
<div class="widget-buttons widget-buttons--<?php echo esc_attr($layout); ?>">
|
||||
<?php foreach ($buttons as $btn) :
|
||||
$btn_text = sanitize_text_field($btn['text'] ?? '');
|
||||
$btn_url = esc_url($btn['url'] ?? '');
|
||||
$btn_style = sanitize_key($btn['style'] ?? 'primary');
|
||||
$btn_icon = sanitize_text_field($btn['icon'] ?? '');
|
||||
$btn_target = !empty($btn['new_window']) ? '_blank' : '_self';
|
||||
if ($btn_text === '' || $btn_url === '') continue;
|
||||
?>
|
||||
<a href="<?php echo $btn_url; ?>" class="widget-buttons__btn widget-buttons__btn--<?php echo esc_attr($btn_style); ?>" target="<?php echo esc_attr($btn_target); ?>" rel="noopener">
|
||||
<?php if ($btn_icon) : ?><i class="<?php echo esc_attr($btn_icon); ?>" aria-hidden="true"></i> <?php endif; ?>
|
||||
<?php echo esc_html($btn_text); ?>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif;
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
$wrap = 'widget-buttons widget-buttons--' . $layout . ' align-' . $align;
|
||||
if ($radius) {
|
||||
$wrap .= ' is-radius';
|
||||
}
|
||||
if ($hollow) {
|
||||
$wrap .= ' is-hollow';
|
||||
}
|
||||
echo '<div class="' . esc_attr($wrap) . '" style="--btn-gap:' . esc_attr((string) $gap) . 'px">';
|
||||
foreach ($items as $btn) {
|
||||
$style = in_array($btn['style'], ['primary', 'secondary', 'outline', 'text', 'pink', 'blue', 'green', 'yellow', 'purple'], true)
|
||||
? $btn['style']
|
||||
: 'primary';
|
||||
$cls = 'widget-buttons__btn widget-buttons__btn--' . $style;
|
||||
$href = $btn['url'] !== '' ? $btn['url'] : 'javascript:void(0)';
|
||||
$tgt = $btn['new_window'] && $btn['url'] !== '' ? ' target="_blank" rel="noopener noreferrer"' : '';
|
||||
echo '<a href="' . esc_url($href) . '" class="' . esc_attr($cls) . '"' . $tgt . '>';
|
||||
if ($btn['icon'] !== '') {
|
||||
echo '<i class="' . esc_attr($btn['icon']) . '" aria-hidden="true"></i> ';
|
||||
}
|
||||
echo esc_html($btn['text']);
|
||||
if ($btn['icon_right'] !== '') {
|
||||
echo ' <i class="' . esc_attr($btn['icon_right']) . '" aria-hidden="true"></i>';
|
||||
}
|
||||
echo '</a>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
public function form($instance): void {
|
||||
$buttons = isset($instance['buttons']) && is_array($instance['buttons']) ? $instance['buttons'] : [];
|
||||
while (count($buttons) < 3) {
|
||||
$buttons[] = ['text' => '', 'url' => '', 'style' => 'primary', 'icon' => '', 'new_window' => false];
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('title'); ?>"><?php esc_html_e('标题(可选):', 'aksrt'); ?></label>
|
||||
<input class="widefat" type="text" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title'] ?? ''); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('layout'); ?>"><?php esc_html_e('布局:', 'aksrt'); ?></label>
|
||||
<select class="widefat" id="<?php echo $this->get_field_id('layout'); ?>" name="<?php echo $this->get_field_name('layout'); ?>">
|
||||
<option value="vertical" <?php selected($instance['layout'] ?? '', 'vertical'); ?>><?php esc_html_e('垂直', 'aksrt'); ?></option>
|
||||
<option value="horizontal" <?php selected($instance['layout'] ?? '', 'horizontal'); ?>><?php esc_html_e('水平', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<hr>
|
||||
<?php foreach ($buttons as $i => $btn) : ?>
|
||||
<div style="border:1px solid #ddd;padding:6px;margin-bottom:6px;border-radius:4px;">
|
||||
<p style="margin:0 0 4px;">
|
||||
<input class="widefat" type="text" name="<?php echo $this->get_field_name("buttons[{$i}][text]"); ?>" value="<?php echo esc_attr($btn['text']); ?>" placeholder="<?php esc_attr_e('按钮文字', 'aksrt'); ?>">
|
||||
</p>
|
||||
<p style="margin:0 0 4px;">
|
||||
<input class="widefat" type="url" name="<?php echo $this->get_field_name("buttons[{$i}][url]"); ?>" value="<?php echo esc_attr($btn['url']); ?>" placeholder="<?php esc_attr_e('链接地址', 'aksrt'); ?>">
|
||||
</p>
|
||||
<p style="margin:0 0 4px;">
|
||||
<select class="widefat" name="<?php echo $this->get_field_name("buttons[{$i}][style]"); ?>">
|
||||
<option value="primary" <?php selected($btn['style'] ?? '', 'primary'); ?>><?php esc_html_e('主要', 'aksrt'); ?></option>
|
||||
<option value="secondary" <?php selected($btn['style'] ?? '', 'secondary'); ?>><?php esc_html_e('次要', 'aksrt'); ?></option>
|
||||
<option value="outline" <?php selected($btn['style'] ?? '', 'outline'); ?>><?php esc_html_e('线框', 'aksrt'); ?></option>
|
||||
<option value="text" <?php selected($btn['style'] ?? '', 'text'); ?>><?php esc_html_e('文字', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p style="margin:0 0 4px;">
|
||||
<input class="widefat" type="text" name="<?php echo $this->get_field_name("buttons[{$i}][icon]"); ?>" value="<?php echo esc_attr($btn['icon'] ?? ''); ?>" placeholder="<?php esc_attr_e('图标(可选)', 'aksrt'); ?>">
|
||||
</p>
|
||||
<p style="margin:0;">
|
||||
<label><input type="checkbox" name="<?php echo $this->get_field_name("buttons[{$i}][new_window]"); ?>" value="1" <?php checked(!empty($btn['new_window'])); ?>> <?php esc_html_e('新窗口打开', 'aksrt'); ?></label>
|
||||
</p>
|
||||
</div>
|
||||
<?php endforeach;
|
||||
}
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$buttons = [];
|
||||
if (isset($new_instance['buttons']) && is_array($new_instance['buttons'])) {
|
||||
$allowed_styles = ['primary', 'secondary', 'outline', 'text'];
|
||||
foreach ($new_instance['buttons'] as $btn) {
|
||||
if (!is_array($btn)) continue;
|
||||
$style = sanitize_key($btn['style'] ?? 'primary');
|
||||
if (!in_array($style, $allowed_styles, true)) $style = 'primary';
|
||||
$buttons[] = [
|
||||
'text' => sanitize_text_field($btn['text'] ?? ''),
|
||||
'url' => esc_url_raw($btn['url'] ?? ''),
|
||||
'style' => $style,
|
||||
'icon' => sanitize_text_field($btn['icon'] ?? ''),
|
||||
'new_window' => !empty($btn['new_window']),
|
||||
];
|
||||
}
|
||||
}
|
||||
return [
|
||||
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
||||
'layout' => in_array($new_instance['layout'] ?? '', ['vertical', 'horizontal'], true) ? $new_instance['layout'] : 'vertical',
|
||||
'buttons' => $buttons,
|
||||
];
|
||||
}
|
||||
public function form($instance): void {
|
||||
$buttons = isset($instance['buttons']) && is_array($instance['buttons']) ? $instance['buttons'] : [];
|
||||
while (count($buttons) < 4) {
|
||||
$buttons[] = ['text' => '', 'url' => '', 'style' => 'primary', 'icon' => '', 'icon_right' => '', 'new_window' => false];
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题(可选)', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('布局', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('layout')); ?>">
|
||||
<option value="horizontal" <?php selected(($instance['layout'] ?? 'horizontal'), 'horizontal'); ?>><?php esc_html_e('水平', 'aksrt'); ?></option>
|
||||
<option value="vertical" <?php selected(($instance['layout'] ?? ''), 'vertical'); ?>><?php esc_html_e('垂直', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
<label><?php esc_html_e('对齐', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('align')); ?>">
|
||||
<option value="center" <?php selected(($instance['align'] ?? 'center'), 'center'); ?>><?php esc_html_e('居中', 'aksrt'); ?></option>
|
||||
<option value="left" <?php selected(($instance['align'] ?? ''), 'left'); ?>><?php esc_html_e('左', 'aksrt'); ?></option>
|
||||
<option value="right" <?php selected(($instance['align'] ?? ''), 'right'); ?>><?php esc_html_e('右', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('radius')); ?>" value="1" <?php checked(!empty($instance['radius'])); ?>> <?php esc_html_e('圆角胶囊', 'aksrt'); ?></label>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('hollow')); ?>" value="1" <?php checked(!empty($instance['hollow'])); ?>> <?php esc_html_e('镂空', 'aksrt'); ?></label>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('go_link')); ?>" value="1" <?php checked(!empty($instance['go_link'])); ?>> <?php esc_html_e('外链跳转页', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php foreach ($buttons as $i => $btn) : ?>
|
||||
<div style="border:1px solid #ddd;padding:6px;margin-bottom:6px;border-radius:4px;">
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name("buttons[{$i}][text]")); ?>" value="<?php echo esc_attr((string) ($btn['text'] ?? '')); ?>" placeholder="<?php esc_attr_e('按钮文字', 'aksrt'); ?>">
|
||||
<input class="widefat" type="url" name="<?php echo esc_attr($this->get_field_name("buttons[{$i}][url]")); ?>" value="<?php echo esc_attr((string) ($btn['url'] ?? '')); ?>" placeholder="<?php esc_attr_e('链接', 'aksrt'); ?>">
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name("buttons[{$i}][icon]")); ?>" value="<?php echo esc_attr((string) ($btn['icon'] ?? '')); ?>" placeholder="<?php esc_attr_e('左图标 class', 'aksrt'); ?>">
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name("buttons[{$i}][icon_right]")); ?>" value="<?php echo esc_attr((string) ($btn['icon_right'] ?? '')); ?>" placeholder="<?php esc_attr_e('右图标 class', 'aksrt'); ?>">
|
||||
<select class="widefat" name="<?php echo esc_attr($this->get_field_name("buttons[{$i}][style]")); ?>">
|
||||
<?php foreach (['primary' => '主要', 'secondary' => '次要', 'outline' => '线框', 'text' => '文字', 'pink' => '粉', 'blue' => '蓝', 'green' => '绿'] as $k => $lab) : ?>
|
||||
<option value="<?php echo esc_attr($k); ?>" <?php selected(($btn['style'] ?? 'primary'), $k); ?>><?php echo esc_html($lab); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name("buttons[{$i}][new_window]")); ?>" value="1" <?php checked(!empty($btn['new_window'])); ?>> <?php esc_html_e('新窗口', 'aksrt'); ?></label>
|
||||
</div>
|
||||
<?php endforeach;
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$buttons = [];
|
||||
if (isset($new_instance['buttons']) && is_array($new_instance['buttons'])) {
|
||||
foreach ($new_instance['buttons'] as $btn) {
|
||||
if (!is_array($btn)) {
|
||||
continue;
|
||||
}
|
||||
$text = sanitize_text_field((string) ($btn['text'] ?? ''));
|
||||
if ($text === '') {
|
||||
continue;
|
||||
}
|
||||
$buttons[] = [
|
||||
'text' => $text,
|
||||
'url' => esc_url_raw(trim((string) ($btn['url'] ?? ''))),
|
||||
'style' => sanitize_key((string) ($btn['style'] ?? 'primary')),
|
||||
'icon' => sanitize_text_field((string) ($btn['icon'] ?? '')),
|
||||
'icon_right' => sanitize_text_field((string) ($btn['icon_right'] ?? '')),
|
||||
'new_window' => !empty($btn['new_window']),
|
||||
];
|
||||
if (count($buttons) >= 8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'layout' => ($new_instance['layout'] ?? '') === 'vertical' ? 'vertical' : 'horizontal',
|
||||
'align' => in_array(($new_instance['align'] ?? ''), ['left', 'center', 'right'], true) ? $new_instance['align'] : 'center',
|
||||
'radius' => !empty($new_instance['radius']) ? 1 : 0,
|
||||
'hollow' => !empty($new_instance['hollow']) ? 1 : 0,
|
||||
'go_link' => !empty($new_instance['go_link']) ? 1 : 0,
|
||||
'gap' => max(4, min(30, (int) ($new_instance['gap'] ?? 10))),
|
||||
'buttons' => $buttons,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Categories list (zibll-like options depth).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -13,60 +15,154 @@ class CategoriesWidget extends \WP_Widget {
|
||||
parent::__construct(
|
||||
'aksrt_categories',
|
||||
esc_html__('AKSRT 分类目录', 'aksrt'),
|
||||
array(
|
||||
'description' => esc_html__('以列表形式展示文章分类', 'aksrt'),
|
||||
[
|
||||
'description' => esc_html__('以列表形式展示文章分类', 'aksrt'),
|
||||
'customize_selective_refresh' => true,
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance) {
|
||||
echo $args['before_widget'];
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
|
||||
$title = apply_filters('widget_title', $instance['title'], $instance, $this->id_base);
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
if ($title): ?>
|
||||
<h3 class="widget-title"><?php echo $title; ?></h3>
|
||||
<?php endif;
|
||||
$count = max(1, min(50, (int) ($instance['count'] ?? 8)));
|
||||
$orderby = sanitize_key((string) ($instance['orderby'] ?? 'count'));
|
||||
if (!in_array($orderby, ['count', 'name', 'id', 'slug'], true)) {
|
||||
$orderby = 'count';
|
||||
}
|
||||
$order = strtoupper((string) ($instance['order'] ?? 'DESC')) === 'ASC' ? 'ASC' : 'DESC';
|
||||
$hide_empty = !isset($instance['hide_empty']) || !empty($instance['hide_empty']);
|
||||
$hierarchical = !empty($instance['hierarchical']);
|
||||
$parent = max(0, (int) ($instance['parent'] ?? 0));
|
||||
$show_count = !isset($instance['show_count']) || !empty($instance['show_count']);
|
||||
$exclude = $this->parse_ids((string) ($instance['exclude'] ?? ''));
|
||||
$include = $this->parse_ids((string) ($instance['include'] ?? ''));
|
||||
|
||||
$count = absint($instance['count'] ?: 8);
|
||||
$cats = get_categories(array('number' => $count, 'orderby' => 'count', 'order' => 'DESC'));
|
||||
?>
|
||||
<ul class="widget-list">
|
||||
<?php foreach ($cats as $cat): ?>
|
||||
<li>
|
||||
<a href="<?php echo esc_url(get_category_link($cat->term_id)); ?>"><?php echo esc_html($cat->name); ?></a>
|
||||
<span><?php echo (int)$cat->count; ?></span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php
|
||||
echo $args['after_widget'];
|
||||
$term_args = [
|
||||
'taxonomy' => 'category',
|
||||
'number' => $count,
|
||||
'orderby' => $orderby,
|
||||
'order' => $order,
|
||||
'hide_empty' => $hide_empty,
|
||||
'hierarchical' => $hierarchical,
|
||||
];
|
||||
if ($parent > 0) {
|
||||
$term_args['parent'] = $parent;
|
||||
}
|
||||
if ($include) {
|
||||
$term_args['include'] = $include;
|
||||
$term_args['orderby'] = 'include';
|
||||
unset($term_args['number']);
|
||||
}
|
||||
if ($exclude) {
|
||||
$term_args['exclude'] = $exclude;
|
||||
}
|
||||
|
||||
$cats = get_categories($term_args);
|
||||
if (!$cats) {
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<ul class="widget-list aksrt-cat-list">';
|
||||
foreach ($cats as $cat) {
|
||||
echo '<li>';
|
||||
echo '<a href="' . esc_url(get_category_link($cat->term_id)) . '">' . esc_html($cat->name) . '</a>';
|
||||
if ($show_count) {
|
||||
echo '<span class="count">' . (int) $cat->count . '</span>';
|
||||
}
|
||||
echo '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function form($instance) {
|
||||
$title = $instance['title'] ?? __('分类目录', 'aksrt');
|
||||
$count = isset($instance['count']) ? (int)$instance['count'] : 8;
|
||||
/** @return array<int,int> */
|
||||
private function parse_ids(string $raw): array {
|
||||
if ($raw === '') {
|
||||
return [];
|
||||
}
|
||||
$ids = [];
|
||||
foreach (preg_split('/[\s,]+/', $raw) ?: [] as $p) {
|
||||
$id = (int) $p;
|
||||
if ($id > 0) {
|
||||
$ids[] = $id;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('title'); ?>"><?php esc_html_e('标题:', 'aksrt'); ?></label>
|
||||
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
|
||||
name="<?php echo $this->get_field_name('title'); ?>"
|
||||
type="text" value="<?php echo esc_attr($title); ?>">
|
||||
<label><?php esc_html_e('标题:', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? __('分类目录', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('count'); ?>"><?php esc_html_e('显示数量:', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" id="<?php echo $this->get_field_id('count'); ?>"
|
||||
name="<?php echo $this->get_field_name('count'); ?>"
|
||||
type="number" min="1" max="50" value="<?php echo $count; ?>">
|
||||
<label><?php esc_html_e('显示数量:', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="50" name="<?php echo esc_attr($this->get_field_name('count')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['count'] ?? 8))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('排序', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('orderby')); ?>">
|
||||
<option value="count" <?php selected(($instance['orderby'] ?? 'count'), 'count'); ?>><?php esc_html_e('文章数', 'aksrt'); ?></option>
|
||||
<option value="name" <?php selected(($instance['orderby'] ?? ''), 'name'); ?>><?php esc_html_e('名称', 'aksrt'); ?></option>
|
||||
<option value="id" <?php selected(($instance['orderby'] ?? ''), 'id'); ?>><?php esc_html_e('ID', 'aksrt'); ?></option>
|
||||
<option value="slug" <?php selected(($instance['orderby'] ?? ''), 'slug'); ?>><?php esc_html_e('别名', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('order')); ?>">
|
||||
<option value="DESC" <?php selected(($instance['order'] ?? 'DESC'), 'DESC'); ?>><?php esc_html_e('降序', 'aksrt'); ?></option>
|
||||
<option value="ASC" <?php selected(($instance['order'] ?? ''), 'ASC'); ?>><?php esc_html_e('升序', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('父分类 ID(0=全部)', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="0" name="<?php echo esc_attr($this->get_field_name('parent')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['parent'] ?? 0))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('包含 ID', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('include')); ?>" value="<?php echo esc_attr((string) ($instance['include'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('排除 ID', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('exclude')); ?>" value="<?php echo esc_attr((string) ($instance['exclude'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_count')); ?>" value="1" <?php checked(!isset($instance['show_count']) || !empty($instance['show_count'])); ?>> <?php esc_html_e('显示数量', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('hide_empty')); ?>" value="1" <?php checked(!isset($instance['hide_empty']) || !empty($instance['hide_empty'])); ?>> <?php esc_html_e('隐藏空分类', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('hierarchical')); ?>" value="1" <?php checked(!empty($instance['hierarchical'])); ?>> <?php esc_html_e('层级', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new, $old) {
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$orderby = sanitize_key((string) ($new_instance['orderby'] ?? 'count'));
|
||||
if (!in_array($orderby, ['count', 'name', 'id', 'slug'], true)) {
|
||||
$orderby = 'count';
|
||||
}
|
||||
return [
|
||||
'title' => sanitize_text_field($new['title']),
|
||||
'count' => absint($new['count']),
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'count' => max(1, min(50, (int) ($new_instance['count'] ?? 8))),
|
||||
'orderby' => $orderby,
|
||||
'order' => strtoupper((string) ($new_instance['order'] ?? 'DESC')) === 'ASC' ? 'ASC' : 'DESC',
|
||||
'parent' => max(0, (int) ($new_instance['parent'] ?? 0)),
|
||||
'include' => sanitize_text_field((string) ($new_instance['include'] ?? '')),
|
||||
'exclude' => sanitize_text_field((string) ($new_instance['exclude'] ?? '')),
|
||||
'show_count' => !empty($new_instance['show_count']) ? 1 : 0,
|
||||
'hide_empty' => !empty($new_instance['hide_empty']) ? 1 : 0,
|
||||
'hierarchical' => !empty($new_instance['hierarchical']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class CustomHtmlGapWidget extends \WP_Widget {
|
||||
$mode = sanitize_key($instance['mode'] ?? 'html');
|
||||
|
||||
if ($mode === 'gap') {
|
||||
$height = max(0, min(200, (int) ($instance['gap_height'] ?? 20)));
|
||||
$height = max(0, min(500, (int) ($instance['gap_height'] ?? 20)));
|
||||
echo '<div class="widget-custom-gap" style="height:' . (int) $height . 'px;" aria-hidden="true"></div>';
|
||||
return;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class CustomHtmlGapWidget extends \WP_Widget {
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('gap_height'); ?>"><?php esc_html_e('间距高度(px,仅间距模式):', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" type="number" min="0" max="200" id="<?php echo $this->get_field_id('gap_height'); ?>" name="<?php echo $this->get_field_name('gap_height'); ?>" value="<?php echo (int) ($instance['gap_height'] ?? 20); ?>">
|
||||
<input class="tiny-text" type="number" min="0" max="500" id="<?php echo $this->get_field_id('gap_height'); ?>" name="<?php echo $this->get_field_name('gap_height'); ?>" value="<?php echo (int) ($instance['gap_height'] ?? 20); ?>">
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
@@ -61,7 +61,7 @@ class CustomHtmlGapWidget extends \WP_Widget {
|
||||
'mode' => in_array($new_instance['mode'] ?? '', ['html', 'gap'], true) ? $new_instance['mode'] : 'html',
|
||||
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
||||
'content' => wp_kses_post($new_instance['content'] ?? ''),
|
||||
'gap_height' => max(0, min(200, (int) ($new_instance['gap_height'] ?? 20))),
|
||||
'gap_height' => max(0, min(500, (int) ($new_instance['gap_height'] ?? 20))),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Friend links / bookmarks widget (settings list + WP bookmarks).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,68 +11,140 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class FriendLinksWidget extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_friend_links', esc_html__('AKSRT 友情链接', 'aksrt'), [
|
||||
'description' => esc_html__('显示友情链接列表', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_friend_links', esc_html__('AKSRT 友情链接', 'aksrt'), [
|
||||
'description' => esc_html__('显示友情链接(设置项或 WordPress 书签)。', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget'];
|
||||
$title = apply_filters('widget_title', $instance['title'] ?? __('友情链接', 'aksrt'), $instance, $this->id_base);
|
||||
$show_icon = !empty($instance['show_icon']);
|
||||
$columns = max(1, min(4, (int) ($instance['columns'] ?? 2)));
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? __('友情链接', 'aksrt')), $instance, $this->id_base);
|
||||
$show_icon = !empty($instance['show_icon']) || !isset($instance['show_icon']);
|
||||
$columns = max(1, min(4, (int) ($instance['columns'] ?? 2)));
|
||||
$source = sanitize_key((string) ($instance['source'] ?? 'settings'));
|
||||
$go_link = !empty($instance['go_link']);
|
||||
$limit = max(1, min(100, (int) ($instance['limit'] ?? 24)));
|
||||
|
||||
if ($title) echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
if ($title) {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
$links = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_friend_links() : [];
|
||||
$links = $this->resolve_links($source, $instance, $limit);
|
||||
if (!$links) {
|
||||
echo function_exists('aksrt_get_widget_null')
|
||||
? aksrt_get_widget_null(__('暂无友情链接', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
: '<p class="widget-empty">' . esc_html__('暂无友情链接', 'aksrt') . '</p>';
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="widget-friend-links" style="--fl-columns:<?php echo (int) $columns; ?>;">
|
||||
<?php foreach ($links as $link) :
|
||||
$name = sanitize_text_field((string) ($link['name'] ?? ''));
|
||||
$url = (string) ($link['url'] ?? '');
|
||||
$desc = sanitize_text_field((string) ($link['description'] ?? $link['desc'] ?? ''));
|
||||
$icon = (string) ($link['icon'] ?? $link['image'] ?? '');
|
||||
if ($name === '' || $url === '') {
|
||||
continue;
|
||||
}
|
||||
if ($go_link && function_exists('aksrt_go_link')) {
|
||||
$url = aksrt_go_link($url, true);
|
||||
}
|
||||
?>
|
||||
<a href="<?php echo esc_url($url); ?>" class="widget-friend-links__item" target="_blank" rel="noopener noreferrer" title="<?php echo esc_attr($desc); ?>">
|
||||
<?php if ($show_icon && $icon !== '') : ?>
|
||||
<img src="<?php echo esc_url($icon); ?>" alt="" class="widget-friend-links__icon" width="16" height="16" loading="lazy">
|
||||
<?php endif; ?>
|
||||
<span class="widget-friend-links__name"><?php echo esc_html($name); ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
if (!empty($links)) : ?>
|
||||
<div class="widget-friend-links" style="--fl-columns:<?php echo (int) $columns; ?>;">
|
||||
<?php foreach ($links as $link) :
|
||||
$name = sanitize_text_field($link['name'] ?? '');
|
||||
$url = esc_url($link['url'] ?? '');
|
||||
$desc = sanitize_text_field($link['description'] ?? '');
|
||||
$icon = esc_url($link['icon'] ?? '');
|
||||
if ($name === '' || $url === '') continue;
|
||||
?>
|
||||
<a href="<?php echo $url; ?>" class="widget-friend-links__item" target="_blank" rel="noopener noreferrer" title="<?php echo esc_attr($desc); ?>">
|
||||
<?php if ($show_icon && $icon) : ?>
|
||||
<img src="<?php echo $icon; ?>" alt="" class="widget-friend-links__icon" width="16" height="16"<?php echo function_exists('aksrt_lazy_loading') ? aksrt_lazy_loading('widget') : ' loading="lazy"'; ?>>
|
||||
<?php endif; ?>
|
||||
<span class="widget-friend-links__name"><?php echo esc_html($name); ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无友情链接', 'aksrt')) : '<p class="widget-empty">' . esc_html__('暂无友情链接', 'aksrt') . '</p>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif;
|
||||
/**
|
||||
* @param array<string,mixed> $instance
|
||||
* @return array<int, array<string,string>>
|
||||
*/
|
||||
private function resolve_links(string $source, array $instance, int $limit): array {
|
||||
if ($source === 'bookmarks') {
|
||||
$bm_args = [
|
||||
'orderby' => sanitize_key((string) ($instance['orderby'] ?? 'name')) ?: 'name',
|
||||
'order' => strtoupper((string) ($instance['order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC',
|
||||
'limit' => $limit,
|
||||
];
|
||||
$cats = trim((string) ($instance['cats'] ?? ''));
|
||||
if ($cats !== '') {
|
||||
$bm_args['category'] = $cats;
|
||||
}
|
||||
$out = [];
|
||||
foreach (get_bookmarks($bm_args) as $b) {
|
||||
$out[] = [
|
||||
'name' => (string) $b->link_name,
|
||||
'url' => (string) $b->link_url,
|
||||
'description' => (string) $b->link_description,
|
||||
'icon' => (string) $b->link_image,
|
||||
];
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
$links = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_friend_links() : [];
|
||||
if (!is_array($links) || !$links) {
|
||||
// Fallback to WP bookmarks when settings empty.
|
||||
return $this->resolve_links('bookmarks', $instance, $limit);
|
||||
}
|
||||
return array_slice(array_values($links), 0, $limit);
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('title'); ?>"><?php esc_html_e('标题:', 'aksrt'); ?></label>
|
||||
<input class="widefat" type="text" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title'] ?? __('友情链接', 'aksrt')); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('columns'); ?>"><?php esc_html_e('列数:', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" type="number" min="1" max="4" id="<?php echo $this->get_field_id('columns'); ?>" name="<?php echo $this->get_field_name('columns'); ?>" value="<?php echo (int) ($instance['columns'] ?? 2); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo $this->get_field_name('show_icon'); ?>" value="1" <?php checked(!empty($instance['show_icon'])); ?>> <?php esc_html_e('显示站点图标', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<p style="color:#666;font-size:12px;"><?php esc_html_e('链接数据在后台"友链管理"中配置。', 'aksrt'); ?></p>
|
||||
<?php
|
||||
}
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题:', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? __('友情链接', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('数据源', 'aksrt'); ?>
|
||||
<select class="widefat" name="<?php echo esc_attr($this->get_field_name('source')); ?>">
|
||||
<option value="settings" <?php selected(($instance['source'] ?? 'settings'), 'settings'); ?>><?php esc_html_e('后台友链设置', 'aksrt'); ?></option>
|
||||
<option value="bookmarks" <?php selected(($instance['source'] ?? ''), 'bookmarks'); ?>><?php esc_html_e('WordPress 链接', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('列数:', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="4" name="<?php echo esc_attr($this->get_field_name('columns')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['columns'] ?? 2))); ?>">
|
||||
</label>
|
||||
<label><?php esc_html_e('数量', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="100" name="<?php echo esc_attr($this->get_field_name('limit')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['limit'] ?? 24))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('书签分类 ID(书签模式)', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('cats')); ?>" value="<?php echo esc_attr((string) ($instance['cats'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_icon')); ?>" value="1" <?php checked(!empty($instance['show_icon']) || !isset($instance['show_icon'])); ?>> <?php esc_html_e('显示站点图标', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('go_link')); ?>" value="1" <?php checked(!empty($instance['go_link'])); ?>> <?php esc_html_e('外链跳转页', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
||||
'columns' => max(1, min(4, (int) ($new_instance['columns'] ?? 2))),
|
||||
'show_icon'=> !empty($new_instance['show_icon']),
|
||||
];
|
||||
}
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'source' => ($new_instance['source'] ?? '') === 'bookmarks' ? 'bookmarks' : 'settings',
|
||||
'columns' => max(1, min(4, (int) ($new_instance['columns'] ?? 2))),
|
||||
'limit' => max(1, min(100, (int) ($new_instance['limit'] ?? 24))),
|
||||
'cats' => sanitize_text_field((string) ($new_instance['cats'] ?? '')),
|
||||
'show_icon' => !empty($new_instance['show_icon']) ? 1 : 0,
|
||||
'go_link' => !empty($new_instance['go_link']) ? 1 : 0,
|
||||
'orderby' => sanitize_key((string) ($new_instance['orderby'] ?? 'name')),
|
||||
'order' => strtoupper((string) ($new_instance['order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ class HotPostsWidget extends \WP_Widget {
|
||||
$count = absint($instance['count'] ?? 5);
|
||||
$order_by = $instance['order_by'] ?? 'views';
|
||||
$days = absint($instance['days'] ?? 30);
|
||||
$show_thumb = !empty($instance['show_thumb']);
|
||||
|
||||
if ($title) {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
@@ -85,6 +86,13 @@ class HotPostsWidget extends \WP_Widget {
|
||||
?>
|
||||
<div class="hot-post-item <?php echo esc_attr($rank_class); ?>">
|
||||
<span class="hot-post-item__rank"><?php echo esc_html($index); ?></span>
|
||||
<?php if ($show_thumb) :
|
||||
$thumb = get_the_post_thumbnail_url(get_the_ID(), 'thumbnail');
|
||||
?>
|
||||
<a class="hot-post-item__thumb<?php echo $thumb ? '' : ' is-empty'; ?>" href="<?php the_permalink(); ?>">
|
||||
<?php if ($thumb) : ?><img src="<?php echo esc_url($thumb); ?>" alt="" loading="lazy" /><?php endif; ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<div class="hot-post-item__info">
|
||||
<a href="<?php the_permalink(); ?>" class="hot-post-item__title"><?php the_title(); ?></a>
|
||||
<div class="hot-post-item__meta">
|
||||
@@ -132,7 +140,11 @@ class HotPostsWidget extends \WP_Widget {
|
||||
<label for="<?php echo $this->get_field_id('days'); ?>"><?php esc_html_e('时间范围(天,0=不限):', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" id="<?php echo $this->get_field_id('days'); ?>" name="<?php echo $this->get_field_name('days'); ?>" type="number" min="0" max="365" value="<?php echo $days; ?>">
|
||||
</p>
|
||||
<?php
|
||||
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_thumb')); ?>" value="1" <?php checked(!empty($instance['show_thumb'])); ?>> <?php esc_html_e('显示缩略图', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Vertical icon cards grid (zibll zib_widget_ui_icon_card).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,91 +11,134 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class IconCardsWidget extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_icon_cards', esc_html__('AKSRT 图标卡片', 'aksrt'), [
|
||||
'description' => esc_html__('显示图标+文字卡片网格', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_icon_cards', esc_html__('AKSRT 图标卡片', 'aksrt'), [
|
||||
'description' => esc_html__('图标在上、文案在下的竖版图标卡片网格。', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget'];
|
||||
$title = apply_filters('widget_title', $instance['title'] ?? '', $instance, $this->id_base);
|
||||
$cards = isset($instance['cards']) && is_array($instance['cards']) ? $instance['cards'] : [];
|
||||
$columns = max(1, min(4, (int) ($instance['columns'] ?? 2)));
|
||||
public function widget($args, $instance): void {
|
||||
$cards = isset($instance['cards']) && is_array($instance['cards']) ? $instance['cards'] : [];
|
||||
$columns = max(1, min(4, (int) ($instance['columns'] ?? $instance['pc_row'] ?? 2)));
|
||||
$m_cols = max(1, min(3, (int) ($instance['m_row'] ?? 2)));
|
||||
$go_link = !empty($instance['go_link']);
|
||||
$show_bg = !isset($instance['show_widget_bg']) || !empty($instance['show_widget_bg']);
|
||||
$icon_size = max(18, min(48, (int) ($instance['icon_size'] ?? 28)));
|
||||
|
||||
if ($title) echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
$valid = [];
|
||||
foreach ($cards as $card) {
|
||||
if (!is_array($card)) {
|
||||
continue;
|
||||
}
|
||||
$title = sanitize_text_field((string) ($card['title'] ?? ''));
|
||||
if ($title === '') {
|
||||
continue;
|
||||
}
|
||||
$url = esc_url_raw(trim((string) ($card['link'] ?? $card['url'] ?? '')));
|
||||
if ($url !== '' && $go_link && function_exists('aksrt_go_link')) {
|
||||
$url = aksrt_go_link($url, true);
|
||||
}
|
||||
$valid[] = [
|
||||
'title' => $title,
|
||||
'icon' => sanitize_text_field((string) ($card['icon'] ?? '')),
|
||||
'desc' => sanitize_text_field((string) ($card['description'] ?? $card['desc'] ?? '')),
|
||||
'url' => $url,
|
||||
];
|
||||
}
|
||||
if (!$valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($cards)) : ?>
|
||||
<div class="widget-icon-cards" style="--ic-columns:<?php echo (int) $columns; ?>;">
|
||||
<?php foreach ($cards as $card) :
|
||||
$card_title = sanitize_text_field($card['title'] ?? '');
|
||||
$card_icon = sanitize_text_field($card['icon'] ?? '');
|
||||
$card_link = esc_url($card['link'] ?? '');
|
||||
$card_desc = sanitize_text_field($card['description'] ?? '');
|
||||
if ($card_title === '') continue;
|
||||
$tag = $card_link !== '' ? 'a' : 'div';
|
||||
$extra = $card_link !== '' ? ' href="' . $card_link . '" target="_blank" rel="noopener"' : '';
|
||||
?>
|
||||
<<?php echo $tag; ?> class="widget-icon-cards__item"<?php echo $extra; ?>>
|
||||
<?php if ($card_icon) : ?>
|
||||
<div class="widget-icon-cards__icon"><i class="<?php echo esc_attr($card_icon); ?>" aria-hidden="true"></i></div>
|
||||
<?php endif; ?>
|
||||
<div class="widget-icon-cards__text">
|
||||
<div class="widget-icon-cards__title"><?php echo esc_html($card_title); ?></div>
|
||||
<?php if ($card_desc) : ?>
|
||||
<div class="widget-icon-cards__desc"><?php echo esc_html($card_desc); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</<?php echo $tag; ?>>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif;
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
$style = sprintf('--ic-columns:%d;--ic-m-columns:%d;--ic-icon:%dpx;', $columns, $m_cols, $icon_size);
|
||||
echo '<div class="widget-icon-cards' . ($show_bg ? '' : ' is-bare') . '" style="' . esc_attr($style) . '">';
|
||||
foreach ($valid as $card) {
|
||||
$tag = $card['url'] !== '' ? 'a' : 'div';
|
||||
$extra = $card['url'] !== '' ? ' href="' . esc_url($card['url']) . '" target="_blank" rel="noopener noreferrer"' : '';
|
||||
echo '<' . $tag . ' class="widget-icon-cards__item is-vertical"' . $extra . '>';
|
||||
if ($card['icon'] !== '') {
|
||||
echo '<div class="widget-icon-cards__icon"><i class="' . esc_attr($card['icon']) . '" aria-hidden="true"></i></div>';
|
||||
}
|
||||
echo '<div class="widget-icon-cards__text">';
|
||||
echo '<div class="widget-icon-cards__title">' . esc_html($card['title']) . '</div>';
|
||||
if ($card['desc'] !== '') {
|
||||
echo '<div class="widget-icon-cards__desc">' . esc_html($card['desc']) . '</div>';
|
||||
}
|
||||
echo '</div></' . $tag . '>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
public function form($instance): void {
|
||||
$cards = isset($instance['cards']) && is_array($instance['cards']) ? $instance['cards'] : [];
|
||||
while (count($cards) < 4) {
|
||||
$cards[] = ['title' => '', 'icon' => '', 'link' => '', 'description' => ''];
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('title'); ?>"><?php esc_html_e('标题(可选):', 'aksrt'); ?></label>
|
||||
<input class="widefat" type="text" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title'] ?? ''); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('columns'); ?>"><?php esc_html_e('列数:', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" type="number" min="1" max="4" id="<?php echo $this->get_field_id('columns'); ?>" name="<?php echo $this->get_field_name('columns'); ?>" value="<?php echo (int) ($instance['columns'] ?? 2); ?>">
|
||||
</p>
|
||||
<hr>
|
||||
<?php foreach ($cards as $i => $card) : ?>
|
||||
<div style="border:1px solid #ddd;padding:6px;margin-bottom:6px;border-radius:4px;">
|
||||
<p style="margin:0 0 4px;"><input class="widefat" type="text" name="<?php echo $this->get_field_name("cards[{$i}][title]"); ?>" value="<?php echo esc_attr($card['title']); ?>" placeholder="<?php esc_attr_e('标题', 'aksrt'); ?>"></p>
|
||||
<p style="margin:0 0 4px;"><input class="widefat" type="text" name="<?php echo $this->get_field_name("cards[{$i}][icon]"); ?>" value="<?php echo esc_attr($card['icon']); ?>" placeholder="<?php esc_attr_e('图标类名 (如 fas fa-star)', 'aksrt'); ?>"></p>
|
||||
<p style="margin:0 0 4px;"><input class="widefat" type="text" name="<?php echo $this->get_field_name("cards[{$i}][description]"); ?>" value="<?php echo esc_attr($card['description']); ?>" placeholder="<?php esc_attr_e('描述(可选)', 'aksrt'); ?>"></p>
|
||||
<p style="margin:0;"><input class="widefat" type="url" name="<?php echo $this->get_field_name("cards[{$i}][link]"); ?>" value="<?php echo esc_attr($card['link']); ?>" placeholder="<?php esc_attr_e('链接(可选)', 'aksrt'); ?>"></p>
|
||||
</div>
|
||||
<?php endforeach;
|
||||
}
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$cards = [];
|
||||
if (isset($new_instance['cards']) && is_array($new_instance['cards'])) {
|
||||
foreach ($new_instance['cards'] as $card) {
|
||||
if (!is_array($card)) continue;
|
||||
$cards[] = [
|
||||
'title' => sanitize_text_field($card['title'] ?? ''),
|
||||
'icon' => sanitize_text_field($card['icon'] ?? ''),
|
||||
'link' => esc_url_raw($card['link'] ?? ''),
|
||||
'description' => sanitize_text_field($card['description'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
return [
|
||||
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
||||
'columns' => max(1, min(4, (int) ($new_instance['columns'] ?? 2))),
|
||||
'cards' => $cards,
|
||||
];
|
||||
}
|
||||
public function form($instance): void {
|
||||
$cards = isset($instance['cards']) && is_array($instance['cards']) ? $instance['cards'] : [];
|
||||
while (count($cards) < 4) {
|
||||
$cards[] = ['title' => '', 'icon' => '', 'link' => '', 'description' => ''];
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题(可选):', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('PC 列数:', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="4" name="<?php echo esc_attr($this->get_field_name('columns')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['columns'] ?? 2))); ?>">
|
||||
</label>
|
||||
<label><?php esc_html_e('移动列数', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="3" name="<?php echo esc_attr($this->get_field_name('m_row')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['m_row'] ?? 2))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('go_link')); ?>" value="1" <?php checked(!empty($instance['go_link'])); ?>> <?php esc_html_e('外链跳转页', 'aksrt'); ?></label>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_widget_bg')); ?>" value="1" <?php checked(!isset($instance['show_widget_bg']) || !empty($instance['show_widget_bg'])); ?>> <?php esc_html_e('卡片背景', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<hr>
|
||||
<?php foreach ($cards as $i => $card) : ?>
|
||||
<div style="border:1px solid #ddd;padding:6px;margin-bottom:6px;border-radius:4px;">
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name("cards[{$i}][title]")); ?>" value="<?php echo esc_attr((string) ($card['title'] ?? '')); ?>" placeholder="<?php esc_attr_e('标题', 'aksrt'); ?>">
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name("cards[{$i}][icon]")); ?>" value="<?php echo esc_attr((string) ($card['icon'] ?? '')); ?>" placeholder="<?php esc_attr_e('图标类名', 'aksrt'); ?>">
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name("cards[{$i}][description]")); ?>" value="<?php echo esc_attr((string) ($card['description'] ?? '')); ?>" placeholder="<?php esc_attr_e('描述', 'aksrt'); ?>">
|
||||
<input class="widefat" type="url" name="<?php echo esc_attr($this->get_field_name("cards[{$i}][link]")); ?>" value="<?php echo esc_attr((string) ($card['link'] ?? '')); ?>" placeholder="<?php esc_attr_e('链接', 'aksrt'); ?>">
|
||||
</div>
|
||||
<?php endforeach;
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$cards = [];
|
||||
if (isset($new_instance['cards']) && is_array($new_instance['cards'])) {
|
||||
foreach ($new_instance['cards'] as $card) {
|
||||
if (!is_array($card)) {
|
||||
continue;
|
||||
}
|
||||
$title = sanitize_text_field((string) ($card['title'] ?? ''));
|
||||
if ($title === '') {
|
||||
continue;
|
||||
}
|
||||
$cards[] = [
|
||||
'title' => $title,
|
||||
'icon' => sanitize_text_field((string) ($card['icon'] ?? '')),
|
||||
'link' => esc_url_raw(trim((string) ($card['link'] ?? ''))),
|
||||
'description' => sanitize_text_field((string) ($card['description'] ?? '')),
|
||||
];
|
||||
if (count($cards) >= 12) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'columns' => max(1, min(4, (int) ($new_instance['columns'] ?? 2))),
|
||||
'm_row' => max(1, min(3, (int) ($new_instance['m_row'] ?? 2))),
|
||||
'go_link' => !empty($new_instance['go_link']) ? 1 : 0,
|
||||
'show_widget_bg' => !empty($new_instance['show_widget_bg']) ? 1 : 0,
|
||||
'cards' => $cards,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Scrolling notice bar (zibll widget_ui_notice lite).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,64 +11,165 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class NoticeWidget extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_notice', esc_html__('AKSRT 公告', 'aksrt'), [
|
||||
'description' => esc_html__('显示公告/通知信息', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_notice', esc_html__('AKSRT 滚动公告', 'aksrt'), [
|
||||
'description' => esc_html__('多条公告滚动显示。', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget'];
|
||||
$title = apply_filters('widget_title', $instance['title'] ?? '', $instance, $this->id_base);
|
||||
$content = wp_kses_post($instance['content'] ?? '');
|
||||
$style = sanitize_key($instance['style'] ?? 'info');
|
||||
$icon = sanitize_text_field($instance['icon'] ?? 'fas fa-bullhorn');
|
||||
public function widget($args, $instance): void {
|
||||
$items = $this->normalize_items($instance);
|
||||
if (!$items) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($title) echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
?>
|
||||
<div class="widget-notice widget-notice--<?php echo esc_attr($style); ?>">
|
||||
<?php if ($icon) : ?>
|
||||
<div class="widget-notice__icon"><i class="<?php echo esc_attr($icon); ?>" aria-hidden="true"></i></div>
|
||||
<?php endif; ?>
|
||||
<div class="widget-notice__content"><?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
|
||||
</div>
|
||||
<?php
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
$color = sanitize_html_class((string) ($instance['color'] ?? 'c-blue'));
|
||||
$blank = !empty($instance['blank']);
|
||||
$radius = !empty($instance['radius']);
|
||||
$interval = max(2, min(15, (int) ($instance['interval'] ?? 4)));
|
||||
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('title'); ?>"><?php esc_html_e('标题(可选):', 'aksrt'); ?></label>
|
||||
<input class="widefat" type="text" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title'] ?? ''); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('content'); ?>"><?php esc_html_e('公告内容:', 'aksrt'); ?></label>
|
||||
<textarea class="widefat" rows="4" id="<?php echo $this->get_field_id('content'); ?>" name="<?php echo $this->get_field_name('content'); ?>"><?php echo esc_textarea($instance['content'] ?? ''); ?></textarea>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('style'); ?>"><?php esc_html_e('样式:', 'aksrt'); ?></label>
|
||||
<select class="widefat" id="<?php echo $this->get_field_id('style'); ?>" name="<?php echo $this->get_field_name('style'); ?>">
|
||||
<option value="info" <?php selected($instance['style'] ?? '', 'info'); ?>><?php esc_html_e('信息(蓝色)', 'aksrt'); ?></option>
|
||||
<option value="success" <?php selected($instance['style'] ?? '', 'success'); ?>><?php esc_html_e('成功(绿色)', 'aksrt'); ?></option>
|
||||
<option value="warning" <?php selected($instance['style'] ?? '', 'warning'); ?>><?php esc_html_e('警告(黄色)', 'aksrt'); ?></option>
|
||||
<option value="danger" <?php selected($instance['style'] ?? '', 'danger'); ?>><?php esc_html_e('危险(红色)', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('icon'); ?>"><?php esc_html_e('图标类名:', 'aksrt'); ?></label>
|
||||
<input class="widefat" type="text" id="<?php echo $this->get_field_id('icon'); ?>" name="<?php echo $this->get_field_name('icon'); ?>" value="<?php echo esc_attr($instance['icon'] ?? 'fas fa-bullhorn'); ?>">
|
||||
<small style="color:#666;"><?php esc_html_e('Font Awesome 类名,如: fas fa-bullhorn', 'aksrt'); ?></small>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
||||
'content' => wp_kses_post($new_instance['content'] ?? ''),
|
||||
'style' => in_array($new_instance['style'] ?? '', ['info', 'success', 'warning', 'danger'], true) ? $new_instance['style'] : 'info',
|
||||
'icon' => sanitize_text_field($new_instance['icon'] ?? 'fas fa-bullhorn'),
|
||||
];
|
||||
}
|
||||
$uid = 'aksrt-notice-' . esc_attr($this->id);
|
||||
$class = 'aksrt-scroll-notice color-' . $color . ($radius ? ' is-radius' : '');
|
||||
echo '<div class="' . esc_attr($class) . '" id="' . $uid . '" data-interval="' . esc_attr((string) ($interval * 1000)) . '">';
|
||||
echo '<div class="aksrt-scroll-notice__icon"><i class="fas fa-bullhorn" aria-hidden="true"></i></div>';
|
||||
echo '<div class="aksrt-scroll-notice__viewport">';
|
||||
foreach ($items as $i => $item) {
|
||||
$active = $i === 0 ? ' is-active' : '';
|
||||
$inner = '';
|
||||
if ($item['icon'] !== '') {
|
||||
$inner .= '<i class="' . esc_attr($item['icon']) . '" aria-hidden="true"></i> ';
|
||||
}
|
||||
$inner .= esc_html($item['title']);
|
||||
echo '<div class="aksrt-scroll-notice__item' . esc_attr($active) . '">';
|
||||
if ($item['href'] !== '') {
|
||||
$tgt = $blank ? ' target="_blank" rel="noopener noreferrer"' : '';
|
||||
echo '<a href="' . esc_url($item['href']) . '"' . $tgt . '>' . $inner . '</a>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
} else {
|
||||
echo '<span>' . $inner . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div></div>';
|
||||
|
||||
if (count($items) > 1) {
|
||||
?>
|
||||
<script>
|
||||
(function(){
|
||||
var root=document.getElementById(<?php echo wp_json_encode($uid); ?>);
|
||||
if(!root||root._aksrtNotice)return; root._aksrtNotice=1;
|
||||
var items=[].slice.call(root.querySelectorAll('.aksrt-scroll-notice__item'));
|
||||
var i=0, ms=parseInt(root.getAttribute('data-interval')||'4000',10)||4000;
|
||||
setInterval(function(){
|
||||
if(items.length<2)return;
|
||||
items[i].classList.remove('is-active');
|
||||
i=(i+1)%items.length;
|
||||
items[i].classList.add('is-active');
|
||||
}, ms);
|
||||
})();
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $instance
|
||||
* @return array<int, array{title:string,icon:string,href:string}>
|
||||
*/
|
||||
private function normalize_items(array $instance): array {
|
||||
$raw = $instance['items'] ?? $instance['img_ids'] ?? null;
|
||||
if ($raw === null && !empty($instance['content'])) {
|
||||
// Legacy single content.
|
||||
return [[
|
||||
'title' => wp_strip_all_tags((string) $instance['content']),
|
||||
'icon' => sanitize_text_field((string) ($instance['icon'] ?? 'fas fa-bullhorn')),
|
||||
'href' => '',
|
||||
]];
|
||||
}
|
||||
if (is_string($raw)) {
|
||||
$decoded = json_decode($raw, true);
|
||||
$raw = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
if (!is_array($raw)) {
|
||||
return [];
|
||||
}
|
||||
$out = [];
|
||||
foreach ($raw as $row) {
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
$title = sanitize_text_field((string) ($row['title'] ?? $row['content'] ?? ''));
|
||||
if ($title === '') {
|
||||
continue;
|
||||
}
|
||||
$out[] = [
|
||||
'title' => $title,
|
||||
'icon' => sanitize_text_field((string) ($row['icon'] ?? '')),
|
||||
'href' => esc_url_raw(trim((string) ($row['href'] ?? $row['url'] ?? $row['link'] ?? ''))),
|
||||
];
|
||||
if (count($out) >= 12) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
$items = $this->normalize_items($instance);
|
||||
if (!$items) {
|
||||
$items = [
|
||||
['title' => '', 'icon' => 'fas fa-bullhorn', 'href' => ''],
|
||||
['title' => '', 'icon' => 'fas fa-info-circle', 'href' => ''],
|
||||
];
|
||||
}
|
||||
$json = wp_json_encode($items, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题(可选)', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('公告条目 JSON', 'aksrt'); ?>
|
||||
<textarea class="widefat" rows="6" name="<?php echo esc_attr($this->get_field_name('items')); ?>" placeholder='[{"title":"公告内容","icon":"fas fa-bullhorn","href":""}]'><?php echo esc_textarea((string) $json); ?></textarea>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('切换间隔(秒)', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="2" max="15" name="<?php echo esc_attr($this->get_field_name('interval')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['interval'] ?? 4))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('主题色 class', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('color')); ?>">
|
||||
<?php foreach (['c-blue' => '蓝', 'c-green' => '绿', 'c-yellow' => '黄', 'c-red' => '红', 'c-purple' => '紫'] as $k => $label) : ?>
|
||||
<option value="<?php echo esc_attr($k); ?>" <?php selected(($instance['color'] ?? 'c-blue'), $k); ?>><?php echo esc_html($label); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('blank')); ?>" value="1" <?php checked(!empty($instance['blank'])); ?>> <?php esc_html_e('链接新窗口', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('radius')); ?>" value="1" <?php checked(!empty($instance['radius'])); ?>> <?php esc_html_e('两端圆形', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'items' => $this->normalize_items(['items' => $new_instance['items'] ?? []]),
|
||||
'interval' => max(2, min(15, (int) ($new_instance['interval'] ?? 4))),
|
||||
'color' => sanitize_html_class((string) ($new_instance['color'] ?? 'c-blue')),
|
||||
'blank' => !empty($new_instance['blank']) ? 1 : 0,
|
||||
'radius' => !empty($new_instance['radius']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Recent comments mini list (zibll widget_ui_new_comment lite).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,81 +11,115 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class RecentCommentsWidget extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_recent_comments', esc_html__('AKSRT 最新评论', 'aksrt'), [
|
||||
'description' => esc_html__('显示最新评论列表', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_recent_comments', esc_html__('AKSRT 最新评论', 'aksrt'), [
|
||||
'description' => esc_html__('显示最新评论列表', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget'];
|
||||
$title = apply_filters('widget_title', $instance['title'] ?? __('最新评论', 'aksrt'), $instance, $this->id_base);
|
||||
$count = max(1, min(20, (int) ($instance['count'] ?? 5)));
|
||||
$show_avatar = !empty($instance['show_avatar']);
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? __('最新评论', 'aksrt')), $instance, $this->id_base);
|
||||
$count = max(1, min(20, (int) ($instance['count'] ?? $instance['limit'] ?? 5)));
|
||||
$show_avatar = !isset($instance['show_avatar']) || !empty($instance['show_avatar']);
|
||||
$outpost = max(0, (int) ($instance['outpost'] ?? 0));
|
||||
$outer = sanitize_text_field((string) ($instance['outer'] ?? ''));
|
||||
|
||||
if ($title) echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
$comments = get_comments([
|
||||
'number' => $count,
|
||||
'status' => 'approve',
|
||||
'post_status' => 'publish',
|
||||
]);
|
||||
$query = [
|
||||
'number' => $count,
|
||||
'status' => 'approve',
|
||||
'post_status' => 'publish',
|
||||
];
|
||||
if ($outpost > 0) {
|
||||
$query['post__not_in'] = [$outpost];
|
||||
}
|
||||
if ($outer !== '') {
|
||||
// Exclude comments containing outer keywords (comma separated).
|
||||
// Implemented post-filter below.
|
||||
}
|
||||
$comments = get_comments($query);
|
||||
if ($outer !== '' && $comments) {
|
||||
$keys = array_filter(array_map('trim', preg_split('/[,,]/', $outer) ?: []));
|
||||
if ($keys) {
|
||||
$comments = array_values(array_filter($comments, static function ($c) use ($keys) {
|
||||
$body = (string) $c->comment_content;
|
||||
foreach ($keys as $k) {
|
||||
if ($k !== '' && str_contains($body, $k)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if ($comments) : ?>
|
||||
<div class="widget-recent-comments">
|
||||
<?php foreach ($comments as $comment) :
|
||||
$post = get_post($comment->comment_post_ID);
|
||||
if (!$post) continue;
|
||||
?>
|
||||
<div class="widget-recent-comments__item">
|
||||
<?php if ($show_avatar) : ?>
|
||||
<div class="widget-recent-comments__avatar">
|
||||
<?php echo get_avatar($comment, 32); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="widget-recent-comments__body">
|
||||
<div class="widget-recent-comments__meta">
|
||||
<strong class="widget-recent-comments__author"><?php echo esc_html($comment->comment_author); ?></strong>
|
||||
<span class="widget-recent-comments__time"><?php echo esc_html(human_time_diff(strtotime($comment->comment_date), current_time('timestamp'))); ?></span>
|
||||
</div>
|
||||
<p class="widget-recent-comments__text">
|
||||
<a href="<?php echo esc_url(get_comment_link($comment)); ?>"><?php echo esc_html(wp_trim_words($comment->comment_content, 15, '...')); ?></a>
|
||||
</p>
|
||||
<span class="widget-recent-comments__post">
|
||||
<?php esc_html_e('于', 'aksrt'); ?> <a href="<?php echo esc_url(get_permalink($post->ID)); ?>"><?php echo esc_html(get_the_title($post->ID)); ?></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php echo function_exists('aksrt_get_widget_null') ? aksrt_get_widget_null(__('暂无评论', 'aksrt')) : '<p class="widget-empty">' . esc_html__('暂无评论', 'aksrt') . '</p>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<?php endif;
|
||||
if ($comments) {
|
||||
echo '<div class="widget-recent-comments comment-mini-lists">';
|
||||
foreach ($comments as $comment) {
|
||||
$post = get_post($comment->comment_post_ID);
|
||||
if (!$post) {
|
||||
continue;
|
||||
}
|
||||
echo '<div class="widget-recent-comments__item">';
|
||||
if ($show_avatar) {
|
||||
echo '<div class="widget-recent-comments__avatar">' . get_avatar($comment, 32) . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '<div class="widget-recent-comments__body">';
|
||||
echo '<div class="widget-recent-comments__meta">';
|
||||
echo '<strong class="widget-recent-comments__author">' . esc_html($comment->comment_author) . '</strong>';
|
||||
echo '<span class="widget-recent-comments__time">' . esc_html(human_time_diff(strtotime($comment->comment_date), current_time('timestamp'))) . '</span>';
|
||||
echo '</div>';
|
||||
echo '<p class="widget-recent-comments__text"><a href="' . esc_url(get_comment_link($comment)) . '">' . esc_html(wp_trim_words($comment->comment_content, 15, '...')) . '</a></p>';
|
||||
echo '<div class="widget-recent-comments__post muted-2-color em09"><a href="' . esc_url(get_permalink($post)) . '">' . esc_html(get_the_title($post)) . '</a></div>';
|
||||
echo '</div></div>';
|
||||
}
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<p class="widget-empty">' . esc_html__('暂无评论', 'aksrt') . '</p>';
|
||||
}
|
||||
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('title'); ?>"><?php esc_html_e('标题:', 'aksrt'); ?></label>
|
||||
<input class="widefat" type="text" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title'] ?? __('最新评论', 'aksrt')); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('count'); ?>"><?php esc_html_e('显示数量:', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" type="number" min="1" max="20" id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>" value="<?php echo (int) ($instance['count'] ?? 5); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo $this->get_field_name('show_avatar'); ?>" value="1" <?php checked(!empty($instance['show_avatar'])); ?>> <?php esc_html_e('显示头像', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? __('最新评论', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('数量', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="20" name="<?php echo esc_attr($this->get_field_name('count')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['count'] ?? 5))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('排除文章 ID', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="0" name="<?php echo esc_attr($this->get_field_name('outpost')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['outpost'] ?? 0))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('排除关键词(逗号)', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('outer')); ?>" value="<?php echo esc_attr((string) ($instance['outer'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_avatar')); ?>" value="1" <?php checked(!isset($instance['show_avatar']) || !empty($instance['show_avatar'])); ?>> <?php esc_html_e('显示头像', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
||||
'count' => max(1, min(20, (int) ($new_instance['count'] ?? 5))),
|
||||
'show_avatar' => !empty($new_instance['show_avatar']),
|
||||
];
|
||||
}
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'count' => max(1, min(20, (int) ($new_instance['count'] ?? 5))),
|
||||
'outpost' => max(0, (int) ($new_instance['outpost'] ?? 0)),
|
||||
'outer' => sanitize_text_field((string) ($new_instance['outer'] ?? '')),
|
||||
'show_avatar' => !empty($new_instance['show_avatar']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Search box with hot keywords (zibll widget_ui_search lite).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,49 +11,129 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class SearchWidget extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_search', esc_html__('AKSRT 搜索', 'aksrt'), [
|
||||
'description' => esc_html__('带样式的搜索框', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct('aksrt_search', esc_html__('AKSRT 搜索', 'aksrt'), [
|
||||
'description' => esc_html__('搜索框,可显示热门关键词。', 'aksrt'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget'];
|
||||
$title = apply_filters('widget_title', $instance['title'] ?? '', $instance, $this->id_base);
|
||||
if ($title) echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
$placeholder = sanitize_text_field($instance['placeholder'] ?? __('搜索文章...', 'aksrt'));
|
||||
?>
|
||||
<div class="widget-search-box">
|
||||
<form role="search" method="get" action="<?php echo esc_url(home_url('/')); ?>">
|
||||
<div class="widget-search-box__inner">
|
||||
<input type="search" name="s" class="widget-search-box__input" placeholder="<?php echo esc_attr($placeholder); ?>" value="<?php echo esc_attr(get_search_query()); ?>" autocomplete="off">
|
||||
<button type="submit" class="widget-search-box__btn" aria-label="<?php esc_attr_e('搜索', 'aksrt'); ?>">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('title'); ?>"><?php esc_html_e('标题(可选):', 'aksrt'); ?></label>
|
||||
<input class="widefat" type="text" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title'] ?? ''); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('placeholder'); ?>"><?php esc_html_e('占位文本:', 'aksrt'); ?></label>
|
||||
<input class="widefat" type="text" id="<?php echo $this->get_field_id('placeholder'); ?>" name="<?php echo $this->get_field_name('placeholder'); ?>" value="<?php echo esc_attr($instance['placeholder'] ?? __('搜索文章...', 'aksrt')); ?>">
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
$placeholder = sanitize_text_field((string) ($instance['placeholder'] ?? __('开启精彩搜索', 'aksrt')));
|
||||
$show_kw = !empty($instance['show_keywords']);
|
||||
$show_history = !empty($instance['show_history']);
|
||||
$kw_title = sanitize_text_field((string) ($instance['keywords_title'] ?? __('热门搜索', 'aksrt')));
|
||||
$more_but = sanitize_text_field((string) ($instance['more_but'] ?? ''));
|
||||
$more_url = esc_url_raw(trim((string) ($instance['more_but_url'] ?? '')));
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
||||
'placeholder' => sanitize_text_field($new_instance['placeholder'] ?? ''),
|
||||
];
|
||||
}
|
||||
$keywords = [];
|
||||
if ($show_kw) {
|
||||
if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'hot_search_keywords')) {
|
||||
$keywords = \AKSRT\Settings\Settings::hot_search_keywords();
|
||||
} elseif (function_exists('aksrt_get_setting')) {
|
||||
$raw = (string) aksrt_get_setting('hot_search_keywords', '');
|
||||
$keywords = array_values(array_filter(array_map('trim', preg_split('/[\r\n,,]+/', $raw) ?: [])));
|
||||
}
|
||||
$custom = trim((string) ($instance['keywords'] ?? ''));
|
||||
if ($custom !== '') {
|
||||
$keywords = array_values(array_filter(array_map('trim', preg_split('/[\r\n,,]+/', $custom) ?: [])));
|
||||
}
|
||||
$keywords = array_slice($keywords, 0, 12);
|
||||
}
|
||||
?>
|
||||
<div class="widget-search-box aksrt-search-widget">
|
||||
<form role="search" method="get" action="<?php echo esc_url(home_url('/')); ?>">
|
||||
<div class="widget-search-box__inner">
|
||||
<input type="search" name="s" class="widget-search-box__input" placeholder="<?php echo esc_attr($placeholder); ?>" value="<?php echo esc_attr(get_search_query()); ?>" autocomplete="off">
|
||||
<button type="submit" class="widget-search-box__btn" aria-label="<?php esc_attr_e('搜索', 'aksrt'); ?>">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php if ($show_history) : ?>
|
||||
<div class="aksrt-search-widget__history" data-aksrt-search-history>
|
||||
<div class="aksrt-search-widget__kw-title"><?php esc_html_e('搜索历史', 'aksrt'); ?></div>
|
||||
<div class="aksrt-search-widget__history-list" data-aksrt-search-history-list></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($keywords) : ?>
|
||||
<div class="aksrt-search-widget__keywords">
|
||||
<?php if ($kw_title !== '') : ?>
|
||||
<div class="aksrt-search-widget__kw-title"><?php echo esc_html($kw_title); ?></div>
|
||||
<?php endif; ?>
|
||||
<div class="aksrt-search-widget__kw-list">
|
||||
<?php foreach ($keywords as $kw) : ?>
|
||||
<a class="aksrt-search-widget__kw" href="<?php echo esc_url(add_query_arg('s', $kw, home_url('/'))); ?>"><?php echo esc_html($kw); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($more_but !== '' && $more_url !== '') : ?>
|
||||
<div class="aksrt-search-widget__more">
|
||||
<a href="<?php echo esc_url($more_url); ?>"><?php echo esc_html($more_but); ?></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题(可选)', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('占位文本', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('placeholder')); ?>" value="<?php echo esc_attr((string) ($instance['placeholder'] ?? __('开启精彩搜索', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_keywords')); ?>" value="1" <?php checked(!empty($instance['show_keywords'])); ?>> <?php esc_html_e('显示热门关键词', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_history')); ?>" value="1" <?php checked(!empty($instance['show_history'])); ?>> <?php esc_html_e('显示搜索历史', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('关键词标题', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('keywords_title')); ?>" value="<?php echo esc_attr((string) ($instance['keywords_title'] ?? __('热门搜索', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('自定义关键词(逗号/换行;空=后台配置)', 'aksrt'); ?>
|
||||
<textarea class="widefat" rows="2" name="<?php echo esc_attr($this->get_field_name('keywords')); ?>"><?php echo esc_textarea((string) ($instance['keywords'] ?? '')); ?></textarea>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('更多按钮文案', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('more_but')); ?>" value="<?php echo esc_attr((string) ($instance['more_but'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('更多按钮链接', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('more_but_url')); ?>" value="<?php echo esc_attr((string) ($instance['more_but_url'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'placeholder' => sanitize_text_field((string) ($new_instance['placeholder'] ?? '')),
|
||||
'show_keywords' => !empty($new_instance['show_keywords']) ? 1 : 0,
|
||||
'show_history' => !empty($new_instance['show_history']) ? 1 : 0,
|
||||
'keywords_title' => sanitize_text_field((string) ($new_instance['keywords_title'] ?? '')),
|
||||
'keywords' => sanitize_textarea_field((string) ($new_instance['keywords'] ?? '')),
|
||||
'more_but' => sanitize_text_field((string) ($new_instance['more_but'] ?? '')),
|
||||
'more_but_url' => esc_url_raw(trim((string) ($new_instance['more_but_url'] ?? ''))),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Tag cloud (zibll widget_ui_tag_cloud lite).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -13,60 +15,138 @@ class TagCloudWidget extends \WP_Widget {
|
||||
parent::__construct(
|
||||
'aksrt_tag_cloud',
|
||||
esc_html__('AKSRT 标签云', 'aksrt'),
|
||||
array(
|
||||
'description' => esc_html__('展示文章标签云', 'aksrt'),
|
||||
[
|
||||
'description' => esc_html__('展示文章标签/分类云', 'aksrt'),
|
||||
'customize_selective_refresh' => true,
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance) {
|
||||
echo $args['before_widget'];
|
||||
public function widget($args, $instance): void {
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
$title = apply_filters('widget_title', $instance['title'], $instance, $this->id_base);
|
||||
$count = absint($instance['count'] ?: 15);
|
||||
$taxonomy = sanitize_key((string) ($instance['taxonomy'] ?? 'post_tag'));
|
||||
if (!taxonomy_exists($taxonomy)) {
|
||||
$taxonomy = 'post_tag';
|
||||
}
|
||||
$number = max(1, min(80, (int) ($instance['count'] ?? $instance['number'] ?? 15)));
|
||||
$orderby = sanitize_key((string) ($instance['orderby'] ?? 'count'));
|
||||
if (!in_array($orderby, ['count', 'name', 'id'], true)) {
|
||||
$orderby = 'count';
|
||||
}
|
||||
$show_count = !empty($instance['show_count']);
|
||||
$blank = !empty($instance['blank']);
|
||||
$color = sanitize_html_class((string) ($instance['color'] ?? 'rand'));
|
||||
$fixed_width = !empty($instance['fixed_width']);
|
||||
|
||||
if ($title): ?>
|
||||
<h3 class="widget-title"><?php echo $title; ?></h3>
|
||||
<?php endif;
|
||||
?>
|
||||
$tags = get_terms([
|
||||
'taxonomy' => $taxonomy,
|
||||
'orderby' => $orderby,
|
||||
'order' => 'DESC',
|
||||
'number' => $number,
|
||||
'hide_empty' => !empty($instance['hide_empty']),
|
||||
]);
|
||||
if (is_wp_error($tags) || !$tags) {
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
|
||||
<div class="tag-cloud">
|
||||
<?php
|
||||
$tags = get_tags(['number' => $count, 'orderby' => 'count', 'order' => 'DESC']);
|
||||
foreach ($tags as $tag):
|
||||
$size = 12 + min(4, (int)($tag->count / 5));
|
||||
?>
|
||||
<a href="<?php echo esc_url(get_tag_link($tag->term_id)); ?>" style="font-size:<?php echo $size ?>px;">#<?php echo esc_html($tag->name); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php
|
||||
echo $args['after_widget'];
|
||||
$palette = ['c-blue', 'c-yellow', 'c-green', 'c-purple', 'c-red', '', 'c-blue-2', 'c-yellow-2', 'c-green-2', 'c-purple-2', 'c-red-2', ''];
|
||||
$i = random_int(0, 10);
|
||||
$wrap = 'tag-cloud aksrt-tag-cloud author-tag' . ($fixed_width ? ' fixed-width' : '');
|
||||
echo '<div class="' . esc_attr($wrap) . '">';
|
||||
foreach ($tags as $tag) {
|
||||
$url = get_term_link($tag);
|
||||
if (is_wp_error($url)) {
|
||||
continue;
|
||||
}
|
||||
$cls = 'but';
|
||||
if ($color === 'rand') {
|
||||
if ($i > 10) {
|
||||
$i = 0;
|
||||
}
|
||||
$cls .= ' ' . $palette[$i];
|
||||
$i++;
|
||||
} elseif ($color !== '') {
|
||||
$cls .= ' ' . $color;
|
||||
}
|
||||
$tgt = $blank ? ' target="_blank" rel="noopener noreferrer"' : '';
|
||||
$count = $show_count ? '<span class="em09 tag-count"> (' . (int) $tag->count . ')</span>' : '';
|
||||
echo '<a href="' . esc_url($url) . '" class="text-ellipsis ' . esc_attr(trim($cls)) . '"' . $tgt . '>' . esc_html($tag->name) . $count . '</a>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function form($instance) {
|
||||
$title = $instance['title'] ?? __('标签云', 'aksrt');
|
||||
$count = isset($instance['count']) ? (int)$instance['count'] : 15;
|
||||
public function form($instance): void {
|
||||
$taxs = get_taxonomies(['public' => true], 'objects');
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('title'); ?>"><?php esc_html_e('标题:', 'aksrt'); ?></label>
|
||||
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
|
||||
name="<?php echo $this->get_field_name('title'); ?>"
|
||||
type="text" value="<?php echo esc_attr($title); ?>">
|
||||
<label><?php esc_html_e('标题:', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? __('标签云', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo $this->get_field_id('count'); ?>"><?php esc_html_e('标签数量:', 'aksrt'); ?></label>
|
||||
<input class="tiny-text" id="<?php echo $this->get_field_id('count'); ?>"
|
||||
name="<?php echo $this->get_field_name('count'); ?>"
|
||||
type="number" min="1" max="50" value="<?php echo $count; ?>">
|
||||
<label><?php esc_html_e('分类法', 'aksrt'); ?>
|
||||
<select class="widefat" name="<?php echo esc_attr($this->get_field_name('taxonomy')); ?>">
|
||||
<?php foreach ($taxs as $tax) : ?>
|
||||
<option value="<?php echo esc_attr($tax->name); ?>" <?php selected(($instance['taxonomy'] ?? 'post_tag'), $tax->name); ?>><?php echo esc_html($tax->labels->name); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('标签数量:', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="80" name="<?php echo esc_attr($this->get_field_name('count')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['count'] ?? 15))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('排序', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('orderby')); ?>">
|
||||
<option value="count" <?php selected(($instance['orderby'] ?? 'count'), 'count'); ?>><?php esc_html_e('数量', 'aksrt'); ?></option>
|
||||
<option value="name" <?php selected(($instance['orderby'] ?? ''), 'name'); ?>><?php esc_html_e('名称', 'aksrt'); ?></option>
|
||||
<option value="id" <?php selected(($instance['orderby'] ?? ''), 'id'); ?>><?php esc_html_e('ID', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('颜色', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('color')); ?>">
|
||||
<option value="rand" <?php selected(($instance['color'] ?? 'rand'), 'rand'); ?>><?php esc_html_e('随机', 'aksrt'); ?></option>
|
||||
<option value="c-blue" <?php selected(($instance['color'] ?? ''), 'c-blue'); ?>><?php esc_html_e('蓝', 'aksrt'); ?></option>
|
||||
<option value="c-green" <?php selected(($instance['color'] ?? ''), 'c-green'); ?>><?php esc_html_e('绿', 'aksrt'); ?></option>
|
||||
<option value="c-yellow" <?php selected(($instance['color'] ?? ''), 'c-yellow'); ?>><?php esc_html_e('黄', 'aksrt'); ?></option>
|
||||
<option value="c-purple" <?php selected(($instance['color'] ?? ''), 'c-purple'); ?>><?php esc_html_e('紫', 'aksrt'); ?></option>
|
||||
<option value="c-red" <?php selected(($instance['color'] ?? ''), 'c-red'); ?>><?php esc_html_e('红', 'aksrt'); ?></option>
|
||||
<option value="" <?php selected(($instance['color'] ?? ''), ''); ?>><?php esc_html_e('默认', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_count')); ?>" value="1" <?php checked(!empty($instance['show_count'])); ?>> <?php esc_html_e('显示数量', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('blank')); ?>" value="1" <?php checked(!empty($instance['blank'])); ?>> <?php esc_html_e('新窗口', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('fixed_width')); ?>" value="1" <?php checked(!empty($instance['fixed_width'])); ?>> <?php esc_html_e('固定宽度', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('hide_empty')); ?>" value="1" <?php checked(!empty($instance['hide_empty'])); ?>> <?php esc_html_e('隐藏空标签', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new, $old) {
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field($new['title']),
|
||||
'count' => absint($new['count']),
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'taxonomy' => sanitize_key((string) ($new_instance['taxonomy'] ?? 'post_tag')),
|
||||
'count' => max(1, min(80, (int) ($new_instance['count'] ?? 15))),
|
||||
'orderby' => in_array(($new_instance['orderby'] ?? ''), ['count', 'name', 'id'], true) ? $new_instance['orderby'] : 'count',
|
||||
'color' => sanitize_html_class((string) ($new_instance['color'] ?? 'rand')),
|
||||
'show_count' => !empty($new_instance['show_count']) ? 1 : 0,
|
||||
'blank' => !empty($new_instance['blank']) ? 1 : 0,
|
||||
'fixed_width' => !empty($new_instance['fixed_width']) ? 1 : 0,
|
||||
'hide_empty' => !empty($new_instance['hide_empty']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,28 @@ class WidgetAuthorCard extends \WP_Widget {
|
||||
if ($bio !== '') {
|
||||
echo '<div class="aksrt-author-card__bio">' . esc_html(wp_trim_words($bio, 28)) . '</div>';
|
||||
}
|
||||
$show_badge = !isset($instance['show_badge']) || !empty($instance['show_badge']);
|
||||
if ($show_badge && class_exists('\AKSRT\User\Badges') && \AKSRT\User\Badges::public_display()) {
|
||||
$wear = \AKSRT\User\Badges::get_wear($author_id);
|
||||
if ($wear === '') {
|
||||
// zibll alias fallback
|
||||
$wear = sanitize_key((string) get_user_meta($author_id, 'wear_medal', true));
|
||||
}
|
||||
if ($wear !== '') {
|
||||
$map = \AKSRT\User\Badges::get_dictionary_map();
|
||||
if (isset($map[$wear])) {
|
||||
$badge = $map[$wear];
|
||||
echo '<div class="aksrt-author-card__badge tone-' . esc_attr((string) ($badge['tone'] ?? 'neutral')) . '">';
|
||||
if (!empty($badge['icon_url'])) {
|
||||
echo '<img src="' . esc_url((string) $badge['icon_url']) . '" alt="" width="16" height="16" loading="lazy" /> ';
|
||||
} else {
|
||||
echo '<i class="fas fa-medal" aria-hidden="true"></i> ';
|
||||
}
|
||||
echo esc_html((string) $badge['label']);
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($show_stats) {
|
||||
echo '<div class="aksrt-author-card__stats">';
|
||||
echo '<span><b>' . esc_html((string) $post_count) . '</b>' . esc_html__('文章', 'aksrt') . '</span>';
|
||||
@@ -94,6 +116,13 @@ class WidgetAuthorCard extends \WP_Widget {
|
||||
echo '<span><b>' . esc_html((string) $followers) . '</b>' . esc_html__('粉丝', 'aksrt') . '</span>';
|
||||
echo '</div>';
|
||||
}
|
||||
$cuid = get_current_user_id();
|
||||
$show_follow = !isset($instance['show_follow']) || !empty($instance['show_follow']);
|
||||
if ($show_follow && $cuid > 0 && $cuid !== $author_id && class_exists('\AKSRT\User\Follow')) {
|
||||
$following = \AKSRT\User\Follow::get_instance()->is_following($cuid, $author_id);
|
||||
$label = $following ? __('已关注', 'aksrt') : __('关注', 'aksrt');
|
||||
echo '<button type="button" class="aksrt-author-card__btn aksrt-author-card__follow' . ($following ? ' is-following' : '') . '" data-aksrt-follow="' . (int) $author_id . '">' . esc_html($label) . '</button>';
|
||||
}
|
||||
echo '<a class="aksrt-author-card__btn" href="' . esc_url($home) . '">' . esc_html__('查看主页', 'aksrt') . '</a>';
|
||||
echo '</div></div>';
|
||||
|
||||
@@ -115,7 +144,9 @@ class WidgetAuthorCard extends \WP_Widget {
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_img_bg')); ?>" value="1" <?php checked(!isset($instance['show_img_bg']) || !empty($instance['show_img_bg'])); ?>> <?php esc_html_e('显示封面', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_stats')); ?>" value="1" <?php checked(!isset($instance['show_stats']) || !empty($instance['show_stats'])); ?>> <?php esc_html_e('显示统计', 'aksrt'); ?></label>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_stats')); ?>" value="1" <?php checked(!isset($instance['show_stats']) || !empty($instance['show_stats'])); ?>> <?php esc_html_e('显示统计', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_follow')); ?>" value="1" <?php checked(!isset($instance['show_follow']) || !empty($instance['show_follow'])); ?>> <?php esc_html_e('显示关注按钮', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_badge')); ?>" value="1" <?php checked(!isset($instance['show_badge']) || !empty($instance['show_badge'])); ?>> <?php esc_html_e('显示佩戴徽章', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
@@ -126,6 +157,8 @@ class WidgetAuthorCard extends \WP_Widget {
|
||||
'user_id' => max(0, (int) ($new_instance['user_id'] ?? 0)),
|
||||
'show_img_bg' => !empty($new_instance['show_img_bg']) ? 1 : 0,
|
||||
'show_stats' => !empty($new_instance['show_stats']) ? 1 : 0,
|
||||
'show_follow' => !empty($new_instance['show_follow']) ? 1 : 0,
|
||||
'show_badge' => !empty($new_instance['show_badge']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
/**
|
||||
* WordPress bookmark / links list (zibll widget_ui_links_lists_2).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Widgets;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class WidgetBookmarkLinks extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_bookmark_links',
|
||||
esc_html__('AKSRT 链接列表', 'aksrt'),
|
||||
[
|
||||
'description' => esc_html__('WordPress 链接(书签)列表,适合友链/导航。', 'aksrt'),
|
||||
'classname' => 'widget_aksrt_bookmark_links',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
$limit = max(0, min(100, (int) ($instance['links_limit'] ?? 12)));
|
||||
$orderby = sanitize_key((string) ($instance['links_orderby'] ?? 'name'));
|
||||
if (!in_array($orderby, ['name', 'updated', 'rating', 'rand', 'id'], true)) {
|
||||
$orderby = 'name';
|
||||
}
|
||||
$order = strtoupper((string) ($instance['links_order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC';
|
||||
$type = sanitize_key((string) ($instance['type'] ?? 'card'));
|
||||
if (!in_array($type, ['card', 'image', 'simple'], true)) {
|
||||
$type = 'card';
|
||||
}
|
||||
$go_link = !empty($instance['go_link']);
|
||||
$blank = !isset($instance['blank']) || !empty($instance['blank']);
|
||||
$nofollow = !empty($instance['nofollow']);
|
||||
$show_box = !empty($instance['show_box']);
|
||||
|
||||
$bm_args = [
|
||||
'orderby' => $orderby === 'rand' ? 'rand' : $orderby,
|
||||
'order' => $order,
|
||||
'limit' => $limit > 0 ? $limit : -1,
|
||||
];
|
||||
$cats = trim((string) ($instance['links_cats'] ?? ''));
|
||||
if ($cats !== '' && $cats !== 'all') {
|
||||
$bm_args['category'] = $cats;
|
||||
}
|
||||
$bookmarks = get_bookmarks($bm_args);
|
||||
if (!$bookmarks) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
$wrap = 'aksrt-bookmark-links style-' . $type . ($show_box ? ' has-box' : '');
|
||||
echo '<div class="' . esc_attr($wrap) . '">';
|
||||
foreach ($bookmarks as $b) {
|
||||
$url = (string) $b->link_url;
|
||||
if ($url !== '' && $go_link && function_exists('aksrt_go_link')) {
|
||||
$url = aksrt_go_link($url, true);
|
||||
}
|
||||
$rel = [];
|
||||
if ($nofollow) {
|
||||
$rel[] = 'nofollow';
|
||||
}
|
||||
if ($blank) {
|
||||
$rel[] = 'noopener';
|
||||
$rel[] = 'noreferrer';
|
||||
}
|
||||
$rel_attr = $rel ? ' rel="' . esc_attr(implode(' ', $rel)) . '"' : '';
|
||||
$tgt = $blank ? ' target="_blank"' : '';
|
||||
$img = (string) $b->link_image;
|
||||
$name = (string) $b->link_name;
|
||||
$desc = (string) $b->link_description;
|
||||
|
||||
echo '<a class="aksrt-bookmark-links__item" href="' . esc_url($url) . '"' . $tgt . $rel_attr . '>';
|
||||
if ($type !== 'simple' && $img !== '') {
|
||||
echo '<img class="aksrt-bookmark-links__img" src="' . esc_url($img) . '" alt="" loading="lazy" />';
|
||||
}
|
||||
echo '<span class="aksrt-bookmark-links__text">';
|
||||
echo '<span class="aksrt-bookmark-links__name">' . esc_html($name) . '</span>';
|
||||
if ($type === 'card' && $desc !== '') {
|
||||
echo '<span class="aksrt-bookmark-links__desc">' . esc_html($desc) . '</span>';
|
||||
}
|
||||
echo '</span></a>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('链接分类 ID(逗号,空=全部)', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('links_cats')); ?>" value="<?php echo esc_attr((string) ($instance['links_cats'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('数量(0=不限)', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="0" max="100" name="<?php echo esc_attr($this->get_field_name('links_limit')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['links_limit'] ?? 12))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('样式', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('type')); ?>">
|
||||
<option value="card" <?php selected(($instance['type'] ?? 'card'), 'card'); ?>><?php esc_html_e('图文卡片', 'aksrt'); ?></option>
|
||||
<option value="image" <?php selected(($instance['type'] ?? ''), 'image'); ?>><?php esc_html_e('图片', 'aksrt'); ?></option>
|
||||
<option value="simple" <?php selected(($instance['type'] ?? ''), 'simple'); ?>><?php esc_html_e('纯文字', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('排序', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('links_orderby')); ?>">
|
||||
<option value="name" <?php selected(($instance['links_orderby'] ?? 'name'), 'name'); ?>><?php esc_html_e('名称', 'aksrt'); ?></option>
|
||||
<option value="updated" <?php selected(($instance['links_orderby'] ?? ''), 'updated'); ?>><?php esc_html_e('更新', 'aksrt'); ?></option>
|
||||
<option value="rating" <?php selected(($instance['links_orderby'] ?? ''), 'rating'); ?>><?php esc_html_e('评分', 'aksrt'); ?></option>
|
||||
<option value="rand" <?php selected(($instance['links_orderby'] ?? ''), 'rand'); ?>><?php esc_html_e('随机', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('links_order')); ?>">
|
||||
<option value="ASC" <?php selected(($instance['links_order'] ?? 'ASC'), 'ASC'); ?>><?php esc_html_e('升序', 'aksrt'); ?></option>
|
||||
<option value="DESC" <?php selected(($instance['links_order'] ?? ''), 'DESC'); ?>><?php esc_html_e('降序', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('blank')); ?>" value="1" <?php checked(!isset($instance['blank']) || !empty($instance['blank'])); ?>> <?php esc_html_e('新窗口', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('nofollow')); ?>" value="1" <?php checked(!empty($instance['nofollow'])); ?>> <?php esc_html_e('nofollow', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('go_link')); ?>" value="1" <?php checked(!empty($instance['go_link'])); ?>> <?php esc_html_e('外链跳转页', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_box')); ?>" value="1" <?php checked(!empty($instance['show_box'])); ?>> <?php esc_html_e('外框盒子', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'links_cats' => sanitize_text_field((string) ($new_instance['links_cats'] ?? '')),
|
||||
'links_limit' => max(0, min(100, (int) ($new_instance['links_limit'] ?? 12))),
|
||||
'links_orderby' => sanitize_key((string) ($new_instance['links_orderby'] ?? 'name')),
|
||||
'links_order' => strtoupper((string) ($new_instance['links_order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC',
|
||||
'type' => in_array(($new_instance['type'] ?? ''), ['card', 'image', 'simple'], true) ? $new_instance['type'] : 'card',
|
||||
'blank' => !empty($new_instance['blank']) ? 1 : 0,
|
||||
'nofollow' => !empty($new_instance['nofollow']) ? 1 : 0,
|
||||
'go_link' => !empty($new_instance['go_link']) ? 1 : 0,
|
||||
'show_box' => !empty($new_instance['show_box']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ class WidgetCoverCards extends \WP_Widget {
|
||||
|
||||
foreach ($items as $item) {
|
||||
$image = esc_url($item['image'] ?? '');
|
||||
$video = esc_url($item['video'] ?? '');
|
||||
$link = esc_url($item['link'] ?? '');
|
||||
$card_title = sanitize_text_field($item['title'] ?? '');
|
||||
$desc = sanitize_text_field($item['desc'] ?? '');
|
||||
@@ -53,7 +54,11 @@ class WidgetCoverCards extends \WP_Widget {
|
||||
|
||||
echo '<div class="aksrt-cover-card"' . ($card_style ? ' style="' . esc_attr($card_style) . '"' : '') . '>';
|
||||
|
||||
if ($image) {
|
||||
if ($video) {
|
||||
echo '<div class="aksrt-cover-card__bg is-video">';
|
||||
echo '<video src="' . esc_url($video) . '" muted loop autoplay playsinline></video>';
|
||||
echo '</div>';
|
||||
} elseif ($image) {
|
||||
echo '<div class="aksrt-cover-card__bg">';
|
||||
echo '<img src="' . esc_url($image) . '" alt="' . esc_attr($card_title) . '"' . (function_exists('aksrt_lazy_loading') ? aksrt_lazy_loading('widget') : ' loading="lazy"') . '>';
|
||||
echo '</div>';
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* Icon cover cards (zibll zib_widget_ui_icon_cover_card).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Widgets;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class WidgetIconCoverCards extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_icon_cover_cards',
|
||||
esc_html__('AKSRT 图标封面卡', 'aksrt'),
|
||||
[
|
||||
'description' => esc_html__('横向图标 + 标题/描述的导航卡片。', 'aksrt'),
|
||||
'classname' => 'widget_aksrt_icon_cover_cards',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
$cards = $this->normalize($instance['cards'] ?? []);
|
||||
if (!$cards) {
|
||||
return;
|
||||
}
|
||||
$cols = max(1, min(4, (int) ($instance['pc_row'] ?? 2)));
|
||||
$m_cols = max(1, min(2, (int) ($instance['m_row'] ?? 1)));
|
||||
$icon_size = max(16, min(48, (int) ($instance['icon_size'] ?? 25)));
|
||||
$radius = !empty($instance['icon_radius4']);
|
||||
$go_link = !empty($instance['go_link']);
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
$style = sprintf('--aksrt-icc-pc:%d;--aksrt-icc-m:%d;--aksrt-icc-icon:%dpx;', $cols, $m_cols, $icon_size);
|
||||
echo '<div class="aksrt-icon-cover' . ($radius ? ' is-radius' : '') . '" style="' . esc_attr($style) . '">';
|
||||
foreach ($cards as $card) {
|
||||
$url = $card['url'];
|
||||
if ($url !== '' && $go_link && function_exists('aksrt_go_link')) {
|
||||
$url = aksrt_go_link($url, true);
|
||||
}
|
||||
$tag = $url !== '' ? 'a' : 'div';
|
||||
$href = $url !== '' ? ' href="' . esc_url($url) . '"' . ($card['target'] !== '' ? ' target="' . esc_attr($card['target']) . '" rel="noopener noreferrer"' : '') : '';
|
||||
echo '<' . $tag . ' class="aksrt-icon-cover__item"' . $href . '>';
|
||||
echo '<div class="aksrt-icon-cover__icon">';
|
||||
if ($card['icon_image'] !== '') {
|
||||
echo '<img src="' . esc_url($card['icon_image']) . '" alt="" loading="lazy" />';
|
||||
} elseif ($card['icon'] !== '') {
|
||||
echo '<i class="' . esc_attr($card['icon']) . '" aria-hidden="true"></i>';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '<div class="aksrt-icon-cover__text">';
|
||||
if ($card['title'] !== '') {
|
||||
echo '<div class="aksrt-icon-cover__title">' . esc_html($card['title']) . '</div>';
|
||||
}
|
||||
if ($card['desc'] !== '') {
|
||||
echo '<div class="aksrt-icon-cover__desc">' . esc_html($card['desc']) . '</div>';
|
||||
}
|
||||
echo '</div></' . $tag . '>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $raw
|
||||
* @return array<int, array<string,string>>
|
||||
*/
|
||||
private function normalize($raw): array {
|
||||
if (is_string($raw)) {
|
||||
$decoded = json_decode($raw, true);
|
||||
$raw = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
if (!is_array($raw)) {
|
||||
return [];
|
||||
}
|
||||
$out = [];
|
||||
foreach ($raw as $row) {
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
$title = sanitize_text_field((string) ($row['title'] ?? ''));
|
||||
$icon = sanitize_text_field((string) ($row['icon'] ?? ''));
|
||||
$icon_image = esc_url_raw(trim((string) ($row['icon_image'] ?? $row['customize_icon'] ?? '')));
|
||||
if ($title === '' && $icon === '' && $icon_image === '') {
|
||||
continue;
|
||||
}
|
||||
$url = '';
|
||||
if (is_array($row['link'] ?? null)) {
|
||||
$url = esc_url_raw(trim((string) ($row['link']['url'] ?? '')));
|
||||
$target = sanitize_text_field((string) ($row['link']['target'] ?? ''));
|
||||
} else {
|
||||
$url = esc_url_raw(trim((string) ($row['url'] ?? $row['link'] ?? '')));
|
||||
$target = sanitize_text_field((string) ($row['target'] ?? '_blank'));
|
||||
}
|
||||
$out[] = [
|
||||
'title' => $title,
|
||||
'desc' => sanitize_text_field((string) ($row['desc'] ?? '')),
|
||||
'icon' => $icon,
|
||||
'icon_image' => $icon_image,
|
||||
'url' => $url,
|
||||
'target' => $target,
|
||||
];
|
||||
if (count($out) >= 16) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
$json = is_string($instance['cards'] ?? null)
|
||||
? (string) $instance['cards']
|
||||
: wp_json_encode($this->normalize($instance['cards'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('卡片 JSON', 'aksrt'); ?>
|
||||
<textarea class="widefat" rows="7" name="<?php echo esc_attr($this->get_field_name('cards')); ?>" placeholder='[{"title":"文档","desc":"使用说明","icon":"fas fa-book","url":"https://"}]'><?php echo esc_textarea((string) $json); ?></textarea>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('PC 列', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="4" name="<?php echo esc_attr($this->get_field_name('pc_row')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['pc_row'] ?? 2))); ?>">
|
||||
</label>
|
||||
<label><?php esc_html_e('移动列', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="2" name="<?php echo esc_attr($this->get_field_name('m_row')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['m_row'] ?? 1))); ?>">
|
||||
</label>
|
||||
<label><?php esc_html_e('图标字号', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="16" max="48" name="<?php echo esc_attr($this->get_field_name('icon_size')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['icon_size'] ?? 25))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('icon_radius4')); ?>" value="1" <?php checked(!empty($instance['icon_radius4'])); ?>> <?php esc_html_e('图标圆角方形', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('go_link')); ?>" value="1" <?php checked(!empty($instance['go_link'])); ?>> <?php esc_html_e('外链跳转页', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'cards' => $this->normalize($new_instance['cards'] ?? []),
|
||||
'pc_row' => max(1, min(4, (int) ($new_instance['pc_row'] ?? 2))),
|
||||
'm_row' => max(1, min(2, (int) ($new_instance['m_row'] ?? 1))),
|
||||
'icon_size' => max(16, min(48, (int) ($new_instance['icon_size'] ?? 25))),
|
||||
'icon_radius4' => !empty($new_instance['icon_radius4']) ? 1 : 0,
|
||||
'go_link' => !empty($new_instance['go_link']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
/**
|
||||
* Main posts list (zibll zib_widget_ui_main_post lite).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Widgets;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class WidgetMainPosts extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_main_posts',
|
||||
esc_html__('AKSRT 文章列表', 'aksrt'),
|
||||
[
|
||||
'description' => esc_html__('卡片/迷你/列表样式的文章模块。', 'aksrt'),
|
||||
'classname' => 'widget_aksrt_main_posts',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
$count = max(1, min(30, (int) ($instance['count'] ?? 6)));
|
||||
$style = sanitize_key((string) ($instance['style'] ?? 'list'));
|
||||
if (!in_array($style, ['list', 'card', 'mini'], true)) {
|
||||
$style = 'list';
|
||||
}
|
||||
$orderby = sanitize_key((string) ($instance['orderby'] ?? 'date'));
|
||||
$cat = (int) ($instance['cat'] ?? 0);
|
||||
$limit_day = max(0, (int) ($instance['limit_day'] ?? 0));
|
||||
$show_thumb = !isset($instance['show_thumb']) || !empty($instance['show_thumb']);
|
||||
$show_meta = !isset($instance['show_meta']) || !empty($instance['show_meta']);
|
||||
$show_number = !empty($instance['show_number']);
|
||||
|
||||
$query = [
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => $count,
|
||||
'ignore_sticky_posts' => true,
|
||||
'no_found_rows' => true,
|
||||
];
|
||||
if ($cat > 0) {
|
||||
$query['cat'] = $cat;
|
||||
}
|
||||
if ($limit_day > 0) {
|
||||
$query['date_query'] = [['after' => $limit_day . ' days ago']];
|
||||
}
|
||||
switch ($orderby) {
|
||||
case 'views':
|
||||
$query['meta_key'] = 'aksrt_post_views';
|
||||
$query['orderby'] = 'meta_value_num';
|
||||
$query['order'] = 'DESC';
|
||||
break;
|
||||
case 'comments':
|
||||
$query['orderby'] = 'comment_count';
|
||||
$query['order'] = 'DESC';
|
||||
break;
|
||||
case 'rand':
|
||||
$query['orderby'] = 'rand';
|
||||
break;
|
||||
case 'modified':
|
||||
$query['orderby'] = 'modified';
|
||||
$query['order'] = 'DESC';
|
||||
break;
|
||||
default:
|
||||
$query['orderby'] = 'date';
|
||||
$query['order'] = 'DESC';
|
||||
}
|
||||
|
||||
$q = new \WP_Query($query);
|
||||
if (!$q->have_posts()) {
|
||||
wp_reset_postdata();
|
||||
return;
|
||||
}
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
echo '<div class="aksrt-main-posts style-' . esc_attr($style) . '">';
|
||||
$i = 0;
|
||||
while ($q->have_posts()) {
|
||||
$q->the_post();
|
||||
$i++;
|
||||
$thumb = $show_thumb ? get_the_post_thumbnail_url(get_the_ID(), $style === 'card' ? 'medium' : 'thumbnail') : '';
|
||||
$views = (int) get_post_meta(get_the_ID(), 'aksrt_post_views', true);
|
||||
|
||||
if ($style === 'card') {
|
||||
echo '<a class="aksrt-main-posts__card" href="' . esc_url(get_permalink()) . '">';
|
||||
echo '<div class="aksrt-main-posts__thumb' . ($thumb ? '' : ' is-empty') . '">';
|
||||
if ($thumb) {
|
||||
echo '<img src="' . esc_url($thumb) . '" alt="" loading="lazy" />';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '<div class="aksrt-main-posts__body">';
|
||||
echo '<div class="aksrt-main-posts__title">' . esc_html(get_the_title()) . '</div>';
|
||||
if ($show_meta) {
|
||||
echo '<div class="aksrt-main-posts__meta"><span>' . esc_html(get_the_date()) . '</span>';
|
||||
if ($views > 0) {
|
||||
echo '<span><i class="fas fa-eye"></i> ' . esc_html((string) $views) . '</span>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div></a>';
|
||||
} else {
|
||||
echo '<a class="aksrt-main-posts__row" href="' . esc_url(get_permalink()) . '">';
|
||||
if ($show_number) {
|
||||
echo '<span class="aksrt-main-posts__num">' . esc_html((string) $i) . '</span>';
|
||||
}
|
||||
if ($show_thumb) {
|
||||
echo '<span class="aksrt-main-posts__thumb mini' . ($thumb ? '' : ' is-empty') . '">';
|
||||
if ($thumb) {
|
||||
echo '<img src="' . esc_url($thumb) . '" alt="" loading="lazy" />';
|
||||
}
|
||||
echo '</span>';
|
||||
}
|
||||
echo '<span class="aksrt-main-posts__body">';
|
||||
echo '<span class="aksrt-main-posts__title">' . esc_html(get_the_title()) . '</span>';
|
||||
if ($show_meta) {
|
||||
echo '<span class="aksrt-main-posts__meta">' . esc_html(get_the_date()) . '</span>';
|
||||
}
|
||||
echo '</span></a>';
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
wp_reset_postdata();
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('数量', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="30" name="<?php echo esc_attr($this->get_field_name('count')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['count'] ?? 6))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('样式', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('style')); ?>">
|
||||
<option value="list" <?php selected(($instance['style'] ?? 'list'), 'list'); ?>><?php esc_html_e('列表', 'aksrt'); ?></option>
|
||||
<option value="mini" <?php selected(($instance['style'] ?? ''), 'mini'); ?>><?php esc_html_e('迷你', 'aksrt'); ?></option>
|
||||
<option value="card" <?php selected(($instance['style'] ?? ''), 'card'); ?>><?php esc_html_e('卡片', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('排序', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('orderby')); ?>">
|
||||
<option value="date" <?php selected(($instance['orderby'] ?? 'date'), 'date'); ?>><?php esc_html_e('时间', 'aksrt'); ?></option>
|
||||
<option value="modified" <?php selected(($instance['orderby'] ?? ''), 'modified'); ?>><?php esc_html_e('更新', 'aksrt'); ?></option>
|
||||
<option value="views" <?php selected(($instance['orderby'] ?? ''), 'views'); ?>><?php esc_html_e('浏览', 'aksrt'); ?></option>
|
||||
<option value="comments" <?php selected(($instance['orderby'] ?? ''), 'comments'); ?>><?php esc_html_e('评论', 'aksrt'); ?></option>
|
||||
<option value="rand" <?php selected(($instance['orderby'] ?? ''), 'rand'); ?>><?php esc_html_e('随机', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('分类 ID(0=全部)', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="0" name="<?php echo esc_attr($this->get_field_name('cat')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['cat'] ?? 0))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('最近 N 天(0=不限)', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="0" name="<?php echo esc_attr($this->get_field_name('limit_day')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['limit_day'] ?? 0))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_thumb')); ?>" value="1" <?php checked(!isset($instance['show_thumb']) || !empty($instance['show_thumb'])); ?>> <?php esc_html_e('显示缩略图', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_meta')); ?>" value="1" <?php checked(!isset($instance['show_meta']) || !empty($instance['show_meta'])); ?>> <?php esc_html_e('显示 meta', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_number')); ?>" value="1" <?php checked(!empty($instance['show_number'])); ?>> <?php esc_html_e('显示序号', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$style = sanitize_key((string) ($new_instance['style'] ?? 'list'));
|
||||
if (!in_array($style, ['list', 'card', 'mini'], true)) {
|
||||
$style = 'list';
|
||||
}
|
||||
$orderby = sanitize_key((string) ($new_instance['orderby'] ?? 'date'));
|
||||
if (!in_array($orderby, ['date', 'modified', 'views', 'comments', 'rand'], true)) {
|
||||
$orderby = 'date';
|
||||
}
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'count' => max(1, min(30, (int) ($new_instance['count'] ?? 6))),
|
||||
'style' => $style,
|
||||
'orderby' => $orderby,
|
||||
'cat' => max(0, (int) ($new_instance['cat'] ?? 0)),
|
||||
'limit_day' => max(0, (int) ($new_instance['limit_day'] ?? 0)),
|
||||
'show_thumb' => !empty($new_instance['show_thumb']) ? 1 : 0,
|
||||
'show_meta' => !empty($new_instance['show_meta']) ? 1 : 0,
|
||||
'show_number' => !empty($new_instance['show_number']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
* Term aggregation cards (zibll zib_widget_ui_term_lists_card lite).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Widgets;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
class WidgetTermAggregation extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_term_aggregation',
|
||||
esc_html__('AKSRT 分类聚合', 'aksrt'),
|
||||
[
|
||||
'description' => esc_html__('分类封面 + 最新文章列表聚合卡。', 'aksrt'),
|
||||
'classname' => 'widget_aksrt_term_aggregation',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
$taxonomy = sanitize_key((string) ($instance['taxonomy'] ?? 'category'));
|
||||
if (!taxonomy_exists($taxonomy)) {
|
||||
$taxonomy = 'category';
|
||||
}
|
||||
$term_ids = $this->parse_ids((string) ($instance['term_ids'] ?? ''));
|
||||
$count = max(1, min(12, (int) ($instance['count'] ?? 4)));
|
||||
$orderby = sanitize_key((string) ($instance['orderby'] ?? 'date'));
|
||||
$columns = max(1, min(3, (int) ($instance['columns'] ?? 1)));
|
||||
|
||||
if (!$term_ids) {
|
||||
// Fallback: top terms by count.
|
||||
$terms = get_terms([
|
||||
'taxonomy' => $taxonomy,
|
||||
'number' => max(1, min(4, (int) ($instance['auto_terms'] ?? 2))),
|
||||
'orderby' => 'count',
|
||||
'order' => 'DESC',
|
||||
'hide_empty' => true,
|
||||
]);
|
||||
if (is_wp_error($terms) || !$terms) {
|
||||
return;
|
||||
}
|
||||
$term_ids = array_map(static fn($t) => (int) $t->term_id, $terms);
|
||||
}
|
||||
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
echo '<div class="aksrt-term-agg" style="--aksrt-ta-cols:' . esc_attr((string) $columns) . '">';
|
||||
foreach ($term_ids as $term_id) {
|
||||
$term = get_term($term_id, $taxonomy);
|
||||
if (!$term || is_wp_error($term)) {
|
||||
continue;
|
||||
}
|
||||
$link = get_term_link($term);
|
||||
if (is_wp_error($link)) {
|
||||
continue;
|
||||
}
|
||||
$cover = '';
|
||||
$img_id = (int) get_term_meta($term_id, 'thumbnail_id', true);
|
||||
if (!$img_id) {
|
||||
$img_id = (int) get_term_meta($term_id, '_aksrt_cover', true);
|
||||
}
|
||||
if ($img_id) {
|
||||
$cover = wp_get_attachment_image_url($img_id, 'medium') ?: '';
|
||||
}
|
||||
if ($cover === '') {
|
||||
$cover = (string) get_term_meta($term_id, '_aksrt_cover_url', true);
|
||||
}
|
||||
|
||||
$posts_q = [
|
||||
'post_type' => 'post',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => $count,
|
||||
'ignore_sticky_posts' => true,
|
||||
'no_found_rows' => true,
|
||||
'tax_query' => [[
|
||||
'taxonomy' => $taxonomy,
|
||||
'field' => 'term_id',
|
||||
'terms' => $term_id,
|
||||
]],
|
||||
];
|
||||
if ($orderby === 'views') {
|
||||
$posts_q['meta_key'] = 'aksrt_post_views';
|
||||
$posts_q['orderby'] = 'meta_value_num';
|
||||
$posts_q['order'] = 'DESC';
|
||||
} elseif ($orderby === 'modified') {
|
||||
$posts_q['orderby'] = 'modified';
|
||||
$posts_q['order'] = 'DESC';
|
||||
} else {
|
||||
$posts_q['orderby'] = 'date';
|
||||
$posts_q['order'] = 'DESC';
|
||||
}
|
||||
$q = new \WP_Query($posts_q);
|
||||
|
||||
echo '<div class="aksrt-term-agg__card">';
|
||||
echo '<a class="aksrt-term-agg__head" href="' . esc_url($link) . '">';
|
||||
echo '<div class="aksrt-term-agg__cover' . ($cover ? '' : ' is-empty') . '"' . ($cover ? ' style="background-image:url(' . esc_url($cover) . ')"' : '') . '></div>';
|
||||
echo '<div class="aksrt-term-agg__name">' . esc_html($term->name) . '</div>';
|
||||
echo '<div class="aksrt-term-agg__count">' . esc_html(sprintf(_n('%d 篇', '%d 篇', (int) $term->count, 'aksrt'), (int) $term->count)) . '</div>';
|
||||
echo '</a>';
|
||||
if ($q->have_posts()) {
|
||||
echo '<ul class="aksrt-term-agg__posts">';
|
||||
while ($q->have_posts()) {
|
||||
$q->the_post();
|
||||
echo '<li><a href="' . esc_url(get_permalink()) . '">' . esc_html(get_the_title()) . '</a></li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
wp_reset_postdata();
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/** @return array<int,int> */
|
||||
private function parse_ids(string $raw): array {
|
||||
if ($raw === '') {
|
||||
return [];
|
||||
}
|
||||
$ids = [];
|
||||
foreach (preg_split('/[\s,]+/', $raw) ?: [] as $p) {
|
||||
$id = (int) $p;
|
||||
if ($id > 0) {
|
||||
$ids[] = $id;
|
||||
}
|
||||
}
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
$taxs = get_taxonomies(['public' => true], 'objects');
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('分类法', 'aksrt'); ?>
|
||||
<select class="widefat" name="<?php echo esc_attr($this->get_field_name('taxonomy')); ?>">
|
||||
<?php foreach ($taxs as $tax) : ?>
|
||||
<option value="<?php echo esc_attr($tax->name); ?>" <?php selected(($instance['taxonomy'] ?? 'category'), $tax->name); ?>><?php echo esc_html($tax->labels->name); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('term ID(逗号,空=自动热门)', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('term_ids')); ?>" value="<?php echo esc_attr((string) ($instance['term_ids'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('每分类文章数', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="12" name="<?php echo esc_attr($this->get_field_name('count')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['count'] ?? 4))); ?>">
|
||||
</label>
|
||||
<label><?php esc_html_e('列数', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="1" max="3" name="<?php echo esc_attr($this->get_field_name('columns')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['columns'] ?? 1))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('文章排序', 'aksrt'); ?>
|
||||
<select name="<?php echo esc_attr($this->get_field_name('orderby')); ?>">
|
||||
<option value="date" <?php selected(($instance['orderby'] ?? 'date'), 'date'); ?>><?php esc_html_e('时间', 'aksrt'); ?></option>
|
||||
<option value="modified" <?php selected(($instance['orderby'] ?? ''), 'modified'); ?>><?php esc_html_e('更新', 'aksrt'); ?></option>
|
||||
<option value="views" <?php selected(($instance['orderby'] ?? ''), 'views'); ?>><?php esc_html_e('浏览', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$orderby = sanitize_key((string) ($new_instance['orderby'] ?? 'date'));
|
||||
if (!in_array($orderby, ['date', 'modified', 'views'], true)) {
|
||||
$orderby = 'date';
|
||||
}
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'taxonomy' => sanitize_key((string) ($new_instance['taxonomy'] ?? 'category')),
|
||||
'term_ids' => sanitize_text_field((string) ($new_instance['term_ids'] ?? '')),
|
||||
'count' => max(1, min(12, (int) ($new_instance['count'] ?? 4))),
|
||||
'columns' => max(1, min(3, (int) ($new_instance['columns'] ?? 1))),
|
||||
'orderby' => $orderby,
|
||||
'auto_terms' => max(1, min(4, (int) ($new_instance['auto_terms'] ?? 2))),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Current-user / guest identity card (zibll widget_ui_user parity).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,142 +11,208 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class WidgetUserCard extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_user_card',
|
||||
__('用户卡片', 'aksrt'),
|
||||
['description' => __('在侧栏显示当前登录用户或指定用户的信息卡片。', 'aksrt')]
|
||||
);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_user_card',
|
||||
__('用户卡片', 'aksrt'),
|
||||
['description' => __('未登录显示登录入口;登录后显示当前用户卡片、签到与快捷按钮。', 'aksrt')]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : '';
|
||||
$show_stats = !empty($instance['show_stats']);
|
||||
$show_actions = !empty($instance['show_actions']);
|
||||
public function widget($args, $instance): void {
|
||||
$show_cover = !isset($instance['show_img_bg']) || !empty($instance['show_img_bg']);
|
||||
$show_stats = !empty($instance['show_stats']) || !isset($instance['show_stats']);
|
||||
$show_actions = !empty($instance['show_button']) || !isset($instance['show_button']);
|
||||
$show_checkin = !empty($instance['show_checkin']) || !isset($instance['show_checkin']);
|
||||
$loged_title = (string) ($instance['loged_title'] ?? __('Hi!请登录', 'aksrt'));
|
||||
$btn1_text = (string) ($instance['button_1_text'] ?? __('发布文章', 'aksrt'));
|
||||
$btn2_text = (string) ($instance['button_2_text'] ?? __('用户中心', 'aksrt'));
|
||||
|
||||
// 获取目标用户
|
||||
$user_id = !empty($instance['user_id']) ? (int) $instance['user_id'] : 0;
|
||||
if ($user_id <= 0 && is_user_logged_in()) {
|
||||
$user_id = get_current_user_id();
|
||||
}
|
||||
// Fixed user id wins; else current user.
|
||||
$user_id = !empty($instance['user_id']) ? (int) $instance['user_id'] : 0;
|
||||
if ($user_id <= 0 && is_user_logged_in()) {
|
||||
$user_id = get_current_user_id();
|
||||
}
|
||||
|
||||
if ($user_id <= 0) return;
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user) return;
|
||||
if ($user_id <= 0) {
|
||||
$this->render_guest($show_cover, $loged_title);
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取用户统计
|
||||
$post_count = count_user_posts($user_id, 'post', true);
|
||||
$comment_count = get_comments(['user_id' => $user_id, 'count' => true]);
|
||||
$follower_count = 0;
|
||||
$following_count = 0;
|
||||
if (class_exists('\AKSRT\User\Follow')) {
|
||||
$follower_count = \AKSRT\User\Follow::get_instance()->get_follower_count($user_id);
|
||||
$following_count = \AKSRT\User\Follow::get_instance()->get_following_count($user_id);
|
||||
}
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user) {
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
return;
|
||||
}
|
||||
|
||||
// 头像
|
||||
$avatar_url = function_exists('aksrt_get_avatar_url')
|
||||
? aksrt_get_avatar_url($user_id, ['size' => 144])
|
||||
: get_avatar_url($user_id, ['size' => 144]);
|
||||
$is_self = is_user_logged_in() && (int) get_current_user_id() === $user_id;
|
||||
$avatar_url = function_exists('aksrt_get_avatar_url')
|
||||
? aksrt_get_avatar_url($user_id, ['size' => 144])
|
||||
: get_avatar_url($user_id, ['size' => 144]);
|
||||
$profile_url = function_exists('aksrt_get_user_home_url')
|
||||
? aksrt_get_user_home_url($user_id)
|
||||
: get_author_posts_url($user_id);
|
||||
$center_url = function_exists('aksrt_get_user_center_url')
|
||||
? aksrt_get_user_center_url()
|
||||
: $profile_url;
|
||||
$compose_url = home_url('/');
|
||||
// Prefer front submit / write page when available.
|
||||
if (function_exists('get_pages')) {
|
||||
$pages = get_pages(['meta_key' => '_wp_page_template', 'meta_value' => 'templates/pages/page-submit.php', 'number' => 1]);
|
||||
if (!empty($pages[0])) {
|
||||
$compose_url = get_permalink($pages[0]);
|
||||
}
|
||||
}
|
||||
if ($compose_url === home_url('/') && function_exists('aksrt_get_user_center_url')) {
|
||||
$compose_url = aksrt_get_user_center_url('posts');
|
||||
}
|
||||
$bio = get_user_meta($user_id, 'description', true);
|
||||
if (!is_string($bio) || $bio === '') {
|
||||
$bio = (string) $user->description;
|
||||
}
|
||||
$cover = (string) get_user_meta($user_id, 'aksrt_cover', true);
|
||||
if ($cover === '') {
|
||||
$cover = (string) get_user_meta($user_id, 'custom_avatar_cover', true);
|
||||
}
|
||||
|
||||
// 用户主页链接
|
||||
$profile_url = function_exists('aksrt_get_user_home_url')
|
||||
? aksrt_get_user_home_url($user_id)
|
||||
: get_author_posts_url($user_id);
|
||||
$post_count = count_user_posts($user_id, 'post', true);
|
||||
$follower_count = 0;
|
||||
$following_count = 0;
|
||||
if (class_exists('\AKSRT\User\Follow')) {
|
||||
$follower_count = \AKSRT\User\Follow::get_instance()->get_follower_count($user_id);
|
||||
$following_count = \AKSRT\User\Follow::get_instance()->get_following_count($user_id);
|
||||
}
|
||||
|
||||
// 简介
|
||||
$bio = get_user_meta($user_id, 'description', true);
|
||||
if (!$bio) $bio = $user->description ?: '';
|
||||
echo '<div class="aksrt-user-card user-card zib-widget widget">';
|
||||
if ($show_cover) {
|
||||
$bg = $cover !== '' ? ' style="background-image:url(' . esc_url($cover) . ')"' : '';
|
||||
echo '<div class="aksrt-user-card__cover user-cover graphic"' . $bg . '></div>';
|
||||
}
|
||||
echo '<div class="aksrt-user-card__body card-content">';
|
||||
if ($show_checkin && $is_self && function_exists('aksrt_header_user_checkin_btn')) {
|
||||
// Reuse compact check-in button markup (without details if already long).
|
||||
$btn = aksrt_header_user_checkin_btn($user_id);
|
||||
if ($btn !== '') {
|
||||
echo '<div class="aksrt-user-card__checkin">' . $btn . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
echo '<div class="aksrt-user-card__avatar user-avatar">';
|
||||
echo '<a href="' . esc_url($profile_url) . '"><img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($user->display_name) . '" loading="lazy" width="72" height="72" /></a>';
|
||||
echo '</div>';
|
||||
echo '<h4 class="aksrt-user-card__name user-name"><a href="' . esc_url($profile_url) . '">' . esc_html($user->display_name) . '</a></h4>';
|
||||
if ($bio !== '') {
|
||||
echo '<p class="aksrt-user-card__bio user-desc">' . esc_html(wp_trim_words($bio, 24)) . '</p>';
|
||||
}
|
||||
if ($show_stats) {
|
||||
echo '<div class="aksrt-user-card__stats">';
|
||||
echo '<div class="aksrt-user-card__stat"><span class="aksrt-user-card__stat-value">' . esc_html(number_format_i18n($post_count)) . '</span><span class="aksrt-user-card__stat-label">' . esc_html__('文章', 'aksrt') . '</span></div>';
|
||||
echo '<div class="aksrt-user-card__stat"><span class="aksrt-user-card__stat-value">' . esc_html(number_format_i18n($follower_count)) . '</span><span class="aksrt-user-card__stat-label">' . esc_html__('粉丝', 'aksrt') . '</span></div>';
|
||||
echo '<div class="aksrt-user-card__stat"><span class="aksrt-user-card__stat-value">' . esc_html(number_format_i18n($following_count)) . '</span><span class="aksrt-user-card__stat-label">' . esc_html__('关注', 'aksrt') . '</span></div>';
|
||||
echo '</div>';
|
||||
}
|
||||
if ($show_actions && $is_self) {
|
||||
echo '<div class="aksrt-user-card__actions user-btns">';
|
||||
echo '<a class="aksrt-user-card__btn aksrt-user-card__btn--primary but jb-pink" href="' . esc_url($compose_url) . '">' . esc_html($btn1_text) . '</a>';
|
||||
echo '<a class="aksrt-user-card__btn aksrt-user-card__btn--ghost but jb-blue" href="' . esc_url($center_url) . '">' . esc_html($btn2_text) . '</a>';
|
||||
echo '</div>';
|
||||
} elseif ($show_actions) {
|
||||
echo '<div class="aksrt-user-card__actions"><a class="aksrt-user-card__btn aksrt-user-card__btn--primary" href="' . esc_url($profile_url) . '">' . esc_html__('查看主页', 'aksrt') . '</a></div>';
|
||||
}
|
||||
echo '</div></div>';
|
||||
|
||||
echo $args['before_widget'];
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
if ($title) {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
}
|
||||
private function render_guest(bool $show_cover, string $loged_title): void {
|
||||
$login = function_exists('aksrt_get_login_url') ? aksrt_get_login_url() : wp_login_url();
|
||||
$register = function_exists('aksrt_get_register_url') ? aksrt_get_register_url() : wp_registration_url();
|
||||
$default_avatar = function_exists('get_avatar_url')
|
||||
? get_avatar_url(0, ['size' => 144, 'force_default' => true])
|
||||
: includes_url('images/blank.gif');
|
||||
|
||||
echo '<div class="aksrt-user-card">';
|
||||
$oauth_html = '';
|
||||
if (class_exists('\AKSRT\Auth\OAuth')) {
|
||||
$oauth = \AKSRT\Auth\OAuth::get_instance();
|
||||
if (method_exists($oauth, 'render_social_buttons')) {
|
||||
$oauth_html = (string) $oauth->render_social_buttons(__('社交账号登录', 'aksrt'));
|
||||
} elseif (method_exists($oauth, 'get_login_buttons')) {
|
||||
$oauth_html = (string) $oauth->get_login_buttons();
|
||||
}
|
||||
}
|
||||
|
||||
// 头像
|
||||
echo '<div class="aksrt-user-card__avatar">';
|
||||
echo '<a href="' . esc_url($profile_url) . '">';
|
||||
echo '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($user->display_name) . '"' . (function_exists('aksrt_lazy_loading') ? aksrt_lazy_loading('avatar') : ' loading="lazy"') . '>';
|
||||
echo '</a>';
|
||||
echo '</div>';
|
||||
echo '<div class="aksrt-user-card user-card zib-widget widget is-guest">';
|
||||
if ($show_cover) {
|
||||
echo '<div class="aksrt-user-card__cover user-cover graphic is-empty"></div>';
|
||||
}
|
||||
echo '<div class="aksrt-user-card__body card-content">';
|
||||
echo '<div class="aksrt-user-card__avatar user-avatar"><img src="' . esc_url($default_avatar) . '" alt="" width="72" height="72" loading="lazy" /></div>';
|
||||
echo '<div class="aksrt-user-card__guest-title">' . esc_html($loged_title) . '</div>';
|
||||
echo '<div class="aksrt-user-card__actions">';
|
||||
echo '<a class="aksrt-user-card__btn aksrt-user-card__btn--primary signin-loader" href="' . esc_url($login) . '">' . esc_html__('登录', 'aksrt') . '</a>';
|
||||
if ($register) {
|
||||
echo '<a class="aksrt-user-card__btn aksrt-user-card__btn--ghost signup-loader" href="' . esc_url($register) . '">' . esc_html__('注册', 'aksrt') . '</a>';
|
||||
}
|
||||
echo '</div>';
|
||||
if ($oauth_html !== '') {
|
||||
echo '<div class="aksrt-user-card__oauth social_loginbar">' . $oauth_html . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
echo '</div></div>';
|
||||
}
|
||||
|
||||
// 昵称
|
||||
echo '<h4 class="aksrt-user-card__name">';
|
||||
echo '<a href="' . esc_url($profile_url) . '">' . esc_html($user->display_name) . '</a>';
|
||||
echo '</h4>';
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题(可选)', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('固定用户 ID(0=当前用户)', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="0" name="<?php echo esc_attr($this->get_field_name('user_id')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['user_id'] ?? 0))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('未登录文案', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('loged_title')); ?>" value="<?php echo esc_attr((string) ($instance['loged_title'] ?? __('Hi!请登录', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('按钮1文案', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('button_1_text')); ?>" value="<?php echo esc_attr((string) ($instance['button_1_text'] ?? __('发布文章', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('按钮2文案', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('button_2_text')); ?>" value="<?php echo esc_attr((string) ($instance['button_2_text'] ?? __('用户中心', 'aksrt'))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_img_bg')); ?>" value="1" <?php checked(!isset($instance['show_img_bg']) || !empty($instance['show_img_bg'])); ?>> <?php esc_html_e('显示封面', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_stats')); ?>" value="1" <?php checked(!isset($instance['show_stats']) || !empty($instance['show_stats'])); ?>> <?php esc_html_e('显示统计', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_button')); ?>" value="1" <?php checked(!isset($instance['show_button']) || !empty($instance['show_button'])); ?>> <?php esc_html_e('显示操作按钮', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('show_checkin')); ?>" value="1" <?php checked(!isset($instance['show_checkin']) || !empty($instance['show_checkin'])); ?>> <?php esc_html_e('显示签到(本人)', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
// 简介
|
||||
if ($bio) {
|
||||
echo '<p class="aksrt-user-card__bio">' . esc_html(wp_trim_words($bio, 20)) . '</p>';
|
||||
}
|
||||
|
||||
// 统计
|
||||
if ($show_stats) {
|
||||
echo '<div class="aksrt-user-card__stats">';
|
||||
echo '<div class="aksrt-user-card__stat"><span class="aksrt-user-card__stat-value">' . number_format_i18n($post_count) . '</span><span class="aksrt-user-card__stat-label">' . esc_html__('文章', 'aksrt') . '</span></div>';
|
||||
echo '<div class="aksrt-user-card__stat"><span class="aksrt-user-card__stat-value">' . number_format_i18n($follower_count) . '</span><span class="aksrt-user-card__stat-label">' . esc_html__('粉丝', 'aksrt') . '</span></div>';
|
||||
echo '<div class="aksrt-user-card__stat"><span class="aksrt-user-card__stat-value">' . number_format_i18n($following_count) . '</span><span class="aksrt-user-card__stat-label">' . esc_html__('关注', 'aksrt') . '</span></div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
// 操作按钮
|
||||
if ($show_actions) {
|
||||
echo '<div class="aksrt-user-card__actions">';
|
||||
if (is_user_logged_in() && (int) get_current_user_id() === $user_id) {
|
||||
echo '<a href="' . esc_url($profile_url) . '" class="aksrt-user-card__btn aksrt-user-card__btn--primary">' . esc_html__('个人主页', 'aksrt') . '</a>';
|
||||
if (function_exists('aksrt_get_user_center_url')) {
|
||||
echo '<a href="' . esc_url(aksrt_get_user_center_url()) . '" class="aksrt-user-card__btn aksrt-user-card__btn--ghost">' . esc_html__('设置', 'aksrt') . '</a>';
|
||||
}
|
||||
} else {
|
||||
echo '<a href="' . esc_url($profile_url) . '" class="aksrt-user-card__btn aksrt-user-card__btn--primary">' . esc_html__('查看主页', 'aksrt') . '</a>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : '';
|
||||
$user_id = !empty($instance['user_id']) ? (int) $instance['user_id'] : 0;
|
||||
$show_stats = !empty($instance['show_stats']);
|
||||
$show_actions = !empty($instance['show_actions']);
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php esc_html_e('标题(可选):', 'aksrt'); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('user_id')); ?>"><?php esc_html_e('用户 ID(0 = 当前登录用户):', 'aksrt'); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('user_id')); ?>" name="<?php echo esc_attr($this->get_field_name('user_id')); ?>" type="number" value="<?php echo esc_attr((string) $user_id); ?>" min="0">
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_stats')); ?>" name="<?php echo esc_attr($this->get_field_name('show_stats')); ?>" value="1" <?php checked($show_stats); ?>>
|
||||
<?php esc_html_e('显示统计(文章、粉丝、关注)', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_actions')); ?>" name="<?php echo esc_attr($this->get_field_name('show_actions')); ?>" value="1" <?php checked($show_actions); ?>>
|
||||
<?php esc_html_e('显示操作按钮', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$instance = [];
|
||||
$instance['title'] = sanitize_text_field($new_instance['title'] ?? '');
|
||||
$instance['user_id'] = (int) ($new_instance['user_id'] ?? 0);
|
||||
$instance['show_stats'] = !empty($new_instance['show_stats']);
|
||||
$instance['show_actions'] = !empty($new_instance['show_actions']);
|
||||
return $instance;
|
||||
}
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'user_id' => max(0, (int) ($new_instance['user_id'] ?? 0)),
|
||||
'loged_title' => sanitize_text_field((string) ($new_instance['loged_title'] ?? '')),
|
||||
'button_1_text' => sanitize_text_field((string) ($new_instance['button_1_text'] ?? '')),
|
||||
'button_2_text' => sanitize_text_field((string) ($new_instance['button_2_text'] ?? '')),
|
||||
'show_img_bg' => !empty($new_instance['show_img_bg']) ? 1 : 0,
|
||||
'show_stats' => !empty($new_instance['show_stats']) ? 1 : 0,
|
||||
'show_button' => !empty($new_instance['show_button']) ? 1 : 0,
|
||||
'show_checkin' => !empty($new_instance['show_checkin']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,13 @@ class WidgetUserRanking extends \WP_Widget {
|
||||
echo $args['before_widget'];
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
|
||||
if (!empty($instance['checkin_btn']) && is_user_logged_in() && function_exists('aksrt_header_user_checkin_btn')) {
|
||||
$cbtn = aksrt_header_user_checkin_btn(get_current_user_id());
|
||||
if ($cbtn !== '') {
|
||||
echo '<div class="aksrt-user-ranking__checkin mb10">' . $cbtn . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
|
||||
echo '<ul class="aksrt-user-ranking">';
|
||||
$rank = 0;
|
||||
foreach ($users as $user) {
|
||||
@@ -110,6 +117,58 @@ class WidgetUserRanking extends \WP_Widget {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'checkin_all_day':
|
||||
global $wpdb;
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT user_id, meta_value as val FROM {$wpdb->usermeta}
|
||||
WHERE meta_key IN ('aksrt_checkin_all_day','checkin_all_day')
|
||||
ORDER BY CAST(meta_value AS UNSIGNED) DESC
|
||||
LIMIT %d",
|
||||
$count * 2
|
||||
), ARRAY_A);
|
||||
$seen = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$uid = (int) $row['user_id'];
|
||||
if (isset($seen[$uid])) continue;
|
||||
$seen[$uid] = true;
|
||||
$user = get_userdata($uid);
|
||||
if ($user) {
|
||||
$users[] = [
|
||||
'id' => $uid,
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n((int) $row['val']) . ' 天',
|
||||
];
|
||||
}
|
||||
if (count($users) >= $count) break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'checkin_continuous_day':
|
||||
global $wpdb;
|
||||
$rows = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT user_id, meta_value as val FROM {$wpdb->usermeta}
|
||||
WHERE meta_key IN ('aksrt_checkin_continuous_day','checkin_continuous_day')
|
||||
ORDER BY CAST(meta_value AS UNSIGNED) DESC
|
||||
LIMIT %d",
|
||||
$count * 2
|
||||
), ARRAY_A);
|
||||
$seen = [];
|
||||
foreach ((array) $rows as $row) {
|
||||
$uid = (int) $row['user_id'];
|
||||
if (isset($seen[$uid])) continue;
|
||||
$seen[$uid] = true;
|
||||
$user = get_userdata($uid);
|
||||
if ($user) {
|
||||
$users[] = [
|
||||
'id' => $uid,
|
||||
'name' => $user->display_name,
|
||||
'value' => number_format_i18n((int) $row['val']) . ' 天',
|
||||
];
|
||||
}
|
||||
if (count($users) >= $count) break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'followers':
|
||||
if (class_exists('\AKSRT\User\Follow')) {
|
||||
global $wpdb;
|
||||
@@ -157,6 +216,8 @@ class WidgetUserRanking extends \WP_Widget {
|
||||
<option value="credits" <?php selected($rank_by, 'credits'); ?>><?php esc_html_e('积分', 'aksrt'); ?></option>
|
||||
<option value="posts" <?php selected($rank_by, 'posts'); ?>><?php esc_html_e('文章数', 'aksrt'); ?></option>
|
||||
<option value="followers" <?php selected($rank_by, 'followers'); ?>><?php esc_html_e('粉丝数', 'aksrt'); ?></option>
|
||||
<option value="checkin_all_day" <?php selected($rank_by, 'checkin_all_day'); ?>><?php esc_html_e('累计签到', 'aksrt'); ?></option>
|
||||
<option value="checkin_continuous_day" <?php selected($rank_by, 'checkin_continuous_day'); ?>><?php esc_html_e('连续签到', 'aksrt'); ?></option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
@@ -169,15 +230,22 @@ class WidgetUserRanking extends \WP_Widget {
|
||||
<?php esc_html_e('显示头像', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" name="<?php echo esc_attr($this->get_field_name('checkin_btn')); ?>" value="1" <?php checked(!empty($instance['checkin_btn'])); ?>>
|
||||
<?php esc_html_e('顶部显示签到按钮', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$instance = [];
|
||||
$instance['title'] = sanitize_text_field($new_instance['title'] ?? '');
|
||||
$instance['rank_by'] = in_array($new_instance['rank_by'] ?? '', ['credits', 'posts', 'followers'], true) ? $new_instance['rank_by'] : 'credits';
|
||||
$instance['rank_by'] = in_array($new_instance['rank_by'] ?? '', ['credits', 'posts', 'followers', 'checkin_all_day', 'checkin_continuous_day'], true) ? $new_instance['rank_by'] : 'credits';
|
||||
$instance['count'] = max(1, min(20, (int) ($new_instance['count'] ?? 5)));
|
||||
$instance['show_avatar'] = !empty($new_instance['show_avatar']);
|
||||
$instance['checkin_btn'] = !empty($new_instance['checkin_btn']);
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Video player widget (zibll dplayer lite via native video / oEmbed).
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
@@ -9,124 +11,123 @@ defined('ABSPATH') || exit;
|
||||
|
||||
class WidgetVideoPlayer extends \WP_Widget {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_video_player',
|
||||
__('视频播放器', 'aksrt'),
|
||||
['description' => __('在侧栏嵌入视频播放器。', 'aksrt')]
|
||||
);
|
||||
}
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'aksrt_video_player',
|
||||
__('视频播放器', 'aksrt'),
|
||||
['description' => __('侧栏/流体区嵌入视频播放器。', 'aksrt')]
|
||||
);
|
||||
}
|
||||
|
||||
public function widget($args, $instance): void {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : '';
|
||||
$video_url = !empty($instance['video_url']) ? $instance['video_url'] : '';
|
||||
$poster = !empty($instance['poster']) ? $instance['poster'] : '';
|
||||
$autoplay = !empty($instance['autoplay']);
|
||||
$aspect_ratio = !empty($instance['aspect_ratio']) ? $instance['aspect_ratio'] : '16:9';
|
||||
public function widget($args, $instance): void {
|
||||
$title = (string) ($instance['title'] ?? '');
|
||||
$video_url = trim((string) ($instance['video_url'] ?? $instance['url'] ?? ''));
|
||||
$poster = trim((string) ($instance['poster'] ?? $instance['pic'] ?? ''));
|
||||
$autoplay = !empty($instance['autoplay']);
|
||||
$loop = !empty($instance['loop']);
|
||||
$muted = $autoplay || !empty($instance['muted']);
|
||||
$hide_controller = !empty($instance['hide_controller']);
|
||||
$scale = max(20, min(100, (int) ($instance['scale_height'] ?? 56)));
|
||||
$aspect = (string) ($instance['aspect_ratio'] ?? '');
|
||||
|
||||
if (empty($video_url)) return;
|
||||
if ($video_url === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析视频类型
|
||||
$embed_url = $this->get_embed_url($video_url);
|
||||
$is_embed = !empty($embed_url);
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
if ($title !== '') {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
echo $args['before_widget'];
|
||||
if ($aspect !== '' && str_contains($aspect, ':')) {
|
||||
$parts = explode(':', $aspect);
|
||||
if (count($parts) === 2 && (int) $parts[0] > 0) {
|
||||
$scale = (int) round(((int) $parts[1] / (int) $parts[0]) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
if ($title) {
|
||||
echo $args['before_title'] . esc_html($title) . $args['after_title'];
|
||||
}
|
||||
$embed = $this->get_embed_url($video_url);
|
||||
$cls = 'aksrt-video-widget' . ($hide_controller ? ' controller-hide' : '');
|
||||
echo '<div class="' . esc_attr($cls) . '" style="padding-bottom:' . esc_attr((string) $scale) . '%">';
|
||||
if ($embed !== '') {
|
||||
$src = $embed;
|
||||
if ($autoplay) {
|
||||
$src = add_query_arg(['autoplay' => '1', 'mute' => '1'], $src);
|
||||
}
|
||||
echo '<iframe src="' . esc_url($src) . '" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen loading="lazy"></iframe>';
|
||||
} else {
|
||||
$attrs = ' controls playsinline';
|
||||
if ($autoplay) {
|
||||
$attrs .= ' autoplay';
|
||||
}
|
||||
if ($loop) {
|
||||
$attrs .= ' loop';
|
||||
}
|
||||
if ($muted) {
|
||||
$attrs .= ' muted';
|
||||
}
|
||||
if ($poster !== '') {
|
||||
$attrs .= ' poster="' . esc_url($poster) . '"';
|
||||
}
|
||||
echo '<video' . $attrs . '><source src="' . esc_url($video_url) . '"></video>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
// 计算 padding-bottom
|
||||
$ratio_parts = explode(':', $aspect_ratio);
|
||||
if (count($ratio_parts) === 2 && (int) $ratio_parts[1] > 0) {
|
||||
$padding = ((int) $ratio_parts[1] / (int) $ratio_parts[0]) * 100;
|
||||
} else {
|
||||
$padding = 56.25; // 16:9
|
||||
}
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
echo '<div class="aksrt-video-widget" style="padding-bottom: ' . esc_attr(number_format($padding, 4)) . '%;">';
|
||||
private function get_embed_url(string $url): string {
|
||||
if (preg_match('#(?:youtube\.com/watch\?v=|youtu\.be/)([A-Za-z0-9_-]+)#', $url, $m)) {
|
||||
return 'https://www.youtube.com/embed/' . rawurlencode($m[1]);
|
||||
}
|
||||
if (preg_match('#bilibili\.com/video/(BV[\w]+)#', $url, $m)) {
|
||||
return 'https://player.bilibili.com/player.html?bvid=' . rawurlencode($m[1]) . '&high_quality=1';
|
||||
}
|
||||
if (preg_match('#v\.qq\.com/.+?/([A-Za-z0-9]+)\.html#', $url, $m)) {
|
||||
return 'https://v.qq.com/txp/iframe/player.html?vid=' . rawurlencode($m[1]);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($is_embed) {
|
||||
echo '<iframe src="' . esc_url($embed_url) . '" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen' . (function_exists('aksrt_lazy_loading') ? aksrt_lazy_loading('widget') : ' loading="lazy"') . '></iframe>';
|
||||
} else {
|
||||
echo '<video' . ($autoplay ? ' autoplay' : '') . ' controls playsinline';
|
||||
if ($poster) echo ' poster="' . esc_url($poster) . '"';
|
||||
echo '>';
|
||||
echo '<source src="' . esc_url($video_url) . '">';
|
||||
echo '</video>';
|
||||
}
|
||||
public function form($instance): void {
|
||||
?>
|
||||
<p>
|
||||
<label><?php esc_html_e('标题', 'aksrt'); ?>
|
||||
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('视频 URL', 'aksrt'); ?>
|
||||
<input class="widefat" type="url" name="<?php echo esc_attr($this->get_field_name('video_url')); ?>" value="<?php echo esc_attr((string) ($instance['video_url'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('封面图 URL', 'aksrt'); ?>
|
||||
<input class="widefat" type="url" name="<?php echo esc_attr($this->get_field_name('poster')); ?>" value="<?php echo esc_attr((string) ($instance['poster'] ?? '')); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><?php esc_html_e('高度占比 %', 'aksrt'); ?>
|
||||
<input class="tiny-text" type="number" min="20" max="100" name="<?php echo esc_attr($this->get_field_name('scale_height')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['scale_height'] ?? 56))); ?>">
|
||||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('autoplay')); ?>" value="1" <?php checked(!empty($instance['autoplay'])); ?>> <?php esc_html_e('自动播放', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('loop')); ?>" value="1" <?php checked(!empty($instance['loop'])); ?>> <?php esc_html_e('循环', 'aksrt'); ?></label><br>
|
||||
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('hide_controller')); ?>" value="1" <?php checked(!empty($instance['hide_controller'])); ?>> <?php esc_html_e('隐藏控制条样式', 'aksrt'); ?></label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
echo $args['after_widget'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 YouTube / Bilibili 链接为嵌入 URL
|
||||
*/
|
||||
private function get_embed_url(string $url): string {
|
||||
// YouTube
|
||||
if (preg_match('/(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]+)/', $url, $m)) {
|
||||
return 'https://www.youtube.com/embed/' . $m[1];
|
||||
}
|
||||
|
||||
// Bilibili
|
||||
if (preg_match('/bilibili\.com\/video\/(BV[a-zA-Z0-9]+)/', $url, $m)) {
|
||||
return 'https://player.bilibili.com/player.html?bvid=' . $m[1] . '&high_quality=1';
|
||||
}
|
||||
|
||||
// 腾讯视频
|
||||
if (preg_match('/v\.qq\.com\/x\/page\/([a-zA-Z0-9]+)/', $url, $m)) {
|
||||
return 'https://v.qq.com/txp/iframe/player.html?vid=' . $m[1];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function form($instance): void {
|
||||
$title = !empty($instance['title']) ? $instance['title'] : '';
|
||||
$video_url = !empty($instance['video_url']) ? $instance['video_url'] : '';
|
||||
$poster = !empty($instance['poster']) ? $instance['poster'] : '';
|
||||
$autoplay = !empty($instance['autoplay']);
|
||||
$aspect_ratio = !empty($instance['aspect_ratio']) ? $instance['aspect_ratio'] : '16:9';
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php esc_html_e('标题(可选):', 'aksrt'); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text" value="<?php echo esc_attr($title); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('video_url')); ?>"><?php esc_html_e('视频 URL:', 'aksrt'); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('video_url')); ?>" name="<?php echo esc_attr($this->get_field_name('video_url')); ?>" type="url" value="<?php echo esc_attr($video_url); ?>" placeholder="https://...">
|
||||
<small><?php esc_html_e('支持 MP4、YouTube、Bilibili、腾讯视频链接', 'aksrt'); ?></small>
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('poster')); ?>"><?php esc_html_e('封面图 URL:', 'aksrt'); ?></label>
|
||||
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('poster')); ?>" name="<?php echo esc_attr($this->get_field_name('poster')); ?>" type="url" value="<?php echo esc_attr($poster); ?>">
|
||||
</p>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr($this->get_field_id('aspect_ratio')); ?>"><?php esc_html_e('宽高比:', 'aksrt'); ?></label>
|
||||
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('aspect_ratio')); ?>" name="<?php echo esc_attr($this->get_field_name('aspect_ratio')); ?>">
|
||||
<option value="16:9" <?php selected($aspect_ratio, '16:9'); ?>>16:9</option>
|
||||
<option value="4:3" <?php selected($aspect_ratio, '4:3'); ?>>4:3</option>
|
||||
<option value="1:1" <?php selected($aspect_ratio, '1:1'); ?>>1:1</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label>
|
||||
<input type="checkbox" id="<?php echo esc_attr($this->get_field_id('autoplay')); ?>" name="<?php echo esc_attr($this->get_field_name('autoplay')); ?>" value="1" <?php checked($autoplay); ?>>
|
||||
<?php esc_html_e('自动播放(仅 MP4)', 'aksrt'); ?>
|
||||
</label>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function update($new_instance, $old_instance): array {
|
||||
$instance = [];
|
||||
$instance['title'] = sanitize_text_field($new_instance['title'] ?? '');
|
||||
$instance['video_url'] = esc_url_raw($new_instance['video_url'] ?? '');
|
||||
$instance['poster'] = esc_url_raw($new_instance['poster'] ?? '');
|
||||
$instance['autoplay'] = !empty($new_instance['autoplay']);
|
||||
$instance['aspect_ratio'] = in_array($new_instance['aspect_ratio'] ?? '', ['16:9', '4:3', '1:1'], true) ? $new_instance['aspect_ratio'] : '16:9';
|
||||
return $instance;
|
||||
}
|
||||
public function update($new_instance, $old_instance): array {
|
||||
return [
|
||||
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
|
||||
'video_url' => esc_url_raw(trim((string) ($new_instance['video_url'] ?? ''))),
|
||||
'poster' => esc_url_raw(trim((string) ($new_instance['poster'] ?? ''))),
|
||||
'scale_height' => max(20, min(100, (int) ($new_instance['scale_height'] ?? 56))),
|
||||
'autoplay' => !empty($new_instance['autoplay']) ? 1 : 0,
|
||||
'loop' => !empty($new_instance['loop']) ? 1 : 0,
|
||||
'hide_controller' => !empty($new_instance['hide_controller']) ? 1 : 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,10 @@ $address_book = is_array($cart_view['address_book'] ?? null) ? $cart_view['addre
|
||||
?>
|
||||
|
||||
<main id="main-content" class="site-main content-shell" tabindex="-1">
|
||||
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
||||
<?php if (is_active_sidebar('shop_cart_top_fluid')) : ?>
|
||||
<div class="aksrt-fluid-widget aksrt-fluid-widget--shop"><?php dynamic_sidebar('shop_cart_top_fluid'); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
||||
|
||||
<div
|
||||
class="aksrt-cart-page container"
|
||||
@@ -283,4 +286,7 @@ $address_book = is_array($cart_view['address_book'] ?? null) ? $cart_view['addre
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php if (is_active_sidebar('shop_cart_bottom_fluid')) : ?>
|
||||
<div class="aksrt-fluid-widget aksrt-fluid-widget--shop"><?php dynamic_sidebar('shop_cart_bottom_fluid'); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php get_footer(); ?>
|
||||
|
||||
@@ -55,6 +55,9 @@ $tabs = [
|
||||
];
|
||||
?>
|
||||
|
||||
<?php if (is_active_sidebar('shop_order_top_fluid')) : ?>
|
||||
<div class="aksrt-fluid-widget aksrt-fluid-widget--shop"><?php dynamic_sidebar('shop_order_top_fluid'); ?></div>
|
||||
<?php endif; ?>
|
||||
<main id="main-content" class="site-main content-shell" tabindex="-1">
|
||||
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
||||
<div class="container aksrt-orders-page" data-aksrt-order-center>
|
||||
@@ -369,4 +372,7 @@ $tabs = [
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php if (is_active_sidebar('shop_order_bottom_fluid')) : ?>
|
||||
<div class="aksrt-fluid-widget aksrt-fluid-widget--shop"><?php dynamic_sidebar('shop_order_bottom_fluid'); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php get_footer(); ?>
|
||||
|
||||
@@ -38,11 +38,15 @@ $author = $author_id > 0 ? get_userdata($author_id) : null;
|
||||
?>
|
||||
|
||||
<main id="main-content" class="site-main content-shell content-shell--stream content-shell--product" tabindex="-1">
|
||||
<?php if (is_active_sidebar('shop_product_top_fluid')) : ?>
|
||||
<div class="aksrt-fluid-widget aksrt-fluid-widget--shop"><?php dynamic_sidebar('shop_product_top_fluid'); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
||||
|
||||
<?php if (!empty($product)) : ?>
|
||||
<div class="content-wrap container">
|
||||
<div class="content-layout content-layout--no-sidebar">
|
||||
<?php $has_shop_sidebar = is_active_sidebar('shop_product_sidebar'); ?>
|
||||
<div class="content-layout <?php echo $has_shop_sidebar ? 'content-layout--with-sidebar' : 'content-layout--no-sidebar'; ?>">
|
||||
<div class="content-layout__primary">
|
||||
<div
|
||||
class="aksrt-product-page"
|
||||
@@ -431,8 +435,16 @@ $author = $author_id > 0 ? get_userdata($author_id) : null;
|
||||
|
||||
</div><!-- .aksrt-product-page -->
|
||||
</div><!-- .content-layout__primary -->
|
||||
<?php if (!empty($has_shop_sidebar)) : ?>
|
||||
<aside class="content-layout__sidebar aksrt-shop-widget-zone">
|
||||
<?php dynamic_sidebar('shop_product_sidebar'); ?>
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
</div><!-- .content-layout -->
|
||||
</div><!-- .content-wrap -->
|
||||
<?php if (is_active_sidebar('shop_product_bottom_fluid')) : ?>
|
||||
<div class="aksrt-fluid-widget aksrt-fluid-widget--shop"><?php dynamic_sidebar('shop_product_bottom_fluid'); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Mobile purchase tabbar -->
|
||||
<div class="aksrt-product-page__mobile-bar" data-aksrt-mobile-purchase>
|
||||
|
||||
@@ -9,6 +9,12 @@ defined('ABSPATH') || exit;
|
||||
|
||||
get_header();
|
||||
|
||||
if (is_active_sidebar('shop_home_top_fluid')) {
|
||||
echo '<div class="aksrt-fluid-widget aksrt-fluid-widget--shop">';
|
||||
dynamic_sidebar('shop_home_top_fluid');
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
$term = get_queried_object();
|
||||
$paged = max(1, (int) get_query_var('paged'));
|
||||
$orderby = '';
|
||||
@@ -141,4 +147,9 @@ wp_enqueue_script(
|
||||
AKSRT_VERSION,
|
||||
true
|
||||
);
|
||||
if (is_active_sidebar('shop_product_bottom_fluid')) {
|
||||
echo '<div class="aksrt-fluid-widget aksrt-fluid-widget--shop">';
|
||||
dynamic_sidebar('shop_product_bottom_fluid');
|
||||
echo '</div>';
|
||||
}
|
||||
get_footer();
|
||||
|
||||
@@ -9,6 +9,12 @@ defined('ABSPATH') || exit;
|
||||
|
||||
get_header();
|
||||
|
||||
if (is_active_sidebar('shop_home_top_fluid')) {
|
||||
echo '<div class="aksrt-fluid-widget aksrt-fluid-widget--shop">';
|
||||
dynamic_sidebar('shop_home_top_fluid');
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
$term = get_queried_object();
|
||||
$paged = max(1, (int) get_query_var('paged'));
|
||||
$orderby = '';
|
||||
@@ -165,4 +171,9 @@ wp_enqueue_script(
|
||||
AKSRT_VERSION,
|
||||
true
|
||||
);
|
||||
if (is_active_sidebar('shop_product_bottom_fluid')) {
|
||||
echo '<div class="aksrt-fluid-widget aksrt-fluid-widget--shop">';
|
||||
dynamic_sidebar('shop_product_bottom_fluid');
|
||||
echo '</div>';
|
||||
}
|
||||
get_footer();
|
||||
|
||||
Reference in New Issue
Block a user