abhibavishi/wp-to-static/SKILL.md
Convert a WordPress website to a static site and deploy to Cloudflare Pages. Mirrors the rendered HTML via SSH, extracts only referenced assets (shrinks 1.5GB+ to ~25MB), fixes URLs, self-hosts fonts, strips WordPress cruft, and deploys. Use when migrating a WordPress site to static hosting.
npx skillsauth add openclaw/skills wp-to-staticInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Convert a WordPress website to a pixel-perfect static site and deploy it to Cloudflare Pages. Zero attack surface, zero hosting cost, instant load times.
Before running this skill, the user MUST have:
gh auth status to verify. If not logged in, run gh auth login first.wrangler whoami to verify. If not logged in, run wrangler login first.eval "$(ssh-agent -s)"
ssh-add ~/.ssh/your_wp_key
~/.ssh/known_hosts.Required (stop and ask if any are missing):
WP_SSH_HOST — SSH hostname (e.g., ssh.example.com)WP_SSH_USER — SSH usernameWP_SSH_PORT — SSH port (e.g., 18765)WP_SSH_KEY — Path to SSH private key file (e.g., ~/.ssh/wp_key). Key must have chmod 600 permissions.WP_SITE_URL — WordPress site URL (e.g., https://example.com)WP_SITE_NAME — Short project name (e.g., mysite)Optional:
CF_ACCOUNT_ID — Cloudflare account ID for Pages deploymentGH_REPO_VISIBILITY — private (default) or publicssh-agent — keys are loaded into the agent before running, so no passphrase is passed via environment variables or command argumentsStrictHostKeyChecking=no) — the server must already be in ~/.ssh/known_hostsssh, ssh-agent, rsync, curl, git, gh, wrangler.gh auth status succeeds. If not, tell user to run gh auth login.wrangler whoami succeeds (if CF_ACCOUNT_ID is set). If not, tell user to run wrangler login.chmod 600).Test the connection using the key from ssh-agent:
ssh -i $WP_SSH_KEY -p $WP_SSH_PORT $WP_SSH_USER@$WP_SSH_HOST "echo connected"
If the key requires a passphrase and ssh-agent is not loaded, tell the user:
Please add your SSH key to ssh-agent first:
eval "$(ssh-agent -s)"
ssh-add /path/to/your/key
Then re-run /wp-to-static
If the host key is not recognized, tell the user to connect manually once first to verify and accept the host key:
Please connect to the server once manually to verify the host key:
ssh -i $WP_SSH_KEY -p $WP_SSH_PORT $WP_SSH_USER@$WP_SSH_HOST
Accept the host key, then re-run /wp-to-static
Do NOT use StrictHostKeyChecking=no. Do NOT bypass host key verification.
SSH in and find the WordPress public_html directory. Common locations:
~/www/DOMAIN/public_html/~/public_html/~/htdocs//var/www/html/Confirm by finding wp-config.php. Store path as WP_ROOT.
Run wget --mirror on the server (not locally):
cd /tmp && rm -rf static_mirror && mkdir -p static_mirror && cd static_mirror && \
wget --mirror --convert-links --adjust-extension --page-requisites --no-parent \
--restrict-file-names=windows -e robots=off --timeout=30 --tries=3 --wait=0.5 \
--user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
$WP_SITE_URL/ 2>&1 | tail -30
If wget is not available on the server, fall back to curl locally for rendered HTML.
Create ./build/site (NEVER use the project root as temp dir).
Exclude server-side code and sensitive files. Only static assets (images, CSS, JS, fonts) are needed. PHP files, config files, and other server-side code must NEVER be downloaded.
RSYNC_EXCLUDE="--exclude='*.php' --exclude='wp-config*' --exclude='.htaccess' --exclude='*.sql' --exclude='*.log' --exclude='debug.log' --exclude='error_log' --exclude='.env' --exclude='*.bak' --exclude='*.backup'"
rsync -avz $RSYNC_EXCLUDE server:/tmp/static_mirror/DOMAIN/ ./build/site/
rsync -avz $RSYNC_EXCLUDE server:$WP_ROOT/wp-content/uploads/ ./build/site/wp-content/uploads/
rsync -avz $RSYNC_EXCLUDE server:$WP_ROOT/wp-content/themes/ ./build/site/wp-content/themes/
rsync -avz $RSYNC_EXCLUDE server:$WP_ROOT/wp-content/plugins/ ./build/site/wp-content/plugins/
rsync -avz $RSYNC_EXCLUDE server:$WP_ROOT/wp-includes/ ./build/site/wp-includes/
After rsync, verify no PHP or config files were downloaded:
find ./build/site -name '*.php' -o -name 'wp-config*' -o -name '.htaccess' -o -name '.env' | head -20
If any are found, delete them before proceeding.
This is the key step. Parse all HTML and CSS files to find every referenced local file:
From HTML: src=, href=, data-src=, data-srcset=, srcset=, inline background-image: url()
From CSS: All url() references — resolve relative paths from CSS file location to site root.
Write the list to ./build/referenced-files.txt, then copy only those files to ./public/ preserving directory structure. This typically shrinks 1.5GB+ down to ~25MB.
In index.html and ALL CSS files:
$WP_SITE_URL/ → empty string (relative paths).ttf to ./public/fonts/@font-face src: to fonts/filename.ttf<link rel="preconnect"> for Google Fonts domainsCSS path resolution is critical. If CSS is at wp-content/uploads/cache/file.css:
wp-content/uploads/ → ../../wp-content/themes/ → ../../themes/wp-includes/ → ../../../wp-includes/Remove:
<meta name="generator" ...> (WordPress, WPBakery, Slider Revolution)<link rel="EditURI"...>, <link rel="alternate"...> (RSS, oEmbed)<link rel="https://api.w.org/"...>, <link rel="shortlink"...><link rel="profile" href="gmpg.org/xfn/11"><link rel="dns-prefetch"...> for fonts.googleapis.comwp-json root references in inline JSONKeep: Email addresses, <link rel="canonical"> (update to /)
Create ./public/_headers with aggressive caching for /fonts/*, /wp-content/*, /wp-includes/*.
Create ./public/_redirects redirecting /wp-admin/*, /wp-login.php, /xmlrpc.php, /feed/* → / (302).
python3 -m http.server from ./public/Before any git operations, remove the ./build/ directory to ensure no server-side code, PHP files, or sensitive data can accidentally be committed:
rm -rf ./build
Verify only ./public/ remains and contains no PHP or config files:
find ./public -name '*.php' -o -name 'wp-config*' -o -name '.htaccess' -o -name '.env'
This must return empty. If not, delete those files before proceeding.
Then deploy:
git init, commit ONLY ./public/ and .gitignoregit config http.postBuffer 524288000 (for binary assets)gh repo create $WP_SITE_NAME --private --source=. --pushCLOUDFLARE_ACCOUNT_ID=$CF_ACCOUNT_ID wrangler pages project create $WP_SITE_NAME --production-branch mainCLOUDFLARE_ACCOUNT_ID=$CF_ACCOUNT_ID wrangler pages deploy ./public --project-name $WP_SITE_NAMEStrictHostKeyChecking=no or bypass SSH host verification./build/ for temp files, ./public/ for output — only ./public/ is committed./build/ BEFORE any git operations to prevent accidental commits of server-side files./public/ contains no PHP or config files before committingtools
Use when the user wants to connect to, test, or use the McDonalds service at mcp.mcd.cn, including checking authentication, probing MCP endpoints, listing tools, or calling McDonalds MCP tools through a reusable local CLI.
development
Web scraping platform — Twitter/X data, Vinted marketplace, and general web scraping API
development
SlowMist AI Agent Security Review — comprehensive security framework for skills, repositories, URLs, on-chain addresses, and products (Claude Code version)
data-ai
去除中文文本中的 AI 写作痕迹,使其读起来自然。基于维基百科 AI 写作特征指南,检测 24 种 AI 模式。触发词:humanizer-cn、去除 AI 痕迹、去除 AI 写作痕迹、中文文本人性化。