私は2つの投稿タイプがあります:products
とproduct_variations
と言いましょう。 pre_get_posts
でクエリを変更して、すべてのproductをmeta_keys "_visible" = "true"
および"_available" = "true"
に、そしてすべてのproduct_variationsをmeta_key "_featured" = "true"
にすることができます。
Product_variationsはmeta_keys "_visible"/"_available"
を持っていません、そしてその逆も同様です、それでまっすぐにAND
meta_queryは結果を返しません。 2つのフィールドが一方の投稿タイプに対してOR
関連し、もう一方の投稿タイプに対してAND
関連しているため、OR
関連はまったく正しくありません。
これを少しだけ視覚的にするために、書き出すのがどれほど複雑かを実感しました。
**product**
_visible = true
_available = true
**product_variation**
_featured = true
これはクエリ引数で可能ですか。
これはposts_where
を通じて可能ですか?
別のクエリを実行してから、どういうわけか結果をマージする必要がありますか?
これはクエリ引数で可能ですか。
私はそうは思わない。
これは
'posts_where'
を通じて可能ですか?
おそらく'posts_*'
だけでなくsome'posts_where'
フィルタを使っても可能です。あるいは、 'posts_request'
filterを使用してクエリを完全にオーバーライドすることもできます。
別のクエリを実行してから結果を何らかの方法でマージする必要がありますか。
それが最も単純な選択であり、最もカスタマイズが容易なもの、例えば製品に対する制限および製品のバリエーションに対する異なる制限を使用することが容易であろう。
さらに、後者が非常に複雑である場合、常に2つのクエリが単一のクエリより遅くなるわけではないため、このアプローチは必ずしもパフォーマンス面で最悪ではありません。
4番目の方法は、完全にカスタムのSQLを作成することです。トリックをするかもしれない(漠然とテストされた)クエリは以下の通りです:
$products_and_variations = $wpdb->get_results("
SELECT * FROM (
SELECT products.* FROM {$wpdb->posts} products
LEFT JOIN {$wpdb->postmeta} meta1 ON meta1.post_id = products.ID
LEFT JOIN {$wpdb->postmeta} meta2 ON meta2.post_id = products.ID
WHERE products.post_type = 'product'
AND products.post_status = 'publish'
AND (meta1.meta_key = '_visible' AND meta1.meta_value = '1')
AND (meta2.meta_key = '_available' AND meta2.meta_value = '1')
GROUP BY products.ID
UNION
SELECT variations.* FROM {$wpdb->posts} variations
LEFT JOIN {$wpdb->postmeta} meta3 ON meta3.post_id = variations.ID
WHERE variations.post_type = 'product_variation'
AND variations.post_status = 'publish'
AND (meta3.meta_key = '_featured' AND meta3.meta_value = '1')
GROUP BY variations.ID
)
posts
ORDER BY post_date DESC
LIMIT 0, 100
");
あなたは気づくことができます:
このようなものを使用する前に、2つのクエリによるアプローチと比較してパフォーマンスをテストし、パフォーマンスが大幅に向上した場合にのみカスタムクエリを使用します。
これはpre_get_posts
を使った別のアプローチです。
要件に応じて各投稿タイプの all /投稿IDを取得するには、get_posts()
(x2クエリ)を使用します。 fields
パラメータ('fields' => 'ids'
)をクエリの引数に追加して、ポストIDを取得するだけです。これによりパフォーマンスが大幅に向上し、リソースの面でそれほど難しくありません。だから、あなたは2つのポストIDの配列になってしまうでしょう
2つの配列をarray_merge()
とマージして、すべてのポストIDを保持する「スーパー」配列を作成する必要があります。
あなたはこれを一時的なものに保存し、投稿が更新されたとき、一時的な状態を消去するとき、一時的な状態をフラッシュするとき、または投稿されていないときに公開します。これはあなたのサイトのパフォーマンスを構成しないことを保証します。
あなたのニーズに合ったIDの配列ができたので、post__in
のpost_idの配列をpre_get_posts
に渡すことができます。
例(、これは単なる例示にすぎないのでテストしていません。残念ながら、適切なコーディングのための時間はありません)
function get_all_special_posts()
{
/*
* This is here were you would want to introduce your transient
*/
$args1 = [
'post_type' => 'post_type_1',
'fields' => 'ids',
'nopaging' => true,
'meta_query' => [[ /*Your specific custom fields */ ]]
];
$query1 = get_posts( $args1 );
$args2 = [
'post_type' => 'post_type_2',
'fields' => 'ids',
'nopaging' => true,
'meta_query' => [[ /*Your specific custom fields */ ]]
];
$query2 = get_posts( $args2 );
$post_ids = array_merge( $query1, $query2 );
/*
* Set your transient here, you would want to store $post_ids in the transient
*/
return $post_ids;
}
ポストパブリッシュ、ゴミ箱、ゴミ捨て、更新時に一時的なものをフラッシュする関数を忘れずに作成してください。これについてはtransition_post_status
を見てください。非常に用途の広いフック2つの希望する投稿タイプのみをターゲットにするには、$post->post_type
を使用してください
add_action( 'pre_get_posts', function ( $q )
{
if ( !is_admin() && $q->is_main_query() && $q->is_home() ) {
$q->set( 'post__in', get_all_special_posts() );
}
});
念のために、私は最初にget_all_special_posts()
が実際に有効な配列を持っているかどうか、そしてそれがpost__in
に渡される前にそれが空でないかどうかをチェックします