Editor: Add Navigation Area infrastructure
Copies Navigation Area infrastrucutre from lib/navigation.php in Gutenberg. This allows a Navigation block to be associated with a particular area which persists when switching theme. Props antonvlasenko, mamaduka, spacedmonkey. See #54337. Built from https://develop.svn.wordpress.org/trunk@52145 git-svn-id: http://core.svn.wordpress.org/trunk@51737 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
2128238311
commit
93d4851bbf
|
@ -2447,3 +2447,63 @@ function the_block_editor_meta_box_post_form_hidden_fields( $post ) {
|
||||||
*/
|
*/
|
||||||
do_action( 'block_editor_meta_box_hidden_fields', $post );
|
do_action( 'block_editor_meta_box_hidden_fields', $post );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable block editor for wp_navigation type posts so they can be managed via the UI.
|
||||||
|
*
|
||||||
|
* @since 5.9.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param bool $value Whether the CPT supports block editor or not.
|
||||||
|
* @param string $post_type Post type.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function _disable_block_editor_for_navigation_post_type( $value, $post_type ) {
|
||||||
|
if ( 'wp_navigation' === $post_type ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This callback disables the content editor for wp_navigation type posts.
|
||||||
|
* Content editor cannot handle wp_navigation type posts correctly.
|
||||||
|
* We cannot disable the "editor" feature in the wp_navigation's CPT definition
|
||||||
|
* because it disables the ability to save navigation blocks via REST API.
|
||||||
|
*
|
||||||
|
* @since 5.9.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param WP_Post $post An instance of WP_Post class.
|
||||||
|
*/
|
||||||
|
function _disable_content_editor_for_navigation_post_type( $post ) {
|
||||||
|
$post_type = get_post_type( $post );
|
||||||
|
if ( 'wp_navigation' !== $post_type ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_post_type_support( $post_type, 'editor' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This callback enables content editor for wp_navigation type posts.
|
||||||
|
* We need to enable it back because we disable it to hide
|
||||||
|
* the content editor for wp_navigation type posts.
|
||||||
|
*
|
||||||
|
* @since 5.9.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @see _disable_content_editor_for_navigation_post_type
|
||||||
|
*
|
||||||
|
* @param WP_Post $post An instance of WP_Post class.
|
||||||
|
*/
|
||||||
|
function _enable_content_editor_for_navigation_post_type( $post ) {
|
||||||
|
$post_type = get_post_type( $post );
|
||||||
|
if ( 'wp_navigation' !== $post_type ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_post_type_support( $post_type, 'editor' );
|
||||||
|
}
|
||||||
|
|
|
@ -59,7 +59,17 @@ $preload_paths = array(
|
||||||
'/wp/v2/global-styles/' . $active_global_styles_id . '?context=edit',
|
'/wp/v2/global-styles/' . $active_global_styles_id . '?context=edit',
|
||||||
'/wp/v2/global-styles/' . $active_global_styles_id,
|
'/wp/v2/global-styles/' . $active_global_styles_id,
|
||||||
'/wp/v2/themes/' . $active_theme . '/global-styles',
|
'/wp/v2/themes/' . $active_theme . '/global-styles',
|
||||||
|
'/wp/v2/block-navigation-areas?context=edit',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$areas = get_option( 'fse_navigation_areas', array() );
|
||||||
|
$active_areas = array_intersect_key( $areas, get_navigation_areas() );
|
||||||
|
foreach ( $active_areas as $post_id ) {
|
||||||
|
if ( $post_id ) {
|
||||||
|
$preload_paths[] = add_query_args( 'context', 'edit', rest_get_route_for_post( $post_id ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
block_editor_rest_api_preload( $preload_paths, $block_editor_context );
|
block_editor_rest_api_preload( $preload_paths, $block_editor_context );
|
||||||
|
|
||||||
$editor_settings = get_block_editor_settings(
|
$editor_settings = get_block_editor_settings(
|
||||||
|
|
|
@ -583,6 +583,17 @@ add_action( 'admin_footer-post.php', 'wp_add_iframed_editor_assets_html' );
|
||||||
add_action( 'admin_footer-post-new.php', 'wp_add_iframed_editor_assets_html' );
|
add_action( 'admin_footer-post-new.php', 'wp_add_iframed_editor_assets_html' );
|
||||||
add_action( 'admin_footer-widgets.php', 'wp_add_iframed_editor_assets_html' );
|
add_action( 'admin_footer-widgets.php', 'wp_add_iframed_editor_assets_html' );
|
||||||
|
|
||||||
|
add_action( 'use_block_editor_for_post_type', '_disable_block_editor_for_navigation_post_type', 10, 2 );
|
||||||
|
add_action( 'edit_form_after_title', '_disable_content_editor_for_navigation_post_type' );
|
||||||
|
add_action( 'edit_form_after_editor', '_enable_content_editor_for_navigation_post_type' );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable "Post Attributes" for wp_navigation post type. The attributes are
|
||||||
|
* also conditionally enabled when a site has custom templates. Block Theme
|
||||||
|
* templates can be available for every post type.
|
||||||
|
*/
|
||||||
|
add_filter( 'theme_wp_navigation_templates', '__return_empty_array' );
|
||||||
|
|
||||||
// Taxonomy.
|
// Taxonomy.
|
||||||
add_action( 'init', 'create_initial_taxonomies', 0 ); // Highest priority.
|
add_action( 'init', 'create_initial_taxonomies', 0 ); // Highest priority.
|
||||||
add_action( 'change_locale', 'create_initial_taxonomies' );
|
add_action( 'change_locale', 'create_initial_taxonomies' );
|
||||||
|
@ -670,6 +681,7 @@ add_action( 'wp_footer', 'the_block_template_skip_link' );
|
||||||
add_action( 'setup_theme', 'wp_enable_block_templates' );
|
add_action( 'setup_theme', 'wp_enable_block_templates' );
|
||||||
|
|
||||||
// Navigation areas.
|
// Navigation areas.
|
||||||
add_action( 'setup_theme', '_register_default_navigation_areas' );
|
add_action( 'setup_theme', '_wp_register_default_navigation_areas' );
|
||||||
|
add_action( 'switch_theme', '_wp_migrate_menu_to_navigation_post', 99, 3 );
|
||||||
|
|
||||||
unset( $filter, $action );
|
unset( $filter, $action );
|
||||||
|
|
|
@ -29,7 +29,7 @@ function register_navigation_areas( $new_areas ) {
|
||||||
* @since 5.9.0
|
* @since 5.9.0
|
||||||
* @access private
|
* @access private
|
||||||
*/
|
*/
|
||||||
function _register_default_navigation_areas() {
|
function _wp_register_default_navigation_areas() {
|
||||||
register_navigation_areas(
|
register_navigation_areas(
|
||||||
array(
|
array(
|
||||||
'primary' => _x( 'Primary', 'navigation area' ),
|
'primary' => _x( 'Primary', 'navigation area' ),
|
||||||
|
@ -50,3 +50,208 @@ function get_navigation_areas() {
|
||||||
global $navigation_areas;
|
global $navigation_areas;
|
||||||
return $navigation_areas;
|
return $navigation_areas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrates classic menus to a block-based navigation post on theme switch.
|
||||||
|
* Assigns the created navigation post to the corresponding navigation area.
|
||||||
|
*
|
||||||
|
* @since 5.9.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param string $new_name Name of the new theme.
|
||||||
|
* @param WP_Theme $new_theme New theme.
|
||||||
|
* @param WP_Theme $old_theme Old theme.
|
||||||
|
*/
|
||||||
|
function _wp_migrate_menu_to_navigation_post( $new_name, WP_Theme $new_theme, WP_Theme $old_theme ) {
|
||||||
|
// Do nothing when switching to a theme that does not support site editor.
|
||||||
|
if ( ! wp_is_block_template_theme() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_nav_menu_locations() calls get_theme_mod() which depends on the stylesheet option.
|
||||||
|
// At the same time, switch_theme runs only after the stylesheet option was updated to $new_theme.
|
||||||
|
// To retrieve theme mods of the old theme, the getter is hooked to get_option( 'stylesheet' ) so that we
|
||||||
|
// get the old theme, which causes the get_nav_menu_locations to get the locations of the old theme.
|
||||||
|
$get_old_theme_stylesheet = static function() use ( $old_theme ) {
|
||||||
|
return $old_theme->get_stylesheet();
|
||||||
|
};
|
||||||
|
add_filter( 'option_stylesheet', $get_old_theme_stylesheet );
|
||||||
|
|
||||||
|
$locations = get_nav_menu_locations();
|
||||||
|
$area_mapping = get_option( 'fse_navigation_areas', array() );
|
||||||
|
|
||||||
|
foreach ( $locations as $location_name => $menu_id ) {
|
||||||
|
// Get the menu from the location, skipping if there is no
|
||||||
|
// menu or there was an error.
|
||||||
|
$menu = wp_get_nav_menu_object( $menu_id );
|
||||||
|
if ( ! $menu || is_wp_error( $menu ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu_items = _wp_get_menu_items_at_location( $location_name );
|
||||||
|
if ( empty( $menu_items ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$post_name = 'classic_menu_' . $menu_id;
|
||||||
|
|
||||||
|
// Get or create to avoid creating too many wp_navigation posts.
|
||||||
|
$query = new WP_Query;
|
||||||
|
$matching_posts = $query->query(
|
||||||
|
array(
|
||||||
|
'name' => $post_name,
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'post_type' => 'wp_navigation',
|
||||||
|
'posts_per_page' => 1,
|
||||||
|
'fields' => 'ids',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! empty( $matching_posts ) ) {
|
||||||
|
$navigation_post_id = $matching_posts[0]->ID;
|
||||||
|
} else {
|
||||||
|
$menu_items_by_parent_id = _wp_sort_menu_items_by_parent_id( $menu_items );
|
||||||
|
$parsed_blocks = _wp_parse_blocks_from_menu_items( $menu_items_by_parent_id[0], $menu_items_by_parent_id );
|
||||||
|
$post_data = array(
|
||||||
|
'post_type' => 'wp_navigation',
|
||||||
|
'post_title' => sprintf(
|
||||||
|
/* translators: %s: the name of the menu, e.g. "Main Menu". */
|
||||||
|
__( 'Classic menu: %s' ),
|
||||||
|
$menu->name
|
||||||
|
),
|
||||||
|
'post_name' => $post_name,
|
||||||
|
'post_content' => serialize_blocks( $parsed_blocks ),
|
||||||
|
'post_status' => 'publish',
|
||||||
|
);
|
||||||
|
$navigation_post_id = wp_insert_post( $post_data );
|
||||||
|
}
|
||||||
|
|
||||||
|
$area_mapping[ $location_name ] = $navigation_post_id;
|
||||||
|
}
|
||||||
|
remove_filter( 'option_stylesheet', $get_old_theme_stylesheet );
|
||||||
|
|
||||||
|
update_option( 'fse_navigation_areas', $area_mapping );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the menu items for a WordPress menu location.
|
||||||
|
*
|
||||||
|
* @since 5.9.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param string $location The menu location.
|
||||||
|
* @return array Menu items for the location.
|
||||||
|
*/
|
||||||
|
function _wp_get_menu_items_at_location( $location ) {
|
||||||
|
if ( empty( $location ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build menu data. The following approximates the code in `wp_nav_menu()`.
|
||||||
|
|
||||||
|
// Find the location in the list of locations, returning early if the
|
||||||
|
// location can't be found.
|
||||||
|
$locations = get_nav_menu_locations();
|
||||||
|
if ( ! isset( $locations[ $location ] ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the menu from the location, returning early if there is no
|
||||||
|
// menu or there was an error.
|
||||||
|
$menu = wp_get_nav_menu_object( $locations[ $location ] );
|
||||||
|
if ( ! $menu || is_wp_error( $menu ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) );
|
||||||
|
_wp_menu_item_classes_by_context( $menu_items );
|
||||||
|
|
||||||
|
return $menu_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts a standard array of menu items into a nested structure keyed by the
|
||||||
|
* id of the parent menu.
|
||||||
|
*
|
||||||
|
* @since 5.9.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param array $menu_items Menu items to sort.
|
||||||
|
* @return array An array keyed by the id of the parent menu where each element
|
||||||
|
* is an array of menu items that belong to that parent.
|
||||||
|
*/
|
||||||
|
function _wp_sort_menu_items_by_parent_id( $menu_items ) {
|
||||||
|
$sorted_menu_items = array();
|
||||||
|
foreach ( $menu_items as $menu_item ) {
|
||||||
|
$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
|
||||||
|
}
|
||||||
|
unset( $menu_items, $menu_item );
|
||||||
|
|
||||||
|
$menu_items_by_parent_id = array();
|
||||||
|
foreach ( $sorted_menu_items as $menu_item ) {
|
||||||
|
$menu_items_by_parent_id[ $menu_item->menu_item_parent ][] = $menu_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $menu_items_by_parent_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns menu item data into a nested array of parsed blocks
|
||||||
|
*
|
||||||
|
* @since 5.9.0
|
||||||
|
* @access private
|
||||||
|
*
|
||||||
|
* @param array $menu_items An array of menu items that represent
|
||||||
|
* an individual level of a menu.
|
||||||
|
* @param array $menu_items_by_parent_id An array keyed by the id of the
|
||||||
|
* parent menu where each element is an
|
||||||
|
* array of menu items that belong to
|
||||||
|
* that parent.
|
||||||
|
* @return array An array of parsed block data.
|
||||||
|
*/
|
||||||
|
function _wp_parse_blocks_from_menu_items( $menu_items, $menu_items_by_parent_id ) {
|
||||||
|
if ( empty( $menu_items ) ) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$blocks = array();
|
||||||
|
|
||||||
|
foreach ( $menu_items as $menu_item ) {
|
||||||
|
$class_name = ! empty( $menu_item->classes ) ? implode( ' ', (array) $menu_item->classes ) : null;
|
||||||
|
$id = ( null !== $menu_item->object_id && 'custom' !== $menu_item->object ) ? $menu_item->object_id : null;
|
||||||
|
$opens_in_new_tab = null !== $menu_item->target && '_blank' === $menu_item->target;
|
||||||
|
$rel = ( null !== $menu_item->xfn && '' !== $menu_item->xfn ) ? $menu_item->xfn : null;
|
||||||
|
$kind = null !== $menu_item->type ? str_replace( '_', '-', $menu_item->type ) : 'custom';
|
||||||
|
|
||||||
|
$block = array(
|
||||||
|
'blockName' => isset( $menu_items_by_parent_id[ $menu_item->ID ] ) ? 'core/navigation-submenu' : 'core/navigation-link',
|
||||||
|
'attrs' => array(
|
||||||
|
'className' => $class_name,
|
||||||
|
'description' => $menu_item->description,
|
||||||
|
'id' => $id,
|
||||||
|
'kind' => $kind,
|
||||||
|
'label' => $menu_item->title,
|
||||||
|
'opensInNewTab' => $opens_in_new_tab,
|
||||||
|
'rel' => $rel,
|
||||||
|
'title' => $menu_item->attr_title,
|
||||||
|
'type' => $menu_item->object,
|
||||||
|
'url' => $menu_item->url,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( isset( $menu_items_by_parent_id[ $menu_item->ID ] ) ) {
|
||||||
|
$block['innerBlocks'] = _wp_parse_blocks_from_menu_items(
|
||||||
|
$menu_items_by_parent_id[ $menu_item->ID ],
|
||||||
|
$menu_items_by_parent_id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$block['innerBlocks'] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$block['innerContent'] = array_map( 'serialize_block', $block['innerBlocks'] );
|
||||||
|
|
||||||
|
$blocks[] = $block;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $blocks;
|
||||||
|
}
|
||||||
|
|
|
@ -480,13 +480,12 @@ function create_initial_post_types() {
|
||||||
'labels' => array(
|
'labels' => array(
|
||||||
'name' => __( 'Navigation Menus' ),
|
'name' => __( 'Navigation Menus' ),
|
||||||
'singular_name' => __( 'Navigation Menu' ),
|
'singular_name' => __( 'Navigation Menu' ),
|
||||||
'menu_name' => _x( 'Navigation Menus', 'Admin Menu text' ),
|
|
||||||
'add_new' => _x( 'Add New', 'Navigation Menu' ),
|
'add_new' => _x( 'Add New', 'Navigation Menu' ),
|
||||||
'add_new_item' => __( 'Add New Navigation Menu' ),
|
'add_new_item' => __( 'Add New Navigation Menu' ),
|
||||||
'new_item' => __( 'New Navigation Menu' ),
|
'new_item' => __( 'New Navigation Menu' ),
|
||||||
'edit_item' => __( 'Edit Navigation Menu' ),
|
'edit_item' => __( 'Edit Navigation Menu' ),
|
||||||
'view_item' => __( 'View Navigation Menu' ),
|
'view_item' => __( 'View Navigation Menu' ),
|
||||||
'all_items' => __( 'All Navigation Menus' ),
|
'all_items' => __( 'Navigation Menus' ),
|
||||||
'search_items' => __( 'Search Navigation Menus' ),
|
'search_items' => __( 'Search Navigation Menus' ),
|
||||||
'parent_item_colon' => __( 'Parent Navigation Menu:' ),
|
'parent_item_colon' => __( 'Parent Navigation Menu:' ),
|
||||||
'not_found' => __( 'No Navigation Menu found.' ),
|
'not_found' => __( 'No Navigation Menu found.' ),
|
||||||
|
@ -494,15 +493,15 @@ function create_initial_post_types() {
|
||||||
'archives' => __( 'Navigation Menu archives' ),
|
'archives' => __( 'Navigation Menu archives' ),
|
||||||
'insert_into_item' => __( 'Insert into Navigation Menu' ),
|
'insert_into_item' => __( 'Insert into Navigation Menu' ),
|
||||||
'uploaded_to_this_item' => __( 'Uploaded to this Navigation Menu' ),
|
'uploaded_to_this_item' => __( 'Uploaded to this Navigation Menu' ),
|
||||||
// Some of these are a bit weird, what are they for?
|
|
||||||
'filter_items_list' => __( 'Filter Navigation Menu list' ),
|
'filter_items_list' => __( 'Filter Navigation Menu list' ),
|
||||||
'items_list_navigation' => __( 'Navigation Menus list navigation' ),
|
'items_list_navigation' => __( 'Navigation Menus list navigation' ),
|
||||||
'items_list' => __( 'Navigation Menus list' ),
|
'items_list' => __( 'Navigation Menus list' ),
|
||||||
),
|
),
|
||||||
|
'description' => __( 'Navigation menus that can be inserted into your site.' ),
|
||||||
'public' => false,
|
'public' => false,
|
||||||
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
|
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
|
||||||
'has_archive' => false,
|
'has_archive' => false,
|
||||||
'show_ui' => false,
|
'show_ui' => wp_is_block_template_theme(),
|
||||||
'show_in_menu' => 'themes.php',
|
'show_in_menu' => 'themes.php',
|
||||||
'show_in_admin_bar' => false,
|
'show_in_admin_bar' => false,
|
||||||
'show_in_rest' => true,
|
'show_in_rest' => true,
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
* @global string $wp_version
|
* @global string $wp_version
|
||||||
*/
|
*/
|
||||||
$wp_version = '5.9-alpha-52144';
|
$wp_version = '5.9-alpha-52145';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||||
|
|
Loading…
Reference in New Issue