wp-sitemap-〇〇-1.xml にアクセスするとトップページに飛ぶ原因と対策

プログラミング/ツール開発

どうも、ぽんこつ先生です。

今日はちょっと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を追加できますが、このためだけにプラグイン入れるのも重たい。静的ページをサイトマップに追加したいだけなら、今回のコードで十分です。

ではまた。

 

タイトルとURLをコピーしました