Change which sidebar get_sidebar() gets from functions.php

I have this code in a template file, which loads sidebar-sidebar_a.php:

get_sidebar('sidebar_a');

I would like to add a function to sidebar.php which has the effect of changing that to this if some condition is met:

Read More
get_sidebar('other');

so that it instead loads sidebar-other.php.

I thought that this would work, but it seems to have no effect:

add_action('get_sidebar', 'my_sidebar_logic');

function my_sidebar_logic($sidebar) {
    // Load a different sidebar if the user is logged in
    if (is_user_logged_in()) {
        return 'other';
    }

    return $sidebar;
}

What can I do to get the effect I want?

Related posts

Leave a Reply

4 comments

  1. 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 . '/' . $template_name)) {
                $located = STYLESHEETPATH . '/' . $template_name;
                break;
            } else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
                $located = TEMPLATEPATH . '/' . $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;
    }
    
  2. Just pass a variable to get_sidebar():

    // Determine sidebar
    $sidebar = ( is_user_logged_in() ? 'other' : 'sidebar_a' );
    // Get the sidebar
    get_sidebar( $sidebar );
    
  3. Themes

    Just wrap it in the thinnest and most unintrusive logic: A filter.

    // In you theme: Calls the default sidebar
    get_sidebar( apply_filters( 'wpse64492_sidebar', '' ) );
    

    Then you can switch in your functions.php file:

    function wpse64492_sidebar_name( $name = '' )
    {
        // Call sidebar-single.php on single view posts
        is_single() AND $name = 'single';
    
        return $name;
    }
    add_filter( 'wpse64492_sidebar', 'wpse64492_sidebar_name' );
    

    Plugins

    If you want to do it from a plugin, use the action:

    <?php
    /** Plugin Name: (#64492) Switch sidebars per request */
    function wpse64492_sidebar( $name )
    {
        // Conditional logic: Some other sidebar for page 2+ on paged archives
        if ( is_paged() )
        {
            // Avoid recurrsion: remove itself
            remove_filter( current_filter(), __FUNCTION__ );
            return get_sidebar( 'paged' );
        }
    
        // Default return
        return $name;
    }
    add_action( 'get_sidebar', 'wpse64492_sidebar' );
    
  4. You can call the actual sidebar in the function as well.

    add_action('get_sidebar', 'my_sidebar_logic');
    
    function my_sidebar_logic($sidebar) {
        // Load a different sidebar if the user is logged in
        if (is_user_logged_in()) {
              get_sidebar('other');
        }   
    }