Avoid losing widgets when switching themes - take one, props aaroncampbell, see #17979

git-svn-id: http://svn.automattic.com/wordpress/trunk@18630 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
azaozz 2011-09-02 22:13:55 +00:00
parent 1fd69ecf36
commit 4852c5887f
4 changed files with 140 additions and 97 deletions

View File

@ -44,10 +44,17 @@ $help .= '<p>' . __('<a href="http://codex.wordpress.org/Appearance_Widgets_Scre
$help .= '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>';
add_contextual_help($current_screen, $help);
// These are the widgets grouped by sidebar
$sidebars_widgets = wp_get_sidebars_widgets();
if ( empty( $sidebars_widgets ) )
$sidebars_widgets = wp_get_widget_defaults();
// register the inactive_widgets area as sidebar
register_sidebar(array(
'name' => __('Inactive Widgets'),
'id' => 'wp_inactive_widgets',
'class' => 'inactive',
'description' => '',
'before_widget' => '',
'after_widget' => '',
@ -55,78 +62,22 @@ register_sidebar(array(
'after_title' => '',
));
// These are the widgets grouped by sidebar
$sidebars_widgets = wp_get_sidebars_widgets();
if ( empty( $sidebars_widgets ) )
$sidebars_widgets = wp_get_widget_defaults();
// look for "lost" widgets, this has to run at least on each theme change
function retrieve_widgets() {
global $wp_registered_widget_updates, $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
$_sidebars_widgets = array();
$sidebars = array_keys($wp_registered_sidebars);
unset( $sidebars_widgets['array_version'] );
$old = array_keys($sidebars_widgets);
sort($old);
sort($sidebars);
if ( $old == $sidebars )
return;
// Move the known-good ones first
foreach ( $sidebars as $id ) {
if ( array_key_exists( $id, $sidebars_widgets ) ) {
$_sidebars_widgets[$id] = $sidebars_widgets[$id];
unset($sidebars_widgets[$id], $sidebars[$id]);
}
foreach ( $sidebars_widgets as $sidebar_id => $widgets ) {
if ( empty( $wp_registered_sidebars[ $sidebar_id ] ) && ! empty( $widgets ) ) {
// register the inactive_widgets area as sidebar
register_sidebar(array(
'name' => __( 'Inactive Widgets (Previous Theme)' ),
'id' => $sidebar_id,
'class' => 'orphaned',
'description' => __( 'This is a left over sidebar from an old theme and does not show anywhere on your site' ),
'before_widget' => '',
'after_widget' => '',
'before_title' => '',
'after_title' => '',
));
}
// if new theme has less sidebars than the old theme
if ( !empty($sidebars_widgets) ) {
foreach ( $sidebars_widgets as $lost => $val ) {
if ( is_array($val) )
$_sidebars_widgets['wp_inactive_widgets'] = array_merge( (array) $_sidebars_widgets['wp_inactive_widgets'], $val );
}
}
// discard invalid, theme-specific widgets from sidebars
$shown_widgets = array();
foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
if ( !is_array($widgets) )
continue;
$_widgets = array();
foreach ( $widgets as $widget ) {
if ( isset($wp_registered_widgets[$widget]) )
$_widgets[] = $widget;
}
$_sidebars_widgets[$sidebar] = $_widgets;
$shown_widgets = array_merge($shown_widgets, $_widgets);
}
$sidebars_widgets = $_sidebars_widgets;
unset($_sidebars_widgets, $_widgets);
// find hidden/lost multi-widget instances
$lost_widgets = array();
foreach ( $wp_registered_widgets as $key => $val ) {
if ( in_array($key, $shown_widgets, true) )
continue;
$number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
if ( 2 > (int) $number )
continue;
$lost_widgets[] = $key;
}
$sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
wp_set_sidebars_widgets($sidebars_widgets);
}
retrieve_widgets();
if ( count($wp_registered_sidebars) == 1 ) {
@ -387,8 +338,15 @@ $i = 0;
foreach ( $wp_registered_sidebars as $sidebar => $registered_sidebar ) {
if ( 'wp_inactive_widgets' == $sidebar )
continue;
$closed = $i ? ' closed' : ''; ?>
<div class="widgets-holder-wrap<?php echo $closed; ?>">
$wrap_class = 'widgets-holder-wrap';
if ( !empty( $registered_sidebar['class'] ) )
$wrap_class .= ' sidebar-' . $registered_sidebar['class'];
if ( $i )
$wrap_class .= ' closed'; ?>
<div class="<?php esc_attr_e( $wrap_class ); ?>">
<div class="sidebar-name">
<div class="sidebar-name-arrow"><br /></div>
<h3><?php echo esc_html( $registered_sidebar['name'] ); ?>

View File

@ -218,6 +218,7 @@ add_action( 'wp_footer', 'wp_print_footer_scripts', 20 );
add_action( 'wp_head', 'wp_shortlink_wp_head', 10, 0 );
add_action( 'template_redirect', 'wp_shortlink_header', 11, 0 );
add_action( 'wp_print_footer_scripts', '_wp_footer_scripts' );
add_action( 'init', 'check_theme_switched', 99 );
if ( isset( $_GET['replytocom'] ) )
add_filter( 'pre_option_blog_public', '__return_zero' );

View File

@ -1248,19 +1248,26 @@ function preview_theme_ob_filter_callback( $matches ) {
function switch_theme($template, $stylesheet) {
global $wp_theme_directories;
$old_theme = get_current_theme();
update_option('template', $template);
update_option('stylesheet', $stylesheet);
if ( count($wp_theme_directories) > 1 ) {
update_option('template_root', get_raw_theme_root($template, true));
update_option('stylesheet_root', get_raw_theme_root($stylesheet, true));
}
delete_option('current_theme');
$theme = get_current_theme();
if ( is_admin() && false === get_option( "theme_mods_$stylesheet" ) ) {
$default_theme_mods = (array) get_option( "mods_$theme" );
add_option( "theme_mods_$stylesheet", $default_theme_mods );
}
do_action('switch_theme', $theme);
update_option( 'theme_switched', $old_theme );
do_action( 'switch_theme', $theme );
}
/**

View File

@ -547,6 +547,7 @@ function register_sidebar($args = array()) {
'name' => sprintf(__('Sidebar %d'), $i ),
'id' => "sidebar-$i",
'description' => '',
'class' => '',
'before_widget' => '<li id="%1$s" class="widget %2$s">',
'after_widget' => "</li>\n",
'before_title' => '<h2 class="widgettitle">',
@ -1055,30 +1056,7 @@ function wp_get_sidebars_widgets($deprecated = true) {
unset($_sidebars_widgets);
case 2 :
$sidebars = array_keys( $wp_registered_sidebars );
if ( !empty( $sidebars ) ) {
// Move the known-good ones first
foreach ( (array) $sidebars as $id ) {
if ( array_key_exists( $id, $sidebars_widgets ) ) {
$_sidebars_widgets[$id] = $sidebars_widgets[$id];
unset($sidebars_widgets[$id], $sidebars[$id]);
}
}
// move the rest to wp_inactive_widgets
if ( !isset($_sidebars_widgets['wp_inactive_widgets']) )
$_sidebars_widgets['wp_inactive_widgets'] = array();
if ( !empty($sidebars_widgets) ) {
foreach ( $sidebars_widgets as $lost => $val ) {
if ( is_array($val) )
$_sidebars_widgets['wp_inactive_widgets'] = array_merge( (array) $_sidebars_widgets['wp_inactive_widgets'], $val );
}
}
$sidebars_widgets = $_sidebars_widgets;
unset($_sidebars_widgets);
}
$sidebars_widgets = retrieve_widgets();
}
}
@ -1215,3 +1193,102 @@ function the_widget($widget, $instance = array(), $args = array()) {
function _get_widget_id_base($id) {
return preg_replace( '/-[0-9]+$/', '', $id );
}
function check_theme_switched() {
if ( false !== ( $old_theme = get_option( 'theme_switched' ) ) && !empty( $old_theme ) ) {
global $sidebars_widgets;
if ( ! is_array( $sidebars_widgets ) )
$sidebars_widgets = wp_get_sidebars_widgets();
$key = md5( $old_theme );
// Store widgets for 1 week so we can restore if needed
set_transient( 'old_widgets_' . $key, $sidebars_widgets, 604800 );
retrieve_widgets();
update_option( 'theme_switched', false );
}
}
// look for "lost" widgets, this has to run at least on each theme change
function retrieve_widgets() {
global $wp_registered_widget_updates, $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
$key = md5( get_current_theme() );
if ( false !== ( $_sidebars_widgets = get_transient( "old_widgets_{$key}" ) ) ) {
delete_transient( "old_widgets_{$key}" );
} else {
if ( ! is_array( $sidebars_widgets ) )
$sidebars_widgets = wp_get_sidebars_widgets();
$sidebars = array_keys($wp_registered_sidebars);
unset( $sidebars_widgets['array_version'] );
$old = array_keys($sidebars_widgets);
sort($old);
sort($sidebars);
if ( $old == $sidebars )
return;
$_sidebars_widgets = array(
'wp_inactive_widgets' => $sidebars_widgets['wp_inactive_widgets']
);
unset( $sidebars_widgets['wp_inactive_widgets'] );
foreach ( $wp_registered_sidebars as $id => $settings ) {
if ( ! empty( $sidebars_widgets ) )
$_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
}
if ( !empty($sidebars_widgets) ) {
$orphaned = 0;
foreach ( $sidebars_widgets as $val ) {
if ( is_array($val) && ! empty( $val ) )
$_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
}
}
}
// discard invalid, theme-specific widgets from sidebars
$shown_widgets = array();
foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
if ( !is_array($widgets) )
continue;
$_widgets = array();
foreach ( $widgets as $widget ) {
if ( isset($wp_registered_widgets[$widget]) )
$_widgets[] = $widget;
}
$_sidebars_widgets[$sidebar] = $_widgets;
$shown_widgets = array_merge($shown_widgets, $_widgets);
}
$sidebars_widgets = $_sidebars_widgets;
unset($_sidebars_widgets, $_widgets);
// find hidden/lost multi-widget instances
$lost_widgets = array();
foreach ( $wp_registered_widgets as $key => $val ) {
if ( in_array($key, $shown_widgets, true) )
continue;
$number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
if ( 2 > (int) $number )
continue;
$lost_widgets[] = $key;
}
$sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
wp_set_sidebars_widgets($sidebars_widgets);
return $sidebars_widgets;
}