Glaciate
An open-source, full-featured Wordpress Static Site plugin
Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/brian-maloney/glaciate/archive/refs/heads/main.zipPublish a WordPress site as static files. Every feature is free: there's no premium version, no license key and no tracking.
You keep writing in WordPress. Glaciate renders each page through your own site, exactly as a visitor sees it, rewrites its addresses to the public site, and publishes plain HTML, CSS and images that any host can serve without PHP or a database.
- Works with your theme and plugins. Block themes, classic themes and page builders all render as they do live.
- Rebuilds only what changed. While a page renders, Glaciate records the posts, terms, authors, settings and queries it used. Edit a post and only the pages that show it are rebuilt and redeployed.
- Publishes where you host. A folder on the server, a ZIP file, Amazon S3 or S3-compatible storage (with CloudFront invalidation), SFTP, a Git branch (GitHub Pages, GitLab Pages and similar), Netlify or Cloudflare. Credentials are stored encrypted, or set by constants and environment variables so they're never stored.
- Search and forms keep working. Search runs in the visitor's browser from an index published with the site. Contact Form 7, WPForms, Gravity Forms and comment forms send their submissions back to WordPress, directly or through a small receiver you host anywhere.
- Feels like WordPress. A "Publish to static" button in the editor, a status in the admin bar, Site Health checks, and a WP-CLI command for everything.
- Contacts nothing you didn't choose. The only outside requests go to the deploy target and captcha you configure.
readme.txt is the WordPress.org page, with the FAQ, the external services list and the changelog.
Requirements
- WordPress 6.9 or later (tested up to 7.1), single site or multisite
- PHP 7.4 to 8.5
- Pretty permalinks (anything but "Plain")
- A server that can make HTTP requests to its own address. Behind a proxy or in a container, point it at the web
server with
define( 'GLACIATE_CONNECT_TO', '127.0.0.1:80' );in wp-config.php.
docs/SUPPORT.md has the full support matrix and what each deploy target, search mode and form plugin needs.
Install
Use a release ZIP from GitHub Releases: it includes the plugin's
PHP dependencies, and a .sha256 file next to it checks the download. Upload it under Plugins → Add New → Upload
Plugin and activate it. A ZIP installed this way doesn't update itself; install the next release the same way.
A Git checkout has no dependencies installed. Run composer install --no-dev in the plugin folder (Composer needs PHP
8.1 or newer for this step, which also prefixes the bundled libraries), or build the release ZIP yourself with
npm run build:zip (see Development).
Quick start
- Go to Static Site in the admin menu.
- Choose where the static site goes.
- Click Publish my site.
From then on, changes are published right after you save, at set times, or when you click Publish. A full rebuild runs nightly as a safety net.
The same works from WP-CLI:
wp glaciate target set s3 bucket www.example.org
wp glaciate target set s3 region eu-west-1
wp glaciate target set s3 access_key_id AKIA...
printf %s "$AWS_SECRET_ACCESS_KEY" | wp glaciate secret set s3 secret_access_key
wp glaciate target check s3
wp glaciate settings set target s3
wp glaciate build --full --sync
wp glaciate status
wp glaciate why /about/ # what a page depends on
wp glaciate doctor # the Site Health checks
wp help glaciate lists every command.
Extending
Every stage has actions and filters, listed in docs/HOOKS.md. Deploy targets are pluggable through
Glaciate\Deploy\DeployerInterface and the glaciate_register_deployers action. Themes can mark what search
indexes with data-glaciate-search and data-glaciate-search-ignore, and other forms with
data-glaciate-form="name".
How it works
- docs/ARCHITECTURE.md: the build pipeline, dependency tracking, deployers, search and forms.
- docs/THREAT_MODEL.md: what Glaciate protects and how.
- docs/DECISIONS.md: the non-obvious choices and why they were made.
Development
There's no PHP on the host. Everything runs in Docker through wp-env, so you need Docker and Node.js 20 or later.
npm install
npm run env:start # WordPress on http://localhost:8888 (admin / password), tests site on :8889
npm run composer install
npm run lint:php # WordPress Coding Standards and PHP 7.4 compatibility
npm run test:unit # no WordPress loaded
npm run test:integration # against the WordPress test suite
npm run test:js # search and forms clients, in Node
npm run test:system # real builds over HTTP (erases the :8889 site's content)
npm run test:e2e # Playwright: live vs static screenshots (erases the :8889 site's content)
npm run build:zip # build/glaciate-<version>.zip from the committed tree
npm run sftp:start and npm run git:start start the throwaway servers the SFTP and Git deploy tests need; without
them those tests skip. CLAUDE.md has the project's conventions and rules for changes.
To release, bump Version and GLACIATE_VERSION in glaciate.php and Stable tag in readme.txt, add the
changelog entry, commit, and push an x.y.z tag. The Release workflow runs CI on the tag, builds the ZIP, runs Plugin
Check on it and publishes a GitHub Release with the ZIP and its checksum. To release an existing tag, run the workflow
by hand with that tag.
Security
Please report vulnerabilities privately; see SECURITY.md.
License
GPL-2.0-or-later; see LICENSE. The bundled Action Scheduler is GPL-3.0-or-later, so the distributed plugin as a whole is under GPLv3 terms. phpseclib and its paragonie dependencies are MIT.