WordPress.org

Make WordPress Core

Ticket #39692: 39692.4.diff

File 39692.4.diff, 9.5 KB (added by westonruter, 6 months ago)

Δ https://github.com/xwp/wordpress-develop/pull/245/files/5445156..4054096

  • 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..aa5809840a 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        $remapped_nav_menu_locations = wp_get_remapped_nav_menu_locations( $new_nav_menu_locations, $old_nav_menu_locations ); 
     1040        set_theme_mod( 'nav_menu_locations', $remapped_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 remapped to new nav menu locations. 
     1052 */ 
     1053function wp_get_remapped_nav_menu_locations( $new_nav_menu_locations, $old_nav_menu_locations ) { 
     1054        $registered_nav_menus   = get_registered_nav_menus(); 
     1055 
     1056        if ( ! empty( $old_nav_menu_locations ) ) { 
     1057                // If old and new theme have just one location, map it. 
     1058                if ( 1 === count( $old_nav_menu_locations ) && 1 === count( $registered_nav_menus ) ) { 
     1059                        $new_nav_menu_locations[ key( $registered_nav_menus ) ] = array_pop( $old_nav_menu_locations ); 
     1060                } else { 
     1061                        $old_locations = array_keys( $old_nav_menu_locations ); 
     1062 
     1063                        // Map locations with the same slug. 
     1064                        foreach ( $registered_nav_menus as $location => $name ) { 
     1065                                if ( in_array( $location, $old_locations, true ) ) { 
     1066                                        $new_nav_menu_locations[ $location ] = $old_nav_menu_locations[ $location ]; 
     1067                                        unset( $old_nav_menu_locations[ $location ] ); 
     1068                                } 
     1069                        } 
     1070 
     1071                        if ( ! empty( $old_nav_menu_locations ) ) { 
     1072                                /* 
     1073                                 * If old and new theme both have locations that contain phrases 
     1074                                 * from within the same group, make an educated guess and map it. 
     1075                                 */ 
     1076                                $common_slug_groups = array( 
     1077                                        array( 'header', 'main', 'navigation', 'primary', 'top' ), 
     1078                                        array( 'bottom', 'footer', 'secondary', 'subsidiary' ), 
     1079                                        array( 'social' ), 
     1080                                        // TODO: Find a second slug or remove, since locations with same slug are already mapped. 
     1081                                ); 
     1082 
     1083                                // Go through each group... 
     1084                                foreach ( $common_slug_groups as $slug_group ) { 
     1085 
     1086                                        // ...and see if any of these slugs... 
     1087                                        foreach ( $slug_group as $slug ) { 
     1088 
     1089                                                // ...and any of the new menu locations... 
     1090                                                foreach ( $registered_nav_menus as $new_location => $name ) { 
     1091 
     1092                                                        // ...actually match! 
     1093                                                        if ( false !== stripos( $new_location, $slug ) || false !== stripos( $slug, $new_location ) ) { 
     1094 
     1095                                                                // Then see if any of the old locations... 
     1096                                                                foreach ( $old_nav_menu_locations as $location => $menu_id ) { 
     1097 
     1098                                                                        // ...match a slug in the same group. 
     1099                                                                        foreach ( $slug_group as $slug ) { 
     1100                                                                                if ( false !== stripos( $location, $slug ) || false !== stripos( $slug, $location ) ) { 
     1101 
     1102                                                                                        // Make sure this location wasn't mapped and removed previously. 
     1103                                                                                        if ( ! empty( $old_nav_menu_locations[ $location ] ) ) { 
     1104 
     1105                                                                                                // We have a match that can be mapped! 
     1106                                                                                                $new_nav_menu_locations[ $new_location ] = $old_nav_menu_locations[ $location ]; 
     1107 
     1108                                                                                                // Remove the mapped location so it can't be mapped again. 
     1109                                                                                                unset( $old_nav_menu_locations[ $location ] ); 
     1110 
     1111                                                                                                // Go back and check the next new menu location. 
     1112                                                                                                continue 3; 
     1113                                                                                        } 
     1114                                                                                } 
     1115                                                                        } 
     1116                                                                } 
     1117                                                        } 
     1118                                                } 
     1119                                        } 
     1120                                } 
     1121                        } 
     1122                } 
     1123        } 
     1124 
     1125        return $new_nav_menu_locations; 
     1126} 
  • 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..413a236190
    - +  
     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( 
     30                        'unique-slug' => 1, 
     31                ); 
     32                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations ); 
     33 
     34                _wp_menus_changed(); 
     35                $this->assertEqualSets( $old_nav_menu_locations, get_theme_mod( 'nav_menu_locations' ) ); 
     36        } 
     37 
     38        /** 
     39         * Locations with the same name should map. 
     40         */ 
     41        function test_locations_with_same_slug() { 
     42                $old_nav_menu_locations = array( 
     43                        'primary' => 1, 
     44                        'secondary' => 2, 
     45                ); 
     46                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations ); 
     47                register_nav_menu( 'secondary', 'Secondary' ); 
     48 
     49                _wp_menus_changed(); 
     50                $this->assertEqualSets( $old_nav_menu_locations, get_theme_mod( 'nav_menu_locations' ) ); 
     51        } 
     52 
     53        /** 
     54         * If the new theme was previously active, we should fall back to that data. 
     55         */ 
     56        function test_new_theme_previously_active() { 
     57                $old_nav_menu_locations = array( 
     58                        'primary' => 3, 
     59                ); 
     60                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations ); 
     61                $previous_locations = array( 
     62                        'primary' => 1, 
     63                        'secondary' => 2, 
     64                ); 
     65                set_theme_mod( 'nav_menu_locations', $previous_locations ); 
     66 
     67                _wp_menus_changed(); 
     68                $expected = array_merge( $previous_locations, $old_nav_menu_locations ); 
     69                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) ); 
     70        } 
     71 
     72        /** 
     73         * Make educated guesses on theme locations. 
     74         */ 
     75        function test_location_guessing() { 
     76                $old_nav_menu_locations = array( 
     77                        'header' => 1, 
     78                        'footer' => 2, 
     79                ); 
     80                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations ); 
     81                register_nav_menu( 'secondary', 'Secondary' ); 
     82 
     83                _wp_menus_changed(); 
     84                $expected = array( 
     85                        'primary' => 1, 
     86                        'secondary' => 2, 
     87                ); 
     88                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) ); 
     89        } 
     90 
     91        /** 
     92         * Make sure two locations that fall in the same group don't get the same menu assigned. 
     93         */ 
     94        function test_location_guessing_one_menu_per_group() { 
     95                $old_nav_menu_locations = array( 
     96                        'top-menu' => 1, 
     97                        'secondary' => 2, 
     98                ); 
     99                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations ); 
     100                register_nav_menu( 'main', 'Main' ); 
     101 
     102                _wp_menus_changed(); 
     103                $expected = array( 
     104                        'main' => 1, 
     105                ); 
     106                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) ); 
     107        } 
     108 
     109        /** 
     110         * Make sure two locations that fall in the same group get menus assigned from the same group. 
     111         */ 
     112        function test_location_guessing_one_menu_per_location() { 
     113                $old_nav_menu_locations = array( 
     114                        'navigation-menu' => 1, 
     115                        'top-menu' => 2, 
     116                ); 
     117                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations ); 
     118                register_nav_menu( 'main', 'Main' ); 
     119 
     120                _wp_menus_changed(); 
     121                $expected = array( 
     122                        'main' => 1, 
     123                        'primary' => 2, 
     124                ); 
     125                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) ); 
     126        } 
     127 
     128        /** 
     129         * Technically possible to register menu locations numerically. 
     130         */ 
     131        function test_numerical_locations() { 
     132                $old_nav_menu_locations = array( 
     133                        'main' => 1, 
     134                        'secondary' => 2, 
     135                        'tertiary' => 3, 
     136                ); 
     137                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations ); 
     138                register_nav_menu( 1 , 'First' ); 
     139 
     140                _wp_menus_changed(); 
     141                $expected = array( 
     142                        'primary' => 1, 
     143                ); 
     144                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) ); 
     145        } 
     146}