admin管理员组

文章数量:1122846

I'm converting Classic Editor content to blocks, and one of our nav menus uses a custom walker to format things very specifically. I don't see a way to use a Nav Walker on the Navigation Block, so I searched and found a filter that seems applicable: block_core_navigation_render_inner_blocks.

The filter takes one parameter, $inner_blocks, but I am finding that this variable is an object that contains a protected blocks property. While they're protected, I can't actually change anything about the $inner_blocks->blocks array's contents - meaning I can't actually change the output.

Is there a different filter or method I should be using? Ultimately I need to be able to have a <span> inside each menu item's label as well as text that is outside of the <span>. If there's an easier way to do that in the Editor, I'm all ears, but when I try to add any HTML it just outputs %lt;span%gt; visibly instead of using it as a tag.

I'm converting Classic Editor content to blocks, and one of our nav menus uses a custom walker to format things very specifically. I don't see a way to use a Nav Walker on the Navigation Block, so I searched and found a filter that seems applicable: block_core_navigation_render_inner_blocks.

The filter takes one parameter, $inner_blocks, but I am finding that this variable is an object that contains a protected blocks property. While they're protected, I can't actually change anything about the $inner_blocks->blocks array's contents - meaning I can't actually change the output.

Is there a different filter or method I should be using? Ultimately I need to be able to have a <span> inside each menu item's label as well as text that is outside of the <span>. If there's an easier way to do that in the Editor, I'm all ears, but when I try to add any HTML it just outputs %lt;span%gt; visibly instead of using it as a tag.

Share Improve this question asked Sep 25, 2024 at 21:34 WebElaineWebElaine 9,6741 gold badge16 silver badges27 bronze badges 1
  • 1 what you are trying to do is filter the core/navigation-link block. I went through the code and it seems to be rendering here - https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/navigation-link/index.php#172. Currently, there doesn't seem to be a filter that may help you. You can maybe try overriding the function. Also, it's a good prospect for an update to the core block. – Divjot Singh Commented Sep 28, 2024 at 3:16
Add a comment  | 

1 Answer 1

Reset to default 1

First I was about to suggest you'd try replacing the render_callback of the core/navigation block. The custom rendering callback would have returned a class extending the WP_Navigation_Block_Renderer class. E.g.

add_filter( 'block_type_metadata_settings', 'wpse_426956_replace_core_nav_block_renderer', 10, 2 );
function wpse_426956_replace_core_nav_block_renderer( array $settings, array $metadata ): array {
    if ( 'core/navigation' === $metadata['name'] ) {
        $settings['render_callback'] = 'wpse_426956_my_core_nav_block_renderer';
    }

    return $settings;
}

function wpse_426956_my_core_nav_block_renderer( array $attributes, string $content, WP_Block $block ): string {
    return WPSE_426956_WP_Navigation_Block_Renderer::render( $attributes, $content, $block );
}

class WPSE_426956_WP_Navigation_Block_Renderer extends WP_Navigation_Block_Renderer
{
    public static function render( $attributes, $content, $block )
    {
        return '<span>Is this where the magic happens?</span>';
    }
}

But then I realized this would be a rather steep uphill battle as the default renderer contains mostly private methods. You could probably work around the private visibility with some Reflection trickery, but that might not be worth the effort.

After a facepalm moment, it occured to me (as Divjot Singh already pointed out in the comments - let's not talk about reading comprehension) that you could just replace the core/navigation-link rendering callback. E.g.

add_filter( 'block_type_metadata_settings', 'wpse_426956_replace_core_nav_link_block_renderer', 10, 2 );
function wpse_426956_replace_core_nav_link_block_renderer( array $settings, array $metadata ): array {
    if ( 'core/navigation-link' === $metadata['name'] ) {
        $settings['render_callback'] = 'wpse_426956_my_core_nav_link_block_renderer';
    }

    return $settings;
}

function wpse_426956_my_core_nav_link_block_renderer( array $attributes, string $content, WP_Block $block ): string {
    return '<span>Yes, this is where the magic happens.</span>';
}

After some additional digging around I bumped into a question posted here earlier this year. It reminded me about the render_block_{$this->name} filter, which could also be used in this case.

add_filter( 'render_block_core/navigation-link', 'wpse_426956_render_block_core_navigation_link', 10, 3 );
function wpse_426956_render_block_core_navigation_link( string $block_content, array $block, WP_Block $instance ): string {
    return sprintf(
        '<li class="wp-block-navigation-item wp-block-navigation-link">
            <a class="wp-block-navigation-item__content" href="%1$s">
                <span class="wp-block-navigation-item__label">
                    <span>%2$s</span>%3$s
                </span>
            </a>
        </li>',
        esc_url( $block['attrs']['url'] ?? '#' ),
        esc_html( $block['attrs']['label'] ?? __( 'Nav link', 'textdomain' ) ),
        esc_html__( 'Yay?', 'textdomain' )
    );
}

The code examples above unfortunately only work on the front end as the core/navigation-link block seems to use js to render the link preview in the editor - see edit.js. Changing that is another great opportunity for an uphill battle, if you're feeling adventurous and want to replace the block's Edit component with a custom one - as Lovor offers in an answer to an older question.

本文标签: Filtering the Navigation Block