Make WordPress Core

Ticket #39692: 39692.6.diff

File 39692.6.diff, 12.3 KB (added by westonruter, 7 years ago)

Δ https://github.com/xwp/wordpress-develop/pull/245/commits/48a67c0bf0410cae15686b4ff1216c3daa2e2301

  • 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..73b40bcd21 100644
    final class WP_Customize_Nav_Menus { 
    2929        /**
    3030         * Previewed Menus.
    3131         *
     32         * @todo This is unused and can be removed.
     33         *
    3234         * @since 4.3.0
    3335         * @var array
    3436         */
    3537        public $previewed_menus;
    3638
    3739        /**
     40         * Original nav menu locations before the theme was switched.
     41         *
     42         * @since 4.9.0
     43         * @var array
     44         */
     45        protected $original_nav_menu_locations;
     46
     47        /**
    3848         * Constructor.
    3949         *
    4050         * @since 4.3.0
    final class WP_Customize_Nav_Menus { 
    4252         * @param object $manager An instance of the WP_Customize_Manager class.
    4353         */
    4454        public function __construct( $manager ) {
    45                 $this->previewed_menus = array();
    46                 $this->manager         = $manager;
     55                $this->previewed_menus = array(); // @todo This is unused and can be removed.
     56                $this->manager = $manager;
     57                $this->original_nav_menu_locations = get_nav_menu_locations();
    4758
    4859                // See https://github.com/xwp/wp-customize-snapshots/blob/962586659688a5b1fd9ae93618b7ce2d4e7a421c/php/class-customize-snapshot-manager.php#L469-L499
    4960                add_action( 'customize_register', array( $this, 'customize_register' ), 11 );
    final class WP_Customize_Nav_Menus { 
    582593                        $choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '…' );
    583594                }
    584595
     596                // Attempt to re-map the nav menu location assignments when previewing a theme switch.
     597                $remapped_nav_menu_locations = array();
     598                if ( ! $this->manager->is_theme_active() ) {
     599                        $remapped_nav_menu_locations = wp_get_remapped_nav_menu_locations( get_nav_menu_locations(), $this->original_nav_menu_locations );
     600                }
     601
    585602                foreach ( $locations as $location => $description ) {
    586603                        $setting_id = "nav_menu_locations[{$location}]";
    587604
    final class WP_Customize_Nav_Menus { 
    600617                                ) );
    601618                        }
    602619
     620                        // Override the assigned nav menu location if remapped during previewed theme switch.
     621                        if ( isset( $remapped_nav_menu_locations[ $location ] ) ) {
     622                                $this->manager->set_post_value( $setting_id, $remapped_nav_menu_locations[ $location ] );
     623                        }
     624
    603625                        $this->manager->add_control( new WP_Customize_Nav_Menu_Location_Control( $this->manager, $setting_id, array(
    604626                                'label'       => $description,
    605627                                '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..aaeca74d33 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        // 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..db582b8a12
    - +  
     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                register_nav_menus( array(
     20                        'primary' => 'Primary',
     21                ) );
     22        }
     23
     24        /**
     25         * Two themes with one location each should just map.
     26         */
     27        function test_one_location_each() {
     28                $old_nav_menu_locations = array(
     29                        'unique-slug' => 1,
     30                );
     31                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     32
     33                _wp_menus_changed();
     34                $this->assertEqualSets( $old_nav_menu_locations, get_theme_mod( 'nav_menu_locations' ) );
     35        }
     36
     37        /**
     38         * Locations with the same name should map.
     39         */
     40        function test_locations_with_same_slug() {
     41                $old_nav_menu_locations = array(
     42                        'primary' => 1,
     43                        'secondary' => 2,
     44                );
     45                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     46                register_nav_menu( 'secondary', 'Secondary' );
     47
     48                _wp_menus_changed();
     49                $this->assertEqualSets( $old_nav_menu_locations, get_theme_mod( 'nav_menu_locations' ) );
     50        }
     51
     52        /**
     53         * If the new theme was previously active, we should fall back to that data.
     54         */
     55        function test_new_theme_previously_active() {
     56                $old_nav_menu_locations = array(
     57                        'primary' => 3,
     58                );
     59                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     60                $previous_locations = array(
     61                        'primary' => 1,
     62                        'secondary' => 2,
     63                );
     64                set_theme_mod( 'nav_menu_locations', $previous_locations );
     65
     66                _wp_menus_changed();
     67                $expected = array_merge( $previous_locations, $old_nav_menu_locations );
     68                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) );
     69        }
     70
     71        /**
     72         * Make educated guesses on theme locations.
     73         */
     74        function test_location_guessing() {
     75                $old_nav_menu_locations = array(
     76                        'header' => 1,
     77                        'footer' => 2,
     78                );
     79                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     80                register_nav_menu( 'secondary', 'Secondary' );
     81
     82                _wp_menus_changed();
     83                $expected = array(
     84                        'primary' => 1,
     85                        'secondary' => 2,
     86                );
     87                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) );
     88        }
     89
     90        /**
     91         * Make sure two locations that fall in the same group don't get the same menu assigned.
     92         */
     93        function test_location_guessing_one_menu_per_group() {
     94                $old_nav_menu_locations = array(
     95                        'top-menu' => 1,
     96                        'secondary' => 2,
     97                );
     98                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     99                register_nav_menu( 'main', 'Main' );
     100
     101                _wp_menus_changed();
     102                $expected = array(
     103                        'main' => 1,
     104                );
     105                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) );
     106        }
     107
     108        /**
     109         * Make sure two locations that fall in the same group get menus assigned from the same group.
     110         */
     111        function test_location_guessing_one_menu_per_location() {
     112                $old_nav_menu_locations = array(
     113                        'navigation-menu' => 1,
     114                        'top-menu' => 2,
     115                );
     116                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     117                register_nav_menu( 'main', 'Main' );
     118
     119                _wp_menus_changed();
     120                $expected = array(
     121                        'main' => 1,
     122                        'primary' => 2,
     123                );
     124                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) );
     125        }
     126
     127        /**
     128         * Technically possible to register menu locations numerically.
     129         */
     130        function test_numerical_locations() {
     131                $old_nav_menu_locations = array(
     132                        'main' => 1,
     133                        'secondary' => 2,
     134                        'tertiary' => 3,
     135                );
     136                update_option( 'theme_switch_menu_locations', $old_nav_menu_locations );
     137                register_nav_menu( 1 , 'First' );
     138
     139                _wp_menus_changed();
     140                $expected = array(
     141                        'primary' => 1,
     142                );
     143                $this->assertEqualSets( $expected, get_theme_mod( 'nav_menu_locations' ) );
     144        }
     145}