コンテンツへスキップ

robots.txtとsitemap.xmlの基礎 — クローラーに何を伝えているか、どちらが優先されるか

検索エンジンのクローラー(Webページを自動で巡回して内容を集めるプログラム)は、サイトを訪れたとき、いきなり記事ページを読みに行くわけではない。多くの場合、まずrobots.txtで「どこを見てよいか」を確認し、sitemap.xmlで「どんなページがあるか」の一覧を受け取る。この2つのファイルはどちらも「クローラー向けの案内」という点で似ているため混同されやすいが、伝えている内容も、効く場面もまったく違う。前回までのhreflang・JSON-LD・OGPが「ページの中身をどう解釈してほしいか」の話だったのに対し、今回はその手前、クローラーがページにたどり着くまでの話を整理する。

補足: クローラーは「ボット」「スパイダー」とも呼ばれる。GoogleのGooglebot、MicrosoftのBingbotが代表例で、各ボットは User-Agent というHTTPヘッダーで自分の名前を名乗ってアクセスしてくる。robots.txtはこの名前ごとにルールを書き分けられる仕組みになっている。

一言でいうと — robots.txtは「立入禁止の看板」、sitemap.xmlは「館内案内図」

最初に役割の違いを表にしておく。

robots.txt sitemap.xml
伝えていること 「このパスはクロールしないでほしい」 「このサイトにはこういうURLがある」
性質 制限(除外の指示) 発見の手がかり(追加のヒント)
置き場所 ホストのルート直下に1つだけ(/robots.txt) どこでもよい(robots.txtやSearch Consoleで場所を知らせる)
形式 プレーンテキスト XML
守られなかったら 行儀のよいクローラーは従う(強制力はない) 載っていても巡回・登録される保証はない

robots.txtは「ここは入らないで」という引き算、sitemap.xmlは「こういうページもあります」という足し算の情報だ、と捉えると整理しやすい。どちらもクローラーへの「お願い」であって、アクセスを物理的に止めたり、検索結果への掲載を約束させたりする力はない。

robots.txtの書き方 — 4つの命令で足りる

robots.txtの中身は、基本的に次の4種類の行の組み合わせである。

  • User-agent: — 以降のルールをどのクローラーに適用するか(* は全クローラー)
  • Disallow: — クロールしないでほしいパス(前方一致)
  • Allow: — Disallow の中で例外的に許可するパス
  • Sitemap: — sitemap.xmlの場所(フルURLで書く・User-agent とは無関係に全体に効く)

実例として、このブログの英語版が載っている en.wpmm.jp の robots.txt をそのまま示す。

User-agent: *
Allow: /

Disallow: /config.php
Disallow: /includes/

Sitemap: https://en.wpmm.jp/sitemap.xml
Sitemap: https://en.wpmm.jp/blog/wp-sitemap.xml

全クローラーに対して基本はすべて許可し、設定ファイルと内部用のディレクトリだけをクロール対象から外している。最後の2行でLP側のサイトマップとブログ側のサイトマップを並べて申告しているのは、後述するようにブログのWordPressがサブディレクトリに入っているためである。

Allow: / と Disallow: /includes/ のように両方が当てはまるパスでは、主要な検索エンジンはより長く(具体的に)一致したルールを優先する。/includes/foo.php に対しては /(1文字)より /includes/(10文字)の方が長く一致するので、Disallow が勝つ。書いた順番ではなく一致の長さで決まる点は、正規表現に慣れていると意外に感じやすいところだ。

robots.txtは「ホストのルートに1つだけ」

robots.txtでもっともつまずきやすいのが置き場所である。クローラーが読みに行くのは、スキーム+ホスト名ごとに、そのルート直下の /robots.txt だけだ。https://wpmm.jp/robots.txt と https://en.wpmm.jp/robots.txt は別物として扱われ、サブディレクトリ下に置いたファイルは参照されない。

このブログはまさにこのケースに当たる。WordPressは本来、物理ファイルが無くても /robots.txt へのアクセスに対して仮想的なrobots.txtを自動生成して返す機能を持っている。しかし wpmm.jp/blog のようにWordPressをサブディレクトリにインストールしていると、その仮想robots.txtは https://wpmm.jp/blog/robots.txt で生成されることになり、そこはクローラーが見に来る場所ではない。実際にアクセスすると、WordPressの404ページが返ってくる。

curl -s -o /dev/null -w "%{http_code}\n" https://wpmm.jp/blog/robots.txt
# 404
curl -s -o /dev/null -w "%{http_code}\n" https://wpmm.jp/robots.txt
# 200

つまり、サブディレクトリ型のWordPressでは、WordPress側の設定やプラグインでrobots.txtを編集してもクローラーには一切届かない。ルールやサイトマップの場所を伝えたいなら、ホストのルートにある robots.txt(このサイトの場合はLP側が管理している物理ファイル)に書く必要がある。前述のen.wpmm.jpのrobots.txtにブログ側の wp-sitemap.xml が並んでいるのはこのためだ。

補足: robots.txt自体が返すHTTPステータスにも意味がある。404(存在しない)の場合、クローラーは「制限なし」とみなして全体をクロールする。一方、5xx(サーバーエラー)が続くと、主要な検索エンジンは「どこが禁止か分からない」ため慎重側に倒し、一時的にサイト全体のクロールを控えることがある。ステータスコードの大分類はHTTPステータスコードの記事で整理している。

robots.txtは鍵ではない

robots.txtについて必ず押さえておきたいのは、これはアクセス制御の仕組みではないという点である。

  • robots.txtは誰でも閲覧できる公開ファイルであり、書いたパスは第三者にも読まれる
  • 従うかどうかはクローラー側の善意に任されており、ルールを無視するプログラムも存在する
  • Disallow したURLでも、他サイトからリンクされていれば「URLだけ」が検索結果に出ることがある

このため、「見られては困るページを Disallow で隠す」という使い方は逆効果になりうる。公開したくないものは、robots.txtではなく認証やサーバー側のアクセス制限で守るのが原則だ。robots.txtはあくまで「クロールしても意味のない場所に、クローラーの時間を使わせない」ための整理の道具と考えるのがよい。

sitemap.xmlの中身 — URLの一覧と最終更新日時

sitemap.xmlは、サイト内のURLを列挙したXMLファイルである。最小構成では <url> ごとに <loc>(URL)を書き、必要に応じて <lastmod>(最終更新日時)を添える。

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://wpmm.jp/blog/safe-wordpress-maintenance-with-ssh-wpcli/</loc>
    <lastmod>2026-05-13T15:30:06+09:00</lastmod>
  </url>
  ...
</urlset>

仕様上は <changefreq>(更新頻度)や <priority>(優先度)といった要素もあるが、Googleはこの2つを参照しないと公式に説明している。実運用で意味を持つのは、正確な <loc> と、実際の更新と一致した <lastmod> の2つと考えてよい。<lastmod> を毎日機械的に書き換えるような運用は、かえって信頼されなくなる。

URLが多いサイトでは、サイトマップを種類ごとに分割し、それらを束ねるサイトマップインデックス(<sitemapindex>)を置く構成が一般的である。WordPressはバージョン5.5からこの仕組みをコアに標準搭載しており、/wp-sitemap.xml にアクセスするとインデックスが返る。このブログのインデックスは次のようになっている。

<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap><loc>https://wpmm.jp/blog/wp-sitemap-posts-post-1.xml</loc></sitemap>
  <sitemap><loc>https://wpmm.jp/blog/wp-sitemap-posts-page-1.xml</loc></sitemap>
  ...
</sitemapindex>

投稿・固定ページごとにサイトマップが分かれ、それぞれのファイルに個別記事のURLと <lastmod> が並ぶ。記事を公開・更新するとWordPressが自動で反映するので、手でXMLを書き換える必要はない。

「どちらが優先されるか」— 答えは「役割が違うので競合させない」

では、robots.txtで Disallow したURLをsitemap.xmlに載せたらどうなるか。この場合、クローラーはrobots.txtに従い、そのURLを取得しない。サイトマップは「こういうURLがある」と知らせるだけで、クロールの許可を上書きする力はないからだ。Search Consoleでは「送信されたURLがrobots.txtによってブロックされました」といった警告として表面化する。

ここから分かるのは、「どちらが優先か」を気にするより、2つのファイルが矛盾したシグナルを出さないように揃えることの方が大事だという点である。考え方は次の通り。

  • 検索結果に出したいページ: robots.txtで許可し、sitemap.xmlに載せる
  • 検索結果に出したくないページ: sitemap.xmlから外す(robots.txtでブロックするかは次の節の注意点を参照)

noindexとDisallowを同時に使ってはいけない理由

「検索結果に出したくない」ページについて、もっとも多い誤解がこれである。ページの <meta name="robots" content="noindex"> は「このページを検索結果に載せないで」という指示だが、この指示はクローラーがページを取得して初めて読める。そのページをrobots.txtで Disallow してしまうと、クローラーはページを取りに来ないので、noindex を読む機会がない。結果として、外部からリンクされていれば「URLだけ」が検索結果に残り続ける、という逆転現象が起きる。

  • Disallow = 「中を見ないで」(クロールの制御)
  • noindex = 「中を見たうえで、載せないで」(インデックスの制御)

検索結果から確実に外したいなら、robots.txtではブロックせず、ページ側で noindex を返すのが正しい組み合わせになる。

このブログでの揃え方

このブログのテーマ wpmm-blog では、404・検索結果・カテゴリー/タグのアーカイブページに noindex を付けている(薄い・似通った一覧ページがインデックス未登録のまま大量に検出され、クローラーの巡回を無駄に消費するのを避けるため)。実装はWordPressの wp_robots フィルターで行っている。

add_filter('wp_robots', function ($robots) {
    if (is_404() || is_search() || is_category() || is_tag() || is_tax()) {
        $robots['noindex'] = true;
        unset($robots['index']);
        // follow はデフォルトのまま残し、内部記事へのリンクはたどってもらう
    }
    ...
    return $robots;
});

そして、ここで noindex にしたカテゴリー・タグのページをサイトマップにも載せないよう、WordPressコアのサイトマップからタクソノミー部分を除外している。

add_filter('wp_sitemaps_taxonomies', function ($taxonomies) {
    unset($taxonomies['category']);
    unset($taxonomies['post_tag']);
    return $taxonomies;
});

「サイトマップで送信しているのにページはnoindex」という状態は、クローラーから見ると「載せてほしいのか、載せてほしくないのか」分からない矛盾したシグナルになる。robots.txtではブロックせず(noindex を読んでもらうため)、サイトマップからは外し(矛盾を作らないため)、ページ側で noindex を返す——この3点をセットで揃えているわけだ。先ほど示したサイトマップインデックスに投稿と固定ページのサイトマップしか並んでいないのは、この設定の結果である。

よくある落とし穴

  • サブディレクトリのrobots.txtを編集して満足する: クローラーが読むのはホストのルート直下だけ。WordPressをサブディレクトリに置いている場合、WordPress側の仮想robots.txtは効かない
  • 公開前の Disallow: / を消し忘れる: 開発中にサイト全体をブロックしたまま公開し、いつまでも検索結果に出ない。WordPressの「検索エンジンがサイトをインデックスしないようにする」設定も同様に確認対象
  • noindexにしたいページをDisallowする: クローラーが noindex を読めなくなり、かえってURLが残る
  • サイトマップのURLが実際のURLと食い違う: http/https、www の有無、末尾スラッシュの有無が正規URL(canonical)とずれていると、リダイレクト先を指したサイトマップになってしまう
  • 別のプラグインがサイトマップのURLを横取りする: 旧来のサイトマップ生成プラグインが有効なままだと、WordPressコアの /wp-sitemap.xml が空の内容を返すことがある。このブログでも立ち上げ時に遭遇し、プラグインを無効化したうえでパーマリンク設定(リライトルール)を再生成して解消した
  • robots.txtで秘密のパスを隠そうとする: 公開ファイルなので、かえって場所を知らせることになる

まとめ

robots.txtは「クロールしないでほしい場所」を伝える制限のファイルで、ホストのルート直下に1つだけ置く。sitemap.xmlは「こういうURLがある」を伝える発見の手がかりで、正確なURLと最終更新日時が要になる。両者は役割が違うため、「どちらが優先か」ではなく矛盾しないように揃えることが大切で、特に「検索結果から外したいページはDisallowせずnoindexを返し、サイトマップからも外す」という組み合わせは押さえておきたい。検索エンジンとの付き合いは、ページの中身を整える前に、クローラーへの案内を正しく整えるところから始まる。