ラムネグから一言:寝る前に読むとくだらなすぎて逆に寝れると好評なすごい適当なブログをこっちではじめてます.
laravelでsitemap.xml作成とネット検索すると「laravelium/sitemap」っていうパッケージ?プラグインみたいなので簡単に作れるよ!って出てきます。
実際わたし自身、2020年くらいにlaravelで作ったサイトではこの「laravelium/sitemap」でサイトマップを作ってたんです。
ただ、今2022年、新しいlaravel8で動いているサイトでこの「laravelium/sitemap」をインストールしようとするとエラーが出ます。
確か「illuminate/support」がどうたらこうたら、みたいなエラー。なんとなく英語のエラー斜め読みした感じですが、
- 「laravelium/sitemap」を使うにはこれこれこのバージョンの「illuminate/support」が必要だけれど、キミの環境の「illuminate/support」とはバージョン合わないよね?んじゃインストールできないよ。
てことだと思います。
確かによーく調べてみると「laravelium/sitemap」は最終更新が2年前で止まってるんですよね。そりゃ現行のlaravelには合わないよなーと。
てことでlaravelでサイトマップ(sitemap.xml)を自作しました。参考にさせてもらったサイトに、laravelでサイトマップを作る骨子は載ってたんですが、細かい部分が抜けてて、んじゃそこらへんまとめられたらなーってことで。
ほぼコピペでいけると思うんで参考にしてみてください。
sitemap.xmlの基礎
laravelでsitemap.xmlを自作する前に、まずサイトマップの基礎をさくっとおさらいしときます。
sitemap.xmlは一つで作る事もできますが、記載できるURLが50,000個までと決まっています。なのでできれば親サイトマップと子サイトマップに分けておいた方が将来的に楽ができます。
グーグルのサーチコンソールに登録するのは親サイトマップだけでよくて、この親には子サイトマップのURLが載ってるので後はグーグルさんが勝手にその子サイトマップのURLから子サイトマップの情報を取得してくれるってワケ。
はい、おさらい終了!
①まずコントローラー作る
んじゃlaravelでsitemap.xmlを自作していきます。上で書いたように親サイトマップと子サイトマップを分けて作っていきます。
まずコントローラーを作ります。ここらへんはlaravelしてるなら当たり前の部分ですよね。
php artisan make:controller SitemapController
②web.phpにルートを記載
次にグーグルのクローラーがsitemap.xmlを見に来た時用のURLをweb.phpに記述します。
web.php
Route::get('/sitemap.xml', 'App\Http\Controllers\SitemapController@sitemap')->name('sitemap.sitemap');
Route::get('/sitemap/○○.xml','App\Http\Controllers\SitemapController@○○')->name('sitemap.○○');
Route::get('/sitemap/××.xml','App\Http\Controllers\SitemapController@××')->name('sitemap.××');
Route::get('/sitemap/△△.xml','App\Http\Controllers\SitemapController@△△')->name('sitemap.△△');
一行目がおさらいのところで書いた親サイトマップのルート設定、んで下3行が子サイトマップのルート設定です。
○○やら××やらの部分は自分で決めてくださいね。例えば「posts」っていうテーブルにたくさん記事データが入ってて、それらを一つずつサイトマップに記載したいならpostとか、categoriesにカテゴリが入っててカテゴリページもsitemapに載せたいならcategoryとか。なんでもいいです。
また4つ5つと増やしてもOK。tagsにタグ情報が入っててタグページもsitemapに入れたかったら一行増やしてtagにすればOKです。
一応ここから続くサンプルとしては○○に「post」、××に「category」、△△に「other」と入れた場合で書いていきますね。
③SitemapControllerの中身を書く
んじゃ続いて①で作ったサイトマップ用のコントローラー(別に既存のコントローラーに書いてもいいんですが分けておいた方が分かりやすいと思います)の中身をゴリゴリ書いていきましょう。
もし偶然postとcategoryでやってる人がいるならこのままコピペすれば動きます。そうじゃない場合は自分の環境に合わせて叩くテーブルを変えてくださいね。
SitemapController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post;
use App\Models\Category;
class SitemapController extends Controller
{
/************************************************
* 親サイトマップ
*/
public function sitemap(){
return response()->view('sitemap.sitemap')->header('Content-Type', 'text/xml');
}
/************************************************
* 子サイトマップ(記事)
*/
public function post(){
$posts = Post::all();
return response()->view('sitemap.post', compact('posts'))->header('Content-Type', 'text/xml');
}
/************************************************
* 子サイトマップ(カテゴリ)
*/
public function category(){
$categories = Category::all();
return response()->view('sitemap.category', compact('categories'))->header('Content-Type', 'text/xml');
}
/************************************************
* サイトマップその他もろもろ
*/
public function other(){
return response()->view('sitemap.other')->header('Content-Type', 'text/xml');
}
}
ポイントとしては「->all()
」でそのテーブルの全情報をゲットしてる所だと思います。
普通ならそんなことして、そしてレコード大量だったりしたらすんごい処理に時間がかかっちゃうんですがsitemap.xmlは人が見るやつじゃないんで構いません。そんなSEO的な表示速度を追い求める必要がないんですね。
なぜ「response()」やら「header()」やらが必要なのかは、スミマセン、私もよくわかってません。ここらへんは参考にした記事のまんまです。headerの方は一応わかりますがresponse()は…、一度なくしてやってみたら確かにエラーになりました。必要ってことはわかりました。
④それぞれのbladeファイルを作成&書く
上での例でいうとそれぞれ、
- sitemap/sitemap.blade.php
- sitemap/post.blade.php
- sitemap/category.blade.php
- sitemap/other.blade.php
を作ります。
「views」フォルダ内にまず「sitemap」フォルダを作って、その中にsitemap,post,cateogry,otherそれぞれのbladeファイルを作ります。
んで中をゴリゴリ書いていきます。
親サイトマップのサンプル(コピペ可)
sitemap.blade.php
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>{{ route('sitemap.post') }}</loc>
</sitemap>
<sitemap>
<loc>{{ route('sitemap.category') }}</loc>
</sitemap>
<sitemap>
<loc>{{ route('sitemap.other') }}</loc>
</sitemap>
</sitemapindex>
ポイントは「locの部分だけイジる事」です。他はおまじないだと思ってください。htmlでいう所のhtml lang="ja"
とかそういうのと同じです。
てことでpostとかcategoryじゃないならこのlocの所をご自身の環境に合わせて変えてくださいね。んで4つ目5つ目の子サイトマップがある場合は、
<sitemap>
<loc>{{ route('sitemap.~~') }}</loc>
</sitemap>
とsitemapタグを含む3行をどんどん増やしていけばOKです。
また「なんで一行目だけechoしてるの?」という部分に関しては参考にした記事によるとこうしないと認識しないから、だそうです。先人様サマサマですね。
子サイトマップサンプル
post.blade.php
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@foreach ($posts as $post)
<url>
<loc>{{ route('post', $post->slug ) }}</loc>
<lastmod>{{ $post->updated_at->format('c') }}</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
@endforeach
</urlset>
まず大事なのがいじるのはforeachタグの中4行分だけってこと。それ以外はおまじないです。あと普通のbladeファイルと全く同じなのでいろんな命令(例えば@ifとか@phpとか)はそのまま使えます。
やってることはコントローラーからもらった$postsをぐるぐる回して、一個ずつ記事情報を載せてってるだけです。
ここでも一番大事なのはlocの個所で、ここにその記事のURLが入るようにしましょう。たぶん環境によってroute()の書き方が変わってくると思います。
んでSEOの記事によるとchangefreqとpriorityに関してはグーグルは考慮してないらしいんでいらないかも。まー確かにサイト作った人が「このページ大事だから!」っていくら吠えたところでそんなの天下のグーグル様は気にしないのが普通かーと思いますよね。
「lastmod」は最終更新日を入れる欄で、ここはたぶんグーグルも見てるはずなんでちょっとはこだわりましょう。…でも「lastmod」はちょっと厄介なんです。
記事データとかならlaravelだと普通にやってればupdated_atに更新日を入れてくれてるんでそれをformat関数でsitemap.xmlに合う形式に変換(オプション「c」で一発変換出来ちゃいます)すればいいだけで特に難しくないんですが、例えばcategoryページの最終更新日時って難しくないですか?
たぶんcategoryのテーブルに入ってるupdated_atの値はカテゴリ自体(カテゴリ名とかカテゴリスラッグとか)が変更された時刻が入ってるのが普通だと思うので、ここは各自腕の見せ所だと思います。
例えばcategoriesだけではきちんとしたlastmodを設定できないんで、「そのカテゴリの記事が最後に追加された日時」をSitemapControllerの段階でクエリを使って求めるように追記したり。こだわるならなんかそういう一手間がいると思います。
other.blade.phpにはトップページとかを書く
んでcategory.blade.phpはpost.blade.phpと同じでぐるぐる回すだけなんで割愛して、最後に残った子サイトマップであるohter.blade.phpを。
otherってなんやねん、って話なんですがここにはサイトトップページとかお問い合わせページ、そういった単発モノのURLを記載していきます。
other.blade.php
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>{{ route('index') }}</loc>
<lastmod>{{ ********* }}</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>{{ route('contact') }}</loc>
<lastmod>{{ ********* }}</lastmod>
<changefreq>monthly</changefreq>
<priority>0.1</priority>
</url>
</urlset>
ここも一番厄介なのは「lastmod」。サンプル内では「*********」で書いちゃいましたがたぶん人によって取り方が全然違ってくるのでコピペではできない部分になります。
トップページについてはそのサイトのトップページにどんな情報を載せてるかで最終更新日時、というか内容が変わったタイミングって変わってくると思います。
自分のサイトのトップページにどんなものを載せてるのかを考えて一番しっくりくる時刻を設定しましょう。ここでもさっきと同じでcreated_atやupdated_atに「->format('c')
」すればsitemap.xmlに乗せる時刻形式に変えてくれます。
またコンタクトとかはそもそも更新も何もそのページはずーっと変更しないと思うんで、lastmodの値も決め打ちでイイと思います。
さっきからsitemap.xmlに乗せる時刻形式って書いてますが、こんなのです。
- 2022-09-18T23:43:24+09:00
日付と時刻の間に「T」が入ってることと、末尾に「+09:00」が入るのだけがミソで他は普通です。
なんか適当にサイトを公開した日付っぽく書いておけばいいと思います。そもそもお問い合わせページをsitemap.xmlに乗せる必要もないかもしれないですね。そこまで大事じゃないし。
完成!
これで後はグーグルサーチコンソールに登録してサイトマップの所からsitemap.xmlを送信すればOK!
お疲れさまでした。
まとめ
今回はlaravelでsitemap.xmlを自作する方法を書きました。できるだけコピペで済むように具体的なソースコードでサンプルを示したつもりです。
laravelでsitemap.xmlを自作する際のキモとしては、
- 「
->format('c')
」でW3C形式、つまりsitemapの時刻形式に一発変換できること - 結局やってるのはグーグルさんが来たとき用のページ(でもhtmlじゃなくてxml)をbladeで作ってるだけってこと
- 「->all()」がちょっと怖いかもだけど人が見るページじゃないから大丈夫!ってこと
の3つくらいだと思います。
頑張って作ってみてくださいね。…というかlaravel、サイトマップ作成昨日くらいデフォルトで持っといてほしい。プラグインというかパッケージも2年前で止まってるという…。
参考記事
https://zenn.dev/naoki0722/articles/222ac2d3377daf【おしらせ、というか完全なる宣伝】
文体がもうぜんぜん適当すぎてあれだけどものすごい自由に書いてるブログ「檸檬だくだく」もよろしく.寝る前に読める恐ろしくくだらないやつです.
こんなにも一ミリも目を引かれないタイトルを取り扱ってます: ココア20g / ハイチュウとかってさ / なぜ米と小麦を食べようと思ったのかの謎 /