Der page:fragments Hook ermöglicht es einem Plugin, rohes HTML, Skripte oder Stylesheets zu öffentlichen Seiten beizutragen. Es ist das richtige Werkzeug für Analytics-Tags, Drittanbieter-Widgets, benutzerdefiniertes CSS und alles andere, das JavaScript oder Markup direkt in den Browser des Besuchers liefern muss.
Es ist auf native Plugins beschränkt, da seine Ausgabe als First-Party-Code im Browser läuft, außerhalb jeglicher Sandbox-Grenzen. Wenn Sie nur strukturierte Metadaten beitragen müssen — Meta-Tags, OpenGraph, JSON-LD, zugelassene <link> rels — verwenden Sie stattdessen page:metadata, das sowohl für sandboxed als auch für native Plugins verfügbar ist. Siehe Hooks: page:metadata.
Capability
page:fragments erfordert die hooks.page-fragments:register Capability:
return definePlugin({
id: "analytics-gtm",
version: "1.0.0",
capabilities: ["hooks.page-fragments:register"],
// ...
});
Die Capability muss auch im Descriptor erscheinen.
Wo Fragmente gerendert werden
Templates können Fragmente empfangen, indem sie die relevanten Komponenten aus emdash/ui einbinden:
<EmDashHead />— rendert Fragmente mitplacement: "head"plus allepage:metadataBeiträge.<EmDashBodyStart />— rendert Fragmente mitplacement: "body:start".<EmDashBodyEnd />— rendert Fragmente mitplacement: "body:end".
Templates, die eine dieser Komponenten weglassen, ignorieren stillschweigend Fragmente, die auf diese Platzierung abzielen — Ihr Plugin bricht nicht, die Fragmente erscheinen einfach nicht. Dokumentieren Sie Ihre Platzierungsanforderung in der README des Plugins.
Contribution-Arten
Ein Hook kann eine von drei Contribution-Arten zurückgeben:
type PageFragmentContribution =
| {
kind: "external-script";
placement: PagePlacement;
src: string;
async?: boolean;
defer?: boolean;
attributes?: Record<string, string>;
key?: string;
}
| {
kind: "inline-script";
placement: PagePlacement;
code: string;
attributes?: Record<string, string>;
key?: string;
}
| {
kind: "html";
placement: PagePlacement;
html: string;
key?: string;
};
PagePlacement ist "head" | "body:start" | "body:end".
Beispiele
Externes Skript
Der folgende Hook fügt einen Drittanbieter-Tag-Manager in <head> ein:
"page:fragments": async (event, ctx) => {
const containerId = await ctx.kv.get<string>("settings:gtmContainerId");
if (!containerId) return null;
return {
kind: "external-script",
placement: "head",
src: `https://www.googletagmanager.com/gtm.js?id=${containerId}`,
async: true,
};
},
Inline-Skript
Der folgende Hook führt ein kleines JavaScript-Stück oben im <body> auf Content-Seiten aus:
"page:fragments": async (event, ctx) => {
if (event.page.kind !== "content") return null;
return {
kind: "inline-script",
placement: "body:start",
code: `window.contentId = ${JSON.stringify(event.page.content?.id)};`,
};
},
HTML-Fragment
Der folgende Hook fügt ein noscript-Fallback am Ende von <body> hinzu:
"page:fragments": async (event, ctx) => {
const containerId = await ctx.kv.get<string>("settings:gtmContainerId");
if (!containerId) return null;
return {
kind: "html",
placement: "body:end",
html: `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${containerId}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>`,
};
},
Mehrere Fragmente
Ein Hook kann ein Array zurückgeben, um mehrere Fragmente auf einmal beizutragen. Der folgende Hook fügt sowohl ein Skript als auch ein noscript-Fallback hinzu:
"page:fragments": async (event, ctx) => {
const id = await ctx.kv.get<string>("settings:gtmContainerId");
if (!id) return null;
return [
{
kind: "external-script",
placement: "head",
src: `https://www.googletagmanager.com/gtm.js?id=${id}`,
async: true,
},
{
kind: "html",
placement: "body:end",
html: `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${id}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>`,
},
];
},
Page Event
Der page:fragments Hook erhält dieselbe Event-Form wie page:metadata:
{
page: {
url: string;
path: string;
locale: string | null;
kind: "content" | "custom";
pageType: string;
title: string | null;
pageTitle?: string | null;
description: string | null;
canonical: string | null;
image: string | null;
content?: { collection: string; id: string; slug: string | null };
}
}
Verwenden Sie event.page.kind und event.page.pageType, um zu entscheiden, ob Sie auf einer bestimmten Seite beitragen möchten — zum Beispiel Analytics bei Admin-Vorschauen überspringen oder JSON-LD nur bei Blog-Posts einfügen.
Wann stattdessen page:metadata verwenden
Wenn Sie tatsächlich benötigen:
- Eine Meta-Beschreibung, Robots-Direktive oder Twitter-Card →
page:metadatamitkind: "meta". - Eine OpenGraph-Eigenschaft →
page:metadatamitkind: "property". - Einen kanonischen oder alternativen
<link>→page:metadatamitkind: "link". - Einen JSON-LD-Graph →
page:metadatamitkind: "jsonld".
page:metadata funktioniert in sandboxed Plugins, erhält kostenlose Validierung und Deduplizierung und vermeidet die Vertrauenslast, rohes HTML an Besucher zu liefern. Greifen Sie nur dann auf page:fragments zurück, wenn Sie JavaScript oder HTML liefern müssen.