Skip to content

moving pages around envs#1671

Open
mwvolo wants to merge 9 commits into
mainfrom
move-content-btw-envs
Open

moving pages around envs#1671
mwvolo wants to merge 9 commits into
mainfrom
move-content-btw-envs

Conversation

@mwvolo
Copy link
Copy Markdown
Member

@mwvolo mwvolo commented Mar 5, 2026

What this does

Replaces the legacy wagtailimportexport package (deleted) with wagtail-transfer, which lets editors pull pages and snippets directly from another Wagtail instance over the admin — no zip files.

Changes

  • Removed the vendored wagtailimportexport/ directory.
  • Added wagtail-transfer==0.11 to requirements/base.txt.
  • Swapped wagtail_transfer into INSTALLED_APPS and mounted path('admin/wagtail-transfer/', ...) so the route lives under the CDN-routed /admin/* namespace (bare /wagtail-transfer/ and /apps/cms/wagtail-transfer/ are not CDN-routed and fall through to the frontend). The mount is placed before the broader admin/ include because Django matches URL patterns in order.
  • Settings in openstax/settings/base.py:
    • WAGTAILTRANSFER_SECRET_KEY — this instance's auth key. Validated via a Django system check (openstax.E001) instead of at module-import time, so collectstatic during AMI bake (before runtime secrets are loaded) does not blow up.
    • WAGTAILTRANSFER_SOURCES — populated from WAGTAILTRANSFER_SOURCES_JSON (preferred) or single-source WAGTAILTRANSFER_SOURCE_NAME/_URL/_KEY env vars.
    • WAGTAILTRANSFER_LOOKUP_FIELDS — natural-key matching for 12 snippet models so cross-env updates don't duplicate.
  • Removed stale wagtailimportexport/* ignore from codecov.yml.
  • Added docs/wagtail-transfer-page-sync.md describing options for syncing pages that already exist independently on multiple envs (out of scope for this PR — see Scope).

Scope — important

This is intended for promoting new content forward (e.g., new pages built on staging → prod). It is not set up to sync pages that already exist independently on both environments.

Pages on dev/staging/prod currently have different IDs, slugs, and image references because they were created at different times. Wagtail-transfer matches pages by an internal UUID stored in wagtail_transfer_idmapping — with nothing in that table and no overlap, transferring a page that already exists on the destination will create a second copy rather than updating in place. Snippets are matched by natural key (name, title, etc.) so they update correctly regardless of ID.

If we ever need to "join" a legacy page across envs, see docs/wagtail-transfer-page-sync.md for the options we considered and the tradeoffs.

Setup per environment

1. Set the secret keys

Each environment needs its own WAGTAILTRANSFER_SECRET_KEY. The key on a source must match the SECRET_KEY configured under that source's entry on the destination.

Example: prod pulls from staging.

  • On staging: WAGTAILTRANSFER_SECRET_KEY=<staging-secret>
  • On prod: in WAGTAILTRANSFER_SOURCES_JSON, the staging entry's SECRET_KEY must equal <staging-secret>.

The SSM-managed parameter is mapped to the WAGTAILTRANSFER_SECRET_KEY env var at instance launch by the deployment side. The CMS itself no longer fails at import time if the placeholder is in effect (this was breaking AMI bake); instead, manage.py check reports openstax.E001 so CI/dev still catches the misconfiguration.

2. Configure sources (preferred: JSON)

# On prod — can pull from staging and dev
WAGTAILTRANSFER_SECRET_KEY=<prod-secret>
WAGTAILTRANSFER_SOURCES_JSON='{
  "staging": {
    "BASE_URL": "https://staging.openstax.org/admin/wagtail-transfer/",
    "SECRET_KEY": "<staging-secret>"
  },
  "dev": {
    "BASE_URL": "https://dev.openstax.org/admin/wagtail-transfer/",
    "SECRET_KEY": "<dev-secret>"
  }
}'

For a single source, the older form still works:

WAGTAILTRANSFER_SOURCE_NAME=staging
WAGTAILTRANSFER_SOURCE_URL=https://staging.openstax.org/admin/wagtail-transfer/
WAGTAILTRANSFER_SOURCE_KEY=<staging-secret>

Settings will fail loudly at startup if the JSON is malformed or if the single-source vars are partially set.

3. Run migrations

python manage.py migrate wagtail_transfer

4. Grant access

Superusers see "Import" in the Wagtail admin automatically. For other users, create a group with the "Can import pages and snippets from other sites" permission and add them.

Usage

In Wagtail admin → Import → choose a source → browse its page tree → select what to pull.

Recommended workflow:

  • Build new pages/snippets on staging.
  • Hit Import on prod, pick staging, select the new content, run.
  • Edit snippets on staging at any time and re-import to update prod (matched by name).
  • Don't expect this to reconcile pages that already exist on both sides — see docs/wagtail-transfer-page-sync.md.

  Changes Made

  1. Removed wagtailimportexport/ — the entire vendored package directory
  2. Added wagtail-transfer==0.11 to requirements/base.txt
  3. Replaced wagtailimportexport with wagtail_transfer in INSTALLED_APPS (openstax/settings/base.py)
  4. Added wagtail-transfer settings to base.py — configurable via env vars:
    - WAGTAILTRANSFER_SECRET_KEY — this instance's auth key
    - WAGTAILTRANSFER_SOURCE_NAME / _URL / _KEY — defines the source to pull from
  5. Added URL route wagtail-transfer/ in openstax/urls.py (above the catch-all wagtail route)

  What's Needed Next

  Per-environment setup:

  On each environment, set these env vars:

  # On production — pull from staging
  WAGTAILTRANSFER_SECRET_KEY=<prod-secret>
  WAGTAILTRANSFER_SOURCE_NAME=staging
  WAGTAILTRANSFER_SOURCE_URL=https://staging.openstax.org/wagtail-transfer/
  WAGTAILTRANSFER_SOURCE_KEY=<staging-secret>

  # On staging — the secret key must match what prod uses as SOURCE_KEY
  WAGTAILTRANSFER_SECRET_KEY=<staging-secret>

  The SECRET_KEY on the source must match the SOURCE_KEY configured on the destination.

  Run migrations on each environment:
  python manage.py migrate wagtail_transfer

  Permissions: Superusers get access automatically. For other users, create a group with the "Can import pages and
  snippets from other sites" permission.

  Usage: In Wagtail admin, there will be a new "Import" option. You browse the source environment's page tree and
  select what to pull in — no more zip files.
Copilot AI review requested due to automatic review settings March 5, 2026 06:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the vendored wagtailimportexport page import/export implementation with the upstream wagtail-transfer package, wiring it into settings via environment variables and exposing the required transfer endpoint.

Changes:

  • Remove the legacy wagtailimportexport app (code, templates, and tests).
  • Add wagtail-transfer==0.11, enable wagtail_transfer in INSTALLED_APPS, and add env-driven WAGTAILTRANSFER_* settings.
  • Add the wagtail-transfer/ URL route ahead of the Wagtail catch-all route.

Reviewed changes

Copilot reviewed 18 out of 20 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
requirements/base.txt Adds the wagtail-transfer dependency needed for cross-environment imports.
openstax/settings/base.py Swaps installed app to wagtail_transfer and adds env-configurable transfer secrets/sources.
openstax/urls.py Exposes wagtail-transfer/ endpoints (before Wagtail’s catch-all).
wagtailimportexport/admin_urls.py Removes legacy admin URL routing for the vendored tool.
wagtailimportexport/apps.py Removes vendored app config.
wagtailimportexport/config.py Removes vendored config.
wagtailimportexport/exporting.py Removes legacy export implementation.
wagtailimportexport/forms.py Removes legacy import/export forms.
wagtailimportexport/functions.py Removes legacy helper utilities for zips/FKs/media.
wagtailimportexport/importing.py Removes legacy import implementation.
wagtailimportexport/templates/wagtailimportexport/index.html Removes legacy admin templates.
wagtailimportexport/templates/wagtailimportexport/import-page.html Removes legacy admin templates.
wagtailimportexport/templates/wagtailimportexport/export-page.html Removes legacy admin templates.
wagtailimportexport/tests/test_functions.py Removes legacy tests.
wagtailimportexport/tests/tests.py Removes legacy tests.
wagtailimportexport/views.py Removes legacy views.
wagtailimportexport/wagtail_hooks.py Removes legacy Wagtail admin hooks/menu item.
wagtailimportexport/__init__.py Removes vendored package init.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread openstax/settings/base.py
Comment thread openstax/settings/base.py Outdated
Comment thread openstax/urls.py
from wagtailautocomplete.urls.admin import urlpatterns as autocomplete_admin_urls
from wagtail import urls as wagtail_urls
from wagtail_transfer import urls as wagtailtransfer_urls
from . import wagtail_transfer_patches # noqa: F401 — applied on import
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants