Skip to content

feat(bulk-editor): add Save edits / Cancel edits for manual edits#23437

Open
JorPV wants to merge 3 commits into
release/28.1from
bulk-editor/apply-discard-all
Open

feat(bulk-editor): add Save edits / Cancel edits for manual edits#23437
JorPV wants to merge 3 commits into
release/28.1from
bulk-editor/apply-discard-all

Conversation

@JorPV

@JorPV JorPV commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Context

Free users should be albe to make several manual edits across rows and save them in one action, instead of applying each field one by one. This adds batch Save edits / Cancel edits actions for manual edits. Per a product decision, manual editing and AI generation are mutually exclusive.

Summary

This PR can be summarized in the following changelog entry:

  • Adds Save edits and Cancel edits actions to the bulk editor to save or discard multiple manual edits at once.

Relevant technical choices:

  • Batch save: a new onApplyAll groups every editing row's open drafts into one request per endpoint (update_search / update_social), reusing the existing bulk-update routes; onDiscardAll clears all drafts, reverting to the last-saved values.
  • Mutual exclusion: each row's Edit button is disabled while Premium reports AI suggestions pending review (hasExternalPendingChanges), and AI generation is already disabled while manual edits are unsaved — so only one review bar shows at a time.
  • Free-owned: the manual actions live in Free (ManualReviewActions, gated on the active tab); Premium needs no change, as its AI-disable-while-editing behaviour already exists.

Test instructions

Test instructions for the acceptance test before the PR gets merged

This PR can be acceptance tested by following these steps:

Free — manual editing (Save edits / Cancel edits)

Run on a site with only Yoast SEO Free active.

  1. Go to Yoast SEO → Tools → Bulk editor and open the Search appearance tab.
  2. Click Edit on a row and change its SEO title, meta description, and/or focus keyphrase.
  3. Click Edit on one or two more rows and change their fields too.
  4. Confirm a bar appears above the table reading "N rows with unsaved changes" with Save edits and Cancel edits buttons.
  5. Click Save edits: confirm all edited rows save in a single action, leave edit mode, and show the new values in the table. Reload the page and confirm the values persisted.
  6. Edit a few rows again, then click Cancel edits: confirm every row exits edit mode and reverts to its previously-saved values, and that no save request is sent (nothing persists after a reload).
  7. Repeat steps 2–6 on the Social appearance tab (social title / social description).
  8. Confirm the Generate SEO titles / Generate meta descriptions upsell buttons stay visible and clickable while editing (clicking one opens the upsell modal).

Premium — manual + AI (mutual exclusion)

Run on a site with Yoast SEO Premium active and a valid subscription.

  1. Go to Yoast SEO → Tools → Bulk editor.
  2. Manual disables AI: click Edit on a row and change a field. Confirm the Generate SEO titles / Generate meta descriptions buttons become disabled (with a "Save your manual edits to use AI generation" hint) while the Save edits / Cancel edits bar is shown. Save or cancel and confirm the Generate buttons re-enable.
  3. AI disables manual: select one or more rows and click Generate SEO titles (or meta descriptions) to produce AI suggestions. While suggestions are pending review, confirm every row's Edit button is disabled and the AI Apply all / Discard all bar is shown.
  4. Apply or discard the AI suggestions and confirm the Edit buttons re-enable once nothing is pending.
  5. Confirm the two bars never appear at the same time: you see one or the other, never both.
  6. Different labels per mode: confirm the action labels differ by source so it's always clear what you are acting on:
    • Manual editsSave edits / Cancel edits (Free's see 🧵 thread).
    • AI suggestionsApply all / Discard all (Premium's BulkReviewActions).
      You should never see the same label set for both, and the summary text differs too ("N rows with unsaved changes" for manual vs the AI suggestion count).

Relevant test scenarios

  • Changes should be tested with the browser console open
  • Changes should be tested on different posts/pages/taxonomies/custom post types/custom taxonomies
  • Changes should be tested on different editors (Default Block/Gutenberg/Classic/Elementor/other)
  • Changes should be tested on different browsers
  • Changes should be tested on multisite

Test instructions for QA when the code is in the RC

  • QA should use the same steps as above.

QA can test this PR by following these steps:

  • Not applicable — the bulk editor feature is unreleased; this is a non-user-facing enhancement within it.

Impact check

This PR affects the following parts of the plugin, which may require extra testing:

  • The bulk editor's manual inline editing and its interaction with Premium's AI generation (the mutual-exclusion guards).

Other environments

  • This PR also affects Shopify. I have added a changelog entry starting with [shopify-seo], added test instructions for Shopify and attached the Shopify label to this PR.
  • This PR also affects Yoast SEO for Google Docs. I have added a changelog entry starting with [yoast-doc-extension], added test instructions for Yoast SEO for Google Docs and attached the Google Docs Add-on label to this PR.

Documentation

  • I have written documentation for this change. For example, comments in the Relevant technical choices, comments in the code, documentation on Confluence / shared Google Drive / Yoast developer portal, or other.

Quality assurance

  • I have tested this code to the best of my abilities.
  • During testing, I had activated all plugins that Yoast SEO provides integrations for.
  • I have added unit tests to verify the code works as intended.
  • If any part of the code is behind a feature flag, my test instructions also cover cases where the feature flag is switched off.
  • I have written this PR in accordance with my team's definition of done.
  • I have checked that the base branch is correctly set.
  • I have run grunt build:images and committed the results, if my PR introduces or edits images or SVGs.

Innovation

  • No innovation project is applicable for this PR.

Fixes Yoast/plugins-automated-testing#3063

@JorPV JorPV added the changelog: non-user-facing Needs to be included in the 'Non-userfacing' category in the changelog label Jul 8, 2026
@JorPV JorPV requested a review from Copilot July 8, 2026 15:02
@JorPV JorPV added the innovation Innovative issue. Relating to performance, memory or data-flow. label Jul 8, 2026
@JorPV JorPV added this to the 28.1 milestone Jul 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds batch “Save edits / Cancel edits” controls for manual inline edits in the bulk editor, and enforces mutual exclusion between manual editing and Premium AI suggestion review (disabling row editing while AI suggestions are pending).

Changes:

  • Introduces batched manual save/discard behavior via useInlineEdit (onApplyAll / onDiscardAll) and wires it into the bulk editor UI.
  • Adds a new ManualReviewActions UI in the bulk action bar with proper singular/plural copy and disabled state while saving.
  • Disables each row’s Edit button when Premium reports external pending changes (hasExternalPendingChanges), with accompanying test coverage.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/js/tests/bulk-editor/hooks/use-inline-edit.test.js Adds unit tests covering batched manual apply/discard behavior and failure handling.
packages/js/tests/bulk-editor/bulk-editor-table.test.js Tests that row Edit buttons are disabled when Premium AI suggestions are pending.
packages/js/tests/bulk-editor/bulk-action-bar.test.js Adds tests for ManualReviewActions copy/actions and for showing manual review actions alongside Free upsell buttons.
packages/js/src/bulk-editor/hooks/use-inline-edit.js Adds isApplyingAll state and onApplyAll batching logic; exposes new handlers via editing.
packages/js/src/bulk-editor/components/table/table-row.js Disables per-row Edit button when hasExternalPendingChanges is true.
packages/js/src/bulk-editor/components/table/table-body.js Threads hasExternalPendingChanges down to each row.
packages/js/src/bulk-editor/components/table/bulk-editor-table.js Accepts and passes hasExternalPendingChanges into the table body.
packages/js/src/bulk-editor/components/bulk-editor-content.js Computes editCount, shows bulk actions when there are unsaved edits, and wires batch apply/discard props to BulkActions.
packages/js/src/bulk-editor/components/bulk-action-bar.js Adds ManualReviewActions (Save/Cancel edits UI) and renders it when there are unsaved manual edits.

Comment thread packages/js/src/bulk-editor/components/bulk-action-bar.js
Comment thread packages/js/src/bulk-editor/hooks/use-inline-edit.js
@coveralls

coveralls commented Jul 8, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 55556

Coverage increased (+0.03%) to 55.036%

Details

  • Coverage increased (+0.03%) from the base build.
  • Patch coverage: 4 uncovered changes across 1 file (44 of 48 lines covered, 91.67%).
  • 1 coverage regression across 1 file.

Uncovered Changes

File Changed Covered %
packages/js/src/bulk-editor/hooks/use-inline-edit.js 37 33 89.19%
Total (6 files) 48 44 91.67%

Coverage Regressions

1 previously-covered line in 1 file lost coverage.

File Lines Losing Coverage Coverage
packages/js/src/bulk-editor/store/edits.js 1 87.5%

Coverage Stats

Coverage Status
Relevant Lines: 71742
Covered Lines: 39358
Line Coverage: 54.86%
Relevant Branches: 18579
Covered Branches: 10351
Branch Coverage: 55.71%
Branches in Coverage %: Yes
Coverage Strength: 41949.04 hits per line

💛 - Coveralls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog: non-user-facing Needs to be included in the 'Non-userfacing' category in the changelog innovation Innovative issue. Relating to performance, memory or data-flow.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants