Current status:

  • Created a working way to submit JSON formatted blogposts to this site, code on GitHub
  • Included that in my earlier scripts to create posts from my feed reading, that I now no longer then have to post by hand.
  • Created a Microsub client to replace my feed reader, in which I can respond directly from within the page I am reading, and do so to different websites I maintain.
  • Combined the same basic script with a local webform so I can very quickly post something. I don’t think I will be using this possibility much but it was a good way to add a front-end to the micropub script first and fast.
  • Can take a local markdown file written in Obsidian and post it as html to my site. This is by far the most useful to me
    • I write my blogposts in Obsidian, drafts live in a specific writing folder. They have two inline data fields, status and tags. While writing a note has status ‘writing’, when it is ready to publish I set the status to ‘draft’.
    • Within Obsidian I use the same status field to create a dynamic overview of posts being written, ready to publish, and previously published (using the DataView plugin).
    • When I’m ready to post, I hit a hotkey which launches my PHP script. It looks at all files in the specific writing folder and checks for files that changed within the last few hours and if those contain a status field ‘draft’. For those that do it transforms the markdown in those files to html, and then posts that to my site, using the tags in the other data field to tag and categorise the post. It also sets the status field in my notes from ‘draft’ to ‘posted’.
    • I could also run the script every hour or so using a cron job, so that anything posts automatically, while I go on with my other work.
  • Use the form in my feedreader to save an article in markdown to my notes in Obsidian with my rationale and some remarks.
  • Use the form in my feedreader to post an annotation to (similarly formatted to posting it to my notes in Obsidian)


Local first, personal, narrow band
See blogpost.

Narrow band means:
my preferences can be treated as default inputs
my tasks are predictable to me
together they are functions with parameters, aka code.


Micropub standard
IndieWeb wiki on Micropub
Tips from Jan Boddez (in Dutch)
Jamie Tanna’s work on his personal micropub client
Jamie Tanna’s tool to get authorisation tokens manually, great for testing/development.
Parsedown, which I use to translate markdown files written in Obsidian, to HTML for my site.

I am trying to add an additional RSS feed, using a different template, to my blog. Most documentation on seems to be aimed at replacing an existing feed, or alter its contents.

The additional feed is meant to fulfill Peter’s request to have a comments feed that shows only real comments, not all the likes, reposts etc I also receive through WebMentions. It is a very logical request, but I also want to keep the original comments RSS feed that includes all interaction with content on this site. So I need to add a new RSS feed. doesn’t really contain any complete step-by-step explanations for anything, including for adding customised RSS feeds. It also doesn’t have any info on excluding pingbacks from comment feeds, which would be similar to what I’m trying to do. I tried stuff based on snippets of documentation I did find, but couldn’t put those snippets together into a coherent path to a solution.

Then I found a guide at WPBeginner dot com (WP beginner, that’s me, even though I’ve been a WP user and tinkerer since 2004) It’s from 2016 so maybe not concurrent with today’s version of WP. Following their explanation, I added the following to my child theme’s functions.php:

add_action('init', 'extracommentsRSS');
function extracommentsRSS(){
add_feed('commentsdupe', 'extracommentsrssFunc');

function extracommentsrssFunc() {
get_template_part('rss2', 'commentsdupe');

The first part adds the new feed to WP, the second function tells it where to look for the template for the feed. That template, named rss2-commentsdupe.php, is located within the child-theme folder.

The URL for the feed now works, however it first prompted a download of an empty file due to the template file having a wrong name. With that name corrected (based on Jan’s comments below), it does load the template correctly.

The template itself still has issues (meaning it doesn’t work as intended at all): the while has_comments() loop provides no results, as it does not get passed any variables. Because the get_template_part is not provided with those variables before getting called. Jan suggested adding the query to the template. Did that, but now struggle to find a way to lift the comments from the query result.

The query below gets the latest 20 approved reactions on my site of the type ‘comment’ (as opposed to e.g. pingback or webmention):

$query = new WP_Comment_Query( array( 'status' => 'approve', 'type' => 'comment', 'number' => 20, 'orderby' => 'commentdate_date' ) );

The result if I print it as arrays, contains 7 elements (the query, the query arguments, default query arguments (?), an empty one, an array with the 20 requested WP comment objects, and two more empty ones).
The query works as intended, but now I do not know how a) to access the 5th element, and b) handle the WP comment objects within it. What seems to be intended functions for it (have_comments(), the_comment()) don’t seem to work.

The below code at least does not work. If I test it like this, it never enters the while loop, so never echoes ‘BOE’

while ( $query->have_comments() ) :
echo 'BOE';
$comment_post = get_post( $comment->comment_post_ID );
$GLOBALS['post'] = $comment_post;
?> etc.

After some more suggestions by Jan Boddez, ao that have_comments() doesn’t work for wp_comment_query, I then established that get_comments to query the comments, and then a foreach to loop through them works the way I need it to.

$query = get_comments( array( 'status' => 'approve', 'type' => 'comment', 'number' => 20, 'orderby' => 'commentdate_date' ) );

foreach ($query as $comment):
$comment_post = get_post( $comment->comment_post_ID );
$GLOBALS['post'] = $comment_post;

Once I had that the original feed template could be fully re-used, and now validates:

[Valid RSS]

My current, October 2019, WP set-up is:

Theme: Sempress (with adaptations in a child theme I created)


  • Akismet Anti-Spam
  • Bridgy, for posting to Twitter from my site (and through the service getting back-feed from Twitter and Mastodon). I should be using Syndication Links as a replacement, but haven’t installed that yet.
  • Category to Pages WUD, to add categories to pages, which I use to make my 1-man ‘wiki’
  • Classic Editor, as some of the IndieWeb plugins don’t work with WordPress block structure, so I retain the old posting interface
  • IndieAuth
  • IndieWeb
  • Mastodon Autopost, to post to Mastodon from my site
  • Micropub, to allow me to post to my site using various clients such as Indigenous on my Android
  • Post Kinds, to create different types of postings, including likes, bookmarks etc.
  • Posted Today, to create ‘on this day in …’ lists of my older posts
  • Postie, to post on this site by sending an e-mail
  • Semantic-Linkbacks, to present mentions, likes etc from others in a nicer way
  • Simple Location, allows me to add locations to postings. Don’t actually use it.
  • Ultimate Category Excluder, allows me to keep specific categories on/off the front page, in/out the RSS feed, search or archive overviews. I use this a lot, creating different content streams
  • WebMention, to let other sites know I link to them, to hear from other sites they link to me
  • WebSub, not sure why I’m using it or what it does
  • Widget Context, to keep some widgets off single post pages as they interfere with correct microformats interpretation (machine readability)
  • Wordfence Security
  • Yarns, a microsub server. Not actively in use yet. I’m trying to set-up one of my existing WP test site as my microsub server. As I don’t want all my feed subscriptions in my live site’s WP database. So ideally I have the subscriptions in another site, while interacting with them from this site.

Ten of these plugins are IndieWeb related, and form a collective block of functionality.

I post in three languages on this site: English (mostly), Dutch, German (sometimes).
To better allow language detection I have added mark-up for it in various places. I also add translation links to the RSS feed items that are not in English.

Note: All my non-English posts are in specific categories that provide the language (e.g. nederlands for Dutch, and deutsch for German)

Adaptations made:

Translation links in RSS feed items

In functions.php of my (child)-theme I added (based on this code by Jan Boddez):

add_filter( 'the_content_feed', 'my_content_feed' );
function my_content_feed( $content ) {
	global $post;
$testurl = get_permalink($post);
if ( has_category( 'nederlands', $post->ID)) {
     $basetranslate = '';
     $testedurl = urlencode($testurl);
     $basetranslate = $basetranslate.$testedurl;
     $addedlink= '<br/><a href="'.$basetranslate.'">machine translation into English</a><br/>';
     $content = $content.$addedlink;
if ( has_category( 'deutsch', $post->ID)) {
     $basetranslate = '';
     $testedurl = urlencode($testurl);
     $basetranslate = $basetranslate.$testedurl;
     $addedlink= '<br/><a href="'.$basetranslate.'">machine translation into English</a><br/>';
     $content = $content.$addedlink;

	return $content;

Setting page wide default language

The function for setting a page wide default considers two cases: when displaying a single post, and when displaying a category archive.
In functions.php of my (child)-theme I added:

function tonsempress_language_attributes($langtoets){
  // ton: if called from single or cat will have right language otherwise default
$langtoets ="en-us";
if (is_single()){
if ( in_category('nederlands') ) {
$langtoets = "nl-nl";}
if ( in_category('deutsch') ) {
$langtoets = "de-de";}
if (is_category('nederlands')){$langtoets = "nl-nl";}
if (is_category('deutsch')){$langtoets = "de-de";}
  // return the new language attribute
  return 'lang="'.$langtoets.'"';

add_filter('language_attributes', 'tonsempress_language_attributes');

Setting item language on front page

Items on the front page (!) that are in Dutch or German will get a span with their language attribute set accordingly. I changed this in index.php of the child theme, where it considers if a Dutch or German category post is being displayed, in the WordPress Loop:

<?php /* Start the Loop */ ?>
<?php while ( have_posts() ) : the_post(); ?>
	/* Include the Post-Format-specific template for the content.
	* If you want to overload this in a child theme then include a file
	* called content-___.php (where ___ is the Post Format name) and that will be used instead.
<?php /* if in Dutch or German categories, on the homepage added Oct 2019*/?>
	<?php  if ( is_home() ) {
                    if ( in_category( 'nederlands' ) ) { ?><span lang="nl-nl"><?php }
                    if ( in_category( 'deutsch' ) ) { ?><span lang="de-de"><?php }
	get_template_part( 'content', get_post_format() );

	/* if in Dutch or German categories, on the homepage added Oct 2019*/
		if ( is_home() ) {
                     if ( in_category( 'nederlands' ) ) { ?></span><?php }
                     if ( in_category( 'deutsch' ) ) { ?></span><?php }

<?php endwhile; ?>


Webmentions were shown as “Peter mentioned this on”, but that does not provide context for a reader to decide if they want to click to go there. So I want to display a part of the linked item, as a teaser. Years ago pingbacks were presented like that on my site.


Find out how webmentions are stored, and how they are presented. Change the presentation by displaying an excerpt.


It turned out that webmentions are actually stored in full (so the text of the linked item is available in my wordpress database). It was just that the template for how it got presented needed tweaking. There is also a character count limit, below which a mention is indeed shown as I like it. All this however isn’t done in the theme, but in a plugin, called Semantic Linkbacks and in a specific file: class-linkbacks-handler.php. Once I localised that, I could change what I needed.
So I

  1. changed the character count limit to 500
    // Mentions with content less than this length will be rendered inline.
    define( 'MAX_INLINE_MENTION_LENGTH', 500 );
  2. changed the template for a webmention in public static function get_comment_type_excerpts()
    It was 'mention'=> __( '%1$s mentioned %2$s on href="%3$s">%4$s., 'semantic-linkbacks' )
    I changed it to
    'mention'=> __( '%1$s mentioned %2$s on href="%3$s">%4$s: %5$s', 'semantic-linkbacks' )
    This adds a 5th parameter at the end. This will hold the excerpt.
  3. Then filled that template in, in function public static function comment_text_excerpt
    • After it sets the length of the webmention, stored in $text in $text_len I evaluated that to see if it is longer then the limit. If so it sets a delimiter $text_delim to that maximum, or else sets it to the actual length.
    • Then I create a text snippet from the start of the text to that delimiter $text_snip = substr($text, 0, $text_delim) and add a few dots to the end $text_snip .=" ...."
    • That snippet is then added as 5th parameter to a call of the template mentioned above $text = sprintf( $comment_type_excerpts[ $semantic_linkbacks_type ], get_comment_author_link( $comment->comment_ID ), $post_type, $url, $host, $text_snip);


  • This tweak is to a plugin, so the next update will overwrite my changes. Need to figure out how to post it back to the plugin source so it might get incorporated as an option
  • Still need to change how the excerpt is selected. Now it is some 500 characters from the start of a posting. I want it to be 500 characters around the actual link.
  • It seems I need to change webmentions for various types, as a reply to a comment I made is shown as ‘x mentioned y’ (I changed it to the text of the actual comment by hand in this case.)
  • A summary overview of changes I made to this site, to make it more fully a indieweb hub / my core online presence. The set-up of my WordPress installation also has been described.

    Theme related tweaks

    • Created child theme of Sempress, to be able to change appearance and functions
    • Renamed comments to reactions (as they contain likes, reposts, mentions etc.)
      in the entry-footer template and the comments template
    • Removed h-card microformats, and put in a generic link to my about page for the author in the Sempress function sempress_posted_on. Without a link to the author mentions show up as anonymous elsewhere.
    • Removed the sharing buttons I used (although they were GDPR compliant using the Sharriff plugin, but they got in the way a lot I felt.
    • Added a few menu options for various aspects of my postings (books, check-ins, languages)
    • Introduced several categories to deal with different content streams: Dutch, German for non-English postings, Day to Day for things not on the home page, Plazes for check-ins, Books for ehh books, RSS-Only for unlisted postings, and Micromessage for tweets I send from the blog. This allows me to vary how I display these different types of things (or not)
    • Displaying last edited and created dates to (wiki)pages
    • Added a widget with projects I support
    • Added to the single post template a section that mentions and links the number of annotations for that post, where they exist.

    Functionality related tweaks

    Other tweaks

    • Set up 2 additional WordPress instances for testing purposes (Proto and Meso)