Check your posts (notes, articles, etc.) are marked up with h-entry:

Success!

We found the following post h-entry on your site:

Name

Connecting My Site to the Wider Web

Author

Negate This

Content

Over the past two weeks, I've worked on adding a number of notable features to my website:Adding Microformats to all of my pages.Adding Webmentions support to all of my pages.Bridging my website to the Fediverse and to Bluesky.Publishing an RSS feed.Mirroring my recent Letterboxd posts to my Movies page.Addings Tags to my posts. All of these features are supported by major architectural changes I've made to my custom static site generator.Microformats Microformats are a way of marking up HTML to make it easier to represent relevant data. These data can be a number of things, from the contents of a blog post, metadata regarding a blog post (e.g. time published, who the author is, etc.), your social profile, and much more. For example, this blog post has the following HTML structure:

The
tag has the class h-entry, which denotes that the contents of this tag will be syndicated. The
tag has the class e-content, which represents the actual data being syndicated, A.K.A. the text I've composed for this blog post. By explicitly marking up the HTML in this way, the data making up my blog post can be parsed easily and then transformed to better fit the presentation of wherever it gets syndicated to. A quick example of this is the Indiewebify.me website, which is used to validate that a site is using Microformats correctly. Here is the validation for this page. As you can see, Indiewebify.me is able to parse the contents and metadata of this blog post.Webmentions Webmentions are a way to have conversations and interactions between websites without the need for a central service. Essentially, a website will denote a Webmention server where it can be contacted at. Think of it like a mailbox that holds messages from other people. The location of this "mailbox" is denoted in an HTML tag. For example: When someone publishes something to their site, let's say Site A, that includes a link to somewhere else, let's say Site B, their publishing software can pull Site B's HTML, look for the link that says where their "mailbox" is, then send a message to that "mailbox." The message is something along the lines of "Hey, me (Site A) has mentioned you here: https://site-a.com/my-cool-post." The Webmention server will store this message, and the owner of Site B can periodically check their mailbox and update their website with any messages people have sent to it. At the end of most pages on my site, there is a Webmentions section that will contain any Webmentions for that particular page. Currently, the only page that contains any Webmentions is my home page, but my hope is that this will change with the introduction of the next feature.Bridging to the Fediverse and Bluesky With Microformats, I have a way of denoting the components of a "post". With Webmentions, I have a way of receiving "comments". Putting these two pieces together, I have the basis for a rudimentary social media site. In fact, people from the non-profit A New Social have created a tool called Bridgy Fed to leverage Microformats and Webmentions to bridge sites to other social media platforms, namely the Fediverse and Bluesky. I've enabled this bridging feature on my own site. What this means in practice is that my site's posts will automatically be converted to a post on the Fediverse / Bluesky, so you can literally follow my site on either of these platforms to receive updates. The steps for how this works are as follows:All of the posts which I wish to publish have an invisible link in them that points to Bridgy Fed.When I publish a new post, all the links in that post get sent a Webmention, including that invisible link to Bridgy Fed.Bridgy Fed receives this Webmention, essentially notifying it that I've made a new post.Bridgy Fed will get my new post, and use the Microformats to parse it for the author, publish time, contents, etc.Bridgy will use this parsed data to create a new post on the Fediverse / Bluesky post on my behalf.When an interaction occurs on these posts, such as a like or comment, Bridgy Fed will send it to my Webmention "mailbox" so that I can display them on my site if I so please. This allows me to participate in a wider social media landscape without ever leaving my own web site, where I have full creative control.Publishing an RSS Feed While publishing my site's posts to social media is fun, I've also begun publishing an RSS feed. RSS stands for Really Simple Syndication, and is a standardized way to post updates to a feed so that people can follow along from their feed readers. You can stick my RSS feed link into a feed reader (my feed reader of choice is Read You | APK link on Android) and have it periodically check for updates, which you can read fully from the feed reader. You never once have to actually visit my site to read its contents! RSS feeds were a way bigger deal over a decade ago, but even now they're used quite extensively for people to follow podcasts ("or wherever you get your podcasts"). Lots of sites unknowingly publish RSS feeds because Wordpress automatically generates them at /feed. Some news sites provide RSS feeds for different categories of news. For example, the RSS feed for PBS's Poltics News Hour section is here. You can technically follow Substack users' posts by adding /feed to the end of their URL and sticking that into a feed reader. You don't get the full contents most of the time, unfortunately, but it's still an easy way to keep up with people's posts without needing to download another damn app! Just the other day, I found out that Letterboxd provides RSS feeds for every user at their user profile URL + /rss, which gave me an idea...Mirroring my Letterboxd posts Now, when I update my site, my recent Letterboxd reviews get mirrored to my Movies page! It does this by parsing my Letterboxd user's RSS feed, then converting the contents to HTML. The Letterboxd RSS feed has a surprising amount of information. Below is an example of one of the s included in the feed. Petite Maman, 2021 - ★★★★★ https://letterboxd.com/mackwells/film/petite-maman/ letterboxd-review-1186083446 Mon, 2 Feb 2026 10:49:11 +1300 2026-02-01 No Petite Maman 2021 5.0 Yes 749004

Criterion Challenge 2026 - Film #4

There's nothing I can say to convey how touching this film was. We were all children once, with big thoughts and big feelings. Every single one of us.

Ate nothing while watching this.

MackWells
There's the HTML representation of my review, the movie's TMBD ID, whether I liked the movie, the date I watched it, etc. Enough information to easily just copy my reviews off of Letterboxd and share them elsewhere.Adding Tags to My Post My posts can now contain tags, which you can click to take you to other similarly tagged posts. You can also browse all tags at the tags page. This was just a quality-of-life addition. I used to have tags way back when I built my site using Hugo, but I never re-added them after switching to my custom static site generator. That is, until I decided to pull the curtain on my old, untouched code and refactor it.The Technical Part Feel free to skip this if you don't care about the technical aspects of making this site. I started programming in Clojure a couple of years ago after I gained an interest in Lisps). Clojure is a Lisp that's hosted on the Java Virtual Machine (JVM), so all Clojure code can interoperate with Java code and libraries, making it a pragmatic choice as far as Lisps go. Clojure is not limited to being hosted on the JVM, however. People have created Clojure that targets JavaScript (ClojureScript), .NET (ClojureCLR), Flutter and Dart (ClojureDart), and recently C++ (jank). A defining characteristic of Clojure is that "code is data." This is meant in a very literal sense. Clojure code is just a bunch of lists. Take the following Clojure code, which defines a variable x and assigns it the value of 5.(def x 5) This code is literally a list of 3 items:def, the function being called.x, the symbol that will store the value.5, the value being stored in item 2. This makes handling data, transforming it, and representing it very easy and fun to do in Clojure. For example, in Clojure, it's common to represent HTML using "Hiccup" syntax. This:[:div {:class [h-entry]} [:a {:href "https://example.com"} "Example page"]] Is equivalent to this HTML:
Example page
Once again, the Hiccup representation is just a list, where the first item is a keyword for the HTML tag that this list represents. Since it's just a list, we can use the many functions available in Clojure to create and transform lists to programmatically create HTML. That sounds a lot like what static site generators do, huh? I thought so, too. Years ago, I looked into using Clojure code to create a custom static site generator, found this blog post, pretty much copied it verbatim, and left it at that. It worked perfectly for a while, but it was hard to add features that I really wanted, like my Music page. When I decided to add the features I mentioned at the beginning of this post, I knew it was time to refactor my code.How it all works At the core of the static site generator is statis, a Clojure library containing functions for creating static websites. Basically, stasis takes a hash map where the keys are the page slug and the values are HTML strings.{"/about/index.html" "Just imagine this is a bunch of HTML"} And converts it to files on your filesystem.my_folder | l___about | l___index.html That's it. Nothing fancy. All I have to do, then, is create this hash map for all of my pages. My starting point is a directory, resources, that contains all the files that will turn into my website.resource | |___index.html | |___posts | |___index.html | |___first-piece.md | l___what-is-old-and-what-is-new.html My posts are either Markdown files or HTML files. Each file is composed of two parts:--- title: First Piece date: 2020-11-03 type: post tags: ["technology", "general"] --- Blah blah blah just yapping. Everything inbetween the --- are metadata about the page, and everything after are the contents of the page, again, either in Markdown or HTML. I then grab all of the contents of resources and store them into a hash map.{"/resources/posts/first-piece.md" "---\ntitle: First Piece\nBLAH BLAH you know the rest"} From here, I need to change the key to the slug that it will represent on my site, and change the contents of the file into a structured format. The structured format I decided on has the following shape:{:metadata {:title "First Piece" :date #inst "2020-11-03T10:29:17.000-00:00" :type :post :tags ["technology" "general"]} :raw-hiccup ([:p "Blah blah blah just yapping."]) :links [] :slug "/posts/first-piece/index.html"} The metadata that were originally inbetween the --- have been transformed into a hash map with appropriate Clojure data types. The contents of the file have been transformed into their Hiccup syntax representation. Any links found in the post are collected so that Webmentions can be searched for and sent, and the slug is placed into the hash map to easily have access to it when formatting a page later. The result is a "page map" that looks like this.{"/posts/first-piece/index.html" {:metadata {:title "First Piece" :date #inst "2020-11-03T10:29:17.000-00:00" :type :post :tags ["technology" "general"]} :raw-hiccup ([:p "Blah blah blah just yapping."]) :links [] :slug "/posts/first-piece/index.html"}} From here, each page's raw-hiccup is placed into a Hiccup list representing the entire HTML document; the , ,
,
, etc. The resulting Hiccup uses the page's metadata to appriopriately create the page title, add the tag list, the time published information, etc. That Hiccup then gets transformed into the corresponding HTML string and gets added to the structured format of the page under :html. Thus, creating the final hash map needed for stasis to render the pages is as simple as traversing this "page map" and grabbing the final :html value for all keys. The very nice thing about this system is that adding special pages is as simple as creating a "page map" for the special page and merging it with the "page map" before rendering everything. That's how creating my RSS feed works, in fact. I simply create a page map for it, where :html contains the string contents of the RSS feed.{"/feed.xml" {:html "Just imagine this is an RSS feed"}} Then I merge this into the page map before passing it into the stasis function.Why? One reason is that I thought having a bigger audience would force me to start writing again. The last time I wrote a blog post was over 2 years ago, and the last time I wrote a blog post that I can say I'm proud of was never! Even this post I'm writing in a rush because I got burnt out from working on my site and don't want to touch it again for a few weeks. The real reason for this slew of changes is because I found Bridgy Fed and thought, "People being able to follow my site from Bluesky would be kinda cool." That thought led me to add Microformats and Webmentions, and things spiraled from there to the point of obsession and burn out. Ahh if only I poured this much work into crafts or something. Follow me on the Fediverse at @negatethis.com@negatethis.com or on Bluesky or subscribe to my RSS feed! 🫶

Published

URL https://negatethis.com/posts/connecting-my-site-to-the-wider-web/index.html

Syndicated Copies

Add URLs of POSSEd copies!

<a rel="syndication" class="u-syndication" href="…">…</a>

Categories

  • technology
  • indieweb
  • clojure

Your h-entries should have, at minimum, the following properties:

  • e-content — the main content of the post
  • p-name — if your post is an article with a name, use this classname.
  • dt-published — the datetime the post was published at, in ISO8601 format, with a timezone
  • u-url — the canonical URL of the post, especially important on pages listing multiple posts

It’s a common convention for the published datetime to be a link to the post itself, but they can be separate if you want.

There should also be some way to discover the author of the post — either link to your homepage (which should have your h-card on it) from anywhere within the body of the page with rel=author, or optionally embed a p-author h-card in the h-entry.

The web is an expressive medium, and as such there are many other properties which you can add to your posts. Check out the h-entry documentation for a full list.

Want to be able to use h-entry data in your code? Check out the open-source implementations.

Previous Step | Home | Next Step