質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

Q&A

解決済

1回答

2064閲覧

WP_Queryでカンマが入った数値のカスタムフィールドをカンマなしでソートしたい

nekora

総合スコア501

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

0グッド

0クリップ

投稿2020/10/08 07:58

編集2020/10/19 05:42

いつもお世話になっております。最近wordpressもphpも皆様のおかげでだいぶ慣れたきました。

今回、お知恵を拝借したいのは、要約した箇条書きにすると以下のようになります。

  1. 顧客のサーバーにカスタム投稿タイプで商品が登録されている
  2. その商品にはカスタムフィールドに値段が設定されているが、他の処理で必要なためカンマ区切りの金額になっている
  3. WP_Queryで値段でソートして全件取得したところ、カンマ前までの数値でソートされており、12,200 12,800 12,300のように値段順にきちんとソートされない
  4. 商品数が多いのと他の処理ではカンマが必要なためデータの変更は出来ない
  5. どうにかしてカンマが入ってても12,200 12,300 12,800のようにソートしたい

追記3 ついに成功・解決したコードと方法論

いただいたアドバイスとグーグル先生に聞きまくってついに希望通りの結果が得られましたので記載します。

クエリーを投げてる部分、このままでは値段順に並ばない。

php

1$args = array( 2 'post_type' => 'product', // 取得する投稿タイプのスラッグ, 3 'posts_per_page' => 18, 4 'paged' => $paged, 5 'orderby' => 'meta_value_num', 6 'order' => 'DESC', 7 'meta_key' => '値段', 8 'post_status' => 'publish', 9 ); 10 $wp_query = new WP_Query( $args ); 11

アドバイスをいただいてposts_requestをフックしてSQLを書き換えるコード

php

1add_filter('posts_request', function ($query) { 2 global $template; 3 4 if( basename($template) != "search.php" ) { 5 return $query; 6 } 7 8 //echo "<br>" . $query . "<br>"; 9 10 $pos3 = mb_strrpos( $query, "L" ); 11 $queryLimit = mb_substr( $query, $pos3 ); 12 13 //echo "<br>" . $queryLimit . "<br>"; 14 15 //echo "<br>" . "enter overwite query" . "<br>"; 16 $query = 17 " 18 SELECT SQL_CALC_FOUND_ROWS wp_posts.* 19 FROM wp_posts 20 INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) 21 INNER JOIN ( 22 SELECT meta_id, post_id, meta_key, CAST(REPLACE(meta_value,',','') AS DECIMAL) AS meta_value_no_comma 23 FROM wp_postmeta 24 WHERE wp_postmeta.meta_key = '値段' 25 ORDER BY `meta_value_no_comma` DESC ) AS wp_postmeta2 ON ( wp_posts.ID = wp_postmeta2.post_id) 26 WHERE 1=1 AND ( wp_postmeta.meta_key = '値段' ) AND wp_posts.post_type = 'product' AND ((wp_posts.post_status = 'publish')) 27 GROUP BY wp_posts.ID 28 ORDER BY `meta_value_no_comma` DESC " . $queryLimit; 29 30 //echo "<br>" . $query . "<br>"; 31 32 return $query; 33});

これで思い通りの結果を得られました。キモとなったのは別名に対して ` バッククオートで囲めば別名で使用できるということでした。

sql

1SELECT SQL_CALC_FOUND_ROWS wp_posts.* 2FROM wp_posts 3INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) 4INNER JOIN ( SELECT meta_id, post_id, meta_key, CAST(REPLACE(meta_value,',','') AS DECIMAL) AS meta_value_no_comma 5 FROM wp_postmeta 6 WHERE wp_postmeta.meta_key = '値段' 7 ORDER BY `meta_value_no_comma` DESC ) AS wp_postmeta2 8 ON ( wp_posts.ID = wp_postmeta2.post_id) 9WHERE 1=1 AND ( wp_postmeta.meta_key = '値段' ) 10AND wp_posts.post_type = 'product' 11AND ((wp_posts.post_status = 'publish')) 12GROUP BY wp_posts.ID 13ORDER BY `meta_value_no_comma` DESC 14LIMIT 0, 18 15```参考になったリンクも記載しておきます 16 17[MySQL の ORDER BY 句でカラムの別名が使えない](https://techblog.recochoku.jp/2723) 18 19[MySqlのデベロッパーページの別名の使用方法](https://dev.mysql.com/doc/refman/5.6/ja/problems-with-alias.html) 20 21--- 22 23### 追記2 さらにアドバイスをいただいて試したこと 24KazuhiroHatano様がしきりにJOINして別名とおっしゃていたのが何となく引っかかっていて、progateではwhereにしかサブクエリを書くものがなかったので 25whereにしか書けないのかと、思い込んでいましたが、再度のアドバイスでも同じことをおっしゃってらしたので、 26もしや・・・と思い。グーグルで```SQL JOIN サブクエリ```で検索かけたらHITして**JOINでも使えるじゃん!**と分かり。 27**SQLを書き直しました。が、しかし、今度は別のエラーメッセージが表示されるようになりました。** 28 29再度書き直したSQL 30```SQL 31SELECT SQL_CALC_FOUND_ROWS wp_posts.* 32FROM wp_posts 33INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) 34INNER JOIN ( 35 SELECT post_id, meta_key, CAST(REPLACE(meta_value,',','') AS DECIMAL) 36 FROM wp_postmeta 37 WHERE 1=1 AND ( wp_postmeta.meta_key = '値段' ) AND wp_posts.post_type = 'product' AND ((wp_posts.post_status = 'publish')) 38 ) AS wp_postmeta2 39WHERE 1=1 AND ( wp_postmeta.meta_key = '値段' ) AND wp_posts.post_type = 'product' AND ((wp_posts.post_status = 'publish')) 40GROUP BY wp_posts.ID 41ORDER BY wp_postmeta2.meta_value+0 DESC LIMIT 0, 18" 42

新たに出てきたエラーメッセージはこちらです。

Unknown column 'wp_posts.post_type' in 'where clause'

申し訳ありませんが、再度アドバイスをいただけたら幸いです。

追記 アドバイスをいただいてから試したこと

function.phpに以下の記述を追加

php

1add_filter('posts_request', function ($query) { 2 global $template; 3 $original_sql = "SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( wp_postmeta.meta_key = '値段' ) AND wp_posts.post_type = 'product' AND ((wp_posts.post_status = 'publish')) GROUP BY wp_posts.ID ORDER BY wp_postmeta.meta_value+0 DESC LIMIT 0, 18"; 4 5 if( basename($template) != "search.php" ) { 6 return $query; 7 } 8 9 echo "<br>" . $query . "<br>"; 10 11 $pos1 = mb_strrpos( $query, "L" ); 12 $original_sql = mb_substr( $original_sql, 0, $pos1-6 ); 13 14 $pos2 = mb_strrpos( $query, "L" ); 15 $queryLimit = mb_substr( $query, $pos2 ); 16 17 $query = mb_substr( $query, 0, $pos2 ); 18 19 echo "<br>" . str_replace(PHP_EOL, '', str_replace(' ', '', $original_sql)) . "<br>"; 20 echo "<br>" . str_replace(PHP_EOL, '', str_replace(' ', '', $query)) . "<br>"; 21 22 echo "<br>" . $queryLimit . "<br>"; 23 24 if (str_replace(PHP_EOL, '', str_replace(' ', '', $original_sql)) == str_replace(PHP_EOL, '', str_replace(' ', '', $query))) { 25 26 echo "<br>" . "enter overwite query" . "<br>"; 27 $query = 28 " 29 SELECT SQL_CALC_FOUND_ROWS wp_posts.*, wp_postmeta.non_comma_value   30 FROM wp_posts 31 INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) 32 WHERE 1=1 AND ( wp_postmeta.meta_key = '値段' ) AND wp_posts.post_type = 'product' AND ((wp_posts.post_status = 'publish')) AND ( 33 SELECT *, CAST(REPLACE(meta_value,',','') AS DECIMAL) AS non_comma_value 34 FROM wp_postmeta 35 WHERE wp_posts.ID = wp_postmeta.post_id 36 ) 37 GROUP BY wp_posts.ID 38 ORDER BY non_comma_value+0 DESC 39 " . $queryLimit; 40 } 41 42 echo "<br>" . $query . "<br>"; 43 44 return $query; 45}); 46

上記のコードで変更前のSQLをDUMPしたものが下記で

SQL

1SELECT SQL_CALC_FOUND_ROWS wp_posts.* 2 FROM wp_posts 3 INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( wp_postmeta.meta_key = '値段' ) AND wp_posts.post_type = 'product' AND ((wp_posts.post_status = 'publish')) 4 GROUP BY wp_posts.ID 5 ORDER BY wp_postmeta.meta_value+0 DESC 6 LIMIT 0, 18

私のコードで修正したSQLが以下になります。

SQL

1SELECT SQL_CALC_FOUND_ROWS wp_posts.*, wp_postmeta.non_comma_value 2 FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( wp_postmeta.meta_key = '値段' ) 3 AND wp_posts.post_type = 'product' 4 AND ((wp_posts.post_status = 'publish')) 5 AND ( SELECT *, CAST(REPLACE(meta_value,',','') AS DECIMAL) AS non_comma_value 6 FROM wp_postmeta WHERE wp_posts.ID = wp_postmeta.post_id ) 7 GROUP BY wp_posts.ID 8 ORDER BY non_comma_value+0 DESC 9 LIMIT 0, 18

が、このSQLを実行する前にSQL構文チェッカーで問題なしと出たので、実行してみたところ以下のエラーメッセージが出て
ここからどこをどうやって直せばいいのか分かりません。

Unknown column 'wp_postmeta.non_comma_value' in 'field list'

直すべきところをアドバイスいただけたら幸いですm(_ _)m

やったこと、試したこと

・まずカスタムフィールドでソートする方法が判らず、検索条件を変えて色々グーグル先生に教わって
やっと、なんとかカスタムフィールドで値段順にソートできるようになった。
・しかし詳細を見てみると上記の通り正しくソートされていないことが判明
・custom_WP_Queryみたいなのを作って対応できないかグーグル先生に2時間聞いてみたが、答えが見つからなかった。
・再度、検索条件を変えてグーグル先生に質問すること2時間。解決策がHITせず、こちらに来たしだいです

以下が検索に使っているコードです。これをどうすれば思い通りの結果が得られるか、お知恵を貸していただけませんでしょうか。

php

1<?php 2 $args = array( 3 'post_type' => 'product', // 取得する投稿タイプのスラッグ, 4 'posts_per_page' => 18, 5 'paged' => $paged, 6 'orderby' => 'meta_value_num', 7 'order' => 'DESC', 8 'meta_key' => '値段', 9 'post_status' => 'publish', 10 ); 11 $wp_query = new WP_Query( $args ); 12?> 13

以上となります。なにとぞよろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

手順だけ

get_meta_sqlで当該のフィールドを
CAST(REPLACE(meta_value,',','') AS DECIMAL)した値で
エイリアス名をつけてJOINしておいておき、それをorderbyに指定する


参考までに

ウチのプラグインの複数のフィールドの値を利用した計算結果を利用して
meta_queryを書けるようにするためのフィルタフックとメソッド

meta_queryで指定したエイリアス名をorderbyに使えるようにもなってます

php

1add_filter('get_meta_sql',function($sql,$queries,$type,$primary_table,$primary_id_column,$context){ 2 $meta_table=_get_meta_table($type); 3 foreach($queries as $key=>$query){ 4 if(!is_array($query) || empty($query['compute'])){continue;} 5 if(empty($query['alias'])){error_log('compute meta_query must have alias');continue;} 6 if(empty($query['keys'])){error_log('compute meta_query must have keys');continue;} 7 $sql['join'].= 8 " LEFT JOIN (". 9 Catpow\util\sql\meta::select_computed_value($type,$meta_table,$query['keys'],$query['compute'],$query['where']??null). 10 ") AS {$query['alias']} ". 11 "ON ({$primary_table}.{$primary_id_column} = {$query['alias']}.{$type}_id) "; 12 } 13 return $sql; 14},10,6); 15add_filter('meta_query_find_compatible_table_alias',function($alias,$clause){ 16 if(isset($clause['alias'])){return $clause['alias'];} 17 return $alias; 18},10,2);

php

1namespace Catpow\util\sql; 2class meta extends sql{ 3 public static function select_computed_value($type,$table,$keys,$compute,$where=null){ 4 $primary_alias=key($keys); 5 $primary_key=array_shift($keys); 6 if(is_numeric($primary_alias)){$primary_alias = $primary_key;} 7 $sql="SELECT {$primary_alias}.{$type}_id,({$compute}) AS meta_value FROM {$table} AS {$primary_alias} "; 8 foreach($keys as $alias=>$key){ 9 if(is_numeric($alias)){$alias = $key;} 10 $sql.= 11 "INNER JOIN {$table} AS {$alias} ". 12 "ON {$primary_alias}.{$type}_id = {$alias}.{$type}_id ". 13 "AND {$alias}.meta_key = '{$key}' "; 14 } 15 $sql.="WHERE {$primary_alias}.meta_key = '{$primary_key}'"; 16 if(isset($where)){$sql.=' AND '.$where;} 17 return $sql; 18 } 19}

投稿2020/10/08 10:43

編集2020/10/14 06:12
KazuhiroHatano

総合スコア7819

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nekora

2020/10/09 20:06

レスありがとうございます。function.phpでフックして、WHERE句とJOIN句をVAR_DUMP() したり、SQL全文を確認したくて、posts_requestフックでSQL全文をVAR_DUMP()したりしてます。 ただ、当方DB系を苦手としており、いままで避けてきましたが、そういうわけには行かなくなりましたので progateで急いでSQLについて勉強しているところです。 ですので、回答とベストアンサーの選択に少々お時間をいただくことになると思いますがご容赦ください。
nekora

2020/10/13 03:59

大変お待たせしましたSQLの学習を終えて質問文の追記のようにSQLを組んで実行してみたのですが。 エラーになってしまいます。 大変心苦しいのですが、これのどこをどう直せばいいのか、ご教示いただけると幸いです。
KazuhiroHatano

2020/10/13 04:42

やり方は一つじゃないので、ウチのやり方のヒント的な 値自体のエイリアスはnon_comma_valueとかでなくmeta_valueとして サブクエリの結果を擬似的なpostmetaテーブルとしてJOINしてエイリアス名をつける その上でサブクエリにつけたエイリアス名でorderby句が生成されるようにする meta_query_find_compatible_table_alias https://developer.wordpress.org/reference/hooks/meta_query_find_compatible_table_alias/
nekora

2020/10/14 05:25

なかなか返答ができなかった奴に、見捨てずに、新たなアドバイスを頂きありがとうございます。 しかし、今度は別のエラーが出てしまいました。SQL編集前は認識していたカラムがSQLを編集したら カラムを認識しなくなってしまいました。 大変心苦しいのですが最最度、SQLのレビューとアドバイスを頂けたら幸いです。
KazuhiroHatano

2020/10/14 05:49

サブクエリでは計算結果の値をmeta_valueとする(AS meta_value) "擬似的なpostmetaテーブル”を作るイメージ この擬似的なpostmetaテーブルをJOINしてorderbyに使います --- ここから先はSQL文を直書きするなら関係なし あとはこの擬似テーブルにエイリアス名をつけて orderbyで使えるようにしたいわけだけど 通常の処理でJOINされてないのでWPのマニュアルにあるようにmeta_queryのパラメータで キー値を設定しておけばorderbyで使えるエイリアス名がつけれる、というわけにはいかない なのでmeta_query_find_compatible_table_aliasフィルタフックを使って 任意のエイリアス名をorderbyの指定に使えるようにします
nekora

2020/10/19 05:45

色々とアドバイス有難うございました。 お陰様で、ついに思い通りの結果を得ることができました。 KazuhiroHatano様のアドバイスのおかげです。ベストアンサー&高評価付けさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問