Site icon WebDevStudios

Sharing Sidebars Across a Multisite Network

Sidebars are great.  Multisite is great.  Doing something once so that it can be shared across an entire network is great, too.

So, it should stand to reason that sharing a specific sidebar, or set of sidebars, across an entire multisite network should be just as great (and easy), right?

Well, if it were, we wouldn’t be here right now.

I know what you may be thinking…

Just use switch_to_blog(), ya dingus!

Oh, how I wish it were that easy!  That was our first guess as well, but it unfortunately didn’t do the trick.  Apparently, switch_to_blog() is a trick that does not work when attempting to share a sidebar across a network.  Total bummer.

In our situation, though, we had a set of sidebars in our footer that we wanted the client to be able to manage but also share across every site within their network.  So, hardcoding the widgets in place wouldn’t have been a proper solution; neither would have been telling the client that they would need to manage three sidebars on 300+ sites.  Ouch.

We had our task: allow a set of sidebars to be displayed across the sites in a multisite network.

We had our problem: switch_to_blog() doesn’t work for this, so we needed to figure out another way to accomplish our goal.

Now we have our solution.

The first thing we want to do is build the output of our sidebars. That seems kind of important, right? Can’t see some sidebars if we’re not telling the sidebars to display. We don’t want to just display the sidebars and be done with it, though. What we want to do is store our sidebars in a transient. This transient will be deleted whenever a widget is updated in one of our three sidebars (you’ll see this later, be patient!). In order to store our set of sidebars as a variable, we need to wrap everything in an output buffer.

/**
 * Generate sidebar for footer across all sites
 */
add_action( 'init', 'wds_footer_widgets_all_sites' );
function wds_footer_widgets_all_sites() {

    if ( ! is_main_site() )
        return;

    if ( ! ( $wds_footer_widgets = get_site_transient( 'wds_footer_widgets' ) ) ) {
        // start output buffer
        ob_start();

        // Display our footer sidebars
        if ( ! dynamic_sidebar( 'sidebar-footer-1' ) ) :
                endif; // end sidebar widget area

        if ( ! dynamic_sidebar( 'sidebar-footer-2' ) ) :
        endif; // end sidebar widget area

        if ( ! dynamic_sidebar( 'sidebar-footer-3' ) ) :
        endif; // end sidebar widget area

        // grab the data from the output buffer and put it in our variable
        $wds_footer_widgets = ob_get_contents();
        ob_end_clean();

        // Put sidebar into a transient for 4 hours
        set_site_transient( 'wds_footer_widgets', $wds_footer_widgets, 4*60*60 );
    }
}

Next comes our theme’s footer. This is a bit more straight forward – we want to get the site transient that we established in our functions file above, then display its contents.

// Display our stored footer widgets
$show_footer_sidebar = get_site_transient( 'wds_footer_widgets' );
echo $show_footer_sidebar;

Now we should have our sidebars displaying, but we also want some additional magic to happen. We need to clear our transient when a widget is updated or saved in one of our three footer sidebars.  The first step of this process is to enqueue some scripts that we’re going to be using. I’m doing this in a separate file housing all of our AJAX-related commands, ajax-functions.php in our theme’s /inc/ directory.

/**
 * Enqueue and localize our scripts
 */
add_action( 'admin_enqueue_scripts', 'wds_enqueue_ajax_scripts' );
function wds_enqueue_ajax_scripts() {
    global $current_screen;

    // Only register these scripts if we're on the widgets page
    if ( $current_screen->id == 'widgets' ) {
        wp_enqueue_script( 'wds_ajax_scripts', get_stylesheet_directory_uri() . '/js/admin-widgets.js', array( 'jquery' ), 1, true );
        wp_localize_script( 'wds_ajax_scripts', 'wds_AJAX', array( 'wds_widget_nonce' => wp_create_nonce( 'widget-update-nonce' ) ) );
    }
}

In the same file, we want to create the AJAX function that runs when updating our sidebars. This function checks to make sure our nonce is present; if it is, it deletes the site transient.

/**
 * Register our AJAX call
 */
add_action( 'wp_ajax_wds-reset-transient', 'wds_ajax_wds_reset_transient', 1 );

/**
 * AJAX Helper to delete our transient when a widget is saved
 */
function wds_ajax_wds_reset_transient() {

    // Delete our footer transient.  This runs when a widget is saved or updated.  Only do this if our nonce is passed.
    if ( ! empty( $_REQUEST['wds-widget-nonce'] ) )
        delete_site_transient( 'wds_footer_widgets' );
}

We’ll need a JavaScript file to handle some back-end functionality, and we’ll need to localize the script so we can interact with that file.  We’re passing a nonce in our script as well; this will ensure that our widget form is being updated properly.

Finally, we want to create the AJAX that is going to listen for an updated widget. With jQuery first, we’re listening for a click on the remove, close, or save links on individual widgets within one of our three specific sidebars. If one of those links is clicked and we’re in one of our specified sidebars, we want to run our AJAX function.

jQuery(document).ready(function($){

    function wds_reset_footer_transient() {

        // Run our AJAX call to delete our site transient
        $.ajax({
            type : 'post',
            dataType : 'json',
            url : ajaxurl,
            data : {
                'action' : 'wds-reset-transient',
                'wds-widget-nonce' : wds_AJAX.wds_widget_nonce
            },
            error: function ( xhr, ajaxOptions, thrownError ) {
                console.log( thrownError );
                console.log( ajaxOptions );
            }
        });
    }

    // If one of our update buttons is clicked on a single widget
    $( '.widgets-holder-wrap' ).on( 'click', '.widget-control-remove, .widget-control-close, .widget-control-save', function() {

        // Get our parent, or sidebar, ID
        var widget_parent_div = $(this).parents().eq(5).attr( 'id' );

        // And if our parent div ID, or our sidebar ID, is one of the following
        if ( widget_parent_div == 'sidebar-footer-1' || widget_parent_div == 'sidebar-footer-2' || widget_parent_div == 'sidebar-footer-3' ) {

            // Run our function
            wds_reset_footer_transient();
        }
    });
});

And that’s about it! Now you can manage a set of sidebars on the main site within your network and pass those sidebars to every site within your network. One set of widgets to manage for an entire network of sites. It wasn’t the solution that jumped out at us at first, but it’s the one we found and it’s the one that works for us. We’re pretty happy with the way it turned out, and we think the client is going to be happy only having to edit their widgets once and have those changes visible on 300+ sites.

Exit mobile version