WP Query: поиск записей по первой букве заголовка
Мне нужно выполнить поиск записей с помощью WP_Query() и выбрать только те записи, которые начинаются с определенной буквы. Я нашел несколько старых постов с фильтрами, которые работали до версии 4.4, но начиная с 4.4 в WP_Query добавили поиск по заголовку.
$q = new WP_Query( array('post_type'=>'post','title'=>'This Song Title') );
Этот код вернет только точные совпадения записей с заголовком "This Song Title".
Мне же нужно получить все записи, которые начинаются, в данном примере, с буквы 'T'.
Я также нашел этот пост, на который так и не дали полноценного ответа. Там есть принятый ответ, но я не понимаю, как он решает вопрос. Как ограничить поиск первой буквой заголовка?
Другие возможности запроса, такие как поиск по комментариям и мета-полям, имеют параметр 'compare' для добавления LIKE% в запросы, но для заголовка такой возможности, похоже, нет.

Это невозможно сделать напрямую с помощью WP_Query
"из коробки", но используя фильтр posts_where
для поиска пользовательского аргумента в WP_Query
, можно добавить такую функциональность.
Предположим, что starts_with
— это имя аргумента, который мы хотим использовать. Мы можем отфильтровать posts_where
, чтобы добавить условие WHERE
, ограничивающее результаты только теми, которые начинаются с заданного значения, если starts_with
был установлен в запросе:
function wpse_298888_posts_where( $where, $query ) {
global $wpdb;
$starts_with = esc_sql( $query->get( 'starts_with' ) );
if ( $starts_with ) {
$where .= " AND $wpdb->posts.post_title LIKE '$starts_with%'";
}
return $where;
}
add_filter( 'posts_where', 'wpse_298888_posts_where', 10, 2 );
После добавления этого фильтра мы можем выполнять запросы следующим образом:
$query = new WP_Query( array(
'starts_with' => 'M',
) );
Это вернет все записи, начинающиеся с буквы "M".
Если вы хотите фильтровать основной запрос, вы также можете использовать этот аргумент в pre_get_posts
:
function wpse_298888_pre_get_posts( $query ) {
if ( $query->is_main_query() ) {
$query->set( 'starts_with', 'M' );
}
}
add_action( 'pre_get_posts', 'wpse_298888_pre_get_posts' );

Это работает идеально, но я внес одно изменение, которое может помочь другим. Я использовал REGEXP вместо LIKE, чтобы можно было объединить заголовки, начинающиеся с цифр 0-9, в одну группу.
$where .= " AND $wpdb->posts.post_title REGEXP '^$starts_with'";

Можно ли сделать наоборот — выбрать все записи и/или страницы, которые не начинаются с определенной буквы/строки? Я хочу исключить из результатов поиска определенные страницы, чьи заголовки начинаются с одного и того же слова, но хочу оставить это открытым на случай, если таких страниц станет больше, вместо использования статических ID. Это не записи, поэтому у них нет меток или категорий.

Я дважды проверил и не вижу проблем в коде. Если вы не скопировали этот код точно, скорее всего, у вас где-то синтаксическая ошибка в вашем коде.

@VincenzoPiromalli Если вы фильтруете основной запрос с помощью метода pre_get_posts
, то обычная пагинация будет работать корректно.

Просто имейте в виду, что если у вас заголовки на сложном языке с диакритическими знаками, результат может быть неточным. Кодировка базы данных для поля заголовка также играет большую роль. Даже в этом случае результат может быть не идеальным. Кроме того, я бы экранировал строку, которую вы передаёте, с помощью чего-то вроде: mb_substr($starts_with, 0, 1) // для CH и двойных букв, а также $wpdb->esc_like()
