true, 'single' => true, 'type' => 'string', ] ); register_post_meta( 'nav_menu_item', '_gb_menu_condition_invert', [ 'show_in_rest' => true, 'single' => true, 'type' => 'boolean', ] ); } /** * Get the conditions limit per page. */ private function get_conditions_limit() { return apply_filters( 'generateblocks_menu_conditions_limit', 100 ); } /** * Add condition fields to menu items. * * @param string $item_id Menu item ID as a numeric string. * @param WP_Post $menu_item Menu item data object. * @param int $depth Depth of menu item. Used for padding. * @param stdClass|null $args An object of menu item arguments. * @param int $current_object_id Nav menu ID. */ public function add_condition_fields( $item_id, $menu_item, $depth, $args, $current_object_id ) { $condition_id = get_post_meta( $item_id, '_gb_menu_condition', true ); $invert = get_post_meta( $item_id, '_gb_menu_condition_invert', true ); // Get conditions for dropdown. static $conditions_cache = null; if ( null === $conditions_cache ) { // Get the most recent conditions. $conditions_cache = get_posts( [ 'post_type' => 'gblocks_condition', 'posts_per_page' => $this->get_conditions_limit(), 'orderby' => 'date', 'order' => 'DESC', 'post_status' => 'publish', 'suppress_filters' => false, 'no_found_rows' => true, ] ); } $conditions = $conditions_cache; // Always include the currently selected condition if it's not in the list. if ( $condition_id && 'gblocks_condition' === get_post_type( $condition_id ) ) { $found = false; foreach ( $conditions as $condition ) { if ( $condition->ID === $condition_id ) { $found = true; break; } } if ( ! $found ) { $selected_condition = get_post( $condition_id ); if ( $selected_condition ) { // Add it to the list for this menu item only. $conditions = array_merge( [ $selected_condition ], $conditions ); } } } // Check if there are more conditions than we're showing. $total_conditions = wp_count_posts( 'gblocks_condition' )->publish; $has_more = $total_conditions > count( $conditions_cache ); ?>

ID; // Skip if already marked for removal. if ( in_array( $item_id, $removed_items, true ) ) { continue; } // Check if parent was removed. $parent_id = ! empty( $item->menu_item_parent ) ? (int) $item->menu_item_parent : 0; if ( $parent_id && in_array( $parent_id, $removed_items, true ) ) { $removed_items[] = $item_id; continue; } // Check condition. $condition_id = get_post_meta( $item_id, '_gb_menu_condition', true ); if ( $condition_id && ! $this->should_show_menu_item( $item_id, $condition_id ) ) { $removed_items[] = $item_id; } } // If no items were removed, return the original array. if ( empty( $removed_items ) ) { return $sorted_menu_items; } // Filter out removed items. $final_items = []; foreach ( $sorted_menu_items as $item ) { if ( ! in_array( (int) $item->ID, $removed_items, true ) ) { $final_items[] = $item; } } return $final_items; } /** * Check if a menu item should be shown based on its condition. * * @param int $menu_item_id The menu item ID. * @param string $condition_id The condition ID. * @return bool Whether to show the menu item. */ private function should_show_menu_item( $menu_item_id, $condition_id ) { $condition_id = absint( $condition_id ); if ( ! $condition_id ) { return true; } $invert_condition = get_post_meta( $menu_item_id, '_gb_menu_condition_invert', true ) === '1'; // Check cache first to avoid repeated evaluations. $cache_key = $condition_id . '_' . ( $invert_condition ? '1' : '0' ); if ( isset( $this->condition_cache[ $cache_key ] ) ) { return $this->condition_cache[ $cache_key ]; } // Default to showing the menu item. $show = true; // Check if the condition post exists and is published. $condition_post = get_post( $condition_id ); if ( $condition_post && 'publish' === $condition_post->post_status ) { // Get the condition data. $display_conditions = get_post_meta( $condition_id, '_gb_conditions', true ); if ( ! empty( $display_conditions ) ) { // Use the existing conditions system to evaluate. $show = GenerateBlocks_Pro_Conditions::show( $display_conditions ); // If invert is enabled, flip the result. if ( $invert_condition ) { $show = ! $show; } } } // Cache the result. $this->condition_cache[ $cache_key ] = $show; return $show; } /** * Add menu item conditions handler to usage search. * * @param array $handlers Existing handlers. * @param int $condition_id The condition ID. * @return array Modified handlers. */ public function add_menu_usage_handler( $handlers, $condition_id ) { $handlers['menu_item_conditions'] = [ 'method' => 'search_menu_item_conditions_usage', 'label' => __( 'Menu Item Conditions', 'generateblocks-pro' ), ]; return $handlers; } /** * AJAX handler for searching conditions. */ public function ajax_search_conditions() { // Verify nonce. if ( ! wp_verify_nonce( $_GET['_ajax_nonce'], 'gb_search_conditions' ) ) { wp_die(); } $search = isset( $_GET['search'] ) ? sanitize_text_field( $_GET['search'] ) : ''; $page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1; $per_page = $this->get_conditions_limit(); $args = [ 'post_type' => 'gblocks_condition', 'posts_per_page' => $per_page, 'paged' => $page, 'orderby' => 'date', 'order' => 'DESC', 'post_status' => 'publish', ]; if ( $search ) { $args['s'] = $search; $args['orderby'] = 'relevance'; } $conditions = get_posts( $args ); $total = wp_count_posts( 'gblocks_condition' )->publish; $results = []; foreach ( $conditions as $condition ) { $results[] = [ 'id' => $condition->ID, 'text' => $condition->post_title ? $condition->post_title : __( 'Untitled Condition', 'generateblocks-pro' ), ]; } wp_send_json( [ 'results' => $results, 'pagination' => [ 'more' => ( $page * $per_page ) < $total, ], ] ); } /** * AJAX handler for loading more conditions. */ public function ajax_load_more_conditions() { // Verify nonce. if ( ! wp_verify_nonce( $_GET['_ajax_nonce'], 'gb_load_more_conditions' ) ) { wp_die(); } $page = isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 2; $limit = $this->get_conditions_limit(); $offset = ( $page - 1 ) * $limit; $conditions = get_posts( [ 'post_type' => 'gblocks_condition', 'posts_per_page' => $limit, 'offset' => $offset, 'orderby' => 'date', 'order' => 'DESC', 'post_status' => 'publish', 'suppress_filters' => false, 'no_found_rows' => false, ] ); $formatted_conditions = []; foreach ( $conditions as $condition ) { $formatted_conditions[] = [ 'id' => $condition->ID, 'title' => $condition->post_title ? $condition->post_title : __( 'Untitled Condition', 'generateblocks-pro' ), ]; } $total = wp_count_posts( 'gblocks_condition' )->publish; $has_more = ( $page * $limit ) < $total; wp_send_json_success( [ 'conditions' => $formatted_conditions, 'has_more' => $has_more, ] ); } /** * Add admin scripts for dynamic UI behavior. * * @param string $hook_suffix The current admin page. */ public function add_admin_scripts( $hook_suffix ) { // Only load on nav-menus.php page. if ( 'nav-menus.php' !== $hook_suffix ) { return; } wp_enqueue_script( 'gb-menu-item-conditions', GENERATEBLOCKS_PRO_DIR_URL . 'dist/menu-item-conditions.js', array(), GENERATEBLOCKS_PRO_VERSION, true ); wp_localize_script( 'gb-menu-item-conditions', 'gbMenuConditions', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'nonces' => array( 'loadMore' => wp_create_nonce( 'gb_load_more_conditions' ), 'search' => wp_create_nonce( 'gb_search_conditions' ), ), 'strings' => array( 'loading' => __( 'Loading...', 'generateblocks-pro' ), 'loadMore' => __( 'Load More', 'generateblocks-pro' ), ), ) ); } } // Initialize the class. GenerateBlocks_Pro_Menu_Item_Conditions::get_instance()->init();