The wordpress/abilities-api Composer package was archived in February 2026, marked
abandoned on Packagist with no replacement package suggested, because its
functionality merged into WordPress core with 6.9. If it’s still in your
composer.json, this lesson walks through removing it correctly, without breaking
anything that depends on the functions it provided.
Lesson 1’s corrected picture of what’s actually in core. A local WordPress environment you can safely test a dependency change in before touching production.
Step 1: Confirm you’re actually on the archived package
Check your project’s composer.json for the exact package name:
grep -n "wordpress/abilities-api" composer.json composer.lock
If nothing matches, you likely built directly against core’s Abilities API already and this specific lesson doesn’t apply to you, though the version-guard pattern in Step 3 is still worth reviewing. If you see a match, also search your plugin’s bootstrap file for a manual include, some early adopters of the package required it directly rather than through Composer’s autoloader:
grep -rn "abilities-api" --include="*.php" .
Step 2: Remove the package
# Removes the dependency and updates composer.json + composer.lock
composer remove wordpress/abilities-api
If your bootstrap file had a manual require pointing at a path inside vendor/wordpress/abilities-api, delete that line too, composer remove won’t catch a hardcoded path.
// File: my-plugin.php
// Remove a line that looked like this:
// require_once __DIR__ . '/vendor/wordpress/abilities-api/src/bootstrap.php';
Step 3: Replace the package check with a version requirement
The standalone package’s whole design intent, as its own README stated, was to “ship
first as a Composer package, then migrate smoothly to core,” meaning the function names
you already call, wp_register_ability(), wp_get_ability(), wp_get_abilities(),
wp_register_ability_category(), and their companions, are the same names core
provides. Your migration is mostly about the dependency, not a function-by-function
rewrite.
What does need to change is any guard code that checked for the package rather than the functions themselves. Replace a package-presence check with a straightforward function check, which now correctly reflects “is this running on WordPress 6.9+”:
// File: my-plugin.php
add_action( 'plugins_loaded', function () {
if ( ! function_exists( 'wp_register_ability' ) ) {
add_action( 'admin_notices', function () {
echo '<div class="notice notice-error"><p>';
esc_html_e( 'My Plugin requires WordPress 6.9 or later for the Abilities API.', 'my-plugin' );
echo '</p></div>';
} );
return;
}
add_action( 'wp_abilities_api_init', 'my_plugin_register_abilities' );
} );
Also update your plugin’s readme.txt and main plugin file header, since these are
what site owners and the plugin directory actually check:
// File: readme.txt
Requires at least: 6.9
Requires PHP: 7.4
If your plugin has already decided to require WordPress 6.9 as a hard minimum (via the
readme.txt header above), the function_exists() check becomes a safety net rather
than a strict requirement, WordPress itself won’t let a site running an older core
install a plugin declaring Requires at least: 6.9. Keep the guard if you want a
friendlier failure message instead of a blocked install; drop it if you’re comfortable
relying on the readme.txt declaration alone.
Step 4: Confirm nothing else in your dependency tree pulls it back in
Some intermediate libraries or starter kits bundled the archived package transitively. Check your full lock file, not just your direct requirements:
composer why wordpress/abilities-api
If this returns a result after you’ve removed your own direct requirement, another dependency still requires it, and you’ll need to update or replace that dependency too, an abandoned package with no security coverage isn’t something you want lingering in a lock file even if nothing calls it directly.
Test it: confirm the swap didn’t break anything
composer install
wp eval 'var_dump( function_exists( "wp_register_ability" ) ); var_dump( wp_get_abilities() );'
The first var_dump should print bool(true) on a 6.9+ install with no Composer
package involved at all. The second should print your plugin’s registered abilities
exactly as before, since core’s function signatures and return shapes match what the
standalone package provided.
It’s easy to read “drop the old Abilities API dependency” and reflexively also remove
wordpress/mcp-adapter from composer.json, especially if you’ve absorbed the
mistaken idea that everything AI-related merged into core at once. Don’t. The MCP
Adapter is a real, ongoing, separate dependency, covered again in Lesson 7. This
lesson only concerns the archived Abilities API package.
Recap
The archived wordpress/abilities-api Composer package is safe to remove once your
project targets WordPress 6.9 or later, since the same function names now live in
core with no install step. Swap any package-existence guard for a function_exists()
or readme.txt version requirement, check your lock file for transitive references,
and confirm with wp eval that the functions still resolve correctly after the
package is gone.
Resources & further reading
- Archived abilities-api repository, GitHub
- wordpress/abilities-api on Packagist, Packagist
- Abilities API in WordPress 6.9, make.wordpress.org
- Abilities API reference, developer.wordpress.org