Как создать пользовательский поиск для произвольного типа записей?
У меня есть поле поиска для записей блога, но мне нужно другое для произвольного типа записей. Как создать эту пользовательскую форму поиска с другим макетом результатов поиска?

Вот что я попробовал и получил решение в 3 шага. Допустим, ваш произвольный тип записи - "products"
1. Добавьте код функции, здесь вы можете указать archive-search.php
function template_chooser($template)
{
global $wp_query;
$post_type = get_query_var('post_type');
if( $wp_query->is_search && $post_type == 'products' )
{
return locate_template('archive-search.php'); // перенаправление на archive-search.php
}
return $template;
}
add_filter('template_include', 'template_chooser');
2. Создайте шаблон результатов поиска для произвольного типа записи (archive-search.php)
<?php
/* Template Name: Custom Search */
get_header(); ?>
<div class="contentarea">
<div id="content" class="content_right">
<h3>Результаты поиска для: <?php echo htmlentities($s, ENT_QUOTES, 'UTF-8'); ?> </h3>
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<div id="post-<?php the_ID(); ?>" class="posts">
<article>
<h4><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></h4>
<p><?php the_excerpt(); ?></p>
<p align="right"><a href="<?php the_permalink(); ?>">Читать далее</a></p>
<span class="post-meta"> Автор: <?php the_author(); ?>
| Дата: <?php echo date('j F Y'); ?></span>
</article><!-- #post -->
</div>
<?php endwhile; ?>
<?php endif; ?>
</div><!-- content -->
</div><!-- contentarea -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
Создайте форму поиска
В этой форме поиска значение "products" скрыто, и поиск будет выполняться только по записям типа products.<div> <h3>Поиск товаров</h3> <form role="search" action="<?php echo site_url('/'); ?>" method="get" id="searchform"> <input type="text" name="s" placeholder="Поиск товаров"/> <input type="hidden" name="post_type" value="products" /> <!-- // скрытое значение 'products' --> <input type="submit" alt="Поиск" value="Поиск" /> </form> </div>
для получения дополнительной информации рекомендую перейти по ссылке
http://www.wpbeginner.com/wp-tutorials/how-to-create-advanced-search-form-in-wordpress-for-custom-post-types/

Совет: при регистрации типа записи аргумент publicly_queryable должен быть установлен как true. В противном случае get_query_var('post_type') никогда не вернет значение post_type, указанное в аргументе url. https://codex.wordpress.org/Function_Reference/register_post_type#Arguments

Еще один совет/предлагаемое изменение: get_query_var('post_type')
возвращал массив (а не строку), поэтому не мог сравниваться напрямую. Поскольку я ищу только один тип записи за раз, я просто изменил переменную $post_type
на $post_type[0]
.

есть ли способ переписать URL с http://localhost:3000/?s=cloud%27&post_type=product
на http://localhost:3000/search/cloud/product

@YarGnawh Извините за поздний ответ, посмотрите это https://wordpress.stackexchange.com/questions/15418/pretty-permalinks-for-search-results-with-extra-query-var. Также есть плагин для перезаписи https://wordpress.org/plugins/rewrite/

фильтр search_template
кажется более подходящей альтернативой для template_include

Приведенный выше код сработал для меня. Мне просто нужно было отредактировать <?php the_exerpt(); ?> и изменить его на <?php the_excerpt(); ?>

Вот что работает у меня. Не так элегантно, но я не смог заставить работать другие предложенные решения.
Форма поиска для произвольного типа записей:
<form role="search" method="get" class="search-form" action="<?php echo home_url( '/' ); ?>">
<label>
<span class="screen-reader-text"><?php echo _x( 'Искать:', 'label' ) ?></span>
<input type="search" class="search-field" placeholder="<?php echo esc_attr_x( 'Поиск …', 'placeholder' ) ?>" value="<?php echo get_search_query() ?>" name="s" title="<?php echo esc_attr_x( 'Искать:', 'label' ) ?>" />
<input type="hidden" name="post_type" value="book" />
</label>
<input type="submit" class="search-submit" value="<?php echo esc_attr_x( 'Поиск', 'submit button' ) ?>" />
</form>
В файле functions.php:
function searchfilter($query) {
if ($query->is_search && !is_admin() ) {
if(isset($_GET['post_type'])) {
$type = $_GET['post_type'];
if($type == 'book') {
$query->set('post_type',array('book'));
}
}
}
return $query;
}
add_filter('pre_get_posts','searchfilter');
В файле search.php:
<?php if (have_posts()) : ?>
<?php while (have_posts()) : the_post(); ?>
<?php if(isset($_GET['post_type'])) {
$type = $_GET['post_type'];
if($type == 'book') {?>
/* Формат для произвольного типа записей "book" */
<?php } else { ?>
/* Формат для произвольных типов записей, которые не являются "book",
или вы можете использовать elseif для указания второго типа записи
таким же образом, как выше. Скопируйте формат по умолчанию сюда, если у вас
только один произвольный тип записи. */
<?php } ?>
<?php } else { ?>
/* Формат для отображения, когда параметр post_type
не установлен (т.е. формат по умолчанию) */
<?php } ?>
<?php endwhile; else: ?>
/* Что отображать, если результатов нет. */
<?php endif; ?>
Естественно, во всех трех местах вам нужно заменить "book" на ваш произвольный тип записи.
Надеюсь, это кому-нибудь поможет!

Более актуальный короткий код
function template_chooser($template)
{
global $wp_query;
$post_type = $wp_query->query_vars["pagename"];
if( isset($_GET['s']) && $post_type == 'products' )
{
return locate_template('archive-search.php'); // перенаправление на archive-search.php
}
return $template;
}
add_filter('template_include', 'template_chooser');

Я искал возможность использовать две разные формы для обычного поиска и поиска по пользовательскому типу записей.
Мой пользовательский тип записей использует другой заголовок, чем обычные страницы. На обычной странице вызов моей формы поиска выглядит так:
<?php get_search_form(true); ?>
А вызов формы поиска в заголовке пользовательского типа записей выглядит так:
<?php get_template_part('search','library'); ?>
Которая имеет дополнительное поле:
<input type="hidden" name="post_type" value="library" /> //Где "library" - это мой пользовательский тип записей.
В файле functions.php у меня есть следующий код, который вы предоставили.
/** Пользовательский поиск для библиотеки */
function search_library($template)
{
global $wp_query;
$post_type = get_query_var('post_type');
if( $wp_query->is_search && $post_type == 'library' )
{
return locate_template('search-library.php'); // перенаправление на archive-search.php
}
return $template;
}
add_filter('template_include', 'search_library');
Этот код определяет, выполняется ли поиск по пользовательским полям, и в этом случае показывает результаты поиска в пользовательском шаблоне, в противном случае используется обычный шаблон.
Редактирование: исправлен вызов функции get_search_form(), которая возвращала бы true в любом случае.

Стоит отметить, что get_search_form('true')
должно быть get_search_form(true)
. Функция get_search_form
ожидает булево значение на входе, то есть либо true
, либо false
. Заключая значение в кавычки, вы передаете строку, а не булев параметр. По тому, как устроена эта функция, оба варианта 'true'
и 'false'
вернут один и тот же результат, потому что они оба являются непустыми строками (что приводит к тому, что функция возвращает true в обоих случаях).

Чтобы исправить проблему с пустым поиском, вы можете заменить код функции на следующий:
function template_chooser($template)
{
global $wp_query;
$post_type = get_query_var('post_type');
if( isset($_GET['s']) && $post_type == 'products' )
{
return locate_template('archive-search.php'); // перенаправление на archive-search.php
}
return $template;
}
add_filter('template_include', 'template_chooser');

У меня есть 10 произвольных типов записей (CPT), каждый со своей собственной страницей результатов поиска (с разными макетами), и стандартный подход не работал для меня.
После дополнительного исследования я нашел этот подход, где вы настраиваете шаблон search.php для загрузки другого шаблона, если в URL присутствует CPT.
По сути, в search.php нужно вставить следующее:
<?php
// проверяем, есть ли тип записи в URL + nonce для безопасности
if ( isset( $_GET['post_type'], $_GET['custom_search_nonce_field'] ) && wp_verify_nonce( $_GET['custom_search_nonce_field'], 'custom_search_nonce_action' ) ) {
// сохраняем для дальнейшего использования
$post_type = $_GET['post_type'];
// проверяем, существует ли шаблон поиска
if ( locate_template( 'search-' . $post_type . '.php' ) ) {
// загружаем его и выходим
get_template_part( 'search', $post_type );
exit;
}
}
?>
а форма поиска будет выглядеть примерно так:
<form class="search" action="<?php echo home_url( '/' ); ?>">
<input type="search" name="s" placeholder="Поиск…">
<input type="submit" value="Искать">
<input type="hidden" name="post_type" value="kb_article">
<?php wp_nonce_field( 'custom_search_nonce_action', 'custom_search_nonce_field' ); ?>
</form>

Я знаю, что это старая тема, но я использую пользовательские шорткоды в файле functions.php, чтобы включить поиск, привязанный к определенным типам записей и, в моем случае, пользовательским таксономиям. Я использую Pods для архива видеолекций по годам и хотел, чтобы поиск осуществлялся только в пределах этого года. Это сейчас работает (в моем файле functions.php):
/*Пользовательский поиск для Видео Архива 2020 года - добавляет шорткод [2020search] для поиска*/
function video2020searchform( $form ) {
$form = '<form role="search" method="get" id="searchform" action="' . home_url( '/' ) . '" >
<div class="my-custom-search"><label class="screen-reader-text" for="s">' . __('Поиск:') . '</label>
<input type="hidden" name="video_year" value="video-archive-2020" />
<input type="text" value="' . get_search_query() . '" name="s" id="s" placeholder="Поиск в архивах 2020 года по спикеру или ключевому слову..." />
<input type="submit" id="searchsubmit" value="'. esc_attr__('Поиск') .'" />
</div>
</form>';
return $form;
}
add_shortcode('2020search', 'video2020searchform');
// конец формы поиска 2020 года.
Затем у меня есть страница с избранными видео за 2020 год, с шорткодом формы поиска над ней, чтобы пользователи могли искать остальные материалы за 2020 год. name="video_year"
- это пользовательская таксономия, созданная с помощью Pods, тип записи также создан с помощью Pods и называется "videos", а value="video-archive-2020"
- это ярлык из года видео Pods, который мне нужен. Если у вас есть пользовательский тип записи "books", таксономия "book-genre" и вы пытаетесь ограничить поиск категорией "adventure", то "book-genre" будет значением 'name', а "adventure" будет значением 'value'. Надеюсь, это кому-то поможет, и спасибо всем за предыдущие ответы!

В моем случае поиск работал отлично. Мне просто нужно было отфильтровать запрос, чтобы искать только среди типов записей курсов Learndash. Вот что я сделал:
// Фильтрует поисковый запрос, чтобы включать только тип записи 'sfwd-courses'
function fn_search_courses_only($query) {
if( $query->is_search && ! is_admin() ) {
$query->set( 'post_type', 'sfwd-courses' );
}
}
add_action( 'pre_get_posts', 'fn_search_courses_only' );
