Adding IDs to the Gutenberg heading block

I had planned to add anchor links to headings on this site when I came across On Adding IDs to Headings by Chris Coyier.

The Gutenberg heading block allows us to manually add IDs for each heading but, like Chris, I want IDs to be automatically added to each heading.

To see an example, navigate to my /uses page and hover over a title. You’ll see a # that you can click on which will jump directly to that heading.

Chris initially used jQuery to add IDs to headings but after that stopped working he started using a plugin called Add Anchor Links.

The plugin does the job but as someone who 1) likes to have as few plugins as possible installed and 2) loves to tinker, I thought I’d try and come up with a solution that doesn’t involve installing a plugin.

Here’s the code:

add_filter( 'render_block', 'origin_add_id_to_heading_block', 10, 2 );
function origin_add_id_to_heading_block( $block_content, $block ) {
	if ( 'core/heading' == $block['blockName'] ) {
		$block_content = preg_replace_callback("#<(h[1-6])>(.*?)</\\1>#", "origin_add_id_to_heading", $block_content);
	}
	return $block_content;
}

function origin_add_id_to_heading($match) {
	list(, $heading, $title) = $match;
	$id = sanitize_title_with_dashes($title);
	$anchor = '<a href="#'.$id.'" aria-hidden="true" class="anchor" id="'.$id.'" title="Anchor for '.$title.'">#</a>';
	return "<$heading id='$id'>$title $anchor</$heading>";
}

To get this working, you’ll need to add this code to functions.php in your theme.

Here’s how the code snippet above works:

  • We’re using the render_block filter to modify the markup of the block before it is rendered
  • The render_block filter calls the origin_add_id_to_heading_block function which then checks to make sure we’re only updating the heading block
  • We then use the preg_replace_callback function to detect h1, h2, h3 etc using regex before calling the origin_add_id_to_heading function
  • The origin_add_id_to_heading function creates the markup we need: it creates the ID by taking the heading text and replacing spaces with dashes using WordPress’s sanitize_title_with_dashes function, then returns the markup we need

Let me know if you have any suggestions or improvements.

Update (24/06/20): This solution only works on posts/pages that use Gutenberg. The Add Anchor Links plugin works on all content so use this plugin if all of your content isn’t converted to Gutenberg.

Marc Jenkins Avatar

Hey, I'm Marc Jenkins.
I'm a designer & developer from the UK. I run a WordPress consultancy called 16BY9. Folks hire me to make their WordPress websites run faster and make them more money.