Вопрос или проблема
Мне нужно создать “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 и модифицировать запрос вручную:
-
Использование фильтра
posts_clauses
:
Этот фильтр позволяет модифицировать различные части SQL-запроса, в том числе и условие WHERE. -
Реализация кастомного улучшения:
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-запросов и достичь нужного результата, используя "ИЛИ" между текстовым и мета-поиском.