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
8 changes: 0 additions & 8 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -489,11 +489,3 @@ function gutenberg_enqueue_vips_loader() {
function gutenberg_enqueue_video_conversion_loader() {
wp_enqueue_script_module( '@wordpress/video-conversion/loader' );
}

/**
* Enqueues the core abilities script module in the admin screens.
*/
add_action( 'admin_enqueue_scripts', 'gutenberg_enqueue_core_abilities' );
function gutenberg_enqueue_core_abilities() {
wp_enqueue_script_module( '@wordpress/core-abilities' );
}
26 changes: 20 additions & 6 deletions packages/core-abilities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,37 @@ _This package assumes that your code will run in an ES2015+ environment. If you'

## Usage

This package is designed to be loaded as a script module on WordPress admin pages. It exposes an `initialize()` function that, on first call:
This package is designed to be loaded as a script module on WordPress admin pages. When loaded, it automatically:

1. Fetches all ability categories from `/wp-abilities/v1/categories` and registers them with `@wordpress/abilities`
2. Fetches all abilities from `/wp-abilities/v1/abilities` and registers them with a `callback` that handles execution via REST API
1. Fetches all ability categories from `/wp-abilities/v1/categories`
2. Registers them with `@wordpress/abilities`
3. Fetches all abilities from `/wp-abilities/v1/abilities`
4. Registers them with a `callback` that handles execution via REST API

Initialization is lazy: importing the package does not trigger network requests. Call `initialize()` from the feature that needs abilities — for example, when the workflow palette opens. Repeated calls return the same in-flight or resolved promise, so the requests fire at most once.
Simply import the package to initialize the WordPress abilities:

```js
import { initialize } from '@wordpress/core-abilities';
import '@wordpress/core-abilities';
```

Initialization is asynchronous because categories and abilities are fetched from the REST API. To wait for registration to finish before calling `getAbilities()` or `executeAbility()`, await the exported `ready` promise:

```js
import { ready } from '@wordpress/core-abilities';
import { getAbilities, executeAbility } from '@wordpress/abilities';

await initialize();
await ready;

console.log( getAbilities() );
console.log( await executeAbility( 'core/get-site-info' ) );
```

To defer the network requests until a feature actually needs abilities, import the package dynamically from that feature — the module (and therefore its requests) only loads when the `import()` call runs:

```js
await import( '@wordpress/core-abilities' );
```

## Contributing to this package

This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects.
Expand Down
23 changes: 8 additions & 15 deletions packages/core-abilities/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,14 @@ async function initializeAbilities(): Promise< void > {
}
}

let initializePromise: Promise< void > | null = null;

/**
* Fetches and registers core abilities and their categories.
*
* Memoized: repeated calls return the same in-flight or resolved promise, so
* callers can invoke it from multiple entry points without triggering duplicate
* REST requests.
* Initialize WordPress abilities integration.
*/
export function initialize(): Promise< void > {
if ( ! initializePromise ) {
initializePromise = ( async () => {
await initializeCategories();
await initializeAbilities();
} )();
}
return initializePromise;
async function initialize(): Promise< void > {
// Fetch and register categories, then abilities
await initializeCategories();
await initializeAbilities();
}

// Auto-initialize on import.
export const ready: Promise< void > = initialize();
5 changes: 3 additions & 2 deletions packages/workflow/src/components/workflow-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
} from '@wordpress/keyboard-shortcuts';
import { Icon, search as inputIcon } from '@wordpress/icons';
import { executeAbility, store as abilitiesStore } from '@wordpress/abilities';
import { initialize as initializeCoreAbilities } from '@wordpress/core-abilities';

/**
* Internal dependencies
Expand Down Expand Up @@ -128,7 +127,9 @@ export function WorkflowMenu() {

useEffect( () => {
if ( isOpen ) {
initializeCoreAbilities();
// Load @wordpress/core-abilities on demand. Importing it fetches
// and registers all server abilities and categories.
import( '@wordpress/core-abilities' );

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.

Suggested change
import( '@wordpress/core-abilities' );
import( '@wordpress/core-abilities' ).catch( ( error ) => {
// eslint-disable-next-line no-console
console.error( 'Failed to load core abilities:', error );
} );

Should we catch errors just in case?

}
}, [ isOpen ] );

Expand Down
Loading