-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Copy navigation area infrastructure from Gutenberg #1865
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
Changes from 1 commit
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
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,3 +50,202 @@ 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 _migrate_menu_to_navigation_post( $new_name, $new_theme, $old_theme ) { | ||
noisysocks marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
noisysocks marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // 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 = _get_menu_items_at_location( $location_name ); | ||
| if ( empty( $menu_items ) ) { | ||
| continue; | ||
| } | ||
|
|
||
| $post_name = 'classic_menu_' . $menu_id; | ||
| $post_status = 'publish'; | ||
noisysocks marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // 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' => $post_status, | ||
| 'post_type' => 'wp_navigation', | ||
| 'posts_per_page' => 1, | ||
| ) | ||
| ); | ||
|
|
||
| if ( count( $matching_posts ) ) { | ||
noisysocks marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| $navigation_post_id = $matching_posts[0]->ID; | ||
| } else { | ||
noisysocks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| $menu_items_by_parent_id = _sort_menu_items_by_parent_id( $menu_items ); | ||
| $parsed_blocks = _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' => $post_status, | ||
| ); | ||
| $navigation_post_id = wp_insert_post( $post_data ); | ||
|
Member
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
Member
Author
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.
Contributor
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 _menu_items_at_location( $location ) { | ||
noisysocks marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 _sort_menu_items_by_parent_id( $menu_items ) { | ||
noisysocks marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| $sorted_menu_items = array(); | ||
| foreach ( (array) $menu_items as $menu_item ) { | ||
noisysocks marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| $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 _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, | ||
| ), | ||
| ); | ||
|
|
||
| $block['innerBlocks'] = isset( $menu_items_by_parent_id[ $menu_item->ID ] ) | ||
| ? _parse_blocks_from_menu_items( $menu_items_by_parent_id[ $menu_item->ID ], $menu_items_by_parent_id ) | ||
| : array(); | ||
noisysocks marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| $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_typeso that the editor doesn't appear when you edit the CPT. This re-enables it.