3 abordagens para adicionar campos configuráveis ​​ao seu plugin WordPress

Publicados: 2022-03-10
Resumo rápido ↬ Quem criou um plugin WordPress entende a necessidade de criar campos configuráveis ​​para modificar o funcionamento do plugin. Existem inúmeros usos para opções configuráveis ​​em um plugin e quase tantas maneiras de implementar essas opções. Veja bem, o WordPress permite que os autores de plugins criem sua própria marcação em suas páginas de configurações. Como efeito colateral, as páginas de configurações podem variar muito entre os plugins. Neste artigo, abordaremos três maneiras comuns de tornar seu plug-in configurável. Começaremos criando uma página de configurações e criando nossos campos usando a API de configurações padrão do WordPress. Em seguida, mostrarei como configurar seus campos com um manipulador personalizado. Por fim, mostrarei como integrar um ótimo plug-in de campos configuráveis ​​Advanced Custom Fields (ACF) em seu próprio plug-in.

Qualquer pessoa que tenha criado um plugin WordPress entende a necessidade de criar campos configuráveis ​​para modificar o funcionamento do plugin. Existem inúmeros usos para opções configuráveis ​​em um plugin e quase tantas maneiras de implementar essas opções. Veja bem, o WordPress permite que os autores de plugins criem sua própria marcação em suas páginas de configurações. Como efeito colateral, as páginas de configurações podem variar muito entre os plugins.

Neste artigo, abordaremos três maneiras comuns de tornar seu plug-in configurável. Começaremos criando uma página de configurações e criando nossos campos usando a API de configurações padrão do WordPress.

Leitura adicional no SmashingMag:

  • Estenda o WordPress com campos personalizados
  • Hacks de campos personalizados para WordPress
  • Estendendo campos personalizados avançados com seus próprios controles
  • O guia completo para tipos de postagem personalizados

Em seguida, mostrarei como configurar seus campos com um manipulador personalizado. Por fim, mostrarei como integrar um ótimo plug-in de campos configuráveis ​​Advanced Custom Fields (ACF) em seu próprio plug-in.

Mais depois do salto! Continue lendo abaixo ↓

Como este é um post longo, aqui está um índice com links para cada uma das principais seções:

  • Criando nossa página de plugins e configurações
  • Abordagem 1: Usando a funcionalidade interna do WordPress
  • Abordagem 2: configurando um formulário e um manipulador personalizados
  • Abordagem 3: Integrando ACF (Advanced Custom Fields) em seu plug-in

Para exemplos de código, consulte o repositório que configurei para acompanhar este post.

Criando nossa página de plugins e configurações

A primeira coisa que precisamos fazer é configurar nosso plugin e criar uma página de configurações. Todas as três abordagens descritas neste artigo começam com a estrutura do plugin abaixo. Essa estrutura de plug-in é orientada a objetos, portanto, pode haver algumas diferenças em seu próprio código se seu plug-in for escrito de forma procedural. Preste atenção especial ao formato da função de retorno de chamada nas ações e filtros.

 /* Plugin Name: Smashing Fields Plugin description: >- Setting up configurable fields for our plugin. Author: Matthew Ray Version: 1.0.0 */ class Smashing_Fields_Plugin { // Our code will go here } new Smashing_Fields_Plugin();

Dentro da nossa classe vamos adicionar um gancho de ação para adicionar a página de configurações:

 public function __construct() { // Hook into the admin menu add_action( 'admin_menu', array( $this, 'create_plugin_settings_page' ) ); }

Você pode ver que o callback da nossa ação é create_plugin_settings_page , então vamos criar esse método. Nota: Eu configurei os argumentos como variáveis ​​nomeadas separadas para dar algum contexto ao nosso código, mas você pode simplesmente colocar os valores diretamente na função para economizar memória.

 public function create_plugin_settings_page() { // Add the menu item and page $page_title = 'My Awesome Settings Page'; $menu_title = 'Awesome Plugin'; $capability = 'manage_options'; $slug = 'smashing_fields'; $callback = array( $this, 'plugin_settings_page_content' ); $icon = 'dashicons-admin-plugins'; $position = 100; add_menu_page( $page_title, $menu_title, $capability, $slug, $callback, $icon, $position ); }

Dê uma olhada no códice WP para add_menu_page para mais informações.

Esta função criará nossa página, bem como o item de menu. As partes importantes aqui são os argumentos de slug, capacidade e retorno de chamada. O slug que usaremos mais tarde para registrar nossos campos, então escreva isso em algum lugar. Você pode alterar a capacidade de permitir que diferentes níveis de usuário acessem sua página de configurações. Quanto ao retorno de chamada, criaremos esse método em breve. Observe que você também pode colocar uma classe de traço diretamente na função para alterar o ícone do menu. O último argumento é a posição do item de menu dentro do menu; brinque com este número para encontrar o local no menu que você gostaria que suas configurações caíssem. Nota: você pode usar valores decimais para evitar conflitos com outros itens de menu.

Nosso próximo passo é criar o método de retorno de chamada plugin_settings_page_content para nossa página de configurações.

 public function plugin_settings_page_content() { echo 'Hello World!'; }

Se você salvar seu plugin e atualizar o painel de administração do WordPress, deverá ver o seguinte:

Layout inicial para a página de configurações
O estado inicial da página de configurações. (Ver versão grande)

Você pode ver que sua página de configurações é um item de menu de nível superior. Você pode preferir deixar assim com base nas necessidades da sua página de configurações. No entanto, você também pode querer ter suas configurações de plug-in em outro item de menu. Nesse caso, você simplesmente alterará a última linha do método create_plugin_settings_page para o seguinte:

 add_submenu_page( 'options-general.php', $page_title, $menu_title, $capability, $slug, $callback );

Aqui estamos alterando a função add_menu_page para add_submenu_page e anexando um novo argumento. Esse argumento é o item de menu pai no qual a nova página de configurações estará. Na documentação add_submenu_page você pode ver uma lista muito boa para os itens do menu pai e seus slugs. Você também pode ver que não temos mais os dois últimos argumentos, $icon e $position . Como estamos agora na seção do submenu, não temos mais controle sobre a posição do elemento. Além disso, os submenus não têm ícones disponíveis para eles, portanto, não há necessidade desse argumento.

Se você salvar este novo código, verá que nossa página de configurações será exibida no item de menu Configurações:

A página do submenu está agora em configurações
A página de configurações agora foi colocada no menu Configurações. (Ver versão grande)

Em muitos casos, o local mais apropriado para adicionar uma página de configurações do plug-in é no item Configurações. No codex do WordPress, explica que a seção Configurações é usada para “Exibir opções de plug-in que apenas administradores devem visualizar”. No entanto, isso é apenas uma orientação, não uma regra.

Agora que temos nossa página de configurações configurada e sabemos como mover os itens, podemos começar a trabalhar nos campos. O trabalho que fizemos até agora será reutilizado para os vários métodos abaixo.

Abordagem 1: Usando a funcionalidade interna do WordPress

Antes de nos aprofundarmos muito no código, vamos analisar alguns dos prós e contras de usar essa abordagem.

Prós

  • Fácil de integrar em páginas de configurações existentes
  • A higienização é feita para você
  • É improvável que quebre, pois o código é gerenciado pelo WordPress
  • Pode ser usado para temas e plugins
  • Flexível, seguro e extensível

Contras

  • A validação de dados personalizados é manual
  • Tipos de campo avançados (repetidores, mapas, uploads, etc.) são mais difíceis de implementar

Quando você deve usar essa abordagem?

Essa abordagem é flexível o suficiente para que possa ser personalizada para páginas de configurações muito simples ou muito avançadas. Você pode usar esse método na maioria das situações se não se importar em fazer algumas coisas manualmente.

Começando

Usando essa abordagem, precisaremos seguir a mesma marcação que as próprias páginas de opções do WordPress usam. Devemos modificar nosso método plugin_settings_page_content para o seguinte:

 public function plugin_settings_page_content() { ?> <div class="wrap"> <h2>My Awesome Settings Page</h2> <form method="post" action="options.php"> <?php settings_fields( 'smashing_fields' ); do_settings_sections( 'smashing_fields' ); submit_button(); ?> </form> </div> <?php }

A marcação acima é diretamente do codex do WordPress na criação de páginas de opções. O nome do método deve corresponder ao nome do retorno de chamada que colocamos na função add_menu_page acima. A div do wrapper é, na verdade, a mesma que um formulário padrão do WordPress e extrairá os estilos dessas seções. A tag de form está apontando para o manipulador de formulário de opções padrão do WordPress.

As três linhas do PHP fazem várias coisas:

  • A função settings_fields é basicamente uma referência para o resto dos nossos campos. O argumento de string que você coloca nessa função deve corresponder à variável $slug que configuramos anteriormente – ela estará em todos os campos que registrarmos posteriormente no plugin. Essa função também gera algumas entradas ocultas para o nonce, ação de formulário e alguns outros campos para a página de opções.
  • A próxima função, do_settings_sections , é um espaço reservado para as seções e campos que registraremos em outro lugar em nosso plugin.
  • A última função, submit_button , produzirá a entrada de envio, mas também adicionará algumas classes com base no status da página. Pode haver outros argumentos que você queira passar para a função submit_button ; eles são descritos no códice.

Se atualizarmos nossa página de configurações, devemos obter algo parecido com isto:

Página de configurações do WordPress em branco
Nossa página de configurações antes de registrar seções e campos.

Está parecendo um pouco escasso! Vamos começar a configurar os campos agora.

Seções e campos

O WordPress separa suas páginas de opções em seções. Cada seção pode ter uma lista de campos associados a ela. Precisamos registrar uma seção em nosso plugin antes de começarmos a adicionar nossos campos. Adicione o seguinte código à sua função construtora:

 add_action( 'admin_init', array( $this, 'setup_sections' ) );

Este gancho irá configurar as seções para nossa página. Aqui está o código para o retorno de chamada:

 public function setup_sections() { add_settings_section( 'our_first_section', 'My First Section Title', false, 'smashing_fields' ); }

O primeiro argumento é um identificador exclusivo para a seção e usaremos isso para os campos que desejamos atribuir à seção. Esses identificadores devem ser exclusivos para todas as novas seções desta página. O próximo argumento é o título gerado acima da seção – você pode fazer o que quiser. O terceiro argumento é o retorno de chamada. No momento, eu o configurei como false , mas revisitaremos isso em breve. O quarto argumento é a página de opções à qual as opções serão adicionadas (a variável $slug anterior).

Então, por que há um false em nosso retorno de chamada? Bem, algo que não fica muito claro ao configurar as opções do WordPress usando sua documentação é que várias seções podem compartilhar um retorno de chamada. Muitas vezes, quando você configura um retorno de chamada, há uma relação de 1 para 1 entre o gancho e o retorno de chamada. Então, apenas como exemplo, vamos tentar criar três seções com o mesmo retorno de chamada:

 public function setup_sections() { add_settings_section( 'our_first_section', 'My First Section Title', array( $this, 'section_callback' ), 'smashing_fields' ); add_settings_section( 'our_second_section', 'My Second Section Title', array( $this, 'section_callback' ), 'smashing_fields' ); add_settings_section( 'our_third_section', 'My Third Section Title', array( $this, 'section_callback' ), 'smashing_fields' ); }

Todas essas três seções têm o callback section_callback definido nesse terceiro slot de argumento. Se criarmos um método que corresponda a esse retorno de chamada e soltarmos um “Hello World” lá:

 public function section_callback( $arguments ) { echo '

Olá Mundo

'; }

obtemos algo parecido com isso:

Três seções compartilhando a mesma função de retorno de chamada
Três seções compartilhando o mesmo retorno de chamada.

Eu sei o que você está pensando: "Por que diabos eu iria querer ter o mesmo texto em todas as minhas seções?" A resposta é que você provavelmente não faria. É aqui que podemos ficar um pouco complicados com a função add_settings_section . Se você observar a documentação dessa função, verá que na parte Notas da página a função de retorno de chamada receberá uma matriz de argumentos que se correlacionam diretamente com os argumentos em nosso gancho. Se você entrar e var_dump( $arguments ) , verá todos os argumentos sendo passados ​​para nossa função.

Podemos então escrever um switch simples em nosso retorno de chamada para alterar o texto com base no ID que é passado para ele:

 public function section_callback( $arguments ) { switch( $arguments['id'] ){ case 'our_first_section': echo 'This is the first description here!'; break; case 'our_second_section': echo 'This one is number two'; break; case 'our_third_section': echo 'Third time is the charm!'; break; } }

Agora temos texto personalizado para cada seção que podemos alterar em uma função!

Texto personalizado em cada seção
Texto personalizado em cada seção.

Claro, você também pode especificar retornos de chamada exclusivos para essas seções, mas essa abordagem permite que você consolide seu código em uma única função. Essa ideia funciona da mesma forma para configurar campos. Podemos fazer com que todos os nossos campos compartilhem um retorno de chamada e produza o tipo de campo correto com base nos argumentos que passamos. Vamos adicionar os campos ao nosso método construtor. Coloque este código logo após o gancho de nossas seções no construtor:

 add_action( 'admin_init', array( $this, 'setup_fields' ) );

Como você já conhece o exercício, vou apenas dar o retorno de chamada para nossa ação:

 public function setup_fields() { add_settings_field( 'our_first_field', 'Field Name', array( $this, 'field_callback' ), 'smashing_fields', 'our_first_section' ); }

Os argumentos nesta função são semelhantes aos da função de seções. O primeiro argumento é o identificador exclusivo do campo. O segundo é o rótulo que aparece ao lado do campo. No terceiro argumento você pode ver que estou chamando o método field_callback ; vamos criar esse retorno de chamada em apenas um segundo. A quarta é a página de opções que queremos usar (nosso $slug de antes). O quinto argumento é o identificador exclusivo da seção à qual queremos atribuir esse campo.

Aqui está o código para o retorno de chamada em nosso terceiro argumento:

 public function field_callback( $arguments ) { echo '<input name="our_first_field" type="text" value="' . get_option( 'our_first_field' ) . '" />'; }

Aqui estou simplesmente copiando o identificador exclusivo do campo para o nome, ID e nossa função get_option . Vamos ver como nossa página fica com nosso novo campo anexado:

Nossa página de configurações com nosso primeiro campo.
A página de configuração com nosso primeiro campo anexado.

Incrível, temos nosso campo na página! Tente adicionar algum conteúdo a ele e clicar em salvar alterações, vou esperar aqui…

Você fez isso? Se você fez tudo certo até este ponto, deve ter recebido um erro dizendo algo como ERROR: options page not found ou similar. A razão pela qual isso acontece é na verdade um recurso de segurança no WordPress.

Você vê, sem esse recurso, um usuário poderia entrar no HTML e alterar o nome de um campo para qualquer coisa que quisesse, clicar em salvar e inseriria essa opção no banco de dados com qualquer nome que fosse dado (assumindo que era um válido nome da opção). Isso pode permitir que qualquer usuário altere as opções em outras páginas (mesmo aquelas que normalmente não podem acessar) simplesmente digitando o nome correto no campo e clicando em salvar – não é legal.

Este problema é resolvido adicionando uma função chamada register_setting . A menos que você diga especificamente ao WordPress, “Ei, este campo pode ser salvo nesta página”, o WordPress não atualizará um campo no banco de dados. Então, abaixo de nossa marcação de campo, adicionaremos essa nova função. Aqui está a aparência do retorno de chamada depois que adicionamos o código:

 public function field_callback( $arguments ) { echo '<input name="our_first_field" type="text" value="' . get_option( 'our_first_field' ) . '" />'; register_setting( 'smashing_fields', 'our_first_field' ); }

O primeiro argumento na nova função é a página de opções em que queremos salvar o campo (o $slug anterior) e o segundo argumento é o campo que queremos salvar. Agora tente atualizar o campo – funcionou!

Parabéns! Você acabou de salvar seu primeiro campo usando a API de configurações do WordPress. Agora, e se quisermos ter alguns tipos de campo diferentes em vez de apenas texto? Vamos revisitar nosso retorno de chamada de campo e falar sobre essa variável $arguments sendo passada para nossa função.

Argumentos de campo

Se entrarmos em nosso campo de retorno de chamada e var_dump( $arguments ) , obteremos um array vazio. O que da? Em nosso retorno de chamada da seção, temos um monte de coisas sobre a seção. Bem, há algo diferente acontecendo aqui. Se você verificar a documentação de add_settings_field , há um quinto argumento que pode ser passado para a função. Essa variável se correlaciona diretamente com a variável $arguments em nosso retorno de chamada. Então, vamos querer colocar nossas coisas novas lá.

Se olharmos para um dos campos padrão em uma página de configurações do WordPress, podemos ver que existem várias áreas que podemos adicionar ao nosso campo para obter alguma formatação padrão. Aqui está uma captura de tela do campo de fuso horário na página de configurações gerais:

O campo de fuso horário do WordPress
O campo de fuso horário do WordPress. (Ver versão grande)

Usando este campo como ponto de partida, vamos examinar os dados que queremos passar para nosso retorno de chamada de campo.

  • O identificador exclusivo
  • O rótulo do campo (Fuso horário no exemplo)
  • Em que seção deve entrar
  • O tipo de campo (texto, textarea, select, etc.)
  • No caso de haver várias opções, vamos querer aquelas
  • Talvez um espaço reservado se o tipo de campo suportar um
  • Texto auxiliar (à direita do campo no exemplo)
  • Texto suplementar (abaixo do campo no exemplo)
  • Talvez uma seleção padrão, se houver uma

A partir desta lista, podemos configurar uma matriz associativa de campos e valores que podemos passar para nosso retorno de chamada:

 public function setup_fields() { $fields = array( array( 'uid' => 'our_first_field', 'label' => 'Awesome Date', 'section' => 'our_first_section', 'type' => 'text', 'options' => false, 'placeholder' => 'DD/MM/YYYY', 'helper' => 'Does this help?', 'supplemental' => 'I am underneath!', 'default' => '01/01/2015' ) ); foreach( $fields as $field ){ add_settings_field( $field['uid'], $field['label'], array( $this, 'field_callback' ), 'smashing_fields', $field['section'], $field ); register_setting( 'smashing_fields', $field['uid'] ); } }

Então, a primeira coisa que temos aqui é uma variável chamada $fields que conterá todos os campos que queremos criar. Dentro desse array temos outro array que contém os dados específicos de cada campo. Configurei os dados para corresponder exatamente à nossa lista acima. Em seguida, percorro cada campo (adicionaremos mais em breve) na matriz, adiciono o campo e o registro. No final da função add_settings_field também estou adicionando toda a matriz de dados para esse campo específico para que possamos fazer algumas coisas na função de retorno de chamada. Vamos dar uma olhada nessa função de retorno de chamada aqui:

 public function field_callback( $arguments ) { $value = get_option( $arguments['uid'] ); // Get the current value, if there is one if( ! $value ) { // If no value exists $value = $arguments['default']; // Set to our default } // Check which type of field we want switch( $arguments['type'] ){ case 'text': // If it is a text field printf( '<input name="%1$s" type="%2$s" placeholder="%3$s" value="%4$s" />', $arguments['uid'], $arguments['type'], $arguments['placeholder'], $value ); break; } // If there is help text if( $helper = $arguments['helper'] ){ printf( '<span class="helper"> %s</span>', $helper ); // Show it } // If there is supplemental text if( $supplimental = $arguments['supplemental'] ){ printf( '<p class="description">%s</p>', $supplimental ); // Show it } }

No exemplo acima, estamos fazendo várias coisas. Estamos definindo os valores padrão para campos se estiverem vazios e adicionando o auxiliar e o texto suplementar. A parte mais importante em nosso código, porém, é a instrução switch. Nesta declaração vamos descrever como nossos argumentos serão tratados com base no tipo de campo que queremos.

Por exemplo, se temos um campo de texto, não precisamos ter várias opções. No entanto, uma lista suspensa <select> deve ter opções para funcionar corretamente. Como já temos os tipos de texto configurados, vamos executar este código e ver o que obtemos.

Nosso campo preenchido incluindo placeholder
Nosso campo preenchido incluindo texto de espaço reservado. (Ver versão grande)

Ao carregar a página de configurações do plug-in, você deverá ver o campo superior nesta imagem. A parte inferior é o que você verá se remover o conteúdo do campo (ou seja, o espaço reservado). Se eu remover os argumentos helper ou supplimental de nossa matriz de campos, eles devem desaparecer na página de configurações. Também podemos alterar o argumento da section e mover o posicionamento do campo nas seções.

OK, então temos campos de texto; que tal alguns tipos de campo mais complexos? Vamos dar outra olhada em nossa instrução switch e adicionar a opção para áreas de texto e seleções simples:

 switch( $arguments['type'] ){ case 'text': // If it is a text field printf( '<input name="%1$s" type="%2$s" placeholder="%3$s" value="%4$s" />', $arguments['uid'], $arguments['type'], $arguments['placeholder'], $value ); break; case 'textarea': // If it is a textarea printf( '<textarea name="%1$s" placeholder="%2$s" rows="5" cols="50">%3$s</textarea>', $arguments['uid'], $arguments['placeholder'], $value ); break; case 'select': // If it is a select dropdown if( ! empty ( $arguments['options'] ) && is_array( $arguments['options'] ) ){ $options_markup = '; foreach( $arguments['options'] as $key => $label ){ $options_markup .= sprintf( '<option value="%s" %s>%s</option>', $key, selected( $value, $key, false ), $label ); } printf( '<select name="%1$s">%2$s</select>', $arguments['uid'], $options_markup ); } break; }

No código acima, você notará várias diferenças entre cada um dos tipos de campo. Embora as áreas de texto sejam funcionalmente semelhantes aos campos de texto normais, elas exigem marcação diferente. As listas suspensas selecionadas são um animal totalmente diferente por causa das opções. Precisamos percorrer as opções e definir valores, estados selecionados e rótulos. Portanto, nossa marcação é drasticamente diferente.

Agora que atualizamos nossa função de retorno de chamada, vamos ver como os dados do campo foram alterados:

 $fields = array( array( 'uid' => 'our_first_field', 'label' => 'Awesome Date', 'section' => 'our_first_section', 'type' => 'text', 'options' => false, 'placeholder' => 'DD/MM/YYYY', 'helper' => 'Does this help?', 'supplemental' => 'I am underneath!', 'default' => '01/01/2015' ), array( 'uid' => 'our_second_field', 'label' => 'Awesome Date', 'section' => 'our_first_section', 'type' => 'textarea', 'options' => false, 'placeholder' => 'DD/MM/YYYY', 'helper' => 'Does this help?', 'supplemental' => 'I am underneath!', 'default' => '01/01/2015' ), array( 'uid' => 'our_third_field', 'label' => 'Awesome Select', 'section' => 'our_first_section', 'type' => 'select', 'options' => array( 'yes' => 'Yeppers', 'no' => 'No way dude!', 'maybe' => 'Meh, whatever.' ), 'placeholder' => 'Text goes here', 'helper' => 'Does this help?', 'supplemental' => 'I am underneath!', 'default' => 'maybe' ) );

Aqui estão três campos, cada um usando um tipo de campo diferente em nosso plugin. O primeiro já passamos. O segundo é o nosso novo campo textarea . Podemos passar os mesmos parâmetros com o array (com exceção do UID), mas uma simples alteração no nosso tipo e obteremos uma área de textarea . O último campo nesta matriz é a lista suspensa de seleção. A principal atualização aqui é a adição do array de opções. Adicionamos um array associativo simples com a chave do array como o valor da opção HTML e o rótulo. Usando esta matriz, aqui está a aparência de nossos campos:

Nossa página de configurações após o preenchimento dos campos
Nossa página de configurações com campos. (Ver versão grande)

Quase pronto!

Agora temos uma página de configurações de plugin em funcionamento. Configuramos as seções da página, as opções, todos os retornos de chamada e registramos os campos. A única coisa que resta é obter nossos valores de configuração em outro lugar. Acredite ou não, já fizemos isso. Na parte superior do nosso retorno de campo, você pode ver que estamos verificando o valor do banco de dados:

 $value = get_option( $arguments['uid'] );

Podemos usar o mesmo código em nosso plugin (ou tema) e simplesmente passar o uid para a função. Então, se eu quisesse obter o valor de our_first_field eu simplesmente escreveria:

 get_option('our_first_field')

Oi presto! Temos nosso plugin incrível e nossas configurações incríveis! Obviamente, configuramos apenas alguns tipos de campo, mas eu passei e adicionei mais no repositório de código para essa abordagem (especificamente campos de texto, senhas, números, áreas de texto, listas suspensas de seleção, seleções múltiplas, botões de opção e caixas de seleção).

Abordagem 2: configurando um formulário e um manipulador personalizados

No passado, essa abordagem era a única maneira de adicionar páginas de configurações. Antes do WordPress 2.7, os autores de plugins precisavam criar seus próprios formulários e manipuladores personalizados. Isso obviamente levou a muitos bugs e inconsistências entre os plugins. Embora essa abordagem seja um pouco obsoleta, ainda é uma opção viável em alguns casos.

Prós

  • Você pode enviar o formulário para manipuladores personalizados e remotos
  • Você pode ignorar algumas das restrições internas da API de configurações

Contras

  • A compatibilidade deve ser mantida pelo desenvolvedor
  • Deve higienizar e validar manualmente

Quando você deve usar essa abordagem?

Use essa abordagem quando for absolutamente necessário ter um manipulador personalizado ou uma interface altamente personalizada. Você provavelmente pode se safar com a Abordagem 1 na maioria dos casos, mas tem mais flexibilidade com validação e manuseio usando esse método.

Começando

Antes de entrarmos nos detalhes, precisamos criar um cenário em que usaríamos um manipulador personalizado. Para simplificar, vamos criar um formulário que verificará um nome de usuário e um endereço de e-mail. Poderíamos extrair os dados de um banco de dados ou até mesmo de um servidor remoto. Nesse caso, configurarei uma matriz com nomes de usuários e endereços de e-mail válidos para verificarmos. Em seguida, armazenaremos os valores de campo inseridos pelo usuário e os armazenaremos no banco de dados.

Criando o formulário

Como mencionei antes, seguiremos os mesmos passos que fizemos em “Criando nossa página de plugins e configurações”. Para esta abordagem, configuraremos nossos campos usando marcação HTML estática. Adicionaremos este código ao retorno de chamada da função plugin_settings_page_content assim:

 public function plugin_settings_page_content() { ?> <div class="wrap"> <h2>My Awesome Settings Page</h2> <form method="POST"> <table class="form-table"> <tbody> <tr> <th><label for="username">Username</label></th> <td><input name="username" type="text" value="" class="regular-text" /></td> </tr> <tr> <th><label for="email">Email Address</label></th> <td><input name="email" type="text" value="" class="regular-text" /></td> </tr> </tbody> </table> <p class="submit"> <input type="submit" name="submit" class="button button-primary" value="Check My Info!"> </p> </form> </div> <?php }

Você pode ver acima que estamos apenas adicionando algum HTML estático para nossos campos. Estamos duplicando a marcação das páginas principais de configurações do WordPress. Também estamos omitindo a ação do formulário para que ele envie o formulário para a página atual, em oposição ao manipulador options.php padrão.

Antes de escrevermos nosso manipulador personalizado, vamos colocar alguns recursos de segurança rápidos. A primeira coisa que devemos fazer é colocar um nonce em nosso formulário. Os nonces protegerão contra tentativas de falsificação de solicitações entre sites, o que é semelhante à falsificação de usuários ou ataques de repetição. Vamos colocar o nonce em nosso HTML:

 <form method="POST"> <?php wp_nonce_field( 'awesome_update', 'awesome_form' ); ?> <table class="form-table">

O wp_nonce_field adicionará alguns campos ocultos ao nosso formulário; o nonce e o referenciador. Voltaremos ao nonce quando passarmos pelo código do manipulador.

Em seguida, precisamos adicionar um campo para detectar quando o formulário foi atualizado. Podemos fazer isso simplesmente adicionando um campo oculto no topo do nosso formulário:

 <form method="POST"> <input type="hidden" name="updated" value="true" /> <?php wp_nonce_field( 'awesome_update', 'awesome_form' ); ?> <table class="form-table">

Agora podemos colocar um trecho de código no topo de nossa página para detectar quando nosso formulário é enviado e nos enviar para nosso manipulador personalizado:

 public function plugin_settings_page_content() { if( $_POST['updated'] === 'true' ){ $this->handle_form(); } ?> <div class="wrap"> <h2>My Awesome Settings Page</h2>

Aqui estamos simplesmente verificando se o campo oculto updated foi enviado e, se for, chamamos um método em nosso plugin chamado handle_form . É aqui que podemos começar a escrever nosso manipulador personalizado.

Criando o manipulador

Há algumas coisas que precisamos verificar no manipulador antes de realmente gerenciarmos os dados do formulário. Primeiro precisamos verificar se nosso nonce existe e é válido:

 public function handle_form() { if( ! isset( $_POST['awesome_form'] ) || ! wp_verify_nonce( $_POST['awesome_form'], 'awesome_update' ) ){ ?> <div class="error"> <p>Sorry, your nonce was not correct. Please try again.</p> </div> <?php exit; } else { // Handle our form data } }

O código acima verifica se o nonce está correto. Se for inválido, damos ao usuário uma mensagem sobre o motivo pelo qual o formulário não foi atualizado. Se o nonce existir e estiver correto, podemos manipular nosso formulário. Vamos escrever o código para nosso manipulador de formulários agora (este código substituirá o comentário no snippet acima):

 $valid_usernames = array( 'admin', 'matthew' ); $valid_emails = array( '[email protected]', '[email protected]' ); $username = sanitize_text_field( $_POST['username'] ); $email = sanitize_email( $_POST['email'] ); if( in_array( $username, $valid_usernames ) && in_array( $email, $valid_emails ) ){ update_option( 'awesome_username', $username ); update_option( 'awesome_email', $email );?> <div class="updated"> <p>Your fields were saved!</p> </div> <?php } else { ?> <div class="error"> <p>Your username or email were invalid.</p> </div> <?php }

Vamos analisar o código nesta seção. As primeiras linhas são as matrizes de nomes de usuário/e-mails válidos que verificaremos. Esses valores de matriz podem ser preenchidos de qualquer lugar.

As próximas duas linhas são os valores que nosso usuário inseriu no formulário. Estamos usando as funções de higienização integradas que o WordPress nos oferece. Esta etapa é importante para evitar várias vulnerabilidades com formulários da web. Em seguida, verificamos se os valores fornecidos pelos usuários estão em nosso array de valores aceitáveis. Se estiverem, atualize as opções de formulário no banco de dados. Essa etapa também pode ser substituída por um mecanismo de armazenamento personalizado. Também estamos dando ao usuário uma mensagem de que seus campos foram salvos. Se a entrada do usuário for inválida, informamos isso.

A última coisa que precisamos fazer é mostrar os campos armazenados no formulário depois de serem inseridos. Faremos isso da mesma forma que recuperaríamos esses campos em outro lugar no plugin: com a função get_option . Aqui estão os campos depois de adicionarmos o código correto:

 <tr> <th><label for="username">Username</label></th> <td><input name="username" type="text" value="<?php echo get_option('awesome_username'); ?>" class="regular-text" /></td> </tr> <tr> <th><label for="email">Email Address</label></th> <td><input name="email" type="text" value="<?php echo get_option('awesome_email'); ?>" class="regular-text" /></td> </tr>

Agora estamos prontos para testar nosso formulário. Tente colocar o nome de usuário admin e o endereço de e-mail [email protected] . Você deve obter o seguinte em seu formulário:

Os campos salvos após inserirmos os valores corretos
Os campos salvos após inserirmos os valores corretos. (Ver versão grande)

Se você tentar definir um dos campos com um valor inválido, deverá receber uma mensagem de erro e os campos não deverão ser atualizados devido ao nosso manipulador personalizado.

Isso é tudo para a nossa segunda abordagem! Agora você configurou um formulário e um manipulador personalizados para gerenciar seus campos de plug-in. O código completo para esta abordagem pode ser encontrado no repositório deste artigo. Agora, vamos passar para a nossa abordagem final.

Abordagem 3: Integrando ACF (Advanced Custom Fields) em seu plug-in

Se você ainda não usou o ACF de Elliot Condon, deixe-me apresentá-lo. ACF é um gerenciador de campo maravilhoso para WordPress. Uma das melhores coisas sobre isso é a interface de configuração de campo. Isso facilita bastante a criação de campos para várias páginas diferentes no WordPress (como postagens, páginas, usuários, taxonomias e até suas próprias páginas de opções integradas). Você pode pensar “Não consigo integrar o plugin de outra pessoa ao meu – isso é obscuro!” mas o Sr. Condon entende a situação de seus colegas desenvolvedores e planejou isso em seu plugin. Você pode ver a documentação dele sobre este tópico, mas vou reafirmar um pouco disso aqui. Vamos repassar as regras.

  1. Primeiro, se você estiver distribuindo um plug-in gratuito, deverá usar a versão gratuita do ACF. Isso é para que as pessoas não consigam a versão PRO do seu plugin gratuito – isso não seria legal. Você pode usar a versão PRO em plugins e temas premium sem problemas, apenas certifique-se de comprar a licença de desenvolvedor.
  2. Em segundo lugar, não modifique as informações de direitos autorais da ACF. Dê algum crédito ao homem!
  3. Por último, não distribua a chave de licença com seu plugin.

Agora, os prós e contras desta abordagem:

Prós

  • Muito fácil de integrar em temas e plugins
  • Você pode aproveitar os campos avançados que fazem parte do ACF
  • As atualizações de código e segurança são gerenciadas pela equipe do ACF
  • O ACF tem ótimos complementos e suporte se você ficar preso
  • Configurar seus campos é super simples por causa da interface do usuário de configuração de campo

Contras

  • Acesso limitado à marcação
  • Cria uma dependência para seu plugin ou tema
  • Para manter o ACF atualizado, você deve mantê-lo atualizado em seus arquivos de plugin/tema (mais informações abaixo)

Quando você deve usar essa abordagem?

Quando você deseja criar uma interface de configurações avançadas muito rapidamente e não precisa personalizar a aparência.

Começando

For this approach I will show you how to set up the options page for the free version of ACF. To view a guide on setting up the PRO version check out the ACF documentation. To get started we will be adding ACF to our plugin directory. First, download the latest version of ACF and unzip its contents. In your plugin directory create a (Ver versão grande)

Again, we will follow the steps we did in “Creating Our Plugin And Settings Page”. Before we get into that, though, we should include ACF in our plugin.

Include ACF In Your Plugin

It's actually pretty easy to include ACF in your plugin – there are only three steps. First we have to include the main ACF file with PHP. Add the following code to the bottom of our constructor function:

 include_once( plugin_dir_path( __FILE__ ) . 'vendor/advanced-custom-fields/acf.php' );

If you refresh the admin you should see a new menu item titled Custom Fields . Before we go into that page and start setting up our fields we need to update a couple of paths in ACF. We need to tell ACF to look for its front-end assets and file includes in our plugin directory instead of its normal place. Add these two hooks to your constructor:

 add_filter( 'acf/settings/path', array( $this, 'update_acf_settings_path' ) ); add_filter( 'acf/settings/dir', array( $this, 'update_acf_settings_dir' ) );

And the callbacks for those hooks:

 public function update_acf_settings_path( $path ) { $path = plugin_dir_path( __FILE__ ) . 'vendor/advanced-custom-fields/'; return $path; } public function update_acf_settings_dir( $dir ) { $dir = plugin_dir_url( __FILE__ ) . 'vendor/advanced-custom-fields/'; return $dir; }

The first callback updates the include paths for the PHP files within the ACF plugin. The second updates the URIs for the ACF assets. Now we can set up our fields.

Configuring Your Fields

Now comes the fun part: the ACF field configuration UI. Add a title and any fields you'd like in your form. There is a great walkthrough of what everything on this page does in the ACF documentation. Here's how I have set up mine:

ACF fields configured
My ACF fields in the configuration UI. (Ver versão grande)

Once you are ready hit the Publish button on the right and your fields will be saved. Now we have to get the fields we set up into our plugin. Right now they only exist in the database. On the left-hand navigation, click the Tools item. On the new page, select the field group we just created and hit Generate Export Code . This will create a chunk of PHP code that we can now include in our plugin.

To add the options, we need to add a method call to our constructor. Add this line to the end of your constructor after our ACF include:

 $this->setup_options();

Then we can create the method that will wrap our options:

 public function setup_options() { if( function_exists( 'register_field_group' ) ) { register_field_group(array ( 'id' => 'acf_awesome-options', 'title' => 'Awesome Options', 'fields' => array ( array ( 'key' => 'field_562dc35316a0f', 'label' => 'Awesome Name', 'name' => 'awesome_name', 'type' => 'text', 'default_value' => ', 'placeholder' => ', 'prepend' => ', 'append' => ', 'formatting' => 'html', 'maxlength' => ', ), array ( 'key' => 'field_562dc9affedd6', 'label' => 'Awesome Date', 'name' => 'awesome_date', 'type' => 'date_picker', 'date_format' => 'yymmdd', 'display_format' => 'dd/mm/yy', 'first_day' => 1, ), array ( 'key' => 'field_562dc9bffedd7', 'label' => 'Awesome WYSIWYG', 'name' => 'awesome_wysiwyg', 'type' => 'wysiwyg', 'default_value' => ', 'toolbar' => 'full', 'media_upload' => 'yes', ), ), 'location' => array ( array ( array ( 'param' => 'options_page', 'operator' => '==', 'value' => 'smashing_fields', ), ), ), 'menu_order' => 0, 'position' => 'normal', 'style' => 'default', 'label_placement' => 'top', 'instruction_placement' => 'label', 'hide_on_screen' => ', 'active' => 1, 'description' => ', )); } }

Now that we have our fields ready to go, we can add them to the settings page.

Modifying The Settings Page Code

To add the fields we just created to the page we will need to update our plugin_settings_page_content method.

Previously, we set up the form tag for our page. In this case we will let ACF do that part for us. Here is what our updated function should look like:

public function plugin_settings_page_content() { do_action('acf/input/admin_head'); // Add ACF admin head hooks do_action('acf/input/admin_enqueue_scripts'); // Add ACF scripts $options = array( 'id' => 'acf-form', 'post_id' => 'options', 'new_post' => false, 'field_groups' => array( 'acf_awesome-options' ), 'return' => admin_url('admin.php?page=smashing_fields'), 'submit_value' => 'Update', ); acf_form( $options ); }

As duas primeiras linhas de nossa função estão adicionando os scripts e estilos que precisaremos para os campos de configurações. Depois disso estamos configurando as opções do nosso formulário. Você pode notar que o valor no argumento field_groups corresponde ao ID da nossa função register_field_group . Para ver os outros parâmetros de configuração, dê uma olhada na documentação do acf_form . A última linha da nossa função vai renderizar o formulário.

Se você tentar carregar a página de configurações agora, poderá ver que a página está realmente quebrada. Isso ocorre porque o ACF precisa localizar algumas variáveis ​​para JavaScript. Para fazer isso, precisamos adicionar outro gancho ao nosso construtor:

 add_action( 'admin_init', array( $this, 'add_acf_variables' ) );

Agora precisamos configurar o callback:

 public function add_acf_variables() { acf_form_head(); }

Você pode tentar adicionar algum conteúdo e salvar e deve funcionar como nossas outras duas abordagens. É assim que nossa página deve ficar:

Formulário ACF concluído
Nosso formulário ACF preenchido. (Ver versão grande)

Há apenas alguns itens de limpeza que precisamos resolver:

  • Você pode querer ocultar o fato de estar usando o ACF para seu plugin. Se for esse o caso, você precisa ocultar o item de menu Campos personalizados . Você pode fazer isso adicionando este snippet à sua função construtora:

     add_filter( 'acf/settings/show_admin', '__return_false' );
  • Devemos remover a versão do banco de dados do nosso grupo de campos. Basta ir à seção de campos personalizados e clicar no botão da lixeira. Esta etapa é opcional, pois afetará apenas o ambiente em que você criou o plug-in, mas pode apresentar problemas se você estiver testando seu plug-in no mesmo ambiente.

Usando campos ACF em seu plug-in

Para obter os campos ACF que você criou, basta usar a função padrão get_field do ACF. A primeira opção deve ser o ID exclusivo do campo e o segundo argumento definido como 'option' . Aqui está como obteríamos o campo Awesome Date :

 get_field( 'awesome_date', 'option' )

E é isso. Agora você configurou um plugin com configurações ACF! Você pode visualizar o código dessa abordagem no repositório.

Conclusão

Então aí está: três maneiras de tornar seus plugins configuráveis. Eu adoraria ouvir sobre os plugins que você pode criar usando esses métodos. Mais uma vez, configurei um repositório que abriga o código para cada uma dessas abordagens. Sinta-se à vontade para bifurcá-los e personalizá-los para atender às suas próprias necessidades.

Quanto às minhas preferências pessoais para essas abordagens, costumo me inclinar para a Abordagem 1. Prefiro manter o menor número possível de dependências em meus plugins e você pode personalizar a marcação para criar um tema na página de configurações para projetos personalizados. Para protótipos rápidos ou projetos em que preciso configurar campos muito avançados, usarei o ACF - mas adiciona um nível de complexidade ao gerenciamento de atualizações de plugins.

Vale destacar também a proposta de uma API Fields de Scott Clark. Embora ainda seja um trabalho em andamento, a API essencialmente permitiria aos desenvolvedores de plugins e temas a capacidade de usar a mesma interface que a API do Customizer para criar campos de configurações em outras áreas do painel de administração.

Alternativas ACF

Como apontado nos comentários abaixo, e para dar aos desenvolvedores outras opções semelhantes à abordagem ACF, você pode conferir algumas alternativas que podem oferecer recursos diferentes. Se você tiver mais, por favor, envie-os nos comentários abaixo! Aqui eles estão em nenhuma ordem particular:

  • CMB2 por WebDevStudios
  • Meta Box de Tran Ngoc Tuan Anh (Rilwis)