Laravelアプリケーションにサイトマップを導入する

laravel-sitemapというライブラリを使用してLaravelアプリケーションにサイトマップを導入する
最新版はGitLabにあるらしい
https://gitlab.com/Laravelium/Sitemap

で、インストールしようとしたのだが以下の様にGitLabの認証が必要と言われてインストール出来ない。

Cloning failed, enter your GitLab credentials to access private repos

いろいろ試しているとLaravel 6.x, 7.x 対応のバージョンだと認証なしでダウンロードできる様だが、5.x対応のバージョンだとGitLab認証が求められてしまう模様
本番環境のコンテナは自動ビルドなので認証求められるのは辛い・・・。
これは本ライブラリの仕様なのか設定ミスなのかよくわからないが一旦見送る。

もう1つのライブラリ

サイトマップを生成するライブラリはもう一つ、spatie/laravel-sitemapというのがあって、英語で検索するとこちらのほうが検索上位だったりする。

packagistのインストール数もspatie/laravel-sitemapの方が多い

spatie/laravel-sitemapをインストールする

という訳でspatie/laravel-sitemapをインストールします。

readmeを読んでいて気づいたのだが、このライブラリはサイトをクロールしてサイトマップを作ってくれるらしい。
設定すればJavaScriptも実行してリンクを辿るとの事。
ちなみに以下のコードでクロールできる。

use Spatie\Sitemap\SitemapGenerator;

SitemapGenerator::create('https://example.com')->writeToFile($path);

どうやって実行するかには言及されていないので、コマンドを作って毎日n時に実行とかしとけばOKだろ(多分)
という訳でコマンドを作って実行してみた。

class SitemapGeneratingCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sitemap:generate';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $path = Storage::disk('local')->path('sitemap.xml');
        SitemapGenerator::create(config('app.url'))->writeToFile($path);
    }
}
php artisan sitemap:generate

そして出力されたのがこちらのxml
空なんだが・・・?

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
</urlset>

あー。この処理を実行するdockerコンテナ内の/etc/hostsにはドメインが記載されていないから、ローカル環境はクロールできないか。
本番環境のURLを指定したら一応、動いた。

対象のサイトはJavaScriptゴリゴリなので、全然リンクが拾えてない。

config/sitemap.phpexecute_javascriptをtrueにするとJSも処理されるらしいので有効にして再実行してみる。

以下のエラーが発生した。
どうやらnpmとnodeに依存しているらしい。(nodeからbrower.jsを実行しようとしている)

Symfony\Component\Process\Exception\ProcessFailedException  : The command "PATH=$PATH:/usr/local/bin NODE_PATH=`npm root -g` node '/var/www/app/vendor/spatie/browsershot/src/../bin/browser.js'

...(略)...

Error Output:
================
sh: npm: not found
sh: node: not found

うーん、このためだけにコンテナにnodeとnpmを追加するの微妙だな・・・。

ARCANEDEV/LaravelSitemapを導入する。

ARCANEDEV/LaravelSitemapというライブラリもあって、こちらはシンプルにxmlを構築できるだけっぽい。
packagistのインストール数も上記2つほど多くない。
というわけでこちらを入れてみる。

Laravelのレスポンスを構築してくれるのでControllerにこんな感じで書ける

    public function posts()
    {
        $manager = new SitemapManager();

        $map = Sitemap::make()->setPath(action('SitemapController@posts'));
        Post::all()->each(function (Post $discussion) use ($map) {
            $url = action('PostController@read', [
                'discussion' => $discussion->id
            ]);
            $map->create($url, function (Url $url) use ($discussion) {
                $url->setLastMod($discussion->updated_at)
                    ->setChangeFreq('weekly')
                    ->setPriority(1.0);
            });
        });
        $manager->add('dummy', $map);

        return $manager->respond();
    }

で、実際にURLを開いたら以下のエラーが出た・・・。

No hint path defined for [sitemap]

以下の箇所で、viewsの名前空間sitemapにアクセスしているが、名前空間がちゃんと登録されていないためエラーが発生している。

publishもやっていてresources/views/vendor/sitemapも存在するのに何故・・・?

php artisan vendor:publish --provider="Arcanedev\LaravelSitemap\LaravelSitemapServiceProvider"

Laravel 5.x系なのでライブラリ側がちゃんと対応できてないのかも。
一応、AppServiceProviderbootメソッドに以下を追記してやると、viewsの名前空間が登録されて、上記のエラーが回避できる。
今回はこれで回避する事にした。(ここまでさんざん他のライブラリにもハマって来たので心が折れた)

$this->loadViewsFrom(resource_path('views/vendor/sitemap'), 'sitemap');

紆余曲折ありつつも、sitemap.xmlが取得できる状態になった。

robots.txtにサイトマップのパスを記述する

/public/robots.txtに追記する

User-agent: *
Disallow:

Sitemap: https://your-domain/sitemap.xml

Search Consoleにサイトマップを登録する

サイトマップの登録おわり!
ライブラリ選定で時間掛かりすぎて肝心のサイトマップの内容をやっつけで作ってしまった。
近いうちに見直す!

コメントする