Sending likes and replies using custom fields

Historically, we would visit someone else's site to leave a comment or click a like button. Sometimes these interactions would be held within their own site's data but, frequently, they would be stored remotely - think Facebook Likes or Disqus comments.

In keeping with owning your content, part of the #indieweb ethos is to perform these actions on your own site but pass them back so they show in both locations. The original, however, is held by yourself.

The Post Kinds plugin for WordPress is designed to add support for "responding to and interacting with other sites" by implementing "kinds of posts" - specific post types with a particular purpose. So I thought I'd give it a try.

The plugin didn't work in the way I'd imagined, however, and caused issues with my theme due to the way it maps its own post types to those already in WordPress.

While new templates can be designed for how it integrates, all I really wanted it for was likes and replies so the effort required to get everything back as if should be seemed a bit counter-productive.

Back to the drawing board.

A different way

Once webmentions are enabled the actual markup required to turn a link to another page into a like or reply is actually pretty simple - specific classes are added to identify their purpose:

  • Reply = class="u-in-reply-to"
  • Like = class="u-like-of"

This would be easy enough to add to the post HTML but, as I avoid the WordPress back end as much as possible, I wanted an easier way.

What if I could automatically add this without a plugin?

As I post from my phone I starting thinking how I could pass a URL to WordPress along with the post; I was instantly reminded of the trick I used to tell it about the path to microcast episodes:

Custom fields.

A like is usually a short post so perfect for Drafts and Workflow - custom fields can be populated directly from the 'Post to WordPress' action.

Replies are more likely to be longer posts but Ulysses doesn't, natively, allow for the same behaviour. I would just have to add the custom field after posting as a draft.

Now that the link data could be included with the post how could it be added with the relevant markup to trigger webmentions?

Functions

I had already used code in functions.php to alter posts (the creation of hashtag links, for example) but this was purely a run-time change altering how the content was displayed, not stored:

add_filter( 'the_content', 'linked_hashtags' );

To trigger webmentions the links need to be included in the actual body of the post so modifying the_content wouldn't work. Luckily, WordPress includes a way to do this in content_save_pre which lets you modify a post's content before being saved to the database.

In order to build the webmention links I needed to get the page title as well as the link. The function file_get_contents() reads the contents of a file (in this case a web page) into a string and I used an example found on the web to extract the page title from that:

$str = file_get_contents($replyurl);
$str = trim(preg_replace('/\s+/', ' ', $str));
preg_match("/\<title\>(.*)\<\/title\>/i",$str,$replytitle);

Putting it together

With all the pieces in place, all that remained was to put everything together running a function to build the links when saving the post:

add_filter( 'content_save_pre', 'mentiontypes' );

Pulling the URL from the custom field is done using get_post_meta() specifying the post ID and field name. The required string is built and added to the front of the post content before being returned back to the post as the new body.

Because content_save_pre runs whenever a post is saved editing would cause the link to be re-added on each occasion. To prevent this I opted to delete the custom field using delete_post_meta() after the link is first inserted to avoid duplication.

The full code is included below. Let me know if you can think of any improvements.

Update: Jeremy Cherfas pointed out that some consider file_get_contents() to be insecure so advised using wp_remote_get() instead. The code below has been updated to reflect this change.

function mentiontypes ( $content ) {

  $id = get_the_ID();
  $types = array ( 'Reply', 'Liked' );

  foreach ( $types as $type) {
    $mentionurl = (get_post_meta($id, $type, true));

    if ( $mentionurl !="" ) {
      $url = wp_remote_get($mentionurl);
      $str = wp_remote_retrieve_body($url);
      $str = trim(preg_replace('/\s+/', ' ', $str));
      preg_match("/\<title\>(.*)\<\/title\>/i",$str,$mentontitle);

      if ( $type == 'Reply' ) {
        $mentionstr = '<p><em>In reply to: <a class="u-in-reply-to" href="' . $mentionurl . '">' . $mentiontitle[1] . '</a>...</em></p>';
      } else {
        $mentionstr = '<p><em>Liked: <a class="u-like-of" href="' . $mentionurl . '">' . $mentiontitle[1] . '</a>...</em></p>';
      }

      $content = $mentionstr . $content;
      delete_post_meta( $id, $type, $mentionurl );
    }
  }

  return $content;  
}

add_filter( 'content_save_pre', 'mentiontypes' );

Mentions

  • Colin Walker
  • Chris Aldrich