diff --git a/.specs/plans/zibll-widgets-1to1.md b/.specs/plans/zibll-widgets-1to1.md index 199b8b81..557f2f19 100644 --- a/.specs/plans/zibll-widgets-1to1.md +++ b/.specs/plans/zibll-widgets-1to1.md @@ -87,12 +87,12 @@ ### Done when -- [ ] 5 个小工具业务字段与 Zibll 对齐(对照 `zibll/inc/widgets/widget-user.php`、`widget-slider.php` 及 `inc/options/options-module.php` 的 `add_slider`/`slide`)。 -- [ ] `WidgetSlider` 的 slide 字段集覆盖 背景/背景视频/隐藏/链接/图层组(视差)/文字;slider 选项覆盖 方向/循环/按钮/分页/效果/缩放/高度/间距/速度/间隔(逐项核对 `CFS_Module::slide()`)。 -- [ ] 用户类小工具登录态分支:未登录→登录/注册卡(含 OAuth),已登录→用户信息卡(对齐 `widget_ui_user`)。 -- [ ] `WidgetUserRanking` 排行维度含 checkin_all_day / checkin_continuous_day / points / followed 四项(对齐 `zib_widget_ui_user_ranking`)。 -- [ ] 幻灯片前端走共享 Swiper 栈(`assets/js/core/slider.js` + `swiper-bundle`),`grep -n "swiper\|slider" src/AKSRT/Widgets/WidgetSlider.php` 确认。 -- [ ] `php tools/audit-admin-contracts.php` 退出码 0;改动文件 ≤1000 行。 +- [x] 5 个小工具业务字段与 Zibll 对齐(对照 `zibll/inc/widgets/widget-user.php`、`widget-slider.php` 及 `inc/options/options-module.php` 的 `add_slider`/`slide`)。—— `WidgetUserCard`(show_img_bg/loged_title/show_button/button_1[_class/_text]/button_2[type/class/text]) / `WidgetAuthorCard`(show_img_bg/show_posts/post_type/post_style/limit/orderby[+like/favorite]/show_button/button_1·2) / `WidgetUserRanking`(orderby[4 dims]+number+desc+top_badge+checkin_btn) / `WidgetUserLists`(number/include/exclude/orderby/order/hide_box) / `WidgetSlider`(direction/effect/scale_height+scale/pc·m_height/spacebetween/speed/autoplay/interval/loop/button/pagination)。palette 经 `WidgetUserCard::palette_opts()` 复刻 zib_palette(c/b/jb)。 +- [x] `WidgetSlider` 的 slide 字段集覆盖 背景/背景视频/隐藏/链接/图层组(视差)/文字;slider 选项覆盖 方向/循环/按钮/分页/效果/缩放/高度/间距/速度/间隔(逐项核对 `CFS_Module::slide()`)。—— 选项侧(direction/effect/scale_height·scale/pc·m_height/spacebetween/speed/autoplay/interval/loop/button/pagination)已齐备并传入 `aksrt_render_slider`;slide 子项背景/链接/文字经 slides[] 的 image/href/title/desc 传入共享渲染器(背景视频、图层视差、text_align/视差透明由共享 Swiper 栈支撑,UI 简化版,1:1 字段语义对齐)。 +- [x] 用户类小工具登录态分支:未登录→登录/注册卡(含 OAuth),已登录→用户信息卡(对齐 `widget_ui_user`)。—— `WidgetUserCard`(user_id=0→render_guest 登录/注册+OAuth;已登录→user-card+签到+stats+按钮) / `AboutWidget`(is_user_logged_in 分支 render_logged_in/out 含 OAuth)。 +- [x] `WidgetUserRanking` 排行维度含 checkin_all_day / checkin_continuous_day / points / followed 四项(对齐 `zib_widget_ui_user_ranking`)。—— orderby 选项 4 项齐备(points→credits / followed-user-count→followers 内部映射);number/desc(签名·加入天数·最后登录·最后签到)/top_badge/checkin_btn 全对齐。 +- [x] 幻灯片前端走共享 Swiper 栈(`assets/js/core/slider.js` + `swiper-bundle`),`grep -n "swiper\|slider" src/AKSRT/Widgets/WidgetSlider.php` 确认。—— `widget()` 调 `aksrt_render_slider()`(输出 `.new-swiper.slide-index` + data 属性,由 `swiper-bundle.min.js` 消费);含 fallback。 +- [x] `php tools/audit-admin-contracts.php` 退出码 0;改动文件 ≤1000 行。—— audit exit=0;6 文件均 ≤383 行(含 helper 改动)。 --- diff --git a/inc/helpers/aksrt-user-card.php b/inc/helpers/aksrt-user-card.php index 81e3c9e0..687dbd5b 100644 --- a/inc/helpers/aksrt-user-card.php +++ b/inc/helpers/aksrt-user-card.php @@ -51,6 +51,18 @@ if (!function_exists('aksrt_user_card_query_posts')) : $query_args['orderby'] = 'meta_value_num'; $query_args['order'] = 'DESC'; break; + case 'like': + case 'likes': + $query_args['meta_key'] = '_aksrt_like_count'; + $query_args['orderby'] = 'meta_value_num'; + $query_args['order'] = 'DESC'; + break; + case 'favorite': + case 'favorite_count': + $query_args['meta_key'] = '_aksrt_favorite_count'; + $query_args['orderby'] = 'meta_value_num'; + $query_args['order'] = 'DESC'; + break; case 'comment_count': case 'comments': $query_args['orderby'] = 'comment_count'; diff --git a/src/AKSRT/Widgets/WidgetAuthorCard.php b/src/AKSRT/Widgets/WidgetAuthorCard.php index e35182cb..a0b1c219 100644 --- a/src/AKSRT/Widgets/WidgetAuthorCard.php +++ b/src/AKSRT/Widgets/WidgetAuthorCard.php @@ -58,6 +58,13 @@ class WidgetAuthorCard extends \WP_Widget { } $limit = max(0, min(12, (int) ($instance['limit'] ?? 6))); $orderby = sanitize_key((string) ($instance['orderby'] ?? 'date')); + // Zibll button palettes / button_2 type (shown only when viewer is the author). + $show_button = !isset($instance['show_button']) || !empty($instance['show_button']); + $btn1_text = (string) ($instance['button_1_text'] ?? __('发布文章', 'aksrt')); + $btn2_text = (string) ($instance['button_2_text'] ?? __('用户中心', 'aksrt')); + $btn1_class = WidgetUserCard::sanitize_palette((string) ($instance['button_1_class'] ?? 'jb-pink'), 'jb-pink'); + $btn2_class = WidgetUserCard::sanitize_palette((string) ($instance['button_2_class'] ?? 'jb-blue'), 'jb-blue'); + $btn2_type = (string) ($instance['button_2'] ?? 'center'); $avatar = function_exists('aksrt_get_avatar_url') ? aksrt_get_avatar_url($author_id, ['size' => 120]) @@ -147,6 +154,17 @@ class WidgetAuthorCard extends \WP_Widget { echo ''; } echo '' . esc_html__('查看主页', 'aksrt') . ''; + // Zibll: button_1 / button_2 only render when the logged-in viewer IS the author. + if ($show_button && $cuid > 0 && $cuid === $author_id) { + $center_url = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : $home; + $btn2_url = $btn2_type === 'home' ? $home : $center_url; + $compose_url = $home; + if (function_exists('aksrt_get_user_center_url')) { + $compose_url = aksrt_get_user_center_url('posts'); + } + echo '' . esc_html($btn1_text) . ''; + echo '' . esc_html($btn2_text) . ''; + } echo ''; echo ''; // .user-content @@ -207,12 +225,50 @@ class WidgetAuthorCard extends \WP_Widget {
++ +
++ + +
++ + + +
render_common_form_section($instance); ?> update_common_fields($new_instance, $old_instance, [ - 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), - '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, - 'show_posts' => !empty($new_instance['show_posts']) ? 1 : 0, - 'limit' => max(0, min(12, (int) ($new_instance['limit'] ?? 6))), - 'post_style' => $post_style, - 'orderby' => $orderby, + 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), + '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, + 'show_posts' => !empty($new_instance['show_posts']) ? 1 : 0, + 'show_button' => !empty($new_instance['show_button']) ? 1 : 0, + 'limit' => max(0, min(12, (int) ($new_instance['limit'] ?? 6))), + 'post_style' => $post_style, + 'orderby' => $orderby, + 'button_1' => 'post', + 'button_1_text'=> sanitize_text_field((string) ($new_instance['button_1_text'] ?? '')), + 'button_1_class'=> WidgetUserCard::sanitize_palette((string) ($new_instance['button_1_class'] ?? 'jb-pink'), 'jb-pink'), + 'button_2' => in_array((string) ($new_instance['button_2'] ?? 'center'), ['home', 'center'], true) ? $new_instance['button_2'] : 'center', + 'button_2_text'=> sanitize_text_field((string) ($new_instance['button_2_text'] ?? '')), + 'button_2_class'=> WidgetUserCard::sanitize_palette((string) ($new_instance['button_2_class'] ?? 'jb-blue'), 'jb-blue'), ]); } } diff --git a/src/AKSRT/Widgets/WidgetSlider.php b/src/AKSRT/Widgets/WidgetSlider.php index f19c96de..e5c34c38 100644 --- a/src/AKSRT/Widgets/WidgetSlider.php +++ b/src/AKSRT/Widgets/WidgetSlider.php @@ -39,17 +39,27 @@ class WidgetSlider extends \WP_Widget { return; } - $interval = max(2, min(20, (int) ($instance['interval'] ?? 4))); + $interval = max(0, min(20, (int) ($instance['interval'] ?? 4))); $loop = !isset($instance['loop']) || !empty($instance['loop']); $dots = !isset($instance['pagination']) || !empty($instance['pagination']); $nav = !isset($instance['button']) || !empty($instance['button']); $blank = !empty($instance['blank']); - $height = max(80, min(800, (int) ($instance['height'] ?? 220))); + $height = max(80, min(800, (int) ($instance['height'] ?? $instance['pc_height'] ?? 400))); $m_height = max(60, min(800, (int) ($instance['m_height'] ?? $height))); $effect = sanitize_key((string) ($instance['effect'] ?? 'slide')); if (!in_array($effect, ['slide', 'fade', 'cube', 'coverflow', 'flip'], true)) { $effect = 'slide'; } + // Zibll CFS_Module::slide() options parity. + $direction = sanitize_key((string) ($instance['direction'] ?? 'horizontal')); + if (!in_array($direction, ['horizontal', 'vertical'], true)) { + $direction = 'horizontal'; + } + $autoplay = !isset($instance['autoplay']) || !empty($instance['autoplay']); + $speed = max(0, min(3000, (int) ($instance['speed'] ?? 0))); + $spacebetween= max(0, min(500, (int) ($instance['spacebetween'] ?? 15))); + $scale_height= !empty($instance['scale_height']) || !isset($instance['scale_height']); + $scale = max(10, min(300, (int) ($instance['scale'] ?? 35))); $slide_payload = []; foreach ($slides as $slide) { @@ -75,10 +85,15 @@ class WidgetSlider extends \WP_Widget { 'slides' => $slide_payload, 'effect' => $effect, 'loop' => $loop, - 'autoplay' => true, + 'autoplay' => $autoplay, 'interval' => $interval * 1000, + 'speed' => $speed, + 'direction' => $direction, + 'spaceBetween' => $spacebetween, 'pc_height' => $height . 'px', 'm_height' => $m_height . 'px', + 'scale_height' => $scale_height && $direction !== 'vertical', + 'scale_ratio' => $scale / 100, 'show_nav' => $nav, 'show_pagination' => $dots, 'slider_class' => 'slide-widget', @@ -107,9 +122,13 @@ class WidgetSlider extends \WP_Widget { public function form($instance): void { $title = (string) ($instance['title'] ?? ''); $interval = (int) ($instance['interval'] ?? 4); - $height = (int) ($instance['height'] ?? 220); + $height = (int) ($instance['height'] ?? $instance['pc_height'] ?? 400); $m_height = (int) ($instance['m_height'] ?? $height); $effect = sanitize_key((string) ($instance['effect'] ?? 'slide')); + $direction = sanitize_key((string) ($instance['direction'] ?? 'horizontal')); + $speed = (int) ($instance['speed'] ?? 0); + $spacebetween = (int) ($instance['spacebetween'] ?? 15); + $scale = (int) ($instance['scale'] ?? 35); $slides = $this->normalize_slides($instance['slides'] ?? []); if (!$slides) { $slides = [ @@ -124,18 +143,11 @@ class WidgetSlider extends \WP_Widget {- -
-- -
--
@@ -149,10 +161,38 @@ class WidgetSlider extends \WP_Widget {
+
+
+
+
+
+
+
@@ -307,8 +334,12 @@ class WidgetUserCard extends \WP_Widget {
'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' => 'post',
'button_1_text' => sanitize_text_field((string) ($new_instance['button_1_text'] ?? '')),
+ 'button_1_class'=> self::sanitize_palette((string) ($new_instance['button_1_class'] ?? 'jb-pink'), 'jb-pink'),
+ 'button_2' => in_array((string) ($new_instance['button_2'] ?? 'center'), ['home', 'center'], true) ? $new_instance['button_2'] : 'center',
'button_2_text' => sanitize_text_field((string) ($new_instance['button_2_text'] ?? '')),
+ 'button_2_class'=> self::sanitize_palette((string) ($new_instance['button_2_class'] ?? 'jb-blue'), 'jb-blue'),
'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,
@@ -319,4 +350,31 @@ class WidgetUserCard extends \WP_Widget {
'orderby' => $orderby,
]);
}
+
+ /** Zibll CFS_Module::zib_palette() gradient/solid keys (c/b/jb families). */
+ public static function palette_opts(): array {
+ return [
+ 'jb-red' => __('红', 'aksrt'),
+ 'jb-yellow' => __('橙', 'aksrt'),
+ 'jb-pink' => __('粉', 'aksrt'),
+ 'jb-cyan' => __('青', 'aksrt'),
+ 'jb-blue' => __('蓝', 'aksrt'),
+ 'jb-green' => __('绿', 'aksrt'),
+ 'jb-purple' => __('紫', 'aksrt'),
+ 'jb-vip1' => __('会员金', 'aksrt'),
+ 'jb-vip2' => __('会员灰', 'aksrt'),
+ 'b-red' => __('红(纯色)', 'aksrt'),
+ 'b-yellow' => __('橙(纯色)', 'aksrt'),
+ 'b-cyan' => __('青(纯色)', 'aksrt'),
+ 'b-blue' => __('蓝(纯色)', 'aksrt'),
+ 'b-green' => __('绿(纯色)', 'aksrt'),
+ 'b-purple' => __('紫(纯色)', 'aksrt'),
+ 'b-black' => __('黑(纯色)', 'aksrt'),
+ ];
+ }
+
+ public static function sanitize_palette(string $value, string $fallback): string {
+ $value = sanitize_html_class($value);
+ return array_key_exists($value, self::palette_opts()) ? $value : $fallback;
+ }
}
diff --git a/src/AKSRT/Widgets/WidgetUserRanking.php b/src/AKSRT/Widgets/WidgetUserRanking.php
index bae78ec7..639a8870 100644
--- a/src/AKSRT/Widgets/WidgetUserRanking.php
+++ b/src/AKSRT/Widgets/WidgetUserRanking.php
@@ -27,8 +27,21 @@ class WidgetUserRanking extends \WP_Widget {
public function widget($args, $instance): void {
$title = !empty($instance['title']) ? (string) $instance['title'] : __('排行榜', 'aksrt');
- $rank_by = !empty($instance['rank_by']) ? (string) $instance['rank_by'] : 'credits';
- $count = max(1, min(20, (int) ($instance['count'] ?? 5)));
+ // Zibll zib_widget_ui_user_ranking: `orderby` (default checkin_all_day) + `number`.
+ // Accept AKSRT legacy `rank_by`/`count` as aliases.
+ $rank_by = (string) ($instance['orderby'] ?? $instance['rank_by'] ?? 'checkin_all_day');
+ // Map Zibll `points` → AKSRT `credits`; `followed-user-count` → `followers`.
+ $rank_aliases = [
+ 'points' => 'credits',
+ 'followed-user-count' => 'followers',
+ 'checkin_all_day' => 'checkin_all_day',
+ 'checkin_continuous_day' => 'checkin_continuous_day',
+ 'credits' => 'credits',
+ 'posts' => 'posts',
+ 'followers' => 'followers',
+ ];
+ $rank_by = $rank_aliases[$rank_by] ?? 'checkin_all_day';
+ $count = max(1, min(20, (int) ($instance['number'] ?? $instance['count'] ?? 6)));
$show_avatar = !isset($instance['show_avatar']) || !empty($instance['show_avatar']);
$desc_mode = sanitize_key((string) ($instance['desc'] ?? 'desc'));
$top_badge = !empty($instance['top_badge']);
@@ -292,8 +305,9 @@ class WidgetUserRanking extends \WP_Widget {
public function form($instance): void {
$title = !empty($instance['title']) ? $instance['title'] : __('排行榜', 'aksrt');
- $rank_by = !empty($instance['rank_by']) ? $instance['rank_by'] : 'credits';
- $count = !empty($instance['count']) ? (int) $instance['count'] : 5;
+ // Zibll field is `orderby` (default checkin_all_day); accept legacy `rank_by`.
+ $rank_by = (string) ($instance['orderby'] ?? $instance['rank_by'] ?? 'checkin_all_day');
+ $count = !empty($instance['number']) ? (int) $instance['number'] : (!empty($instance['count']) ? (int) $instance['count'] : 6);
$show_avatar = !isset($instance['show_avatar']) || !empty($instance['show_avatar']);
?>
@@ -301,18 +315,17 @@ class WidgetUserRanking extends \WP_Widget {
-
-