[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-navigation-fallback.php (source)

   1  <?php
   2  /**
   3   * WP_Navigation_Fallback class
   4   *
   5   * Manages fallback behavior for Navigation menus.
   6   *
   7   * @package WordPress
   8   * @subpackage Navigation
   9   * @since 6.3.0
  10   */
  11  
  12  /**
  13   * Manages fallback behavior for Navigation menus.
  14   *
  15   * @access public
  16   * @since 6.3.0
  17   */
  18  class WP_Navigation_Fallback {
  19  
  20      /**
  21       * Updates the wp_navigation custom post type schema, in order to expose
  22       * additional fields in the embeddable links of WP_REST_Navigation_Fallback_Controller.
  23       *
  24       * The Navigation Fallback endpoint may embed the full Navigation Menu object
  25       * into the response as the `self` link. By default, the Posts Controller
  26       * will only expose a limited subset of fields but the editor requires
  27       * additional fields to be available in order to utilize the menu.
  28       *
  29       * Used with the `rest_wp_navigation_item_schema` hook.
  30       *
  31       * @since 6.4.0
  32       *
  33       * @param array $schema The schema for the `wp_navigation` post.
  34       * @return array The modified schema.
  35       */
  36  	public static function update_wp_navigation_post_schema( $schema ) {
  37          // Expose top level fields.
  38          $schema['properties']['status']['context']  = array_merge( $schema['properties']['status']['context'], array( 'embed' ) );
  39          $schema['properties']['content']['context'] = array_merge( $schema['properties']['content']['context'], array( 'embed' ) );
  40  
  41          /*
  42           * Exposes sub properties of content field.
  43           * These sub properties aren't exposed by the posts controller by default,
  44           * for requests where context is `embed`.
  45           *
  46           * @see WP_REST_Posts_Controller::get_item_schema()
  47           */
  48          $schema['properties']['content']['properties']['raw']['context']           = array_merge( $schema['properties']['content']['properties']['raw']['context'], array( 'embed' ) );
  49          $schema['properties']['content']['properties']['rendered']['context']      = array_merge( $schema['properties']['content']['properties']['rendered']['context'], array( 'embed' ) );
  50          $schema['properties']['content']['properties']['block_version']['context'] = array_merge( $schema['properties']['content']['properties']['block_version']['context'], array( 'embed' ) );
  51  
  52          /*
  53           * Exposes sub properties of title field.
  54           * These sub properties aren't exposed by the posts controller by default,
  55           * for requests where context is `embed`.
  56           *
  57           * @see WP_REST_Posts_Controller::get_item_schema()
  58           */
  59          $schema['properties']['title']['properties']['raw']['context'] = array_merge( $schema['properties']['title']['properties']['raw']['context'], array( 'embed' ) );
  60  
  61          return $schema;
  62      }
  63  
  64      /**
  65       * Gets (and/or creates) an appropriate fallback Navigation Menu.
  66       *
  67       * @since 6.3.0
  68       *
  69       * @return WP_Post|null the fallback Navigation Post or null.
  70       */
  71  	public static function get_fallback() {
  72          /**
  73           * Filters whether or not a fallback should be created.
  74           *
  75           * @since 6.3.0
  76           *
  77           * @param bool $create Whether to create a fallback navigation menu. Default true.
  78           */
  79          $should_create_fallback = apply_filters( 'wp_navigation_should_create_fallback', true );
  80  
  81          $fallback = static::get_most_recently_published_navigation();
  82  
  83          if ( $fallback || ! $should_create_fallback ) {
  84              return $fallback;
  85          }
  86  
  87          $fallback = static::create_classic_menu_fallback();
  88  
  89          if ( $fallback && ! is_wp_error( $fallback ) ) {
  90              // Return the newly created fallback post object which will now be the most recently created navigation menu.
  91              return $fallback instanceof WP_Post ? $fallback : static::get_most_recently_published_navigation();
  92          }
  93  
  94          $fallback = static::create_default_fallback();
  95  
  96          if ( $fallback && ! is_wp_error( $fallback ) ) {
  97              // Return the newly created fallback post object which will now be the most recently created navigation menu.
  98              return $fallback instanceof WP_Post ? $fallback : static::get_most_recently_published_navigation();
  99          }
 100  
 101          return null;
 102      }
 103  
 104      /**
 105       * Finds the most recently published `wp_navigation` post type.
 106       *
 107       * @since 6.3.0
 108       *
 109       * @return WP_Post|null the first non-empty Navigation or null.
 110       */
 111  	private static function get_most_recently_published_navigation() {
 112  
 113          $parsed_args = array(
 114              'post_type'              => 'wp_navigation',
 115              'no_found_rows'          => true,
 116              'update_post_meta_cache' => false,
 117              'update_post_term_cache' => false,
 118              'order'                  => 'DESC',
 119              'orderby'                => 'date',
 120              'post_status'            => 'publish',
 121              'posts_per_page'         => 1,
 122          );
 123  
 124          $navigation_post = new WP_Query( $parsed_args );
 125  
 126          if ( count( $navigation_post->posts ) > 0 ) {
 127              return $navigation_post->posts[0];
 128          }
 129  
 130          return null;
 131      }
 132  
 133      /**
 134       * Creates a Navigation Menu post from a Classic Menu.
 135       *
 136       * @since 6.3.0
 137       *
 138       * @return int|WP_Error The post ID of the default fallback menu or a WP_Error object.
 139       */
 140  	private static function create_classic_menu_fallback() {
 141          // See if we have a classic menu.
 142          $classic_nav_menu = static::get_fallback_classic_menu();
 143  
 144          if ( ! $classic_nav_menu ) {
 145              return new WP_Error( 'no_classic_menus', __( 'No Classic Menus found.' ) );
 146          }
 147  
 148          // If there is a classic menu then convert it to blocks.
 149          $classic_nav_menu_blocks = WP_Classic_To_Block_Menu_Converter::convert( $classic_nav_menu );
 150  
 151          if ( is_wp_error( $classic_nav_menu_blocks ) ) {
 152              return $classic_nav_menu_blocks;
 153          }
 154  
 155          if ( empty( $classic_nav_menu_blocks ) ) {
 156              return new WP_Error( 'cannot_convert_classic_menu', __( 'Unable to convert Classic Menu to blocks.' ) );
 157          }
 158  
 159          // Create a new navigation menu from the classic menu.
 160          $classic_menu_fallback = wp_insert_post(
 161              array(
 162                  'post_content' => $classic_nav_menu_blocks,
 163                  'post_title'   => $classic_nav_menu->name,
 164                  'post_name'    => $classic_nav_menu->slug,
 165                  'post_status'  => 'publish',
 166                  'post_type'    => 'wp_navigation',
 167              ),
 168              true // So that we can check whether the result is an error.
 169          );
 170  
 171          return $classic_menu_fallback;
 172      }
 173  
 174      /**
 175       * Determines the most appropriate classic navigation menu to use as a fallback.
 176       *
 177       * @since 6.3.0
 178       *
 179       * @return WP_Term|null The most appropriate classic navigation menu to use as a fallback.
 180       */
 181  	private static function get_fallback_classic_menu() {
 182          $classic_nav_menus = wp_get_nav_menus();
 183  
 184          if ( ! $classic_nav_menus || is_wp_error( $classic_nav_menus ) ) {
 185              return null;
 186          }
 187  
 188          $nav_menu = static::get_nav_menu_at_primary_location();
 189  
 190          if ( $nav_menu ) {
 191              return $nav_menu;
 192          }
 193  
 194          $nav_menu = static::get_nav_menu_with_primary_slug( $classic_nav_menus );
 195  
 196          if ( $nav_menu ) {
 197              return $nav_menu;
 198          }
 199  
 200          return static::get_most_recently_created_nav_menu( $classic_nav_menus );
 201      }
 202  
 203  
 204      /**
 205       * Sorts the classic menus and returns the most recently created one.
 206       *
 207       * @since 6.3.0
 208       *
 209       * @param WP_Term[] $classic_nav_menus Array of classic nav menu term objects.
 210       * @return WP_Term The most recently created classic nav menu.
 211       */
 212  	private static function get_most_recently_created_nav_menu( $classic_nav_menus ) {
 213          usort(
 214              $classic_nav_menus,
 215              static function ( $a, $b ) {
 216                  return $b->term_id - $a->term_id;
 217              }
 218          );
 219  
 220          return $classic_nav_menus[0];
 221      }
 222  
 223      /**
 224       * Returns the classic menu with the slug `primary` if it exists.
 225       *
 226       * @since 6.3.0
 227       *
 228       * @param WP_Term[] $classic_nav_menus Array of classic nav menu term objects.
 229       * @return WP_Term|null The classic nav menu with the slug `primary` or null.
 230       */
 231  	private static function get_nav_menu_with_primary_slug( $classic_nav_menus ) {
 232          foreach ( $classic_nav_menus as $classic_nav_menu ) {
 233              if ( 'primary' === $classic_nav_menu->slug ) {
 234                  return $classic_nav_menu;
 235              }
 236          }
 237  
 238          return null;
 239      }
 240  
 241  
 242      /**
 243       * Gets the classic menu assigned to the `primary` navigation menu location
 244       * if it exists.
 245       *
 246       * @since 6.3.0
 247       *
 248       * @return WP_Term|null The classic nav menu assigned to the `primary` location or null.
 249       */
 250  	private static function get_nav_menu_at_primary_location() {
 251          $locations = get_nav_menu_locations();
 252  
 253          if ( isset( $locations['primary'] ) ) {
 254              $primary_menu = wp_get_nav_menu_object( $locations['primary'] );
 255  
 256              if ( $primary_menu ) {
 257                  return $primary_menu;
 258              }
 259          }
 260  
 261          return null;
 262      }
 263  
 264      /**
 265       * Creates a default Navigation Block Menu fallback.
 266       *
 267       * @since 6.3.0
 268       *
 269       * @return int|WP_Error The post ID of the default fallback menu or a WP_Error object.
 270       */
 271  	private static function create_default_fallback() {
 272  
 273          $default_blocks = static::get_default_fallback_blocks();
 274  
 275          // Create a new navigation menu from the fallback blocks.
 276          $default_fallback = wp_insert_post(
 277              array(
 278                  'post_content' => $default_blocks,
 279                  'post_title'   => _x( 'Navigation', 'Title of a Navigation menu' ),
 280                  'post_name'    => 'navigation',
 281                  'post_status'  => 'publish',
 282                  'post_type'    => 'wp_navigation',
 283              ),
 284              true // So that we can check whether the result is an error.
 285          );
 286  
 287          return $default_fallback;
 288      }
 289  
 290      /**
 291       * Gets the rendered markup for the default fallback blocks.
 292       *
 293       * @since 6.3.0
 294       *
 295       * @return string default blocks markup to use a the fallback.
 296       */
 297  	private static function get_default_fallback_blocks() {
 298          $registry = WP_Block_Type_Registry::get_instance();
 299  
 300          // If `core/page-list` is not registered then use empty blocks.
 301          return $registry->is_registered( 'core/page-list' ) ? '<!-- wp:page-list /-->' : '';
 302      }
 303  }


Generated : Sat Apr 27 08:20:02 2024 Cross-referenced by PHPXref