Ticket #39693: 39693.7.diff
File 39693.7.diff, 19.0 KB (added by , 8 years ago) |
---|
-
src/wp-includes/theme.php
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 … … 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
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 928 // Clear cached value used in wp_get_sidebars_widgets(). 929 $_wp_sidebars_widgets = null; 930 931 if ( ! isset( $sidebars_widgets['array_version'] ) ) { 926 932 $sidebars_widgets['array_version'] = 3; 933 } 934 927 935 update_option( 'sidebars_widgets', $sidebars_widgets ); 928 936 } 929 937 … … 1113 1121 * 1114 1122 * @param string|bool $theme_changed Whether the theme was changed as a boolean. A value 1115 1123 * of 'customize' defers updates for the Customizer. 1116 * @return array |void1124 * @return array Updated sidebars widgets. 1117 1125 */ 1118 1126 function retrieve_widgets( $theme_changed = false ) { 1119 1127 global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets; 1120 1128 1121 $registered_sidebar_keys = array_keys( $wp_registered_sidebars ); 1122 $orphaned = 0; 1129 $registered_sidebars_keys = array_keys( $wp_registered_sidebars ); 1130 $registered_widgets_ids = array_keys( $wp_registered_widgets ); 1131 $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' ); 1123 1132 1124 $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );1125 1133 if ( is_array( $old_sidebars_widgets ) ) { 1126 1134 // time() that sidebars were stored is in $old_sidebars_widgets['time'] 1127 $ _sidebars_widgets = $old_sidebars_widgets['data'];1135 $sidebars_widgets = $old_sidebars_widgets['data']; 1128 1136 1129 1137 if ( 'customize' !== $theme_changed ) { 1130 1138 remove_theme_mod( 'sidebars_widgets' ); 1131 1139 } 1140 } else { 1141 if ( empty( $sidebars_widgets ) ) { 1142 return array(); 1143 } 1132 1144 1133 foreach ( $_sidebars_widgets as $sidebar => $widgets ) { 1134 if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) { 1135 continue; 1136 } 1145 unset( $sidebars_widgets['array_version'] ); 1137 1146 1138 if ( !in_array( $sidebar, $registered_sidebar_keys ) ) { 1139 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets; 1140 unset( $_sidebars_widgets[$sidebar] ); 1141 } 1147 $sidebars_widgets_keys = array_keys( $sidebars_widgets ); 1148 sort( $sidebars_widgets_keys ); 1149 sort( $registered_sidebars_keys ); 1150 1151 if ( $sidebars_widgets_keys === $registered_sidebars_keys ) { 1152 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1153 1154 return $sidebars_widgets; 1142 1155 } 1143 } else { 1144 if ( empty( $sidebars_widgets ) ) 1145 return; 1156 } 1146 1157 1147 unset( $sidebars_widgets['array_version'] ); 1158 // Discard invalid, theme-specific widgets from sidebars. 1159 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1160 $sidebars_widgets = wp_map_sidebars_widgets( $sidebars_widgets ); 1148 1161 1149 $old = array_keys($sidebars_widgets); 1150 sort($old); 1151 sort($registered_sidebar_keys); 1152 1153 if ( $old == $registered_sidebar_keys ) 1154 return; 1155 1156 $_sidebars_widgets = array( 1157 'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array() 1158 ); 1159 1160 unset( $sidebars_widgets['wp_inactive_widgets'] ); 1161 1162 foreach ( $wp_registered_sidebars as $id => $settings ) { 1163 if ( $theme_changed ) { 1164 $_sidebars_widgets[$id] = array_shift( $sidebars_widgets ); 1165 } else { 1166 // no theme change, grab only sidebars that are currently registered 1167 if ( isset( $sidebars_widgets[$id] ) ) { 1168 $_sidebars_widgets[$id] = $sidebars_widgets[$id]; 1169 unset( $sidebars_widgets[$id] ); 1170 } 1171 } 1162 // Find hidden/lost multi-widget instances. 1163 $shown_widgets = call_user_func_array( 'array_merge', $sidebars_widgets ); 1164 $lost_widgets = array_diff( $registered_widgets_ids, $shown_widgets ); 1165 1166 foreach ( $lost_widgets as $key => $widget_id ) { 1167 $number = preg_replace( '/.+?-([0-9]+)$/', '$1', $widget_id ); 1168 1169 if ( is_numeric( $number ) && (int) $number < 2 ) { 1170 unset( $lost_widgets[ $key ] ); 1172 1171 } 1172 } 1173 $sidebars_widgets['wp_inactive_widgets'] = array_merge( $lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets'] ); 1173 1174 1174 foreach ( $sidebars_widgets as $val ) { 1175 if ( is_array($val) && ! empty( $val ) ) 1176 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val; 1175 if ( 'customize' !== $theme_changed ) { 1176 wp_set_sidebars_widgets( $sidebars_widgets ); 1177 } 1178 1179 return $sidebars_widgets; 1180 } 1181 1182 /** 1183 * Compares a list of sidebars with their widgets against a whitelist. 1184 * 1185 * @since 4.9.0 1186 * 1187 * @param array $old_sidebars_widgets List of sidebars and their widget instance IDs. 1188 * @return array Mapped sidebars widgets. 1189 */ 1190 function wp_map_sidebars_widgets( $old_sidebars_widgets ) { 1191 global $wp_registered_sidebars; 1192 1193 $new_sidebars_widgets = array(); 1194 1195 // Short-circuit if there are no sidebars to map. 1196 if ( ! is_array( $old_sidebars_widgets ) || empty( $old_sidebars_widgets ) ) { 1197 return $new_sidebars_widgets; 1198 } 1199 1200 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) { 1201 if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) { 1202 $new_sidebars_widgets[ $sidebar ] = (array) $widgets; 1203 unset( $old_sidebars_widgets[ $sidebar ] ); 1177 1204 } 1178 1205 } 1179 1206 1180 // discard invalid, theme-specific widgets from sidebars 1181 $shown_widgets = array(); 1207 // If old and new theme have just one sidebar, map it and we're done. 1208 if ( 1 === count( $old_sidebars_widgets ) && 1 === count( $wp_registered_sidebars ) ) { 1209 $new_sidebars_widgets[ key( $wp_registered_sidebars ) ] = array_pop( $old_sidebars_widgets ); 1182 1210 1183 foreach ( $_sidebars_widgets as $sidebar => $widgets ) { 1184 if ( !is_array($widgets) ) 1185 continue; 1211 return $new_sidebars_widgets; 1212 } 1213 1214 // Map locations with the same slug. 1215 $old_sidebars = array_keys( $old_sidebars_widgets ); 1186 1216 1187 $_widgets = array(); 1188 foreach ( $widgets as $widget ) { 1189 if ( isset($wp_registered_widgets[$widget]) ) 1190 $_widgets[] = $widget; 1217 foreach ( $wp_registered_sidebars as $sidebar => $name ) { 1218 if ( in_array( $sidebar, $old_sidebars, true ) ) { 1219 $new_sidebars_widgets[ $sidebar ] = $old_sidebars_widgets[ $sidebar ]; 1220 unset( $old_sidebars_widgets[ $sidebar ] ); 1221 } else { 1222 $new_sidebars_widgets[ $sidebar ] = array(); 1191 1223 } 1224 } 1192 1225 1193 $_sidebars_widgets[$sidebar] = $_widgets; 1194 $shown_widgets = array_merge($shown_widgets, $_widgets); 1226 // If there are no old sidebars left, then we're done. 1227 if ( empty( $old_sidebars_widgets ) ) { 1228 return $new_sidebars_widgets; 1195 1229 } 1196 1230 1197 $sidebars_widgets = $_sidebars_widgets; 1198 unset($_sidebars_widgets, $_widgets); 1231 /* 1232 * If old and new theme both have sidebars that contain phrases 1233 * from within the same group, make an educated guess and map it. 1234 */ 1235 $common_slug_groups = array( 1236 array( 'sidebar', 'primary', 'main', 'right' ), 1237 array( 'second', 'left' ), 1238 array( 'sidebar-2', 'footer', 'bottom' ), 1239 array( 'header', 'top' ), 1240 ); 1199 1241 1200 // find hidden/lost multi-widget instances 1201 $lost_widgets = array(); 1202 foreach ( $wp_registered_widgets as $key => $val ) { 1203 if ( in_array($key, $shown_widgets, true) ) 1204 continue; 1242 // Go through each group... 1243 foreach ( $common_slug_groups as $slug_group ) { 1205 1244 1206 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key); 1245 // ...and see if any of these slugs... 1246 foreach ( $slug_group as $slug ) { 1207 1247 1208 if ( 2 > (int) $number )1209 continue;1248 // ...and any of the new sidebars... 1249 foreach ( $wp_registered_sidebars as $new_sidebar => $args ) { 1210 1250 1211 $lost_widgets[] = $key; 1251 // ...actually match! 1252 if ( false === stripos( $new_sidebar, $slug ) && false === stripos( $slug, $new_sidebar ) ) { 1253 continue; 1254 } 1255 1256 // Then see if any of the old sidebars... 1257 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) { 1258 1259 // ...and any slug in the same group... 1260 foreach ( $slug_group as $slug ) { 1261 1262 // ... have a match as well. 1263 if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) { 1264 continue; 1265 } 1266 1267 // Make sure this sidebar wasn't mapped and removed previously. 1268 if ( ! empty( $old_sidebars_widgets[ $sidebar ] ) ) { 1269 1270 // We have a match that can be mapped! 1271 $new_sidebars_widgets[ $new_sidebar ] = array_merge( $new_sidebars_widgets[ $new_sidebar ], $old_sidebars_widgets[ $sidebar ] ); 1272 1273 // Remove the mapped sidebar so it can't be mapped again. 1274 unset( $old_sidebars_widgets[ $sidebar ] ); 1275 1276 // Go back and check the next new sidebar. 1277 continue 3; 1278 } 1279 } // endforeach ( $slug_group as $slug ) 1280 } // endforeach ( $old_sidebars_widgets as $sidebar => $menu_id ) 1281 } // endforeach foreach ( $wp_registered_sidebars as $new_sidebar => $name ) 1282 } // endforeach ( $slug_group as $slug ) 1283 } // endforeach ( $common_slug_groups as $slug_group ) 1284 1285 $orphaned = 0; 1286 foreach ( $old_sidebars_widgets as $widgets ) { 1287 if ( is_array( $widgets ) && ! empty( $widgets ) ) { 1288 $new_sidebars_widgets[ 'orphaned_widgets_' . ( ++$orphaned ) ] = $widgets; 1289 } 1212 1290 } 1213 1291 1214 $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']); 1215 if ( 'customize' !== $theme_changed ) { 1216 wp_set_sidebars_widgets( $sidebars_widgets ); 1292 return $new_sidebars_widgets; 1293 } 1294 1295 /** 1296 * Compares a list of sidebars with their widgets against a whitelist. 1297 * 1298 * @since 4.9.0 1299 * 1300 * @param array $sidebars_widgets List of sidebars and their widget instance IDs. 1301 * @param array $whitelist List of widget IDs to compare against. 1302 * @return array Sidebars with whitelisted widgets. 1303 */ 1304 function _wp_remove_unregistered_widgets( $sidebars_widgets, $whitelist ) { 1305 foreach ( $sidebars_widgets as $sidebar => $widgets ) { 1306 if ( is_array( $widgets ) ) { 1307 $sidebars_widgets[ $sidebar ] = array_intersect( $widgets, $whitelist ); 1308 } 1217 1309 } 1218 1310 1219 1311 return $sidebars_widgets; -
tests/phpunit/tests/widgets.php
726 726 727 727 $_wp_sidebars_widgets = array(); 728 728 $this->assertInternalType( 'array', $result ); 729 $this->assert NotEmpty( $result);729 $this->assertEquals( $result, $sidebars_widgets ); 730 730 731 731 foreach ( $sidebars_widgets as $widgets ) { 732 732 $this->assertInternalType( 'array', $widgets ); … … 775 775 $result = retrieve_widgets( true ); 776 776 777 777 // $sidebars_widgets matches registered sidebars. 778 $this->assertNull( $result ); 778 $this->assertInternalType( 'array', $result ); 779 $this->assertEquals( $result, $sidebars_widgets ); 779 780 780 781 foreach ( $sidebars_widgets as $widgets ) { 781 782 $this->assertInternalType( 'array', $widgets ); … … 784 785 $this->assertContains( 'tag_cloud-1', $sidebars_widgets['sidebar-1'] ); 785 786 $this->assertContains( 'text-1', $sidebars_widgets['sidebar-2'] ); 786 787 787 // No widget validity checkwhen $sidebars_widgets matches registered sidebars.788 $this->assert Contains( 'custom_widget-1',$sidebars_widgets['sidebar-3'] );788 // Invalid widget removed, even when $sidebars_widgets matches registered sidebars. 789 $this->assertEmpty( $sidebars_widgets['sidebar-3'] ); 789 790 790 791 // No lost widgets when $sidebars_widgets matches registered sidebars. 791 792 $this->assertEmpty( $sidebars_widgets['wp_inactive_widgets'] ); … … 814 815 815 816 $_wp_sidebars_widgets = array(); 816 817 $this->assertInternalType( 'array', $result ); 817 $this->assert NotEmpty( $result);818 $this->assertEquals( $result, $sidebars_widgets ); 818 819 819 820 foreach ( $sidebars_widgets as $widgets ) { 820 821 $this->assertInternalType( 'array', $widgets ); … … 857 858 858 859 $_wp_sidebars_widgets = array(); 859 860 $this->assertInternalType( 'array', $result ); 860 $this->assert NotEmpty( $result);861 $this->assertEquals( $result, $sidebars_widgets ); 861 862 862 863 foreach ( $sidebars_widgets as $widgets ) { 863 864 $this->assertInternalType( 'array', $widgets ); 864 865 } 865 866 866 /* 867 * Only returns intersection of registered sidebars and saved sidebars, 868 * so neither fantasy-sidebar nor sidebar-3 will make the cut. 869 */ 867 // This sidebar is not registered anymore. 870 868 $this->assertArrayNotHasKey( 'fantasy', $sidebars_widgets ); 871 $this->assertArray NotHasKey( 'sidebar-3', $sidebars_widgets );869 $this->assertArrayHasKey( 'sidebar-3', $sidebars_widgets ); 872 870 873 871 // archives-2 ends up as an orphan because of the above behavior. 874 872 $this->assertContains( 'archives-2', $sidebars_widgets['orphaned_widgets_1'] ); … … 915 913 916 914 $_wp_sidebars_widgets = array(); 917 915 $this->assertInternalType( 'array', $result ); 918 $this->assert NotEmpty( $result);916 $this->assertEquals( $result, $sidebars_widgets ); 919 917 920 918 foreach ( $sidebars_widgets as $widgets ) { 921 919 $this->assertInternalType( 'array', $widgets ); … … 940 938 // Sidebar_widgets option was not updated. 941 939 $this->assertNotEquals( $sidebars_widgets, wp_get_sidebars_widgets() ); 942 940 } 941 942 function test_retreive_widgets_with_single_widget() { 943 global $sidebars_widgets; 944 945 wp_widgets_init(); 946 947 // Register single-dimension widget. 948 wp_register_sidebar_widget( 'single', 'Single', '__return_false', array(), array() ); 949 wp_register_widget_control( 'single', 'Single', '__return_false', array(), array() ); 950 951 $this->register_sidebars( array( 'sidebar-1', 'sidebar-2', 'wp_inactive_widgets' ) ); 952 953 $sidebars_widgets = array( 954 'sidebar-1' => array( 'tag_cloud-1' ), 955 'wp_inactive_widgets' => array(), 956 ); 957 958 // Theme changed. 959 $result = retrieve_widgets( true ); 960 961 $this->assertContains( 'single', $result['wp_inactive_widgets'] ); 962 } 963 964 /** 965 * Test _wp_remove_unregistered_widgets. 966 * 967 * @covers _wp_remove_unregistered_widgets() 968 */ 969 public function test__wp_remove_unregistered_widgets() { 970 $widgets = array( 971 'sidebar-1' => array( 'tag_cloud-1' ), 972 'sidebar-2' => array( 'text-1' ), 973 'fantasy' => array( 'archives-2' ), 974 'wp_inactive_widgets' => array(), 975 'array_version' => 3, 976 ); 977 978 $whitelist = array( 'tag_cloud-1', 'text-1' ); 979 980 $filtered_widgets = _wp_remove_unregistered_widgets( $widgets, $whitelist ); 981 982 $this->assertInternalType( 'array', $filtered_widgets ); 983 $this->assertArrayHasKey( 'fantasy', $filtered_widgets ); 984 $this->assertEmpty( $filtered_widgets['fantasy'] ); 985 $this->assertArrayHasKey( 'array_version', $filtered_widgets ); 986 $this->assertEquals( 3, $filtered_widgets['array_version'] ); 987 $this->assertInternalType( 'integer', $filtered_widgets['array_version'] ); 988 } 989 990 /** 991 * wp_map_sidebars_widgets Tests. 992 */ 993 994 /** 995 * Two themes with one sidebar each should just map, switching to a theme not previously-active. 996 * 997 * @covers wp_map_sidebars_widgets() 998 */ 999 public function test_one_sidebar_each() { 1000 $this->register_sidebars( array( 'primary' ) ); 1001 $prev_theme_sidebars = array( 1002 'unique-slug' => 1, 1003 ); 1004 1005 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 1006 1007 $expected_sidebars = array( 1008 'primary' => 1, 1009 ); 1010 $this->assertEquals( $expected_sidebars, $new_next_theme_sidebars ); 1011 } 1012 1013 /** 1014 * Sidebars with the same name should map, switching to a theme not previously-active. 1015 * 1016 * @covers wp_map_sidebars_widgets() 1017 */ 1018 public function test_sidebars_with_same_slug() { 1019 $this->register_sidebars( array( 'primary', 'secondary' ) ); 1020 $prev_theme_sidebars = array( 1021 'primary' => 1, 1022 'secondary' => 2, 1023 ); 1024 1025 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 1026 1027 $this->assertEquals( $prev_theme_sidebars, $new_next_theme_sidebars ); 1028 } 1029 1030 /** 1031 * Make educated guesses on theme sidebars. 1032 * 1033 * @covers wp_map_sidebars_widgets() 1034 */ 1035 public function test_sidebar_guessing() { 1036 $this->register_sidebars( array( 'primary', 'secondary' ) ); 1037 1038 $prev_theme_sidebars = array( 1039 'header' => array(), 1040 'footer' => array(), 1041 ); 1042 1043 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 1044 1045 $expected_sidebars = array( 1046 'primary' => array(), 1047 'secondary' => array(), 1048 ); 1049 $this->assertEquals( $expected_sidebars, $new_next_theme_sidebars ); 1050 } 1051 1052 /** 1053 * Make sure two sidebars that fall in the same group don't get the same menu assigned. 1054 * 1055 * @covers wp_map_sidebars_widgets() 1056 */ 1057 public function test_sidebar_guessing_one_menu_per_group() { 1058 $this->register_sidebars( array( 'primary' ) ); 1059 $prev_theme_sidebars = array( 1060 'top-menu' => array(), 1061 'secondary' => array(), 1062 ); 1063 1064 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 1065 1066 $expected_sidebars = array( 1067 'main' => array(), 1068 ); 1069 $this->assertEqualSets( $expected_sidebars, $new_next_theme_sidebars ); 1070 } 1071 1072 /** 1073 * Make sure two sidebars that fall in the same group get menus assigned from the same group. 1074 * 1075 * @covers wp_map_sidebars_widgets() 1076 */ 1077 public function test_sidebar_guessing_one_menu_per_sidebar() { 1078 $this->register_sidebars( array( 'primary', 'main' ) ); 1079 1080 $prev_theme_sidebars = array( 1081 'navigation-menu' => array(), 1082 'top-menu' => array(), 1083 ); 1084 1085 $new_next_theme_sidebars = wp_map_sidebars_widgets( $prev_theme_sidebars ); 1086 1087 $expected_sidebars = array( 1088 'main' => array(), 1089 'primary' => array(), 1090 ); 1091 $this->assertEquals( $expected_sidebars, $new_next_theme_sidebars ); 1092 } 943 1093 }