SOY CMSでサイトマップ結合プラグインを作成しましたで、SOY CMSとSOY Shopで作成した各々のサイトマップのXMLファイルを統合して、一枚のXMLファイルを生成するプラグインを紹介しました。


このプラグインを活用して、サイトマップのページを作成したいという要望がありましたので、

SOY CMSのモジュールを活用して、サイトマップのページを作成してみます。


モジュールについては下記の記事をご覧ください。

SOY CMSでどのページでも使えるブログのサイドバーを作ってみた

SOY CMS/ShopでPHPモジュールに使用の制限を設けました


はじめに



サイトマップ用のモジュールを作成します。

このモジュールのタグをサイトマップを表示したいページに貼り付けます。


ページにタグを貼り付けたら、モジュールのエディタを開き、コードを書いていきます。

コードを作成するに当たって行わければならないことは、

・サイトマップ統合プラグインで作成したXMLファイルを読み込む

・読み込んだサイトマップから各ページへのリンクを生成する


リンクの生成に関して、一点程問題が生じる。

それは、


<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<url>
		<loc>http://example.com/</loc>
		<priority>1</priority>
		<lastmod>2016-09-10T11:48:51+09:00</lastmod>
	</url>
</urlset>

生成されるXMLを読むと、ページ名が登録されていないということ。

読み込んだXMLからリンク一覧を作成する際、ページ名を取得する処理を加えなければならない。


ページ名の取得を考えてみたところ、

ページ名を取得するときは、対象となるページのHTMLを取得して、head内にあるtitleタグの値を取得すれば良さそうなので、この処理を追加することにしよう。


これらを踏まえてコードを書いてみた。


//サイトマップ統合プラグインで生成したXMLファイルを取得する。
$xml = simplexml_load_string(file_get_contents("http://example.com/merge.xml"));

$htmls = array();

//念の為にXMLファイルにURLが格納されているか調べてからHTMLに出力する
if(count($xml->url)){
	$htmls[] = "<ul>";
	foreach($xml->url as $obj){
		//XMLに記述されている各ページのHTMLを取得する
		$html = @file_get_contents($obj->loc);

		//HTMLを取得出来なかった場合はスルー
		if(is_null($html)) continue;

		//titleタグに記述されている文字列を取得して、リンクを生成する
		if(preg_match('/<title>(.*)<\/title>/', $html, $tmp)){
			$htmls[] = "<li><a href=\"" . $obj->loc . "\">" . htmlspecialchars($tmp[1], ENT_QUOTES, "UTF-8") . "</a></li>";
		}
	}
	$htmls[] = "</ul>";
}

echo implode("\n", $htmls);

これでなんとか出来そうだと実行してみたところ無限ループにハマった。

どこでハマった調べてみたら、

XMLに記述されている各ページのURLからHTMLファイルを取得する処理で、

今回のモジュールのタグを設置したページからHTMLを取得する際、再起みたいに何度もこのモジュールが発生するらしい。


この問題を避けるために、


//GETでxml_searchというindexがある場合は処理を行わない
if(isset($_GET["xml_search"])) return;

$xml = simplexml_load_string(file_get_contents("http://example.com/merge.xml"));

$htmls = array();
if(count($xml->url)){
	$htmls[] = "<ul>";
	foreach($xml->url as $obj){
		//HTMLを取得する際、URLの末尾に?xml_searchを追加しておく
		$html = @file_get_contents($obj->loc . "?xml_search");

		if(is_null($html)) continue;

		if(preg_match('/<title>(.*)<\/title>/', $html, $tmp)){
			$htmls[] = "<li><a href=\"" . $obj->loc . "\">" . htmlspecialchars($tmp[1], ENT_QUOTES, "UTF-8") . "</a></li>";
		}
	}
	$htmls[] = "</ul>";
}

echo implode("\n", $htmls);

上記の様にHTMLを取得する際に、xml_searchというGETのパラメータを追加しておき、このパラメータがあるページでは、今回のモジュールは実行しないという処理を追加することで、再起っぽい関数の実行を避けることができた。

※タグを設置したページを最初から除外しておく方法もある


とりあえず表示の確認をしてみると、



荒削りながら出来た。

各ページのタイトルの表記はPHPの処理でどうにかしたり、

各ページを出力する際に丁寧に設定することで回避できるからこれ以上触れないとして、


それ以上に深刻な問題がある。


それは、

このHTMLを出力する処理が半端無く重い!

ということ


なので、

キャッシュの生成といった処理が必要になりそうだ。


-続く-