WordPress: Advanced Custom Fields Google Mapの緯度経度で検索する

Advanced Custom Fields 便利です。
Google Mapフィールドにすれば、投稿時も記事でもさくっとGoogle Mapが使えるのはいいんですが、値をシリアライズしてカスタムフィールドに格納してしまうので、meta_queryで使いづらい・・・ ぞと。

緯度と経度単体のカスタムフィールド化で解決

記事保存時のアクション wp_insert_post をフックして、緯度、経度単体のカスタムフィールドとして値を別途保存すればいい感じになります。

これで get_field() や、 get_post_meta() で latと lngが取り出せるし、meta_query指定で抽出も簡単です。

緯度経度は準備できた! 実際に使いたいのはたぶん、こんなケース?

緯度経度をピンポイントでズバリ! の検索をすることはほとんど無くて、
実際に検索を利用したいケースを想定するならば、
お店紹介のブログやらで「このお店も近くにあります!」的な関連表示をしたい!
とか、そんなところでしょうか。

MySQL的に記述の2点間のなんとなくな距離は

SQRT(POWER(ABS(lat1 – lat2), 2) + POWER(ABS(lng1 – lng2), 2))

だと思うんですが、これをORDER BY指定に・・・ と思っても
WP_Queryにこれ、さくっと渡せないんですよねー。
渡せないですよね? ね?

渡せるのであれば、おまるくんの無駄骨を笑いつつ、そっとページを閉じるのを推奨です・・・。
やっぱり渡せないのであれば、この後の記事を参考にするといいぜ!!

まずはDECIMALの扱いを補正

まずORDER BY で計算して重たくなるの嫌なので、あらかじめ対象件数少なくしよう。

と思って、まずは緯度経度をBETWEEENであらかじめ絞り込み!
が、うまくいかないという悲しい事態になります。

どうやら、カスタムフィールドのDECIMALは、クエリ生成時にCAST(value AS DECIMAL)にキャストされているらしく、小数点以下が丸め込まれてしまうんですね。

get_meta_sql でWHERE句を小数点以下6桁までよろしくお願いします!
なフィルターフックで対応。
同様の事が ORDER BY句でも起きるので、こちらも posts_orderby で対応しておきます。

ぼくのかんがえたWP_Queryクラス

ORDER BY指定にさくっとちょっと長ったらしい感じの指定ができないのは、
$orderbyの中身をurldecode(explode(‘ ‘, $orderby))して、最後にjoin(‘,’, $orderby) しているせい。
そのおかげで+やらスペースやらが思った通りに渡せていないのです。

WP_Queryクラスを継承して、小さな親切余計なお世話ばりの変換を無くす派生クラスを作ってみます。

余計なお世話が起きている本丸はparse_orderbyメソッド。
便宜上スペースを無くしてもいいんですが、urlencodeの利用を生かし、
スペースが+変換されてしまうのを防ぐために事前にタブに変換してしまうスタティックメソッド encodeも追加しました。

利用の際は、このメソッドで変換をかけながら ORDER BYを指定します。

WP_Query本来の ORDER BY指定については、{}でくくることで対応します。

orderby => ‘ID‘ やら orderby=> ‘rand’ はこのクラスでは
orderby => ‘{ID}’ やら orderby => ‘{rand}’ と表現する感じですね。
{}外はそのままの文字がORDER BY 句の表現になるよ なクラスです。

あの場所との距離は判る、君のとの距離は判らずじまい

早速できたクラスを使って、ORDER BYに距離順を設定してみます。
ORDER取るだけなので SQRTはいらないかな?

これで距離的な抽出はばっちり!

君との距離はまだ、わからないけれど・・・。