Change which sidebar get_sidebar() gets from functions.php

Get sidebar is a really thin wrapper around locate_template, which just searches the current child theme and parent theme directory for the given sidebar.

get_sidebar in wp-includes/general-template.php:

$templates = array();
if ( isset($name) )
    $templates[] = "sidebar-{$name}.php";

$templates[] = 'sidebar.php';

// Backward compat code will be removed in a future release
if ('' == locate_template($templates, true))
    load_template( ABSPATH . WPINC . '/theme-compat/sidebar.php');

}

And locate_template (in wp-includes/template.php):

<?php
/**
 * Retrieve the name of the highest priority template file that exists.
 *
 * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
 * inherit from a parent theme can just overload one file.
 *
 * @since 2.7.0
 *
 * @param string|array $template_names Template file(s) to search for, in order.
 * @param bool $load If true the template file will be loaded if it is found.
 * @param bool $require_once Whether to require_once or require. Default true. Has no effect if $load is false.
 * @return string The template filename if one is located.
 */
function locate_template($template_names, $load = false, $require_once = true ) {
    $located = '';
    foreach ( (array) $template_names as $template_name ) {
        if ( !$template_name )
            continue;
        if ( file_exists(STYLESHEETPATH . "https://wordpress.stackexchange.com/" . $template_name)) {
            $located = STYLESHEETPATH . "https://wordpress.stackexchange.com/" . $template_name;
            break;
        } else if ( file_exists(TEMPLATEPATH . "https://wordpress.stackexchange.com/" . $template_name) ) {
            $located = TEMPLATEPATH . "https://wordpress.stackexchange.com/" . $template_name;
            break;
        }
    }

    if ( $load && '' != $located )
        load_template( $located, $require_once );

    return $located;
}

The reason your hook into get_sidebar doesn’t work is because it’s an action. It just fires. It doesn’t allow you to change the result. Your sidebar will still be included regardless of the your hooked action.

That levels you a few options.

1. Pass a variable into get_sidebar

Chip Bennett’s solution: pass a variable into the get_sidebar function. Not bad.

2. Write Your Own Sidebar Logic

And use it in place of get_sidebar. A simple example:

<?php
function mytheme_sidebar($name)
{
     $name = apply_filters('mytheme_sidebar', $name);
     get_sidebar($name);
}

Then use your own filter to modify the sidebar

<?php
add_filter('mytheme_sidebar', 'mytheme_custom_sidebar');
function mytheme_custom_sidebar($name)
{
    return is_user_logged_in() ? 'loggedin' : $name;
}

This will be the most flexible. If it’s a public theme, end users will be able to customize things. If it’s for a client, when the inevitably ask you for more stuff, it’s easily done.

3. Look Deeper

get_sidebar just includes the appropriate theme files. dynamic_sidebar is where the work is done.

If you take a look inside that function, the most interesting line is:

$sidebars_widgets = wp_get_sidebars_widgets();

wp_get_sidebars_widgets fetches all the currently registered widgets for all sidebars on the site.

<?php
/**
 * Retrieve full list of sidebars and their widgets.
 *
 * Will upgrade sidebar widget list, if needed. Will also save updated list, if
 * needed.
 *
 * @since 2.2.0
 * @access private
 *
 * @param bool $deprecated Not used (deprecated).
 * @return array Upgraded list of widgets to version 3 array format when called from the admin.
 */
function wp_get_sidebars_widgets($deprecated = true) {
    if ( $deprecated !== true )
        _deprecated_argument( __FUNCTION__, '2.8.1' );

    global $wp_registered_widgets, $_wp_sidebars_widgets, $sidebars_widgets;

    // If loading from front page, consult $_wp_sidebars_widgets rather than options
    // to see if wp_convert_widget_settings() has made manipulations in memory.
    if ( !is_admin() ) {
        if ( empty($_wp_sidebars_widgets) )
            $_wp_sidebars_widgets = get_option('sidebars_widgets', array());

        $sidebars_widgets = $_wp_sidebars_widgets;
    } else {
        $sidebars_widgets = get_option('sidebars_widgets', array());
    }

    if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
        unset($sidebars_widgets['array_version']);

    $sidebars_widgets = apply_filters('sidebars_widgets', $sidebars_widgets);
    return $sidebars_widgets;
}

The key line there: apply_filters('sidebars_widget', ...). Money.

Register a secondary sidebar only for logged in users:

<?php
add_action('widgets_init', 'wpse64492_register');
function wpse64492_register()
{
    register_sidebar(array(
        'name'  => __('Logged In Sidebar', 'wpse64492'),
        'id'    => 'logged-in'
    ));
}

Then hook into sidebars_widgets and swap the normal sidebar for the logged in version.

<?php
add_filter('sidebars_widgets', 'wpse64492_switch');
function wpse64492_switch($widgets)
{
    if(is_admin())
        return $widgets;

    $key = 'sidebar-1'; // the sidebar you want to change!

    if(isset($widgets[$key]) && is_user_logged_in() && isset($widgets['logged-in']))
        $widgets[$key] = $widgets['logged-in'];

    return $widgets;
}