-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Copy navigation area infrastructure from Gutenberg #1865
Changes from all commits
5dcb11e
8526afb
d46eb50
3e60e6e
c3b9d2d
d686a6f
86d97ef
696c320
7449d66
9513276
176164e
14ffacc
6d974ce
07379cf
1799e29
5ca5336
49d8b87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,7 @@ function register_navigation_areas( $new_areas ) { | |
* @since 5.9.0 | ||
* @access private | ||
*/ | ||
function _register_default_navigation_areas() { | ||
function _wp_register_default_navigation_areas() { | ||
register_navigation_areas( | ||
array( | ||
'primary' => _x( 'Primary', 'navigation area' ), | ||
|
@@ -50,3 +50,208 @@ function get_navigation_areas() { | |
global $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() ); | ||
noisysocks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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 ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There NEEDs to be some error handling here. What is the database falls over and this returns a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returning error here and then Error 500 from the API endpoint sounds like a sensible thing to do |
||
} | ||
|
||
$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; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we doing this? Are not just not register support for editor, until we are ready?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We temporarily disable it in
_disable_content_editor_for_navigation_post_type
so that the editor doesn't appear when you edit the CPT. This re-enables it.