Des asked if I was planning to release my Webmentions Directory as a plugin rather than a page template.

I hadn't considered it but he got me thinking.

I wondered about the best way to do it and came up with creating a shortcode that can be entered on any post or page, and also in a template with the do_shortcode() function.

An initial version is in place on my site and seems to be working fine. It relies on the indieweb Semantic Linkbacks plugin being installed and domain exclusions can only be added by modifying the plugin code - for now.

I will look to add a settings page for the easy addition of exclusions. For example, I have my own domain and micro.blog currently excluded from the list.

As always, you can find it on GitHub.

Status

Improving the webmentions directoryComments

When creating my webmentions author directory I originally wanted to avoid any reliance on the #indieweb Semantic Linkbacks plugin, as not everyone will be using it, and I wanted to keep things fairly self-contained.

It also meant that if you are not using webmentions you could just remove that argument from the initial query and just use the template for any comments.

Unfortunately, WordPress doesn't provide proper support for comment types as it does post types.

So, when a webmention reply is received (as opposed to likes or RSVPs etc.) WordPress the plugin converts it to a normal comment, removing its 'comment_type' value. This means it doesn't get caught if filtering for only webmentions. (Thanks to Michael for the full lowdown.)

In order to catch these replies I am forced to add a check against the 'semantic_linkbacks_type' for each comment to see if it is actually a reply.

$wmreply = get_comment_meta( $comment->comment_ID, 'semantic_linkbacks_type', true );

  then check if

$wmreply == 'reply'

The original query included 'type' => 'webmention' but this, obviously, had to be removed so that the linkbacks check could be performed against all comments.

Combining the two type checks gives the desired result but, for my purposes, there is a caveat.

I wanted the directory to list those engaging via directly from their own sites but the above also lists replies send from Micro.blog as the service supports webmentions. I have, therefore, added it to the list of exceptions not to return authors for - I had already excluded my own domains and blank urls.

The current (sanitised) version of the directory page template is available on GitHub.

Lightbulb moment

After making these changes I realised there should actually be an easier way, or a more streamlined one at least.

What if when a comment is received we immediately perform the linkbacks type check and, if true, rewrite the comment_type value back to the comments table in the database?

But that's a project for another time.

Improving the webmentions directory

On comments and webmentionsComments

In reply to: Depending on how they show up, I'll sometimes take webmentions which show up as "XXX mentioned this on YYY" and change the metadata in wp_comments...

There seems to be a lot of inconsistency in the way webmentions and microformats are handled or implemented between different platforms, especially Known and WordPress.

I've had to dive into the database on a number of occasions to add webmention as the comment type because it has not been detected properly.

While we can do this we certainly shouldn't have to.

On comments and webmentions

I currently have webmentions enabled for posts from my own site; it serves as a means to highlight relevant posts or, maybe, parts of a thread.

But it almost feels like I'm flying in the face of convention and that most wouldn't do this.

Maybe I'll filter them into their own "relevant posts" section to differentiate them from external mentions.

But, as Tantek Çelik suggested on the Indieweb Slack, they could possibly be used as much more than just relevant posts.

This, however, leads me on to other ideas. A link from one post to another just shows as "mentioned this post" in the list of comments which isn't that illustrative. I could post it as a reply (using my custom fields solution) but what if I wanted the reply link within the body rather than at the start of the post?

Markdown let's you include inline HTML so you could add the u-in-reply-to class to the link but switching to HTML when writing in markdown always feels awkward.

What if Markdown was extended to allow for microformats attributes to be added links?

Instead of just

[link_text_here](url_here "Title")

We could have

[link_text_here](url_here "Title" c:'class_names, comma_separated' r:'rel_type' )

A quick search reveals Markdown supersets like Maruku and Kramdown but these would require a different toolset.

Status

Sending likes and replies using custom fieldsComments

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' );
Sending likes and replies using custom fields