是否根据用户定义的元值顺序对帖子进行排序?

时间:2015-09-30 作者:Rutwick Gangurde

我已经设置了一些CPT,并为每个CPT存储了一个元键/val。当我收到这些帖子时,我需要按元值排序,但是,the order of the meta values will be defined in an array by me. 这个default ordering for meta values is either alphabetical or numerical, 这是我不想要的。

我将用一个例子来解释:

Post 1 =>
Meta key: Fruit
Meta value: Apple

Post 2 =>
Meta key: Fruit
Meta value: Melon

Post 3 =>
Meta key: Fruit
Meta value: Guava

Post 4 =>
Meta key: Fruit
Meta value: Banana
我从外部来源获得订单,我想按此顺序获得帖子。示例:我在数组中获得一个订单:[\'Apple\', \'Banana\', \'Guava\', \'Melon\']. 当我取CPT时,我需要按此顺序取。(忽略字母顺序,我只是想给出一个一般的例子)。

如何使用meta_query 或其他解决方案?

如果存在现有线程,请将我重定向到它。

3 个回复
SO网友:birgire

我提出的解决方案已经由@cybmeta(+1)发布,但我还是添加了它,因为它以一般方式处理;-)

以同样的方式WP_Query 参数:

\'post__in\' => [1,2,3],
\'orderby\' => \'post__in\'
使用自定义的顺序:

ORDERBY FIELD( wp_posts.ID, 1, 2, 3 )
我们可以使用以下方法定义自己的元排序:

\'meta__in\' => [ \'apple\', \'orange\', \'banana\' ],
\'orderby\' => \'meta__in\'
要获取以下SQL部件:

ORDERBY FIELD( wp_postmeta.meta_value, \'apple\', \'orange\', \'banana\' )
首先,我们定义自己版本的wp_parse_id_list() 助手函数。

/**
* Note that this function is based on the core wp_parse_id_list() function.
* Clean up an array, comma- or space-separated list of string keys.
*
* @uses sanitize_key()
* @param array|string $list List of keys.
* @return array Sanitized array of keys.
*/
function wpse_parse_meta_list( $list )
{
    if ( ! is_array( $list ) )
        $list = preg_split(\'/[\\s,]+/\', $list);

    return array_unique( array_map( \'sanitize_key\', $list ) );
}   
然后我们构建以下演示插件,以添加对\'meta__in\' 订购,英寸WP_Query:

<?php
/**
 * Plugin Name: Support for order by meta__in in WP_Query
 */

add_filter( \'posts_orderby\', function ( $orderby, \\WP_Query $q )
{
    if( $meta__in = $q->get( \'meta__in\' ) )
    {
        if( is_array( $meta__in ) && ! empty( $meta__in ) )
        {
            global $wpdb;   

            // Transform the meta__in array into a comma separated strings of keys
            // Example [ \'apple\', \'banana\' ] --> "apple", "banana"
            $list = \'"\' . join( \'","\', wpse_parse_meta_list( $meta__in ) ) . \'"\';           

            // Override the orderby part with custom ordering:
            $orderby = " FIELD( {$wpdb->postmeta}.meta_value, {$list} ) ";
        }
    }
    return $orderby;
}, 10, 2 );

/**
 * Note that this function is based on the core wp_parse_id_list() function.
 * Clean up an array, comma- or space-separated list of string keys.
 *
 * @uses sanitize_key()
 * @param array|string $list List of keys.
 * @return array Sanitized array of keys.
 */
function wpse_parse_meta_list( $list )
{
    if ( ! is_array( $list ) )
        $list = preg_split(\'/[\\s,]+/\', $list);

    return array_unique( array_map( \'sanitize_key\', $list ) );
}   
我们在插件中添加了helper函数。

注意:我们只使用\'meta__in\' 用于订购而非额外订购的参数WHERE 限制,就像我们对\'post__in\' 参数但这可能是一个有趣的扩展;-)

还要注意的是get_posts(), 那只是一个WP_Query wrapper默认设置了以下参数:

\'suppress_filters\' => true 
即不接受posts_* 默认情况下过滤。

所以如果你不能使用WP_Queryget_posts() 使用suppress_filters => false, 那么您需要一种替代方法,例如@PieterGoosen建议的方法。

SO网友:cybmeta

如果元字段的值是单个值(未序列化),则此筛选器可以工作:

add_filter( \'posts_orderby\', \'custom_posts_orderby\' );
function custom_posts_orderby( $orderby_statement ) {

    $custom_order = array( \'Apple\', \'Banana\', \'Guava\', \'Melon\' );

    $custom_order = implode ( ", ", $custom_order );

    $orderby_statement = "FIELD( meta_value, " . $custom_order . " )";

    return $orderby_statement;

}
请注意,这将影响所有查询,因此您需要定义是否应用筛选器的条件。

您可以看到更多示例来构建ORDER BY FIELD() statemnet输入this post.

SO网友:Pieter Goosen

正如我所说的,IMHO,对于你所需要的,你最好的选择是usort() 对返回的帖子数组进行排序

这是一个未经检验的理论

$sortorder = [\'Apple\', \'Banana\', \'Guava\', \'Melon\'];
$args = [
    \'meta_query\' => [
        [
            \'key\'   => \'Fruit\',
            \'value\' => $sortorder
        ]
    ],
];
$q = new WP_Query( $args );

@usort( $q->posts, function( $a, $b ) use ( $sortorder  ) {
    // Get the meta values from the two posts to be compared
    $array_a = get_post_meta( $a->ID, \'Fruit\', true );
    $array_b = get_post_meta( $b->ID, \'Fruit\', true );

    // Reverse our $sortorder, key/value becomes value/key
    $flipped_order = array_flip( $sortorder );

    // Let start our sorting
    // If our meta values are the same order by date
    if ( $flipped_order[$array_a] != $flipped_order[$array_b] ) {
        return $flipped_order[$array_a] - $flipped_order[$array_b] // Swop around to reverse ordering
    } else {
        return $a->post_date < $b->post_date; // Change to > if you need oldest posts first
    }
});

// Run your loop normally
编辑我的代码没有带来任何安全性。你应该确保$sortorder 是有效数组,则需要在使用这些值之前对其进行清理和验证,以避免恶意代码。

您也可以对主查询执行此操作,唯一的问题是您希望包装usort() 中的函数the_posts 过滤然后使用$posts 代替$q->posts

相关推荐

列出分类法:如果分类法没有POST,就不要列出分类法--取决于定制的POST-META?

这可能很难解释,我不知道是否有解决办法!?我有一个名为“wr\\u event”的自定义帖子类型和一个名为“event\\u type”的分层自定义分类法。自定义帖子类型有一个元框,用于event_date 并且与此帖子类型关联的所有帖子都按以下方式排序event_date. 我在循环中有一个特殊的条件来查询event_date 已经发生了-在这种情况下,它没有显示,但只列在我的档案中。就像你可以使用wp_list_categories() 我编写了一个自定义函数,它以完全相同的方式列出所有分类术语。现在