WordPressプラグインの開発(6)

この記事は1年以上前に書かれました。
内容が古くなっている可能性がありますのでご注意下さい。


WordPressの投稿や固定ページにOpenStreetMapの地図を貼り付けるためのプラグイン、Embed OSMのバージョン0.6では、ショートコードジェネレータを追加して操作性を向上します。

投稿や固定ページの編集画面に、以下のようなメタボックスを追加します。

地図をドラッグし、縮尺を変え、[Generate shortcode]ボタンをクリックすると以下のようなショートコードが生成されますので、編集画面にコピペします。

[embed_osm lat="35.32395" lon="139.55598" zoom="16" layer="cycle"]

レイヤーは、mapnik(標準)、cycle(サイクリングマップ)、transport(交通マップ)から選択します。選択しないと、プラグインのオプション設定で指定したレイヤーが使用されます。

プラグインのオプション設定画面も大幅に機能拡張します。

まず、メタボックスに表示される地図のホームポジションを設定できるようにします。ホームポジションを変更するときは、地図をドラッグし、縮尺を変え、[Get Coordinates from Map]ボタンをクリックするとテキストボックスの値が更新されますので、その状態で[変更を保存]をクリックします。

さらに、地図上にマーカーを表示するかどうか、地図の下の「大きな地図を表示」リンクを表示するかどうかも選択できるようにします。

前回からの変更点を中心に解説します。

はじめに、メタボックスとオプション設定画面でレイヤーを選択するためのリストボックス作成時に使用する変数

static $layers = array('-', 'mapnik', 'cycle', 'transport');

を、EmbedOSMクラスのメンバ変数として追加します。

public function __construct() {
  register_activation_hook(__FILE__, array(&$this,'embed_osm_activate'));
  register_uninstall_hook(__FILE__, 'EmbedOSM::embed_osm_uninstall');
  add_shortcode('embed_osm', array(&$this, 'embed_osm_handler'));
  add_action('admin_menu', array(&$this, 'embed_osm_menu'));
  add_action('admin_init', array(&$this, 'embed_osm_init'));
}

コンストラクタには、管理画面の初期化時に呼ばれるadmin_initアクションのフックメソッドを追加し、embed_osm_init()で

public function embed_osm_init() {
  add_meta_box('embed_osm', 'Embed OSM shortcode', array(&$this, 'embed_osm_box'), 'post');
  add_meta_box('embed_osm', 'Embed OSM shortcode', array(&$this, 'embed_osm_box'), 'page');
}

投稿と固定ページの編集画面にメタボックスを追加します。

プラグインの初期化時にデータベースに登録する設定値として、

add_option('embed_osm_lat', '35.32395');
add_option('embed_osm_lon', '139.55598');
add_option('embed_osm_zoom', '15');
add_option('embed_osm_marker', 'show');
add_option('embed_osm_link', 'show');

ホームポジションの緯度経度、ズームレベル、マーカーとリンクの表示/非表示を追加します、
プラグインのアンインストール時には、これらをデータベースから削除します。

delete_option('embed_osm_lat');
delete_option('embed_osm_lon');
delete_option('embed_osm_zoom');
delete_option('embed_osm_marker');
delete_option('embed_osm_link');

投稿や固定ページの編集画面に追加するメタボックスを表示するのがembed_osm_box()メソッドです。

public function embed_osm_box() {
  $width = get_option('embed_osm_width');
  $height = get_option('embed_osm_height');
  $layer = get_option('embed_osm_layer');
  $lat = get_option('embed_osm_lat');
  $lon = get_option('embed_osm_lon');
  $zoom = get_option('embed_osm_zoom');

  echo 'Map Layer : <select id="embed_osm_layer" onChange="embed_osm_showmap();">';
  foreach (self::$layers as $ly ) {
    if(strcmp($ly, $layer) == 0) {
      echo '<option value="'.$ly.'" selected>'.$ly.'</option>';
    } else {
      echo '<option value="'.$ly.'">'.$ly.'</option>';
    }
  }
  echo '</select><br />';
  echo '<div id="embmapdiv" style="width:'.$width.'px;height:'.$height.'px;"></div>';
  echo '<br /><a class="button" onClick="embed_osm_genshortcode();">Generate shortcode</a><br />';
  echo '<br /><textarea id="embed_osm_shortcode" rows="2" style="max-width:100%;min-width:100%" onClick="this.select();" readonly></textarea><br />';

  echo '<script type="text/javascript" src="'.plugins_url().'/embed-osm/openlayers/OpenLayers.js"></script>';
  echo '<script type="text/javascript">
    var map;
    var tileurl;
    var lat = '.$lat.';
    var lon = '.$lon.';
    var zoom = '.$zoom.';
    var lonLat;
    function embed_osm_showmap() {
      var lonLat;
      switch(embed_osm_layer.value) {
        case "cycle":
          tileurl = '.self::CYCLE_URL.';
          break;
        case "transport":
          tileurl = ',self::TRANSPORT_URL.';
          break;
        default:
          tileurl = ',self::MAPNIK_URL.';
      }
      if(map) {
        zoom = map.getZoom();
        lonLat = map.getCenter().transform(
          map.getProjectionObject(),
          new OpenLayers.Projection("EPSG:4326"));
        lon = lonLat.lon;
        lat = lonLat.lat;
        map.destroy();
      }
      map = new OpenLayers.Map("embmapdiv");
      map.addLayer(new OpenLayers.Layer.OSM("", tileurl));
      lonLat = new OpenLayers.LonLat(lon, lat).transform(
        new OpenLayers.Projection("EPSG:4326"),
        map.getProjectionObject() );
      map.setCenter(lonLat, zoom);
    };

    function embed_osm_genshortcode() {
      var lonLat = map.getCenter().transform(
        map.getProjectionObject(),
        new OpenLayers.Projection("EPSG:4326"));
      var layer = embed_osm_layer.value == "-" ?
        "" : " layer=\"" + embed_osm_layer.value + "\"";

      embed_osm_shortcode.value = "[embed_osm" +
        " lat=\"" + Math.round(lonLat.lat*100000) / 100000 + "\"" +
        " lon=\"" + Math.round(lonLat.lon*100000) / 100000 + "\"" +
        " zoom=\"" + map.getZoom() + "\"" +
        layer + "]";
      embed_osm_shortcode.select();
    };

    embed_osm_showmap();
  </script>';
}

前半ではオプション設定値を取得し、メタボックスの画面を作成します。レイヤーが変更されたときには、地図の再描画のためにJavaScriptのembed_osm_showmap() 関数を呼び出します。[Generate shortcode]ボタンがクリックされたら、embed_osm_genshortcode()関数を呼び出してショートコードを生成します。

後半で、embed_osm_showmap() 関数とembed_osm_genshortcode()関数のJavaScriptコードを出力します。
embed_osm_showmap() 関数は、既に地図を描画済のときには地図を破棄してから再作成します。そのため、破棄する前に現在の座標情報を保存します。
embed_osm_genshortcode()関数は、地図から取得した座標情報とリストボックスから取得したレイヤー情報を用いてショートコードを作成し、テキストエリアの値に設定します。

ショートコードの処理をするembed_osm_handler()メソッドでは、マーカーと「大きな地図を表示」リンクの表示/非表示を表すオプション設定値を取得し、

$marker = get_option('embed_osm_marker');
$link = get_option('embed_osm_link');

その値によって出力する内容を変更します。

いよいよ最後、オプション設定画面を表示するembed_osm_options()メソッドです。

  function embed_osm_options() {
    if ( !current_user_can( 'manage_options' ) )  {
      wp_die( __( 'insufficient permissions.' ) );
    }

    if (isset($_POST['update_option'])) {
      check_admin_referer('embed_osm_options');
      $width = $_POST['embed_osm_width'];
      if(is_numeric($width)){
        update_option('embed_osm_width', $width);
      }
      $height = $_POST['embed_osm_height'];
      if(is_numeric($height)){
        update_option('embed_osm_height', $height);
      }
      $layer = $_POST['embed_osm_layer'];
      update_option('embed_osm_layer', $layer);
      $lat = $_POST['embed_osm_lat'];
      update_option('embed_osm_lat', $lat);
      $lon = $_POST['embed_osm_lon'];
      update_option('embed_osm_lon', $lon);
      $zoom = $_POST['embed_osm_zoom'];
      update_option('embed_osm_zoom', $zoom);
      $marker = $_POST['embed_osm_marker'];
      update_option('embed_osm_marker', $marker);
      $link = $_POST['embed_osm_link'];
      update_option('embed_osm_link', $link);
    }

    $width = get_option('embed_osm_width');
    $height = get_option('embed_osm_height');
    $layer = get_option('embed_osm_layer');
    $lat = get_option('embed_osm_lat');
    $lon = get_option('embed_osm_lon');
    $zoom = get_option('embed_osm_zoom');
    $marker = get_option('embed_osm_marker');
    $link = get_option('embed_osm_link');

    echo '<div><h2>Embed OSM Options</h2>';
    echo '<form name="form" method="post" action="">';
    wp_nonce_field('embed_osm_options');
    echo '<table class="form-table"><tbody>';
    echo '<tr><td>Map Width</td>';
    echo '<td><input type="text" name="embed_osm_width" value="'.$width.'" size="20"></td></tr>';
    echo '<tr><td>Map Height</td>';
    echo '<td><input type="text" name="embed_osm_height" value="'.$height.'" size="20"></td></tr>';
    echo '<tr><td>Map Layer</td>';
    echo '<td><select name="embed_osm_layer" id="embed_osm_layer" onChange="embed_osm_showmap2();">';
    foreach (self::$layers as $ly ) {
      if(strcmp($ly, $layer) == 0) {
        echo '<option value="'.$ly.'" selected>'.$ly.'</option>';
      } else {
        echo '<option value="'.$ly.'">'.$ly.'</option>';
      }
    }
    echo '</select></td></tr>';
    echo '<tr><td>Home Position</td><td>';
    echo 'Latitude : <input type="text" id="embed_osm_lat" name="embed_osm_lat" value="'.$lat.'" size="10" readonly>';
    echo ' Longitude : <input type="text" id="embed_osm_lon" name="embed_osm_lon" value="'.$lon.'" size="10" readonly>';
    echo ' Zoom : <input type="text" id="embed_osm_zoom" name="embed_osm_zoom" value="'.$zoom.'" size="10" readonly><br />';
    echo '<p><a class="button" onClick="embed_osm_getvalue();">Get Coordinates from Map</a><br /><br />';
    echo '<div id="defmapdiv" style="width:'.$width.'px;height:'.$height.'px;"></div></td></tr>';
    $show = $marker === 'show' ? ' checked' : '';
    $hide = $marker === 'hide' ? ' checked' : '';
    echo '<tr><td>Marker</td><td><input type="radio" name="embed_osm_marker" value="show"'.$show.'>Show<br /><input type="radio" name="embed_osm_marker" value="hide"'.$hide.'>Hide</td></tr>';
    $show = $link === 'show' ? ' checked' : '';
    $hide = $link === 'hide' ? ' checked' : '';
    echo '<tr><td>Link to Large Map</td><td><input type="radio" name="embed_osm_link" value="show"'.$show.'>Show<br /><input type="radio" name="embed_osm_link" value="hide"'.$hide.'>Hide</td></tr>';
    echo '</tbody></table>';
    echo '<input type="submit" name="update_option" class="button button-primary" value="'.esc_attr__('Save Changes').'" />';
    echo '</form>';
    echo '</div>';

    echo '<script type="text/javascript" src="'.plugins_url().'/embed-osm/openlayers/OpenLayers.js"></script>';
    echo '<script type="text/javascript">
      var map;
      var tileurl;
      var lat = '.$lat.';
      var lon = '.$lon.';
      var zoom = '.$zoom.';
      var lonLat;

      function embed_osm_showmap2() {
        var lonLat;
        switch(embed_osm_layer.value) {
          case "cycle":
            tileurl = '.self::CYCLE_URL.';
            break;
          case "transport":
            tileurl = ',self::TRANSPORT_URL.';
            break;
          default:
            tileurl = ',self::MAPNIK_URL.';
        }
        if(map) {
          zoom = map.getZoom();
          lonLat = map.getCenter().transform(
            map.getProjectionObject(),
            new OpenLayers.Projection("EPSG:4326"));
          lon = lonLat.lon;
          lat = lonLat.lat;
          map.destroy();
        }
        map = new OpenLayers.Map("defmapdiv");
        map.addLayer(new OpenLayers.Layer.OSM("", tileurl));
        var lonLat = new OpenLayers.LonLat(lon, lat).transform(
          new OpenLayers.Projection("EPSG:4326"),
          map.getProjectionObject() );
        map.setCenter(lonLat, zoom);
      }

      function embed_osm_getvalue() {
        var lonLat = map.getCenter().transform(
          map.getProjectionObject(),
          new OpenLayers.Projection("EPSG:4326"));
        embed_osm_lat.value = Math.round(lonLat.lat*100000) / 100000;
        embed_osm_lon.value = Math.round(lonLat.lon*100000) / 100000;
        embed_osm_zoom.value = map.getZoom();
      }

      embed_osm_showmap2();
    </script>';

  }

前半では、セキュリティチェックのあと、POSTされて来た場合には設定値を更新します。その後オプション設定画面を作成します。
後半では、JavaScript関数embed_osm_showmap2()とembed_osm_getvalue()を出力します。
embed_osm_showmap2()関数は、最初の地図表示と、レイヤーが変更されたときの再表示を行います。
embed_osm_getvalue()関数は、[Get Coordinates from Map]ボタンをクリックしたときに呼び出され、地図から取得した座標情報をテキストボックスにセットします。

以上で、ショートコードジェネレータ付きのプラグインの完成です。

今回作成したプラグインのダウンロードはこちらからどうぞ。

WordPressプラグインの開発 1234567891011