LaJungle FSE — Guide du développeur
Bonnes pratiques pour créer un site avec le thème lajungle-fse et les plugins ljd-core + ljd-blocks. Stack native FSE, sans ACF, sans Blade.
Stack technique
Le projet repose sur Bedrock comme base WordPress, un thème FSE natif
(sans Sage, sans Blade), le plugin ljd-core pour la logique métier PHP
et le plugin ljd-blocks pour les blocs Gutenberg React.
- Bedrock — structure, Composer, .env
- WordPress 7 (
roots/wordpress-full) - Docker — Nginx + PHP 8.3 + MySQL
- WP-CLI via
make wp
- FSE natif (parts, templates, theme.json)
- PostCSS + cssnano pour le CSS
- Chargement via
config/features.php - Basé sur TwentyTwentyFive
- CPT, taxonomies, features PHP
- Abstractions
AbstractFeature,AbstractCPT
- Blocs Gutenberg custom (React)
block.json+edit.js+save.js- @wordpress/scripts (Webpack) pour les scripts JS
- Blocs natifs Gutenberg
- Blocs custom React via ljd-blocks
Démarrer un projet
Prérequis
- Docker Desktop
- Node.js
- npm
Installation complète
TODOArchitecture du projet
Le projet suit la structure Bedrock. Le code métier est dans web/app/,
séparé du core WordPress dans web/wp/ (géré par Composer, ne pas modifier).
mon-projet/
├── config/ ← Config Bedrock par environnement
│ ├── application.php ← Config globale (DB, salts, WP_ENV)
│ └── environments/ ← development.php / staging.php
├── web/
│ ├── app/
│ │ ├── mu-plugins/ ← Must-use plugins (autoloadés)
│ │ ├── plugins/
│ │ │ ├── ljd-core/ ← Plugin PHP : CPT, Features, Fields
│ │ │ │ ├── src/ ← Abstracts, CPT, Features, Fields
│ │ │ │ ├── ljd-core.php
│ │ │ │ └── composer.json
│ │ │ └── ljd-blocks/ ← Plugin blocs Gutenberg React
│ │ │ ├── src/
│ │ │ │ ├── blocks/ ← Blocs custom (block.json + edit/save/render)
│ │ │ │ ├── sub-blocks/ ← Sous-blocs (parent + allowedBlocks)
│ │ │ │ ├── extensions/ ← Scripts éditeur (meta-fields, options-page…)
│ │ │ │ ├── components/ ← Composants React partagés
│ │ │ │ ├── hooks/ ← Hooks React custom
│ │ │ │ └── lib/ ← Fonctions utilitaires pures
│ │ │ ├── ljd-blocks.php
│ │ │ └── webpack.config.js ← auto-découverte extensions + blocks
│ │ └── themes/
│ │ └── lajungle-fse/ ← Thème FSE natif
│ │ ├── parts/ ← Template parts (header, footer…)
│ │ ├── templates/ ← Templates de page FSE (.html)
│ │ ├── src/Features/ ← Features PHP du thème
│ │ ├── config/
│ │ │ ├── blocks.php ← Whitelist des blocs autorisés
│ │ │ └── features.php ← Liste des features à charger
│ │ ├── theme.json ← Design tokens (couleurs, typo, espacements)
│ │ ├── style.css ← CSS global minimal (minifié → style.min.css)
│ │ └── functions.php ← Bootstrap (lit et instancie features.php)
│ └── wp/ ← Core WordPress (Composer — ne pas modifier)
├── .env ← Variables locales (gitignorée)
├── .env.example ← Template à copier
├── composer.json ← Bedrock + dépendances PHP
├── Makefile ← Toutes les commandes de développement
└── docker-compose.yml ← Stack locale (Nginx + PHP + MySQL)
Plugin = bibliothèque · Thème = orchestrateur
Le plugin ljd-core ne déclare aucune feature par lui-même.
C'est le thème qui orchestre via config/features.php :
// web/app/themes/lajungle-fse/config/features.php
return [
// Features du thème
ThemeSetup::class, Assets::class, BlockStyles::class,
// CPTs déclarés dans ljd-core
NewsCPT::class, JobOfferCPT::class,
// Features de ljd-core
AllowedBlocks::class, Security::class, CleanPatterns::class,
];
features.php n'est pas enregistré.
Design system — theme.json v3
Tout le design system est centralisé dans theme.json (schéma v3, WP 6.6+).
Pas de SCSS ni de variables CSS manuelles dans le thème — WordPress génère
automatiquement les custom properties CSS à partir de theme.json.
(Le plugin ljd-blocks peut utiliser PostCSS/SCSS pour ses styles d'éditeur — voir Architecture ljd-blocks.)
theme.json// theme.json — structure racine (à inclure dans tout projet)
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": { /* couleurs, typo, espacements… */ },
"styles": { /* styles par défaut */ },
"templateParts": [],
"customTemplates": []
}
$schema et "version": 3
Le $schema active la validation et l'autocomplétion dans VS Code / PhpStorm.
"version": 3 est requis pour les fonctionnalités WP 6.6+ (presets border-radius, styles formulaires, pseudo-classes bouton).
Référence : theme.json living reference.
Palette de couleurs
Désactiver les palettes natives pour forcer l'utilisation de la palette projet :
"color": {
"defaultPalette": false,
"defaultGradients": false,
"palette": [
{ "slug": "base", "color": "#FFFFFF", "name": "Base" },
{ "slug": "contrast", "color": "#111111", "name": "Contrast" },
{ "slug": "accent-1", "color": "#FFEE58", "name": "Accent 1" },
{ "slug": "accent-3", "color": "#503AA8", "name": "Accent 3" }
]
}
En CSS : var(--wp--preset--color--accent-1) · Dans theme.json : var:preset|color|accent-1
Typographie fluide
Les tailles fluides calculent automatiquement un clamp() selon la largeur du viewport :
"fontSizes": [
{ "slug": "small", "size": "0.875rem", "fluid": false },
{ "slug": "medium", "size": "1rem",
"fluid": { "min": "1rem", "max": "1.125rem" } },
{ "slug": "xx-large", "size": "2.15rem",
"fluid": { "min": "2.15rem", "max": "3rem" } }
]
Échelle d'espacements
| Slug | Nom | Valeur | CSS |
|---|---|---|---|
20 | Tiny | 10px | var(--wp--preset--spacing--20) |
40 | Small | 30px | var(--wp--preset--spacing--40) |
50 | Regular | clamp(30px, 5vw, 50px) | var(--wp--preset--spacing--50) |
60 | Large | clamp(30px, 7vw, 70px) | var(--wp--preset--spacing--60) |
80 | XX-Large | clamp(70px, 10vw, 140px) | var(--wp--preset--spacing--80) |
Polices auto-hébergées
Déclarer les polices dans theme.json, pas en CSS. Les fichiers woff2 sont dans assets/fonts/ :
"fontFamilies": [{
"slug": "manrope",
"fontFamily": "Manrope, sans-serif",
"fontFace": [{
"src": ["file:./assets/fonts/manrope/Manrope-VariableFont_wght.woff2"],
"fontWeight": "200 800"
}]
}]
Workflow Figma → theme.json
- Export des tokens Figma
Exporter couleurs, typographies et espacements (plugin Tokens Studio ou export manuel).
- Traduction en slugs cohérents
Nommer
base,contrast,accent-1… pour réutilisation entre projets. - Mise à jour de theme.json
Modifier la section
settingspour les tokens, etstyles.blockspour appliquer aux blocs natifs. - Validation dans le Site Editor
Ouvrir Apparence → Éditeur et vérifier que couleurs et typographies apparaissent dans la sidebar.
var:preset|color|accent-1 (syntaxe interne), pas
var(--wp--preset--color--accent-1) — WordPress gère le rendu
selon le contexte (front / éditeur).
Styles par bloc — styles.blocks
Appliquer des styles par défaut à n'importe quel bloc dans tout le site, sans CSS inline. Indispensable pour harmoniser les résultats de Query Loop :
"styles": {
"blocks": {
"core/post-title": {
"typography": { "fontSize": "var:preset|font-size|x-large" }
},
"core/post-excerpt": {
"color": { "text": "var:preset|color|muted" }
},
"core/buttons": {
"spacing": { "margin": { "top": "var:preset|spacing|40" } }
}
}
}
Nouveautés WP 6.9
Déclarer des presets dans settings.border.radiusSizes pour un sélecteur visuel dans l'éditeur. Les utilisateurs peuvent toujours saisir une valeur libre.
Styler <input> et <select> via styles.elements.input — border, color, shadow, spacing. Focus state non disponible en 6.9.
Styler :hover et :focus du bloc Button directement dans theme.json, sans CSS additionnel.
Polices — Font Library & theme.json WP 6.5+
WordPress propose deux mécanismes pour gérer les polices. Les confondre ou les mélanger génère des doublons, des conflits et des surprises en production. Choisir l'un ou l'autre selon le contexte ; ne pas utiliser les deux sur le même projet.
- Polices déclarées dans le dépôt git
- Fichiers
.woff2versionnés dansassets/fonts/ - Reproductible, déployable, auditeable
- À utiliser sur tous les projets LaJungle
- Upload via Apparence → Polices dans l'admin
- Stockage dans
wp-content/fonts/(hors git) - Fonctionnel pour prototypage ou site client sans dev
- À éviter sur les projets avec thème custom
theme.json déclare une police et que la Font Library en upload une
du même nom, WordPress génère deux @font-face avec des chemins différents.
Résultat : comportement imprévisible selon l'ordre de chargement des styles.
Bonnes pratiques 2026 — À faire / À éviter
| ✅ À faire | ❌ À éviter |
|---|---|
| Variable font WOFF2 — un seul fichier pour toutes les graisses | Charger 4–5 fichiers statiques quand une variable font existe |
Auto-héberger les polices dans assets/fonts/ (versionnées git) |
Google Fonts via wp_enqueue_style ou @import — requête tierce, RGPD |
Déclarer dans theme.json avec "fontDisplay": "swap" |
Définir les @font-face manuellement en CSS — doublon avec theme.json |
| Subsetté latin + latin-ext — retire les glyphes inutiles (−60 à −80 %) | Embarquer la police complète (2 000+ glyphes) pour un site en français |
| Précharger uniquement la police body (1–2 max) via Feature PHP | Précharger toutes les polices — contention réseau, ralentit le rendu |
defaultFontFamilies: false pour masquer les polices natives WP |
Laisser les polices WP par défaut polluer le sélecteur éditeur |
| Tout versionner dans git — reproductible entre tous les envs | Uploader via Apparence → Polices sur un thème custom (hors git = dérive) |
Déclaration dans theme.json — fontFamilies + fontFace
Déclarer chaque famille avec ses variantes directement dans theme.json.
WordPress génère automatiquement les règles @font-face et les variables CSS
--wp--preset--font-family--{slug}.
Le préfixe file: résout le chemin depuis la racine du thème :
// theme.json — settings.typography.fontFamilies
"fontFamilies": [
{
"slug": "manrope",
"name": "Manrope",
"fontFamily": "Manrope, sans-serif",
"fontFace": [
{
"fontFamily": "Manrope",
"fontWeight": "200 800", // plage variable font
"fontStyle": "normal",
"fontDisplay": "swap", // évite le FOIT
"src": ["file:./assets/fonts/manrope/Manrope-VariableFont_wght.woff2"]
}
]
},
{
"slug": "playfair",
"name": "Playfair Display",
"fontFamily": "'Playfair Display', Georgia, serif",
"fontFace": [
{
"fontFamily": "Playfair Display",
"fontWeight": "400",
"fontStyle": "normal",
"fontDisplay": "swap",
"src": ["file:./assets/fonts/playfair/PlayfairDisplay-Regular.woff2"]
},
{
"fontFamily": "Playfair Display",
"fontWeight": "700",
"fontStyle": "normal",
"fontDisplay": "swap",
"src": ["file:./assets/fonts/playfair/PlayfairDisplay-Bold.woff2"]
}
]
}
]
fontFace suffit avec une plage "fontWeight": "200 800".
Le fichier .woff2 pèse souvent moins lourd que la somme de 4 ou 5 fichiers statiques.
Préférer systématiquement les variable fonts en 2026.
Appliquer une police par défaut — styles.typography
Définir les polices de base du site dans la section styles de theme.json :
"styles": {
"typography": {
"fontFamily": "var:preset|font-family|manrope" // police du body
},
"blocks": {
"core/heading": {
"typography": {
"fontFamily": "var:preset|font-family|playfair"
}
}
}
}
Désactiver les polices et tailles par défaut de WordPress
WordPress 6.5+ inclut un jeu de polices par défaut (Inter, Cardo…) qui apparaissent dans le sélecteur de l'éditeur si on ne les désactive pas explicitement. Forcer uniquement les polices du projet :
"settings": {
"typography": {
"defaultFontSizes": false, // masque les tailles WP (small, medium…)
"defaultFontFamilies": false, // masque les polices WP par défaut
"fontFamilies": [ /* vos polices uniquement */ ],
"fontSizes": [ /* vos tailles uniquement */ ]
}
}
Structure des fichiers de police
Stocker les polices dans assets/fonts/, organisées par famille.
N'embarquer que les variantes réellement utilisées dans le design :
lajungle-fse/assets/fonts/
├── manrope/
│ └── Manrope-VariableFont_wght.woff2 ← toutes graisses (200–800)
└── playfair/
├── PlayfairDisplay-Regular.woff2 ← 400 normal
├── PlayfairDisplay-Italic.woff2 ← 400 italic (si utilisé)
└── PlayfairDisplay-Bold.woff2 ← 700 normal
.ttf, .eot et .woff — ils augmentent la taille du dépôt
et ne servent plus à rien. Un seul fichier par variante suffit.
Subsetting — réduire le poids des fichiers
Une police complète peut contenir des milliers de glyphes (cyrillique, grec, symboles…) inutiles pour un site en français. Le subsetting conserve uniquement les caractères nécessaires et réduit la taille de 60 à 80 %.
- Google Fonts Helper (gwfh.mranftl.com) — télécharger directement les subset
latin+latin-exten WOFF2 - Glyphhanger — outil CLI Node.js pour subsetté à partir du HTML réel du projet
- FontForge / pyftsubset — subsetting précis par liste de caractères Unicode
Pour un site français standard : subset latin + latin-ext (accents, ligatures) est suffisant.
Préchargement des polices critiques
WordPress ne génère pas automatiquement de <link rel="preload"> pour les polices
déclarées dans theme.json. Ajouter le preload manuellement dans une Feature du thème
pour uniquement la police du body (au-dessus de la ligne de flottaison) :
// src/Features/FontPreload.php
class FontPreload extends AbstractFeature
{
public function register(): void
{
add_action('wp_head', [$this, 'preloadFonts'], 1);
}
public function preloadFonts(): void
{
$fonts = [
'manrope/Manrope-VariableFont_wght.woff2',
// ne pas précharger plus de 2 polices — contention réseau
];
foreach ($fonts as $font) {
$url = get_theme_file_uri("assets/fonts/{$font}");
echo "<link rel=\"preload\" as=\"font\" type=\"font/woff2\" "
. "href=\"{$url}\" crossorigin>\n";
}
}
}
Puis ajouter FontPreload::class dans config/features.php.
Variables CSS générées automatiquement
Pour chaque famille déclarée dans theme.json, WordPress génère une custom property
utilisable partout :
| Slug | Variable CSS | Syntaxe theme.json interne |
|---|---|---|
manrope | var(--wp--preset--font-family--manrope) | var:preset|font-family|manrope |
playfair | var(--wp--preset--font-family--playfair) | var:preset|font-family|playfair |
En CSS custom (fichier style.css ou style de bloc) : utiliser la syntaxe
var(--wp--preset--...). Dans theme.json (styles.blocks,
styles.elements) : utiliser la syntaxe var:preset|font-family|slug.
Font Library UI — quand l'utiliser
L'interface Apparence → Polices (/wp-admin/font-library.php)
est utile dans deux cas précis :
- Prototypage rapide — tester une police Google Fonts avant de l'intégrer proprement dans
theme.json - Site client sans développeur — le client gère lui-même ses polices sans accès au code
Les polices uploadées via cette interface sont stockées dans
wp-content/fonts/ et référencées dans la base de données —
elles ne sont pas versionnées et peuvent disparaître lors d'une migration.
theme.json. Désactiver l'accès si nécessaire via le filtre
block_editor_settings_all ou en retirant la capacité edit_theme_options
aux rôles non-admin.
Récapitulatif — checklist polices 2026
- Variable font WOFF2 uniquement
Télécharger via Google Fonts Helper, subset latin + latin-ext. Un seul fichier par famille quand c'est une variable font.
- Versionner dans
assets/fonts/Les fichiers
.woff2font partie du dépôt git — reproductibilité garantie entre environnements. - Déclarer dans
theme.jsonavecfontDisplay: swapToujours ajouter
"fontDisplay": "swap"sur chaquefontFacepour éviter le texte invisible pendant le chargement. - Désactiver les polices et tailles WP par défaut
defaultFontFamilies: false+defaultFontSizes: falsedanssettings.typography. - Précharger uniquement la police body
Feature
FontPreloadavecadd_action('wp_head', ..., 1)— maximum 2 polices. - Ne jamais uploader via l'UI Font Library sur un thème custom
Les fonts hors git = dérive entre environnements. Tout passe par
theme.json.
Layout FSE — Parts & Templates
Template Parts (parts/)
Les parts sont des fragments réutilisables (header, footer, sidebar). Les déclarer dans theme.json :
parts/ — pas dans des sous-dossiers. WordPress ne scanne pas les répertoires imbriqués pour les template parts.
"templateParts": [
{ "area": "header", "name": "header", "title": "Header" },
{ "area": "header", "name": "header-large-title", "title": "Header large" },
{ "area": "header", "name": "vertical-header", "title": "Vertical header" },
{ "area": "footer", "name": "footer", "title": "Footer" },
{ "area": "uncategorized", "name": "sidebar", "title": "Sidebar" }
]
Inclusion dans un template :
<!-- wp:template-part {"slug":"header"} /-->
Templates (templates/)
| Fichier | Quand utilisé |
|---|---|
front-page.html | Page d'accueil — priorité absolue sur home.html et page.html |
index.html | Fallback universel (requis) |
home.html | Page de blog (liste des articles) |
page.html | Page statique standard |
page-no-title.html | Template personnalisé — page sans titre |
single.html | Article de blog |
archive.html | Archives (catégories, dates, CPT) |
search.html | Résultats de recherche |
404.html | Page non trouvée |
Anatomie d'un template page
<!-- templates/page.html -->
<!-- wp:template-part {"slug":"header"} /-->
<!-- wp:group {"tagName":"main","layout":{"type":"constrained"}} -->
<main class="wp-block-group">
<!-- wp:group {"align":"full","layout":{"type":"constrained"}} -->
<div class="wp-block-group alignfull">
<!-- wp:post-featured-image /-->
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-content {"align":"full","layout":{"type":"constrained"}} /-->
</div>
<!-- /wp:group -->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer"} /-->
Template pour un CPT
Créer les fichiers dans templates/ — WordPress les détecte automatiquement
selon sa hiérarchie :
single-posttype.html— vue d'un item uniquearchive-posttype.html— liste des itemstaxonomy-slug.html— items d'une taxonomie donnée
theme.json et les
clamp(). Ne pas ajouter de media queries dans les templates HTML.
Templates personnalisés — customTemplates
Pour qu'un template apparaisse dans la liste déroulante "Template" de l'éditeur de page, le déclarer dans theme.json :
"customTemplates": [
{ "name": "page-no-title", "title": "Page sans titre", "postTypes": ["page"] },
{ "name": "landing", "title": "Landing Page", "postTypes": ["page"] }
]
Le fichier correspondant doit exister dans templates/ — ex. templates/landing.html. Le champ name doit correspondre exactement au nom du fichier (sans .html).
theme.json et les fichiers .html. Si un changement de thème ne s'applique pas :– Styles : Apparence → Éditeur → Styles → ⋮ → Réinitialiser les styles.
– Templates : Éditeur → Templates → sélectionner → ⋮ → Effacer les modifications.
Query Loop — core/query
Le bloc core/query est le seul mécanisme FSE pour afficher des listes de posts ou de CPT dans les templates HTML. Il remplace WP_Query dans les templates et prend en charge la pagination native, les filtres et le rendu server-side.
Structure complète
<!-- templates/archive-news.html — liste paginée de News -->
<!-- wp:query {
"query": { "postType": "news", "perPage": 12, "order": "desc", "orderBy": "date" },
"namespace": "ljd/news-list"
} -->
<div class="wp-block-query">
<!-- wp:post-template {"layout":{"type":"grid","columnCount":3}} -->
<!-- wp:post-featured-image {"isLink":true} /-->
<!-- wp:post-terms {"term":"news_category"} /-->
<!-- wp:post-title {"isLink":true,"level":3} /-->
<!-- wp:post-excerpt {"moreText":"Lire la suite"} /-->
<!-- wp:post-date /-->
<!-- /wp:post-template -->
<!-- wp:query-pagination {"layout":{"type":"flex","justifyContent":"center"}} -->
<!-- wp:query-pagination-previous /-->
<!-- wp:query-pagination-numbers /-->
<!-- wp:query-pagination-next /-->
<!-- /wp:query-pagination -->
<!-- wp:query-no-results -->
<!-- wp:paragraph --><p>Aucun résultat.</p><!-- /wp:paragraph -->
<!-- /wp:query-no-results -->
</div>
<!-- /wp:query -->
Paramètres query clés
| Paramètre | Type | Usage |
|---|---|---|
postType | string | Slug du CPT ciblé ("news", "job_offer"…) |
perPage | number | Nombre d'items par page |
order / orderBy | string | "desc"/"date", "asc"/"title", "asc"/"menu_order"… |
taxQuery | object | Filtrer par terme de taxonomie — {"news_category":[42]} |
inherit | boolean | true = hérite de la requête de la page courante (archive, recherche) |
sticky | string | "exclude" pour ignorer les posts épinglés |
offset | number | Décaler les résultats (utile pour les "featured" séparés) |
Mode hérité — templates d'archive
Dans un template archive-news.html ou taxonomy-news_category.html, utiliser "inherit":true pour que WordPress injecte automatiquement les paramètres de l'archive courante (type, terme, pagination) :
<!-- wp:query {"query":{"inherit":true},"namespace":"ljd/news-archive"} -->
<!-- ... -->
<!-- /wp:query -->
postType ou perPage dans un template d'archive si inherit:true est actif — WordPress gère la requête. Réserver les paramètres manuels aux pages statiques qui embarquent une Query Loop.
Blocs enfants disponibles dans post-template
core/post-titlecore/post-excerptcore/post-contentcore/post-featured-image
core/post-datecore/post-authorcore/post-terms(taxo)core/read-more
core/query-paginationcore/query-pagination-previouscore/query-pagination-numberscore/query-pagination-nextcore/query-no-results
namespace — QueryLoopExcludeCurrentPost
L'attribut namespace identifie une Query Loop spécifique dans les filtres PHP.
La feature QueryLoopExcludeCurrentPost de ljd-core l'utilise pour
exclure automatiquement le post courant des listes "articles liés" sur les pages single :
<!-- Query Loop sur un single-news.html — exclut le post courant -->
<!-- wp:query {
"query": { "postType": "news", "perPage": 3 },
"namespace": "ljd/news-related"
} -->
pre_get_posts, query_loop_block_query_vars) sans affecter les autres loops de la page.
Patterns
Les patterns sont des compositions de blocs réutilisables exposées dans l'inserteur.
Préférer les patterns filesystem (dans patterns/) aux patterns
enregistrés en PHP dans une Feature — ils sont automatiquement découverts par WordPress.
Pattern filesystem (patterns/*.php)
Chaque fichier dans patterns/ est un pattern. L'en-tête PHP (commentaire) déclare ses métadonnées :
<?php
/**
* Title: Grille News
* Slug: ljd/news-grid
* Categories: lajungle
* Block Types: core/query
* Inserter: true
*/
?>
<!-- wp:query {"query":{"postType":"news","perPage":6}} -->
<div class="wp-block-query">
<!-- wp:post-template {"layout":{"type":"grid","columnCount":3}} -->
<!-- wp:post-title {"isLink":true,"level":3} /-->
<!-- wp:post-excerpt /-->
<!-- /wp:post-template -->
</div>
<!-- /wp:query -->
En-têtes disponibles
| En-tête | Obligatoire | Description |
|---|---|---|
Title | Oui | Nom affiché dans l'inserteur |
Slug | Oui | Identifiant unique namespace/nom |
Categories | Non | Catégorie dans l'inserteur (enregistrée via register_block_pattern_category) |
Block Types | Non | Propose automatiquement le pattern quand ce bloc est inséré |
Inserter | Non | false = pattern interne, non visible dans l'inserteur |
Post Types | Non | Limite la visibilité à certains types de posts |
Gestion des blocs
Whitelist des blocs (config/blocks.php)
Seuls les blocs listés sont accessibles dans l'éditeur.
Le fichier retourne un tableau PHP de slugs, ou true pour tout autoriser.
C'est AllowedBlocks::class (listé dans config/features.php) qui lit ce fichier
et hook allowed_block_types_all.
// config/blocks.php
return [
// ── Layout ───────────────────────────────────────────────────────────────
'core/group',
'core/columns', 'core/column',
'core/row', 'core/stack', 'core/grid',
// ── Contenu ──────────────────────────────────────────────────────────────
'core/paragraph', 'core/heading',
'core/list', 'core/list-item',
'core/quote', 'core/pullquote',
'core/table', 'core/details',
'core/code', 'core/preformatted', 'core/verse',
// ── Media ────────────────────────────────────────────────────────────────
'core/image', 'core/gallery',
'core/video', 'core/audio', 'core/file',
'core/cover', 'core/media-text',
// ── Design ───────────────────────────────────────────────────────────────
'core/buttons', 'core/button',
'core/separator', 'core/spacer', 'core/html',
// ── Navigation & thème ───────────────────────────────────────────────────
'core/navigation', 'core/navigation-link', 'core/navigation-submenu',
'core/site-logo', 'core/site-title', 'core/site-tagline',
'core/template-part', 'core/pattern',
// ── Query Loop ───────────────────────────────────────────────────────────
'core/query', 'core/post-template',
'core/post-title', 'core/post-excerpt', 'core/post-featured-image',
'core/post-date', 'core/post-terms', 'core/post-author', 'core/post-content',
'core/query-no-results',
'core/query-pagination', 'core/query-pagination-next',
'core/query-pagination-previous', 'core/query-pagination-numbers'
];
true au lieu du tableau désactive le filtre et autorise tous les blocs.
Pratique en dev pour déboguer sans contrainte. Si config/blocks.php est absent, AllowedBlocks retourne aussi true par défaut.
Pour ajouter un bloc ponctuellement sans modifier le fichier (ex. depuis un autre plugin) :
add_filter('lajungle_core/allowed_blocks', function(array $blocks): array {
$blocks[] = 'mon-plugin/mon-bloc';
return $blocks;
});
Bloc custom React
mon-bloc/
├── block.json ← Déclaration, attributs, supports
├── edit.js ← Interface éditeur (React)
├── save.js ← HTML statique sauvegardé en base
└── style.css ← Style front (optionnel)
// block.json — structure minimale
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "ljd/mon-bloc",
"title": "Mon Bloc",
"category": "lajungle",
"supports": { "html": false, "color": { "background": true } },
"attributes": {
"titre": { "type": "string", "default": "" }
},
"editorScript": "file:./index.js"
}
"source": "meta" dans les attributs
La source meta est dépréciée et génère des comportements imprévisibles à long terme. Pour lier un attribut à un meta field, utiliser les Block Bindings (core/post-meta, WP 6.5+) ou passer la valeur via render.php avec get_post_meta().
apiVersion: 3 est obligatoire pour tous les nouveaux blocs. WP 6.9 émet des warnings console pour apiVersion 2 quand SCRIPT_DEBUG est activé.
WP 6.3–6.9 : l'éditeur passe en iframe si tous les blocs du contenu sont apiVersion 3+ — un seul bloc apiVersion 2 désactive l'iframe pour ce contenu.
WP 7.0 : l'iframe est activée systématiquement, indépendamment de l'apiVersion.
Bénéfices : isolation des styles admin, unités vw/vh et media queries correctes. Vérifier que tous les handles CSS sont déclarés dans block.json — les styles non référencés ne se chargent pas dans l'iframe.