sanitizer = $sanitizer; $this->index = $index; } /** * Every menu item with an active rule, most recently changed menu first, * then in menu order. * * `menu` is where the item is: a classic menu's ID, or the ID of the post * that holds the Navigation block (a Navigation menu, template, template * part or other content). * * @return array, modified: int}> */ public function all(): array { $items = array_merge( $this->classic(), $this->navigation() ); // usort() isn't stable on PHP 7.4, so ties keep their menu order by position. $order = array_flip( array_column( $items, 'key' ) ); usort( $items, static function ( array $a, array $b ) use ( $order ): int { return array( $b['modified'], $order[ $a['key'] ] ) <=> array( $a['modified'], $order[ $b['key'] ] ); } ); return $items; } /** * Whether a sanitized rule is on and has at least one condition. * * @param array $rule Sanitized rule. * @return bool */ public static function is_active( array $rule ): bool { if ( empty( $rule['enabled'] ) ) { return false; } foreach ( (array) ( $rule['groups'] ?? array() ) as $group ) { if ( ! empty( $group['conditions'] ) ) { return true; } } return false; } /** * Classic menu items with an active rule. Items not saved in a menu yet * (drafts) are left out. * * @return array, modified: int}> */ private function classic(): array { $ids = get_posts( array( 'post_type' => 'nav_menu_item', 'post_status' => 'publish', 'posts_per_page' => -1, 'fields' => 'ids', 'orderby' => 'menu_order', 'order' => 'ASC', 'no_found_rows' => true, 'meta_key' => ClassicMenuFilter::META_KEY, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Admin only, menu items with a rule. ) ); $ids = array_map( 'intval', $ids ); update_meta_cache( 'post', $ids ); update_object_term_cache( $ids, 'nav_menu_item' ); $items = array(); foreach ( $ids as $id ) { $rule = $this->sanitizer->sanitize( get_post_meta( $id, ClassicMenuFilter::META_KEY, true ) ); $post = get_post( $id ); $menu = get_the_terms( $id, 'nav_menu' ); if ( ! self::is_active( $rule ) || null === $post || ! is_array( $menu ) || array() === $menu ) { continue; } $item = wp_setup_nav_menu_item( $post ); $items[] = array( 'key' => 'classic-' . $id, 'label' => trim( html_entity_decode( wp_strip_all_tags( (string) ( $item->title ?? '' ) ), ENT_QUOTES, 'UTF-8' ) ), 'source' => 'classic', 'menu' => (int) $menu[0]->term_id, 'menu_name' => $menu[0]->name, 'menu_type' => __( 'Classic menu', 'yangra-conditional' ), 'edit_url' => admin_url( 'nav-menus.php?action=edit&menu=' . (int) $menu[0]->term_id ), 'rule' => $rule, 'modified' => (int) strtotime( $post->post_modified_gmt . ' UTC' ), ); } return $items; } /** * Navigation items with an active rule, from the content index. * * @return array, modified: int}> */ private function navigation(): array { $items = array(); foreach ( $this->index->live_posts() as $post_id => $index ) { $list = isset( $index['menu_list'] ) && is_array( $index['menu_list'] ) ? $index['menu_list'] : array(); $post = array() === $list ? null : get_post( $post_id ); if ( null === $post ) { continue; } $type = get_post_type_object( $post->post_type ); foreach ( $list as $position => $entry ) { $rule = $this->sanitizer->sanitize( $entry['rule'] ?? null ); if ( ! self::is_active( $rule ) ) { continue; } $items[] = array( 'key' => 'navigation-' . $post_id . '-' . $position, 'label' => isset( $entry['label'] ) ? (string) $entry['label'] : '', 'source' => 'navigation', 'menu' => (int) $post_id, 'menu_name' => trim( html_entity_decode( wp_strip_all_tags( $post->post_title ), ENT_QUOTES, 'UTF-8' ) ), 'menu_type' => null !== $type ? (string) $type->labels->singular_name : $post->post_type, 'edit_url' => (string) get_edit_post_link( $post_id, 'raw' ), 'rule' => $rule, 'modified' => (int) strtotime( $post->post_modified_gmt . ' UTC' ), ); } } return $items; } }