-
Mahmoud Aglan authored
Building an existing client site inside the builder surfaced the gaps between "the blocks exist" and "the blocks can express a finished design". Each of these was found by rendering the target and comparing it, not by reading the code. Blueprint export/import (v2) now carries the whole design, not a third of it. It exported pages only — so importing a design gave you the content with a default theme and no navigation, which looks nothing like its source. It now carries theme settings and menus too. Menu items record their page by SLUG, because a page id means nothing in another tenant's database and would import a navigation pointing at whatever happened to hold that id. Tracking identifiers are deliberately excluded from the whitelist: importing a design must never start reporting one client's traffic into another's account. v1 files still import. Isolation that did not isolate. BlockRenderer catches a failing block so the rest of the site survives, but Laravel's View::render() calls flushState() when any view throws, which clears the section stack of the page *around* it. Rendered inside the layout's @section, one bad block therefore killed the whole page at @endsection with an unrelated "Cannot end a section" error — the exact opposite of the intent. Blocks are now rendered before the layout runs, where there is no open section to corrupt. Bilingual content reached templates raw. Translatable repeater sub-fields (a button label, a card title, a partner name) are stored as ['ar'=>…,'en'=>…] and read straight out of the data array, so they arrived at {{ }} as arrays and took the block down with "htmlspecialchars(): array given". website_text() resolves them, and 49 such reads across 15 block views now use it. The English site rendered right-to-left. website.css hardcoded `direction: rtl` on .website-body, silently overriding the dir attribute the layout computes from the locale. Direction now follows the document. There was no English at all. No lang/ directory existed, so every __() returned its Arabic key and English visitors read Arabic form labels, buttons and helper text. lang/en.json covers all 125 public-site strings. Smaller gaps, each of which made a real design impossible to express: - 'glass' was a valid navbar template and a forbidden column value; the CHECK constraint predated it, so choosing it failed at write time. - navbar_cta_text had no English twin, so a bilingual site showed one language's button to both audiences. - An empty navbar CTA fell back to the default label, so the button could not be turned off. - An anchor menu item resolved to a bare "#id", which points at nothing from a sub-page; it now addresses the homepage in the reader's language. - A footer column title was a plain string, so it could not be bilingual; the 'about' column dropped the social row whenever columns were configured. - product_showcase stacked its showcase under a centred headline instead of laying out as the split it is. - A map field stores coords as ['lat'=>…,'lng'=>…] and the view passed the array to urlencode(), killing the block. - New: 'stacked' info cards, a footer spacer, heading rules and eyebrows on the contact block, and a nowrap on highlighted heading fragments so "Welcome to {OC-Sport}" cannot break mid-phrase. Verified against a local Postgres replica carrying a real 11-page bilingual site: 22 page/locale combinations answer 200 with zero logged block failures, all 137 block/variant combinations render, reserved and unknown paths still 404, the four migrations apply and roll back on both an existing tenant and a from-scratch install + seed, and the suite passes (140 tests, 483 assertions). Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
21792905