どうも、ぽんこつ先生です。
今日はちょっとWordpressの話題です。
このサイト、立ち上げて1か月弱なんですけど、しばらくブログとか書いてなかったので、
「外部からリンク貼ってるし、特に何もしなくてもそのうちインデックスされるでしょ」
くらいに考えていたんですけど、昨日なんとなくチェックしてみたんです。
site:https://wild-duck.net
何とびっくり!
まさかの、トップページとお問い合わせページしかない・・・・
いやいや、ちゃんと内部リンクも繋いでるし、外部からもリンク貼ってるし…。
調べてみると、どうやら最近のGoogleは「sitemap.xmlに載ってないページはクロールの優先度が低い」らしい。昔は外部リンクさえあれば勝手にクロールしてくれたのに、時代は変わったんですね。
というわけで、sitemap.xmlをちゃんと整備することにしました。
WordPress標準のサイトマップ機能
WordPress 5.5から、サイトマップ機能が標準搭載されています。
https://あなたのサイト/wp-sitemap.xml
にアクセスすると、自動生成されたサイトマップが見れます。便利な時代になりましたね。
ただ、このサイトマップ、WordPressで管理している投稿や固定ページしか含まれないんです。
私のサイトには /lp/ や /tools/ ディレクトリに静的なHTMLファイルがいくつかあるんですが、これらは当然含まれない。手動でsitemap.xmlを作って管理するのも面倒だし、ファイルが増えるたびに更新するのも現実的じゃない。
じゃあ、WordPress標準のサイトマップに機能追加しよう!と思ったわけです。
カスタムサイトマッププロバイダーを作る
調べてみると、WP_Sitemaps_Provider クラスを継承して、自分でプロバイダーを作れるらしい。
子テーマの functions.php にこんなコードを追加しました。
class Static_Pages_Sitemap_Provider extends WP_Sitemaps_Provider {
public $name = 'static-pages';
public function get_url_list($page_num, $object_subtype = '') {
$url_list = [];
$scan_dirs = ['lp', 'tools', 'doc'];
foreach ($scan_dirs as $dir) {
$dir_path = ABSPATH . $dir;
if (!is_dir($dir_path)) continue;
$this->scan_recursive($dir_path, $url_list);
}
return $url_list;
}
private function scan_recursive($dir_path, &$url_list) {
$items = glob($dir_path . '/*');
foreach ($items as $item) {
if (is_dir($item)) {
$this->scan_recursive($item, $url_list);
} elseif (pathinfo($item, PATHINFO_EXTENSION) === 'html') {
$relative = str_replace(ABSPATH, '', $item);
$url_list[] = [
'loc' => home_url('/' . $relative),
'lastmod' => date('Y-m-d', filemtime($item)),
];
}
}
}
public function get_max_num_pages($object_subtype = '') {
return 1;
}
}
add_action('wp_sitemaps_init', function() {
wp_register_sitemap_provider('static-pages', new Static_Pages_Sitemap_Provider());
});
指定したディレクトリを再帰的にスキャンして、.html ファイルを自動でサイトマップに追加する仕組みです。
wp-sitemap.xml を確認すると、ちゃんと wp-sitemap-static-pages-1.xml へのリンクが追加されてる。
やったー!
と思ってクリックしたら…
トップページに飛ぶ
は?
URLバーには wp-sitemap-static-pages-1.xml と表示されてるのに、中身はトップページ。
なんで?
原因調査開始
まず、プロバイダーがちゃんと登録されてるか確認。
add_action('init', function() {
if (isset($_GET['test_providers'])) {
$providers = wp_get_sitemap_providers();
header('Content-Type: application/json');
echo json_encode(array_keys($providers), JSON_PRETTY_PRINT);
exit;
}
}, 99);
結果
["static-pages", "posts", "taxonomies"]
登録されてる。
次に、URLのマッチングを確認。
add_filter('do_parse_request', function($do, $wp, $extra_query_vars) {
if (strpos($_SERVER['REQUEST_URI'], 'wp-sitemap-static-pages') !== false) {
global $wp_rewrite;
$rules = $wp_rewrite->wp_rewrite_rules();
$request = ltrim($_SERVER['REQUEST_URI'], '/');
foreach ($rules as $pattern => $query) {
if (preg_match("#^$pattern#", $request, $matches)) {
header('Content-Type: text/plain');
echo "MATCHED!\nPattern: $pattern\n";
print_r($matches);
exit;
}
}
}
return $do;
}, 1, 3);
結果
MATCHED!
Pattern: ^wp-sitemap-([a-z]+?)-(\d+?)\.xml$
Matches: Array
(
[0] => wp-sitemap-static-pages-1.xml
[1] => static
[2] => pages-1
)
ん? [1] => static ?
あー!!!
原因判明:プロバイダー名のハイフン
WordPressのリライトルールはこうなってます。
^wp-sitemap-([a-z]+?)-(\d+?)\.xml$
[a-z]+? は 小文字アルファベットのみ にマッチします。ハイフンは含まれない。
だから static-pages という名前だと:
staticまでマッチ →$matches[1]- 残りの
-pages-1が(\d+?)と合わない → マッチ失敗
結果、WordPressがこのURLを正しく処理できず、トップページが表示されていたわけです。
解決策
プロバイダー名からハイフンを削除するだけ。
public $name = 'staticpages'; // ハイフンなし
登録時も同様に、
wp_register_sitemap_provider('staticpages', new Static_Pages_Sitemap_Provider());
これで wp-sitemap-staticpages-1.xml というURLになり、正規表現にマッチするようになります。
完成版コード
class Static_Pages_Sitemap_Provider extends WP_Sitemaps_Provider {
public $name = 'staticpages';
public function get_url_list($page_num, $object_subtype = '') {
$url_list = [];
$scan_dirs = ['lp', 'tools', 'doc']; // スキャン対象ディレクトリ
foreach ($scan_dirs as $dir) {
$dir_path = ABSPATH . $dir;
if (!is_dir($dir_path)) continue;
$this->scan_recursive($dir_path, $url_list);
}
return $url_list;
}
private function scan_recursive($dir_path, &$url_list) {
$items = glob($dir_path . '/*');
foreach ($items as $item) {
if (is_dir($item)) {
$this->scan_recursive($item, $url_list);
} elseif (pathinfo($item, PATHINFO_EXTENSION) === 'html') {
$relative = str_replace(ABSPATH, '', $item);
$url_list[] = [
'loc' => home_url('/' . $relative),
'lastmod' => date('Y-m-d', filemtime($item)),
];
}
}
}
public function get_max_num_pages($object_subtype = '') {
return 1;
}
}
add_action('wp_sitemaps_init', function() {
wp_register_sitemap_provider('staticpages', new Static_Pages_Sitemap_Provider());
});
$scan_dirs の配列を編集すれば、スキャン対象のディレクトリを自由に変更できます。サブディレクトリも再帰的に探索するので、lp/campaign/2025/page.html みたいな深い階層のファイルも自動で拾います。
まとめ
というわけで、原因は プロバイダー名にハイフンを使っていた という、なんとも地味なものでした。
公式ドキュメントには「ハイフン使うな」なんて書いてないんですよ。リライトルールの正規表現を見ないと気づかない罠。
同じ症状で困ってる人がいたら、まずプロバイダー名を確認してみてください。
それにしても、昔は外部リンクさえあれば勝手にインデックスされたのに、今はsitemap.xmlをちゃんと整備しないとダメな時代になりました。Googleさんも忙しいんでしょうね。
SEOプラグイン(Rank MathやYoast SEO)を使えばGUIでカスタムURLを追加できますが、このためだけにプラグイン入れるのも重たい。静的ページをサイトマップに追加したいだけなら、今回のコードで十分です。
ではまた。
