Platform: Miva Empressa (current, new admin)
Category: Template Architecture / Performance
Verified: Yes — live branch experiment
Background & Motivation
Global headers, footers, and page templates accumulate heavy computational MVT code alongside UI markup — price group logic, customer detection, feature flag checks, struct population — tangled in with the HTML. The goal of this pattern is separation of concerns: move the programming layer into fragments, leave UI templates focused on presentation.
Previously handled with a function_something naming convention in ReadyTheme content sections — sections that output nothing visual but set l.settings variables for downstream use. Fragments are the native, more performant replacement.
Fragment Syntax
<!-- Simple fragment, no data sharing -->
<mvt:fragment code="my_fragment_code" />
<!-- With local l.settings share -->
<mvt:fragment code="my_fragment_code" share="shared_data" />
<!-- With nested struct member -->
<mvt:fragment code="my_fragment_code" share="shared_data:member1:member2" />
<!-- With global variable share -->
<mvt:fragment code="my_fragment_code" share="global:shared_data" />
Fragments can be called from any interpreted template — pages, layouts, other fragments.
The Share Attribute — Pass by Reference
The share attribute is the key architectural feature. It works like pass-by-reference — the named variable is bidirectionally linked between the calling template and the fragment. Whatever the fragment writes to l.settings:fragment:share is immediately reflected in the caller's named variable after the fragment returns.
Calling template
<mvt:assign name="l.settings:customer:id" value="g.customer_id" />
<mvt:fragment code="compute_customer" share="customer" />
<!-- l.settings:customer is now populated by the fragment -->
&mvt:customer:price_group;
&mvt:customer:display_name;
Inside the fragment
<!-- Read incoming data -->
<mvt:eval expr="l.settings:fragment:share:id" />
<!-- Write results back -->
<mvt:assign name="l.settings:fragment:share:price_group" value="'retail'" />
<mvt:assign name="l.settings:fragment:share:display_name" value="'Scot Ranney'" />
Note: The share bridge is a single named variable — the entire l.settings scope is NOT automatically available inside a fragment. Data must be explicitly declared in the share contract. This is a feature, not a limitation — it forces clean interfaces between the programming and UI layers.
Experiment Results
Verified bidirectional struct sharing in a live branch:
<!-- Calling template -->
<mvt:assign name="l.settings:scot:fname" value="'Scot'" />
<mvt:assign name="l.settings:scot:lname" value="'Ranney'" />
<mvt:fragment code="hellotest" share="scot" />
<!-- After: l.settings:scot:fname = 'xScot', l.settings:scot:lname = 'xRanney' -->
<!-- Inside fragment hellotest -->
<mvt:assign name="l.settings:fragment:share:fname" value="'xScot'" />
<mvt:assign name="l.settings:fragment:share:lname" value="'xRanney'" />
Mutations to fragment:share members are reflected in the calling template's named variable immediately after the fragment returns. Full struct pass-by-reference confirmed.
Architectural Patterns
1. Input/Output Struct — Function Replacement
Seed a struct with inputs, call the fragment, read computed outputs. Clean function signature pattern.
<mvt:assign name="l.settings:pricing:base_price" value="l.settings:product:price" />
<mvt:assign name="l.settings:pricing:group" value="g.customer_group" />
<mvt:fragment code="compute_pricing" share="pricing" />
&mvt:pricing:final_price;
&mvt:pricing:discount_label;
2. Namespace Isolation — No Variable Collisions
Each fragment owns a named struct. Multiple fragments on the same page cannot stomp each other's variables.
<mvt:fragment code="load_customer_data" share="customer" />
<mvt:fragment code="load_inventory_flags" share="inventory" />
<mvt:fragment code="load_promo_rules" share="promo" />
<!-- All three structs available, fully isolated -->
3. Pipeline / Context Builder
Build up a single context struct progressively through a chain of focused fragments.
<mvt:fragment code="ctx_customer" share="ctx" />
<mvt:fragment code="ctx_pricing" share="ctx" />
<mvt:fragment code="ctx_inventory" share="ctx" />
<!-- ctx struct fully populated, available to all downstream UI code -->
Performance Rationale
ReadyTheme content sections spin up the full Miva page rendering ecosystem on every call — full module initialization, full l.settings population, associated DB lookups. Fragments render in a narrow isolated scope and skip all of that overhead.
|
ReadyTheme function_something |
Page Fragment |
| Runtime overhead | Full ecosystem per call | Isolated, lean scope |
l.settings population | Full, every call | Only share-declared data |
| DB lookups | Yes, per call | Only what the fragment explicitly does |
| Data contract | Implicit, anything goes | Explicit via share attribute |
| Admin location | Clutters content section list | Fragment admin area |
Pages with multiple function_something content sections can see meaningful TTFB improvement when migrated to fragments — each section eliminated removes a full ecosystem spin-up from the render cycle.
Migration Path — function_something to Fragments
- Identify all
function_something or widget_something content sections that produce no HTML output
- For each, create a fragment with an appropriate
share struct
- Replace the
<mvt:item name="readytheme" param="contentsection( 'function_something' )" /> call with <mvt:fragment code="fragment_code" share="my_struct" />
- Remove the old content section
Rule of thumb: ReadyTheme content sections own HTML output. Fragments own the computational layer.
Discovered and documented during a Bootstrap 4→5 conversion project. Fragment behavior confirmed by direct experiment — bidirectional struct sharing via share is live and working on current Empressa. This pattern replaces the ProContent module approach and the function_something ReadyTheme hack for computational code isolation.
https://www.scotsscripts.com/mvblog/fragments-fragment-experiments-and-claudes-wrap-up.html