Close
Stay up to date with all things Laravel, Tailwind, WordPress & PHP

Subscribe now to my e-mail newsletter and get my latest articles and project updates delivered directly to your inbox. Never miss an update.

Automatically add anchor links to Gutenberg headings

Published January 26, 2021; last updated on January 28, 2021
Automatically add anchor links to Gutenberg headings

When you have a blog, you sometimes just want to link to the start of a specific paragraph. Especially with longer articles, I like to break it up in larger chunks. Unfortunately, the Gutenberg editor doesn’t automatically add an id to every heading it generates. You’d have to do this manually. As this is a very laborious task, especially when you publish regularly, I’m happy that there is an automated way of adding this.

Below a small table of contents for this article, made possible by the automatic id‘s (the table is made manually):

  1. Add a filter to the_content()
  2. Wrapping up

Besides the increased user experience advantage, it also has a (slight) SEO benefit. Adding an id to every heading allows Google to link to individual paragraphs/sections on your page. The below screenshot is from the ‘Pages’ section in my Google Search Console and as you see, Google has linked to individual sections on my guide about cleaning up the WordPress head tag.

This also increases the user experience. By immediately offering the piece of information a user need, people are less likely to bounce back to Google, which helps to decrease your bounce rate.

Search consoles link to individual sections on a blog page by using anchor links.
A screenshot from the ‘Pages’ section in Google Search Console, which demonstrates that Google links to individual anchor links.

Add a filter to the_content()

First, we’ll add a filter to the WordPress/Gutenberg post content. After the Gutenberg output is generated (e.g. a draft is saved or a change published), we’ll apply this filter to automatically add the required id‘s.

Go to your functions.php and add the following code:

    //Filter the content
    function prefix_heading_ids( $content ) {
    
        $pattern = '#(?P<full_tag><(?P<tag_name>h\d)(?P<tag_extra>[^>]*)>(?P<tag_contents>[^<]*)</h\d>)#i';
        if ( preg_match_all( $pattern, $content, $matches, PREG_SET_ORDER ) ) {
            $find = array();
            $replace = array();
            foreach( $matches as $match ) {
                if ( strlen( $match['tag_extra'] ) && false !== stripos( $match['tag_extra'], 'id=' ) ) {
                    continue;
                }
                $find[]    = $match['full_tag'];
                $id        = sanitize_title( $match['tag_contents'] );
                $id_attr   = sprintf( ' id="%s"', $id );
                $replace[] = sprintf( '<%1$s%2$s%3$s>%4$s</%1$s>', $match['tag_name'], $match['tag_extra'], $id_attr, $match['tag_contents']);
            }
            $content = str_replace( $find, $replace, $content );
        }
        return $content;
    }

    add_filter( 'the_content', 'prefix_heading_ids' );

Now you’ve successfully added id‘s to headings in Gutenberg. Every id is derived from the heading text itself. Where a heading first looked like this

<h2>Get a list of all the categories</h2>

They now look like this:

<h2 id="get-a-list-of-all-the-categories">Get a list of all the categories</h2>

Awesome isn’t it?

Wrapping up

As you saw, we used the filter 'the_content' to filter and add the heading id‘s. This filter is called every time a page loads. This means that it may negatively impact your page performance. It’s not that heavy, but it is something small to be reckoned with. Especially if you’re using a lightweight theme, like I do, the benefits outweigh the downsides. Let me know if this has been helpful!

Stay up to date with all things Laravel, Tailwind, WordPress & PHP

Subscribe now to my e-mail newsletter and get my latest articles and project updates delivered directly to your inbox. Never miss an update.

Image Ralph J. Smit
Ralph is a designer gone developer. He happily lives in the Netherlands. His passion for good design drove him towards development, because he felt that no-code tools were too limiting. On this blog, Ralph writes the articles he would've wanted to have during his continual developer journey. → Follow on Twitter

Comments

Leave a reply

Your email address will not be published. Required fields are marked *