WP_query с OR-связью между args[‘s’] и arg[‘meta_query’]

Вопрос или проблема

Мне нужно создать “OR” отношение между args[‘s’] и args[‘meta_query’]. Когда я определяю

‘relation’ => “OR” в списке массивов, он все равно генерирует SQL с отношением AND.

Фрагмент кода следующий

   if( isset($_GET['resume_search_keyword']) && $_GET['resume_search_keyword'] != '' ) :
    $resume_args['s'] = $_GET['resume_search_keyword'];
   endif;

    $resume_search_skills = array(
      'key' => '_resume_skills',
      'value' => $_GET['resume_search_keyword'],
      'compare' => 'LIKE'
    );

    $resume_search_job_duties = array(
      'key' => '_resume_job_duties',
      'value' => $_GET['resume_search_keyword'],
      'compare' => 'LIKE'
    );

  $resume_args['meta_query'] = array(
    'relation' => "OR",
    $resume_search_job_duties,
    $resume_search_skills
  );

  $resumes = new WP_Query($resume_args);

Сгенерированный SQL следующий

SELECT SQL_CALC_FOUND_ROWS
    wp_posts.ID
FROM
    wp_posts
        INNER JOIN
    wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE
    1 = 1
        AND (((wp_posts.post_title LIKE '%teaching%')
        OR (wp_posts.post_excerpt LIKE '%teaching%')
        OR (wp_posts.post_content LIKE '%teaching%')))
        AND ((wp_postmeta.meta_key = '_resume_job_duties'
        AND wp_postmeta.meta_value LIKE '%teaching%')
        OR (wp_postmeta.meta_key = '_resume_skills'
        AND wp_postmeta.meta_value LIKE '%teaching%'))
        AND wp_posts.post_type="resume"
        AND (wp_posts.post_status="publish"
        OR wp_posts.post_author = 3
        AND wp_posts.post_status="private")

Что я хочу вместо этого

SELECT SQL_CALC_FOUND_ROWS
    wp_posts.ID
FROM
    wp_posts
        INNER JOIN
    wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE
    1 = 1
        AND (((wp_posts.post_title LIKE '%teaching%')
        OR (wp_posts.post_excerpt LIKE '%teaching%')
        OR (wp_posts.post_content LIKE '%teaching%')))
        **OR** ((wp_postmeta.meta_key = '_resume_job_duties'
        AND wp_postmeta.meta_value LIKE '%teaching%')
        OR (wp_postmeta.meta_key = '_resume_skills'
        AND wp_postmeta.meta_value LIKE '%teaching%'))
        AND wp_posts.post_type="resume"
        AND (wp_posts.post_status="publish"
        OR wp_posts.post_author = 3
        AND wp_posts.post_status="private")

Может ли кто-то помочь, где я ошибаюсь?

Попробуйте это:

$query = new WP_Query( array(
    'meta_query' => array(
        'relation' => 'OR',
        'resume_skills_clause' => array(
            'key' => '_resume_skills',
            'value' => $_GET['resume_search_keyword'],
            'compare' => 'LIKE'
        ),
        'resume_job_duties_clause' => array(
            'key' => "_resume_job_duties",
            'value' => $_GET['resume_search_keyword'],
            'compare' => 'LIKE'
        )
    )
));

.

Ответ или решение

Теория

При работе с WP_Query в WordPress для выполнения сложных запросов зачастую требуется комбинировать различные условия поиска. Один из таких сценариев включает создание условия с логической операцией "ИЛИ" между полем поиска args['s'] и мета-запросами args['meta_query']. Однако, по умолчанию WordPress не позволяет напрямую использовать логическое "ИЛИ" между основным текстовым поиском (args['s']) и мета-запросами. Это связано с особенностями генерации SQL-запросов в ядре WordPress, где текстовый поиск всегда сочетается с другими условиями через "И".

Пример

В вашем случае, исходный код:

if (isset($_GET['resume_search_keyword']) && $_GET['resume_search_keyword'] != '') {
    $resume_args['s'] = $_GET['resume_search_keyword'];
}

$resume_search_skills = array(
    'key' => '_resume_skills',
    'value' => $_GET['resume_search_keyword'],
    'compare' => 'LIKE'
);

$resume_search_job_duties = array(
    'key' => '_resume_job_duties',
    'value' => $_GET['resume_search_keyword'],
    'compare' => 'LIKE'
);

$resume_args['meta_query'] = array(
    'relation' => 'OR',
    $resume_search_job_duties,
    $resume_search_skills
);

$resumes = new WP_Query($resume_args);

Генерирует SQL с использованием "AND" для соединения основных и мета-условий, что не соответствует вашей цели. В SQL это отражается следующим образом:

SELECT SQL_CALC_FOUND_ROWS
    wp_posts.ID
FROM
    wp_posts
    INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
WHERE
    1 = 1
    AND (((wp_posts.post_title LIKE '%teaching%')
    OR (wp_posts.post_excerpt LIKE '%teaching%')
    OR (wp_posts.post_content LIKE '%teaching%')))
    AND ((wp_postmeta.meta_key = '_resume_job_duties'
    AND wp_postmeta.meta_value LIKE '%teaching%')
    OR (wp_postmeta.meta_key = '_resume_skills'
    AND wp_postmeta.meta_value LIKE '%teaching%'))
    AND wp_posts.post_type="resume"
    AND (wp_posts.post_status="publish"
    OR wp_posts.post_author = 3
    AND wp_posts.post_status="private")

Применение

Чтобы добиться искомого SQL-запроса, можно воспользоваться фильтрами WordPress и модифицировать запрос вручную:

  1. Использование фильтра posts_clauses:
    Этот фильтр позволяет модифицировать различные части SQL-запроса, в том числе и условие WHERE.

  2. Реализация кастомного улучшения:

function modify_wp_query_clauses($clauses, $wp_query) {
    global $wpdb;

    if (isset($wp_query->query['s']) && !empty($wp_query->query['meta_query'])) {
        $s_like = '%' . esc_sql($wpdb->esc_like($wp_query->query['s'])) . '%';
        $new_where = " AND ((({$wpdb->posts}.post_title LIKE '$s_like')
            OR ({$wpdb->posts}.post_excerpt LIKE '$s_like')
            OR ({$wpdb->posts}.post_content LIKE '$s_like'))
            OR " . substr($clauses['where'], strpos($clauses['where'], 'AND (') + 5);

        $clauses['where'] = $new_where;
    }

    return $clauses;
}

add_filter('posts_clauses', 'modify_wp_query_clauses', 10, 2);

if (isset($_GET['resume_search_keyword']) && $_GET['resume_search_keyword'] != '') {
    $resume_args['s'] = $_GET['resume_search_keyword'];
}

$resume_search_skills = array(
    'key' => '_resume_skills',
    'value' => $_GET['resume_search_keyword'],
    'compare' => 'LIKE'
);

$resume_search_job_duties = array(
    'key' => '_resume_job_duties',
    'value' => $_GET['resume_search_keyword'],
    'compare' => 'LIKE'
);

$resume_args['meta_query'] = array(
    'relation' => 'OR',
    $resume_search_job_duties,
    $resume_search_skills
);

$resumes = new WP_Query($resume_args);

Таким образом, с помощью фильтров WordPress можно гибко управлять формированием SQL-запросов и достичь нужного результата, используя "ИЛИ" между текстовым и мета-поиском.

Оцените материал
Добавить комментарий

Капча загружается...