Skip to content

Navigation block ref is always stripped when creating a child theme, causing menu references to be lost/mismatched #866

Description

@goutetsuguma

Description

When creating a child theme via the "Create child theme" feature, the ref attribute is unconditionally removed from every core/navigation block in every exported template part — regardless of any user setting.

This causes navigation blocks that were pointing at distinct menus (e.g. a header menu vs. a footer menu) to lose that association. After WordPress falls back to resolving a navigation without an explicit ref, the wrong menu can end up being displayed (for example, the header ends up showing what was previously the footer's menu).

Steps to reproduce

Reproduced with the default Twenty Twenty-Four theme (no other plugins involved), so this is not theme-specific:

  1. Create two distinct wp_navigation posts (e.g. "Header Menu" and "Footer Menu").
  2. Set the header template part to reference one (<!-- wp:navigation {"ref":4} /-->) and the footer template part to reference the other (<!-- wp:navigation {"ref":5} /-->).
  3. Use Create Block Theme's "Create child theme" action to generate a child theme.
  4. Inspect the exported child theme's parts/header.html and parts/footer.html.

Expected: each Navigation block keeps referencing its original menu (ref:4 / ref:5).

Actual: both ref attributes are gone:

<!-- header.html -->
<!-- wp:navigation /-->

<!-- footer.html -->
<!-- wp:navigation /-->

No error is raised — the reference is silently lost. In a real site, this typically manifests as the header ending up showing what was previously the footer's menu (or vice versa), once WordPress core falls back to resolving a navigation without an explicit ref.

Likely cause

In includes/create-theme/theme-templates.php:

private static function eliminate_environment_specific_content_from_block( $block, $options = null ) {
    ...
    // (optionally) remove ref attribute from nav blocks
    if ( 'core/navigation' === $block['blockName'] && isset( $block['attrs']['ref'] ) ) {
        if ( ! $options || ( array_key_exists( 'removeNavRefs', $options ) && $options['removeNavRefs'] ) ) {
            unset( $block['attrs']['ref'] );
        }
    }

When $options is null, the ref is removed unconditionally.

In includes/create-theme/theme-create.php, create_child_theme() calls:

CBT_Theme_Templates::add_templates_to_local( 'user', $new_theme_path, $theme['slug'] );

...without passing an $options argument, so $options defaults to null all the way down to eliminate_environment_specific_content_from_block(), and the ref is always stripped.

This differs from clone_current_theme() in the same file, which explicitly passes:

$template_options = array(
    'localizeText'   => false,
    'removeNavRefs'  => false,
    'localizeImages' => false,
);

...so navigation refs are preserved when cloning the current theme. It looks like create_child_theme() was simply never updated to pass the same (or an equivalent) $options array.

This seems related to, but distinct from, #574 (fixed via #572), which addressed the "Save Changes" panel flow reprocessing all templates instead of only changed ones. The "Create child theme" flow appears to be a separate code path that wasn't covered by that fix.

Environment

  • Create Block Theme: 2.10.1 (originally observed), reproduced against current trunk
  • WordPress: 7.1
  • Theme: reproduced with the default Twenty Twenty-Four theme via WP Playground — confirms this is not specific to any particular theme; originally reported against a third-party theme ("X-T9")

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions