PluginProbe
Gutenberg / 12.1.0
Gutenberg v12.1.0
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
← All changes | lib/navigation.php +222 -14 12.6.012.1.0 View file →
@@ -36,10 +36,11 @@
36 36 'labels' => $labels,
37 37 'description' => __( 'Navigation menus.', 'gutenberg' ),
38 38 'public' => false,
39 39 'has_archive' => false,
40 - 'show_ui' => true,
41 - 'show_in_menu' => false,
40 + // We should disable UI for non-FSE themes.
41 + 'show_ui' => gutenberg_is_fse_theme(),
42 + 'show_in_menu' => 'themes.php',
42 43 'show_in_admin_bar' => false,
43 44 'show_in_rest' => true,
44 45 'map_meta_cap' => true,
45 46 'rest_base' => 'navigation',
@@ -48,20 +49,8 @@
48 49 'title',
49 50 'editor',
50 51 'revisions',
51 52 ),
52 - 'capabilities' => array(
53 - 'edit_others_posts' => 'edit_theme_options',
54 - 'delete_posts' => 'edit_theme_options',
55 - 'publish_posts' => 'edit_theme_options',
56 - 'create_posts' => 'edit_theme_options',
57 - 'read_private_posts' => 'edit_theme_options',
58 - 'delete_private_posts' => 'edit_theme_options',
59 - 'delete_published_posts' => 'edit_theme_options',
60 - 'delete_others_posts' => 'edit_theme_options',
61 - 'edit_private_posts' => 'edit_theme_options',
62 - 'edit_published_posts' => 'edit_theme_options',
63 - ),
64 53 );
65 54
66 55 register_post_type( 'wp_navigation', $args );
67 56 }
@@ -192,8 +181,114 @@
192 181 return $gutenberg_navigation_areas;
193 182 }
194 183
195 184 /**
185 + * Returns the API paths to preload to make the navigation area block load fast.
186 + *
187 + * @return array A list of paths.
188 + */
189 +function gutenberg_get_navigation_areas_paths_to_preload() {
190 + $areas = gutenberg_get_navigation_areas_menus();
191 + $active_areas = array_intersect_key( $areas, gutenberg_get_navigation_areas() );
192 + $paths = array(
193 + '/wp/v2/block-navigation-areas?context=edit',
194 + );
195 + foreach ( $active_areas as $post_id ) {
196 + if ( 0 !== $post_id ) {
197 + $paths[] = "/wp/v2/navigation/$post_id?context=edit";
198 + }
199 + }
200 + return $paths;
201 +}
202 +
203 +/**
204 + * Migrates classic menus to a block-based navigation post on theme switch.
205 + * Assigns the created navigation post to the corresponding navigation area.
206 + *
207 + * @param string $new_name Name of the new theme.
208 + * @param WP_Theme $new_theme New theme.
209 + * @param WP_Theme $old_theme Old theme.
210 + * @see switch_theme WordPress action.
211 + */
212 +function gutenberg_migrate_menu_to_navigation_post( $new_name, $new_theme, $old_theme ) {
213 + // Do nothing when switching to a theme that does not support site editor.
214 + if ( ! gutenberg_experimental_is_site_editor_available() ) {
215 + return;
216 + }
217 +
218 + // get_nav_menu_locations() calls get_theme_mod() which depends on the stylesheet option.
219 + // At the same time, switch_theme runs only after the stylesheet option was updated to $new_theme.
220 + // To retrieve theme mods of the old theme, the getter is hooked to get_option( 'stylesheet' ) so that we
221 + // get the old theme, which causes the get_nav_menu_locations to get the locations of the old theme.
222 + $get_old_theme_stylesheet = function() use ( $old_theme ) {
223 + return $old_theme->get_stylesheet();
224 + };
225 + add_filter( 'option_stylesheet', $get_old_theme_stylesheet );
226 +
227 + $locations = get_nav_menu_locations();
228 + $area_mapping = gutenberg_get_navigation_areas_menus();
229 +
230 + foreach ( $locations as $location_name => $menu_id ) {
231 + // Get the menu from the location, skipping if there is no
232 + // menu or there was an error.
233 + $menu = wp_get_nav_menu_object( $menu_id );
234 + if ( ! $menu || is_wp_error( $menu ) ) {
235 + continue;
236 + }
237 +
238 + $menu_items = gutenberg_get_menu_items_at_location( $location_name );
239 + if ( empty( $menu_items ) ) {
240 + continue;
241 + }
242 +
243 + $post_name = 'classic_menu_' . $menu_id;
244 + $post_status = 'publish';
245 +
246 + // Get or create to avoid creating too many wp_navigation posts.
247 + $query = new WP_Query;
248 + $matching_posts = $query->query(
249 + array(
250 + 'name' => $post_name,
251 + 'post_status' => $post_status,
252 + 'post_type' => 'wp_navigation',
253 + 'posts_per_page' => 1,
254 + )
255 + );
256 +
257 + if ( count( $matching_posts ) ) {
258 + $navigation_post_id = $matching_posts[0]->ID;
259 + } else {
260 + $menu_items_by_parent_id = gutenberg_sort_menu_items_by_parent_id( $menu_items );
261 + $parsed_blocks = gutenberg_parse_blocks_from_menu_items( $menu_items_by_parent_id[0], $menu_items_by_parent_id );
262 + $post_data = array(
263 + 'post_type' => 'wp_navigation',
264 + 'post_title' => sprintf(
265 + /* translators: %s: the name of the menu, e.g. "Main Menu". */
266 + __( 'Classic menu: %s', 'gutenberg' ),
267 + $menu->name
268 + ),
269 + 'post_name' => $post_name,
270 + 'post_content' => serialize_blocks( $parsed_blocks ),
271 + 'post_status' => $post_status,
272 + );
273 + $navigation_post_id = wp_insert_post( $post_data, true );
274 + // If wp_insert_post fails *at any time*, then bale out of the entire
275 + // migration attempt returning the WP_Error object.
276 + if ( is_wp_error( $navigation_post_id ) ) {
277 + return $navigation_post_id;
278 + }
279 + }
280 +
281 + $area_mapping[ $location_name ] = $navigation_post_id;
282 + }
283 + remove_filter( 'option_stylesheet', $get_old_theme_stylesheet );
284 +
285 + update_option( 'wp_navigation_areas', $area_mapping );
286 +}
287 +
288 +add_action( 'switch_theme', 'gutenberg_migrate_menu_to_navigation_post', 99, 3 );
289 +
290 +/**
196 291 * Retrieves navigation areas.
197 292 *
198 293 * @return array Navigation areas.
199 294 */
@@ -206,8 +301,121 @@
206 301 $legacy_option_key = 'fse_navigation_areas';
207 302 $areas = get_option( $legacy_option_key, array() );
208 303 }
209 304 return $areas;
305 +}
306 +
307 +// The functions below are copied over from packages/block-library/src/navigation/index.php
308 +// Let's figure out a better way of managing these global PHP dependencies.
309 +
310 +/**
311 + * Returns the menu items for a WordPress menu location.
312 + *
313 + * @param string $location The menu location.
314 + * @return array Menu items for the location.
315 + */
316 +function gutenberg_get_menu_items_at_location( $location ) {
317 + if ( empty( $location ) ) {
318 + return;
319 + }
320 +
321 + // Build menu data. The following approximates the code in
322 + // `wp_nav_menu()` and `gutenberg_output_block_nav_menu`.
323 +
324 + // Find the location in the list of locations, returning early if the
325 + // location can't be found.
326 + $locations = get_nav_menu_locations();
327 + if ( ! isset( $locations[ $location ] ) ) {
328 + return;
329 + }
330 +
331 + // Get the menu from the location, returning early if there is no
332 + // menu or there was an error.
333 + $menu = wp_get_nav_menu_object( $locations[ $location ] );
334 + if ( ! $menu || is_wp_error( $menu ) ) {
335 + return;
336 + }
337 +
338 + $menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) );
339 + _wp_menu_item_classes_by_context( $menu_items );
340 +
341 + return $menu_items;
342 +}
343 +
344 +
345 +/**
346 + * Sorts a standard array of menu items into a nested structure keyed by the
347 + * id of the parent menu.
348 + *
349 + * @param array $menu_items Menu items to sort.
350 + * @return array An array keyed by the id of the parent menu where each element
351 + * is an array of menu items that belong to that parent.
352 + */
353 +function gutenberg_sort_menu_items_by_parent_id( $menu_items ) {
354 + $sorted_menu_items = array();
355 + foreach ( (array) $menu_items as $menu_item ) {
356 + $sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
357 + }
358 + unset( $menu_items, $menu_item );
359 +
360 + $menu_items_by_parent_id = array();
361 + foreach ( $sorted_menu_items as $menu_item ) {
362 + $menu_items_by_parent_id[ $menu_item->menu_item_parent ][] = $menu_item;
363 + }
364 +
365 + return $menu_items_by_parent_id;
366 +}
367 +
368 +/**
369 + * Turns menu item data into a nested array of parsed blocks
370 + *
371 + * @param array $menu_items An array of menu items that represent
372 + * an individual level of a menu.
373 + * @param array $menu_items_by_parent_id An array keyed by the id of the
374 + * parent menu where each element is an
375 + * array of menu items that belong to
376 + * that parent.
377 + * @return array An array of parsed block data.
378 + */
379 +function gutenberg_parse_blocks_from_menu_items( $menu_items, $menu_items_by_parent_id ) {
380 + if ( empty( $menu_items ) ) {
381 + return array();
382 + }
383 +
384 + $blocks = array();
385 +
386 + foreach ( $menu_items as $menu_item ) {
387 + $class_name = ! empty( $menu_item->classes ) ? implode( ' ', (array) $menu_item->classes ) : null;
388 + $id = ( null !== $menu_item->object_id && 'custom' !== $menu_item->object ) ? $menu_item->object_id : null;
389 + $opens_in_new_tab = null !== $menu_item->target && '_blank' === $menu_item->target;
390 + $rel = ( null !== $menu_item->xfn && '' !== $menu_item->xfn ) ? $menu_item->xfn : null;
391 + $kind = null !== $menu_item->type ? str_replace( '_', '-', $menu_item->type ) : 'custom';
392 +
393 + $block = array(
394 + 'blockName' => isset( $menu_items_by_parent_id[ $menu_item->ID ] ) ? 'core/navigation-submenu' : 'core/navigation-link',
395 + 'attrs' => array(
396 + 'className' => $class_name,
397 + 'description' => $menu_item->description,
398 + 'id' => $id,
399 + 'kind' => $kind,
400 + 'label' => $menu_item->title,
401 + 'opensInNewTab' => $opens_in_new_tab,
402 + 'rel' => $rel,
403 + 'title' => $menu_item->attr_title,
404 + 'type' => $menu_item->object,
405 + 'url' => $menu_item->url,
406 + ),
407 + );
408 +
409 + $block['innerBlocks'] = isset( $menu_items_by_parent_id[ $menu_item->ID ] )
410 + ? gutenberg_parse_blocks_from_menu_items( $menu_items_by_parent_id[ $menu_item->ID ], $menu_items_by_parent_id )
411 + : array();
412 + $block['innerContent'] = array_map( 'serialize_block', $block['innerBlocks'] );
413 +
414 + $blocks[] = $block;
415 + }
416 +
417 + return $blocks;
210 418 }
211 419
212 420 /**
213 421 * Shim that hides ability to edit visibility and status for wp_navigation type posts.