在自定义查询中按元键值对WP_QUERY结果进行排序

时间:2017-04-16 作者:Gavin

我有一个用于根据默认WordPress字段和元值搜索项目的查询。我想根据名为project_date, 这是一个时间戳。这是我到目前为止使用的SQL。

SELECT wp_posts.* FROM wp_posts
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.id = mt1.post_id)
WHERE 1 = 1
AND ((wp_posts.post_title LIKE \'%testingsearch%\') OR (mt1.meta_key = \'description\' AND mt1.meta_value LIKE \'%testingsearch%\')))
AND wp_posts.post_type = \'project\'
AND ((wp_posts.post_status = \'publish\'))
GROUP BY wp_posts.id
我不知道如何包含元字段project_dateORDER BY. 很明显,这样的事情是行不通的,因为你不能使用WHEREORDER BY 细分市场:

ORDER BY mt1.meta_value WHERE mt1.meta_key = \'project_date\' DESC
如何按此meta\\u键排序?

1 个回复
SO网友:Paul \'Sparrow Hawk\' Biron

如前所述,您的问题与主题无关,因为它完全与SQL相关。

然而,以下两种解决方案将其转化为WP ese。

解决方案1

$args = array (
    \'post_type\' => \'project\',
    \'post_status\' => \'publish\',
    \'s\' => \'testingsearch\',
    \'meta_query\' => array (
        \'relation\' => \'OR\',
        \'project_date\' => array (
            \'key\' => \'project_date\',
            \'compare\' => \'EXISTS\',
            ),
        array (
            \'key\' => \'description\',
            \'value\' => \'testingsearch\',
            \'compare\' => \'LIKE\',
            ),
        ),
    \'orderby\' => \'project_date\',
    \'order\' => \'DESC\',
    ) ;

$p = new WP_Query ($args) ;
此解决方案利用Query improvements in WP 4.2: ‘orderby’ and ‘meta_query’.

然而,它执行的查询比您的问题中的查询更加混乱。特别是,它搜索post_contentpost_excerpt 除了post_title.

如果针对您的用例搜索这些附加字段是可以的,那么您就完成了。如果没有,请参阅解决方案2。

SQL Produced

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM
    wp_posts 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 )
WHERE 1=1 AND
    ((
        (wp_posts.post_title LIKE \'%testingsearch%\') OR
        (wp_posts.post_excerpt LIKE \'%testingsearch%\') OR
        (wp_posts.post_content LIKE \'%testingsearch%\')
     )) AND
    ( 
        wp_postmeta.meta_key = \'project_date\' 
        OR 
        ( mt1.meta_key = \'description\' AND mt1.meta_value LIKE \'%testingsearch%\' )
    ) AND
    wp_posts.post_type = \'project\' AND
    ((wp_posts.post_status = \'publish\'))
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value DESC
LIMIT 0, 10
溶液2
add_filter (\'posts_where\', \'wpse_posts_where\', 10, 2) ;

function
wpse_posts_where ($where, $query)
{
    global $wpdb ;
    if ($search = $query->get (\'_title_only\')) {
        $search = \'%\' . $wpdb->esc_like ($search) . \'%\' ;
        $where .= $wpdb->prepare (" AND {$wpdb->posts}.post_title LIKE \'%s\'", $search) ;
        }

    return ($where) ;
}

$args = array (
    \'post_type\' => \'project\',
    \'post_status\' => \'publish\',
    // the "private" _title_only arg is "trapped" by the function above that is
    // hooked into \'posts_where\' to limit the search to only post_title
    \'_title_only\' => \'testingsearch\',
    \'meta_query\' => array (
        \'relation\' => \'OR\',
        \'project_date\' => array (
            \'key\' => \'project_date\',
            \'compare\' => \'EXISTS\',
            ),
        array (
            \'key\' => \'description\',
            \'value\' => \'testingsearch\',
            \'compare\' => \'LIKE\',
            ),
        ),
    \'orderby\' => \'project_date\',
    \'order\' => \'DESC\',
    ) ;

$p = new WP_Query ($args) ;
就post\\u meta的排序而言,此解决方案与解决方案1的工作方式类似,但与posts_where 将搜索限制为post_title.

注意使用wpdb::esc_like()wpdb::prepare() 在连接到的func中posts_where 防止SQL注入攻击。

SQL Produced

SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM
    wp_posts 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 )
WHERE 1=1 AND
    ( 
        wp_postmeta.meta_key = \'project_date\' 
        OR 
        ( mt1.meta_key = \'description\' AND mt1.meta_value LIKE \'%testingsearch%\' )
    ) AND
    wp_posts.post_type = \'project\' AND
    ((wp_posts.post_status = \'publish\')) AND
    wp_posts.post_title LIKE \'%testingsearch%\'
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value DESC
LIMIT 0, 10