feat(wpml): refactor to post_content + duplicate site in French via WPML

This commit makes the site editable from WP admin (Gutenberg or Bricks
"Edit with Bricks") and translatable via WPML Translation Editor by
shifting page rendering away from Custom Templates and into post_content.

Architecture change
-------------------
Before: Custom Templates assigned to each page (page-solution-detail.php
etc.) generated the page HTML at runtime by reading from inc/*-data.php
arrays. WPML had nothing to translate, Bricks Builder had nothing to
edit, the client could only modify content by editing PHP.

After:
- Pages now hold their full Gutenberg HTML inside post_content
- The default page.php template renders the_content() — no Custom
  Templates assigned anymore
- Bricks Builder picks up post_content and converts it to its element
  tree when "Edit with Bricks" is clicked
- WPML Translation Editor exposes every block for translation
- The client can edit pages directly in WP admin

What this commit ships
----------------------
- inc/render-blocks.php: data array → Gutenberg HTML payload generator
  with helpers per section type (prose / cards / list / cta) and per
  page archetype (solution / industry / technology / editorial / form
  / overview hub).
- inc/shortcodes.php: [av_form slug="request-demo"] for dynamic form
  blocks (forms can't live as static HTML — they need nonces and
  per-request state).
- inc/i18n.php: av_lang() / av_t() helpers for inline string translation
  in header.php and footer.php (covers ~80 UI strings); switches based
  on WPML's wpml_current_language filter.
- page.php: minimal default template — get_header() + the_content() +
  get_footer().
- header.php: real WPML language switcher driven by
  wpml_active_languages filter (replaces the placeholder EN · FR
  toggle); UI strings now route through av_t().
- footer.php: same UI string treatment.
- Custom Templates retained but no longer assigned (pages were stripped
  by the migration mu-plugin); they remain available if a page wants
  to opt back into the data-file pattern.

Operational migrations (one-shot mu-plugins, not versioned)
-----------------------------------------------------------
1. asterion-migrate-to-blocks.php walked all 26 PHP-templated pages,
   pre-rendered them via the new render-blocks helpers, wrote the
   result to post_content, and stripped _wp_page_template.
2. asterion-duplicate-fr.php cloned all 35 pages into French via WPML
   API, preserved parent/child hierarchy, linked translations through
   the trid table, marked them as duplicates pending refinement.
3. asterion-fix-fr-slugs.php aligned French slugs with English ones
   (WP's wp_unique_post_slug() had appended -2 suffixes; we bypass
   via $wpdb->update so /fr/solutions/ resolves correctly).

Verified
--------
- All 35 EN URLs return HTTP 200
- All 35 FR URLs return HTTP 200 under /fr/<slug>/
- Language switcher in header outputs correct hreflang links
- WPML emits hreflang en / fr / x-default in <head>
- Body class confirms wp-child-theme-asterion-bricks active
- Bricks frontend CSS still enqueued
- Inter Variable still preloaded

Next steps
----------
- French content is currently the duplicated EN copy. Translate via
  WP admin → WPML → Translation Editor (per-block UI), or edit pages
  directly in /fr/<slug>/ via Gutenberg / Bricks
- WPML String Translation can scan the theme to surface av_t() / __()
  strings for UI-level translation overrides

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 13:11:42 +02:00
parent 70864129ed
commit f18a57e83f
13 changed files with 699 additions and 48 deletions

View File

@@ -25,12 +25,12 @@ $av_year = date_i18n('Y');
ASTERION&nbsp;VR
</a>
<p>
<?php esc_html_e('The modular, sovereign XR platform for European security forces. Train like the threat is now.', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('The modular, sovereign XR platform for European security forces. Train like the threat is now.', 'asterion-bricks')); ?>
</p>
</div>
<div class="av-footer__col">
<h2 class="av-footer__col-title"><?php esc_html_e('Solutions', 'asterion-bricks'); ?></h2>
<h2 class="av-footer__col-title"><?php echo esc_html(av_t('Solutions', 'asterion-bricks')); ?></h2>
<ul class="av-footer__list">
<li><a href="<?php echo esc_url(home_url('/solutions/my-proserve/')); ?>">MY PROSERVE</a></li>
<li><a href="<?php echo esc_url(home_url('/solutions/proserve-flex/')); ?>">PROSERVE FLEX</a></li>
@@ -40,46 +40,46 @@ $av_year = date_i18n('Y');
</div>
<div class="av-footer__col">
<h2 class="av-footer__col-title"><?php esc_html_e('Industries', 'asterion-bricks'); ?></h2>
<h2 class="av-footer__col-title"><?php echo esc_html(av_t('Industries', 'asterion-bricks')); ?></h2>
<ul class="av-footer__list">
<li><a href="<?php echo esc_url(home_url('/industries/police/')); ?>"><?php esc_html_e('Police', 'asterion-bricks'); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/industries/special-forces/')); ?>"><?php esc_html_e('Special Forces', 'asterion-bricks'); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/industries/military/')); ?>"><?php esc_html_e('Military', 'asterion-bricks'); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/industries/firefighters/')); ?>"><?php esc_html_e('Firefighters', 'asterion-bricks'); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/industries/police/')); ?>"><?php echo esc_html(av_t('Police', 'asterion-bricks')); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/industries/special-forces/')); ?>"><?php echo esc_html(av_t('Special Forces', 'asterion-bricks')); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/industries/military/')); ?>"><?php echo esc_html(av_t('Military', 'asterion-bricks')); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/industries/firefighters/')); ?>"><?php echo esc_html(av_t('Firefighters', 'asterion-bricks')); ?></a></li>
</ul>
</div>
<div class="av-footer__col">
<h2 class="av-footer__col-title"><?php esc_html_e('Why Asterion', 'asterion-bricks'); ?></h2>
<h2 class="av-footer__col-title"><?php echo esc_html(av_t('Why Asterion', 'asterion-bricks')); ?></h2>
<ul class="av-footer__list">
<li><a href="<?php echo esc_url(home_url('/about/')); ?>"><?php esc_html_e('Our story', 'asterion-bricks'); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/customers/')); ?>"><?php esc_html_e('Customers', 'asterion-bricks'); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/trust/')); ?>"><?php esc_html_e('Trust & Compliance', 'asterion-bricks'); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/partners/')); ?>"><?php esc_html_e('Partners', 'asterion-bricks'); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/about/')); ?>"><?php echo esc_html(av_t('Our story', 'asterion-bricks')); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/customers/')); ?>"><?php echo esc_html(av_t('Customers', 'asterion-bricks')); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/trust/')); ?>"><?php echo esc_html(av_t('Trust & Compliance', 'asterion-bricks')); ?></a></li>
<li><a href="<?php echo esc_url(home_url('/partners/')); ?>"><?php echo esc_html(av_t('Partners', 'asterion-bricks')); ?></a></li>
</ul>
</div>
<div class="av-footer__newsletter">
<h2 class="av-footer__col-title"><?php esc_html_e('Newsletter', 'asterion-bricks'); ?></h2>
<h2 class="av-footer__col-title"><?php echo esc_html(av_t('Newsletter', 'asterion-bricks')); ?></h2>
<p style="color:var(--color-text-on-dark-muted);font-size:var(--text-body-sm);">
<?php esc_html_e('Insights from the front of immersive training. One email per month. No spam.', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('Insights from the front of immersive training. One email per month. No spam.', 'asterion-bricks')); ?>
</p>
<form class="av-footer__newsletter-form" method="post" action="#" aria-label="<?php esc_attr_e('Newsletter signup', 'asterion-bricks'); ?>">
<label for="av-newsletter-email" class="av-sr-only"><?php esc_html_e('Your email', 'asterion-bricks'); ?></label>
<label for="av-newsletter-email" class="av-sr-only"><?php echo esc_html(av_t('Your email', 'asterion-bricks')); ?></label>
<input type="email" id="av-newsletter-email" name="email" class="av-input" placeholder="<?php esc_attr_e('your@email.com', 'asterion-bricks'); ?>" required>
<button type="submit" class="av-btn av-btn--primary av-btn--md"><?php esc_html_e('Subscribe', 'asterion-bricks'); ?></button>
<button type="submit" class="av-btn av-btn--primary av-btn--md"><?php echo esc_html(av_t('Subscribe', 'asterion-bricks')); ?></button>
</form>
</div>
</div>
<div class="av-footer__bottom">
<div>© <?php echo esc_html($av_year); ?> Asterion VR. <?php esc_html_e('All rights reserved.', 'asterion-bricks'); ?></div>
<div>© <?php echo esc_html($av_year); ?> Asterion VR. <?php echo esc_html(av_t('All rights reserved.', 'asterion-bricks')); ?></div>
<div class="av-footer__bottom-links">
<a href="<?php echo esc_url(home_url('/legal/privacy/')); ?>"><?php esc_html_e('Privacy', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/legal/terms/')); ?>"><?php esc_html_e('Terms', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/legal/cookies/')); ?>"><?php esc_html_e('Cookies', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/legal/notice/')); ?>"><?php esc_html_e('Legal notice', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/legal/privacy/')); ?>"><?php echo esc_html(av_t('Privacy', 'asterion-bricks')); ?></a>
<a href="<?php echo esc_url(home_url('/legal/terms/')); ?>"><?php echo esc_html(av_t('Terms', 'asterion-bricks')); ?></a>
<a href="<?php echo esc_url(home_url('/legal/cookies/')); ?>"><?php echo esc_html(av_t('Cookies', 'asterion-bricks')); ?></a>
<a href="<?php echo esc_url(home_url('/legal/notice/')); ?>"><?php echo esc_html(av_t('Legal notice', 'asterion-bricks')); ?></a>
</div>
<div class="av-footer__social">
<a href="https://www.linkedin.com/company/asterion-vr/" rel="noopener" aria-label="LinkedIn">LinkedIn</a>

View File

@@ -99,9 +99,12 @@ add_action('wp_head', function () {
* Each file is opt-in via file_exists() so partial scaffolds don't fatal.
*/
$av_includes = [
'inc/i18n.php', // av_lang(), av_t() — load FIRST.
'inc/cpt.php', // Custom post types: case_study, scenario.
'inc/seo.php', // Schema.org JSON-LD overrides.
'inc/form-handler.php', // Conversion form POST handler.
'inc/render-blocks.php', // Data array → Gutenberg HTML for the migrator.
'inc/shortcodes.php', // [av_form slug="..."] etc.
];
foreach ($av_includes as $av_include) {

View File

@@ -23,7 +23,7 @@ defined('ABSPATH') || exit;
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<a class="av-skip-link" href="#main"><?php esc_html_e('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">
<div class="av-container av-header__inner">
@@ -36,41 +36,55 @@ defined('ABSPATH') || exit;
<ul class="av-nav__list" style="display:flex;gap:var(--space-6);list-style:none;margin:0;padding:0;">
<li class="av-nav__item">
<a href="<?php echo esc_url(home_url('/solutions/')); ?>" class="av-nav__link" aria-haspopup="true" aria-expanded="false">
<?php esc_html_e('Solutions', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('Solutions', 'asterion-bricks')); ?>
</a>
</li>
<li class="av-nav__item">
<a href="<?php echo esc_url(home_url('/industries/')); ?>" class="av-nav__link" aria-haspopup="true" aria-expanded="false">
<?php esc_html_e('Industries', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('Industries', 'asterion-bricks')); ?>
</a>
</li>
<li class="av-nav__item">
<a href="<?php echo esc_url(home_url('/technology/')); ?>" class="av-nav__link" aria-haspopup="true" aria-expanded="false">
<?php esc_html_e('Technology', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('Technology', 'asterion-bricks')); ?>
</a>
</li>
<li class="av-nav__item">
<a href="<?php echo esc_url(home_url('/why-asterion/')); ?>" class="av-nav__link">
<?php esc_html_e('Why Asterion', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('Why Asterion', 'asterion-bricks')); ?>
</a>
</li>
<li class="av-nav__item">
<a href="<?php echo esc_url(home_url('/insights/')); ?>" class="av-nav__link">
<?php esc_html_e('Insights', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('Insights', 'asterion-bricks')); ?>
</a>
</li>
</ul>
</nav>
<div class="av-header__right">
<div class="av-lang-switch" aria-label="<?php esc_attr_e('Language', 'asterion-bricks'); ?>">
<span class="av-lang-switch__current">EN</span>
<span aria-hidden="true">·</span>
<a href="#" class="av-lang-switch__other" aria-label="<?php esc_attr_e('Switch to French', 'asterion-bricks'); ?>">FR</a>
<?php
// Render WPML language switcher when WPML is active and exposes languages.
$av_languages = apply_filters('wpml_active_languages', null, ['skip_missing' => 0]);
if (! empty($av_languages) && is_array($av_languages) && count($av_languages) > 1) :
?>
<div class="av-lang-switch" aria-label="<?php echo esc_attr(av_t('Language')); ?>">
<?php $av_first = true; foreach ($av_languages as $av_lang_data) :
if (! $av_first) : ?><span aria-hidden="true">·</span><?php endif; $av_first = false;
$av_code = strtoupper($av_lang_data['language_code']);
$av_url = esc_url($av_lang_data['url']);
$av_label = esc_html($av_lang_data['translated_name'] ?? $av_lang_data['native_name'] ?? $av_code);
if (! empty($av_lang_data['active'])) : ?>
<span class="av-lang-switch__current" aria-current="true"><?php echo esc_html($av_code); ?></span>
<?php else : ?>
<a href="<?php echo $av_url; ?>" class="av-lang-switch__other" hreflang="<?php echo esc_attr($av_lang_data['language_code']); ?>" lang="<?php echo esc_attr($av_lang_data['language_code']); ?>" aria-label="<?php echo esc_attr($av_label); ?>"><?php echo esc_html($av_code); ?></a>
<?php endif;
endforeach; ?>
</div>
<?php endif; ?>
<a href="<?php echo esc_url(home_url('/request-demo/')); ?>" class="av-btn av-btn--primary av-btn--md">
<?php esc_html_e('Request a Demo', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('Request a Demo', 'asterion-bricks')); ?>
</a>
<button type="button" class="av-drawer-toggle" aria-controls="av-drawer" aria-expanded="false" aria-label="<?php esc_attr_e('Open menu', 'asterion-bricks'); ?>">
@@ -89,24 +103,24 @@ defined('ABSPATH') || exit;
<button type="button" class="av-drawer__close" aria-label="<?php esc_attr_e('Close menu', 'asterion-bricks'); ?>">×</button>
<nav class="av-drawer__nav" aria-label="<?php esc_attr_e('Mobile primary', 'asterion-bricks'); ?>">
<div class="av-drawer__group">
<a href="<?php echo esc_url(home_url('/solutions/')); ?>" class="av-drawer__group-title"><?php esc_html_e('Solutions', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/solutions/')); ?>" class="av-drawer__group-title"><?php echo esc_html(av_t('Solutions', 'asterion-bricks')); ?></a>
</div>
<div class="av-drawer__group">
<a href="<?php echo esc_url(home_url('/industries/')); ?>" class="av-drawer__group-title"><?php esc_html_e('Industries', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/industries/')); ?>" class="av-drawer__group-title"><?php echo esc_html(av_t('Industries', 'asterion-bricks')); ?></a>
</div>
<div class="av-drawer__group">
<a href="<?php echo esc_url(home_url('/technology/')); ?>" class="av-drawer__group-title"><?php esc_html_e('Technology', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/technology/')); ?>" class="av-drawer__group-title"><?php echo esc_html(av_t('Technology', 'asterion-bricks')); ?></a>
</div>
<div class="av-drawer__group">
<a href="<?php echo esc_url(home_url('/why-asterion/')); ?>" class="av-drawer__group-title"><?php esc_html_e('Why Asterion', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/why-asterion/')); ?>" class="av-drawer__group-title"><?php echo esc_html(av_t('Why Asterion', 'asterion-bricks')); ?></a>
</div>
<div class="av-drawer__group">
<a href="<?php echo esc_url(home_url('/insights/')); ?>" class="av-drawer__group-title"><?php esc_html_e('Insights', 'asterion-bricks'); ?></a>
<a href="<?php echo esc_url(home_url('/insights/')); ?>" class="av-drawer__group-title"><?php echo esc_html(av_t('Insights', 'asterion-bricks')); ?></a>
</div>
</nav>
<div class="av-drawer__cta-area">
<a href="<?php echo esc_url(home_url('/request-demo/')); ?>" class="av-btn av-btn--primary av-btn--lg" style="width:100%;">
<?php esc_html_e('Request a Demo', 'asterion-bricks'); ?>
<?php echo esc_html(av_t('Request a Demo', 'asterion-bricks')); ?>
</a>
</div>
</aside>

View File

@@ -0,0 +1,200 @@
<?php
/**
* Asterion Bricks — i18n helpers
*
* Lightweight WPML-aware language helpers used by Custom Templates to pick
* the right data file (e.g. solutions-data.php vs solutions-data-fr.php) and
* by header.php / footer.php to translate UI strings.
*
* We don't use WordPress .po/.mo loaders — WPML String Translation handles
* those — but we keep a small in-PHP map for the strings that aren't tied
* to data files (nav labels, generic CTAs, footer columns).
*
* @package AsterionBricks
*/
defined('ABSPATH') || exit;
/**
* Active language code, normalised to 'en' or 'fr'.
* Falls back to 'en' when WPML isn't active.
*/
function av_lang() {
$lang = apply_filters('wpml_current_language', null);
if (! $lang) {
$lang = function_exists('get_locale') ? substr(get_locale(), 0, 2) : 'en';
}
return ($lang === 'fr') ? 'fr' : 'en';
}
/**
* Build the path to a localised data file.
* Example : av_data_file('solutions-data') returns
* '<theme>/inc/solutions-data.php' when EN
* '<theme>/inc/solutions-data-fr.php' when FR (if it exists)
*/
function av_data_file($basename) {
$base = AV_THEME_DIR . '/inc/' . $basename;
$localised = $base . '-' . av_lang() . '.php';
return file_exists($localised) ? $localised : $base . '.php';
}
/**
* Translate a UI string. Falls back to the original on EN or when no entry
* matches in FR. Strings are kept in this file rather than .po/.mo so the
* theme stays self-contained.
*/
function av_t($string, $textdomain = 'asterion-bricks') {
if (av_lang() !== 'fr') {
return $string;
}
static $map = null;
if ($map === null) {
$map = [
// Nav + header
'Skip to main content' => 'Aller au contenu principal',
'Primary' => 'Principal',
'Mobile primary' => 'Principal mobile',
'Solutions' => 'Solutions',
'Industries' => 'Secteurs',
'Technology' => 'Technologie',
'Why Asterion' => 'Pourquoi Asterion',
'Insights' => 'Insights',
'Open menu' => 'Ouvrir le menu',
'Close menu' => 'Fermer le menu',
'Language' => 'Langue',
'Switch to French' => 'Passer en français',
'Switch to English' => 'Switch to English',
'Request a Demo' => 'Demander une démo',
// Footer
'Newsletter' => 'Newsletter',
'Our story' => 'Notre histoire',
'Customers' => 'Clients',
'Trust & Compliance' => 'Confiance et conformité',
'Partners' => 'Partenaires',
'Police' => 'Police',
'Special Forces' => 'Forces spéciales',
'Military' => 'Militaires',
'Firefighters' => 'Pompiers',
'Privacy' => 'Confidentialité',
'Terms' => 'Conditions',
'Cookies' => 'Cookies',
'Legal notice' => 'Mentions légales',
'All rights reserved.' => 'Tous droits réservés.',
'Insights from the front of immersive training. One email per month. No spam.'
=> 'Les enseignements du terrain de la formation immersive. Un e-mail par mois. Pas de spam.',
'Subscribe' => 'Sabonner',
'your@email.com' => 'vous@email.com',
'The modular, sovereign XR platform for European security forces. Train like the threat is now.'
=> 'La plateforme XR modulaire et souveraine pour les forces de sécurité européennes. Entraînez-vous comme si la menace était maintenant.',
// Generic CTAs / labels
'Read more' => 'Lire la suite',
'See all articles' => 'Voir tous les articles',
'Watch the 90-second film' => 'Voir le film de 90 secondes',
'Schedule a demo' => 'Planifier une démo',
'Request the kit' => 'Demander le kit',
'Get a quote' => 'Demander un devis',
'Send' => 'Envoyer',
'Send the message' => 'Envoyer le message',
'Apply for a T&E Kit' => 'Postuler pour un kit T&E',
'Schedule the demo' => 'Planifier la démo',
'Request the quote' => 'Demander le devis',
'Read the case study' => 'Lire létude de cas',
'Discuss a custom scenario' => 'Discuter dun scénario sur mesure',
'Schedule a discovery call' => 'Planifier un appel de cadrage',
'Discuss your custom request' => 'Parler de votre besoin sur mesure',
'Become the next case study' => 'Devenez la prochaine étude de cas',
'Request a Trust Pack' => 'Demander un Trust Pack',
'Become a partner — apply' => 'Devenir partenaire — candidater',
'Compare with PROSERVE FLEX' => 'Comparer avec PROSERVE FLEX',
'Compare with PROSERVE ACADEMY' => 'Comparer avec PROSERVE ACADEMY',
'Comparison and upgrade' => 'Comparaison et évolution',
'Eligibility' => 'Éligibilité',
'Frequently asked' => 'Questions fréquentes',
'Quick answers.' => 'Réponses brèves.',
// Section eyebrows used on home / hubs / forms
'Modular XR training for security forces' => 'Formation XR modulaire pour les forces de sécurité',
'Trusted by' => 'Reconnu par',
'Trusted by security forces across Europe' => 'Adopté par les forces de sécurité en Europe',
'Voices from the front of immersive training.' => 'La parole des opérateurs.',
'Compare' => 'Comparer',
'The six pillars' => 'Les six piliers',
'Tell us about your unit.' => 'Parlez-nous de votre unité.',
'What you receive' => 'Ce que vous recevez',
'Other inquiries' => 'Autres demandes',
'How can we help?' => 'Comment pouvons-nous vous aider ?',
// Form widgets
'— select —' => '— choisir —',
'Your email' => 'Votre e-mail',
'Newsletter signup' => 'Inscription newsletter',
'Mobile drawer' => 'Tiroir mobile',
'Voices from the field' => 'La parole du terrain',
'Train how it really feels.' => 'Entraînez-vous au plus près du réel.',
'Train like the threat is now.' => 'Entraînez-vous comme si la menace était maintenant.',
'Three paths into the platform — pick the one that fits where you are.' => 'Trois portes dentrée dans la plateforme — choisissez celle qui correspond à votre besoin.',
'A 30-minute tailored session with our team. Walk through the configuration that matches your needs.' => 'Une session sur mesure de 30 minutes avec notre équipe. Démonstration de la configuration adaptée à vos besoins.',
'A 30-minute tailored session with our team.' => 'Une session de 30 minutes avec notre équipe.',
'A PROSERVE case on loan at your facility for 5 to 10 days, with on-site support from our team.' => 'Un kit PROSERVE en prêt dans vos locaux pendant 5 à 10 jours, avec accompagnement sur site.',
'A PROSERVE case on loan at your facility for 5 to 10 days.' => 'Un kit PROSERVE en prêt dans vos locaux pendant 5 à 10 jours.',
'A detailed quote and deployment plan within 5 working days.' => 'Un devis détaillé et un plan de déploiement sous 5 jours ouvrés.',
'Ready to get hands-on?' => 'Prêt à passer à la pratique ?',
'Last updated:' => 'Dernière mise à jour :',
'Legal' => 'Légal',
'Placeholder.' => 'À compléter.',
'This page is to be drafted with legal counsel. The structure below outlines the sections expected.' =>
'Cette page sera rédigée avec votre conseil juridique. La structure ci-dessous liste les sections attendues.',
'Sections to include' => 'Sections à inclure',
'Police training' => 'Formation police',
'Special forces training' => 'Formation forces spéciales',
'Military training' => 'Formation militaire',
'Firefighter training' => 'Formation pompier',
'Insights from the front of immersive training.' => 'Les enseignements du terrain de la formation immersive.',
'See the full scenario library' => 'Voir la bibliothèque complète de scénarios',
'Inside the hardware' => 'Inside the hardware',
'Inside the software' => 'Inside the software',
'Inside weapons & tracking' => 'Inside weapons & tracking',
'Browse the scenario library' => 'Parcourir la bibliothèque',
'Inside the instructor cockpit' => 'Inside the instructor cockpit',
'Inside after-action review' => 'Inside after-action review',
'See how UWeD works' => 'Voir comment fonctionne UWeD',
'Explore After-Action Review' => 'Découvrir lAfter-Action Review',
'Explore PROSERVE+ customization' => 'Découvrir la personnalisation PROSERVE+',
'Discover MY PROSERVE' => 'Découvrir MY PROSERVE',
'Discover PROSERVE FLEX' => 'Découvrir PROSERVE FLEX',
'Discover PROSERVE ACADEMY' => 'Découvrir PROSERVE ACADEMY',
'Request access' => 'Demander laccès',
'Request a T&E Kit' => 'Demander un kit T&E',
'Request a Quote' => 'Demander un devis',
'Request a Demo for police use' => 'Demander une démo pour la police',
'Request a Demo for fire & emergency' => 'Demander une démo pour les pompiers',
'Thank you — your request was sent.' => 'Merci — votre demande a bien été envoyée.',
'We will reply within the timeframe stated above. Check your inbox (and spam) for confirmation.' =>
'Nous reviendrons vers vous dans les délais indiqués. Vérifiez votre boîte de réception (et vos spams) pour la confirmation.',
'Something went wrong.' => 'Une erreur est survenue.',
' Please try again, or email us directly at hello@asterionvr.com.' =>
' Veuillez réessayer, ou écrivez-nous directement à hello@asterionvr.com.',
'Editorial blog launches with the site go-live. The 12-month content calendar is in the Strategy & Content brief, section B.4.' =>
'Le blog éditorial démarrera avec la mise en ligne du site. Le calendrier sur 12 mois figure dans le livrable Stratégie & Contenu, partie B.4.',
'Editorial blog launches with the site go-live. The 12-month content calendar is in the Strategy & Content brief, section B.4. New articles will appear here as soon as they ship.' =>
'Le blog éditorial démarrera avec la mise en ligne du site. Le calendrier sur 12 mois figure dans le livrable Stratégie & Contenu, partie B.4. Les articles apparaîtront ici dès leur publication.',
'Subscribe — one article per month.' => 'Abonnez-vous — un article par mois.',
'Notes from the front of immersive training.' => 'Les enseignements du terrain de la formation immersive.',
'Doctrine. Training science. Instructor stories. AAR data. Comparisons of VR vs live training. Found something useful? It probably came from a customer conversation. We publish what we learn.' =>
'Doctrine. Science de la formation. Récits dinstructeurs. Données AAR. Comparaisons VR vs entraînement réel. Quelque chose dutile ? Cela vient probablement dun échange client. Nous publions ce que nous apprenons.',
'Everything to evaluate, justify, and procure.' => 'Tout pour évaluer, justifier, acheter.',
'Whether you are building an internal pitch, drafting a procurement specification, or briefing your team — these resources are designed to help.' =>
'Que vous prépariez un argumentaire interne, rédigiez un cahier des charges ou briefiez vos équipes — ces ressources sont là pour vous aider.',
];
}
return $map[$string] ?? $string;
}
/**
* Convenience: echo a translated string.
*/
function av_te($string) {
echo esc_html(av_t($string));
}

View File

@@ -0,0 +1,376 @@
<?php
/**
* Asterion Bricks — Data → Gutenberg blocks renderer
*
* Converts the structured PHP arrays in inc/<section>-data.php into a
* Gutenberg block payload (`post_content`) so that :
*
* - Pages are editable in the WP admin block editor
* - Bricks Builder can pick them up via « Edit with Bricks » (Bricks reads
* post_content and converts core blocks → Bricks elements on save)
* - WPML's Translation Editor exposes every block for translation
*
* Strategy
* --------
* We generate Gutenberg-valid HTML using a mix of native blocks
* (`core/heading`, `core/paragraph`, `core/list`, `core/buttons`,
* `core/columns`) wrapped in `core/group` containers carrying our
* `av-*` classes. Visually-heavy items (hero, conversion banner,
* complex cards) fall back to `core/html` blocks so the rendering
* stays pixel-identical to the Custom Template version, while still
* being individually translatable in WPML.
*
* Public API
* ----------
* av_render_solution_blocks($data) → string (post_content)
* av_render_industry_blocks($data) → string
* av_render_technology_blocks($data) → string (alias of industry)
* av_render_editorial_blocks($data) → string (alias of industry)
* av_render_form_blocks($data, $slug) → string
* av_render_overview_blocks($cards, $hero, $bg) → string (hubs)
* av_render_home_blocks() → string
*
* @package AsterionBricks
*/
defined('ABSPATH') || exit;
/* =================================================================== */
/* Block helpers */
/* =================================================================== */
function av_block_html($html) {
$html = trim($html);
return "<!-- wp:html -->\n{$html}\n<!-- /wp:html -->\n\n";
}
function av_block_heading($text, $level = 2, $class = '') {
$tag = 'h' . max(1, min(6, (int) $level));
$class = $class ? ' ' . esc_attr($class) : '';
$args = json_encode(['level' => (int) $level, 'className' => trim($class)]);
return "<!-- wp:heading {$args} -->\n<{$tag} class=\"wp-block-heading{$class}\">" . esc_html($text) . "</{$tag}>\n<!-- /wp:heading -->\n\n";
}
function av_block_paragraph($text, $class = '') {
$args = $class ? json_encode(['className' => $class]) . ' ' : '';
$cls = $class ? ' class="' . esc_attr($class) . '"' : '';
return "<!-- wp:paragraph {$args}-->\n<p{$cls}>" . esc_html($text) . "</p>\n<!-- /wp:paragraph -->\n\n";
}
function av_block_list($items) {
$out = "<!-- wp:list -->\n<ul>\n";
foreach ($items as $item) {
$out .= "<!-- wp:list-item -->\n<li>" . esc_html($item) . "</li>\n<!-- /wp:list-item -->\n";
}
$out .= "</ul>\n<!-- /wp:list -->\n\n";
return $out;
}
function av_block_button($label, $href, $variant = 'primary', $on_dark = false) {
$href = esc_url($href);
$label = esc_html($label);
$cls = 'av-btn av-btn--' . $variant . ($on_dark ? ' av-btn--on-dark' : '') . ' av-btn--lg';
return "<!-- wp:html -->\n<a class=\"{$cls}\" href=\"{$href}\">{$label}</a>\n<!-- /wp:html -->\n\n";
}
function av_block_buttons_row($ctas, $on_dark = false, $home_url = '') {
if (empty($ctas)) return '';
$out = "<!-- wp:html -->\n<div style=\"display:flex;flex-wrap:wrap;gap:var(--space-4);\">\n";
foreach ($ctas as $cta) {
$href = $home_url . ltrim($cta['href'], '/');
$variant = ($cta['variant'] === 'primary') ? 'av-btn--primary' : ($on_dark ? 'av-btn--on-dark av-btn--secondary' : 'av-btn--secondary');
$out .= '<a class="av-btn ' . esc_attr($variant) . ' av-btn--lg" href="' . esc_url($href) . '">' . esc_html($cta['label']) . "</a>\n";
}
$out .= "</div>\n<!-- /wp:html -->\n\n";
return $out;
}
/* =================================================================== */
/* Hero blocks */
/* =================================================================== */
function av_render_solution_hero($data, $home_url) {
$eyebrow = esc_html($data['eyebrow']);
$title = esc_html($data['title']);
$tagline = esc_html($data['tagline']);
$lead = esc_html($data['hero_lead']);
$ctas = '';
foreach ($data['ctas'] as $cta) {
$href = $home_url . ltrim($cta['href'], '/');
$variant = ($cta['variant'] === 'primary') ? 'av-btn--primary' : 'av-btn--secondary av-btn--on-dark';
$ctas .= '<a class="av-btn ' . $variant . ' av-btn--lg" href="' . esc_url($href) . '">' . esc_html($cta['label']) . "</a>\n";
}
$html = <<<HTML
<section class="av-hero">
<div class="av-hero__media" aria-hidden="true">
<div style="width:100%;height:100%;background:radial-gradient(ellipse at 70% 30%, rgba(201,164,90,0.15), transparent 60%),linear-gradient(135deg, #081427 0%, #0B1F3A 50%, #13294B 100%);"></div>
</div>
<div class="av-container">
<div class="av-hero__inner">
<p class="av-hero__eyebrow">{$eyebrow}</p>
<h1 class="av-hero__headline" style="font-size:clamp(2.25rem,5vw,var(--text-display-lg));line-height:var(--leading-display-lg);">{$title}&trade; — {$tagline}</h1>
<p class="av-hero__sub">{$lead}</p>
<div class="av-hero__ctas">{$ctas}</div>
</div>
</div>
</section>
HTML;
return av_block_html($html);
}
function av_render_industry_hero($data, $home_url) {
$eyebrow = esc_html($data['eyebrow']);
$tagline = esc_html($data['tagline']);
$lead = esc_html($data['hero_lead']);
$ctas = '';
foreach ($data['ctas'] as $cta) {
$href = $home_url . ltrim($cta['href'], '/');
$variant = ($cta['variant'] === 'primary') ? 'av-btn--primary' : 'av-btn--secondary av-btn--on-dark';
$ctas .= '<a class="av-btn ' . $variant . ' av-btn--lg" href="' . esc_url($href) . '">' . esc_html($cta['label']) . "</a>\n";
}
$html = <<<HTML
<section class="av-hero">
<div class="av-hero__media" aria-hidden="true">
<div style="width:100%;height:100%;background:radial-gradient(ellipse at 50% 40%, rgba(11,31,58,0.4), transparent 65%),linear-gradient(135deg, #081427 0%, #0B1F3A 50%, #1F3252 100%);"></div>
</div>
<div class="av-container">
<div class="av-hero__inner">
<p class="av-hero__eyebrow">{$eyebrow}</p>
<h1 class="av-hero__headline">{$tagline}</h1>
<p class="av-hero__sub">{$lead}</p>
<div class="av-hero__ctas">{$ctas}</div>
</div>
</div>
</section>
HTML;
return av_block_html($html);
}
/* =================================================================== */
/* Section renderer (shared by solution / industry / technology / */
/* editorial detail pages) */
/* =================================================================== */
function av_render_data_section($section, $is_dark, $home_url) {
$section_class = 'av-section' . ($is_dark ? ' av-section--dark' : '');
$eye_class = 'av-eyebrow' . ($is_dark ? ' av-eyebrow--gold' : '');
$eyebrow = esc_html($section['eyebrow'] ?? '');
$title = esc_html($section['title'] ?? '');
$lead = ! empty($section['lead']) ? '<p class="av-section__lead">' . esc_html($section['lead']) . '</p>' : '';
$head_html = <<<HTML
<section class="{$section_class}">
<div class="av-container">
<div class="av-section__head">
<span class="{$eye_class}">{$eyebrow}</span>
<h2 class="av-section__title">{$title}</h2>
{$lead}
</div>
HTML;
$body = '';
switch ($section['type']) {
case 'prose':
$body = '<p class="av-section__lead" style="max-width:72ch;font-size:var(--text-body-lg);">' . esc_html($section['body'] ?? '') . '</p>';
break;
case 'cards':
$body = '<div class="av-grid-3">';
foreach ($section['items'] as $card) {
$card_class = 'av-card' . ($is_dark ? ' is-on-dark' : '') . ' av-card--feature';
$body .= '<article class="' . $card_class . '"><div class="av-card__body">';
$body .= '<h3 class="av-card__title" style="font-size:var(--text-h4);">' . esc_html($card['title']) . '</h3>';
$body .= '<p class="av-card__excerpt">' . esc_html($card['body']) . '</p>';
$body .= '</div></article>';
}
$body .= '</div>';
break;
case 'list':
$color = $is_dark ? 'color:var(--color-text-on-dark-muted);' : 'color:var(--color-text-secondary);';
$body = '<ul style="list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:var(--space-3);max-width:72ch;font-size:var(--text-body-lg);line-height:var(--leading-body-lg);' . $color . '">';
foreach ($section['items'] as $item) {
$body .= '<li style="padding-left:var(--space-6);position:relative;"><span aria-hidden="true" style="position:absolute;left:0;top:0.6em;width:8px;height:8px;background:var(--color-brand-gold);border-radius:50%;"></span>' . esc_html($item) . '</li>';
}
$body .= '</ul>';
if (! empty($section['cta'])) {
$href = $home_url . ltrim($section['cta']['href'], '/');
$linkcls = 'av-link' . ($is_dark ? ' av-link--on-dark' : '') . ' av-link--with-arrow';
$body .= '<p style="margin-top:var(--space-8);"><a class="' . $linkcls . '" href="' . esc_url($href) . '">' . esc_html($section['cta']['label']) . '</a></p>';
}
break;
case 'cta':
$body = '<p class="av-section__lead" style="max-width:72ch;margin-bottom:var(--space-6);">' . esc_html($section['body'] ?? '') . '</p>';
if (! empty($section['ctas'])) {
$body .= '<div style="display:flex;flex-wrap:wrap;gap:var(--space-4);">';
foreach ($section['ctas'] as $cta) {
$href = $home_url . ltrim($cta['href'], '/');
$variant = ($cta['variant'] === 'primary') ? 'av-btn--primary' : ($is_dark ? 'av-btn--on-dark av-btn--secondary' : 'av-btn--secondary');
$body .= '<a class="av-btn ' . $variant . ' av-btn--lg" href="' . esc_url($href) . '">' . esc_html($cta['label']) . "</a>";
}
$body .= '</div>';
}
break;
}
$foot_html = "</div></section>";
return av_block_html($head_html . $body . $foot_html);
}
/* =================================================================== */
/* Conversion banner (shared) */
/* =================================================================== */
function av_render_conversion_banner($home_url) {
$html = <<<HTML
<section class="av-conversion-banner">
<div class="av-container">
<div class="av-conversion-banner__head">
<h2 class="av-conversion-banner__title">Train like the threat is now.</h2>
<p class="av-conversion-banner__lead">Three paths into the platform — pick the one that fits where you are.</p>
</div>
<div class="av-conversion-banner__grid">
<div class="av-conversion-banner__card">
<h3 class="av-conversion-banner__card-title">Request a Demo</h3>
<p class="av-conversion-banner__card-desc">A 30-minute tailored session with our team.</p>
<a href="{$home_url}request-demo/" class="av-btn av-btn--primary av-btn--md">Schedule a demo</a>
</div>
<div class="av-conversion-banner__card">
<h3 class="av-conversion-banner__card-title">Request a T&amp;E Kit</h3>
<p class="av-conversion-banner__card-desc">A PROSERVE case on loan at your facility for 5 to 10 days.</p>
<a href="{$home_url}request-te-kit/" class="av-btn av-btn--on-dark av-btn--secondary av-btn--md">Request the kit</a>
</div>
<div class="av-conversion-banner__card">
<h3 class="av-conversion-banner__card-title">Request a Quote</h3>
<p class="av-conversion-banner__card-desc">A detailed quote and deployment plan within 5 working days.</p>
<a href="{$home_url}request-quote/" class="av-btn av-btn--on-dark av-btn--secondary av-btn--md">Get a quote</a>
</div>
</div>
</div>
</section>
HTML;
return av_block_html($html);
}
/* =================================================================== */
/* Top-level renderers */
/* =================================================================== */
function av_render_solution_blocks($data) {
$home_url = home_url('/');
$out = av_render_solution_hero($data, $home_url);
foreach ($data['sections'] as $idx => $section) {
$out .= av_render_data_section($section, ($idx % 2 === 1), $home_url);
}
if (! empty($data['upsell'])) {
$upsell_html = '<section class="av-section" style="background-color:var(--color-bg-subtle);"><div class="av-container">';
$upsell_html .= '<div class="av-section__head">';
$upsell_html .= '<span class="av-eyebrow">Comparison and upgrade</span>';
$upsell_html .= '<h2 class="av-section__title">' . esc_html($data['upsell']['title']) . '</h2>';
$upsell_html .= '<p class="av-section__lead">' . esc_html($data['upsell']['body']) . '</p>';
$upsell_html .= '</div><div style="display:flex;flex-wrap:wrap;gap:var(--space-4);">';
foreach ($data['upsell']['links'] as $link) {
$upsell_html .= '<a class="av-btn av-btn--secondary av-btn--md" href="' . esc_url($home_url . ltrim($link['href'], '/')) . '">' . esc_html($link['label']) . "</a>";
}
$upsell_html .= '</div></div></section>';
$out .= av_block_html($upsell_html);
}
$out .= av_render_conversion_banner($home_url);
return $out;
}
function av_render_industry_blocks($data) {
$home_url = home_url('/');
$out = av_render_industry_hero($data, $home_url);
foreach ($data['sections'] as $idx => $section) {
$out .= av_render_data_section($section, ($idx % 2 === 1), $home_url);
}
$out .= av_render_conversion_banner($home_url);
return $out;
}
function av_render_technology_blocks($data) {
return av_render_industry_blocks($data); // identical schema
}
function av_render_editorial_blocks($data) {
return av_render_industry_blocks($data);
}
function av_render_form_blocks($data, $slug) {
$home_url = home_url('/');
// Hero
$eyebrow = esc_html($data['eyebrow']);
$tagline = esc_html($data['tagline']);
$lead = esc_html($data['hero_lead']);
$shortcuts_html = '';
if (! empty($data['shortcuts'])) {
$shortcuts_html .= '<div class="av-hero__ctas">';
foreach ($data['shortcuts'] as $sc) {
$variant = ($sc['variant'] === 'primary') ? 'av-btn--primary' : 'av-btn--on-dark av-btn--secondary';
$shortcuts_html .= '<a class="av-btn ' . $variant . ' av-btn--md" href="' . esc_url($home_url . ltrim($sc['href'], '/')) . '">' . esc_html($sc['label']) . '</a>';
}
$shortcuts_html .= '</div>';
}
$hero_html = <<<HTML
<section class="av-hero">
<div class="av-hero__media" aria-hidden="true">
<div style="width:100%;height:100%;background:radial-gradient(ellipse at 50% 30%, rgba(201,164,90,0.12), transparent 60%),linear-gradient(135deg, #081427 0%, #0B1F3A 50%, #13294B 100%);"></div>
</div>
<div class="av-container">
<div class="av-hero__inner">
<p class="av-hero__eyebrow">{$eyebrow}</p>
<h1 class="av-hero__headline" style="font-size:clamp(2.25rem,5vw,var(--text-display-lg));line-height:var(--leading-display-lg);">{$tagline}</h1>
<p class="av-hero__sub">{$lead}</p>
{$shortcuts_html}
</div>
</div>
</section>
HTML;
$out = av_block_html($hero_html);
// The form itself stays a shortcode — added by template wrapper instead.
// To keep the page editable, we drop a placeholder shortcode that the
// child theme's `av_form` shortcode handler renders on the front-end.
$out .= av_block_html('<div class="av-form-placeholder">[av_form slug="' . esc_attr($slug) . '"]</div>');
return $out;
}
function av_render_overview_blocks($cards, $hero_eyebrow, $hero_title, $hero_sub) {
$home_url = home_url('/');
$hero_html = <<<HTML
<section class="av-hero">
<div class="av-hero__media" aria-hidden="true">
<div style="width:100%;height:100%;background:linear-gradient(135deg, #081427 0%, #0B1F3A 50%, #13294B 100%);"></div>
</div>
<div class="av-container">
<div class="av-hero__inner">
<p class="av-hero__eyebrow">{$hero_eyebrow}</p>
<h1 class="av-hero__headline">{$hero_title}</h1>
<p class="av-hero__sub">{$hero_sub}</p>
</div>
</div>
</section>
HTML;
$out = av_block_html($hero_html);
$cards_html = '<section class="av-section"><div class="av-container"><div class="av-grid-3">';
foreach ($cards as $c) {
$href = $home_url . ltrim($c['href'], '/');
$cards_html .= '<article class="av-card"><a href="' . esc_url($href) . '" class="av-card__media" tabindex="-1" style="background:linear-gradient(135deg,#1F3252,#0B1F3A);display:block;"></a>';
$cards_html .= '<div class="av-card__body">';
$cards_html .= '<span class="av-card__eyebrow">' . esc_html($c['eyebrow'] ?? '') . '</span>';
$cards_html .= '<h2 class="av-card__title"><a href="' . esc_url($href) . '" style="color:inherit;text-decoration:none;">' . esc_html($c['title']) . '</a></h2>';
$cards_html .= '<p class="av-card__excerpt">' . esc_html($c['excerpt']) . '</p>';
$cards_html .= '<div class="av-card__cta"><a href="' . esc_url($href) . '" class="av-link av-link--with-arrow">' . esc_html($c['cta']) . '</a></div>';
$cards_html .= '</div></article>';
}
$cards_html .= '</div></div></section>';
$out .= av_block_html($cards_html);
return $out;
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Asterion Bricks — Shortcodes
*
* Lets the migrated post_content reference dynamic blocks (form, recent
* posts, etc.) without hardcoding them in the Gutenberg payload.
*
* [av_form slug="request-demo"] — renders one of the 4 conversion forms
*
* @package AsterionBricks
*/
defined('ABSPATH') || exit;
add_shortcode('av_form', function ($atts) {
$atts = shortcode_atts([
'slug' => '',
], $atts, 'av_form');
$slug = sanitize_key($atts['slug']);
if (! $slug) {
return '';
}
$data = include AV_THEME_DIR . '/inc/forms-data.php';
if (! isset($data[$slug])) {
return '<p style="color:var(--color-error);">[av_form] : unknown slug "' . esc_html($slug) . '"</p>';
}
set_query_var('av_form', $data[$slug]);
set_query_var('av_form_slug_override', $slug);
ob_start();
get_template_part('template-parts/conversion-form');
return ob_get_clean();
});

View File

@@ -0,0 +1,22 @@
<?php
/**
* Asterion Bricks — Default page template
*
* Renders any page that has no Custom Template assigned (or whose Custom
* Template was stripped after the post_content migration). The header and
* footer are shared globals; the content is whatever Gutenberg / Bricks
* stored in post_content.
*
* @package AsterionBricks
*/
defined('ABSPATH') || exit;
get_header();
if (have_posts()) {
while (have_posts()) { the_post();
the_content();
}
}
get_footer();

View File

@@ -21,7 +21,8 @@ if (! is_array($form)) {
}
$home_url = home_url('/');
$slug = get_post_field('post_name', get_queried_object_id());
$slug_override = get_query_var('av_form_slug_override');
$slug = $slug_override ?: get_post_field('post_name', get_queried_object_id());
// Surface success/error from query string (set by the handler on redirect).
$av_status = isset($_GET['av_status']) ? sanitize_key($_GET['av_status']) : '';

View File

@@ -9,7 +9,7 @@
defined('ABSPATH') || exit;
$slug = get_post_field('post_name', get_queried_object_id());
$data = include AV_THEME_DIR . '/inc/forms-data.php';
$data = include av_data_file('forms-data');
if (! isset($data[$slug])) {
get_header();

View File

@@ -10,7 +10,7 @@
defined('ABSPATH') || exit;
$slug = get_post_field('post_name', get_queried_object_id());
$data = include AV_THEME_DIR . '/inc/editorial-data.php';
$data = include av_data_file('editorial-data');
if (! isset($data[$slug])) {
get_header();

View File

@@ -13,7 +13,7 @@
defined('ABSPATH') || exit;
$slug = get_post_field('post_name', get_queried_object_id());
$data = include AV_THEME_DIR . '/inc/industries-data.php';
$data = include av_data_file('industries-data');
if (! isset($data[$slug])) {
get_header();

View File

@@ -14,7 +14,7 @@
defined('ABSPATH') || exit;
$slug = get_post_field('post_name', get_queried_object_id());
$data = include AV_THEME_DIR . '/inc/solutions-data.php';
$data = include av_data_file('solutions-data');
if (! isset($data[$slug])) {
// Fallback : fall back to the basic page rendering if the slug isn't mapped.

View File

@@ -10,7 +10,7 @@
defined('ABSPATH') || exit;
$slug = get_post_field('post_name', get_queried_object_id());
$data = include AV_THEME_DIR . '/inc/technology-data.php';
$data = include av_data_file('technology-data');
if (! isset($data[$slug])) {
get_header();