ウェブサイトの構成によっては、そのすべてのページを Google などの検索エンジンが検出できない場合があります。そのような場合は、XML サイトマップを作成し、その存在を知らせることで、サイトの構成を検索エンジンに正しく伝えることが出来ます。
XML サイトマップとは、sitemaps.org の定めるフォーマットに沿って書かれた XML ドキュメントのことです。Drupal には、XML サイトマップを作成するためのサードパーティー製モジュールがいくつか存在しますが、ここではそういったモジュールは使わずに、「Views で XML サイトマップを作る」ということをやってみたいと思います。
Views には RSS を生成する機能があります。今回作成する XML サイトマップは、これに近いものです。RSS の表示は views_plugin_display_feed.inc(/sites/all/modules/views/plugins/views_plugin_display_feed.inc)というディスプレイプラグインが担っています。今回はこれを参考に、XML 用のディスプレイプラグインを作成します。プラグインの内容は以下のようになります。
<?php /** * @file * XML ディスプレイプラグイン。 */ /** * XML サイトマップのような、XML ドキュメントの出力を行います。 * @ingroup views_display_plugins */ class custom_plugin_display_xml extends views_plugin_display_page { function uses_breadcrumb() { return FALSE; } /** * ここで NULL を返すことで、Drupal はページ全体の通常の生成過程は * 行わず、内容のみを表示させることが出来ます。 */ function execute() { $output = $this->view->render(); if (empty($output)) { return drupal_not_found(); } // ヘッダー情報を追加 drupal_add_http_header('Content-Type', 'application/xml; charset=utf-8'); print $output; } function preview() { if (!empty($this->view->live_preview)) { return '<pre>' . check_plain($this->view->render()) . '</pre>'; } return $this->view->render(); } }
これを、カスタムモジュール内の views フォルダ(/sites/all/modules/custom/custom/views/)に custom_plugin_display_xml.inc として配置します。(※ views フォルダが無い場合は、作成してください。カスタムモジュールをまだ作成していない場合は、カスタムモジュールの作り方を参考に、作成&有効化してください。)
プラグインの場所を Views に知らせるために、カスタムモジュールの .info ファイル(/sites/all/modules/custom/custom/custom.info)に以下の行を追加します。
files[] = views/custom_plugin_display_xml.inc
次に、プラグインの内容を Views に伝えるため、モジュール名.views.inc ファイルをカスタムモジュールの views フォルダに設置し(/sites/all/modules/custom/custom/views/custom.views.inc)、そこに hook_views_plugins() を実装します。
/** * hook_views_plugins() の実装 */ function custom_views_plugins() { $plugins = array( 'display' => array( 'custom xml' => array( 'title' => t('Custom Xml'), 'help' => t('xml ドキュメントを生成します。'), 'handler' => 'custom_plugin_display_xml',// さきほど作成したディスプレイプラグインの名前です。 'theme' => 'views_view', 'uses hook menu' => TRUE, 'use ajax' => FALSE, 'use pager' => FALSE, 'accept attachments' => FALSE, 'admin' => t('Custom Xml'), 'help topic' => 'display-xml', ), ), ); return $plugins; }
次に、これらの設定を適用させるため、カスタムモジュールに hook_views_api() を実装します。
/** * hook_views_api() の実装 */ function custom_views_api() { return array( 'api' => 3.0, 'path' => drupal_get_path('module', 'custom') .'/views', 'template path' => drupal_get_path('module', 'custom') .'/views/templates', ); }
ここまで完了したら、モジュール管理ページ(「管理」 > 「モジュール」)から、画面下「設定を保存」ボタンをクリックして、モジュールの設定を再構築します。そのあと、「管理」 > 「環境設定」 > 「開発」 > 「パフォーマンス」から、「すべてのキャッシュをクリアー」ボタンをクリックして、キャッシュをクリアしてください。
これで、Views に XML ドキュメントを出力させる準備が出来ました。(※ 難しいのはここまでです。ここからは通常の Views の操作に入ります。)
「管理」 > 「サイト構築」 > Views にアクセスし、「Add new view」をクリック。
View name に「XML サイトマップ」、システム内部名称に「sitemap_xml」と入力、表示のところは「コンテンツ」 of the 「すべて」となるように選択します。「Create a page」のチェックを外し、「Continue & edit」ボタンをクリックします。
ビューの設定画面です。ディスプレイの「+Add」ボタンをクリックすると、今作成した「Custom Xml」ディスプレイが選択肢に入っているので、クリックしてください。
「Custom Xml」ディスプレイの設定画面になりました。真ん中の PAGE SETTINGS のところ、パスに「sitemap.xml」と入力し、画面右上、「保存」ボタンをクリックし、とりあえず設定を保存します。
「/sitemap.xml」にアクセスすると、上のように表示されると思います(Chrome の場合)。プラグインの設定どおり、Drupal の通常のページ生成処理は行われず、ビューの内容のみが出力されています。ヘッダー情報に 'application/xml' と指定しているので、ブラウザでは HTML としてのレンダリングは行われず、XML 文書として、タグがそのまま表示されています。
sitemaps.org のフォーマットに沿って、全体のマークアップを整形します。もういちど、ビューの設定画面に戻ってください。
画面右側、Advanced エリアをクリックして開き、Theme: information のリンクをクリック。
テーマに関する情報が表示されます。このうちの Display output というのは、ビュー全体に適用されるテーマです。横に並んでいる .tpl.php で終わる文字列の集合は、テンプレートファイルとして適用され得る名前を、適用範囲の広い順に並べられたものです。太字のものが、現在適用されているテンプレートの名前です。ここでは「XML サイトマップ」ビューだけに適用されるテンプレートを作成するため、views-view--sitemap-xml.tpl.php という名前のファイルを、カスタムモジュールの views > templates フォルダ内(/sites/all/modules/custom/custom/views/templates/)に配置してください(※ templates フォルダが無い場合は、作成してください)。内容は、以下のようになります。
<<?php print '?xml '; ?>version="1.0" encoding="UTF-8"<?php print '?'; ?>> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc><?php print $GLOBALS['base_url'] . $GLOBALS['base_path']; ?></loc> <lastmod><?php print date('c'); ?></lastmod> <changefreq>always</changefreq> <priority>1.0</priority> </url> <?php if ($header): ?> <?php print $header; ?> <?php endif; ?> <?php if ($attachment_before): ?> <?php print $attachment_before; ?> <?php endif; ?> <?php if ($rows): ?> <?php print $rows; ?> <?php endif; ?> <?php if ($attachment_after): ?> <?php print $attachment_after; ?> <?php endif; ?> <?php if ($footer): ?> <?php print $footer; ?> <?php endif; ?> </urlset>
sitemap.org のフォーマットに従い、全体を <urlset> タグでマークアップしています。以下、<url> タグが続くわけですが、トップページは固定で良いので、ここに直接記述しています。そのほかの動的な部分は、各変数のところに出力されます。図8 のテーマに関する情報の画面下「Rescan template files」ボタンをクリックし、テーマレジストリを再構築したら、/sitemap.xml ページを見てみましょう。
テーマが適用され、全体が <urlset> でマークアップされました。
次に、<url> 属性以下の、各項目を追加していきます。ビューの設定画面に戻ってください。
画面左側、FIELDS の設定を行います。まず、タイトルは使用しないので削除します。(※ 「タイトル」をクリックし、設定画面下「削除」ボタンをクリック。)
タイトルを削除したら、FIELDS の横の「追加」ボタンをクリック。
「コンテンツ: パス」、「コンテンツ: Updated/commented date」、「Global: Custom text」を選択します。これらは XML サイトマップの各 url においてそれぞれ、<loc>、<lastmod>、<changefreq> の項目となります。「Apply (all displays)」ボタンをクリックしてください。
各設定では、「Create a label」のチェックをはずし、少し下の STYLE SETTINGS では、「Customize field HTML」、「Customize label HTML」、「Customize field and label HTML」すべてにチェックを入れ、それぞれ HTML element セレクトボックスに「- なし -」を選択します(※ これで、フィールドの規定のマークアップはすべて取り除かれます)。
コンテンツ: Updated/commented date の設定では、日付の書式に「カスタム」を選択、Custom date format には「c」と入力してください。(※ これで、「2012-12-03T12:15:37+09:00」といったような、ISO 8601 の書式が適用されます。)Global: Custom text では、テキストに「monthly」等、<changefreq> 属性で指定したい値を入力してください。
順番を修正したい場合は、「追加」の脇のボタンをクリックし、「rearrange」をクリック、Rearrange fields の画面でフィールドをドラッグして順番を修正できます。
もうひとつ、各url における <priority> を追加したい場合は、Global: Custom text をもうひとつ追加します。設定は1つめの Custom text と同様にし、テキストには 0.5 など、<priority> 属性で指定したい値を入力してください。
このあたりでいちど設定を保存し、出力を確認してみましょう。
トップページより下の各行が <div> でマークアップされていますが、その中の各フィールドはマークアップが除外され、そのまま出力されています。あといくつかテンプレートを修正し、これらの出力を整えていきます。
「行」のテンプレートを修正してみましょう。<div> タグが適用されているのを、<url> タグに修正します。これは、図8 のところの、Style output のテンプレートになります。views-view-unformatted--sitemap-xml.tpl.php をカスタムモジュールの views > templates フォルダに作成し(/sites/all/modules/custom/custom/views/templates/views-view-unformatted--sitemap-xml.tpl.php)、内容を以下のように修正します。
<?php /** * XML サイトマップ用テンプレート * <h3> タグを削除 * $row のラッパーを <url> タグに。 */ ?> <?php foreach ($rows as $id => $row): ?> <url> <?php print $row; ?> </url> <?php endforeach; ?>
次に「パス」フィールドのテンプレートを修正します。これは、図8 のところの、Field コンテンツ: パス (ID: path) のテンプレートになります。views-view-field--sitemap-xml--path.tpl.php をカスタムモジュールの views > templates フォルダに作成し(/sites/all/modules/custom/custom/views/templates/views-view-field--sitemap-xml--path.tpl.php)、内容を以下のように修正します。
<?php /** * $output の前に $GLOBALS['base_url'] を追加し、エンティティのエスケープ処理。 * <loc></loc> でラップ。 */ ?> <loc><?php print htmlentities($GLOBALS['base_url'] . $output, ENT_QUOTES, 'UTF-8'); ?></loc>
次に「Updated/commented date」フィールドのテンプレートを修正します。これは、図8 のところの、Field コンテンツ: Updated/commented date (ID: last_updated) のテンプレートになります。views-view-field--sitemap-xml--last-updated.tpl.php をカスタムモジュールの views > templates フォルダに作成し(/sites/all/modules/custom/custom/views/templates/views-view-field--sitemap-xml--last-updated.tpl.php)、内容を以下のように修正します。
<?php /** * <lastmod> でラップ。 */ ?> <lastmod><?php print $output; ?></lastmod>
次に「Custom text」フィールドのテンプレートを修正します。これは、図8 のところの、Field Global: Custom text (ID: nothing) のテンプレートになります。views-view-field--sitemap-xml--nothing.tpl.php をカスタムモジュールの views > templates フォルダに作成し(/sites/all/modules/custom/custom/views/templates/views-view-field--sitemap-xml--nothing.tpl.php)、内容を以下のように修正します。
<?php /** * <changefreq> でラップ。 */ ?> <changefreq><?php print $output; ?></changefreq>
次に、もうひとつの「Custom text」フィールドのテンプレートを修正します。これは、図8 のところの、Field Global: Custom text (ID: nothing_1) のテンプレートになります。views-view-field--sitemap-xml--nothing-1.tpl.php をカスタムモジュールの views > templates フォルダに作成し(/sites/all/modules/custom/custom/views/templates/views-view-field--sitemap-xml--nothing-1.tpl.php)、内容を以下のように修正します。
<?php /** * <priority> でラップ */ ?> <priority><?php print $output; ?></priority>
これで完了です。テンプレートディレクトリを再構築して、出力を確認してみましょう。
sitemap.org のフォーマットに沿った XML サイトマップが出来上がりました。これは Google などの検索エンジンで、正しく認識されます。
以上、Views で XML サイトマップを生成する「基本」を説明してきましたが、いかがだったでしょうか。これをさらにカスタマイズして、<changefreq> や <priority> をコンテンツタイプごとに設定する、といったことも出来ます(※1)。また、タクソノミータームのページを加えることも出来ます。
それらの応用は、Views の基本的な動作を理解していれば、それほど難しくはありません。頭の体操なので、是非チャレンジしてみてください。
※1 ヒント: FILTER CRITERIA でコンテンツタイプを絞る→「添付」ディスプレイを追加し、メインとは別のフィルターをかける→今回作成した「Custom XML」ディスプレイで、ヘッダー/フッターから、添付ディスプレイを取り込む。