
A weekend (well, several weekends) of running 2003’s WordPress on a 2026 stack — with one rule: don’t rewrite the 2003 code.
TL;DR
I took WordPress 0.71-gold — the very first tagged release of WordPress from May 2003, the descendant of b2/cafelog, predating Hello Dolly, themes, plugins, and the loop as we know it — and got it running on PHP 8.3 / MySQL 8 / Docker / npm workspaces / PHPStan / Playwright / a custom block editor.
Rule of the game: don’t rewrite the 2003 code. Only change what’s strictly necessary to make it run. Everything modern lives in the environment around it.
I also made it runnable straight from a browser.
Same idea as WordPress Playground — no install, no server, PHP 8.3 compiled to WebAssembly, with in-browser SQLite as the database.

The button below boots 0.71 right there in your tab. Please give it a click.
Why?
WordPress turns 23 this month. Most people have never actually clicked around in 0.71. The b2/cafelog fork, Matt's June 9th announcement post — the early WordPress story exists as reading material, but there is no environment left where you can actually try it.
So I figured I’d build that environment.
The problem: PHP 4-era code does not boot on PHP 8.
ereg() is gone. ext/mysql is gone. PHP4-style constructors are gone.
MySQL 8’s strict mode rejects half of what 2003 b2/cafelog wrote.
You hit a wall of fatals before you ever reach a login screen.
…which, fair enough.
So the policy became: modernize only what’s needed to boot.
Keep the 2003 surface as-is. Wrap it in a 2026 toolchain.
A “let’s see what’s underneath” kind of project.
The “don’t touch the code” rule, with the small print
A short list of what had to change inside src/:
ext/mysql→mysqli(themysql_*family simply isn’t in PHP 8 anymore)- POSIX
ereg*→ PCRE - PHP4-style
function ClassName()constructors →__construct() - Removed/renamed PHP built-ins and superglobals
- MySQL 8: reserved words,
sql_mode=STRICT_*, charset weirdness - Security work (SQLi, XSS, CSRF, auth/session, access control, file upload, info disclosure)
That last one isn’t negotiable.
WordPress 0.71 was written before “prepared statement” was a phrase people said out loud.
Running it as-is on the public internet would be close to a felony.
So 0.71 is treated as a local-only artifact, and publishing goes through a different path (more on that later).
Everything else modern (Docker, PHPUnit, PHPStan, Playwright, WPCS) lives outside src/. The 2003 directory stays as 2003 as possible.
For what it’s worth: PHPStan is at level 0 with 0 errors, WPCS (WordPress-Core) is also at 0 errors.
On 2003 b2/cafelog code. That felt good.
Tooling, named in the modern WordPress dialect
If you’ve used wp-cli / wp-env / wp-now, the layout will feel familiar straight away. (The resemblance is intentional.)
Modern WordPress This project What it does wp-cli071-clinpx 071 <command> — CLI for 0.71, includes static exportwp-env071-envnpx 071-env start — PHP 8.3 / MySQL 8 Docker env managerwp-now / Playground071-nowWordPress 0.71 in your browser — PHP-WASM + SQLite
npm run setup installs everything in one go (npm workspaces, the block-editor Vite build, the Composer dev tooling). npx 071-env start boots Docker.
Open wp-install.php and you’re looking at the 2003 WordPress installer, served by PHP 8.3 from a 2026 laptop.
It is a strange feeling, and I do recommend it.
071-now (0.71 in the browser)
If you only click one thing in this post, please make it the playground link.
The whole 0.71 site runs inside the browser tab itself. PHP 8.3 compiled to WebAssembly, SQLite as the database, server side does nothing.
Same machinery as WordPress Playground, pointed at a 23-year-old codebase.
Honestly, this is also the safest possible way to run 0.71.
Nothing exposed, nothing persisted server-side.
Break it as much as you want, refresh, start over.
…and a block editor, too
This chapter ate a weekend.
Once 0.71 was booting on PHP 8.3 + MySQL 8, things got a bit greedy.
“As long as we’re here, let’s drop a block editor in.”
Now — WordPress 0.71 has no REST API.
No theme system. No wp_enqueue_script.
Modern Gutenberg is built on a stack of assumptions that simply don’t exist in 0.71, so a straight port isn’t on the table.
But — you can mount @wordpress/block-editor (the React package, not the full plugin) against a minimal custom backend, store block markup in the existing post_content column, and let 0.71’s existing front end render it. And it works.

The classic b2edit.php editor stays as the default; the block editor sits next to it as an experimental alternative (not a replacement).
So: on a codebase that predates the WordPress loop as we know it, you can write a post in blocks, hit save, and the 0.71 front end renders it without noticing anything has changed.
Investigation notes are in docs/gutenberg-investigation.md if you want to see where the seams are.
※ And yes — this post was written in the block editor mounted on 0.71.
Tests, because there’s no telling what’s hiding in old code
Old code is full of behaviour you only learn by poking. So I laid down a safety net.
- 94 PHPUnit tests — covering the unit-testable parts of the 2003 code (text formatters, the bundled Textile parser, date/URL/number helpers, and DB-dependent helpers like
get_postdata()/get_userdata()/get_the_category()) via a fake$wpdb. - Playwright E2E — drives the running Docker blog from a real browser. Log in, create/edit/delete a post, add/delete a category, then hit the home page, single post (
?p=), category (?cat=), monthly archive (?m=), and the RSS 2.0 feed. Every page is asserted to produce zero PHPFatal/Warning/Deprecatedoutput. - Seeded E2E data is prefixed
E2E:and removed by name, so the suite is safe to re-run without touching your own posts.
Publishing safely — static export
Once it works, some people will inevitably want to actually publish with it.
So I built in the safest possible publishing flow for WordPress 0.71.
The intended workflow:
- Write posts in the local Docker blog.
npx 071 exportdumps the whole site to static HTML.- Upload only the static files anywhere — GitHub Pages, S3, Cloudflare Pages, whatever.
The public server runs no PHP and no MySQL, so the 2003 codebase is never exposed.
If 0.71 output is going anywhere near the internet, I couldn’t think of any other reasonable way to do it (and still can’t).
The static export is just one command:
$ npx 071 export
What touching the code taught me about WordPress’s history
A few things became unavoidable once the code was actually in my hands.
First: 0.71 has no pages. Just posts and categories.
Comments and trackbacks exist — but there are no themes, no media library, no widgets, no plugin system, and obviously no REST API.
And going further: there’s no “Dashboard.” Hit /wp-admin and what you get is the editor and a post list. That’s all there is.

“WordPress is a CMS” is something we say automatically. Read the 0.71 code, though, and the truth rises right up off the page: this was, very precisely, a blog tool.
And from there, it grew to power over 40% of the entire web.
Twenty-something years from that codebase to that share. With both ends of that arc sitting in the same git checkout under my hand, the abstract fact of “WordPress got big” landed at a completely different resolution than I’d held it in my head before.
The other surprise: how cleanly the block editor drops in.
@wordpress/block-editor turned out to be far more standalone than I’d assumed. It doesn’t insist on the REST API. It doesn’t insist on the theme system.
Wire up save and load against any backend you’ve got, and it will happily run — even on top of a 2003 codebase.
The amount of work the Gutenberg project must have put into making the editor portable like that — that only really landed for me here, on the other side of the experiment.
Democratize Publishing
There’s something else this project pushed me to revisit.
0.71 has no pages, as I said. 0.71 was, very precisely, a blog tool.
From there, WordPress quietly grew into “the free thing you build corporate sites, e-commerce sites, membership sites, and landing pages with.”
Even in client work, it has been a long time since WordPress was anything but the first name on the table when someone needs a company site.
But underneath, I don’t think WordPress’s essence has actually changed.
WordPress.org’s stated mission is “Democratize Publishing” — and I think that’s still the whole game.
Whether WordPress looks like a blog tool or a site-building tool in any given decade is a surface difference. The root has been in the same place for 20+ years.
In day-to-day client work, almost nobody walks in saying “I want a WordPress.”
What clients actually want is a website — something they can update themselves. WordPress, the product, is never the goal.
The reason we still propose WordPress is that we want to hand them that “you can publish on your own” — that little piece of “Democratize Publishing.” That’s the actual value being transferred.
And because that value lives in the open source itself, getting more familiar with the codebase — reading it, poking it, breaking it — is part of how we get better at the job. The whole thing is sitting right there in public.
Studying it, playing with it — both are permitted, for anyone.
Pulling 0.71 out and dropping it onto a 2026 stack was, in part, just my own form of “play and learn.”
If we’re going to recommend WordPress, we may as well know it well. Saying that as much to myself as to anyone else.
What this isn’t
For the record: this is not production software.
It is not a hardening of 0.71 for real use.
It is not a “you should run your blog on 0.71″ pitch.
The README says this in bold, and I’ll say it again here — please don’t.

The closest honest description is: an archaeology project that happens to be runnable.
A way to read 2003 WordPress in its own habitat, with modern tooling resting gently on top.
Done with 0.7 on WordPress 7.0’s release day, twenty-three years later. That’s all this really is.
Try it
If any of this sounds interesting, please give the button a click and meet WordPress 0.71, unexpectedly back from 2003, running in 2026.
Repo
https://github.com/mt8/wordpress-0.71-gold
Local setup:
$ git clone https://github.com/mt8/wordpress-0.71-gold
$ cd wordpress-0.71-gold
$ npm i
$ npm run setup
$ npx 071-env start
About 3 minutes from a fresh laptop to staring at the 2003 installer.
Hope it’s useful for anyone working on something similar.
Happy 23rd, WordPress.
The first release still boots.
