WordPress|All in One SEO サイトマップを分割して大規模サイトに対応する方法

大規模なWordPressサイトでは、記事数が数万件を超えるケースも珍しくありません。
その場合、1つのサイトマップにすべてのURLを収録すると以下の問題が発生します。

  • XMLファイルが巨大化し、クローラーの処理が遅くなる
  • メモリ消費が増え、サーバー負荷が高くなる
  • 50,000件以上のURLを含むと Googleの制限に引っかかる

このようなケースでは、サイトマップを分割して複数のXMLに分ける 方法が有効です。


サイトマップ分割の基本ルール

  • 1ファイルあたり 50,000 URL または 50MB 未満 が上限(Google / Bing共通ルール)
  • インデックスファイル(sitemap.xml)から各分割ファイルを参照する必要がある
  • 分割数に制限はない(sitemap-1.xml, sitemap-2.xml …のように増やせる)

実装例:専用サイトマップを分割出力する

以下のコードは、カスタム投稿タイプ company のサイトマップを 2,000件ごとに分割 して出力する例です。

<?php
/**
 * 分割サイトマップの実装例
 */

// インデックスに分割サイトマップを登録
add_filter('aioseo_sitemap_indexes', function ($indexes) {
    if (is_admin() || wp_doing_ajax() || wp_doing_cron()) {
        return $indexes;
    }

    // 投稿数を取得
    $count = wp_count_posts('company')->publish ?? 0;
    $per_file = 2000;
    $pages = ceil($count / $per_file);

    for ($i = 1; $i <= $pages; $i++) {
        $indexes[] = [
            'loc'     => home_url("/sitemap-company-{$i}.xml"),
            'lastmod' => current_time('Y-m-d\TH:i:sP'),
        ];
    }

    return $indexes;
});

// 分割されたサイトマップの出力
add_action('template_redirect', function () {
    if (preg_match('#sitemap-company-(\d+)\.xml$#', $_SERVER['REQUEST_URI'], $m)) {
        $page     = (int) $m[1];
        $per_file = 2000;
        $offset   = ($page - 1) * $per_file;

        header('Content-Type: application/xml; charset=UTF-8');

        $posts = get_posts([
            'post_type'      => 'company',
            'post_status'    => 'publish',
            'posts_per_page' => $per_file,
            'offset'         => $offset,
            'orderby'        => 'date',
            'order'          => 'DESC',
            'no_found_rows'  => true,
        ]);

        echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
        <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
            <?php foreach ($posts as $post): ?>
                <url>
                    <loc><?php echo esc_url(get_permalink($post)); ?></loc>
                    <lastmod><?php echo esc_html(get_post_modified_time('c', true, $post)); ?></lastmod>
                </url>
            <?php endforeach; ?>
        </urlset>
        <?php
        exit;
    }
});

コード解説

  • インデックス登録
    aioseo_sitemap_indexes に対して、分割数に応じた複数の sitemap-company-N.xml を追加。
  • get_posts()offsetposts_per_page
    各ページに収録する件数(例:2,000件)を指定し、offset で開始位置を制御。
  • クエリ最適化 (no_found_rows => true)
    ページ数計算はすでに済んでいるため、SQLの総数計算を省略して高速化。

応用アイデア

  • キャッシュと併用
    前回の記事で解説した「Transients API」を使えば、分割ファイルごとにキャッシュ可能。
    sitemap-company-1.xml などをキーにすれば効率的です。
  • 条件付き分割
    例えば「カテゴリごとに分割」「年ごとに分割」といった柔軟な構成も可能。
    クローラーが無駄に読み込む必要がなくなり効率的になります。

まとめ

  • サイトマップは 1ファイル5万件・50MB制限 があるため、大規模サイトでは分割必須
  • aioseo_sitemap_indexes でインデックス登録し、分割ファイルを生成する
  • offsetposts_per_page を活用して効率的に出力
  • キャッシュや条件分割と組み合わせれば、さらに最適化可能

コメント

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