More Gutenberg Doing It Wrong™: making Navigation blocks editable… sort of

By this point I have more-or-less embraced Gutenberg, a.k.a. the WordPress Block Editor. But I have not embraced Full Site Editing, a.k.a. the Site Editor, and I am not sure I ever will. I do not know who it is for, although I suspect it is for people who do not yet exist… namely, future WordPress freelancers who don’t know how to write code. The types of power users/professionals who currently spend their time in the ecosystems of tools like Divi, Elementor, Beaver Builder, etc.

Anyway… the present-day moving target of using the Block Editor as a professional site building interface has some weird gaps in its capabilities. And site navigation, in particular, is a chasm, a crevasse, a gaping maw of unfinished business.

Navigation has never been a particularly strong suit of WordPress, since WordPress was envisioned as a blogging tool and not a general-purpose CMS. Going back to the early days of constructing navigation piecemeal by setting a parent page and menu order on each individual page, to plugins like CMS Tree Page View, to the well-designed but weirdly detached custom menus that have been a staple of WordPress development lo these many years, building menus in WordPress has always been a bit “off.” I get what the core team is going for with the new Navigation blocks, but they’re still not quite flexible enough for code-centric developers like myself, and more importantly, there’s no way to just edit them directly.

The Block Editor has introduced a couple of types of “reusable” content that gets stored as standalone entries in the wp_posts table. First you have Reusable Blocks which are awesome. And then you have Navigation Blocks, i.e. the purpose of this post.

Something that’s a bit sticky about both of these types of reusable content is that there isn’t really a standalone way to edit them. And it doesn’t always make sense — despite what the core team apparently thinks — to always edit them in context (either the Site Editor or the Block Editor within a page). Because sometimes a theme developer might want to put them right into a template. (And a theme developer might not want to use the Site Editor to build their templates, which I believe will always be a legitimate approach.)

So, what do we do? Well, Bill Erickson has a great post showing how to add Reusable Blocks to the admin menu. This works incredibly well, and I’ve built it into my new base block theme. What I really like about it is that it works just the way you would expect — you get the Block Editor, but the only thing in it is the reusable content itself.

Building off of this, I thought I might be able to take the same approach, just using the wp_navigation post type instead of wp_block. And it works, at least, to the extent of getting a Navigation Blocks item to appear in the admin menu, taking you to an index page that lists all of the stored Navigation blocks, and an editing screen for those blocks.

But it’s a classic editor screen. Without the editor. You can change the title of the Navigation block, but if you want to actually edit its contents, you’re out of luck.

Digging around in the WordPress source code reveals some clunky code (includes/admin-filters.php, lines 87-89) designed specifically for the purpose of preventing direct editing of the Navigation blocks:

add_action( 'use_block_editor_for_post_type', '_disable_block_editor_for_navigation_post_type', 10, 2 );
add_action( 'edit_form_after_title', '_disable_content_editor_for_navigation_post_type' );
add_action( 'edit_form_after_editor', '_enable_content_editor_for_navigation_post_type' );

(This bit of code also reveals that even the core team has trouble telling the difference between actions and filters.)

I haven’t figured out why the core team doesn’t want us to do something it seems obvious that we’d want to do but… well, when have I ever let that stop me?

I’m still trying to figure out how to actually get the Block Editor to load. Removing the use_block_editor_for_post_type (ahem) “action” doesn’t do it, and neither does adding my own (ahem) filter that does the opposite. So, for now, we are left with the classic editor. But I did figure out a way to get it to always default to the Text tab, since the Visual tab won’t display anything. (I haven’t bothered to put in the effort to figure out how to only display the Text tab, but anyone who wades this deep ought to know what they’re getting themselves into.)

Here, then, is my variation on Bill Erickson’s Reusable Blocks code. This will get the Navigation Blocks item to appear in your admin menu:

function rm34_admin_menu_navigation() {
    add_menu_page(
        'Navigation Blocks',
        'Navigation Blocks',
        'edit_others_posts',
        'edit.php?post_type=wp_navigation',
        '',
        'dashicons-welcome-widgets-menus',
        34
    );
}
add_action('admin_menu', 'rm34_admin_menu_navigation');

And once you have that going, then you can use this to get the editor to appear, and to default to the Text tab:

function rm34_enable_wp_navigation_editor() {
    add_post_type_support('wp_navigation', 'editor');
}
add_action('edit_form_after_title', 'rm34_enable_wp_navigation_editor', 11);

function rm34_enable_wp_navigation_editor_text_mode($r) {
    global $post;
    if (get_post_type($post) == 'wp_navigation') { $r = 'html'; }
    return $r;
}
add_filter('wp_default_editor', 'rm34_enable_wp_navigation_editor_text_mode');

(Note: You could use the private _enable_content_editor_for_navigation_post_type() function instead of the add_post_type_support() line, since it does the same thing, but I’m avoiding using private functions. Even I am not that much of an iconoclast. What I’m doing here, specifically with the 11 priority, is turning the editor back on for wp_navigation posts immediately after it has been turned off, rather than on a later action as the above code excerpt from includes/admin-filters.php does.)

What you choose to do from here… well, I don’t really want to know. You need to be able to edit raw Gutenberg comment tags, because that’s what you’ll be working with. And just be aware that the code does not include the <!-- wp:navigation --> tags that wrap everything when the block actually gets used in a page.

In my case, I just wanted to get the data to paste directly into my template, so I wasn’t just stuck with a ref number for a menu I had no direct way to modify. Once I got the code, I deleted the saved Navigation block altogether.

All of which is to say, the old nav menus made a lot more sense from a coding perspective.

The pleasure (and pain) of independent discovery

Menu screenshotI was pretty proud of myself when I came up with the solution for the dropdown menus I use in the navigation bar in my current site design. They don’t require all of the cockamamie JavaScript most older solutions did. They surely don’t work in older browsers (I’m guessing), but that really doesn’t matter now. Most significantly to me, though, I had never seen a solution that worked like what I am doing.

I guess it was just a lack of looking. There’s even a term for this approach, Suckerfish Dropdowns, although I’m not doing exactly what they recommend as far as IE support is concerned. However, I haven’t actually noticed it being necessary.

Now that may well be because I’m not even trying to support versions before IE 7, what with all of the transparent PNGs I’ve got everywhere. But still, the solution I’m using works great across all of the browsers I’ve tested: Firefox 2.x, Safari 2.x/3.x, and IE 7. The only complaint I have with it is that the positioning differs slightly between the browsers: the menus appear a few pixels higher in IE than in Firefox or Safari, such that they’re jammed up against the text of the menu header. But if I move them lower, the necessary contact (or really, probably overlap) between the menu header and the menu itself doesn’t happen… and if there’s a gap of even 1 pixel between the bottom of the header and the top of the menu, the menu will disappear if you don’t mouse over it fast enough.

Geez. I read a paragraph like that last one and I just have to ask myself, what am I doing with my life???