CakePHP4でサイトマップXMLを作成するコマンドをcronジョブに登録する方法
CakePHP4でプログラムを定期実行する
目的:ブログページのサイトマップXMLを作成すること、SEO対策
cronジョブを登録するときに共有サーバーでよくやるのは root/bin 配下にファイルを配置して、ウィザードでcrontabに登録する方法だと思う。では、CakePHPではどのようにcrontabに登録するのか見ていく。
CakePHP公式 - cron ジョブに登録してシェルを実行する
現時点ではシェルというやり方とコマンドオブジェクトという選択肢があるようだが、公式によると、シェルは非推奨となっていることがわかる。
”バージョン 3.6.0 で非推奨: Shell は 3.6.0 で非推奨ですが、 5.x までは削除されません。 代わりに コマンドオブジェクト を使用してください。”
ということで今回はコマンドオブジェクトでやっていく。
cronへの登録
さっそくcrontabにどのように記述するかの結論から。
# 毎日10時05分に実行
5 10 * * * cd /full/path/to/ROOT && bin/cake sitemap
どういうことかというと、cake/binコマンドが叩けるのはルートディレクトリ上なのでcdコマンドでルートディレクトリに移動する。そしてbin/cakeコマンドを叩くというわけだ。 このときのsitemapというのはコマンドオブジェクトのファイル名に由来する。 ではサイトマップ XMLを作成する実行ファイルを作っていく。
コマンドオブジェクト 実行ファイル作成
- root/srcディレクトリは以下に「Command」の名前でディレクトリを作成する
- SitemapCommand.phpの名前でファイルを作成する。
.
└── src
└── Command
└── SitemapCommand.php
ファイル名をSitemapCommand.phpとし、クラスを作成することでbin/cake sitemapというコマンドが実行可能となる。
// SitemapCommand.php
<?php
declare(strict_types=1);
namespace App\Command;
use Cake\Command\Command;
use Cake\Console\Arguments;
use Cake\Console\ConsoleIo;
class SitemapCommand extends Command
{
// デフォルトのテーブルを定義。
protected $defaultTable = 'Blogs';
public function execute(Arguments $args, ConsoleIo $io): ?int
{
// データベースからデータ取得
$query = $this->fetchTable()->find()->innerJoinWith('BlogsCategories')->limit('1000');
$blogs = $query->select(['cat_label' => 'BlogsCategories.category_label', 'slug' => 'Blogs.slug', 'modified' => 'Blogs.modified']);
// XML作成
$xml_date = '<?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" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">';
foreach ($blogs as $blog){
$url = BASE_URL . "/blogs/" . $blog->cat_label . "/" . $blog->slug . "/";
$modify_date = new \DateTime("$blog->modified", new \DateTimeZone('Asia/Tokyo'));
$modified_iso8601 = $modify_date->format('Y-m-d\TH:i:s') . '+09:00';
$xml_date .= '<url><loc>' . $url . '</loc><lastmod>' . $modified_iso8601 . '</lastmod><changefreq>monthly</changefreq><priority>0.8</priority></url>';
}
$xml_date .= '</urlset>';
// XML保存
file_put_contents(ROOT . "/webroot/sitemap.xml", $xml_date);
$io->out(print_r($xml_date, true));
return null;
}
}
POINT
- rotected $defaultTable = '***';部分にテーブルを定義することで引数なしで
fetchTable()
が使えるようになる。 - ※保存先はROOT/webroot/sitemap.xml ROOT/sitemap.xmlだと404になるので注意。
- CakePHPプロジェクトにおいて https://devil-code.com/sitemap.xml を表示したい場合はwebroot配下に置く。CSSも同様にhttps://devil-code.com/css/style.css はwebroot/css/style.cssとなる。
- urlタグの上限数が50,000でファイルサイズは10MB以下にする必要がある。
sitemap.xmlの形式
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://devil-code.com/blogs/mysql/calender/</loc>
<lastmod>2022-11-26T13:48:00+09:00</lastmod>
</url>
</urlset>
POINT
- URLは正規化されたものであること。(httpsとhttpを統一、末尾のスラッシュを統一して重複コンテンツを避ける)
- 日付はW3CのDatetime形で記述する必要がある。 ※私はこの記事の方法でフォーマットした。 PHPで時間(DATETIME型)をISO 8601に変換する方法
最後に
CakePHPでのプログラムをスケジュールするのに最初は少々慣れが必要かもしれないがなれたら開発効率が大きく上がりそうだ。
また、SEO対策においてサイトマップは大規模なサイトや公開して間もないサイトに有効だという情報を得た。 ロボットにサイトマップで知らせることでコンテンツ量が多すぎてもロボットに知らせたいリンクを示すことができるのだという。 今回公開して間もない, 現実的に被リンクはしばらく見込めないという観点から作っておいてマイナスにはならないだろうと思い作成してみた。 どこまで改善することできるのか今後が楽しみである。