Ticket #39693: 39693.5.diff
File 39693.5.diff, 17.7 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..e30f1571ba 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 $_sidebars_widgets = $wp_customize->post_value( $wp_customize->get_setting( 'old_sidebars_widgets_data' ) ); 711 } elseif ( is_array( $sidebars_widgets ) ) { 712 $_sidebars_widgets = $sidebars_widgets; 713 } 714 715 if ( is_array( $_sidebars_widgets ) ) { 716 set_theme_mod( 'sidebars_widgets', array( 717 'time' => time(), 718 'data' => $_sidebars_widgets, 719 ) ); 720 } 721 719 722 // Migrate from the old mods_{name} option to theme_mods_{slug}. 720 723 if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) { 721 724 $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..bcb35b0d98 100644
function _wp_sidebars_changed() { 1107 1107 * 1108 1108 * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value 1109 1109 * of 'customize' defers updates for the Customizer. 1110 * @return array |void1110 * @return array 1111 1111 */ 1112 1112 function retrieve_widgets( $theme_changed = false ) { 1113 1113 global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets; 1114 1114 1115 $registered_sidebar_keys = array_keys( $wp_registered_sidebars ); 1116 $orphaned = 0; 1115 $registered_sidebars_keys = array_keys( $wp_registered_sidebars ); 1116 $registered_widgets_ids = array_keys( $wp_registered_widgets ); 1117 $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' ); 1117 1118 1118 $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );1119 1119 if ( is_array( $old_sidebars_widgets ) ) { 1120 1120 // time() that sidebars were stored is in $old_sidebars_widgets['time'] 1121 $ _sidebars_widgets = $old_sidebars_widgets['data'];1121 $sidebars_widgets = $old_sidebars_widgets['data']; 1122 1122 1123 1123 if ( 'customize' !== $theme_changed ) { 1124 1124 remove_theme_mod( 'sidebars_widgets' ); 1125 1125 } 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 1126 } else { 1138 if ( empty( $sidebars_widgets ) ) 1139 return; 1127 if ( empty( $sidebars_widgets ) ) { 1128 return array(); 1129 } 1140 1130 1141 1131 unset( $sidebars_widgets['array_version'] ); 1142 1132 1143 $ old = array_keys($sidebars_widgets);1144 sort( $old);1145 sort( $registered_sidebar_keys);1133 $sidebars_widgets_keys = array_keys( $sidebars_widgets ); 1134 sort( $sidebars_widgets_keys ); 1135 sort( $registered_sidebars_keys ); 1146 1136 1147 if ( $ old == $registered_sidebar_keys )1148 return;1137 if ( $sidebars_widgets_keys === $registered_sidebars_keys ) { 1138 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1149 1139 1150 $_sidebars_widgets = array(1151 'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()1152 );1140 return $sidebars_widgets; 1141 } 1142 } 1153 1143 1154 unset( $sidebars_widgets['wp_inactive_widgets'] ); 1144 // Discard invalid, theme-specific widgets from sidebars. 1145 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1146 $sidebars_widgets = _wp_map_sidebars( $sidebars_widgets ); 1155 1147 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 } 1148 // Find hidden/lost multi-widget instances. 1149 $shown_widgets = call_user_func_array( 'array_merge', $sidebars_widgets ); 1150 $lost_widgets = array_diff( $registered_widgets_ids, $shown_widgets ); 1151 1152 foreach ( $lost_widgets as $key => $widget_id ) { 1153 $number = preg_replace( '/.+?-([0-9]+)$/', '$1', $widget_id ); 1154 1155 if ( (int) $number < 2 ) { 1156 unset( $lost_widgets[ $key ] ); 1166 1157 } 1158 } 1159 $sidebars_widgets['wp_inactive_widgets'] = array_merge( $lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets'] ); 1160 1161 if ( 'customize' !== $theme_changed ) { 1162 wp_set_sidebars_widgets( $sidebars_widgets ); 1163 } 1164 1165 return $sidebars_widgets; 1166 } 1167 1168 /** 1169 * Compares a list of sidebars with their widgets against a whitelist. 1170 * 1171 * @since 4.9.0 1172 * 1173 * @param array $old_sidebars_widgets List of sidebars and their widget instance IDs. 1174 * @return array Mapped sidebars widgets. 1175 */ 1176 function _wp_map_sidebars( $old_sidebars_widgets ) { 1177 global $wp_registered_sidebars; 1167 1178 1168 foreach ( $sidebars_widgets as $val ) { 1169 if ( is_array($val) && ! empty( $val ) ) 1170 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val; 1179 $new_sidebars_widgets = array(); 1180 1181 // Short-circuit if there are no sidebars to map. 1182 if ( ! is_array( $old_sidebars_widgets ) || empty( $old_sidebars_widgets ) ) { 1183 return $new_sidebars_widgets; 1184 } 1185 1186 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) { 1187 if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) { 1188 $new_sidebars_widgets[ $sidebar ] = (array) $widgets; 1189 unset( $old_sidebars_widgets[ $sidebar ] ); 1171 1190 } 1172 1191 } 1173 1192 1174 // discard invalid, theme-specific widgets from sidebars 1175 $shown_widgets = array(); 1193 // If old and new theme have just one sidebar, map it and we're done. 1194 if ( 1 === count( $old_sidebars_widgets ) && 1 === count( $wp_registered_sidebars ) ) { 1195 $new_sidebars_widgets[ key( $wp_registered_sidebars ) ] = array_pop( $old_sidebars_widgets ); 1196 1197 return $new_sidebars_widgets; 1198 } 1176 1199 1177 foreach ( $_sidebars_widgets as $sidebar => $widgets ) { 1178 if ( !is_array($widgets) ) 1179 continue; 1200 // Map locations with the same slug. 1201 $old_sidebars = array_keys( $old_sidebars_widgets ); 1180 1202 1181 $_widgets = array(); 1182 foreach ( $widgets as $widget ) { 1183 if ( isset($wp_registered_widgets[$widget]) ) 1184 $_widgets[] = $widget; 1203 foreach ( $wp_registered_sidebars as $sidebar => $name ) { 1204 if ( in_array( $sidebar, $old_sidebars, true ) ) { 1205 $new_sidebars_widgets[ $sidebar ] = $old_sidebars_widgets[ $sidebar ]; 1206 unset( $old_sidebars_widgets[ $sidebar ] ); 1207 } else { 1208 $new_sidebars_widgets[ $sidebar ] = array(); 1185 1209 } 1210 } 1186 1211 1187 $_sidebars_widgets[$sidebar] = $_widgets; 1188 $shown_widgets = array_merge($shown_widgets, $_widgets); 1212 // If there are no old sidebars left, then we're done. 1213 if ( empty( $old_sidebars_widgets ) ) { 1214 return $new_sidebars_widgets; 1189 1215 } 1190 1216 1191 $sidebars_widgets = $_sidebars_widgets; 1192 unset($_sidebars_widgets, $_widgets); 1217 /* 1218 * If old and new theme both have sidebars that contain phrases 1219 * from within the same group, make an educated guess and map it. 1220 */ 1221 $common_slug_groups = array( 1222 array( 'sidebar', 'primary', 'main', 'right' ), 1223 array( 'second', 'left' ), 1224 array( 'footer', 'bottom' ), 1225 array( 'header', 'top' ), 1226 ); 1227 1228 // Go through each group... 1229 foreach ( $common_slug_groups as $slug_group ) { 1230 1231 // ...and see if any of these slugs... 1232 foreach ( $slug_group as $slug ) { 1233 1234 // ...and any of the new sidebars... 1235 foreach ( $wp_registered_sidebars as $new_sidebar => $args ) { 1236 1237 // ...actually match! 1238 if ( false === stripos( $new_sidebar, $slug ) && false === stripos( $slug, $new_sidebar ) ) { 1239 continue; 1240 } 1241 1242 // Then see if any of the old sidebars... 1243 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) { 1193 1244 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; 1245 // ...and any slug in the same group... 1246 foreach ( $slug_group as $slug ) { 1199 1247 1200 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key); 1248 // ... have a match as well. 1249 if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) { 1250 continue; 1251 } 1201 1252 1202 if ( 2 > (int) $number )1203 continue;1253 // Make sure this sidebar wasn't mapped and removed previously. 1254 if ( ! empty( $old_sidebars_widgets[ $sidebar ] ) ) { 1204 1255 1205 $lost_widgets[] = $key; 1256 // We have a match that can be mapped! 1257 $new_sidebars_widgets[ $new_sidebar ] = array_merge( $new_sidebars_widgets[ $new_sidebar ], $old_sidebars_widgets[ $sidebar ] ); 1258 1259 // Remove the mapped sidebar so it can't be mapped again. 1260 unset( $old_sidebars_widgets[ $sidebar ] ); 1261 1262 // Go back and check the next new sidebar. 1263 continue 3; 1264 } 1265 } // endforeach ( $slug_group as $slug ) 1266 } // endforeach ( $old_sidebars_widgets as $sidebar => $menu_id ) 1267 } // endforeach foreach ( $wp_registered_sidebars as $new_sidebar => $name ) 1268 } // endforeach ( $slug_group as $slug ) 1269 } // endforeach ( $common_slug_groups as $slug_group ) 1270 1271 $orphaned = 0; 1272 foreach ( $old_sidebars_widgets as $widgets ) { 1273 if ( is_array( $widgets ) && ! empty( $widgets ) ) { 1274 $new_sidebars_widgets[ 'orphaned_widgets_' . ( ++$orphaned ) ] = $widgets; 1275 } 1206 1276 } 1207 1277 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 ); 1278 return $new_sidebars_widgets; 1279 } 1280 1281 /** 1282 * Compares a list of sidebars with their widgets against a whitelist. 1283 * 1284 * @since 4.9.0 1285 * 1286 * @param array $sidebars_widgets List of sidebars and their widget instance IDs. 1287 * @param array $whitelist List of widget IDs to compare against. 1288 * @return array Sidebars with whitelisted widgets. 1289 */ 1290 function _wp_remove_unregistered_widgets( $sidebars_widgets, $whitelist ) { 1291 foreach ( $sidebars_widgets as $sidebar => $widgets ) { 1292 if ( is_array( $widgets ) ) { 1293 $sidebars_widgets[ $sidebar ] = array_intersect( $widgets, $whitelist ); 1294 } 1211 1295 } 1212 1296 1213 1297 return $sidebars_widgets; -
tests/phpunit/tests/widgets.php
diff --git tests/phpunit/tests/widgets.php tests/phpunit/tests/widgets.php index 233a7a8b02..7ab4122b85 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() 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( $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() 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( $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() 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( $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() 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( $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() 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( $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 }