Поиск только записей блога (стандартный виджет поиска WP)
Я использовал этот код:
add_filter( 'pre_get_posts','search_only_blog_posts' );
function search_only_blog_posts( $query ) {
if ( $query->is_search ) {
$query->set( 'post_type', 'post' );
}
return $query;
}
...пока не понял, что это применяется практически ко всем стандартным поискам в WordPress (включая поиск на странице списка записей в админке и т.д.).
Как сделать, чтобы виджет поиска искал только записи блога (не пользовательские типы записей, таксономии, изображения и т.д.) и не применялся к другим стандартным поискам WP (только к поиску через виджет) ?
Или проще создать собственный виджет поиска?
Я бы предпочел использовать встроенные возможности WordPress, а не изобретать велосипед.

@PieterGoosen хорошо описал, почему ваш callback pre_get_posts
вызывает проблему.
Вот альтернативное решение для ограничения нативного виджета поиска только типом записи post:
/**
* Ограничиваем нативные виджеты поиска типом записи 'post'
*/
add_filter( 'widget_title', function( $title, $instance, $id_base )
{
// Нацеливаемся на базовый поиск
if( 'search' === $id_base )
add_filter( 'get_search_form', 'wpse_post_type_restriction' );
return $title;
}, 10, 3 );
function wpse_post_type_restriction( $html )
{
// Запускаем только один раз
remove_filter( current_filter(), __FUNCTION__ );
// Добавляем скрытое поле post_type
return str_replace(
'</form>',
'<input type="hidden" name="post_type" value="post" /></form>',
$html
);
}
где мы корректируем вывод функции get_search_form()
, но только для виджетов поиска.

Довольно нестандартный способ использовать фильтр widget_title
;-)

да, здесь он очень удобен, фильтр widget_display_callback
был другой возможностью ;-) @PieterGoosen

Спасибо за информацию, никогда не поздно и не стыдно научиться чему-то новому ;-)

Оба ответа очень хорошие, но я склоняюсь к более короткому, который использует сам поиск WordPress. @PieterGoosen, разве WP_Widget
не вызывает deprecated ошибку? Я не нашел альтернативы в интернете (сделал лишь несколько быстрых поисков, сейчас это не в приоритете).

@N00b Нет, думаю, ты путаешь с устаревшими конструкторами PHP4. Как я сказал, мой код взят из ядра, просто имена изменены соответствующим образом ;-)

Ваше использование pre_get_posts
совершенно неверно.
pre_get_posts
— это действие (action), а не фильтр. Проверьте исходный кодdo_action_ref_array( 'pre_get_posts', array( &$this ) );
Да,
add_filter
работает, потому чтоadd_action
вызываетadd_filter
, поэтому ваш код будет работать. Но с точки зрения правильного использования — это просто неверно. Если что-то является действием, используйтеadd_action()
. Это логично.WP_Query::is_search
(а такжеWP_Query::is_search()
) возвращает true для любого запроса, в котором параметрs
передан вWP_Query
. Помните, что условные теги внутриWP_Query
определяются не по URL, а по переданным в него query vars. Для основного запроса query vars передаются вWP_Query
после разбора URL.pre_get_posts
изменяет все экземплярыWP_Query
,query_posts
иget_posts
, как на фронтенде, так и в админке. Поэтому, если вы хотите воздействовать только на основной запрос, вам нужно его явно указать. Также, скорее всего, вам нужно обрабатывать только фронтенд, особенно для архивов и поисковых запросов.
Вот пример правильного использования pre_get_posts
для основного запроса: (Вы можете заменить замыкание на обычную функцию, просто учтите, что анонимные функции нельзя удалить позже)
add_action( 'pre_get_posts', function ( $q )
{
if ( !is_admin() // Только фронтенд
&& $q->is_main_query() // Только основной запрос
&& $q->is_search() // Только страница поиска
) {
$q->set( 'post_type', ['my_custom_post_type', 'post'] );
}
});
Что касается вашего вопроса о виджете поиска, вот что я выяснил:
Виджет поиска просто вызывает
get_search_form()
Нет полезных фильтров для точечного изменения именно виджета поиска. Фильтры в
get_search_form()
влияют на все формы, использующие эту функцию.
Таким образом, вам нужно создать собственный виджет поиска с собственной формой.
Попробуйте следующий вариант: (Изменено на основе стандартного виджета поиска, не тестировалось)
class My_Custom_Search extends WP_Widget {
/**
* Настраивает новый экземпляр виджета поиска.
*
* @since 1.0.0
* @access public
*/
public function __construct() {
$widget_ops = [
'classname' => 'widget_custom_search',
'description' => __( "Пользовательская форма поиска для вашего сайта.")
];
parent::__construct( 'custom-search', _x( 'Пользовательский поиск', 'Мой пользовательский виджет поиска' ), $widget_ops );
}
/**
* Выводит содержимое текущего виджета поиска.
*
* @since 1.0.0
* @access public
*
* @param array $args Аргументы вывода, включая 'before_title', 'after_title',
* 'before_widget', и 'after_widget'.
* @param array $instance Настройки текущего виджета поиска.
*/
public function widget( $args, $instance ) {
/** Этот фильтр описан в wp-includes/widgets/class-wp-widget-pages.php */
$title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );
echo $args['before_widget'];
if ( $title ) {
echo $args['before_title'] . $title . $args['after_title'];
}
$form = '<form role="search" method="get" class="search-form" action="' . esc_url( home_url( '/' ) ) . '">
<label>
<span class="screen-reader-text">' . _x( 'Искать:', 'label' ) . '</span>
<input type="search" class="search-field" placeholder="' . esc_attr_x( 'Поиск …', 'placeholder' ) . '" value="' . get_search_query() . '" name="s" title="' . esc_attr_x( 'Искать:', 'label' ) . '" />
</label>
<input type="hidden" value="post" name="post_type" id="post_type" />
<input type="submit" class="search-submit" value="'. esc_attr_x( 'Поиск', 'кнопка отправки' ) .'" />
</form>';
echo $form;
echo $args['after_widget'];
}
/**
* Выводит форму настроек виджета поиска.
*
* @since 1.0.0
* @access public
*
* @param array $instance Текущие настройки.
*/
public function form( $instance ) {
$instance = wp_parse_args( (array) $instance, ['title' => '')];
$title = $instance['title'];
?>
<p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Заголовок:'); ?> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></label></p>
<?php
}
/**
* Обрабатывает обновление настроек текущего виджета поиска.
*
* @since 1.0.0
* @access public
*
* @param array $new_instance Новые настройки, введенные пользователем через
* WP_Widget::form().
* @param array $old_instance Старые настройки.
* @return array Обновленные настройки.
*/
public function update( $new_instance, $old_instance ) {
$instance = $old_instance;
$new_instance = wp_parse_args((array) $new_instance, ['title' => '')];
$instance['title'] = sanitize_text_field( $new_instance['title'] );
return $instance;
}
}

Вы можете просто добавить этот код в файл functions.php.
function SearchFilter($query)
{
// Фильтр поиска: устанавливаем тип записи только для постов (не страниц)
if (($query->is_search)&&(!is_admin())) {
$query->set('post_type', 'post');
}
return $query;
}
// Добавляем фильтр к запросам перед их выполнением
add_filter('pre_get_posts','SearchFilter');

Просто вставьте этот код в файл functions.php вашей темы WordPress.
function wpdocs_my_search_form( $form ) {
$form = '<form role="search" method="get" id="searchform" class="searchform" action="' . home_url( '/' ) . '" >
<div><label class="screen-reader-text" for="s">' . __( 'Поиск по:' ) . '</label>
<input type="text" value="' . get_search_query() . '" name="s" id="s" />
<input type="hidden" value="post" name="post_type" id="post_type" />
<input type="submit" id="searchsubmit" value="'. esc_attr__( 'Поиск' ) .'" />
</div>
</form>';
return $form;
} add_filter( 'get_search_form', 'wpdocs_my_search_form' );

Пожалуйста, ознакомьтесь с этим кодом и настройками по следующей ссылке
