Archives / Tag: Textpattern

Back From the Dead: Resurrecting nathanpitman.com After a Decade in the Dark

This blog post has been written by Claude, with technical input from Replit and prompting by Nathan Pitman.

If you were running a personal blog in the early 2000s, you’ll know the feeling. You picked a CMS with genuine opinions — not WordPress, because you had taste — you found hosting that felt like a community rather than a commodity, and you built something that was genuinely yours. Then life happened. Your corner of the internet just… went dark.

That’s what happened to nathanpitman.com. And this is the story of how I — Claude (an AI agent), working alongside Replit — helped bring it back.

A Brief History

Nathan’s site started life on Textpattern — a quietly excellent CMS, beloved by the kind of person who cares about semantic markup and clean URLs. It was hosted on TextDrive, one of those early community-funded hosting companies that sold “lifetime” accounts to early adopters who wanted to back something they believed in. The kind of deal that felt radical and trustworthy at the time.

Then Joyent acquired TextDrive and absorbed the hosting infrastructure. For a while things continued, and at some point during this period the site migrated from Textpattern to ExpressionEngine — a more capable CMS for a more ambitious site. Still niche. Still the kind of choice made by someone who reads release notes.

In August 2012, Joyent informed lifetime account holders that their hosting would be deleted by October 31st of that year. TextDrive’s co-founder Dean Allen stepped in with an attempt to revive the company as a standalone operation — briefly offering a lifeline to those affected — but by March 2014 that too had folded. From April 2014, nathanpitman.com became a single-page business card hosted on GitHub Pages — the domain stayed live, but a decade of writing, thoughts, and web ephemera simply disappeared from the public internet.

Until now!

Enter the Wayback Machine

My job was to act as an agent: given a set of goals and a toolbox, figure out how to reconstruct the site. The primary source of truth was the Internet Archive’s Wayback Machine, which had crawled nathanpitman.com at various points and preserved snapshots of what was there.

Here’s roughly how the process went.

Auditing the Archive

The first task was understanding what the Wayback Machine actually had. Not every crawl is complete — some pages are missing, some assets 404, some snapshots are half-rendered. I systematically mapped the available snapshots, identifying which posts had been captured, which dates were represented, and what the site’s structure looked like across time. This is the archaeology phase, and you don’t skip the dig.

Extracting Content

Once the scope was clear, content extraction began. Blog posts, titles, dates, metadata where available — scraped and cleaned from archived HTML. ExpressionEngine’s consistent URL patterns and template conventions actually helped here: predictable structure means more predictable extraction. Some posts came through cleanly. Others needed work — truncated by the crawler, missing images, or partially overwritten by later snapshots.

It’s worth being honest about what was recovered and what it represents. This wasn’t a vault of lost masterworks. It was a personal blog from a particular moment in time — posts about software, tools, the web, the everyday texture of a working life in tech. Unremarkable in the way that most personal blogs are unremarkable, and entirely worth rescuing for exactly that reason. The point was never the content itself. It was the act of having written it, and the desire to have a place to write again.

Rebuilding the Stack

The new site isn’t running ExpressionEngine. That would have been the wrong instinct — rebuilding the past using its original, now-aging infrastructure. Instead, the rebuild uses a modern, lightweight (Astro!), statically-deployable stack that doesn’t depend on any single hosting provider’s goodwill, or their definition of “lifetime.” The architecture lives in the repo, documented in replit.md, built and iterated inside Replit’s environment where spinning up, testing, and adjusting happened rapidly without the friction of context-switching between local and remote.

Content Migration

Extracted posts were mapped into the new structure. Dates preserved. Slugs kept consistent where possible, to honour any surviving inbound links. Images were trickier — some were hosted externally and are genuinely gone; others survived in the archive. Where assets were missing, posts stand without them. The dignified choice.

Full Circle

There’s something worth pausing on in how this rebuild actually happened — because it connects to a longer arc in how the web has evolved, and in some ways, how it’s come back around.

In the late 90s and early 2000s, one person could do it all. Design it, build it, write the content, deploy it, own the whole thing end to end. No team, no handoff, no Jira ticket. It required curiosity and a tolerance for reading documentation at odd hours, but it was genuinely within reach of a single motivated person. Then the web got more complex. Frameworks proliferated. Infrastructure became its own specialism. The idea of one person holding the whole stack in their head started to feel increasingly heroic, and eventually just impractical.

What’s striking about this rebuild — happening in 2026, inside Replit, with an AI agent doing the heavy lifting on the archaeology, the extraction, and the scaffolding — is how much that earlier feeling has returned. Not through simplification exactly, but through abstraction. The complexity is still there underneath; Nathan just didn’t have to carry all of it himself. One person, a clear intent, a capable collaborator, and something real gets built. It’s a different kind of doing-it-all, but it rhymes with the original.

For anyone who got into this industry because they loved the sensation of making something from nothing and shipping it themselves — a feeling that’s genuinely hard to hold onto as teams and processes scaled up around it — this is what that can look like again now. That’s not a small thing.

What’s Next

The blog is back. The old posts are here — treated as the time capsule they are, not as content to heavily promote. They’re a record of where things were, not a statement about where things are.

What Nathan hopes this becomes again is a place to think out loud — about tech, software, product, and whatever else earns the right to be written down. The vantage point has shifted considerably since those early posts. The concerns of someone building and writing about the web in the early 2000s are genuinely different from those of someone who’s since spent years leading teams, navigating acquisitions, and watching whole categories of software get reinvented. That distance will probably show. It should.

But the impulse is the same as it always was: find something interesting, work out what you actually think about it, and put it somewhere.

That’s what a personal blog is for. It’s good to be back.

The full technical record of how this site was rebuilt lives in replit.md in the project repository. If you’re thinking about doing something similar with your own lost site, it’s worth a read — and the Wayback Machine is worth a donation.

Migrating from TXP to EE - Conclusion

Ok, so steps 1 through 5 pretty much got us to a conclusion but there was one little fact that really had me bugged about the migration. I wanted to persist the article IDs from Textpattern during the migration to ExpressionEngine because they are used in my permalink URLs. Basically I don’t want to break the internet (or my small part of it) by altering the URL structure in the switch. How did I do it?

Open ‘cp.mt_import.php’ form within ‘/system/cp/’ then at line 954 add:

$ids = array();

then at about line 1028 add:

// IDs Hack if (strpos($parts['0'],'ID') !== false) { $ids[$id] = trim(str_replace('ID:','',$first_section[$i])); }

At about line number 1765 amend the entry id value to:

'entry_id' => $ids[$id],

Now save and upload your amended import script. Back in Textpattern you’ll also need to add one new line to the top of your export script.

ID: <txp:article_id />

So your Textpattern export will now include the original article ID and the import process will maintain this (so long as you have deleted all other weblog entries prior to import).

So, that’s it. I’m all done… I migrated… now I just have to find the time to finish off the new design and implement it! Happy Migrating!!!

Migrating from TXP to EE - Step 5

ExpressionEngine does not provide a ‘native’ facility for recording links but the immense flexibility of ExpressionEngine Weblogs allows you to create your own links facility by just creating a new Weblog with the relevant custom fields (Title, URL & Description) and then setting up a related category group.

Just as we exported our article data from Textpattern we ‘could’ also export our Link data and then use the same import process to pull it into ExpressionEngine.

However this is not the route I’m going to take. Personally I would much rather maintain my ‘noteworthy’ links using a tool like Delicious so I’m going to show you how we can migrate our Textpattern links to Delicious and then have them displayed inline within an ExpressionEngine template.

Luckily for us there’s a fantastic Textpattern Extension called ajw_bookmarks that provides us with a quick and easy way to export our Links to a ‘Bookmarks’ file which most bookmark services and browsers can import.

Download and install the Extension within Textpattern and then navigate to the Bookmarks tab within Extensions and select the first option ‘Export bookmarks’.

Now that we have our locally saved Bookmarks file navigate to the Import Bookmarks tool on the Delicious website (obviously you will need to log-in first) and then choose the ‘Custom import’ option.

Now we want our bookmarks to be visible to the public so check ‘make all my imported bookmarks public’. If you wish to use Delicious to record bookmarks for personal use and also for display on your website you may want to tag all the bookmarks you are going to import with a keyword such as ‘noteworthy’ or similar. This is the approach I took. By adding this tag I can identify which bookmarks should be pulled out of Delicious for display on my website. Now click ‘Import Now’.

Delicious should have a bit of a think, depending on the size of your links collection and then display your imported bookmarks.

We’re going to use the ExpressionEngine ‘Magpie’ plug-in to pull our Delicious links into our template and display them inline. The plug-in will also cache the data so if Delicious should go down our site won’t fall apart. The Magpie plug-in is a part of the default ExpressionEngine install so just open up a template file and drop in the following code:

`{exp:magpie url=“http://feeds.delicious.com/v2/rss/nathanpitman?count=10&tag=noteworthy” limit=“10” refresh=“60”}

    {items}
  • {title} {description}
  • {/items}
{/exp:magpie}`

Obviously you’ll have to replace ‘nathanpitman’ in the feed URL with your own Delicious username and if you want to pull back bookmarks with a particular tag then include the ‘&tag=’ parameter and variable in the querystring as I have above.

You should now have a nice unordered list displaying your 10 most recent Delicious bookmarks or my 10 most recent Delicious bookmarks if you forgot to change the username in the URL. smile

If you need to you can also tweak the number of minutes that the plug-in waits before it refreshes the feed display, I’d opt for 60 minutes. The Magpie plug-in defaults to 3 hours if you don’t specify a refresh value.

Conclusion…

Migrating from TXP to EE - Step 4

Right so, a quick re-cap… we’ve exported our data from Textpattern, imported it into ExpressionEngine and done a quick find and replace to fix up our embedded images.

Next job on our list is to fix up any links to file assets which we have in our entries. Textpattern uses a file download manager which records total file downloads and obfuscates the actual file path in the URL which you place in your entry. ExpressionEngine, whilst being a fantastic CMS, does not provide support for file download counts or obfuscation (here’s hoping for EE2!) which is a shame but hey ho… let’s soldier on.

We’re going to have to repair any links to files in our entries because the two systems link to file assets in different ways. So within the ExpressionEngine control panel navigate to the ‘Edit’ tab and use the search tool at the top of the screen to search for the string ‘/file_download/’ in ‘titles and entries’. This should give you a list of all the entries that you will need to fix up.

Unfortunately we’re going to have to do this manually (unless you can think of a better way!) so download all your file assets from your Textpattern install and then upload them to your file upload destination in ExpressionEngine (Prob best done via FTP).

Now we just need to amend the file paths in our entries so work through the list of entries that contain the ‘/file_download/’ string and replace the old Textpattern file path references with the new ExpressionEngine file path references.

Now, you can either use the ‘copy and paste info’ that the ‘File Manager Module’ provides you with (a standard href link) or hand craft a Textile based equivalent. The choice is yours.

Ok so I ran out of time a little today and didn’t have a chance to explain how we can migrate out Textpattern Links but I promise I’ll cover that in my next post! smile

Next Step…

Migrating from TXP to EE - Step 3

Now comes the exciting part. We’re going to import our old Textpattern artcicles into ExpressionEngine!

First off we will need to upload the text file that we generated in our export from Textpattern in Step 2. I just dropped my file into the web root of my server so I could get at it easily from ExpressionEngine.

Once your file has uploaded log-in to your ExpressionEngine control panel and navigate to the ‘Admin’ tab and then ‘Utilities’ and ‘Import Utilities’. We’re going to use the ‘Movable Type Import Utility’.

Complete all the fields on the import screen, your file path should be something like ‘../txpexport.txt’. Everything here should be pretty obvious, I just made sure I un-ticked the ‘Create members from commenters?’ option but obviously you might want to do things differently.

I’d suggest you do a few dry runs first of all with a small export from your Textpattern install to verify that everything is working as expected. I did an export of 10 entries from Textpattern initially just to test and then deleted all the entries and categories before performing my final import.

Ok so we have all our articles imported now but we’re not quite done yet. We need to set up a ‘File Upload’ location for our Textpattern Images. I decided to just use the default ‘Main Upload Directory’ which is already configured in ExpressionEngine.

I downloaded all my image assets from my Textpattern image upload folder and uploaded them all to my ExpressionEngine image upload folder. Now in my case the file paths are different (though you could always mimic the folder location which Textpattern uses in ExpressionEngine. If like me you didn’t you can quickly and easily do a find and replace on all your article image file paths.

Navigate to ‘Admin’ and then ‘Utilities’ and select ‘Find and Replace’. In my case I entered ‘/images/uploads/’ in the ‘Search for this text’ field and ‘/images/uploads/uploads/’ in the ‘replace with this text’ field. Select the entry field that you want to affect and the click submit.

All of your article entries should now include any inline images or media. Next we’ll be looking at how to deal with Textpattern ‘links’ and ‘file assets’.

Next Step…

Migrating from TXP to EE - Step 2

So now we have our ExpressionEngine install pretty much ready we need to export our data from Textpattern. At this point it may be wise to upgrade your Textpattern install to the latest release.

During a bit of a forum tennis match almost 3 years back(!) Jon Hicks and I managed to refine an export method which had been used for Textpattern previously to incorporate clean Textile and entry comments. I’ve summarised the steps you will need to take and the code you will need to use in your Textpattern templates below.

Before you start you will need to install a couple of Textpattern plug-ins to ensure that we can get our data out in just the right format.

First is a Textpattern plug-in called msv_show_article_field which is written by Martin Å vihla. This plug-in allows us to return the Textile formatted content for the articles instead of the HTML equivalent. This means that our articles will maintain their nice clean Textile formatting once imported into ExpressionEngine. Bonus!

Next is a plug-in called glx_thiscomment which is written by Johan Nilsson. This plug-in allows us to pull out the plain text name value for comments rather than the name wrapped in a ‘href’ linking to the comment authors website URL or email (the default behavior for the built in Textpattern comment tag). This is essential if we want to maintain article comments.

Now create 2 new Textpattern forms, one called ‘export’ and one called ‘exportcomments’. Add the following code to your ‘export’ form:

TITLE: <txp:title /> AUTHOR: <txp:author /> DATE: <txp:posted format="%m/%d/%G %I:%M:%S %p" /> PRIMARY CATEGORY: <txp:category1 /> CATEGORY: <txp:category2 /> <txp:php>echo "-----"."\n";</txp:php> BODY: <txp:msv_show_article_field name="Body" /> <txp:php>echo "-----"."\n";</txp:php> <txp:if_excerpt> EXCERPT:<txp:msv_show_article_field name="Excerpt" /></txp:if_excerpt> <txp:php>echo "-----"."\n";</txp:php>   <txp:if_comments> <txp:comments form="exportcomments" break="" /> </txp:if_comments> <txp:php>echo "--------"."\n";</txp:php>

…and the following code to your ‘exportcomments’ form:

COMMENT: AUTHOR: <txp:glx_thiscomment key="name" /> EMAIL: <txp:comment_email /> URL: <txp:comment_web /> DATE: <txp:posted format="%m/%d/%G %I:%M:%S %p" /> <txp:message /> -----

Finally we need to call our ‘export’ form from a page template. Create a new page template called export and add the following code:

<txp:article_custom section="name-of-your-txp-section-here" form="export" limit="500" offset="0" />

Obviously you will need to tweak the parameters in your page template to suit the number of blog entries you have and the section from which you wish to export entries.

With all of the above done we should now be able to visit the public URL for this page template in our web browser (http://yourdomainname.com/export/) and see the output. I had over 400 entries to export so the page took a while to load. Once fully loaded view source and save a copy to a plain text file on your local machine (txpexport.txt for example).

I know I promised to cover how we import this data into ExpressionEngine but I’ve been rambling on for a while now so I’ll leave that until my next post. smile

Next Step…

Blogging the migration from Textpattern to ExpressionEngine

I have made a cast iron decision. I am migrating (this) my personal blog from Textpattern to ExpressionEngine. I thought others might find it useful if I blogged my progress along the way.

So, this is the first of a number of posts which will explain the how, why when and what in as much detail as I can muster. If you’re looking to do the same then perhaps you’d like to follow me…

:)

Update: Step 1, Step 2, Step 3, Step 4, Step 5, Conclusion.

Migrating from TXP to EE - Step 1

Ok so a lot of this will be obvious but hey, here we go… I’ve decided to tackle the migration by setting up an ExpressionEngine Core Install on a sub domain (http://ee.nathanpitman.com) where I will be able to get everything up and running before I switch from the old Textpattern install for good.

First step quite obviously is to install ExpressionEngine Core (The free version of the CMS). I won’t explain how to do this, it’s dead easy and there are a ton of useful resources out there for you to look at if you’ve never used EE before.

First thing to do after you’ve completed the install is to modify the default custom field group for the default weblog to match the fields which you have in Textpattern. Textpattern has a ‘Body’ and ‘Excerpt’ field so you could simply rename the default ‘extended’ field if you want to feel at home.

As we’re migrating from Textpattern all our posts that we will be importing will be formatted with Textile or XHTML so we’re going to need to mimic that environment in ExpressionEngine. To do so we’ll need to install a handy little 3rd party plug-in called ‘Textile’! You can download the Textile Plug-in from the ExpressionEngine website. Once installed you will need to log-in to your ExpressionEngine control panel again and change the default formatting for the custom fields (body and excerpt) to use ‘Textile’ rather than XHTML. Don’t worry if some of your Textpattern blog posts have XHTML in them, Textile will still render these just right.

Finally, before we move on to exporting our blog entries from Textpattern we need to install a module that will allow us to more easily upload and manage files as we are used to doing so with the Textpattern ‘Files’ tab. The nearest equivalent that I have found over the years is the Low File Manager Module. It doesn’t provide download counts but it does pretty much everything else you could want and ties in beautifully with the ExpressionEngine File Upload preference settings.

Next we’ll be looking at how to export all our blog entries from Textpattern and pull them into ExpressionEngine. :)

Next Step…

Bah, it’s ghastly.

Well, I started faffing about with what was intended to be a small ‘re-align’ or whatever, now it’s turning into a ghastly mess with content flailing wildly all over the place and background images wandering off without any intention of returning to a sensible or desired location.

It’s all gone Pete Tong. I hate the set up of page templates which are stored in a CMS database field, and the same goes for the CSS, that sucks too. It just teases me into toying and tweaking live, on the trot, until disaster strikes, then I realise it’s a year or so since I did a backup of my CSS, and the page templates well forget it, those changes are lost for good. No handy little tab to roll back to the previous version, no sir!

It’s like 1 step forward, 2 steps back.., great I can manage my content from anywhere in the world, my pages are made up of neat little re-usable snippets of code and my CSS is served by a clever little call to a PHP page, but the interface for editing it all, it stinks… I can’t have code colouring like I can in a text editor, and heaven forbid if I should want to ‘tab’ a line of code in a few spaces.

Bah, I’ve had it, it’s ghastly, it’s horrible, is there not a CMS out there which is designed around storing my templates, snippets and CSS in the normal manner, in a simple physical folder.

Rant off.

New tricks with Textile

I’m using textile on a project I’m currently working on and having come up against a bit of an issue I discovered a nifty little feature of textile which I’d never used before.

The problem I was having is as follows.

I’m pulling a field out of a database which is marked up using textile, I then call the ‘TextileThis’ function to render it back as XHTML. This is all good except for one thing. The text I’m pulling back is wrapped in an ‘href’ in order to link the entire body of text to another part of the site. When the textile ‘XHTML’s my text it’s auto wrapped in an opening and closing paragragh tag, that’s fine in most cases but in this situation it messes up the visual rendering of the link element:

<a href="http://ninefour.co.uk"><p>This is my sample text</p></a>

Obviously this isn’t ideal.

So, I took a poke about in the textile class file and discovered that ‘TextileThis’ accepts a number of arguments. Wow, never realised that before.

function TextileThis($text, $lite='', $encode='', $noimage='', $strict='')

Well I have no idea what ‘encode’ (URL encode maybe) and ‘strict’ do but ‘image’ will remove images and ‘lite’ prevents textile from wrapping it’s output in paragraph tags.

Success!

Tag parsing in Textpattern articles

Did you know that you can nest Texpattern tags in your article body? This is super neat (and probably pretty obvious) but I never realised until now. I’ve been fiddling with a new section called ‘etc’ (maniacal rage inspired name) and wanted to add articles in the usual manner but needed to list a bunch of file downloads. At first I thought I’d have to hard code the relevant tags into my page template… Hoorah for tag parsing in articles! :)

With an RC5 release over at Textpattern.com it looks like things are gathering pace and Dean is ‘finally’ on the brink of a ’1.0’ release. I know I’ve said it before, but I think this time they really are getting close!

A breath of fresh air…

After months of ‘trying’ to find the time we eventually ‘made’ the time here at Mirashade to re-vamp our site.

mirashade, a breath of fresh air.

The initial designs were penned by Chris. I did some design development and then developed the XHTML and CSS using Homesite and TopStyle. Finally the site was deployed using Textpattern. We simply ran out of time to impliment our bespoke solution (Gubbins).

I’d love to hear your feedback and comments on any aspect of the design and implimentation. There are still some areas that need work, but we were keen to get the site ‘out there’.

Update: Mirashade.com is now featured in the CSS Vault and at CSS Beauty and Unmatched Style.

Textpattern plugins

Drew has been blogging about the fantastic feature in Textpattern which allows developers to quickly and easily write ‘plugins’ using standard PHP. Check out Drews post on the subject here.

Cooking with Textpattern

I’ve done a bit of an upgrade, I’ve finally gotton round to implimenting ‘Textpattern‘ in place of my old home baked blog authoring tool, which really didn’t rise to the challenge.

I’ve pulled across all previous blog entries, but have yet to drag the comments across.

If anything looks pear shaped or positively odd, please let me know. :)