1 Introduction
I have always wanted to build a synchronously updated static copy for my WordPress-based dynamic blog. On one hand, this is out of the pursuit of ”full-site caching” and ”always online” capabilities—after all, in the early days, the blog had not implemented disaster recovery and active-active deployment, and once WordPress itself went down, the entire site would experience access anomalies. On the other hand, I also hoped that in some special scenarios, such as publishing the blog to a private network (like DN42), or when the 443 port of some domains needs to be disguised (to mask the special role of certain paths on these domains), there could be a read-only copy that can run independently of the WordPress environment.
In fact, in the early days, I also tried other routes for ”dynamic blog staticization” solutions, such as the article on building a static blog with Hexo based on Cloudflare Pages (see:Home Data Center Series: Building a Static Blog with Hexo and Deploying It to Cloudflare Pages). At that time, messing around with this was actually to pave the way for subsequent ”staticization”: the idea back then was to later export WordPress articles as structured data and then import them into Hexo to regenerate a static site. This method is theoretically feasible, but ultimately made me give up: from format conversion to style customization, as well as the differences of the Argon theme on WordPress and Hexo, various details required extra effort, and the generated site always had a sense of fragmentation in visual effects, which was still a far cry from the ”authentic” static blog that is almost identical to the WordPress dynamic blog that I wanted.
Until recently, I discovered a very interesting WordPress plugin:Simply Static. It can directly staticize the entire WordPress website into HTML files and export them to the local directory of the host machine while retaining the original style and page structure. This method neither relies on content migration nor changes the front-end presentation; it is more like putting a ”snapshot layer detached from the database and PHP” behind WordPress, making me feel that this ”staticization” route is finally reliable.
2 Introduction to Simply Static Plugin
Simply Static is a plugin focused on ”full-site staticization” of WordPress websites. Its concept is not complicated but very practical: by simulating visits to all pages of the WordPress site, it ”crawls” these pages, converts them into standard HTML, CSS, JS, and static resource files, and finally exports them to a specified local directory, or directly uploads them to remote targets (such as GitHub, S3, FTP, etc.).
Simply put, its principle is more like a crawler running inside WordPress, which visits your website as a visitor and saves the rendered results of dynamic pages as static content. This is different from traditional caching plugins, which mostly improve response performance at runtime, while Simply Static is completely ”pre-rendered” and can still run independently after leaving the WordPress environment.
The benefits of this approach are very obvious:
- Static resources, extremely fast access: Since there is no database query and PHP execution overhead, the loading speed of static sites is usually far faster than dynamic sites.
- Extremely high availability: The exported HTML pages can be deployed on any static site platform, such as Cloudflare Pages, GitHub Pages, Vercel, etc. Even if the origin WordPress site goes down, the static copy remains online.
- Significantly improved security: Static sites have no attack surfaces like backends or databases. Even if publicly accessed, they are almost impossible to hack.
- Easy to integrate into automated workflows: Through scheduled tasks or Webhooks, it is even possible to achieve regular staticization and automatic deployment, forming a CI/CD-style content update workflow.
Of course, its ”staticization” does not come without a cost. Since static sites no longer have PHP execution capabilities, all functions relying on dynamic interaction (such as search, comments, login) will fail—however, if your goal is originally a ”read-only copy” or a cache acceleration layer, this is instead a very clean implementation path.
Simply Static itself supports three export modes:
- Local Directory Export(Local Directory): Writes the generated HTML files to a directory on the WordPress host machine, suitable for manual synchronization or deployment later.
- ZIP Archive Packaging(ZIP Archive): Automatically packages into a ZIP file after exporting, making it easy to download or transfer.
- Remote Deployment Mode(Remote URL): Can configure remote targets such as FTP, S3, or GitHub, and automatically upload and deploy after exporting, which is very suitable for a fully automated deployment chain.
Personally, I highly recommend the ”Local Directory Export” mode. Combined with a Git repository and scheduled scripts, it is not only easy to debug but also integrates the deployment process into the existing version control system.
Note: Why don't I recommend directly using Simply Static's remote deployment feature to publish the site to GitHub, but instead choose to manually push it using Git commands? Actually, the reason is very realistic:Because I can't afford Simply Static Pro(Many features that look ”automated and hassle-free” often have a line of small print behind them: ”Available for paid users”). Instead of relying on the remote synchronization feature provided by the plugin and eventually running into pitfalls due to permission or frequency limits, it is better to manage it yourself with Git, which is clear, controllable, and easier to integrate into your own deployment workflow. Although slightly ”primitive”, for individual users, this is precisely the optimal solution between cost and efficiency. As the old saying goes: ”You can still have dignity even when freeloading“.
3 Git Initialization (Optional)
This part of the content is not mandatory; it is only needed if you plan to store the static files exported by Simply Static in a Git directory and push them to a remote repository (such as GitHub) via Git commands. This article does not cover the specific operations of this part (it was originally included, but felt off-topic and not essential, so it was deleted; I will write a dedicated article on ”how to achieve fully automated updates for static blogs” in the future). The reason for mentioning it here is that if you have this need, you need to perform a series of Git-related initialization operations in a certain order before Simply Static exports the static files.
If you only save the exported directory locally and publish the website directly using web servers like Nginx, Apache, or OpenResty, you can completely skip this step, and it will not affect the normal use of the site. Simply put, if you do not have ”code hosting” or ”automated deployment” needs, then Git is not a must-have option here.
However, even for a purely static website, using Git to manage the exported versions can bring some additional benefits: such as version rollback, team collaboration, automated deployment (CI/CD), etc. Especially when you hope to synchronize this static site to remote nodes or integrate it into a larger publishing workflow in the future, a Git repository will be a very useful infrastructure.
4 Simply Static Plugin Installation and Settings
1 Simply Static Plugin Installation
Install directly using the plugin marketplace:

Once the installation is complete, simply click activate:

2 Simply Static Plugin Settings
2.1 Overview
The settings of the Simply Static plugin are actually very simple, with only two core parts:Replacing URLs and Deployment Settings: The former determines which domain name and protocol all internal links in the exported static pages should point to, and whether to force replacement; the latter is responsible for specifying where these static files are ultimately exported, such as packaging into a zip file or writing to a local directory. In most scenarios, once these two configurations are set, you can directly generate the static site, and almost all other settings can be kept at their defaults (the real reason is that almost all other settings are paid features~).
2.2 “General”-“Replacing URLs”:

Note: In the following text, my ”static” blog URL ”
https://staticblog.tangwudi.com“ will be used as an example.
Replacing URLs
This option determines how Simply Static handles internal links, such as posts, pages, and resource addresses, when exporting HTML. There are three options in the dropdown menu:
| Option | Meaning & Purpose | Recommended Scenario |
|---|---|---|
| Absolute URLs | All full internal links (“https://blog.tangwudi.com/xx/xx“) will be replaced, such as https://staticblog.tangwudi.com/xx/xx, while the original ”relative paths” within the site are not affected. |
Recommended for online-deployed static sites |
| Relative Path | Replace full internal links withrelative paths, such as /page/ or ../images/xx.jpg | Offline use, portable HTML files |
| Offline Usage | All links become purefile relative paths, such as ./page.html, suitable for serverless zip packages | Making offline documents, copying to USB drives, etc. |
For static sites intended to be deployed to Cloudflare Pages or self-built OpenResty,Absolute URLs is recommended, as it is the most stable and compatible.
Scheme and Host
When you select “Absolute URLs”, two additional configuration items will appear to define the link prefix:
| Setting Item | Description | Example |
|---|---|---|
| Scheme | Select the protocol used by the links, usually http or https | If your website uses HTTPS, select https:// |
| Host | Enter your static site domain name | e.g., staticblog.tangwudi.com |
The final result is that all internal links will be uniformly replaced with formats like:
https://staticblog.tangwudi.com/technology/article123/
This prevents the issue of residual original WordPress domain names and avoids resource cross-origin issues or loading failures.
Force URL Replacements
Disabled by default, this option means:Even if the link is already the correct URL, it is forced to be replaced again with your specified Scheme + Host.
Purpose:
- Fix some old domains that ”slipped through the net” in plugin/theme outputs;
- Resolve hardcoded links left by certain shortcodes or JS plugins;
- Avoid the exported site mixing multiple domains, which affects loading or caching;
- Unify link styles, which is beneficial for SEO and front-end deployment debugging.
Recommended to enable (especially when deploying on public domains or CDNs)
2.3 “Deploy”-“Deployment Settings”:

This part of the settings determines: the static HTML files generated by Simply StaticIn what way and where to ultimately exportThe free version supports two export methods, corresponding to different use cases.
1、Deployment Method (Export Method)
This is the method for exporting the static site. There are two options in the dropdown menu of the free version:
| Option | Meaning & Purpose | Recommended Scenario |
|---|---|---|
| ZIP Archive | Package the export results into a zip file for users to download and handle themselves | Manual backup and one-time transfer scenarios |
| Local Directory | Write the export results directly to a local directory on the server, suitable for automatic deployment | Recommended for synchronous deployment scenarios, such as git push or reverse proxy publishing |
2、Path (Export Directory Path)
This path is the directory path where the static files are actually written, and is only displayed after selecting Local Directory is selected. This path must be a path that the server where WordPress is located can access and write to.
If you deployed WordPress via Docker (like me), you need to mount the host machine's target directory inside the container using the ”-v” parameter. For example, to mount the default path of the website created in OpenResty installed via the 1Panel panel to the ”/export/static” path inside the WordPress container, use the ”-v” parameter as follows:
-v /opt/1panel/apps/openresty/openresty/www/sites/staticblog.tangwudi.com/index:/export/static
Then, in WordPress, fill in the Path of the Simply Static plugin:
/export/static
In this way, the generated static site content will be written directly into the Web service directory corresponding to the OpenResty website.
3、Clear Local Directory Before Deploy
This checkbox indicates: before each export,whether to clear the target directory first。
- It is recommended to check this to ensure no old files remain in the export directory;
- If you have some extra files that you do not want to be overwritten, or plan to upload them to object storage, the ”Clear Local Directory” option should not be checked. Otherwise, you cannot achieve the effect of ”incremental synchronization”, which is equivalent to re-uploading everything every time you update.
If you plan to automate synchronization or integrate into an existing Web service, it is recommended to choose the “Local Directory” mode and expose the host machine's target directory to the container in advance via mounting. For example, map /opt/.../index to “/export/static” inside the container, and then configure the corresponding path in the plugin (pay attention to the permissions of the index directory; incorrect settings will cause Simply Static export to fail). This way, the static content will go directly into the Web service directory after each export, which is very convenient to use with Git management or reverse proxy.
5 Exporting Static Site
1 Diagnose Compatibility Issues First
Before starting the export, let's check if there are any compatibility issues between Simply Static and URLs, servers, WordPress, plugins, file systems, or databases:

For example, in my case, there is a compatibility issue with the Redis plugin:

After disabling the Redis plugin, it looks normal:

2 Start Exporting

Then, depending on the performance of the host machine and the number of pages that need to be converted, it will take different amounts of time. My export time this time is as follows:

Final export results:

Note: Actually, this kind of export does not necessarily have to be performed on a VPS. You should know that VPS performance is generally not very good and is not suitable for resource-intensive operations (unless you are rich and don't care). If you insist on exporting on a VPS and have a large number of articles, it might take anywhere from tens of minutes to several hours, and during this period, the VPS's system resource consumption will spike. Therefore, if conditions permit, you can completely build a WordPress site on your high-performance home computer to perform this export operation, and then use git commands or GitHub Desktop to complete the push operation. Subsequently, the VPS only needs to git clone it to use.
3 Publish
Assuming that, as mentioned earlier, the directory exported by Simply Static is directly specified as the corresponding root directory of the web service software website (OpenResty in this case), then it is actually already accessible directly on the local network. However, to publish it to the public internet, one final step is required.
Taking publishing via Cloudflare Tunnel as an example, you only need to set the public hostname in the tunnel to point to port 80 of OpenResty. Generally, for cases where cloudflared is installed directly on the VPS, pointing directly to localhost:80 is sufficient. However, because I deployed it in a home data center, the structure is relatively complex: cloudflared is deployed on an LXC, while the redundant WordPress node is on another virtual machine, so I cannot directly use localhost:80, as shown below:

4 Actual Effect Demonstration

I must say, the fidelity is surprisingly high, except for the Font Awesome icon display issue:

This is because when I used Font Awesome icons in WordPress, I chose the local hosting method (see article:Home Data Center Series WordPress Icon Font Optimization: Locally Hosted FontAwesome, Saying Goodbye to API Limits), aiming to solve the issue of occasionally exceeding Font Awesome's monthly API request limit when previously importing via CDN.
But this ”optimization” strategy turned into a hidden trouble after converting to a ”static site”. Because tools like Simply Static export pure static HTML files, they do not parse or verify whether resources like JS and fonts are actually accessible. Once these locally hosted resource paths are not exported correctly (such as missing font files, path spelling changes, or missing MIME types), the front end will experience issues like icons not displaying or messed-up styles:
More importantly, Font Awesome usually relies on a whole set of font files (such as .woff2, .ttf, etc.) and related CSS or JS files. If any part is not exported or is improperly configured (such as missing MIME response headers), it will cause the browser to fail to load. In contrast, although the CDN hosting solution is subject to external networks, it can at least guarantee complete resources, correct paths, and matching types, making deployment much more worry-free.
Therefore, although local hosting is more flexible and controllable when running a dynamic blog, it may instead bring additional maintenance costs and compatibility issues when building a ”static version”. It is recommended that when exporting a static version, you prioritize a stable CDN solution, or ensure that local resources are complete, paths are correct, and service configurations are fully set up, in order to truly achieve a perfect static site with ”high fidelity and consistent experience”. But in my case, never mind, I'm too lazy to bother with it~~.
As for the actual effect after ”staticization”, everyone can also experience it directly:https://staticblog.tangwudi.com, and in the future, I will also keep this ”static” blog updated in sync with my main WordPress blog. After implementing the high-availability solution with active-active WordPress nodes, I have now further achieved the ”always-on” status of the "static" blog. Now my mind is completely at ease.
The fidelity of different WordPress staticization solutions cannot be generalized. The reason why I was able to achieve high fidelity after ”staticization” is mainly because the Argon theme I use is itself a theme with a clear front-end structure and few dependencies. It builds pages largely using native HTML + CSS + a small amount of JS, without relying too much on dynamic rendering or asynchronous loading interaction logic, nor does it have complex Ajax requests. Therefore, Simply Static can restore the complete page structure and visual style almost exactly as they were during the export process.
In addition, I rarely rely on dynamic shortcodes or features requiring login status (such as likes, tips, personalized user recommendations, etc.) in the theme, which also greatly simplifies the complexity of staticization. In other words, the “pure front-end friendliness” of the Argon theme itself makes it very suitable for being exported as a static site.
Overall, if you choose a highly dynamic theme that heavily relies on databases or login status, achieving high fidelity after staticization will be much more difficult, and may even require secondary development or customized export processes. On the other hand, a theme with a clean structure and simple logic like Argon is almost an ideal ”out-of-the-box” match for staticization.
6 Afterword
In fact, there is another extremely suitable use case for the ”staticization” of WordPress dynamic blogs—and that ispublishing blog content in China using an ICP-filed domain name. Since domestic compliance requirements don't allow comment sections anyway, and comments are one of the greatest dynamic values of WordPress, retaining dynamic logic in this scenario is actually a waste. It's better to simply export a pure static version and host it using domestic object storage + CDN. This easily achieves site-wide caching with excellent performance, and even saves you a WAF—after all, it's entirely static files, leaving virtually no attack surface.
If we go a step further, combining it with Cloudflare'sdynamic redirection feature(For example, implementing redirection based on the visitor's IP country or ASN), you can build an intelligent access strategy:
- Overseas visitorsAutomatically access the dynamic WordPress main site to get the full experience, including comments, subscriptions, backend interactions, and other functions;
- Domestic visitorsWill automatically redirect to the domestic ICP-filed domain name to access the static read-only version. The page loading speed is extremely fast (due to using a domestic CDN), and there is no need to endure Cloudflare's instability and ”negative optimization” in China.
This approach balances both functionality and performance, while also bypassing various domestic compliance restrictions and access barriers, which is equivalent to achievingdual entry points and an optimized experience. Best of all, this structure naturally supports ”incremental synchronization” and even ”automated deployment” with extremely low maintenance costs. It is highly suitable for blog owners who want to target both Chinese and English bilingual users and balance the experience of both domestic and international readers.
The next step is to fully automate the entire process: weekly scheduled automatic export via Simply Static, scheduled automatic git push to the GitHub repository, and automatic deployment to Cloudflare Pages. This will maintain a weekly scheduled automatic synchronization between the ”static” blog and the main WordPress blog. I will write a dedicated article later to document each step of this process.