Advance Widget Pack screen letting the site owner * enable/disable individual widgets and blocks. Disabling a feature only * hides it from being added new (the widget picker, or the block inserter * via allowed_block_types_all) — anywhere it's already placed keeps * rendering normally, so turning a feature off can't silently break an * existing sidebar or post. */ class Awp_Settings { const OPTION = 'awp_enabled_features'; /** * Registry of every AWP feature: which widget class and/or block name it * corresponds to, and its display label. A feature may have a widget, a * block, or both — disabling it hides whichever surfaces it has. * * @return array[] Keyed by feature slug. */ public static function get_features() { return array( 'recent-posts' => array( 'label' => __( 'Recent Posts', 'advance-widget-pack' ), 'widget' => 'Awp_Recent_Post', 'block' => 'advance-widget-pack/recent-posts', ), 'popular-posts' => array( 'label' => __( 'Popular Posts', 'advance-widget-pack' ), 'widget' => 'Awp_Popular_Post', 'block' => 'advance-widget-pack/popular-posts', ), 'random-posts' => array( 'label' => __( 'Random Posts', 'advance-widget-pack' ), 'widget' => 'Awp_Random_Post', 'block' => null, ), 'featured-posts' => array( 'label' => __( 'Featured Posts', 'advance-widget-pack' ), 'widget' => 'Awp_Feature_Post', 'block' => null, ), 'recent-comments' => array( 'label' => __( 'Recent Comments', 'advance-widget-pack' ), 'widget' => 'Awp_Recent_Comments', 'block' => null, ), 'author-details' => array( 'label' => __( 'Author Details', 'advance-widget-pack' ), 'widget' => 'Awp_Author_Bio', 'block' => null, ), 'author-list' => array( 'label' => __( 'Author List', 'advance-widget-pack' ), 'widget' => 'Awp_Author_List', 'block' => null, ), 'related-posts' => array( 'label' => __( 'Related Posts', 'advance-widget-pack' ), 'widget' => 'Awp_Related_Posts', 'block' => 'advance-widget-pack/related-posts', ), 'tag-cloud' => array( 'label' => __( 'Tag Cloud', 'advance-widget-pack' ), 'widget' => 'Awp_Tag_Cloud', 'block' => 'advance-widget-pack/tag-cloud', ), 'social-links' => array( 'label' => __( 'Social Links', 'advance-widget-pack' ), 'widget' => 'Awp_Social_Links', 'block' => 'advance-widget-pack/social-links', ), 'top-authors' => array( 'label' => __( 'Top Authors', 'advance-widget-pack' ), 'widget' => 'Awp_Top_Authors', 'block' => 'advance-widget-pack/top-authors', ), 'table-of-contents' => array( 'label' => __( 'Table of Contents', 'advance-widget-pack' ), 'widget' => 'Awp_Table_Of_Contents', 'block' => 'advance-widget-pack/table-of-contents', ), 'countdown-timer' => array( 'label' => __( 'Countdown Timer', 'advance-widget-pack' ), 'widget' => null, 'block' => 'advance-widget-pack/countdown-timer', ), 'reading-progress-bar' => array( 'label' => __( 'Reading Progress Bar', 'advance-widget-pack' ), 'widget' => null, 'block' => 'advance-widget-pack/reading-progress-bar', ), ); } /** * Whether a given feature is currently enabled. * * @param string $feature_slug One of the keys from get_features(). * @return bool */ public static function is_enabled( $feature_slug ) { $enabled = get_option( self::OPTION ); // No option saved yet (fresh install or pre-settings-page upgrade): // everything is enabled by default so existing behavior is unchanged. if ( false === $enabled || ! is_array( $enabled ) ) { return true; } return ! empty( $enabled[ $feature_slug ] ); } public function __construct() { add_action( 'admin_menu', array( $this, 'add_menu' ) ); add_action( 'admin_init', array( $this, 'register_setting' ) ); add_filter( 'allowed_block_types_all', array( $this, 'filter_allowed_blocks' ), 10, 2 ); // Hide disabled widgets from the "Available Widgets" list on both the // classic wp-admin/widgets.php screen and the Customizer widgets // panel, without touching registration (existing sidebar placements // keep rendering — dynamic_sidebar() calls the widget directly and // never consults this "available" list). add_action( 'load-widgets.php', array( $this, 'hide_disabled_widgets_from_factory' ) ); add_action( 'customize_register', array( $this, 'hide_disabled_widgets_from_factory' ), 20 ); // Hide disabled widgets from the block-based widgets screen's Legacy // Widget block dropdown. add_filter( 'widget_types_to_hide_from_legacy_widget_block', array( $this, 'filter_legacy_widget_block_list' ) ); } /** * Removes disabled widget classes from $wp_widget_factory->widgets so * they no longer appear in the "Available Widgets" picker. Only hooked * on the admin screens where that list is built (see __construct()), so * normal widgets_init registration and sidebar rendering are unaffected. */ public function hide_disabled_widgets_from_factory() { global $wp_widget_factory; foreach ( self::get_features() as $slug => $feature ) { if ( $feature['widget'] && ! self::is_enabled( $slug ) ) { unset( $wp_widget_factory->widgets[ $feature['widget'] ] ); } } } /** * Hides disabled widgets from the block-based widgets screen's Legacy * Widget block dropdown, keyed by id_base rather than class name. * * Deliberately does NOT look up id_base via $wp_widget_factory->widgets: * hide_disabled_widgets_from_factory() may have already unset the same * disabled widgets from that array earlier in the same request (both are * hooked on admin screens that can run together), which would make the * lookup fail here. Instead each class's own id_base is resolved directly * by instantiating it once, independent of the factory's current state. * * @param string[] $widgets List of widget id_base slugs to hide. * @return string[] */ public function filter_legacy_widget_block_list( $widgets ) { foreach ( self::get_features() as $slug => $feature ) { if ( ! $feature['widget'] || self::is_enabled( $slug ) ) { continue; } if ( class_exists( $feature['widget'] ) ) { $widgets[] = ( new $feature['widget']() )->id_base; } } return $widgets; } /** * Adds Settings > Advance Widget Pack. */ public function add_menu() { add_options_page( __( 'Advance Widget Pack', 'advance-widget-pack' ), __( 'Advance Widget Pack', 'advance-widget-pack' ), 'manage_options', 'advance-widget-pack', array( $this, 'render_page' ) ); } /** * Registers the enabled-features option. */ public function register_setting() { register_setting( 'awp_settings_group', self::OPTION, array( 'type' => 'array', 'sanitize_callback' => array( $this, 'sanitize' ), 'default' => self::all_enabled_default(), ) ); } /** * Default option value: every feature enabled, matching pre-settings-page * behavior so activating this version changes nothing until the site * owner opts to disable something. * * @return array */ private static function all_enabled_default() { return array_fill_keys( array_keys( self::get_features() ), 1 ); } /** * Sanitizes the posted checkbox list into a slug => 1 map, dropping any * unknown keys and ensuring every known feature has an explicit value. * * @param array $input Raw posted values. * @return array */ public function sanitize( $input ) { $input = (array) $input; $output = array(); foreach ( array_keys( self::get_features() ) as $slug ) { $output[ $slug ] = ! empty( $input[ $slug ] ) ? 1 : 0; } return $output; } /** * Hides disabled blocks from the block inserter. Blocks stay registered * (see awp_register_blocks() in the main plugin file), so a block * instance already placed in a post keeps rendering even after this * filter removes it from the "add new block" list. * * @param bool[]|true $allowed_block_types Array of allowed block type slugs, or true (all allowed). * @param WP_Block_Editor_Context $context Editor context (unused). * @return bool[]|true */ public function filter_allowed_blocks( $allowed_block_types, $context ) { $disabled_blocks = array(); foreach ( self::get_features() as $slug => $feature ) { if ( $feature['block'] && ! self::is_enabled( $slug ) ) { $disabled_blocks[] = $feature['block']; } } if ( ! $disabled_blocks ) { return $allowed_block_types; } // If core/other plugins already returned a specific allow-list, just // remove our disabled ones from it. Otherwise (true = "all allowed"), // build a full list of every registered block minus our disabled ones. if ( true === $allowed_block_types ) { $allowed_block_types = wp_list_pluck( WP_Block_Type_Registry::get_instance()->get_all_registered(), 'name' ); } return array_values( array_diff( $allowed_block_types, $disabled_blocks ) ); } /** * Renders the settings page: one checkbox per feature. */ public function render_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } ?>

$feature ) : ?>
/>