web-dev-qa-db-ja.com

Posts_where/posts_joinを使って自分自身の入れ子になったmeta_queryを作成するにはどうすればいいですか?

私の投稿の一部(全部ではありません)はメタキー/値としての価格を持っています。今日、私はpre_get_postsアクションを使用して、ユーザーが特定の値の範囲内にある価格を検索できるようにします。

これは私が今日使用しているコードです、そしてそれは働いています。

add_action('pre_get_posts', 'my_search_price');
function my_search_price( $query ) {
    if ($query->get('maxprice') != "" && $query->get('minprice') != "" && $query->is_main_query()) {

        $maxprice = intval($query->get('maxprice'));
        $minprice = intval($query->get('minprice'));

        $meta = array();
        $meta[] = 
        array (
            'key' => 'price',
            'value' => $maxprice,
            'compare' => '<=',
            'type' => 'numeric'
        );

        $meta[] = 
        array (
            'key' => 'price',
            'value' => $minprice,
            'compare' => '>=',
            'type' => 'numeric'
        );

        $meta[] = 
        array (
            'key' => 'price_updated',
            'value' => time()-(60*60*24*14),
            'compare' => '>',
            'type' => 'numeric'
        );

        $query->set('meta_query', $meta);
    }
}

私の問題は、投稿の中には2番目の値段を持つものもあり、これもメタキー/値として格納されています。新しい価格の名前は "price_used"で、この価格には "price_used_updated"という名前の独自の更新されたキー/値があります。

新しい価格も処理できるように、関数my_search_price()を変更したいと思います。結果は、 "price" OR "price_used"がminpriceとmaxpriceの間にある投稿になります。 "price_updated"/"price_used_updated"は最長14日でなければなりません。

他の記事を読んで理解したように、meta_queryはネストできません。だから私は代わりにposts_joinまたは/そしてposts_whereフィルタを使ってSQLを修正する必要があります。

誰かが解決策への正しい方向を教えてください。私はもっ​​と高度なmeta_queryが必要な最初の人ではないと思います。しかし、私は以前にSQLクエリを修正したことがありません。

私がしたことはこれらのページを読むことです:

更新:結果クエリは次のようになります。

SELECT SQL_CALC_FOUND_ROWS wp_posts.*, mtGP2.meta_value, mtAM2.meta_value
FROM wp_posts

INNER JOIN wp_postmeta AS mtGP1 ON (wp_posts.ID = mtGP1.post_id)
INNER JOIN wp_postmeta AS mtGP2 ON (wp_posts.ID = mtGP2.post_id)

INNER JOIN wp_postmeta AS mtAM1 ON (wp_posts.ID = mtAM1.post_id)
INNER JOIN wp_postmeta AS mtAM2 ON (wp_posts.ID = mtAM2.post_id)

WHERE 1=1

AND wp_posts.post_type = 'post'
AND wp_posts.post_status = 'publish'

AND
(
(mtGP1.meta_key = 'price' AND CAST(mtGP1.meta_value AS SIGNED) BETWEEN 1 AND 10
AND mtGP2.meta_key = 'price_updated' AND CAST(mtGP2.meta_value AS SIGNED) > NOW()-60*60*24*14)
OR
(mtAM1.meta_key = 'price_used' AND CAST(mtAM1.meta_value AS SIGNED) BETWEEN 1 AND 10
AND mtAM2.meta_key = 'price_used_updated' AND CAST(mtAM2.meta_value AS SIGNED) > NOW()-60*60*24*14)
)
GROUP BY wp_posts.ID

しかし、このクエリには2つの問題があります。

1)とても遅い

2)私はまだ問題を抱えています、なぜなら私はどのようにしてwordpressで問い合わせを実行するのかわからないからです。私はpost_whereとposts_joinフィルタを使う必要があると思いますが、その方法がわからない。

UPDATE2。私はそれがもはや遅くないようにクエリを書き直しました。しかし、私はまだ(私のオリジナルのmy_search_price()関数のように)フィルタやアクションを使ってwordpressでクエリを実装する方法を知りません。

SELECT SQL_CALC_FOUND_ROWS *
  FROM
(
SELECT wp_posts.*
FROM wp_posts
INNER JOIN wp_postmeta AS mtGP1 ON (wp_posts.ID = mtGP1.post_id)
INNER JOIN wp_postmeta AS mtGP2 ON (wp_posts.ID = mtGP2.post_id)
WHERE 1=1
AND wp_posts.post_type = 'post'
AND wp_posts.post_status = 'publish'
AND mtGP1.meta_key = 'price'
AND CAST(mtGP1.meta_value AS SIGNED) BETWEEN 1 AND 10
AND mtGP2.meta_key = 'app_updated'
AND CAST(mtGP2.meta_value AS SIGNED) > UNIX_TIMESTAMP()-60*60*24*14
GROUP BY wp_posts.ID

UNION

SELECT wp_posts.*
FROM wp_posts
INNER JOIN wp_postmeta AS mtGP1 ON (wp_posts.ID = mtGP1.post_id)
INNER JOIN wp_postmeta AS mtGP2 ON (wp_posts.ID = mtGP2.post_id)
WHERE 1=1
AND wp_posts.post_type = 'post'
AND wp_posts.post_status = 'publish'
AND mtGP1.meta_key = 'price_used'
AND CAST(mtGP1.meta_value AS SIGNED) BETWEEN 1 AND 10
AND mtGP2.meta_key = 'price_used_updated'
AND CAST(mtGP2.meta_value AS SIGNED) > UNIX_TIMESTAMP()-60*60*24*14
GROUP BY wp_posts.ID
) AS t
2
PappApp

UNIONWP_Queryで動作させる方法を概説します。

add_filter(
  'posts_request',
  function ($clauses) {

    $clauses = str_replace('SQL_CALC_FOUND_ROWS','',$clauses,$scfr);

    $scfr = (0 < $scfr) : 'SQL_CALC_FOUND_ROWS' : '';

    $clause2 = $clauses; // manipulate this

    return "SELECT {$scfr} u.* FROM (({$clauses}) UNION ({$clause2})) as u";
  },
  1,
  2
);

WP_Query引数を設定してUNIONの前半を生成し、それからそれを操作してクエリ全体を作成します。このようなものは近いはずです。

add_action('pre_get_posts', 'my_search_price');
function my_search_price( $query ) {
    if ($query->get('maxprice') != "" && $query->get('minprice') != "" && $query->is_main_query()) {

        $maxprice = intval($query->get('maxprice'));
        $minprice = intval($query->get('minprice'));

        $meta = array();

        $meta[] =
          array (
              'key' => 'price',
              'value' => array($maxprice,$minprice),
              'compare' => 'between',
          );

        $meta[] = 
          array (
              'key' => 'app_updated',
              'value' => time()-(60*60*24*14),
              'compare' => '>',
              'type' => 'numeric'
          );

        $query->set('meta_query', $meta);
    }
}

add_filter(
  'posts_request',
  function ($clauses) {

    $clauses = str_replace('SQL_CALC_FOUND_ROWS','',$clauses,$scfr);

    $scfr = (0 < $scfr) ? 'SQL_CALC_FOUND_ROWS' : '';

    $clause2 = str_replace('price','price_used',$clauses); // manipulate this
    $clause2 = str_replace('app_updated','price_used_updated',$clauses);

    return "SELECT {$scfr} u.* FROM (({$clauses}) UNION ({$clause2})) as u";
  },
  1,
  2
);

望まないときに実行されないように、post_requestsフィルタにロジックを追加する必要があります。

2
s_ha_dum