Skip to content

[3.0] Stop drawing an empty tab menu with an unresolved label - #9407

Merged
live627 merged 2 commits into
SimpleMachines:release-3.0from
albertlast:3.0/generic-menu-empty-tabs
Aug 10, 2026
Merged

[3.0] Stop drawing an empty tab menu with an unresolved label#9407
live627 merged 2 commits into
SimpleMachines:release-3.0from
albertlast:3.0/generic-menu-empty-tabs

Conversation

@albertlast

Copy link
Copy Markdown
Collaborator

Description

Admin and moderation pages whose menu has no title of its own drew a mobile tab menu containing nothing, labelled with the literal text {label} Menu. Straight off Admin → Scheduled Tasks:

<a class="mobile_generic_menu_1_tabs">
	<span class="menu_icon"></span>
	<span class="text_menu">{label} Menu</span>
</a><ul class="dropmenu dropdown_menu_1_tabs">
		</ul>
Two lists with the same name

The block is guarded on Utils::$context['tabs'] but draws $tab_context['tabs']:

if (!empty(Utils::$context['tabs'])) {
	…
	foreach ($tab_context['tabs'] as $sa => $tab) {

They are not the same list. Utils::$context['tabs'] is set as a side effect of drawing the menu itself, from whichever area is selected:

// template_generic_menu_dropdown_above()
if (!empty($area['selected']) && empty(Utils::$context['tabs'])) {
	Utils::$context['tabs'] = $area['subsections'] ?? [];
}

$tab_context['tabs'] is only assembled from it inside the if (!empty($tab_context['title'])) branch further up. So on a page that has subsections but no tab title, the first is full and the second was never built — the guard passes, the loop finds nothing.

And why the label stayed raw

$tab_context['title'] was never set either, so the call passes ['label' => null]. Localization\MessageFormatter::formatMessage() filters its arguments before handing them over:

->format(array_filter($args, 'is_scalar'))

is_scalar(null) is false, so the argument is dropped, and ICU leaves an unmatched placeholder in the output rather than substituting an empty string. Reproduced directly — ['label' => null] through intl gives " Menu", but with the argument filtered out it gives "{label} Menu".

The guard now names the list that actually gets drawn, and the label falls back to '' so the same thing cannot happen if a menu ever gets tabs without a title.

Checked

Four pages on the running forum. {label} no longer appears anywhere, Scheduled Tasks draws no #adm_submenus at all, and the pages that do have tabs are untouched:

<span class="text_menu">Reported Members Menu</span>
<span class="text_menu">Manage Members Menu</span>
<span class="text_menu">Features and Options Menu</span>

Found by sweeping every rendered page of a stock forum for unsubstituted {placeholders}. This is one of the three the sweep turned up.

GenericMenu.template.php is also touched by #9392, which makes this element a nav landmark; the two do not overlap.

Issues References (Fixes|Related|Closes)

Related to #7933

Admin and moderation pages whose menu has no title of its own drew a mobile
tab menu containing nothing, labelled with the literal text "{label} Menu".

The block is guarded on Utils::$context['tabs'] but draws
$tab_context['tabs']. Those are not the same list.
Utils::$context['tabs'] is set as a side effect of drawing the menu itself,
from the selected area's subsections, while $tab_context['tabs'] is only
assembled from it inside the "does this menu have a title" branch above. On a
page with subsections but no tab title - Scheduled Tasks, for one - the first
is full and the second was never built, so the guard passed and the loop had
nothing to iterate.

The label came out raw for the same reason: $tab_context['title'] was never
set, and Localization\MessageFormatter drops non-scalar arguments before
formatting, so a null one leaves its placeholder in the output rather than
resolving to an empty string.

The guard now names the list that gets drawn, and the label falls back to an
empty string. Pages that do have tabs are untouched: Manage Members, Features
and Options and Reported Members all still get their menus.

Signed-off-by: Mathias Papenbrock <mathiaspapealbert@hotmail.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
@albertlast

Copy link
Copy Markdown
Collaborator Author

Pushed a second commit.

Sweeping the admin area with the first commit applied turned up an Undefined array key "label" on ?action=admin;area=current_theme, which the change had exposed rather than caused. Themes::execute() sets four tabs on tab_data, each carrying only a description; the labels are meant to be filled in by the loop above, which walks Utils::$context[tabs]. current_theme is its own admin area with no subsections, so that array is empty, the loop never runs, and the four tabs stay unlabelled. Under the old guard the block was skipped for the same reason, so nothing was drawn and nothing complained.

An unlabelled tab cannot be drawn, so it should not count towards there being anything to draw either. Filtering first, then guarding on the result, handles both: pages with real tabs are unaffected, current_theme draws nothing at all. The disabled check folds into the same filter, and template_generic_menu() already skips unlabelled areas the same way a few lines above.

Verified on ?action=admin;area=theme;sa=list (all four tabs still render: Manage and Install, Theme Settings, Member Options, Modify Themes) and on ?action=admin;area=current_theme (no tab menu, and the error log stays clean).

An area with no subsections of its own leaves $tab_context['tabs'] entries
unlabelled, because the loop that fills labels in only walks the areas the
menu knows about. Drawing one is an undefined key notice and an empty link,
so filter them out first, the way the areas above already are. Filtering
before the guard keeps the wrapper from being drawn for nothing.

Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
@albertlast
albertlast force-pushed the 3.0/generic-menu-empty-tabs branch from de51d24 to 4d2a93a Compare August 8, 2026 21:55
@jdarwood007 jdarwood007 added this to the 3.0 Alpha 5 milestone Aug 8, 2026
@live627
live627 merged commit 6c08e1d into SimpleMachines:release-3.0 Aug 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants