[{"excerpt":"--report-a11y writes a11y-report.md next to the export. It changes nothing — it tells you what you are about to publish, measured against WCAG 2.2 contrast and non-text-content criteria.","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"--report-a11y writes a11y-report.md next to the export. It changes nothing — it tells you what you are about to publish, measured against WCAG 2.2 contrast and non-text-content criteria.\nWrites a11y-report.md next to the export. It changes nothing — it tells you what you are\nabout to publish:\n1wpexportjson export --url https://example.com -f ssg --report-a11y\n\n\n\nCheck\nCriterion\n\n\n\n\nInline editor colours below a 4.5:1 contrast ratio\nWCAG 2.2 SC 1.4.3 Contrast (Minimum)\n\n\nImages with no alt text\nWCAG 2.2 SC 1.1.1 Non-text Content\n\n\n\nContrast is measured against the declared background-color where the content sets one, and\nagainst white otherwise — which is the worst case for the bright palette the classic WordPress\neditor offered. A 2010-era site typically carries a handful of these (#ffff00 on white is\n1.07:1 against a 4.5:1 requirement). Redesigning the content is not the exporter's job, but\nknowing before you publish is.","title":"Accessibility report","translation_key":"","url":"/accessibility/"},{"excerpt":"WordPress Export JSON is a monorepo containing two complementary applications for exporting WordPress content:","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"System Overview\nWordPress Export JSON is a monorepo containing two complementary applications for exporting WordPress content:\n\nwpexportjson - REST API based exporter with brute force capabilities\nwpxmlrpc - XML-RPC based exporter for authenticated access\n\nExport flow\n\ngraph TB\n    A[CLI Interface] --\u003e B[Configuration Manager]\n    B --\u003e C[WordPress API Client]\n    C --\u003e D[Content Discovery]\n    D --\u003e E[Brute Force Scanner]\n    D --\u003e F[Media Downloader]\n    E --\u003e G[Export Engine]\n    F --\u003e G\n    G --\u003e H[JSON Exporter]\n    G --\u003e I[Markdown Exporter]\n    G --\u003e K[Shopify Exporter]\n    G --\u003e L[Magento Exporter]\n    G --\u003e M[Wix/Squarespace/Webflow]\n    G --\u003e N[Ghost/Strapi/Contentful]\n    G --\u003e O[Weebly/PrestaShop]\n    H --\u003e J[Output Files]\n    I --\u003e J\n    K --\u003e J\n    L --\u003e J\n    M --\u003e J\n    N --\u003e J\n    O --\u003e J\n\nHigh-Level Architecture\n\ngraph TB\n    subgraph \"WordPress Export JSON Monorepo\"\n        subgraph \"Applications\"\n            A1[wpexportjson CLI]\n            A2[wpxmlrpc CLI]\n        end\n        \n        subgraph \"Internal Packages\"\n            API[api - REST Client]\n            XMLRPC[xmlrpc - XML-RPC Client]\n            CONFIG[config - Configuration]\n            EXPORT[export - Export Engine]\n            MEDIA[media - Media Downloader]\n            BRUTE[bruteforce - Content Scanner]\n        end\n        \n        subgraph \"Models\"\n            MODELS[models - Data Structures]\n        end\n    end\n    \n    subgraph \"WordPress Site\"\n        WP_REST[WordPress REST API]\n        WP_XMLRPC[WordPress XML-RPC]\n        WP_MEDIA[Media Files]\n    end\n    \n    subgraph \"Output\"\n        JSON[JSON Export]\n        MD[Markdown Export]\n        MEDIA_FILES[Downloaded Media]\n    end\n    \n    A1 --\u003e API\n    A1 --\u003e BRUTE\n    A2 --\u003e XMLRPC\n    \n    API --\u003e CONFIG\n    XMLRPC --\u003e CONFIG\n    \n    A1 --\u003e EXPORT\n    A2 --\u003e EXPORT\n    \n    EXPORT --\u003e MEDIA\n    \n    API --\u003e MODELS\n    XMLRPC --\u003e MODELS\n    EXPORT --\u003e MODELS\n    \n    API --\u003e WP_REST\n    XMLRPC --\u003e WP_XMLRPC\n    MEDIA --\u003e WP_MEDIA\n    \n    EXPORT --\u003e JSON\n    EXPORT --\u003e MD\n    MEDIA --\u003e MEDIA_FILES\n\nComponent Architecture\n1. Command Line Applications\nwpexportjson\n\nPurpose: Primary application for WordPress content export\nProtocol: WordPress REST API\nFeatures:\n\nPublic API access (no authentication required)\nBrute force content discovery\nHigh performance concurrent processing\nMedia download with progress tracking\n\n\n\nwpxmlrpc\n\nPurpose: Alternative exporter for authenticated access\nProtocol: WordPress XML-RPC\nFeatures:\n\nAuthenticated access to private content\nLegacy WordPress support\nUser credential based authentication\n\n\n\n2. Core Internal Packages\napi Package\n1type Client struct {\n2    config     *config.Config\n3    httpClient *resty.Client\n4    baseURL    string\n5}\n\nREST API client implementation\nHandles pagination automatically\nSupports concurrent requests\nError handling and retries\nDiscovers custom post types from /wp/v2/types (posttypes.go) and fetches\ntheir entries, excluding WordPress internals, plugin bookkeeping types and a\ntheme's saved layouts/templates\n\nxmlrpc Package\n1type Client struct {\n2    config   *config.Config\n3    username string\n4    password string\n5    endpoint string\n6    blogID   int\n7}\n\nXML-RPC protocol implementation\nAuthentication handling\nXML marshaling/unmarshaling\nLegacy WordPress compatibility\n\nconfig Package\n 1type Config struct {\n 2    URL           string\n 3    Output        string\n 4    Format        string\n 5    BruteForce    bool\n 6    MaxID         int\n 7    DownloadMedia bool\n 8    Concurrent    int\n 9    // ... other fields\n10}\n\nCentralized configuration management\nEnvironment variable support\nFile-based configuration\nValidation and defaults\n\nexport Package\n1type Exporter struct {\n2    config     *config.Config\n3    downloader *media.Downloader\n4}\n\nMulti-format export engine\nJSON and Markdown output\nMedia path resolution\nContent transformation\n\nmedia Package\n1type Downloader struct {\n2    config     *config.Config\n3    httpClient *http.Client\n4    mediaDir   string\n5    progress   *progressbar.ProgressBar\n6}\n\nConcurrent media downloading\nProgress tracking\nFile deduplication\nPath sanitization\nContent URL rewriting (urlrewrite.go)\n\nurlrewrite.go is deliberately separate from downloader.go: downloading and content\nrewriting are distinct responsibilities that happen at different stages of an export.\nIt builds a urlIndex keyed on the normalised upload path — scheme, host, query and\ncase stripped — rather than on the literal source_url, because WordPress stores\npost_content with whatever URL form was current when the post was written while the\nREST API reports the site's present-day form. A single regex pass over the rendered\ncontent then resolves each URL-ish token against that index, so src, href and\nsrcset are rewritten uniformly. Unresolvable references with a -{width}x{height}\nsuffix fall back to the nearest surviving width.\nThe URLRewriter is built once per export (Exporter.updateMediaPaths) and reused\nfor every field, since indexing is O(media) and would otherwise repeat per post. The\nsame instance localises body content, excerpt, og_image and the mediaMap behind\nfeatured_image — one mechanism rather than a second one per field. Because it only\nsubstitutes on an index hit, a URL that is not a downloaded attachment (a CDN image, an\nexternal og:image) passes through untouched, and addresses of the source site\n(canonical_url, link, hreflangs) are simply never fed to it.\nbruteforce Package\n1type Scanner struct {\n2    config    *config.Config\n3    apiClient *api.Client\n4}\n\nID enumeration scanning\nConcurrent content discovery\nProgress reporting\nConfigurable limits\n\n3. Data Models\nCore WordPress Types\n 1type WordPressPost struct {\n 2    ID              int\n 3    Date            WordPressTime\n 4    Title           RenderedContent\n 5    Content         RenderedContent\n 6    // ... other fields\n 7}\n 8\n 9type WordPressMedia struct {\n10    ID              int\n11    SourceURL       string\n12    MediaDetails    MediaDetails\n13    // ... other fields\n14}\nCustom Types\n1type WordPressTime struct {\n2    time.Time\n3}\n4\n5func (wt *WordPressTime) UnmarshalJSON(data []byte) error {\n6    // Handles multiple WordPress date formats\n7}\nData Flow Architecture\nREST API Export Flow\n\nsequenceDiagram\n    participant CLI as wpexportjson CLI\n    participant API as REST Client\n    participant WP as WordPress REST API\n    participant BF as Brute Force Scanner\n    participant EXP as Export Engine\n    participant MEDIA as Media Downloader\n    \n    CLI-\u003e\u003eAPI: Initialize client\n    CLI-\u003e\u003eAPI: Get site info\n    API-\u003e\u003eWP: GET /wp-json/wp/v2/\n    WP--\u003e\u003eAPI: Site information\n    \n    CLI-\u003e\u003eAPI: Get posts\n    API-\u003e\u003eWP: GET /wp-json/wp/v2/posts\n    WP--\u003e\u003eAPI: Posts data\n    \n    CLI-\u003e\u003eAPI: Get pages, media, etc.\n    API-\u003e\u003eWP: Multiple paginated requests\n    WP--\u003e\u003eAPI: Content data\n    \n    opt Brute Force Enabled\n        CLI-\u003e\u003eBF: Scan for missing content\n        BF-\u003e\u003eAPI: Test individual IDs\n        API-\u003e\u003eWP: GET /wp-json/wp/v2/posts/{id}\n        WP--\u003e\u003eAPI: Additional content\n    end\n    \n    CLI-\u003e\u003eEXP: Export data\n    EXP-\u003e\u003eMEDIA: Download media files\n    MEDIA-\u003e\u003eWP: Download media URLs\n    EXP-\u003e\u003eEXP: Generate output files\n\nXML-RPC Export Flow\n\nsequenceDiagram\n    participant CLI as wpxmlrpc CLI\n    participant XMLRPC as XML-RPC Client\n    participant WP as WordPress XML-RPC\n    participant EXP as Export Engine\n    \n    CLI-\u003e\u003eXMLRPC: Initialize with credentials\n    CLI-\u003e\u003eXMLRPC: Test connection\n    XMLRPC-\u003e\u003eWP: wp.getOptions\n    WP--\u003e\u003eXMLRPC: Connection confirmed\n    \n    CLI-\u003e\u003eXMLRPC: Get posts\n    XMLRPC-\u003e\u003eWP: wp.getPosts\n    WP--\u003e\u003eXMLRPC: Posts data\n    \n    CLI-\u003e\u003eXMLRPC: Get pages, media, etc.\n    XMLRPC-\u003e\u003eWP: Multiple XML-RPC calls\n    WP--\u003e\u003eXMLRPC: Content data\n    \n    CLI-\u003e\u003eEXP: Export data\n    EXP-\u003e\u003eEXP: Generate output files\n\nFile System Architecture\nProject Structure\nwpexportjson/\n├── cmd/                    # Application entry points\n│   ├── wpexportjson/      # REST API client\n│   └── wpxmlrpc/          # XML-RPC client\n├── internal/              # Internal packages\n│   ├── api/               # REST API client\n│   ├── xmlrpc/            # XML-RPC client\n│   ├── config/            # Configuration management\n│   ├── export/            # Export engine\n│   ├── media/             # Media downloader\n│   └── bruteforce/        # Brute force scanner\n├── pkg/                   # Public packages\n│   └── models/            # Data models\n├── docs/                  # Documentation\n├── build/                 # Build artifacts\n├── dist/                  # Release binaries\n└── export/                # Default export directory\n\nExport Output Structure\nJSON Format\nexport/\n├── export.json           # Complete export data\n└── media/               # Downloaded media files\n    ├── 1_image.jpg\n    ├── 2_video.mp4\n    └── ...\n\nMarkdown Format\nexport/\n├── README.md            # Site information\n├── posts/               # Individual post files\n│   ├── 2024-01-01-post-title.md\n│   └── ...\n├── pages/               # Individual page files\n│   ├── 2024-01-01-page-title.md\n│   ├── cpt_services/    # One directory per custom post type\n│   │   └── wms-implementation.md\n│   └── ...\n├── media/               # Downloaded media files\n│   ├── 1_image.jpg\n│   └── ...\n└── metadata.json        # Categories, tags, users, marketing (incl. theme\n                         # palette), custom_types\n\nConcurrency Architecture\nWorker Pool Pattern\n1// Media downloader uses worker pools\n2jobs := make(chan models.WordPressMedia, len(mediaItems))\n3results := make(chan bool, len(mediaItems))\n4\n5// Start workers\n6for i := 0; i \u0026lt; d.config.Concurrent; i++ {\n7    go d.worker(jobs, results)\n8}\nBrute Force Scanning\n 1// Concurrent ID scanning\n 2for i := 0; i \u0026lt; s.config.Concurrent; i++ {\n 3    wg.Add(1)\n 4    go func() {\n 5        defer wg.Done()\n 6        for id := range jobs {\n 7            // Process ID\n 8        }\n 9    }()\n10}\nError Handling Architecture\nLayered Error Handling\n\nHTTP Level: Connection errors, timeouts\nAPI Level: HTTP status codes, rate limiting\nData Level: JSON parsing, validation\nApplication Level: Business logic errors\n\nRetry Strategy\n1// Exponential backoff with jitter\n2for attempt := 0; attempt \u0026lt;= maxRetries; attempt++ {\n3    if success := operation(); success {\n4        return nil\n5    }\n6    time.Sleep(time.Duration(attempt+1) * time.Second)\n7}\nSecurity Architecture\nAuthentication\n\nREST API: No authentication (public endpoints)\nXML-RPC: Username/password or application passwords\nMedia Downloads: Follows WordPress authentication\n\nData Protection\n\nNo credential storage in configuration files\nEnvironment variable support\nHTTPS enforcement for XML-RPC\n\nPerformance Considerations\nOptimization Strategies\n\nConcurrent Processing: Configurable worker pools\nPagination: Automatic handling of large datasets\nCaching: File existence checks for media\nProgress Tracking: Real-time feedback\nMemory Management: Streaming for large files\n\nScalability Limits\n\nREST API: Rate limiting by WordPress\nXML-RPC: Generally slower than REST\nMemory: Proportional to content size\nDisk: Media files can be large\n\nExtension Points\nAdding New Export Formats\n\nImplement format in export package\nAdd format validation in config\nUpdate CLI flags and documentation\n\nAdding New Content Types\n\nDefine models in pkg/models\nAdd API methods in api or xmlrpc\nUpdate export logic\n\nCustom Authentication\n\nExtend xmlrpc.Client for new auth methods\nAdd configuration options\nUpdate CLI interface\n\nTesting Architecture\nUnit Tests\n\nIndividual package testing\nMock HTTP clients\nConfiguration validation\n\nIntegration Tests\n\nEnd-to-end export testing\nWordPress test site setup\nOutput validation\n\nPerformance Tests\n\nLarge dataset handling\nConcurrent operation testing\nMemory usage profiling","title":"Architecture","translation_key":"","url":"/architecture/"},{"excerpt":"Every flag wpexportjson export accepts, what it defaults to, and the configuration-file form of the same settings — plus the checkpoint that makes an interrupted export resumable instead of a restart.","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Every flag wpexportjson export accepts, what it defaults to, and the configuration-file form of the same settings — plus the checkpoint that makes an interrupted export resumable instead of a restart.\nUsage\nBasic Export\n1wpexportjson export --url https://your-wordpress-site.com\nAdvanced Options\n1wpexportjson export \\\n2  --url https://your-wordpress-site.com \\\n3  --format markdown \\\n4  --output ./my-export \\\n5  --brute-force \\\n6  --max-id 10000 \\\n7  --download-media \\\n8  --concurrent 10\nConfiguration File\nCreate a config.yaml file:\n1url: \u0026#34;https://your-wordpress-site.com\u0026#34;\n2output: \u0026#34;./export\u0026#34;\n3format: \u0026#34;json\u0026#34;\n4brute_force: true\n5max_id: 10000\n6download_media: true\n7concurrent: 10\nThen run:\n1wpexportjson export --config config.yaml\nCommand line options\n\n\n\nOption\nDescription\nDefault\n\n\n\n--urlWordPress site URLRequired\n--outputOutput directory or file./export\n--formatExport format (json/ markdown/ ssg/ shopify/ magento/ wordpress/ drupal/ wix/ squarespace/ webflow/ weebly/ prestashop/ ghost/ strapi/ contentful)json\n--brute-forceEnable brute force ID discoveryfalse\n--max-idMaximum ID for brute force10000\n--scan-rangeRescan a specific inclusive ID range for posts/pages/media, e.g. 100-200\"\"\n--max-media-mbPer-file media download size cap in MB (0 = built-in default of 2048)0\n--download-mediaDownload images and videostrue\n--no-mediaDisable media downloads (alias for --download-media=false)false\n--relevant-media-onlyDownload only featured images and media linked in content (images, PDFs, videos, etc.)false\n--exclude-media-typesMedia types to skip (comma-separated: images,videos,audio,documents,archives,pdf,gif)-\n--media-path-styleForm of rewritten media paths: root (/media/…, resolves at any URL depth) or relative (media/…)root\n--link-styleForm of link/canonical_url/hreflangs: absolute (source URL) or root (root-relative path)absolute(root for ssg)\n--extract-metaWhich meta tags to keep beyond the named SEO fields: all, none, or a comma-separated allow-listall\n--report-a11yWrite a11y-report.md flagging WCAG 2.2 contrast and missing alt-text issuesfalse\n--concurrentConcurrent downloads5\n--zipCreate ZIP archive of exportfalse\n--no-filesRemove export files after creating ZIP (requires --zip)false\n--no-postsSkip exporting blog postsfalse\n--no-pagesSkip exporting pagesfalse\n--no-productsSkip exporting WooCommerce productsfalse\n--no-custom-typesSkip the custom post types a theme or plugin registeredfalse\n--custom-typesExport only these custom types (comma-separated slugs, e.g. cpt_services,cpt_portfolio)-\n--no-usersSkip exporting usersfalse\n--no-tagsSkip exporting tagsfalse\n--no-menusSkip exporting navigation menus (they need authentication — see the navigation menus guide)false\n--no-commentsSkip exporting reader commentsfalse\n--path-filterFilter posts/pages by URL path pattern (e.g., /fr/arts/)-\n--flat-htmlConvert HTML to Markdown (Bricks Builder, Elementor support)false\n--basic-htmlClean HTML to basic elements (tables, lists, links - for Shopify)false\n--ssg-sectionsMarkdown: emit ## Excerpt/## Content sections and omit the duplicate body H1 (for ssg)false\n--preserve-classesCSS classes to preserve from HTML processing (comma-separated, supports wildcards like klaviyo-form-*)-\n--preserve-idsElement IDs to preserve from HTML processing (comma-separated, supports wildcards)-\n--assisted-crawlCrawl URLs to extract SEO metadata (title, description, og tags)false\n--exclude-tagsSEO tags to exclude (comma-separated: title,meta:description,og:title,canonical,lang,hreflangs)-\n--crawl-contentCrawl pages with empty content (Bricks, Elementor page builders)false\n--skip-empty-contentSkip posts/pages with empty content from exportfalse\n--auth-userUsername for Basic Auth (prompts for password if --auth-pass not provided)-\n--auth-passPassword for Basic Auth-\n--auth-tokenBearer token for authentication-\n--rate-limitDelay between API requests in milliseconds (prevents server rate limiting)0\n--retriesAttempts for a request the site answers with 5xx or 429, or drops. Exponential backoff with jitter, honouring Retry-After3\n--resumeResume from checkpoint if previous export was interruptedfalse\n--timeoutHTTP request timeout in seconds (increase for slow servers)30\n--verbose, -vEnable verbose outputfalse\n--quiet, -qSuppress all output, only return exit codefalse\n--configConfiguration file path-\n\n\nResume / checkpoint\nWhen exporting large sites, the --resume flag enables automatic checkpoint saving. If the export is interrupted (network error, server timeout, etc.), you can resume from where it left off:\n1# First export attempt (interrupted at 90%)\n2wpexportjson export --url https://large-site.com --resume -f markdown\n3# Error: connection timeout...\n4\n5# Resume from checkpoint\n6wpexportjson export --url https://large-site.com --resume -f markdown\n7# Resuming from checkpoint: export/large-site.com.2026-02-02/.wpexport_checkpoint.json\n8# Checkpoint: posts=1500 (done=true), pages=42 (done=false)...\nThe checkpoint file (.wpexport_checkpoint.json) is automatically deleted on successful completion.","title":"Command line reference","translation_key":"","url":"/cli/"},{"excerpt":"Comments are the one part of a site its owner did not write: names, dates, threads and opinions readers left over years. They ship by default, addressed by page URL rather than by a post ID that…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Comments are the one part of a site its owner did not write: names, dates, threads and opinions readers left over years. They ship by default, addressed by page URL rather than by a post ID that means nothing on the other side of a migration.\nComments are the one part of a site its owner did not write: names, dates, threads and\nopinions readers left over years. They ship by default, from /wp/v2/comments, which a\npublic WordPress serves without authentication — and serves approved comments only,\nwhich is exactly what a migration wants (pending and spam rows are moderation state, not\ncontent).\nThey leave the export as one comments.json beside metadata.json:\n 1{\n 2  \u0026#34;total\u0026#34;: 128,\n 3  \u0026#34;pages\u0026#34;: 31,\n 4  \u0026#34;exported_at\u0026#34;: \u0026#34;2026-08-14T18:20:11Z\u0026#34;,\n 5  \u0026#34;comments\u0026#34;: [\n 6    {\n 7      \u0026#34;id\u0026#34;: 4711,\n 8      \u0026#34;post\u0026#34;: 812,\n 9      \u0026#34;parent\u0026#34;: 0,\n10      \u0026#34;post_url\u0026#34;: \u0026#34;/blog/wms-implementation-pitfalls/\u0026#34;,\n11      \u0026#34;author\u0026#34;: \u0026#34;Jan Kowalski\u0026#34;,\n12      \u0026#34;author_url\u0026#34;: \u0026#34;https://example.org\u0026#34;,\n13      \u0026#34;author_avatar\u0026#34;: \u0026#34;https://secure.gravatar.com/avatar/…?s=96\u0026#34;,\n14      \u0026#34;date\u0026#34;: \u0026#34;2024-03-01T10:00:00Z\u0026#34;,\n15      \u0026#34;date_gmt\u0026#34;: \u0026#34;2024-03-01T09:00:00Z\u0026#34;,\n16      \u0026#34;content\u0026#34;: \u0026#34;\u0026lt;p\u0026gt;Świetny tekst — u nas WMS wszedł dokładnie tak.\u0026lt;/p\u0026gt;\u0026#34;,\n17      \u0026#34;status\u0026#34;: \u0026#34;approved\u0026#34;,\n18      \u0026#34;type\u0026#34;: \u0026#34;comment\u0026#34;,\n19      \u0026#34;link\u0026#34;: \u0026#34;/blog/wms-implementation-pitfalls/#comment-4711\u0026#34;\n20    }\n21  ]\n22}\nTwo things make the file portable:\n\npost_url, not just post. A WordPress post ID means nothing on the other side of a\nmigration; the page address does. It takes the same form as the post's own link, so\n--link-style root yields /blog/…/ and the default yields the absolute URL. A comment\nwhose post was not exported (excluded by --no-posts, a path filter, or left in draft)\nfalls back to its own permalink with the #comment-N anchor trimmed off.\nCreation order. Comments are sorted by id, so a reply never precedes the comment it\nanswers when a target system replays them into a table with a parent reference.\n\nA site with the REST route switched off or gated prints a note and carries on —\n--no-comments skips the attempt entirely. The two cases read differently, because\ntheir remedies do: a site that turned commenting off answers 403 rest_comment_disabled and is reported as having no comments, while a gated route is\nthe one worth --auth-user/--auth-token. An export with no comments writes no file: an\nempty comments.json would claim the site has none, when the truth may be that they were\nnever requested.","title":"Reader comments","translation_key":"","url":"/comments/"},{"excerpt":"Building, testing and finding your way around the source tree. The toolchain is Go 1.26.6 and GNU Make; every task below has a Make target so CI and a laptop run the same command.","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Building, testing and finding your way around the source tree. The toolchain is Go 1.26.6 and GNU Make; every task below has a Make target so CI and a laptop run the same command.\nSetup and build\nPrerequisites\n\nGo 1.26.6 or later (the version go.mod declares; earlier 1.26 patches carry\nthe standard-library advisories this tool is exposed to)\nMake\n\nSetup\n 1# Clone the repository\n 2git clone https://github.com/tradik/wpexporter.git\n 3cd wpexporter\n 4\n 5# Install dependencies\n 6make deps\n 7\n 8# Install development tools\n 9make dev-install\n10\n11# Run in development mode\n12make dev\nBuilding\n1# Build for current platform\n2make build\n3\n4# Build release binaries for all platforms\n5make release\nTesting\n 1# Run tests\n 2make test\n 3\n 4# Run linter\n 5make lint\n 6\n 7# Run the security scanner\n 8make sec\n 9\n10# Format code\n11make format\n12\n13# Everything CI runs: vet, lint, gosec, tests\n14make check\nmake sec builds gosec from the tools/ module rather than expecting it on\nPATH, so it is the same binary — and the same exclusion list — the pipeline\nuses. Nothing to install; the first run compiles it into build/.\nProject structure\nwpexporter/\n├── cmd/\n│   ├── wpexporter/          # umbrella command — export, xmlrpc, mcp\n│   ├── wpexportjson/        # REST API exporter\n│   ├── wpxmlrpc/            # XML-RPC exporter\n│   └── wpmcp/               # MCP server\n├── internal/\n│   ├── api/                 # WordPress REST client\n│   ├── xmlrpc/              # XML-RPC client\n│   ├── mcp/                 # MCP protocol server\n│   ├── bruteforce/          # ID enumeration for unlisted content\n│   ├── cli/                 # command wiring shared by the binaries\n│   ├── config/              # configuration, CLI and file\n│   ├── export/              # one exporter per output format\n│   ├── media/               # media download and URL rewriting\n│   ├── seo/                 # assisted crawl and metadata extraction\n│   ├── flathtml/            # HTML to Markdown conversion\n│   ├── basichtml/           # HTML reduction for store importers\n│   ├── filter/              # content filters (paths, types)\n│   ├── cache/               # HTTP response cache\n│   ├── checkpoint/          # resume state\n│   └── version/             # build stamp\n├── pkg/\n│   └── models/              # data models, the only exported package\n├── docs/                    # the guides, published at wpexporter.tradik.com\n├── templates/ssgtheme/      # the documentation site's theme\n├── man/                     # man pages\n├── tools/                   # separate module: gosec, pinned by tools/go.sum\n├── Makefile                 # build automation\n├── go.mod                   # Go module definition\n└── README.md                # project overview","title":"Development","translation_key":"","url":"/development/"},{"excerpt":"Wix, Squarespace, Webflow and Weebly each read a different shape: JSON, WXR-compatible XML, CMS collection CSVs, or both XML and JSON. What every one of them shares is that the importer pulls media…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Wix, Squarespace, Webflow and Weebly each read a different shape: JSON, WXR-compatible XML, CMS collection CSVs, or both XML and JSON. What every one of them shares is that the importer pulls media from the live site, so the export leaves those URLs absolute.\nWix Export Format\nThe Wix export format generates a JSON file containing posts, pages, categories, tags, and media that can be imported to Wix.\nOutput Files\n\n\n\nFile\nDescription\n\n\n\n\nwix_export.json\nComplete export with all content\n\n\n\nWix Content Mapping\n\n\n\nWordPress Source\nWix Destination\n\n\n\n\nPosts\nBlog posts\n\n\nPages\nStatic pages\n\n\nCategories\nBlog categories\n\n\nTags\nBlog tags\n\n\nFeatured Image\nCover image\n\n\nSEO Data\nSEO fields\n\n\n\nUsage Example\n1wpexportjson export --url https://your-wordpress-site.com -f wix\nSquarespace Export Format\nThe Squarespace export format generates a WXR-compatible XML file that can be imported directly into Squarespace.\nOutput Files\n\n\n\nFile\nDescription\n\n\n\n\nsquarespace_export.xml\nComplete WXR export for Squarespace import\n\n\n\nSquarespace Content Mapping\n\n\n\nWordPress Source\nSquarespace Destination\n\n\n\n\nPosts\nBlog posts\n\n\nPages\nPages\n\n\nCategories\nCategories\n\n\nTags\nTags\n\n\nMedia\nMedia library items\n\n\n\nUsage Example\n1wpexportjson export --url https://your-wordpress-site.com -f squarespace\nImporting to Squarespace\n\nLog in to your Squarespace account\nGo to Settings \u0026gt; Advanced \u0026gt; Import/Export\nClick Import\nSelect WordPress as the source\nUpload squarespace_export.xml\n\nWebflow Export Format\nThe Webflow export format generates CSV files compatible with Webflow CMS import.\nOutput Files\n\n\n\nFile\nDescription\n\n\n\n\nwebflow_posts.csv\nBlog posts as CMS items\n\n\nwebflow_pages.csv\nStatic pages\n\n\nwebflow_categories.csv\nCategories\n\n\nwebflow_authors.csv\nAuthors\n\n\nwebflow_export.json\nComplete JSON backup\n\n\n\nWebflow Content Mapping\n\n\n\nWordPress Source\nWebflow Destination\n\n\n\n\nPost Title\nName\n\n\nPost Slug\nSlug\n\n\nPost Content\nPost Body\n\n\nPost Date\nPublished On\n\n\nAuthor\nAuthor reference\n\n\nCategories\nCategories (multi-reference)\n\n\nTags\nTags\n\n\nSEO Data\nSEO fields\n\n\n\nUsage Example\n1wpexportjson export --url https://your-wordpress-site.com -f webflow\nWeebly Export Format\nThe Weebly export format generates both XML and JSON files for maximum compatibility.\nOutput Files\n\n\n\nFile\nDescription\n\n\n\n\nweebly_export.xml\nWXR-compatible XML export\n\n\nweebly_export.json\nJSON export with posts and pages\n\n\n\nUsage Example\n1wpexportjson export --url https://your-wordpress-site.com -f weebly","title":"Website builder export formats","translation_key":"","url":"/formats-builders/"},{"excerpt":"WXR for WordPress itself, and JSON shaped for the migration tool of Drupal, Ghost, Strapi and Contentful. These formats keep the content model — posts, pages, taxonomies, authors and media as…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"WXR for WordPress itself, and JSON shaped for the migration tool of Drupal, Ghost, Strapi and Contentful. These formats keep the content model — posts, pages, taxonomies, authors and media as separate entities rather than flattened rows.\nWordPress WXR Export Format\nThe WordPress export format generates a WXR (WordPress eXtended RSS) XML file that can be imported into another WordPress installation. This is the standard format used by WordPress for content migration.\nOutput Files\nWhen exporting to WordPress format, the following file is generated:\n\n\n\nFile\nDescription\n\n\n\n\nwordpress_export.xml\nComplete WXR export with all content\n\n\n\nWXR Content Mapping\n\n\n\nWordPress Source\nWXR Element\n\n\n\n\nPosts\n\u0026lt;item\u0026gt; with \u0026lt;wp:post_type\u0026gt;post\u0026lt;/wp:post_type\u0026gt;\n\n\nPages\n\u0026lt;item\u0026gt; with \u0026lt;wp:post_type\u0026gt;page\u0026lt;/wp:post_type\u0026gt;\n\n\nMedia/Attachments\n\u0026lt;item\u0026gt; with \u0026lt;wp:post_type\u0026gt;attachment\u0026lt;/wp:post_type\u0026gt;\n\n\nCategories\n\u0026lt;wp:category\u0026gt;\n\n\nTags\n\u0026lt;wp:tag\u0026gt;\n\n\nAuthors\n\u0026lt;wp:author\u0026gt;\n\n\nFeatured Images\n\u0026lt;wp:postmeta\u0026gt; with _thumbnail_id\n\n\nSEO Data\n\u0026lt;wp:postmeta\u0026gt; with Yoast-compatible keys\n\n\n\nUsage Example\n1# Export WordPress content to WXR format\n2wpexportjson export --url https://your-wordpress-site.com -f wordpress\n3\n4# Export to WordPress WXR and create ZIP for easy transfer\n5wpexportjson export --url https://your-wordpress-site.com -f wordpress --zip\nImporting to WordPress\n\nLog in to your WordPress Admin Dashboard\nGo to Tools \u0026gt; Import\nClick Install Now under WordPress (if not already installed)\nClick Run Importer\nUpload wordpress_export.xml\nAssign authors and select whether to import attachments\nClick Submit to complete\n\n\nNote: WXR is the official WordPress import/export format. For best results, review the WordPress Import documentation.\n\nDrupal Export Format\nThe Drupal export format generates JSON files compatible with Drupal's Migrate module. This format is designed for migrating WordPress content to Drupal 8/9/10.\nOutput Files\nWhen exporting to Drupal format, the following files are generated:\n\n\n\nFile\nDescription\n\n\n\n\ndrupal_export.json\nComplete export with all content types\n\n\ndrupal_nodes.json\nPosts and pages as Drupal nodes\n\n\ndrupal_terms.json\nCategories and tags as taxonomy terms\n\n\ndrupal_users.json\nUsers as Drupal user accounts\n\n\ndrupal_media.json\nMedia files as Drupal media entities\n\n\n\nDrupal Content Mapping\n\n\n\nWordPress Source\nDrupal Destination\n\n\n\n\nPosts\nNode type: article\n\n\nPages\nNode type: page\n\n\nCategories\nTaxonomy vocabulary: categories\n\n\nTags\nTaxonomy vocabulary: tags\n\n\nFeatured Image\nMedia entity reference (field_image)\n\n\nPost Content\nBody field with full_html format\n\n\nPost Excerpt\nBody summary field\n\n\nSEO Data\nMetatag module fields\n\n\n\nUsage Example\n1# Export WordPress content to Drupal format\n2wpexportjson export --url https://your-wordpress-site.com -f drupal\n3\n4# Export to Drupal and create ZIP for easy transfer\n5wpexportjson export --url https://your-wordpress-site.com -f drupal --zip\nImporting to Drupal\n\nInstall the Migrate and Migrate Source JSON modules\nUpload the JSON files to your Drupal server\nCreate migration configuration files referencing the JSON sources\nRun migrations using Drush: drush migrate:import --all\n\n\nNote: Drupal migration requires custom migration YAML configuration. The JSON structure is designed to work with migrate_source_json plugin. For best results, review the Drupal Migrate documentation.\n\nGhost Export Format\nThe Ghost export format generates a JSON file compatible with Ghost CMS import.\nOutput Files\n\n\n\nFile\nDescription\n\n\n\n\nghost_export.json\nComplete Ghost import format\n\n\n\nGhost Content Mapping\n\n\n\nWordPress Source\nGhost Destination\n\n\n\n\nPosts\nPosts\n\n\nPages\nPages\n\n\nCategories\nTags (with category prefix)\n\n\nTags\nTags\n\n\nUsers\nUsers\n\n\nFeatured Image\nFeature image\n\n\nSEO Data\nMeta fields\n\n\n\nUsage Example\n1wpexportjson export --url https://your-wordpress-site.com -f ghost\nImporting to Ghost\n\nLog in to your Ghost Admin panel\nGo to Settings \u0026gt; Labs\nFind Import content section\nUpload ghost_export.json\n\nStrapi Export Format\nThe Strapi export format generates JSON files compatible with Strapi v4 headless CMS.\nOutput Files\n\n\n\nFile\nDescription\n\n\n\n\nstrapi_export.json\nComplete export with all content types\n\n\nstrapi_articles.json\nBlog articles\n\n\nstrapi_pages.json\nPages\n\n\nstrapi_categories.json\nCategories\n\n\nstrapi_tags.json\nTags\n\n\nstrapi_authors.json\nAuthors\n\n\nstrapi_media.json\nMedia files\n\n\n\nStrapi Content Mapping\n\n\n\nWordPress Source\nStrapi Destination\n\n\n\n\nPosts\nArticles (collection type)\n\n\nPages\nPages (collection type)\n\n\nCategories\nCategories (collection type)\n\n\nTags\nTags (collection type)\n\n\nUsers\nAuthors (collection type)\n\n\nMedia\nMedia library\n\n\nSEO Data\nSEO component fields\n\n\n\nUsage Example\n1wpexportjson export --url https://your-wordpress-site.com -f strapi\nContentful Export Format\nThe Contentful export format generates a JSON file compatible with Contentful's import tool.\nOutput Files\n\n\n\nFile\nDescription\n\n\n\n\ncontentful_export.json\nComplete Contentful import format\n\n\n\nContentful Content Mapping\n\n\n\nWordPress Source\nContentful Destination\n\n\n\n\nPosts\nblogPost content type\n\n\nPages\npage content type\n\n\nCategories\ncategory content type\n\n\nTags\ntag content type\n\n\nUsers\nauthor content type\n\n\nMedia\nAssets\n\n\n\nContent Types Created\nThe export includes content type definitions for:\n\nblogPost - Blog posts with title, slug, content, author, categories, tags\npage - Static pages with title, slug, content\ncategory - Categories with name, slug, description\ntag - Tags with name, slug\nauthor - Authors with name, slug, bio\n\nUsage Example\n1wpexportjson export --url https://your-wordpress-site.com -f contentful\nImporting to Contentful\n\nInstall the Contentful CLI: npm install -g contentful-cli\nLog in: contentful login\nImport: contentful space import --content-file contentful_export.json","title":"CMS and headless export formats","translation_key":"","url":"/formats-cms/"},{"excerpt":"Posts and pages become products: Shopify and Magento take comma-delimited CSV, PrestaShop takes semicolon-delimited CSV, and each importer wants its own column names. Media URLs stay absolute in all…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Posts and pages become products: Shopify and Magento take comma-delimited CSV, PrestaShop takes semicolon-delimited CSV, and each importer wants its own column names. Media URLs stay absolute in all three — the target platform imports the files from the live site.\nShopify Export Format\nThe Shopify export format generates CSV files compatible with Shopify's product import system. This allows you to migrate WordPress content (posts, pages) to Shopify as products.\nOutput Files\nWhen exporting to Shopify format, the following files are generated:\n\n\n\nFile\nDescription\n\n\n\n\nshopify_posts.csv\nWordPress posts exported as Shopify products\n\n\nshopify_pages.csv\nWordPress pages exported as Shopify products\n\n\nshopify_products.csv\nCombined posts and pages as products\n\n\nshopify_metadata.csv\nSite metadata and export statistics\n\n\n\nCSV Column Mapping\nWordPress content is mapped to Shopify product fields as follows:\n\n\n\nWordPress Field\nShopify Field\n\n\n\n\nPost Slug\nHandle\n\n\nPost Title\nTitle\n\n\nPost Content (HTML)\nBody (HTML)\n\n\nAuthor Name\nVendor\n\n\nFirst Category\nType\n\n\nTags\nTags (comma-separated)\n\n\nPost Status\nPublished (TRUE/FALSE)\n\n\nFeatured Image\nImage Src\n\n\nPost Excerpt\nSEO Description\n\n\nPost ID\nVariant SKU (format: WP-{id})\n\n\n\nNote: The Body (HTML) field includes a styled metadata header with post details (ID, slug, dates, status, author, categories, tags, and hreflang links when available via --assisted-crawl).\nUsage Example\n1# Export WordPress content to Shopify format\n2wpexportjson export --url https://your-wordpress-site.com -f shopify\n3\n4# Export to Shopify and create ZIP for easy upload\n5wpexportjson export --url https://your-wordpress-site.com -f shopify --zip\nImporting to Shopify\n\nLog in to your Shopify Admin\nGo to Products \u0026gt; Import\nClick Add file and select shopify_products.csv\nReview the import preview\nClick Import products\n\n\nNote: The exported CSV follows Shopify's official product CSV format. For best results, review the Shopify CSV import documentation.\n\nMagento Export Format\nThe Magento export format generates CSV files compatible with Magento 2's product import system. This allows you to migrate WordPress content (posts, pages) to Magento as simple products.\nOutput Files\nWhen exporting to Magento format, the following files are generated:\n\n\n\nFile\nDescription\n\n\n\n\nmagento_posts.csv\nWordPress posts exported as Magento products\n\n\nmagento_pages.csv\nWordPress pages exported as Magento products\n\n\nmagento_products.csv\nCombined posts and pages as products\n\n\nmagento_metadata.csv\nSite metadata and export statistics\n\n\n\nCSV Column Mapping\nWordPress content is mapped to Magento product fields as follows:\n\n\n\nWordPress Field\nMagento Field\n\n\n\n\nPost Slug (uppercase)\nsku\n\n\nPost Title\nname\n\n\nPost Content (HTML)\ndescription\n\n\nPost Excerpt\nshort_description\n\n\nCategories\ncategories (Default Category/Name format)\n\n\nTags\nmeta_keywords\n\n\nPost Slug\nurl_key\n\n\nPost Title\nmeta_title\n\n\nPost Excerpt\nmeta_description\n\n\nFeatured Image\nbase_image, small_image, thumbnail_image\n\n\nPost Status\nproduct_online (1=enabled, 0=disabled)\n\n\n\nUsage Example\n1# Export WordPress content to Magento format\n2wpexportjson export --url https://your-wordpress-site.com -f magento\n3\n4# Export to Magento and create ZIP for easy upload\n5wpexportjson export --url https://your-wordpress-site.com -f magento --zip\nImporting to Magento 2\n\nLog in to your Magento 2 Admin Panel\nGo to System \u0026gt; Data Transfer \u0026gt; Import\nSelect Products as Entity Type\nChoose Add/Update as Import Behavior\nUpload magento_products.csv\nClick Check Data to validate\nClick Import to complete\n\n\nNote: Before importing, ensure image files are uploaded to /pub/media/import/ on your Magento server. For best results, review the Magento 2 CSV import documentation.\n\nPrestaShop Export Format\nThe PrestaShop export format generates semicolon-delimited CSV files compatible with PrestaShop's import system. Posts and pages are converted to products.\nOutput Files\n\n\n\nFile\nDescription\n\n\n\n\nprestashop_products.csv\nProducts (from posts/pages)\n\n\nprestashop_posts.csv\nBlog posts\n\n\nprestashop_pages.csv\nCMS pages\n\n\nprestashop_categories.csv\nProduct categories\n\n\nprestashop_metadata.csv\nExport metadata\n\n\nprestashop_export.json\nComplete JSON backup\n\n\n\nPrestaShop Content Mapping\n\n\n\nWordPress Source\nPrestaShop Destination\n\n\n\n\nPost Title\nProduct name\n\n\nPost Content\nProduct description\n\n\nPost Excerpt\nShort description\n\n\nCategories\nProduct categories\n\n\nTags\nTags\n\n\nFeatured Image\nProduct image\n\n\nPost ID\nReference (WP-{id})\n\n\n\nUsage Example\n1wpexportjson export --url https://your-wordpress-site.com -f prestashop","title":"E-commerce export formats","translation_key":"","url":"/formats-ecommerce/"},{"excerpt":"Fifteen formats, one crawl. The exporter reads the site once and writes whichever shape the target needs, so choosing a destination is a flag rather than a second export — and switching destinations…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Fifteen formats, one crawl. The exporter reads the site once and writes whichever shape the target needs, so choosing a destination is a flag rather than a second export — and switching destinations costs nothing but the write.\n\n\n\nFlag\nWrites\nGuide\n\n\n\n\n-f json (default)\nJSON documents, media localised to /media/…\nCommand line reference\n\n\n-f markdown\nOne Markdown file per post and page, YAML front matter\nHTML to Markdown\n\n\n-f ssg\nA drop-in content source: URL-mirroring paths, single-spelled front matter, cleaned body HTML\nStatic site generator format\n\n\n-f shopify\nshopify_posts.csv, shopify_pages.csv, shopify_products.csv, shopify_metadata.csv\nE-commerce formats\n\n\n-f magento\nmagento_posts.csv, magento_pages.csv, magento_products.csv, magento_metadata.csv\nE-commerce formats\n\n\n-f prestashop\nSemicolon-delimited product, post, page, category and metadata CSVs, plus a JSON backup\nE-commerce formats\n\n\n-f wordpress\nwordpress_export.xml — WXR, the format WordPress imports natively\nCMS and headless formats\n\n\n-f drupal\ndrupal_export.json plus per-entity node, term, user and media files\nCMS and headless formats\n\n\n-f ghost\nghost_export.json\nCMS and headless formats\n\n\n-f strapi\nstrapi_export.json plus per-collection article, page, category, tag, author and media files\nCMS and headless formats\n\n\n-f contentful\ncontentful_export.json\nCMS and headless formats\n\n\n-f wix\nwix_export.json\nWebsite builder formats\n\n\n-f squarespace\nsquarespace_export.xml — WXR, which Squarespace imports as WordPress\nWebsite builder formats\n\n\n-f webflow\nPost, page, category and author CSVs for CMS collections, plus a JSON backup\nWebsite builder formats\n\n\n-f weebly\nweebly_export.xml and weebly_export.json\nWebsite builder formats\n\n\n\nmarkdown and ssg both write pages under the path their URL states, so a page\npublished at /zerowisko/znaczenie/ becomes pages/zerowisko/znaczenie.md.\nWordPress page addresses are hierarchical and a slug is unique only within its\nbranch: written flat, a child page and an unrelated top-level page sharing a\nslug landed on one file and one of them was lost (#38). Two documents that still\nwant the same file — a site whose links are missing, so both fall back to their\nslug — are both written, the second with its WordPress ID appended, and the\nsubstitution is reported. The summary states pages written against pages fetched\nwhenever the two differ.\nTwo things hold for every platform format, and only for those: media URLs are\nleft absolute, because the target platform imports the files from the live\nsite, and address fields (link, canonical_url) stay absolute too. json,\nmarkdown and ssg localise media instead — see\nMedia and URL rewriting for the per-format contract in full.\nAdding --zip to any of them archives the result; --no-files then removes the\nloose files, leaving only the archive.","title":"Export formats","translation_key":"","url":"/formats/"},{"excerpt":"wpexporter ships as a single static binary for Linux, macOS, Windows and FreeBSD, plus a Docker image. Every package installs the umbrella wpexporter command alongside the three standalone tools —…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"wpexporter ships as a single static binary for Linux, macOS, Windows and FreeBSD, plus a Docker image. Every package installs the umbrella wpexporter command alongside the three standalone tools — wpexportjson, wpxmlrpc and wpmcp — which behave identically to their subcommand form.\nHomebrew (macOS / Linux)\n1brew install tradik/tap/wpexporter\nThis installs the wpexporter umbrella command plus the wpexportjson, wpxmlrpc and\nwpmcp binaries, and the man pages.\nSnap (Linux)\n1sudo snap install wpexporter\nProvides the wpexporter command, plus wpexporter.wpexportjson, wpexporter.wpxmlrpc\nand wpexporter.wpmcp.\nFrom Source\n1git clone https://github.com/tradik/wpexporter.git\n2cd wpexporter\n3make build\n4\n5# Optional: Install man pages (requires sudo)\n6sudo make install-man\n7man wpexportjson\nUsing Go Install\n1go install github.com/tradik/wpexporter/cmd/wpexporter@latest\n2go install github.com/tradik/wpexporter/cmd/wpexportjson@latest\n3go install github.com/tradik/wpexporter/cmd/wpxmlrpc@latest\n4go install github.com/tradik/wpexporter/cmd/wpmcp@latest\nUsing Docker\nDocker images are available from GitHub Container Registry:\n 1# Pull the latest image\n 2docker pull ghcr.io/tradik/wpexporter:latest\n 3\n 4# Run wpexporter\n 5docker run --rm -v $(pwd)/export:/export ghcr.io/tradik/wpexporter:latest \\\n 6  wpexportjson export --url https://example.com --output /export\n 7\n 8# Run wpxmlrpc\n 9docker run --rm -v $(pwd)/export:/export ghcr.io/tradik/wpexporter:latest \\\n10  wpxmlrpc export --url https://example.com --username admin --password mypassword --output /export\n11\n12# Run wpmcp (MCP server over stdio)\n13docker run --rm -i ghcr.io/tradik/wpexporter:latest wpmcp\nAll four binaries — wpexporter, wpexportjson, wpxmlrpc and wpmcp — ship in the image.","title":"Installation","translation_key":"","url":"/install/"},{"excerpt":"--flat-html turns rendered HTML into clean Markdown, with conversion rules you can extend per site and elements you can keep intact. Gutenberg content is covered by the same pass: its blocks are HTML…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"--flat-html turns rendered HTML into clean Markdown, with conversion rules you can extend per site and elements you can keep intact. Gutenberg content is covered by the same pass: its blocks are HTML with comment markers, and the markers are stripped on the way out.\nThe --flat-html option converts HTML content to clean Markdown format. This is useful for:\n\nSites using page builders (Bricks Builder, Elementor) that output complex HTML\nMigrating content to markdown-based systems\nCleaning up HTML before export\n\nBuilt-in Conversions\n\n\n\nHTML Element\nMarkdown Output\n\n\n\n\n\u0026lt;h1\u0026gt; - \u0026lt;h6\u0026gt;\n# - ######\n\n\n\u0026lt;p\u0026gt;\nPlain text with line breaks\n\n\n\u0026lt;strong\u0026gt;, \u0026lt;b\u0026gt;\n**bold**\n\n\n\u0026lt;em\u0026gt;, \u0026lt;i\u0026gt;\n*italic*\n\n\n\u0026lt;a href=\u0026quot;...\u0026quot;\u0026gt;\n[text](url)\n\n\n\u0026lt;img src=\u0026quot;...\u0026quot; alt=\u0026quot;...\u0026quot;\u0026gt;\n![alt](src)\n\n\n\u0026lt;ul\u0026gt;, \u0026lt;ol\u0026gt;\n- or 1. lists\n\n\n\u0026lt;blockquote\u0026gt;\n\u0026gt; quote\n\n\n\u0026lt;code\u0026gt;\n`inline`\n\n\n\u0026lt;pre\u0026gt;\u0026lt;code\u0026gt;\n``` code block\n\n\n\u0026lt;hr\u0026gt;\n---\n\n\nBricks: .brxe-heading\n## heading\n\n\nBricks: .brxe-text\nparagraph\n\n\n\nCustom Conversion Rules\nYou can define custom rules in your config.yaml for site-specific HTML classes:\n 1flat_html_rules:\n 2  # Bricks Builder custom headings\n 3  - class: \u0026#34;brxe-heading\u0026#34;\n 4    tag: \u0026#34;div\u0026#34;\n 5    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n 6\n 7  # Elementor headings\n 8  - class: \u0026#34;elementor-heading-title\u0026#34;\n 9    markdown: \u0026#34;# {content}\\n\\n\u0026#34;\n10\n11  # Custom paragraph class\n12  - class: \u0026#34;my-paragraph\u0026#34;\n13    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n14\n15  # Specific tag + class combination\n16  - class: \u0026#34;custom-quote\u0026#34;\n17    tag: \u0026#34;span\u0026#34;\n18    markdown: \u0026#34;\u0026gt; {content}\\n\\n\u0026#34;\nRule fields:\n\nclass (required): CSS class to match\ntag (optional): HTML tag to match (e.g., \u0026quot;div\u0026quot;, \u0026quot;span\u0026quot;)\nmarkdown: Output template where {content} is replaced with the element's text\n\nPreserving HTML Elements\nUse --preserve-classes and --preserve-ids to keep certain elements intact during HTML processing with --flat-html or --basic-html. This is useful for:\n\nNewsletter signup forms (Klaviyo, Mailchimp)\nEmbedded widgets and third-party scripts\nCustom interactive elements you don't want converted\n\n 1# Preserve Klaviyo forms (with wildcard)\n 2wpexportjson export --url https://example.com --basic-html \\\n 3  --preserve-classes \u0026#34;klaviyo-form-*\u0026#34;\n 4\n 5# Preserve specific elements by ID\n 6wpexportjson export --url https://example.com --flat-html \\\n 7  --preserve-ids \u0026#34;newsletter-form,sidebar-widget\u0026#34;\n 8\n 9# Combine classes and IDs (comma-separated)\n10wpexportjson export --url https://example.com --basic-html \\\n11  --preserve-classes \u0026#34;klaviyo-form-*,mailchimp-widget\u0026#34; \\\n12  --preserve-ids \u0026#34;contact-form\u0026#34;\nWildcard support:\n\nklaviyo-form-* matches klaviyo-form-XL7uTf, klaviyo-form-ABC123, etc.\nbrxe-*-section matches brxe-hero-section, brxe-footer-section, etc.\n\nConfiguration file:\n1preserve_classes:\n2  - \u0026#34;klaviyo-form-*\u0026#34;\n3  - \u0026#34;mailchimp-widget\u0026#34;\n4preserve_ids:\n5  - \u0026#34;newsletter-form\u0026#34;\nUsage Example\n1# Convert HTML to Markdown with default rules\n2wpexportjson export --url https://example.com --flat-html -f markdown\n3\n4# With custom rules from config file\n5wpexportjson export --url https://example.com --flat-html --config config.yaml -f markdown\n6\n7# Combine with content crawling for page builder sites\n8wpexportjson export --url https://example.com --crawl-content --flat-html -f markdown\nMarkdown Frontmatter Output\nWhen using --assisted-crawl with markdown format, SEO fields are included in the frontmatter:\n 1---\n 2id: 123\n 3title: \u0026#34;Original Post Title\u0026#34;\n 4seo_title: \u0026#34;SEO Optimized Title | Site Name\u0026#34;\n 5meta_description: \u0026#34;A compelling description for search engines...\u0026#34;\n 6og_title: \u0026#34;Title for Social Sharing\u0026#34;\n 7og_image: \u0026#34;https://example.com/social-image.jpg\u0026#34;\n 8lang: \u0026#34;en-US\u0026#34;\n 9hreflangs:\n10  - lang: \u0026#34;en-US\u0026#34;\n11    href: \u0026#34;https://example.com/post/\u0026#34;\n12  - lang: \u0026#34;de-DE\u0026#34;\n13    href: \u0026#34;https://example.com/de/post/\u0026#34;\n14  - lang: \u0026#34;fr-FR\u0026#34;\n15    href: \u0026#34;https://example.com/fr/post/\u0026#34;\n16excerpt: \u0026#34;A brief summary of the post content...\u0026#34;\n17# ... other fields\n18---\n19\n20# Post Title\n21\n22The full post content follows directly after the frontmatter...\nGutenberg blocks support\nWordPress Gutenberg editor stores content as HTML with special comment markers. Here's how wpexporter handles Gutenberg blocks:\n✅ Standard Export Behavior\nGutenberg blocks export automatically in all formats:\n\n\n\nContent Type\nExport Result\n\n\n\n\nStandard blocks (paragraphs, headings, lists)\n✅ Exported as HTML content\n\n\nCore blocks (quote, code, image, gallery)\n✅ Embedded HTML preserved\n\n\nCustom blocks (plugins, themes)\n✅ Rendered HTML output\n\n\nBlock patterns \u0026amp; reusable blocks\n✅ Resolved to final HTML\n\n\n\nNo configuration needed for JSON, WordPress WXR, or HTML-preserving formats.\n🔄 Markdown Conversion with --flat-html\nWhen exporting to Markdown format, use --flat-html to convert Gutenberg HTML to clean Markdown:\n1# Convert Gutenberg content to Markdown\n2wpexportjson export --url https://example.com --flat-html -f markdown\nCommon Gutenberg CSS classes for custom rules in config.yaml:\n 1flat_html_rules:\n 2  # Core Gutenberg blocks\n 3  - class: \u0026#34;wp-block-heading\u0026#34;\n 4    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n 5  - class: \u0026#34;wp-block-paragraph\u0026#34;\n 6    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n 7  - class: \u0026#34;wp-block-quote\u0026#34;\n 8    markdown: \u0026#34;\u0026gt; {content}\\n\\n\u0026#34;\n 9  - class: \u0026#34;wp-block-code\u0026#34;\n10    markdown: \u0026#34;```\\n{content}\\n```\\n\\n\u0026#34;\n11  - class: \u0026#34;wp-block-preformatted\u0026#34;\n12    markdown: \u0026#34;```\\n{content}\\n```\\n\\n\u0026#34;\n13  - class: \u0026#34;wp-block-list\u0026#34;\n14    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n15  - class: \u0026#34;wp-block-image\u0026#34;\n16    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n17\n18  # Extended blocks\n19  - class: \u0026#34;wp-block-pullquote\u0026#34;\n20    markdown: \u0026#34;\u0026gt; **{content}**\\n\\n\u0026#34;\n21  - class: \u0026#34;wp-block-verse\u0026#34;\n22    markdown: \u0026#34;*{content}*\\n\\n\u0026#34;\n23  - class: \u0026#34;wp-block-table\u0026#34;\n24    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n📋 Block Detection\nThe exporter preserves Gutenberg comment markers in HTML exports:\n1\u0026lt;!-- wp:paragraph --\u0026gt;\n2\u0026lt;p\u0026gt;Content here...\u0026lt;/p\u0026gt;\n3\u0026lt;!-- /wp:paragraph --\u0026gt;\nThese markers are stripped during Markdown conversion with --flat-html.","title":"HTML to Markdown conversion","translation_key":"","url":"/markdown/"},{"excerpt":"wpmcp speaks the Model Context Protocol over stdio, so Claude and other assistants can inspect and export a WordPress site without a shell between them. Eight tools cover site information, listings…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"wpmcp speaks the Model Context Protocol over stdio, so Claude and other assistants can inspect and export a WordPress site without a shell between them. Eight tools cover site information, listings, a single post and a full export in any supported format.\nClaude Desktop Configuration (claude_desktop_config.json):\n1{\n2  \u0026#34;mcpServers\u0026#34;: {\n3    \u0026#34;wpexporter\u0026#34;: {\n4      \u0026#34;command\u0026#34;: \u0026#34;wpmcp\u0026#34;,\n5      \u0026#34;args\u0026#34;: [\u0026#34;serve\u0026#34;]\n6    }\n7  }\n8}\nClaude Code Configuration (.claude/mcp.json):\n1{\n2  \u0026#34;mcpServers\u0026#34;: {\n3    \u0026#34;wpexporter\u0026#34;: {\n4      \u0026#34;type\u0026#34;: \u0026#34;stdio\u0026#34;,\n5      \u0026#34;command\u0026#34;: \u0026#34;wpmcp\u0026#34;,\n6      \u0026#34;args\u0026#34;: [\u0026#34;serve\u0026#34;]\n7    }\n8  }\n9}\nAvailable MCP Tools:\n\n\n\nTool\nDescription\n\n\n\n\nlist_formats\nList all 14 available export formats\n\n\nget_site_info\nGet WordPress site information\n\n\nlist_posts\nList posts with optional path filtering\n\n\nlist_pages\nList pages from a site\n\n\nexport_site\nFull site export to any format\n\n\nget_post\nGet a specific post by ID\n\n\nlist_categories\nList all categories\n\n\nlist_media\nList media files\n\n\n\nexport_site writes the same tree the CLI does, reader comments included, and\nreports the counts back to the caller — an agent has no console to read warnings\nfrom, so stats.comments is where a site whose comment route is closed shows up\nas a zero. noPosts, noPages, noProducts and noComments switch a\ncollection off, matching the --no-… flags in the CLI reference.","title":"MCP server","translation_key":"","url":"/mcp/"},{"excerpt":"What happens to images, documents and videos when an export downloads them: where the files land, which URL forms are recognised as the same asset, which fields get rewritten in each format, and how…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"What happens to images, documents and videos when an export downloads them: where the files land, which URL forms are recognised as the same asset, which fields get rewritten in each format, and how to take only the media the content actually uses.\nWhen downloading media with --download-media, the exporter rewrites URLs in exported content to point to local files.\n📁 File Organization\nDownloaded media files are stored in a structured format, in a subfolder per media category\n(images, videos, audio, documents, archives, code, other):\nexport/\n├── posts/\n│   └── my-post.md\n├── pages/\n│   └── about.md\n└── media/\n    ├── images/\n    │   ├── 123_featured-image.jpg\n    │   └── 124_inline-photo.png\n    ├── documents/\n    │   └── 125_document.pdf\n    └── videos/\n        └── 126_video.mp4\n\nNaming pattern: {media_id}_{original_filename}{extension}\n🔄 URL Rewriting\nEvery reference to a downloaded attachment is rewritten — src, href, srcset and any\nother URL occurrence are treated identically, so the export keeps working once the source\nWordPress host is retired.\n\n\n\nOriginal URL\nRewritten Path\n\n\n\n\nhttps://example.com/wp-content/uploads/2025/01/photo.jpg\n/media/images/123_photo.jpg\n\n\nhttps://example.com/wp-content/uploads/2025/01/photo-300x200.jpg\n/media/images/123_photo-300x200.jpg\n\n\nhttps://example.com/wp-content/uploads/2025/01/photo-150x150.jpg\n/media/images/123_photo-150x150.jpg\n\n\n\nFiles the media library does not list are salvaged. Page-builder renditions\n(uploads/elementor/thumbs/…), attachments whose record was deleted while the file is still\nserved, and brand assets declared only in the document head never appear in /wp/v2/media —\nso without this they stayed absolute and the migrated site hotlinked the source host. Every\nsame-host asset URL that content, SEO metadata or the marketing block references and the\nlibrary cannot account for is fetched into media/\u0026lt;kind\u0026gt;/ under a name prefixed with a short\nhash of its source path (page builders repeat basenames across directories). A URL on a\nforeign host is left alone — it is somebody else's file — and one that no longer resolves is\nskipped rather than failing the export.\nMatching is scheme- and host-insensitive. WordPress stores post_content with whatever URL\nform was current when the post was written, while the REST API reports source_url in the site's\npresent-day form. All of these resolve to the same exported file:\n\n\n\nReference form in content\nExample\n\n\n\n\ncurrent form\nhttps://example.com/wp-content/uploads/…\n\n\nhistoric scheme\nhttp://example.com/wp-content/uploads/…\n\n\nwww / former domain\nhttps://www.example.com/…, http://old-domain.example/…\n\n\nprotocol-relative\n//example.com/wp-content/uploads/…\n\n\nroot-relative\n/wp-content/uploads/…\n\n\nwith a query string\n…/photo.jpg?ver=2\n\n\n\nURLs that do not correspond to a downloaded attachment are left untouched.\n📐 Path Style: --media-path-style\n\n\n\nValue\nEmitted path\nWhen to use\n\n\n\n\nroot (default)\n/media/images/123_photo.jpg\nResolves identically from any URL depth — correct for a page served at /about/team/\n\n\nrelative\nmedia/images/123_photo.jpg\nOnly correct for content served from the site root; kept for backwards compatibility with pre-1.7.9 exports\n\n\n\n1# Default — root-relative, works at any URL depth\n2wpexportjson export --url https://example.com -f markdown --download-media\n3\n4# Pre-1.7.9 behaviour\n5wpexportjson export --url https://example.com -f markdown --media-path-style relative\nURL rewriting applies to the json and markdown formats only, and can be disabled entirely\nwith --keep-original-urls (other formats always keep original URLs, since the target platform\nimports media from the live site).\n📋 Per-Format URL Contract\nWhat each format does with URLs, so you know what you are getting before you run an export:\n\n\n\nFormat\nMedia URLs\nAddress fields (link, canonical_url)\n\n\n\n\njson\nlocalised to /media/…\nabsolute (--link-style root to change)\n\n\nmarkdown\nlocalised to /media/…\nabsolute (--link-style root to change)\n\n\nssg\nlocalised to /media/…\nroot-relative by default\n\n\nshopify, magento, wordpress, drupal, wix, squarespace, webflow, weebly, prestashop, ghost, strapi, contentful\nleft absolute — the target platform imports media from the live site\nabsolute\n\n\n\n--keep-original-urls disables all rewriting for json, markdown and ssg.\n🗂️ Which Fields Are Localised\n\n\n\nField\nLocalised\nWhy\n\n\n\n\nbody content (content.rendered)\n✅\nassets\n\n\nexcerpt\n✅\nassets\n\n\nfeatured_image\n✅\nasset\n\n\nog_image\n✅ when it resolves\nasset — but an og:image on a CDN or third-party host isn't a downloaded attachment, so it stays absolute\n\n\ncanonical_url\n⚙️ --link-style\naddress of the source site, not an asset\n\n\nlink\n⚙️ --link-style\nas above\n\n\nhreflangs[].href\n⚙️ --link-style\nas above\n\n\n\n🔗 Address Fields: --link-style\nlink, canonical_url and hreflangs[].href are addresses of the source site, not assets, so\nthey are governed separately from media:\n\n\n\nValue\nEmitted\nWhen to use\n\n\n\n\nabsolute (default)\nhttps://example.com/2010/07/21/389/\nYou need the original URL — to derive the target URL yourself, or because the old site stays up\n\n\nroot\n/2010/07/21/389/\nYou are rebuilding the site at the same paths. Preserves each URL (and its search ranking) on the new host without pinning content to the old one\n\n\n\n1# Rebuilding at the same paths on a new host\n2wpexportjson export --url https://example.com -f markdown --link-style root\nOnly same-host addresses are converted. An hreflang alternate or canonical pointing at a\ndifferent host keeps pointing where it points. Query strings and fragments are preserved\n(/a/?page=2#top).\n📷 Size Variants\nWordPress generates multiple image sizes (thumbnail, medium, large, full). The exporter:\n\n✅ Downloads the original full-size image and every registered size variant\n✅ Rewrites each variant URL to its own exported file, preserving responsive srcset\n✅ Handles -{width}x{height} suffixed URLs automatically\n✅ Remaps stale variants: a registered-size change regenerates thumbnails but never\nrewrites the markup already linking to the old dimensions. A reference to a\nno-longer-generated photo-300x199.jpg is remapped to the closest surviving width\n(photo-300x225.jpg) instead of being left as a dead path. Run with --verbose to see\neach remap.\n\n🎯 Selective Media with --relevant-media-only\nFor sites with large media libraries, use --relevant-media-only to download only used media:\n1wpexportjson export --url https://example.com --relevant-media-only -f markdown\nWhat gets downloaded:\n\n\n\nMedia Type\nDownloaded\nCondition\n\n\n\n\nFeatured images\n✅ Yes\nReferenced by featured_media field\n\n\nContent images\n✅ Yes\nFound in \u0026lt;img\u0026gt; tags within content\n\n\nExcerpt images\n✅ Yes\nFound in \u0026lt;img\u0026gt; tags within excerpt\n\n\nLinked PDFs/documents\n✅ Yes\nFound in \u0026lt;a href\u0026gt; tags (pdf, docx, xlsx, etc.)\n\n\nLinked videos\n✅ Yes\nFound in \u0026lt;a href\u0026gt; tags (mp4, webm, avi, etc.)\n\n\nLinked archives\n✅ Yes\nFound in \u0026lt;a href\u0026gt; tags (zip, rar, 7z, etc.)\n\n\nUnused library items\n❌ No\nNot referenced by any post/page\n\n\n\nBenefits:\n\n📉 Significantly reduces export size\n⚡ Faster export for content-heavy sites\n🎯 Only relevant assets are included (images, documents, videos)\n\n💡 Examples\n 1# Download all media (default)\n 2wpexportjson export --url https://example.com -f markdown\n 3\n 4# Download only featured images and content images\n 5wpexportjson export --url https://example.com --relevant-media-only -f markdown\n 6\n 7# Skip media download entirely\n 8wpexportjson export --url https://example.com --no-media -f markdown\n 9\n10# Combine with path filter for targeted export\n11wpexportjson export --url https://example.com --path-filter=/blog/ --relevant-media-only -f markdown","title":"Media and URL rewriting","translation_key":"","url":"/media/"},{"excerpt":"Menu structure is the one part of a site that cannot be reconstructed from the content afterwards — nothing in a post records which menu it belonged to, in what order, or under what label. Menus are…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Menu structure is the one part of a site that cannot be reconstructed from the content afterwards — nothing in a post records which menu it belonged to, in what order, or under what label. Menus are exported into metadata.json, and WordPress gates them behind authentication.\nMenu structure is the one part of a site that cannot be reconstructed from the content\nafterwards — nothing in a post records which menu it belonged to, in what order, or under\nwhat label. Menus are exported into metadata.json:\n 1\u0026#34;menus\u0026#34;: [\n 2  {\n 3    \u0026#34;id\u0026#34;: 3, \u0026#34;name\u0026#34;: \u0026#34;Categories\u0026#34;, \u0026#34;slug\u0026#34;: \u0026#34;categories\u0026#34;, \u0026#34;locations\u0026#34;: [\u0026#34;primary\u0026#34;],\n 4    \u0026#34;items\u0026#34;: [\n 5      { \u0026#34;id\u0026#34;: 41, \u0026#34;title\u0026#34;: \u0026#34;Malta\u0026#34;, \u0026#34;url\u0026#34;: \u0026#34;/malta/\u0026#34;, \u0026#34;parent\u0026#34;: 0, \u0026#34;order\u0026#34;: 1,\n 6        \u0026#34;type\u0026#34;: \u0026#34;taxonomy\u0026#34;, \u0026#34;object\u0026#34;: \u0026#34;category\u0026#34;, \u0026#34;object_id\u0026#34;: 5 },\n 7      { \u0026#34;id\u0026#34;: 42, \u0026#34;title\u0026#34;: \u0026#34;About Us\u0026#34;, \u0026#34;url\u0026#34;: \u0026#34;/about-us\u0026#34;, \u0026#34;parent\u0026#34;: 0, \u0026#34;order\u0026#34;: 2,\n 8        \u0026#34;type\u0026#34;: \u0026#34;post_type\u0026#34;, \u0026#34;object\u0026#34;: \u0026#34;page\u0026#34;, \u0026#34;object_id\u0026#34;: 7 }\n 9    ]\n10  }\n11]\nItem URLs follow --link-style, so navigation matches the exported permalinks. An item\npointing at another host keeps its absolute URL. Items are ordered by menu_order, which is\nwhat the site renders by.\n⚠️ Menus require authentication\nWordPress gates /wp/v2/menus behind the edit_theme_options capability, so a public REST\nAPI still refuses them regardless of how the menus are configured:\n1$ curl -s https://example.com/wp-json/wp/v2/menus\n2{\u0026#34;code\u0026#34;:\u0026#34;rest_cannot_view\u0026#34;,\u0026#34;message\u0026#34;:\u0026#34;Sorry, you are not allowed to view menus.\u0026#34;,\u0026#34;data\u0026#34;:{\u0026#34;status\u0026#34;:401}}\nPass credentials to include them:\n1wpexportjson export --url https://example.com --auth-user admin --auth-pass \u0026#34;app password\u0026#34;\n2# or\n3wpexportjson export --url https://example.com --auth-token \u0026#34;$TOKEN\u0026#34;\nWithout credentials the export prints a note and carries on — menus are simply absent.\n--no-menus skips the attempt entirely.","title":"Navigation menus","translation_key":"","url":"/menus/"},{"excerpt":"Complete flathtmlrules sets for the builders whose markup a generic converter cannot read on its own: Bricks, Elementor, Divi, Oxygen and GenerateBlocks. Copy the block for the builder the site uses…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Complete flat_html_rules sets for the builders whose markup a generic converter cannot read on its own: Bricks, Elementor, Divi, Oxygen and GenerateBlocks. Copy the block for the builder the site uses into your config file — or combine several, which is what a site that changed builders once already needs.\nBelow are complete configuration examples for popular WordPress page builders.\nBricks Builder\n 1# config-bricks.yaml\n 2flat_html_rules:\n 3  # Headings\n 4  - class: \u0026#34;brxe-heading\u0026#34;\n 5    tag: \u0026#34;div\u0026#34;\n 6    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n 7  - class: \u0026#34;brxe-heading\u0026#34;\n 8    tag: \u0026#34;h1\u0026#34;\n 9    markdown: \u0026#34;# {content}\\n\\n\u0026#34;\n10  - class: \u0026#34;brxe-heading\u0026#34;\n11    tag: \u0026#34;h2\u0026#34;\n12    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n13  - class: \u0026#34;brxe-heading\u0026#34;\n14    tag: \u0026#34;h3\u0026#34;\n15    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n16\n17  # Text blocks\n18  - class: \u0026#34;brxe-text\u0026#34;\n19    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n20  - class: \u0026#34;brxe-text-basic\u0026#34;\n21    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n22\n23  # Lists\n24  - class: \u0026#34;brxe-list\u0026#34;\n25    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n26\n27  # Buttons (extract as links)\n28  - class: \u0026#34;brxe-button\u0026#34;\n29    markdown: \u0026#34;[{content}]\\n\\n\u0026#34;\n30\n31  # Code blocks\n32  - class: \u0026#34;brxe-code\u0026#34;\n33    markdown: \u0026#34;```\\n{content}\\n```\\n\\n\u0026#34;\nElementor\n 1# config-elementor.yaml\n 2flat_html_rules:\n 3  # Headings\n 4  - class: \u0026#34;elementor-heading-title\u0026#34;\n 5    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n 6  - class: \u0026#34;elementor-size-large\u0026#34;\n 7    markdown: \u0026#34;# {content}\\n\\n\u0026#34;\n 8  - class: \u0026#34;elementor-size-medium\u0026#34;\n 9    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n10  - class: \u0026#34;elementor-size-small\u0026#34;\n11    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n12\n13  # Text widgets\n14  - class: \u0026#34;elementor-text-editor\u0026#34;\n15    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n16  - class: \u0026#34;elementor-widget-text-editor\u0026#34;\n17    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n18\n19  # Buttons\n20  - class: \u0026#34;elementor-button-text\u0026#34;\n21    markdown: \u0026#34;[{content}]\\n\\n\u0026#34;\n22\n23  # Lists\n24  - class: \u0026#34;elementor-icon-list-text\u0026#34;\n25    markdown: \u0026#34;- {content}\\n\u0026#34;\n26\n27  # Testimonials\n28  - class: \u0026#34;elementor-testimonial-content\u0026#34;\n29    markdown: \u0026#34;\u0026gt; {content}\\n\\n\u0026#34;\n30  - class: \u0026#34;elementor-testimonial-name\u0026#34;\n31    markdown: \u0026#34;**{content}**\\n\\n\u0026#34;\n32\n33  # Tabs and accordions\n34  - class: \u0026#34;elementor-tab-title\u0026#34;\n35    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n36  - class: \u0026#34;elementor-tab-content\u0026#34;\n37    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n38  - class: \u0026#34;elementor-accordion-title\u0026#34;\n39    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n40  - class: \u0026#34;elementor-accordion-content\u0026#34;\n41    markdown: \u0026#34;{content}\\n\\n\u0026#34;\nDivi Builder\n 1# config-divi.yaml\n 2flat_html_rules:\n 3  # Module titles\n 4  - class: \u0026#34;et_pb_module_header\u0026#34;\n 5    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n 6\n 7  # Text modules\n 8  - class: \u0026#34;et_pb_text_inner\u0026#34;\n 9    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n10\n11  # Blurb modules\n12  - class: \u0026#34;et_pb_blurb_content\u0026#34;\n13    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n14  - class: \u0026#34;et_pb_blurb_title\u0026#34;\n15    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n16\n17  # Buttons\n18  - class: \u0026#34;et_pb_button\u0026#34;\n19    markdown: \u0026#34;[{content}]\\n\\n\u0026#34;\n20\n21  # Testimonials\n22  - class: \u0026#34;et_pb_testimonial_description\u0026#34;\n23    markdown: \u0026#34;\u0026gt; {content}\\n\\n\u0026#34;\n24  - class: \u0026#34;et_pb_testimonial_author\u0026#34;\n25    markdown: \u0026#34;**{content}**\\n\\n\u0026#34;\n26\n27  # Tabs\n28  - class: \u0026#34;et_pb_tab_title\u0026#34;\n29    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n30  - class: \u0026#34;et_pb_tab_content\u0026#34;\n31    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n32\n33  # Toggle/Accordion\n34  - class: \u0026#34;et_pb_toggle_title\u0026#34;\n35    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n36  - class: \u0026#34;et_pb_toggle_content\u0026#34;\n37    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n38\n39  # Pricing tables\n40  - class: \u0026#34;et_pb_pricing_title\u0026#34;\n41    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n42  - class: \u0026#34;et_pb_pricing_content\u0026#34;\n43    markdown: \u0026#34;{content}\\n\\n\u0026#34;\nOxygen Builder\n 1# config-oxygen.yaml\n 2flat_html_rules:\n 3  # Headings\n 4  - class: \u0026#34;ct-headline\u0026#34;\n 5    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n 6  - class: \u0026#34;ct-headline\u0026#34;\n 7    tag: \u0026#34;h1\u0026#34;\n 8    markdown: \u0026#34;# {content}\\n\\n\u0026#34;\n 9  - class: \u0026#34;ct-headline\u0026#34;\n10    tag: \u0026#34;h2\u0026#34;\n11    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n12  - class: \u0026#34;ct-headline\u0026#34;\n13    tag: \u0026#34;h3\u0026#34;\n14    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n15\n16  # Text blocks\n17  - class: \u0026#34;ct-text-block\u0026#34;\n18    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n19\n20  # Rich text\n21  - class: \u0026#34;ct-rich-text\u0026#34;\n22    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n23\n24  # Buttons\n25  - class: \u0026#34;ct-button\u0026#34;\n26    markdown: \u0026#34;[{content}]\\n\\n\u0026#34;\n27\n28  # Links\n29  - class: \u0026#34;ct-link-text\u0026#34;\n30    markdown: \u0026#34;{content}\\n\\n\u0026#34;\nGenerateBlocks\n 1# config-generateblocks.yaml\n 2flat_html_rules:\n 3  # Headlines\n 4  - class: \u0026#34;gb-headline\u0026#34;\n 5    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n 6  - class: \u0026#34;gb-headline\u0026#34;\n 7    tag: \u0026#34;h1\u0026#34;\n 8    markdown: \u0026#34;# {content}\\n\\n\u0026#34;\n 9  - class: \u0026#34;gb-headline\u0026#34;\n10    tag: \u0026#34;h2\u0026#34;\n11    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n12  - class: \u0026#34;gb-headline\u0026#34;\n13    tag: \u0026#34;h3\u0026#34;\n14    markdown: \u0026#34;### {content}\\n\\n\u0026#34;\n15\n16  # Buttons\n17  - class: \u0026#34;gb-button\u0026#34;\n18    markdown: \u0026#34;[{content}]\\n\\n\u0026#34;\n19  - class: \u0026#34;gb-button-text\u0026#34;\n20    markdown: \u0026#34;{content}\u0026#34;\nCombining Multiple Page Builders\nIf your site uses multiple page builders or plugins, you can combine rules:\n 1# config-combined.yaml\n 2flat_html_rules:\n 3  # Bricks Builder\n 4  - class: \u0026#34;brxe-heading\u0026#34;\n 5    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n 6  - class: \u0026#34;brxe-text\u0026#34;\n 7    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n 8\n 9  # Elementor\n10  - class: \u0026#34;elementor-heading-title\u0026#34;\n11    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n12  - class: \u0026#34;elementor-text-editor\u0026#34;\n13    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n14\n15  # WPBakery/Visual Composer\n16  - class: \u0026#34;vc_custom_heading\u0026#34;\n17    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n18  - class: \u0026#34;wpb_text_column\u0026#34;\n19    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n20\n21  # Gutenberg blocks\n22  - class: \u0026#34;wp-block-heading\u0026#34;\n23    markdown: \u0026#34;## {content}\\n\\n\u0026#34;\n24  - class: \u0026#34;wp-block-paragraph\u0026#34;\n25    markdown: \u0026#34;{content}\\n\\n\u0026#34;\n26  - class: \u0026#34;wp-block-quote\u0026#34;\n27    markdown: \u0026#34;\u0026gt; {content}\\n\\n\u0026#34;","title":"Page builder conversion rules","translation_key":"","url":"/page-builders/"},{"excerpt":"One command per job: point the exporter at a WordPress site, choose a format, and read the files it writes. These are the invocations worth knowing before anything else — every flag they use is…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"One command per job: point the exporter at a WordPress site, choose a format, and read the files it writes. These are the invocations worth knowing before anything else — every flag they use is spelled out in the command line reference.\nREST API Export (wpexporter)\n 1# Export all content from a WordPress site\n 2wpexportjson export --url https://example.com --output ./export\n 3\n 4# Export with brute force discovery\n 5wpexportjson export --url https://example.com --brute-force --output ./export\n 6\n 7# Export to specific format\n 8wpexportjson export --url https://example.com --format json --output ./export.json\n 9\n10# Export and create ZIP archive\n11wpexportjson export --url https://example.com --zip\n12\n13# Export to ZIP only (remove files after creating ZIP)\n14wpexportjson export --url https://example.com --zip --no-files\n15\n16# Export to Markdown with ZIP archive\n17wpexportjson export --url https://example.com -f markdown --zip\n18\n19# Export to Shopify-compatible CSV format\n20wpexportjson export --url https://example.com -f shopify\n21\n22# Export to Shopify CSV with ZIP archive\n23wpexportjson export --url https://example.com -f shopify --zip\n24\n25# Export to Magento-compatible CSV format\n26wpexportjson export --url https://example.com -f magento\n27\n28# Export to Magento CSV with ZIP archive\n29wpexportjson export --url https://example.com -f magento --zip\n30\n31# Export to WordPress WXR format (for WordPress import)\n32wpexportjson export --url https://example.com -f wordpress\n33\n34# Export to Drupal-compatible JSON format\n35wpexportjson export --url https://example.com -f drupal\n36\n37# Export to Wix-compatible JSON format\n38wpexportjson export --url https://example.com -f wix\n39\n40# Export to Squarespace-compatible XML format\n41wpexportjson export --url https://example.com -f squarespace\n42\n43# Export to Webflow-compatible CSV format\n44wpexportjson export --url https://example.com -f webflow\n45\n46# Export to Weebly-compatible format (XML + JSON)\n47wpexportjson export --url https://example.com -f weebly\n48\n49# Export to PrestaShop-compatible CSV format\n50wpexportjson export --url https://example.com -f prestashop\n51\n52# Export to Ghost-compatible JSON format\n53wpexportjson export --url https://example.com -f ghost\n54\n55# Export to Strapi-compatible JSON format\n56wpexportjson export --url https://example.com -f strapi\n57\n58# Export to Contentful-compatible JSON format\n59wpexportjson export --url https://example.com -f contentful\nXML-RPC Export (wpxmlrpc)\n1# Export with authentication\n2wpxmlrpc export --url https://example.com --username admin --password mypassword --output ./xmlrpc-export\n3\n4# Export to markdown format\n5wpxmlrpc export --url https://example.com --username admin --password mypassword --format markdown --output ./markdown-export","title":"Quick start","translation_key":"","url":"/quickstart/"},{"excerpt":"--assisted-crawl fetches the rendered page behind each post, so the titles, meta descriptions, OpenGraph tags and hreflang alternates a plugin renders — and the REST API never exposes — leave with…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"--assisted-crawl fetches the rendered page behind each post, so the titles, meta descriptions, OpenGraph tags and hreflang alternates a plugin renders — and the REST API never exposes — leave with the content. The same pass records the site's own marketing wiring into metadata.json.\nThe --assisted-crawl option enables extraction of SEO metadata by crawling actual page URLs. This is useful when:\n\nRankMath, Yoast, or other SEO plugins are installed\nSEO data is not exposed via WordPress REST API\nYou need accurate \u0026lt;title\u0026gt; tags and meta descriptions\n\nExtracted SEO Fields\n\n\n\nField\nSource\n\n\n\n\nseo_title\n\u0026lt;title\u0026gt; tag content\n\n\nmeta_description\n\u0026lt;meta name=\u0026quot;description\u0026quot;\u0026gt;\n\n\nmeta_keywords\n\u0026lt;meta name=\u0026quot;keywords\u0026quot;\u0026gt;\n\n\nog_title\n\u0026lt;meta property=\u0026quot;og:title\u0026quot;\u0026gt;\n\n\nog_description\n\u0026lt;meta property=\u0026quot;og:description\u0026quot;\u0026gt;\n\n\nog_image\n\u0026lt;meta property=\u0026quot;og:image\u0026quot;\u0026gt;\n\n\ncanonical_url\n\u0026lt;link rel=\u0026quot;canonical\u0026quot;\u0026gt;\n\n\nlang\n\u0026lt;html lang=\u0026quot;...\u0026quot;\u0026gt; or \u0026lt;meta http-equiv=\u0026quot;Content-Language\u0026quot;\u0026gt;\n\n\nhreflangs\n\u0026lt;link rel=\u0026quot;alternate\u0026quot; hreflang=\u0026quot;...\u0026quot;\u0026gt; (all language variants)\n\n\n\nUsage Example\n 1# Export with SEO metadata extraction\n 2wpexportjson export --url https://example.com --assisted-crawl -f markdown\n 3\n 4# Combine with path filter for specific sections\n 5wpexportjson export --url https://example.com --path-filter=/blog/ --assisted-crawl -f markdown\n 6\n 7# With authentication for protected sites\n 8wpexportjson export --url https://example.com --auth-user admin --auth-pass secret --assisted-crawl\n 9\n10# Exclude specific SEO tags from extraction\n11wpexportjson export --url https://example.com --assisted-crawl --exclude-tags \u0026#39;meta:description,og:title\u0026#39;\n12\n13# With rate limiting to prevent server overload (500ms delay between requests)\n14wpexportjson export --url https://example.com --rate-limit 500 -f markdown\n15\n16# Resume interrupted export (checkpoint is saved automatically)\n17wpexportjson export --url https://example.com --resume -f markdown\nSite-level marketing metadata\n--assisted-crawl also reads the home page once and records the site's marketing\nwiring into metadata.json under marketing, so a migration can configure the\ntarget instead of re-entering it by hand:\n 1{\n 2  \u0026#34;marketing\u0026#34;: {\n 3    \u0026#34;verification\u0026#34;: {\n 4      \u0026#34;google-site-verification\u0026#34;: \u0026#34;abc123\u0026#34;,\n 5      \u0026#34;facebook-domain-verification\u0026#34;: \u0026#34;fb456\u0026#34;\n 6    },\n 7    \u0026#34;social_profiles\u0026#34;: {\n 8      \u0026#34;facebook\u0026#34;: \u0026#34;https://facebook.com/example\u0026#34;,\n 9      \u0026#34;instagram\u0026#34;: \u0026#34;https://instagram.com/example\u0026#34;\n10    },\n11    \u0026#34;og_site_name\u0026#34;: \u0026#34;Example Site\u0026#34;,\n12    \u0026#34;og_image\u0026#34;: \u0026#34;https://example.com/wp-content/uploads/2024/05/social.jpg\u0026#34;,\n13    \u0026#34;twitter_site\u0026#34;: \u0026#34;@example\u0026#34;,\n14    \u0026#34;favicon\u0026#34;: \u0026#34;https://example.com/favicon-192x192.png\u0026#34;,\n15    \u0026#34;apple_touch_icon\u0026#34;: \u0026#34;https://example.com/apple-touch-icon.png\u0026#34;,\n16    \u0026#34;theme_color\u0026#34;: \u0026#34;#0f172a\u0026#34;\n17  }\n18}\nThe theme's palette\nmarketing.colors carries the palette by role — primary, secondary,\naccent, text, background, link — so a migrated site arrives in its own\ncolours rather than the target theme's defaults.\nIt is read from the CSS custom properties a theme declares (block themes,\nElementor, GeneratePress 3.x). A theme that declares none has not stopped having\na palette: classic themes write their colours as ordinary rules, so the roles are\nthen taken from body (background and text), a (link), the header or\nnavigation rule (primary, falling back to theme_color, which is the brand\ncolour by definition) and the button rule (accent).\nWordPress core's own --wp--preset--color--* properties are never read: they are\nGutenberg's defaults, identical on every site, and recording them would say\nsomething false about this one. The background and text pair is contrast-checked\nbefore it is emitted — two rules that cannot be a page's real body pair are two\ndifferent contexts read as one, and nothing is recorded rather than a guess.\nFavicon, apple-touch-icon and logo are read from the document's \u0026lt;link rel=...\u0026gt;\ntags (the largest declared favicon size wins), social profiles from \u0026lt;header\u0026gt; and\n\u0026lt;footer\u0026gt; links, and relative paths are resolved to absolute URLs. Everything is\nbest-effort: a value the site does not declare is omitted rather than invented.\nTracking identifiers (GA4, GTM, Meta Pixel, Hotjar, Clarity, …) are recorded\nseparately under analytics.","title":"SEO metadata extraction","translation_key":"","url":"/seo/"},{"excerpt":"-f ssg writes a drop-in content source for SSG and other static site generators. Where markdown is a faithful dump of what WordPress returned, ssg is a content source: one name per concept, paths…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"-f ssg writes a drop-in content source for SSG and other static site generators. Where markdown is a faithful dump of what WordPress returned, ssg is a content source: one name per concept, paths that mirror the site, and body HTML cleaned of the old theme's scaffolding.\nA drop-in content source for spagu/ssg and other static site\ngenerators. Where markdown is a faithful dump of what WordPress returned, ssg is a\ncontent source: one name per concept, paths that mirror the site, and body HTML cleaned of\nthe old theme's scaffolding.\n1wpexportjson export --url https://example.com -f ssg -o export/site \\\n2  --assisted-crawl --crawl-content\n📂 Layout\nexport/site/\n├── metadata.json                       categories / tags / users / media\n├── comments.json                       reader comments, addressed by page URL\n├── pages/\n│   ├── about.md                        /about/\n│   └── baby-water-instructor/\n│       └── cost.md                     /baby-water-instructor/cost/\n├── posts/\n│   └── swimming/\n│       └── swimming-lesson.md          posts sit at least one level below posts/\n└── media/images/…\n\nPages are nested to mirror their URL, so the site's information architecture stays visible\nin the file tree. Posts sit under their category; one with no resolvable category lands in\nposts/uncategorized/.\n📝 Front Matter\nSingle-spelled — a generator reads one name per concept, not three:\n\n\n\nKey\nSource\n\n\n\n\ntitle\nseo_title if the site rendered one, else the post title\n\n\nslug, status, type\nas reported by WordPress\n\n\ndate, modified\nRFC 3339\n\n\nlink\nroot-relative by default (--link-style absolute to change)\n\n\nauthor\nresolved to a name via metadata.json users[]\n\n\ncategory\nthe post's first named category\n\n\ndescription\nmeta_description, else og_description, else the excerpt\n\n\nexcerpt\nplain text, theme \u0026quot;Continue reading\u0026quot; chrome removed\n\n\nfeatured_image\nlocalised media path\n\n\n\nEmpty values emit no key at all, so a generator sees an absent key rather than an empty\nstring.\n🧹 Content Cleanup\nApplied to the body of every ssg document:\n\n\n\nTransform\nWhy\n\n\n\n\nHTML entities → UTF-8 (\u0026amp;#8211; → –, \u0026amp;hellip; → …)\nThe file is UTF-8; the entities are noise that survives into the rendered page. \u0026amp;lt;, \u0026amp;gt;, \u0026amp;amp;, \u0026amp;quot; and \u0026amp;#39; stay encoded — decoding those would turn escaped markup into live markup\n\n\nalt filled from the media library's alt_text\nWCAG 2.2 SC 1.1.1 Non-text Content. An existing alt is never overwritten\n\n\nWordPress classes dropped (wp-image-*, size-*, align*, attachment-*, wp-block-*)\nThey refer to the old theme's stylesheet. Authored classes are kept\n\n\ntitle dropped when it merely repeats the filename\nCarries no information a reader can use\n\n\nloading, decoding, sizes dropped\nBrowser hints the generator emits itself\n\n\n\nThe markdown format keeps its existing output, with two exceptions that were plainly bugs:\nentities are decoded there too, and the excerpt no longer carries the \u0026quot;Continue reading\u0026quot; anchor.","title":"Static site generator format","translation_key":"","url":"/ssg-format/"},{"excerpt":"The wpxmlrpc tool provides an alternative method for exporting WordPress content using the XML-RPC protocol. This is particularly useful when the REST API is disabled or when you need to access…","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Overview\nThe wpxmlrpc tool provides an alternative method for exporting WordPress content using the XML-RPC protocol. This is particularly useful when the REST API is disabled or when you need to access content that requires authentication.\nPrerequisites\n\nWordPress site with XML-RPC enabled\nValid WordPress username and password\nAdministrative or editor privileges on the WordPress site\n\nInstallation\nHomebrew (macOS / Linux)\n1brew install tradik/tap/wpexporter\nSnap (Linux)\n1sudo snap install wpexporter\nFrom Source\n1git clone https://github.com/tradik/wpexporter.git\n2cd wpexporter\n3make build\nThe XML-RPC client will be built as build/wpxmlrpc.\nUsing Go Install\n1go install github.com/tradik/wpexporter/cmd/wpxmlrpc@latest\nBasic Usage\nCommand Structure\n1wpxmlrpc export --url \u0026lt;wordpress-url\u0026gt; --username \u0026lt;username\u0026gt; --password \u0026lt;password\u0026gt; [options]\nRequired Parameters\n\n\n\nParameter\nDescription\nExample\n\n\n\n\n--url\nWordPress site URL\nhttps://example.com\n\n\n--username\nWordPress username\nadmin\n\n\n--password\nWordPress password\nyour-password\n\n\n\nOptional Parameters\n\n\n\nParameter\nShort\nDescription\nDefault\n\n\n\n\n--output\n-o\nOutput directory or file\n./xmlrpc-export\n\n\n--format\n-f\nExport format (json/markdown)\njson\n\n\n--verbose\n-v\nEnable verbose output\nfalse\n\n\n--config\n\nConfiguration file path\n-\n\n\n\nExamples\nBasic Export\n1wpxmlrpc export --url https://myblog.com --username admin --password mypassword\nExport to Specific Directory\n1wpxmlrpc export \\\n2  --url https://myblog.com \\\n3  --username admin \\\n4  --password mypassword \\\n5  --output ./my-blog-backup\nExport as Markdown\n1wpxmlrpc export \\\n2  --url https://myblog.com \\\n3  --username admin \\\n4  --password mypassword \\\n5  --format markdown \\\n6  --output ./markdown-export\nUsing Configuration File\nCreate a config.yaml file:\n1url: \u0026#34;https://myblog.com\u0026#34;\n2output: \u0026#34;./xmlrpc-export\u0026#34;\n3format: \u0026#34;json\u0026#34;\n4verbose: true\nThen run:\n1wpxmlrpc export --username admin --password mypassword --config config.yaml\nSecurity Considerations\nPassword Security\n\nNever hardcode passwords in scripts or configuration files\nUse environment variables for sensitive data:\n1export WP_USERNAME=\u0026#34;admin\u0026#34;\n2export WP_PASSWORD=\u0026#34;mypassword\u0026#34;\n3wpxmlrpc export --url https://myblog.com --username $WP_USERNAME --password $WP_PASSWORD\n\n\nHTTPS Requirement\n\nAlways use HTTPS URLs when possible to encrypt credentials in transit\nAvoid using XML-RPC over unencrypted HTTP connections\n\nApplication Passwords (WordPress 5.6+)\nFor enhanced security, use WordPress Application Passwords:\n\nGo to your WordPress admin → Users → Your Profile\nScroll to \u0026quot;Application Passwords\u0026quot;\nCreate a new application password\nUse the generated password instead of your regular password\n\nXML-RPC Methods Used\nThe tool uses the following WordPress XML-RPC methods:\n\n\n\nMethod\nPurpose\nAuthentication Required\n\n\n\n\nwp.getOptions\nSite information and connection test\nYes\n\n\nwp.getPosts\nRetrieve posts\nYes\n\n\nwp.getPages\nRetrieve pages\nYes\n\n\nwp.getMediaLibrary\nRetrieve media files\nYes\n\n\nwp.getTerms\nRetrieve categories and tags\nYes\n\n\nwp.getUsers\nRetrieve users\nYes\n\n\n\nTroubleshooting\nXML-RPC Disabled\nIf you get an error about XML-RPC being disabled:\n\n\nCheck if XML-RPC is enabled:\n1curl -X POST https://yoursite.com/xmlrpc.php \\\n2  -H \u0026#34;Content-Type: text/xml\u0026#34; \\\n3  -d \u0026#39;\u0026lt;?xml version=\u0026#34;1.0\u0026#34;?\u0026gt;\u0026lt;methodCall\u0026gt;\u0026lt;methodName\u0026gt;system.listMethods\u0026lt;/methodName\u0026gt;\u0026lt;/methodCall\u0026gt;\u0026#39;\n\n\nEnable XML-RPC in WordPress:\nAdd to your theme's functions.php:\n1add_filter(\u0026#39;xmlrpc_enabled\u0026#39;, \u0026#39;__return_true\u0026#39;);\n\n\nCheck for security plugins that might block XML-RPC\n\n\nAuthentication Errors\n\nVerify username and password are correct\nCheck if two-factor authentication is enabled (may require app passwords)\nEnsure the user has sufficient privileges\n\nConnection Issues\n\nVerify the WordPress URL is correct\nCheck if the site is behind a firewall or CDN\nTry increasing timeout in configuration\n\nLarge Sites\nFor sites with many posts/pages:\n\nThe tool automatically handles pagination\nConsider using the REST API client (wpexportjson) for better performance\nMonitor memory usage for very large exports\n\nOutput Formats\nJSON Format\nExports all data as a single JSON file with the following structure:\n 1{\n 2  \u0026#34;site\u0026#34;: { ... },\n 3  \u0026#34;posts\u0026#34;: [ ... ],\n 4  \u0026#34;pages\u0026#34;: [ ... ],\n 5  \u0026#34;media\u0026#34;: [ ... ],\n 6  \u0026#34;categories\u0026#34;: [ ... ],\n 7  \u0026#34;tags\u0026#34;: [ ... ],\n 8  \u0026#34;users\u0026#34;: [ ... ],\n 9  \u0026#34;stats\u0026#34;: { ... },\n10  \u0026#34;exported_at\u0026#34;: \u0026#34;2024-01-07T12:00:00Z\u0026#34;\n11}\nMarkdown Format\nCreates a directory structure:\noutput/\n├── README.md           # Site information\n├── posts/             # Individual post files\n│   ├── 2024-01-01-post-title.md\n│   └── ...\n├── pages/             # Individual page files\n│   ├── 2024-01-01-page-title.md\n│   └── ...\n├── media/             # Downloaded media files\n│   ├── image1.jpg\n│   └── ...\n└── metadata.json      # Categories, tags, users, etc.\n\nComparison with REST API Client\n\n\n\nFeature\nXML-RPC (wpxmlrpc)\nREST API (wpexportjson)\n\n\n\n\nAuthentication\nUsername/Password\nPublic API (no auth needed)\n\n\nPerformance\nSlower\nFaster\n\n\nBrute Force\nNot supported\nSupported\n\n\nMedia Download\nLimited\nFull support\n\n\nCompatibility\nOlder WordPress\nWordPress 4.7+\n\n\nSecurity\nRequires credentials\nNo credentials needed\n\n\n\nConfiguration File Reference\n 1# WordPress site URL (required via CLI)\n 2url: \u0026#34;https://your-wordpress-site.com\u0026#34;\n 3\n 4# Output directory or file path\n 5output: \u0026#34;./xmlrpc-export\u0026#34;\n 6\n 7# Export format: json or markdown\n 8format: \u0026#34;json\u0026#34;\n 9\n10# Download media files (images, videos, etc.)\n11download_media: true\n12\n13# Number of concurrent downloads\n14concurrent: 5\n15\n16# HTTP request timeout in seconds\n17timeout: 30\n18\n19# Number of retries for failed requests\n20retries: 3\n21\n22# User agent string for HTTP requests\n23user_agent: \u0026#34;WordPress-XML-RPC-Export/1.0\u0026#34;\n24\n25# Enable verbose output\n26verbose: false\nAdvanced Usage\nBatch Processing\nProcess multiple sites:\n1#!/bin/bash\n2sites=(\u0026#34;site1.com\u0026#34; \u0026#34;site2.com\u0026#34; \u0026#34;site3.com\u0026#34;)\n3for site in \u0026#34;${sites[@]}\u0026#34;; do\n4  wpxmlrpc export --url \u0026#34;https://$site\u0026#34; --username admin --password \u0026#34;$WP_PASSWORD\u0026#34; --output \u0026#34;./exports/$site\u0026#34;\n5done\nAutomated Backups\nCreate a cron job for regular backups:\n1# Add to crontab (crontab -e)\n20 2 * * 0 /usr/local/bin/wpxmlrpc export --url https://myblog.com --username admin --password \u0026#34;$WP_PASSWORD\u0026#34; --output \u0026#34;/backups/$(date +\\%Y-\\%m-\\%d)\u0026#34;\nAPI Reference\nThe XML-RPC client can be used programmatically:\n 1package main\n 2\n 3import (\n 4    \u0026#34;github.com/tradik/wpexporter/internal/config\u0026#34;\n 5    \u0026#34;github.com/tradik/wpexporter/internal/xmlrpc\u0026#34;\n 6)\n 7\n 8func main() {\n 9    cfg := config.DefaultConfig()\n10    cfg.URL = \u0026#34;https://example.com\u0026#34;\n11    \n12    client, err := xmlrpc.NewClient(cfg, \u0026#34;username\u0026#34;, \u0026#34;password\u0026#34;)\n13    if err != nil {\n14        panic(err)\n15    }\n16    \n17    posts, err := client.GetPosts()\n18    if err != nil {\n19        panic(err)\n20    }\n21    \n22    // Process posts...\n23}\nSupport and Contributing\n\nReport issues: GitHub Issues\nDocumentation: Project README\nContributing: See Contributing Guidelines","title":"WordPress XML-RPC Export Manual","translation_key":"","url":"/xmlrpc_manual/"},{"excerpt":"Updated: 2026-08-14","lang":"","locale":"","tags":null,"taxonomies":{"category":["Documentation"]},"text":"Updated: 2026-08-14\nEvery action is pinned by commit SHA, never by tag: a tag is mutable and can be\nmoved onto different code after review. The trailing comment records which\nrelease that SHA is, down to the patch — a bare # v6 next to a SHA cannot be\nchecked against anything, and one of them had drifted a whole major behind what\nthe comment claimed.\nCurrent Versions in CI/CD Pipeline\n.github/workflows/ci.yml\n\n\n\nAction\nVersion\nNode.js\nNotes\n\n\n\n\nactions/checkout\nv7.0.1\n24\n\n\n\nactions/setup-go\nv7.0.0\n24\nESM runtime, @actions/cache 6.2\n\n\nactions/upload-artifact\nv7.0.1\n24\n\n\n\nactions/download-artifact\nv8.0.1\n24\n\n\n\ncodecov/codecov-action\nv7.0.0\n24\n\n\n\ngolangci/golangci-lint-action\nv9.3.0\n24\nlinter itself resolved as latest\n\n\nsoftprops/action-gh-release\nv3.0.2\n24\nv3 = Node 24 runtime; inputs unchanged from v2\n\n\ndocker/build-push-action\nv7.3.0\n24\n\n\n\ndocker/setup-buildx-action\nv4.2.0\n24\n\n\n\ndocker/login-action\nv4.6.0\n24\n\n\n\ndocker/metadata-action\nv6.2.0\n24\n\n\n\nsnapcore/action-build\nv1\n24 (forced)\nFORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true\n\n\nsnapcore/action-publish\nv1\n24 (forced)\nFORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true\n\n\n\n.github/workflows/docs-site.yml\n\n\n\nAction\nVersion\nNode.js\nNotes\n\n\n\n\nactions/checkout\nv7.0.1\n24\n\n\n\nspagu/ssg\nv1.8.32\nDocker\nthe site generator, pinned to its newest release\n\n\n\nToolchain pinned in the workflow\n\n\n\nTool\nVersion\nWhere\n\n\n\n\nGo\n1.26.6\ngo-version: in every job, and go 1.26.6 in go.mod\n\n\ngosec\nv2.28.0\ntool directive in tools/go.mod, every transitive version fixed by tools/go.sum\n\n\ngolangci-lint\nlatest\nversion: latest in the lint job\n\n\n\ngosec lives in a separate tools/ module rather than in the project's own\ngo.mod: it is built with go -C tools build, so the scanner and everything\nbeneath it come from a lock file, while its dependency tree — gRPC,\nOpenTelemetry, a handful of cloud SDKs — stays out of wpexporter's. go install pkg@version would pin only gosec itself and re-resolve the rest on every run.\nUpgrading it is two commands:\n1go -C tools get -tool github.com/securego/gosec/v2/cmd/gosec@vX.Y.Z\n2make sec        # builds the pinned scanner and runs it exactly as CI does\nChecking for updates\nscripts/check-actions-dynamic-v2.sh reports what is available. To verify a\npin by hand — resolve the SHA the workflow uses and compare it to the tag the\ncomment claims:\n1# Which release is this SHA?\n2gh api \u0026#34;repos/actions/checkout/tags?per_page=100\u0026#34; --paginate \\\n3  --jq \u0026#39;.[] | select(.commit.sha==\u0026#34;\u0026lt;SHA\u0026gt;\u0026#34;) | .name\u0026#39;\n4\n5# What is the newest release, and which commit does it point at?\n6gh api repos/actions/checkout/releases/latest --jq .tag_name\n7gh api repos/actions/checkout/git/ref/tags/v7.0.1 --jq .object.sha\nAnnotated tags answer with a tag object rather than a commit; dereference it\nwith gh api repos/\u0026lt;owner\u0026gt;/\u0026lt;repo\u0026gt;/git/tags/\u0026lt;sha\u0026gt; --jq .object.sha.\nNote: All actions run on the Node.js 24 runtime. Node.js 20 leaves the\nGitHub Actions runners on September 16th, 2026.","title":"GitHub Actions Versions Report","translation_key":"","url":"/github-actions-versions/"}]