In the module Menu Assignment tab (com_modules, "Only on the pages selected"), the tree of menu items renders correctly as long as every branch is at most 2 levels deep. As soon as a branch goes 3 levels deep and then returns to a shallower sibling, the HTML nesting breaks: the visual tree collapses into a flat list from that point onward, and the built-in "None"/"All" buttons (which operate via document.querySelectorAll('.treeselect input')) stop affecting the items that fell outside the broken structure, since they are no longer valid descendants of .treeselect in the DOM.
This is not related to volume/performance — it reproduces with a handful of items, as long as the depth pattern is right. It's a pure HTML-generation logic bug.
Affected file
administrator/components/com_modules/tmpl/module/edit_assignment.php
Root cause
The loop that builds the <ul>/<li> structure from each $link->level closes tags asymmetrically relative to how it opens them:
if ($prevlevel < $link->level) {
echo '<ul class="treeselect-sub">';
} elseif ($prevlevel > $link->level) {
echo str_repeat('</li></ul>', $prevlevel - $link->level);
} else {
echo '</li>';
}Going up a level (nesting deeper): opens <ul class="treeselect-sub"> but deliberately leaves the parent <li> open (correct, since the <li> must wrap the new <ul>).
Going down a level (returning to a shallower sibling): closes str_repeat('</li></ul>', $prevlevel - $link->level). For a drop of exactly 1 level, this closes one </li> (the deepest item) and one </ul> (its container) — but it never closes the <li> of the ancestor node that was left open when the tree went deeper. The next sibling <li> is then emitted "raw," without a <ul> wrapping it, and ends up nested inside the ancestor's still-open <li> instead of being its properly wrapped sibling.
The bug appears specifically at the transition from a level-3 leaf back to a level-2 sibling (or any comparable "return to shallower" transition), and is cumulative: each additional 3-level branch that follows adds one more unclosed <li>, worsening the visual collapse progressively further down the list.
Steps to reproduce
Create a menu with a structure like:
Item A (level 1)
├─ Item B (level 2)
├─ Item C (level 2)
│ ├─ Item C.1 (level 3)
│ └─ Item C.2 (level 3)
└─ Item D (level 2) <-- this is where the break happens
Go to Content → Site Modules → (any module) → Menu Assignment.
Select "Only on the pages selected."
Observe the tree: Item B and Item C (with its two level-3 children) render with correct indentation. Item D — and every item after it — loses tree styling and renders as a flat, unindented list.
Click "None": only the checkboxes that were still correctly nested inside .treeselect get unchecked; items after the break point (like Item D) remain checked because they've fallen outside the .treeselect container's DOM scope.
Real-world data sample confirming the pattern
From a production site with a "Campanha da Fraternidade" menu (anonymized column names kept, lft/rgt are consistent/uncorrupted — this rules out nested-set data corruption as the cause):
id title level parent_id
1672 As faces da violência: a criança 2 1130
1673 Voltar 3 1672
1674 Cuidar do meio ambiente é uma ação diária 3 1672
1675 O cuidado com a criação... 3 1672
1676 Campanha da Fraternidade 2017... 3 1672
1677 Exposição no Museu da Vida 3 1672
3029 Superação da Violência e Campanha... 2 1130 <- breaks here
The transition from 1677 (level 3) to 3029 (level 2) is exactly the level-3-to-level-2 drop described above. The same pattern repeats at every subsequent level-3 branch in the same menu (e.g. after item 1670 and after item 1132), each occurrence compounding the visual breakage further down the tree.
Expected behavior
The tree should render with correct nesting/indentation regardless of how many levels deep a branch goes, and bulk actions ("All"/"None"/filter) should affect every checkbox in the tree.
Suggested fix
Close the ancestor's <li> as well when dropping back to a shallower level:
} elseif ($prevlevel > $link->level) {
echo str_repeat('</li></ul>', $prevlevel - $link->level) . '</li>';
}This closes the ancestor <li> left open by the "going deeper" branch, so the next sibling is correctly wrapped as part of the same <ul> rather than nested inside a <li> that should already have been closed.
Environment
Joomla 5.x
Reproduced locally on XAMPP, PHP 8.2.12
Not related to max_input_vars, browser, or number of total menu items — purely a function of tree depth/shape
| Labels |
Removed:
?
|
||
| Labels |
Added:
No Code Attached Yet
|
||
| Labels |
Added:
Information Required
|
||
Can you post a screenshot please as I dont see the problem you describe (unless I missed something)