Skip to content

Set up abilities API abstraction layers#803

Draft
agibson-godaddy wants to merge 7 commits intomasterfrom
poc/abilities-api
Draft

Set up abilities API abstraction layers#803
agibson-godaddy wants to merge 7 commits intomasterfrom
poc/abilities-api

Conversation

@agibson-godaddy
Copy link
Contributor

@agibson-godaddy agibson-godaddy commented Mar 4, 2026

Summary

This sets up Abilities API abstraction layers for plugins to:

  1. Register abilities
  2. Future: use ability registration to automatically integrate with various interfaces (REST API, CLI, MCP, etc.). I've added the REST integration as an example, but not sure if we should ship with it right out of the gate or not. Mostly wanted to validate that we could do the job.

Details

Core resources

  • HasAbilitiesContract -- to be used in classes (probably main plugin files) that provide abilities.
  • JsonSerializable -- interface that can be used on classes that serve as models that have abilities (e.g. a MembershipPlan class). This creates definitions for JSON serialized data, and the schema that corresponds to that data.
  • Ability -- DTO representation of an ability. Largely follows the WordPress input args, but with additional properties that would enable certain features (such as SV framework REST integration, or in the future a CLI integration, etc.)
  • Same goes for another DTOs

Basic implementation

Example implementation: https://github.com/gdcorp-partners/woocommerce-memberships/pull/1272

Core steps are:

1. Create abilities

Create a class (e.g. GetPlan that implements MakesAbilityContract. This defines a public method makeAbility() : Ability. Build the Ability DTO as desired.

2. Create a provider

Create a provider class that extends AbstractAbilitiesProvider.

  • Abilities are defined in $abilities property. Each item is the name of your abilities class. I chose the class name approach to avoid having one file that defines 30 abilities and getting unwieldy.
  • Categories are defined via getCategories() method. I chose a method here instead of the class-per-category approach since category definitions take up less space and you'll have less of them.

Example:

<?php

use SkyVerge\WooCommerce\PluginFramework\v6_0_1\Abilities\AbstractAbilitiesProvider;
use SkyVerge\WooCommerce\PluginFramework\v6_0_1\Abilities\DataObjects\AbilityCategory;

class AbilitiesProvider extends AbstractAbilitiesProvider
{
    protected array $abilities = [
        Plsn\GetPlan::class,
    ];

    public function getCategories() : array
    {
        return [
            new AbilityCategory(
                'woocommerce-memberships',
                __( 'WooCommerce Memberships', 'woocommerce-memberships' ),
                __( 'Abilities related to WooCommerce Memberships.', 'woocommerce-memberships' ),
            ),
        ];
    }
}

3. Implement HasAbilitiesContract

In the main plugin class file, update the class to implement HasAbilitiesContract. This will give you a getAbilitiesProvider() method to implement. Return an instance of your created provider.


That's pretty much it for bootstrapping.

JsonSerializable

The purpose of the JsonSerializable interface is to standardize return values for objects. If you have an ability that returns an object, that object must be JSON serializable. You cannot return a Membership_Plan object on its own, unless that object can be JSON serialized.

WordPress core checks for the base PHP JsonSerializable interface and accepts that. I took this a step further by having the framework define its own version that extends that. This ensures:

  1. We define what the serialized data is (from base JsonSerializable interface)
  2. We define what the schema for that data is (from SV JsonSerializable interface)

The overall purpose of this is to keep code DRY and ensure that our returned data is standardized whether we're doing a "get plan" call or a "list plans" call.

QA

Before merge

  • I have confirmed these changes in each supported minor WooCommerce version

@agibson-godaddy agibson-godaddy self-assigned this Mar 4, 2026
@ajaynes-godaddy
Copy link
Contributor

Neat!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants