Skip to content

WT-1469: Add management commands for importing WordPress blog posts - #1627

Open
StuartMacKay wants to merge 171 commits into
mozmeao:mainfrom
StuartMacKay:wagtail-wordpress-import
Open

WT-1469: Add management commands for importing WordPress blog posts#1627
StuartMacKay wants to merge 171 commits into
mozmeao:mainfrom
StuartMacKay:wagtail-wordpress-import

Conversation

@StuartMacKay

Copy link
Copy Markdown
Contributor

One-line summary

Import Wordpress blog posts, exported from blog.mozilla.org, into Wagtail CMS.

Significant changes and points to review

This pull request adds two management commands:

  1. import_wordpress_blog_posts, which parses the WordPress export XML into BlogArticlePage entries (topics, tags, authors, images, and content blocks).

  2. import_wordpress_redirects, which creates Redirect records from the CSV the import command produces.

Also adds an Author snippet model with a BlogArticlePage.author field and ?author= filtering on the blog index, plus tests for all of the above.

Issue / Bugzilla link

https://mozilla-hub.atlassian.net/browse/WT-1469

Testing

These two commands import the WordPress blog export into Wagtail. Test them locally against mozilla-blog-posts.xml.

IMPORTANT: If you want to test using Docker you will have to modify Dockerfile to copy the xml file so the management commands can access it. Insert the follwing starting at line 107

COPY ./mozilla-blog-posts.xml ./

Import the blog posts

python manage.py import_wordpress_blog_posts mozilla-blog-posts.xml --dry-run`

Confirms the file parses cleanly and shows what would be imported, without writing anything.

python manage.py import_wordpress_blog_posts mozilla-blog-posts.xml

Runs the import for real. Look for a final summary line like:

Done. 68 imported, 0 skipped, 0 failed.

Any failures are logged per-post to stderr and don't stop the rest of the import.

Verify in the Wagtail admin:

  • Under the Blog index page, confirm the new BlogArticlePages appear with the correct title, topic, tags, author, and hero image.
  • Open a couple of articles and check the body content renders (text, inline images, code blocks) and, for the two posts with old YouTube embeds, that the embed link renders as plain text.
  • Check Snippets → Authors and Snippets → Tags to confirm authors/topics/tags were created (not duplicated).

Re-run to check idempotency:

python manage.py import_wordpress_blog_posts mozilla-blog-posts.xml

Should report 0 imported, 68 skipped, 0 failed — no duplicate pages created.

Create redirects from the old WordPress URLs

The first command writes wordpress_redirects.csv (old permalink → new page). Use it to create Wagtail redirects:

python manage.py import_wordpress_redirects wordpress_redirects.csv --dry-run

Shows what redirects would be created.

python manage.py import_wordpress_redirects wordpress_redirects.csv

Creates the redirects for real.

Verify in the Wagtail admin:

  • Go to Settings → Redirects and confirm entries exist mapping old blog.mozilla.org/en/... paths to the new blog article pages.
  • Re-run the command again — it should report the redirects as already existing rather than duplicating them.

StuartMacKay and others added 7 commits July 20, 2026 15:04
Adds two management commands:

1. import_wordpress_blog_posts, which parses the WordPress export XML
   into BlogArticlePage entries (topics, tags, authors, images, and
   content blocks).

2. import_wordpress_redirects, which creates Redirect records from the
   CSV the import command produces.

Also adds an Author snippet model with a BlogArticlePage.author field
and ?author= filtering on the blog index, plus tests for all of the
above.
@StuartMacKay
StuartMacKay marked this pull request as ready for review July 23, 2026 11:01
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.39024% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.30%. Comparing base (19d0962) to head (ee43b46).

Files with missing lines Patch % Lines
springfield/cms/models/pages.py 98.02% 3 Missing ⚠️
...management/commands/import_wordpress_blog_posts.py 99.62% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1627      +/-   ##
==========================================
+ Coverage   88.55%   89.30%   +0.75%     
==========================================
  Files         177      178       +1     
  Lines       12386    13109     +723     
==========================================
+ Hits        10968    11707     +739     
+ Misses       1418     1402      -16     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

lucianoratamero and others added 30 commits August 13, 2026 22:53
Editors can pick topics and tags on the Blog Options panel to keep their
articles out of automatic feeds.

get_feed_exclusions() resolves the field to translation keys
Both listing routes accept ?tag=<slug> alongside the existing ?topic=.
Feed exclusions always apply, except to the single topic or tag the
reader explicitly selected: ?topic=X spares X, ?tag=Y spares Y, and a
topic page spares its own topic.
BlogLatestArticlesBlock lists N latest articles
BlogCardsListSourceBlock lists N articles from a topic or tag

BlogArticleSectionValue is populated by the index page, which handles
the querying logic to guarantee that articles don't show up twice on the
blocks.
Drop fields that populated the "More Articles" section and implement the
logic for the new "Article Sections".

The index page queries the articles for each block, excluding the ones
already displayed from the next block's filter.
Posts whose ImageFeatured is blank still attach their header image, so the
first ImageURL entry becomes the hero instead of the post importing with no
image at all - which also left its cards imageless on the index and related
article lists.

Claude-Session: https://claude.ai/code/session_01Pjpe9S6YPcmAqQtVB68erJ
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.

3 participants