= $dismissed_until ); } /** * Render the FSE feature-limitation warning notice. */ public static function render_feature_limitation_notice() { if ( ! self::should_show_feature_limitation_notice() ) { return; } ?>

:

__( 'Unauthorized action.', 'advance-menu-manager' ) ), 403 ); } $user_id = get_current_user_id(); if ( $user_id <= 0 ) { wp_send_json_error( array( 'message' => __( 'Invalid user.', 'advance-menu-manager' ) ), 400 ); } update_user_meta( $user_id, self::FEATURE_NOTICE_META, time() + self::FEATURE_NOTICE_DISMISS_SECONDS ); wp_send_json_success(); } /** * Whether Core classic→block converter is available (WP 6.3+). * * @return bool */ public static function is_supported() { return class_exists( 'WP_Classic_To_Block_Menu_Converter' ); } /** * Pause sync while AMM is still updating menu item meta. */ public static function defer() { self::$deferred = true; } /** * Resume sync and flush any pending menu IDs. * * @param array $extra_menu_ids Extra classic menu IDs to sync now. * @param array $aliases Optional name/slug aliases keyed by menu ID. */ public static function resume( $extra_menu_ids = array(), $aliases = array() ) { self::$deferred = false; $menu_ids = array_unique( array_filter( array_map( 'absint', array_merge( self::$pending_menu_ids, (array) $extra_menu_ids ) ) ) ); self::$pending_menu_ids = array(); foreach ( $menu_ids as $menu_id ) { $menu_aliases = isset( $aliases[ $menu_id ] ) ? (array) $aliases[ $menu_id ] : array(); self::sync_classic_menu( $menu_id, $menu_aliases ); } } /** * Handle core menu updates. * * @param int $menu_id Classic menu term ID. */ public static function on_wp_update_nav_menu( $menu_id ) { $menu_id = absint( $menu_id ); if ( $menu_id <= 0 ) { return; } if ( self::$deferred ) { self::$pending_menu_ids[] = $menu_id; return; } self::sync_classic_menu( $menu_id ); } /** * Convert a classic menu and overwrite matching wp_navigation posts. * * @param int $menu_id Classic menu term ID. * @param array $aliases Extra titles/slugs to match (e.g. previous menu name). * @return int Number of wp_navigation posts updated. */ public static function sync_classic_menu( $menu_id, $aliases = array() ) { if ( ! self::is_supported() ) { return 0; } $menu_id = absint( $menu_id ); if ( $menu_id <= 0 ) { return 0; } $menu = wp_get_nav_menu_object( $menu_id ); if ( ! $menu || is_wp_error( $menu ) ) { return 0; } $block_markup = WP_Classic_To_Block_Menu_Converter::convert( $menu ); if ( is_wp_error( $block_markup ) ) { return 0; } $match_tokens = self::build_match_tokens( $menu, $aliases ); $navigations = self::get_navigation_posts(); $updated = 0; foreach ( $navigations as $navigation ) { if ( ! self::navigation_matches( $navigation, $match_tokens ) ) { continue; } $result = wp_update_post( array( 'ID' => (int) $navigation->ID, 'post_content' => $block_markup, ), true ); if ( ! is_wp_error( $result ) ) { $updated++; } } /** * Fires after a classic menu has been synced to matching Navigation posts. * * @param int $menu_id Classic menu term ID. * @param WP_Term $menu Classic menu object. * @param int $updated Number of Navigation posts updated. * @param string $block_markup Serialized Navigation inner blocks. */ do_action( 'dsamm_classic_menu_synced_to_navigation', $menu_id, $menu, $updated, $block_markup ); return $updated; } /** * Build match tokens from classic menu + aliases. * * @param WP_Term $menu Classic menu. * @param array $aliases Extra names/slugs. * @return array */ private static function build_match_tokens( $menu, $aliases = array() ) { $tokens = array( self::normalize_token( $menu->name ), self::normalize_token( $menu->slug ), self::normalize_token( sanitize_title( $menu->name ) ), ); foreach ( (array) $aliases as $alias ) { if ( ! is_string( $alias ) || '' === $alias ) { continue; } $tokens[] = self::normalize_token( $alias ); $tokens[] = self::normalize_token( sanitize_title( $alias ) ); } return array_values( array_unique( array_filter( $tokens ) ) ); } /** * Whether a Navigation post matches classic menu tokens. * * @param WP_Post $navigation Navigation post. * @param array $tokens Normalized match tokens. * @return bool */ private static function navigation_matches( $navigation, $tokens ) { $candidates = array( self::normalize_token( $navigation->post_title ), self::normalize_token( $navigation->post_name ), self::normalize_token( sanitize_title( $navigation->post_title ) ), ); foreach ( $candidates as $candidate ) { if ( '' !== $candidate && in_array( $candidate, $tokens, true ) ) { return true; } } return false; } /** * Normalize a title/slug for comparison. * * @param string $value Raw value. * @return string */ private static function normalize_token( $value ) { $value = is_string( $value ) ? trim( $value ) : ''; if ( '' === $value ) { return ''; } return strtolower( $value ); } /** * Fetch all Navigation menu posts. * * @return WP_Post[] */ private static function get_navigation_posts() { $posts = get_posts( array( 'post_type' => 'wp_navigation', 'post_status' => array( 'publish', 'draft', 'private' ), 'numberposts' => -1, 'orderby' => 'ID', 'order' => 'ASC', 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) ); return is_array( $posts ) ? $posts : array(); } }