¿Cuáles son las ventajas de la API de configuración?

13

Permítanme presentar esto diciendo que casi nunca trabajo con WordPress; de hecho, la última vez que hice un sitio en WordPress fue en 2.2. Ayer hice un desastre de todo y hice varias preguntas aquí tratando de hacer que funcione un complemento de menú básico.

Ahora tengo el complemento completamente funcional y se comporta exactamente como esperaba, así que decidí hacer cambios menores aquí y allá para agregar funcionalidad y compatibilidad, incluido el uso de la API de configuración. Sin embargo, un momento muy breve en la lectura de tutoriales en esta API y me confundí bastante, luego esta confusión solo se profundizó a medida que leía e intentaba implementar los ejemplos, lo que se hizo aún más difícil por el hecho de que mi complemento se implementa como una clase .

A menos que esté haciendo algo mal, por lo que entiendo que usar la API de configuración requiere la creación de una nueva función POR CONFIGURACIÓN. Esto significa 3-5 funciones para el complemento promedio, y hasta cientos para complementos más avanzados. Simplemente parece absurdo escribir tantas funciones (y desarrollar un sistema de nombres para evitar confundirlas) cuando podría importar fácilmente todas las $_POSTvariables aplicables en una matriz y renunciar a todo el desastre.

Tal vez soy anticuado, pero a menos que haya algo que ganar, no veo la razón para triplicar o cuadruplicar la cantidad de código que estoy escribiendo. Así es como gestioné las opciones antes de intentar agregar la API de configuración:

    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);
        }
    }

Ahora con la API de configuración tengo algo más parecido a lo siguiente:

    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?
    }

Probablemente sea dolorosamente obvio por las barras de desplazamiento que el código ya es más largo con solo dos opciones. Es obvio por los comentarios que no entiendo completamente lo que estoy haciendo. Luego está la cuestión de tener 5 nuevas funciones (y eliminar solo 1) para lograr todo esto.

Entonces, ¿qué ventaja estoy obteniendo de todo este trabajo extra?

stevendesu
fuente
No los use para tales casos. Creo que están destinados a principiantes de PHP, que necesitan 3-4 opciones dentro de su complemento / tema. Esta es una de las "características" que nunca deberían haberse implementado ... Es básicamente una API para otra API :)
onetrickpony
3
Utilizo la API de configuración para todo lo que escribo, todo depende de cómo la uses, ten en cuenta que puedes usar la API sin siquiera usar add_settings_sectiony add_settings_field, esas dos funciones agregan hinchazón a tu código más que nada, evítalos y evita la hinchazón ...
t31os
1
Hago lo mismo que t3los: registro la configuración en sí, luego solo codifico los formularios en HTML en mi página de configuración. Si desea ver una forma realmente fácil de hacer esto y mantener el código para más adelante, consulte el complemento SEO de WordPress de Yoast.
chrisguitarguy

Respuestas:

8

Mi punto de vista es que el objetivo principal y el beneficio de la API de configuración es la estructura .

Ayuda a mantener configuraciones complejas:

  • ordenada (lógica de registro y secciones);
  • seguro (nonces, devoluciones de llamada de validación);
  • extensible (enganchado a otra página o permitiendo engancharlo).

Al igual que con cualquier sobrecarga estructural, beneficia los casos de uso más complejos y los menos simples.

Entonces puede implementar cualquier cosa que haga la API de configuración sin usarla. La pregunta es si puede lograrlo de manera confiable, segura y extensible.

Rarst
fuente
Finalmente conseguí que mi página de Configuración funcionara con la ayuda de este tutorial: alisothegeek.com/2011/01/wordpress-settings-api-tutorial-1 y con la ayuda de las declaraciones de cambio y las funciones de ayuda, debo decir que las cosas ahora están más ordenadas en mi código (lo cual es bueno ya que planeo pasar de mis dos configuraciones de prueba a 15-20 configuraciones totales).
stevendesu
1
@steven_desu sí, el chiste es que todos los que usan la API de configuración escriben un marco para ello. :) Las funciones de ayuda de pareja son casi inevitables. También tenga en cuenta que la API de configuración no se considera finalizada y hay planes (vagos) para mejorarla en el futuro (creo que se mencionó en el contexto de los planes 3.3).
Rarst
1
Ciertamente espero que haya mejorado. Sinceramente, no veo ventajas para la API de configuración, sino que cada ventaja que estoy disfrutando ahora es el resultado del marco que tomé prestado. Me gusta que todos los elementos de formulario ahora se generen dinámicamente con la misma apariencia ... pero eso no es API de configuración. Me gusta que la configuración predeterminada y la configuración de registro se manejen con las mismas definiciones ... pero esa no es la API de configuración. Me gusta que jQuery no sólo hace que las formas bonitas, pero se ha mejorado progresivamente - pero tenía que código manualmente la mejora progresiva ...
stevendesu
5

Si utiliza devoluciones de llamada correctamente, no es necesario todo el código redundante. Así es como implemento la API de configuración, de una manera que es completamente escalable .

Ventajas (entre otras cosas):

  • La API de configuración fuerza la desinfección de los datos de usuarios no confiables.
  • La API de configuración fuerza que las opciones se registren como una matriz de opciones, lo que da como resultado una sola entrada de base de datos wp_options, en lugar de entradas de base de datos discretas para cada opción
  • La API de configuración facilita el fortalecimiento de la seguridad del formulario de configuración
  • La API de configuración facilita la interfaz de usuario de administrador coherente con la interfaz de usuario principal de administrador, lo que resulta en una mejor UX
Chip Bennett
fuente
Entonces, ¿esencialmente impone estándares de seguridad y estéticos que ya seguía sin su ayuda? Sin embargo, leeré el tutorial que vinculaste. Si hace que la API de configuración sea tan fácil como codificar manualmente los formularios (o más fácil), entonces aceptaré esta respuesta
stevendesu
¿Eres consciente de que el código fuente al que apuntaste implementa las funciones oenology_get_settings_by_tab()y oenology_get_default_optionssin definirlas primero? Pensé que era lo suficientemente malo en 209 líneas de código (después de eliminar comentarios y líneas en blanco), pero una vez que se definan esas funciones, será aún más largo ... ¿Para cuatro opciones?
stevendesu
Se definen en otra parte. El oenology_get_settings_by_tab()no es realmente relevante para lo que estás haciendo. Pero usted tiene que definir su forma de campo de marcado algún lugar , tal y como lo tiene para validar la entrada del usuario / desinfectar alguna manera , así que si estás haciendo bien, tendrá todo lo mismo código también.
Chip Bennett
0

Gracias por publicar esto, me preguntaba exactamente lo mismo. Muchas funciones

Para reducirlos, puede almacenar sus opciones como matrices. Wordpress serializa los datos por usted. Esto ahorra en código (o funciona de todos modos), pero empeora los datos. Por ejemplo, si desea ordenar, editar a mano, exportar, etc., sus tablas, tendrán estos valores serializados. Por otro lado, su complemento agrega menos entradas a la tabla de opciones y son más fáciles de limpiar.

Así que aquí está tu código rehecho. Algunas notas

  • Mi ejemplo muestra opciones simples (de_w, de_h) y una opción de matriz (de_width_height).
  • Siempre desinfecte la entrada del usuario. Usé números enteros en el ejemplo porque son fáciles de desinfectar.
  • No necesita $ _POST, nonces, check_admin_referer (), update_option (), etc., cuando utiliza la API de configuración.
  • El guardado ocurre en la carga de la página siguiente, no en el apagado. Entonces WP hace una redirección a su página. Entonces, para depurar, imprima algunos resultados y llame a wp_die () en una de las funciones de validación.
  • La acción del formulario siempre es "options.php". Así es como funciona la API de configuración. No uses nada más. Bueno, puedes usar admin_url ('options.php') si quieres.
  • WP imprimirá el mensaje de guardado para usted.
  • Mejoras no incluidas aquí: uso <label>para accesibilidad. Usando add_settings_error (), settings_error (), que maneja mensajes y errores. Esa es a menudo la única razón para tener funciones de validación separadas para cada opción. Puede ver a continuación validate_w () y validate_h () podría ser una función. Miré tratando de abstraer el mensaje, pero no recuerdo que reciban suficiente información en la devolución de llamada de validación. Como en qué campo estás trabajando.
  • Las funciones de devolución de llamada de validación obtienen un valor bruto $ _POST de la API de configuración. Me gusta nombrar el parámetro como tal, $ raw. Para la opción de matriz, obtienes una matriz, como magia.
  • Editar: $ this es mejor 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
fuente