web-dev-qa-db-ja.com

配列であるmeta_keyによるWP_User_Queryの順序

さまざまな数値を含む配列であるachievementsという名前のユーザーメタデータを設定しました。 WP_User_Queryを使用して、この配列内のpointsという名前の特定のキーでリストを並べたいと思います。

以下:

$args = array(
    'order' => 'DESC',
    'orderby' => 'meta_value_num',
    'meta_key' => 'achievements',
    'number' => $no,
    'offset' => $offset
);

... achievementsが数値の場合に機能します。メタデータキーpoints内のキーachievementsをターゲットとするように$args配列を変更するにはどうすればよいですか。

ユーザーに対してachievementsprint_r()を実行すると、次のように返されます。

Array ( [x1] => 74 [x2] => 383 [x3] => 457 [x4] => 81 [points] => 301 [x5] => 382 [x6] => 12 )
2

separate userメタキーで値を保存できます。

x1, ..., x6, points

配列の代わりに:

achievements

あなたのWP_User_Query()の使い方を簡単にし、直列化された配列をユーザーメタ値として扱う必要がないようにするため。

しかし、私はあなたがすでにこの設定を考えていて、それを避けたいと思ったと思います; - )

妥協は、pointsのみをachievements配列から別のメタキーに移動することです。

更新:

ユーザー数が比較的少ない場合は、次の(未テストの)PHP並べ替えを使用できます。

$users2points = array();

$args = array(
    'meta_key' => 'achievements',
    'number'   => $no,
    'offset'   => $offset
);

$users = get_users( $args );

foreach( (array) $users as $user )
{
    $meta = get_user_meta( 'achievements', $user->ID );
    if( isset( $meta['points'] )
        $users2points[$user->ID] = $meta['points'];
}

asort( $users2points, SORT_NUMERIC );

print_r( $users2points );

更新2:

$usersオブジェクトのWP_User配列に直接作用するもう1つの冒険PHP並べ替えがあります。

$args = array(
    'meta_key' => 'achievements',
    'number'   => $no,
    'offset'   => $offset
);

$users = get_users( $args );

foreach( (array) $users as $user )
{
    $meta = get_user_meta( 'achievements', $user->ID );

    // Here we assume the points values are greater or equal to 0:
    $user->points = ( isset( $meta['points'] ) ?  $meta['points'] : 0;
}

/*
usort( $users, function( $a, $b ) {
    return gmp_cmp( $a->points, $b->points );
});
*/

// The gmp_cmp() might suffer from a memory leak,
// according to some PHP bug reports,
// so let's use this instead:    

usort( $users, function( $a, $b ) {
    if( $a->points === $b->points )
        return 0;
    else
        return ( $a->points > $b->points ) ? 1 : -1;
});


print_r( $users );
2
birgire

SQLを使用してそれを行う方法は、シリアル化された値を取り出すためにSUBSTRLOCATEを使用することです。

function wpse162668_pre_user_query( $query ) {
    if ( ( $orderby = $query->get( 'orderby' ) ) != 'achievements_points' ) {
        return $query;
    }
    global $wpdb;

    $order = $query->get( 'order' );
    $points_str = 's:6:"points";i:';
    $query->query_fields .= $wpdb->prepare(
        ', SUBSTR(wp_usermeta.meta_value, LOCATE(%s, wp_usermeta.meta_value) + %d)+0 AS ' . $orderby,
        $points_str, strlen( $points_str )
    );
    $query->query_orderby = 'ORDER BY ' . $orderby . ' ' . $order . ', user_login ASC';

    return $query;
}

それから$argsorderby'orderby' => 'achievements_points'に変更し、get_usersをフィルターでラップします。

add_filter( 'pre_user_query', 'wpse162668_pre_user_query', 10, 2 );
$users = get_users( $args );
remove_filter( 'pre_user_query', 'wpse162668_pre_user_query', 10 );

整数へのキャスト(+0)は、動作します。MySQLは、末尾の非数値のものを無視します。 WPAlchemy_MetaBoxクラスを繰り返しグループと共に使用するため、このメソッドはさまざまな組み合わせで(postmetaではなく、usermetaでは)かなり使用しますが、非常に面倒です。

1
bonger