WP_Query з "post_title LIKE" щось% ""?


44

Мені потрібно робити WP_Queryз a LIKEна post_title.

Я почав з цього регулярного WP_Query:

$wp_query = new WP_Query( 
    array (
        'post_type'        => 'wp_exposants',
        'posts_per_page'   => '1',
        'post_status'      => 'publish',
        'orderby'          => 'title', 
        'order'            => 'ASC',
        'paged'            => $paged
    )
); 

Але те, що я насправді хочу зробити, виглядає так у SQL:

$query = "
        SELECT      *
        FROM        $wpdb->posts
        WHERE       $wpdb->posts.post_title LIKE '$param2%'
        AND         $wpdb->posts.post_type = 'wp_exposants'
        ORDER BY    $wpdb->posts.post_title
";
$wpdb->get_results($query);

Вихід друкує результати, які мене очікують, але я використовую регулярний <?php while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>для відображення результатів.
І це не працює $wpdb->get_results().

Як я можу досягти того, що я описав тут?

Відповіді:


45

Я б вирішив це за допомогою фільтра WP_Query. Той, що виявляє додаткову змінну запиту і використовує це як префікс заголовка.

add_filter( 'posts_where', 'wpse18703_posts_where', 10, 2 );
function wpse18703_posts_where( $where, &$wp_query )
{
    global $wpdb;
    if ( $wpse18703_title = $wp_query->get( 'wpse18703_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'' . esc_sql( $wpdb->esc_like( $wpse18703_title ) ) . '%\'';
    }
    return $where;
}

Таким чином, ви все ще можете зателефонувати WP_Query, ви просто передаєте заголовок як wpse18703_titleаргумент (або змінюєте ім'я на щось коротше).


Цього якимось чином не вистачає $wpdb->prepare().
кайзер

@kaiser: Давно минуло, але я думаю, що це було неможливо prepare(). $wpdb->prepare('LIKE "%s%%"', 'banana')повернеться "LIKE ''banana'%'", тож ми повинні самі побудувати запит і зробити втечу теж.
Ян Фабрі

1
@JanFabry Радий бачити вас agaaaaaaaain! :) Завітайте в чат деякий час, гм? StopPress буде радий бачити вас. Про те prepare(). Так, це хитро, і мені довелося спробувати це кілька разів, перш ніж обійтись. Від чого - то я тільки що зробив: $wpdb->prepare( ' AND {$wpdb->posts}.post_title LIKE %s ', esc_sql( '%'.like_escape( trim( $term ) ).'%' ) ). І я майже впевнений, що esc_sql()це непотрібне і просто параноїчне.
кайзер

Здається, ви не можете шукати рядок із '(апострофом) всередині. Я думаю, це через втечу? Я ще не знайшов рішення
Вінсент Деко

19

Спрощено:

function title_filter( $where, &$wp_query )
{
    global $wpdb;
    if ( $search_term = $wp_query->get( 'search_prod_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
    }
    return $where;
}

$args = array(
    'post_type' => 'product',
    'posts_per_page' => $page_size,
    'paged' => $page,
    'search_prod_title' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'
);

add_filter( 'posts_where', 'title_filter', 10, 2 );
$wp_query = new WP_Query($args);
remove_filter( 'posts_where', 'title_filter', 10, 2 );
return $wp_query;

13
Будь ласка, додайте пояснення разом із кодом.
s_ha_dum

2
Велике спрощення
Тімо Хуовінен

1
Кодекс - я думаю, що я пояснив себе, як мінімум для мене. Дякуємо, що поділилися повним сценарієм.
Хассан тато хан

Використовуйте '$ wpdb-> esc_like (' замість 'esc_sql (like_escape ('
fdrv

@fdrv Ви маєте рацію, але згідно з wp docs $ wpdb-> esc_like все ще потрібен esc_sql (). Тож я думаю, що правильним кодом буде esc_sql ($ wpdb-> esc_like ($ search_term))
Waqas Bukhary

16

Ви хотіли оновити цей код, ви, хлопці, працювали над wordpress 4.0 і вище, оскільки esc_sql () застаріло на 4.0 вище.

function title_filter($where, &$wp_query){
    global $wpdb;

    if($search_term = $wp_query->get( 'search_prod_title' )){
        /*using the esc_like() in here instead of other esc_sql()*/
        $search_term = $wpdb->esc_like($search_term);
        $search_term = ' \'%' . $search_term . '%\'';
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }

    return $where;
}

Решта речі така ж.

Також хочу зазначити, що ви можете використовувати змінну s в аргументах WP_Query для передачі пошукових термінів, які також шукатиму назву повідомлення, на яку я вірю.

Подобається це:

$args = array(
    'post_type' => 'post',
    's' => $search_term,
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC'        
);
$wp_query = new WP_Query($args);

Що саме search_prod_title? Чи варто змінити це на щось інше?
Антоніос Цимуртос

З тих пір, коли esc_sqlвиписується з друку? Це не. $wpdb->escapeХоча ... developer.wordpress.org/reference/functions/esc_sql
Джеремі

Зауважте, що параметр s також шукає вміст публікації, що може бути не бажаною метою. =)
Крістін Купер

10

З деяким вразливим рішенням, розміщеним тут, я надходжу з трохи спрощеною та санітарною версією.

По-перше, ми створюємо функцію для posts_whereфільтра, яка дозволяє показувати лише повідомлення, що відповідають певним умовам:

function cc_post_title_filter($where, &$wp_query) {
    global $wpdb;
    if ( $search_term = $wp_query->get( 'cc_search_post_title' ) ) {
        $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . $wpdb->esc_like( $search_term ) . '%\'';
    }
    return $where;
}

Тепер ми додаємо cc_search_post_titleдо нашого запиту аргументи:

$args = array(
    'cc_search_post_title' => $search_term, // search post title only
    'post_status' => 'publish',
);

І нарешті оберніть фільтр навколо запиту:

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$query = new WP_Query($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

Використання get_posts ()

Деякі функції, які отримують публікації, не запускають фільтри, тому функції фільтрувальних файлів posts_where, які ви додаєте, не змінять запит. Якщо ви плануєте використовувати get_posts()для запитів своїх публікацій, вам потрібно встановити suppress_filtersзначення false у масиві аргументів:

$args = array(
    'cc_search_post_title' => $search_term,
    'suppress_filters' => FALSE,
    'post_status' => 'publish',
);

Тепер ви можете використовувати get_posts():

add_filter( 'posts_where', 'cc_post_title_filter', 10, 2 );
$posts = get_posts($args);
remove_filter( 'posts_where', 'cc_post_title_filter', 10 );

Що з sпараметром?

sПараметр доступний:

$args = array(
    's' => $search_term,
);

Якщо ви додаєте пошуковий термін до sроботи параметра, і він буде шукати заголовок публікації, він також буде шукати вміст публікації.

Що з titleпараметром, який було додано до WP 4.4?

Передача пошукового терміна в titleпараметр:

$args = array(
    'title' => $search_term,
);

Чутливий до регістру і LIKE, ні %LIKE%. Це означає, що пошук helloне поверне публікацію з назвою Hello Worldабо Hello.


Відмінно. Я шукав "post_title" як параметр і, очевидно, нічого не знайшов.
MastaBaba

7

Спираючись на інші відповіді перед мною, щоб забезпечити гнучкість у ситуації, коли ви хочете шукати публікацію, яка містить слово в метаполі АБО в заголовку публікації, я надаю цей варіант через аргумент "title_filter_relation". У цій реалізації я допускаю лише входи "АБО" або "І" із замовчуванням "І".

function title_filter($where, &$wp_query){
    global $wpdb;
    if($search_term = $wp_query->get( 'title_filter' )){
        $search_term = $wpdb->esc_like($search_term); //instead of esc_sql()
        $search_term = ' \'%' . $search_term . '%\'';
        $title_filter_relation = (strtoupper($wp_query->get( 'title_filter_relation'))=='OR' ? 'OR' : 'AND');
        $where .= ' '.$title_filter_relation.' ' . $wpdb->posts . '.post_title LIKE '.$search_term;
    }
    return $where;
}

Ось приклад коду в дії для дуже простого типу публікації "faq", де питання - сама назва публікації:

add_filter('posts_where','title_filter',10,2);
$s1 = new WP_Query( array(
    'post_type' => 'faq',
    'posts_per_page' => -1,
    'title_filter' => $q,
    'title_filter_relation' => 'OR',
    'post_status' => 'publish',
    'orderby'     => 'title', 
    'order'       => 'ASC',
    'meta_query' => array(
        'relation' => 'OR',
        array(
            'key' => 'faq_answer',
            'value' => $q,
            'compare' => 'LIKE'
        )
    )
));
remove_filter('posts_where','title_filter',10,2);

1
Гарне розуміння, додавання користувальницьких "варіантів запитів" до переданих аргументів запитів WP_Query, щоб мати доступ до них у posts_whereфільтрі.
Том Ожер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.