Close remaining zibll more-widgets gaps: horizontal icon-cover cards and native WordPress bookmark/links list with go_link/nofollow.
786 lines
24 KiB
PHP
786 lines
24 KiB
PHP
<?php
|
||
/**
|
||
* Widget registration and placement rules.
|
||
*
|
||
* @package AKSRT
|
||
*/
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
/**
|
||
* Register custom widgets.
|
||
*/
|
||
function aksrt_register_widgets() {
|
||
register_widget('\AKSRT\Widgets\AboutWidget');
|
||
register_widget('\AKSRT\Widgets\CategoriesWidget');
|
||
register_widget('\AKSRT\Widgets\TagCloudWidget');
|
||
register_widget('\AKSRT\Widgets\HotPostsWidget');
|
||
register_widget('\AKSRT\Widgets\TabPostsWidget');
|
||
register_widget('\AKSRT\Widgets\CategoryBlockWidget');
|
||
register_widget('\AKSRT\Widgets\CategoryTabsWidget');
|
||
register_widget('\AKSRT\Widgets\CategoryRecommendWidget');
|
||
|
||
// 第一批通用 widget
|
||
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');
|
||
|
||
// 用户卡片
|
||
register_widget('\AKSRT\Widgets\WidgetUserCard');
|
||
|
||
// 用户排行榜
|
||
register_widget('\AKSRT\Widgets\WidgetUserRanking');
|
||
|
||
// 图文封面卡片
|
||
register_widget('\AKSRT\Widgets\WidgetCoverCards');
|
||
|
||
// 视频播放器
|
||
register_widget('\AKSRT\Widgets\WidgetVideoPlayer');
|
||
|
||
// 语言切换器
|
||
register_widget('\AKSRT\Widgets\WidgetLangSwitch');
|
||
|
||
// 一言轮播
|
||
register_widget('\AKSRT\Widgets\WidgetYiyan');
|
||
|
||
// 文章目录树(zibll posts_navs)
|
||
register_widget('\AKSRT\Widgets\WidgetPostsNavs');
|
||
|
||
// 幻灯片
|
||
register_widget('\AKSRT\Widgets\WidgetSlider');
|
||
|
||
// zibll more widgets batch
|
||
register_widget('\AKSRT\Widgets\WidgetPartnersScroll');
|
||
register_widget('\AKSRT\Widgets\WidgetIframe');
|
||
register_widget('\AKSRT\Widgets\WidgetComboInfo');
|
||
register_widget('\AKSRT\Widgets\WidgetTextTitle');
|
||
register_widget('\AKSRT\Widgets\WidgetUserLists');
|
||
|
||
register_widget('\AKSRT\Widgets\WidgetPricingPlans');
|
||
register_widget('\AKSRT\Widgets\WidgetFaq');
|
||
register_widget('\AKSRT\Widgets\WidgetStats');
|
||
register_widget('\AKSRT\Widgets\WidgetReviews');
|
||
register_widget('\AKSRT\Widgets\WidgetHighlights');
|
||
register_widget('\AKSRT\Widgets\WidgetFeatureIntro');
|
||
register_widget('\AKSRT\Widgets\WidgetTermCards');
|
||
register_widget('\AKSRT\Widgets\WidgetPaidPosts');
|
||
register_widget('\AKSRT\Widgets\WidgetAuthorCard');
|
||
register_widget('\AKSRT\Widgets\WidgetOnelinePosts');
|
||
register_widget('\AKSRT\Widgets\WidgetTiltCases');
|
||
register_widget('\AKSRT\Widgets\WidgetMainPosts');
|
||
register_widget('\AKSRT\Widgets\WidgetTermAggregation');
|
||
register_widget('\AKSRT\Widgets\WidgetIconCoverCards');
|
||
register_widget('\AKSRT\Widgets\WidgetBookmarkLinks');
|
||
|
||
|
||
// Forum widgets
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumBoardList')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumBoardList');
|
||
}
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumHotTopics')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumHotTopics');
|
||
}
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumRecentTopics')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumRecentTopics');
|
||
}
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumPlateLists')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumPlateLists');
|
||
}
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumPlateInfo')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumPlateInfo');
|
||
}
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumPlateModerator')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumPlateModerator');
|
||
}
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumTopicLists')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumTopicLists');
|
||
}
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumTopicTerms')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumTopicTerms');
|
||
}
|
||
if (class_exists('\AKSRT\Widgets\WidgetForumTabTopics')) {
|
||
register_widget('\AKSRT\Widgets\WidgetForumTabTopics');
|
||
}
|
||
|
||
// Shop product widgets (§6.9)
|
||
register_widget('\AKSRT\Widgets\WidgetProductList');
|
||
register_widget('\AKSRT\Widgets\WidgetProductOneline');
|
||
register_widget('\AKSRT\Widgets\WidgetProductTab');
|
||
|
||
aksrt_maybe_repair_sidebar_blog_widgets();
|
||
}
|
||
add_action('widgets_init', 'aksrt_register_widgets');
|
||
|
||
if (!function_exists('aksrt_widget_sidebar_area_ids')) {
|
||
/**
|
||
* Sidebars intended for sidebar-only widgets.
|
||
*
|
||
* @return array<int, string>
|
||
*/
|
||
function aksrt_widget_sidebar_area_ids(): array {
|
||
return [
|
||
'home_sidebar',
|
||
'sidebar-blog',
|
||
'sidebar-article',
|
||
'all_sidebar_top',
|
||
'all_sidebar_bottom',
|
||
'cat_sidebar',
|
||
'tag_sidebar',
|
||
'search_sidebar',
|
||
];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_archive_area_ids')) {
|
||
/**
|
||
* Widget zones for archive pages (cat/tag/search).
|
||
*
|
||
* @return array<int, string>
|
||
*/
|
||
function aksrt_widget_archive_area_ids(): array {
|
||
return [
|
||
'cat_top_fluid',
|
||
'cat_top_content',
|
||
'cat_bottom_content',
|
||
'cat_bottom_fluid',
|
||
'cat_sidebar',
|
||
'tag_top_fluid',
|
||
'tag_top_content',
|
||
'tag_bottom_content',
|
||
'tag_bottom_fluid',
|
||
'tag_sidebar',
|
||
'search_top_fluid',
|
||
'search_top_content',
|
||
'search_bottom_content',
|
||
'search_bottom_fluid',
|
||
'search_sidebar',
|
||
];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_homepage_area_ids')) {
|
||
/**
|
||
* Homepage widget zones for homepage-only widgets.
|
||
*
|
||
* @return array<int, string>
|
||
*/
|
||
function aksrt_widget_homepage_area_ids(): array {
|
||
return [
|
||
'home_top_fluid',
|
||
'home_top_content',
|
||
'home_bottom_content',
|
||
'home_bottom_fluid',
|
||
];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_single_area_ids')) {
|
||
/**
|
||
* Single post/page widget zones.
|
||
*
|
||
* @return array<int, string>
|
||
*/
|
||
function aksrt_widget_single_area_ids(): array {
|
||
return [
|
||
'single_top_fluid',
|
||
'single_top_content',
|
||
'single_bottom_content',
|
||
'single_bottom_fluid',
|
||
];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_base_from_id')) {
|
||
/**
|
||
* Get widget base id from a stored widget instance id.
|
||
*/
|
||
function aksrt_widget_base_from_id(string $widget_id): string {
|
||
return preg_replace('/-\d+$/', '', $widget_id) ?: $widget_id;
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_allowed_sidebars')) {
|
||
/**
|
||
* Allowed sidebar ids for a widget base id.
|
||
*
|
||
* @return array<int, string>
|
||
*/
|
||
function aksrt_widget_allowed_sidebars(string $widget_base_id): array {
|
||
$sidebar_only = [
|
||
'aksrt_about',
|
||
'aksrt_categories',
|
||
'aksrt_tag_cloud',
|
||
'aksrt_hot_posts',
|
||
];
|
||
$homepage_only = [
|
||
'aksrt_category_recommend',
|
||
];
|
||
$hybrid = [
|
||
'aksrt_tab_posts',
|
||
'aksrt_category_block',
|
||
'aksrt_category_tabs',
|
||
];
|
||
|
||
if (in_array($widget_base_id, $sidebar_only, true)) {
|
||
return aksrt_widget_sidebar_area_ids();
|
||
}
|
||
|
||
if (in_array($widget_base_id, $homepage_only, true)) {
|
||
return aksrt_widget_homepage_area_ids();
|
||
}
|
||
|
||
if (in_array($widget_base_id, $hybrid, true)) {
|
||
return array_values(array_unique(array_merge(
|
||
aksrt_widget_sidebar_area_ids(),
|
||
aksrt_widget_homepage_area_ids()
|
||
)));
|
||
}
|
||
|
||
return [];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_is_allowed_in_sidebar')) {
|
||
/**
|
||
* Whether a widget base id can be assigned to the given sidebar id.
|
||
*/
|
||
function aksrt_widget_is_allowed_in_sidebar(string $widget_base_id, string $sidebar_id): bool {
|
||
if ($widget_base_id === '' || $sidebar_id === '') {
|
||
return true;
|
||
}
|
||
|
||
if ($sidebar_id === 'wp_inactive_widgets' || strpos($sidebar_id, 'orphaned_widgets') === 0) {
|
||
return true;
|
||
}
|
||
|
||
$allowed = aksrt_widget_allowed_sidebars($widget_base_id);
|
||
if (empty($allowed)) {
|
||
return true;
|
||
}
|
||
|
||
return in_array($sidebar_id, $allowed, true);
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_get_area_context')) {
|
||
/**
|
||
* Resolve widget area context from sidebar args.
|
||
*/
|
||
function aksrt_widget_get_area_context(array $args): string {
|
||
$sidebar_id = isset($args['id']) ? (string) $args['id'] : '';
|
||
|
||
if (in_array($sidebar_id, aksrt_widget_sidebar_area_ids(), true)) {
|
||
return 'sidebar';
|
||
}
|
||
|
||
if (in_array($sidebar_id, aksrt_widget_homepage_area_ids(), true)) {
|
||
return 'homepage';
|
||
}
|
||
|
||
if (in_array($sidebar_id, aksrt_widget_archive_area_ids(), true)) {
|
||
return 'archive';
|
||
}
|
||
|
||
if (in_array($sidebar_id, aksrt_widget_single_area_ids(), true)) {
|
||
return 'single';
|
||
}
|
||
|
||
return 'other';
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// Shared Widget Form Helper — 公共表单字段与显示规则
|
||
// ============================================================
|
||
|
||
if (!function_exists('aksrt_widget_common_defaults')) {
|
||
/**
|
||
* Default values for shared widget instance fields.
|
||
*
|
||
* @return array<string, mixed>
|
||
*/
|
||
function aksrt_widget_common_defaults(): array {
|
||
return [
|
||
'subtitle' => '',
|
||
'title_link' => '',
|
||
'show_type' => 'all',
|
||
'show_id_type' => '',
|
||
'show_ids' => '',
|
||
'sidebar_affix' => false,
|
||
'animation_in' => '',
|
||
'animation_repeat'=> false,
|
||
];
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_normalize_common')) {
|
||
/**
|
||
* Normalize common widget instance fields, filling defaults for legacy instances.
|
||
*
|
||
* @param array<string, mixed> $instance
|
||
* @return array<string, mixed>
|
||
*/
|
||
function aksrt_widget_normalize_common(array $instance): array {
|
||
$defaults = aksrt_widget_common_defaults();
|
||
$result = array_merge($defaults, $instance);
|
||
|
||
$result['subtitle'] = sanitize_text_field($result['subtitle'] ?? '');
|
||
$result['title_link'] = esc_url_raw($result['title_link'] ?? '');
|
||
$result['show_type'] = in_array($result['show_type'] ?? '', ['all', 'pc', 'mobile'], true) ? $result['show_type'] : 'all';
|
||
$result['show_id_type'] = in_array($result['show_id_type'] ?? '', ['', 'include', 'exclude'], true) ? $result['show_id_type'] : '';
|
||
$result['show_ids'] = sanitize_text_field($result['show_ids'] ?? '');
|
||
$result['sidebar_affix'] = !empty($result['sidebar_affix']);
|
||
$result['animation_in'] = sanitize_key($result['animation_in'] ?? '');
|
||
$result['animation_repeat']= !empty($result['animation_repeat']);
|
||
|
||
return $result;
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_render_common_form')) {
|
||
/**
|
||
* Render shared widget admin form fields.
|
||
*
|
||
* Call this from your widget's form() method after rendering custom fields.
|
||
*
|
||
* @param array<string, mixed> $instance Current widget instance.
|
||
*/
|
||
function aksrt_widget_render_common_form(array $instance): void {
|
||
$instance = aksrt_widget_normalize_common($instance);
|
||
?>
|
||
<hr style="margin:16px 0 12px;border-color:#e0e0e0;">
|
||
<p style="font-size:12px;color:#666;margin-bottom:8px;font-weight:600;"><?php esc_html_e('显示规则', 'aksrt'); ?></p>
|
||
|
||
<p>
|
||
<label for="<?php echo esc_attr($instance['show_type_id'] ?? ''); ?>"><?php esc_html_e('显示设备', 'aksrt'); ?></label><br>
|
||
<select name="<?php echo esc_attr($instance['show_type_name'] ?? 'show_type'); ?>" id="<?php echo esc_attr($instance['show_type_id'] ?? ''); ?>" class="widefat">
|
||
<option value="all" <?php selected($instance['show_type'], 'all'); ?>><?php esc_html_e('全部', 'aksrt'); ?></option>
|
||
<option value="pc" <?php selected($instance['show_type'], 'pc'); ?>><?php esc_html_e('仅 PC', 'aksrt'); ?></option>
|
||
<option value="mobile" <?php selected($instance['show_type'], 'mobile'); ?>><?php esc_html_e('仅移动端', 'aksrt'); ?></option>
|
||
</select>
|
||
</p>
|
||
|
||
<p>
|
||
<label for="<?php echo esc_attr($instance['show_id_type_id'] ?? ''); ?>"><?php esc_html_e('ID 显示规则', 'aksrt'); ?></label><br>
|
||
<select name="<?php echo esc_attr($instance['show_id_type_name'] ?? 'show_id_type'); ?>" id="<?php echo esc_attr($instance['show_id_type_id'] ?? ''); ?>" class="widefat">
|
||
<option value="" <?php selected($instance['show_id_type'], ''); ?>><?php esc_html_e('不限制', 'aksrt'); ?></option>
|
||
<option value="include" <?php selected($instance['show_id_type'], 'include'); ?>><?php esc_html_e('仅指定 ID 显示', 'aksrt'); ?></option>
|
||
<option value="exclude" <?php selected($instance['show_id_type'], 'exclude'); ?>><?php esc_html_e('指定 ID 隐藏', 'aksrt'); ?></option>
|
||
</select>
|
||
</p>
|
||
|
||
<p>
|
||
<label for="<?php echo esc_attr($instance['show_ids_id'] ?? ''); ?>"><?php esc_html_e('文章/页面 ID', 'aksrt'); ?></label><br>
|
||
<input type="text" name="<?php echo esc_attr($instance['show_ids_name'] ?? 'show_ids'); ?>" id="<?php echo esc_attr($instance['show_ids_id'] ?? ''); ?>" class="widefat" value="<?php echo esc_attr($instance['show_ids']); ?>" placeholder="<?php esc_attr_e('逗号分隔,如: 1,2,3', 'aksrt'); ?>">
|
||
</p>
|
||
|
||
<p>
|
||
<label>
|
||
<input type="checkbox" name="<?php echo esc_attr($instance['sidebar_affix_name'] ?? 'sidebar_affix'); ?>" value="1" <?php checked($instance['sidebar_affix']); ?>>
|
||
<?php esc_html_e('侧栏吸顶', 'aksrt'); ?>
|
||
</label>
|
||
</p>
|
||
|
||
<p>
|
||
<label for="<?php echo esc_attr($instance['animation_in_id'] ?? ''); ?>"><?php esc_html_e('入场动画', 'aksrt'); ?></label><br>
|
||
<select name="<?php echo esc_attr($instance['animation_in_name'] ?? 'animation_in'); ?>" id="<?php echo esc_attr($instance['animation_in_id'] ?? ''); ?>" class="widefat">
|
||
<option value="" <?php selected($instance['animation_in'], ''); ?>><?php esc_html_e('无', 'aksrt'); ?></option>
|
||
<option value="fadeIn" <?php selected($instance['animation_in'], 'fadeIn'); ?>><?php esc_html_e('淡入', 'aksrt'); ?></option>
|
||
<option value="fadeInUp" <?php selected($instance['animation_in'], 'fadeInUp'); ?>><?php esc_html_e('上移淡入', 'aksrt'); ?></option>
|
||
<option value="fadeInDown" <?php selected($instance['animation_in'], 'fadeInDown'); ?>><?php esc_html_e('下移淡入', 'aksrt'); ?></option>
|
||
<option value="fadeInLeft" <?php selected($instance['animation_in'], 'fadeInLeft'); ?>><?php esc_html_e('左移淡入', 'aksrt'); ?></option>
|
||
<option value="fadeInRight" <?php selected($instance['animation_in'], 'fadeInRight'); ?>><?php esc_html_e('右移淡入', 'aksrt'); ?></option>
|
||
<option value="zoomIn" <?php selected($instance['animation_in'], 'zoomIn'); ?>><?php esc_html_e('缩放进入', 'aksrt'); ?></option>
|
||
</select>
|
||
</p>
|
||
|
||
<p>
|
||
<label>
|
||
<input type="checkbox" name="<?php echo esc_attr($instance['animation_repeat_name'] ?? 'animation_repeat'); ?>" value="1" <?php checked($instance['animation_repeat']); ?>>
|
||
<?php esc_html_e('动画重复播放', 'aksrt'); ?>
|
||
</label>
|
||
</p>
|
||
<?php
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_update_common')) {
|
||
/**
|
||
* Process shared widget form fields in update().
|
||
*
|
||
* @param array<string, mixed> $new_instance
|
||
* @param array<string, mixed> $old_instance
|
||
* @return array<string, mixed>
|
||
*/
|
||
function aksrt_widget_update_common(array $new_instance, array $old_instance): array {
|
||
$merged = array_merge($old_instance, $new_instance);
|
||
return aksrt_widget_normalize_common($merged);
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_render_common_before')) {
|
||
/**
|
||
* Render common wrapper attributes and classes before widget content.
|
||
*
|
||
* Outputs CSS classes for animation, affix, show_type, etc.
|
||
* Call this at the start of widget() before rendering content.
|
||
*
|
||
* @param array $args Sidebar args.
|
||
* @param array $instance Widget instance.
|
||
* @return array Modified args with extra classes.
|
||
*/
|
||
function aksrt_widget_get_common_wrapper_classes(array $args, array $instance): array {
|
||
$instance = aksrt_widget_normalize_common($instance);
|
||
$classes = [];
|
||
|
||
// Show type: PC or mobile
|
||
if ($instance['show_type'] === 'pc') {
|
||
$classes[] = 'aksrt-widget--pc-only';
|
||
} elseif ($instance['show_type'] === 'mobile') {
|
||
$classes[] = 'aksrt-widget--mobile-only';
|
||
}
|
||
|
||
// Sidebar affix
|
||
if ($instance['sidebar_affix']) {
|
||
$classes[] = 'aksrt-widget--affix';
|
||
}
|
||
|
||
// Animation
|
||
if ($instance['animation_in'] !== '') {
|
||
$classes[] = 'aksrt-widget--animated';
|
||
$classes[] = 'aksrt-anim-' . $instance['animation_in'];
|
||
if ($instance['animation_repeat']) {
|
||
$classes[] = 'aksrt-anim-repeat';
|
||
}
|
||
}
|
||
|
||
return $classes;
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_should_display_by_ids')) {
|
||
/**
|
||
* Check if the current post/page should display the widget based on show_id_type and show_ids.
|
||
*
|
||
* @param array $instance Widget instance.
|
||
* @return bool
|
||
*/
|
||
function aksrt_widget_should_display_by_ids(array $instance): bool {
|
||
$instance = aksrt_widget_normalize_common($instance);
|
||
|
||
if ($instance['show_id_type'] === '' || $instance['show_ids'] === '') {
|
||
return true;
|
||
}
|
||
|
||
$current_id = get_the_ID();
|
||
if (!$current_id) {
|
||
return true; // Not on a singular page, allow display
|
||
}
|
||
|
||
$ids = array_filter(array_map('absint', explode(',', $instance['show_ids'])));
|
||
|
||
if ($instance['show_id_type'] === 'include') {
|
||
return in_array($current_id, $ids, true);
|
||
}
|
||
|
||
if ($instance['show_id_type'] === 'exclude') {
|
||
return !in_array($current_id, $ids, true);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_widget_render_location_help')) {
|
||
/**
|
||
* Render placement hint inside widget admin forms.
|
||
*/
|
||
function aksrt_widget_render_location_help(string $scope): void {
|
||
$messages = [
|
||
'sidebar' => __('仅限侧栏区域:首页侧栏、博客侧栏、文章侧栏、全站侧栏、分类/标签/搜索侧栏。', 'aksrt'),
|
||
'homepage' => __('仅限首页挂载区域:首页顶部/底部全宽、首页内容上方/下方。', 'aksrt'),
|
||
'hybrid' => __('支持侧栏、首页和归档页挂载区域。', 'aksrt'),
|
||
'archive' => __('仅限归档页挂载区域:分类页、标签页、搜索页的顶部/底部/侧栏。', 'aksrt'),
|
||
];
|
||
|
||
if (empty($messages[$scope])) {
|
||
return;
|
||
}
|
||
|
||
printf(
|
||
'<p style="margin-top:10px;font-size:12px;color:#666;">%s</p>',
|
||
esc_html($messages[$scope])
|
||
);
|
||
}
|
||
}
|
||
|
||
if (!function_exists('aksrt_filter_widget_display_by_area')) {
|
||
/**
|
||
* Prevent widgets from rendering outside their allowed areas,
|
||
* and apply per-widget display rules (show_type, show_id_type/show_ids).
|
||
*
|
||
* @param array|false $instance Widget instance.
|
||
* @param WP_Widget $widget Widget object.
|
||
* @param array $args Sidebar args.
|
||
* @return array|false
|
||
*/
|
||
function aksrt_filter_widget_display_by_area($instance, WP_Widget $widget, array $args) {
|
||
$sidebar_id = isset($args['id']) ? (string) $args['id'] : '';
|
||
$widget_base_id = isset($widget->id_base) ? (string) $widget->id_base : '';
|
||
|
||
if ($instance === false) {
|
||
return false;
|
||
}
|
||
|
||
// Layer 1: Area legality check
|
||
if (!aksrt_widget_is_allowed_in_sidebar($widget_base_id, $sidebar_id)) {
|
||
return false;
|
||
}
|
||
|
||
// Layer 2: Display rule check (show_type for PC/mobile)
|
||
if (is_array($instance) && function_exists('aksrt_widget_normalize_common')) {
|
||
$normalized = aksrt_widget_normalize_common($instance);
|
||
|
||
// Show type: PC / mobile filter
|
||
if ($normalized['show_type'] === 'pc' && wp_is_mobile()) {
|
||
return false;
|
||
}
|
||
if ($normalized['show_type'] === 'mobile' && !wp_is_mobile()) {
|
||
return false;
|
||
}
|
||
|
||
// Show IDs: whitelist / blacklist filter
|
||
if (!aksrt_widget_should_display_by_ids($normalized)) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return $instance;
|
||
}
|
||
}
|
||
add_filter('widget_display_callback', 'aksrt_filter_widget_display_by_area', 10, 3);
|
||
|
||
if (!function_exists('aksrt_filter_widget_sidebar_assignments')) {
|
||
/**
|
||
* Move disallowed widget assignments back to the inactive widgets bucket.
|
||
*
|
||
* @param mixed $new_value New sidebars_widgets option value.
|
||
* @param mixed $old_value Previous option value.
|
||
* @return mixed
|
||
*/
|
||
function aksrt_filter_widget_sidebar_assignments($new_value, $old_value) {
|
||
if (!is_array($new_value)) {
|
||
return $new_value;
|
||
}
|
||
|
||
$removed = [];
|
||
|
||
foreach ($new_value as $sidebar_id => $widget_ids) {
|
||
if (!is_array($widget_ids) || $sidebar_id === 'wp_inactive_widgets') {
|
||
continue;
|
||
}
|
||
|
||
$filtered = [];
|
||
foreach ($widget_ids as $widget_id) {
|
||
if (!is_string($widget_id) || $widget_id === '') {
|
||
continue;
|
||
}
|
||
|
||
$widget_base_id = aksrt_widget_base_from_id($widget_id);
|
||
if (aksrt_widget_is_allowed_in_sidebar($widget_base_id, (string) $sidebar_id)) {
|
||
$filtered[] = $widget_id;
|
||
} else {
|
||
$removed[] = $widget_id;
|
||
}
|
||
}
|
||
|
||
$new_value[$sidebar_id] = array_values($filtered);
|
||
}
|
||
|
||
if (empty($removed)) {
|
||
return $new_value;
|
||
}
|
||
|
||
if (!isset($new_value['wp_inactive_widgets']) || !is_array($new_value['wp_inactive_widgets'])) {
|
||
$new_value['wp_inactive_widgets'] = [];
|
||
}
|
||
|
||
$assigned = [];
|
||
foreach ($new_value as $widget_ids) {
|
||
if (!is_array($widget_ids)) {
|
||
continue;
|
||
}
|
||
|
||
foreach ($widget_ids as $widget_id) {
|
||
if (is_string($widget_id) && $widget_id !== '') {
|
||
$assigned[$widget_id] = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
foreach (array_values(array_unique($removed)) as $widget_id) {
|
||
if (!isset($assigned[$widget_id]) && !in_array($widget_id, $new_value['wp_inactive_widgets'], true)) {
|
||
$new_value['wp_inactive_widgets'][] = $widget_id;
|
||
}
|
||
}
|
||
|
||
return $new_value;
|
||
}
|
||
}
|
||
add_filter('pre_update_option_sidebars_widgets', 'aksrt_filter_widget_sidebar_assignments', 10, 2);
|
||
|
||
/**
|
||
* Ensure widget instance config exists.
|
||
*/
|
||
function aksrt_ensure_widget_instance(string $option_name, int $number, array $defaults): void {
|
||
$instances = get_option($option_name, []);
|
||
|
||
if (!is_array($instances)) {
|
||
$instances = [];
|
||
}
|
||
|
||
if (!isset($instances['_multiwidget'])) {
|
||
$instances['_multiwidget'] = 1;
|
||
}
|
||
|
||
if (empty($instances[$number]) || !is_array($instances[$number])) {
|
||
$instances[$number] = $defaults;
|
||
update_option($option_name, $instances);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Repair the sidebar-blog structure and seed default sidebar widgets on first install.
|
||
*/
|
||
function aksrt_maybe_repair_sidebar_blog_widgets(): void {
|
||
$sidebars = get_option('sidebars_widgets', []);
|
||
$seeded = (bool) get_option('aksrt_sidebar_blog_seeded', false);
|
||
|
||
if (!is_array($sidebars)) {
|
||
$sidebars = [];
|
||
}
|
||
|
||
$current = $sidebars['sidebar-blog'] ?? null;
|
||
$needs_repair = false;
|
||
$normalized = [];
|
||
|
||
if (is_array($current)) {
|
||
foreach ($current as $item) {
|
||
if (is_array($item)) {
|
||
$needs_repair = true;
|
||
}
|
||
|
||
if (is_string($item) && $item !== '') {
|
||
$normalized[] = $item;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($needs_repair) {
|
||
$sidebars['sidebar-blog'] = array_values($normalized);
|
||
update_option('sidebars_widgets', $sidebars);
|
||
update_option('aksrt_sidebar_blog_seeded', true);
|
||
return;
|
||
}
|
||
|
||
if ($current !== null) {
|
||
if (!$seeded) {
|
||
update_option('aksrt_sidebar_blog_seeded', true);
|
||
}
|
||
return;
|
||
}
|
||
|
||
if ($seeded) {
|
||
return;
|
||
}
|
||
|
||
aksrt_ensure_widget_instance('widget_aksrt_about', 2, [
|
||
'title' => '',
|
||
]);
|
||
aksrt_ensure_widget_instance('widget_aksrt_categories', 2, [
|
||
'title' => __('分类目录', 'aksrt'),
|
||
'count' => 8,
|
||
]);
|
||
aksrt_ensure_widget_instance('widget_aksrt_tag_cloud', 2, [
|
||
'title' => __('标签云', 'aksrt'),
|
||
'count' => 15,
|
||
]);
|
||
|
||
$sidebars['sidebar-blog'] = [
|
||
'aksrt_about-2',
|
||
'aksrt_categories-2',
|
||
'aksrt_tag_cloud-2',
|
||
];
|
||
update_option('sidebars_widgets', $sidebars);
|
||
update_option('aksrt_sidebar_blog_seeded', true);
|
||
}
|
||
|
||
/**
|
||
* Register a block editor collection for AKSRT widgets.
|
||
*/
|
||
add_action('enqueue_block_editor_assets', function () {
|
||
$screen = get_current_screen();
|
||
if (!$screen || $screen->id !== 'widgets') {
|
||
return;
|
||
}
|
||
|
||
wp_add_inline_script('wp-blocks', '
|
||
document.addEventListener("DOMContentLoaded", function() {
|
||
if (typeof wp !== "undefined" && wp.blocks && wp.blocks.registerBlockCollection) {
|
||
wp.blocks.registerBlockCollection("aksrt", {
|
||
title: "AKSRT 主题小工具",
|
||
icon: undefined
|
||
});
|
||
}
|
||
});
|
||
');
|
||
});
|
||
|
||
/**
|
||
* Assign AKSRT widgets to the AKSRT block category in the widgets editor.
|
||
*
|
||
* @param array<string, mixed> $metadata Block metadata.
|
||
* @return array<string, mixed>
|
||
*/
|
||
add_filter('block_type_metadata', function ($metadata) {
|
||
$aksrt_widgets = [
|
||
'aksrt_about',
|
||
'aksrt_categories',
|
||
'aksrt_tag_cloud',
|
||
];
|
||
|
||
if (!empty($metadata['name']) && in_array($metadata['name'], $aksrt_widgets, true)) {
|
||
$metadata['category'] = 'aksrt';
|
||
}
|
||
|
||
return $metadata;
|
||
});
|
||
|
||
/**
|
||
* Show widget placement hints in the admin form.
|
||
*/
|
||
add_action('in_widget_form', function (WP_Widget $widget): void {
|
||
$map = [
|
||
'aksrt_about' => 'sidebar',
|
||
'aksrt_categories' => 'sidebar',
|
||
'aksrt_tag_cloud' => 'sidebar',
|
||
'aksrt_hot_posts' => 'sidebar',
|
||
'aksrt_tab_posts' => 'hybrid',
|
||
'aksrt_category_block' => 'hybrid',
|
||
'aksrt_category_tabs' => 'hybrid',
|
||
'aksrt_category_recommend' => 'homepage',
|
||
];
|
||
|
||
$scope = $map[$widget->id_base] ?? '';
|
||
if ($scope !== '') {
|
||
aksrt_widget_render_location_help($scope);
|
||
}
|
||
}, 10, 1);
|