Utilize the new client-side Abilities API#482
Utilize the new client-side Abilities API#482dkotter wants to merge 10 commits intoWordPress:developfrom
Conversation
…ion to utilize this new package
…ly for each of our experiments/features so the client-side API is used
…ts themselves work fine
|
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #482 +/- ##
=============================================
+ Coverage 69.16% 69.19% +0.02%
- Complexity 981 982 +1
=============================================
Files 63 63
Lines 4648 4652 +4
=============================================
+ Hits 3215 3219 +4
Misses 1433 1433
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| return; | ||
| } | ||
|
|
||
| wp_enqueue_script_module( '@wordpress/core-abilities' ); |
There was a problem hiding this comment.
Out of curiosity, can the build tool detect this script module dependency and automatically include it in the asset file for the entry point that needs it? It would be a more future-proof approach rather than remembering to add it manually.
There was a problem hiding this comment.
I'll admit my knowledge on this is limited so I could be wrong here but my understanding is that since this is a script module and not a classic script, dependency extraction doesn't work here. I think we'd have to move away from using wp_enqueue_script for all of our scripts and convert those all into modules we import via wp_enqueue_script_module, along with some other changes. So this seemed like the easiest approach.
But if I'm wrong on this and there's a better approach, definitely interested in learning that.
One thing we could do that I had considered is update our Asset_Loader::enqueue_script method to auto include this script module when needed. That would reduce the duplication here and new experiments in the future wouldn't need to have this line added. Would just need an extra argument added to Asset_Loader::enqueue_script to determine if this module should be enqueued or not
There was a problem hiding this comment.
@sirreal, would you mind sharing insights what’s possible with WordPress 7.0 as minimum version in regards to mixing scripts and script modules?
There was a problem hiding this comment.
This isn’t a blocker. I’m not even sure we can do much about it without larger changes.
There was a problem hiding this comment.
Changeset 61587 landed in WordPress to allow Classic Scripts to depend on Script Modules.
Usage looks like this:
wp_register_script_module( '@example/module', /*…*/ );
wp_enqueue_script(
'example-classic',
'/classic.js',
array( 'classic-script-dependency' ), // Classic script dependencies.
null,
array(
// Script module dependencies are declared here.
'module_dependencies' => array( '@example/module' ),
)
);There's a related issue about updating build tooling:
There was a problem hiding this comment.
Was the error you saw like this?
TypeError: Failed to resolve module specifier '@wordpress/core-abilities'
I get an error around not being able to find the Ability, example Error: Ability not found: ai/title-generation. This goes away once I add wp_enqueue_script_module( '@wordpress/core-abilities' )
Is there a compelling reason not to use modules more broadly in this project? Module->module dependencies should work without issue.
Just not the way things have been setup before this. I'm not opposed to moving that direction but that's likely a larger discussion and task.
For the script that depends on the abilities module, adding defer is a workaround that should resolve the issue.
We do already set 'strategy' => 'defer'. I added 'in_footer' => true to test but that doesn't fix things either.
There was a problem hiding this comment.
This seems to work, although there are some issues with it:
wp_register_script(
'example',
false,
array( 'wp-api-fetch', 'wp-url', 'wp-data', 'wp-i18n', ),
false,
array(
'in_footer' => true,
'strategy' => 'defer',
'module_dependencies' => array( '@wordpress/abilities', '@wordpress/core-abilities' ),
),
);
wp_enqueue_script( 'example' );
wp_add_inline_script(
'example',
<<<JAVASCRIPT
( async () => {
await import( '@wordpress/core-abilities' );
const m = await import( '@wordpress/abilities' );
window.m = m;
console.log({m});
} )()
JAVASCRIPT,
);It seems like the abilities modules expect several classic WordPress scripts to be present (see the dependency array in the example script).
Calling the @wordpress/abilities module's getAbilities() function is an array with 2 entries. That may be because I don't have this plugin registered? Can you provide details about the steps to discover the issue you're seeing?
There was a problem hiding this comment.
Here's the steps I'm following:
- Checkout this PR and run
npm i && npm run build - Comment out this line so the script module isn't loaded: https://github.com/WordPress/ai/pull/482/changes#diff-9b683a19a4d64a079b42ade32de8038f235d7b12f619ae623796f7a9eff667cdR69
- Go to
Settings > AIand turn on Title Generation (you don't even need an AI Connector setup to test this) - Go to a post, open the browser console, click into the title and click the Regenerate button that shows
- You should see an error in the console:
Error: Ability not found: ai/title-generation. Right after that, should see a message:[AI] Client ability execution is unavailable. Falling back to REST.. If using the client-side API doesn't work, we fallback to making direct REST requests usingapiFetch - Uncomment out the script module line above and try the steps again
- This time you should see an error around invalid schema due to
sanitize_callback, which will be addressed when the next beta version of 7.0 is released. So it tried to use theexecuteAbilityfunction but that failed due to schema validation issues and it then falls back to usingapiFetchagain
Looking at your code example, there are some differences to what I've been trying. I've only been including @wordpress/core-abilities as a script module and only been importing @wordpress/abilities. I tried adjusting that to include both but still get the same error.
I even replaced my code with the following (adjusted slightly from your example) and got the same error (if I comment out wp_enqueue_script_module( '@wordpress/core-abilities' )):
wp_register_script(
'example',
false,
array( 'wp-api-fetch', 'wp-url', 'wp-data', 'wp-i18n', ),
false,
array(
'in_footer' => true,
'strategy' => 'defer',
'module_dependencies' => array( '@wordpress/abilities', '@wordpress/core-abilities' ),
),
);
wp_enqueue_script( 'example' );
wp_add_inline_script(
'example',
<<<JAVASCRIPT
( async () => {
await import( '@wordpress/core-abilities' );
const m = await import( '@wordpress/abilities' );
window.m = m;
m.executeAbility('ai/title-generation');
} )()
JAVASCRIPT,
);
There was a problem hiding this comment.
Thanks, I tested this out and was able to reproduce.
As far as I can tell, it's a race condition. It has more to do with wp-data than with the module system. I didn't see any initial state in the DOM, so the abilities store has an empty ability list until the request to /wp-json/wp-abilities/v1/abilities completes and data is present in the store. Eager evaluation here that expects abilities data to be present is extremely likely to fail because the initial abilities are [].
If I run the following on the browser console, I see the abilities are present (after the page has loaded and data is in the store).
const wpAbilities = await import('@wordpress/abilities');
wpAbilities.getAbilities();
// [ …4 items… ]I believe that manually enqueuing the module in your case changes the race conditions without eliminating them.
An example like this makes the race clear:
wp_register_script(
'example',
false,
array( 'wp-api-fetch', 'wp-url', 'wp-data', 'wp-i18n' ),
false,
array(
'in_footer' => true,
'strategy' => 'defer',
'module_dependencies' => array( '@wordpress/abilities' ),
),
);
wp_enqueue_script( 'example' );
wp_add_inline_script(
'example',
<<<JAVASCRIPT
( async () => {
const wpAbilities = await import( '@wordpress/abilities' );
console.log( 'Initial abilities: %o', wpAbilities.getAbilities().map( ab => ab.name ) );
const wpData = window.wp.data;
const selectAbilities = wpData.select( wpAbilities.store )
const {promise, resolve} = Promise.withResolvers();
const unsubscribe = wpData.subscribe(
(...args) => {
if ( wpAbilities.getAbilities().length ) {
resolve()
}
}
);
await promise;
unsubscribe();
console.log( 'After subscription: %o', wpAbilities.getAbilities().map( ab => ab.name ) );
} )()
JAVASCRIPT,
);In my testing I see:
Initial abilities: []
After subscription: (4) ['core/get-site-info', 'core/get-environment-info', 'ai/title-generation', 'ai/get-post-details']
…o false but if you pass true, will load the core abilities script module
… pass true as the new third argument
Important
This relies on a new version of WordPress 7.0 being shipped that includes https://core.trac.wordpress.org/ticket/65035. Marking this as blocked until then.
What?
Closes #346
Ensure we properly use the new client-side Abilities API
Why?
We currently have a helper method that attempted to use the client-side Abilities API, falling back to making direct API requests if it wasn't available. This was based on the older client-side API and so needed updating with the new version that is shipping with WordPress 7.0 (see post).
Note this code was pulled directly from #364, as that PR is no split into this one and #481
How?
runAbilityhelper function to use the new client-side Abilities API@wordpress/core-abilitiesscript module is loaded anytime an Ability needs itUse of AI Tools
AI assistance: Yes
Tool(s): Cursor
Model(s): GPT-5.3 Codex
Used for: Determining how to properly load the
@wordpress/core-abilitiesscript module based on our current setup. Also used it to debug schema validation errors. Most work was then done by meTesting Instructions
npm i && npm run build[AI] Client ability execution unavailable. Falling back to REST.Changelog Entry