-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Preserve scheduled and private status when publishing custom posts #25552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
crazytonyli
wants to merge
5
commits into
trunk
Choose a base branch
from
bugfix/preserve-prepublish-status
base: trunk
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+63
−9
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
1426522
Format CustomPostEditorService.swift
crazytonyli d2765ed
Preserve scheduled and private status when publishing custom posts
crazytonyli b1f8253
Add a test case
crazytonyli 797c79c
Add missing `pending` case
crazytonyli 87b6edd
Add more status to the test case
crazytonyli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
35 changes: 35 additions & 0 deletions
35
Tests/AgentTests/post-editor/custom-post-preserve-publish-statuses.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Preserve User-Selected Status When Publishing a Custom Post | ||
|
|
||
| Regression test for the bug where publishing a REST custom post from the pre-publishing sheet flattens a user-selected status (`private`, `pending`, or `future`/scheduled) to a public `publish`, discarding the user's intent. | ||
|
|
||
| ## Prerequisites | ||
| - Logged in to the app with the test account. | ||
| - The site has at least one custom post type registered with REST API support, and the custom post types entry is visible on the My Site screen. If no custom post type is available, fail with "Prerequisite not met: site has no REST custom post type". | ||
|
|
||
| ## Status Matrix | ||
|
|
||
| Perform the steps below **once per row**. Each row creates a separate post with its own title. | ||
|
|
||
| | Status | Title | How to set it from the pre-publish sheet | | ||
| | --------- | ---------------------- | -------------------------------------------------------------------------------------- | | ||
| | `private` | CPT private preserve | Open "Post Settings" and set Visibility to "Private". | | ||
| | `pending` | CPT pending preserve | Scroll to "More Options" and toggle "Pending Review" on. | | ||
| | `future` | CPT scheduled preserve | Tap the "Date" row and pick a date at least 7 days in the future, then confirm. | | ||
|
|
||
| ## Steps (per row) | ||
| 1. From "My Site", tap **"More"**, then tap one of the available custom post types (e.g., "Books"). | ||
| 2. Tap the FAB ("+") to create a new custom post and enter the row's **Title**. | ||
| 3. Tap **"Publish"** in the top-right corner to open the pre-publish sheet. | ||
| 4. Apply the row's **"How to set it"** action. | ||
| 5. Return to the pre-publish sheet. For `future`, the primary button changes from "Publish" to "Schedule". | ||
| 6. Tap the primary button to commit. Dismiss the confirmation screen. | ||
|
|
||
| ## Verification (per row, via REST API) | ||
| - Look up the post by title against the custom post type's REST endpoint (e.g., `/wp/v2/<cpt-rest-base>?search=<title>&status=any`). Authenticate with the application password — private and future posts aren't returned to anonymous requests. | ||
| - **Regression assertion:** the post's `status` field is exactly the row's `Status`. Any other value (especially `"publish"`) indicates the bug has regressed. | ||
|
|
||
| ## Cleanup (REST API) | ||
| - Trash every post created during this test, regardless of pass or fail. | ||
|
|
||
| ## Expected Outcome | ||
| - For each row, the custom post is saved with the user-selected status preserved through the publish path. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,9 +85,10 @@ class CustomPostEditorService { | |
| let capabilities = PostSettingsCapabilities(from: details) | ||
| // At the moment, category & tags are separated from custom taxonomies. We can unify them as taxonomies later, | ||
| // by which point we won't need this filter logic. | ||
| self.taxonomies = (try? blog.taxonomies | ||
| .filter { capabilities.customTaxonomySlugs.contains($0.slug) } | ||
| .sorted(using: KeyPathComparator(\.name))) ?? [] | ||
| self.taxonomies = | ||
| (try? blog.taxonomies | ||
| .filter { capabilities.customTaxonomySlugs.contains($0.slug) } | ||
| .sorted(using: KeyPathComparator(\.name))) ?? [] | ||
|
|
||
| switch self.state { | ||
| case let .newPost(params): | ||
|
|
@@ -122,12 +123,12 @@ class CustomPostEditorService { | |
|
|
||
| case (.newPost(let existing), true): | ||
| var params = settings.makeCreateParameters(from: existing, taxonomies: taxonomies) | ||
| params.status = params.status?.normalizedPublishStatus() ?? .publish | ||
|
|
||
| // Update content | ||
| if let delegate { | ||
| let hasTitle = details.supports.map[.title] == .bool(true) | ||
| let editorContent = try await delegate.editorContent(for: self) | ||
| params.status = .publish | ||
| params.title = hasTitle ? editorContent.title : nil | ||
| params.content = editorContent.content | ||
| } | ||
|
|
@@ -140,7 +141,7 @@ class CustomPostEditorService { | |
|
|
||
| case (.existingPost(let post, _), true): | ||
| var params = settings.makeUpdateParameters(from: post, taxonomies: taxonomies) | ||
| params.status = .publish | ||
| params.status = PostStatus(settings.status).normalizedPublishStatus() | ||
|
|
||
| // Update content | ||
| if let delegate { | ||
|
|
@@ -162,7 +163,7 @@ class CustomPostEditorService { | |
| switch state { | ||
| case .newPost(let existing): | ||
| var params = existing | ||
| params.status = publish ? .publish : .draft | ||
| params.status = publish ? (existing.status?.normalizedPublishStatus() ?? .publish) : .draft | ||
| params.title = hasTitle ? content.title : nil | ||
| params.content = content.content | ||
| try await create(params: params) | ||
|
|
@@ -181,7 +182,7 @@ class CustomPostEditorService { | |
| params = PostUpdateParams(meta: nil) | ||
| } | ||
| if publish { | ||
| params.status = .publish | ||
| params.status = pending.map { PostStatus($0.status).normalizedPublishStatus() } ?? .publish | ||
| } | ||
| params.title = hasTitle ? content.title : nil | ||
| params.content = content.content | ||
|
|
@@ -195,7 +196,8 @@ class CustomPostEditorService { | |
| guard try await !hasBeenModified(post: post) else { throw PostUpdateError.conflicts } | ||
|
|
||
| let endpoint = details.toPostEndpointType() | ||
| let updatedPost = try await wpService.posts().updatePost(endpointType: endpoint, postId: post.id, params: params) | ||
| let updatedPost = try await wpService.posts() | ||
| .updatePost(endpointType: endpoint, postId: post.id, params: params) | ||
| state = .existingPost(updatedPost) | ||
| initialSettings = settings | ||
|
|
||
|
|
@@ -265,7 +267,8 @@ extension PostCreateParams { | |
| params.status = .draft | ||
|
|
||
| if let categoryID = blog.settings?.defaultCategoryID, | ||
| categoryID != PostCategory.uncategorized { | ||
| categoryID != PostCategory.uncategorized | ||
| { | ||
| params.categories = [TermId(categoryID.int64Value)] | ||
| } | ||
|
|
||
|
|
@@ -278,3 +281,19 @@ extension PostCreateParams { | |
| return params | ||
| } | ||
| } | ||
|
|
||
| private extension PostStatus { | ||
| /// Maps a user-selected status to the one used by a publish action. | ||
| /// `.future`, `.private`, and `.pending` are preserved because they carry | ||
| /// their own publishing semantics (scheduled, password/private visibility, | ||
| /// submit for review); every other selection (draft) collapses to | ||
| /// `.publish` so the post is published normally. | ||
| func normalizedPublishStatus() -> PostStatus { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if a user without publishing permission goes through this flow? Will it preserve
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! Addressed in the latest commit. |
||
| switch self { | ||
| case .future: return .future | ||
| case .private: return .private | ||
| case .pending: return .pending | ||
| default: return .publish | ||
| } | ||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe not related to this PR, but can
params.statusever benil?If not, maybe it doesn't need to be optional and we could flatten this out? Or maybe it should be able to be
nilto represent "the user hasn't told us what they want"?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm okay with it being non-optional. We can always give new posts a default "draft" status, which sounds very reasonable to me.