Hey there!

So, one of my goals is to make my site as compliant to IndieWeb as possible, but there was one particular protocol that was giving me trouble: delete.

See, the issue is that WordPress doesn’t have a way to distinguish trashed posts versus posts that are no longer available. Buuuuut, I think I found a hacky workaround, involving categories!

The first thing I did was to create a new category, in this case, “deleted”. The actual name doesn’t matter, but I figured that’d be intuitive enough. Then, I faced three issues:

  • Hiding the posts from the main page and blog roll
  • Creating a tombstone page distinct from the 404 page. 404 doesn’t mean 410
  • Setting the status code for the HTTP response to 410

With that said, let’s look at the code.

For the first issue, it’s pretty easy to hide posts, using a filter. I found a tutorial here, and I used a modified version of method 2:

function exclude_category($query) {
if(is_admin()) {
return $query;
$query->set( 'cat', '-55' );
return $query;
add_filter( 'pre_get_posts', 'exclude_category' );

55 happens to be my category id. Yours will be different, probably. Of note, I experimented quite a bit with the conditions to hide it, because just changing the query across the board would also hide it from the admin page, meaning we can’t quite see the posts we deleted. So, we only filter if we are not on the admin pages using is_admin().

The next part is the tombstone and status code. Fortunately, I was able to modify both in the same place by modifying the template I’m using. At the time of writing, I’m using Autonomie with my own modifications.

Here is the full modified Single Post template:

* The Template for displaying all single posts.
* @package Autonomie
* @since Autonomie 1.0.0

get_header(); ?>

<main id="primary" <?php autonomie_main_class(); ?><?php autonomie_semantics( 'main' ); ?>>

<?php while ( have_posts() ) : the_post(); ?>
<?php if(in_category("deleted")): ?>
<?php status_header( 410, 'deleted' ) ?>
<div class="entry-content e-content" itemprop="description articleBody">
<div class="h-entry">
<time class="dt-updated" datetime="<?php echo get_the_modified_date(); ?>">Removed on: <?php echo get_the_modified_date(); ?></time>
<p class="p-name p-content">
There was a post here. It's gone now.
<?php else: ?>
<?php get_template_part( 'templates/content', get_post_format() ); ?>

// If comments are open or we have at least one comment, load up the comment template
if ( comments_open() || '0' != get_comments_number() ) {
comments_template( '', true );
<?php endif; ?>

<?php endwhile; // end of the loop. ?>
</main><!-- #content -->

<?php autonomie_content_nav( 'nav-below' ); ?>

<?php get_footer(); ?>

The status code is easy to change. Just call status_header( 410, 'deleted' ). For the tombstone, we just need to add a conditional tag to check the category: if(in_category("deleted")):.

Yes, I’m absolutely certain there is probably a better way to handle the tombstone via how WordPress handles templates, but… I’m really, really new to wordpress and PHP, so a hack it is. If this was Sitecore, I’d be all over that. But you know, Sitecore and IndieWeb probably form some sort of contradiction. πŸ˜›

Check out the result for the deleted test post I made: Test.

There are still some issues, though. I’ve noticed that deleting a post in this way doesn’t automatically send a web mention, so Bridgy needs to be notified by hand. I’m also unsure if I need to do any additional modifications to my feed.

I’m contemplating actually pulling out all this behavior into its own plugin, to let WordPress handle deletions much more gracefully, including notifying any downstream servers of the removal.

2 thoughts on “IndieWeb delete hack for WordPress

Leave a Reply