Tip: Add Anchor Links in WordPress Posts via Shortcode

When you’re writing long-form posts (as I frequently do at Sell with WP), it’s really helpful to be able to add anchor links in WordPress posts. These are usually added to headings so users can link directly to a section of content within your post. This makes navigation and reference far easier for your readers.

However, users don’t always know these are there, so it’s handy to add a link icon or image so that users can click it and simply get the URL with the anchor link included for easy sharing. I add these at Sell with WP for major sections – click here to jump to the bottom of an article, and you’ll see a link icon next to the header.

Adding these manually is a bit of a pain, as you have to add the h2 element, add an id, write the header, add your link image or icon, wrap a link around this icon / image that uses the id, and then close the header. It ends up looking like this when you type it:

<h2 id="anchor">Sample Heading <a href="#anchor"><img src="/wp-content/uploads/link-image.png" /></a></h2>

Sounds like a pain, huh? You could use something like the ONet Linkifier to add links to your headings automatically and create a link image when hovered. I don’t like to do this automatically since I like to create my own id and have the icon there without hovering for a visual cue, so I created a shortcode do this for me. Below is some code that you can add to your site using the Code Snippets plugin to create the same shortcode for your use.

First, you’ll need a link icon. You should use a font icon for best performance — FontAwesome is great for this, or we can use Dashicons, which is built into WordPress.

You may want to change the prefixes for these functions / shortcodes to your own prefix (I use sww_ for Sell with WP shortcodes).

 * Create a shortcode to insert a header (h2) with an anchor icon.
 * Use [h2 id="anchor"]Heading[/h2]
 * @since 1.0
function create_new_heading( $atts, $content = null ) {
    $a = shortcode_atts( array(
        'id' => false,
    ), $atts );

    // make sure dashicons is enqueued
    wp_enqueue_script( 'dashicons' );

    // generate an anchor if we don't pass one in
    $anchor = $a['id'] ? $a['id'] : sanitize_title( $content );

    // Buffer output
    echo '<h2 id="'. esc_attr( $anchor ) . '">' . wp_kses_post( $content ) . ' <a href="#' . esc_attr( $anchor ) . '"><span class="dashicons dashicons-admin-links"></span></a></h2>';
    // Return buffered contents
    return ob_get_clean();
add_shortcode( 'h2', 'create_new_heading' );

The part after add_shortcode here is h2 – this is what I use for my shortcode. You can change this to whatever you’d like if you don’t want to use this text. Just make sure it’s easy to type, as you probably don’t want to change this once it’s set up.

You’d then use this shiny new code by inserting the shortcode into your content:
[h2 id="test"]My Test Heading[/h2]

This will output HTML that looks like this:

<h2 id="test">My Test Heading <a href="#test"><span class="dashicons dashicons-admin-links"></span></a></h2>

On your page, the content will look like this when it’s displayed:

My Test Heading

Hover over or click my link icon above, and you’ll see that it’s using the test anchor that I’ve added in via the shortcode attribute. You can change whatever the id is equal to, but it should be unique on each page. For example, I can use a “read-more” id on each page, but don’t want to duplicate this within a single post or page.

If you don’t want to pass the ID / anchor in manually, that’s okay! This line of code will generate one by dasherizing the heading text:

$anchor = $a['id'] ? $a['id'] : sanitize_title( $content );

While I still have to type a bit of info into each of my articles, this shortcode saves me a lot of time within each long-form post that I write while still making it easy for my users to read, navigate, and share my content.

You can also use this shortcode for other headings, change it to an h3, adjust the shortcode name, etc. Just be sure to rename your function if you duplicate this, as you can’t have two functions with the same name.

Alternatively, you could add a shortcode that lets you enter a header size (1 through 6) as well as the id. I have a gist available for that here:

Want to read more? The documentation on the Shortcode API is fairly helpful. smile