WordPressからLeafletのポップアップを操作する

事例の概要

地図表示でマーカーを表示するとき、マーカーをクリックするとポップアップ表示するだけでなく、外部のテキストからポップアップを開くことができれば、より便利です(下図)。

この機能を実現するためには、Leaflet側のマーカーのポップアップとWordPressで表示するテキスト表示を動的に連動させることが必要です。

コード量も増えるので、再利用しやすいようにClassに分けて記述することが理想的です。

【お知らせ】
上記の事例3に示すオブジェクト指向(MVCモデル)の使い方については、本書で詳しく解説しています。


ER図活用によるWebサイトの全体デザイン

ER図

WordPressの投稿タイプやタクソノミーを理解しようとするとき、ER図を書いてみると、視覚的に理解しやすくなります。

データの集合をエンティティと呼びます。下図は、3つのエンティティ(ブログ投稿、市区町村、ジャンル)をデータの実例付きで図示したものです。
 ER図では、主キーと外部キーを記述します。主キーは、図056の最左端のデータ項目で、エンティティのレコードを識別します。表の右端にある「市区町村ID」「ジャンルID」は、それ自身が別のエンティティの主キーとなり得るデータ項目で、外部キーと呼ばれます。 一つのエンティティに主キーは必ず一つですが、外部キーは複数持つことができます。図では、ブログ投稿は二つの外部キーを持つことによって、「ジャンル」と「市区町村」2つのエンティティを関連を持っています。
 また、「市区町村」の事例は、外部キーが自身の主キーと結びつく「親子関係」のエンティティの事例です。

ブログ投稿と市区町村の関係は、1:N

・1つのブログ投稿に対し1つの市区町村が関連。
・その市区町村は別のブログ投稿とも関連。

ブログ投稿とジャンルの関係は、N:N

・ジャンルは、1つのブログ投稿に対し複数設定可能。
(例)
西仲通り商店街は、「商店街」と「路地」に関連

市区町村は親子ループ(1:N)を持つ

・1つの親は1つまたは複数の子を持つ。
・子に対し、親は1つ。
・同一エンティティの中で主キーと外部キーが結びつく(親子関係)。

主キーと外部キー

上記のER図の主キーと外部キーのみを表記すると下図のようになります。主キーと外部キーに注目すると、下記4パターンに集約されます。
ⓐDestinationパターン
ⓑSourceパターン(MetaQuery、TaxQuery)
ⓒAncestorsパターン(現世代→先祖)
ⓓDescendantsパターン(現世代→子孫)

WEBサイトの要件をER図に書き表す

Webサイトを開発する前に全体のデザイン(設計)をすることが必要です。まず、エンティティを抽出し、それらの関連づけを行うための主キー、外部キーはを決めることが重要です。

下図は当サイトの場合のER図の事例です。WordPressは投稿タイプとタクソノミーの2種類がありますので、どちらにするかも最初にするかを決めておく必要があります。

WordPressの外部キー

エンティティ同士の関連には、
 ❶投稿タイプとタクソノミーの関連づけ
 ❷投稿タイプのカスタムフィールドによる関連づけ
 ❸parentフィールドによる親子関係の関連づけ
の3種類があります。

オブジェクト指向によるWordPressへのMVCモデル適用

WordPressはイベント駆動型モデルであると言われています。これは、URLを指定するだけで自動的にデータを取得(メインクエリー)し、自動的にテンプレートファイルを選択して画面表示(メインループ)するものです。

しかし、カスタム投稿タイプやカスタムタクソノミーを使ったWebアプリケーション開発に重きを置く場合は、サブクエリーを多用する場面が増えてきます。

WordPressには、サブクエリーを効率よく開発するためのモデルがありません。

今回は、サブクエリーを効率よく開発するために、MVCモデルを適用することについて解説します。

MVCモデルは、Modelクラス、Viewクラスにコードを集約し、オブジェックト指向の継承やオーバーライドを使って、類似のコードを抽象化することによって、コーディングの作業を軽減することができます。

次にオブジェクト指向でないコード(従来の書き方)とMVCモデルを使ったオブジェクト指向のコードを比較してみることにします。

オブジェクト指向でないコード

//サブクエリー
	 $args = array(		
 //条件の記述
	 );
 //WP_Query
	 $the_query = new WP_Query($args) ;

//サブループ
	 if($the_query->have_posts()){
	   While($the_query->have_posts()){
		   $the_query->the_post();
		     //表示の記述
		     the_title() ;
	       echo "<br>\n" ;	
	   }
	 }//endif

オブジェクト指向のコード(MVCモデル)

class Controller
{
 public function __construct($var){
	   $par =(object)$var;
	   $user = new Model($args);
   または
   $user = new ViewPost() ;
   $user->format();
 }
}

class Model
{
	public function __construct($var)
	{
	
//サブクエリー
		$args = array(		
  //条件の記述
		);
  //WP_Query
		$the_query = new WP_Query($args) ;

//サブループ
		if($the_query->have_posts()){
			While($the_query->have_posts()){
				$the_query->the_post();
					//Viewクラスの呼び出し
					$user = new ViewPost() ;
                                 $user->format();
			}
		}//endif
	}//endfunction
}//endclass

class View
{
public function __format()	

	}//endfunction
}//endclass

class ViewPost extends View
{
public function __format()
			//表示
			the_title() ;
			echo "<br>\n" ;		
	}//endfunction
}//endclass
//呼び出す側 
$args = arry(
//条件の記述
);
$user  = new Controller($args);

サブクエリー(WP_Query)とサブループは、書き方のパータンがたくさんあり、すべてのパターンを覚えるのは大変なことです。そのため、書くたびにコードディングミスが起こり、完成するまでに時間がかかります。当然のことながら、これをメンテする作業も大変です。

これに対し、オブジェクト指向で書かれたコードは、呼び出す側は、フィルタリング条件を記述してクラスを呼び出すだけで、サブクエリー~サブループ~表示までの処理が完了します。
 もちろん、呼び出される側のクラスとして、Controllerクラス、Modelクラス、Viewクラスがあり、これらのコードを合わせると、オブジェクト指向を使った場合の方がコードの量は格段に増えます。しかし、これらのクラスは、再利用することを前提に作成していますので、次回からは、呼び出す側の記述のみで済みます。
 また、クラスには、スーパークラス(親クラス)の機能を継承して、差分の部分のみをサブクラス(子クラス)に記述することができ、メンテの効率が向上します。

WordPressの基本構造の概念図

WordPressの基本の理解で最も重要なことは、構造の理解です。理解するためには、図で示すことが最も近道です。
WordPressは、クエリーとループから成り立っています。

クエリー:データの検索
ループ:データの表示

WordPressの入門時に一番初めに理解すべきことは、メインクエリーとメインループですが、メインクエリーは「WordPressコア」と呼ばれる基本部分に包含されていて、通常はカスタマイズできないということです。(メインクエリーをカスタマイズするには、「フック」という特別なカスタマイズ方法を用います。)

WordPressの基本構造の概念図

WordPressのカスタマイズを理解の第一歩は、テーマの中にあるメインループを見つけ出し、ループの中の記述を自分の好みに合うようにカスタマイズし、実感をつかむことです。

<?php 
if ( have_posts() ) {
	while ( have_posts() ) {
		the_post(); 
		//
		// この部分が記述(カスタマイズ)部分
		//
	} // end while
} // end if
?>

上記のコードのif ( have_posts() )から} // end ifまでがメインループの記述で、その内側の部分がカスタマイズ部分で、ここに、たとえば、the_title();と書けば、投稿のタイトルが表示され、the_content();と書けば、投稿の本文が表示されるわけです。

<?php 
if ( have_posts() ) {
	while ( have_posts() ) {
		the_post(); 
		//記述(カスタマイズ)部分
          the_title();
          the_content();
		//
	} // end while
} // end if
?>

もう一つ重要なポイントは、このメインループが実行される手前の段階で、「WordPressコア」の中のメインクエリーが、既に実行を完了しており、その結果がオブジェクトと呼ばれるデータの塊に保持されているということです。この塊から具体的なデータを抜き出す命令が、the_title();the_content();です。このとき、データは複数件あるので、これをメインループで回して表示しています。

WordPressのカスタマイズで頻繁に出てくるサブループについては、上記の概念図に併記すると理解が深まります。
メインクエリーが「WordPressコア」の中にあって、自動的に実行されるものであるのに対し、サブクエリーは、自分でコードを書く(カスタマイズする)ことが必要ですが、行っている処理は、メインクエリーと同じです。(両方ともWP_Queryが実行されている同じ処理。)

サブクエリーの結果は、オブジェクトに出力され、それを表示するのがサブループです。メインループとサブループの書き方は、ほぼ同じです。

上記の概念図では、左から右へ「クエリー」「ループ」「表示」と情報が転送され、全体としては、上から下へ「メイン」「サブ」と処理が進んでいくことを図示しています。

WP_Queryのカスタマイズ事例(4)万能型サブクエリー

これまで、WP_Queryのカスタマイズ事例※1※2※3を示してきましたが、今回は、このうちのDestinationパターン※1とSourceパターン※2の事例を統合した万能型サブクエリーについて解説します。

WP_Queryのカスタマイズ事例(3)親子( 先祖・子孫)クエリー。

カスタム投稿タイプの先祖の表示。

前回※1 「投稿のカスタムフィールドに関連付けられた投稿の表示」で、ブログ記事に文献の情報を関連付ける事例を紹介しました。(実際の画面サンプルはこちらです。)

この例では、「第八章 月島の商業」が関連付けられていますが、この上の階層である「第三編 明治以降の月島」と最上位階層である書籍名の「月島発展史」を併せて表示しています。

カスタム投稿タイプ「参考文献」は、親子関係を持った木(ツリー)構造になっていて、最初に関連付けされた「第八章 月島の商業」をキーに、祖先(父母→祖父母)の階層を表示しています。

リスト37639は、カスタム投稿タイプの祖先を表示するコードです。

カスタム投稿タイプの子孫の表示。

カスタム投稿タイプ「参考文献」の全体を一覧表示する場合は、階層のトップのIDを指定し、それをキーに子孫の階層を上から順番に検索して表示します。(実際の画面サンプルはこちらです。)

リスト37639は、投稿の子孫を表示するコードです。WordPressのテンプレートタグ「get posts」を使って子孫を検索しています。 

タクソノミーの祖先と子孫の表示

木(ツリー)構造を持つタクソノミーの全体を表示する事例を紹介します。(実際の画面サンプルはこちらです。)

たとえば「中央区」を選択した場合、祖先に東京都、子孫に月島3丁目があります。これらの表示をクリックするとどちらにでも移動できるようにすると便利です。また、自分が現在どの階層にいるかも解りやすくなります。

リスト36732は、タクソノミーの祖先と子孫の両方を表示する事例です。現世代の「中央区」を指定すると、まずその先祖を表示し、次に子孫を表示します。

WP_Queryのカスタマイズ事例(2)Sourceパターン( meta_queryとtax_query)

リスト37167は、meta_queryの事例。
リスト37179は、tax_queryの事例です。

WP_Queryのカスタマイズ事例(1)Destinationパターン

今回は、投稿データに関連付けられたタクソノミーや別の投稿を表示する方法について紹介します。

WP_Queryは、あるデータの集合(これをエンティティと呼びます)の外部キーから別のエンティティの主キーを検索しデータ群(オブジェクト)取得する仕組み(クラス)です。
 WordPressの場合のエンティティは、「投稿タイプ」「カスタム投稿」「カテゴリー」「ターム」「カスタムタクソノミー」などのデータの集合です。これらのエンティティ同士は、主キーと外部キーで関連付けられます。

下図は、ブログ投稿の外部キーにカスタムタクソノミー「ジャンル」が関連づけられている場合を図示したものです。

Destinationパターン

リスト37209は、投稿のカスタムフィールドに関連付けられた投稿の表示の事例です。
ブログ記事のような投稿データに、別の投稿データを関連づけて表示したい場合があります。

リスト37211は、投稿に関連付けられたタクソノミーの表示の事例です。
ブログ記事のような投稿データには、タクソノミー(カテゴリー、タグ)を関連づけて記事の分類分けをしますが、このとき、ブログ記事のタイトルの上部や本文の末尾などにタクソノミーを表示したい場合があります。

ブログ投稿(Post)とジャンル(Term)のER図

WP_Queryのカスタマイズ

サブクラスにおいてWP_Queryを使うことのメリットは、拡張(継承)してカスタムクラスを作れることです。Rakhitha Nimesh Ratnayake(ラーキサ・ニーメシュ・ラーネヤク)は、その著書「WordPressによるWebアプリケーション開発」の中で、WP_Queryクラスの継承の用例を示しています。*1

リスト37188は、ラーネヤク氏が示した用例を本書のテーマに即してアレンジしたものです。
通常、WP_Queryを使うときは、次のように配列にすべてのフィルタリング条件を記述しなければなりませんが、リスト37188では、Modelクラスの中にこの記述を書いているので、呼び出す側は、1行のコードのみで済みます。

たしかに、同じフィルタリング条件を何度も繰り返し使う場合はこの方法が有効であり、クラスを継承すれば、少し異なる条件の場合も含めて抽象化できるかもしれません。

しかし、あらゆるパターンのサブクエリー(投稿の場合、タームの場合、親子の場合)と表示をすべて網羅的に抽象化するためには、もう一工夫必要です。

リスト36618は、リスト37188をアレンジし、この課題を解決するための方法です。

呼び出す側に、フィルタリング条件を羅列しますが、そこには値を直接記述します。これを受け取ったModelクラスは、その値をWP_Queryのフィルタリング条件にあてはめます。
この方法のメリットは、面倒なWP_Queryの記述から解放されるということです。
さらに、表示するViewクラスの名称なども呼び出す側の条件に加えることにより、サブクエリーから表示までを一貫して抽象化することができそうです。

Leaflet入門

「Leaflet」は、Webサイトに地図を載せる場合に利用するツールです。
「Leaflet」はフリーソフトでありながら、細かなオプションが用意されているのが特徴です。

リスト1 は、背景となる地図(ベース地図)を表示するコードです。
WordPressにLeafletを埋め込む場合は、事前準備として、function.phpに、Leafletを読み込むコードを記述します。

「日本版MapWarper」のジオリファレンス機能について

◆ジオリファレンスとは

古地図をWEB地図上に表示するためには、スキャナーやデジタルカメラなどを使って紙の地図をデジタル化し、それをWEB地図上に貼り付けるわけですが、このとき、
(1)古地図に緯度・経度の情報を付加する作業
(2)古地図を適切な形に整形して (ゆがめて) 現実の地図の上に置く作業
が必要です。この作業のことをジオリファレンスと言います。

◆日本版MapWarperについて

日本版MapWarper」は、このジオリファレンスを簡単に行うことができるツール(ジオリファレンサー)です。
オープンソース・ソフトウェアなので、誰でも無料で利用でき、公開した地図(されている地図)は、誰でも閲覧でき、ダウンロード利用できます。

◆「大正3年頃の鯖江図」のジオリファレンス事例

今回は、鯖江市が公開している古地図データ*1 を日本版MapWarperにアップロードして、ジオリファレンスを行います。

古地図

日本版MapWarperに会員登録し、ログインし、メニューの「地図をアップロードする」を使って古地図をアップロードします。

次に、「整形」の機能を使って、古地図を変形・伸縮させて現実の地図の座標に合うよう整形(ジオリファレンス)します。画面の左側が古地図、右側が現実の地図です。大正時代の地図は現在の地図にぴったりと重なりませんので、ここで補正を行います。両方の地図の一致する場所をダブルクリックして基準点を登録します。今回は、11か所の基準点を登録しました。①から⑪までの基準点が図示されています。

整形画面

最後に「切り抜き」の機能を使って古地図の余分な部分を取り除くと完成です。

「プレビュー」のタブに切り換えると、現実の地図の上に古地図が重ねられた状態が確認できます。*2

プレビュー画面

PHPのコードをパーツ化する方法(2)クラスを使う方法

前回※1、get_template_part()に引数を渡す方法を紹介しましたが、この方法では、
(1)呼び出す側にset_query_varと呼び出される側にget_query_varをその都度書かなければならないこと。
(2)PHPファイル別々に作成するので、見通しが悪くなること。
ことが、課題です。
そこで、今回は、これに代わる方法として、classを呼び出す方法を紹介します。


PHPのコードをパーツ化する方法(1)get_template_part()で引数を渡す方法

WordPressのカスタマイズの規模が大きくなると、8割~9割は同じようなPHPのコードを何度も書いていることがあります。このようなときは、別ファイルを作成してソースコードを分割し、コードを再利用することにします。
分割した別ファイルは、get_template_part()によって呼び出しますが、このとき、再利用の度合いを高めるために引数を渡したい場合があります。

WordPressCodexには、テンプレートに変数を渡す方法が解説されています。
今回は、一例として、引数taxと引数termを渡して、テンプレート側サブクエリーを実行する例を紹介します。