問題描述
我認為問題本質上與 sql 查詢結構有關,我不是專家….
我需要透過 2 個引數搜尋帖子 (自定義帖子型別):
-
pd_city
-
pd_country
請注意,meta_query 關係是’OR’,所以如果上述兩個之一都是有一些結果。
第三鍵 (is_sponsored) 用於排序帖子! “is_sponsored” 值等於 1 的帖子可以是 1 或 0,而頂部應列出。
所以這裡是 WordPress 的事情:
$sfp_query_args = array(
'sfp_complex_search' => 'yeap',
'tax_query' => array( array( 'taxonomy' => 'sfp_post_category', 'terms' => $term_id ) ),
//'meta_key' => 'is_sponsored',
'post_type' => 'sfpposts',
'post_status' => 'publish',
'showposts' => (int)$per_page,
'paged' => $paged,
'meta_query' => array( 'relation' => 'OR',
array( 'key' => 'pd_city', 'value' => $sfp_search_meta, 'compare' => 'LIKE' ),
array( 'key' => 'pd_country', 'value' => $sfp_search_meta, 'compare' => 'LIKE' ),
array( 'key' => 'is_sponsored' )
)
);
$sfp_search = new WP_Query( $sfp_query_args );
我也需要用”posts_orderby” 過濾結果,以獲得那些贊助到頂部:
add_filter( 'posts_orderby', 'sfp_modify_search' );
function sfp_modify_search( $orderby ) {
if( !is_admin() && is_page( $this->options[ 'sfp_page_entries_search' ] ) ) {
global $wpdb;
$orderby = " CASE WHEN mt2.meta_value = 0 THEN 1 END, $wpdb->posts.post_date DESC ";
}
return $orderby;
}
真正的問題依賴於這個查詢,返回來自”sfp_post_category” 的所有 POSTS,不僅是匹配”pd_city” 或”pd_country” 的所有 POSTS,因為所有 POSTS 都有”is_sponsored” 元鍵 (並且值設定為 1 或 0) 。再次:”is_sponsored” 需要排序!
當 var_dump
var_dump( $sfp_search->request );
… WordPress 的 sql 看起來像這樣:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id IN (77) )
AND wp_posts.post_type = 'sfpposts'
AND (wp_posts.post_status = 'publish')
AND ( (wp_postmeta.meta_key = 'pd_city'
AND CAST(wp_postmeta.meta_value AS CHAR)
LIKE '%something%')
OR (mt1.meta_key = 'pd_country'
AND CAST(mt1.meta_value AS CHAR)
LIKE '%something%')
OR mt2.meta_key = 'is_sponsored' )
GROUP BY wp_posts.ID
ORDER BY CASE WHEN mt2.meta_value = 0 THEN 1 END, wp_posts.post_date DESC
LIMIT 0, 10
如何從結果中刪除與”pd_city” 或”pd_country” 不匹配的所有帖子?
最佳解決方案
罪魁禍首
這個問題的罪魁禍首是不支援不同和/或巢狀關係的元查詢 – 順便說一下,這也使我以前堅持不了。在最近有一個搜尋場景的情況下。
您想要做的只是無法透過 WP_Query 以及一個迴圈單獨完成。如您所知,無論是將排序鍵放在 meta_query 陣列中還是將其作為一般查詢引數,都不會有所作為。如果您將元查詢關係設定為 OR,並在查詢 args 的任何位置指定 meta_key,而不設定附帶的 meta_value 引數,查詢將始終至少返回設定該 meta_key 的所有帖子。為方便起見,為了完整性:當使用具有!=的單個 meta_query 作為 meta_compare 的值時,查詢將返回所有結果,而 meta_key 設定不等於給定的 meta_value – 它不會返回任何沒有使用 meta_key 的帖子。元查詢失敗的另一點。
解決方案 1
我看到兩個選項。一方面,您可以從查詢中省略 is_sponsored 元金鑰,省略分頁,獲取正確的帖子,並使用 WP_Query 的第二個例項進行排序,並透過 post__in 引數傳遞過濾的帖子 ID:
$sfp_search_args = array(
'sfp_complex_search' => 'yeap',
'tax_query' => array( array( 'taxonomy' => 'sfp_post_category', 'terms' => $term_id ) ),
'post_type' => 'sfpposts',
'post_status' => 'publish',
'meta_query' => array(
'relation' => 'OR',
array( 'key' => 'pd_city', 'value' => $sfp_search_meta, 'compare' => 'LIKE' ),
array( 'key' => 'pd_country', 'value' => $sfp_search_meta, 'compare' => 'LIKE' )
)
);
$sfp_search = new WP_Query( $sfp_search_args );
$post_ids = array();
while ( $sfp_search->have_posts() ) : $sfp_search->next_post();
$post_ids[] = $sfp_search->post->ID;
endwhile;
$sfp_ordered_args(
'post__in' => $post_ids,
// note that 'showposts' is deprected
'posts_per_page' => (int)$per_page,
'paged' => $paged,
'meta_key' => 'is_sponsored',
'order' => 'DESC',
'orderby' => 'meta_value_num date'
);
$sfp_ordered = new WP_Query( $sfp_ordered_args );
while ( $sfp_ordered->have_posts() ) : $sfp_ordered->next_post();
// display posts
endwhile;
請注意,WP_Query 的 $orderby 引數將採用由空格分隔的多個值。您的搜尋修改可能比必要更復雜。
解決方案 2
由於我喜歡你的想法 var_dumping 查詢物件的 request 屬性,讓我開始一個快速的,並且,未經測試 – 備註的建議:
如果您透過將 OR mt2.meta_key = 'is_sponsored'的邏輯運運算元更改為 AND 稍微修改給定的 SQL,並相應地移動給定的 SQL,則可以使用 $wpdb 來拉動帖子:
$sfp_post_ids = $wpdb->get_col(
"
SELECT wp_posts.ID
FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
WHERE 1=1
AND ( wp_term_relationships.term_taxonomy_id = $term_id )
AND wp_posts.post_type = 'sfpposts'
AND (wp_posts.post_status = 'publish')
AND ( (wp_postmeta.meta_key = 'pd_city'
AND CAST(wp_postmeta.meta_value AS CHAR)
LIKE '%$sfp_search_meta%')
OR (mt1.meta_key = 'pd_country'
AND CAST(mt1.meta_value AS CHAR)
LIKE '%$sfp_search_meta%') )
AND mt2.meta_key = 'is_sponsored'
GROUP BY wp_posts.ID
ORDER BY CASE WHEN mt2.meta_value = 0 THEN 1 END, wp_posts.post_date DESC
"
);
此時,您還有兩個選擇:使用簡單的 foreach 對 $sfp_post_ids 陣列進行迭代,並在該迴圈中單獨使用 get_post()提取後置資料,或者,如果您想要 WP_Query 的優點 – 分頁,模板標籤等 – 將 $sfp_post_ids 進給到 post__in 引數,如解決方案 1 所示。
參考文獻
注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。