Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Changelog

All notable changes to the WordPress to Wagtail Connector will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Complete documentation including setup guide, field mapping guide, and troubleshooting guide
- Make commands for simplifying project setup and management
- Project structure documentation

### Changed

- Updated documentation to use make commands instead of uv run commands
- Improved field processor for handling richtext content

### Fixed

- Fixed typos and inconsistencies in documentation
- Fixed page hierarchy issues with better parent-child relationship handling

## [0.1.0] - 2025-05-21

### Added

- Initial release with basic WordPress to Wagtail migration functionality
- Support for posts, pages, authors, categories, tags, and comments
- Django admin interface for managing imports
- Wagtail integration for viewing imported content
- Docker setup for WordPress test instance
218 changes: 218 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Makefile for Wagtail-WordPress Connector

# Constants
WORDPRESS_ROOT = wordpress.docker
WORDPRESS_URL = http://localhost:8888
WORDPRESS_API = wp-json/wp/v2
DC = docker-compose

# Help command
.PHONY: help
help:
@echo "Wagtail-WordPress Connector Commands"
@echo ""
@echo "WordPress Container Commands:"
@echo " make wp-build - Wordpress: initial setup"
@echo " make wp-up - Wordpress: start the container"
@echo " make wp-load - Wordpress: import the demo data"
@echo " make wp-down - Wordpress: stop the container"
@echo " make wp-destroy - Wordpress: destroy the container"
@echo ""
@echo "Wagtail Virtual Environment Commands:"
@echo " make wt-migrate - Wagtail: run migrations"
@echo " make wt-superuser - Wagtail: create superuser"
@echo " make wt-run - Wagtail: run the server"
@echo " make wt-fixtree - Wagtail: fix the tree"
@echo ""
@echo "Django Import Commands:"
@echo " make import-authors - Django: import authors from wordpress"
@echo " make import-categories - Django: import categories from wordpress"
@echo " make import-tags - Django: import tags from wordpress"
@echo " make import-pages - Django: import pages from wordpress"
@echo " make import-posts - Django: import posts from wordpress"
@echo " make import-media - Django: import media from wordpress"
@echo " make import-comments - Django: import comments from wordpress"
@echo " make import-all - Django: import all data from wordpress"
@echo ""
@echo "Node.js Commands:"
@echo " make node-setup - Install Node.js dependencies"
@echo " make node-build - Build all frontend assets for production"
@echo " make node-start - Start the frontend development server"
@echo " make node-styles - Compile CSS styles"
@echo " make node-styles-watch - Watch and compile CSS styles"
@echo " make node-scripts - Compile JavaScript"
@echo " make node-scripts-watch - Watch and compile JavaScript"
@echo ""
@echo "Convenience Commands:"
@echo " make start - Run all commands to set up and start the development environment"
@echo " make stop - Stop all running services"
@echo " make destroy - Destroy and cleanup wordpress and wagtail"

# WordPress Commands
.PHONY: wp-build
wp-build:
@echo "WordPress: initial setup"
@if [ ! -f "$(WORDPRESS_ROOT)/.env" ]; then \
cp $(WORDPRESS_ROOT)/.env.example $(WORDPRESS_ROOT)/.env; \
fi
@mkdir -p $(WORDPRESS_ROOT)/wp-content/plugins
@cd $(WORDPRESS_ROOT)/wp-content/plugins && \
if [ ! -d "wp-graphql-offset-pagination" ]; then \
git clone https://github.com/valu-digital/wp-graphql-offset-pagination.git; \
else \
echo "Plugin wp-graphql-offset-pagination already exists"; \
fi

.PHONY: wp-up
wp-up:
@echo "WordPress: start the container"
@cd $(WORDPRESS_ROOT) && $(DC) up -d

.PHONY: wp-down
wp-down:
@echo "WordPress: stop the container"
@cd $(WORDPRESS_ROOT) && $(DC) down

.PHONY: wp-destroy
wp-destroy:
@echo "WordPress: destroy the container"
@cd $(WORDPRESS_ROOT) && $(DC) down --volumes
@echo "Do you want to clean up the files? (y/n)"
@read cleanup; \
if [ "$$cleanup" = "y" ]; then \
if [ -f "$(WORDPRESS_ROOT)/.env" ]; then \
rm $(WORDPRESS_ROOT)/.env; \
echo "Removed .env file"; \
fi; \
if [ -d "$(WORDPRESS_ROOT)/wp-content" ]; then \
rm -rf $(WORDPRESS_ROOT)/wp-content; \
echo "Removed wp-content directory"; \
fi; \
if [ -d "$(WORDPRESS_ROOT)/xml" ]; then \
rm -rf $(WORDPRESS_ROOT)/xml; \
echo "Removed xml directory"; \
fi; \
if [ -f "db.sqlite3" ]; then \
rm -rf db.sqlite3; \
echo "Removed wagtail database"; \
fi; \
fi

.PHONY: wp-load
wp-load:
@echo "WordPress: import the demo data"
@if [ -z "$$(cd $(WORDPRESS_ROOT) && $(DC) ps | grep wordpress)" ]; then \
$(MAKE) wp-up; \
fi
@cd $(WORDPRESS_ROOT) && $(DC) exec -T wordpress bin/init.sh

# Wagtail/Django Commands
.PHONY: wt-migrate
wt-migrate:
@echo "Wagtail: run migrations"
uv run manage.py migrate

.PHONY: wt-superuser
wt-superuser:
@echo "Wagtail: create superuser"
uv run manage.py createsuperuser

.PHONY: wt-run
wt-run:
@echo "Wagtail: run the server"
uv run manage.py runserver

.PHONY: wt-fixtree
wt-fixtree:
@echo "Wagtail: fix the tree"
uv run manage.py fixtree

# Import Commands
.PHONY: import-authors
import-authors:
@echo "Django: import authors from wordpress"
uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/users WPAuthor

.PHONY: import-categories
import-categories:
@echo "Django: import categories from wordpress"
uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/categories WPCategory

.PHONY: import-tags
import-tags:
@echo "Django: import tags from wordpress"
uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/tags WPTag

.PHONY: import-pages
import-pages:
@echo "Django: import pages from wordpress"
uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/pages WPPage

.PHONY: import-posts
import-posts:
@echo "Django: import posts from wordpress"
uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/posts WPPost

.PHONY: import-media
import-media:
@echo "Django: import media from wordpress"
uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/media WPMedia

.PHONY: import-comments
import-comments:
@echo "Django: import comments from wordpress"
uv run manage.py import $(WORDPRESS_URL)/$(WORDPRESS_API)/comments WPComment

.PHONY: import-all
import-all: import-authors import-categories import-tags import-pages import-posts import-media import-comments
@echo "Imported all WordPress data"

# Convenience Commands
.PHONY: start
start: wp-build wp-up wp-load wt-migrate wt-superuser import-all wt-run
@echo "Development environment started"

.PHONY: stop
stop: wp-down
@echo "Development environment stopped"
@echo "Note: There is no direct equivalent for 'dj stop' and 'wt stop' in the CLI, but WordPress container has been stopped."

.PHONY: destroy
destroy: wp-destroy
@echo "Development environment destroyed"

# Node.js Commands
.PHONY: node-setup
node-setup:
@echo "Installing Node.js dependencies"
@npm install

.PHONY: node-build
node-build:
@echo "Building frontend assets"
@npm run build

.PHONY: node-start
node-start:
@echo "Starting the frontend development server"
@npm start

.PHONY: node-styles
node-styles:
@echo "Compiling CSS styles"
@npm run styles

.PHONY: node-styles-watch
node-styles-watch:
@echo "Watching and compiling CSS styles"
@npm run styles:watch

.PHONY: node-scripts
node-scripts:
@echo "Compiling JavaScript"
@npm run scripts

.PHONY: node-scripts-watch
node-scripts-watch:
@echo "Watching and compiling JavaScript"
@npm run scripts:watch
110 changes: 69 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,75 +1,103 @@
# Wordess to Wagtail Importer (Experimental)
# WordPress to Wagtail Importer (Experimental)

[![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
[![Wagtail 7.0+](https://img.shields.io/badge/wagtail-7.0+-green.svg)](https://wagtail.org/)
[![Django 5.2+](https://img.shields.io/badge/django-5.2+-orange.svg)](https://www.djangoproject.com/)

This is an experimental project to import WordPress content including pages and posts into Wagtail.

It's not yet ready for production use but a lot of the basic functionality is in place.
It's not yet ready for production use, but most of the core functionality is in place.

## Features

- Import WordPress pages and posts into a Django application
- Inspect WordPress API endpoints to understand available data
- Transfer selected WordPress content to Wagtail
- Preserve authors, categories, and tags as Wagtail snippets
- Create redirects from WordPress URLs to new Wagtail URLs
- Manage imported content through Wagtail's admin interface

## Requirements

- Python 3.10+ (earlier versions may work)
- Python 3.13+
- UV & Docker
- WordPress CLI (instllled via Docker)
- Wordpress Data (currently using a test data set used for building themes)
- Wagtail v6.4 (earlier versions may work)
- Django v5.1 (earlier versions may work)
- Lots of patience :)
- WordPress CLI (installed via Docker)
- WordPress instance with REST API enabled
- Wagtail 7.0+
- Django 5.2+

## Workflow Overview

## Overall Goals
The migration process follows these steps:

- To demostrate importing WordPress content into a Django app.
- Be able to manipulate the imported data using the django-admin.
- Be able to transfer selected imported wordpress data over to a Wagtail site.
- Be able to manage the imported data in Wagtail which will have no dependency on the WordPress instance.
- Once all data is transferred to Wagtail, the WordPress connector app can be removed from the project.
1. Import WordPress data into Django models
2. Manage and curate the imported data using the Django admin
3. Transfer selected content to Wagtail from the Django admin
4. Manage the transferred content in the Wagtail admin
5. Remove the WordPress connector app from the project when finished

![Example Screen Shot](./docs/screen-wagtail.png "Wagtail site with imported WordPress data")
![Wagtail site with imported WordPress data](./docs/screen-wagtail.png "Wagtail site with imported WordPress data")

![Example Screen Shot](./docs/screen-wagtail-admin.png "Wagtail admin for managing imported data")
![Wagtail admin for managing imported data](./docs/screen-wagtail-admin.png "Wagtail admin for managing imported data")

The overall workflow is as follows:
### Importing WordPress Data

1. Import WordPress data into Django
2. Manage the imported data in the Django admin
3. Transfer the data to Wagtail from the Django admin
4. Manage the transferred data in the Wagtail admin
5. Remove the WordPress connector app from the project
The importer uses a Django management command to import data from a WordPress instance. While this example imports data from a local WordPress instance, the importer can connect to any WordPress site with the REST API enabled.

### Importing WordPress data
To use this for your own site, you'll need to add the `wp_connector` package to your Wagtail project, configure it to point to your WordPress instance, and run the importer.

The importer will use a Django management command that will import the data from a WordPress instance.
### WordPress API Inspection

Although this example imports data from a local WordPress instance, the importer can be used to import data from any WordPress instance that has the JSON api enabled.
The project includes API inspection tools (`wp_api_inspector.py` and `find_anchor_links.py`) to help you understand the structure of your WordPress data before importing.

The only package that should be added to your final production site, for importing and transferring the Wordpress Pages and Posts to Wagtail, is the `wp_connector` package. You'll need to add some temporary configuration to Wagtail and then run the importer against your own live WordPress instance, which will need it's JSON api enabled.
### Transferring Data to Wagtail

### Transfering data to Wagtail
The Django admin interface provides a way to select and transfer WordPress content to Wagtail:

Using the django admin admin interface you will be able to select and transfer the data to Wagtail. Posts and Pages are the main focus for the transfer but linked data such as authors, categories, tags, etc. are also be transferred across. Authors, Categories and Tags are created as snippets. Tags are created within the available Wagtail taggit integration.
- Pages and Posts are created as corresponding Wagtail page types
- Authors, Categories, and Tags are created as Wagtail snippets
- Tags integrate with Wagtail's taggit implementation
- Redirects are automatically created from WordPress URLs to Wagtail URLs

The transfer process also includes creating redirects from the old WordPress urls to the new Wagtail urls.
![Django Admin for transferring data](./docs/screen-django.png "Django Admin for transferring data")

Images and docs linked to and embedded in the transferred pages and posts are also transferred to Wagtail into the Wagtail media library. This action also including updating the links in the content to point to the new Wagtail media urls. (This is not yet implemented)
### Media Handling (Coming Soon)

### Completing the transfer
The transfer process will include handling images and documents:

Once you have transferred all the data to Wagtail, you can remove the WordPress connector module. This will leave you with a Wagtail site that has no dependency on the WordPress instance. You can then manage the site as you would any other Wagtail site.
- Media files will be transferred to the Wagtail media library
- Content references will be updated to point to new Wagtail media URLs
- *Note: This feature is not yet fully implemented*

![Example Screen Shot](./docs/screen-django.png "Django Admin for transferring data")
### Completing the Transfer

Once you've transferred all your content to Wagtail, you can remove the WordPress connector module. Your Wagtail site will have no dependencies on the WordPress instance, allowing you to manage it like any other Wagtail site.

## Project Setup & Usage

View the [Setup & Usage Guide](./docs/setup.md) for instructions on setting up the project.
For detailed setup instructions, see the [Setup & Usage Guide](./docs/setup.md).

## ToDo's
## Todo Items

- Images and Documents are not yet imported
- Comments are not yet imported
- and probably lots more I've not yet thought of 😆
- Complete media import (images and documents)
- Add comment import functionality
- Improve error handling and reporting during imports
- Add more customization options for content mapping

## Issues
## Issues & Roadmap

I am maintaing a list of issues and features in the [issues](https://github.com/wagtail-examples/wagtail-wordpress-connector/issues) section of the repository.
Issues and feature requests are tracked in the [GitHub issues](https://github.com/wagtail-examples/wagtail-wordpress-connector/issues) section.

## Contributing

If you would like to contribute to this project, please fork the repository and submit a pull request.
Contributions are welcome! To contribute:

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the terms included in the LICENSE file.
Loading