WP24Horas
PARCEIRO RECOMENDADO Vai colocar um WordPress no ar? Comece com uma hospedagem que acompanha o seu projeto. Conhecer a HostGator link patrocinado

Desenvolvimento e Programação

Como criar uma Ability no WordPress: plugin completo passo a passo

Por Asllan Maciel6 min de leitura
Plugin WordPress conectado a um agente de IA por uma rede de Abilities e APIs

No primeiro artigo da série, vimos como a Abilities API transforma funções de plugins em capacidades que ferramentas e agentes conseguem descobrir. Agora vamos construir uma ability com entrada parametrizada, validação automática e permissão vinculada ao objeto consultado.

O exemplo recebe o ID de um post e devolve título, status, tipo, URL e resumo. A ação é somente de leitura, mas não fica aberta para qualquer usuário: só pode executá-la quem tiver permissão para editar o post solicitado.

O contrato que vamos construir

Nossa ability se chamará wp24/get-post-summary e receberá:

{
  "post_id": 123
}

A resposta terá este formato:

{
  "id": 123,
  "title": "Título do post",
  "status": "publish",
  "post_type": "post",
  "url": "https://example.com/titulo-do-post/",
  "excerpt": "Resumo do conteúdo"
}

Esse contrato é importante para integrações e agentes. A ferramenta sabe que post_id é obrigatório e inteiro; também sabe exatamente quais propriedades encontrará no resultado.

Fluxo de uma Ability no WordPress: plugin, registro, validação, permissão e resposta ao agente de IA
Do registro no plugin à resposta estruturada consumida pelo agente de IA.

Estrutura mínima do plugin

Crie uma pasta chamada wp24-abilities-demo dentro de wp-content/plugins e adicione o arquivo wp24-abilities-demo.php:

<?php
/**
 * Plugin Name: WP24Horas Abilities Demo
 * Version: 0.2.0
 * Requires at least: 6.9
 * Requires PHP: 7.4
 */

defined( 'ABSPATH' ) || exit;

O requisito mínimo é WordPress 6.9 porque foi nessa versão que a Abilities API entrou no Core.

Registrando a categoria

Toda ability pertence a uma categoria. O registro deve acontecer no hook específico da API:

add_action( 'wp_abilities_api_categories_init', 'wp24_register_category' );

function wp24_register_category(): void {
	wp_register_ability_category(
		'wp24-site',
		array(
			'label'       => __( 'Informações do site', 'wp24-abilities-demo' ),
			'description' => __( 'Ações de consulta sobre o site WordPress.', 'wp24-abilities-demo' ),
		)
	);
}

O slug aceita letras minúsculas, números e hífens. A categoria ajuda clientes a filtrar e organizar as capacidades descobertas.

Definindo o schema de entrada

O input_schema usa a sintaxe de JSON Schema suportada pela REST API do WordPress:

'input_schema' => array(
	'type'                 => 'object',
	'additionalProperties' => false,
	'required'             => array( 'post_id' ),
	'properties'           => array(
		'post_id' => array(
			'type'        => 'integer',
			'minimum'     => 1,
			'description' => __( 'ID do post que será consultado.', 'wp24-abilities-demo' ),
		),
	),
),

Três decisões merecem atenção:

  • required impede a execução sem post_id;
  • minimum rejeita zero e números negativos;
  • additionalProperties: false rejeita parâmetros que não fazem parte do contrato.

O schema valida a forma dos dados. Ele não substitui autorização nem confirma que o post realmente existe.

Definindo o schema de saída

A resposta também deve ser validada:

'output_schema' => array(
	'type'                 => 'object',
	'additionalProperties' => false,
	'required'             => array( 'id', 'title', 'status', 'post_type', 'url', 'excerpt' ),
	'properties'           => array(
		'id'        => array( 'type' => 'integer' ),
		'title'     => array( 'type' => 'string' ),
		'status'    => array( 'type' => 'string' ),
		'post_type' => array( 'type' => 'string' ),
		'url'       => array( 'type' => 'string', 'format' => 'uri' ),
		'excerpt'   => array( 'type' => 'string' ),
	),
),

Validar a saída evita que uma alteração futura no callback quebre silenciosamente os consumidores da ability.

Permissão vinculada ao post

Uma checagem genérica como current_user_can( 'edit_posts' ) não é suficiente. Um autor pode editar posts próprios e não ter acesso aos posts de outra pessoa. Por isso, verificamos a permissão meta edit_post com o ID concreto:

function wp24_can_get_post_summary( $input ) {
	if ( ! is_array( $input ) || empty( $input['post_id'] ) ) {
		return new WP_Error(
			'wp24_missing_post_id',
			__( 'Informe um post_id válido.', 'wp24-abilities-demo' )
		);
	}

	$post_id = (int) $input['post_id'];

	if ( ! get_post( $post_id ) ) {
		return new WP_Error(
			'wp24_post_not_found',
			__( 'O post solicitado não existe.', 'wp24-abilities-demo' )
		);
	}

	return current_user_can( 'edit_post', $post_id );
}

A permission_callback recebe a mesma entrada do callback de execução. Ela pode retornar true, false ou um WP_Error com uma mensagem específica.

Implementando a execução

Depois da validação e da autorização, o callback pode montar a resposta:

function wp24_get_post_summary( array $input ) {
	$post = get_post( (int) $input['post_id'] );

	if ( ! $post ) {
		return new WP_Error(
			'wp24_post_not_found',
			__( 'O post solicitado não existe.', 'wp24-abilities-demo' )
		);
	}

	return array(
		'id'        => (int) $post->ID,
		'title'     => get_the_title( $post ),
		'status'    => get_post_status( $post ),
		'post_type' => get_post_type( $post ),
		'url'       => get_permalink( $post ),
		'excerpt'   => wp_strip_all_tags( get_the_excerpt( $post ) ),
	);
}

Mesmo com a verificação anterior, o callback trata a ausência do post. Essa defesa evita depender de estado que pode mudar entre autorização e execução.

Registrando a ability completa

Juntando os componentes:

add_action( 'wp_abilities_api_init', 'wp24_register_post_summary_ability' );

function wp24_register_post_summary_ability(): void {
	wp_register_ability(
		'wp24/get-post-summary',
		array(
			'label'               => __( 'Resumo de um post', 'wp24-abilities-demo' ),
			'description'         => __( 'Retorna um resumo estruturado de um post que o usuário autenticado pode editar.', 'wp24-abilities-demo' ),
			'category'            => 'wp24-site',
			'input_schema'        => array( /* schema de entrada */ ),
			'output_schema'       => array( /* schema de saída */ ),
			'execute_callback'    => 'wp24_get_post_summary',
			'permission_callback' => 'wp24_can_get_post_summary',
			'meta'                => array(
				'show_in_rest' => true,
				'annotations'  => array(
					'readonly'    => true,
					'destructive' => false,
					'idempotent'  => true,
				),
			),
		)
	);
}

As anotações informam a ferramentas que repetir a chamada não modifica o site. Elas são metadados semânticos; a segurança continua dependendo da autenticação e da permission_callback.

Testando em PHP

Com o plugin ativo e um usuário autenticado:

$ability = wp_get_ability( 'wp24/get-post-summary' );

$result = $ability->execute(
	array(
		'post_id' => 123,
	)
);

if ( is_wp_error( $result ) ) {
	error_log( $result->get_error_message() );
}

Teste pelo menos quatro casos:

  1. post existente e autorizado;
  2. post existente sem permissão;
  3. post_id inexistente;
  4. entrada inválida ou com campos extras.

Testando pela REST API

Use uma Application Password própria para a integração, não a senha principal da conta:

curl --user "USUARIO:SENHA_DE_APLICATIVO" \
  --request GET \
  --get \
  --data-urlencode 'input={"post_id":123}' \
  "https://example.com/wp-json/wp-abilities/v1/abilities/wp24/get-post-summary/run"

A requisição passa pelo mesmo pipeline: normalização, validação de entrada, permissão, execução e validação de saída.

Por que a permissão usa a entrada

Para abilities parametrizadas, autorização frequentemente depende do objeto. Alguns exemplos:

  • editar um post específico;
  • consultar um pedido concreto;
  • reembolsar uma compra determinada;
  • acessar dados de um membro;
  • alterar uma configuração de uma filial.

Verificar apenas uma capability genérica pode autorizar mais dados do que o necessário. Prefira as meta capabilities do WordPress sempre que a decisão depender de um objeto.

Checklist antes de expor pela REST

  1. recuse propriedades não documentadas;
  2. declare todos os campos obrigatórios;
  3. use limites como minimum, enum e maxLength quando fizer sentido;
  4. autorize o objeto, não apenas o tipo de ação;
  5. retorne somente os dados necessários;
  6. remova HTML quando o consumidor espera texto;
  7. use WP_Error para falhas previsíveis;
  8. marque corretamente efeitos colaterais;
  9. teste com usuários de papéis diferentes;
  10. revogue credenciais usadas apenas durante o desenvolvimento.

Próximo passo: auditoria e políticas no WordPress 7.1

Agora temos uma ability parametrizada com um contrato verificável e autorização por objeto. No próximo artigo, usaremos os filtros do WordPress 7.1 para adicionar auditoria e uma política adicional sem modificar o callback original.

Baixe o plugin de demonstração 0.2.0 e compare a nova ability com wp24/site-summary, criada no primeiro artigo da série.

Sobre o autor

Asllan Maciel

Asllan Maciel, Fundador do WP24Horas, Consultor de Marketing Digital e amante do Empreendedorismo Digital. Tem um caso de amor com o WordPress.