Skip to content

Internal Link Shortcode

Those that are supposed to know such things say that internal links are really important on your websites. But just plain links are kind of ugly. So, I wrote the following little snippet that adds a [block_link] shortcode to WordPress

All of the code for this is available in a GitHub repository. Everything that follows here is loaded directly from that repo.

Block Link Shortcode

I was looking for a nice, easy way to embed internal links on a site without going to just plain text links. Lifehacker does a really good job of internal links, and I modeled this plugin a bit from their style.

What's it do?

With the code from block_link.php added to your theme functions.php you'll get a new shortcode [block_link]. You can use it in 3 different ways.

  • [block_link id=#] will embed the post or page by database ID
  • [block_link slug="permalink"] will embed the post or page by permalink
  • [block_link url="url_to_page"] will embed the post or page by trying to determine by URL. It does need to be a URL on your site.

Assuming that it can figure out what post you're trying to embed it'll kick out the HTML to build the block link.

What's it look like?

Block Link Example

I originally wrote this shortcode snippet for my site You can see a block link in action on the page for a square root curve calculator.

Be sure to look at the SASS file in this repo to see how the link is styled. The actual link is wrapped in quite a few styles, and the included SASS makes it look like the screen shot with some help from flexboxes.


It didn't seem worthwhile to split this off into a separate plugin, so I just dumped the code from block_link.php in this repo into the functions.php file for my theme. Such a small little snippet just didn't seem to warrant a separate plugin.

To use with your theme just paste the code from block_links.php into your theme functions.php file. If that doesn't make sense to you, there's a pretty good explanation on

Images, Title and Excerpts

The title comes from the post title that you're linking to.

The subtext is pulled from one of several different places, in this order. It will first look for an excerpt that you've entered for the post. If the execrpt is empty it will look to meta data from the Yoast SEO plugin. First meta description, then the Facebook description and then the Twitter description.

The same thing happens for the image. First choice is the featured image. Then it will look to Yoast Facebook and Twitter images.


Do whatever you want with the SASS in block_links.scss. What's there is what I'm using on my sites, but you can tweak it however you want.

Why not a plugin?

This was originally going to be a plugin, but since it's pretty likely you're going to want to add the CSS to your theme instead of loading a separate external file just for this little block it made more sense to just toss the code into functions.php instead.

Here’s the PHP that adds the shortcode. It goes into the functions.php file for your theme, or you could paste it into a separate plugin if you’d rather.

add_shortcode('block_link', 'block_link');
function block_link( $atts ) {
  global $post;
  $atts = shortcode_atts( [
      'id' => '',
      'slug' => '',
      'url' => ''
          ], $atts );

  /* If the ID wasn't passed we have to do a little more work
   * to figure it out
  if ( empty( $atts[ 'id' ] ) ) {
    if ( ! empty( $atts[ 'slug' ] ) ) {
      $test_post = get_posts( [
          'name' => $atts[ 'slug' ],
          'post_status' => 'publish',
          'numberposts' => 1,
          'post_type' => ['post', 'page']
              ] );
      $atts[ 'id' ] = ! empty( $test_post ) ? $test_post[ 0 ]->ID : 0;
    else if ( ! empty( $atts[ 'url' ] ) ) {
      $atts[ 'id' ] = url_to_postid( $atts[ 'url' ] );

  /* If we can't find the post, just don't show anything except maybe some
   * comments if we're in debug mode.
  if ( empty( $atts[ 'id' ] ) ) { return 'id is empty';
    return defined( 'WP_DEBUG' ) && true === WP_DEBUG ? '<-- Post not found for block link -->' : '';

  /* Time to load the post and build the layout */
  $link_post = get_post( $atts[ 'id' ] );

  if ( empty( $link_post ) ) { die('no post by id');
    return defined( 'WP_DEBUG' ) && true === WP_DEBUG ? '<-- Could not find post by ID for block link -->' : '';

  /* Start with the image if it exists */
  $image_url = get_the_post_thumbnail( $link_post, 'thumbnail' );

  if ( empty( $image_url ) ) {
    // Fallback to Yoast meta fields
    $yoast_url = get_metadata( $link_post->post_type, $link_post->ID, '_yoast_wpseo_opengraph-image', true );
    if ( empty( $yoast_url ) ) {
      // Try Twitter
      $yoast_url = get_metadata( $link_post->post_type, $link_post->ID, '_yoast_wpseo_twitter-image', true );
    if ( ! empty( $yoast_url ) ) {
      $attachment_id = attachment_url_to_postid( $yoast_url );
      if ( $attachment_id ) {
        $yoast_url = wp_get_attachment_image( $attachment_id, 'thumbnail' );
        $image_url = $yoast_url;

  /* Excerpt is next */
  $excerpt = has_excerpt( $link_post->ID ) ? get_the_excerpt( $link_post ) : '';

  if ( empty( $excerpt ) ) {
    $excerpt = get_metadata( $link_post->post_type, $link_post->ID, '_yoast_wpseo_metadesc', true );
  if ( empty( $excerpt ) ) {
    $excerpt = get_metadata( $link_post->post_type, $link_post->ID, '_yoast_wpseo_opengraph-description', true );
  if ( empty( $excerpt ) ) {
    $excerpt = get_metadata( $link_post->post_type, $link_post->ID, '_yoast_wpseo_twitter-description', true );
  if ( empty( $excerpt ) ) {
    /* Just make sure it's a string */
    $excerpt = '';

  /* And now, it's time to build the HTML */
  $permalink = get_permalink( $link_post );
  $html = '<div class="block-link">';
  if ( ! empty( $image_url ) ) {
    $html .= '<a href="' . $permalink . '">';
    $html .= '<div class="link-image">' . $image_url . '</div>';
    $html .= '</a>';
  $html .= '<div class="link-text">';
  $html .= '<a href="' . $permalink . '">';
  $html .= '<div class="link-hdr">' . get_the_title( $link_post ) . '</div>';
  $html .= '<div class="link-excerpt">' . $excerpt . '</div>';
  $html .= '</a>';
  $html .= '</div>'; // .link-text
  $html .= '</div>'; // .block-link
  $html .= '</a>';

  return $html;

This is the SASS that I use on the site I originally wrote this for. Feel free to copy and paste it, and customize it however you like.

.block-link {
    border-top: 1px solid gainsboro;
    border-bottom: 1px solid gainsboro;
    overflow: auto;
    margin: {
        top: 16px;
        bottom: 16px;
        right: 0px;
        left: 0px;
    padding: {
        top: 8px;
        bottom: 8px;
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;

    .link-image {
        flex-grow: 0;
        width: 100px;
        img {
            max-height: 100px !important;
            width: auto !important;
    .link-text {
        flex-grow: 1;
        padding-left: 8px;
        max-height: 100px;
        overflow: hidden;
        text-overflow: ellipsis;
        .link-hdr {
            font-size: 1.5em;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        .link-excerpt {
            overflow: hidden;
    a {
        color: black;
        text-decoration: none;
            color: black;
Published inCodingWordPress

Be First to Comment

Leave a Reply

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