人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

グ?グルマップのマ?カ?表示について質問させてください。
現在、WordPressの投稿を店舗の情報として固定ペ?ジのグ?グルマップにマ?カ?を立てています。
(投稿のひとつひとつが店舗になっています)
店舗情報にカスタムフィ?ルドで緯度(lat)と経度(lon)という情報を作り、その値に基づいてマップにマ?カ?を立てています。
が、現状では、店舗情報を登録する際、住所を緯度経度に変換してから登録しないとマップにマ?カ?が立たず、面倒くさいのです。
グ?グルマップのマ?カ?ポジション部分は以下のようなコ?ドにしているのですが、カスタムフィ?ルドの「住所(address)」を入力するだけでマップにマ?カ?を立てられるようにするにはどうすれば良いでしょうか。

position: new google.maps.LatLng( <?php echo post_custom("lat")?>,<?php echo post_custom("lon")?> ),

教えてください、よろしくお願いいたします。

●質問者: mocchi
●カテゴリ:コンピュータ ウェブ制作
○ 状態 :終了
└ 回答数 : 1/1件

▽最新の回答へ

1 ● a-kuma3
●1200ポイント ベストアンサー

Google Maps API の Geocoder クラスというのを使うと住所から緯度、経度などを取得できます。
https://developers.google.com/maps/documentation/javascript/reference?hl=ja#Geocoder

google maps api 住所 緯度 経度」という感じでググると、サンプルソースを置いてあるところが見つかります。

などなど

質問にあるコードの断片は、google.maps.Marker への引数でしょうか。
エラー処理などをバッサリと省き、エッセンスだけを抜き出すと、こんな感じになります(php の埋め込みはありますが、基本 javascript です)。

 var map = ...
 var geocoder = new google.maps.Geocoder();

 geocoder.geocode({
 address: "<?php echo post_custom('address') ?>" // カスタムフィールド address の値
 }, function(results, status) {
 if (status == google.maps.GeocoderStatus.OK) {

 // 緯度、経度(検索結果のひとつ目)
 var latlng = results[0].geometry.location;

 // 緯度、経度を指定して Marker を作成
 var marker = new google.maps.Marker({
 position: latlng,
 map: map
 });

 ...

 }
 });

ちょっと気を付けなければいけないのは、以下の 2点。

Web API も用意されてます。
https://developers.google.com/maps/documentation/geocoding/intro?hl=ja#GeocodingRequests

こんなリクエストをと送ると、XML で京都駅の位置情報などが取得できます(%E4%BA%AC%E9%83%BD%E9%A7%85 は、京都駅を URL Encode したものです)。

http://maps.google.com/maps/api/geocode/xml?address=%E4%BA%AC%E9%83%BD%E9%A7%85

応答はこんな感じ。

<GeocodeResponse>
 <status>OK</status>
 <result>
 ...
 <geometry>
 <location>
 <lat>34.9858490</lat>
 <lng>135.7587667</lng>
 </location>
 ...
 </geometry>
 </result>
</GeocodeResponse>

# 先のマニュアルにあるように、JSON 推奨ですが。

こちらを使えば、file_get_contents() を使って、PHP 側で取得することも可能です。
複数の検索結果が返ってきたり、実在する住所でも検索結果が返ってこないこともある、というところは javascript の API と同じです。


mocchiさんのコメント
ざっくり書いていただいたサンプルコ?ドを流用するだけで、緯度経度情報を削除した後も住所からマ?カ?が表示されました。ありがとうございます。 ただ、問題がひとつありまして、今まで複数表示されていたマ?カ?がひとつだけしか表示されなくなってしまいました。 (ル?プで取得する一番最初の店舗のみ表示) しかしながら、住所から位置情報を取得するのは念願でしたからすごく嬉しいです。 現状のコ?ドは以下としていますが、マ?カ?がひとつだけしか表示されない原因がもしお分かりでしたらおしえていただけませんでしょうか。 var geocoder = new google.maps.Geocoder(); geocoder.geocode({ address: "<?php echo post_custom('address') ?>" // カスタムフィールド address の値 }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { // 緯度、経度(検索結果のひとつ目) var latlng = results[0].geometry.location; marker[<?php echo $m++; ?>] = new google.maps.Marker({ icon: 'http://abcdefg.com/images/marker.png', position: latlng, map: map, title: '<?php the_title(); ?>' }) } });

a-kuma3さんのコメント
>> ただ、問題がひとつありまして、今まで複数表示されていたマ?カ?がひとつだけしか表示されなくなってしまいました。 << 元のソースをを見ないと何とも、という感じなのですが、[http://q.hatena.ne.jp/1452655930:title=この質問]と同じやつなんですよね、きっと。 PHP の方でループを回すと、javascript の非同期処理とかがわけが分からなくなるので、PHP のループでは javascript のデータを作るところにまとめて、Google Maps API を使うところは javascript だけで固めてみてはどうでしょうか(修正量が多いかな?)。 非同期処理なので、それぞれ独立した Marker であれば、Geocoder#geocode をループで呼び出しても動きます。 例えば、こんな感じ。 >|javascript| var map = new google.maps.Map(document.getElementById("map"), { zoom: 7, center: new google.maps.LatLng(36,138), mapTypeId: google.maps.MapTypeId.ROADMAP }); var geocoder = new google.maps.Geocoder(); // 住所の配列(ここを、PHP で作る) var address_list = [ "東京駅", "有楽町駅", "神田駅", ]; var bounds = new google.maps.LatLngBounds(); address_list.forEach(function(address) { geocoder.geocode({ address: address }, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { // 緯度、経度(検索結果のひとつ目) var latlng = results[0].geometry.location; console.log(results[0]); bounds.extend(latlng); // 緯度、経度を指定して Marker を作成 var marker = new google.maps.Marker({ position: latlng, map: map }); new google.maps.InfoWindow({ content: results[0].address_components[0].long_name }).open(map, marker); map.fitBounds(bounds); } }); }); ||< jsfiddle で試したのがこちら。 https://jsfiddle.net/a_kuma3/dkj8c9ev/

mocchiさんのコメント
回答いただきありがとうございます。 はい、おっしゃる通り、そちらの質問の時にもa-kuma3さんに助けていただきました。 いつもお世話になっております。 今回いただいた回答を元にやってみたのですが、どうしてもル?プを組み込むとエラ?がでてしまいまして。。 元のコ?ドを書かせていただくと、それを見ていただくのに大変労力を使わせてしまうと思っていたのですが、新たにコ?ドまで書いていただいて本当に恐縮しております。 恐れ入りますが、もちろん増ポイントさせていただきますので元のコ?ドもみていただけませんでしょうか。 以下、元のコ?ドとなります。 >|| <?php if (have_posts()) { while (have_posts()) { the_post(); get_template_part('content', 'page'); } } ?> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <?php $categories = get_post_meta( $post->ID, 'displaycategory', true); if ( have_posts() ) : query_posts('category_name=' . $categories . '&showposts=10000'); ?> <div id="map" style="width: 99%; height: 650px;"></div> <script type="text/javascript"> google.maps.event.addDomListener(window, 'load', function() { var mapdiv = document.getElementById( 'map' ); var myOptions = { zoom: 14, center: new google.maps.LatLng( <?php echo post_custom("centerlat")?>,<?php echo post_custom("centerlng")?> ), mapTypeId: google.maps.MapTypeId.ROADMAP, scaleControl: true }; var map = new google.maps.Map( mapdiv, myOptions ); var marker = []; var infowindow = []; <?php $m=0; $m1=0; $m2=0; $i=0; $i2=0; ?> <?php while (have_posts()) : the_post(); ?> marker[<?php echo $m++; ?>] = new google.maps.Marker({ icon: 'http://abcdefg/images/marker.png', position: new google.maps.LatLng( <?php echo post_custom("lat")?>,<?php echo post_custom("lon")?> ), map: map, title: '<?php the_title(); ?>' }); infowindow[<?php echo $i++; ?>] = new google.maps.InfoWindow({ content: '<div style="width : 100%;height : 36PX;">'+'<?php echo post_custom("Name")?>:<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>', size: new google.maps.Size( 50, 30 ) }); google.maps.event.addListener( marker[<?php echo $m1++; ?>], 'click', function() { var iw = infowindow[<?php echo $i2++; ?>]; if (iw.getMap() == null){ iw.open(map, marker[<?php echo $m2++; ?>]); } else{ iw.close(); } }); <?php endwhile; // End the loop. Whew. ?> var markerCluster = new MarkerClusterer( map, marker ); }); </script> <?php endif; ?> ||< お手すきの折にでも目を通していただければ嬉しいです。 お手数をおかけいたします。

a-kuma3さんのコメント
コメントにあった範囲を書き換えてみました。 >|php| <?php if (have_posts()) { while (have_posts()) { the_post(); get_template_part('content', 'page'); } } ?> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <?php $categories = get_post_meta( $post->ID, 'displaycategory', true); if ( have_posts() ) : query_posts('category_name=' . $categories . '&showposts=10000'); ?> <div id="map" style="width: 99%; height: 650px;"></div> <script type="text/javascript"> google.maps.event.addDomListener(window, 'load', function() { var mapdiv = document.getElementById( 'map' ); var myOptions = { zoom: 14, center: new google.maps.LatLng( <?php echo post_custom("centerlat")?>,<?php echo post_custom("centerlng")?> ), mapTypeId: google.maps.MapTypeId.ROADMAP, scaleControl: true }; var map = new google.maps.Map( mapdiv, myOptions ); var marker = []; var infowindow = []; // ★ここから書き換えてます var posts = []; <?php while (have_posts()) : the_post(); ?> posts.push({ address: '<?php echo post_custom("address")?>', name: '<?php echo post_custom("Name")?>', link: '<?php the_permalink(); ?>', title: '<?php the_title(); ?>' }); <?php endwhile; // End the loop. Whew. ?> for (var i = 0 ; i < posts.length ; ++i) { geocoder.geocode({ address: posts[i].address }, (function() { var post = posts[i]; return function(results, status) { if (status == google.maps.GeocoderStatus.OK) { // 緯度、経度(検索結果のひとつ目) var latlng = results[0].geometry.location; // 緯度、経度を指定して Marker を作成 var m = new google.maps.Marker({ icon: 'http://abcdefg/images/marker.png', position: latlng, map: map, title: post.title }); marker.push(m); var iw = new google.maps.InfoWindow({ content: '<div style="width : 100%;height : 36px;">' + post.name + ':<a href="' + post.link + '">"' + post.title + '</a>', size: new google.maps.Size( 50, 30 ) }); infowindow.push(iw); google.maps.event.addListener( m, 'click', function() { if (iw.getMap() == null){ iw.open(map, m); } else { iw.close(); } }); if (marker.length == posts.length) { var markerCluster = new MarkerClusterer( map, marker ); } } }; })() ); } }); </script> <?php endif; ?> ||< Marker の icon の URL も、コメントにあったままです。 javascript の範囲でしか動作を確認してませんが、MarkerClusterer が最後に一回だけ呼び出されるところまでは確認しました。。

mocchiさんのコメント
ありがとうございます。 マ?カ?アイコンのURLも編集しました。 現状でマ?カ?は表示されないのですが、いただいた対応が嬉しくありがたく思っております。 このまま未解決でも増ポイントさせていただきます。 本当にありがとうございます。

a-kuma3さんのコメント
jsfiddle で試してみました。 https://jsfiddle.net/b6ks7L1w/ ぼくがコメントに書いたコードと、ほぼ同じです。 変更したところは、以下の 6点。 - 記事があるかどうかの php の判定を取り除いた - jsfiddle に合わせて、javascript と html を分解し、Google Maps API の External Resources として指定した - Map の中心座標を php のコードではなく、数字を直接指定した - Marker のアイコンを、ぼくのプロフィール画像にした - php で記事のループになっているところを、こんな感じに展開されるであろう javascript のコードにした - <span style="color: red;">Geocoder のインスタンスを生成</span>(Map の次の行) 最後の、Geocoder の生成は大丈夫ですか? 抜けてません?

a-kuma3さんのコメント
もうひとつ、変更点。 吹き出しに余計なダブルクォートが入ってたので消しました。

mocchiさんのコメント
再度コ?ドをチェック、さらには検証までしていただいてしていただいて感謝します。 ありがとうございます。 無料のWordpressサ?ビスがあったので、そこに今の環境と全く同じものを作り、ゲストアカウントを作りました。 お手数をおかけいたしますが、こちらにログインし、内部からコ?ドをチェックしていただけませんでしょうか。 私の能力不足のためにここに書けないでいる「こりゃあかんわ」みたいなものがあるのだろうと思うのです。 サイトURL http://eiji3.wp.xdomain.jp ログインペ?ジ http://eiji3.wp.xdomain.jp/wp-admin ユ?ザ?名 guest パスワ?ド maptest このサイトでは店舗情報を5つ登録していて、これらのマ?カ?をトップペ?ジのマップに表示したいのです。 アドバンスカスタムフィ?ルドというプラグインでカスタムフィ?ルドを作っております。 投稿(post)には店舗情報に関するフィ?ルドを追加し、固定ペ?ジにはマップ表示に関するフィ?ルドを追加しております。 サイトのトップペ?ジは固定ペ?ジ「top」に設定しており、コ?ドをチェックしていただきたいのは固定ペ?ジのデフォルトテンプレ?ト「page.php」なのです。 「外観」→「テ?マの編集」→「個別投稿ペ?ジ(page.php)」 現状では地図のみが表示されマ?カ?は表示されませんが、店舗情報(post)に追加したカスタムフィ?ルドのlatとlonで位置情報を取得する以下のコ?ドに差し替えるとマ?カ?が5つとも表示されるのです(差し替えてみてください)。 >|| <?php if (have_posts()) { while (have_posts()) { the_post(); get_template_part('content', 'page'); } } ?> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <?php $categories = get_post_meta( $post->ID, 'displaycategory', true); if ( have_posts() ) : query_posts('category_name=' . $categories . '&showposts=10000'); ?> <div id="map" style="width: 99%; height: 650px;"></div> <script type="text/javascript"> google.maps.event.addDomListener(window, 'load', function() { var mapdiv = document.getElementById( 'map' ); var myOptions = { zoom: 14, center: new google.maps.LatLng( <?php echo post_custom("centerlat")?>,<?php echo post_custom("centerlng")?> ), mapTypeId: google.maps.MapTypeId.ROADMAP, scaleControl: true }; var map = new google.maps.Map( mapdiv, myOptions ); var marker = []; var infowindow = []; <?php $m=0; $m1=0; $m2=0; $i=0; $i2=0; ?> <?php while (have_posts()) : the_post(); ?> marker[<?php echo $m++; ?>] = new google.maps.Marker({ icon: 'http://maps.google.co.jp/mapfiles/ms/icons/red-dot.png', position: new google.maps.LatLng( <?php echo post_custom("lat")?>,<?php echo post_custom("lon")?> ), map: map, title: '<?php the_title(); ?>' }); infowindow[<?php echo $i++; ?>] = new google.maps.InfoWindow({ content: '<div style="width : 100%;height : 36PX;">'+'<?php echo post_custom("Name")?>:<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>', size: new google.maps.Size( 50, 30 ) }); google.maps.event.addListener( marker[<?php echo $m1++; ?>], 'click', function() { var iw = infowindow[<?php echo $i2++; ?>]; if (iw.getMap() == null){ iw.open(map, marker[<?php echo $m2++; ?>]); } else{ iw.close(); } }); <?php endwhile; // End the loop. Whew. ?> var markerCluster = new MarkerClusterer( map, marker ); }); </script> <?php endif; ?> ||< (マ?カ?アイコンはグ?グルのものに変更しています) a-kuma3さんに検証いただいているペ?ジでは実際に住所でマ?カ?が表示されているので、こちら側に問題があるのは明白で、ただその原因がまったくわからないのです。。

a-kuma3さんのコメント
なはは、デバッグ環境まで用意されちった <tt>:-)</tt> 実は、WordPress の実物を触るのは初めてだったりします。 せっかくなので、修正してみました。 - 33行目に、MarkerCluster のライブラリを読み込みを追加 - 51行目に、Geocoder のインスタンス生成を追加 - 89行目にあったダブルクォートをひとつ消した MarkerCluster も使いたいんですよね? SVN のソースを直接参照するようにしちゃいましたけど、きちんと使うときは自分のサイトに設置して、そちらを参照するようにしてください。

mocchiさんのコメント
ありがとうございます、ログインしていただいての修正をいただいたのですね。ありがとうございます。 さっそく本番環境に移植しました。 本番環境の方でも住所からマ?カ?を取得し、トップペ?ジに表示されたのですが、マップに表示されるマ?カ?の上限が9個のみとなってしまうのです。 これはおかしいと思いまして、こちらのテスト環境の方の登録店舗数を試しに12件ほどに増やしたのですが、やはりマップ上には9個までしかマップに表示されないのです。 これは住所からマ?カ?を表示させる際の仕様なのでしょうか。 ちなみに、登録店舗が9件を超えるとMarkerClusterが無効化され(これは構わないのですが)マ?カ?が近くにあっても数字表示でなくなりました。 仮に投稿(店舗情報)をゴミ箱に入れ、9件以下にすると数字表記が復活します。 もしかして原因はこれかと思い、33行目のMarkerCluster のライブラリを読み込みを試しに削除してみたのですが、やはり9件までしかマップに表示されません(削除後、元に戻しました)。 仕様であるならば住所から位置情報を取得するのは諦めるほかないのですが、そのあたりご存じでしたら教えていただけませんでしょうか。

a-kuma3さんのコメント
https://developers.google.com/maps/documentation/geocoding/usage-limits?hl=ja Geocoding API には、無料で配下の制限があります。 - 2500回 / 1日 - 10回 / 1秒 この 2番目の制限に引っかかっているのだと思います。 https://developers.google.com/maps/premium/usage-limits#usage-rates-by-api 課金しても、1秒当たり 10回までの制限は緩和されなくて、0.25秒経つと次のリクエストを受け付けてもらえます。 https://developers.google.com/maps/articles/geocodestrat#quota-limits Google 的には、実行結果をキャッシュしておくか、リクエストを適当な間をあけて送れ、ということのようです。 20個くらいまでだったら、0.25秒待って 2回に分けて処理すれば、Geocoding API 自体が 0.5秒くらいかかるので、あまり気にならないかもしれません。

a-kuma3さんのコメント
>> 20個くらいまでだったら、0.25秒待って 2回に分けて処理すれば、Geocoding API 自体が 0.5秒くらいかかるので、あまり気にならないかもしれません。 << []http://eiji3.wp.xdomain.jp/[] の方で、ちょっと試してみました。 やっつけなので、20個までの対応ですけれど、10個を超えた分は 0.5秒待ってから位置情報を取得するようにしてみました。

mocchiさんのコメント
本当に親身になっていただいた回答を複数いただき感服いたしました。 本番環境では緯度経度デ?タからの位置情報を使うことになると思うのですが、今回かいていただいたコ?ドは別の機会に活用させていただく所存でして、本当に助かりました。 ありがとうございました。 また、もうすぐ時間切れとなるもうひとつの質問、 「WordPressにおけるPHPの超初歩的な質問をさせてください」 http://q.hatena.ne.jp/1462302456 でもお世話になっております。 こちらの質問は間もなく終了してしまうので再質問させていただく形になりそうですが、 今回つくらせていただいたWordpressのテスト環境(http://eiji3.wp.xdomain.jp)で今度はこちらを再現しました。 もし差支えがない場合、こちらの方でもa-kuma3さんに回答をいただきたく存じます。 テスト環境のトップペ?ジには入力フォ?ムがあり、これに「世田谷区」と入力すると世田谷区にある店舗が、「千代田区」と入力すると千代田区の店舗が表示されるようになっています。 ただこのフォ?ムに「あ」と表示するだけでもマップが表示されてしまいます。 入力されたワ?ドを、住所に含む店舗がない場合、マップは非表示かつ「該当する店舗はありませんでした」と表示したい、という趣旨の質問になっております。 こちらでも助けていただければ有難く、なにとぞよろしくお願いいたします。 今回の質問では本当に素晴らしい対応をしていただき感激しております。 本当にありがとうございました。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ