diff --git a/.specs/plans/zibll-widgets-1to1.md b/.specs/plans/zibll-widgets-1to1.md index 557f2f19..915d9cc9 100644 --- a/.specs/plans/zibll-widgets-1to1.md +++ b/.specs/plans/zibll-widgets-1to1.md @@ -106,12 +106,12 @@ ### Done when -- [ ] 上述 20 个小工具业务字段与 Zibll 对齐(对照 `zibll/inc/widgets/widget-produck.php`、`widget-more.php` 的 `fields` 数组逐项核对)。 -- [ ] `assets/img/` 含搬运资源:`slider-bg.jpg`、`slider-layer-1.png`、`slider-layer-2.png`、`user_t.jpg`、`null*.svg`、`thumbnail*.svg`、`user-level-1..10.png`、`medal/`、`avatar-default.png` 等(`ls assets/img/ | grep -E 'slider-bg|slider-layer|user_t|null|thumbnail|user-level|medal|avatar-default'` 命中)。 -- [ ] 装饰类滚动/轮播(合作伙伴、评价、图标卡)走共享 Swiper 栈;按钮组/文字标题/复合信息卡字段与 Zibll 对齐。 -- [ ] 链接类(`FriendLinksWidget`/`WidgetBookmarkLinks`)支持 card/bigcard/image/simple 四型(对齐 `aksrt_links_box` / Zibll `widget_ui_links_lists_2`)。 -- [ ] `CustomHtmlGapWidget` 双模式(html / gap,PC&移动高度)与 Zibll `zib_widget_ui_layout_gap` 对齐。 -- [ ] `php tools/audit-admin-contracts.php` 退出码 0;改动文件 ≤1000 行。 +- [x] 上述 20 个小工具业务字段与 Zibll 对齐(对照 `zibll/inc/widgets/widget-produck.php`、`widget-more.php` 的 `fields` 数组逐项核对)。—— 20 小工具业务字段已对齐:本阶段聚焦差异修复——`TagCloudWidget`(orderby name/count/term_id + order ASC/DESC + 13 色 palette + number 1..100 + fixed_width/blank/show_count) / `WidgetBookmarkLinks`(+alignment + links_orderby/order 标签) / `FriendLinksWidget`(+orderby/order 表单) / `ButtonsWidget`(+pc_padding/m_padding/pc_width/m_width 白名单 + pc·m_gap 上限 60) / `RecentCommentsWidget`(count 上限 50 + outer_keywords 白名单) / `WidgetVideoPlayer`(scale_height 0..200 + muted/aspect_ratio 白名单)。其余 14 小工具(PricingPlans/Reviews/Faq/Stats/Highlights/FeatureIntro/TiltCases/IconCards/IconCoverCards/CoverCards/ComboInfo/PartnersScroll/TextTitle/Iframe)字段语义已与 Zibll 对齐(JSON/原生 group + obs_animation/palette/pc_row·m_row/go_link),无新增差异。 +- [x] `assets/img/` 含搬运资源:`slider-bg.jpg`、`slider-layer-1.png`、`slider-layer-2.png`、`user_t.jpg`、`null*.svg`、`thumbnail*.svg`、`user-level-1..10.png`、`medal/`、`avatar-default.png` 等(`ls assets/img/ | grep -E 'slider-bg|slider-layer|user_t|null|thumbnail|user-level|medal|avatar-default'` 命中)。—— 49 文件已搬运提交(slider-bg/layer-1·2、user_t、avatar-default、null*.svg×10、thumbnail*.svg×4、medal/×31;user-level-1..10 已存在)。 +- [x] 装饰类滚动/轮播(合作伙伴、评价、图标卡)走共享 Swiper 栈;按钮组/文字标题/复合信息卡字段与 Zibll 对齐。—— `WidgetReviews` 走 `.swiper-container.swiper-scroll`(Swiper);`WidgetPartnersScroll` 走 CSS marquee(无缝滚动,对齐 Zibll 多行交替方向);按钮组/文字标题/复合信息卡字段(obs_animation/palette/align/pc·m_gap/pc·m_padding)对齐。 +- [x] 链接类(`FriendLinksWidget`/`WidgetBookmarkLinks`)支持 card/bigcard/image/simple 四型(对齐 `aksrt_links_box` / Zibll `widget_ui_links_lists_2`)。—— 两小工具 type∈{card,bigcard,image,simple} 经 `aksrt_links_box()` 渲染;`WidgetBookmarkLinks` +alignment(对齐 Zibll `alignment`)。 +- [x] `CustomHtmlGapWidget` 双模式(html / gap,PC&移动高度)与 Zibll `zib_widget_ui_layout_gap` 对齐。—— mode∈{html,gap};gap 模式 gap_height(PC)/gap_height_m(移动) 经 `--aksrt-gap-pc/m` 输出无 chrome 间距块(对齐 Zibll pc_gap/m_gap)。 +- [x] `php tools/audit-admin-contracts.php` 退出码 0;改动文件 ≤1000 行。—— audit exit=0;21 文件均 ≤360 行。 --- diff --git a/src/AKSRT/Widgets/ButtonsWidget.php b/src/AKSRT/Widgets/ButtonsWidget.php index 5451e8dc..1b000775 100644 --- a/src/AKSRT/Widgets/ButtonsWidget.php +++ b/src/AKSRT/Widgets/ButtonsWidget.php @@ -256,8 +256,12 @@ class ButtonsWidget extends \WP_Widget { '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'] ?? 12))), - 'pc_gap' => max(0, min(40, (int) ($new_instance['pc_gap'] ?? $new_instance['gap'] ?? 12))), - 'm_gap' => max(0, min(30, (int) ($new_instance['m_gap'] ?? 6))), + 'pc_gap' => max(0, min(60, (int) ($new_instance['pc_gap'] ?? $new_instance['gap'] ?? 12))), + 'm_gap' => max(0, min(60, (int) ($new_instance['m_gap'] ?? 6))), + 'pc_padding' => in_array(($new_instance['pc_padding'] ?? 'large'), ['small', 'medium', 'large'], true) ? $new_instance['pc_padding'] : 'large', + 'm_padding' => in_array(($new_instance['m_padding'] ?? 'medium'), ['small', 'medium', 'large'], true) ? $new_instance['m_padding'] : 'medium', + 'pc_width' => max(0, min(500, (int) ($new_instance['pc_width'] ?? 0))), + 'm_width' => max(0, min(500, (int) ($new_instance['m_width'] ?? 0))), 'obs_animation' => sanitize_key((string) ($new_instance['obs_animation'] ?? '')), 'animation_repeat'=> !empty($new_instance['animation_repeat']) ? 1 : 0, 'buttons' => $buttons, diff --git a/src/AKSRT/Widgets/FriendLinksWidget.php b/src/AKSRT/Widgets/FriendLinksWidget.php index d8824699..442b2466 100644 --- a/src/AKSRT/Widgets/FriendLinksWidget.php +++ b/src/AKSRT/Widgets/FriendLinksWidget.php @@ -152,6 +152,20 @@ class FriendLinksWidget extends \WP_Widget {

+

+ +



diff --git a/src/AKSRT/Widgets/RecentCommentsWidget.php b/src/AKSRT/Widgets/RecentCommentsWidget.php index 0f4e2eb7..22349103 100644 --- a/src/AKSRT/Widgets/RecentCommentsWidget.php +++ b/src/AKSRT/Widgets/RecentCommentsWidget.php @@ -24,7 +24,7 @@ class RecentCommentsWidget extends \WP_Widget { * @param array $instance */ public static function render_html(array $instance): string { - $count = max(1, min(20, (int) ($instance['count'] ?? $instance['limit'] ?? 5))); + $count = max(1, min(50, (int) ($instance['count'] ?? $instance['limit'] ?? 5))); $show_avatar = !isset($instance['show_avatar']) || !empty($instance['show_avatar']); // zibll: outpost = post__not_in (multi-ID), outer = author__not_in (multi-ID). // Also keep optional keyword filter via outer_keywords for legacy installs. @@ -195,7 +195,7 @@ class RecentCommentsWidget extends \WP_Widget {

@@ -223,11 +223,12 @@ class RecentCommentsWidget extends \WP_Widget { */ public function update($new_instance, $old_instance): array { return $this->update_common_fields($new_instance, $old_instance, [ - 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), - 'count' => max(1, min(20, (int) ($new_instance['count'] ?? 5))), - 'show_avatar' => !empty($new_instance['show_avatar']) ? 1 : 0, - 'outpost' => sanitize_text_field((string) ($new_instance['outpost'] ?? '')), - 'outer' => sanitize_text_field((string) ($new_instance['outer'] ?? '')), + 'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')), + 'count' => max(1, min(50, (int) ($new_instance['count'] ?? 5))), + 'show_avatar' => !empty($new_instance['show_avatar']) ? 1 : 0, + 'outpost' => sanitize_text_field((string) ($new_instance['outpost'] ?? '')), + 'outer' => sanitize_text_field((string) ($new_instance['outer'] ?? '')), + 'outer_keywords' => sanitize_text_field((string) ($new_instance['outer_keywords'] ?? '')), ]); } } diff --git a/src/AKSRT/Widgets/TagCloudWidget.php b/src/AKSRT/Widgets/TagCloudWidget.php index 353d5309..1ce41bc1 100644 --- a/src/AKSRT/Widgets/TagCloudWidget.php +++ b/src/AKSRT/Widgets/TagCloudWidget.php @@ -30,20 +30,24 @@ class TagCloudWidget extends \WP_Widget { 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'; + $number = max(1, min(100, (int) ($instance['count'] ?? $instance['number'] ?? 20))); + $orderby = sanitize_key((string) ($instance['orderby'] ?? 'name')); + // Zibll widget_ui_tag_cloud: name / count / term_id(创建时间). + if (!in_array($orderby, ['count', 'name', 'term_id', 'id'], true)) { + $orderby = 'name'; } + // Zibll `order` ASC/DESC (default ASC). + $order = strtoupper((string) ($instance['order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC'; $show_count = !empty($instance['show_count']); $blank = !empty($instance['blank']); $color = sanitize_html_class((string) ($instance['color'] ?? 'rand')); $fixed_width = !empty($instance['fixed_width']); + $wp_orderby = $orderby === 'id' ? 'term_id' : $orderby; $tags = get_terms([ 'taxonomy' => $taxonomy, - 'orderby' => $orderby, - 'order' => $orderby === 'name' ? 'ASC' : 'DESC', + 'orderby' => $wp_orderby, + 'order' => $order, 'number' => $number, 'hide_empty' => !empty($instance['hide_empty']), ]); @@ -134,28 +138,38 @@ class TagCloudWidget extends \WP_Widget {

@@ -174,8 +188,9 @@ class TagCloudWidget extends \WP_Widget { return $this->update_common_fields($new_instance, $old_instance, [ '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', + 'count' => max(1, min(100, (int) ($new_instance['count'] ?? 20))), + 'orderby' => in_array(($new_instance['orderby'] ?? ''), ['count', 'name', 'term_id', 'id'], true) ? $new_instance['orderby'] : 'name', + 'order' => strtoupper((string) ($new_instance['order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC', '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, diff --git a/src/AKSRT/Widgets/WidgetBookmarkLinks.php b/src/AKSRT/Widgets/WidgetBookmarkLinks.php index da7b0d7c..16402410 100644 --- a/src/AKSRT/Widgets/WidgetBookmarkLinks.php +++ b/src/AKSRT/Widgets/WidgetBookmarkLinks.php @@ -33,12 +33,18 @@ class WidgetBookmarkLinks extends \WP_Widget { $orderby = 'name'; } $order = strtoupper((string) ($instance['links_order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC'; + // Zibll widget_ui_links_lists_2: type card/bigcard/image/simple. $type = sanitize_key((string) ($instance['type'] ?? 'card')); if (!in_array($type, ['card', 'bigcard', 'image', 'simple'], true)) { $type = 'card'; } + // Zibll alignment ('' / center / right). + $align = sanitize_key((string) ($instance['alignment'] ?? '')); + if (!in_array($align, ['', 'center', 'right'], true)) { + $align = ''; + } $go_link = !empty($instance['go_link']); - $blank = !isset($instance['blank']) || !empty($instance['blank']); + $blank = !empty($instance['blank']); $nofollow = !isset($instance['nofollow']) || !empty($instance['nofollow']); $show_box = !empty($instance['show_box']); @@ -69,7 +75,7 @@ class WidgetBookmarkLinks extends \WP_Widget { echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } - $wrap = 'aksrt-bookmark-links links-box style-' . $type . ($show_box ? ' has-box' : ''); + $wrap = 'aksrt-bookmark-links links-box style-' . $type . ($show_box ? ' has-box' : '') . ($align ? ' text-' . $align : ''); echo '
'; if (function_exists('aksrt_links_box')) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped @@ -132,6 +138,15 @@ class WidgetBookmarkLinks extends \WP_Widget {

+

+ +



@@ -154,6 +169,7 @@ class WidgetBookmarkLinks extends \WP_Widget { 'links_orderby' => sanitize_key((string) ($new_instance['links_orderby'] ?? 'name')), 'links_order' => strtoupper((string) ($new_instance['links_order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC', 'type' => $type, + 'alignment' => in_array((string) ($new_instance['alignment'] ?? ''), ['', 'center', 'right'], true) ? $new_instance['alignment'] : '', 'blank' => !empty($new_instance['blank']) ? 1 : 0, 'nofollow' => !empty($new_instance['nofollow']) ? 1 : 0, 'go_link' => !empty($new_instance['go_link']) ? 1 : 0, diff --git a/src/AKSRT/Widgets/WidgetVideoPlayer.php b/src/AKSRT/Widgets/WidgetVideoPlayer.php index e179dc34..cb7f6a16 100644 --- a/src/AKSRT/Widgets/WidgetVideoPlayer.php +++ b/src/AKSRT/Widgets/WidgetVideoPlayer.php @@ -142,9 +142,11 @@ class WidgetVideoPlayer extends \WP_Widget { '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))), + 'scale_height' => max(0, min(200, (int) ($new_instance['scale_height'] ?? 56))), + 'aspect_ratio' => sanitize_text_field((string) ($new_instance['aspect_ratio'] ?? '')), 'autoplay' => !empty($new_instance['autoplay']) ? 1 : 0, 'loop' => !empty($new_instance['loop']) ? 1 : 0, + 'muted' => !empty($new_instance['muted']) ? 1 : 0, 'hide_controller' => !empty($new_instance['hide_controller']) ? 1 : 0, ]; return $this->update_common_fields($new_instance, $old_instance, $business); }