A API Abilities, introduzida no WordPress 6.9, estabelece uma linguagem comum que permite que todos os componentes do WordPress — tanto o núcleo quanto os plugins — exponham suas funcionalidades de forma unificada e compreensível para pessoas e máquinas. Isso prepara seu site WordPress para integração com ferramentas externas de automação de maneira padronizada e segura.

Se você está se perguntando como a API Abilities pode ser utilizada na prática, imagine um modelo de IA que orienta um usuário durante todo o processo de compra e até mesmo permite concluir a compra sem que ele precise acessar seu site de eCommerce. Ou imagine um pipeline de CI/CD no GitHub Actions que processa o texto extraído de um arquivo de áudio ou vídeo e o envia ao WordPress para publicação. As possibilidades são praticamente ilimitadas.

A API Abilities transforma o papel do WordPress dentro do ecossistema. Ele deixa de ser apenas um blog, ou mesmo um CMS, para atuar como um mecanismo de execução distribuído, que pode ser orquestrado externamente, funcionando como uma espécie de sistema operacional preparado para agentes autônomos.

Quer saber mais? Vamos explorar o assunto.

Para que serve uma ability

Uma ability é um recurso descobrível e executável em um site WordPress que permite realizar operações específicas para entidades externas (como modelos de IA) ou componentes internos.

A API pode ser utilizada para tarefas como:

  • Pesquisar conteúdo ou executar operações específicas no banco de dados.
  • Ler as configurações do site.
  • Criar um artigo.
  • Converter uma estrutura JSON em blocos do Gutenberg.

Expor uma ability significa tornar uma funcionalidade específica interoperável. Antes que uma ability possa ser descoberta e utilizada, ela precisa ser registrada em um catálogo centralizado. Somente então o WordPress e os modelos de IA poderão descobri-la, compreender seu propósito e executá-la quando necessário.

Por padrão, as funcionalidades dos seus plugins permanecem totalmente isoladas. Ao registrar uma ability, você declara que a lógica subjacente está disponível como um serviço para todo o ecossistema.

Vamos ver um exemplo. Se o seu plugin possui uma função que converte um objeto JSON inicial em conteúdo estruturado pronto para blocos do Gutenberg, você pode registrá-la como uma ability. Isso permite que outras ferramentas com as permissões necessárias executem exatamente a mesma função.

Em nosso tutorial anterior sobre o WordPress AI Client, o plugin era responsável pela lógica principal de enviar um arquivo de áudio para o modelo de IA, que retornava uma resposta estruturada em JSON para gerar blocos do Gutenberg. No entanto, essa funcionalidade permanecia restrita ao nosso plugin. Ao registrar esse processo como uma ability, você desacopla sua execução, permitindo que qualquer entidade externa acione toda a lógica do plugin simplesmente enviando um objeto JSON contendo o ID de um arquivo de áudio.

Uma “ability” funciona como um contrato formal entre a lógica PHP subjacente e qualquer entidade que solicite sua execução. Esse contrato define quais dados a ability espera receber como entrada, qual é seu propósito e qual esquema de dados será retornado como saída.

Ao registrar uma ability, ela é adicionada ao registro de abilities do seu site. A partir desse momento, o WordPress passa a atuar como um gateway seguro: ele verifica a autenticação e valida os dados recebidos com base no esquema definido pelo contrato. O WordPress só encaminha a solicitação para a função PHP correspondente quando a carga de dados (payload) atende rigorosamente aos requisitos estabelecidos pelo contrato.

Uma ability é agnóstica. O WordPress não precisa saber qual entidade está solicitando acesso; ele apenas verifica se a solicitação está autorizada e se atende às restrições definidas pelo contrato.

Ao registrar uma ability, seu plugin deixa de ser apenas uma extensão com lógica interna própria e passa a atuar como um provedor de serviços para todo o ecossistema. Seja um aplicativo móvel, um script de automação como Make.com ou Zapier, um agente de IA ou um servidor que se comunica por meio do protocolo MCP, todas essas entidades saberão exatamente como acionar operações estruturadas no seu site.

Trabalhando com a API Abilities

A API Abilities fornece um conjunto abrangente de funções que permitem descobrir as abilities registradas no seu site, executá-las, além de registrar e remover o registro de abilities.

Trabalhando com as abilities do seu site

Você pode recuperar uma lista de todas as abilities registradas ou obter um objeto ability específico. Também é possível verificar determinadas condições, como confirmar se uma ability está registrada ou se o agente possui as permissões necessárias para executá-la.

Obter uma lista das abilities registradas no seu site

A função wp_get_abilities() retorna um array com todas as abilities registradas. Você pode testá-la usando o WP-CLI. Depois de se conectar ao seu site via SSH, navegue  até o diretório raiz do site, onde está localizado o arquivo wp-config.php, utilizando os seguintes comandos:

cd /path/to/your/site
ls wp-config.php

Em seguida, verifique se o WP-CLI reconhece a instalação do seu site:

wp core is-installed
wp option get siteurl

Se você receber a URL do seu site, está tudo pronto para executar o comando a seguir:

wp eval '$abilities = wp_get_abilities(); foreach ( $abilities as $a ) { echo $a->get_name() . PHP_EOL; }'

Esse comando executa código PHP no seu terminal. O código PHP solicita os nomes de todas as abilities registradas no seu site e, por padrão, deve retornar a seguinte resposta:

core/get-site-info
core/get-user-info
core/get-environment-info

Você pode solicitar um conjunto mais completo de dados com o seguinte comando:

wp eval '
$all_abilities = wp_get_abilities();

foreach ( $all_abilities as $ability ) {
	echo "Ability Name: " . esc_html( $ability->get_name() ) . "\n";
	echo "Label: " . esc_html( $ability->get_label() ) . "\n";
	echo "Category: " . esc_html( $ability->get_category() ) . "\n";
	echo "Description: " . esc_html( $ability->get_description() ) . "\n";
	echo "---\n";
}
'

Quando você executar esse comando em um site novo do WordPress 7.0, o terminal vai mostrar a seguinte resposta:

Ability Name: core/get-site-info
Label: Get Site Information
Category: site
Description: Returns site information configured in WordPress. By default returns all fields, or optionally a filtered subset.
---
Ability Name: core/get-user-info
Label: Get User Information
Category: user
Description: Returns profile details for the current authenticated user to support personalization, auditing, and access-aware behavior. By default returns all fields, or optionally a filtered subset.
---
Ability Name: core/get-environment-info
Label: Get Environment Info
Category: site
Description: Returns core details about the site's runtime context for diagnostics and compatibility (environment, PHP runtime, database server info, WordPress version). By default returns all fields, or optionally a filtered subset.
---

Obter um objeto ability

A função wp_get_ability() retorna um único objeto ability com base em seu nome. Você pode testá-la no WP-CLI usando o seguinte comando:

wp eval '
$ability = wp_get_ability( "core/get-site-info" );

if ( ! $ability ) {
	echo "Ability not found\n";
	exit( 1 );
}

echo "Name: " . $ability->get_name() . "\n";
echo "Label: " . $ability->get_label() . "\n";
echo "Category: " . $ability->get_category() . "\n";
echo "Description: " . $ability->get_description() . "\n";
echo "\nInput Schema:\n";
var_dump( $ability->get_input_schema() );
echo "\nOutput Schema:\n";
var_dump( $ability->get_output_schema() );
echo "\nMeta:\n";
var_dump( $ability->get_meta() );
'

Se a ability estiver corretamente registrada no seu site, você receberá a seguinte resposta no terminal:

Name: core/get-site-info
Label: Get Site Information
Category: site
Description: Returns site information configured in WordPress. By default returns all fields, or optionally a filtered subset.

Input Schema:
array(4) {
  ["type"]=>
  string(6) "object"
  ["properties"]=>
  array(1) {
	["fields"]=>
	array(3) {
	  ["type"]=>
	  string(5) "array"
	  ["items"]=>
	  array(2) {
		["type"]=>
		string(6) "string"
		["enum"]=>
		array(8) {
		  [0]=>
		  string(4) "name"
		  [1]=>
		  string(11) "description"
		  [2]=>
		  string(3) "url"
		  [3]=>
		  string(5) "wpurl"
		  [4]=>
		  string(11) "admin_email"
		  [5]=>
		  string(7) "charset"
		  [6]=>
		  string(8) "language"
		  [7]=>
		  string(7) "version"
		}
	  }
	  ["description"]=>
	  string(81) "Optional: Limit response to specific fields. If omitted, all fields are returned."
	}
  }
  ["additionalProperties"]=>
  bool(false)
  ["default"]=>
  array(0) {
  }
}

Output Schema:
array(3) {
  ["type"]=>
  string(6) "object"
  ["properties"]=>
  array(8) {
	["name"]=>
	array(3) {
	  ["type"]=>
	  string(6) "string"
	  ["title"]=>
	  string(10) "Site Title"
	  ["description"]=>
	  string(15) "The site title."
	}
	["description"]=>
	array(3) {
	  ["type"]=>
	  string(6) "string"
	  ["title"]=>
	  string(7) "Tagline"
	  ["description"]=>
	  string(17) "The site tagline."
	}
	["url"]=>
	array(3) {
	  ["type"]=>
	  string(6) "string"
	  ["title"]=>
	  string(18) "Site Address (URL)"
	  ["description"]=>
	  string(94) "The public URL where visitors access the site. May differ from the WordPress installation URL."
	}
	["wpurl"]=>
	array(3) {
	  ["type"]=>
	  string(6) "string"
	  ["title"]=>
	  string(23) "WordPress Address (URL)"
	  ["description"]=>
	  string(83) "The URL where WordPress core files are served. May differ from the public site URL."
	}
	["admin_email"]=>
	array(3) {
	  ["type"]=>
	  string(6) "string"
	  ["title"]=>
	  string(28) "Administration Email Address"
	  ["description"]=>
	  string(37) "The site administrator email address."
	}
	["charset"]=>
	array(3) {
	  ["type"]=>
	  string(6) "string"
	  ["title"]=>
	  string(12) "Site Charset"
	  ["description"]=>
	  string(28) "The site character encoding."
	}
	["language"]=>
	array(3) {
	  ["type"]=>
	  string(6) "string"
	  ["title"]=>
	  string(13) "Site Language"
	  ["description"]=>
	  string(42) "The site locale in dash form (e.g. en-US)."
	}
	["version"]=>
	array(3) {
	  ["type"]=>
	  string(6) "string"
	  ["title"]=>
	  string(17) "WordPress Version"
	  ["description"]=>
	  string(48) "The WordPress core version running on this site."
	}
  }
  ["additionalProperties"]=>
  bool(false)
}

Meta:
array(2) {
  ["annotations"]=>
  array(3) {
	["readonly"]=>
	bool(true)
	["destructive"]=>
	bool(false)
	["idempotent"]=>
	bool(true)
  }
  ["show_in_rest"]=>
  bool(true)
}

Verificar se uma ability está registrada

A função wp_has_ability() permite verificar se uma ability está registrada. No WP-CLI, você pode utilizá-la da seguinte forma:

wp eval '
if ( wp_has_ability( "core/get-site-info" ) ) {
	echo "✓ core/get-site-info is registered\n";
} else {
	echo "✗ core/get-site-info not found\n";
}
'

Se a ability estiver registrada, a seguinte mensagem será exibida no terminal:

✓ core/get-site-info is registered

Verificar as permissões do agente

Você pode verificar se o usuário atual possui as permissões necessárias para executar uma ability usando o método check_permissions() do objeto $ability. Esse método retorna true, false ou um objeto WP_Error. Vamos chamá-lo pelo terminal usando o seguinte comando do WP-CLI:

wp --user=1 eval '
$ability = wp_get_ability( "core/get-site-info" );
if ( $ability ) {
	$has_permissions = $ability->check_permissions();
	if ( true === $has_permissions ) {
		echo "You have permissions to execute this ability.";
	} else {
		if ( is_wp_error( $has_permissions ) ) {
			error_log( "Permissions check failed: " . $has_permissions->get_error_message() );
		}
		echo "You do not have permissions to execute this ability.";
	}
} else {
	echo "Ability not found.";
}
'

Neste exemplo, definimos --user=1; por isso, você receberá a seguinte resposta:

You have permissions to execute this ability.

Registrar uma ability

Agora é hora de registrar uma ability. Para demonstrar um caso de uso real, vamos estender o plugin apresentado em nosso artigo sobre o WordPress AI Client. Esse plugin envia um arquivo de áudio para um modelo de IA, extrai o texto e inicia a geração de blocos do Gutenberg. Nesta seção, veremos como registrar esse processo como uma ability, permitindo que qualquer entidade com as permissões necessárias possa descobri-lo e utilizá-lo.

Antes de registrar uma nova ability, você precisa registrar uma nova categoria de abilities.

Para isso, você vai precisar conectar a função wp_register_ability_category() ao hook  wp_abilities_api_categories_init.

A função aceita um slug exclusivo para a categoria e um array associativo com os argumentos da configuração.

Veja como registrar uma categoria de abilities:

function aicb_register_ability_category(): void {

	if ( ! function_exists( 'wp_register_ability_category' ) ) {
		return;
	}

	wp_register_ability_category(
		'content-generation',
		array(
			'label'       => 'Content Generation',
			'description' => 'AI-powered content transformation and structuring abilities',
		)
	);
}
add_action( 'wp_abilities_api_categories_init', 'aicb_register_ability_category' );

O próximo passo é registrar a ability. Para isso, conecte a função wp_register_ability() à ação wp_abilities_api_init.

A função aceita dois argumentos: o nome da ability, incluindo seu namespace, e um array com os argumentos de configuração da ability.

Veja como registrar a ability no plugin AI Content Builder:

function aicb_register_audio_to_gutenberg_blocks_ability(): void {

	if ( ! function_exists( 'wp_register_ability' ) ) {
		return;
	}

	$input_schema = array( ... );

	$output_schema = array( ... );

	wp_register_ability(
		'ai-content-builder/audio-to-gutenberg-blocks',
		array(
			'category'            => 'content-generation',
			'label'               => 'Audio to Gutenberg Blocks',
			'description'         => 'Transcribes audio and converts the content into WordPress Gutenberg-compatible block objects.',
			'input_schema'        => $input_schema,
			'output_schema'       => $output_schema,
			'execute_callback'    => 'aicb_audio_to_gutenberg_blocks_callback',
			'permission_callback' => static function (): bool {
				return current_user_can( 'edit_posts' );
			},
			'meta'                => array(
				'show_in_rest' => true,
				'annotations'  => array(
					'readonly'     => false,
					'destructive'  => false,
					'idempotent'   => false,
					'instructions' => 'Processes an audio attachment: transcribes it, generates structured blog content via AI, and returns Gutenberg-ready block objects.',
				),
			),
		)
	);
}
add_action( 'wp_abilities_api_init', 'aicb_register_audio_to_gutenberg_blocks_ability' );

Na chamada da função wp_register_ability, configuramos os seguintes argumentos:

  • category: a categoria à qual a ability pertence.
  • label: o nome de exibição da ability.
  • description: uma breve descrição do que a ability faz e qual é a sua finalidade.
  • input_schema: o esquema de dados para os argumentos de entrada.
  • output_schema: o esquema de dados retornado pela ability.
  • execute_callback: a função de callback executada quando a ability é acionada.
  • permission_callback: a função de callback executada para verificar se o agente possui as permissões necessárias para executar a ability.
  • meta: um array com campos adicionais de metadados da ability.
  • show_in_rest: determina se a ability será exposta pela API REST do WordPress.
  • annotations: um array de elementos descritivos que definem o comportamento da ability.

O input_schema é um array que define o contrato de entrada da ability. Ele representa a definição do JSON Schema usada para validar os dados de entrada. No nosso caso específico, ele é definido assim:

$input_schema = array(
	'type'       => 'object',
	'properties' => array(
		'audio_id' => array(
			'type'        => 'integer',
			'description' => 'The ID of the audio attachment to process and convert into Gutenberg blocks.',
		),
	),
	'required'   => array( 'audio_id' ),
);

Esse JSON Schema representa o formato que os dados de entrada devem seguir para que essa ability possa ser utilizada.

O output_schema define o contrato de saída retornado pela ability. Em nosso exemplo, cada item é um objeto que representa um bloco em JSON:

$output_schema = array(
	'type'       => 'object',
	'properties' => array(
		'title'      => array( 'type' => 'string' ),
		'sections'   => array(
			'type'  => 'array',
			'items' => array( 'type' => 'object' ),
		),
		'blocks'     => array(
			'type'  => 'array',
			'items' => array( 'type' => 'object' ),
		),
		'transcript' => array( 'type' => 'string' ),
	),
	'required'   => array( 'blocks' ),
);

O próximo passo é definir a função de callback que será executada quando a ability for acionada (veja o código completo no GitHub):

function aicb_audio_to_gutenberg_blocks_callback( array $args ) {

	// missing code
	// see GitHub
	...

	$structured_json = wp_ai_client_prompt( $prompt )
		->using_system_instruction( $instructions )
		->using_temperature( 0.4 )
		->as_json_response( $schema )
		->generate_text();

	if ( is_wp_error( $structured_json ) ) {
		return $structured_json;
	}

	$structured = json_decode( (string) $structured_json, true );
	if ( ! is_array( $structured ) ) {
		return new \WP_Error(
			'invalid_ai_json',
			'Could not parse structured AI response.',
			array( 'status' => 500 )
		);
	}

	// Normalize the output.
	$normalized = aicb_normalize_structured_post( $structured );

	if ( '' === $normalized['title'] && empty( $normalized['sections'] ) ) {
		return new \WP_Error(
			'empty_structured_content',
			'The AI provider returned empty structured content.',
			array( 'status' => 500 )
		);
	}

	// Convert to Gutenberg blocks.
	$blocks = aicb_sections_to_blocks( $normalized['title'], $normalized['sections'] );

	return $blocks;
}

Essa função invoca duas funções personalizadas. A primeira (aicb_normalize_structured_post) normaliza a saída do modelo de IA para um formato predefinido e sanitiza os dados:

function aicb_normalize_structured_post( array $structured ): array {
	$title = isset( $structured['title'] )
		? sanitize_text_field( (string) $structured['title'] )
		: '';

	$sections = array();

	if ( isset( $structured['sections'] ) && is_array( $structured['sections'] ) ) {
		foreach ( $structured['sections'] as $section ) {
			if ( ! is_array( $section ) ) {
				continue;
			}

			$heading = isset( $section['heading'] )
				? sanitize_text_field( (string) $section['heading'] )
				: '';

			$level = 2;

			$paragraphs = array();
			if ( isset( $section['paragraphs'] ) && is_array( $section['paragraphs'] ) ) {
				foreach ( $section['paragraphs'] as $paragraph ) {
					$clean_paragraph = trim( sanitize_textarea_field( (string) $paragraph ) );
					if ( '' !== $clean_paragraph ) {
						$paragraphs[] = $clean_paragraph;
					}
				}
			}

			$bullet_points = array();
			if ( isset( $section['bullet_points'] ) && is_array( $section['bullet_points'] ) ) {
				foreach ( $section['bullet_points'] as $bullet_point ) {
					$clean_bullet_point = trim( sanitize_text_field( (string) $bullet_point ) );
					if ( '' !== $clean_bullet_point ) {
						$bullet_points[] = $clean_bullet_point;
					}
				}
			}

			if ( '' === $heading || empty( $paragraphs ) ) {
				continue;
			}

			$sections[] = array(
				'heading'       => $heading,
				'level'         => $level,
				'paragraphs'    => $paragraphs,
				'bullet_points' => $bullet_points,
			);
		}
	}

	return array(
		'title'    => $title,
		'sections' => $sections,
	);
}

A função recebe um array estruturado de objetos JSON, normaliza e sanitiza os dados e retorna um array contendo o título e as seções.

A segunda função (aicb_sections_to_blocks) converte os dados normalizados em objetos descritores de blocos e é definida da seguinte forma:

function aicb_sections_to_blocks( string $title, array $sections ): array {
	$blocks = array();

	foreach ( $sections as $section ) {
		if ( ! is_array( $section ) ) {
			continue;
		}

		$heading = isset( $section['heading'] ) ? trim( (string) $section['heading'] ) : '';
		if ( '' === $heading ) {
			continue;
		}

		$paragraphs = array();
		if ( isset( $section['paragraphs'] ) && is_array( $section['paragraphs'] ) ) {
			foreach ( $section['paragraphs'] as $paragraph ) {
				$clean = trim( (string) $paragraph );
				if ( '' !== $clean ) {
					$paragraphs[] = $clean;
				}
			}
		}

		if ( empty( $paragraphs ) ) {
			continue;
		}

		$blocks[] = array(
			'name'       => 'core/heading',
			'attributes' => array(
				'content' => $heading,
				'level'   => 2,
			),
		);

		foreach ( $paragraphs as $paragraph ) {
			$blocks[] = array(
				'name'       => 'core/paragraph',
				'attributes' => array(
					'content' => $paragraph,
				),
			);
		}

		if ( isset( $section['bullet_points'] ) && is_array( $section['bullet_points'] ) ) {
			$bullet_items_html = '';

			foreach ( $section['bullet_points'] as $bullet_point ) {
				$clean_bullet = trim( sanitize_text_field( (string) $bullet_point ) );
				if ( '' === $clean_bullet ) {
					continue;
				}

				// core/list expects HTML in the `values` attribute.
				$bullet_items_html .= '<li>' . esc_html( $clean_bullet ) . '</li>';
			}

			if ( '' !== $bullet_items_html ) {
				$blocks[] = array(
					'name'       => 'core/list',
					'attributes' => array(
						'values' => '<ul>' . $bullet_items_html . '</ul>',
					),
				);
			}
		}
	}

	return $blocks;
}

Os principais destaques dessa função são:

  • A função aceita dois argumentos: uma string que representa o título do artigo e um array com as seções geradas pelo modelo de IA.
  • Para cada seção, a função gera um título e pelo menos um parágrafo.
  • Se houver marcadores (bullet points), ela gera a quantidade correspondente de itens de lista.
  • A função retorna um array $blocks de objetos descritores de blocos, que corresponde ao contrato de saída retornado pela ability ($output_schema).

Observe que a saída da função não é a marcação (markup) bruta dos blocos. Ela será gerada no lado do cliente pela função JavaScript createBlock.

Por exemplo, o elemento de título de uma seção é representado pelo seguinte objeto:

if ( '' !== $heading ) {
	$blocks[] = array(
		'name'       => 'core/heading',
		'attributes' => array(
			'content' => $heading,
			'level'   => ( 3 === $level ) ? 3 : 2,
		),
	);
}

Depois de registrar sua ability, você pode executar no terminal os mesmos comandos do WP-CLI apresentados anteriormente para visualizar seus detalhes. O código a seguir gera o esquema de entrada (input schema) da sua ability:

wp --user=1 eval '
$ability = wp_get_ability( "ai-content-builder/audio-to-gutenberg-blocks" );

if ( ! $ability ) {
    echo "Ability not found\n";
    exit( 1 );
}

echo "Input Schema:\n";
var_dump( $ability->get_input_schema() );
'

Aqui está o resultado no terminal:

Input Schema:
array(3) {
	["type"]=>
	string(6) "object"
	["properties"]=>
	array(1) {
		["audio_id"]=>
		array(2) {
			["type"]=>
			string(7) "integer"
			["description"]=>
			string(76) "The ID of the audio attachment to process and convert into Gutenberg blocks."
		}
	}
	["required"]=>
	array(1) {
		[0]=>
		string(8) "audio_id"
	}
}

Da mesma forma, você pode recuperar o esquema de saída (output schema) da ability:

wp --user=1 eval '
$ability = wp_get_ability( "ai-content-builder/audio-to-gutenberg-blocks" );

if ( ! $ability ) {
    echo "Ability not found\n";
    exit( 1 );
}

echo "Output Schema:\n";
var_dump( $ability->get_output_schema() );
'

Você também pode exibir o objeto completo da sua funcionalidade com o comando a seguir:

wp eval '
$ability = wp_get_ability( "ai-content-builder/audio-to-gutenberg-blocks" );

if ( ! $ability ) {
	echo "Ability not found\n";
	exit( 1 );
}

echo "Name: " . $ability->get_name() . "\n";
echo "Label: " . $ability->get_label() . "\n";
echo "Category: " . $ability->get_category() . "\n";
echo "Description: " . $ability->get_description() . "\n";
echo "\nInput Schema:\n";
var_dump( $ability->get_input_schema() );
echo "\nOutput Schema:\n";
var_dump( $ability->get_output_schema() );
'

Executando uma ability

Para executar uma ability, utilize o método execute() do objeto $ability. Você pode testar a execução da ability core/get-site-info executando o seguinte código PHP por meio do WP-CLI:

wp --user=1 eval '
$ability = wp_get_ability( "core/get-site-info" );

if ( ! $ability ) {
	echo "Ability not found\n";
	exit(1);
}

$result = $ability->execute();

if ( is_wp_error( $result ) ) {
	echo "ERROR: " . $result->get_error_message() . "\n";
	exit(1);
}

echo json_encode( $result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) . "\n";
'

Ao executar esse comando, a ability retornará um objeto JSON semelhante ao seguinte:

{
	"name": "WordPress 7.0",
	"description": "",
	"url": "http://yoursite.kinsta.cloud",
	"wpurl": "http://yoursite.kinsta.cloud",
	"admin_email": "[email protected]",
	"charset": "UTF-8",
	"language": "en-US",
	"version": "7.1-alpha-62550"
}

O exemplo acima mostra uma ability simples que fornece informações sobre o seu site.

Como mencionado anteriormente, uma ability pode exigir dados de entrada, executar operações sobre esses dados e retornar uma saída estruturada. Podemos observar esse comportamento na ability registrada na seção anterior.

Ainda no terminal, navegue até o diretório raiz do seu site e execute o seguinte código PHP:

wp --user=1 eval '
$ability = wp_get_ability( "ai-content-builder/audio-to-gutenberg-blocks" );

if ( ! $ability ) {
	echo "Ability not found\n";
	exit( 1 );
}

$input = array( "audio_id" => 1755 );

$result = $ability->execute( $input );

if ( is_wp_error( $result ) ) {
	echo "ERROR: " . $result->get_error_message() . "\n";
	exit( 1 );
}

echo json_encode( $result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) . "\n";
'

O método execute() envia os dados estruturados de entrada para a ability, que retorna um array de objetos pronto para ser convertido em blocos do Gutenberg:

[
	{
		"name": "core/heading",
		"attributes": {
			"content": "A Well-Deserved Rest Day in Marrakech",
			"level": 2
		}
	},
	{
		"name": "core/paragraph",
		"attributes": {
			"content": "On April 24th, our group of seven motorcyclists took a break from the open road..."
		}
	},
	{
		"name": "core/heading",
		"attributes": {
			"content": "Exploring Jemaa el-Fnaa and the Medina",
			"level": 2
		}
	},
	{
		"name": "core/paragraph",
		"attributes": {
			"content": "Our journey led us straight to Jemaa el-Fnaa, the legendary main square of Marrakech..."
		}
	},
	{
		"name": "core/list",
		"attributes": {
			"values": "<ul><li>Navigating the bustling souks and narrow alleys of the ancient Medina.</li><li>Savoring traditional Moroccan and Berber dishes.</li><li>Experiencing the vibrant street performances and food stalls of Jemaa el-Fnaa at night.</li></ul>"
		}
	},
	...
]

Integração com a API REST

A API Abilities do WordPress fornece uma estrutura unificada de rotas que permite a agentes externos consultar programaticamente as categorias de abilities disponíveis (/categories), inspecionar o contrato de uma ability específica (/abilities/{name}) e executar uma ability por meio do endpoint padrão /abilities/{name}/run.

Veja, por exemplo, uma requisição GET que retorna a lista de categorias do nosso site de testes:

https://yoursite.kinsta.cloud/wp-json/wp-abilities/v1/categories
Todas as solicitações devem ser autorizadas.
Todas as solicitações devem ser autorizadas.

Quando registramos a ability no exemplo anterior, definimos o parâmetro show_in_rest como true. Com isso, nossa ability passou a ficar automaticamente acessível por meio desses endpoints nativos da API REST do WordPress, sob o namespace centralizado wp-abilities/v1.

Isso significa que você não precisa registrar manualmente rotas personalizadas para executar uma ability a partir de um ambiente externo. Agentes externos podem descobrir e executar sua ability utilizando requisições HTTP padrão.

Você pode inspecionar o contrato específico da nossa ability com a seguinte requisição GET:

https://yoursite.kinsta.cloud/wp-json/wp-abilities/v1/abilities/ai-content-builder/audio-to-gutenberg-blocks

Por fim, você pode executar a ability com uma requisição POST autenticada:

https://yoursite.kinsta.cloud/wp-json/wp-abilities/v1/abilities/ai-content-builder/audio-to-gutenberg-blocks/run

Ao enviar esse tipo de requisição, certifique-se de informar os dados de entrada. No nosso exemplo, definimos o seguinte JSON no corpo da requisição:

{
	"input": {
		"audio_id": YOUR_AUDIO_ID
	}
}
Executando uma ability por meio de uma requisição HTTP no Postman.
Executando uma ability por meio de uma requisição HTTP no Postman.

Nossa ability processou o áudio e o enviou ao modelo de IA configurado no site. O modelo retornou uma saída estruturada, que foi posteriormente normalizada e sanitizada, retornando, por fim, o seguinte array de objetos contendo os atributos dos blocos:

{
	"blocks": [
		{
			"name": "core/heading",
			"attributes": { "content": "A Welcome Rest Day in Marrakech", "level": 2 }
		},
		{
			"name": "core/paragraph",
			"attributes": { "content": "On April 24, our group of seven motorcyclists paused our journey..." }
		}
	]
}

E esse é exatamente o resultado que queríamos obter.

O futuro do WordPress é agentic

Enquanto o AI Client e a nova arquitetura de conectores trazem recursos de processamento de IA para dentro do WordPress, a API Abilities redefine a forma como o WordPress interage com o mundo externo. Estamos presenciando uma mudança profunda de paradigma, saindo de uma arquitetura tradicional da Web — baseada na interação manual do usuário, em que cada integração exigia endpoints personalizados e mapeamentos manuais — para uma arquitetura orientada por intenções (intent-driven), concebida desde o início para automação.

Para os desenvolvedores WordPress, a nova API Abilities representa um ponto de inflexão arquitetural, caracterizado pelo desacoplamento das funcionalidades dos plugins que contêm sua lógica, pela aplicação de segurança por meio do contrato de entrada e saída (input/output contract) e pela interoperabilidade nativa em todo o ecossistema.

Em conjunto, esses recursos fazem com que a API Abilities não seja apenas mais uma API, mas um verdadeiro mecanismo de execução distribuído, oferecendo uma visão do futuro cada vez mais agentic do WordPress.

Carlo Daniele Kinsta

Carlo é um apaixonado por webdesign e desenvolvimento frontend. Ele tem mais de 10 anos de experiência com WordPress e colaborou com diversas universidades e instituições educacionais na Itália e na Europa. Carlo já publicou inúmeros artigos e guias sobre WordPress, tanto em sites italianos quanto internacionais, além de revistas impressas. Você pode seguir ele no LinkedIn e no X.