*/ function aksrt_widget_sidebar_area_ids(): array { return [ 'home_sidebar', '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 */ 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 */ 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 */ 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 */ function aksrt_widget_allowed_sidebars(string $widget_base_id): array { $sidebar_only = [ '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() ))); } if ($widget_base_id === 'aksrt_post_pay_box') { return ['sidebar-article']; } 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'; } } 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( '

%s

', 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 (Zibll only_pc / only_sm). if ($normalized['show_type'] === 'only_pc' && wp_is_mobile()) { return false; } if ($normalized['show_type'] === 'only_sm' && !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); /** * 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 $metadata Block metadata. * @return array */ add_filter('block_type_metadata', function ($metadata) { $aksrt_widgets = [ '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_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);