Web design tutorials and tools since 2014Privacy
Search 125 articles

Web Design

WordPress to Static Site: How We Moved 146 Posts (Case Study)

Web Designer Hut ran on WordPress from 2014 until November 2026. Between November 4 and 9 we turned it into plain HTML files kept in Git. They deploy with a CI job, and the WordPress install stays parked on the server as a rollback. This is the full record of how we did it: the export, the cleanup, every kind of redirect we needed, what we replaced, what we lost, and what we measured. All the numbers come from this site’s own repository and server responses.

If you are still deciding whether static suits your site at all, read static vs dynamic websites first. If you are weighing other platforms, see our WordPress alternatives.

The Short Answer

  • Easiest route: the free Simply Static plugin exports your site to a ZIP. Deploying straight to a host, forms and search need Simply Static Pro at $99 a year per site.
  • Our route: crawl the live site, save every page as HTML, then clean it up in Git. This takes more work, but you end up owning plain files with no plugin in the loop.
  • The part that takes longest isn’t the export. Keeping every old URL working with 301s, and telling search engines about removed pages with 410s, took longer.
  • Simplest hosting for the export: Static.app takes the ZIP that Simply Static produces, hosts it with unlimited traffic and handles contact forms on its paid plans. It has a 7-day trial, then costs from $5 a month billed yearly.
  • Keep WordPress as a rollback. We switched the domain’s document root to a new folder and left WordPress untouched in the old one.
  • What changed: the home page went from a Lighthouse score of 74 to 97 and from 1,849 KB to 293 KB. The site folder shrank from 1.3 GB to under 150 MB, and there are no more core or plugin updates.

Why We Did It, and What We Expected

Web Designer Hut home page as rendered by WordPress and its theme before the move
The home page as WordPress rendered it, before the move.

Three reasons. First, the site is a blog: every page is the same for every visitor, so running PHP and a database on each request did nothing useful. Second, upkeep. WordPress core, the theme and every plugin needed updates, and a missed one is how sites get into trouble.

Third, ours did. In 2026 the WordPress install was compromised and began serving Japanese-language spam pages under paths like /product/ and /new-arrival/, plus spam query strings on the home page. Some real posts went missing or were damaged as well. A static site removes the code an attacker would target: there is no login page, no xmlrpc.php and no plugin code to exploit.

We expected faster pages and less maintenance. We also expected to lose the WordPress editor, comments and scheduled posts, and we accepted that, because one person edits this site and is happy working in HTML.

Your Options for Converting WordPress to Static HTML

There are three common ways to do it. Prices and plugin details were checked on November 12, 2026.

1. A static export plugin

Simply Static homepage with the headline Secure, fast, zero-maintenance WordPress
Simply Static is the most-installed static export plugin.

Simply Static has 30,000+ active installs on WordPress.org. The free version generates a static copy of your site and saves it as a ZIP file or to a folder on the server. Pro, at $99 a year for one site, adds deployment to GitHub, Netlify, Cloudflare Pages, S3, BunnyCDN or SFTP, plus incremental exports, working forms, search, comments and redirects. Its maker also sells Simply Static Studio, a hosted service, from $12 a month.

Staatic homepage with the headline Keep your WordPress out of reach and a table of requests bots try
Staatic deploys to more destinations on its free plugin.

Staatic is smaller, with 3,000+ installs. Its free plugin can deploy to a local folder, a ZIP, Amazon S3, GitHub, Netlify or SFTP, and it handles redirects, a custom 404 page and HTTP headers. Forms and search are premium features.

The big advantage of a plugin is that you keep the WordPress editor. You write in WordPress as before, then export, so WordPress keeps running somewhere, usually on a private address. The drawback is that you still maintain WordPress, just out of public view.

2. Crawl and save (what we did)

A crawler visits every page of the live site and saves the HTML, CSS, JavaScript and images exactly as visitors receive them. Afterwards you edit those files directly and WordPress is gone from the workflow. It works with any theme or plugin, because it only sees the output. The downside is the cleanup, described below.

3. Headless WordPress with a static site generator

WordPress stays as the editing back end, and a static site generator such as Astro, Eleventy or Hugo pulls content through the WordPress REST API or a GraphQL plugin and builds the site. You get the editor plus a modern front end, but you rebuild the theme from scratch and maintain two systems. It suits teams with developers and several non-technical writers.

ApproachKeeps the WordPress editorWordPress still runsEffortBest for
Export pluginYesYes, privatelyLowSites with non-technical editors
Crawl and saveNoNo (kept only as a rollback)Medium, mostly cleanupBlogs edited by developers
Headless + generatorYesYes, as an APIHighTeams rebuilding the front end anyway

Our Export and Cleanup

Timeline: November 4 export, November 5 clean up, November 6 deploy, November 9 restore and remove posts
The migration, day by day, from the repository’s commit history.

The first commit, on November 4, held 754 files: 137 dated posts, plus category, author and pagination pages, and 553 files under wp-content. The crawler saved files exactly as WordPress linked them, so some names still carried version strings, such as comment-reply.min.js?ver=7.1.4. The cleanup took the next five days:

  • Assets pointing at the live site. Many pages still loaded images, CSS and theme scripts from the WordPress domain. We downloaded those files, dropped the ?ver= suffixes and pointed every reference at the local copies. Without this step, the static site would have broken the moment WordPress went offline.
  • Clean internal links. We removed index.html from internal links and made canonical tags absolute, clean URLs.
  • Dates out of URLs. Posts lived at /2015/03/06/slug/. We moved them to /slug/ and merged nine posts that existed at both a dated and a short address.
  • WordPress leftovers. We stripped the WordPress generator tag and REST API links from every page head, and fixed shortcodes that had rendered as raw text.
  • CSS. The theme loaded large shared stylesheets. A script now works out which rules each page actually uses and inlines only those in the page.
  • Images. Everything under wp-content/uploads moved to /images/, with new WebP thumbnails.

The hack added a step most migrations won’t need. Fifteen posts, including our best static hosting roundup, were damaged or missing in the export, so we restored them from Wayback Machine snapshots taken before the compromise. Most of their images could not be recovered and were replaced later.

We also used the move to prune. Of 146 posts, we removed 45 that were paid API reviews, theme promotions or thin, dated lists, and expanded 11 thin ones. That left 101 posts. We have published 23 new ones since, including this one, for 124 today.

Keeping URLs and SEO: 301s, 410s, Sitemap, Canonicals

A static site can’t run PHP, but on Apache it still reads .htaccess, and that is where all our redirect rules live. Every old URL now falls into one of four groups.

301 for anything that moved

# Old dated permalinks to /slug/
RewriteRule ^[0-9]{4}/[0-9]{2}/[0-9]{2}/([^/]+)/?$ /$1/ [R=301,L]

# Images and theme files moved out of the WordPress folders
RewriteRule ^wp-content/uploads/(.*)$ /images/$1 [R=301,L]
RewriteRule ^wp-content/themes/(.*)$ /assets/themes/$1 [R=301,L]

# A removed post with a close replacement
RewriteRule ^free-login-form-psd/?$ /login-form-with-flat-design/ [R=301,L]

The image rule keeps old backlinks and Google Images results working. Three of the 45 removed posts had a close replacement, so they redirect instead of disappearing. Listing pages that no longer exist, such as the last pages of the old pagination and a renamed category, redirect to their nearest equivalent.

410 for anything removed on purpose

# Posts removed in November 2026 (42 slugs in four rules)
RewriteRule ^(zerossl|weatherstack-api|ipstack|...)/?$ - [G,L]

# Spam URLs from the compromise
RewriteRule ^product(/|$) - [G,L]
RewriteRule ^new-arrival(/|$) - [G,L]

# Spam query strings like /?i=77282594333
RewriteCond %{QUERY_STRING} ^[a-z]=[0-9]{8,}/?$ [NC]
RewriteRule ^(page/[0-9]+/?)?$ - [G,L]

The [G] flag returns 410 Gone. A 404 says “not found, maybe later”; a 410 says the page was removed deliberately, which tells search engines to drop it. Don’t also block these paths in robots.txt: a crawler that can’t fetch a URL never sees the 410. We point both 404 and 410 at the same themed error page with ErrorDocument.

Keep the query-string rule narrow. Ours only matches a single letter followed by eight or more digits, so ?utm_source= links and the site’s own search, ?s=css, still return 200.

Test every rule against the live server

Terminal-style list of live status codes: 301 for an old dated URL, a replaced post and an old image path, 410 for a removed post and spam URLs, 404 for wp-login.php and xmlrpc.php
Status codes from the live site on November 12, 2026.

After each change we request a sample of old URLs and compare the status codes with what we expect:

for u in /2015/03/06/css-dropdown-menu/ /zerossl/ /product/abc/ /wp-login.php; do
  curl -s -o /dev/null -w "%{http_code} %{redirect_url} $u\n" "https://webdesignerhut.com$u"
done

The WordPress endpoints that bots probe all day, /wp-login.php, /wp-admin/ and /xmlrpc.php, now return a plain 404.

Sitemap, canonicals and metadata

WordPress and its SEO plugin generated the sitemap, canonical tags and social tags. On a static site, that becomes your job. We wrote a new sitemap.xml and robots.txt, gave every page a self-referencing canonical, a meta description, Open Graph tags and JSON-LD, and made sure each page has exactly one H1. Our publishing script adds new posts to the sitemap automatically, so it can’t fall out of date.

Replacing the Dynamic Features

  • Search: WordPress searched the database. Now a script builds a JSON index of every post’s title, description and category, about 120 KB for the 124 posts here, and a small script searches it in the browser. For larger sites, Pagefind does the same job and loads only the parts of the index it needs.
  • Related posts and listings: once done by the theme, now generated by scripts that rewrite the category pages, pagination and a related-posts block whenever we publish.
  • Comments: dropped. The old posts had few, and we didn’t want a third-party script on every page. If you need them, Giscus stores comments in GitHub Discussions.
  • Forms: this site never had a contact form, so nothing to replace. On yours, point the form at a form backend, or use the built-in forms of a host such as Static.app; our HTML contact form guide shows how.
  • RSS: we lost it. WordPress generated /feed/, which now returns 404. It’s on our list to rebuild as a static XML file. Check your feed before you switch, because readers and aggregators depend on it.
  • Scheduled posts: gone. A post goes live when its merge lands.

Deploying: Git, CI and rsync, with WordPress as a Rollback

Diagram: merge to master, CI job runs rsync over SSH into a static folder served as the document root, with the WordPress folder parked as a rollback
The static folder is live; WordPress sits untouched next to it.

We didn’t move hosts. The site stays on the same server, managed with Plesk. We changed three things:

  1. A new folder. We created an empty static folder next to WordPress’s and backed up the WordPress files first (1.3 GB).
  2. A CI job. On every merge to the main branch, a GitLab CI job in a small Alpine container copies the repository’s src/ folder to the server with rsync --delete, so files removed in Git disappear from the server too. The SSH key and known-hosts entry live in protected CI variables. The job also writes a deploy.txt file with the commit hash and time, so a single request shows which version is live.
  3. The switch. We pointed the domain’s document root from the WordPress folder to static. That one setting is the whole cut-over, and the whole rollback: point it back and WordPress serves again, exactly as we left it.

Two details are easy to miss. The rsync --delete must exclude .well-known/, or the next deploy wipes your HTTPS certificate challenges. And back up the database too if you might ever delete the WordPress folder; a file backup alone can’t restore WordPress.

If you’d rather not run a server, the same static folder can go to Cloudflare Pages, Netlify or any host in our static hosting roundup.

A good fit for the plugin route: Static.app

Static.app homepage with the headline One-click hosting solution for your static website and a drop zone for ZIP files
Static.app hosts a static site from a ZIP upload.

If you export with a plugin, Static.app is the shortest path from WordPress to a live static site. Export a ZIP with the free Simply Static plugin, drag it into Static.app, and connect your domain. There is no Git, CI or server to set up, which makes it a good match for designers and small businesses rather than developers.

It also covers two of the gaps a static WordPress export leaves. Forms work by adding a static-form attribute to the form, with submissions collected in the dashboard, so you can drop the contact-form plugin. And you can set 301, 302, 307 or 308 redirects for moved pages. Redirects are set page by page, so a site with pattern rules like our dated-permalink redirect is better served by a host that reads a rules file. Traffic is unlimited on every paid plan.

Static.app has a 7-day trial, not a free plan. Starter costs $5 a month billed yearly, or $6 monthly, for 2 sites; Medium is $10 or $12 for 7 sites. Forms, custom domains and redirects need a paid plan. Prices checked on November 12, 2026.

Results After One Week

The site has been static since November 6. That is too early for search traffic to tell us anything, and we won’t pretend otherwise. This is what we can measure today.

MeasureWordPressStatic
Home page Lighthouse score (mobile)7497
Home page Largest Contentful Paint6.3 s2.4 s
Home page weight1,849 KB293 KB
Site folder on the server1.3 GB147 MB
Posts146124 (101 kept, 23 new)
Broken internal links (crawl of the live site)not measured0 across 170 pages
Core and plugin updates to applyOngoingNone
Deploys since the switchn/a41 merge requests in 7 days

The Lighthouse figures are medians of three mobile runs with Lighthouse 10.4, from our static vs dynamic comparison. Two caveats apply. The “before” pages were a static copy of WordPress’s output, so they leave out the time WordPress spent running PHP and queries; the real site was slower. And the site was redesigned at the same time, so not every gain comes from going static.

On search, Ahrefs still showed 3 ranking keywords and no estimated organic traffic on November 12. That is unchanged from November 10, when we last checked before this article. We will update this section with Search Console data once there are a few weeks of it.

What We Would Do Differently

  • Back up the database on day one. We backed up the files but not the database, so the rollback depends on the old install staying intact.
  • List every URL before you start. Pull the old sitemap, your top pages from Search Console and your top backlinked pages. Then test each one after the switch. We found the merged duplicates and missing posts only by comparing lists.
  • Rebuild the RSS feed before the switch. Not after.
  • Script everything you repeat. Publishing a post here now means running one script that writes the page, updates listings, the sitemap and search index, and renders the thumbnail. Doing that by hand on a static site is how pages drift out of sync.

FAQ

Can I convert WordPress to static HTML for free?

Yes. The free Simply Static plugin exports your site to a ZIP file, and Staatic’s free plugin can also deploy to S3, GitHub, Netlify or SFTP. You can also crawl your site and save the output. Free static hosts such as Cloudflare Pages and GitHub Pages can serve the result.

Will converting WordPress to static hurt my SEO?

Not if every old URL either still works or redirects with a 301, and removed pages return 410. Keep your titles, descriptions, canonicals and sitemap. Faster pages can help a little, but content and links matter far more.

Can I keep using the WordPress editor?

Yes, with an export plugin or a headless setup. WordPress keeps running privately and you publish by exporting. With crawl-and-save, as here, you edit the HTML instead.

What happens to comments and forms?

They stop working, because they need a server. Use a form backend for forms and a hosted service such as Giscus for comments, or drop them. Simply Static Pro and Staatic’s premium plan include form handling.

How do I roll back if something goes wrong?

Keep WordPress where it is, serve the static files from a different folder, and switch the document root. Switching it back restores WordPress. Back up both the files and the database before you start.

Is a static site more secure than WordPress?

It has far less to attack: no login page, no database and no plugin code running on requests. Your server, hosting account and Git repository still need strong passwords and updates.