Skip to content

Knowledge: Rename the Guidelines CPT storage primitive to Knowledge#79149

Draft
gziolo wants to merge 6 commits into
trunkfrom
update/rename-guideline-cpt-to-knowledge
Draft

Knowledge: Rename the Guidelines CPT storage primitive to Knowledge#79149
gziolo wants to merge 6 commits into
trunkfrom
update/rename-guideline-cpt-to-knowledge

Conversation

@gziolo

@gziolo gziolo commented Jun 12, 2026

Copy link
Copy Markdown
Member

What?

This PR is an illustration for the consolidation proposal in #77230 (comment) — it implements the proposed rename of the Guidelines CPT to a Knowledge storage primitive, plus the type consolidation, so the expected end state can be reviewed as working code rather than prose. The direction is still gathering feedback on the issue; this branch exists to make that conversation concrete.

Renames, per the proposal:

  • CPT slug: wp_guidelinewp_knowledge
  • Taxonomy: wp_guideline_typewp_knowledge_type
  • Types registry + filter: wp_guideline_typeswp_knowledge_types
  • Capability namespace: *_guidelines*_knowledge
  • Generic REST route: /wp/v2/guidelines/wp/v2/knowledge (following the attachment/wp/v2/media precedent)
  • Built-in types: contentguideline (the type the site-wide guidelines singleton carries), artifactnote (private freeform working text; the save-time fallback term), memory stays.

The storage primitive tracks the WordPress core counterpart opened at WordPress/wordpress-develop#12201, and has been refreshed to match the refinements made there: the built-in type settled on guideline (not instruction), the capability filter is the public wp_maybe_grant_knowledge_caps() hooked at priority 1 (matching the wp_maybe_grant_* family), wp_knowledge disables autosave (headless storage with no editor session; revisions retained), and the wp_knowledge_type taxonomy is headless (show_ui => false).

Why?

"Knowledge" is the namespace for the storage primitive, API, capabilities, and type registry, while individual rows are referred to by their concrete type (a guideline, a memory, a note). The reasoning, prior feedback, and the full type model are in the proposal comment.

Renaming now is cheap: the feature is an experiment with no backward-compatibility guarantee, and the same rename would be much harder after a core merge.

How?

  • lib/experimental/guidelines/lib/experimental/knowledge/, with the primitive classes renamed (Gutenberg_Knowledge_Post_Type, Gutenberg_Knowledge_REST_Controller).
  • Capabilities: registered as capability_type => array( 'knowledge_item', 'knowledge' ). "Knowledge" is a mass noun, so the singular base must differ from the plural: with both set to knowledge, the generated per-post meta caps (edit_knowledge_item) would collide with the primitives (edit_knowledge), making current_user_can( 'edit_knowledge' ) ambiguous. The *_knowledge_item forms are never granted and never typed in checks — map_meta_cap() resolves them — so the visible capability surface is *_knowledge throughout. A dedicated test (test_post_type_meta_caps_do_not_collide_with_primitives) locks this in.
  • Intentionally unchanged: the Settings → Guidelines page and its client app (routes/guidelines/, zero JS changes), the /wp/v2/content-guidelines singleton route (it now resolves the site-wide post by the guideline term instead of content), all user-facing Guidelines labels, the gutenberg-guidelines experiment id (persisted in site options), and the _guideline_* post meta keys (storage shape is orthogonal to the proposal).
  • Data migration: a one-time migration in lib/upgrade.php moves existing wp_guideline rows and wp_guideline_type terms to the new identifiers and re-slugs the built-in type terms (contentguideline, artifactnote), preserving user-customized term labels. It runs even when the experiment is currently disabled, so integrations already building on the CPT are not orphaned.

Out of scope, as follow-ups per the proposal: the skill type, the knowledge-management ability (Abilities API), pinning the singleton by ID instead of by term, and any evolution of the singleton storage shape.

Testing Instructions

  1. Enable the Guidelines experiment under Gutenberg → Experiments.
  2. Visit Settings → Guidelines, save some guidelines, and confirm the page works unchanged (round-trips through /wp/v2/content-guidelines).
  3. As an admin, GET /wp/v2/knowledge returns the collection (including the singleton row, typed guideline); POST /wp/v2/knowledge without a type creates a private row with the note fallback term.
  4. On a site with pre-rename data: after updating, confirm wp_guideline rows reappear as wp_knowledge with re-slugged type terms (run _gutenberg_migrate_guidelines_to_knowledge() fires once via the version bump in lib/upgrade.php).
  5. npm run test:unit:php:base -- --group knowledge,guidelines — 161 tests covering the full feature.

🤖 Generated with Claude Code

@gziolo gziolo self-assigned this Jun 12, 2026
@gziolo gziolo added [Feature] Guidelines An experimental feature for adding site-wide editorial rules. [Type] Breaking Change For PRs that introduce a change that will break existing functionality No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core labels Jun 12, 2026
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

Size Change: 0 B

Total Size: 8.6 MB

compressed-size-action

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

Flaky tests detected in 9a4a5c7.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/27753842623
📝 Reported issues:

@gziolo

gziolo commented Jun 17, 2026

Copy link
Copy Markdown
Member Author

After opening PR against WordPress core trunk, this PR needs to get refreshed to adjust based on my findings there:

I'll keep this PR in the draft stage also because we need to sort out the story of how we end up storing the content that users save on the Guidelines settings page, which is being explored in:

Both Gutenberg PRs must land in the same Gutenberg plugin release. As part of that, we will most likely also promote Guidelines to a regular feature that is no longer behind and an experiment.

@gziolo gziolo force-pushed the update/rename-guideline-cpt-to-knowledge branch from 4e1214d to 44f408c Compare June 17, 2026 15:00
@gziolo

gziolo commented Jun 18, 2026

Copy link
Copy Markdown
Member Author

Pushed a follow-up commit (1f20bdf) that syncs the review fixes made to the WordPress core counterpart (WordPress/wordpress-develop#12201) after the initial primitive sync, so the two stay aligned:

  • Capability basescapability_type is now array( 'knowledge_item', 'knowledge_items' ), so the primitives use the standard plural form (edit_knowledge_items) while the per-post meta caps keep the singular form (edit_knowledge_item) — the same primitive/meta split WordPress uses for edit_posts vs edit_post. The synthesized primitives, the read remap, and the wp_knowledge_type term capabilities were renamed to match.
  • Trashed-row ownershipwp_maybe_grant_knowledge_caps() resolves the pre-trash status from _wp_trash_meta_status before the per-post grant, so an author can still delete/restore their own row after trashing it (with a regression test).
  • Naming & signature — dropped the underscore prefix from the private wp_knowledge_ensure_default_type_term() / wp_knowledge_maybe_map_term_label() functions and removed the type hints from wp_maybe_grant_knowledge_caps() to match the sibling user_has_cap callbacks.
  • Error code — the collection read returns rest_cannot_read instead of rest_forbidden, matching the font-families/global-styles/comments controllers in core.
  • Taxonomy — dropped the no-op show_admin_column from wp_knowledge_type (the post type is show_ui => false, so it rendered nothing).
  • Tests — assert the revisions routes are registered while the autosaves routes are not.

phpcbf/phpcs are clean. The contributor create/update/delete REST coverage that core added in the same round was already present here, so no duplicate tests were introduced.

One intentional scope note: the Gutenberg-only Content Guidelines singleton controller still returns rest_forbidden for its read check. That controller is the consumer-side piece the core PR explicitly leaves out of scope, so I kept it as-is — happy to align it to rest_cannot_read too if we'd prefer consistency.

gziolo and others added 6 commits June 18, 2026 12:39
Renames the storage-primitive identifiers per the consolidation proposal in
#77230: the CPT slug (wp_guideline -> wp_knowledge), the type taxonomy
(wp_guideline_type -> wp_knowledge_type), the types registry and filter
(wp_guideline_types -> wp_knowledge_types), the capability namespace
(*_guidelines -> *_knowledge), and the generic REST route
(/wp/v2/guidelines -> /wp/v2/knowledge).

The capability registration uses
capability_type => array( 'knowledge_item', 'knowledge' ) because
"knowledge" is a mass noun: with identical singular/plural bases the
generated per-post meta caps would collide with the primitives. The
*_knowledge_item forms are never granted; map_meta_cap() resolves them.

User-facing surfaces are intentionally unchanged: the Settings > Guidelines
page, the /wp/v2/content-guidelines singleton route, all Guidelines labels,
the gutenberg-guidelines experiment id, and the _guideline_* meta keys.
The built-in type slugs (content, artifact, memory) are renamed separately.

Ships a one-time data migration (lib/upgrade.php) that moves existing
wp_guideline rows and wp_guideline_type terms to the new identifiers so
sites already building on the experiment are not orphaned.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Renames two of the three built-in knowledge types per the #77230 proposal
so every type is defined by behavior rather than by relation:

- `content` -> `instruction`: loaded by default when applicable. The
  site-wide guidelines singleton managed by Settings > Guidelines now
  carries the `instruction` term; the /wp/v2/content-guidelines route is
  otherwise unchanged.
- `artifact` -> `note`: private freeform working text, and the fallback
  term assigned on save when no type is given.
- `memory` stays as is.

The one-time migration in lib/upgrade.php now also re-slugs existing
terms (content -> instruction, artifact -> note), replacing term names
only when they still match the previous default labels so customized
labels survive. The re-slug runs independently of the legacy taxonomy
flip so partially migrated rows are covered too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The gutenberg-guidelines flag gates more than the Settings page since the
storage primitive rename: it also enables the wp_knowledge CPT, the
/wp/v2/knowledge API, and the capability namespace integrators build on.
The experiment id and label stay unchanged — the id is persisted in the
gutenberg-experiments option on sites that enabled it, and the label
follows the proposal's rule that the user-facing name stays Guidelines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every other test file in the directory carries a group annotation;
this one was missed when it was introduced, so group-filtered runs
silently skipped it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Aligns the experimental Knowledge implementation with the refined version
ported to WordPress core in WordPress/wordpress-develop#12201:

- Built-in type `instruction` renamed to `guideline`; the core type
  registry consolidated on `guideline`/`memory`/`note`. The migration
  target slug, the TERM_GUIDELINE constant, and the content-guidelines
  singleton follow.
- Type titles now use the `_x( ..., 'knowledge type' )` context.
- Capability filter `_wp_knowledge_synthesize_caps` becomes the public
  `wp_maybe_grant_knowledge_caps`, hooked at priority 1 to match the
  `wp_maybe_grant_*` family.
- Disable autosave support for `wp_knowledge` (headless storage with no
  editor session); revision history is retained.
- Register the `wp_knowledge_type` taxonomy as headless (`show_ui => false`).
- Align the private-status REST error message with core.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror the review fixes made to the wp_knowledge storage primitive in its
WordPress core counterpart (WordPress/wordpress-develop#12201) since the
initial sync:

- Use plural/singular capability bases: capability_type becomes
  array( 'knowledge_item', 'knowledge_items' ) so the primitives follow the
  standard plural form (edit_knowledge_items) while the per-post meta caps
  keep the singular form (edit_knowledge_item), the same primitive/meta split
  WordPress uses for edit_posts vs edit_post. Rename the synthesized
  primitives, the read remap, and the wp_knowledge_type term capabilities
  accordingly.
- Keep authors in control of their own trashed rows: resolve the pre-trash
  status from _wp_trash_meta_status before the per-post grant check so a row
  trashed from private keeps the delete/restore grant.
- Drop the underscore prefix from the private
  wp_knowledge_ensure_default_type_term() and wp_knowledge_maybe_map_term_label()
  functions, and remove the type hints from wp_maybe_grant_knowledge_caps() to
  match the sibling user_has_cap callbacks.
- Return rest_cannot_read instead of rest_forbidden when an unauthorized user
  requests the knowledge collection, aligning with core controllers.
- Drop the no-op show_admin_column from wp_knowledge_type (the post type sets
  show_ui => false, so it rendered nothing).
- Assert the revisions routes are registered while the autosaves routes are
  not, and add a regression test for a contributor deleting their own trashed
  row.

Counterpart: WordPress/wordpress-develop#12201

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gziolo gziolo force-pushed the update/rename-guideline-cpt-to-knowledge branch from 1f20bdf to 9a4a5c7 Compare June 18, 2026 10:39
Comment thread lib/upgrade.php
*
* @since 23.5.0
*/
function _gutenberg_migrate_guidelines_to_knowledge() {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We could also decide not to pursue this step, as the feature is still in the experimental phase.

@gziolo gziolo requested a review from jorgefilipecosta June 18, 2026 10:41
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. No Core Sync Required Indicates that any changes do not need to be synced to WordPress Core [Type] Breaking Change For PRs that introduce a change that will break existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant