Export WordPress posts to CSV or MySQL using the REST API
Project description
WordPress Post Exporter
Python tool to export all published posts from a WordPress site using the official REST API (wp-json/wp/v2), including post content and taxonomy/author metadata.
Features
- Exports all published posts with pagination (
per_page=100). - Supports
csvandsqloutput. - SQL output is MySQL 8 compatible.
- Includes progress logs in the terminal (with optional
--quiet). - Tries
context=editfirst, then automatically falls back tocontext=viewif unauthorized. - Preserves the full API payload in
raw_post_jsonfor custom fields and future migrations.
Exported Data
Each exported post includes:
- Core fields:
id,status,type,slug,link,date,date_gmt,modified,modified_gmt - Title, excerpt, and content in both flavors when available:
*_rendered*_raw(typically available withcontext=edit+ permissions)
- Author:
author_idauthor_name
- Taxonomies:
- categories IDs + names
- tags IDs + names
- Extra fields:
featured_media,comment_status,ping_status,template,format,meta
- Full raw JSON payload:
raw_post_json
Requirements
- Python 3.10+
Installation
Install from PyPI (recommended)
pip install wp-exporter
This installs the wp-export command globally.
Install from source
# Clone the repository
git clone https://github.com/youruser/wp-exporter.git
cd wp-exporter
# Install in editable mode
pip install -e .
# Or install with dev dependencies
pip install -e ".[dev]"
Local development
- (Optional, recommended) create and activate a virtual environment:
python3 -m venv .venv
source .venv/bin/activate
- Install dependencies:
pip install -r requirements.txt
Or install the package in editable mode:
pip install -e .
Authentication
Use one of the following:
- Bearer token
--token
- WordPress Application Password (Basic Auth)
--username--application-password
Note: public exports also work without credentials in many sites, depending on API exposure rules.
Usage
Using wp-export command (after pip install)
# Public/API-view mode (no auth)
wp-export \
--base-url https://example.com \
--format csv \
--output posts.csv
# Bearer token
wp-export \
--base-url https://example.com \
--token YOUR_TOKEN \
--format csv \
--output posts.csv
# Username + Application Password
wp-export \
--base-url https://example.com \
--username admin \
--application-password "xxxx xxxx xxxx xxxx" \
--format sql \
--output posts.sql
Using python main.py (local development)
# Public/API-view mode (no auth)
python3 main.py \
--base-url https://example.com \
--format csv \
--output posts.csv
# Bearer token
python3 main.py \
--base-url https://example.com \
--token YOUR_TOKEN \
--format csv \
--output posts.csv
# Username + Application Password
python3 main.py \
--base-url https://example.com \
--username admin \
--application-password "xxxx xxxx xxxx xxxx" \
--format sql \
--output posts.sql
CLI Arguments
--base-url(required): WordPress site base URL. Example:https://example.com--format:csvorsql(default:csv)--output(required): output file path--token: bearer token--username: WordPress username--application-password: WordPress Application Password--timeout: timeout in seconds per HTTP request (default:30)--quiet: disable progress logs
Progress Output
By default, the exporter prints progress messages such as:
[INFO] Starting export...
[INFO] Fetching published posts (context=edit)...
[INFO] No permission for context=edit. Falling back to public mode (context=view).
[INFO] [posts] page 1/12 | accumulated: 100
[INFO] [posts] page 2/12 | accumulated: 200
[INFO] Total posts found: 1200
[INFO] Normalized: 1200/1200
[INFO] Writing CSV file to posts.csv...
Export completed. 1200 posts written to: posts.csv
CSV Format Specification
The CSV header columns are generated in this order:
iddatedate_gmtmodifiedmodified_gmtslugstatustypelinktitle_renderedtitle_rawexcerpt_renderedexcerpt_rawcontent_renderedcontent_rawauthor_idauthor_namecategories_ids(JSON array string)categories_names(JSON array string)tags_ids(JSON array string)tags_names(JSON array string)featured_mediacomment_statusping_statustemplateformatmeta(JSON object string)raw_post_json(full JSON object string)
Notes:
- CSV encoding is UTF-8.
- Content fields may contain long HTML/text.
- JSON-like columns are serialized as JSON strings.
SQL Format Specification (MySQL 8)
The .sql file includes:
- Session setup:
SET NAMES utf8mb4;SET time_zone = '+00:00';
- Schema reset and creation:
DROP TABLE IF EXISTS posts;CREATE TABLE posts (...) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
- Batched inserts:
INSERT INTO posts (...) VALUES (...), (...), ...;
Column Types
id:BIGINT NOT NULL(primary key)author_id,featured_media:BIGINT NULLdate,date_gmt,modified,modified_gmt:DATETIME NULL- all remaining columns:
LONGTEXT NULL
SQL Compatibility Details
- String escaping is MySQL-safe for:
- backslash (
\\) - single quote (
\') - null byte (
\0) - line break (
\n) - carriage return (
\r) \x1a(\Z)
- backslash (
- Inserts are chunked (200 rows per statement) to reduce very large single statements.
Importing SQL into MySQL 8
mysql -u your_user -p your_database < posts.sql
Project Structure
.
├── main.py
├── requirements.txt
└── wp_exporter
├── __init__.py
├── client.py
├── config.py
├── exporters.py
├── service.py
└── transformers.py
Troubleshooting
401or403from API
- Check credentials/permissions.
- Confirm REST API is enabled.
- If
context=editis blocked, the exporter automatically retries withcontext=view.
- Empty
*_rawfields
- Expected when the authenticated user lacks edit-level permissions.
- In public context, WordPress usually returns only rendered fields.
- Timeout/network issues
- Increase
--timeout. - Check firewall/WAF/proxy restrictions.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wp_exporter-1.0.0.tar.gz.
File metadata
- Download URL: wp_exporter-1.0.0.tar.gz
- Upload date:
- Size: 19.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6fa10d622043eafd9da53bc9c81e67f0e355af7097cb6e34c73989f3281143ae
|
|
| MD5 |
002559f3929040ed64dad6a9c157a0a8
|
|
| BLAKE2b-256 |
035227e34f095668f5e8d11e57ce287b17b88e912c29fb399ed38ce5e1c3123b
|
File details
Details for the file wp_exporter-1.0.0-py3-none-any.whl.
File metadata
- Download URL: wp_exporter-1.0.0-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
958fe3dc42433f6a65e7156486da8a834aa75c25385bbd6c9e6da75a35a90779
|
|
| MD5 |
a8601c434cf6292939c3cf6682b2fac5
|
|
| BLAKE2b-256 |
52dc95f08db05b44008f7a4cf7e5fc93a9b25f964d35869ac697b5907feb8abf
|