Le hook page:fragments permet à un plugin de contribuer du HTML brut, des scripts ou des feuilles de style aux pages publiques. C’est l’outil approprié pour les balises d’analyse, les widgets tiers, le CSS personnalisé et tout ce qui doit livrer du JavaScript ou du balisage directement dans le navigateur du visiteur.
Il est restreint aux plugins natifs car sa sortie s’exécute comme du code first-party dans le navigateur, en dehors de toute limite de sandbox. Si vous devez uniquement contribuer des métadonnées structurées — balises meta, OpenGraph, JSON-LD, <link> rels autorisés — utilisez plutôt page:metadata, qui est disponible pour les plugins sandboxés et natifs. Voir Hooks: page:metadata.
Capability
page:fragments nécessite la capability hooks.page-fragments:register:
return definePlugin({
id: "analytics-gtm",
version: "1.0.0",
capabilities: ["hooks.page-fragments:register"],
// ...
});
La capability doit également apparaître sur le descripteur.
Où les fragments sont rendus
Les templates optent pour recevoir des fragments en incluant les composants pertinents de emdash/ui:
<EmDashHead />— rend les fragments avecplacement: "head"plus toutes les contributionspage:metadata.<EmDashBodyStart />— rend les fragments avecplacement: "body:start".<EmDashBodyEnd />— rend les fragments avecplacement: "body:end".
Les templates qui omettent l’un de ces composants ignorent silencieusement les fragments ciblant ce placement — votre plugin ne casse pas, les fragments n’apparaissent simplement pas. Documentez votre exigence de placement dans le README du plugin.
Types de contribution
Un hook peut retourner l’un des trois types de contribution:
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 est "head" | "body:start" | "body:end".
Exemples
Script externe
Le hook suivant injecte un gestionnaire de balises tiers dans <head>:
"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,
};
},
Script en ligne
Le hook suivant exécute un petit morceau de JavaScript en haut de <body> sur les pages de contenu:
"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)};`,
};
},
Fragment HTML
Le hook suivant ajoute un fallback noscript à la fin de <body>:
"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>`,
};
},
Plusieurs fragments
Un hook peut retourner un tableau pour contribuer plusieurs fragments à la fois. Le hook suivant ajoute à la fois un script et un fallback noscript:
"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>`,
},
];
},
Événement de page
Le hook page:fragments reçoit la même forme d’événement que 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 };
}
}
Utilisez event.page.kind et event.page.pageType pour décider si vous devez contribuer sur une page donnée — par exemple, ignorer les analyses sur les aperçus d’administration ou n’injecter du JSON-LD que sur les articles de blog.
Quand utiliser page:metadata à la place
Si ce dont vous avez réellement besoin est:
- Une meta description, directive robots ou carte Twitter →
page:metadataaveckind: "meta". - Une propriété OpenGraph →
page:metadataaveckind: "property". - Un
<link>canonique ou alternatif →page:metadataaveckind: "link". - Un graphe JSON-LD →
page:metadataaveckind: "jsonld".
page:metadata fonctionne dans les plugins sandboxés, obtient la validation et la déduplication gratuitement, et évite le fardeau de confiance de livrer du HTML brut aux visiteurs. N’utilisez page:fragments que lorsque vous devez livrer du JavaScript ou du HTML.