Добавление div для обертки содержимого виджета после заголовка виджета
Я пытаюсь добавить div для содержимого виджета в моем динамическом сайдбаре.
Вот код регистрации:
register_sidebar(array(
'name' => "Sidebar1",
'id' => 'home-sidebar-1',
'before_widget' => '<div class="sidebar-box">',
'after_widget' => '</div>',
'before_title' => '<div class="title">',
'after_title' => '</div>',
));
Но этот код создает такую структуру:
<div class="sidebar-box">
<div class="title">{ЗАГОЛОВОК ВИДЖЕТА}</div>
{СОДЕРЖИМОЕ ВИДЖЕТА}
</div>
Вот что я пытаюсь получить:
<div class="sidebar-box">
<div class="title">{ЗАГОЛОВОК ВИДЖЕТА}</div>
<div class="content">
{СОДЕРЖИМОЕ ВИДЖЕТА}
</div>
</div>
Как это можно сделать?

В дополнение к ответу Toscho вот что вам нужно для надежного решения:
// если нет заголовка, добавляем обертку содержимого виджета перед виджетом
add_filter( 'dynamic_sidebar_params', 'check_sidebar_params' );
function check_sidebar_params( $params ) {
global $wp_registered_widgets;
$settings_getter = $wp_registered_widgets[ $params[0]['widget_id'] ]['callback'][0];
$settings = $settings_getter->get_settings();
$settings = $settings[ $params[1]['number'] ];
if ( $params[0][ 'after_widget' ] == '</div></div>' && isset( $settings[ 'title' ] ) && empty( $settings[ 'title' ] ) )
$params[0][ 'before_widget' ] .= '<div class="content">';
return $params;
}
Из ответа Toscho:
register_sidebar(array(
'name' => "Sidebar1",
'id' => 'home-sidebar-1',
'before_widget' => '<div class="sidebar-box">',
'after_widget' => '</div></div>',
'before_title' => '<div class="title">',
'after_title' => '</div><div class="content">',
));
Что делает этот код:
- проверяет настройки зарегистрированной боковой панели для виджетов, заканчивающихся на 2 закрывающих тега
<div>
- проверяет, есть ли заголовок
- если нет, он изменяет вывод
before_widget
, чтобы показать открывающий div содержимого виджета
Вы можете использовать этот подход для изменения аргументов боковой панели другими способами на основе настроек экземпляра виджета.

У меня проблема: некоторые виджеты (например, стандартные виджеты WP) устанавливают заголовок по умолчанию, если оставить это поле пустым. Так что ваша функция добавляет div, потому что в этот момент в параметрах нет заголовка, но виджет добавляет его позже, и код получается испорченным. Вы знаете, как проверить наличие заголовка "изнутри" виджета? Спасибо

Нет, без добавления проверки для каждого виджета в отдельности или какого-то ужасно сложного кода, который бы рендерил виджет в тихом режиме, а затем анализировал его на наличие заголовка... Подумаю над этим

Может быть, использование этого хука http://codex.wordpress.org/Function_Reference/the_widget поможет? Его используют (по другой причине) в этой статье http://wp.smashingmagazine.com/2012/12/11/inserting-widgets-with-shortcodes/

Мне понравилась идея обоих ответов @tosco и @sanchothefat - однако у меня возникли трудности с их комбинацией, потому что хотя empty( $settings[ 'title' ]
действительно может вернуть true, сам виджет может выводить заголовок по умолчанию, если он не задан. Этот заголовок затем оборачивается в разметку before_title
и after_title
, и снова страница ломается. По крайней мере, так происходит с некоторыми стандартными виджетами.
Проще просто придерживаться стандартных параметров регистрации виджетов:
register_sidebar(array(
'id' => 'sidebar1',
'name' => __( 'Боковая панель 1', 'bonestheme' ),
'description' => __( 'Первая (основная) боковая панель.', 'bonestheme' ),
'before_widget' => '<div class="block">',
'after_widget' => '</div>',
'before_title' => '<div class="block-title">',
'after_title' => '</div>',
));
а затем добавить фильтр, как предложил Marventus в своем ответе здесь:
http://wordpress.org/support/topic/add-html-wrapper-around-widget-content
function widget_content_wrap($content) {
$content = '<div class="block-content">'.$content.'</div>';
return $content;
}
add_filter('widget_text', 'widget_content_wrap');

Добавьте второй div
к параметру title:
register_sidebar(array(
'name' => "Sidebar1",
'id' => 'home-sidebar-1',
'before_widget' => '<div class="sidebar-box">',
'after_widget' => '</div></div>', // Закрываем оба div-элемента
'before_title' => '<div class="title">', // Открывающий div для заголовка
'after_title' => '</div><div class="content">', // Закрываем title и открываем content
));

Это не сработает, если у виджета нет заголовка - хотя это можно исправить

Вот что нужно сделать для достижения этого:
register_sidebar(array(
'name' => "Боковая панель 1",
'id' => 'home-sidebar-1',
'before_widget' => '<div class="sidebar-box"><div class="content">',
'after_widget' => '</div></div>',
'before_title' => '</div><div class="title">',
'after_title' => '</div><div class="content">',
))
Когда заголовок отсутствует, вы получите:
<div class="sidebar-box"><div class="content">
{CONTENT}
</div></div>
Когда есть заголовок, вы получите:
<div class="sidebar-box"><div class="content">
</div><div class="title">
{TITLE}
<div class="content">
{CONTENT}
</div></div>
Чтобы убедиться, что первый пустой div с классом content не отображается в последнем случае, добавьте это в ваш CSS:
.sidebar-box .content:empty {display:none !important;}

Рассмотрев предыдущие ответы, я думаю, что исправил проблему, которую Cmorales обнаружил в ответе sanchothefat. Определите свой виджет следующим образом:
register_sidebar( array(
'name' => 'Боковая панель',
'id' => 'sidebar',
'before_widget' => '<div class="panel panel-default %2$s" id="%1$s">',
'after_widget' => '</div>',
'before_title' => '',
'after_title' => ''
) );
Важно, чтобы значения по умолчанию для before_title
и after_title
были удалены. После некоторых проб и ошибок я заметил, что первый фильтр, который показывал заголовок по умолчанию, был widget_title
. Затем используйте фильтр widget_title
следующим образом:
function widget_title( $title ) {
if ( $title )
$title = '<div class="panel-heading"><h3 class="panel-title">' . $title . '</h3></div>';
$title .= '<div class="panel-body">';
return $title;
}
По сути, <div class="panel-heading"><h3 class="panel-title">
— это мой before_title
, а </h3></div>
— мой after_title
. Наконец, используйте dynamic_sidebar_params
, чтобы добавить закрывающий div для нашей обёртки контента:
function dynamic_sidebar_params( $params ) {
$params[0]['after_widget'] = '</div>' . $params[0]['after_widget'];
return $params;
}
Это не самое элегантное решение, но оно работает.

Я немного изменил код, чтобы не нужно было трогать register_sidebar. Регистрируем сайдбар обычным способом:
register_sidebar(array(
'name' => "Sidebar1",
'id' => 'home-sidebar-1',
'before_widget' => '<div class="sidebar-box">',
'after_widget' => '</div>',
'before_title' => '<div class="title">',
'after_title' => '</div>',
));
А ниже представлен модифицированный код из решения Sanchothefat:
/**
* Если заголовок не указан, добавляем обертку widget-content в before_widget
* Если заголовок указан, добавляем обертку контента в before_widget
*/
add_filter('dynamic_sidebar_params', 'check_widget_template');
function check_widget_template($params){
global $wp_registered_widgets;
$settings_obj = $wp_registered_widgets[$params[0]['widget_id']]['callback'][0];
$the_settings = $settings_obj->get_settings();
$the_settings = $the_settings[$params[1]['number']];
if (isset($params[0]['id']) && $params[0]['id'] == 'home-sidebar-1') {
if (!isset($the_settings['title']) && empty($the_settings['title'])) {
$params[0]['before_widget'] .= '<div class="widget-inner">';
$params[0]['after_widget'] .= '</div>';
} else {
$params[0]['after_widget'] .= '</div>';
$params[0]['after_title'] .= '<div class="widget-inner">';
}
}
return $params;
}

Как упоминалось в комментариях, некоторые основные виджеты добавляют собственный заголовок, который затем дважды оборачивается в div с контентом. Чтобы удалить их, можно просто вернуть пустую строку. Единственный недостаток — необходимо вручную вводить все заголовки.
function remove_default_widget_title( $title, $instance = [], $id = '' ) {
// Проверяем, установлен ли заголовок и является ли он пустой строкой
if ( isset($instance['title']) && trim($instance['title']) == '' ) {
return '';
}
return $title;
};
// Добавляем фильтр для изменения заголовка виджета
add_filter( 'widget_title', 'remove_default_widget_title', 10, 3 );
Поправьте меня, если я что-то упустил, но мне кажется, это довольно надежное решение.
