Funções e capacidades do WordPress: O guia técnico (2026)

Funções e capacidades do WordPress: O guia técnico (2026)

Última verificação: 13 de outubro de 2026
18 min de leitura
Guia
Desenvolvedor full-stack
Auditor de segurança

O WordPress traz uma lista de controlo de acesso completa e quase ninguém a usa. A falha de permissões que mais vemos em sites de clientes não é um plugin por atualizar, é um redator de conteúdos com a função de Administrador porque alguém precisou que ele reordenasse um menu uma vez. Este guia cobre o que a API de funções e capacidades faz realmente ao nível do código-fonte: onde vivem os dados, porque é que add_role() ignora em silêncio a sua segunda chamada, a que se resolve realmente uma verificação por nome de função e que capacidades são mais amplas do que o nome sugere.

Saiba mais sobre os serviços de segurança WordPress da WPPoland.

Uma única mudança faz quase todo o trabalho: deixe de nomear funções nas suas condições e nomeie a capacidade de que o código precisa. O resto deste guia é o que isso custa na prática, e é a base do trabalho de qualquer programador WordPress que leve a segurança a sério.

#1. Diferença entre função e capacidade no WordPress

O sistema de permissões do WordPress assenta em dois conceitos que convém separar antes de escrever qualquer lógica de controlo de acesso.

#Capacidade (cap)

Uma permissão específica para fazer uma coisa. As capacidades são as unidades atómicas do sistema. Exemplos: edit_posts, publish_pages, install_plugins, manage_options e edit_theme_options.

As capacidades podem ser primitivas (guardadas diretamente na linha das funções) ou meta capacidades (resolvidas em tempo de execução por map_meta_cap() consoante o contexto). Por exemplo, edit_post é uma meta capacidade que se resolve em edit_posts ou edit_others_posts consoante o utilizador seja ou não o autor do artigo.

#Função (role)

Uma coleção de capacidades agrupadas sob um nome. O WordPress guarda o conjunto e avalia a cadeia.

Os conjuntos predefinidos são mais pequenos do que se assume. Segundo a documentação de funções e capacidades, o Editor tem 26 capacidades e o Autor sete: read, upload_files, edit_posts, edit_published_posts, publish_posts, delete_posts, delete_published_posts. O Colaborador tem três: read, edit_posts, delete_posts. Um Colaborador não consegue carregar um ficheiro, e é por isso que “basta torná-lo Colaborador” acaba num pedido de suporte sobre a biblioteca multimédia.

O Editor é o caso interessante. Numa instalação de site único tem unfiltered_html, ou seja, um Editor pode guardar uma etiqueta <script> no conteúdo. Em multisite essa capacidade é negada a todos exceto aos super administradores, como mostra map_meta_cap():

if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML ) {
    $caps[] = 'do_not_allow';
} elseif ( is_multisite() && ! is_super_admin( $user_id ) ) {
    $caps[] = 'do_not_allow';
} else {
    $caps[] = 'unfiltered_html';
}

O que o Editor não tem: edit_theme_options, list_users, edit_users, manage_options nem nada relacionado com plugins.

#Verificar capacidades em vez de funções

Verifique capacidades, nunca nomes de funções.

// ERRADO - nunca faça isto
if ( current_user_can( 'administrator' ) ) { ... }

// CERTO - verifique sempre capacidades
if ( current_user_can( 'manage_options' ) ) { ... }

A primeira linha não é um erro de sintaxe, é algo pior: devolve a resposta certa exatamente no caso que testou. O motivo é uma fusão no fim de WP_User::get_role_caps():

$this->allcaps = array();
foreach ( (array) $this->roles as $role ) {
    $the_role      = $wp_roles->get_role( $role );
    $this->allcaps = array_merge( (array) $this->allcaps, (array) $the_role->capabilities );
}
$this->allcaps = array_merge( (array) $this->allcaps, (array) $this->caps );

$this->caps é o meta de utilizador wp_capabilities em bruto, e as suas chaves são nomes de funções. Por isso administrator => true aterra em allcaps ao lado de capacidades reais e passa a verificação por acidente. A documentação de current_user_can() diz isto mesmo: verificar funções concretas em vez de uma capacidade é suportado apenas em parte e desaconselhado, porque pode produzir resultados pouco fiáveis.

Três formas de isto correr mal, todas vistas em sites reais:

  1. Cria uma função personalizada com manage_options para que um cliente chegue à sua página de definições. current_user_can('administrator') é false para ele, e a sua própria página devolve 403 ao utilizador para quem foi feita.
  2. Uma capacidade concedida diretamente no objeto utilizador, sem função associada, passa qualquer verificação de capacidade e falha qualquer verificação de função.
  3. Em multisite, WP_User::has_cap() faz curto-circuito para super administradores antes de olhar para allcaps e devolve true para tudo o que não seja do_not_allow. Aí uma verificação de função não distingue nada.

#2. Como criar uma função personalizada no WordPress

Antes de escrever uma, verifique se a plataforma já a traz. O WooCommerce acrescenta shop_manager e customer ao ser instalado e, segundo a sua documentação de funções, o Gestor de loja já pode gerir produtos, encomendas, cupões e contas de clientes. Construir um “gestor de loja” paralelo duplica uma função que outra equipa mantém ao ritmo das suas versões.

Quando precisa mesmo de uma, esta é a forma:

add_role(
    'editorial_lead',
    'Responsável editorial',
    [
        'read'                 => true,
        'upload_files'         => true,
        'edit_posts'           => true,
        'edit_others_posts'    => true,
        'edit_published_posts' => true,
        'publish_posts'        => true,
        'delete_posts'         => true,
        'moderate_comments'    => true,
    ]
);

Há duas coisas nesta chamada que não se deduzem da assinatura.

Escreve uma vez e depois ignora-o. O manual de plugins indica que, após a primeira chamada, a função e as suas capacidades ficam guardadas na base de dados e que as chamadas seguintes não fazem nada, incluindo alterar a lista de capacidades. Edita o array, faz o deploy e nada muda. Cada alteração de capacidades precisa, por isso, de uma migração explícita:

const EDITORIAL_LEAD_VERSION = 3;

function wppoland_sync_editorial_lead() {
    if ( (int) get_option( 'wppoland_editorial_lead_version' ) === EDITORIAL_LEAD_VERSION ) {
        return;
    }

    remove_role( 'editorial_lead' );
    add_role( 'editorial_lead', 'Responsável editorial', [ /* ... */ ] );

    update_option( 'wppoland_editorial_lead_version', EDITORIAL_LEAD_VERSION );
}
register_activation_hook( __FILE__, 'wppoland_sync_editorial_lead' );
add_action( 'admin_init', 'wppoland_sync_editorial_lead' );

A cópia em admin_init importa em multisite e em deploys que nunca disparam um hook de ativação. A verificação de versão é o que mantém o código fora do caminho crítico, e o manual avisa que remover e voltar a criar a função sem condição degrada consideravelmente o desempenho.

remove_role() não toca nos utilizadores. Remove a chave da linha de opções. Cada utilizador cujo meta wp_capabilities continue a dizer editorial_lead => true mantém essa chave, WP_Roles::is_role() já devolve false para ela e, por isso, nunca se resolve em capacidades. O utilizador fica com uma cadeia que não concede nada. Reatribua os utilizadores antes de remover uma função, ou imediatamente depois.

Onde está realmente a linha. WP_Roles::for_site() constrói a chave como $wpdb->get_blog_prefix( $this->site_id ) . 'user_roles'. Num site único com o prefixo predefinido isso é wp_user_roles. No subsite 3 de uma rede é wp_3_user_roles, e é por isso que uma função acrescentada num subsite é invisível no seguinte. Se quiser as funções definidas em código e nunca escritas na base de dados, defina a global $wp_user_roles em wp-config.php: o WordPress passa a usá-la e, segundo a referência do core, a opção de funções deixa de ser atualizada e utilizada.

#Etiquetas de funções em sites multilingues

O segundo argumento de add_role() é a etiqueta visível, e WP_Roles::add_role() guarda-a na linha de opções tal como chega. Se a envolver em __(), o que fica guardado é a cadeia no idioma ativo no momento da ativação, e não no idioma de quem abre depois o ecrã de utilizadores. Ao mostrá-la, wp_dropdown_roles() passa a etiqueta por translate_user_role(), que traduz com o contexto User role e o domínio de texto default. Isso cobre as funções do core, cujas cadeias estão no catálogo do WordPress, e não cobre a etiqueta do seu plugin. Num site multilingue guarde o slug e a etiqueta em inglês, e não construa lógica sobre a etiqueta: o slug é o identificador estável.

#3. Como adicionar capacidades a uma função existente

get_role() mais add_cap() é a mudança mais pequena quando uma função predefinida quase serve:

$role = get_role( 'editor' );
if ( $role ) {
    $role->add_cap( 'edit_theme_options' );
}

Aplique a mesma verificação de versão da secção 2. WP_Role::add_cap() aceita exatamente dois parâmetros, add_cap( $cap, $grant = true ), e o segundo decide se a capacidade é concedida ou negada explicitamente, e não se a linha é escrita. Não há aqui um terceiro parâmetro. A forma com três argumentos pertence a WP_Roles::add_cap( $role, $cap, $grant ), outra classe, e é o método para o qual WP_Role::add_cap() delega. Esse método atribui a capacidade e chama update_option() sempre que use_db é true, em cada chamada. Nenhum argumento suprime a escrita, por isso executar add_cap() em init sem guarda significa uma tentativa de escrita de opção em cada pedido.

#Alcance de edit_theme_options em temas de blocos

O problema maior desta linha concreta é o alcance. edit_theme_options é a solução clássica para “o Editor gerir os menus” e, num tema clássico, faz mais ou menos isso: Aparência para widgets, menus, personalizador e cabeçalho. Num tema de blocos é outra capacidade. A documentação do core apresenta-a agora como a capacidade principal que o WordPress verifica para decidir se um utilizador pode aceder aos modelos e geri-los a partir do editor do site, e avisa que não se limita exclusivamente ao editor do site e pode dar acesso a outras funcionalidades administrativas relacionadas com o tema.

Ou seja, o Editor a quem queria deixar reordenar um menu tem agora o editor do site: modelos, partes de modelo, estilos globais e navegação. É uma concessão mais ampla do que switch_themes, que só expõe Aparência e Aparência > Temas.

Se o que quer é realmente uma função para o editor do site, a documentação lista o que é necessário: edit_theme_options para o acesso e o menu de navegação, mais edit_posts, edit_pages e edit_others_posts para gerir modelos, read para pré-visualizar e upload_files para multimédia.

O modo de falha aqui é silencioso, porque o editor do site fala com a API REST. Os endpoints de modelos e partes de modelo verificam edit_theme_options; os de artigos e páginas fazem as suas próprias verificações. Uma função que consegue abrir o editor do site mas não tem edit_others_posts recebe um painel que carrega e depois falha ao guardar. Leia o separador de rede à procura de respostas 401 e 403 antes de acrescentar capacidades às cegas: o código de erro REST nomeia a permissão que falhou.

#Capacidades condicionais com user_has_cap

Algumas regras não cabem numa função porque dependem do objeto: um Editor que não deve mexer nos artigos de uma categoria concreta, por exemplo. É para isso que existe o filtro user_has_cap. WP_User::has_cap() aplica-o depois de map_meta_cap(), com quatro argumentos: $allcaps (o que o utilizador tem), $caps (as primitivas que a verificação exige), $args (a capacidade pedida em $args[0], o ID do utilizador em $args[1] e, normalmente, o ID do objeto em $args[2]) e o objeto WP_User.

add_filter( 'user_has_cap', function ( $allcaps, $caps, $args, $user ) {
    if ( 'edit_post' !== ( $args[0] ?? '' ) || empty( $args[2] ) ) {
        return $allcaps;
    }
    if ( has_term( 'legal', 'category', $args[2] ) && empty( $allcaps['manage_options'] ) ) {
        foreach ( $caps as $cap ) {
            $allcaps[ $cap ] = false;
        }
    }
    return $allcaps;
}, 10, 4 );

Três detalhes do código-fonte decidem se isto funciona. O filtro só vê verificações que levam o ID do objeto, por isso current_user_can( 'edit_posts' ) passa por ele sem que a regra atue. Corre em cada verificação de capacidades, de modo que a saída antecipada da primeira linha não é opcional. E em multisite não chega aos super administradores: has_cap() devolve-lhes true antes de aplicar o filtro, como se vê na secção 6.

#4. Como repor as funções do WordPress

A versão deste script que circula é uma escalada de privilégios remota:

// Não implemente isto em produção.
function wppoland_reset_roles() {
    if ( ! isset( $_GET['reset_roles_secret_key'] ) ) return;

    require_once( ABSPATH . 'wp-admin/includes/schema.php' );
    populate_roles();
}
add_action( 'init', 'wppoland_reset_roles' );

isset() verifica que o parâmetro está presente, não que está correto. Qualquer visitante não autenticado que acrescente ?reset_roles_secret_key a qualquer URL do site restaura as capacidades predefinidas, o que inclui devolver tudo o que tivesse retirado de propósito ao Editor ou ao Autor.

#Como repor funções com wp role reset

O wp role reset corre sobre a mesma função do core e está autenticado pelo acesso à shell:

wp role reset --all
wp role reset editor

Faz também mais do que populate_roles() por si só, e a diferença importa ao depurar. populate_roles() chama populate_roles_160() até populate_roles_300(), e essas funções só chamam add_role() e add_cap(). Não há nelas nenhum remove_cap(). Chamada diretamente, restaura as capacidades removidas e deixa todas as que um plugin tenha acrescentado. O WP-CLI compara ainda com uma instalação limpa, e é por isso que a sua saída se lê assim:

Restored 1 capability to and removed 0 capabilities from 'administrator' role.

As funções personalizadas ficam intactas por qualquer uma das duas vias. Se o problema do site é uma função personalizada mal feita, uma reposição não o resolve.

#Como inspecionar as funções com WP-CLI antes de as repor

O estado que está a depurar é uma linha de opções:

wp option get wp_user_roles --format=json | jq '.editor.capabilities'
wp cap list editor
wp user list --field=user_login --role=administrator

O último é o comando que vale a pena correr em qualquer site que herde. Um número de administradores que o surpreenda é a descoberta.

#5. Como proteger as funções do WordPress

#A. Como rever as contas de administrador no WordPress

O privilégio mínimo não é uma função nova, é uma lista de administradores mais curta. Execute wp user list --role=administrator nos sites que mantém. Contas de agência, um freelancer que saiu e o acesso de suporte de um plugin de há dois anos são os residentes habituais.

Quanto ao conselho clássico de não chamar ‘admin’ ao utilizador: o instalador pede o nome de utilizador desde o WordPress 3.0, por isso a lacuna que resta é a enumeração. O endpoint REST de utilizadores devolve id, name, url, description, link, slug e avatar_urls sem autenticação. roles e capabilities estão no contexto edit e não são expostos, mas slug é o user_nicename, que o WordPress deriva do login a não ser que alguém o altere. Isso é uma lista de nomes de utilizador, não uma brecha, e limitar a taxa de pedidos do formulário de login é o controlo que mais pesa.

#B. Como desativar a edição de ficheiros com DISALLOW_FILE_EDIT

Retirar edit_themes ao Administrador é uma alteração de capacidade que alguém pode desfazer. Uma constante em wp-config.php é verificada dentro de map_meta_cap() e não pode ser sobreposta por uma concessão:

define( 'DISALLOW_FILE_EDIT', true );

DISALLOW_FILE_EDIT mapeia edit_files, edit_plugins e edit_themes para do_not_allow. DISALLOW_FILE_MODS vai mais longe e bloqueia a instalação e atualização de plugins e temas a partir do painel, e desativa o editor de ficheiros como efeito secundário. Num site implementado a partir do Git, DISALLOW_FILE_MODS é a definição honesta, porque as atualizações chegam pelo pipeline de deploy.

DISALLOW_UNFILTERED_HTML funciona da mesma forma e vale a pena em qualquer site editorial onde os Editores não precisem de colar etiquetas de script.

#C. Como mapear meta capacidades em tipos de conteúdo personalizados

register_post_type() define map_meta_cap como null por omissão, não como false. WP_Post_Type::set_props() converte esse null em true quando capabilities está vazio e capability_type é post ou page, por compatibilidade com o comportamento da versão 3.0 (ticket do core #14122), e passa a false em qualquer outro caso. Um capability_type próprio como o de baixo fica, por isso, em false, a não ser que o indique. Defina ambos os argumentos:

register_post_type( 'book', [
    'capability_type' => [ 'book', 'books' ],
    'map_meta_cap'    => true,
] );

A forma de array não é decoração. Com uma cadeia simples, o WordPress acrescenta um s para construir o plural, o que dá storys para story. A referência de register_post_type() indica o array como a forma de passar um plural alternativo.

capability_type => 'book' gera as meta capacidades edit_book, read_book, delete_book e as primitivas edit_books, edit_others_books, delete_books, publish_books, read_private_books. Outras seis, read, delete_private_books, delete_published_books, delete_others_books, edit_private_books e edit_published_books, só são geradas quando map_meta_cap é true, porque só map_meta_cap() as consome. É essa a razão de ser da flag. Sem ela, map_meta_cap() resolve a meta capacidade edit_book na própria cadeia edit_book, sem olhar para quem é o autor nem para se o livro está publicado, por isso quem tiver essa capacidade edita os livros de qualquer pessoa.

Outro valor predefinido a vigiar: create_posts é mapeado para edit_books, a não ser que o defina. Se quiser uma função que edite livros existentes mas nunca crie nenhum, tem de o indicar no array capabilities.

#D. Onde verificar current_user_can em handlers e rotas REST

A verificação fica junto à operação, não no menu. add_menu_page() recebe uma capacidade e com ela esconde uma ligação, mas não protege o handler. Cada handler de admin-post, cada callback AJAX e cada rota REST precisa do seu próprio current_user_can(), e as rotas REST precisam dele em permission_callback e não dentro do handler. Desde o WordPress 5.5, register_rest_route() regista um aviso _doing_it_wrong() quando falta permission_callback, e para uma rota verdadeiramente pública o valor documentado é __return_true.

Para tudo o que atue sobre um objeto concreto, passe o objeto: current_user_can( 'edit_post', $post_id ) passa por map_meta_cap() e resolve a autoria. current_user_can( 'edit_posts' ) não o faz, e responde a uma pergunta sobre o tipo de conteúdo em vez de sobre esse artigo.

#E. Auditoria de acessos e separação de ambientes

Um registo de auditoria que acompanhe inícios de sessão, alterações de funções e ações sensíveis diz-lhe quem concedeu o quê e quando. Plugins como o WP Activity Log cobrem essa função, e também a pode implementar com os hooks do WordPress.

As funções em desenvolvimento, staging e produção reveem-se em separado. Uma função razoável em desenvolvimento, com permissões extra para depurar, pode ser perigosa em produção.

#6. Capacidades do WordPress em multisite e plugins

#Capacidades de rede em Multisite

Em instalações WordPress Multisite as capacidades funcionam a dois níveis: site individual e rede. Segundo a documentação de funções e capacidades, estas dez existem apenas para o super administrador: create_sites, delete_sites, manage_network, manage_sites, manage_network_users, manage_network_plugins, manage_network_themes, manage_network_options, upgrade_network e setup_network.

A parte que surpreende vai no sentido contrário. O Administrador de um subsite perde capacidades que tem num site único. A mesma documentação lista update_core, update_plugins, update_themes, install_plugins, install_themes, delete_themes, delete_plugins, edit_plugins, edit_themes, edit_files, edit_users, add_users, create_users, delete_users e unfiltered_html como capacidades que em multisite só o super administrador tem. Não são retiradas da linha da função: map_meta_cap() converte-as em do_not_allow com a condição is_multisite() && ! is_super_admin( $user_id ), a mesma que viu na secção 1 para unfiltered_html. É por isso que acrescentar install_plugins à função Administrador de um subsite não muda nada.

WP_User::has_cap() trata o super administrador antes de consultar allcaps e antes de aplicar o filtro user_has_cap: se o resultado de map_meta_cap() não contiver do_not_allow, devolve true. Para retirar algo a um super administrador é preciso filtrar map_meta_cap e acrescentar do_not_allow, e não user_has_cap.

Para verificar uma permissão noutro site da rede, o WordPress 6.7 introduziu current_user_can_for_site( $site_id, $capability ), que substitui current_user_can_for_blog(), agora em deprecated.php. O manual de plugins ainda mostra o nome antigo.

#Capacidades do WooCommerce, BuddyPress e bbPress

Plugins como o WooCommerce, o BuddyPress e o bbPress acrescentam as suas próprias capacidades ao sistema. Ao planear a arquitetura de funções para um site que usa estes plugins, tem de considerar tanto as capacidades nativas do WordPress como as acrescentadas pelos plugins.

#Members e User Role Editor para gerir funções

Os plugins Members e User Role Editor oferecem interfaces gráficas para gerir funções e capacidades. Ainda assim, em desenvolvimento profissional é preferível gerir as funções através de código versionado, para que as alterações de permissões passem pela mesma revisão que qualquer outra alteração.

#Resumo

As funções são armazenamento. As capacidades são a decisão. Tudo o que está acima decorre dessa separação:

  • Verifique capacidades, nunca nomes de funções: current_user_can('administrator') resolve-se por uma fusão de chaves do meta de utilizador e devolve false para cada função personalizada que criar.
  • Trate add_role() e add_cap() como migrações sobre uma linha da base de dados, com verificação de versão, e não como configuração que edita e volta a implementar.
  • Leia o alcance real de uma capacidade antes de a conceder. edit_theme_options significa o editor do site num tema de blocos, não só o ecrã de menus.
  • Recupere com wp role reset --all, nunca com um parâmetro de consulta não autenticado, e lembre-se de que deixa as funções personalizadas intactas.
  • Defina map_meta_cap => true em cada tipo de conteúdo personalizado que tenha mais de um autor.

Veja também os nossos serviços de manutenção WordPress para manter o seu site seguro e otimizado.

Próximo passo

Transforme o artigo numa implementação real

Este bloco reforça a ligação interna e conduz o leitor para o passo seguinte mais útil dentro da arquitetura do site.

Perguntas frequentes

Respostas práticas para aplicar o tema na execução real.

Qual é a diferença entre uma função e uma capacidade no WordPress?#
Uma capacidade é uma única cadeia de permissão, como edit_posts ou manage_options. Uma função é um conjunto com nome dessas cadeias, guardado na tabela de opções. O WordPress verifica capacidades no ponto de decisão, por isso a função só importa como o contentor que entrega a capacidade.
Devem verificar-se as funções de utilizador diretamente no código WordPress?#
Não. current_user_can('administrator') funciona por acaso, porque WP_User::get_role_caps() funde o array caps do utilizador, onde os nomes das funções estão como chaves, em allcaps. Continua a devolver false para uma função personalizada que tenha manage_options, por isso a verificação deixa de fora precisamente o utilizador para quem a função foi criada.
Como se repõem funções danificadas no WordPress?#
Execute wp role reset --all com o WP-CLI. Chama populate_roles() e depois compara o resultado, por isso restaura as capacidades predefinidas removidas e retira as acrescentadas. Chamar populate_roles() por conta própria só devolve o que falta, porque as funções populate_roles_* nunca chamam remove_cap().
Porque é que add_role() ignora a minha nova capacidade?#
add_role() escreve na base de dados uma única vez. O manual de plugins diz explicitamente que as chamadas seguintes não fazem nada, incluindo alterar a lista de capacidades. Guarde um número de versão numa opção, compare-o na ativação e chame remove_role() e depois add_role() quando mudar.
Que capacidade controla o editor do site num tema de blocos?#
edit_theme_options é a principal. O WordPress verifica-a nos endpoints REST de modelos e partes de modelo. O uso completo do editor do site costuma precisar também de edit_posts, edit_pages, edit_others_posts, read e upload_files.

Precisa de FAQ adaptado ao setor e mercado? Crio uma versão alinhada com os seus objetivos de negócio.

Fale connosco

Artigos Relacionados