Metadata-Version: 2.4
Name: divi-migrator
Version: 0.1.1
Summary: WordPress Avada/Elementor/Plain HTML to Divi 5 migration framework
Project-URL: Homepage, https://github.com/chriscstewart/Divi-Migrator
Project-URL: Repository, https://github.com/chriscstewart/Divi-Migrator
Project-URL: Issues, https://github.com/chriscstewart/Divi-Migrator/issues
Project-URL: Documentation, https://chriscstewart.github.io/Divi-Migrator/
Author-email: Chris <chris@example.com>
Maintainer-email: Chris <chris@example.com>
License: MIT
License-File: LICENSE
Keywords: avada,divi,divi5,elementor,fusion-builder,migration,wordpress,wp-rest-api
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: pydantic-settings>=2.1.0
Requires-Dist: pydantic>=2.5.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: requests>=2.31.0
Requires-Dist: rich>=13.0.0
Requires-Dist: tenacity>=8.2.0
Requires-Dist: typer>=0.9.0
Provides-Extra: dev
Requires-Dist: mypy>=1.7.0; extra == 'dev'
Requires-Dist: pre-commit>=3.6.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.12.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: types-pyyaml>=6.0.12; extra == 'dev'
Requires-Dist: types-requests>=2.31.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
Description-Content-Type: text/markdown

# divi-migrator

> **WordPress Avada/Elementor/Plain HTML → Divi 5 migration framework.**
> Built for AI-assisted workflows, zero vendor lock-in.

[![PyPI](https://img.shields.io/pypi/v/divi-migrator)](https://pypi.org/project/divi-migrator/)
[![Python](https://img.shields.io/pypi/pyversions/divi-migrator)](https://pypi.org/project/divi-migrator/)
[![License](https://img.shields.io/github/license/chriscstewart/Divi-Migrator)](LICENSE)
[![CI](https://img.shields.io/github/actions/workflow/status/chriscstewart/Divi-Migrator/test.yml)](https://github.com/chriscstewart/Divi-Migrator/actions)

---

## ✨ Features

| Feature | Description |
|---------|-------------|
| 🔍 **Auto-discovery** | Finds all pages/posts with builder content via WP REST API |
| 🎯 **Format detection** | Auto-detects Avada, Elementor, or plain HTML |
| 🔄 **Resumable** | JSON checkpoint survives crashes/restarts |
| 🧹 **Deduplication** | Keeps newest draft per source, removes rest |
| ✅ **Verification** | Validates sections, rows, modules, images, buttons, colors |
| ⚡ **Rate limiting** | Configurable, respects security plugins |
| 🔌 **Extensible** | Plugin architecture for new builders |
| 🎨 **Design system** | Fetches global colors, fonts, presets from Divi Customizer |
| 🏷️ **Migration tracking** | All migrated content tagged with `divi-migrator` category |
| 🔒 **Safe replacement** | Existing content renamed to `-old`, moved to Draft (not deleted) |

---

## 🚀 Quick Start

```bash
# Install
pip install divi-migrator

# Configure (env vars or config.yaml)
export WP_URL="https://yoursite.com"
export WP_USER="migration-bot"
export WP_APP_PASSWORD="***"

# Discover what can be migrated
divi-migrate discover --type page
divi-migrate discover --type post

# Dry run
divi-migrate migrate --type post --limit 5 --dry-run

# Real migration (resumable!)
divi-migrate migrate --type page --limit 50
divi-migrate migrate --type post --limit 100

# Cleanup duplicates
divi-migrate cleanup --type post

# Inspect target site's design system
divi-migrate inspect
```

---

## 📋 Migration Process

Before running the migration, follow these steps to prepare your target site:

### 1. Create a Staging Website First
Never run migrations directly on production. Create a complete staging copy of your site.

### 2. Install and Activate the Latest Divi 5 Theme
Ensure the target site runs Divi 5 (not Divi 4).

### 3. Create a New Blank Homepage and Configure Design Foundation
- Create a blank homepage
- Configure **Divi Options**
- Configure **Divi Customizer settings** 
- Set up **global styling/design system** (colors, fonts, spacing, button defaults, section backgrounds)

**Confirm the new design foundation is correct before migration.** This is what all migrated content will use.

### 4. Create a Dedicated WordPress Migration User
- Create a separate account only for migration tasks
- Generate an **Application Password** for this user
- This isolates migration activity and simplifies rollback/auditing

### 5. Install and Activate the DiviOps Plugin
The [DiviOps plugin](https://github.com/oaris-dev/diviops) provides the REST API endpoints required for migration.

### 6. Connect Your AI Agent to Required MCP Tools
- **DiviOps MCP** — required for all Divi 5 operations
- **WordPress MCP** — [https://github.com/docdyhr/mcp-wordpress](https://github.com/docdyhr/mcp-wordpress) — for additional WP operations

### 7. Give the AI Agent Migration Instructions
Example prompt:
> "Migrate this website from [source theme] to Divi 5 using Divi-Migrator."

The tool automatically tags/categorizes migrated content with `divi-migrator` so it can be easily reviewed, filtered, updated, or removed.

---

## 🏗️ Requirements

| Component | Version |
|-----------|---------|
| WordPress | 6.0+ |
| Divi | 5.0+ |
| **DiviOps Plugin** | [Active (provides REST endpoints)](https://github.com/oaris-dev/diviops) |
| Auth | Application Password (WP 5.6+) |

### DiviOps Endpoints Required

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/wp-json/diviops/v1/page/create` | POST | Create draft with Divi content |
| `/wp-json/diviops/v1/page/update-content/{id}` | POST | Push Divi 5 blocks |
| `/wp-json/diviops/v1/page/get/{id}` | GET | Read page data |
| `/wp-json/diviops/v1/page/get-layout/{id}` | GET | Verify block tree |
| `/wp-json/diviops/v1/meta/flush-cache` | POST | Clear Divi cache |
| `/wp-json/diviops/v1/validate/blocks` | POST | Validate block structure |
| `/wp-json/diviops/v1/global-color/list` | GET | Fetch global colors |
| `/wp-json/diviops/v1/global-font/list` | GET | Fetch global fonts |
| `/wp-json/diviops/v1/preset/list` | GET | Fetch module presets |

---

## ⚙️ Configuration

### Environment Variables

```bash
# Required
WP_URL=https://yoursite.com
WP_USER=migration-bot
WP_APP_PASSWORD=***

# Optional
DIVIOPS_URL=https://yoursite.com          # if different from WP_URL
RATE_LIMIT=2.0                            # seconds between requests
CHECKPOINT_DIR=./checkpoints
SSL_VERIFY=true
```

### Config File (`config.yaml`)

```yaml
wp:
  url: "https://yoursite.com"
  user: "migration-bot"
  app_password: "${WP_APP_PASSWORD}"
  ssl_verify: true
  timeout: 30

diviops:
  url: "https://yoursite.com"   # same as WP_URL if on same host

migration:
  rate_limit: 2.0
  batch_size: 50
  checkpoint_dir: "./checkpoints"
  max_retries: 3
  timeout: 30

verification:
  require_sections: true
  require_images: false
  require_buttons: false
  primary_color_token: "gcid-primary-color"
  default_section_bg: "#f7f4ef"

design_system:
  fetch_on_start: true
  cache_ttl: 3600
  fallback_to_defaults: true
  primary_color_override: null
  section_bg_override: null
```

---

## 🔌 Extending for New Builders

```python
# my_converters/custom.py
from divi_migrator.converters import BaseConverter, register_converter

class CustomBuilderConverter(BaseConverter):
    format_name = "custom_builder"

    def detect(self, content: str) -> bool:
        return 'custom_builder_shortcode' in content

    def convert(self, content: str, source_id: int, design_system=None) -> str:
        # Transform to Divi 5 shortcodes
        return divi_shortcodes

    def extract_assets(self, content: str) -> ExtractedAssets:
        return ExtractedAssets()

# Register
from divi_migrator.converters import register_converter
register_converter("custom_builder", CustomBuilderConverter)
```

Then use: `divi-migrate migrate --converter custom_builder`

---

## 📁 Project Structure

```
divi_migrator/
├── cli.py              # Typer CLI entrypoint
├── config.py           # Pydantic Settings (env + YAML)
├── core/
│   ├── client.py       # WP REST + DiviOps clients
│   ├── inspector.py    # Design system fetcher
│   ├── discovery.py    # Content discovery
│   ├── orchestrator.py # Migration pipeline
│   ├── checkpoint.py   # JSON checkpoint I/O
│   └── verification.py # Layout verification
├── converters/
│   ├── base.py         # BaseConverter + Registry
│   ├── avada.py        # Fusion Builder → Divi 5
│   ├── elementor.py    # Elementor → Divi 5 (stub)
│   └── plain_html.py   # HTML → Divi 5 wrapper
├── models/
│   ├── __init__.py     # MigrationMeta, CheckpointRecord, etc.
│   └── design_system.py # DesignSystem, GlobalColors, etc.
```

---

## 🧪 Testing

```bash
# Unit tests
pytest tests/unit/ -v

# Integration (requires test WP site)
pytest tests/integration/ --wp-url=https://test.site --wp-user=... --wp-pass=...

# Lint + type check
ruff check .
mypy divi_migrator/
```

---

## 🔐 Security

- No credentials stored in code — uses environment variables
- Authentication details never logged
- SSL verification enabled by default (warns if disabled)
- URL validation before requests
- Unsafe protocols rejected

---

## 📄 License

MIT License - see [LICENSE](LICENSE)