WP Manifestindependent plugin directory
manifest / performance / wp-static-python

WP Static Python

WordPress plugin that generates a static HTML site via a Python script and serves static files first (Apache/Nginx).

by Chris · github.com/chrispengcn/wp-static-python

0stars
1release downloads
0forks

Install

The author publishes release zips, so WP-CLI can install straight from GitHub:

wp plugin install https://github.com/chrispengcn/wp-static-python/releases/download/v1.0.0/wp-static-python.zip

Readme

WP Static Python

A lightweight WordPress plugin that generates a static HTML snapshot of your site using a Python script, and configures your web server (Apache or Nginx) to serve static files first — falling back to WordPress dynamically when a static file does not exist.

Features

  • One-page admin dashboard under Settings → WP Static (or WP Static menu)
  • Auto-detects your sitemap (sitemap.xml, sitemap_index.xml, wp-sitemap.xml)
  • Generates copy-paste SSH commands — split into three single-line steps with a Copy button each
  • Installs Python dependencies from requirements.txt automatically
  • Outputs static files into <wordpress-root>/static/
  • Provides ready-to-use .htaccess (Apache) and nginx.conf snippets to enable "static first, dynamic fallback"
  • Works in Docker / local / production environments — commands use paths relative to the WordPress root

Repository Structure

wp-static-python/
├── wp-static-python.php          # Main plugin file
├── README.md
├── LICENSE
└── python/
    └── wpstatic/
        ├── wpstatic.py           # Static site generator script
        └── requirements.txt      # Python dependencies

When you upload the plugin ZIP to WordPress, this whole folder is extracted to wp-content/plugins/wp-static-python/ and is ready to activate.

Requirements

  • WordPress 5.0+
  • PHP 7.2+
  • Python 3 and pip available on the server (or in the Docker container)
  • Apache with mod_rewrite or Nginx
  • A public sitemap (WordPress core generates /wp-sitemap.xml automatically)

Installation

From WordPress admin (ZIP upload)

  1. Download the latest wp-static-python.zip from the Releases page (or clone this repo and zip the wp-static-python folder).
  2. In WordPress, go to Plugins → Add New → Upload Plugin.
  3. Choose the ZIP file and click Install Now.
  4. Click Activate Plugin.

If you download the source ZIP directly from GitHub (green "Code → Download ZIP"), WordPress can still install it. If the extracted folder name differs (e.g. wp-static-python-main), simply rename it to wp-static-python after extraction, or use a release ZIP.

Manual (FTP / SSH)

  1. Upload the wp-static-python folder to wp-content/plugins/.
  2. Activate the plugin through the Plugins menu in WordPress.

Usage

  1. Navigate to the WP Static menu in the admin sidebar.

  2. Confirm the detected Sitemap URL (modify if needed).

  3. Check Force refresh only if you want to overwrite previously generated static files (adds the -f flag).

  4. Copy and run the three SSH commands one by one in your server terminal:

    cd /path/to/wordpress
    python3 -m pip install -r ./wp-content/plugins/wp-static-python/python/wpstatic/requirements.txt
    python3 ./wp-content/plugins/wp-static-python/python/wpstatic/wpstatic.py 'https://yoursite.com/sitemap.xml' ./static/
  5. Configure your web server using the snippets shown on the admin page (also documented below).

  6. Visit your site — static HTML is now served first.

Web Server Configuration

Apache (.htaccess)

Add the following block before the default # BEGIN WordPress section in your WordPress root .htaccess:

# BEGIN WP Static Python - static first
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteRule ^$ /static/index.html [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/static/$1/index.html -f
RewriteRule ^(.+?)/?$ /static/$1/index.html [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/static/$1.html -f
RewriteRule ^(.+?)/?$ /static/$1.html [L]
</IfModule>
# END WP Static Python

# BEGIN WordPress
# ... default WordPress rules remain unchanged ...
# END WordPress

Nginx

Merge the try_files directive into your existing location / block inside the server block:

# Static first: look in /static, then fall back to WordPress
location / {
    try_files /static/$uri /static/$uri/ /static/$uri.html /static/$uri/index.html
              $uri $uri/ /index.php?$args;
}

# Keep your existing PHP handler, e.g.
location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;  # adjust PHP version
}

Test and reload:

sudo nginx -t && sudo systemctl reload nginx

How It Works

For a request such as /about/:

  1. The web server first checks static/about/index.html.
  2. If the file exists, it is returned directly — no PHP or MySQL overhead.
  3. If it does not exist, the request falls through to WordPress' index.php, which renders the dynamic page as usual.

After you change content in WordPress, re-run step 3 (the generator command) to refresh the static files. Purge CDN/page cache if applicable.

Python Script Reference

wpstatic.py <sitemap_url> <output_dir> [-f]

  • Recursively parses sitemap XML (including sub-sitemaps ending in .xml)
  • Downloads the homepage plus every URL found
  • Saves each page as <output_dir>/<path>/index.html
  • -f forces re-download by appending a random query string

Dependencies (requests, lxml) are installed via requirements.txt.

Frequently Asked Questions

Do I need root / sudo? You only need permission to write to the WordPress root directory (so that static/ can be created). Installing Python packages may require sudo or a virtual environment if your system Python is protected — you can also run the commands inside a virtualenv.

Does it work with Docker? Yes. Run the commands inside the container (where /var/www/html is the WordPress root), or on the host if the WordPress directory is bind-mounted — the commands use relative paths and work from either location.

What about WooCommerce / logged-in users? This plugin is best suited for mostly-static marketing / content sites. Dynamic pages (cart, checkout, my-account, admin, logged-in sessions) will fall through to WordPress automatically because no static files are generated for them — do not add such URLs to your sitemap.

How do I exclude a page from being static? Do not include it in your sitemap. You can also use a SEO plugin to set pages to noindex, or simply delete the corresponding folder under static/.

Changelog

1.0.0

  • Initial release: sitemap-based static generation, admin dashboard with copy-to-clipboard SSH commands, Apache and Nginx configuration snippets.

License

GPL-2.0-or-later. See LICENSE.

Read the full README on GitHub →

Releases

TagPublishedAssetDownloads
v1.0.0 Aug 22, 2026 wp-static-python.zip 1