[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |