Sharing Dynamic Sidebars across Multisite Blogs

I’m trying to find away to retrive a dynamic sidebar from one blog and print it on another blog in the same install of WordPress Multisite. I have tried

switch_to_blog($blog_id);
dynamic_sidebar($sidebar_name);
restore_current_blog();

But nothing is returned.

Read More

I also tired to retrive the sidebar through get_blog_option($blog_id, 'sidebar_widgets') but I was only able to retrive an array identify what widgets were used by the sidebar, but I couldn’t find away to process the array into a sidebar.

Related posts

Leave a Reply

5 comments

  1. Unfortunately, the switch_to_blog() method isn’t going to work for this purpose. switch_to_blog() is really only a partial switch – it makes some modifications to $wpdb that help with database queries. But it’s not a complete switch in the way you might imagine.

    In particular, dynamic_sidebar() depends on global called $wp_registered_sidebars. This global is populated by register_sidebar(), which is generally called from a theme file like functions.php. But functions.php, and the rest of the theme setup process, is not re-run by switch_to_blog(). That is to say: if you’re running Twenty Eleven on the current blog, it’ll register its own sidebars during startup; using switch_to_blog() to a blog running Twenty Ten will not tell Twenty Ten to set up its sidebars. You could try forcing it (by loading the switched-blog’s functions.php manually) but this is almost certain to lead to disaster, due to issues with duplicate function names, load order, etc etc etc.

    You might try a somewhat different tack: On the blog with the sidebar that you want, build a function that will print the contents of the sidebar into the output buffer, and then before printing it to the screen, stash it in a site_option. Then you can grab the sidebar (or a static version of it, at least) from any site on the network. This won’t work if you absolutely need a totally dynamic sidebar, but for most purposes you probably don’t.

    Another method (which may be easier) is to render the sidebar with a function in an mu-plugins file or something like that, and then call the function manually in your themes (or hook it to a common sidebar hook). It might take some work to abstract the content out of the WP_Widget architecture, but on the other hand it would be a truly dynamic solution to the problem at hand.

  2. Ran into the same problem and kind of figured out a solution. What i’m doing is the following:

    1.) Whenever something is changed on blog 1’s sidebar, save an array of those widgets and their settings as a sitewide transient, that outdates after 24 hours.

    2.) On all child-blogs, put some code into sidebar.php that grabs this sitewide transient and displays the widgets.

    Sounds pretty easy, but was very hard to figure out … and still is far from perfect.

    Let’s dig into some Code:

    function antwortzeit_cache_widgets() {
        if ( false === ( $widgets = get_site_transient( 'antwortzeit_widgets' ) ) ) {
            global $wp_registered_sidebars, $wp_registered_widgets;
    
            foreach ( (array) $wp_registered_sidebars as $key => $value ) {
                if ( sanitize_title($value['name']) == sanitize_title('Breite Spalte') ) {
                    $index = $key;
                    break;
                }
            }
    
            $sidebars_widgets = wp_get_sidebars_widgets();
            if ( empty( $sidebars_widgets ) )
                return false;
    
            if ( empty($wp_registered_sidebars[$index]) || !array_key_exists($index, $sidebars_widgets) || !is_array($sidebars_widgets[$index]) || empty($sidebars_widgets[$index]) )
                return false;
    
            $sidebar = $wp_registered_sidebars[$index];
            foreach ( (array) $sidebars_widgets[$index] as $id ) {
                if ( !isset($wp_registered_widgets[$id]) ) continue;
    
                $params = array_merge(
                    array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
                    (array) $wp_registered_widgets[$id]['params']
                );
    
                // Substitute HTML id and class attributes into before_widget
                $classname_ = '';
                foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
                    if ( is_string($cn) )
                        $classname_ .= '_' . $cn;
                    elseif ( is_object($cn) )
                        $classname_ .= '_' . get_class($cn);
                }
                $classname_ = ltrim($classname_, '_');
                $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
    
                $params = apply_filters( 'dynamic_sidebar_params', $params );
    
                $widgets[] = array(
                    'callback'  => $wp_registered_widgets[$id]['callback'],
                    'base'      => $wp_registered_widgets[$id]['callback'][0]->id_base,
                    'id'        => $wp_registered_widgets[$id]['callback'][0]->id,
                    'params'    => $params,
                );
            }
            set_site_transient( 'antwortzeit_widgets', $widgets, 60 * 60 * 24 );
        }
    }
    add_action( 'init', 'antwortzeit_cache_widgets');
    

    This belongs into blog 1’s functions.php (or better, a plugin alltogether) and saves the widgets into the bespoke transient every 24 hours.

    function antwortzeit_widgetbruecke( $instance, $new_instance ) {
        delete_site_transient('antwortzeit_widgets');
        antwortzeit_cache_widgets();
        return $instance;
    }
    add_filter( 'widget_update_callback', 'antwortzeit_widgetbruecke', 10, 2 );
    

    This also belongs into blog 1’s functions.php and renews the transient every time the widgets are updated.

    And finally for the other blogs drop into sidebar.php:

    global $blog_id;
    
    if($blog_id !== 1) {
    switch_to_blog(1);
        $widgets = get_site_transient( 'antwortzeit_widgets' );
        if($widgets) :
            foreach($widgets as $widget) :
            if ( is_callable($widget['callback']) ) {
                call_user_func_array($widget['callback'], $widget['params']);
            }
            endforeach; 
        endif;
    restore_current_blog();
    }
    

    Hope, this can help somebody out. If one has any improvements, they’ll be very welcome.

  3. Make sure you have the exact same sidebars registration code running on both sites during widgets_init. That should populate $wp_registered_sidebars and solve the problem that Boone highlighted. Haven’t tried this myself.