Repository navigation
Add core/term-create, core/term-update, and core/term-delete abilities - #1103
jorgefilipecosta wants to merge 33 commits into
Conversation
✅ WordPress Plugin Check Report
📊 ReportAll checks passed! No errors or warnings found. 🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## add/core-terms-query #1103 +/- ##
==========================================================
+ Coverage 82.09% 82.47% +0.37%
- Complexity 3166 3230 +64
==========================================================
Files 131 131
Lines 12673 12957 +284
==========================================================
+ Hits 10404 10686 +282
- Misses 2269 2271 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Tested in the browser console on WordPress 7.1.2, as an administrator, from a post's editor with the Excerpt Generation and Custom Abilities experiments enabled (Excerpt Generation puts Test data: the category Fruit (28554). await ( await import( '@wordpress/core-abilities' ) ).ready;
const { executeAbility } = await import( '@wordpress/abilities' );Create a term const tag = await executeAbility( 'core/term-create', { taxonomy: 'post_tag', name: 'Green', description: 'Like <em>grass</em>.' } );
// { id: 28556, count: 0, name: 'Green', slug: 'green', taxonomy: 'post_tag' }
// The ID is always included.
const citrus = await executeAbility( 'core/term-create', { taxonomy: 'category', name: 'Citrus', parent: 28554, fields: [ 'name', 'slug', 'parent', 'link' ] } );
// { id: 28557, link: 'http://localhost:8896/?cat=28557', name: 'Citrus', slug: 'citrus', parent: 28554 }
// The name is taken under that parent.
await executeAbility( 'core/term-create', { taxonomy: 'category', name: 'Citrus', parent: 28554 } );
// Rejects with { code: 'term_exists', message: 'A term with the name provided already exists with this parent.', data: { status: 400, term_id: 28557 } }Update a term // Renaming keeps the slug.
await executeAbility( 'core/term-update', { id: tag.id, name: 'Lime green', fields: [ 'name', 'slug', 'description' ] } );
// { id: 28556, description: 'Like <em>grass</em>.', name: 'Lime green', slug: 'green' }
await executeAbility( 'core/term-update', { id: citrus.id, parent: 0, fields: [ 'name', 'parent' ] } );
// { id: 28557, name: 'Citrus', parent: 0 }
// `taxonomy` is an optional guard: a term outside it is denied like a missing one.
await executeAbility( 'core/term-update', { id: citrus.id, taxonomy: 'post_tag', name: 'Lemon' } );
// Rejects with { code: 'rest_ability_cannot_execute', message: 'Sorry, you are not allowed to execute this ability.', data: { status: 403 } }
// Tags aren't hierarchical.
await executeAbility( 'core/term-update', { id: tag.id, parent: 28554 } );
// Rejects with { code: 'terms_taxonomy_not_hierarchical', message: 'Cannot set parent term, taxonomy is not hierarchical.', data: { status: 400 } }Delete a term // Terms can't be trashed, so `force` must be true.
await executeAbility( 'core/term-delete', { id: tag.id } );
// Rejects with { code: 'terms_trash_not_supported', message: 'Terms do not support trashing. Set `force` to true to delete.', data: { status: 501 } }
await executeAbility( 'core/term-delete', { id: tag.id, force: true, fields: [ 'name', 'slug' ] } );
// { deleted: true, previous: { id: 28556, name: 'Lime green', slug: 'green' } }
await executeAbility( 'core/term-delete', { id: citrus.id, taxonomy: 'category', force: true } );
// { deleted: true, previous: { id: 28557, count: 0, name: 'Citrus', slug: 'citrus', taxonomy: 'category', parent: 0 } }
// A deleted term can't be read, and the default category can't be deleted.
await executeAbility( 'core/terms-query', { id: tag.id } );
await executeAbility( 'core/term-delete', { id: 1, force: true } );
// Both reject with { code: 'rest_ability_cannot_execute', message: 'Sorry, you are not allowed to execute this ability.', data: { status: 403 } }Rejected by the client // The client rejects these before sending a request.
await executeAbility( 'core/term-create', { taxonomy: 'nav_menu', name: 'Menu' } );
// Rejects with { code: 'ability_invalid_input', message: 'Ability "core/term-create" has invalid input. Reason: input[taxonomy] is not one of category, post_tag.' }
await executeAbility( 'core/term-create', { taxonomy: 'post_tag', name: 'Blue', meta: {} } );
// Rejects with { code: 'ability_invalid_input', message: 'Ability "core/term-create" has invalid input. Reason: meta is not a valid property of Object.' } |
|
@jorgefilipecosta note that I'm holding off on requesting reviews until this comes out of draft status |
What?
Adds
core/term-create,core/term-update, andcore/term-delete, abilities that create, update, and delete categories, tags, and other taxonomy terms. Based on #1099.How?
core/terms-queryinincludes/Abilities/Terms/Terms.php, behind the Custom Abilities experiment, and write only to the taxonomies exposed tocore/terms-query.core/term-createtakes ataxonomyand aname, plus an optionalslug,description, andparent(hierarchical taxonomies only).core/term-updatetakes the term'sidand the values to change.core/term-deletetakes the term'sidandforce, which must betruebecause terms can't be trashed. On update and delete,taxonomyis an optional guard.edit_termsin a hierarchical taxonomy orassign_termsin a flat one. Updating needsedit_term, and deleting needsdelete_term. A missing term, or one outside the exposed taxonomies or the guard, is denied like a missing capability. The default category can't be deleted.core/terms-queryuses, limited byfields. A delete returns{ deleted, previous }.Testing Instructions
core/term-createwith{ "taxonomy": "post_tag", "name": "Example" }, thencore/term-updatewith{ "id": <its ID>, "name": "Renamed" }, thencore/term-deletewith{ "id": <its ID>, "force": true }.npm run test:php -- --filter 'TermCreateTest|TermUpdateTest|TermDeleteTest'npm run test:e2e -- tests/e2e/specs/abilities/core-term-write.spec.jsChangelog Entry