refactor: remove unused widgets

This commit is contained in:
2026-08-15 18:43:49 +08:00
parent 895b7b2014
commit 30b08282f5
10 changed files with 0 additions and 1979 deletions
-10
View File
@@ -36,10 +36,8 @@ function aksrt_register_widgets() {
register_widget('\AKSRT\Widgets\SearchWidget');
register_widget('\AKSRT\Widgets\NoticeWidget');
register_widget('\AKSRT\Widgets\RecentCommentsWidget');
register_widget('\AKSRT\Widgets\FriendLinksWidget');
register_widget('\AKSRT\Widgets\IconCardsWidget');
register_widget('\AKSRT\Widgets\ButtonsWidget');
register_widget('\AKSRT\Widgets\CustomHtmlGapWidget');
// 公告跑马灯
register_widget('\AKSRT\Widgets\WidgetAnnouncement');
@@ -47,9 +45,6 @@ function aksrt_register_widgets() {
// 用户卡片
register_widget('\AKSRT\Widgets\WidgetUserCard');
// 用户排行榜
register_widget('\AKSRT\Widgets\WidgetUserRanking');
// 图文封面卡片
register_widget('\AKSRT\Widgets\WidgetCoverCards');
@@ -66,18 +61,13 @@ function aksrt_register_widgets() {
register_widget('\AKSRT\Widgets\WidgetIframe');
register_widget('\AKSRT\Widgets\WidgetComboInfo');
register_widget('\AKSRT\Widgets\WidgetTextTitle');
register_widget('\AKSRT\Widgets\WidgetUserLists');
register_widget('\AKSRT\Widgets\WidgetFaq');
register_widget('\AKSRT\Widgets\WidgetHighlights');
register_widget('\AKSRT\Widgets\WidgetTermCards');
register_widget('\AKSRT\Widgets\WidgetPostPayBox');
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');
}
add_action('widgets_init', 'aksrt_register_widgets');
-18
View File
@@ -33,7 +33,6 @@ class WidgetAjax {
'/widgets/hot-posts' => 'rest_hot_posts',
'/widgets/oneline-posts' => 'rest_oneline_posts',
'/widgets/recent-comments' => 'rest_recent_comments',
'/widgets/user-lists' => 'rest_user_lists',
'/widgets/tag-cloud' => 'rest_tag_cloud',
'/widgets/categories' => 'rest_categories',
'/widgets/term-cards' => 'rest_term_cards',
@@ -223,23 +222,6 @@ class WidgetAjax {
return new \WP_REST_Response(['success' => true, 'html' => $html], 200);
}
public function rest_user_lists(\WP_REST_Request $request) {
if (!class_exists('\AKSRT\Widgets\WidgetUserLists')) {
return $this->fail();
}
$instance = [
'number' => max(1, min(50, (int) ($request->get_param('number') ?? 8))),
'orderby' => sanitize_key((string) ($request->get_param('orderby') ?? 'user_registered')),
'order' => sanitize_key((string) ($request->get_param('order') ?? 'DESC')),
'include' => sanitize_text_field((string) ($request->get_param('include') ?? '')),
'exclude' => sanitize_text_field((string) ($request->get_param('exclude') ?? '')),
'hide_box' => (int) ($request->get_param('hide_box') ?? 0),
'blur_bg' => (int) ($request->get_param('blur_bg') ?? 0),
];
$html = \AKSRT\Widgets\WidgetUserLists::render_html($instance);
return new \WP_REST_Response(['success' => true, 'html' => $html], 200);
}
public function rest_category_block(\WP_REST_Request $request) {
if (!class_exists('\AKSRT\Widgets\CategoryBlockWidget')) {
return $this->fail();
-115
View File
@@ -1,115 +0,0 @@
<?php
/**
* Custom HTML / layout gap (zibll zib_widget_ui_layout_gap + custom HTML).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class CustomHtmlGapWidget extends \WP_Widget {
use CommonWidgetFields;
public function __construct() {
parent::__construct('aksrt_custom_html_gap', esc_html__('AKSRT 自定义HTML/间距', 'aksrt'), [
'description' => esc_html__('插入自定义 HTML 或布局间距(PC/移动可分设)。', 'aksrt'),
'classname' => 'widget_aksrt_custom_html_gap',
]);
}
/**
* @param array<string,mixed> $args
* @param array<string,mixed> $instance
*/
public function widget($args, $instance): void {
$mode = sanitize_key((string) ($instance['mode'] ?? 'html'));
if ($mode === 'gap') {
$pc = max(0, min(500, (int) ($instance['gap_height'] ?? 20)));
$m = max(0, min(500, (int) ($instance['gap_height_m'] ?? $pc)));
// zibll layout gap: empty spacing block without widget chrome.
$style = sprintf('--aksrt-gap-pc:%dpx;--aksrt-gap-m:%dpx;height:%dpx;', $pc, $m, $pc);
echo '<div class="widget-custom-gap aksrt-layout-gap" style="' . esc_attr($style) . '" aria-hidden="true"></div>';
return;
}
$content = (string) ($instance['content'] ?? '');
if (trim(wp_strip_all_tags($content)) === '' && trim($content) === '') {
if (current_user_can('manage_options')) {
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo function_exists('aksrt_get_widget_null')
? aksrt_get_widget_null(__('请填写 HTML 内容或切换为间距模式', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
: '<div class="c-red muted-box mb10"><b>' . esc_html__('自定义 HTML:', 'aksrt') . '</b>' . esc_html__('请填写内容或切换为间距模式', 'aksrt') . '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
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
}
$full_width = !empty($instance['full_width']);
$cls = 'widget-custom-html' . ($full_width ? ' is-full' : '');
echo '<div class="' . esc_attr($cls) . '">' . wp_kses_post($content) . '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* @param array<string,mixed> $instance
*/
public function form($instance): void {
$mode = sanitize_key((string) ($instance['mode'] ?? 'html'));
?>
<p>
<label for="<?php echo esc_attr($this->get_field_id('mode')); ?>"><?php esc_html_e('模式:', 'aksrt'); ?></label>
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('mode')); ?>" name="<?php echo esc_attr($this->get_field_name('mode')); ?>">
<option value="html" <?php selected($mode, 'html'); ?>><?php esc_html_e('自定义 HTML', 'aksrt'); ?></option>
<option value="gap" <?php selected($mode, 'gap'); ?>><?php esc_html_e('布局间距', 'aksrt'); ?></option>
</select>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php esc_html_e('标题(仅 HTML 模式,可选):', 'aksrt'); ?></label>
<input class="widefat" type="text" id="<?php echo esc_attr($this->get_field_id('title')); ?>" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('content')); ?>"><?php esc_html_e('HTML 内容:', 'aksrt'); ?></label>
<textarea class="widefat" rows="6" id="<?php echo esc_attr($this->get_field_id('content')); ?>" name="<?php echo esc_attr($this->get_field_name('content')); ?>"><?php echo esc_textarea((string) ($instance['content'] ?? '')); ?></textarea>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('gap_height')); ?>"><?php esc_html_e('PC 间距高度 px:', 'aksrt'); ?></label>
<input class="tiny-text" type="number" min="0" max="500" id="<?php echo esc_attr($this->get_field_id('gap_height')); ?>" name="<?php echo esc_attr($this->get_field_name('gap_height')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['gap_height'] ?? 20))); ?>">
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('gap_height_m')); ?>"><?php esc_html_e('移动间距高度 px:', 'aksrt'); ?></label>
<input class="tiny-text" type="number" min="0" max="500" id="<?php echo esc_attr($this->get_field_id('gap_height_m')); ?>" name="<?php echo esc_attr($this->get_field_name('gap_height_m')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['gap_height_m'] ?? $instance['gap_height'] ?? 20))); ?>">
</p>
<p>
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('full_width')); ?>" value="1" <?php checked(!empty($instance['full_width'])); ?>> <?php esc_html_e('HTML 通栏', 'aksrt'); ?></label>
</p>
<?php
$this->render_common_form_section($instance);
}
/**
* @param array<string,mixed> $new_instance
* @param array<string,mixed> $old_instance
* @return array<string,mixed>
*/
public function update($new_instance, $old_instance): array {
$business = [
'mode' => in_array(($new_instance['mode'] ?? ''), ['html', 'gap'], true) ? $new_instance['mode'] : 'html',
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'content' => wp_kses_post((string) ($new_instance['content'] ?? '')),
'gap_height' => max(0, min(500, (int) ($new_instance['gap_height'] ?? 20))),
'gap_height_m' => max(0, min(500, (int) ($new_instance['gap_height_m'] ?? $new_instance['gap_height'] ?? 20))),
'full_width' => !empty($new_instance['full_width']) ? 1 : 0,
]; return $this->update_common_fields($new_instance, $old_instance, $business);
}
}
-207
View File
@@ -1,207 +0,0 @@
<?php
/**
* Friend links / bookmarks widget — routes through aksrt_links_box (zibll parity).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class FriendLinksWidget extends \WP_Widget {
use CommonWidgetFields;
public function __construct() {
parent::__construct('aksrt_friend_links', esc_html__('AKSRT 友情链接', 'aksrt'), [
'description' => esc_html__('友情链接:card / bigcard / image / simple(共享 aksrt_links_box)。', 'aksrt'),
'classname' => 'widget_aksrt_friend_links',
]);
}
/**
* @param array<string,mixed> $args
* @param array<string,mixed> $instance
*/
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);
$source = sanitize_key((string) ($instance['source'] ?? 'settings'));
$go_link = !empty($instance['go_link']);
$limit = max(1, min(100, (int) ($instance['limit'] ?? 24)));
$type = sanitize_key((string) ($instance['type'] ?? 'card'));
if (!in_array($type, ['card', 'bigcard', 'image', 'simple'], true)) {
$type = 'card';
}
$blank = !isset($instance['blank']) || !empty($instance['blank']);
$nofollow = !isset($instance['nofollow']) || !empty($instance['nofollow']);
$show_box = !empty($instance['show_box']) || !isset($instance['show_box']);
if ($title) {
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
$bookmarks = $this->resolve_bookmarks($source, $instance, $limit);
if (!$bookmarks) {
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;
}
$wrap = 'aksrt-friend-links aksrt-bookmark-links links-box style-' . $type . ($show_box ? ' has-box zib-widget' : '');
echo '<div class="' . esc_attr($wrap) . '">';
if (function_exists('aksrt_links_box')) {
echo aksrt_links_box($bookmarks, $type, $nofollow, $go_link, $blank); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
} else {
foreach ($bookmarks as $b) {
$row = (array) $b;
$url = (string) ($row['link_url'] ?? $row['url'] ?? '');
$name = (string) ($row['link_name'] ?? $row['name'] ?? '');
if ($url === '' || $name === '') {
continue;
}
if ($go_link && function_exists('aksrt_go_link')) {
$url = aksrt_go_link($url, true);
}
echo '<a class="aksrt-friend-links__item" href="' . esc_url($url) . '"' . ($blank ? ' target="_blank" rel="noopener noreferrer"' : '') . '>' . esc_html($name) . '</a>';
}
}
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Normalize to get_bookmarks-like objects/arrays for aksrt_links_box.
*
* @param array<string,mixed> $instance
* @return array<int, object|array>
*/
private function resolve_bookmarks(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 !== '' && $cats !== 'all') {
$bm_args['category'] = $cats;
}
return get_bookmarks($bm_args) ?: [];
}
$links = class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::get_friend_links() : [];
if (!is_array($links) || !$links) {
return $this->resolve_bookmarks('bookmarks', $instance, $limit);
}
$out = [];
foreach (array_slice(array_values($links), 0, $limit) as $link) {
if (!is_array($link)) {
continue;
}
$out[] = (object) [
'link_name' => (string) ($link['name'] ?? ''),
'link_url' => (string) ($link['url'] ?? ''),
'link_description' => (string) ($link['description'] ?? $link['desc'] ?? ''),
'link_image' => (string) ($link['icon'] ?? $link['image'] ?? ''),
'link_target' => '_blank',
];
}
return $out;
}
/**
* @param array<string,mixed> $instance
*/
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'); ?>
<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="bigcard" <?php selected(($instance['type'] ?? ''), 'bigcard'); ?>><?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>
<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><?php esc_html_e('书签排序(书签模式)', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('orderby')); ?>">
<option value="name" <?php selected(($instance['orderby'] ?? 'name'), 'name'); ?>><?php esc_html_e('名称', 'aksrt'); ?></option>
<option value="updated" <?php selected(($instance['orderby'] ?? ''), 'updated'); ?>><?php esc_html_e('更新时间', 'aksrt'); ?></option>
<option value="rating" <?php selected(($instance['orderby'] ?? ''), 'rating'); ?>><?php esc_html_e('评分', 'aksrt'); ?></option>
<option value="rand" <?php selected(($instance['orderby'] ?? ''), 'rand'); ?>><?php esc_html_e('随机', 'aksrt'); ?></option>
</select>
<select name="<?php echo esc_attr($this->get_field_name('order')); ?>">
<option value="ASC" <?php selected(($instance['order'] ?? 'ASC'), 'ASC'); ?>><?php esc_html_e('升序', 'aksrt'); ?></option>
<option value="DESC" <?php selected(($instance['order'] ?? ''), 'DESC'); ?>><?php esc_html_e('降序', 'aksrt'); ?></option>
</select>
</label>
</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(!isset($instance['nofollow']) || !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(!isset($instance['show_box']) || !empty($instance['show_box'])); ?>> <?php esc_html_e('外框盒子', 'aksrt'); ?></label>
</p>
<?php
$this->render_common_form_section($instance);
}
/**
* @param array<string,mixed> $new_instance
* @param array<string,mixed> $old_instance
* @return array<string,mixed>
*/
public function update($new_instance, $old_instance): array {
$type = sanitize_key((string) ($new_instance['type'] ?? 'card'));
if (!in_array($type, ['card', 'bigcard', 'image', 'simple'], true)) {
$type = 'card';
}
$business = [
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'source' => ($new_instance['source'] ?? '') === 'bookmarks' ? 'bookmarks' : 'settings',
'type' => $type,
'limit' => max(1, min(100, (int) ($new_instance['limit'] ?? 24))),
'cats' => sanitize_text_field((string) ($new_instance['cats'] ?? '')),
'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,
'orderby' => sanitize_key((string) ($new_instance['orderby'] ?? 'name')),
'order' => strtoupper((string) ($new_instance['order'] ?? 'ASC')) === 'DESC' ? 'DESC' : 'ASC',
// Keep legacy keys so old instances don't explode.
'columns' => max(1, min(4, (int) ($new_instance['columns'] ?? 2))),
'show_icon' => !empty($new_instance['show_icon']) ? 1 : 0,
];
return $this->update_common_fields($new_instance, $old_instance, $business);
}
}
-179
View File
@@ -1,179 +0,0 @@
<?php
/**
* WordPress bookmark / links list (zibll widget_ui_links_lists via aksrt_links_box).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class WidgetBookmarkLinks extends \WP_Widget {
use CommonWidgetFields;
public function __construct() {
parent::__construct(
'aksrt_bookmark_links',
esc_html__('AKSRT 链接列表', 'aksrt'),
[
'description' => esc_html__('WordPress 链接(书签)列表:card / bigcard / image / simple。', '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';
// 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 = !empty($instance['blank']);
$nofollow = !isset($instance['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) {
if (current_user_can('manage_options')) {
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
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;
}
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 links-box style-' . $type . ($show_box ? ' has-box' : '') . ($align ? ' text-' . $align : '');
echo '<div class="' . esc_attr($wrap) . '">';
if (function_exists('aksrt_links_box')) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo aksrt_links_box($bookmarks, $type, $nofollow, $go_link, $blank);
} else {
// Minimal fallback.
foreach ($bookmarks as $b) {
$url = (string) $b->link_url;
if ($url !== '' && $go_link && function_exists('aksrt_go_link')) {
$url = aksrt_go_link($url, true);
}
echo '<a class="aksrt-bookmark-links__item" href="' . esc_url($url) . '"' . ($blank ? ' target="_blank" rel="noopener noreferrer"' : '') . '>';
echo esc_html((string) $b->link_name);
echo '</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="bigcard" <?php selected(($instance['type'] ?? ''), 'bigcard'); ?>><?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><?php esc_html_e('对齐方式', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('alignment')); ?>">
<option value="" <?php selected(($instance['alignment'] ?? ''), ''); ?>><?php esc_html_e('左对齐', 'aksrt'); ?></option>
<option value="center" <?php selected(($instance['alignment'] ?? ''), 'center'); ?>><?php esc_html_e('居中', 'aksrt'); ?></option>
<option value="right" <?php selected(($instance['alignment'] ?? ''), 'right'); ?>><?php esc_html_e('右对齐', 'aksrt'); ?></option>
</select>
</label>
</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(!isset($instance['nofollow']) || !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
$this->render_common_form_section($instance);
}
public function update($new_instance, $old_instance): array {
$type = sanitize_key((string) ($new_instance['type'] ?? 'card'));
if (!in_array($type, ['card', 'bigcard', 'image', 'simple'], true)) {
$type = 'card';
}
$business = [
'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' => $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,
'show_box' => !empty($new_instance['show_box']) ? 1 : 0,
]; return $this->update_common_fields($new_instance, $old_instance, $business);
}
}
-360
View File
@@ -1,360 +0,0 @@
<?php
/**
* FAQ accordion (zibll zib_widget_faq / produck-wid-faq structure parity).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class WidgetFaq extends \WP_Widget {
use CommonWidgetFields;
private const BADGE_TONES = ['purple', 'pink', 'green', 'orange', 'blue'];
public function __construct() {
parent::__construct(
'aksrt_faq',
esc_html__('AKSRT 常见问题', 'aksrt'),
[
'description' => esc_html__('FAQ 摘要卡 + 文档链接列表 + 帮助 CTA。', 'aksrt'),
'classname' => 'widget_aksrt_faq',
]
);
}
public function widget($args, $instance): void {
$faqs = $this->normalize_faqs($instance['faqs'] ?? []);
if (!$faqs) {
if (current_user_can('manage_options')) {
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo function_exists('aksrt_get_widget_null')
? aksrt_get_widget_null(__('请添加至少一条问题', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
: '<div class="c-red muted-box mb20"><b>' . esc_html__('常见问题解答:', 'aksrt') . '</b>' . esc_html__('请添加至少一条问题', 'aksrt') . '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
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
}
$uid = 'aksrt-faq-' . esc_attr($this->id);
echo '<section class="aksrt-faq produck-wid-faq-block" id="' . $uid . '">';
if (!empty($instance['search_s'])) {
$ph = (string) ($instance['search_placeholder'] ?? __('搜索问题…', 'aksrt'));
$btn = (string) ($instance['search_btn_text'] ?? __('搜索', 'aksrt'));
echo '<header class="aksrt-faq__head produck-faq-head">';
echo '<form class="aksrt-faq__search search-form" method="get" action="' . esc_url(home_url('/')) . '" role="search">';
echo '<div class="aksrt-faq__search-wrap produck-faq-search">';
echo '<span class="aksrt-faq__search-icon" aria-hidden="true"><i class="fas fa-search"></i></span>';
echo '<input type="search" name="s" class="aksrt-faq__search-input produck-faq-search-input" placeholder="' . esc_attr($ph) . '" autocomplete="off" />';
echo '<button type="submit" class="aksrt-faq__search-btn produck-faq-search-btn"><span>' . esc_html($btn) . '</span></button>';
echo '</div></form></header>';
}
$doc_title = trim((string) ($instance['doc_title'] ?? ''));
$doc_desc = trim((string) ($instance['doc_desc'] ?? ''));
$doc_icon = sanitize_text_field((string) ($instance['doc_icon'] ?? 'fas fa-book'));
$doc_links = $this->normalize_doc_links($instance['doc_links'] ?? []);
$help_title = trim((string) ($instance['help_title'] ?? ''));
$help_sub = trim((string) ($instance['help_subtitle'] ?? ''));
$help_icon = sanitize_text_field((string) ($instance['help_icon'] ?? 'fas fa-graduation-cap'));
$help_url = esc_url_raw(trim((string) ($instance['help_btn_url'] ?? '')));
$help_btn = trim((string) ($instance['help_btn_text'] ?? ''));
$has_doc = ($doc_title !== '' || $doc_desc !== '' || $doc_links);
$has_help = ($help_title !== '' || $help_sub !== '' || ($help_btn !== '' && $help_url !== ''));
$main_cls = 'aksrt-faq__main produck-faq-main';
if (!$has_doc && !$has_help) {
$main_cls .= ' is-full';
}
echo '<div class="' . esc_attr($main_cls) . '">';
echo '<div class="aksrt-faq__list produck-faq-list-col">';
$n = 0;
foreach ($faqs as $f) {
$n++;
$num = str_pad((string) $n, 2, '0', STR_PAD_LEFT);
$tone = self::BADGE_TONES[($n - 1) % count(self::BADGE_TONES)];
$preview = $f['answer'] !== '' ? wp_strip_all_tags($f['answer']) : '';
if ($preview !== '') {
$preview = wp_trim_words($preview, 28);
}
echo '<details class="aksrt-faq__item produck-faq-summary">';
echo '<summary class="aksrt-faq__summary">';
echo '<span class="aksrt-faq__badge produck-faq-badge tone-' . esc_attr($tone) . '">' . esc_html($num) . '</span>';
echo '<span class="aksrt-faq__qblock">';
echo '<span class="aksrt-faq__q produck-faq-q">' . esc_html($f['question']) . '</span>';
if ($preview !== '') {
echo '<span class="aksrt-faq__preview muted-2-color">' . esc_html($preview) . '</span>';
}
echo '</span>';
echo '<i class="fas fa-angle-down aksrt-faq__chevron" aria-hidden="true"></i>';
echo '</summary>';
if ($f['answer'] !== '') {
echo '<div class="aksrt-faq__a">' . wp_kses_post(wpautop($f['answer'])) . '</div>';
}
echo '</details>';
}
echo '</div>';
if ($has_doc || $has_help) {
echo '<aside class="aksrt-faq__aside produck-faq-aside">';
if ($has_doc) {
echo '<div class="aksrt-faq__doc produck-faq-doc-card zib-widget">';
echo '<div class="aksrt-faq__doc-head">';
if ($doc_icon !== '') {
echo '<span class="aksrt-faq__doc-ico"><i class="' . esc_attr($doc_icon) . '" aria-hidden="true"></i></span>';
}
echo '<div>';
if ($doc_title !== '') {
echo '<h3 class="aksrt-faq__doc-title">' . esc_html($doc_title) . '</h3>';
}
if ($doc_desc !== '') {
echo '<p class="aksrt-faq__doc-desc muted-2-color">' . nl2br(esc_html($doc_desc)) . '</p>';
}
echo '</div></div>';
if ($doc_links) {
echo '<ul class="aksrt-faq__doc-list produck-faq-doc-list">';
foreach ($doc_links as $dl) {
$durl = $dl['url'] !== '' ? $dl['url'] : '#';
echo '<li class="aksrt-faq__doc-li">';
echo '<a class="aksrt-faq__doc-a" href="' . esc_url($durl) . '">';
if ($dl['icon'] !== '') {
echo '<span class="aksrt-faq__doc-li-ico"><i class="' . esc_attr($dl['icon']) . '" aria-hidden="true"></i></span>';
}
echo '<span class="aksrt-faq__doc-li-mid">';
echo '<span class="aksrt-faq__doc-li-title">' . esc_html($dl['title']);
if ($dl['tag'] !== '') {
echo ' <span class="badg badg-sm c-red ml6">' . esc_html($dl['tag']) . '</span>';
}
echo '</span>';
if ($dl['desc'] !== '') {
echo '<span class="aksrt-faq__doc-li-desc muted-2-color">' . esc_html($dl['desc']) . '</span>';
}
echo '</span>';
$go = $dl['btn_text'] !== '' ? $dl['btn_text'] : __('查看教程', 'aksrt');
echo '<span class="aksrt-faq__doc-go">' . esc_html($go) . ' <i class="fas fa-angle-right" aria-hidden="true"></i></span>';
echo '</a></li>';
}
echo '</ul>';
}
echo '</div>';
}
if ($has_help) {
echo '<div class="aksrt-faq__help produck-faq-help-card">';
echo '<div class="aksrt-faq__help-top">';
if ($help_icon !== '') {
echo '<span class="aksrt-faq__help-ico"><i class="' . esc_attr($help_icon) . '" aria-hidden="true"></i></span>';
}
echo '<div class="aksrt-faq__help-text">';
if ($help_title !== '') {
echo '<h3 class="aksrt-faq__help-title">' . esc_html($help_title) . '</h3>';
}
if ($help_sub !== '') {
echo '<p class="aksrt-faq__help-sub">' . nl2br(esc_html($help_sub)) . '</p>';
}
echo '</div></div>';
if ($help_btn !== '' && $help_url !== '') {
echo '<a class="aksrt-faq__help-btn" href="' . esc_url($help_url) . '">' . esc_html($help_btn) . ' <i class="fas fa-arrow-right" aria-hidden="true"></i></a>';
}
echo '</div>';
}
echo '</aside>';
}
echo '</div></section>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* @param mixed $raw
* @return array<int, array{question:string,answer:string,category:string}>
*/
private function normalize_faqs($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;
}
$q = sanitize_text_field((string) ($row['question'] ?? $row['q'] ?? ''));
if ($q === '') {
continue;
}
$out[] = [
'question' => $q,
'answer' => wp_kses_post((string) ($row['answer'] ?? $row['a'] ?? '')),
'category' => sanitize_key((string) ($row['category'] ?? 'all')),
];
if (count($out) >= 30) {
break;
}
}
return $out;
}
/**
* @param mixed $raw
* @return array<int, array{title:string,url:string,desc:string,icon:string,tag:string,btn_text:string}>
*/
private function normalize_doc_links($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'] ?? ''));
$url = esc_url_raw(trim((string) ($row['url'] ?? $row['link'] ?? '')));
if ($title === '' && $url === '') {
continue;
}
$out[] = [
'title' => $title,
'url' => $url,
'desc' => sanitize_text_field((string) ($row['desc'] ?? '')),
'icon' => sanitize_text_field((string) ($row['icon'] ?? '')),
'tag' => sanitize_text_field((string) ($row['tag'] ?? '')),
'btn_text' => sanitize_text_field((string) ($row['btn_text'] ?? '')),
];
if (count($out) >= 12) {
break;
}
}
return $out;
}
public function form($instance): void {
$faqs = $this->normalize_faqs($instance['faqs'] ?? []);
if (!$faqs) {
$faqs = [
['question' => '', 'answer' => '', 'category' => 'all'],
['question' => '', 'answer' => '', 'category' => 'all'],
];
}
$doc_links = $this->normalize_doc_links($instance['doc_links'] ?? []);
if (!$doc_links) {
$doc_links = [
['title' => '', 'url' => '', 'desc' => '', 'icon' => 'fas fa-file-alt', 'tag' => '', 'btn_text' => ''],
];
}
?>
<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><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('search_s')); ?>" value="1" <?php checked(!empty($instance['search_s'])); ?>> <?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('search_placeholder')); ?>" value="<?php echo esc_attr((string) ($instance['search_placeholder'] ?? __('搜索问题…', 'aksrt'))); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('搜索按钮', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('search_btn_text')); ?>" value="<?php echo esc_attr((string) ($instance['search_btn_text'] ?? __('搜索', 'aksrt'))); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('FAQ JSON', 'aksrt'); ?>
<textarea class="widefat" rows="6" name="<?php echo esc_attr($this->get_field_name('faqs')); ?>" placeholder='[{"question":"…","answer":"…"}]'><?php echo esc_textarea((string) wp_json_encode($faqs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); ?></textarea>
</label>
</p>
<hr>
<p><strong><?php esc_html_e('文档卡', 'aksrt'); ?></strong></p>
<p>
<label><?php esc_html_e('文档标题', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('doc_title')); ?>" value="<?php echo esc_attr((string) ($instance['doc_title'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('文档描述', 'aksrt'); ?>
<textarea class="widefat" rows="2" name="<?php echo esc_attr($this->get_field_name('doc_desc')); ?>"><?php echo esc_textarea((string) ($instance['doc_desc'] ?? '')); ?></textarea>
</label>
</p>
<p>
<label><?php esc_html_e('文档图标 class', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('doc_icon')); ?>" value="<?php echo esc_attr((string) ($instance['doc_icon'] ?? 'fas fa-book')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('文档链接 JSON', 'aksrt'); ?>
<textarea class="widefat" rows="5" name="<?php echo esc_attr($this->get_field_name('doc_links')); ?>" placeholder='[{"title":"教程","url":"#","desc":"","icon":"fas fa-file","tag":"热门","btn_text":"查看教程"}]'><?php echo esc_textarea((string) wp_json_encode($doc_links, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); ?></textarea>
</label>
</p>
<hr>
<p><strong><?php esc_html_e('帮助卡', 'aksrt'); ?></strong></p>
<p>
<label><?php esc_html_e('帮助标题', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('help_title')); ?>" value="<?php echo esc_attr((string) ($instance['help_title'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('帮助副标题', 'aksrt'); ?>
<textarea class="widefat" rows="2" name="<?php echo esc_attr($this->get_field_name('help_subtitle')); ?>"><?php echo esc_textarea((string) ($instance['help_subtitle'] ?? '')); ?></textarea>
</label>
</p>
<p>
<label><?php esc_html_e('帮助图标 class', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('help_icon')); ?>" value="<?php echo esc_attr((string) ($instance['help_icon'] ?? 'fas fa-graduation-cap')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('帮助按钮文案', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('help_btn_text')); ?>" value="<?php echo esc_attr((string) ($instance['help_btn_text'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('帮助按钮链接', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('help_btn_url')); ?>" value="<?php echo esc_attr((string) ($instance['help_btn_url'] ?? '')); ?>">
</label>
</p>
<?php
$this->render_common_form_section($instance);
}
public function update($new_instance, $old_instance): array {
$business = [
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'search_s' => !empty($new_instance['search_s']) ? 1 : 0,
'search_placeholder' => sanitize_text_field((string) ($new_instance['search_placeholder'] ?? '')),
'search_btn_text' => sanitize_text_field((string) ($new_instance['search_btn_text'] ?? '')),
'faqs' => $this->normalize_faqs($new_instance['faqs'] ?? []),
'doc_title' => sanitize_text_field((string) ($new_instance['doc_title'] ?? '')),
'doc_desc' => sanitize_textarea_field((string) ($new_instance['doc_desc'] ?? '')),
'doc_icon' => sanitize_text_field((string) ($new_instance['doc_icon'] ?? '')),
'doc_links' => $this->normalize_doc_links($new_instance['doc_links'] ?? []),
'help_title' => sanitize_text_field((string) ($new_instance['help_title'] ?? '')),
'help_subtitle' => sanitize_textarea_field((string) ($new_instance['help_subtitle'] ?? '')),
'help_icon' => sanitize_text_field((string) ($new_instance['help_icon'] ?? '')),
'help_btn_text' => sanitize_text_field((string) ($new_instance['help_btn_text'] ?? '')),
'help_btn_url' => esc_url_raw(trim((string) ($new_instance['help_btn_url'] ?? ''))),
]; return $this->update_common_fields($new_instance, $old_instance, $business);
}
}
-211
View File
@@ -1,211 +0,0 @@
<?php
/**
* Highlights cards (zibll zib_widget_highlights) with scroll animation + go_link.
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class WidgetHighlights extends \WP_Widget {
use CommonWidgetFields;
public function __construct() {
parent::__construct(
'aksrt_highlights',
esc_html__('AKSRT 亮点卡片', 'aksrt'),
[
'description' => esc_html__('大中小尺寸亮点/卖点卡片栅格。', 'aksrt'),
'classname' => 'widget_aksrt_highlights',
]
);
}
/**
* @param array<string,mixed> $args
* @param array<string,mixed> $instance
*/
public function widget($args, $instance): void {
$cards = $this->normalize($instance['cards'] ?? []);
if (!$cards) {
if (current_user_can('manage_options')) {
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
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;
}
$go_link = !empty($instance['go_link']);
$anim = sanitize_key((string) ($instance['obs_animation'] ?? 'slideup'));
$anim_repeat = !empty($instance['animation_repeat']);
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
}
$large = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'large'));
$medium = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'medium'));
$small = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'small'));
if (!$large && !$medium && !$small) {
$medium = $cards;
}
echo '<div class="aksrt-highlights">';
$idx = 0;
foreach (['large' => $large, 'medium' => $medium, 'small' => $small] as $size => $group) {
if (!$group) {
continue;
}
echo '<div class="aksrt-highlights__row is-' . esc_attr($size) . '">';
foreach ($group as $c) {
$pack = function_exists('aksrt_obs_animate_attrs')
? aksrt_obs_animate_attrs($anim, $anim_repeat, $idx * 0.08)
: ['class' => '', 'attr' => ''];
echo $this->card($c, $size, $go_link, $pack); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$idx++;
}
echo '</div>';
}
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* @param array<string,mixed> $c
* @param array{class:string,attr:string} $pack
*/
private function card(array $c, string $size, bool $go_link, array $pack): string {
$color = sanitize_key((string) ($c['color'] ?? 'blue'));
if (!in_array($color, ['blue', 'pink', 'purple', 'green', 'orange', 'cyan'], true)) {
$color = 'blue';
}
$url = (string) ($c['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) . '"' : '';
$img = (string) ($c['image'] ?? '');
$cls = 'aksrt-hl-card size-' . esc_attr($size) . ' color-' . esc_attr($color) . $pack['class'];
$html = '<' . $tag . ' class="' . esc_attr(trim($cls)) . '"' . $href . $pack['attr'] . '>';
if ($img !== '') {
$placeholder = get_template_directory_uri() . '/assets/img/placeholder.svg';
$html .= '<div class="aksrt-hl-card__media"><img class="fit-cover aksrt-lazy lazyload" data-src="' . esc_url($img) . '" src="' . esc_url($placeholder) . '" alt="" loading="lazy" /></div>';
}
$html .= '<div class="aksrt-hl-card__body">';
if (!empty($c['icon'])) {
$html .= '<div class="aksrt-hl-card__icon"><i class="' . esc_attr((string) $c['icon']) . '" aria-hidden="true"></i></div>';
}
if ($c['title'] !== '') {
$html .= '<div class="aksrt-hl-card__title">' . esc_html($c['title']) . '</div>';
}
if ($c['desc'] !== '') {
$html .= '<div class="aksrt-hl-card__desc">' . esc_html($c['desc']) . '</div>';
}
$html .= '</div></' . $tag . '>';
return $html;
}
/**
* @param mixed $raw
* @return array<int, array<string,mixed>>
*/
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'] ?? ''));
$desc = sanitize_text_field((string) ($row['desc'] ?? ''));
if ($title === '' && $desc === '') {
continue;
}
$size = sanitize_key((string) ($row['size'] ?? 'medium'));
if (!in_array($size, ['large', 'medium', 'small'], true)) {
$size = 'medium';
}
$out[] = [
'title' => $title,
'desc' => $desc,
'icon' => sanitize_text_field((string) ($row['icon'] ?? '')),
'image' => esc_url_raw(trim((string) ($row['image'] ?? ''))),
'url' => esc_url_raw(trim((string) ($row['url'] ?? ''))),
'color' => sanitize_key((string) ($row['color'] ?? 'blue')),
'size' => $size,
];
if (count($out) >= 12) {
break;
}
}
return $out;
}
/**
* @param array<string,mixed> $instance
*/
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="8" name="<?php echo esc_attr($this->get_field_name('cards')); ?>" placeholder='[{"title":"高速","desc":"…","size":"large","color":"blue","icon":"fas fa-bolt"}]'><?php echo esc_textarea((string) $json); ?></textarea>
</label>
<small><?php esc_html_e('size: large|medium|small;color: blue/pink/…', 'aksrt'); ?></small>
</p>
<p>
<label><?php esc_html_e('入场动画', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('obs_animation')); ?>">
<option value="" <?php selected(($instance['obs_animation'] ?? 'slideup'), ''); ?>><?php esc_html_e('无', 'aksrt'); ?></option>
<option value="fade" <?php selected(($instance['obs_animation'] ?? 'slideup'), 'fade'); ?>><?php esc_html_e('淡入', 'aksrt'); ?></option>
<option value="slideup" <?php selected(($instance['obs_animation'] ?? 'slideup'), 'slideup'); ?>><?php esc_html_e('上滑', 'aksrt'); ?></option>
<option value="zoomin" <?php selected(($instance['obs_animation'] ?? 'slideup'), 'zoomin'); ?>><?php esc_html_e('放大', 'aksrt'); ?></option>
</select>
</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>
</p>
<?php
$this->render_common_form_section($instance);
}
/**
* @param array<string,mixed> $new_instance
* @param array<string,mixed> $old_instance
* @return array<string,mixed>
*/
public function update($new_instance, $old_instance): array {
$business = [
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'cards' => $this->normalize($new_instance['cards'] ?? []),
'go_link' => !empty($new_instance['go_link']) ? 1 : 0,
'obs_animation' => sanitize_key((string) ($new_instance['obs_animation'] ?? 'slideup')),
'animation_repeat' => !empty($new_instance['animation_repeat']) ? 1 : 0,
]; return $this->update_common_fields($new_instance, $old_instance, $business);
}
}
-272
View File
@@ -1,272 +0,0 @@
<?php
/**
* Tilt cases / showcase intro (zibll zib_widget_ui_tilt_cases lite, no JS tilt).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class WidgetTiltCases extends \WP_Widget {
use CommonWidgetFields;
public function __construct() {
parent::__construct(
'aksrt_tilt_cases',
esc_html__('AKSRT 案例展示', 'aksrt'),
[
'description' => esc_html__('左文案 + 右侧叠层图片案例展示。', 'aksrt'),
'classname' => 'widget_aksrt_tilt_cases',
]
);
}
public function widget($args, $instance): void {
$title = trim((string) ($instance['intro_title'] ?? ''));
$subtitle = trim((string) ($instance['intro_subtitle'] ?? ''));
$badge = trim((string) ($instance['intro_badge_text'] ?? ''));
$images = $this->normalize_images($instance['intro_showcase_images'] ?? []);
$features = $this->normalize_features($instance['intro_features'] ?? []);
$buttons = $this->normalize_buttons($instance['intro_buttons'] ?? []);
if ($title === '' && $subtitle === '' && !$images) {
if (current_user_can('manage_options')) {
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
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;
}
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<div class="aksrt-tilt">';
$pack = function_exists('aksrt_obs_animate_attrs') ? aksrt_obs_animate_attrs('slideup', false, 0) : ['class' => '', 'attr' => ''];
echo '<div class="aksrt-tilt__text' . esc_attr($pack['class']) . '"' . $pack['attr'] . '>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if ($badge !== '') {
$icon = sanitize_text_field((string) ($instance['intro_badge_icon'] ?? ''));
echo '<div class="aksrt-tilt__badge">';
if ($icon !== '') {
echo '<i class="' . esc_attr($icon) . '" aria-hidden="true"></i> ';
}
echo esc_html($badge) . '</div>';
}
if ($title !== '') {
$highlight = trim((string) ($instance['intro_title_highlight'] ?? ''));
$title_html = esc_html($title);
if ($highlight !== '') {
$h = esc_html($highlight);
$title_html = str_replace($h, '<em class="aksrt-tilt__hl">' . $h . '</em>', $title_html);
}
echo '<h2 class="aksrt-tilt__title">' . $title_html . '</h2>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
if ($subtitle !== '') {
echo '<p class="aksrt-tilt__subtitle">' . esc_html($subtitle) . '</p>';
}
if ($features) {
echo '<ul class="aksrt-tilt__features">';
foreach ($features as $f) {
echo '<li>';
if ($f['icon'] !== '') {
echo '<i class="' . esc_attr($f['icon']) . '" aria-hidden="true"></i> ';
}
echo esc_html($f['text']) . '</li>';
}
echo '</ul>';
}
if ($buttons) {
echo '<div class="aksrt-tilt__actions">';
foreach ($buttons as $b) {
$url = $b['url'];
if ($url !== '' && !empty($instance['go_link']) && function_exists('aksrt_go_link')) {
$url = aksrt_go_link($url, true);
}
echo '<a class="aksrt-tilt__btn" href="' . esc_url($url !== '' ? $url : '#') . '">' . esc_html($b['text']) . '</a>';
}
echo '</div>';
}
echo '</div>';
echo '<div class="aksrt-tilt__showcase" data-aksrt-tilt data-tilt-max="12" data-tilt-glare="1">';
if ($images) {
foreach ($images as $i => $img) {
$cls = $i === 0 ? ' is-main' : '';
$placeholder = get_template_directory_uri() . '/assets/img/placeholder.svg';
echo '<div class="aksrt-tilt__img' . esc_attr($cls) . '"><img class="aksrt-lazy lazyload" data-src="' . esc_url($img) . '" src="' . esc_url($placeholder) . '" alt="" loading="lazy" /></div>';
}
} else {
echo '<div class="aksrt-tilt__img is-main is-empty"></div>';
}
echo '</div></div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/** @param mixed $raw @return array<int,string> */
private function normalize_images($raw): array {
if (is_string($raw)) {
$decoded = json_decode($raw, true);
if (is_array($decoded)) {
$raw = $decoded;
} else {
$parts = preg_split('/\r\n|\r|\n|,/', $raw) ?: [];
$raw = $parts;
}
}
if (!is_array($raw)) {
return [];
}
$out = [];
foreach ($raw as $row) {
if (is_array($row)) {
$url = esc_url_raw(trim((string) ($row['image'] ?? $row['url'] ?? '')));
} else {
$url = esc_url_raw(trim((string) $row));
}
if ($url !== '') {
$out[] = $url;
}
if (count($out) >= 5) {
break;
}
}
return $out;
}
/** @param mixed $raw @return array<int, array{text:string,icon:string}> */
private function normalize_features($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_string($row)) {
$text = sanitize_text_field($row);
$icon = '';
} elseif (is_array($row)) {
$text = sanitize_text_field((string) ($row['text'] ?? ''));
$icon = sanitize_text_field((string) ($row['icon'] ?? ''));
} else {
continue;
}
if ($text === '') {
continue;
}
$out[] = ['text' => $text, 'icon' => $icon];
if (count($out) >= 8) {
break;
}
}
return $out;
}
/** @param mixed $raw @return array<int, array{text:string,url:string}> */
private function normalize_buttons($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;
}
$text = sanitize_text_field((string) ($row['text'] ?? $row['btn']['text'] ?? ''));
$url = esc_url_raw(trim((string) ($row['url'] ?? $row['btn']['url'] ?? '')));
if ($text === '') {
continue;
}
$out[] = ['text' => $text, 'url' => $url];
if (count($out) >= 4) {
break;
}
}
return $out;
}
public function form($instance): void {
$images = is_string($instance['intro_showcase_images'] ?? null)
? (string) $instance['intro_showcase_images']
: wp_json_encode($this->normalize_images($instance['intro_showcase_images'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$features = is_string($instance['intro_features'] ?? null)
? (string) $instance['intro_features']
: wp_json_encode($this->normalize_features($instance['intro_features'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$buttons = is_string($instance['intro_buttons'] ?? null)
? (string) $instance['intro_buttons']
: wp_json_encode($this->normalize_buttons($instance['intro_buttons'] ?? []), 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('intro_badge_text')); ?>" value="<?php echo esc_attr((string) ($instance['intro_badge_text'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('角标图标 class', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('intro_badge_icon')); ?>" value="<?php echo esc_attr((string) ($instance['intro_badge_icon'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('标题', 'aksrt'); ?>
<textarea class="widefat" rows="2" name="<?php echo esc_attr($this->get_field_name('intro_title')); ?>"><?php echo esc_textarea((string) ($instance['intro_title'] ?? '')); ?></textarea>
</label>
</p>
<p>
<label><?php esc_html_e('标题高亮词', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('intro_title_highlight')); ?>" value="<?php echo esc_attr((string) ($instance['intro_title_highlight'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('副标题', 'aksrt'); ?>
<textarea class="widefat" rows="2" name="<?php echo esc_attr($this->get_field_name('intro_subtitle')); ?>"><?php echo esc_textarea((string) ($instance['intro_subtitle'] ?? '')); ?></textarea>
</label>
</p>
<p>
<label><?php esc_html_e('特性 JSON', 'aksrt'); ?>
<textarea class="widefat" rows="3" name="<?php echo esc_attr($this->get_field_name('intro_features')); ?>"><?php echo esc_textarea((string) $features); ?></textarea>
</label>
</p>
<p>
<label><?php esc_html_e('按钮 JSON', 'aksrt'); ?>
<textarea class="widefat" rows="3" name="<?php echo esc_attr($this->get_field_name('intro_buttons')); ?>"><?php echo esc_textarea((string) $buttons); ?></textarea>
</label>
</p>
<p>
<label><?php esc_html_e('展示图 JSON/URL 列表', 'aksrt'); ?>
<textarea class="widefat" rows="4" name="<?php echo esc_attr($this->get_field_name('intro_showcase_images')); ?>"><?php echo esc_textarea((string) $images); ?></textarea>
</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>
</p>
<?php
$this->render_common_form_section($instance);
}
public function update($new_instance, $old_instance): array {
$business = [
'intro_badge_text' => sanitize_text_field((string) ($new_instance['intro_badge_text'] ?? '')),
'intro_badge_icon' => sanitize_text_field((string) ($new_instance['intro_badge_icon'] ?? '')),
'intro_title' => sanitize_textarea_field((string) ($new_instance['intro_title'] ?? '')),
'intro_title_highlight' => sanitize_text_field((string) ($new_instance['intro_title_highlight'] ?? '')),
'intro_subtitle' => sanitize_textarea_field((string) ($new_instance['intro_subtitle'] ?? '')),
'intro_features' => $this->normalize_features($new_instance['intro_features'] ?? []),
'intro_buttons' => $this->normalize_buttons($new_instance['intro_buttons'] ?? []),
'intro_showcase_images' => $this->normalize_images($new_instance['intro_showcase_images'] ?? []),
'go_link' => !empty($new_instance['go_link']) ? 1 : 0,
]; return $this->update_common_fields($new_instance, $old_instance, $business);
}
}
-228
View File
@@ -1,228 +0,0 @@
<?php
/**
* Registered user list (zibll widget_ui_user_lists → zib_author_card).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class WidgetUserLists extends \WP_Widget {
use CommonWidgetFields;
public function __construct() {
parent::__construct(
'aksrt_user_lists',
esc_html__('AKSRT 用户列表', 'aksrt'),
[
'description' => esc_html__('展示站点用户迷你名片(头像/身份/关注/简介)。', 'aksrt'),
'classname' => 'widget_aksrt_user_lists',
]
);
}
/** @return array<int,int> */
public static function parse_ids_static(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));
}
/**
* @param array<string,mixed> $instance
*/
public static function render_html(array $instance): string {
$number = max(1, min(50, (int) ($instance['number'] ?? 8)));
$orderby = sanitize_key((string) ($instance['orderby'] ?? 'user_registered'));
$order = strtoupper((string) ($instance['order'] ?? 'DESC')) === 'ASC' ? 'ASC' : 'DESC';
$include = self::parse_ids_static((string) ($instance['include'] ?? ''));
$exclude = self::parse_ids_static((string) ($instance['exclude'] ?? ''));
$hide_box = !empty($instance['hide_box']);
$blur_bg = !empty($instance['blur_bg']);
$query = [
'number' => $number,
'order' => $order,
'fields' => ['ID', 'display_name', 'user_nicename'],
];
if ($include) {
$query['include'] = $include;
$query['orderby'] = 'include';
} else {
switch ($orderby) {
case 'display_name':
$query['orderby'] = 'display_name';
break;
case 'post_count':
$query['orderby'] = 'post_count';
break;
case 'last_login':
$query['meta_key'] = 'aksrt_last_login';
$query['orderby'] = 'meta_value';
break;
case 'followed-user-count':
$query['meta_key'] = 'aksrt_follower_count';
$query['orderby'] = 'meta_value_num';
break;
default:
$query['orderby'] = 'user_registered';
}
}
if ($exclude) {
$query['exclude'] = $exclude;
}
$users = get_users($query);
if (!$users) {
return function_exists('aksrt_get_ajax_null')
? aksrt_get_ajax_null(__('暂无用户', 'aksrt'))
: '<p class="widget-empty ajax-item">' . esc_html__('暂无用户', 'aksrt') . '</p>';
}
if ($orderby === 'followed-user-count' && !$include && class_exists('\AKSRT\User\Follow')) {
$has_meta = false;
foreach ($users as $u) {
if ((int) get_user_meta($u->ID, 'aksrt_follower_count', true) > 0) {
$has_meta = true;
break;
}
}
if (!$has_meta) {
usort($users, static function ($a, $b) {
$fa = \AKSRT\User\Follow::get_instance()->get_follower_count((int) $a->ID);
$fb = \AKSRT\User\Follow::get_instance()->get_follower_count((int) $b->ID);
return $fb <=> $fa;
});
}
}
ob_start();
// zibll: optional zib-widget + text-center user_lists of author-minicard.
$outer = $hide_box ? 'aksrt-user-lists is-bare ajax-item' : 'aksrt-user-lists zib-widget ajax-item';
echo '<div class="' . esc_attr($outer) . '">';
echo '<div class="text-center user_lists">';
foreach ($users as $user) {
$uid = (int) $user->ID;
if (function_exists('aksrt_author_minicard')) {
echo aksrt_author_minicard($uid, 'mb10', $blur_bg); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
} else {
$avatar = function_exists('aksrt_get_avatar_url')
? aksrt_get_avatar_url($uid, ['size' => 96])
: get_avatar_url($uid, ['size' => 96]);
$home = function_exists('aksrt_get_user_home_url')
? aksrt_get_user_home_url($uid)
: get_author_posts_url($uid);
$name = $user->display_name ?: $user->user_nicename;
echo '<a class="author-minicard radius8" href="' . esc_url($home) . '">';
echo '<img class="avatar" src="' . esc_url($avatar) . '" alt="" loading="lazy" width="42" height="42" /> ';
echo esc_html($name);
echo '</a>';
}
}
echo '</div></div>';
return (string) ob_get_clean();
}
/**
* @param array<string,mixed> $args
* @param array<string,mixed> $instance
*/
public function widget($args, $instance): void {
$html = self::render_html($instance);
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 $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* @param array<string,mixed> $instance
*/
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="50" name="<?php echo esc_attr($this->get_field_name('number')); ?>" value="<?php echo esc_attr((string) ((int) ($instance['number'] ?? 8))); ?>">
</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><?php esc_html_e('排序', 'aksrt'); ?>
<select class="widefat" name="<?php echo esc_attr($this->get_field_name('orderby')); ?>">
<option value="user_registered" <?php selected(($instance['orderby'] ?? 'user_registered'), 'user_registered'); ?>><?php esc_html_e('注册时间', 'aksrt'); ?></option>
<option value="display_name" <?php selected(($instance['orderby'] ?? ''), 'display_name'); ?>><?php esc_html_e('昵称', 'aksrt'); ?></option>
<option value="post_count" <?php selected(($instance['orderby'] ?? ''), 'post_count'); ?>><?php esc_html_e('文章数', 'aksrt'); ?></option>
<option value="last_login" <?php selected(($instance['orderby'] ?? ''), 'last_login'); ?>><?php esc_html_e('最后登录', 'aksrt'); ?></option>
<option value="followed-user-count" <?php selected(($instance['orderby'] ?? ''), 'followed-user-count'); ?>><?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('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>
</label>
</p>
<p>
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('hide_box')); ?>" value="1" <?php checked(!empty($instance['hide_box'])); ?>> <?php esc_html_e('不显示背景盒子', 'aksrt'); ?></label><br>
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('blur_bg')); ?>" value="1" <?php checked(!empty($instance['blur_bg'])); ?>> <?php esc_html_e('头像模糊背景', 'aksrt'); ?></label>
</p>
<?php
$this->render_common_form_section($instance);
}
/**
* @param array<string,mixed> $new_instance
* @param array<string,mixed> $old_instance
* @return array<string,mixed>
*/
public function update($new_instance, $old_instance): array {
$orderby = sanitize_key((string) ($new_instance['orderby'] ?? 'user_registered'));
$allowed = ['user_registered', 'display_name', 'post_count', 'last_login', 'followed-user-count'];
if (!in_array($orderby, $allowed, true)) {
$orderby = 'user_registered';
}
$business = [
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'number' => max(1, min(50, (int) ($new_instance['number'] ?? 8))),
'include' => sanitize_text_field((string) ($new_instance['include'] ?? '')),
'exclude' => sanitize_text_field((string) ($new_instance['exclude'] ?? '')),
'orderby' => $orderby,
'order' => strtoupper((string) ($new_instance['order'] ?? 'DESC')) === 'ASC' ? 'ASC' : 'DESC',
'hide_box' => !empty($new_instance['hide_box']) ? 1 : 0,
'blur_bg' => !empty($new_instance['blur_bg']) ? 1 : 0,
]; return $this->update_common_fields($new_instance, $old_instance, $business);
}
}
-379
View File
@@ -1,379 +0,0 @@
<?php
/**
* User ranking lists (zibll zib_user_ranking_lists parity).
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class WidgetUserRanking extends \WP_Widget {
use CommonWidgetFields;
public function __construct() {
parent::__construct(
'aksrt_user_ranking',
__('AKSRT 用户排行榜', 'aksrt'),
[
'description' => __('按积分、文章数或粉丝数排行的用户列表。', 'aksrt'),
'classname' => 'widget_aksrt_user_ranking',
]
);
}
public function widget($args, $instance): void {
$title = !empty($instance['title']) ? (string) $instance['title'] : __('排行榜', 'aksrt');
// 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']);
$affix = function_exists('aksrt_widget_affix_attrs') ? aksrt_widget_affix_attrs($instance) : ['class' => '', 'attr' => ''];
$users = $this->get_ranking($rank_by, $count, $desc_mode);
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$box_cls = 'zib-widget user-ranking-box aksrt-user-ranking-box' . $affix['class'];
echo '<div class="' . esc_attr($box_cls) . '"' . $affix['attr'] . '>';
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
}
}
if (empty($users)) {
echo function_exists('aksrt_get_widget_null')
? aksrt_get_widget_null(__('暂无排行数据', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
: '<p class="aksrt-user-ranking__empty muted-2-color">' . esc_html__('暂无排行数据', 'aksrt') . '</p>';
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
return;
}
$ph = get_template_directory_uri() . '/assets/img/placeholder.svg';
$rank = 0;
foreach ($users as $user) {
$rank++;
$uid = (int) $user['id'];
$user_url = function_exists('aksrt_get_user_home_url')
? aksrt_get_user_home_url($uid)
: get_author_posts_url($uid);
$top_bagd = '';
if ($top_badge && $rank <= 3) {
$tone = $rank === 1 ? 'jb-red' : ($rank === 2 ? 'jb-yellow' : 'b-gray');
$top_bagd = '<badge class="img-badge left hot ' . esc_attr($tone) . '"><i>TOP' . (int) $rank . '</i></badge>';
}
$name_html = function_exists('aksrt_get_user_name')
? aksrt_get_user_name([
'id' => $uid,
'class' => 'flex ac flex1',
'follow' => false,
'medal' => true,
'level' => true,
])
: '<a class="font-bold" href="' . esc_url($user_url) . '">' . esc_html((string) $user['name']) . '</a>';
$avatar_html = '';
if ($show_avatar) {
$avatar_url = function_exists('aksrt_get_avatar_url')
? aksrt_get_avatar_url($uid, ['size' => 42])
: get_avatar_url($uid, ['size' => 42]);
$avatar_html = '<a class="avatar-img" href="' . esc_url($user_url) . '"><img class="avatar aksrt-lazy lazyload" data-src="' . esc_url($avatar_url) . '" src="' . esc_url($ph) . '" alt="" loading="lazy" width="36" height="36" /></a>';
}
$desc = (string) ($user['desc'] ?? '');
$value_label = (string) ($user['value_label'] ?? $user['value'] ?? '');
$value_icon = (string) ($user['value_icon'] ?? 'fa-trophy');
$right_badge = '<span class="badg" title="' . esc_attr($value_label) . '"><i class="fa ' . esc_attr($value_icon) . '" aria-hidden="true"></i><span class="ml6">' . esc_html((string) ($user['value_num'] ?? $user['value'] ?? '')) . '</span></span>';
$mt = $rank > 1 ? ' mt20' : '';
echo '<div class="user-ranking-item aksrt-user-ranking__item relative' . esc_attr($mt) . ($rank <= 3 ? ' is-top' : '') . '">';
echo $top_bagd; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<div class="user-info flex ac">';
echo $avatar_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<div class="user-right flex flex1 ac jsb ml10">';
echo '<div class="flex1 min-w0">';
echo '<div class="font-bold aksrt-user-ranking__name">' . $name_html . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if ($desc !== '') {
echo '<div class="mt3 em09 muted-color text-ellipsis aksrt-user-ranking__desc">' . esc_html($desc) . '</div>';
}
echo '</div>';
echo '<div class="ml20 flex0 aksrt-user-ranking__value">' . $right_badge . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</div></div></div>';
}
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* @return list<array{id:int,name:string,value:string,value_num:string,value_label:string,value_icon:string,desc:string}>
*/
private function get_ranking(string $rank_by, int $count, string $desc_mode = 'desc'): array {
$users = [];
switch ($rank_by) {
case 'credits':
global $wpdb;
$rows = $wpdb->get_results($wpdb->prepare(
"SELECT user_id, meta_value as credits FROM {$wpdb->usermeta}
WHERE meta_key = 'aksrt_credits'
ORDER BY CAST(meta_value AS UNSIGNED) DESC
LIMIT %d",
$count
), ARRAY_A);
foreach ((array) $rows as $row) {
$user = get_userdata((int) $row['user_id']);
if ($user) {
$num = (int) $row['credits'];
$users[] = [
'id' => (int) $row['user_id'],
'name' => $user->display_name,
'value' => number_format_i18n($num) . ' 积分',
'value_num' => (string) number_format_i18n($num),
'value_label' => sprintf(__('积分:%s', 'aksrt'), number_format_i18n($num)),
'value_icon' => 'fa-diamond',
'desc' => $this->user_extra_desc((int) $row['user_id'], $user, $desc_mode),
];
}
}
break;
case 'posts':
$blog_users = get_users([
'number' => $count,
'orderby' => 'post_count',
'order' => 'DESC',
'who' => 'authors',
]);
foreach ($blog_users as $user) {
$post_count = count_user_posts($user->ID, 'post', true);
if ($post_count > 0) {
$users[] = [
'id' => $user->ID,
'name' => $user->display_name,
'value' => number_format_i18n($post_count) . ' 篇',
'value_num' => (string) number_format_i18n($post_count),
'value_label' => sprintf(__('共%d篇文章', 'aksrt'), $post_count),
'value_icon' => 'fa-file-text-o',
'desc' => $this->user_extra_desc($user->ID, $user, $desc_mode),
];
}
}
break;
case 'checkin_all_day':
$users = $this->meta_rank('aksrt_checkin_all_day', ['checkin_all_day'], $count, $desc_mode, 'fa-calendar-check-o', __('累计签到%d天', 'aksrt'), ' 天');
break;
case 'checkin_continuous_day':
$users = $this->meta_rank('aksrt_checkin_continuous_day', ['checkin_continuous_day'], $count, $desc_mode, 'fa-calendar-check-o', __('连续签到%d天', 'aksrt'), ' 天');
break;
case 'followers':
if (class_exists('\AKSRT\User\Follow')) {
global $wpdb;
$follow_table = \AKSRT\Core\DBMigrator::table('follow');
if ($follow_table) {
$rows = $wpdb->get_results($wpdb->prepare(
"SELECT following_id, COUNT(*) as cnt
FROM {$follow_table}
GROUP BY following_id
ORDER BY cnt DESC
LIMIT %d",
$count
), ARRAY_A);
foreach ((array) $rows as $row) {
$user = get_userdata((int) $row['following_id']);
if ($user) {
$num = (int) $row['cnt'];
$users[] = [
'id' => (int) $row['following_id'],
'name' => $user->display_name,
'value' => number_format_i18n($num) . ' 粉丝',
'value_num' => (string) number_format_i18n($num),
'value_label' => sprintf(__('共%d个粉丝', 'aksrt'), $num),
'value_icon' => 'fa-heart',
'desc' => $this->user_extra_desc((int) $row['following_id'], $user, $desc_mode),
];
}
}
}
}
break;
}
return $users;
}
/**
* @param list<string> $alt_keys
* @return list<array{id:int,name:string,value:string,value_num:string,value_label:string,value_icon:string,desc:string}>
*/
private function meta_rank(string $primary_key, array $alt_keys, int $count, string $desc_mode, string $icon, string $label_tpl, string $suffix): array {
global $wpdb;
$keys = array_merge([$primary_key], $alt_keys);
$in = implode(',', array_fill(0, count($keys), '%s'));
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$sql = $wpdb->prepare(
"SELECT user_id, meta_value as val FROM {$wpdb->usermeta}
WHERE meta_key IN ($in)
ORDER BY CAST(meta_value AS UNSIGNED) DESC
LIMIT %d",
...array_merge($keys, [$count * 2])
);
$rows = $wpdb->get_results($sql, ARRAY_A);
$seen = [];
$users = [];
foreach ((array) $rows as $row) {
$uid = (int) $row['user_id'];
if (isset($seen[$uid])) {
continue;
}
$seen[$uid] = true;
$user = get_userdata($uid);
if (!$user) {
continue;
}
$num = (int) $row['val'];
$users[] = [
'id' => $uid,
'name' => $user->display_name,
'value' => number_format_i18n($num) . $suffix,
'value_num' => (string) number_format_i18n($num),
'value_label' => sprintf($label_tpl, $num),
'value_icon' => $icon,
'desc' => $this->user_extra_desc($uid, $user, $desc_mode),
];
if (count($users) >= $count) {
break;
}
}
return $users;
}
private function user_extra_desc(int $user_id, $user, string $mode): string {
switch ($mode) {
case 'user_registered':
if ($user && !empty($user->user_registered)) {
$days = max(0, (int) floor((time() - strtotime($user->user_registered)) / DAY_IN_SECONDS));
return sprintf(__('加入 %d 天', 'aksrt'), $days);
}
return '';
case 'last_login':
$t = (string) get_user_meta($user_id, 'aksrt_last_login', true);
if ($t === '') {
$t = (string) get_user_meta($user_id, 'last_login', true);
}
return $t !== '' ? sprintf(__('最近登录 %s', 'aksrt'), $t) : '';
case 'last_checkin':
$t = (string) get_user_meta($user_id, 'aksrt_last_checkin', true);
if ($t === '') {
$t = (string) get_user_meta($user_id, 'last_checkin', true);
}
return $t !== '' ? sprintf(__('最近签到 %s', 'aksrt'), $t) : '';
case 'desc':
default:
$bio = get_user_meta($user_id, 'description', true);
if (!is_string($bio) || $bio === '') {
$bio = $user ? (string) $user->description : '';
}
return $bio !== '' ? wp_trim_words($bio, 12) : '';
}
}
public function form($instance): void {
$title = !empty($instance['title']) ? $instance['title'] : __('排行榜', 'aksrt');
// 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']);
?>
<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('orderby')); ?>"><?php esc_html_e('榜单类型:', 'aksrt'); ?></label>
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('orderby')); ?>" name="<?php echo esc_attr($this->get_field_name('orderby')); ?>">
<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>
<option value="points" <?php selected($rank_by, 'points'); ?>><?php esc_html_e('用户积分', 'aksrt'); ?></option>
<option value="followed-user-count" <?php selected($rank_by, 'followed-user-count'); ?>><?php esc_html_e('粉丝数量', 'aksrt'); ?></option>
</select>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('number')); ?>"><?php esc_html_e('最大显示数量:', 'aksrt'); ?></label>
<input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('number')); ?>" name="<?php echo esc_attr($this->get_field_name('number')); ?>" type="number" value="<?php echo esc_attr((string) $count); ?>" min="1" max="20">
</p>
<p>
<label>
<input type="checkbox" id="<?php echo esc_attr($this->get_field_id('show_avatar')); ?>" name="<?php echo esc_attr($this->get_field_name('show_avatar')); ?>" value="1" <?php checked($show_avatar); ?>>
<?php esc_html_e('显示头像', 'aksrt'); ?>
</label>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('desc')); ?>"><?php esc_html_e('附加显示:', 'aksrt'); ?></label>
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('desc')); ?>" name="<?php echo esc_attr($this->get_field_name('desc')); ?>">
<option value="desc" <?php selected(($instance['desc'] ?? 'desc'), 'desc'); ?>><?php esc_html_e('用户签名', 'aksrt'); ?></option>
<option value="user_registered" <?php selected(($instance['desc'] ?? ''), 'user_registered'); ?>><?php esc_html_e('加入本站多少天', 'aksrt'); ?></option>
<option value="last_login" <?php selected(($instance['desc'] ?? ''), 'last_login'); ?>><?php esc_html_e('最后登录时间', 'aksrt'); ?></option>
<option value="last_checkin" <?php selected(($instance['desc'] ?? ''), 'last_checkin'); ?>><?php esc_html_e('最后签到时间', 'aksrt'); ?></option>
</select>
</p>
<p>
<label>
<input type="checkbox" name="<?php echo esc_attr($this->get_field_name('top_badge')); ?>" value="1" <?php checked(!empty($instance['top_badge'])); ?>>
<?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 $this->render_common_form_section($instance); ?>
<?php
}
public function update($new_instance, $old_instance): array {
$rank_by = (string) ($new_instance['orderby'] ?? $new_instance['rank_by'] ?? 'checkin_all_day');
$allowed = ['checkin_all_day', 'checkin_continuous_day', 'points', 'followed-user-count', 'credits', 'posts', 'followers'];
if (!in_array($rank_by, $allowed, true)) {
$rank_by = 'checkin_all_day';
}
return $this->update_common_fields($new_instance, $old_instance, [
'title' => sanitize_text_field($new_instance['title'] ?? ''),
'orderby' => $rank_by,
'rank_by' => $rank_by, // keep alias for any legacy readers.
'number' => max(1, min(20, (int) ($new_instance['number'] ?? $new_instance['count'] ?? 6))),
'count' => max(1, min(20, (int) ($new_instance['number'] ?? $new_instance['count'] ?? 6))),
'show_avatar' => !empty($new_instance['show_avatar']) ? 1 : 0,
'checkin_btn' => !empty($new_instance['checkin_btn']) ? 1 : 0,
'top_badge' => !empty($new_instance['top_badge']) ? 1 : 0,
'desc' => in_array($new_instance['desc'] ?? '', ['desc', 'user_registered', 'last_login', 'last_checkin'], true) ? $new_instance['desc'] : 'desc',
]);
}
}