PHP
JavaScript
WordPress
KML
GoogleMapsAPI

Wordpressの投稿から位置情報を取得してGoogleMapに複数のピンを表示する

WordpressのテンプレートからKMLファイルを出力してGoogleMapsAPIを活用

GoogleMAPにピンを表示することはMAP埋め込みやマイマップで簡単にできますが、この方法は細かい設定が難しく、更新も手間です。
不動産、飲食店、会社などの情報をWordpressで管理している場合、管理画面で登録した情報を一つのマップに表示させたいということがあると思います。
その場合WordpressのDBから住所情報を抜き出し、KMLファイルを出力してGoogleMapsAPIを利用してアイコンを表示する方法が便利です。

KMLファイルを読み込んでアイコンを表示する方法。

GoogleMapsAPIのスタートガイドに載っている内容で実現できました。
【GoogleMapsAPIガイド】
https://developers.google.com/maps/documentation/javascript/kml?hl=ja

MAP表示(body部分のみ記載)
<style>
html, body {
height: 370px;
padding: 0;
margin: 0;
}
#map {
height: 360px;
width: 300px;
overflow: hidden;
float: left;
border: thin solid #333;
}
#capture {
height: 360px;
width: 480px;
overflow: hidden;
float: left;
background-color: #ECECFB;
border: thin solid #333;
border-left: none;
}
</style>
<div id="map"></div>
<div id="capture"></div>
<script>
  var map;
    //ソースファイルの読み込み
  var src = 'https://sample/marker/?<?php echo time(); ?>'; 
    function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
            center: new google.maps.LatLng(0, 0),
            zoom: 11,
            mapTypeId: 'terrain'
        });
        var kmlLayer = new google.maps.KmlLayer(src, {
            suppressInfoWindows: true,
            preserveViewport: false,
            map: map
        });
        kmlLayer.addListener('click', function(event) {
            var content = event.featureData.infoWindowHtml;
            var testimonial = document.getElementById('capture');
            testimonial.innerHTML = content;
        });
    }
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script>

上手く表示できているかの確認方法

読み込みKMLファイルのURLを書き換えることで確認できます。
【KMLファイルサンプル】
https://www.google.co.jp/search?q=filetype:kml+velodromes&cad=h

KMLファイル読み込みの注意点

KMLファイルの内容を更新しても内容が反映されないことがあります。
GoogleMapsAPIのキャッシュ有効期限が長く設定されているためです。
正常に表示させるには読み込み先URL後に「?<?php echo time(); ?>」をつけて毎回読み込み直すようにします。

KMLファイル読み込み
var src = 'https://sample/marker/?<?php echo time(); ?>';`

KMLファイルを出力するWordpressのテンプレートの作成

表示させるソースのURLに合わせたテンプレートを作成します。
https://sample/marker/ 」に合わせたpage-marker.phpのテンプレート例です。
GoogleMapsAPIのカスタムフィールド(mapというフィールド名)から位置情報を取得しています。

page-marker.php
<?php
$filename = 'map.kml'; // ファイル名

$xml = new DomDocument('1.0');
$xml->encoding = "UTF-8"; 
$xml->formatOutput = true; 

//kml定義部分
$kml= $xml->appendChild($xml->createElement('kml'));
$kml->setAttribute('xmlns','http://www.opengis.net/kml/2.2');
//Document部分
$Document= $kml->appendChild($xml->createElement('Document'));

//name部分
$name = $Document->appendChild($xml->createElement('name'));
$name->appendChild($xml->createTextNode('SAMPLE MAP'));

//Style部分
$Style = $Document->appendChild($xml->createElement('Style'));
$Style->setAttribute('id','map_style');
//IconStyle
$IconStyle = $Style->appendChild($xml->createElement('IconStyle'));
$Icon = $IconStyle->appendChild($xml->createElement('Icon'));
$href = $Icon->appendChild($xml->createElement('href'));
$href->appendChild($xml->createTextNode('http://sample/map_icon.png?'.time().' '));

//BalloonStyle
$BalloonStyle = $Style->appendChild($xml->createElement('BalloonStyle'));
$text = $BalloonStyle->appendChild($xml->createElement('text'));
$text->appendChild($xml->createTextNode('$[houseinfo]'));

//投稿記事から位置情報とタイトル・アイキャッチ画像を取得
//placemark
//取得したい投稿情報を絞り込み
$list = array(
  'cat' => get_cat_ID('place'),//カテゴリーの指定
  'posts_per_page' => '20', //アイコンの数を指定
  'orderby' => 'date',
  'order' => 'ASC',
);
query_posts($list);
<?php 
if (have_posts()) {
    while (have_posts()) {
        the_post();
        $location = get_field('map');
        if (!empty($location)) {
            $pleceinfo = '';
                    
            if (has_post_thumbnail()) {
                $pleceinfo .= '<img src="'.wp_get_attachment_image_src(get_post_thumbnail_id (), true)[0].'?'.time().'" alt="">';
            } else {
                $pleceinfo .= '<img src="'.bloginfo('template_url').'/common/img/noimage.gif" alt="default image" />';
            }
            $pleceinfo .= '<h3>'.get_the_title().'</h3>';
            $Placemark = $Document->appendChild($xml->createElement('Placemark'));
            $Style = $Placemark->appendChild($xml->createElement('styleUrl'));
            $Style->appendChild($xml->createTextNode('#sample_style'));
            $ExtendData = $Placemark->appendChild($xml->createElement('ExtendedData'));
            $Data = $ExtendData->appendChild($xml->createElement('Data'));
            $Data->setAttribute('name','houseinfo');
            $value = $Data->appendChild($xml->createElement('value'));
            $value->appendChild($xml->createCDATASection($pleceinfo));
            $Point = $Placemark->appendChild($xml->createElement('Point'));
            $coordinates =$Point->appendChild($xml->createElement('coordinates'));
            $coordinates->appendChild($xml->createTextNode($location['lng'].','.$location['lat'].',0'));
        }
    }
}

// HTTPヘッダを出力して
header("Content-disposition: attachment; filename=" . $fileName);
header("Content-type: application/octet-stream; name=" . $fileName);

// DomXMLをXML形式で出力
echo $xml->saveXML();

PHPでCDATAを含むXMLを出力するには

マップのピンの情報はCDATAにhtmlの情報を格納する必要があります。
createTextNodeを利用すると内容が文字化けしてしまい上手くいきませんでした。

上手くいかない例
$value->appendChild($xml->createTextNode('<CDATA[['.$pleceinfo.']]>'));

下記のように記述すると格納できます。

XMLのCDATAを出力
$value->appendChild($xml->createCDATASection($pleceinfo));

まとめ

サンプル画面がなく申し訳ないです。
表示イメージが気になる方はGoogleのガイドが一番参考になるので見てください。
次回はAPIから位置情報を取得してGoogleMAPに表示してみたいと思います。