Skip to content
gioser
ES

tawasuyu · Making

Your WordPress, without WordPress: the same site to the pixel, with its store, without a single line of PHP

A WordPress site is a program that runs every time someone visits, with its database, its plugins and its admin doors open to the internet. qhatu takes it whole, identical to the pixel —and with its store, if it has one—, and leaves nothing to execute: the same site, faster, and without a single line of PHP.

12 min readBy Gioser Editorial

Every time someone opens a page of a WordPress site, a program starts on the server: it reads the database, loads the theme, wakes up every plugin, builds the HTML and sends it. The same thing, over and over, for text that changes once a month. And all the while, that program leaves the doors it is administered through open to the whole internet. This article tells how qhatu —tawasuyu's content manager— takes a real WordPress site whole, leaves it identical to the pixel, brings its WooCommerce store along, and strips away everything that could be attacked.

Chart: on the left, WordPress with 9 of 9 programs answering anyone, with the list of their addresses —wp-login.php, wp-admin, xmlrpc.php, wp-json, the user list, author=1, readme.html, install.php, wp-cron.php—; on the right, qhatu and saywa with 0 of 9, 0 different pixels out of 3,278,400, 825 to 135 milliseconds and zero PHP
Measured on October 24, 2026 on a client's real site and its copy.

The site that is built on every visit

WordPress is the most common way to have a site, and for good reasons: it installs in an afternoon, there is a theme for everything, and a builder like Elementor lets you design without writing code. The price is paid later, in installments. Every plugin is someone else's code running with all of the site's permissions; every postponed update is a door; and the database, the login and the API stay listening around the clock, even if one person edits the site twice a month.

The site all this was tested on belongs to a real client: a retreat center built with WordPress, the WoodMart theme and Elementor Pro, with 64 pages, a gallery, a blog and two contact forms. An ordinary site, of the kind there are millions of. The request was simple: keep it exactly the same, and keep it easy to edit.

One command

What was done by hand on the first day —downloading the rendered site, cleaning what WordPress adds to every file name, re-pointing the forms— is now a verb:

qhatu absorb https://the-site.com/ folder

It reads the sitemaps WordPress publishes, downloads every page and everything it needs —stylesheets, scripts, images in all their sizes, fonts, icons—, and leaves every reference pointing to the local copy. It does not download what is not content: the cart, the admin panel, the feeds, the searches. If part of the site is only assembled by JavaScript in the browser, with --render each page first goes through a headless Chrome and is saved already assembled. On the client's site:

whatmeasured
pages64
resources (stylesheets, scripts, images, fonts)448, 45 MB
time, with a courtesy pause between requests6 minutes
broken references in the copy0

And it does not have to be WordPress: the same verb took a Joomla site, a Squarespace demo that builds everything with JavaScript, and the first website in history, CERN's, with zero broken references in all three.

Identical to the pixel, with a control arm

"Exactly the same" can be measured. The same page of the original and of the copy was opened in Chrome, at 1366 by 2400 pixels, and the two screenshots were compared point by point. On the home page and on a blog post, 0 different pixels out of 3,278,400. For that zero to mean something, the test has a control arm: each screenshot has 216,987 distinct colors, so it is not comparing two blank pages.

And honesty includes what did not come out zero. On a third page, 1,785 different pixels showed up in the menu strip. Before blaming the copy, the original was compared with itself, twice: it gave 1,642 and 0. It is the page itself, which does not paint the same way twice in a row.

No old link breaks

A site with years has links with years: on Facebook, in emails, on other blogs. WordPress answers addresses nobody typed by hand —/?p=123, /2023/05/a-post/, the categories, the feed— and a move that loses them leaves a trail of 404 errors. qhatu builds a table with all of them, and the server checks it before the files. Against the live site: 143 old addresses, none of them a 404 —55 that are still a page and 88 that the table takes to their new place—. And an invented one still gives a 404, which is what has to happen.

Nothing to hack

A WordPress scanner always starts the same way: it asks for the addresses every WordPress has. That same question was asked of both sites, in passive mode —only read requests to public addresses, without trying a single password—:

addresswhat it isWordPresscopy
/wp-login.phpthe login dooranswers404
/wp-admin/the panelanswers404
/xmlrpc.phpthe classic door for batch brute forceanswers404
/wp-json/the APIanswers404
/wp-json/wp/v2/usersthe list of who can log inanswers, with 3 names404
/?author=1the first author's usernametells itno
/readme.htmlthe exact versionanswers404
/wp-admin/install.phpthe installeranswers404
/wp-cron.phptasks anyone can triggeranswers404

Nine out of nine against zero out of nine. On top of that, the original announced in its own code the exact version of WordPress and of two of its plugins: exactly what an attacker looks for to cross against a list of known flaws. It is not that the copy has those doors better locked: it does not have them. There is no PHP to execute, no database to query, no users to guess.

Measuring this turned up a detail worth telling. The copy still said "WordPress" in an invisible tag of the HTML, inherited from the original: a scanner read it and announced a WordPress that no longer existed. The absorber now removes it.

And the contact forms, which in WordPress are one more plugin? On the copy they are handled by a WebAssembly function that runs on the server with declared capabilities: it can store what arrives, read the clock and send the notice by email, and nothing else. It cannot read the disk; what it did not ask for does not exist for it. The messages are read in the panel, and download as a spreadsheet. The search magnifier the copy can add to its menu is another function like that: it reads an index published along with the site, and there is no search server to attack.

And if it also sells

Many WordPress sites are also a store, with WooCommerce. A store is not a set of pages: it is a catalog with prices, variants and stock, and a checkout. So it is not copied as HTML: with --as-content, qhatu reads the catalog through the same public API WooCommerce's own cart uses, and every product goes into qhatu's own store with its name, its exact price, its currency, its images and one variant per combination —size, color—, with the sold-out one marked as sold out. The price never goes through a number with a decimal point: it is stored in cents, and at checkout the server recalculates it against the published catalog, so nobody pays whatever they like by sending another number.

It was tested against a real WooCommerce, with the sample products WooCommerce itself ships with: 16 products and 7 variants came in, and an instrument that compares the original store against the copy, product by product and variant by variant, came out identical. Its control arm: after absorbing, a price was changed and a variant sold out on the original, and the instrument named exactly those two differences. Each product's reviews come with it, at the foot of its page. And with a WordPress application password —the kind WordPress itself lets you create for this— comes how many units are left of each product and each variant too: the server counts down what is sold. Then a purchase was made: a hoodie, into the cart, paid with PayPal in its test environment, and the store came back saying the order was paid, with PayPal's capture recorded on the server side.

That store is online, to look at and to buy with play money: tienda.gioser.net.

And it does not look like two sites stuck together. What qhatu builds —the products, the list, the cart, the blog posts— goes inside the original site's header, menu, footer, colors and fonts. Measured: the header of a page that came from the original and that of a product built by qhatu give 0 different pixels. The phone menu opens on the copy even with the original WordPress already turned off, and it no longer offers "Checkout" or "My account", which do not exist on the copy.

Faster, and measured without cheating

Five pages, five cold loads on each side —a fresh browser per load, no cache—, alternating original and copy so that a bad streak on the network does not fall entirely on one side. The medians:

pagefirst bytelargest paintfull load
home2.5 s → 0.9 s6.1 s → 4.9 s9.9 s → 5.9 s
service page1.9 s → 0.8 s6.5 s → 3.8 s14.9 s → 5.4 s
long page with gallery2.3 s → 0.9 s11.7 s → 6.3 s22.3 s → 7.9 s
blog listing2.4 s → 0.7 s4.5 s → 4.1 s5.1 s → 5.3 s
a post2.3 s → 0.8 s5.9 s → 2.5 s7.0 s → 5.2 s

The bytes that travel are practically the same: it is the same page. What changes is the server. And there is a caveat an honest article has to make: the two sites are on different servers, in different places, and the copy was closer to where it was measured from. So the network was separated from the software. Opening the connection costs 392 milliseconds to the original and 179 to the copy; that is distance, not code. Subtracting one round trip on each side, what remains is the work of building the page:

WordPress: ~825 ms per page saywa: ~135 ms per page
The server's work, with network distance subtracted. Measured with curl, five requests on each side.

And on a phone there is something more. When publishing, qhatu prepares every large image in several widths and the browser picks the one it needs: on the client's home page, seen at 390 pixels wide, 72% fewer image bytes are downloaded, without moving a pixel on a desktop screen.

And it is still edited, in place

A static copy that cannot be touched would be a museum. qhatu's is edited from a panel that lives at its own address —nothing on the public site links to it—, on the page itself, just as it looks:

Screenshot: on the left, the qhatu panel with an article open —date, cover image and the body with its bar for bold, italics, headings, lists, quotes, links and images, and the Save button—; on the right, the same article published on the gioser blog, with its illustration and the heading «Qué es tawasuyu»
The qhatu panel and what it publishes, side by side: on the left you write, on the right is the article as a reader sees it. It is this very blog, which qhatu also builds.

And what the original built with Elementor no longer stays as HTML that can only be touched in place: with --as-content it comes in as qhatu blocks —heroes, columns, carousels, FAQs— that are edited with the block editor and painted with the site's theme. On the client's site, two of its Elementor pages came in as 22 and 12 blocks, five heroes with their background photo and three carousels of ten to twelve photos, without a single widget left without an equivalent and without one image that failed to download.

All of that runs on saywa, tawasuyu's web server. On the machine where this site lives, saywa and the project's own forge have already replaced four programs: the web server, the git forge, the proxy and the PHP interpreter. Someone wrote both pieces from scratch, in Rust, with a rule that repeats across the whole project: what was not measured is not claimed.

What it does not do yet

How to try it

The store in this article is at tienda.gioser.net, and its panel is open: at tienda.gioser.net/_/ anyone can get in with «Try it as an author» and edit it at will; their changes are wiped after 24 hours. The same qhatu builds this journal and the tawasuyu manual, and with one more line in its configuration it becomes a wiki: links by title, each page's signed history, and two people editing the same page at once without overwriting each other. To have the same on your own machine, a freshly created VPS is enough: qhatu server install --domain the-site.com leaves the server, the panel and the certificate running —measured on Debian 13 and Fedora 44, with a test certificate authority: the home page answers over HTTPS seven seconds after having access to the machine— and qhatu absorb brings the WordPress over. qhatu lives in the tawasuyu repository —git.tawasuyu.net, on its own server— under 02_ruway/qhatu, and saywa under 03_ukupacha/saywa. The instruments of this article —exposure, speed, pixels and the store comparison— are in scripts/qhatu-careo/: anyone can run them against their own WordPress and against its copy, and compare.

Background