WordPress.org

Make WordPress Core

Ticket #39692: 39692.7.diff

File 39692.7.diff, 14.0 KB (added by westonruter, 6 months ago)

Δ https://github.com/xwp/wordpress-develop/pull/245/files/48a67c0..b2d5c67

  • src/wp-includes/class-wp-customize-nav-menus.php

    diff --git src/wp-includes/class-wp-customize-nav-menus.php src/wp-includes/class-wp-customize-nav-menus.php
    index 3d7b1f0deb..3b9ca487fd 100644
    final class WP_Customize_Nav_Menus { 
    2727        public $manager; 
    2828 
    2929        /** 
    30          * Previewed Menus. 
     30         * Original nav menu locations before the theme was switched. 
    3131         * 
    32          * @since 4.3.0 
     32         * @since 4.9.0 
    3333         * @var array 
    3434         */ 
    35         public $previewed_menus; 
     35        protected $original_nav_menu_locations; 
    3636 
    3737        /** 
    3838         * Constructor. 
    final class WP_Customize_Nav_Menus { 
    4242         * @param object $manager An instance of the WP_Customize_Manager class. 
    4343         */ 
    4444        public function __construct( $manager ) { 
    45                 $this->previewed_menus = array(); 
    46                 $this->manager         = $manager; 
     45                $this->manager = $manager; 
     46                $this->original_nav_menu_locations = get_nav_menu_locations(); 
    4747 
    4848                // See https://github.com/xwp/wp-customize-snapshots/blob/962586659688a5b1fd9ae93618b7ce2d4e7a421c/php/class-customize-snapshot-manager.php#L469-L499 
    4949                add_action( 'customize_register', array( $this, 'customize_register' ), 11 ); 
    final class WP_Customize_Nav_Menus { 
    582582                        $choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '…' ); 
    583583                } 
    584584 
     585                // Attempt to re-map the nav menu location assignments when previewing a theme switch. 
     586                $mapped_nav_menu_locations = array(); 
     587                if ( ! $this->manager->is_theme_active() ) { 
     588                        $mapped_nav_menu_locations = wp_map_nav_menu_locations( get_nav_menu_locations(), $this->original_nav_menu_locations ); 
     589                } 
     590 
    585591                foreach ( $locations as $location => $description ) { 
    586592                        $setting_id = "nav_menu_locations[{$location}]"; 
    587593 
    final class WP_Customize_Nav_Menus { 
    600606                                ) ); 
    601607                        } 
    602608 
     609                        // Override the assigned nav menu location if mapped during previewed theme switch. 
     610                        if ( isset( $mapped_nav_menu_locations[ $location ] ) ) { 
     611                                $this->manager->set_post_value( $setting_id, $mapped_nav_menu_locations[ $location ] ); 
     612                        } 
     613 
    603614                        $this->manager->add_control( new WP_Customize_Nav_Menu_Location_Control( $this->manager, $setting_id, array( 
    604615                                'label'       => $description, 
    605616                                'location_id' => $location, 
  • src/wp-includes/default-filters.php

    diff --git src/wp-includes/default-filters.php src/wp-includes/default-filters.php
    index 9212e42865..8a8b6a9072 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 1585c62f3d..882aee6287 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        $mapped_nav_menu_locations = wp_map_nav_menu_locations( $new_nav_menu_locations, $old_nav_menu_locations ); 
     1040        set_theme_mod( 'nav_menu_locations', $mapped_nav_menu_locations ); 
     1041        delete_option( 'theme_switch_menu_locations' ); 
     1042} 
     1043 
     1044/** 
     1045 * Re-maps nav menu location assignments according to previous location assignments (in a different theme). 
     1046 * 
     1047 * @since 4.9.0 
     1048 * 
     1049 * @param array $new_nav_menu_locations New nav menu locations assignments. 
     1050 * @param array $old_nav_menu_locations Old nav menu locations assignments. 
     1051 * @return array Nav menus mapped to new nav menu locations. 
     1052 */ 
     1053function wp_map_nav_menu_locations( $new_nav_menu_locations, $old_nav_menu_locations ) { 
     1054        $registered_nav_menus = get_registered_nav_menus(); 
     1055 
     1056        // Short-circuit if there are no old nav menu location assignments to map. 
     1057        if ( empty( $old_nav_menu_locations ) ) { 
     1058                return $new_nav_menu_locations; 
     1059        } 
     1060 
     1061        // If old and new theme have just one location, map it and we're done. 
     1062        if ( 1 === count( $old_nav_menu_locations ) && 1 === count( $registered_nav_menus ) ) { 
     1063                $new_nav_menu_locations[ key( $registered_nav_menus ) ] = array_pop( $old_nav_menu_locations ); 
     1064                return $new_nav_menu_locations; 
     1065        } 
     1066 
     1067        $old_locations = array_keys( $old_nav_menu_locations ); 
     1068 
     1069        // Map locations with the same slug. 
     1070        foreach ( $registered_nav_menus as $location => $name ) { 
     1071                if ( in_array( $location, $old_locations, true ) ) { 
     1072                        $new_nav_menu_locations[ $location ] = $old_nav_menu_locations[ $location ]; 
     1073                        unset( $old_nav_menu_locations[ $location ] ); 
     1074                } 
     1075        } 
     1076 
     1077        // If there are no old nav menu locations left, then we're done. 
     1078        if ( empty( $old_nav_menu_locations ) ) { 
     1079                return $new_nav_menu_locations; 
     1080        } 
     1081 
     1082        /* 
     1083         * If old and new theme both have locations that contain phrases 
     1084         * from within the same group, make an educated guess and map it. 
     1085         */ 
     1086        $common_slug_groups = array( 
     1087                array( 'header', 'main', 'navigation', 'primary', 'top' ), 
     1088                array( 'bottom', 'footer', 'secondary', 'subsidiary' ), 
     1089                array( 'social' ), 
     1090                // TODO: Find a second slug or remove, since locations with same slug are already mapped. 
     1091        ); 
     1092 
     1093        // Go through each group... 
     1094        foreach ( $common_slug_groups as $slug_group ) { 
     1095 
     1096                // ...and see if any of these slugs... 
     1097                foreach ( $slug_group as $slug ) { 
     1098 
     1099                        // ...and any of the new menu locations... 
     1100                        foreach ( $registered_nav_menus as $new_location => $name ) { 
     1101 
     1102                                // ...actually match! 
     1103                                if ( false === stripos( $new_location, $slug ) && false === stripos( $slug, $new_location ) ) { 
     1104                                        continue; 
     1105                                } 
     1106 
     1107                                // Then see if any of the old locations... 
     1108                                foreach ( $old_nav_menu_locations as $location => $menu_id ) { 
     1109 
     1110                                        // ...match a slug in the same group. 
     1111                                        foreach ( $slug_group as $slug ) { 
     1112 
     1113                                                // But skip if the location and slug don't match. 
     1114                                                if ( false === stripos( $location, $slug ) && false === stripos( $slug, $location ) ) { 
     1115                                                        continue; 
     1116                                                } 
     1117 
     1118                                                // Make sure this location wasn't mapped and removed previously. 
     1119                                                if ( ! empty( $old_nav_menu_locations[ $location ] ) ) { 
     1120 
     1121                                                        // We have a match that can be mapped! 
     1122                                                        $new_nav_menu_locations[ $new_location ] = $old_nav_menu_locations[ $location ]; 
     1123 
     1124                                                        // Remove the mapped location so it can't be mapped again. 
     1125                                                        unset( $old_nav_menu_locations[ $location ] ); 
     1126 
     1127                                                        // Go back and check the next new menu location. 
     1128                                                        continue 3; 
     1129                                                } 
     1130                                        } // endforeach ( $slug_group as $slug ) 
     1131                                } // endforeach ( $old_nav_menu_locations as $location => $menu_id ) 
     1132                        } // endforeach foreach ( $registered_nav_menus as $new_location => $name ) 
     1133                } // endforeach ( $slug_group as $slug ) 
     1134        } // endforeach ( $common_slug_groups as $slug_group ) 
     1135 
     1136        return $new_nav_menu_locations; 
     1137} 
  • src/wp-includes/theme.php

    diff --git src/wp-includes/theme.php src/wp-includes/theme.php
    index 2b2fbf2403..1d55f4f27c 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 0000000000..ec346da53b
    - +  
     1<?php 
     2 
     3/** 
     4 * @group navmenus 
     5 */ 
     6class Tests_Nav_Menu_Theme_Change extends WP_UnitTestCase { 
     7 
     8        /** 
     9         * Set up. 
     10         */ 
     11        function setUp() { 
     12                parent::setUp(); 
     13 
     14                // Unregister all nav menu locations. 
     15                foreach ( array_keys( get_registered_nav_menus() ) as $location ) { 
     16                        unregister_nav_menu( $location ); 
     17                } 
     18        } 
     19 
     20        /** 
     21         * Register nav menu locations. 
     22         * 
     23         * @param array $locations Location slugs. 
     24         */ 
     25        function register_nav_menu_locations( $locations ) { 
     26                foreach ( $locations as $location ) { 
     27                        register_nav_menu( $location, ucfirst( $location ) ); 
     28                } 
     29        } 
     30 
     31        /** 
     32         * Two themes with one location each should just map, switching to a theme not previously-active. 
     33         * 
     34         * @covers wp_map_nav_menu_locations() 
     35         */ 
     36        function test_one_location_each() { 
     37                $this->register_nav_menu_locations( array( 'primary' ) ); 
     38                $prev_theme_nav_menu_locations = array( 
     39                        'unique-slug' => 1, 
     40                ); 
     41                $old_next_theme_nav_menu_locations = array(); // It was not active before. 
     42                $new_next_theme_nav_menu_locations = wp_map_nav_menu_locations( $old_next_theme_nav_menu_locations, $prev_theme_nav_menu_locations ); 
     43 
     44                $expected_nav_menu_locations = array( 
     45                        'primary' => 1, 
     46                ); 
     47                $this->assertEquals( $expected_nav_menu_locations, $new_next_theme_nav_menu_locations ); 
     48        } 
     49 
     50        /** 
     51         * Locations with the same name should map, switching to a theme not previously-active. 
     52         * 
     53         * @covers wp_map_nav_menu_locations() 
     54         */ 
     55        function test_locations_with_same_slug() { 
     56                $this->register_nav_menu_locations( array( 'primary', 'secondary' ) ); 
     57                $prev_theme_nav_menu_locations = array( 
     58                        'primary' => 1, 
     59                        'secondary' => 2, 
     60                ); 
     61 
     62                $old_next_theme_nav_menu_locations = array(); // It was not active before. 
     63                $new_next_theme_nav_menu_locations = wp_map_nav_menu_locations( $old_next_theme_nav_menu_locations, $prev_theme_nav_menu_locations ); 
     64 
     65                $expected_nav_menu_locations = $prev_theme_nav_menu_locations; 
     66                $this->assertEquals( $expected_nav_menu_locations, $new_next_theme_nav_menu_locations ); 
     67        } 
     68 
     69        /** 
     70         * If the new theme was previously active, we should honor any changes to nav menu mapping done when the other theme was active. 
     71         * 
     72         * @covers wp_map_nav_menu_locations() 
     73         */ 
     74        function test_new_theme_previously_active() { 
     75                $this->register_nav_menu_locations( array( 'primary' ) ); 
     76 
     77                $prev_theme_nav_menu_locations = array( 
     78                        'primary' => 1, 
     79                        'secondary' => 2, 
     80                ); 
     81 
     82                // Nav menu location assignments that were set on the next theme when it was previously active. 
     83                $old_next_theme_nav_menu_locations = array( 
     84                        'primary' => 3, 
     85                ); 
     86 
     87                $new_next_theme_nav_menu_locations = wp_map_nav_menu_locations( $old_next_theme_nav_menu_locations, $prev_theme_nav_menu_locations ); 
     88 
     89                $expected_nav_menu_locations = wp_array_slice_assoc( $prev_theme_nav_menu_locations, array_keys( get_registered_nav_menus() ) ); 
     90                $this->assertEquals( $expected_nav_menu_locations, $new_next_theme_nav_menu_locations ); 
     91        } 
     92 
     93        /** 
     94         * Make educated guesses on theme locations. 
     95         * 
     96         * @covers wp_map_nav_menu_locations() 
     97         */ 
     98        function test_location_guessing() { 
     99                $this->register_nav_menu_locations( array( 'primary', 'secondary' ) ); 
     100 
     101                $prev_theme_nav_menu_locations = array( 
     102                        'header' => 1, 
     103                        'footer' => 2, 
     104                ); 
     105 
     106                $old_next_theme_nav_menu_locations = array(); 
     107                $new_next_theme_nav_menu_locations = wp_map_nav_menu_locations( $old_next_theme_nav_menu_locations, $prev_theme_nav_menu_locations ); 
     108 
     109                $expected_nav_menu_locations = array( 
     110                        'primary' => 1, 
     111                        'secondary' => 2, 
     112                ); 
     113                $this->assertEquals( $expected_nav_menu_locations, $new_next_theme_nav_menu_locations ); 
     114        } 
     115 
     116        /** 
     117         * Make sure two locations that fall in the same group don't get the same menu assigned. 
     118         * 
     119         * @covers wp_map_nav_menu_locations() 
     120         */ 
     121        function test_location_guessing_one_menu_per_group() { 
     122                $this->register_nav_menu_locations( array( 'primary' ) ); 
     123                $prev_theme_nav_menu_locations = array( 
     124                        'top-menu' => 1, 
     125                        'secondary' => 2, 
     126                ); 
     127 
     128                $old_next_theme_nav_menu_locations = array(); 
     129                $new_next_theme_nav_menu_locations = wp_map_nav_menu_locations( $old_next_theme_nav_menu_locations, $prev_theme_nav_menu_locations ); 
     130 
     131                $expected_nav_menu_locations = array( 
     132                        'main' => 1, 
     133                ); 
     134                $this->assertEqualSets( $expected_nav_menu_locations, $new_next_theme_nav_menu_locations ); 
     135        } 
     136 
     137        /** 
     138         * Make sure two locations that fall in the same group get menus assigned from the same group. 
     139         * 
     140         * @covers wp_map_nav_menu_locations() 
     141         */ 
     142        function test_location_guessing_one_menu_per_location() { 
     143                $this->register_nav_menu_locations( array( 'primary', 'main' ) ); 
     144 
     145                $prev_theme_nav_menu_locations = array( 
     146                        'navigation-menu' => 1, 
     147                        'top-menu' => 2, 
     148                ); 
     149 
     150                $old_next_theme_nav_menu_locations = array(); 
     151                $new_next_theme_nav_menu_locations = wp_map_nav_menu_locations( $old_next_theme_nav_menu_locations, $prev_theme_nav_menu_locations ); 
     152 
     153                $expected_nav_menu_locations = array( 
     154                        'main' => 1, 
     155                        'primary' => 2, 
     156                ); 
     157                $this->assertEquals( $expected_nav_menu_locations, $new_next_theme_nav_menu_locations ); 
     158        } 
     159 
     160        /** 
     161         * Technically possible to register menu locations numerically. 
     162         * 
     163         * @covers wp_map_nav_menu_locations() 
     164         */ 
     165        function test_numerical_locations() { 
     166                $this->register_nav_menu_locations( array( 'primary', 1 ) ); 
     167 
     168                $prev_theme_nav_menu_locations = array( 
     169                        'main' => 1, 
     170                        'secondary' => 2, 
     171                        'tertiary' => 3, 
     172                ); 
     173 
     174                $old_next_theme_nav_menu_locations = array(); 
     175                $new_next_theme_nav_menu_locations = wp_map_nav_menu_locations( $old_next_theme_nav_menu_locations, $prev_theme_nav_menu_locations ); 
     176 
     177                $expected_nav_menu_locations = array( 
     178                        'primary' => 1, 
     179                ); 
     180                $this->assertEqualSets( $expected_nav_menu_locations, $new_next_theme_nav_menu_locations ); 
     181        } 
     182}