Quais são as vantagens da API de configurações?

13

Permita-me dizer isso dizendo que quase nunca trabalho com o WordPress - na verdade, a última vez que fiz um site no WordPress estava de volta durante o 2.2. Ontem fiz uma bagunça de tudo e fiz várias perguntas aqui, tentando fazer com que um plugin básico de menu funcionasse.

Agora tenho o plug-in totalmente funcional e funcionando exatamente como eu esperava, então decidi fazer pequenas alterações aqui e ali para adicionar funcionalidade e compatibilidade - incluindo o uso da API de configurações. No entanto, um momento muito curto para ler os tutoriais dessa API e fiquei bastante confuso; essa confusão só se aprofundou enquanto eu lia e tentava implementar os exemplos - o que foi ainda mais difícil pelo fato de meu plug-in ser implementado como uma classe. .

A menos que eu esteja fazendo algo errado, pelo que entendi usar a API de configurações, é necessária a criação de uma nova função POR CONFIGURAÇÃO. Isso significa 3-5 funções para o plug-in médio e até centenas para plug-ins mais avançados. Parece ridículo escrever essas muitas funções (e desenvolver um sistema de nomes para não confundi-las) quando você poderia importar facilmente todas as $_POSTvariáveis aplicáveis para uma matriz e renunciar a toda a bagunça.

Talvez eu seja antiquado, mas, a menos que haja algo a ganhar com isso, não vejo motivo para triplicar ou quadruplicar a quantidade de código que estou escrevendo. Veja como eu gerenciei as opções antes de tentar adicionar a API de configurações:

    function __construct() {
        /* constructor stuff */
        $this->options = $this->db_options = get_option( 'de-menu-options' );
        if( $this->options === false ){
            $this->options = $this->defaults;
        }
        if (is_admin()) {
            add_action('admin_menu', array(&$this, 'admin_menu'));
        }   
        /* more stuff */

        // When WordPress shuts down we store changes to options
        add_action('shutdown', array(&$this, 'update'));
    }

    public function admin_menu() {
        add_options_page('DE Menu Options', 'DE Menu', 'manage_options', 'de-menu-options', array(&$this, 'options'));
        add_option('de-menu-options', $this->options);
    }

    public function options() {
        if (!current_user_can('manage_options')) {
            wp_die( __('You do not have sufficient permissions to access this page.') );
        }
        if ( !empty($_POST) && check_admin_referer('de-menu-options') ) {
            // These options are saved to the database at shutdown
            $this->options = array(
                "columns" => $_POST["de-menu-columns"],
                "maintenance" => $_POST["de-menu-maintenance"]
            );
            echo 'DE Menu options saved';
        }
?>

<div class="wrap">
    <h2>DE Menu Plugin</h2>
    <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
        <?php settings_fields('de-menu-options'); ?>
        <input type="checkbox" name="de-menu-maintenance" />
        <label for="de-menu-columns">Columns:</label>
        <input type="text" name="de-menu-columns" value="<?php echo $this->options['columns']; ?>" />
        <p class="submit">
        <input type="submit" name="de-menu-submit" value="Update Options »" />
        </p>
    </form>
</div>
<?php
    }

    function update() {
        // By storing all changes at the end we avoid multiple database calls
        $diff = array_diff( $this->options, $this->db_options );
        if( !empty( $diff )  ){
            update_option('de-menu-options', $this->options);
        }
    }

Agora, com a API de configurações, tenho algo mais como o seguinte:

    function __construct() {
        /* constructor stuff */
        // Do I load options? Will they be loaded for me? Who knows?
        if (is_admin()) {
            add_action('admin_menu', array(&$this, 'admin_menu'));
            add_action('admin_init', array(&$this, 'admin_init'));
        }   
        /* more stuff */
        // Settings API should update options for me... I think
    }

    public function admin_menu() {
        add_options_page('DE Menu Options', 'DE Menu', 'manage_options', 'de-menu-options', array(&$this, 'options'));
        add_option('de-menu-options', $this->options);
    }

    public function admin_init() {
        register_setting('de-menu-options','de-menu-options',array(&$this,'validate'));
        add_settings_section('de-menu-main-options', 'Main Settings', 'options_section', 'de-menu-options');
        add_settings_field('de-menu-maintenance', 'Maintenance Mode', array(&$this,'options_maintenance'), 'de-menu-options', 'de-menu-main-options');
        add_settings_field('de-menu-columns', 'Columns', array(&$this,'options_columns'), 'de-menu-options', 'de-menu-main-options');
    }

    public function options() {
        if (!current_user_can('manage_options')) {
            wp_die( __('You do not have sufficient permissions to access this page.') );
        }
        if ( !empty($_POST) && check_admin_referer('de-menu-options') ) {
            // These options are saved to the database at shutdown
            $this->options = array(
                "columns" => $_POST["de-menu-columns"],
                "maintenance" => $_POST["de-menu-maintenance"]
            );
            echo 'DE Menu options saved';
        }
?>

<div class="wrap">
    <h2>DE Menu Plugin</h2>
    <form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>">
        <?php settings_fields('de-menu-options'); ?>
        <?php do_settings_sections('de-menu-options'); ?>
        <p class="submit">
        <input type="submit" name="de-menu-submit" value="Update Options »" />
        </p>
    </form>
</div>
<?php
    }

    public function options_section() {
        echo '<p>' . __('Main description of this section here.','de-menu-lang') . '</p>';
    }

    public function options_maintenance() {
        echo "<input id='de-menu-maintenance' name='options[maintenance]' type='checkbox' />";
    }

    public function options_columns() {
        echo "<input id='de-menu-columns' name='options[columns]' type='checkbox' value=".$this->options['columns']."/>";
    }

    function validate($options) {
        return $options; // I guess?
    }

Provavelmente é dolorosamente óbvio pelas barras de rolagem que o código já é mais longo com apenas duas opções. É óbvio, pelos comentários, que eu não entendo completamente o que estou fazendo. Depois, há a questão de ter 5 novas funções (e remover apenas 1) para realizar tudo isso.

Então, que vantagem estou ganhando com todo esse trabalho extra?

stevendesu
fonte
Não os use para esses casos. Eu acho que eles são destinados a iniciantes em PHP, que precisam de 3-4 opções dentro de seu plugin / tema. Esta é uma das "características" que nunca deveriam ter sido implementadas ... É basicamente uma API para outra API :)
onetrickpony
3
Eu uso a API de configurações para tudo o que escrevo, tudo depende de como você a usa, observe que você pode usar a API sem usar add_settings_sectione add_settings_field, essas duas funções adicionam inchaço ao seu código mais do que tudo, evitam-no e evitam o inchaço.
t31os 29/07
1
Eu faço o mesmo que t3los: registre a configuração em si, então apenas codifico os formulários em HTML na minha página de configurações. Se você quiser ver uma maneira realmente fácil de fazer isso e manter o código para mais tarde, confira o plugin SEO do Yoast para WordPress.
Chrisguitarguy

Respostas:

8

Meu ponto de vista é que o principal objetivo e benefício da API de configurações é a estrutura .

Ajuda a manter configurações complexas:

  • ordenada (lógica de registro e seções);
  • seguro (nonces, retornos de chamada de validação);
  • extensível (conectando-se a outra página ou permitindo conectar-se a).

Como em qualquer sobrecarga estrutural, beneficia casos de uso mais complexos e beneficia casos menos simples.

Assim, você pode implementar tudo o que a API de configurações faz sem usá-lo. A questão é se você pode fazer isso da maneira mais confiável, segura e extensível possível.

Rarst
fonte
Finalmente, minha página Configurações funcionou com a ajuda deste tutorial: alisothegeek.com/2011/01/wordpress-settings-api-tutorial-1 e com a ajuda das instruções do switch e das funções auxiliares, devo dizer que agora as coisas estão mais organizadas no meu código (o que é bom, pois pretendo mudar das minhas duas configurações de teste para 15 a 20 configurações totais).
stevendesu
1
@steven_desu sim, a piada é que todo mundo que usa a API de configurações cria uma estrutura para ela. :) As funções auxiliares de casal são quase inevitáveis. Observe também que a API de configurações não é considerada finalizada e há planos (vagos) para melhorá-la no futuro (acho que foi mencionada no contexto dos planos 3.3).
Rarst 30/07
1
Eu certamente espero que tenha melhorado. Sinceramente, não vejo vantagens na API de configurações, mas todas as vantagens que estou desfrutando agora são o resultado da estrutura que emprestei para ela. Gosto que todos os elementos do formulário agora sejam gerados dinamicamente com a mesma aparência ... mas isso não é a API de configurações. Gosto que as configurações padrão e as configurações de registro sejam tratadas pelas mesmas definições ... mas essa não é a API de configurações. Eu gosto que jQuery não só torna as formas bonitas, mas é progressivamente reforçada - mas eu tinha de código manualmente a valorização progressiva ...
stevendesu
5

Se você usar retornos de chamada corretamente, não haverá necessidade de todo o código redundante. Aqui está como eu implemento a API de configurações, de uma forma que é completamente escalável .

Vantagens (entre outras coisas):

  • A API de configurações força a limpeza de dados do usuário não confiáveis.
  • A API de configurações força as opções a serem registradas como uma matriz de opções, resultando em uma única entrada de banco de dados wp_options, em vez de entradas de banco de dados discretas para cada opção
  • A API de configurações facilita o fortalecimento da segurança do formulário de configurações
  • A API de configurações facilita a interface do usuário do administrador, consistente com a interface principal do administrador, resultando em um melhor UX
Chip Bennett
fonte
Então, essencialmente força os padrões estéticos e de segurança que eu já estava seguindo sem a ajuda dele? Vou ler o tutorial que você vinculou. Se ele faz a API de configuração tão fácil como codificação manualmente as formas (ou mais fácil), então eu vou aceitar essa resposta
stevendesu
Você está ciente de que o código-fonte que você apontou implementa as funções oenology_get_settings_by_tab()e oenology_get_default_optionssem defini-las primeiro? Eu pensei que já era ruim o suficiente em 209 linhas de código (depois de remover comentários e linhas em branco), mas uma vez definidas essas funções, será ainda mais ... Para quatro opções?
31411 stevendesu
Eles são definidos em outro lugar. Não oenology_get_settings_by_tab()é realmente relevante para o que você está fazendo. Mas você tem de definir a sua forma de campo de marcação em algum lugar , assim como você tem a entrada do usuário validar / sanitize de alguma forma , por isso, se você está fazendo certo, você terá tudo o que mesmo código também.
Chip Bennett
0

Obrigado por postar isso, eu queria saber exatamente a mesma coisa. Muitas funções.

Para reduzi-los, você pode armazenar suas opções como matrizes. Wordpress serializa os dados para você. Isso economiza código (ou funciona de qualquer maneira), mas gera dados piores. Por exemplo, se você deseja classificar, editar manualmente, exportar etc. suas tabelas, elas terão esses valores serializados. Por outro lado, seu plugin adiciona menos entradas à tabela de opções e é mais fácil de limpar.

Então, aqui está seu código refazer. Algumas notas:

  • Meu exemplo demonstra as opções simples (de_w, de_h) e uma opção de matriz (de_width_height).
  • Sempre limpe a entrada do usuário. Eu usei números inteiros no exemplo porque eles são fáceis de higienizar.
  • Você não precisa de $ _POST, nonces, check_admin_referer (), update_option () etc.) ao usar a API de configurações.
  • O salvamento acontece no carregamento da próxima página, não no desligamento. Em seguida, o WP redireciona para sua página. Portanto, para depurar, imprima alguma saída e chame wp_die () em uma das funções de validação.
  • A ação do formulário é sempre "options.php". É assim que a API de configurações funciona. Não use mais nada. Bem, você pode usar admin_url ('options.php') se quiser.
  • O WP imprimirá a mensagem salva para você.
  • Aprimoramentos não incluídos aqui: usando <label>para acessibilidade. Usando add_settings_error (), settings_error (), que manipula mensagens e também erros. Esse é geralmente o único motivo para ter funções de validação separadas para cada opção. Você pode ver abaixo validate_w () e validate_h () poderia ser uma função. Tentei abstrair as mensagens, mas você não recebe informações suficientes no retorno de chamada de validação, pelo que me lembro. Como em qual campo você está trabalhando.
  • As funções de retorno de chamada de validação obtêm um valor bruto $ _POST da API de configurações. Eu gosto de nomear o parâmetro como tal, $ raw. Para a opção de matriz, você obtém uma matriz, como mágica.
  • Edit: $ this é melhor que & $ this.

Código:

<?php
$foo= new de_Foo();
class de_Foo {
function __construct() {
    if (is_admin()) {
        add_action('admin_menu', array($this, 'admin_menu'));
        add_action('admin_init', array($this, 'admin_init'));
    } 
}
public function admin_menu() {
    add_options_page(
       'DE Menu Options',
       'DE Menu',
       'manage_options',
       'de-menu-options',
       array($this,'xoxptions')
    );
    // add_option('de-menu-options', $this->options);
}
public function admin_init() {
 register_setting(
      'de-menu-settings-group',
      'de_w',
      array($this, 'validate_w')
 );
 register_setting(
      'de-menu-settings-group',
      'de_h',
      array($this, 'validate_h')
 );
 register_setting(
      'de-menu-settings-group',
      'de_width_height',
      array($this, 'validate_width_height')
 );
 add_settings_section(
      'de-menu-settings-section-size',
      'Size',
      array($this, 'settings_section_size_render'),
      'de-menu-options'
 );
 add_settings_field(
      'de_w',
      'W',
      array($this, 'w_render'),
      'de-menu-options',
      'de-menu-settings-section-size'
 );
 add_settings_field(
      'de_h',
      'H',
      array($this, 'h_render'),
      'de-menu-options',
      'de-menu-settings-section-size'
 );
 add_settings_field(
      'de_width_height',
      'Width / Height',
      array($this, 'width_height_render'),
      'de-menu-options',
      'de-menu-settings-section-size'
 );
}
public function options() {
    if (!current_user_can('manage_options')) {
        wp_die( __('You do not have sufficient permissions to access this page.') );
    }
////////////////////////////
// no no no
////////////////////////////
//         if ( !empty($_POST) && check_admin_referer('de-menu-options') ) {
//             // These options are saved to the database at shutdown
//             $this->options = array(
//                 "columns" => $_POST["de-menu-columns"],
//                 "maintenance" => $_POST["de-menu-maintenance"]
//             );
//             echo 'DE Menu options saved';
//         }
////////////////////////////
?>
<div class="wrap">
<h2>DE Menu Plugin</h2>
<form method="post" action="<?php echo admin_url('options.php'); ?>">
    <?php settings_fields('de-menu-settings-group'); ?>
    <?php do_settings_sections('de-menu-options'); ?>
    <p class="submit">
    <input type="submit" name="de-menu-submit" value="Update Options" />
    </p>
</form>
</div>
<?php
}
public function settings_section_size_render() {
    echo '<p>' . __('Main description of this section here.','de-menu-lang') . '</p>';
}
public function w_render() {
 $w= esc_attr( get_option('de_w') );
 echo "<p><input name='de_w' value='$w'></p>\n";
}
public function h_render() {
 $h= esc_attr( get_option('de_h') );
 echo "<p><input name='de_h' value='$h'></p>\n";
}
public function width_height_render() {
 $width_height= get_option('de_width_height', array());
 $width= esc_attr( @$width_height['width'] );
 $height= esc_attr( @$width_height['height'] );
 echo "<p>Width: <input name='de_width_height[width]' value='$width'></p>\n";
 echo "<p>Height: <input name='de_width_height[height]' value='$height'></p>\n";
}
function validate_w($raw) {
 return (int)$raw;
}
function validate_h($raw) {
 return (int)$raw;
}
function validate_width_height($raw) {
 is_array($raw) or $raw= array();
 $result= array();
 $result['width']= (int)@$raw['width'];
 $result['height']= (int)@$raw['height'];
 return $result;
}
}
kitchin
fonte