先に要点
- sitemap.xml は、検索エンジンにサイト内のURL一覧や更新情報を伝えるためのXMLファイルです。検索順位を直接上げる魔法ではなく、重要なURLを見つけやすくする補助です。
- Googleが実際に見るのは
locと、正確なときだけのlastmodです。changefreqとpriorityは無視されます。 lastmodは「本文ハッシュが変わったときだけ更新」する実装にすると、信頼される更新シグナルになります。毎回現在時刻を入れると逆効果です。- Search Consoleの「取得できませんでした」「サイトマップを読み取れませんでした」は、HTTPステータス・Content-Type・XML構文・robots.txtの4点を切り分ければほぼ原因が特定できます。
Webサイトを公開するとき、SEOまわりでよく出てくるファイルが sitemap.xml です。
ただ、名前からは「サイトマップページのこと?」「出せば必ずインデックスされるの?」「robots.txt と何が違うの?」と迷いやすいところです。
この記事では、2026年6月時点で Google Search Central と sitemaps.org の公式情報を確認しながら、sitemap.xml とは何か、検索エンジンに何を伝えるのか、Webサイト運用でどこに注意するべきかを整理します。
さらに今回は、現場でつまずきやすい2点 ―― lastmod を「本文が本当に変わったときだけ」更新する具体実装と、Search Consoleで出るエラーの切り分け ―― を厚めに扱います。
クローラーへのアクセス方針から見たい場合は、robots.txtとは?検索エンジンとAIクローラーに何を伝えるファイルなのか もあわせて読むとつながりやすいです。
sitemap.xmlとは何か
sitemap.xml は、検索エンジンに対して「このサイトにはこういうURLがあります」と伝えるためのXMLファイルです。 一般的には、次のようなURLで公開されます。
https://example.com/sitemap.xml
このサイトでも、/sitemap.xml を公開しています。記事一覧、カテゴリ、用語集ページなど、検索エンジンに発見してほしい公開URLをまとめています。
Google Search Central では、サイトマップはページ・動画・その他のファイルと、それらの関係について検索エンジンに情報を提供するファイルとして説明されています。 つまり、sitemap.xml は「検索エンジン向けのURL一覧」です。HTMLのサイトマップページ(人間向けの目次)とは別物だと整理しておくと混乱しません。
何を書けばいいのか
かなり基本的なXMLサイトマップは、次のような形です。
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/articles/sample</loc>
<lastmod>2026-06-13T14:51:12+09:00</lastmod>
</url>
</urlset>
主要な要素は次の通りです。
| 要素 | 意味 | 実務での見方 |
|---|---|---|
| loc | ページのURL | 必須。相対URLではなく、絶対URLで正規URLを書く |
| lastmod | 最終更新日時 | 任意。ただし「正確に書けるなら」かなり重要。W3C Datetime形式 |
| changefreq | 更新頻度の目安 | 任意。Googleはこの値を無視すると明記している |
| priority | サイト内での相対的な優先度 | 任意。Googleはこの値を無視すると明記している |
sitemaps.org の仕様では loc が必須で、lastmod・changefreq・priority は任意です。
一方、Google Search Central では、priority と changefreq は無視し、lastmod は「一貫して検証可能なほど正確な場合に」使うと説明されています。
そのため、実務ではまず 正しいlocと正確なlastmod を重視した方がよいです。
lastmod の形式は W3C Datetime(2026-06-13 のような日付だけ、または 2026-06-13T14:51:12+09:00 のようにタイムゾーン付き)で書きます。タイムゾーンのない素朴な日時や独自フォーマットは避けます。
lastmodは「本文ハッシュが変わったときだけ」更新する
ここがこの記事の本題のひとつです。
lastmod は、Googleが「一貫して正確なら参照する」と言っている要素です。逆に言うと、本文が1文字も変わっていないのに毎回ビルド時刻や現在時刻を入れていると、「このサイトの lastmod はあてにならない」と判断され、せっかくのシグナルが無視されます。よくある自動生成の落とし穴がこれです。
解決策はシンプルで、本文(と検索結果に影響する主要メタ情報)のハッシュを保存しておき、ハッシュが変わったときだけ lastmod を現在時刻に更新する という方針です。
なぜハッシュ比較なのか
「更新日時カラム(updated_at)をそのまま使えばいいのでは」と思うかもしれませんが、updated_at は閲覧数カウントの加算、タグの並び替え、内部的なフラグ変更など「本文と無関係な更新」でも動いてしまいます。Googleの言う「significant update(主要コンテンツ・構造化データ・リンクの変更)」だけを拾うには、本文そのものから計算したハッシュを比べるのが確実です。
実装例(PHP / Laravel)
たとえば記事モデルの保存直前で、本文系フィールドからハッシュを作り、変化があったときだけ更新時刻を打ち直します。
// App\Models\Article のイベント(saving)で実行する例
protected static function booted(): void
{
static::saving(function (Article $article) {
// 検索結果に影響する部分だけを連結してハッシュ化する
$payload = implode("\n", [
$article->title,
$article->meta_description,
$article->canonical_url,
$article->body, // 本文(Markdown/HTML)
]);
$newHash = sha1($payload);
// 初回保存、またはハッシュが変わったときだけ更新時刻を打ち直す
if ($article->content_hash !== $newHash) {
$article->content_hash = $newHash;
$article->content_changed_at = now();
}
// ハッシュが同じなら content_changed_at はそのまま(= lastmod が動かない)
});
}
sitemap生成側は、この content_changed_at を lastmod に流し込みます。
// sitemap生成コントローラの抜粋
foreach ($articles as $article) {
$url = $sitemap->addChild('url');
$url->addChild('loc', e(route('articles.show', $article->slug)));
// updated_at ではなく content_changed_at を使うのがポイント
$url->addChild('lastmod', $article->content_changed_at->toAtomString());
}
toAtomString() は 2026-06-13T14:51:12+09:00 のようなW3C Datetime形式を返すので、そのまま lastmod に使えます。
効果の確認(典型的な挙動)
実際にうまく動いているかは、本文を変えずに2回デプロイして lastmod が動かないことを見れば確認できます。
# 1回目(本文を1文字変えてデプロイ)
$ curl -s https://example.com/sitemap.xml | grep -A1 'articles/sample'
<loc>https://example.com/articles/sample</loc>
<lastmod>2026-06-13T14:51:12+09:00</lastmod>
# 2回目(本文は変えず、閲覧数だけ増えた状態で再デプロイ)
$ curl -s https://example.com/sitemap.xml | grep -A1 'articles/sample'
<loc>https://example.com/articles/sample</loc>
<lastmod>2026-06-13T14:51:12+09:00</lastmod> # ← 変わらない(正しい挙動)
このように「本文が変わったときだけ lastmod が進む」状態になれば、Googleに信頼される更新シグナルになります。 WordPressなど自前実装でない場合も、考え方は同じです。「投稿の本文・タイトル更新時刻」を lastmod に使い、閲覧数やコメント追加では更新しないプラグイン設定を選びます。
sitemap.xmlで検索順位は上がるのか
ここは誤解されやすいですが、sitemap.xml を置いただけで検索順位が上がるわけではありません。 サイトマップの役割は、検索エンジンがURLを発見しやすくすることです。
特に効果が分かりやすいのは次のようなサイトです。
ページが増え続ける
記事・商品・求人・用語集などが日々増えるサイト。新規URLの早期発見に効く。
内部リンクで届きにくい
トップから数クリック以上奥にあるページや、リンクの薄いページを拾わせたいとき。
大量ページ・移行直後
数千〜数万URL、あるいはURL整理・サイト移行の直後でクロールを促したいとき。
拡張情報を伝えたい
画像・動画・ニュースなど、通常のクロールでは伝わりにくい情報も渡したいとき。
逆に、数ページだけの小さなサイトで、すべてのページがトップページから自然にリンクされているなら、効果は目立ちにくいかもしれません。 それでも、Search Consoleで送信・確認しやすくなるので、置いておく価値はあります。目安として、50ページを超えたあたりから「あると明確に楽」になり、数百ページ以上では事実上必須と考えてよいです。
robots.txtやIndexNowとの違い
sitemap.xml、robots.txt、IndexNow はSEO運用で一緒に出てきますが、役割は違います。
| 仕組み | 役割 | ひと言で言うと |
|---|---|---|
| sitemap.xml | 検索エンジンにURL一覧や更新日時を伝える | このURLを見つけてほしい |
| robots.txt | クローラーにクロールしてよい範囲を伝える | ここは巡回してよい / 避けてほしい |
| IndexNow | 追加・更新・削除されたURLを検索エンジンへ通知する | このURLが変わった |
robots.txt には、サイトマップの場所を書けます。
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
このサイトの robots.txt も、同じように Sitemap: https://engineer-notes.net/sitemap.xml を入れています。
更新通知との違いを詳しく見たい場合は、IndexNowとは?何がうれしい?仕組み・XMLサイトマップとの違い・注意点を解説 で整理しています。
何を入れて、何を入れないべきか
sitemap.xml には、検索結果に出てほしい正規URLを入れるのが基本です。 逆に、次のようなURLは入れない方が自然です。
- noindex のページ
- ログインが必要なページ
- 管理画面
- 検索結果ページ
- 重複URLやcanonicalではないURL
- 404やリダイレクト先が変わった古いURL
- 下書きや未公開ページ
Google Search Central でも、サイトマップには検索結果に表示したいURLを含めるよう案内されています。 つまり、「存在するURLを全部入れる」のではなく、検索エンジンに見つけてほしい正規の公開URLだけ入れる と考えると分かりやすいです。
大規模サイトでは分割する
Googleのドキュメントでは、1つのサイトマップは未圧縮で50MBまで、または50,000URLまでという制限があります(どちらか先に到達した方が上限)。 これを超える場合は、複数のサイトマップに分け、サイトマップインデックスを使います。
たとえば、次のように分けます。
/sitemaps/articles.xml/sitemaps/products.xml/sitemaps/categories.xml/sitemap_index.xml(上記をまとめるインデックス)
小規模サイトでは気にしなくてよいことが多いですが、EC、求人、メディア、用語集のようにURLが増え続けるサイトでは、最初から分割しやすい設計にしておくと後で楽です。 1ファイルあたりは上限ぎりぎりではなく、運用しやすい1万〜2万URL程度で区切ると、再生成も検証も軽く済みます。
Search Consoleで出るエラーと切り分け
自動生成のsitemapは、壊れていても画面上では気づきにくいのが厄介です。Search Consoleでサイトマップを送信したあとに出やすいエラーを、現象 → 原因 → 確認手順 → 回避 の形でまとめます。切り分けの順番は「HTTPステータス → Content-Type → XML構文 → robots.txt」で見ると速いです。
エラー1: 「サイトマップを取得できませんでした」(Couldn't fetch)
現象
Search Consoleのステータスが「取得できませんでした」になり、検出URL数が空欄や0のまま進まない。
確認手順
まずHTTPステータスを直接見る。200以外なら確実にこれが原因。
回避
200で返るURLに直す。WAF側でGooglebotのUAやIPレンジを許可する。robots.txtでブロックしていないか後述の手順で確認する。
$ curl -sI https://example.com/sitemap.xml | head -n 1
HTTP/2 200 # ← 200 ならOK。403/404/500 ならまずここを直す
ステータスは出るのに「取得できませんでした」が消えないときは、送信したURLそのものが間違っている(例: /sitemap.xml を送ったが実体は /sitemap_index.xml)、または送信直後でGoogle側の再取得がまだ走っていないだけのこともあります。送信後しばらくは「取得できませんでした」のまま表示され、後から成功に変わるケースがあるので、ステータスが200なら一度時間を置くのも有効です。
エラー2: 「サイトマップを読み取れませんでした」(Could not be read / 構文・形式エラー)
現象
取得自体はできているのに「読み取れませんでした」「解析エラー」と出る。
確認手順
Content-Typeと本文の先頭バイトを確認する。application/xml 系であること、先頭が <?xml で始まることを見る。
回避
レスポンスヘッダを application/xml; charset=UTF-8 にする。出力前の余計なechoやBOMを除去し、URL内の & はエンティティ化する。
Content-Typeの取り違えは特に多い失敗です。フレームワークが既定で text/html を返していると、見た目は正しいXMLでも「読み取れませんでした」になります。
$ curl -sI https://example.com/sitemap.xml | grep -i content-type
content-type: application/xml; charset=UTF-8 # ← text/html だとアウト
# 本文の先頭が <?xml で始まっているか(BOMや空行が無いか)も確認
$ curl -s https://example.com/sitemap.xml | head -c 40
<?xml version="1.0" encoding="UTF-8"?>
PHPの場合、出力前に header('Content-Type: application/xml; charset=UTF-8'); を付けます。Laravelなら response($xml, 200)->header('Content-Type', 'application/xml') を返します。
本文先頭にゴミが入っていないかは、head -c 40 で先頭バイトを見るのが手早い確認です。ここに空行やPHPの Notice が混ざっていると解析に失敗します。
エラー3: 「URLが許可されていません」(URL not allowed / robots.txtでブロック)
現象
サイトマップは読めているが、含まれるURLが「ブロック済み」「許可されていません」と警告される。
原因
robots.txtのDisallowでそのパスを禁止している、サイトマップに別ドメインや別サブドメインのURLを入れている、http/https・wwwあり/なしが混在している。
確認手順
robots.txtの内容と、サイトマップ内のドメインが送信先プロパティと一致しているかを照合する。
回避
Disallowを解除するか対象URLをサイトマップから外す。サイトマップ内のURLは送信先プロパティと同じスキーム・ホストの正規URLに統一する。
$ curl -s https://example.com/robots.txt
User-agent: *
Disallow: /articles/ # ← これがあると /articles/ 配下は「URLが許可されていません」になる
Sitemap: https://example.com/sitemap.xml
サイトマップに含めるURLは、Search Consoleに登録したプロパティと同じドメイン・同じスキームでなければなりません。開発環境の http://localhost や別サブドメインのURLが紛れ込むと、まとめて「許可されていません」と弾かれます。lastmod実装と同じく、生成時に config('app.url') など本番URLを基点に組み立てるのが安全です。
sitemap.xmlに関するよくある質問
Q. sitemap.xml はSEOに必要ですか?
A. 直接の順位影響はありませんが、新規ページの早期発見・大量ページの効率的クロール・Search Consoleでの問題検知に役立ちます。数百ページ以上のサイトには事実上必須です。
Q. lastmodは毎回更新してよいですか?
A. ダメです。Googleは「一貫して正確なときだけ」lastmodを参照します。本文が変わっていないのに毎回現在時刻を入れると、サイト全体のlastmodが信頼されなくなります。本文ハッシュを比較し、変わったときだけ更新する実装にしてください。
Q. lastmodはどの形式で書きますか?
A. W3C Datetime形式です。2026-06-13 のような日付だけでも、2026-06-13T14:51:12+09:00 のようにタイムゾーン付きでも構いません。タイムゾーンのない曖昧な日時は避けます。
Q.「サイトマップを取得できませんでした」が消えません。
A. まず curl -sI でHTTPステータスを確認し、200以外なら直します。200なのに消えない場合は、送信URLの取り違え、WAF/CDNによるGooglebotのブロック、再取得待ちのいずれかです。ステータスが正常なら時間を置いて再確認します。
Q.「読み取れませんでした」と出ます。XMLは合っているはずです。
A. Content-Typeが text/html になっていないか確認してください。これが最頻の原因です。次に本文先頭にBOMや空行、警告文が混ざっていないか head -c 40 で見ます。文字コードはUTF-8に統一します。
Q. ファイル分割の必要性は?
A. 50,000URLまたは未圧縮50MBを超えたら分割が必須です。sitemap-articles.xml、sitemap-categories.xml のように分け、sitemap_index.xml でまとめます。運用上は1ファイル1万〜2万URL程度で区切ると扱いやすいです。
Q. 404やnoindexのURLを含めてよいですか?
A. ダメです。200で返る正規のインデックス対象URLだけを含めます。404やnoindexを混ぜると、Search Consoleで警告・エラー扱いになり、クロール効率も落ちます。
Q. 画像・動画・ニュース用のsitemapは別ですか?
A. 用途別の専用スキーマがあります。Image Sitemap、Video Sitemap、News Sitemap、hreflang用のサイトマップなどです。大規模サイトでは複数を組み合わせて使うことが多いです。
まとめ
sitemap.xml は、検索エンジンにサイト内のURL一覧や更新情報を伝えるためのXMLファイルです。 検索順位を直接上げるものではありませんが、検索エンジンが重要なURLを発見しやすくなるため、記事・商品・用語集・カテゴリなどが増えるサイトでは基本的な運用になります。
実装のキモは2つです。1つは、lastmod を本文ハッシュの変化で制御し、「本当に更新があったときだけ」進めること。もう1つは、Search Consoleでエラーが出たら「HTTPステータス → Content-Type → XML構文 → robots.txt」の順で切り分けることです。
そのうえで、robots.txt・IndexNow・内部リンク・canonical・noindex と役割を分けて運用すると、検索エンジンにサイト構造を正確に伝えられます。
参考リンク
- Google Search Central: Build and submit a sitemap
- Google Search Central: Manage your sitemaps with the Sitemaps report
- sitemaps.org: Sitemaps XML format
- engineer.notes: /sitemap.xml
- engineer.notes: /robots.txt