WordPress.org

Make WordPress Core

Ticket #39692: 39692.3.diff

File 39692.3.diff, 8.6 KB (added by welcher, 10 months ago)
  • src/wp-includes/default-filters.php

    diff --git src/wp-includes/default-filters.php src/wp-includes/default-filters.php
    index 9212e42..8a8b6a9 100644
    add_action( 'wp_footer', 'wp_print_footer_scripts', 20 ); 
    262262add_action( 'template_redirect',   'wp_shortlink_header',             11, 0 );
    263263add_action( 'wp_print_footer_scripts', '_wp_footer_scripts'                 );
    264264add_action( 'init',                'check_theme_switched',            99    );
     265add_action( 'after_switch_theme',  '_wp_menus_changed'                      );
    265266add_action( 'after_switch_theme',  '_wp_sidebars_changed'                   );
    266267add_action( 'wp_print_styles',     'print_emoji_styles'                     );
    267268
  • src/wp-includes/nav-menu.php

    diff --git src/wp-includes/nav-menu.php src/wp-includes/nav-menu.php
    index 1585c62..1a32a2b 100644
    function _wp_delete_customize_changeset_dependent_auto_drafts( $post_id ) { 
    10261026        }
    10271027        add_action( 'delete_post', '_wp_delete_customize_changeset_dependent_auto_drafts' );
    10281028}
     1029
     1030/**
     1031 * Handle menu config after theme change.
     1032 *
     1033 * @access private
     1034 * @since 4.9.0
     1035 */
     1036function _wp_menus_changed() {
     1037        $old_nav_menu_locations = get_option( 'theme_switch_menu_locations', array() );
     1038        $new_nav_menu_locations = get_nav_menu_locations();
     1039        $registered_nav_menus   = get_registered_nav_menus();
     1040
     1041
     1042        if ( ! empty( $old_nav_menu_locations ) ) {
     1043                // If old and new theme have just one location, map it.
     1044                if ( 1 === count( $old_nav_menu_locations ) && 1 === count( $registered_nav_menus ) ) {
     1045                        $new_nav_menu_locations[ key( $registered_nav_menus ) ] = array_pop( $old_nav_menu_locations );
     1046                } else {
     1047                        $old_locations = array_keys( $old_nav_menu_locations );
     1048
     1049                        // Map locations with the same slug.
     1050                        foreach ( $registered_nav_menus as $location => $name ) {
     1051                                if ( in_array( $location, $old_locations, true ) ) {
     1052                                        $new_nav_menu_locations[ $location ] = $old_nav_menu_locations[ $location ];
     1053                                        unset( $old_nav_menu_locations[ $location ] );
     1054                                }
     1055                        }
     1056
     1057                        /*
     1058                         * If old and new theme both have locations that contain phrases
     1059                         * from within the same group, make an educated guess and map it.
     1060                         */
     1061                        $common_slug_groups = array(
     1062                                array( 'header', 'main', 'navigation', 'primary', 'top' ),
     1063                                array( 'bottom', 'footer', 'secondary', 'subsidiary' ),
     1064                                array( 'social' ),
     1065                                // TODO: Find a second slug or remove, since locations with same slug are already mapped.
     1066                        );
     1067                       
     1068                        // Go through each group...
     1069                        foreach ( $common_slug_groups as $slug_group ) {
     1070                               
     1071                                // ...and see if any of these slugs...
     1072                                foreach ( $slug_group as $slug ) {
     1073                                       
     1074                                        // ...and any of the new menu locations...
     1075                                        foreach ( $registered_nav_menus as $new_location => $name ) {
     1076                                               
     1077                                                // ...actually match!
     1078                                                if ( false !== stripos( $new_location, $slug ) || false !== stripos( $slug, $new_location ) ) {
     1079                                                       
     1080                                                        // Then see if any of the old locations...
     1081                                                        foreach ( $old_nav_menu_locations as $location => $menu_id ) {
     1082                                                               
     1083                                                                // ...match a slug in the same group.
     1084                                                                foreach ( $slug_group as $slug ) {
     1085                                                                        if ( false !== stripos( $location, $slug ) || false !== stripos( $slug, $location ) ) {
     1086                                                                               
     1087                                                                                // Make sure this location wasn't mapped and removed previously.
     1088                                                                                if ( ! empty( $old_nav_menu_locations[ $location ] ) ) {
     1089                                                                                       
     1090                                                                                        // We have a match that can be mapped!
     1091                                                                                        $new_nav_menu_locations[ $new_location ] = $old_nav_menu_locations[ $location ];
     1092                                                                                       
     1093                                                                                        // Remove the mapped location so it can't be mapped again.
     1094                                                                                        unset( $old_nav_menu_locations[ $location ] );
     1095                                                                                       
     1096                                                                                        // Go back and check the next new menu location.
     1097                                                                                        continue 3;
     1098                                                                                }
     1099                                                                        }
     1100                                                                }
     1101                                                        }
     1102                                                }
     1103                                        }
     1104                                }
     1105                        }
     1106                }
     1107        }
     1108
     1109        set_theme_mod( 'nav_menu_locations', $new_nav_menu_locations );
     1110        delete_option( 'theme_switch_menu_locations' );
     1111}
  • src/wp-includes/theme.php

    diff --git src/wp-includes/theme.php src/wp-includes/theme.php
    index 2b2fbf2..1d55f4f 100644
    function switch_theme( $stylesheet ) { 
    691691        }
    692692
    693693        $nav_menu_locations = get_theme_mod( 'nav_menu_locations' );
     694        add_option( 'theme_switch_menu_locations', $nav_menu_locations );
    694695
    695696        if ( func_num_args() > 1 ) {
    696697                $stylesheet = func_get_arg( 1 );
    function switch_theme( $stylesheet ) { 
    731732                if ( 'wp_ajax_customize_save' === current_action() ) {
    732733                        remove_theme_mod( 'sidebars_widgets' );
    733734                }
    734 
    735                 if ( ! empty( $nav_menu_locations ) ) {
    736                         $nav_mods = get_theme_mod( 'nav_menu_locations' );
    737                         if ( empty( $nav_mods ) ) {
    738                                 set_theme_mod( 'nav_menu_locations', $nav_menu_locations );
    739                         }
    740                 }
    741735        }
    742736
    743737        update_option( 'theme_switched', $old_theme->get_stylesheet() );
  • new file tests/phpunit/tests/menu/nav-menu.php

    diff --git tests/phpunit/tests/menu/nav-menu.php tests/phpunit/tests/menu/nav-menu.php
    new file mode 100644
    index 0000000..b38f1e6
    - +  
     1<?php
     2
     3/**
     4 * @group navmenus
     5 */
     6class Tests_Nav_Menu_Theme_Change extends WP_UnitTestCase {
     7
     8        function setUp() {
     9                register_nav_menus( array(
     10                        'primary' => 'Primary',
     11                ) );
     12
     13                parent::setUp();
     14        }
     15
     16        function tearDown() {
     17                global $_wp_registered_nav_menus;
     18
     19                remove_theme_mod( 'nav_menu_locations' );
     20                $_wp_registered_nav_menus = array();
     21
     22                parent::tearDown();
     23        }
     24
     25        /**
     26         * Two themes with one location each should just map.
     27         */
     28        function test_one_location_each() {
     29                $old_nav_menu_locations = array( 'unique-slug' => 1 );
     30                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     31
     32                _wp_menus_changed();
     33                $this->assertEqualSets( get_theme_mod( 'nav_menu_locations' ), $old_nav_menu_locations );
     34        }
     35
     36        /**
     37         * Locations with the same name should map.
     38         */
     39        function test_locations_with_same_slug() {
     40                $old_nav_menu_locations = array( 'primary' => 1, 'secondary' => 2 );
     41                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     42                register_nav_menu( 'secondary', 'Secondary' );
     43
     44                _wp_menus_changed();
     45                $this->assertEqualSets( get_theme_mod( 'nav_menu_locations' ), $old_nav_menu_locations );
     46        }
     47
     48        /**
     49         * If the new theme was previously active, we should fall back to that data.
     50         */
     51        function test_new_theme_previously_active() {
     52                $old_nav_menu_locations = array( 'primary' => 3 );
     53                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     54                $previous_locations = array( 'primary' => 1, 'secondary' => 2 );
     55                set_theme_mod( 'nav_menu_locations', $previous_locations );
     56
     57                _wp_menus_changed();
     58                $this->assertEqualSets( get_theme_mod( 'nav_menu_locations' ), array_merge( $previous_locations, $old_nav_menu_locations ) );
     59        }
     60
     61        /**
     62         * Make educated guesses on theme locations.
     63         */
     64        function test_location_guessing() {
     65                $old_nav_menu_locations = array( 'header' => 1, 'footer' => 2 );
     66                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     67                register_nav_menu( 'secondary', 'Secondary' );
     68
     69                _wp_menus_changed();
     70                $this->assertEqualSets( get_theme_mod( 'nav_menu_locations' ), array( 'primary' => 1, 'secondary' => 2 ) );
     71        }
     72
     73        /**
     74         * Make sure two locations that fall in the same group don't get the same menu assigned.
     75         */
     76        function test_location_guessing_one_menu_per_group() {
     77                $old_nav_menu_locations = array( 'top-menu' => 1, 'secondary' => 2 );
     78                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     79                register_nav_menu( 'main', 'Main' );
     80
     81                _wp_menus_changed();
     82                $this->assertEqualSets( get_theme_mod( 'nav_menu_locations' ), array( 'main' => 1 ) );
     83        }
     84
     85        /**
     86         * Make sure two locations that fall in the same group get menus assigned from the same group.
     87         */
     88        function test_location_guessing_one_menu_per_location() {
     89                $old_nav_menu_locations = array( 'navigation-menu' => 1, 'top-menu' => 2 );
     90                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     91                register_nav_menu( 'main', 'Main' );
     92
     93                _wp_menus_changed();
     94                $this->assertEqualSets( get_theme_mod( 'nav_menu_locations' ), array( 'main' => 1, 'primary' => 2 ) );
     95        }
     96       
     97        /**
     98         * Technically possible to register menu locations numerically.
     99         */
     100        function test_numerical_locations() {
     101                $old_nav_menu_locations = array( 'main' => 1, 'secondary' => 2, 'tertiary' => 3 );
     102                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     103                register_nav_menu( 1 , 'First' );
     104
     105                _wp_menus_changed();
     106                $this->assertEqualSets( get_theme_mod( 'nav_menu_locations' ), array( 'primary' => 1 ) );
     107        }
     108}