Как изменить сайдбар, получаемый через get_sidebar() из functions.php

7 сент. 2012 г., 19:40:56
Просмотры: 15.5K
Голосов: 2

У меня есть этот код в файле шаблона, который загружает sidebar-sidebar_a.php:

get_sidebar('sidebar_a');

Я хочу добавить функцию в sidebar.php, которая будет изменять это на следующее, если выполняется определенное условие:

get_sidebar('other');

чтобы вместо этого загружался sidebar-other.php.

Я думал, что это сработает, но, похоже, не дает эффекта:

add_action('get_sidebar', 'my_sidebar_logic');

function my_sidebar_logic($sidebar) {
    // Загружаем другой сайдбар, если пользователь авторизован
    if (is_user_logged_in()) {
        return 'other';
    }

    return $sidebar;
}

Что я могу сделать, чтобы получить нужный эффект?

0
Все ответы на вопрос 4
0

Функция get_sidebar является тонкой обёрткой вокруг locate_template, которая просто ищет указанный сайдбар в текущей дочерней и родительской теме.

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

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

$templates[] = 'sidebar.php';

// Обратная совместимость, будет удалено в будущем релизе
if ('' == locate_template($templates, true))
    load_template( ABSPATH . WPINC . '/theme-compat/sidebar.php');

}

И функция locate_templatewp-includes/template.php):

<?php
/**
 * Получает имя файла шаблона с наивысшим приоритетом.
 *
 * Сначала ищет в STYLESHEETPATH, затем в TEMPLATEPATH, чтобы темы,
 * наследующие от родительской темы, могли просто переопределить один файл.
 *
 * @since 2.7.0
 *
 * @param string|array $template_names Файл(ы) шаблона для поиска, в порядке приоритета.
 * @param bool $load Если true, найденный файл шаблона будет загружен.
 * @param bool $require_once Использовать require_once или require. По умолчанию true. Не действует, если $load равен false.
 * @return string Имя файла шаблона, если он найден.
 */
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;
}

Причина, по которой ваш хук в get_sidebar не работает, в том, что это действие (action). Оно просто срабатывает, но не позволяет изменить результат. Ваш сайдбар всё равно будет включён независимо от подключённого действия.

Это оставляет вам несколько вариантов.

1. Передача переменной в get_sidebar

Решение Chip Bennett: передать переменную в функцию get_sidebar. Неплохой вариант.

2. Написать свою логику для сайдбара

И использовать её вместо get_sidebar. Простой пример:

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

Затем используйте свой собственный фильтр для изменения сайдбара:

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

Это будет наиболее гибким решением. Если это публичная тема, конечные пользователи смогут настраивать её. Если это для клиента, когда он неизбежно попросит больше возможностей, это будет легко реализовать.

3. Копнуть глубже

get_sidebar просто подключает соответствующие файлы темы. dynamic_sidebar — это где происходит основная работа.

Если заглянуть внутрь этой функции, самая интересная строка:

$sidebars_widgets = wp_get_sidebars_widgets();

wp_get_sidebars_widgets получает все зарегистрированные виджеты для всех сайдбаров на сайте.

<?php
/**
 * Получает полный список сайдбаров и их виджетов.
 *
 * При необходимости обновляет список виджетов сайдбара. Также сохраняет обновлённый список, если нужно.
 *
 * @since 2.2.0
 * @access private
 *
 * @param bool $deprecated Не используется (устарело).
 * @return array Обновлённый список виджетов в формате массива версии 3 при вызове из админки.
 */
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;

    // Если загрузка с фронтенда, используем $_wp_sidebars_widgets вместо опций,
    // чтобы проверить, не внесла ли функция wp_convert_widget_settings изменения в памяти.
    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;
}

Ключевая строка здесь: apply_filters('sidebars_widget', ...). Вот где можно сделать магию.

Зарегистрируем дополнительный сайдбар только для авторизованных пользователей:

<?php
add_action('widgets_init', 'wpse64492_register');
function wpse64492_register()
{
    register_sidebar(array(
        'name'  => __('Сайдбар для авторизованных', 'wpse64492'),
        'id'    => 'logged-in'
    ));
}

Затем подключимся к фильтру sidebars_widgets и заменим обычный сайдбар на версию для авторизованных пользователей.

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

    $key = 'sidebar-1'; // сайдбар, который нужно изменить!

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

    return $widgets;
}

7 сент. 2012 г. 21:39:26
0

Просто передайте переменную в get_sidebar():

// Определяем сайдбар
$sidebar = ( is_user_logged_in() ? 'other' : 'sidebar_a' );
// Получаем сайдбар
get_sidebar( $sidebar );
7 сент. 2012 г. 19:49:57
0

Темы

Просто оберните это в самую тонкую и ненавязчивую логику: фильтр.

// В вашей теме: вызывает стандартный сайдбар
get_sidebar( apply_filters( 'wpse64492_sidebar', '' ) );

Затем вы можете переключить в файле functions.php:

function wpse64492_sidebar_name( $name = '' )
{
    // Вызывает sidebar-single.php для одиночных записей
    is_single() AND $name = 'single';

    return $name;
}
add_filter( 'wpse64492_sidebar', 'wpse64492_sidebar_name' );

Плагины

Если вы хотите сделать это через плагин, используйте действие:

<?php
/** Plugin Name: (#64492) Переключение сайдбаров по запросу */
function wpse64492_sidebar( $name )
{
    // Условная логика: другой сайдбар для страниц 2+ в архивах с пагинацией
    if ( is_paged() )
    {
        // Избегаем рекурсии: удаляем сам фильтр
        remove_filter( current_filter(), __FUNCTION__ );
        return get_sidebar( 'paged' );
    }

    // Возвращаем по умолчанию
    return $name;
}
add_action( 'get_sidebar', 'wpse64492_sidebar' );
17 окт. 2012 г. 06:23:14
2

Вы также можете вызвать фактическую боковую панель в функции.

add_action('get_sidebar', 'my_sidebar_logic');

function my_sidebar_logic($sidebar) {
    // Загружаем другую боковую панель, если пользователь авторизован
    if (is_user_logged_in()) {
          get_sidebar('other');
    }   
}
7 сент. 2012 г. 19:50:28
Комментарии

Это не приведёт к рекурсивному циклу?

Chip Bennett Chip Bennett
7 сент. 2012 г. 19:54:18

Ах, ты, наверное, прав, я не совсем понял вопрос, я думал про dynamic sidebar

Wyck Wyck
7 сент. 2012 г. 20:06:52