Letting AI agents build galleries: the Abilities API

WordPress 6.9 added the Abilities API: a way for plugins to describe what they can do – with a name, an input and output schema, and a permission check – so that other code, including AI agents, can find and run it. Gallery Z registers four abilities. Together they let an assistant sort your Media Library into categories and build gallery pages from them, within the rights of the user it acts for.

What an ability is

An ability is a function with a contract. It has a name like gallery-z/find-images, a description written for whoever calls it, a JSON schema for its input and its output, and a permission callback. Abilities can also be annotated: read-only, destructive, idempotent. WordPress lists every registered ability over REST, validates the input against the schema before running it, and checks the permission as the current user.

That contract is what makes abilities useful for AI tools. An agent – whether it talks to WordPress through REST or through an MCP adapter that exposes abilities as tools – doesn’t have to guess at endpoints or scrape the admin. It reads the list, sees what each ability expects and returns, and calls it. The plugin decides what is possible; the user’s role decides what is allowed.

The four Gallery Z abilities

They are registered in the category gallery-z, only on WordPress 6.9 and later:

AbilityWhat it doesInput
gallery-z/list-categoriesLists the Gallery Categories with their item counts. Read-only.none
gallery-z/find-imagesFinds Media Library images by category, by search text, or those without any category. Read-only.category, search, untagged, limit (default 50, at most 500)
gallery-z/tag-imagesAdds, removes or replaces Gallery Categories on images; creates missing categories by name.attachment_ids, categories, mode (add, remove, replace)
gallery-z/create-galleryCreates a page with a gallery of the given images, or of every image in a category, optionally with filter buttons.title, attachment_ids or category, layout, filter, columns, status

Over REST

All four are shown in REST. The list is at /wp-json/wp-abilities/v1/abilities, and each ability runs at /wp-json/wp-abilities/v1/abilities/<name>/run. WordPress picks the HTTP method from the annotations:

  • GET for the read-only ones, list-categories and find-images. Input goes into the query string.
  • DELETE for tag-images, because it is annotated as destructive – it can remove or overwrite categories – and idempotent: running it twice has the same effect as once. Input goes into the query string too.
  • POST for create-gallery, which creates something new each time. Input goes into a JSON body under input.

Using another method returns a 405 error. Authentication is WordPress’s own: an application password, for example, created under Users → Profile. Here are the calls against a test site, with their real responses:

$ curl -u "editor:APP PASSWORD" \
  "https://example.com/wp-json/wp-abilities/v1/abilities/gallery-z/list-categories/run"
[{"id":7,"name":"Architecture","slug":"architecture","count":23},
 {"id":10,"name":"Food","slug":"food","count":22},
 {"id":8,"name":"Nature","slug":"nature","count":23}, …]

$ curl -u "editor:APP PASSWORD" -G \
  "https://example.com/wp-json/wp-abilities/v1/abilities/gallery-z/find-images/run" \
  --data-urlencode "input[untagged]=true" --data-urlencode "input[limit]=3"
[{"id":681,"title":"Bagel vendor on cobblestones","alt":"Bagel vendor on cobblestones",
  "url":"https://example.com/wp-content/uploads/2026/09/pexels-photo-18186567-edited.jpeg",
  "categories":[]}]

The counts include posts and pages in a category, not only images. Tagging the one untagged image, and creating a draft page from three categories:

$ curl -u "editor:APP PASSWORD" -X DELETE -G \
  "https://example.com/wp-json/wp-abilities/v1/abilities/gallery-z/tag-images/run" \
  --data-urlencode "input[attachment_ids][]=681" \
  --data-urlencode "input[categories][]=Street"
{"updated":1,"skipped":[],"created_categories":[],
 "categories":[{"id":11,"name":"Street","slug":"street","count":24}]}

$ curl -u "editor:APP PASSWORD" -X POST -H "Content-Type: application/json" \
  "https://example.com/wp-json/wp-abilities/v1/abilities/gallery-z/create-gallery/run" \
  -d '{"input":{"title":"Weekend picks","attachment_ids":[165,196,150,166,195,151,164,194],
       "layout":"grid","columns":4,"filter":true}}'
{"id":1208,"status":"draft","images":8,
 "edit_link":"https://example.com/wp-admin/post.php?post=1208&action=edit",
 "view_link":"https://example.com/?page_id=1208"}
A draft page titled Weekend picks with centered pill filter buttons All, Architecture, Food and Nature above a four-column grid of eight photos
The page the create-gallery call made: a pill filter and a four-column grid, saved as a draft.

The details that matter

  • Categories by name. tag-images and create-gallery accept a category’s name or slug, so an agent can say “Street” without looking up an ID. In add and replace mode, a category that doesn’t exist yet is created.
  • Honest results. updated only counts images whose categories actually changed; IDs that aren’t images, or that the user can’t edit, come back in skipped. New categories are listed in created_categories.
  • Drafts by default. create-gallery saves a draft unless status is publish. A person reviews the page before anyone else sees it.
  • Real blocks. The page holds a Filterable Gallery of core Image blocks with the lightbox on – the same markup you’d get in the editor, editable like any other page. layout is one of masonry (the default), rows, grid, carousel or accordion; columns is 1 to 8.
  • Clear errors. An unknown category returns a 404 error that names the category; a call that ends up with no images returns a 400.

Permissions

Every ability checks the rights of the user it runs as – the same checks as in the admin:

AbilityNeeds
list-categories, find-imagesupload_files
tag-imagesupload_files, the right to assign Gallery Categories, and edit_post for each image; creating a new category also needs the right to edit categories
create-galleryedit_pages, and publish_pages to publish right away

In practice: an Author can find and tag their own uploads but can’t build pages; an Editor can do everything, including publishing. Give an agent an application password for a user with the role you want it to have – not an administrator’s.

What to use it for

  • Sorting a backlog. Ask an assistant to go through the images without a category, look at each one, and tag it. It calls find-images with untagged, then tag-images in batches. You check the result in the Media Library’s category column.
  • A gallery from a brief. “Make a page with our best food photos, in a grid, with filters.” The agent finds candidates, and create-gallery leaves a draft for you to adjust.
  • Housekeeping. list-categories shows categories with few items; tag-images in replace mode merges them onto the right images.
  • Your own scripts. Nothing here is AI-specific. A deploy script or another plugin can call the same endpoints – or wp_get_ability( 'gallery-z/find-images' )->execute() in PHP – with the same validation and permission checks.

The abilities don’t send anything anywhere. Nothing leaves your site unless a tool you connect calls it, and then only what the user behind that tool is allowed to see.

Reference with every input and output field: AI & Abilities API in the docs. The calls above ran against a local test site; IDs and URLs will differ on yours.