Skip to content

Always send comment_status when creating a post#25492

Draft
jkmassel wants to merge 6 commits intotrunkfrom
jkmassel/investigate-25480
Draft

Always send comment_status when creating a post#25492
jkmassel wants to merge 6 commits intotrunkfrom
jkmassel/investigate-25480

Conversation

@jkmassel
Copy link
Copy Markdown
Contributor

@jkmassel jkmassel commented Apr 8, 2026

Summary

Fixes comments being disabled on newly created posts on self-hosted WordPress sites.

Root Cause

The create-post encoders (RemotePostCreateParametersXMLRPCEncoder and RemotePostCreateParametersWordPressComEncoder) skipped sending comment_status and ping_status when the discussion settings matched the app's hardcoded default (.default = comments and pings enabled). This triggered a WordPress core bug (Trac #36462):

  1. The app creates a post without comment_status (because settings match .default)
  2. WordPress's wp.newPost internally creates an auto-draft via get_default_post_to_edit(), then updates it with the provided data
  3. wp_insert_post() sees an existing ID from the auto-draft, treats this as an update, and defaults comment_status to "closed" when the field is omitted
  4. Result: comments are disabled even though the site's default_comment_status is "open"

This was confirmed by testing against a clean WordPress 6.9.4 Docker instance and verified against the WordPress 6.9 source on GitHub:

  • Create via wp.newPost without comment_statusclosed (bug)
  • Create via wp.newPost with comment_status=openopen (correct)
  • Update via wp.editPost without comment_status → preserved (safe — wp.editPost and wp_update_post both merge existing data before calling wp_insert_post)

Note: ping_status is not affected by this bug — wp_insert_post() always calls get_default_comment_status($post_type, 'pingback') for pings regardless of create/update, but it hard-codes "closed" for comment_status on updates.

Changes

  • Always send comment_status and ping_status in both XML-RPC and WP.com REST create encoders, removing the guard that skipped them when they matched .default
  • Map default_comment_status and default_ping_status from the self-hosted REST API (/wp/v2/settings) so new posts are initialized with the site's actual defaults
  • Map default_comment_status and default_ping_status from XML-RPC (wp.getOptions) — previously these keys were returned by WordPress but never mapped, so pure XML-RPC self-hosted sites always fell back to the hardcoded default
  • Always include discussion settings in post updates (via PostRepository) as a defensive measure, since WordPress core's update path also defaults to "closed" when comment_status is omitted
  • Fix nil handling in BlogService.m where [nil boolValue] was silently converting commentsAllowed = nil to false

Fixes #25480

Test plan

  • Create a new post on a self-hosted site with "Allow people to submit comments on new posts" enabled in WP Admin → Settings → Discussion
  • Leave "Allow Comments" enabled in Post Settings
  • Publish the post
  • Verify comments are enabled on the published post (WP Admin → Posts → Quick Edit)
  • Repeat with "Allow Comments" explicitly toggled OFF — verify they remain disabled
  • Edit an existing post, change only the title, and verify comment status is preserved
  • Repeat on a WordPress.com site to confirm no regression

When creating a new post, the app previously skipped sending
comment_status and ping_status if the discussion settings matched
the app's hardcoded default (comments and pings enabled). This
meant the server's own default was used instead of the user's
explicit choice, which could result in comments being disabled
on sites where the server default differs from the app's.

Fixes #25480
@dangermattic
Copy link
Copy Markdown
Collaborator

dangermattic commented Apr 8, 2026

1 Warning
⚠️ This PR is larger than 500 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.
1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

Verifies that create-post encoders (both XML-RPC and WP.com REST)
always include discussion settings in the encoded output, and that
update-post encoders only include them when explicitly set.
@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 8, 2026

App Icon📲 You can test the changes from this Pull Request in WordPress by scanning the QR code below to install the corresponding build.
App NameWordPress
ConfigurationRelease-Alpha
Build Number32007
VersionPR #25492
Bundle IDorg.wordpress.alpha
Commit5473c55
Installation URL5h2muoqvne5fg
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 8, 2026

App Icon📲 You can test the changes from this Pull Request in Jetpack by scanning the QR code below to install the corresponding build.
App NameJetpack
ConfigurationRelease-Alpha
Build Number32007
VersionPR #25492
Bundle IDcom.jetpack.alpha
Commit5473c55
Installation URL6jm5cbjf8v5ng
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 8, 2026

🤖 Build Failure Analysis

This build has failures. Claude has analyzed them - check the build annotations for details.

jkmassel added 2 commits April 8, 2026 13:22
- BlogServiceRemoteCoreREST.mapSiteSettings now maps defaultCommentStatus
  and defaultPingStatus from the Core REST API (/wp/v2/settings) instead
  of setting them to nil. This ensures self-hosted sites' discussion
  preferences are synced to the device.
- Blog.createPost() now initializes allowComments from the blog's synced
  settings (falling back to true if settings haven't been synced yet),
  so new posts respect the server's default_comment_status.
- Add tests for the discussion settings mapping.
WordPress core's wp.editPost defaults comment_status to "closed" when
the field is omitted (Trac #36462). This means any post update that
doesn't explicitly include comment_status — even a simple status change
from draft to publish — silently disables comments.

Fix this by consulting the blog's synced discussion settings in
PostRepository._sync and always including them in update parameters.
The values come from BlogSettings.commentsAllowed and
pingbackInboundEnabled, which are synced from the server's
default_comment_status and default_ping_status.

Also fix BlogService.m to not overwrite discussion settings with false
when RemoteBlogSettings returns nil (since [nil boolValue] == NO in
Obj-C), and initialize allowPings from blog settings in createPost().
@jkmassel jkmassel marked this pull request as draft April 9, 2026 18:50
The XML-RPC `wp.getOptions` response includes `default_comment_status`
and `default_ping_status`, but the app never mapped them. This meant
pure XML-RPC self-hosted sites (no application passwords, no Jetpack)
had nil discussion defaults, causing `Blog.createPost()` to always
fall back to the hardcoded `true` regardless of the site's actual
setting.
Adds a Swift extension on BlogSettings that applies a
SiteSettingsWithEditContext directly, giving callers a clean path
from the Rust networking layer to Core Data without routing through
the ObjC RemoteBlogSettings intermediary.
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.

Bug: Comments disabled on self-hosted sites

3 participants