Ticket #39693: 39693.2.diff
File 39693.2.diff, 18.4 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 $_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( 'time' => time(), 'data' => $_sidebars_widgets ) ); 717 } 718 719 719 // Migrate from the old mods_{name} option to theme_mods_{slug}. 720 720 if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) { 721 721 $default_theme_mods = (array) get_option( 'mods_' . $new_name ); -
src/wp-includes/widgets.php
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 } else { 1127 if ( empty( $sidebars_widgets ) ) { 1128 return array(); 1129 } 1126 1130 1127 foreach ( $_sidebars_widgets as $sidebar => $widgets ) { 1128 if ( 'wp_inactive_widgets' === $sidebar || 'orphaned_widgets' === substr( $sidebar, 0, 16 ) ) { 1129 continue; 1130 } 1131 unset( $sidebars_widgets['array_version'] ); 1131 1132 1132 if ( !in_array( $sidebar, $registered_sidebar_keys ) ) { 1133 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets; 1134 unset( $_sidebars_widgets[$sidebar] ); 1135 } 1133 $sidebars_widgets_keys = array_keys( $sidebars_widgets ); 1134 sort( $sidebars_widgets_keys ); 1135 sort( $registered_sidebars_keys ); 1136 1137 if ( $sidebars_widgets_keys == $registered_sidebars_keys ) { 1138 $sidebars_widgets = _wp_remove_unregistered_widgets( $sidebars_widgets, $registered_widgets_ids ); 1139 1140 return $sidebars_widgets; 1136 1141 } 1137 } else { 1138 if ( empty( $sidebars_widgets ) ) 1139 return; 1142 } 1140 1143 1141 unset( $sidebars_widgets['array_version'] ); 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 ); 1142 1147 1143 $old = array_keys($sidebars_widgets); 1144 sort($old); 1145 sort($registered_sidebar_keys); 1146 1147 if ( $old == $registered_sidebar_keys ) 1148 return; 1149 1150 $_sidebars_widgets = array( 1151 'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array() 1152 ); 1153 1154 unset( $sidebars_widgets['wp_inactive_widgets'] ); 1155 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', array_filter( $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 1167 1168 foreach ( $sidebars_widgets as $val ) { 1169 if ( is_array($val) && ! empty( $val ) ) 1170 $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val; 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; 1178 1179 $new_sidebars_widgets = array(); 1180 1181 // Short-circuit if there are no sidebars to map. 1182 if ( 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 ] = $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 } 1193 1241 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; 1242 // Then see if any of the old sidebars... 1243 foreach ( $old_sidebars_widgets as $sidebar => $widgets ) { 1199 1244 1200 $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key); 1245 // ...and any slug in the same group... 1246 foreach ( $slug_group as $slug ) { 1201 1247 1202 if ( 2 > (int) $number ) 1203 continue; 1248 // ... have a match as well. 1249 if ( false === stripos( $sidebar, $slug ) && false === stripos( $slug, $sidebar ) ) { 1250 continue; 1251 } 1252 1253 // Make sure this sidebar wasn't mapped and removed previously. 1254 if ( ! empty( $old_sidebars_widgets[ $sidebar ] ) ) { 1255 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 ) 1204 1270 1205 $lost_widgets[] = $key; 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
678 678 679 679 } 680 680 681 function test_retrieve_widgets_with_theme_mod() { 682 global $sidebars_widgets, $_wp_sidebars_widgets; 683 684 wp_widgets_init(); 685 686 register_sidebar( array( 687 'name' => 'Primary Sidebar', 688 'id' => 'sidebar-1', 689 ) ); 690 register_sidebar( array( 691 'name' => 'Content Sidebar', 692 'id' => 'sidebar-2', 693 ) ); 694 register_sidebar( array( 695 'name' => 'Footer Widget Area', 696 'id' => 'sidebar-3', 697 ) ); 698 register_sidebar( array( 'id' => 'wp_inactive_widgets' ) ); 699 700 set_theme_mod( 'sidebars_widgets', array( 701 'time' => time(), 702 'data' => array( 703 'sidebar-1' => array( 'tag_cloud-1' ), 704 'sidebar-2' => array( 'text-1' ), 705 'sidebar-3' => array( 'unregistered_widget-1' ), 706 'fantasy' => array( 'archives-2' ), 707 'wp_inactive_widgets' => array(), 708 ), 709 ) ); 710 711 $result = retrieve_widgets( true ); 712 713 $_wp_sidebars_widgets = array(); 714 $this->assertInternalType( 'array', $result ); 715 $this->assertEquals( $result, $sidebars_widgets ); 716 $this->assertContains( 'tag_cloud-1', $sidebars_widgets['sidebar-1'] ); 717 $this->assertContains( 'text-1', $sidebars_widgets['sidebar-2'] ); 718 $this->assertContains( 'archives-2', $sidebars_widgets['orphaned_widgets_1'] ); 719 720 // Unregistered widget should be filtered out. 721 $this->assertEmpty( $sidebars_widgets['sidebar-3'] ); 722 723 // 6 default widgets - 1 active text widget = 5. 724 $this->assertCount( 5, $sidebars_widgets['wp_inactive_widgets'] ); 725 726 // Theme mode with previous widgets was removed. 727 $this->assertFalse( get_theme_mod( 'sidebars_widgets' ) ); 728 729 // Sidebar_widgets option was updated. 730 $this->assertEquals( $sidebars_widgets, wp_get_sidebars_widgets() ); 731 } 732 733 function test_retrieve_widgets_with_sidebars_widgets_matching_registered_sidebars() { 734 global $sidebars_widgets; 735 736 wp_widgets_init(); 737 738 register_sidebar( array( 739 'name' => 'Primary Sidebar', 740 'id' => 'sidebar-1', 741 ) ); 742 register_sidebar( array( 743 'name' => 'Content Sidebar', 744 'id' => 'sidebar-2', 745 ) ); 746 register_sidebar( array( 747 'name' => 'Footer Widget Area', 748 'id' => 'sidebar-3', 749 ) ); 750 register_sidebar( array( 'id' => 'wp_inactive_widgets' ) ); 751 752 $sidebars_widgets = array( 753 'sidebar-1' => array( 'tag_cloud-1' ), 754 'sidebar-2' => array( 'text-1' ), 755 'sidebar-3' => array( 'custom_widget-1' ), 756 'wp_inactive_widgets' => array(), 757 ); 758 759 $result = retrieve_widgets( true ); 760 761 // $sidebars_widgets matches registered sidebars. 762 $this->assertInternalType( 'array', $result ); 763 $this->assertEquals( $result, $sidebars_widgets ); 764 $this->assertContains( 'tag_cloud-1', $sidebars_widgets['sidebar-1'] ); 765 $this->assertContains( 'text-1', $sidebars_widgets['sidebar-2'] ); 766 767 // Invalid widget removed, even when $sidebars_widgets matches registered sidebars. 768 $this->assertEmpty( $sidebars_widgets['sidebar-3'] ); 769 770 // No lost widgets when $sidebars_widgets matches registered sidebars. 771 $this->assertEmpty( $sidebars_widgets['wp_inactive_widgets'] ); 772 } 773 774 function test_retrieve_widgets_with_sidebars_widgets_not_matching_registered_sidebars() { 775 global $sidebars_widgets, $_wp_sidebars_widgets; 776 777 wp_widgets_init(); 778 779 register_sidebar( array( 780 'name' => 'Primary Sidebar', 781 'id' => 'sidebar-1', 782 ) ); 783 register_sidebar( array( 784 'name' => 'Content Sidebar', 785 'id' => 'sidebar-2', 786 ) ); 787 register_sidebar( array( 788 'name' => 'Footer Widget Area', 789 'id' => 'sidebar-3', 790 ) ); 791 register_sidebar( array( 'id' => 'wp_inactive_widgets' ) ); 792 793 $sidebars_widgets = array( 794 'sidebar-1' => array( 'tag_cloud-1' ), 795 'sidebar-2' => array( 'text-1' ), 796 'fantasy' => array( 'unregistered_widget-1' ), 797 'wp_inactive_widgets' => array(), 798 ); 799 800 // Theme changed. 801 $result = retrieve_widgets( true ); 802 803 $_wp_sidebars_widgets = array(); 804 $this->assertInternalType( 'array', $result ); 805 $this->assertEquals( $result, $sidebars_widgets ); 806 807 // Current theme doesn't have a fantasy-sidebar. 808 $this->assertArrayNotHasKey( 'fantasy', $sidebars_widgets ); 809 $this->assertArrayHasKey( 'sidebar-3', $sidebars_widgets ); 810 811 $this->assertContains( 'tag_cloud-1', $sidebars_widgets['sidebar-1'] ); 812 $this->assertContains( 'text-1', $sidebars_widgets['sidebar-2'] ); 813 814 // We should not have orphaned widgets, because widget was not registered. 815 $this->assertArrayNotHasKey( 'orphaned_widgets_1', $sidebars_widgets ); 816 817 // 6 default widgets. 818 $this->assertCount( 6, $sidebars_widgets['wp_inactive_widgets'] ); 819 820 // Sidebar_widgets option was updated. 821 $this->assertEquals( $sidebars_widgets, wp_get_sidebars_widgets() ); 822 823 // Reset. 824 $sidebars_widgets = array( 825 'sidebar-1' => array( 'tag_cloud-1' ), 826 'sidebar-2' => array( 'text-1' ), 827 'fantasy' => array( 'archives-2' ), 828 'wp_inactive_widgets' => array(), 829 ); 830 831 // Theme did not change. 832 $result = retrieve_widgets(); 833 834 $_wp_sidebars_widgets = array(); 835 $this->assertInternalType( 'array', $result ); 836 $this->assertEquals( $result, $sidebars_widgets ); 837 838 // This sidebar is not registered anymore. 839 $this->assertArrayNotHasKey( 'fantasy-sidebar', $sidebars_widgets ); 840 $this->assertArrayHasKey( 'sidebar-3', $sidebars_widgets ); 841 842 // archives-2 ends up as an orphan because of the above behavior. 843 $this->assertContains( 'archives-2', $sidebars_widgets['orphaned_widgets_1'] ); 844 $this->assertContains( 'tag_cloud-1', $sidebars_widgets['sidebar-1'] ); 845 $this->assertContains( 'text-1', $sidebars_widgets['sidebar-2'] ); 846 847 // 6 default widgets - 1 active text widget = 5. 848 $this->assertCount( 5, $sidebars_widgets['wp_inactive_widgets'] ); 849 850 // Sidebar_widgets option was updated. 851 $this->assertEquals( $sidebars_widgets, wp_get_sidebars_widgets() ); 852 } 853 854 function test_retrieve_widgets_for_customizer() { 855 global $sidebars_widgets, $_wp_sidebars_widgets; 856 857 wp_widgets_init(); 858 859 register_sidebar( array( 860 'name' => 'Primary Sidebar', 861 'id' => 'sidebar-1', 862 ) ); 863 register_sidebar( array( 864 'name' => 'Content Sidebar', 865 'id' => 'sidebar-2', 866 ) ); 867 register_sidebar( array( 868 'name' => 'Footer Widget Area', 869 'id' => 'sidebar-3', 870 ) ); 871 register_sidebar( array( 'id' => 'wp_inactive_widgets' ) ); 872 873 $old_sidebars_widgets = array( 874 'time' => time(), 875 'data' => array( 876 'sidebar-1' => array( 'tag_cloud-1' ), 877 'sidebar-2' => array( 'text-1' ), 878 'sidebar-3' => array( 'unregistered_widget-1' ), 879 'fantasy' => array( 'archives-2' ), 880 'wp_inactive_widgets' => array(), 881 ), 882 ); 883 set_theme_mod( 'sidebars_widgets', $old_sidebars_widgets ); 884 885 $result = retrieve_widgets( 'customize' ); 886 887 $_wp_sidebars_widgets = array(); 888 $this->assertInternalType( 'array', $result ); 889 $this->assertEquals( $result, $sidebars_widgets ); 890 $this->assertContains( 'tag_cloud-1', $sidebars_widgets['sidebar-1'] ); 891 $this->assertContains( 'text-1', $sidebars_widgets['sidebar-2'] ); 892 $this->assertContains( 'archives-2', $sidebars_widgets['orphaned_widgets_1'] ); 893 $this->assertEmpty( $sidebars_widgets['sidebar-3'] ); 894 $this->assertCount( 5, $sidebars_widgets['wp_inactive_widgets'] ); 895 896 // Theme mod with previous widgets was not removed. 897 $this->assertEqualSets( $old_sidebars_widgets, get_theme_mod( 'sidebars_widgets' ) ); 898 899 // Sidebar_widgets option was not updated. 900 $this->assertNotEquals( $sidebars_widgets, wp_get_sidebars_widgets() ); 901 } 681 902 }