diff --git a/composer.json b/composer.json index 8d142eb..b17f770 100644 --- a/composer.json +++ b/composer.json @@ -35,6 +35,7 @@ "lewebsimple/advanced-custom-fields-pro": "*", "lewebsimple/ithemes-security-pro": "*", "lewebsimple/kaliroots": "*", + "lewebsimple/polylang-pro": "*", "lewebsimple/wp-offload-ses": "*", "wpackagist-plugin/disable-comments": "*", "wpackagist-plugin/user-switching": "*" diff --git a/composer.lock b/composer.lock index ce3c9d2..80884f2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5a3da24d8abeb9e99f6f31797787cb3c", + "content-hash": "6213374b7b0148dc093add61e4f5be92", "packages": [ { "name": "composer/installers", @@ -203,6 +203,23 @@ "type": "wordpress-theme", "time": "2026-02-09T15:07:56+00:00" }, + { + "name": "lewebsimple/polylang-pro", + "version": "v3.7.7", + "source": { + "type": "git", + "url": "ssh://git@gitea.websimple.com:222/wp-plugins/polylang-pro.git", + "reference": "f13d2bf308d50713f5de50e7734b505e239d068b" + }, + "dist": { + "type": "zip", + "url": "https://satis.ledevsimple.ca/dist/lewebsimple/polylang-pro/lewebsimple-polylang-pro-v3.7.7-e381d8.zip", + "reference": "f13d2bf308d50713f5de50e7734b505e239d068b", + "shasum": "ab06adf3c74f74cf08ec02200943ef1079c723c3" + }, + "type": "wordpress-plugin", + "time": "2026-02-09T14:11:16+00:00" + }, { "name": "lewebsimple/wp-offload-ses", "version": "v1.6.8", @@ -260,16 +277,16 @@ "packages-dev": [ { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.2.0", + "version": "v1.2.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1" + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/845eb62303d2ca9b289ef216356568ccc075ffd1", - "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd", "shasum": "" }, "require": { @@ -352,7 +369,7 @@ "type": "thanks_dev" } ], - "time": "2025-11-11T04:32:07+00:00" + "time": "2026-05-06T08:26:05+00:00" }, { "name": "lewebsimple/wp-phpcs-ruleset", diff --git a/wp-content/themes/cascapedia-st-jules/assets/src/components/PageRenderer.tsx b/wp-content/themes/cascapedia-st-jules/assets/src/components/PageRenderer.tsx index 3c9e8ee..51a0576 100644 --- a/wp-content/themes/cascapedia-st-jules/assets/src/components/PageRenderer.tsx +++ b/wp-content/themes/cascapedia-st-jules/assets/src/components/PageRenderer.tsx @@ -44,10 +44,40 @@ declare global { } } +// WP's PHP serializer omits empty ACF fields, so sections coming from the CMS can +// be missing title/body/etc. Treat those missing-or-empty values as "fall back to +// the local content" instead of letting them blow up the React render. +function isEmptyValue(v: unknown): boolean { + if (v === null || v === undefined) return true; + if (typeof v === "string") return v === ""; + if (Array.isArray(v)) return v.length === 0; + if (typeof v === "object") { + const obj = v as Record; + if ("fr" in obj && "en" in obj) return !obj.fr && !obj.en; + } + return false; +} + +function mergeSection(local: SectionBlock | undefined, wp: SectionBlock): SectionBlock { + if (!local || local.type !== wp.type) return wp; + const merged: Record = { ...local }; + for (const [key, val] of Object.entries(wp)) { + if (!isEmptyValue(val)) merged[key] = val; + } + return merged as unknown as SectionBlock; +} + export function PageRenderer({ page }: { page: PageContent }) { const { t, locale } = useLocale(); const wpPage = window.__CASCA_PAGE__; - const renderedPage = wpPage?.sections?.length ? ({ ...page, ...wpPage } as PageContent) : page; + const wpSections = wpPage?.sections; + const renderedPage = wpSections?.length + ? ({ + ...page, + ...wpPage, + sections: wpSections.map((wpSec, i) => mergeSection(page.sections[i], wpSec)), + } as PageContent) + : page; // Per-page SEO (title + description). React 19 will hoist these to . useEffect(() => {