Fix publish for new pages + homepage settings; add discard & status abilities (v0.4.2) - #19
Conversation
…bilities Critical fixes (v0.4.2): - Publish: Clear staged markers BEFORE status change to prevent guard blocking - Publish: Use internal flag to bypass guard during cs_publish_changeset - Settings: Remap staged IDs to live IDs after content is published (order matters) - Results: Track and return failed_items for accurate publish outcomes New abilities: - changesets/discard: Trash changeset and delete all staged drafts - changesets/status: Readiness check (version, caps, open count) Enhancements: - changesets/get: Include staged_options, staged_styles, style_variation - Agent docs: Front-load plugin install verification before credentials Test coverage: - New page as homepage scenario (the critical dogfood bug) - Discard and status ability tests Fixes homepage 404 when new staged page set as page_on_front. Co-authored-by: Rich Tabor <rich@tabor.email>
There was a problem hiding this comment.
🟡 Changes recommended
The new publish flow can still leave inconsistent state on partial failures (including closing a changeset as published) and the new status ability’s permissions/counting behavior need correction before merging.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR targets a critical Changesets publish bug affecting newly staged pages used as the homepage, and extends the Abilities API surface with new discard and status endpoints while updating documentation/specs for v0.4.2.
Changes:
- Fixes publish flow for new staged content (source_id=0) and adds settings ID remapping, plus partial-failure reporting.
- Adds
changesets/discard(trash + delete staged drafts) andchangesets/status(readiness/status check) abilities. - Updates versioning and documentation (README/readme/BUILD/TEST) to reflect new behaviors and agent setup guidance.
File summaries
| File | Description |
|---|---|
includes/changesets.php |
Adjusts publish ordering/guard bypass; adds discard and status helpers; returns partial failure details. |
abilities/register.php |
Registers new abilities and expands changesets/get response with staged options/styles/variation. |
changesets.php |
Bumps plugin version constant/header to 0.4.2. |
BUILD.md |
Updates spec to document new abilities and publish behavior. |
TEST.md |
Adds manual test scenarios for the fixed homepage publish case and new abilities. |
README.md |
Updates agent prompt/checklist and “What’s new” to 0.4.2. |
readme.txt |
Updates stable tag + changelog + agent setup guidance. |
Review details
Suppressed comments (4)
includes/changesets.php:906
- After a successful publish of a brand-new staged post, the staged markers (_changeset_is_staged/_changeset_id/CS_META_SOURCE) should still be cleared to avoid leaving the post treated as “staged” after it’s live. With the change above, the cleanup needs to happen here (after verification).
$staged_to_live[ $staged_id ] = $staged_id;
$source_ids[] = $staged_id;
$published_new++;
}
includes/changesets.php:916
- Settings are applied (and _changeset_staged_options is deleted) even when some staged items failed to publish. That can persist settings pointing at missing/unpublished content and also makes it impossible to retry publish with the original staged options.
// Apply settings with ID remapping AFTER content is published.
$options = cs_get_staged_options( $changeset_id );
if ( $options ) {
foreach ( $options as $key => $value ) {
// Remap staged IDs to live IDs for settings that reference posts.
includes/changesets.php:961
- The changeset is marked as published and the preview cookie is cleared even when failed_items is non-empty. That prevents discarding/retrying (cs_discard_changeset forbids published) and can hide remaining staged drafts that didn’t apply.
update_post_meta( $changeset_id, '_changeset_status', 'published' );
update_post_meta( $changeset_id, '_changeset_published_at', gmdate( 'c' ) );
update_post_meta( $changeset_id, '_changeset_published_by', get_current_user_id() );
cs_clear_preview_cookie();
includes/changesets.php:974
- cs_publish_changeset now returns extra keys (changeset_id/status/published_new_count and, on partial success, failed_items/partial_success). The registered output_schema for the changesets/publish ability still only declares applied_count and source_ids, which can cause schema/contract drift for API consumers.
$result = array(
'changeset_id' => $changeset_id,
'applied_count' => $applied,
'published_new_count' => $published_new,
'source_ids' => $source_ids,
'status' => 'published',
);
if ( ! empty( $failed_items ) ) {
$result['failed_items'] = $failed_items;
$result['partial_success'] = true;
}
- Files reviewed: 7/7 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| ), | ||
| ), | ||
| 'execute_callback' => 'cs_ability_get_status', | ||
| 'permission_callback' => '__return_true', | ||
| 'meta' => array( |
| $staged_options = cs_get_staged_options( $changeset_id ); | ||
| $staged_styles = cs_get_staged_global_styles( $changeset_id ); | ||
| $style_variation = cs_get_staged_style_variation( $changeset_id ); | ||
|
|
||
| return array( | ||
| 'changeset_id' => $changeset_id, | ||
| 'uuid' => cs_get_changeset_uuid( $changeset_id ), | ||
| 'title' => $changeset->post_title, | ||
| 'status' => cs_get_changeset_status( $changeset_id ), | ||
| 'preview_url' => cs_get_preview_url( $changeset_id ), | ||
| 'staged_items' => $staged_items, | ||
| 'changeset_id' => $changeset_id, | ||
| 'uuid' => cs_get_changeset_uuid( $changeset_id ), | ||
| 'title' => $changeset->post_title, | ||
| 'status' => cs_get_changeset_status( $changeset_id ), | ||
| 'preview_url' => cs_get_preview_url( $changeset_id ), | ||
| 'staged_items' => $staged_items, | ||
| 'staged_options' => $staged_options ? $staged_options : array(), | ||
| 'staged_styles' => $staged_styles ? $staged_styles : null, | ||
| 'style_variation' => $style_variation ? $style_variation : null, | ||
| ); |
| // Promote brand-new staged content to live publish. | ||
| // Clear staged markers FIRST to prevent guard from blocking. | ||
| delete_post_meta( $staged_id, '_changeset_is_staged' ); | ||
| delete_post_meta( $staged_id, '_changeset_id' ); | ||
| delete_post_meta( $staged_id, CS_META_SOURCE ); | ||
|
|
| // Count open changesets. | ||
| $open = get_posts( | ||
| array( | ||
| 'post_type' => 'changeset', | ||
| 'post_status' => 'draft', | ||
| 'posts_per_page' => 1, | ||
| 'meta_query' => array( | ||
| array( | ||
| 'key' => '_changeset_status', | ||
| 'value' => 'open', | ||
| ), | ||
| ), | ||
| 'fields' => 'ids', | ||
| ) | ||
| ); | ||
| $status['open_changeset_count'] = count( $open ); | ||
|
|
Critical Publish Fixes
From Codex dogfood transcript on richa8c22.wordpress.com:
The Bug
When publishing a new staged page (source_id=0) set as homepage via
page_on_front, the page was left as draft while the setting pointed at it → public homepage 404.Root Cause
Publish tried to set
post_status=publishbefore removing_changeset_is_stagedmeta. The plugin's owncs_prevent_staged_publishguard then forced it back to draft. Changeset claimed success, but homepage stayed draft.The Fix
$cs_publishing_changesetglobal flag so the guard allows publish duringcs_publish_changesetpost_statusispublish; track and returnfailed_itemswhen any item failsNew Abilities
changesets/discardTrash/discard an open changeset and delete all staged drafts. Clears preview. Needed because agents had to use raw WP REST to undo.
Example:
{"changeset_id": 123}Returns:
{ "changeset_id": 123, "status": "discarded", "deleted_count": 5 }changesets/statusSetup discovery and readiness check. Returns plugin version, abilities registration status, current user capabilities, and open changeset count.
Example:
{}Returns:
{ "version": "0.4.2", "abilities_registered": true, "user_caps": { "manage_changesets": true, "approve_changesets": true, "publish_changesets": true }, "open_changeset_count": 1 }Use case: Agents should call this before
createto verify Changesets + MCP Adapter are installed and active.Enhancements
changesets/getincludes full change contextNow returns
staged_options,staged_styles, andstyle_variation— not just staged content items. Reviewers need the whole picture.Example response:
{ "changeset_id": 123, "uuid": "...", "title": "Home update", "status": "open", "preview_url": "...", "staged_items": [...], "staged_options": { "show_on_front": "page", "page_on_front": 456 }, "staged_styles": {...}, "style_variation": "twilight" }Agent Documentation Improvements
Setup checklist (verify BEFORE asking for credentials):
changesets/*abilities are available via MCP toolsWhy: Site URL alone ≠ MCP access. Need the adapter plugin + authenticated connection for
changesets/*tools to appear.Updated in README.md and readme.txt with paste-ready agent prompts.
Test Coverage
Added critical test case in TEST.md:
New page as homepage (publish + setting remap)
changesets/save(no source_id)show_on_front=pageandpage_on_front=<staged_id>post_status='publish'(not draft)page_on_frontequals final live ID (remapped)_changeset_is_stagedmeta remainsFiles Changed
includes/changesets.php: Fixed publish order, added discard & status functionsabilities/register.php: Added discard & status abilities; enhanced get with options/styleschangesets.php: Version bump to 0.4.2readme.txt,README.md: Updated changelogs and agent guidanceTEST.md: Added critical test scenariosBUILD.md: Updated spec with new abilitiesVersion
0.4.2
Ready to squash-merge.