Ticket #39693: 39693.6.diff
| File 39693.6.diff, 18.6 KB (added by , 8 years ago) |
|---|
-
src/wp-includes/theme.php
diff --git src/wp-includes/theme.php src/wp-includes/theme.php index 1d55f4f27c..20101e9892 100644
function locale_stylesheet() { 679 679 function switch_theme( $stylesheet ) { 680 680 global $wp_theme_directories, $wp_customize, $sidebars_widgets; 681 681 682 $_sidebars_widgets = null;683 if ( 'wp_ajax_customize_save' === current_action() ) {684 $_sidebars_widgets = $wp_customize->post_value( $wp_customize->get_setting( 'old_sidebars_widgets_data' ) );685 } elseif ( is_array( $sidebars_widgets ) ) {686 $_sidebars_widgets = $sidebars_widgets;687 }688 689 if ( is_array( $_sidebars_widgets ) ) {690 set_theme_mod( 'sidebars_widgets', array( 'time' => time(), 'data' => $_sidebars_widgets ) );691 }692 693 682 $nav_menu_locations = get_theme_mod( 'nav_menu_locations' ); 694 683 add_option( 'theme_switch_menu_locations', $nav_menu_locations ); 695 684 … … function switch_theme( $stylesheet ) { 716 705 717 706 update_option( 'current_theme', $new_name ); 718 707 708 $_sidebars_widgets = null; 709 if ( 'wp_ajax_customize_save' === current_action() ) { 710 $old_sidebars_widgets_data_setting = $wp_customize->get_setting( 'old_sidebars_widgets_data' ); 711 if ( $old_sidebars_widgets_data_setting ) { 712 $_sidebars_widgets = $wp_customize->post_value( $old_sidebars_widgets_data_setting ); 713 } 714 } elseif ( is_array( $sidebars_widgets ) ) { 715 $_sidebars_widgets = $sidebars_widgets; 716 } 717 718 if ( is_array( $_sidebars_widgets ) ) { 719 set_theme_mod( 'sidebars_widgets', array( 720 'time' => time(), 721 'data' => $_sidebars_widgets, 722 ) ); 723 } 724 719 725 // Migrate from the old mods_{name} option to theme_mods_{slug}. 720 726 if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) { 721 727 $default_theme_mods = (array) get_option( 'mods_' . $new_name ); -
src/wp-includes/widgets.php
diff --git src/wp-includes/widgets.php src/wp-includes/widgets.php index fbbdcf5f55..8b7a34b769 100644
function wp_get_sidebars_widgets( $deprecated = true ) { 919 919 * @since 2.2.0 920 920 * @access private 921 921 * 922 * @global array $_wp_sidebars_widgets 922 923 * @param array $sidebars_widgets Sidebar widgets and their settings. 923 924 */ 924 925 function wp_set_sidebars_widgets( $sidebars_widgets ) { 925 if ( !isset( $sidebars_widgets['array_version'] ) ) 926 global $_wp_sidebars_widgets; 927 $_wp_sidebars_widgets = null; // Clear cached value used in wp_get_sidebars_widgets(). 928 if ( ! isset( $sidebars_widgets['array_version'] ) ) { 926 929 $sidebars_widgets['array_version'] = 3; 930 } 927 931 update_option( 'sidebars_widgets', $sidebars_widgets ); 928 932 } 929 933 … … function _wp_sidebars_changed() { 1107 1111 * 1108 1112 * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value 1109 1113 * of 'customize' defers updates for the Customizer. 1110 * @return array |void1114 * @return array Updated sidebars widgets. 1111 1115 */ 1112 1116 function retrieve_widgets( $theme_changed = false ) { 1113 1117 global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets; 1114 1118 1115 $registered_sidebar_keys = array_keys( $wp_registered_sidebars ); 1116 $orphaned = 0; 1119 $registered_sidebars_keys = array_keys( $wp_registered_sidebars ); 1120 $registered_widgets_ids = array_keys( $wp_registered_widgets ); 1121 $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' ); 1117 1122 1118 $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );1119 1123 if ( is_array( $old_sidebars_widgets ) ) { 1120 1124 // time() that sidebars were stored is in $old_sidebars_widgets['time'] 1121 $ _sidebars_widgets = $old_sidebars_widgets['data'];1125 $sidebars_widgets = $old_sidebars_widgets['data']; 1122 1126 1123 1127 if ( 'customize' !== $theme_changed ) { 1124 1128 remove_theme_mod( 'sidebars_widgets' ); 1125 1129 } 1126 1127 foreach ( $_sidebars_widgets as $sidebar => $widgets ) {1128 if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) {1129 continue;1130 }1131 1132 if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {1133 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;1134 unset( $_sidebars_widgets[$sidebar] );1135 }1136 }1137 1130 } else { 1138 if ( empty( $sidebars_widgets ) ) 1139 return; 1131 if ( empty( $sidebars_widgets ) ) { 1132 return array(); 1133 } 1140 1134 1141 1135 unset( $sidebars_widgets['array_version'] ); 1142 1136 1143 $ old = array_keys($sidebars_widgets);1144 sort( $old);1145 sort( $registered_sidebar_keys);1137 $sidebars_widgets_keys = array_keys( $sidebars_widgets ); 1138 sort( $sidebars_widgets_keys ); 1139 sort( $registered_sidebars_keys ); 1146 1140 1147 if ( $ old == $registered_sidebar_keys )1148 return;1141 if ( $sidebars_widgets_keys === $registered_sidebars_keys ) { 1142 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1149 1143 1150 $_sidebars_widgets = array(1151 'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()1152 );1144 return $sidebars_widgets; 1145 } 1146 } 1153 1147 1154 unset( $sidebars_widgets['wp_inactive_widgets'] ); 1148 // Discard invalid, theme-specific widgets from sidebars. 1149 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1150 $sidebars_widgets = wp_map_sidebars_widgets( $sidebars_widgets ); 1155 1151 1156 foreach ( $wp_registered_sidebars as $id => $settings ) { 1157 if ( $theme_changed ) { 1158 $_sidebars_widgets[$id] = array_shift( $sidebars_widgets ); 1159 } else { 1160 // no theme change, grab only sidebars that are currently registered 1161 if ( isset( $sidebars_widgets[$id] ) ) { 1162 $_sidebars_widgets[$id] = $sidebars_widgets[$id]; 1163 unset( $sidebars_widgets[$id] ); 1164 } 1165 } 1152 // Find hidden/lost multi-widget instances. 1153 $shown_widgets = call_user_func_array( 'array_merge', $sidebars_widgets ); 1154 $lost_widgets = array_diff( $registered_widgets_ids, $shown_widgets ); 1155 1156 foreach ( $lost_widgets as $key => $widget_id ) { 1157 $number = preg_replace( '/.+?-([0-9]+)$/', '$1', $widget_id ); 1158 1159 if ( (int) $number < 2 ) { 1160 unset( $lost_widgets[ $key ] ); 1166 1161 } 1162 } 1163 $sidebars_widgets['wp_inactive_widgets'] = array_merge( $lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets'] ); 1164 1165 if ( 'customize' !== $theme_changed ) { 1166 wp_set_sidebars_widgets( $sidebars_widgets ); 1167 } 1168 1169 return $sidebars_widgets; 1170 } 1171 1172 /** 1173 * Compares a list of sidebars with their widgets against a whitelist. 1174 * 1175 * @since 4.9.0 1176 * 1177 * @param array $old_sidebars_widgets List of sidebars and their widget instance IDs. 1178 * @return array Mapped sidebars widgets. 1179 */ 1180 function wp_map_sidebars_widgets( $old_sidebars_widgets ) { 1181 global $wp_registered_sidebars; 1182 1183 $new_sidebars_widgets = array(); 1184 1185 // Short-circuit if there are no sidebars to map. 1186 if ( ! is_array( $old_sidebars_widgets ) || empty( $old_sidebars_widgets ) ) { 1187 return $new_sidebars_widgets; 1188 } 1167 1189 1168 foreach ( $sidebars_widgets as $val ) { 1169 if ( is_array($val) && ! empty( $val ) ) 1170 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val; 1190 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) { 1191 if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) { 1192 $new_sidebars_widgets[ $sidebar ] = (array) $widgets; 1193 unset( $old_sidebars_widgets[ $sidebar ] ); 1171 1194 } 1172 1195 } 1173 1196 1174 // discard invalid, theme-specific widgets from sidebars 1175 $shown_widgets = array(); 1197 // If old and new theme have just one sidebar, map it and we're done. 1198 if ( 1 === count( $old_sidebars_widgets ) && 1 === count( $wp_registered_sidebars ) ) { 1199 $new_sidebars_widgets[ key( $wp_registered_sidebars ) ] = array_pop( $old_sidebars_widgets ); 1176 1200 1177 foreach ( $_sidebars_widgets as $sidebar => $widgets ) { 1178 if ( !is_array($widgets) ) 1179 continue; 1201 return $new_sidebars_widgets; 1202 } 1203 1204 // Map locations with the same slug. 1205 $old_sidebars = array_keys( $old_sidebars_widgets ); 1180 1206 1181 $_widgets = array(); 1182 foreach ( $widgets as $widget ) { 1183 if ( isset($wp_registered_widgets[$widget]) ) 1184 $_widgets[] = $widget; 1207 foreach ( $wp_registered_sidebars as $sidebar => $name ) { 1208 if ( in_array( $sidebar, $old_sidebars, true ) ) { 1209 $new_sidebars_widgets[ $sidebar ] = $old_sidebars_widgets[ $sidebar ]; 1210 unset( $old_sidebars_widgets[ $sidebar ] ); 1211 } else { 1212 $new_sidebars_widgets[ $sidebar ] = array(); 1185 1213 } 1214 } 1186 1215 1187 $_sidebars_widgets[$sidebar] = $_widgets; 1188 $shown_widgets = array_merge($shown_widgets, $_widgets); 1216 // If there are no old sidebars left, then we're done. 1217 if ( empty( $old_sidebars_widgets ) ) { 1218 return $new_sidebars_widgets; 1189 1219 } 1190 1220 1191 $sidebars_widgets = $_sidebars_widgets; 1192 unset($_sidebars_widgets, $_widgets); 1221 /* 1222 * If old and new theme both have sidebars that contain phrases 1223 * from within the same group, make an educated guess and map it. 1224 */ 1225 $common_slug_groups = array( 1226 array( 'sidebar-1', 'sidebar', 'primary', 'main', 'right' ), 1227 array( 'second', 'left' ), 1228 array( 'sidebar-2', 'footer', 'bottom' ), 1229 array( 'header', 'top' ), 1230 ); 1231 1232 // Go through each group... 1233 foreach ( $common_slug_groups as $slug_group ) { 1234 1235 // ...and see if any of these slugs... 1236 foreach ( $slug_group as $slug ) { 1237 1238 // ...and any of the new sidebars... 1239 foreach ( $wp_registered_sidebars as $new_sidebar => $args ) { 1240 1241 // ...actually match! 1242 if ( false === stripos( $new_sidebar, $slug ) && false === stripos( $slug, $new_sidebar ) ) { 1243 continue; 1244 } 1245 1246 // Then see if any of the old sidebars... 1247 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) { 1248 1249 // ...and any slug in the same group... 1250 foreach ( $slug_group as $slug ) { 1251 1252 // ... have a match as well. 1253 if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) { 1254 continue; 1255 } 1256 1257 // Make sure this sidebar wasn't mapped and removed previously. 1258 if ( ! empty( $old_sidebars_widgets[ $sidebar ] ) ) { 1193 1259 1194 // find hidden/lost multi-widget instances 1195 $lost_widgets = array(); 1196 foreach ( $wp_registered_widgets as $key => $val ) { 1197 if ( in_array($key, $shown_widgets, true) ) 1198 continue; 1260 // We have a match that can be mapped! 1261 $new_sidebars_widgets[ $new_sidebar ] = array_merge( $new_sidebars_widgets[ $new_sidebar ], $old_sidebars_widgets[ $sidebar ] ); 1199 1262 1200 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key); 1263 // Remove the mapped sidebar so it can't be mapped again. 1264 unset( $old_sidebars_widgets[ $sidebar ] ); 1201 1265 1202 if ( 2 > (int) $number ) 1203 continue; 1266 // Go back and check the next new sidebar. 1267 continue 3; 1268 } 1269 } // endforeach ( $slug_group as $slug ) 1270 } // endforeach ( $old_sidebars_widgets as $sidebar => $menu_id ) 1271 } // endforeach foreach ( $wp_registered_sidebars as $new_sidebar => $name ) 1272 } // endforeach ( $slug_group as $slug ) 1273 } // endforeach ( $common_slug_groups as $slug_group ) 1204 1274 1205 $lost_widgets[] = $key; 1275 $orphaned = 0; 1276 foreach ( $old_sidebars_widgets as $widgets ) { 1277 if ( is_array( $widgets ) && ! empty( $widgets ) ) { 1278 $new_sidebars_widgets[ 'orphaned_widgets_' . ( ++$orphaned ) ] = $widgets; 1279 } 1206 1280 } 1207 1281 1208 $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']); 1209 if ( 'customize' !== $theme_changed ) { 1210 wp_set_sidebars_widgets( $sidebars_widgets ); 1282 return $new_sidebars_widgets; 1283 } 1284 1285 /** 1286 * Compares a list of sidebars with their widgets against a whitelist. 1287 * 1288 * @since 4.9.0 1289 * 1290 * @param array $sidebars_widgets List of sidebars and their widget instance IDs. 1291 * @param array $whitelist List of widget IDs to compare against. 1292 * @return array Sidebars with whitelisted widgets. 1293 */ 1294 function _wp_remove_unregistered_widgets( $sidebars_widgets, $whitelist ) { 1295 foreach ( $sidebars_widgets as $sidebar => $widgets ) { 1296 if ( is_array( $widgets ) ) { 1297 $sidebars_widgets[ $sidebar ] = array_intersect( $widgets, $whitelist ); 1298 } 1211 1299 } 1212 1300 1213 1301 return $sidebars_widgets; -
tests/phpunit/tests/widgets.php
diff --git tests/phpunit/tests/widgets.php tests/phpunit/tests/widgets.php index 233a7a8b02..12825ca6f5 100644
class Tests_Widgets extends WP_UnitTestCase { 715 715 716 716 $_wp_sidebars_widgets = array(); 717 717 $this->assertInternalType( 'array', $result ); 718 $this->assert NotEmpty( $result);718 $this->assertEquals( $result, $sidebars_widgets ); 719 719 720 720 foreach ( $sidebars_widgets as $widgets ) { 721 721 $this->assertInternalType( 'array', $widgets ); … … class Tests_Widgets extends WP_UnitTestCase { 764 764 $result = retrieve_widgets( true ); 765 765 766 766 // $sidebars_widgets matches registered sidebars. 767 $this->assertNull( $result ); 767 $this->assertInternalType( 'array', $result ); 768 $this->assertEquals( $result, $sidebars_widgets ); 768 769 769 770 foreach ( $sidebars_widgets as $widgets ) { 770 771 $this->assertInternalType( 'array', $widgets ); … … class Tests_Widgets extends WP_UnitTestCase { 773 774 $this->assertContains( 'tag_cloud-1', $sidebars_widgets['sidebar-1'] ); 774 775 $this->assertContains( 'text-1', $sidebars_widgets['sidebar-2'] ); 775 776 776 // No widget validity checkwhen $sidebars_widgets matches registered sidebars.777 $this->assert Contains( 'custom_widget-1',$sidebars_widgets['sidebar-3'] );777 // Invalid widget removed, even when $sidebars_widgets matches registered sidebars. 778 $this->assertEmpty( $sidebars_widgets['sidebar-3'] ); 778 779 779 780 // No lost widgets when $sidebars_widgets matches registered sidebars. 780 781 $this->assertEmpty( $sidebars_widgets['wp_inactive_widgets'] ); … … class Tests_Widgets extends WP_UnitTestCase { 803 804 804 805 $_wp_sidebars_widgets = array(); 805 806 $this->assertInternalType( 'array', $result ); 806 $this->assert NotEmpty( $result);807 $this->assertEquals( $result, $sidebars_widgets ); 807 808 808 809 foreach ( $sidebars_widgets as $widgets ) { 809 810 $this->assertInternalType( 'array', $widgets ); … … class Tests_Widgets extends WP_UnitTestCase { 846 847 847 848 $_wp_sidebars_widgets = array(); 848 849 $this->assertInternalType( 'array', $result ); 849 $this->assert NotEmpty( $result);850 $this->assertEquals( $result, $sidebars_widgets ); 850 851 851 852 foreach ( $sidebars_widgets as $widgets ) { 852 853 $this->assertInternalType( 'array', $widgets ); 853 854 } 854 855 855 /* 856 * Only returns intersection of registered sidebars and saved sidebars, 857 * so neither fantasy-sidebar nor sidebar-3 will make the cut. 858 */ 856 // This sidebar is not registered anymore. 859 857 $this->assertArrayNotHasKey( 'fantasy', $sidebars_widgets ); 860 $this->assertArray NotHasKey( 'sidebar-3', $sidebars_widgets );858 $this->assertArrayHasKey( 'sidebar-3', $sidebars_widgets ); 861 859 862 860 // archives-2 ends up as an orphan because of the above behavior. 863 861 $this->assertContains( 'archives-2', $sidebars_widgets['orphaned_widgets_1'] ); … … class Tests_Widgets extends WP_UnitTestCase { 904 902 905 903 $_wp_sidebars_widgets = array(); 906 904 $this->assertInternalType( 'array', $result ); 907 $this->assert NotEmpty( $result);905 $this->assertEquals( $result, $sidebars_widgets ); 908 906 909 907 foreach ( $sidebars_widgets as $widgets ) { 910 908 $this->assertInternalType( 'array', $widgets ); … … class Tests_Widgets extends WP_UnitTestCase { 929 927 // Sidebar_widgets option was not updated. 930 928 $this->assertNotEquals( $sidebars_widgets, wp_get_sidebars_widgets() ); 931 929 } 930 931 /** 932 * Test _wp_remove_unregistered_widgets. 933 * 934 * @covers _wp_remove_unregistered_widgets() 935 */ 936 public function test__wp_remove_unregistered_widgets() { 937 $widgets = array( 938 'sidebar-1' => array( 'tag_cloud-1' ), 939 'sidebar-2' => array( 'text-1' ), 940 'fantasy' => array( 'archives-2' ), 941 'wp_inactive_widgets' => array(), 942 'array_version' => 3, 943 ); 944 945 $whitelist = array( 'tag_cloud-1', 'text-1' ); 946 947 $filtered_widgets = _wp_remove_unregistered_widgets( $widgets, $whitelist ); 948 949 $this->assertInternalType( 'array', $filtered_widgets ); 950 $this->assertArrayHasKey( 'fantasy', $filtered_widgets ); 951 $this->assertEmpty( $filtered_widgets['fantasy'] ); 952 $this->assertArrayHasKey( 'array_version', $filtered_widgets ); 953 $this->assertEquals( 3, $filtered_widgets['array_version'] ); 954 $this->assertInternalType( 'integer', $filtered_widgets['array_version'] ); 955 } 956 957 /** 958 * _wp_map_sidebars Tests. 959 */ 960 961 /** 962 * Two themes with one sidebar each should just map, switching to a theme not previously-active. 963 * 964 * @covers wp_map_sidebars_widgets() 965 */ 966 public function test_one_sidebar_each() { 967 $this->register_sidebars( array( 'primary' ) ); 968 $prev_theme_sidebars = array( 969 'unique-slug' => 1, 970 ); 971 972 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 973 974 $expected_sidebars = array( 975 'primary' => 1, 976 ); 977 $this->assertEquals( $expected_sidebars, $new_next_theme_sidebars ); 978 } 979 980 /** 981 * Sidebars with the same name should map, switching to a theme not previously-active. 982 * 983 * @covers wp_map_sidebars_widgets() 984 */ 985 public function test_sidebars_with_same_slug() { 986 $this->register_sidebars( array( 'primary', 'secondary' ) ); 987 $prev_theme_sidebars = array( 988 'primary' => 1, 989 'secondary' => 2, 990 ); 991 992 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 993 994 $this->assertEquals( $prev_theme_sidebars, $new_next_theme_sidebars ); 995 } 996 997 /** 998 * Make educated guesses on theme sidebars. 999 * 1000 * @covers wp_map_sidebars_widgets() 1001 */ 1002 public function test_sidebar_guessing() { 1003 $this->register_sidebars( array( 'primary', 'secondary' ) ); 1004 1005 $prev_theme_sidebars = array( 1006 'header' => array(), 1007 'footer' => array(), 1008 ); 1009 1010 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 1011 1012 $expected_sidebars = array( 1013 'primary' => array(), 1014 'secondary' => array(), 1015 ); 1016 $this->assertEquals( $expected_sidebars, $new_next_theme_sidebars ); 1017 } 1018 1019 /** 1020 * Make sure two sidebars that fall in the same group don't get the same menu assigned. 1021 * 1022 * @covers wp_map_sidebars_widgets() 1023 */ 1024 public function test_sidebar_guessing_one_menu_per_group() { 1025 $this->register_sidebars( array( 'primary' ) ); 1026 $prev_theme_sidebars = array( 1027 'top-menu' => array(), 1028 'secondary' => array(), 1029 ); 1030 1031 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 1032 1033 $expected_sidebars = array( 1034 'main' => array(), 1035 ); 1036 $this->assertEqualSets( $expected_sidebars, $new_next_theme_sidebars ); 1037 } 1038 1039 /** 1040 * Make sure two sidebars that fall in the same group get menus assigned from the same group. 1041 * 1042 * @covers wp_map_sidebars_widgets() 1043 */ 1044 public function test_sidebar_guessing_one_menu_per_sidebar() { 1045 $this->register_sidebars( array( 'primary', 'main' ) ); 1046 1047 $prev_theme_sidebars = array( 1048 'navigation-menu' => array(), 1049 'top-menu' => array(), 1050 ); 1051 1052 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 1053 1054 $expected_sidebars = array( 1055 'main' => array(), 1056 'primary' => array(), 1057 ); 1058 $this->assertEquals( $expected_sidebars, $new_next_theme_sidebars ); 1059 } 932 1060 }