refactor: remove unused widgets
This commit is contained in:
@@ -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');
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user