Skip to content

feat: apply post type templates to new posts - #794

Merged
dcalhoun merged 8 commits into
fix/seed-post-entity-resolutionfrom
feat/new-post-template-parity
Oct 30, 2026
Merged

dcalhoun merged 8 commits into
fix/seed-post-entity-resolutionfrom
feat/new-post-template-parity

Conversation

@dcalhoun

@dcalhoun dcalhoun commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

What?

Apply post type templates to new posts.

Why?

Close CMM-2551. Align with core's editor behavior.

How?

  • Seed a local-only auto-draft status so that isEditedPostNew() returns true
  • Apply post templates only to new posts with an empty title and content. Local drafts have no server ID or status to tell them apart from new posts, unlike core, where saving an auto-draft makes it a draft. A new post that starts with content gets no template, whereas core merges it with the template.
  • Add example post type to the local wp-env site

Testing Instructions

Run make wp-env-start and make serve-dev, then open the demo app on iOS and Android and select the local WordPress site. The site registers a Templated Post post type with a block template. If you prepared the editor for this site before, tap Clear Preload Cache first, as the demo app caches the post type.

  1. Select the templated post type and tap Start. Verify that the editor shows the heading "Prefilled heading from the template" and a paragraph with the placeholder "Placeholder paragraph from the template", with the title focused.
  2. Select Post and tap Start. Verify that the editor is empty, with no template.
  3. To open a new post with only a title, as a reopened local draft looks to the editor, temporarily add .setTitle("Trip notes") to applyDemoAppDefaults in ios/Demo-iOS/Sources/Views/SitePreparationView.swift. On Android, change .setTitle("") to .setTitle("Trip notes") in SitePreparationViewModel.kt. Select the templated post type and tap Start. Verify that the title reads "Trip notes" and the template isn't applied. Revert the edit.
  4. Select the templated post type and tap Start without editing. With the Web Inspector (Safari's Develop menu on iOS, chrome://inspect on Android) attached to the editor, run editor.getTitleAndContent() in the console. Verify that it returns changed: false. Type a character, run it again, and verify that it returns changed: true.
  5. Temporarily add 'template_lock' => 'all', to register_post_type in wp-env/mu-plugins/gutenbergkit-templated-post-type.php, then tap Clear Preload Cache. Select the templated post type and tap Start. Verify that you can type in the template's blocks but can't remove or move them, and can't add blocks. Revert the edit.
  6. Tap Browse and open an existing post, then edit it and close it. Verify that it loads and edits as before. On Android, the local WordPress site has no Browse button, so use a site added through the demo app's login.

Tapping into the template's paragraph may hit a caret bug fixed separately in #821.

Accessibility Testing Instructions

N/A, no navigation changes.

Screenshots or screencast

N/A, no visual changes.


AI-generated details

Phase 1b of the CMM-2024 editor-driven saving plan: new-post parity with WP Admin.

  • auto-draft seed: a post without a server ID (-1) is seeded as auto-draft only when its title and content are empty, so isEditedPostNew() is true. A local draft keeps the host's status, since core applies the template to auto-drafts, and core-data blanks their titles, which WP Admin restores through initial edits but GBK doesn't. The status stays local: no bridge message sends it to hosts, and writes are blocked.
  • Post type templates: for new posts, the post type is loaded before render and its block template is passed to setupEditor. Other posts render without waiting for it.
  • Template lock: as WP Admin does, the post type's template and template_lock are added to the editor settings for every post of the type, so locked templates are enforced.
  • Host change baseline: getTitleAndContent() compares against the content after setup, so an untouched new post with a template reports changed: false, and hosts don't prompt to save or upload it.
  • Adds a templated_post post type with a template to wp-env for E2E.

Behavior change to note: core's PostTitle focuses the title on a clean new post, which matches the hosts' own rule of focusing only empty posts. On iOS, the WebView doesn't show the keyboard for programmatic focus. Android should be checked.

Testing

  • Unit: getPost() status for empty posts and local drafts, post type loading for new posts only, the template lock settings, and the host change baseline.
  • E2E (new-post-template.spec.js): the template applies to an empty new post, an untouched template isn't reported as a change, the lock reaches the block editor, and a new post with a title or content keeps it.
  • The full web E2E suite passes locally, except editor-content-changed.spec.js, which is flaky under 7 parallel workers against a slow wp-env (it also fails without these changes).
  • iOS demo app (simulator, wp-env, dev server), before the latest fixes: a new Post opens empty with the title focused. A new templated post shows the template's heading and placeholder paragraph. No error notices appear.

Core behavior to note: after the template applies, Undo is enabled, but the post isn't dirty. Core's setupEditor applies templates via resetEditorBlocks without an undo level, yet editPost still records one. WP Admin calls setupEditor with the same arguments, so it should behave the same way, though I haven't verified that in WP Admin.

🤖 Generated with Claude Code

@dcalhoun
dcalhoun added this pull request to stack #795 October 14, 2026 19:42
@github-actions github-actions Bot added the [Type] Enhancement A suggestion for improvement. label Oct 14, 2026
@wpmobilebot

wpmobilebot commented Oct 14, 2026 •

Copy link
Copy Markdown

XCFramework Build

This PR's XCFramework is available for testing. Add the following to your Package.swift:

.package(url: "https://github.com/wordpress-mobile/GutenbergKit", branch: "pr-build/794")

Built from a4f76ca

@dcalhoun
dcalhoun force-pushed the feat/new-post-template-parity branch 2 times, most recently from 5da948b to efee7c1 Compare October 22, 2026 14:19
@dcalhoun
dcalhoun force-pushed the feat/new-post-template-parity branch from c9a8cc4 to bebbccd Compare October 23, 2026 16:17
@dcalhoun
dcalhoun marked this pull request as ready for review October 23, 2026 16:31
@dcalhoun
dcalhoun requested a review from crazytonyli October 23, 2026 16:34
Comment thread src/utils/editor.jsx Resolved
@dcalhoun
dcalhoun requested a review from crazytonyli October 29, 2026 01:39
@dcalhoun
dcalhoun requested a review from crazytonyli October 30, 2026 01:22
dcalhoun and others added 8 commits October 30, 2026 07:12
WP Admin seeds new posts as auto-drafts, which core relies on to treat a
post as new, e.g. `isEditedPostNew()`. Posts without a server ID were
seeded with the host's status, usually `draft`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Core applies a post type's block template to new posts, but GBK never
passed it to `setupEditor`. Load the post type before rendering and pass
its template for new posts without content: unlike WP Admin's
auto-drafts, a new post can hold a local draft, which core would replace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The gbk_templated slug showed as "Gbk_Templated" in the demo apps, and the template's heading text looked like a placeholder beside the paragraph's real placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNDBX7RNXn3NsfDuV1PkNV
Core blanks the title of auto-drafts and applies the post type's template to them, so seeding every post without a server ID as one erased local drafts' titles, re-applied deleted templates, and focused the title on reopen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNDBX7RNXn3NsfDuV1PkNV
The host compared the editor's content with what it sent, so a new post's template looked like an edit, and hosts prompted to save or uploaded posts the user never touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNDBX7RNXn3NsfDuV1PkNV
Hosts may not preload the post type, such as WordPress-Android for pages, so every other post's first render waited on a network request for a template it never uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNDBX7RNXn3NsfDuV1PkNV
WP Admin adds the post type's template and template_lock to the editor settings, so a locked template's blocks can't be removed, moved, or added to. GBK applied the template without the lock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNDBX7RNXn3NsfDuV1PkNV
The comment implied only GBK's seeded auto-drafts reach this check, but a status the host sends passes through unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YNDBX7RNXn3NsfDuV1PkNV
@dcalhoun
dcalhoun force-pushed the feat/new-post-template-parity branch from 1fabd04 to a4f76ca Compare October 30, 2026 11:12
@dcalhoun

Copy link
Copy Markdown
Member Author

Rebased to resolve conflicts for the stacked PRs.

@dcalhoun
dcalhoun merged commit 29e85ae into trunk Oct 30, 2026
28 checks passed
@dcalhoun
dcalhoun deleted the feat/new-post-template-parity branch October 30, 2026 11:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants