to-wordpress
Health Uyari
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Basarisiz
- rm -rf — Recursive force deletion command in package.json
- process.env — Environment variable access in src/agents/claude.ts
- process.env — Environment variable access in src/agents/codex.ts
- process.env — Environment variable access in src/agents/copilot.ts
- process.env — Environment variable access in src/agents/index.ts
- process.env — Environment variable access in src/cli.tsx
Permissions Gecti
- Permissions — No dangerous permissions requested
This TypeScript-based agent automates the migration of content from various formats (like Markdown files, PDFs, and other static site generators) into WordPress. It orchestrates AI coding assistants to autonomously generate themes, plugins, and import content using an automated attempt, test, and fix loop.
Security Assessment
The tool accesses environment variables across multiple files, likely to manage API keys for the AI agents (Claude, Copilot, Codex). However, the automated scan failed due to a recursive force deletion command (`rm -rf`) found in the `package.json` file. While common in build scripts, if this command is improperly configured or executed unexpectedly, it poses a significant risk of unintended data loss. No hardcoded secrets were detected, and it does not request explicitly dangerous execution permissions, but the inherent nature of an autonomous script executing shell commands requires careful oversight. Overall risk is rated as Medium.
Quality Assessment
The project is actively maintained, with its most recent push happening today. It is properly licensed under the standard MIT license, which is favorable for open-source adoption. However, it suffers from extremely low community visibility, currently sitting at only 5 GitHub stars. This indicates a lack of extensive peer review, testing, and community trust.
Verdict
Use with caution — while the tool is active and MIT-licensed, the low community adoption and presence of risky recursive deletion commands in its scripts warrant a thorough manual code review before execution.
Migrate anything text-shaped to WordPress — driven by Claude Code, GitHub Copilot CLI, or OpenAI Codex. Generates a block theme (FSE), Gutenberg blocks from legacy shortcodes, a site plugin replicating every SSG-level plugin, with an autonomous attempt→test→fix loop.
Migrate anything text-shaped to WordPress — driven by your AI coding agent of choice.
Point it at a Jekyll / Hugo / Eleventy / Gatsby / Next / Astro / Hexo /
Docusaurus / MkDocs site, a WordPress WXR export, a Medium or Substack
export, a folder of Word documents, a spreadsheet of rows, a library of
PDFs, an EPUB, a GitHub repo README, a pile of markdown notes, or plain.txt files. Walk away. Come back to a fully working, pixel-close
WordPress underwp-env
with a block theme (FSE), a site plugin that replicates every
SSG-level plugin and custom endpoint, imported content and media,
preserved permalinks, legacy shortcodes turned into real Gutenberg
blocks, and an autonomous attempt → test → fix verification loop.
Install · Quick start · Agents · How it works · Supported sources · CLI · FAQ
Why
Moving a content-heavy static site to WordPress by hand is a week of
template translation, shortcode rewrites, data shuffling, and URL
remapping. to-wordpress collapses that into one command: a
deterministic TypeScript pipeline drives your chosen AI coding agent —
GitHub Copilot CLI, Claude Code, or OpenAI Codex — in a
hybrid orchestration. The tool owns phase transitions, file I/O,
verification, and retries; the agent handles the creative parts
(templates, custom blocks, edge-case normalization, diagnosis and
repair on failure).
What lands in wp-content/:
- A bespoke block theme (FSE) —
templates/*.html,parts/*.html,theme.jsonv3, matching your source DOM. - A site plugin replicating every non-theme concern including
custom SSG plugins and endpoints (Jekyll_plugins/*.rb→
WordPress rewrite rules + dynamic templates;/llm/endpoints,
generators, category pages, custom feeds). - Legacy source shortcodes converted into real Gutenberg blocks
(block.json apiVersion 3,render.php,edit.js,style.css) —
content is rewritten to use native block markup, not[shortcode]
fallbacks. - Posts, pages, terms, menus, users, featured images — imported via
wp-cliwith original permalinks preserved by default. - A self-written
WORDPRESS_MIGRATION.mdthat
documents every decision so you can audit or replay the run.
Every phase runs as an autonomous agentic loop — attempt, test,
fix, repeat. No user prompts. If a phase crashes, the agent is handed
the error + recent logs and asked to repair before the next retry.
Install
to-wordpress is meant for one-shot runs, so use npx — no global
install needed:
npx to-wordpress ./path/to/your-site
Or install globally if you iterate on the same source:
npm install -g to-wordpress
to-wordpress ./path/to/your-site
Requirements
- Node.js ≥ 20
- Docker (for
wp-envand the source-prerender container) - At least one AI agent CLI — pick whichever you already pay for:
- GitHub Copilot CLI (
copilot):brew install --cask github-copilot-clithencopilot login - Claude Code (
claude): docs.anthropic.com/claude/docs/claude-code - OpenAI Codex CLI (
codex): github.com/openai/codex
- GitHub Copilot CLI (
The tool is self-contained otherwise — no Ruby, no PHP, no wp-cli on
the host. wp-env runs WordPress in Docker and the tool talks to
wp-cli through it.
Quick start
# 1. Clone or cd into any static site
git clone https://github.com/you/your-jekyll-site
cd your-jekyll-site
# 2. Run the migration (default agent: claude)
npx to-wordpress .
# 3. Open the result
open http://localhost:8888
Prefer GitHub Copilot?
npx to-wordpress . --agent copilot
Prefer Codex?
npx to-wordpress . --agent codex
When it finishes you'll have:
your-jekyll-site/
├── .wp-env.json # theme + plugin + content mounted into WordPress
├── WORDPRESS_MIGRATION.md # the plan + per-phase status + state block
└── WORDPRESS_MIGRATION/
├── theme/ # generated block theme (FSE)
│ ├── style.css
│ ├── theme.json # version 3 — presets, fonts, templateParts
│ ├── functions.php
│ ├── templates/ # HTML block templates
│ ├── parts/ # header.html, footer.html, …
│ └── patterns/ # filesystem block patterns
├── plugin/ # site plugin
│ ├── <slug>.php # bootstrap only (header + include loop)
│ ├── includes/ # cpt.php, endpoints.php, redirects.php, …
│ └── blocks/ # Gutenberg blocks generated by blockify
├── content/ # canonical markdown with block markup
├── media/ # collected image assets
├── rendered/ # prerender output (ground truth)
├── import-manifest.json # exact payload fed to wp-cli
├── blocks.json # manifest of blocks blockify generated
├── shortcodes.json # legacy shortcode names (for back-compat)
├── redirects.json # old-path → new-path map
└── verify-report.json # URL parity + count diff from the last run
Agents
Pick your agent via the --agent flag or the TOWP_AGENT env var.
Every phase is agent-agnostic — the same prompts drive any of them,
and the TUI renders events uniformly.
| Agent | Flag | Model default | Override env |
|---|---|---|---|
| Claude Code | --agent claude (default) |
claude-sonnet-4-5 |
CLAUDE_MODEL |
| GitHub Copilot CLI | --agent copilot |
gpt-5.4 |
COPILOT_MODEL, COPILOT_EFFORT |
| OpenAI Codex CLI | --agent codex |
(agent's own default) | CODEX_MODEL |
# One-off override
npx to-wordpress . --agent copilot
# Sticky selection via env
export TOWP_AGENT=codex
npx to-wordpress .
# Specific model (claude is the default, override its model)
CLAUDE_MODEL=claude-opus-4-5 npx to-wordpress .
Adding a new agent is a small file undersrc/agents/ implementing one AgentSpec interface
(binary, arg builder, event parser).
How it works
flowchart LR
src[Source site] --> D[Detect]
D --> P[Plan]
P --> B[Boot wp-env]
B --> T[Theme]
T --> N[Normalize]
N --> BL[Blockify]
BL --> PL[Plugin]
PL --> I[Import]
I --> V[Verify]
V --> TF[Testfix]
TF --> WP["Working WordPress @ localhost:8888"]
Every phase runs through a generic agentic loop:
flowchart TD
Start[Phase] --> A[attempt]
A -->|throws| R[agent diagnoses + patches] --> A
A --> T{test}
T -->|pass| OK[phase ok]
T -->|fail, fix budget| F[agent fixes] --> T
T -->|fail, exhausted| Fail[phase fail]
No user prompts. Every retry decision, every repair invocation, every
fix-pass is parametric via --max-attempts, --max-fix-passes, and--fail-strategy.
| # | Phase | What it does |
|---|---|---|
| 1 | Detect | Probes the source with one detector per SSG. Falls back to a Copilot/Claude/Codex-driven freestyle detector that reads files and never skips a folder. |
| 2 | Plan | Produces WORDPRESS_MIGRATION.md with a template map, a feature-to-plugin map, permalink structure, and acceptance criteria. Fully parametric — all choices come from CLI flags with sensible auto-detected defaults. |
| 3 | Boot wp-env | Writes .wp-env.json, mounts your theme + plugin + work dir, runs npx wp-env start, verifies GET / returns 200. |
| 4 | Theme | Builds the source to capture ground-truth HTML, mirrors _sass/, assets/, _data/, _layouts/, _includes/ into the theme dir, then drives the agent to emit a block theme — theme.json v3, HTML block templates, patterns, functions.php — whose DOM matches the reference. |
| 5 | Normalize | Turns every post/page into canonical markdown with a fixed front-matter schema. Unusual cases are handed to the agent with a strict edge-case prompt. Emits shortcodes.json listing every Liquid include found in content. |
| 6 | Blockify | For every unique shortcode, the agent generates a proper Gutenberg block (block.json apiVersion 3 + render.php + edit.js + style.css) under plugin/blocks/<name>/. Content files are then deterministically rewritten: [wpify_figure src="…"] becomes <!-- wp:theme-slug/figure {"src":"…"} /-->. |
| 7 | Plugin | Generates a site plugin covering CPTs, taxonomies, custom REST routes, SSG-plugin replication (Jekyll _plugins/*.rb generators and custom endpoints like /llm/ ported to WordPress rewrite rules + dynamic templates), comments, analytics, cookie banner, redirects, options page. Registers all the blocks blockify produced. |
| 8 | Import | Runs a generated PHP script via wp eval-file inside the container to upsert posts, terms, menus, users, and media; sets show_on_front; populates the primary menu from _data/menu.yml. |
| 9 | Verify | Counts posts per type with wp-cli, fetches a sample of source URLs, diffs titles / H1s / HTTP status. Writes verify-report.json. Runs its own internal fix loop: on failure, feeds the report to the agent for surgical edits + re-verifies until clean or the fix budget is exhausted. |
| 10 | Testfix | HTTP endpoint sweep against the live WordPress (up to 60 paths: /, blog index, originalPermalinks from index.json). 404/500/timeouts/fatal-error HTML markers trigger an agent-driven fix pass up to --max-fix-passes times. |
Autonomous retries
Every phase respects the same retry/repair contract:
- On crash: the agent is given the error message + the last 120
lines of logs and asked to make a surgical repair. Retry up to--max-attempts(default 3). - On test fail: the test result report (structured JSON) is fed
back to the agent with the fix prompt. Retry up to--max-fix-passes(default 3). - On exhaustion: behavior controlled by
--fail-strategy:continue(default) — mark phase failed, proceed to next.skip— mark phase skipped, proceed to next.abort— stop the migration with exit code 2.
No user input needed at any point. Good for CI.
Supported sources
to-wordpress ships detectors for every shape of content we've seen —
from real SSGs down to "a folder of PDFs". Each detector emits a
detector briefing that steers the theme, plugin, plan, and
normalize phases; binary/tabular formats are first routed through a
per-format conversion prompt (see src/prompts/convert-*.md)
that turns the raw source into canonical markdown before the rest of
the pipeline runs.
Static-site generators
| Source | Kind | What ships |
|---|---|---|
| Jekyll | jekyll |
Posts (_posts/, _drafts/) + any collections/<x>/, pages, layouts, includes, sass, _data/*, _plugins/*.rb source code (ported to WordPress), feature-level detection (giscus, mailchimp, analytics, dark mode, OG/Twitter) |
| Hugo | hugo |
Content sections → collections/CPTs, layouts/**/*.html, data/**/*, static/ |
| Eleventy | eleventy |
src/ or content/ posts, njk/liquid/hbs layouts |
| Hexo | hexo |
source/_posts/ posts + source/*.md pages, permalink preserved from _config.yml |
| Astro | astro |
src/content/<collection>/ collections + src/pages/*.{astro,md,mdx} pages |
| Gatsby | gatsby |
src/pages/*.{tsx,jsx} + content/**/*.md(x) |
| Next.js | next |
App/Pages router + content/ / posts/ / blog/ markdown |
Documentation frameworks
| Source | Kind | What ships |
|---|---|---|
| Docusaurus | docusaurus |
docs/ → docs collection, blog/ → posts, admonitions → Gutenberg groups |
| MkDocs (+ Material) | mkdocs |
docs/ collection, mkdocs.yml nav mirrored in WordPress menu |
CMS / platform exports
| Source | Kind | What ships |
|---|---|---|
| WordPress WXR | wp-wxr |
Full .xml dump: posts, pages, CPTs, categories, tags, authors, featured images |
| Ghost export | ghost-export |
Ghost JSON dump (posts, tags, users) |
| Medium export | medium-export |
posts/<date>_<slug>.html → posts, gists/tweets → Gutenberg embeds, canonical URL preserved |
| Substack export | substack-export |
posts.csv + posts/<id>.html → posts, paid-only → private, podcasts → podcast CPT |
Raw documents / text piles
| Source | Kind | What ships |
|---|---|---|
| Word bundle | docx-folder |
Folder of .docx / .doc / .rtf → one post per document (pandoc/mammoth) |
| Spreadsheet | xlsx-sheet |
.xlsx / .xls / .csv / .tsv → one post per row, column → front-matter field |
| PDF library | pdf-folder |
Folder of .pdf → one post per document, figures become Gutenberg image blocks |
| EPUB books | epub-book |
One .epub → one post per chapter, book metadata → site identity |
| Plain text | text-folder |
Folder of .txt / .rst → one post per file (first line = title) |
| Markdown pile | markdown-folder |
Obsidian / Notion / Zettelkasten exports, wiki-links preserved |
| Plain HTML | plain-html |
Every .html file as a page, every .md file as a post |
Code repos
| Source | Kind | What ships |
|---|---|---|
| GitHub repo | github-repo |
README → SaaS landing page (hero + feature grid + install CTA), docs/ → docs collection, LICENSE/CHANGELOG/CONTRIBUTING → separate pages |
Fallback
| Source | Kind | What ships |
|---|---|---|
| Anything else | unknown |
Deterministic file walker + agent-driven schema fill — never skips a folder |
Adding a new source type
~60 lines of code and one prompt:
- Drop a detector file in
src/detectors/,
implementmatch()+detect(). - Register it in
src/detectors/index.ts. - If the source isn't already markdown, declare
rawSources[]on
theDetectedContext, pick (or add) aRawSourceFormatinsrc/types.ts, and write asrc/prompts/convert-<format>.md.
CLI
Usage: to-wordpress [options] [source]
Migrate any codebase to WordPress. Hybrid orchestration with your AI agent.
Arguments:
source path to the source site to migrate (default: ".")
Options:
-v, --version print version
--agent <kind> which AI agent CLI to use: claude|copilot|codex
(env: TOWP_AGENT) (default: "claude")
--fresh tear down previous wp-env + wipe WORDPRESS_MIGRATION/
--branch <name> git branch for migration work (default: "to-wordpress")
--no-git disable git init / branching / per-phase commits
--skip-boot skip wp-env start (assumes already running)
--skip-copilot use deterministic fallbacks only, don't invoke the agent
-y, --yes headless mode (no TUI, log to stdout)
--only <phase> run only this phase
--from <phase> start from this phase (skip earlier ones)
--until <phase> stop after this phase (skip later ones)
--max-attempts <n> max crash-retry attempts per phase (default: 3)
--max-fix-passes <n> max test-fail-fix iterations per phase (default: 3)
--fail-strategy <strategy> abort|skip|continue on exhaustion (default: "continue")
Plan overrides (no interactive prompts — everything parametric):
--permalinks <mode> keep (mirror source URLs) | default (/%postname%/)
(default: "keep")
--cpts <mode> all (CPT per collection) | none (import as posts)
(default: "all")
--no-redirects skip generating redirects.json
--front-page <slug> static front page slug (auto-detected if omitted)
--blog-index <slug> blog index page slug (auto-detected if omitted)
--privacy-page <slug> privacy policy page slug (auto-detected if omitted)
--admin-user <name> WP admin username (default: "admin")
--admin-password <pass> WP admin password (default: "password")
--admin-email <email> WP admin email (default: "[email protected]")
-h, --help display help
<phase> is one of: detect, plan, boot, theme, normalize,blockify, plugin, import, verify, testfix.
Re-running just the theme
State is persisted inside WORDPRESS_MIGRATION.md, so you can resume
from any phase:
npx to-wordpress ./my-site --from theme --skip-boot
Fully non-interactive (CI)
npx to-wordpress ./my-site -y \
--agent copilot \
--permalinks keep \
--cpts all \
--max-attempts 5 \
--fail-strategy abort
Skip the agent entirely
npx to-wordpress ./my-site --skip-copilot --until normalize
Skipping the agent means every agent-driven step uses the deterministic
fallback — you still get detect, plan, normalize, and import, just
without the pixel-perfect theme transforms, custom blocks, or fix loops.
The migration doc
to-wordpress writes a live, human-readableWORDPRESS_MIGRATION.md inside
your source repo. It contains:
- The phase table with status + timestamps.
- Overview of the migration and permalink strategy.
- A template-mapping table (every source layout/include → WP file).
- A feature-to-output mapping (theme vs plugin vs external plugin).
- Static page list with roles (front, blog-index, privacy, contact).
- A
TOWP:STATEJSON block at the bottom the tool reads back on resume.
You can commit this file — re-running to-wordpress updates it in
place rather than re-planning from scratch.
Prompts
Every agent-driven phase runs with a rigorously structured prompt insrc/prompts/. A shared preamble
(_shared.md) gives every phase the same
autonomy + fidelity contract; each phase adds:
- Explicit Scope (which dirs may be written).
- Explicit Required output (every file that must exist).
- Non-negotiable rules (proper escaping, WP best practices,
apiVersion 3 on blocks,theme.jsonv3,get_block_wrapper_attributes()). - Banned anti-patterns (no TODOs, no Lorem ipsum, no hard-coded
localhost URLs, no silenced PHP errors, no classic theme files in a
block theme). - A self-check the model walks before stopping.
The prompts draw expert-level WordPress knowledge from
WordPress/agent-skills:
block theme structure, Settings API patterns, REST API route
registration, Gutenberg block metadata, security baseline (nonces +
capabilities + sanitization/escaping), activation/deactivation hook
rules.
FAQ
Which agent should I pick? All three work end-to-end. The default
is Claude Code because its thinking deltas give the richest "Muse"
panel and its tool_use events are clean and complete. Copilot streams
the most detailed event firehose (reasoning summaries, fine-grained
tool calls) if you're already paying for it. Codex is terse and fast.
Switch with --agent <kind> or TOWP_AGENT.
Is my data safe? The tool writes everything underWORDPRESS_MIGRATION/ inside your source repo and to a localwp-env Docker volume. No network calls except to the agent's API
and Docker Hub. Nothing is sent to your live WordPress until you
decide to deploy the generated theme/plugin.
Why wp-env? It pins WordPress + PHP versions, runs wp-cli
in-container, and tears down cleanly. You can export the database
afterwards with npx wp-env run cli wp db export.
Block theme, really? Yes — generated themes target Full Site
Editing with theme.json v3, HTML block templates, filesystem
patterns, and custom dynamic blocks where needed. No classicheader.php/footer.php files exist. This matches where WordPress is
going (6.9+).
What happens to my Jekyll _plugins/*.rb? The detector reads
their source, passes it to the plugin prompt, and the agent writes
equivalent WordPress code. A typical example: llm_generator.rb
(creates a parallel /llm/{slug}/ markdown view) becomesincludes/endpoints.php with add_rewrite_rule +template_include + an activation hook that flushes rewrite rules.
What about my Liquid shortcodes? The blockify phase turns every_includes/framework/shortcodes/<name>.html into a proper Gutenberg
block (block.json apiVersion 3, render.php, edit.js, style.css).
Post content is rewritten to use native <!-- wp:slug/name {…} -->
block markup instead of [shortcode] syntax, so the block editor
shows them as real editable blocks.
What about pixel-perfect? The theme phase builds your source site
into HTML first (inside a container so host Ruby/Node versions don't
matter), then feeds that ground-truth DOM to the agent as the exact
target. Verify re-fetches your local WP and diffs structure + titles +
status; any drift goes back to a scoped fix loop.
Can I use a live WordPress instead of wp-env? Not yet — the
import uses wp eval-file inside the wp-env cli container. Remote
WP-via-REST-API is a planned target.
Does it migrate comments? Comments stay wherever they live
(giscus/disqus/commento). The plugin re-attaches the same integration
in WordPress so threads keep working.
What's the agent bill? Expect 5–8 agent sessions per full run
(detect freestyle if needed, plan, theme, blockify, plugin, per-post
normalize edge cases, verify-fix, testfix). A ~40-post Jekyll site
runs in ~20 minutes end-to-end.
Development
git clone https://github.com/f/to-wordpress
cd to-wordpress
npm install
npm run build
node dist/cli.js ./fixtures/unknown --skip-boot --skip-copilot -y --until normalize
Run type checks, unit tests, and build in watch mode:
npm run typecheck
npm test # 30 unit tests covering every agent parser + arg builder
npm run dev
Live smoke test against all three agent CLIs (requires each to be
installed + authenticated; skips gracefully if any aren't):
npx tsx test/agents-live.test.ts
The codebase is:
src/cli.tsx— commander entry + Ink TUI bootstrap.src/agents/— one file per agent (copilot.ts,claude.ts,codex.ts) implementingAgentSpec;index.ts
dispatches via a registry.src/detectors/— one detector per SSG + freestyle fallback.src/phases/— one file per phase, plusloop.ts(the generic attempt→test→fix
runner) andloops.ts(per-phasePhaseLoop<T>factories).src/prompts/— markdown templates + loader.src/tui/— Ink app, event bus, headless logger.src/wp/— thin wrappers aroundnpx wp-envandwp-cli.
PRs welcome — especially new detectors, new prompts for specific
frameworks, new agent integrations, and verify rules that catch more
drift.
License
MIT © Fatih Kadir Akın
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi