Code Ouroboros: A WordPress / Eleventy Hybrid
In a previous post I mentioned that, to properly test a calendar plugin, I needed a vanilla theme, something that would reflect a brand-new project. I could have used Twenty Twenty-Five, but where’s the fun in that? I briefly considered an FSE theme, as I tend to do about twice a year. I even started building one and then… nope. I get it. It’s clearly a great pathway for a lot of people, and if I were going all-in on FSE I’d probably just use Olllie pro. But at the end of the day, I’m a developer. Building things in the UI just isn’t as much fun. I need the smell of console errors in the morning. The flow state of writing CSS. The loop. My IDE. Call it developer experience – whatever. I like the WordPress admin. I like writing in it and creating content, not building layouts. If you do, great. Go for it. So, back to my comfy IDE and a custom hybrid theme. I’ve recently switched my daily driver from VS Code to Nova. I do use AI coding agents – specifically Claude Code, increasingly though, I don’t want that living too much inside my editor, and VS Code is clearly going all-in on that direction. Again, maybe this is “developer experience” (a term I have a few issues with – it feels a bit self-centred, although in the context of this post I’m being self-centred, so… meh). But I’m settling into being more present when writing code, with any AI interaction happening via the CLI / terminal (iTerm2). IMHO, AI code completion removes too much consideration, a tab is just too easy to press. Obviously, I could have built something super simple using patterns I’ve refined over the years, namely the theme that drives this site. But I wanted to try something a little different, based on some of the experiments I’ve been exploring on this blog. theme.json is getting increasingly mature and has become the source of truth for design tokens on the sites I build. I also just straight-up love Eleventy, so in a brief mad-scientist moment I wondered: could I create a WordPress / 11ty hybrid — taking the best of each, and enabling two pathways for publishing content? So that’s what I did. Here’s the file structure: dgwltd-mvp/ ├── src/ │ ├── 11ty/ # Eleventy source files │ │ ├── _config/ # 11ty plugins (filters, shortcodes) │ │ ├── _data/ # Global data files │ │ ├── _includes/ # Layouts and partials │ │ └── content/ # Markdown/HTML content │ ├── assets/ │ │ ├── fonts/ # Web fonts │ │ ├── icons/ # SVG icons │ │ ├── images/ # Source images │ │ ├── scripts/ # JavaScript modules │ │ └── scss/ # Sass stylesheets │ └── utils/ │ └── utopia.ts # Fluid typography utilities ├── build/ # Webpack output (blocks) ├── dist/ # 11ty output + compiled assets ├── scripts/ # Build utilities ├── template-parts/ # WordPress template partials ├── eleventy.config.js # 11ty configuration ├── esbuild.config.js # Application scripts config ├── webpack.config.cjs # Block editor config ├── theme.json # WordPress theme settings ├── functions.php # WordPress theme functions └── *.php # WordPress template files We’ve got all the goodies: theme.json Block variations ES6 imports (e.g. Alpine.js) Minimal SCSS (with optional GOV Design System) Fluid typography via Utopia What really sets this apart is how the Eleventy build consumes theme.json to generate core styles and utilities. For example, WordPress automatically generates a spacing scale and inlines it in the as: First, we consume the JSON in our Eleventy config: const themeJSON = JSON.parse(await readFile(new URL('./theme.json', import.meta.url))); We can then use Eleventy to generate styles via things like: {{ theme.settings.color.palette }} {{ theme.settings.spacing.units }} {{ theme.settings.typography.fontSizes }} And even Tailwind-style spacing tokens: .pt-{{ key }}-{{ subkey }} { padding-block-start: {{ subvalue }}; } The great thing about Eleventy is that you can set the permalink to any file type. So this file (wp.njk) has front matter as simple as: --- permalink: '../src/assets/scss/wp.scss' --- On the PHP side of the theme, this all “just works” out of the box. The Eleventy side, however, needs this declared in the base template: {%- css %} {#- main.css: Full theme styles #} {% include "dist/css/main.css" %} {#- wp.css: Design tokens from theme.json for static pages #} {% include "dist/css/wp.css" %} {% endcss %} At this point we have parity between PHP and static site generation, with both consuming each other in different ways. I now have two clear paths when developing a site. I can build content in the WordPress admin, export it all to Markdown (I have a plugin for that – another time, another post), drop it into the content folder with a data file, and boom: static site. Create {type}.11tydata.js files: // src/11ty/content/posts/post.11tydata.js export default { tags: ["post"], // Collection tag type: "post", // WordPress post type status: "publish", // Post status filter layout: "layouts/base.njk" }; Or I can stay entirely in PHP land and just use Eleventy as the tail to generate some tasty utilities – fluid typography, spacing, service workers, offline pages, and so on. Is this crazy? Probably.Am I enjoying it? Massively. Oh and I was able to test my plugin.
Discussion in the ATmosphere