Guide

Keep documentation synchronized

Enable automatic synchronization only after the same pinned workflow succeeds as a dry run and as a real draft write.

Choose a direction

DirectionGuideMode
Merged Markdown publishes WordPress PagesGitHub to WordPresspublish, or reconcile in a combined workflow
Gutenberg edits open a Markdown pull requestWordPress to GitHubpropose, or reconcile in a combined workflow

Use the combined reconcile workflow below when both authoring paths are valid for the same Page tree.

Stage 1: manual dry run

Use workflow_dispatch, status: draft, delete-mode: trash, and dry-run: true. Review the Action summary and confirm that every planned create, update, and delete is expected.

Stage 2: manual draft write

After explicit approval, change only dry-run to false. The workflow can now create, update, and trash WordPress Pages, so keep the trigger manual while you inspect:

  • the Page hierarchy;
  • titles and headings;
  • Gutenberg block rendering;
  • rewritten internal links;
  • exact GitHub source actions;
  • unexpected unmanaged conflicts.

Stage 3: path-scoped synchronization

After the draft lifecycle succeeds, add the default-branch trigger:

yaml .github/workflows/sync-docs.yml
on:  push:    branches: [main]    paths:      - "docs/**/*.md"      - "docs/**/*.markdown"      - "docs/**/*.json"      - ".github/workflows/sync-docs.yml"  workflow_dispatch:permissions:  contents: read
Only documentation and workflow changes start the ongoing sync.

Keep status: draft if WordPress remains an editorial review gate. Set status: publish only when merged Markdown should update public Pages automatically.

Automatic sync includes removals

Deleting a managed Markdown file schedules its managed WordPress Page for Trash, or permanent deletion when delete-mode: force. Review that policy before enabling the push trigger.

Stage 4: reconcile WordPress edits

After normal publishing is stable, use one workflow for push-based publishing and scheduled WordPress polling:

Before the first reverse-sync run, open Settings → Actions → General for the repository. Under Workflow permissions, enable Allow GitHub Actions to create and approve pull requests, then select Save. For another repository, open the same settings page under its owner and repository name.

GitHub Actions workflow permissions with Allow GitHub Actions to create and approve pull requests enabled
Enable the pull request setting and save it before running WordPress-to-GitHub synchronization.
yaml .github/workflows/sync-docs.yml
on:  push:    branches: [main]    paths: ["docs/**", ".github/workflows/sync-docs.yml"]  schedule:    - cron: "3/5 * * * *"  workflow_dispatch:permissions:  contents: write  pull-requests: writeconcurrency:  group: docspress-sync  cancel-in-progress: falsejobs:  sync:    # Do not publish a merged WordPress proposal back to WordPress.    if: >-      github.event_name != 'push' ||      !contains(        github.event.head_commit.message,        format('from {0}/docspress/wordpress-sync', github.repository_owner)      )    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@FULL_COMMIT_SHA      - uses: Automattic/docspress@FULL_COMMIT_SHA        with:          mode: reconcile          wordpress-site: example.wordpress.com          wordpress-access-token: ${{ secrets.WP_ACCESS_TOKEN }}          docs-dir: docs          root-slug: docs          status: publish
Pushes publish Markdown; schedules propose WordPress edits; merges from the managed proposal branch are skipped.

DocsPress compares the live Gutenberg tree with the tree generated from the current Markdown, then rewrites only source regions whose blocks changed. Unchanged frontmatter, spacing, code-fence languages, tables, and readable block envelopes stay byte-for-byte intact. Plain core blocks become ordinary Markdown. DocsPress and non-portable core blocks use semantic, lossless envelopes instead of exposing raw wp:* comments. If DocsPress cannot map the blocks safely, the run fails instead of regenerating the whole file.

The Action updates one action-owned branch and pull request instead of opening duplicates on every poll.

The job condition skips the push event created when GitHub merges the action-owned docspress/wordpress-sync branch. Scheduled and manual runs still reconcile normally. If you set a custom pull-request-branch, use the same branch name in the condition. As a fallback for workflows without the condition, the Action recognizes its configured branch in GitHub's merge commit and exits successfully without reading or writing WordPress.

While that pull request is open, reconcile leaves the WordPress-only Page untouched. After the pull request merges, the next run recognizes that both sides converge and refreshes the Page sentinel; GitHub-only changes to other Pages can continue publishing in the same run.

Observe each run

The Action exports counters for created, updated, deleted, unchanged, proposed, skipped, and conflict operations plus summary-json for downstream jobs.

The first synchronization walkthrough shows the run overview and generated Sync Summary with tightly cropped screenshots. Use the same counters to review every automatic run.

Pin and update intentionally

Use full verified commit SHAs for both actions/checkout and Automattic/docspress. When adopting a newer DocsPress revision:

  1. inspect its action.yml inputs;
  2. review source and bundled dist/ changes;
  3. update the SHA;
  4. return to a manual dry run;
  5. restore automatic synchronization after verification.

Was this helpful?