Skip to content

Guidelines: Add actions for Import, Export and Revisions of guidelines#76155

Merged
andrewserong merged 47 commits intoWordPress:trunkfrom
iamchughmayank:add/content-guidelines-actions-revision
Mar 11, 2026
Merged

Guidelines: Add actions for Import, Export and Revisions of guidelines#76155
andrewserong merged 47 commits intoWordPress:trunkfrom
iamchughmayank:add/content-guidelines-actions-revision

Conversation

@iamchughmayank
Copy link
Copy Markdown
Contributor

@iamchughmayank iamchughmayank commented Mar 4, 2026

What?

Closes

Extends the Content Guidelines admin page (introduced in #75420) with four operational actions and two new sub-screens:

  • Import — Upload a JSON file to replace the current content guidelines
  • Export — Download the current content guidelines as a JSON file
  • Revision History — Sub-screen showing a paginated table of past revisions
image image image

Why?

Beyond the PR ( #75420 ), this brings feature to maintain revision history and the feature to use custom JSON as content guidelines.

How?

Actions section

A new component renders four action rows (Import, Export, Manage Access, View history).

  • Import: Opens file selector and allows only .json files to be uploaded
  • Export: Downloads current guidelines with filename guidelines.json
  • Revert: Navigates to the revision history screen

Revision History sub-screen

A /revision-history Navigator screen built on DataViews (table layout):

  • Columns: Date (formatted, e.g. Mar 4, 2026, 7:06 pm) and User (author display name)
  • Server-side pagination via GET /wp/v2/content-guidelines/{id}/revisions?_embed=author, reading X-WP-Total / X-WP-TotalPages response headers
  • Client-side search and filter — Filtration can be done by user and date. Date filter opens a calendar view. User filter supports includes and is none of.
  • Restore action — kebab menu → "Restore" opens a confirmation modal; on confirm, calls POST /wp/v2/content-guidelines/{id}/revisions/{rev_id}/restore
image image image

PHP: author embed fix

WP_REST_Revisions_Controller (core) has no prepare_links(), so its responses never include an author link and ?_embed=author silently returns nothing. Added $response->add_link('author', rest_url('wp/v2/users/' . $item->post_author), ['embeddable' => true]) in Gutenberg_Content_Guidelines_Revisions_Controller::prepare_item_for_response() — the same pattern used by WP_REST_Posts_Controller.

Testing Instructions

  1. Navigate to Settings > Content Guidelines in wp-admin.
  2. Verify the four action rows render (Import, Export, Manage Access, View history).
  3. Export — click Export; confirm a .json file downloads with the current guidelines.
  4. Import — modify the downloaded file, then import it; confirm the guidelines update.
  5. View history — confirm the revision history table renders with Date and User columns.
  6. Click on Filter and filter by date.
  7. Click on filter and filter by user/author
  8. Click ⋮ → Restore on a row; confirm the modal opens with the revision date.
  9. Click Restore; confirm the guidelines revert and the modal closes.

@github-actions github-actions bot added the First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository label Mar 4, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 4, 2026

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @iamchughmayank! In case you missed it, we'd love to have you join us in our Slack community.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

@iamchughmayank iamchughmayank force-pushed the add/content-guidelines-actions-revision branch from ff441e7 to 6524a77 Compare March 5, 2026 10:27
@iamchughmayank iamchughmayank changed the title Add/content guidelines actions revision Guidelines: Add actions for Import, Export, Revisions and Access Management of guidelines Mar 5, 2026
@iamchughmayank iamchughmayank marked this pull request as ready for review March 5, 2026 14:14
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 5, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: aswasif007 <[email protected]>
Co-authored-by: iamchughmayank <[email protected]>
Co-authored-by: aagam-shah <[email protected]>
Co-authored-by: fditrapani <[email protected]>
Co-authored-by: saroshaga <[email protected]>
Co-authored-by: mirka <[email protected]>
Co-authored-by: Jameswlepage <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@iamchughmayank iamchughmayank marked this pull request as draft March 5, 2026 14:40
@iamchughmayank iamchughmayank marked this pull request as ready for review March 5, 2026 14:40
@aagam-shah aagam-shah force-pushed the add/content-guidelines-actions-revision branch from 0c948c2 to c1e016e Compare March 6, 2026 12:35
@iamchughmayank iamchughmayank changed the title Guidelines: Add actions for Import, Export, Revisions and Access Management of guidelines Guidelines: Add actions for Import, Export and Revisions of guidelines Mar 6, 2026
@fditrapani
Copy link
Copy Markdown

Nice work on this @iamchughmayank. This is a great start! Here's what I found:

Revision messaging
When you restore a revision, we show this messaging:
image

When I first worked on this, I imagined that the rest of the history would get erased. Seeing it now, I understand we just add a new revision and you can in fact undo this. Can we replace the this can't be undone messaging to "A new revision will be saved so you can always come back."

image

General alignment and clipping
The back button and content don't align very nicely. I also noticed this clipping:

image

If we add 8px of left/right padding to the content (dataview plus description under the back), things line up nicely and we don't get that clipping:

image

Table alignment
There's some weird alignment happening with the table content and table headers:

image

Any chance we can get that cleaned up?

image

Column widths
The first two columns seem really tightly packed:
image

Any chance we can have the first column fill the table width and have the last two columns packed closer together? This is what I had in my design:

image

Revision preview

I didn't have this in my design but I see now how the table doesn't offer much to go on other than the date and person who made the change. Is there any way we can introduce a preview of what changed? Due to the modular nature of the screen, I can see the updates being something like "Updated Site guidlines" or "Added paragraph block guidelines". Ideally we place that as the first column and then pack the date, user, and actions on the far right of the table.

Refreshing

When I visit the revision screen and refresh, it goes back to the main content guidelines page. Any chance we can keep it there?

Screen.Recording.2026-03-06.at.1.47.26.PM.mov

@iamchughmayank iamchughmayank force-pushed the add/content-guidelines-actions-revision branch from 917d8fe to 31c30ce Compare March 9, 2026 14:22
@iamchughmayank
Copy link
Copy Markdown
Contributor Author

@fditrapani - Thanks for the design review. I have implemented the suggestions and tried to add fixes as well. I think it can use another quick glance :)

@fditrapani
Copy link
Copy Markdown

nice work @iamchughmayank. Looking good! Two minor things:

Import modal
We currently show the modal before picking a file. It's a bit jarring to see it right away. Can we show it after a file has been picked instead?

Copy tweak
I know I initially suggested this copy but after reviewing it, it's a bit off:
image

Can we update "A new version will be saved so you can always come back." to "You can undo this anytime from revision history."

image

@iamchughmayank
Copy link
Copy Markdown
Contributor Author

nice work @iamchughmayank. Looking good! Two minor things:

Import modal We currently show the modal before picking a file. It's a bit jarring to see it right away. Can we show it after a file has been picked instead?

Copy tweak I know I initially suggested this copy but after reviewing it, it's a bit off: image

Can we update "A new version will be saved so you can always come back." to "You can undo this anytime from revision history."

image

Re

Import modal We currently show the modal before picking a file. It's a bit jarring to see it right away. Can we show it after a file has been picked instead?

Sorry, I did not realise that was the intention. Are you suggesting that after the file is picked, we show the modal. If the user hits "Continue" then only we carry on with the guidelines import. "Cancel" should drop the selected file. Is that correct?

@fditrapani
Copy link
Copy Markdown

Sorry, I did not realise that was the intention. Are you suggesting that after the file is picked, we show the modal. If the user hits "Continue" then only we carry on with the guidelines import. "Cancel" should drop the selected file. Is that correct?

No problem. We didn't make it explicit one way or the other. The way you described it is how I expected it to work.

@iamchughmayank
Copy link
Copy Markdown
Contributor Author

Sorry, I did not realise that was the intention. Are you suggesting that after the file is picked, we show the modal. If the user hits "Continue" then only we carry on with the guidelines import. "Cancel" should drop the selected file. Is that correct?

No problem. We didn't make it explicit one way or the other. The way you described it is how I expected it to work.

Thanks for the confirmation. I have updated both points in 01d03c3

Copy link
Copy Markdown

@fditrapani fditrapani left a comment

Choose a reason for hiding this comment

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

Nice work @iamchughmayank and thanks for the updates. Looks good on my end!

@iamchughmayank
Copy link
Copy Markdown
Contributor Author

iamchughmayank commented Mar 10, 2026

Would you recommend changing all occurrences of "Content Guidelines" to "Guidelines"?

I think that makes sense. Let me know if you need a hand combing through the screens to see if there are other instances to update.

@fditrapani Thanks :) I was able to scan all the occurrences. Finding the ones wrapped in i18n made it easy.
@Jameswlepage I have changed the "Content Guidelines" -> "Guidelines" wherever applicable.

@saroshaga
Copy link
Copy Markdown

saroshaga commented Mar 10, 2026

Would you recommend changing all occurrences of "Content Guidelines" to "Guidelines"?

I think that makes sense. Let me know if you need a hand combing through the screens to see if there are other instances to update.

@fditrapani Thanks :) I was able to scan all the occurrences. Finding the ones wrapped in i18n made it easy. @Jameswlepage I have changed the "Content Guidelines" -> "Guidelines" wherever applicable.

Note that the WP Admin URL will still have content-guidelines in it for now. Will take up the renaming for this separately.

Copy link
Copy Markdown
Contributor

@aagam-shah aagam-shah left a comment

Choose a reason for hiding this comment

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

Thanks for working on this and addressing all feedback 🚢

@fditrapani
Copy link
Copy Markdown

Thanks for the updates @iamchughmayank! The general Content Guidelines > Guidelines update looks good. Noting @saroshaga's point that the URL needs to be updated too.

I also noticed the following

Notice copy
image

When you upload an invalid file, we say "We ran into a problem importing your guidelines: Check that your file contains valid JSON markup and try again.".

Can we update this to a proper sentence. It should read We ran into a problem importing your guidelines. Check that your file contains valid JSON markup and try again.

Snack copy
image

The generalized snack copy feels robotic and generalized (for a lack of a better word). If we can't say the specific categories (ie: Site guidlines saved., Copy guidelines saved.), can we just say "Guidelines saved."?

Alignment regression
image

I could swear the date header column was aligned to the left at one point. Right now it's misaligned with the content in the column.

Revision table dataview options
These options to move the columns left/right aren't helpful and lead to some award layouts. Do we have the option to remove it?

image

@iamchughmayank
Copy link
Copy Markdown
Contributor Author

iamchughmayank commented Mar 10, 2026

@fditrapani
Regarding "Snack copy" in this comment. There are two types of guidelines - category and block. Here are the snackers for those:

image image image

I hope each snap is self-explanatory. What is your recommendation for these?
Should we show "Guidelines saved" for both category and block?
What about when block guidelines is removed? Should we show "Guidelines saved" again?

@saroshaga
Copy link
Copy Markdown

saroshaga commented Mar 10, 2026

There are two types of guidelines - category and block.

@iamchughmayank : This is incorrect IMO. block is a category in of itself. While the others are "primitive", this one is complex. Please see the discussion here.

I agree with @fditrapani that we need some alignment on the toast notifications. How about we keep it simple with just "Guideline Saved" and "Guideline Removed" ?

@fditrapani
Copy link
Copy Markdown

fditrapani commented Mar 10, 2026

I agree with @fditrapani that we need some alignment on the toast notifications. How about we keep it simple with just "Guideline Saved" and "Guideline Removed" ?

Thanks @saroshaga. This works for me! One minor detail is we should use sentence case so it would be "Guideline saved." and "Guideline removed."

@iamchughmayank
Copy link
Copy Markdown
Contributor Author

There are two types of guidelines - category and block.

@iamchughmayank : This is incorrect IMO. block is a category in of itself. While the others are "primitive", this one is complex. Please see the discussion here.

I agree with @fditrapani that we need some alignment on the toast notifications. How about we keep it simple with just "Guideline Saved" and "Guideline Removed" ?

@saroshaga @fditrapani , I have pushed the changes in dfd8932 whilst maintaining plural condition -

  1. Block guideline saved -> Guidelines saved
  2. Block guideline removed -> Guidelines removed
  3. Guideline category saved -> Guidelines saved

Copy link
Copy Markdown

@saroshaga saroshaga left a comment

Choose a reason for hiding this comment

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

Thank you for diligently addressing the feedback @iamchughmayank !! There are a few non-blocking items that we have already planned for.

I ran a functional test after the latest changes, and it looks good!

Copy link
Copy Markdown

@fditrapani fditrapani left a comment

Choose a reason for hiding this comment

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

Looking good on my end too! thanks for all the updates @iamchughmayank.

@andrewserong andrewserong added [Feature] Guidelines An experimental feature for adding site-wide editorial rules. [Type] Enhancement A suggestion for improvement. labels Mar 10, 2026
Copy link
Copy Markdown
Contributor

@andrewserong andrewserong left a comment

Choose a reason for hiding this comment

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

Nice continued progress here folks! I've left a bunch of comments, but nothing blocking while this is still behind an experiment. A couple of general notes:

  • There's lots of places where as unknown is used, or unknown is used as a type on function parameters. In general this means there's an opportunity to cover missing types / additional error states that might have been missed.
  • The api.ts file now includes functions that could very well be actions on the store instead (i.e. take a look at the core-data package as inspiration)
  • If refactoring to that approach, there's an opportunity to split the store file up into separate files, and to add test coverage

Usability-wise, this is all testing well for me:

✅ Exporting data worked well
✅ Importing a (valid) file worked as expected
✅ Basic error handling works okay (i.e. invalid JSON format, or malformed JSON)

A couple of other observations:

  • Now that importing and exporting has been added, tests should be included to be explicit about what's a supported format. If / when the structure of the JSON changes, it'll be important to ensure formats can be migrated or handled gracefully.
  • While renaming from Content Guidelines to Guidelines makes for simpler language, I'm wondering if it's too simple? As a word "guidelines" could be interpreted as meaning guidelines for user behaviour on a platform (e.g. code of conduct), so I'd favour being specific in naming so that it's clearer what this feature is for. In any case, I'm sure y'all will continue iterating on this 😄

This LGTM for now, so I'll merge this in. No need to reply to all my comments, I mostly wanted to capture the notes as you continue iterating on the feature, as now that's growing in feature scope, it could be a good time to polish some of the architecture in follow-ups.

Nice work again! 🚀

Comment on lines +106 to +114
// Add embeddable author link to get author name in revision history screen
if ( ! empty( $item->post_author ) ) {
$response->add_link(
'author',
rest_url( 'wp/v2/users/' . $item->post_author ),
array( 'embeddable' => true )
);
}

Copy link
Copy Markdown
Contributor

@andrewserong andrewserong Mar 11, 2026

Choose a reason for hiding this comment

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

If you want to include the author in the response, I think you can also do that via registering 'author' as one of the supports somewhere around here:

Though if you do that, you'd also want to make sure 'delete_with_user' is set to false so that if the user who created the guidelines is removed, the guidelines themselves are not.

(Not a blocker, just something that could be looked at in a follow-up if need be)

Edit: Oh wait, I don't think that approach will work since this isn't inheriting from the Post controller. Ignore me! 😄

*/
import { importContentGuidelines, exportContentGuidelines } from '../api';

function getErrorMessage( error: unknown ): string {
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.

Why is the error type unknown here? If we're throwing errors from within functions we've written, shouldn't we know what type it is by the time we get to this function?

(Not a blocker)

try {
const result = await fetchContentGuidelinesRevisions( {
guidelinesId: guidelinesId!,
perPage: 100,
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.

Yes, in a follow-up, it would be good to using the selected page size here instead of hard-coding 👍

<ul role="list" className="content-guidelines__actions-list">
{ ACTIONS.map( ( action ) => {
const descriptionId = `content-guidelines-action-${ action.slug }-description`;
return (
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.

The return statement here is fairly long, so there's possibly an opportunity here to decompose into a sub-component for the action items, which could help readability. It would also offer a way to avoid the buttonProps object which stood out to me as slightly odd.

I.e. instead of an ACTIONS array, create an Action component and pass it what it needs. You then wouldn't need a map either?

Not a blocker for now, the code you've got here works, just stuff to look at in follow-ups as the way it's written looks a little tangled to me.

Comment on lines +62 to +64
select( STORE_NAME ) as unknown as {
getId: () => number | null;
}
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.

I'll just comment on this once but this comes up a few times in this PR — instead of using the STORE_NAME you can import the exported store, then I think you can avoid using as unknown. Since this route is written in TypeScript, we can hopefully avoid any and unknown so that we can try to keep things typed where we can.

const FLAT_CATEGORIES = [ 'site', 'copy', 'images', 'additional' ] as const;

function isValidGuidelinesImport(
data: unknown
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.

Why is data unknown at this stage? Can it be given a proper type?

const { setGuideline, setBlockGuideline } = dispatch( STORE_NAME );
const { createSuccessNotice } = dispatch( noticesStore );

const parsed: unknown = JSON.parse( await file.text() );
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.

Should JSON syntax errors be handled explicitly somewhere? I.e. to have a friendlier version of the following error:

Image

(This might slightly depend on the intended audience for this feature. If you're a developer, the granular error here might be okay, but to a general user uploading malformed JSON, it might be awkward)

};

downloadBlob(
'guidelines.json',
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.

Just an idea for a follow-up, but would it be worth including the date in the filename? I.e. how are folks going to be using the exported format?

const response = ( await apiFetch( {
path: `/wp/v2/content-guidelines/${ guidelinesId }/revisions?${ params }`,
parse: false,
} ) ) as Response;
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.

is the as Response here necessary?

.content-guidelines__actions-notice {
border: none;
border-left: 4px solid $alert-yellow;
background-color: color.adjust($alert-yellow, $lightness: +35%);
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.

Looks like this is just applying the background color of the is-warning state of the Notice component. Is this necessary?

@andrewserong andrewserong merged commit aae46e6 into WordPress:trunk Mar 11, 2026
51 of 52 checks passed
@github-actions github-actions bot added this to the Gutenberg 22.8 milestone Mar 11, 2026
@andrewserong andrewserong added the Backport to Gutenberg RC Pull request that needs to be backported to a Gutenberg release candidate (RC) label Mar 11, 2026
scruffian pushed a commit that referenced this pull request Mar 11, 2026
#76155)

* Add block guidelines management

* Fix spacing of the dataviews

* Remove dataviews sort and filter
And omit dataviews search too when there are less than 6 items

* Exclude blocks that already have guidelines from add-guideline list

Also, use textcontrol instead of combobox in edit mode

* Show confirmation modal when deleting block guideline from table

* Improve save/delete logic

* Use base-style variable

* Fix bootstrapBlockRegistry() placement

* Add types

* Use hstack wrapper for add-block-guideline btn

* Do not remove block-key when removing block guideline

This is because the backend expects empty string in order to delete a block

* Fix issue with empty page after deleting rows

* Fix mistake with wrapping up action-text in double quote

* Add . after success notice text

* Remove undefined keys from block entries

* Add clarifying comment for setting empty string to delete a block guideline

* Content Guidelines: Add actions section UI

* Adds simple import and export function

* Content Guidelines: Add manage access and revision screens

* Content Guidelines: Search in revision history screen

* Content guidelines: Use filterSortAndPaginate from DataViews to implement search in guidelines revision history screen

* Content guidelines: Hide Manage Access action button for MVP

* Improve spacing

* Content guidelines: Use DataViews inbuilt filtering

* Refetch content-guidelines after restoring a revision

* Improve revision-history page styles

* Content guidelines: remove manage-access from MVP

* Content Guidelines: Use Notice as error message component instead of Snackbar

* Content Guidelines: Addresses PR feedback:
1. Uses downloadBlob from wordpress/blob
2. Adds isRTL support to the chevron
3. Uses dateI18n to format date on revision screen
4. Adds efficient catching of error during revision restoration

* Content Guidelines: Align author to the right of revision history table

* Content guidelines: Rebase with #76187

* Content guideliens: Adds confirmation modal to import guidelines

* Content guidelines: Updates modal sequence and copy

* Content guidelines: Addresses PR feedback to:1. Fix unnecessary try/catch
2. Remov unnecessary lint escapes
3. Use memoisation to avoid rerenders

* Content guidelines: Remove unnecessary overrides in CSS, where possible

* Content guidelines: Use memoisation in filter and pagination to avoid rerenders

* Content guidelines: Revert changes done by incorrect rebase and merge

* Content guidelines: Revert unnecessary changes brought in incorrect rebase

* Content guidelines: Handle guidelines import error correctly by restoring previous version

* Content guidelines: Pre-emptively add override for wordpress/ui Notice component

* Content guidelines: Update copy for content guidelines import error

* Guidelines: Rename "Content Guidelines" to "Guidelines" in all user-facing strings

Rename the feature from "Content Guidelines" to "Guidelines" across all
user-facing strings (page title, menu item, experiments toggle, notices,
modals, aria labels, error messages) while keeping variable and file names
unchanged. This aligns with the decision to use the shorter name while
the feature remains experimental.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* Content guidelines: Change the text 'content guidelines' to 'guidelines' in user facing interfaces

* Content Guidelines: Remove lint override which is not live yet

* Content guidelines: Updates copy of import error notice and removes moving revision history columns feature

* Content guidelines: Updates snackbar/toast message copy

---------

Co-authored-by: Ahmed Sayeed Wasif <[email protected]>
Co-authored-by: Aagam Shah <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
Co-authored-by: aswasif007 <[email protected]>
Co-authored-by: iamchughmayank <[email protected]>
Co-authored-by: aagam-shah <[email protected]>
Co-authored-by: fditrapani <[email protected]>
Co-authored-by: saroshaga <[email protected]>
Co-authored-by: mirka <[email protected]>
Co-authored-by: Jameswlepage <[email protected]>
@scruffian
Copy link
Copy Markdown
Contributor

I just cherry-picked this PR to the release/22.7 branch to get it included in the next release: 10a8796

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

Labels

[Feature] Guidelines An experimental feature for adding site-wide editorial rules. First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants