Skip to content

Keep chapters in sync with the WordPress/library repo - #2

Merged
obenland merged 5 commits into
WordPress:trunkfrom
robertbpugh:add/chapter-import
Oct 16, 2026
Merged

obenland merged 5 commits into
WordPress:trunkfrom
robertbpugh:add/chapter-import

Conversation

@robertbpugh

@robertbpugh robertbpugh commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

This makes wordpress.org/book pull chapter edits from WordPress/library on its own, so nobody has to paste them in by hand any more.

Konstantin, this is the follow-up to the GPL chapter you updated by hand. It uses the same wporg-markdown importer as the handbooks, wired up the way wporg-developer's theme does it. The library now has a manifest.json (WordPress/library#130) mapping each of the 61 chapter files to the slug of its existing post here.

What it does

Each hourly run reads the manifest, then updates each listed chapter whose Markdown changed. It only touches post content and title. Dates, slugs, the dated permalinks and the mb_vol / mb_part / mb_chapter navigation meta stay as they are.

It also fixes footnotes on every chapter. The posts still contain [footnote] shortcodes that nothing renders any more, so readers see the raw brackets. The imported chapters use real footnotes with working links both ways.

Where it differs from the shared importer

The handbook defaults would misbehave on a book, so this subclass reads the manifest itself and changes seven things:

  • It reads and checks the whole manifest before writing anything. Every entry needs a slug, title and source inside WordPress/library, or the run stops with the book untouched. Fetches use wp_safe_remote_get(), and the manifest can't set any other post meta.
  • It never creates posts. The shared importer creates one for any manifest entry it can't match, so a typo would publish a stray post. A new chapter needs its post made by hand first.
  • It only imports chapters in the current manifest, while the shared importer re-imports every post that ever had a source.
  • It renames footnote anchors. Jetpack Markdown names them fn:1, and KSES strips #fn:1 links as a bad protocol, so they become fn-{post ID}-1.
  • It applies manifest titles on unchanged runs too, and stores the ETag only after the post saves, so a failed save retries next time.
  • It strips the volume title and chapter heading at the top of each file, since the theme already shows the title.
  • It points relative image paths at raw.githubusercontent.com, like the handbooks' images.

Sharing previews

Links to the book show up bare in Slack and on social sites, because this theme never turned on Jetpack's Open Graph tags the way the other wordpress.org themes do. This adds them:

  • Chapters get their title, opening lines and first image. Jetpack skips images without a height attribute, which is every chapter image, so the theme picks the first one itself. Chapters without images fall back to the wordpress.org default image from site-branding.php.
  • The home page gets a description of both volumes, since the site's own description only covers Volume 2.

These go live with the deploy and don't depend on the import being switched on.

Rolling it out

Nothing changes when this deploys. The import stays off until the option below is set.

Jetpack is already active on the book site. From the wordpress.org web root:

wp --url=https://wordpress.org/book/ plugin activate wporg-markdown
wp --url=https://wordpress.org/book/ book import
wp --url=https://wordpress.org/book/ option update wporg_book_import_enabled 1

The last command turns on the hourly import, which schedules itself on the next page load.

A dry run is optional, since the import has already run against copies of all 61 live chapters (see Testing). If you want one, wp --url=https://wordpress.org/book/ book import --dry-run lists each chapter, whether it would change, and its word count before and after, without writing anything.

library#130 has merged, so the manifest is on trunk.

Testing

I ran it in wp-env with copies of all 67 live posts, importing from the #130 branch:

  • The dry run listed all 61 chapters with no title changes. The first import updated 61, and a second run updated 0, because GitHub answered 304 for every chapter.
  • Footnote links and back-links resolve in every chapter. The 21 images in the Introduction and A New Logo load from GitHub.
  • Dates, slugs and mb_* meta are unchanged. Volume 2 posts keep their chapter titles rather than the volume title.
  • A title changed by hand was put back on the next unchanged run.
  • A forced failed save was reported, and the next run repaired the post.
  • A manifest entry with a typo created no post, and a chapter removed from the manifest was left untouched.
  • A manifest pointing at a URL outside WordPress/library, or with a malformed entry, was rejected before anything was written.
  • wp book import exits non-zero when any chapter fails or is skipped.
  • The block editor shows a warning, with a link to the file on GitHub, on imported chapters only.
  • phpcs with the wporg ruleset is clean.

The lint check on this PR fails before it reaches the code. composer install can't fetch the wporg-mu-plugins commit pinned in composer.lock, which is no longer on its build branch, so this needs a lockfile refresh on trunk.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MXBwXzdG2XPckiBuLKiFZ1

@robertbpugh
robertbpugh marked this pull request as ready for review October 13, 2026 23:59
Copilot AI balanced review requested due to automatic review settings October 13, 2026 23:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

robertbpugh and others added 5 commits October 16, 2026 12:05
Adds a chapter importer built on the wporg-markdown importer that
developer.wordpress.org uses, following its theme's pattern. The
library's manifest.json maps each chapter file to an existing post
slug; the importer updates only those posts' content and titles.

Differences from the shared importer, so it is safe on a book:
- never creates posts, so a manifest typo can't publish a stray post
- only imports chapters in the current manifest
- renames Jetpack Markdown footnote anchors (fn:1), which KSES strips
- applies the manifest title even when the file is unchanged
- stores the ETag only after the post saves, so failures retry
- strips the volume title and chapter heading the site already shows
- points relative image paths at raw.githubusercontent.com
- stays off until wporg_book_import_enabled is set; wp book import
  --dry-run reports what would change first

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MXBwXzdG2XPckiBuLKiFZ1
- Read and validate the whole manifest before writing anything, and
  reject entries whose source is outside WordPress/library. Replaces
  the shared importer's manifest handling, which writes any meta the
  manifest lists and exits WP-CLI on errors.
- Fetch with wp_safe_remote_get(), without following chapter redirects.
- Exit non-zero from wp book import when a chapter fails or is skipped.
- Show the overwrite warning in the block editor, not just the classic one.
- Use the same published-post lookup for dry runs and imports.
- Keep query strings when resolving image paths, and resolve
  root-relative paths against the repo root.
- Rename to class-chapter-importer.php and create it in functions.php.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MXBwXzdG2XPckiBuLKiFZ1
- A blank slug made WP_Query drop the name filter and match the newest
  post, so slugs must now be non-empty and already sanitized.
- Source URLs are checked after decoding, so %2e%2e can't climb out of
  WordPress/library.
- wp book import --dry-run exits non-zero when a chapter can't be
  fetched or has no post.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MXBwXzdG2XPckiBuLKiFZ1
Links to the book showed up bare in Slack and on social sites, because
the theme never turned on Jetpack's Open Graph tags the way the other
wordpress.org themes do.

- Turn them on with jetpack_enable_open_graph.
- Describe both volumes on the home page; the site description only
  covers Volume 2.
- Use a chapter's first image, since Jetpack skips images without a
  height attribute and no chapter image has one. Chapters without
  images fall back to the wordpress.org default image.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uTEZEmU5AYzhgPvhx3HvJ
site-branding.php strips -256x256 style sizes from og:image, which
turned chapter 8's Gutenberg icon into a 404. Images named that way are
passed over, falling back to the default image. Also drop the forced
large Twitter card, since some first images are too small for one, and
skip sources that don't survive esc_url_raw.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uTEZEmU5AYzhgPvhx3HvJ
@obenland
obenland merged commit d9ac2dd into WordPress:trunk Oct 16, 2026
1 check passed
@obenland

Copy link
Copy Markdown
Member
$ wp --url=https://wordpress.org/book/ book import --dry-run
introduction                                  changes  words  2919 ->  2961  title same
hello-world                                   changes  words  1435 ->  1435  title same
the-only-blogger-in-corsica                   changes  words  3145 ->  3130  title same
the-blogging-software-dilemma                 changes  words  1217 ->  1217  title same
guiding-principles                            changes  words   854 ->   854  title same
the-gpl                                       changes  words  1498 ->  1494  title same
wordpresss-first-developers                   changes  words  1473 ->  1473  title "WordPress' First Developers" -> "WordPress’ First Developers"
inside-the-bazaar                             changes  words  1440 ->  1439  title same
support-and-documentation                     changes  words  1232 ->  1225  title same
freedom-zero                                  changes  words  1387 ->  1380  title same
wordpress-1-2-mingus                          changes  words  1107 ->  1107  title "WordPress 1.2 "Mingus"" -> "WordPress 1.2 “Mingus”"
the-birth-of-wp-hackers                       changes  words  1179 ->  1172  title same
themes                                        changes  words  1047 ->  1031  title same
development-in-a-funnel                       changes  words  1040 ->  1036  title same
a-new-logo                                    changes  words   707 ->   641  title same
wordpress-incorporated                        changes  words  1807 ->  1800  title same
wordpress-com                                 changes  words   944 ->   942  title same
akismet                                       changes  words   649 ->   649  title same
shuttle                                       changes  words  1148 ->  1078  title same
automattic                                    changes  words  1626 ->  1627  title same
growing-pains                                 changes  words  1004 ->  1004  title same
wordcamp-2006                                 changes  words   496 ->   482  title same
speeding-the-release-cycle                    changes  words   991 ->   991  title same
trademarks                                    changes  words  1017 ->  1018  title same
habari                                        changes  words  2015 ->  1994  title same
creating-a-folksonomy                         changes  words  2239 ->  2225  title same
sponsored-themes                              changes  words  2189 ->  2182  title same
update-notifications                          changes  words  1553 ->  1551  title same
happy-cog-redesign                            changes  words  1133 ->  1091  title same
premium-themes                                changes  words  2627 ->  2618  title same
riding-the-crazyhorse                         changes  words  1696 ->  1662  title same
themes-are-gpl-too                            changes  words  1115 ->  1115  title same
improving-infrastructure                      changes  words  1199 ->  1197  title same
meeting-in-person                             changes  words  1220 ->  1213  title same
update-notifications-redux                    changes  words  1104 ->  1104  title same
the-wordpress-foundation                      changes  words  1585 ->  1585  title same
wordpress-3-0                                 changes  words  2220 ->  2218  title same
the-wordcamp-guidelines                       changes  words   651 ->   651  title same
dealing-with-a-growing-project                changes  words  1096 ->  1096  title same
thesis                                        changes  words  1139 ->  1138  title same
the-transition-to-release-leads               changes  words  1582 ->  1575  title same
the-community-summit                          changes  words   628 ->   628  title same
the-spirit-of-the-gpl                         changes  words  1261 ->  1259  title same
the-problem-with-post-formats                 changes  words   883 ->   876  title same
mp6                                           changes  words  1597 ->  1590  title same
building-blocks-catching-up-on-2013           changes  words  1127 ->  1111  title same
chapter-2-buddypress                          changes  words   832 ->   837  title same
chapter-3-plugging-into-plugins               changes  words  1566 ->  1559  title same
chapter-4-activating-diversity-and-inclusion  changes  words  1965 ->  2089  title same
chapter-5-wordcamp-us-philadelphia            changes  words   627 ->   630  title same
chapter-6-the-customizer                      changes  words  1209 ->  1209  title same
chapter-7-wordcamp-jurisdictions              changes  words  1358 ->  1354  title same
chapter-8-a-modern-day-printing-press         changes  words  1550 ->  1547  title same
chapter-9-open-source-a-political-choice      changes  words   798 ->   939  title same
chapter-10-wix-and-wordpress-go-head-to-head  changes  words  1126 ->  1119  title same
chapter-11-the-wordpress-economy              changes  words  1354 ->  1337  title same
chapter-12-wordpress-matures                  changes  words  1370 ->  1353  title same
chapter-13-the-pandemic                       changes  words  2985 ->  2951  title same
chapter-14-parlez-vous-wordpress-sil-vous-plait changes  words  1603 ->  1598  title same
chapter-15-together-again                     changes  words  1580 ->  1577  title same
chapter-16-the-future-of-wordpress            changes  words   720 ->   711  title same

@obenland

Copy link
Copy Markdown
Member
$ wp --url=https://wordpress.org/book/ book import
[…]
Success: 61 updated, 0 unchanged, 0 failed, 0 skipped.

$ wp --url=https://wordpress.org/book/ cron event list | grep wporg_book_import_chapters
wporg_book_import_chapters	2026-10-16 18:40:25	59 minutes 47 seconds	1 hour

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