WordPressからの移行 Astro EmDash TypeScript サイトマップ

EmDashのコレクションのURLパターンを/{slug}/にしても、EmDashが出すサイトマップには/fooのように末尾スラッシュのないURLが載ります。サイトが/foo/を正規のURLにしている場合、サイトマップの全URLが301を返すことになります。Astroの設定は変えずに、記事と固定ページのサイトマップと同じパスのルートを自分で作り、EmDashのサイトマップの代わりに返して対処します。

確かめたのはEmDash 1.3.1です。

末尾スラッシュが消える仕組み

EmDashはURLパターンからURLを作るとき、末尾のスラッシュを必ず外します。付け直すのは、AstroのtrailingSlashが"always"の時だけです。初期設定の"ignore"のままでは、URLパターンに/を書いても消えます。

trailingSlashを”always”にしない

astro.config.mjsにtrailingSlash: "always"を入れると、サイトマップには末尾スラッシュが付きます。しかし開発サーバーでは、管理画面(/_emdash/admin)とAPI(/_emdash/api/〜)が404になりました。Astroのルーティング全体に影響する設定なので、サイトマップのためだけに変えないほうが安全です。

同じパスのルートを作ってサイトマップを差し替える

EmDashのコレクション別サイトマップは、/sitemap-[collection].xmlという動的なルートです。src/pages/sitemap-posts.xml.tsのような固定のルートを作ると、Astroはそちらを優先します。

import type { APIRoute } from "astro";
import { getEmDashCollection } from "emdash";

const escapeXml = (s: string) =>
	s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

export const GET: APIRoute = async ({ site, url }) => {
	const origin = (site ?? url).origin;
	const urls: string[] = [];
	let cursor: string | undefined;
	do {
		// ログインしていない状態で取得するので、下書きは含まれない
		const { entries, nextCursor } = await getEmDashCollection("posts", {
			orderBy: { published_at: "desc" },
			limit: 100,
			cursor,
		});
		for (const entry of entries) {
			const loc = escapeXml(`${origin}/${encodeURIComponent(entry.id)}/`);
			const lastmod = entry.data.updatedAt ?? entry.data.publishedAt;
			urls.push(
				`<url><loc>${loc}</loc>` +
					(lastmod ? `<lastmod>${new Date(lastmod).toISOString()}</lastmod>` : "") +
					"</url>",
			);
		}
		cursor = nextCursor;
	} while (cursor);

	const body = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">${urls.join("")}</urlset>`;
	return new Response(body, { headers: { "Content-Type": "application/xml; charset=utf-8" } });
};

WXRから取り込んだ直後は、updatedAtが取り込みの日時になり、全記事のlastmodが同じ日になります。公開日を出したい場合は、publishedAtを先に見るように順番を入れ替えます。

固定ページ用には、"posts"を"pages"に替えたsitemap-pages.xml.tsを作ります。サイトマップの一覧(/sitemap.xml)は、EmDashのものをそのまま使います。中身はsitemap-posts.xmlとsitemap-pages.xmlへのリンクだけなので、末尾スラッシュの問題は起きません。

載っているURLがすべて200か確かめる

差し替えた後は、サイトマップに載ったURLを全部開いて、200が返るか確かめます。試したサイトでは、公開中の記事20件と固定ページ4件のすべてが200でした。下書きの記事は、サイトマップに載りませんでした。