Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 107 additions & 2 deletions docs/7.javascript-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,46 @@ if ( ability ) {
}
```

### `getAbilityCategories()`

Returns an array of all registered ability categories.

**Parameters:** None

**Returns:** `Promise<Array>` - Array of category objects

**Example:**

```javascript
const categories = await getAbilityCategories();
console.log( `Found ${ categories.length } categories` );

// List all categories
categories.forEach( ( category ) => {
console.log( `${ category.label }: ${ category.description }` );
} );
```

### `getAbilityCategory( slug )`

Retrieves a specific category by slug.

**Parameters:**

- `slug` (string) - The category slug (e.g., 'data-retrieval')

**Returns:** `Promise<Object|null>` - The category object or null if not found

**Example:**

```javascript
const category = await getAbilityCategory( 'data-retrieval' );
if ( category ) {
console.log( 'Label:', category.label );
console.log( 'Description:', category.description );
}
```

### `executeAbility( name, input = null )`

Executes an ability with the provided input data.
Expand Down Expand Up @@ -98,7 +138,7 @@ Registers a client-side ability that runs in the browser.

- `ability` (object) - The ability configuration object

**Returns:** `void`
**Returns:** `Promise<void>`

**Example:**

Expand All @@ -110,7 +150,7 @@ const showNotification = ( message ) => {
};

// Register a notification ability which calls the showNotification function
registerAbility( {
await registerAbility( {
name: 'my-plugin/show-notification',
label: 'Show Notification',
description: 'Display a notification message to the user',
Expand Down Expand Up @@ -160,13 +200,78 @@ Removes a previously registered client-side ability.

- `name` (string) - The ability name to unregister

**Returns:** `void`

**Example:**

```javascript
// Unregister an ability
unregisterAbility( 'my-plugin/old-ability' );
```

### `registerAbilityCategory( slug, args )`

Registers a client-side ability category. This is useful when registering client-side abilities that introduce new categories not defined by the server.

**Parameters:**

- `slug` (string) - The category slug (lowercase alphanumeric with dashes only)
- `args` (object) - Category configuration object
- `label` (string) - Human-readable label for the category
- `description` (string) - Detailed description of the category
- `meta` (object, optional) - Optional metadata about the category

**Returns:** `Promise<void>`

**Example:**

```javascript
// Register a new category
await registerAbilityCategory( 'block-editor', {
label: 'Block Editor',
description: 'Abilities for interacting with the WordPress block editor',
} );

// Register a category with metadata
await registerAbilityCategory( 'custom-category', {
label: 'Custom Category',
description: 'A category for custom abilities',
meta: {
priority: 'high',
icon: 'dashicons-admin-customizer',
},
} );

// Then register abilities using the new category
await registerAbility( {
name: 'my-plugin/insert-block',
label: 'Insert Block',
description: 'Inserts a block into the editor',
category: 'block-editor', // Uses the client-registered category
callback: async ( { blockType } ) => {
// Implementation
return { success: true };
},
} );
```

### `unregisterAbilityCategory( slug )`

Removes a previously registered client-side category.

**Parameters:**

- `slug` (string) - The category slug to unregister

**Returns:** `void`

**Example:**

```javascript
// Unregister a category
unregisterAbilityCategory( 'block-editor' );
```

## Error Handling

All functions return promises that may reject with specific error codes:
Expand Down
108 changes: 105 additions & 3 deletions packages/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,39 @@ if ( ability ) {
}
```

#### `registerAbility( ability: Ability ): void`
#### `getAbilityCategories(): Promise<AbilityCategory[]>`

Returns all registered ability categories. Categories are used to organize abilities into logical groups.

```javascript
const categories = await getAbilityCategories();
console.log( `Found ${ categories.length } categories` );

categories.forEach( ( category ) => {
console.log( `${ category.label }: ${ category.description }` );
} );
```

#### `getAbilityCategory( slug: string ): Promise<AbilityCategory | null>`

Returns a specific ability category by slug, or null if not found.

```javascript
const category = await getAbilityCategory( 'data-retrieval' );
if ( category ) {
console.log( `Found category: ${ category.label }` );
console.log( `Description: ${ category.description }` );
}
```

#### `registerAbility( ability: Ability ): Promise<void>`
Copy link
Member

Choose a reason for hiding this comment

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

We will need an update in another document the example with missing await, too:

https://github.com/WordPress/abilities-api/blob/trunk/docs/7.javascript-client.md#registerability-ability-

A larger question for later is how to avoid redundancy between these two documents. Is this one auto-generated from JSDoc?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I updated this document with all the new methods and updated the await in the example.

A larger question for later is how to avoid redundancy between these two documents. Is this one auto-generated from JSDoc?

This one is not auto-generated. I'm not sure the best way to keep them in sync to be honest.

I do think it's valuable for the client package README to have a function definition and such. Especially if it gets split off into Gutenberg. But we also don't want to duplicate stuff in multiple places obviously..

Copy link
Member

@gziolo gziolo Oct 16, 2025

Choose a reason for hiding this comment

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

Gutenberg has tooling in place that allows auto-generating the list of public methods based on the JSDoc, so that would cover the README file nicely, as these methods are very well documented.


Registers a client-side ability. Client abilities are executed locally in the browser and must include a callback function and a valid category.

```javascript
import { registerAbility } from '@wordpress/abilities';

registerAbility( {
await registerAbility( {
name: 'my-plugin/navigate',
label: 'Navigate to URL',
description: 'Navigates to a URL within WordPress admin',
Expand All @@ -126,6 +151,61 @@ registerAbility( {
} );
```

#### `unregisterAbility( name: string ): void`

Unregisters a client-side ability from the store.

```javascript
import { unregisterAbility } from '@wordpress/abilities';

unregisterAbility( 'my-plugin/navigate' );
```

#### `registerAbilityCategory( slug: string, args: AbilityCategoryArgs ): Promise<void>`

Registers a client-side ability category. This is useful when registering client-side abilities that introduce new categories not defined by the server.

```javascript
import { registerAbilityCategory } from '@wordpress/abilities';

// Register a new category
await registerAbilityCategory( 'block-editor', {
label: 'Block Editor',
description: 'Abilities for interacting with the WordPress block editor',
} );

// Register a category with optional metadata
await registerAbilityCategory( 'custom-category', {
label: 'Custom Category',
description: 'A category for custom abilities',
meta: {
color: '#ff0000',
},
} );

// Then register abilities using the new category
await registerAbility( {
name: 'my-plugin/insert-block',
label: 'Insert Block',
description: 'Inserts a block into the editor',
category: 'block-editor', // Uses the client-registered category
callback: async ( { blockType } ) => {
// Implementation
return { success: true };
},
} );
```

#### `unregisterAbilityCategory( slug: string ): void`

Unregisters an ability category from the store.

```javascript
import { unregisterAbilityCategory } from '@wordpress/abilities';

unregisterAbilityCategory( 'block-editor' );
```

#### `executeAbility( name: string, input?: Record<string, any> ): Promise<any>`

Executes an ability with optional input parameters. The HTTP method is automatically determined based on the ability's annotations:
Expand All @@ -152,6 +232,8 @@ When using with `@wordpress/data`:

- `getAbilities( args: AbilitiesQueryArgs = {} )` - Returns all abilities from the store, optionally filtered by query arguments
- `getAbility( name: string )` - Returns a specific ability from the store
- `getAbilityCategories()` - Returns all categories from the store
- `getAbilityCategory( slug: string )` - Returns a specific category from the store

```javascript
import { useSelect } from '@wordpress/data';
Expand All @@ -164,17 +246,37 @@ function MyComponent() {
[]
);

// Get all categories
const categories = useSelect(
( select ) => select( abilitiesStore ).getAbilityCategories(),
[]
);

// Get abilities in a specific category
const dataAbilities = useSelect(
( select ) =>
select( abilitiesStore ).getAbilities( { category: 'data-retrieval' } ),
[]
);

// Get a specific category
const dataCategory = useSelect(
( select ) => select( abilitiesStore ).getAbilityCategory( 'data-retrieval' ),
[]
);

return (
<div>
<h2>All Abilities ({ allAbilities.length })</h2>
<h2>Data Retrieval Abilities</h2>
<h2>Categories ({ categories.length })</h2>
<ul>
{ categories.map( ( category ) => (
<li key={ category.slug }>
<strong>{ category.label }</strong>: { category.description }
</li>
) ) }
</ul>
<h2>{ dataCategory?.label } Abilities</h2>
<ul>
{ dataAbilities.map( ( ability ) => (
<li key={ ability.name }>{ ability.label }</li>
Expand Down
Loading