必须为每种语言生成独立sitemap-{lang}.xml并用sitemapindex.xml聚合;loc需为带语言前缀的绝对URL,数据库查语言字段或按多表/路由规则分组,中文路径用rawurlencode()编码,lastmod用DateTime::ATOM格式。

ThinkPHP 本身不内置多语言 Sitemap 支持,必须手动为每种语言生成独立的 sitemap-{lang}.xml 文件,并用 sitemapindex.xml 统一聚合 —— 否则 Google Search Console 会报“重复 URL”或忽略非默认语言页。
怎么按语言分组查数据(不是简单拼 lang 参数)
多语言 Sitemap 的核心是:每条 <loc> 必须指向该语言的真实页面,且 URL 中要体现语言标识(如 /zh/article/123、/en/article/123)。不能靠 $_GET['lang'] 或 session 动态切换,必须从数据库字段或路由规则中明确提取语言维度。
- 如果内容表有
lang字段(如articles.lang IN ('zh', 'en', 'ja')),直接WHERE lang = 'zh'查 - 如果用多库或多表(
articles_zh、articles_en),需分别连接并统一字段结构 - 如果靠 URL 前缀识别(如 Nginx 重写
/zh/.*→index.php?lang=zh),千万别在 Sitemap 里写?lang=zh,必须生成带前缀的绝对路径:https://example.com/zh/article/123 - 中文等语言 URL 路径含 UTF-8 字符时,必须用
rawurlencode()编码,不能只靠htmlspecialchars()
DOMDocument 写多语言 Sitemap 时最容易漏的三件事
拼字符串生成 XML 在多语言场景下几乎必出错:中文路径没编码、& 没转义、lastmod 时间格式不合法。用 DOMDocument 是底线要求。
-
DOMDocument初始化必须指定 UTF-8:new DOMDocument('1.0', 'UTF-8');否则中文节点名或文本会乱码 - 每个
<loc>值必须用htmlspecialchars($url, ENT_XML1, 'UTF-8')——ENT_QUOTES不行,ENT_XML1才能正确处理&和 Unicode -
lastmod必须用DateTime::ATOM格式,例如(new DateTime($row['updated_at']))->format(DateTime::ATOM);仅date('Y-m-d')会被 Google 完全忽略
sitemapindex.xml 怎么关联多个语言子文件
主索引文件不是可选的,Google 和 Bing 都要求通过 sitemapindex 显式声明语言分片,否则各语言 Sitemap 会被当成冲突资源处理。
立即学习“PHP免费学习笔记(深入)”;
- 子文件命名建议用语言代码规范:
sitemap-zh.xml、sitemap-en.xml、sitemap-ja.xml,避免cn、eng等非标准缩写 -
<sitemapindex>的xmlns必须是http://www.sitemaps.org/schemas/sitemap/0.9,不能漏,也不能写错成http://www.sitemaps.org/schemas/sitemapindex/0.9 - 每个
<sitemap>块里的<lastmod>应取对应语言文件的最后生成时间,不是主站更新时间;可用filemtime()获取 - 生成顺序无关紧要,但所有子文件必须和
sitemapindex.xml同级部署,例如都放在网站根目录下
真正难的不是生成,而是确保每条 <loc> 返回 HTTP 200 且响应头 Content-Language 匹配其语言代码 —— 这一点绝大多数 ThinkPHP 多语言项目都没配,导致 Sitemap 提交后无收录效果。



















