問題描述

我認為問題本質上與 sql 查詢結構有關,我不是專家….

我需要通過 2 個參數搜索帖子 (自定義帖子類型):

  1. pd_city

  2. 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。