chore: session 2 snapshot — archive before Bricks-first restart

Snapshots the project at the end of session 2, just before resetting to a
Bricks-first orthodox architecture. RESTART-PLAN.md at the root explains
why this approach is being abandoned and what the next session will look like.

Why we restart
- Three architectures got stacked: Custom PHP Templates → Gutenberg blocks
  in post_content → Bricks data in post meta. Each layer fights the next.
- Bricks Builder UI does not load because our header.php / footer.php /
  page.php emit chrome that conflicts with Bricks' own template-parts.
- CSS overrides multiplied (Gutenberg + Bricks variants) and still don't
  pixel-match the original PHP-rendered visual.
- 8+ one-shot mu-plugins live in LocalWP to patch over inconsistencies.

What survives the restart (preserved here on main)
- BRIEF, both PDFs, .txt extracts (sources of truth)
- assets/css/tokens.css (full design system, untouched)
- assets/fonts/Inter-Variable*.woff2 (RGPD self-hosted)
- inc/<section>-data.php files (text copy from PDF strategie, will become
  /content-source/ on next session for reuse as translation dictionary
  and as input to programmatic page generation)
- The Git repo, remote, branch main
- LocalWP site, Bricks v2.3.4, WPML 4.9.3 with active licenses
- WPML EN + FR setup with directory URL strategy

What gets wiped at the start of next session
- wp-content/themes/asterion-bricks/header.php / footer.php / page.php /
  index.php / front-page.php / template-parts/ / templates/
- inc/render-blocks.php, inc/render-blocks-native.php, inc/render-bricks.php
- inc/shortcodes.php, inc/i18n.php, inc/form-handler.php
- 35+ WP pages created over the session
- All one-shot mu-plugins in LocalWP/wp-content/mu-plugins/

Restart approach (detailed in RESTART-PLAN.md)
- Minimalist child theme: style.css, functions.php, theme.json, tokens.css,
  trimmed utilities.css, fonts, inc/cpt.php — that's it.
- No header.php / footer.php / page.php in child theme — Bricks Templates
  (Header / Footer / Single — Page) take over via Bricks' Conditions.
- User builds 5-7 archetype Bricks templates visually (~1-2h each) then
  programmatic generation fills the variants from inc/*-data.php sources.
- WPML duplication after EN is validated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 14:30:51 +02:00
parent f18a57e83f
commit 026be81373
8 changed files with 1150 additions and 9 deletions

250
RESTART-PLAN.md Normal file
View File

@@ -0,0 +1,250 @@
# Restart Plan — Asterion VR refonte
**Date** : 2026-05-09 — fin de session 2
**Décision** : repartir d'une base propre, avec une approche Bricks-first orthodoxe.
---
## 1. Pourquoi redémarrer
L'approche actuelle a empilé trois architectures incompatibles :
1. **Custom Templates PHP** rendant depuis des data files (livrée, fonctionnait visuellement mais non éditable)
2. **Migration Gutenberg blocks** dans `post_content` (rendu visuel cassé, blocs `core/html` non éditables)
3. **Migration Bricks data** dans `_bricks_page_content_2` (Bricks builder UI ne s'affiche pas correctement parce que mes `header.php` / `footer.php` interfèrent)
À chaque tentative de fix, je rajoute un patch (override CSS, mu-plugin, conditionnel). Le résultat :
- Code du child theme pollué (multiple renderers coexistent : `render-blocks.php`, `render-blocks-native.php`, `render-bricks.php`)
- Settings Bricks bricolés, pas alignés sur le workflow Bricks officiel
- 35 pages WP créées + 4 doublons supprimés + duplications WPML qui ont nécessité un patch slug
- mu-plugins en cascade (8+ fichiers one-shot dans LocalWP)
**Bricks attend que le thème soit _minimaliste_ et qu'il prenne lui-même la main sur le rendu.** Mon child theme actuel fait l'inverse : il fournit des templates complets qui combattent Bricks.
---
## 2. Ce qu'on garde (à préserver dans le repo avant reset)
| Asset | Lieu actuel | Sort |
|---|---|---|
| Brief + 2 PDFs + .txt extraits | racine repo | **garder tel quel** — sources de vérité |
| `inc/solutions-data.php` + `industries-data.php` + `technology-data.php` + `editorial-data.php` + `forms-data.php` | child theme | **garder, mais déplacer dans `/content-source/`** — données pures, réutilisables comme source de génération ou comme dictionnaire de traduction WPML |
| `assets/css/tokens.css` (palette, typo, spacing, motion) | child theme | **garder dans le nouveau child theme** — design system partagé entre Bricks et notre CSS |
| `assets/fonts/Inter-Variable.woff2` + `Inter-Variable-Italic.woff2` | child theme | **garder** (RGPD, déjà self-hostés) |
| `BRIEF-Claude-Code.md`, `MISSING-ASSETS.md`, `README.md` | racine | **garder, à amender** |
| Repo Git, remote `git.polymorph.fr`, branche `main` | — | **garder**, on continue dessus |
| LocalWP `asterion-2026` site, WordPress 6.9, port 10004 | LocalWP | **garder**, juste reset le contenu pages + theme |
| Bricks parent v2.3.4 + WPML 4.9.3 + licenses | LocalWP | **garder** |
## Ce qu'on supprime / archive
- Tout `wp-content/themes/asterion-bricks/` actuel **archivé dans une branche `archive/php-templates`** puis ré-init du dossier
- Toutes les pages WP créées (35+) → wipe complet
- Tous les mu-plugins one-shot dans LocalWP → wipe (sauf `asterion-debug.php` et `asterion-status.php` que je laisse temporairement comme outils dev)
- Les overrides CSS Gutenberg / Bricks accumulés
- Les Custom Templates `templates/page-*.php`
- Les renderers PHP `render-blocks.php`, `render-blocks-native.php`, `render-bricks.php`
---
## 3. Architecture cible — Bricks-first orthodoxe
### 3.1. Child theme minimaliste
Le child theme `asterion-bricks` ne fait **plus** :
- ❌ Pas de `header.php` / `footer.php` custom (Bricks gère via ses **templates**)
- ❌ Pas de `front-page.php` / `page.php` / `index.php` custom (Bricks gère)
- ❌ Pas de Custom Templates `page-*.php`
Le child theme fait **uniquement** :
-`style.css` : header WP avec `Template: bricks` (obligatoire)
-`functions.php` : enqueue tokens.css + utilities.css en frontend, register CPT (case_study, scenario), self-host fonts
-`assets/css/tokens.css` : design tokens (couleurs, typo, spacing) en CSS variables
-`assets/css/utilities.css` : helpers très ciblés uniquement (`.av-skip-link`, `.av-sr-only`)
-`assets/fonts/` : Inter Variable self-hosté
-`inc/cpt.php` : Custom Post Types
-`theme.json` : optionnel, pour Gutenberg color picker en cohérence
**Total estimé : 8 fichiers, ~400 lignes.** Drastiquement plus léger.
### 3.2. Bricks Templates (= header / footer / archives / single)
Tout le shell visuel devient des **Bricks Templates** créés via le builder :
| Template Bricks | Type | Rôle |
|---|---|---|
| `Header` | header | Logo + nav (Solutions / Industries / Technology / Why Asterion / Insights) + CTA + lang switcher |
| `Footer` | footer | 5 colonnes + bottom strip |
| `Archive — Insights` | archive | Liste des posts (blog hub) |
| `Single — Insight` | single | Article de blog |
| `Archive — Customers` | archive | Liste case_study |
| `Single — Case Study` | single | Page case_study individuelle |
| (option) `Single — Page` | single | Fallback si une page n'a pas de Bricks data |
Ces templates s'appliquent automatiquement à toutes les pages/posts via les **Bricks "Conditions"** (par exemple "Apply on : All pages"). Tu (Jérôme) construis ces 5-7 templates **une seule fois** dans Bricks, à ton rythme.
### 3.3. Pages individuelles
Pour chaque page (Home, Solutions hub, MY PROSERVE, Industries hub, Police, etc.), 2 options selon l'effort qu'on veut investir :
**Option A — Build visuel dans Bricks (recommandé pour les 7 templates de page)**
1. Tu (Jérôme) construis 1 page de chaque archetype dans Bricks builder :
- Home
- Solution detail (1 fois → réutilisable pour les 4 tiers)
- Industry detail (1 fois → 4 industries)
- Technology detail (1 fois → 6 tech pages)
- Editorial (1 fois → 5 pages)
- Conversion form (1 fois → 4 forms)
- Legal (1 fois → 4 legals)
2. Pour chaque archetype, tu **sauvegardes en Template Bricks** avec un nom (ex. "Solution Detail") dans Bricks → Templates.
3. Pour les variantes (4 solutions, 4 industries, etc.) : tu importes le template puis change juste le contenu textuel (Bricks "Bulk Edit" ou copy-paste).
**Effort estimé** : 7 templates × 30-60 min de build visuel = 4-7h de ton temps.
**Option B — Génération programmatique depuis les data files**
Une fois UN template Bricks finalisé visuellement pour un archetype, je peux :
1. Récupérer son JSON via `_bricks_page_content_2`
2. Identifier les "slots" textuels (le titre h1, les paragraphes, les card items, etc.)
3. Pour chaque variante (Police, Military, etc.), prendre les data du fichier `industries-data.php`, faire un templating substitution, écrire dans la nouvelle page WP.
Je l'ai prouvé techniquement — la difficulté c'est de **partir d'un template Bricks bien construit** pour ne pas inventer le format.
→ Je propose qu'on fasse **A pour 1 industrie + 1 solution + 1 tech**, puis **B pour les 11 autres similaires** (4 industries × 4 solutions × 6 tech, soit 14, dont 3 déjà manuels = 11 à générer).
### 3.4. Traduction WPML
Méthode standard :
1. Une fois une page EN finalisée dans Bricks (template + contenu), elle a son `_bricks_page_content_2`
2. Dans WPML → Translation Dashboard → choisir la page → "Translate"
3. WPML Translation Editor scanne les valeurs textuelles dans le JSON Bricks et expose un éditeur côté-à-côté EN/FR
4. Tu / le linguiste rentre les traductions, valide, publie
Pour pré-remplir : on peut écrire un mu-plugin one-shot qui pour chaque page EN crée la page FR via WPML API + pré-remplit les traductions en utilisant les data files (déjà bilingues si je les structure ainsi). Mais à faire APRÈS qu'au moins 1 page soit validée en Bricks.
### 3.5. Tokens et style cohérence
Mes tokens CSS (couleurs, typo, spacing) doivent être accessibles dans Bricks pour qu'on puisse les sélectionner via les controls Bricks (color picker, font picker, etc.).
Bricks a une feature **Theme Styles** qui permet de définir une palette globale et des variables CSS. On va :
1. Importer `tokens.css` via `functions.php` (chargé sur frontend ET dans builder)
2. Configurer **Bricks → Theme Styles** avec la même palette (color slugs `brand-navy`, `brand-gold`, etc.) référençant nos variables
3. Quand tu construis dans Bricks builder, tu choisis "Brand Navy" dans le color picker → Bricks émet `var(--bricks-color-brand-navy)` que je mappe à `var(--color-brand-navy)` dans tokens.css
Résultat : le design system est centralisé dans `tokens.css`, mais accessible visuellement dans Bricks builder. Tu modifies un token → tout le site update.
---
## 4. Étapes de restart (ordre)
### Phase 0 — Backup (avant compactage)
1. Créer une branche `archive/session-2-php-templates` depuis `main`
2. Pousser sur le remote
3. La branche `main` reste là où elle est (juste un commit "archive snapshot" et on continue)
### Phase 1 — Reset du theme
1. `git rm -r wp-content/themes/asterion-bricks/`
2. Recréer le child theme **minimaliste** (8 fichiers, comme décrit en 3.1)
3. `tokens.css` repris en l'état (déjà parfait)
4. Ré-importer Inter fonts (déjà téléchargées)
5. Activer le child theme
### Phase 2 — Reset des pages WP
1. Mu-plugin one-shot qui : `wp_delete_post(force) sur tous les posts type=page`. Garde le post `Sample Page` ou wipe complet. Reset des options `_bricks_page_content_2` partout.
2. Reset Bricks settings : `delete_option('bricks_global_settings')` puis re-set juste `postTypes = ['page','post','case_study','scenario']`.
### Phase 3 — Bricks Theme Styles
1. Tu ouvres **Bricks → Theme Styles** dans WP admin
2. Tu crées une theme style "Asterion VR" appliquée à tout le site
3. Tu y configures : couleurs (utilise mes hex de tokens.css), typo (Inter), heading sizes
4. Sauvegarde
### Phase 4 — Templates Bricks
1. **Header** : Bricks → Templates → Add New → type "Header" → tu construis le menu sticky avec 5 items + CTA + lang switcher → conditions "Apply on : Entire website"
2. **Footer** : pareil, type "Footer", 5 colonnes + bottom strip
3. (option) **Single — Page fallback** pour les pages sans Bricks data
### Phase 5 — Première vraie page
1. WP admin → Pages → Add New → "Industries" (slug `industries`) → publier vide
2. Ouvrir **Edit with Bricks**
3. Construire la page hub Industries (hero + 4 cards) en Bricks éléments natifs, en utilisant le copy depuis `content-source/industries-data.php`
4. Sauver → exporter le template → versionner le JSON dans `wp-content/themes/asterion-bricks/templates/industries-overview.json`
### Phase 6 — Validation
Tu valides visuellement Industries. Si OK, on continue avec :
- 4 pages industry detail (template "Industry Detail")
- Solutions hub + 4 tiers
- Technology hub + 6 pillars
- Editorial × 5
- Conversion × 4
- Legal × 4
- Insights / Resources
- Home
Soit **34 pages** à construire au total. Avec mon aide pour la génération programmatique (option B en 3.3), on en fait probablement **7 manuellement, 27 générées** à partir des templates manuels.
### Phase 7 — WPML
Une fois EN finalisé, mu-plugin one-shot qui :
- Duplique chaque page EN en FR via WPML API (utilise les data FR des data files comme pré-remplissage)
- Tu valides, le linguiste affine
---
## 5. Risques résiduels
- **Bricks license** : si elle expire (annuelle), le builder est bridé. Vérifier renouvellement.
- **Format JSON Bricks** : peut changer entre versions Bricks majeures (v3.x). On versionne nos exports template JSON pour pouvoir les re-importer.
- **Performance** : Bricks ajoute du CSS / JS supplémentaire vs HTML pur. Lighthouse cible (90+) atteignable mais demande optimisation (lazy load, caching).
- **WPML traduction** : le linguiste doit comprendre Bricks Translation Editor (formation 30 min suffisent normalement).
---
## 6. Compactage du contexte
Avant de redémarrer, il faut :
1. **Mettre à jour les memories** (`project_asterion_status.md`, etc.) avec :
- L'état archivé en branche
- Le plan ci-dessus
- Les data files (sources de vérité textuelle)
- Les tokens.css (à reprendre tel quel)
- Les contraintes (XAMPP intouchable, Bricks-first, etc.)
2. **Compactage du contexte** : tu commandes `/compact` ou redémarres une nouvelle session, je reprends depuis les memories.
---
## 7. Time-box
| Phase | Effort dev (moi) | Effort utilisateur (toi) | Calendrier |
|---|---|---|---|
| 0 — Backup | 5 min | 0 | jour J |
| 1 — Theme reset | 30 min | valider | jour J |
| 2 — Pages reset | 15 min | 0 | jour J |
| 3 — Theme Styles | 0 | 30 min | jour J |
| 4 — Templates header/footer | 0 | 1-2h | jour J/J+1 |
| 5 — 1ère page (Industries) | 30 min guidance | 30 min | jour J+1 |
| 6 — Validation + autres pages | 2-3h génération | 4-7h build | semaine |
| 7 — WPML traductions | 1h génération | 30 min × 35 pages = ~17h | linguiste 1-2 semaines |
**On peut avoir un site EN complet en Bricks dans 1 semaine** si tu mets 4-7h de build visuel. La trad FR vient ensuite.
---
## 8. Ce que je veux que tu confirmes avant de démarrer
1. **OK pour archiver la session actuelle dans une branche `archive/session-2-php-templates` ?** (rien ne se perd, juste isolé)
2. **OK pour le child theme minimaliste sans header.php / footer.php** ? (Bricks gère via templates)
3. **Tu acceptes de construire 5-7 templates Bricks visuels** (1-2h chacun) ? Ou tu préfères que je tente une génération 100% programmatique (plus risqué, format JSON instable) ?
4. **OK pour les CPT case_study + scenario en plus de page/post** ? (déjà déclarés, on les garde)
Réponds aux 4. Ensuite : `/compact` et on redémarre propre.

View File

@@ -672,6 +672,10 @@
.av-hero { .av-hero {
position: relative; position: relative;
background-color: var(--color-brand-navy); background-color: var(--color-brand-navy);
background-image:
radial-gradient(ellipse at 70% 30%, rgba(201, 164, 90, 0.15), transparent 60%),
radial-gradient(ellipse at 20% 70%, rgba(31, 91, 168, 0.20), transparent 60%),
linear-gradient(135deg, var(--color-brand-navy-deep) 0%, var(--color-brand-navy) 50%, var(--color-bg-dark-elevated) 100%);
color: var(--color-text-on-dark); color: var(--color-text-on-dark);
overflow: hidden; overflow: hidden;
isolation: isolate; isolation: isolate;
@@ -920,6 +924,361 @@
} }
/* ============================================================================
12c. Bricks Builder element overrides — when a Bricks element carries one
of our `av-*` classes, raise specificity so our design-system rules
win against Bricks default styles (which use a single `.brxe-*`
class selector).
============================================================================ */
/* Hero — re-apply our layout & background on top of brxe-section. */
.brxe-section.av-hero {
position: relative;
background-color: var(--color-brand-navy);
/* Use background (shorthand) so .bricks-lazy-hidden's
`background-image: none !important` doesn't kill the gradient outright;
the shorthand wins by being declared after the shorthand reset. */
background:
radial-gradient(ellipse at 70% 30%, rgba(201, 164, 90, 0.15), transparent 60%),
radial-gradient(ellipse at 20% 70%, rgba(31, 91, 168, 0.20), transparent 60%),
linear-gradient(135deg, var(--color-brand-navy-deep) 0%, var(--color-brand-navy) 50%, var(--color-bg-dark-elevated) 100%);
color: var(--color-text-on-dark);
min-height: 70vh;
display: flex;
align-items: center;
justify-content: center;
padding-block: var(--space-20);
}
@media (min-width: 1024px) {
.brxe-section.av-hero { min-height: 85vh; padding-block: var(--space-32); }
}
.brxe-container.av-hero__inner {
width: 100%;
max-width: var(--container-max);
margin-inline: auto;
padding-inline: var(--container-padding-mobile);
display: flex;
flex-direction: column;
gap: var(--space-6);
align-items: flex-start;
}
@media (min-width: 768px) { .brxe-container.av-hero__inner { padding-inline: var(--container-padding-tablet); } }
@media (min-width: 1280px) { .brxe-container.av-hero__inner { padding-inline: var(--container-padding-desktop); } }
/* Hero typography on Bricks-rendered text-basic + heading. */
.brxe-text-basic.av-hero__eyebrow {
font-size: var(--text-overline);
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: var(--tracking-overline);
color: var(--color-brand-gold);
margin: 0;
}
.brxe-heading.av-hero__headline {
font-family: var(--font-display);
font-size: clamp(2.5rem, 6vw, var(--text-display-xl));
line-height: var(--leading-display-xl);
font-weight: var(--font-weight-bold);
letter-spacing: var(--tracking-tight);
color: var(--color-text-on-dark);
margin: 0;
max-width: 18ch;
}
.brxe-text-basic.av-hero__sub {
font-size: var(--text-body-lg);
line-height: var(--leading-body-lg);
color: var(--color-text-on-dark-muted);
max-width: 60ch;
margin: 0;
}
/* Section spacing on Bricks-rendered sections. */
.brxe-section.av-section {
padding-block: var(--space-16);
}
@media (min-width: 1024px) {
.brxe-section.av-section { padding-block: var(--space-20); }
}
/* Plain Bricks container reuses our container width / padding. */
.brxe-container.av-container {
max-width: var(--container-max);
margin-inline: auto;
padding-inline: var(--container-padding-mobile);
width: 100%;
}
@media (min-width: 768px) { .brxe-container.av-container { padding-inline: var(--container-padding-tablet); } }
@media (min-width: 1280px) { .brxe-container.av-container { padding-inline: var(--container-padding-desktop); } }
/* Cards grid — Bricks `block` element uses display:flex column by default.
Force CSS grid back. */
.brxe-block.av-grid-3 {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-6);
width: 100%;
}
@media (min-width: 768px) { .brxe-block.av-grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .brxe-block.av-grid-3 { grid-template-columns: repeat(3, 1fr); } }
.brxe-block.av-grid-4 {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-6);
width: 100%;
}
@media (min-width: 768px) { .brxe-block.av-grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1280px) { .brxe-block.av-grid-4 { grid-template-columns: repeat(4, 1fr); } }
/* Card design on Bricks block. */
.brxe-block.av-card {
background-color: var(--color-bg-elevated);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
overflow: hidden;
padding: var(--space-6);
display: flex;
flex-direction: column;
gap: var(--space-3);
transition:
box-shadow var(--duration-default) var(--ease-default),
transform var(--duration-default) var(--ease-default);
}
@media (min-width: 768px) {
.brxe-block.av-card { padding: var(--space-8); }
}
.brxe-block.av-card:hover {
box-shadow: var(--shadow-md);
transform: translateY(-2px);
}
.brxe-text-basic.av-card__eyebrow {
font-size: var(--text-overline);
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: var(--tracking-overline);
color: var(--color-text-muted);
margin: 0;
}
.brxe-heading.av-card__title {
font-family: var(--font-display);
font-size: var(--text-h3);
line-height: var(--leading-h3);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
margin: 0;
}
.brxe-text-basic.av-card__excerpt {
font-size: var(--text-body-md);
line-height: var(--leading-body-md);
color: var(--color-text-secondary);
margin: 0;
flex: 1;
}
/* Button on Bricks button element. Bricks renders <a class="brxe-button bricks-button">. */
.brxe-button.av-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--space-2);
height: 44px;
padding: 0 var(--space-5);
font-family: var(--font-body);
font-size: var(--text-body-md);
font-weight: var(--font-weight-semibold);
line-height: 1;
text-decoration: none;
border: var(--border-default) solid transparent;
border-radius: var(--radius-sm);
cursor: pointer;
white-space: nowrap;
align-self: flex-start;
transition:
background-color var(--duration-fast) var(--ease-default),
color var(--duration-fast) var(--ease-default),
transform var(--duration-fast) var(--ease-default),
border-color var(--duration-fast) var(--ease-default);
}
.brxe-button.av-btn--md { height: 44px; padding: 0 var(--space-5); }
.brxe-button.av-btn--lg { height: 52px; padding: 0 1.75rem; font-size: var(--text-body-lg); }
.brxe-button.av-btn--primary {
background-color: var(--color-brand-gold);
color: var(--color-brand-navy);
border-color: var(--color-brand-gold);
}
.brxe-button.av-btn--primary:hover,
.brxe-button.av-btn--primary:focus-visible {
background-color: var(--color-brand-gold-soft);
border-color: var(--color-brand-gold-soft);
transform: translateY(-1px);
}
.brxe-button.av-btn--secondary {
background-color: transparent;
color: var(--color-brand-navy);
border-color: var(--color-brand-navy);
}
.brxe-button.av-btn--secondary:hover,
.brxe-button.av-btn--secondary:focus-visible {
background-color: var(--color-brand-navy);
color: var(--color-text-on-dark);
}
/* ============================================================================
12b. Gutenberg block overrides — neutralize default layout styles when
a block also carries one of our `av-*` design-system classes. We
keep our grid / spacing / button rules in charge.
============================================================================ */
/* Group blocks: drop the WP layout flow constraints that introduce extra margins. */
.av-hero.wp-block-group,
.av-section.wp-block-group,
.av-card.wp-block-group,
.av-card__body.wp-block-group,
.av-container.wp-block-group,
.av-hero__inner.wp-block-group {
margin-block: 0;
}
/* Hero overrides — keep the hero layout we already had. */
.av-hero.wp-block-group {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
}
.av-hero__inner.wp-block-group {
width: 100%;
}
/* Container blocks: WP `is-layout-constrained` pads/centers via wp-container-X
helpers. We keep our own .av-container width/padding. */
.av-container.wp-block-group {
max-width: var(--container-max);
margin-inline: auto;
padding-inline: var(--container-padding-mobile);
width: 100%;
}
@media (min-width: 768px) { .av-container.wp-block-group { padding-inline: var(--container-padding-tablet); } }
@media (min-width: 1280px) { .av-container.wp-block-group { padding-inline: var(--container-padding-desktop); } }
/* Columns: WP forces display:flex via .is-layout-flex. We force grid back so
our 1/2/3/4-col responsive rules win. */
.av-grid-3.wp-block-columns,
.av-grid-3.wp-block-columns.is-layout-flex {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-6);
}
@media (min-width: 768px) {
.av-grid-3.wp-block-columns,
.av-grid-3.wp-block-columns.is-layout-flex { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
.av-grid-3.wp-block-columns,
.av-grid-3.wp-block-columns.is-layout-flex { grid-template-columns: repeat(3, 1fr); }
}
.av-grid-4.wp-block-columns,
.av-grid-4.wp-block-columns.is-layout-flex {
display: grid;
grid-template-columns: 1fr;
gap: var(--space-6);
}
@media (min-width: 768px) {
.av-grid-4.wp-block-columns,
.av-grid-4.wp-block-columns.is-layout-flex { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1280px) {
.av-grid-4.wp-block-columns,
.av-grid-4.wp-block-columns.is-layout-flex { grid-template-columns: repeat(4, 1fr); }
}
/* Each column: drop the flex-basis WP applies. */
.wp-block-columns.av-grid-3 > .wp-block-column,
.wp-block-columns.av-grid-4 > .wp-block-column {
flex-basis: auto !important;
flex-grow: 0 !important;
min-width: 0 !important;
}
/* Section spacing — re-apply our padding-block to the migrated section blocks. */
.av-section.wp-block-group {
padding-block: var(--space-16);
}
@media (min-width: 1024px) {
.av-section.wp-block-group { padding-block: var(--space-20); }
}
/* Cards inside a wp-block-column: keep our card design. */
.av-card.wp-block-group {
background-color: var(--color-bg-elevated);
border-radius: var(--radius-md);
box-shadow: var(--shadow-sm);
overflow: hidden;
height: 100%; /* fill the column for visual rhythm */
}
.av-card__body.wp-block-group {
padding: var(--space-6);
display: flex;
flex-direction: column;
gap: var(--space-3);
height: 100%;
}
@media (min-width: 768px) {
.av-card__body.wp-block-group { padding: var(--space-8); }
}
/* Buttons row: WP wraps every button in `.wp-block-button` and adds
`.is-layout-flex` to the parent, which centers and adds gap.
Strip the WP padding/margin so our `.av-btn` sizing wins. */
.wp-block-buttons.av-card__cta,
.wp-block-buttons.av-hero__ctas {
margin: 0;
padding: 0;
}
.wp-block-button.av-btn {
margin: 0;
}
.wp-block-button.av-btn .wp-block-button__link {
/* Reset Gutenberg's built-in button skin — let .av-btn rules win. */
background: transparent;
color: inherit;
padding: 0;
border-radius: 0;
font-size: inherit;
font-weight: inherit;
line-height: 1;
transition: none;
text-decoration: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
/* Inherit our .av-btn padding via the containing flex layout. */
}
/* Auto-margin-top to push CTAs to the bottom of cards. */
.av-card__cta {
margin-top: auto;
padding-top: var(--space-4);
}
/* Eyebrow / overline reset — Gutenberg paragraph defaults could drift. */
p.av-card__eyebrow,
p.av-hero__eyebrow {
margin: 0;
}
/* WordPress core "global styles" reset noise — collapse the auto block-margin
that pushes our text away from the hero edges. */
.wp-block-group.av-hero > .wp-block-group,
.wp-block-group.av-section > .wp-block-group {
margin-block: 0;
}
/* ============================================================================ /* ============================================================================
13. Reveal animation (scroll-triggered, JS-driven via main.js) 13. Reveal animation (scroll-triggered, JS-driven via main.js)
============================================================================ */ ============================================================================ */

View File

@@ -12,6 +12,14 @@
defined('ABSPATH') || exit; defined('ABSPATH') || exit;
$av_year = date_i18n('Y'); $av_year = date_i18n('Y');
// Mirror the bail-out in header.php: don't emit our footer chrome inside
// the Bricks builder canvas/iframe.
if (function_exists('bricks_is_builder') && bricks_is_builder()) {
wp_footer();
echo '</body></html>';
return;
}
?> ?>
</main><!-- /#main --> </main><!-- /#main -->

View File

@@ -103,7 +103,9 @@ $av_includes = [
'inc/cpt.php', // Custom post types: case_study, scenario. 'inc/cpt.php', // Custom post types: case_study, scenario.
'inc/seo.php', // Schema.org JSON-LD overrides. 'inc/seo.php', // Schema.org JSON-LD overrides.
'inc/form-handler.php', // Conversion form POST handler. 'inc/form-handler.php', // Conversion form POST handler.
'inc/render-blocks.php', // Data array → Gutenberg HTML for the migrator. 'inc/render-blocks.php', // Data array → core/html migrator (legacy, kept for fallback).
'inc/render-blocks-native.php', // Data array → native Gutenberg blocks (legacy POC).
'inc/render-bricks.php', // Data array → Bricks Builder native elements (current target).
'inc/shortcodes.php', // [av_form slug="..."] etc. 'inc/shortcodes.php', // [av_form slug="..."] etc.
]; ];
@@ -150,10 +152,20 @@ add_action('after_setup_theme', function () {
}); });
/** /**
* Disable Gutenberg block library default styles when Bricks is active * Disable Gutenberg block library default styles on the public frontend only
* we own typography end-to-end through tokens.css. * we own typography end-to-end through tokens.css.
*
* Skipped when:
* - inside the Bricks Builder canvas (?bricks=run, ?brickspreview=1) — those
* screens rely on the WP-core stylesheets for their own UI / preview.
* - in the WP admin itself.
*/ */
add_action('wp_enqueue_scripts', function () { add_action('wp_enqueue_scripts', function () {
if (is_admin()) return;
if (function_exists('bricks_is_builder') && bricks_is_builder()) return;
if (function_exists('bricks_is_frontend_builder_iframe') && bricks_is_frontend_builder_iframe()) return;
if (! empty($_GET['bricks']) || ! empty($_GET['brickspreview'])) return;
wp_dequeue_style('wp-block-library'); wp_dequeue_style('wp-block-library');
wp_dequeue_style('wp-block-library-theme'); wp_dequeue_style('wp-block-library-theme');
wp_dequeue_style('global-styles'); wp_dequeue_style('global-styles');

View File

@@ -23,6 +23,16 @@ defined('ABSPATH') || exit;
<body <?php body_class(); ?>> <body <?php body_class(); ?>>
<?php wp_body_open(); ?> <?php wp_body_open(); ?>
<?php
// In Bricks Builder mode, the parent theme's `template-parts/builder.php`
// calls get_header() / get_footer() to inherit our enqueues — but the
// builder UI then mounts directly into <body>. Emitting our own chrome
// here covers it visually, so we bail early.
if (function_exists('bricks_is_builder') && bricks_is_builder()) {
return;
}
?>
<a class="av-skip-link" href="#main"><?php echo esc_html(av_t('Skip to main content', 'asterion-bricks')); ?></a> <a class="av-skip-link" href="#main"><?php echo esc_html(av_t('Skip to main content', 'asterion-bricks')); ?></a>
<header class="av-header" role="banner"> <header class="av-header" role="banner">

View File

@@ -0,0 +1,228 @@
<?php
/**
* Asterion Bricks — Native Gutenberg block renderer (POC for Industries)
*
* Generates strictly-standard Gutenberg blocks (core/group, core/heading,
* core/paragraph, core/columns, core/column, core/buttons, core/button,
* core/list) so that:
*
* 1. Pages are editable in the WP admin block editor — every text node
* is a real block, not a raw HTML wrapper.
* 2. "Edit with Bricks" converts these to Bricks elements (Container,
* Heading, Text-Basic, Button, …) per Bricks Builder docs.
* 3. WPML's Translation Editor exposes one entry per block.
*
* Convention: every block carries a `className` attribute matching our
* existing `av-*` CSS classes so the rendered HTML inherits the design
* system styles.
*
* Public API (POC, will replace inc/render-blocks.php once validated):
* av_n_render_industries_overview() → string (single hub page)
*
* @package AsterionBricks
*/
defined('ABSPATH') || exit;
/**
* Build a Gutenberg block array (the shape `serialize_blocks()` expects).
* `innerHTML` is the wrapper template — Gutenberg uses it as a delimiter
* map, with NULL entries marking where children get inlined.
*/
function av_n_block($name, $attrs = [], $inner_blocks = [], $inner_html = '') {
return [
'blockName' => $name,
'attrs' => $attrs,
'innerBlocks' => $inner_blocks,
'innerHTML' => $inner_html,
'innerContent' => [$inner_html],
];
}
/**
* Group block (tagName configurable). Used for sections, containers, cards.
* Children are kept as innerBlocks; innerContent uses NULL placeholders so
* Gutenberg slots them in at render time.
*/
function av_n_group($attrs, $children, $tag = 'div') {
$attrs = array_merge(['tagName' => $tag], $attrs);
$class = trim('wp-block-group ' . ($attrs['className'] ?? ''));
// Build innerContent: opening tag, then NULL per child, then closing tag.
$inner_content = ['<' . $tag . ' class="' . esc_attr($class) . '">'];
foreach ($children as $child) {
$inner_content[] = null;
}
$inner_content[] = '</' . $tag . '>';
return [
'blockName' => 'core/group',
'attrs' => $attrs,
'innerBlocks' => $children,
'innerHTML' => '<' . $tag . ' class="' . esc_attr($class) . '"></' . $tag . '>',
'innerContent' => $inner_content,
];
}
function av_n_heading($text, $level = 2, $class = '') {
$tag = 'h' . max(1, min(6, (int) $level));
$cls = trim('wp-block-heading ' . $class);
$html = '<' . $tag . ' class="' . esc_attr($cls) . '">' . esc_html($text) . '</' . $tag . '>';
return [
'blockName' => 'core/heading',
'attrs' => array_filter([
'level' => (int) $level,
'className' => $class ?: null,
]),
'innerBlocks' => [],
'innerHTML' => $html,
'innerContent' => [$html],
];
}
function av_n_paragraph($text, $class = '') {
$html = $class
? '<p class="' . esc_attr($class) . '">' . esc_html($text) . '</p>'
: '<p>' . esc_html($text) . '</p>';
return [
'blockName' => 'core/paragraph',
'attrs' => $class ? ['className' => $class] : [],
'innerBlocks' => [],
'innerHTML' => $html,
'innerContent' => [$html],
];
}
function av_n_button($label, $href, $variants = 'av-btn av-btn--primary av-btn--lg') {
$btn_html = '<div class="wp-block-button ' . esc_attr($variants) . '"><a class="wp-block-button__link wp-element-button" href="' . esc_url($href) . '">' . esc_html($label) . '</a></div>';
return [
'blockName' => 'core/button',
'attrs' => ['className' => $variants],
'innerBlocks' => [],
'innerHTML' => $btn_html,
'innerContent' => [$btn_html],
];
}
function av_n_buttons_row($buttons, $class = 'av-hero__ctas') {
$opening = '<div class="wp-block-buttons ' . esc_attr($class) . '">';
$closing = '</div>';
$inner_content = [$opening];
foreach ($buttons as $b) {
$inner_content[] = null;
}
$inner_content[] = $closing;
return [
'blockName' => 'core/buttons',
'attrs' => ['className' => $class],
'innerBlocks' => $buttons,
'innerHTML' => $opening . $closing,
'innerContent' => $inner_content,
];
}
function av_n_column($children, $width = null) {
$attrs = $width ? ['width' => $width] : [];
$opening = '<div class="wp-block-column"' . ($width ? ' style="flex-basis:' . esc_attr($width) . '"' : '') . '>';
$closing = '</div>';
$inner_content = [$opening];
foreach ($children as $c) $inner_content[] = null;
$inner_content[] = $closing;
return [
'blockName' => 'core/column',
'attrs' => $attrs,
'innerBlocks' => $children,
'innerHTML' => $opening . $closing,
'innerContent' => $inner_content,
];
}
function av_n_columns($columns, $class = 'av-grid-4') {
$opening = '<div class="wp-block-columns ' . esc_attr($class) . '">';
$closing = '</div>';
$inner_content = [$opening];
foreach ($columns as $c) $inner_content[] = null;
$inner_content[] = $closing;
return [
'blockName' => 'core/columns',
'attrs' => array_filter(['className' => $class, 'isStackedOnMobile' => true]),
'innerBlocks' => $columns,
'innerHTML' => $opening . $closing,
'innerContent' => $inner_content,
];
}
/* ========================================================================== */
/* Industries overview hub — proof of concept */
/* ========================================================================== */
function av_n_render_industries_overview() {
$home = home_url('/');
$industries = [
['eyebrow' => 'National & Municipal', 'title' => 'Police', 'excerpt' => 'Vehicle stops, identity checks, urban CQB, de-escalation, riot containment. Built for the realities of contemporary policing.', 'href' => '/industries/police/', 'cta' => 'Police training'],
['eyebrow' => 'Tactical units', 'title' => 'Special Forces', 'excerpt' => 'Hostage rescue, dynamic entries, hostile crowd extraction, sniper-spotter coordination. Built for the units where every error has a name.', 'href' => '/industries/special-forces/', 'cta' => 'Special forces training'],
['eyebrow' => 'Armed forces', 'title' => 'Military', 'excerpt' => 'MOUT, convoy escort, FOB defense, IED awareness, joint operation drills. Built for armed forces that deploy fast and adapt faster.', 'href' => '/industries/military/', 'cta' => 'Military training'],
['eyebrow' => 'Emergency services', 'title' => 'Firefighters', 'excerpt' => "Structure fires, hazmat, multi-casualty triage, confined-space rescue, industrial accidents. Built for first responders who can't rehearse the worst day at full scale.", 'href' => '/industries/firefighters/', 'cta' => 'Firefighter training'],
];
/* ----- Hero (section / container / inner) ----- */
$hero_inner = av_n_group(
['className' => 'av-container av-hero__inner', 'layout' => ['type' => 'constrained']],
[
av_n_paragraph('Industries', 'av-hero__eyebrow'),
av_n_heading('Built with operators, for operators.', 1, 'av-hero__headline'),
av_n_paragraph(
'PROSERVE™ is not a generic VR platform repackaged for the public sector. Every scenario, every weapon profile, every instructor metric was specified by serving and former operators in close partnership with our engineering team.',
'av-hero__sub'
),
],
'div'
);
$hero = av_n_group(
['className' => 'av-hero'],
[$hero_inner],
'section'
);
/* ----- Cards section ----- */
$card_columns = [];
foreach ($industries as $ind) {
$card_inner = av_n_group(
['className' => 'av-card__body'],
[
av_n_paragraph($ind['eyebrow'], 'av-card__eyebrow'),
av_n_heading($ind['title'], 2, 'av-card__title'),
av_n_paragraph($ind['excerpt'], 'av-card__excerpt'),
av_n_buttons_row(
[av_n_button($ind['cta'], $home . ltrim($ind['href'], '/'), 'av-btn av-btn--secondary av-btn--md')],
'av-card__cta'
),
],
'div'
);
$card = av_n_group(
['className' => 'av-card'],
[$card_inner],
'article'
);
$card_columns[] = av_n_column([$card]);
}
$cards_grid = av_n_columns($card_columns, 'av-grid-4');
$section_container = av_n_group(
['className' => 'av-container', 'layout' => ['type' => 'constrained']],
[$cards_grid],
'div'
);
$section = av_n_group(
['className' => 'av-section'],
[$section_container],
'section'
);
return serialize_blocks([$hero, $section]);
}

View File

@@ -0,0 +1,258 @@
<?php
/**
* Asterion Bricks — Bricks Builder native data renderer (POC: Industries)
*
* Generates the array of element descriptors that Bricks Builder expects in
* the post meta `_bricks_page_content_2` (constant `BRICKS_DB_PAGE_CONTENT`).
*
* Schema, confirmed by reading Bricks parent theme source
* (`includes/password-protection.php` and `includes/elements/base.php`):
*
* [
* [
* 'id' => string, // unique, via Bricks\Helpers::generate_random_id(false)
* 'name' => 'section' | 'container' | 'block' | 'heading' | 'text-basic' | 'button' | …,
* 'parent' => 0 | string, // 0 = page root, else parent's id
* 'children' => [string, …], // optional, for nestable elements
* 'settings' => [
* 'text' => 'Hello',
* 'tag' => 'h1' | 'h2' | …,
* 'link' => ['type' => 'external', 'url' => 'https://…'],
* '_cssClasses' => 'av-hero',
* …
* ],
* ],
* …
* ]
*
* Once stored, opening the page in WP admin and clicking "Edit with Bricks"
* surfaces every element in the Bricks builder canvas, fully editable.
*
* Frontend rendering is handled by Bricks itself — our `page.php` simply
* lets Bricks take over via its `template_include` filter.
*
* @package AsterionBricks
*/
defined('ABSPATH') || exit;
/**
* Generate a Bricks-compatible random element ID.
* Falls back to a local md5 prefix if the Bricks namespace isn't loaded yet.
*/
function av_brx_id() {
if (class_exists('\\Bricks\\Helpers') && method_exists('\\Bricks\\Helpers', 'generate_random_id')) {
return \Bricks\Helpers::generate_random_id(false);
}
return substr(md5(uniqid((string) mt_rand(), true)), 0, 6);
}
/**
* Tiny element factory.
*/
function av_brx_el($name, $parent, $settings = [], $children = null) {
$el = [
'id' => av_brx_id(),
'name' => $name,
'parent' => $parent,
'settings' => $settings,
];
if ($children !== null) {
$el['children'] = $children;
}
return $el;
}
/* =================================================================== */
/* Industries overview — proof of concept */
/* =================================================================== */
function av_brx_render_industries_overview() {
$home_url = home_url('/');
/* ---- pre-allocate IDs so we can hand them to parents/children ---- */
$hero_section_id = av_brx_id();
$hero_container_id = av_brx_id();
$hero_eyebrow_id = av_brx_id();
$hero_h1_id = av_brx_id();
$hero_sub_id = av_brx_id();
$cards_section_id = av_brx_id();
$cards_container_id = av_brx_id();
$cards_grid_id = av_brx_id();
$industries = [
[
'eyebrow' => 'National & Municipal',
'title' => 'Police',
'excerpt' => 'Vehicle stops, identity checks, urban CQB, de-escalation, riot containment. Built for the realities of contemporary policing.',
'href' => '/industries/police/',
'cta' => 'Police training',
],
[
'eyebrow' => 'Tactical units',
'title' => 'Special Forces',
'excerpt' => 'Hostage rescue, dynamic entries, hostile crowd extraction, sniper-spotter coordination. Built for the units where every error has a name.',
'href' => '/industries/special-forces/',
'cta' => 'Special forces training',
],
[
'eyebrow' => 'Armed forces',
'title' => 'Military',
'excerpt' => 'MOUT, convoy escort, FOB defense, IED awareness, joint operation drills. Built for armed forces that deploy fast and adapt faster.',
'href' => '/industries/military/',
'cta' => 'Military training',
],
[
'eyebrow' => 'Emergency services',
'title' => 'Firefighters',
'excerpt' => "Structure fires, hazmat, multi-casualty triage, confined-space rescue, industrial accidents. Built for first responders who can't rehearse the worst day at full scale.",
'href' => '/industries/firefighters/',
'cta' => 'Firefighter training',
],
];
$card_ids = [];
foreach ($industries as $i => $_) {
$card_ids[$i] = [
'card' => av_brx_id(),
'eyebrow' => av_brx_id(),
'title' => av_brx_id(),
'excerpt' => av_brx_id(),
'btn' => av_brx_id(),
];
}
$cards_children = array_map(fn($ids) => $ids['card'], $card_ids);
/* ---- assemble flat element array ---- */
$elements = [];
// 1. Hero section ----------------------------------------------------
$elements[] = [
'id' => $hero_section_id,
'name' => 'section',
'parent' => 0,
'children' => [$hero_container_id],
'settings' => ['_cssClasses' => 'av-hero'],
'label' => 'Hero',
];
$elements[] = [
'id' => $hero_container_id,
'name' => 'container',
'parent' => $hero_section_id,
'children' => [$hero_eyebrow_id, $hero_h1_id, $hero_sub_id],
'settings' => ['_cssClasses' => 'av-container av-hero__inner'],
];
$elements[] = [
'id' => $hero_eyebrow_id,
'name' => 'text-basic',
'parent' => $hero_container_id,
'settings' => [
'text' => 'Industries',
'tag' => 'p',
'_cssClasses' => 'av-hero__eyebrow',
],
];
$elements[] = [
'id' => $hero_h1_id,
'name' => 'heading',
'parent' => $hero_container_id,
'settings' => [
'tag' => 'h1',
'text' => 'Built with operators, for operators.',
'_cssClasses' => 'av-hero__headline',
],
];
$elements[] = [
'id' => $hero_sub_id,
'name' => 'text-basic',
'parent' => $hero_container_id,
'settings' => [
'text' => 'PROSERVE™ is not a generic VR platform repackaged for the public sector. Every scenario, every weapon profile, every instructor metric was specified by serving and former operators in close partnership with our engineering team.',
'tag' => 'p',
'_cssClasses' => 'av-hero__sub',
],
];
// 2. Cards section ---------------------------------------------------
$elements[] = [
'id' => $cards_section_id,
'name' => 'section',
'parent' => 0,
'children' => [$cards_container_id],
'settings' => ['_cssClasses' => 'av-section'],
'label' => 'Industries grid',
];
$elements[] = [
'id' => $cards_container_id,
'name' => 'container',
'parent' => $cards_section_id,
'children' => [$cards_grid_id],
'settings' => ['_cssClasses' => 'av-container'],
];
$elements[] = [
'id' => $cards_grid_id,
'name' => 'block',
'parent' => $cards_container_id,
'children' => $cards_children,
'settings' => ['_cssClasses' => 'av-grid-4'],
];
foreach ($industries as $i => $ind) {
$ids = $card_ids[$i];
$elements[] = [
'id' => $ids['card'],
'name' => 'block',
'parent' => $cards_grid_id,
'children' => [$ids['eyebrow'], $ids['title'], $ids['excerpt'], $ids['btn']],
'settings' => ['_cssClasses' => 'av-card'],
'label' => $ind['title'],
];
$elements[] = [
'id' => $ids['eyebrow'],
'name' => 'text-basic',
'parent' => $ids['card'],
'settings' => [
'text' => $ind['eyebrow'],
'tag' => 'p',
'_cssClasses' => 'av-card__eyebrow',
],
];
$elements[] = [
'id' => $ids['title'],
'name' => 'heading',
'parent' => $ids['card'],
'settings' => [
'tag' => 'h2',
'text' => $ind['title'],
'_cssClasses' => 'av-card__title',
],
];
$elements[] = [
'id' => $ids['excerpt'],
'name' => 'text-basic',
'parent' => $ids['card'],
'settings' => [
'text' => $ind['excerpt'],
'tag' => 'p',
'_cssClasses' => 'av-card__excerpt',
],
];
$elements[] = [
'id' => $ids['btn'],
'name' => 'button',
'parent' => $ids['card'],
'settings' => [
'text' => $ind['cta'],
'tag' => 'a',
'link' => [
'type' => 'external',
'url' => $home_url . ltrim($ind['href'], '/'),
],
'_cssClasses' => 'av-btn av-btn--secondary av-btn--md',
],
];
}
return $elements;
}

View File

@@ -2,10 +2,14 @@
/** /**
* Asterion Bricks — Default page template * Asterion Bricks — Default page template
* *
* Renders any page that has no Custom Template assigned (or whose Custom * If the current page has Bricks data in its `_bricks_page_content_2` post
* Template was stripped after the post_content migration). The header and * meta, defer to Bricks' own renderer (Bricks\Frontend::render_content). This
* footer are shared globals; the content is whatever Gutenberg / Bricks * is the same pattern Bricks parent's page.php uses; we keep it here so the
* stored in post_content. * child theme stays in charge of the markup wrapping (header, footer).
*
* Otherwise fall back to the standard the_content() loop — covers pages
* still rendered from post_content (Gutenberg) and any temporarily-empty
* page that just hits a non-Bricks Custom Template.
* *
* @package AsterionBricks * @package AsterionBricks
*/ */
@@ -13,9 +17,21 @@ defined('ABSPATH') || exit;
get_header(); get_header();
if (have_posts()) { $av_bricks_data = class_exists('\\Bricks\\Helpers')
while (have_posts()) { the_post(); ? \Bricks\Helpers::get_bricks_data(get_the_ID(), 'content')
the_content(); : null;
if (! empty($av_bricks_data) && class_exists('\\Bricks\\Frontend')) {
// Bricks emits its own <main id="brx-content"> wrapper — render with `div`
// tag so we don't end up with double <main> (the global one comes from
// header.php / footer.php).
\Bricks\Frontend::render_content($av_bricks_data, ['id' => 'brx-content'], '', '', 'div');
} else {
if (have_posts()) {
while (have_posts()) {
the_post();
the_content();
}
} }
} }