Как изменить сайдбар, получаемый через get_sidebar() из functions.php
У меня есть этот код в файле шаблона, который загружает 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;
}
Что я могу сделать, чтобы получить нужный эффект?
Функция 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_template
(в wp-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;
}

Темы
Просто оберните это в самую тонкую и ненавязчивую логику: фильтр.
// В вашей теме: вызывает стандартный сайдбар
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' );

Вы также можете вызвать фактическую боковую панель в функции.
add_action('get_sidebar', 'my_sidebar_logic');
function my_sidebar_logic($sidebar) {
// Загружаем другую боковую панель, если пользователь авторизован
if (is_user_logged_in()) {
get_sidebar('other');
}
}
