Unlocking Multilingual Menus: How to Make Your WordPress Full-Site-Editing Navigation Translatable with Polylang!

If you’ve ever found yourself knee-deep in PHP, wrestling with WordPress native navigation blocks, and wondering why your menus look like they’ve been lost in translation (literally), you’re not alone! Fear not! Today, we’ll transform that jumbled mess into a beautifully translatable masterpiece using Polylang.

Understanding Polylang and Full Site Editing (FSE)

Polylang is a fantastic tool for creating multilingual WordPress sites, but it isn’t fully integrated with Full Site Editing (FSE) and Block themes. The traditional WordPress menus are absent in FSE and have been replaced with navigation blocks linked to wp_navigation posts. While Polylang offers some compatibility with FSE, the removal of classic menu functionality leaves users without a straightforward solution for translating navigation content. Additionally, navigation content is stored only in the database, making it impossible to embed directly in the theme’s code translating through WordPress's native internationalization (i18n) features.

Making the navigation menus of a WordPress site translatable with the Polylang plugin can be achieved in just fifty lines of code. Here’s a step-by-step guide.

Step 1: Make wp_navigation Post Type Translatable

The navigation block is connected to a wp_navigation post where links and menu items are stored. This allows the user to display the same menu across different navigation blocks.

First, we will make this post type translatable by Polylang using the pll_get_post_types filter.

function nangka_making_wp_navigation_translatable( $post_types, $is_settings ) {
    if ( ! $is_settings ) {
        $post_types['wp_navigation'] = 'wp_navigation';
    }
    return $post_types;
}
add_filter( 'pll_get_post_types', 'nangka_making_wp_navigation_translatable', 10, 2 );

Step 2: Add a Submenu in the Dashboard

Making the wp_navigation post type translatable with Polylang serves an essential internal technical purpose. But it did not add the Polylang translation toolboxes in the Full Site Editing (FSE) Editor because Gutenberg is not invoked in the same manner within this context. As a result, we will manage translations through the list page located at /wp-admin/edit.php?post_type=wp_navigation.

For added convenience, we will create a submenu under Appearance:

function nangka_add_submenu_navigation_posts() {
    add_theme_page(
        __( 'Navigation menus', 'nangka' ),
        __( 'Navigation menus', 'nangka' ),
        'edit_theme_options',
        'edit.php?post_type=wp_navigation',
        '',
        10
    );
}
add_action( 'admin_init', 'nangka_add_submenu_navigation_posts', 100 );

You can now navigate to see the list of wp_navigation posts. On this list page, you can edit the language of a navigation content using the quick edit feature and add translations using the Polylang buttons.

Opening the wp_navigation post for editing will launch the Full Site Editing (FSE) Editor, which is the expected behavior for managing your WordPress menus. This functionality allows users to easily customize and translate their navigation items when creating a multilingual site with Polylang.

Step 3: Handle Menu Rendering with Translation

Now that we have translations for our Navigation posts, we need to load the appropriate content based on the language of the loaded page. To accomplish this, we will replace the rendering callback of the navigation block to modify the ref attribute with the translated navigation post ID before rendering the block. This ensures that users always see the correct content based on their selected language.

function nangka_navigation_render_callback_with_translation( $settings, $metadata ) {
    if ( 'core/navigation' !== $metadata['name'] ) {
        return $settings;
    }

    $default_render_callback = $settings['render_callback'] ?? null;
    $settings['render_callback'] = function ( $attributes, $content, $block ) use ( $default_render_callback ) {
        $wp_nav_id = absint( $attributes['ref'] ?? 0 );
        if ( ! empty( $wp_nav_id ) && function_exists( 'pll_get_post' ) ) {
            $wp_nav_id = pll_get_post( $wp_nav_id );
            if ( ! empty( $wp_nav_id ) ) {
                $attributes['ref'] = $wp_nav_id;
            }
        }

        return ! empty( $default_render_callback )
            ? call_user_func( $default_render_callback, $attributes, $content, $block )
            : $content;
    };
    return $settings;
}
add_filter( 'block_type_metadata_settings', 'nangka_navigation_render_callback_with_translation', 10, 2 );

Conclusion

With these three simple functions, we now have translatable navigation menus! Further step could be adding the Polylang meta widget in the FSE Editor, but it may not be crucial for every use case.

This technique can also be applied to other post types like wp_template and wp_template_part. Currently, the only way to make them translatable is by creating a theme or child theme and using patterns (see this video for a full explanation). However, it was even not possible to implement this with Navigation since its content resides solely in the database and cannot be translated directly in code.

0
Subscribe to my newsletter

Read articles from Geoffrey Brossard directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Geoffrey Brossard
Geoffrey Brossard

Versatile dev focusing on media outlets and publishers websites.