Navigation with a top-level Page List produces invalid ul > ul markup
Description
When a top-level core/page-list is placed between navigation items, the Navigation block can render a <ul> directly inside its navigation container <ul>:
<ul class="wp-block-navigation__container">
<li class="wp-block-navigation-item">Home</li>
<ul class="wp-block-page-list">
<li class="wp-block-pages-list__item wp-block-navigation-item">Blog</li>
</ul>
<li class="wp-block-navigation-item">Last</li>
</ul>That violates the HTML content model for ul: its children may be li or script-supporting elements, not another ul. It can also result in inconsistent list semantics for assistive technologies.
The issue occurs because WP_Navigation_Block_Renderer::get_inner_blocks_html() treats an inner block as a list item when its rendered markup contains any LI tag. A top-level Page List therefore opens the Navigation container list, but Page List still emits its own outer ul.
The Page List renderer already knows when it is a Navigation child (showSubmenuIcon is present in its block context). It only suppresses its outer list when core/isInsideSubmenu is true.
Related discussion: #81282.
Step-by-step reproduction instructions
- Create a Navigation block with no menu reference, or edit a navigation menu.
- Add a Navigation Link.
- Add a Page List as a top-level Navigation child.
- Add another Navigation Link after it.
- Render the page and inspect the Navigation markup.
For example:
<!-- wp:navigation {"layout":{"type":"flex","justifyContent":"space-between"}} -->
<!-- wp:navigation-link {"label":"Home","url":"/","kind":"custom"} /-->
<!-- wp:page-list /-->
<!-- wp:navigation-link {"label":"Last","url":"/last","kind":"custom"} /-->
<!-- /wp:navigation -->Actual result
core/page-list emits an outer ul even though it is a direct Navigation child. The Navigation renderer then places that ul inside .wp-block-navigation__container, alongside the surrounding li items.
This also makes the Page List a separate flex child, so justify-content: space-between, wrapping, and item spacing do not treat its generated page items as peers of adjacent Navigation links.
Expected result
Every top-level navigation destination should participate in the same list and layout contract. A Page List should expand into peer li elements at its insertion point; a nested page list belongs inside the li for its parent page:
<ul class="wp-block-navigation__container">
<li class="wp-block-navigation-item">Home</li>
<li class="wp-block-pages-list__item wp-block-navigation-item">
About
<ul>
<li class="wp-block-pages-list__item wp-block-navigation-item">Team</li>
</ul>
</li>
<li class="wp-block-navigation-item">Last</li>
</ul>In particular, the navigation container should not contain a direct child ul produced by a top-level Page List.
Possible minimal fix
One candidate is to keep the existing meaning of $is_nested intact and only change Page List's wrapper decision:
$wrapper_markup = ( $is_nested || $is_navigation_child )
? '%2$s'
: '<ul %1$s>%2$s</ul>';This would let a top-level Page List in Navigation emit its generated li items into the Navigation container, as it already does for a Page List inside a submenu.
There is a compatibility consideration: omitting Page List's wrapper also omits the wp-block-page-list wrapper class. An alternative is to address this in the Navigation renderer by defining an explicit item/fragment contract for children. Either approach should preserve standalone Page List rendering and submenu overlay-color behavior.
Environment info
WordPress 7.1
Confirmed local reproduction
This was also reproduced on a running local WordPress 7.1 environment at http://localhost:8884/, not only by reading source. Its published wp_navigation menu contains a top-level Page List, and the rendered home page contains:
<ul class="wp-block-navigation__container ...">
<ul class="wp-block-page-list">
<li class="wp-block-pages-list__item wp-block-navigation-item">...</li>
</ul>
</ul>The local environment renders this shape in two Navigation instances on the same page.
References
- HTML
ulcontent model: https://html.spec.whatwg.org/dev/grouping-content.html#the-ul-element - Navigation renderer:
WP_Navigation_Block_Renderer::get_inner_blocks_html() - Page List renderer:
render_block_core_page_list()
Source: WordPress/gutenberg