Chat on WhatsApp
Hyvä Theme 12 min read

Magento Luma Module Not Working in Hyvä — The Diagnostic Order

Your Luma extension worked yesterday on Magento Blank. Today on Hyvä it renders nothing — or worse, breaks the page silently with no console error. The fix is not "reinstall the module" or "flush cache". There is a diagnostic order — four checks in sequence, each with a distinct DevTools signal — that resolves 95% of Luma-to-Hyvä incompatibilities. This guide walks the order using real modules we have debugged (Mageplaza, Amasty, MGS) on Magento 2.4.4 — 2.4.9 production sites. Each step has the actual symptom, the actual signal, and the actual fix — not a generic compatibility checklist.

Magento Luma Module Not Working in Hyvä — The Diagnostic Order

Luma module compatibility is the implementation gap that breaks Magento 2 extensions when a merchant migrates from the legacy Luma frontend to Hyvä on Magento 2.4.4 — 2.4.9, and the fix is rarely "contact the vendor" — it is a four-step diagnostic order that identifies which of Knockout, RequireJS, the Magento_Ui dependency tree, or the phtml inheritance chain is failing, and applies the correct port for that layer. This guide walks that order with real symptoms from production debugs on kishansavaliya.com client sites.

Hyvä ships without Knockout, RequireJS, or Magento_Ui — so any Luma module that depends on them renders nothing until ported.

That single sentence is the entire root cause of 95% of "module not working in Hyvä" tickets. The Luma extension is not broken — it is making API calls into a stack that does not exist on Hyvä. The fix is to either find the vendor's HyvaCompat module, write your own compatibility layer, or replace the JavaScript surface with Alpine.js or Magewire.

Hyvä ships ~20KB of Alpine.js where Luma ships ~400KB of RequireJS + Knockout + Magento_Ui. The bulk drop is the entire reason Hyvä exists — but it is also why every Luma module needs a compatibility layer.

The diagnostic order at a glance

StepSymptomDevTools signalFix
1Block is missing entirely, no markup in DOMNothing in console; composer show has no *HyvaCompatInstall vendor's HyvaCompat module or write your own
2Block markup renders but is inert (no interactivity)Uncaught ReferenceError: ko is not definedReplace Knockout with Alpine.js or Magewire
3JavaScript file 404s or fails to executeModule name "Magento_Ui/js/..." has not been loaded yetRemove RequireJS shim, port to ES modules or inline JS
4Block exists in layout XML but renders empty stringgetChildHtml('parent.block') returns "" — parent does not exist on HyväOverride layout XML with Hyvä's container names

Work the table top-to-bottom. Step 1 is the cheapest to check — if the vendor ships a compatibility module, install it and stop. Only descend the order if the higher-level check is clean.

Step 1 — Missing HyvaCompat module

This is the first check because it is the cheapest fix when it applies. The Hyvä team and three-quarters of the Magento extension ecosystem now ship companion modules named <vendor>_<module>HyvaCompat. If one exists for the broken module, installing it solves the problem without you writing a line of code.

How to check

composer show | grep -i hyva
# Look for entries like:
#   hyva-themes/magento2-mageplaza-blog
#   hyva-themes/magento2-amasty-shopby-graphql
#   mgs/m2-hyva-compat

composer show | grep -i <vendor>
# Compare against what's installed

If the broken module is Mageplaza_Blog, the compatibility module is hyva-themes/magento2-mageplaza-blog. If the broken module is Amasty_Shopby, look for hyva-themes/magento2-amasty-shopby. The cross-reference list lives at the public Hyvä compatibility tracker.[1]

The public compatibility list

Hyvä maintains hyva.io/compatible-modules as the canonical registry. Three statuses matter:

  • Native Hyvä — module works on Hyvä out of the box, no companion needed.
  • Compat module available — vendor or community ships a *HyvaCompat package, install it.
  • Not compatible — no compat exists, you write your own (Step 2-4 territory).

Cross-check with the GitHub repo hyva-themes/magento2-compatibility-checker, which audits an installed Magento codebase and prints a table of modules with their Hyvä compatibility status.[2] Run it before any Hyvä migration estimate.

When Step 1 fails

If composer show reveals a compat module already installed but the block still renders empty, the compat module's version may not match the parent module's version. Check composer.json constraints — Hyvä compat modules often pin to a narrow range like ^4.2 and silently disable themselves on out-of-range parents.

Step 2 — Knockout binding error

If no compat module exists or the compat module is installed but the block still does not work, drop into DevTools. The most common Step 2 symptom is the block markup is present in the DOM but completely inert — no click handlers fire, no values bind, no AJAX calls go out.

How to spot it

Open the browser console on the Hyvä page. Look for:

Uncaught ReferenceError: ko is not defined
    at HTMLDivElement.<anonymous> (mageplaza-blog.js:42)
    at applyBindings (mageplaza-blog.js:8)

That error confirms the module's phtml is emitting data-bind="..." attributes that expect Knockout to hydrate them at page load. Hyvä strips Knockout entirely, so the bindings are dead attributes — they appear in the DOM but do nothing.

How to confirm

Search the rendered HTML source for data-bind:

view-source:https://example.com/page-with-broken-module/
<!-- Look for: -->
<div data-bind="text: postTitle, attr: { href: postUrl }"></div>
<div data-bind="foreach: posts">
    <div data-bind="text: title"></div>
</div>

If you see data-bind in the rendered HTML, the phtml is the problem. Knockout would normally read those attributes, evaluate the JavaScript expressions inside, and hydrate the values. Without Knockout, the attributes are inert.

The fix — port to Alpine.js

Rewrite the phtml to use Alpine.js directives. The translation is mechanical:

<!-- BEFORE (Luma + Knockout) -->
<div data-bind="text: postTitle"></div>
<div data-bind="foreach: posts">
    <div data-bind="text: title, click: $parent.openPost"></div>
</div>

<!-- AFTER (Hyvä + Alpine.js) -->
<div x-data="{ postTitle: '<?= $block->escapeJs($title) ?>' }">
    <span x-text="postTitle"></span>
</div>
<div x-data="{ posts: <?= $block->escapeJs(json_encode($posts)) ?> }">
    <template x-for="post in posts" :key="post.id">
        <div x-text="post.title" @click="openPost(post)"></div>
    </template>
</div>

Alpine.js reads the same kind of attribute-driven directives, but the runtime is 15KB vs Knockout's 60KB + the entire Magento_Ui tree.

When state must persist — use Magewire

If the original Knockout component held server-mutating state (a wishlist toggle, a quote update), port to Magewire instead of Alpine. Magewire is server-rendered reactive PHP — the component class lives in app/code/Vendor/Module/Magewire/ and emits Tailwind-friendly HTML on every interaction.[3]

<?php
// app/code/Mageplaza/BlogHyvaCompat/Magewire/Search.php
namespace Mageplaza\BlogHyvaCompat\Magewire;

use Magewirephp\Magewire\Component;

class Search extends Component
{
    public string $query = '';
    public array $results = [];

    public function updatedQuery(string $value): void
    {
        $this->results = $this->searchProvider->search($value);
    }
}

Step 3 — RequireJS shim collision

The third common failure: the JavaScript file itself never loads or never executes. The block markup is in the DOM, no ko error appears, but the console shows a RequireJS error.

How to spot it

Uncaught Error: Module name "Magento_Ui/js/lib/view/utils/async"
has not been loaded yet for context: _
Use require([])
    https://requirejs.org/docs/errors.html#notloaded

Or:

Uncaught Error: Script error for: Magento_Catalog/js/product/storage/storage-service
https://requirejs.org/docs/errors.html#scripterror

Both errors mean the module declared a requirejs-config.js entry expecting Hyvä to load the dependency. Hyvä's requirejs-config.js registry excludes the entire Magento_Ui namespace — those modules are intentionally missing.

The fix — inline the JavaScript or port to ES modules

If the module's JavaScript is small (under 50 lines), inline it directly in the phtml inside a <script> tag. Hyvä does not ship a module loader, but it does ship a hook for inline scripts:

<script>
(() => {
    'use strict';
    const init = () => {
        document.querySelectorAll('[data-mageplaza-search]').forEach((el) => {
            el.addEventListener('input', (e) => {
                fetch('/rest/V1/mageplaza-blog/search?q=' + encodeURIComponent(e.target.value))
                    .then(r => r.json())
                    .then(data => renderResults(el, data));
            });
        });
    };
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
</script>

For larger JavaScript surfaces, port to ES modules served from view/frontend/web/js/ and loaded via a plain <script type="module"> tag. Drop the requirejs-config.js entirely on the Hyvä theme path.

The layout XML

<!-- view/frontend/layout/default.xml on the HyvaCompat module -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <script src="Mageplaza_BlogHyvaCompat::js/search.mjs" type="module" defer="true"/>
    </head>
</page>

Step 4 — phtml fall-through

The most subtle failure. The module declares its block in layout/default.xml via a reference to a parent container that exists on Luma but does not exist on Hyvä — so the block renders into nothingness.

How to spot it

The block markup does not appear in the DOM at all. No JavaScript errors fire. The layout XML appears correct. The phtml file exists. But the page shows no trace of the module.

Search the layout XML for the parent reference:

<referenceContainer name="sidebar.additional">
    <block class="Amasty\Shopby\Block\Navigation"
           name="amasty.shopby.navigation"
           template="Amasty_Shopby::layer/view.phtml"/>
</referenceContainer>

The container sidebar.additional exists on the Luma theme but Hyvä's category layout uses different container names (catalog.leftnav, page.top, main.content). Your block is being attached to a container that does not render on Hyvä.

How to confirm

Enable Magento's layout debug mode and inspect the rendered layout:

bin/magento dev:profiler:enable
# Or set 'enableLayoutDebug' to true in app/etc/env.php
# Then load the page and search the response for:
# <!-- Container 'sidebar.additional' is not rendered -->

That HTML comment appears in the response if the container does not exist in the active layout — it confirms Step 4.

The fix — override layout XML with Hyvä container names

Inside the HyvaCompat module, ship a view/frontend/layout/<handle>.xml that re-attaches the block to a Hyvä-native container:

<!-- Mageplaza_BlogHyvaCompat/view/frontend/layout/catalog_category_view.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      layout="1column"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <!-- Hyvä uses 'catalog.leftnav', not 'sidebar.additional' -->
        <referenceContainer name="catalog.leftnav">
            <block class="Amasty\Shopby\Block\Navigation"
                   name="amasty.shopby.navigation.hyva"
                   template="Mageplaza_BlogHyvaCompat::layer/view.phtml"/>
        </referenceContainer>
    </body>
</page>

The companion phtml file must also be re-themed for Tailwind — drop the Luma CSS classes (block, block-content, filter-options) and replace them with Tailwind equivalents (border-b, py-4, space-y-2).

Real modules, real diagnoses

The same diagnostic order applies across every Luma module we have debugged. Three concrete cases from production sites:

Mageplaza_Blog — Step 2 (Knockout)

The Mageplaza_Blog widget renders a recent-posts list using a Knockout foreach. On Hyvä the list markup appears in DOM but no titles render. Console shows ko is not defined. Fix: replace the Knockout component with an Alpine.js x-data block populated from the PHP block's $block->getRecentPosts() serialized to JSON. About 2-3 hours per widget.

Amasty_Shopby — Step 4 (phtml fall-through)

Amasty_Shopby's layered navigation declares itself into sidebar.additional. On Hyvä category pages, that container does not exist. The fix is a layout XML override re-pointing to catalog.leftnav plus a Tailwind re-skin of the filter template. Amasty itself ships an Amasty-HyvaCompat module[4] that does this — install it first via composer (Step 1 short-circuits the fix).

MGS_Mega_Menu — Step 3 (RequireJS shim)

MGS_Mega_Menu's dropdown JavaScript declares a requirejs-config.js shim against jquery/ui. On Hyvä, jQuery is gone entirely. Symptom: menu opens but the dropdown does not animate or stay open. Fix: rewrite the open/close logic in ~30 lines of vanilla JavaScript with addEventListener + CSS transitions, drop the entire requirejs-config.js file.

The diagnostic order is also a porting order

If you are writing the HyvaCompat module yourself (no vendor ships one), the four-step order doubles as your build order. Do them in sequence:

  1. Layout XML first — re-target containers (Step 4) so the block renders at all.
  2. RequireJS purge — strip the requirejs-config.js entries (Step 3) so no JavaScript loader errors fire.
  3. Knockout replacement — port data-bind to Alpine.js or Magewire (Step 2) so the block becomes interactive.
  4. Composer metapackage — publish it as <vendor>_<module>HyvaCompat so the next site that hits the same issue can solve Step 1 by composer alone.

That is the same order Mageplaza, Amasty, and Hyvä Themes themselves follow when shipping their compat modules — copy the pattern, not the code.

FAQ

Can I use a Luma module on Hyvä without porting?

Only if the module is a pure-backend module (admin-only, no frontend phtml) or if it renders static HTML with no JavaScript. The moment the module ships a data-bind attribute, a requirejs-config.js entry, or a web/template/*.html Knockout template, you need a compat layer.

How do I tell if a module needs Step 2, 3, or 4 without installing it?

Open the module's source on GitHub or Packagist. Search the view/frontend/ tree for data-bind (Step 2 trigger), requirejs-config.js (Step 3 trigger), and referenceContainer names (Step 4 trigger). A module that has all three needs all three fixes.

Will Hyvä 2.x change any of this?

Hyvä's checkout module shifted to Magewire as the default in late 2024, but the diagnostic order for catalog and CMS modules is unchanged through Magento 2.4.9. Watch the Hyvä Themes changelog when 2.x ships in 2026.

How long does a typical port take?

For a small widget (Mageplaza_Blog recent posts): 2-4 hours. For a complex layered navigation (Amasty_Shopby): 18-30 hours. For a full multi-step checkout extension (Amasty_OneStepCheckout): 60-90 hours. Pricing scales by JavaScript surface area, not by the module's perceived "size".

What if the vendor refuses to ship a HyvaCompat?

Build your own under a different namespace (<YourAgency>_<Vendor>HyvaCompat) and ship it as a private composer package. The vendor's license usually permits a compatibility shim — verify the module's LICENSE.txt before publishing.

Is there an automated tool?

The hyva-themes/magento2-compatibility-checker repo runs static analysis on an installed Magento codebase and prints a per-module compatibility report.[5] It catches Step 1 and partially Step 3 (it cannot evaluate Step 2 or Step 4 without a running render). Use it as the first audit pass, not the only one.

Do I need to flush cache between fixes?

Yes — layout XML changes require setup:upgrade + cache:flush. phtml changes need cache:clean layout block_html full_page. JavaScript changes need setup:static-content:deploy -f. Cache pollution is the second-most-common reason a fix appears not to work.

Citations

  1. [1] Hyvä Themes — Compatible Modules registry: hyva.io/compatible-modules.html
  2. [2] Hyvä Themes — Compatibility Checker GitHub: github.com/hyva-themes/magento2-compatibility-checker
  3. [3] Magewire documentation: magewirephp.dev
  4. [4] Amasty Hyvä Compatibility module: amasty.com/docs/doku.php?id=magento_2:hyva-compatibility
  5. [5] Hyvä Themes — Compatibility Checker tool: github.com/hyva-themes/magento2-compatibility-checker
Got a Luma module rendering empty on Hyvä?

I diagnose Luma-to-Hyvä compatibility issues on a fixed-scope sprint — full audit of the installed module list, per-module port plan, and the actual HyvaCompat code shipped on Magento 2.4.4 — 2.4.9. Fixed quote from $499 audit · $2,499 sprint · ~20h @ $25/hr. See hire me.