*/ private $all_hidden = array(); /** * Constructor. * * @param BlockVisibility $visibility Block visibility. */ public function __construct( BlockVisibility $visibility ) { $this->visibility = $visibility; } /** * Registers hooks. * * @return void */ public function register(): void { add_filter( 'block_core_navigation_render_inner_blocks', array( $this, 'check_items' ) ); add_filter( 'render_block_core/navigation', array( $this, 'render_navigation' ), 20 ); add_filter( 'render_block_core/navigation-submenu', array( $this, 'render_submenu' ), 20 ); } /** * Notes whether our rules hide every top-level item of the Navigation block * about to render. The items aren't changed. * * Runs while the block renders, after WordPress picked the items (from the * block, its menu, or a fallback), so hiding items never triggers a fallback. * * @param mixed $inner_blocks The Navigation block's items (a WP_Block_List). * @return mixed The items, unchanged. */ public function check_items( $inner_blocks ) { $hidden = 0; $shown = 0; if ( is_iterable( $inner_blocks ) && $this->visibility->applies() ) { foreach ( $inner_blocks as $inner_block ) { if ( $inner_block instanceof WP_Block && $this->visibility->is_hidden( $inner_block->parsed_block ) ) { ++$hidden; } else { ++$shown; } } } // Only when our rules hid the items: an already empty menu behaves as WordPress normally does. $this->all_hidden[] = $hidden > 0 && 0 === $shown; return $inner_blocks; } /** * Renders nothing for a Navigation block whose items our rules all hid. * * @param mixed $block_content Rendered Navigation block. * @return mixed */ public function render_navigation( $block_content ) { $all_hidden = array_pop( $this->all_hidden ); return true === $all_hidden ? '' : $block_content; } /** * Turns a Submenu with an empty sub-item list into a plain item: removes the * empty list, the submenu toggle or icon, and the `has-child` class. * * Only its own list can be empty here: nested Submenus render (and are * cleaned) first, and an empty list means there's nothing nested left. * * @param mixed $block_content Rendered Submenu block. * @return mixed */ public function render_submenu( $block_content ) { if ( ! is_string( $block_content ) || '' === $block_content || ! $this->visibility->applies() ) { return $block_content; } $empty_list = '#