Having successfully created an initial javascript powered badges page for my website I wanted to move towards creating a more permanent solution.
So I decided to set up a new Eleventy project and copy over the badge related stuff. This was slightly complicated by the fact that the day I decided to do this was the day Eleventy version 3.0 was released. I’d been thinking about trying it out anyway, so this seemed like a good opportunity. So I switched most of my code over to ESM modules without any difficulty. The only ones that gave me any trouble were the CSP generation files, and I’d copied those from somewhere else, so I initially took the easy way out and let them stay as they were (making them .cjs files). Now I had a working project it was time to generate a real website.
Originally I had assumed that I would copy the URL structure from WordPress thus giving me the option of setting up page by page redirection, however that would mean paying WordPress money and after recent events I felt pretty disinclined to do that, plus paying them to leave felt pretty ridiculous.
So I had free reign to design a new scheme. So I decided on a simple structure
• /badges/badge-number/badge-title for the badges themselves as the date on which they were posted is largely irrelevant (and badge title is not always unique).
• /categories/category-name for categories
• /tags/tag-name for tags
• / for the main page
I started with the individual badge pages. I’d already written code to pull in tags and categories from WordPress at build time, so fetching the data was simple and creating a page from a data object is straightforward.
At this point though the complications multiplied.
I needed to create a ‘processed’ version of the badge data. WordPress provides the title and content as rendered HTML. It also throws in extra non breaking spaces into the title (presumably to prevent orphaned words) but in my masonry view l realised they had to go, as did the escaped characters which were spoiling the title slug (the he library was my friend here).
I wanted each badge to be identified by its collection number which wasn’t data WordPress knew, other than I’ve named all the badge images consistently. Time for a regular expression to retrieve it.
Similarly I wanted a very specific excerpt which needed several regular expressions to create.
The tags and categories come back from WordPress as numeric ids but I needed to look up the names and (worse than that) the names had also been rendered into HTML so again I need to decode them so that they could be used by slugify to generate a link.
(Yes, I’m going to have to rewrite a lot of this when I have static local data).
Now I had badge pages, I could move on. The sidebar links were next as it merely needed the links directing to my pages rather than WordPress.
(I skipped doing the search at this point, we’ll come back to that later).
Once I had some page pages built from data, it was time to move onto the tags and categories. These two things are basically the same, for each I wanted a page with a list of badges. In some cases though there are a lot of badges (the badge category is actually everything), so it was going to need paginating.
For the badge pages I simply used Eleventy pagination with a page size of one. For tags and categories though I wanted pagination for each individual tag, the ‘double pagination problem’. This requires creating a collection (in my case from the badges data) indexed by both tag (or category) and page number. This site was incredibly helpful in giving me an approach to follow.
I discovered a few interesting things (mostly by accident) here:
- You can create a collection of pages that are generated from data. You need to set.
pagination: data: badges addAllPagesToCollections: true
in the front matter and then you can do
collection.getFilteredByGlob('**/badge.njk'); - You can create a collection from your global data directly using
collection.getAll()[0].data.badges
I wanted to use the former method basing the collection on the pages but I couldn’t work out how to access the badge data for each one. So I used the latter. Then I built a double collection and created pages from that. I added next and previous buttons so all the badges for a category (or tag) could be viewed.
Javascript or no Javascript
Given that I had built this whole thing already in a single page you might be wondering why I went through all that (I certainly was). I had decided I wanted the pagination to work without javascript and only if javascript was on I would replace it with progressive loading.
I’d already written the progressive loading logic in my one page version, all I needed was something to progressively load. For this I created a second template for each category, tag and the index that output json instead of HTML. The trickiest bit was generating valid json containing my HTML excerpt string that I needed for each card. The solution here was to use filters in my template
{
"excerpt" : {{ badge.excerpt | dump | safe}}
}
did the trick. I had to add a little bit more code to handle switching over to progressive loading gracefully and I was done (except of course for a lack of search).
So now I have a working and deployable site. Cue cheering.
At this point I took the time to revisit the CSP generation, as it was pretty slow over the ~1500 pages I now had. I realised that the code I had copied used the JSDOM library and found a similar library, linkedom, which ran significantly faster. Rewriting my code slightly gave me the impetus to convert it into module format as well.
Searching
Being able to search my badges is incredibly important to me. After all the lack of a search box on my main WordPress page was one of the things that triggered all this.
I had been recommended PageFind as a search engine. The documentation made it sound ridiculously easy. Mark up your html, point PageFind at it and go!
At one level it was; in only a few minutes I had a searchable site. I created a search box in the sidebar to take you to a search results page to run the requested search and it felt nearly done.
The tricky bit now was that I wanted the search page to display the same badge cards as the rest of the site.
PageFind is set up to index html pages, and it extracts the text it finds and offers this up as search results. I wanted the same excerpt as elsewhere and that contains a table. Luckily PageFind allows you to add your own metadata to indexed content.
I added an attribute in my page to contain my excerpt but now I needed to insert html containing quote marks into an attribute string. Javascript escape function to the rescue. Creating an Eleventy filter to call that function provided a valid string.
Then my search javascript can unescape the metadata before displaying it. This all feels incredibly clunky and it is possible there’s a better way that I’ve missed but for now I have a search that works.
Creating a static site from WordPress has mostly involved a lot of escaping data in one way or another. I have a sneaking suspicion that the next stage of this project will involve a lot of rewriting, but this stage is done for now.




