Webmentions work log 20200117

I hadn’t taken a close look at the IndieWeb comments documentation when I marked up the latest version of comments for this site last week. Today I’m going to follow some of the advice Chris had and stare closer at some prior art.

My first objective is to remove all of the unnecessary classes added to comments by WordPress through comment_class(). To aid in helpful front-end styling, things like odd, even, bypostauthor, and a handful of others are automatically added. I’m doing anything fancy, so I removed pretty much everything and went with a default of class="u-comment h-cite".

Much of the markup around this has things like u-like and u-url and h-cite and I knew there had to be some reasoning, but hadn’t bothered to actually dig in to what it all means. Today I found the documentation for microformat prefixes and everything makes a lot more sense. Go figure.

This list is mostly a reproduction of the one on that page.

  • h- for root class names like h-entry or h-cite
  • u- for URL class names like u-url. This makes the least immediate sense to me because I’m putting things like u-like and u-mention at the <article> level rather the URLs it wraps, though that might be the intention—this container has URLs.
  • dt- for datetime properties, which I use on the <time> element.
  • p- for plain text.
  • e- for element tree properties, or basically: contains HTML.

I’m happy I spent some time actually staring at this. I’ve been “familiar” in the sense that I’ve used the markup for years, but I haven’t paid close enough attention to things like p- and e- prefixes.

My initial version of comments had the comment text wrapped in a .comment-content container. I first switched that with .p-content today before reading the prefix spec. Because I made the decision to add paragraph markup to webmention content and allow things like URLs, I decided .e-content would be the most accurate fit and switched things again.

I then noticed a comment by Tantek on the IndieWeb comments page saying that .h-entry is probably better for comments written on the actual site while .h-cite is best for comments that have a canonical location elsewhere. I went ahead and added a detection for “standard” comments and injected .h-entry for those.

WordPress’s comment type detection is um, yeah.

The comment_type column can be empty, “pingback”, or “trackback” by default. I think this column alone is probably the most annoying thing about even starting with comment types. I left a comment on the associated ticket along those lines.

For now I assume comments that have no comment_type and have a meta key of protocol with the value webmention as added by the webmention plugin are in fact webmentions. Those use .h-cite and other comments with an empty comment_type use .h-entry.

Things are looking a bit cleaner in the source now, or at least making a bit more sense. I’m going to ship that and head over to watch some basketball and stew on why college athletics don’t have URLs to individual events. 🙄

I’ll plan on creating a post type this weekend that I can use for dedicated replies and likes. Sounds like a party. 🎉

Thoughts for the week's end

New Born, by Matthias Lindermayr is very chill trumpet jazz. The spaciness reminds me quite a bit of Miles Davis, who’s Kind of Blue is very much a solid part of my top 10.

I got here by poking around at the contributors to the Sepalot album, A New Cycle, another that I’ve really enjoyed lately.

🎥 Watched Train to Busan (2016) last Friday and immediately designated it a top 5 zombie flick. It may be a top 3. What an excellent time.

We followed that up with Psychokinesis (2018) from the same writer and director, Yeon Sang-ho. It was much different than Train to Busan—more comedy. I thought both movies did an excellent job of communicating the motivations of people.

📺 Watched the first two episodes of The Outsider on HBO. Really well done so far. Ben Mendelsohn is such a great lead character actor. If that’s a thing.

We also watched the first four episodes of Watchmen on HBO. Wow. What an amazing show. I’m completely unfamiliar with the comics and I’m kind of happy because every bit of the show is just blowing me away.

This Sankey diagram of imprints owned by the top five book publishers in the US is an interesting view of how you may think you’re looking at a book from a small press, but it’s really part of a bigger machine. Also fun from that site, “Plain English: A Cheat Sheet“. I made a decision to use “ebook” instead of “e-book” or “eBook” in a post the other day and briefly thought of creating a style guide page to go with it. Having that personal tip sheet seems like it could be fun.

Alphabet is nearing a valuation of one trillion US dollars. At this point, any time a government fines Google $1.6 billion for antitrust behavior, it’s as affordable for them as someone who makes $100k a year signing up for another $13/month streaming service.

See also Microsoft, Apple, Amazon, and, soon, Facebook.

Living concrete sounds really, really cool. Xenobots, self-healing robots created from frog stem cells, sound really, really terrifying. That both are partially funded by DARPA adds to any dystopian storyline, even if DARPA funds everything.

The concrete article stuck in my head today as I was breaking down the ungodly amount of styrofoam that my new desk and shelves were packed in. I’m somewhat surprised that in 2020 we don’t have some kind of solution we can drizzle onto the styrofoam and have it at least break itself down into a clump of goop that goes in the trash. Shipping that off to the landfill feels horrible.

Happy Friday!

Webmentions work log 20200115

Tonight is Pullman’s first Homebrew Website Club and I’m going to use the allocated hacking time to figure out what might be misfiring in the Webmention plugin’s always approve feature.

Side note: It feels weird typing “Webmention” rather than “webmention”. I think I’m going to use the lowercase version from now on unless I feel like being official about something.

The first hurdle I’ve run into is making two local sites communicate with each other in WordPress. I haven’t had to do this in a while, so my config is a little out of whack.

The most obvious issue is SSL verification. WordPress by default verifies SSL certificates when using things like wp_remote_get(). I have jeremyfelt.test and letsmakeplugins.test setup locally through Valet and both have self-signed certificates that WordPress doesn’t handle.

add_filter( 'https_ssl_verify', '__return_false' );

I added a filter in an mu-plugin to ignore SSL verification on the local sites.

The next hurdle is that WordPress uses gethostbyname() in wp_http_validate_url() to find the IP address of the domain and make sure it isn’t, which in this case… it is!

add_filter( 'http_request_host_is_external', '__return_true' );

I added another filter in an mu-plugin to ignore this validation so that I can do all kinds of non-secure things in my local environment. Exciting!

To make sure things were operating as expected, I followed Aaron’s guide to sending manual webmentions. Sometimes using curl is a lot nicer than working through PHP as a way to see what’s really happening. I started an Xdebug session in my editor and watched for incoming webmention requests.

When the webmention endpoint receives a new webmention, it applies a webmention_comment_data filter to process all of the comment data through a handful of things. One of these things is the endpoint’s auto_approve() method, which compares the comment data against the list of auto-allowed domains. Once all this is complete, it creates the new comment with wp_new_comment()—I’m not familiar enough with the reasoning or differences, but it’s possible that wp_insert_comment() could work here as an alternative. I’ll save that for later.

Anyhow. wp_new_comment() sanitizes things so that they look right before comment insertion. It also does the following:

$commentdata['comment_approved'] = wp_allow_comment( $commentdata, $avoid_die );

So whether the comment is already marked as approved (it was) or not, it is run through an extra handful of checks via wp_allow_comment(), including: check_comment().

In check_comment(), WordPress looks at the current comment_moderation option value and if it is set to 1 to enable comment moderation, then false is immediately returned whether or not the comment data was already marked as approved.

There’s another opportunity to filter this value, and I think it’s probably safe to do so.

$approved = apply_filters( 'pre_comment_approved', $approved, $commentdata );

By hooking into the pre_comment_approved filter, we can check to see if the comment type is a webmention and if it was originally set with an approved status. If so, then we can tell wp_allow_comment() to return true and everything works as intended.

add_filter( 'pre_comment_approved', 'jf_check_comment', 10, 2 );
function jf_check_comment( $approved, $commentdata ) {
if ( 'webmention' !== $commentdata['comment_type'] ) {
return $approved;
if ( 1 === $commentdata['comment_approved'] ) {
return 1;
return $approved;

Aside: I noticed that the documentation for the $approved parameter does not mention that trash is one of the possible values. I opened up a new trac ticket and assigned as a good first bug.

I tested this out as an mu-plugin and tried with my local domains both on and off the allowed domain list and things seem to be working as I expect. I turned this into a pull request to see if everyone else expects the same. 🙂

I’m feeling good about this. It’s at least closer to a solution than I was the other day. I also have a working local development environment for playing with webmentions, which will make future progress even smoother.

I’ll toss the filter into my custom plugin so that I can use it right away. This also clears out one of my to-dos from the last work log. I’ll probably work on a replies post type next because that seems like the next most fun. 🎉

Webmentions work log 20200113

Why not, right?

I shipped a great bug yesterday. A big thanks to Chris Aldrich for catching that and sending me a DM today to let me know.

With all my cleverness around separating comment types for display below posts, I forgot to check for cases where there was some kind of Webmention, but no regular or reply comments. That resulted in an empty array being passed to the comment__in argument for get_comments(), which then resulted in every single comment! A conversation, indeed.

In the process of fixing that, I also decided to only show each section—Likes, Mentions, etc…—if that section had at least one action. This makes more sense to me than empty headings. I also added “bookmark” as an accepted type.

There are a handful of other types left via the Semantic Linkbacks plugin and I should probably decide how to manage them.

I kind of like the idea of “read” being something I see in the WordPress dashboard, but not on the front-end. I made that the case for now along with all of the RSVP, invited, watch, follow, listen, tag, and repost actions. I’ll revisit those in the future if I think of something fun to do with them. For now, I’ll still get them in my dashboard.

The idea of “favorite” has become synonymous with “like” for me when I think about it in the context of social networks. I’m going to mirror those for now and continue to think about differences. I could almost see doing the same thing with “bookmark”, but I’ll keep them separate for the time being.

Now that I’ve adjusted what reactions show up, the get_comments_number() count is not to be trusted. Instead of displaying the number of reactions, I decided to remove the count entirely. For now, I’ll leave the “16 comments” thing alone on archive views just to confuse everyone.

At some point during the day, I was hoping for custom comment statuses in WordPress as a way to separate public and private comments in some kind of workflow. There’s an open trac ticket that’s had some traction in the past and I left some feedback. I was also happy to see a bit of recent traffic on the custom comment types ticket. I’m not sure how I want to chime in yet, but I think they would be very useful.

There is a part of me that things comments need to be approached entirely different. The first thing I would consider doing is creating a wp_comment_author table that tracks unique authors in some way. I’ve only thought through the good parts of that and not the bad, so it may be a ridiculous idea. But I would like to do things like “mark author as spam” and have that combination of name/email/website never appear again. To do that in the current data structure, you’d have to store data in strange ways to try and match things when a new comment comes in.

I’ve been working on a ridiculous plugin, the Self Sustaining Spam Stopper, to see if every day spam blocking is possible without the use of a centralized service and without having to spend a lot of time. It’s already catching most spam, though some tooling around marking words, phrases, and paragraphs as “always spam” from the WordPress admin will be much more interesting.

Things to dig into next:

  • All of these actions are great in the Semantic Linkbacks plugin, but I’ve completely lost track of where they’re standardized. I thought I remembered reading the Webmention spec the other day and not seeing them there. I need to investigate a little bit more and see how they’re created and if there are more specific intentions.
  • I’m not completely sure yet, but I don’t think the “approve & whitelist” option via the Webmention plugin is working for me. I’m still finding myself approving things received from the allowed list of domains. I need to verify / troubleshoot this.
  • Propose that “approve & whitelist” be changed to something like “approve & allowlist” or “always allow”.
  • I think I’d like a “replies” post type I can use to reply to comments on other peoples’ sites. I want to keep my main feed as standard posts without generating a kind of firehose.
  • I may extend on that to my own “likes” so that I can notify people when I like their posts.
  • And I want to make sure I have a clever way of RSVPing to things. I’m headed to the IndieWeb Summit in June and sending an RSVP from this site will be fun. I’m not even linking to it yet just in case it accidentally handles the RSVP for me. 😂

Thoughts for the week's end

Anne Trubek writes an excellent newsletter. In the most recent edition, she talks through some of the financial issues with literary awards. It focuses on Galley Beggar and their success with Ducks, Newburyport, a book released last year that was shortlisted for the Booker.

I’m a perfect audience for this because I immediately pre-ordered Ducks, Newburyport last February after reading an article in the Irish Times that highlighted it with a handful of others from independent presses. I have a strange draw to “It’s 900 pages, it’s one sentence long…“. I haven’t read it yet, but absolutely will in 2020.

Anyhow. It’s nuts to think about the logistics required to play in the world of big prizes. Sam Jordison, one of Galley Beggar’s founders, wrote an interesting piece in October that shed some light on the money and time required by the publisher and author once a book is nominated. That piece was particularly critical of the Booker’s handling of the dual prize that was awarded this year.

I’ll avoid recapping the entire story here. Instead, I definitely recommend checking out Anne’s newsletter.

In the meantime, I went all in and actually subscribed to Galley Beggar’s “Galley Buddy” service, so I’ll be getting 4 of their books over the next year. If you find yourself tempted to do the same thing, let me know and we can have a focused book club.

I’ve been using VIM ever since I can remember knowing what it was. Let’s call it 20 years?

Only today did I bother to look up how to search and replace text. Only today! Even though I’ve spent countless hours adjusting domain names in nginx config files. Even though I know VIM is literally a text editor. Even though I’ve actually watched this amazing video in which VIM’s creator, Bram Moolenaar, walks through all of the crazy things you can do in VIM.

I never bothered to try :%s/search/replace/g. Imagine that.

I had a moment where I realized I’ve been using DNSimple to manage my DNS for about 9 years. A genuine feeling I have is how fantastic of a service it’s been and how I’m happy it hasn’t gone away and hasn’t changed in any strange way.

Of course, as soon as I thought that I started calculating how much money I had spent on this service alone over the last 9 years and it’s somewhere in the neighborhood of $1200-$1500. That’s a lot of money!

It’s disappointing that we took the idea of property from the physical world and transferred it directly to the digital world. For things like address management, it’d sure be nice if there was a viable commons.

On the last day before returning to work for the first time this decade, I received notice of a credit added to Happy Prime‘s Slack account due to one team member’s inactivity—me!

This must mean I’ve done the best among the three of us at keeping Slack closed for the previous two weeks. 🙂

Here’s an idea to carry into 2020:

You cannot create or curate a community where everyone is welcome. It’s an incoherent, fake goal. It sounds nice but it is categorically impossible. Some people, by their very presence, make a space unsafe and unwelcoming to others.

Holden Shearer, Twitter, January 2, 2020

This is an interesting thread to think about. I know I’ve struggled in the past with trying to be welcoming to new community members while also identifying who’s “offhand” remark is going to become a problem and figuring out how to tell them it’s not welcome. Something to strive toward!

I’ve realized more and more that I want something I can only describe as inline blocks in Gutenberg. That may solve some of the pains I have with “block editor” vs “text editor” and one day allow for a text editor inside a block—maybe?

I’m also ruminating on WordPress being the “operating system for the web” and how a good OS would probably allow for a plethora of editors. 🤔

Just fucking blog” is pretty good advice from Bix. [via Joho the Blog]

See, blogging is easy” is an excellent sentiment from Evan Williams. It’s nice to see one of the originals back and using the tool he founded.

Of course there’s a but!

Medium is one of those centralized hosted writing services that could choose to implement its proprietary features (e.g. “claps”) using decentralized protocols and open web standards so that the general web can participate and benefit.

Twitter is another: “likes”, “retweets”.

WordPress.com is another: “reblogs”, “likes”.

Granted, there’s a lot of work involved, but it’d be fun!

📺 We finished season one of the Politician on Netflix this week. It was really, really good. Such great characters and almost like a prequel to House of Cards. Looking forward to where things go in Season 2 while also hoping it has a solid arc.

📺 And we finished the Dracula mini-series—3 long episodes—on Netflix. It was somewhere around 95% really well done. I’d feel weird giving away the 5% that I thought was horribly done, so I’ll be quiet. I guess ping me if you want to share rants.

Oh, and if this comes back for a season 2, I’ll take back most of the nice thoughts I have about the show.

📚 I finished Terry Pratchett’s Equal Rites this week. It’s the 3rd of the Discworld series and 1st of the Witch series. I love the idea of headology already and I’m very much becoming a Terry Pratchett fan. Mort is next on the list.