私はいくつかのCPTを設定し、それぞれにメタキー/ valを保存しました。これらの投稿を取得するときは、メタ値で並べ替える必要がありますが、メタ値の順序は自分で配列に定義されます 。メタ値のデフォルトの順序はアルファベット順または数値順のいずれかですが、これは望ましくありません。
例で説明します。
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
または他の解決策を使用してそれを達成するにはどうすればよいですか?
既存のスレッドがある場合は、それを私にリダイレクトしてください。
私の提案した解決策はすでに@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 ) );
}
ここで、プラグインにヘルパー関数を追加しました。
'meta__in'
パラメータの場合のように、'post__in'
パラメータは順序付けにのみ使用され、追加のWHERE
制限には使用されません。しかし、それは面白い拡張かもしれません;-)
また、get_posts()
は単なるWP_Query
ラッパーであり、デフォルトで次のパラメータが設定されています。
'suppress_filters' => true
つまり、デフォルトではposts_*
フィルタを受け付けません。
WP_Query
と一緒にsuppress_filters => false
やget_posts()
を使うことができないのであれば、代わりのアプローチが必要です。 @PieterGoosenが提案しました。
メタフィールドの値が単一値(直列化されていない)の場合、このフィルタは機能します。
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を構築するためのより多くの例をこの投稿 で見ることができます 。
私が言ったように、私見、あなたが必要とするもののためのあなたの最善の選択肢は投稿の返された配列をソートするための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
を使用することです。