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>";
}Code language: PHP (php)

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.