Каковы преимущества API настроек?

13

Позвольте мне предвосхитить это, сказав, что я почти никогда не работал с WordPress - фактически, когда я в последний раз делал сайт в WordPress, вернулся в 2.2. Вчера я все испортил и задал несколько вопросов, пытаясь заставить работать основной плагин меню.

Теперь у меня есть плагин, полностью работоспособный и ведущий себя точно так, как я ожидал, поэтому я решил внести небольшие изменения здесь и там, чтобы добавить функциональность и совместимость - в том числе с помощью API настроек. Тем не менее, очень короткий момент в чтении руководств по этому API, и я сильно запутался, затем эта путаница только углубилась, когда я продолжил читать и попытался реализовать примеры - что стало еще более трудным из-за того, что мой плагин реализован как класс ,

Если я не делаю что-то не так, из того, что я понимаю, для использования API настроек требуется создание новой функции НА НАСТРОЙКИ. Это означает 3-5 функций для среднего плагина и до сотни для более сложных плагинов. Просто кажется нелепым писать такое множество функций (и разрабатывать систему именования, чтобы не перепутать их), когда вы с такой же легкостью можете импортировать все применимые $_POSTпеременные в массив и отказаться от всего беспорядка.

Возможно, я старомоден, но если от этого что-то не получится, я не вижу причины, чтобы утроить или увеличить в четыре раза объем написанного кода. Вот как я управлял параметрами, прежде чем пытаться добавить API настроек:

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

Теперь с настройками API у меня есть что-то похожее на следующее:

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

Вероятно, из полос прокрутки до боли видно, что код уже длиннее всего с двумя вариантами. Из комментариев очевидно, что я не совсем понимаю, что делаю. Тогда есть вопрос наличия 5 новых функций (и удаления только 1), чтобы выполнить все это.

Так какое же преимущество я получаю от всей этой дополнительной работы?

stevendesu
источник
Не используйте их в таких случаях. Я думаю, что они предназначены для начинающих PHP, которым нужно 3-4 варианта внутри своего плагина / темы. Это одна из «функций», которые никогда не должны были быть реализованы ... Это в основном API для другого API :)
onetrickpony
3
Я использую API настроек для всего, что я пишу, все зависит от того, как вы его используете, обратите внимание, что вы можете использовать API, даже не используя, add_settings_sectionи add_settings_fieldэти две функции добавляют вздутие живота в ваш код больше, чем что-либо другое, избегайте их и вы избегаете вздутия
t31os
1
Я делаю то же самое, что и t3los: регистрирую саму настройку, а затем просто кодирую формы в HTML на моей странице настроек. Если вы хотите увидеть действительно простой способ сделать это и сохранить код для дальнейшего использования, воспользуйтесь плагином Yoast для WordPress SEO.
chrisguitarguy

Ответы:

8

Моя точка зрения заключается в том, что основной целью и преимуществом API настроек является структура .

Это помогает сохранять сложные настройки параметров:

  • упорядоченно (логика оформления и разделы);
  • безопасный (одноразовые номера, обратные вызовы проверки);
  • расширяемый (подключение на другую страницу или разрешение на подключение).

Как и в случае любых таких структурных накладных расходов, это приносит пользу более сложным вариантам использования и выгодно менее простым.

Таким образом, вы можете реализовать все, что API настроек делает без его использования. Вопрос в том, сможете ли вы сделать это надежным, безопасным и расширяемым способом.

Rarst
источник
Я наконец-то получил свою страницу настроек, работающую с помощью этого урока: alisothegeek.com/2011/01/wordpress-settings-api-tutorial-1 и с помощью операторов switch и вспомогательных функций я должен сказать, что теперь все упорядочено в моем коде (что приятно, так как я планирую перейти от двух моих тестовых настроек к 15-20 общим настройкам).
stevendesu
1
@steven_desu Да, шутка в том, что каждый, кто использует API настроек, создает для этого фреймворк. :) Пара вспомогательных функций практически неизбежна. Также обратите внимание, что API настроек не считается завершенным и есть (смутные) планы по его улучшению в будущем (я думаю, что это было упомянуто в контексте планов 3.3).
Первый
1
Я конечно надеюсь, что это улучшится. Честно говоря, я не вижу преимуществ API настроек, но каждое преимущество, которым я сейчас пользуюсь, является результатом структуры, которую я заимствовал для него. Мне нравится, что все элементы формы теперь динамически генерируются с одинаковым внешним видом ... но это не API настроек. Мне нравится, что настройки по умолчанию и настройки регистрации обрабатываются по одним и тем же определениям ... но это не API настроек. Мне нравится, что jQuery не только делает формы красивыми, но и постепенно совершенствуется, - но мне пришлось вручную кодировать прогрессивное улучшение ...
stevendesu
5

Если вы используете обратные вызовы правильно, вам не нужен весь избыточный код. Вот как я могу реализовать API настроек таким образом, чтобы он был полностью масштабируемым .

Преимущества (среди прочего):

  • API настроек принудительно очищает ненадежные пользовательские данные.
  • API настроек принудительно регистрирует опции как массив опций, что приводит к одной записи в базе данных wp_options, а не к отдельным записям в базе данных для каждой опции
  • API настроек облегчает усиление безопасности формы настроек
  • API настроек облегчает интерфейс администратора в соответствии с основным интерфейсом администратора, в результате чего улучшается UX
Чип Беннетт
источник
Таким образом, это по существу заставляет безопасность и эстетические стандарты, которым я уже следовал без его помощи? Я прочитаю учебник, на который вы ссылались. Если это сделает API настроек таким же простым, как ручное кодирование форм (или проще), тогда я приму этот ответ
stevendesu
Знаете ли вы, что исходный код, на который вы указали, реализует функции oenology_get_settings_by_tab()и oenology_get_default_optionsдаже не определяет их сначала? Я думал, что это было достаточно плохо с 209 строками кода (после удаления комментариев и пустых строк), но как только эти функции будут определены, это будет еще длиннее ... Для четырех вариантов?
stevendesu
Они определены в другом месте. На oenology_get_settings_by_tab()самом деле не имеет отношения к тому, что вы делаете. Но вы должны определить свою форму поля разметки где - то , как вы должны для проверки / дезинфицировать пользовательского ввода - то , так что если вы делаете это правильно, вы будете иметь все тот же код , как хорошо.
Чип Беннетт
0

Спасибо за публикацию, мне было интересно то же самое. Много функций.

Чтобы уменьшить их, вы можете хранить ваши параметры в виде массивов. Wordpress сериализует данные для вас. Это экономит код (или функции в любом случае), но ухудшает данные. Например, если вы хотите отсортировать, отредактировать вручную, экспортировать и т. Д. Ваши таблицы, они будут иметь эти сериализованные значения. С другой стороны, ваш плагин добавляет меньше записей в таблицу параметров, и их легче очистить.

Итак, вот ваш код переделан. Несколько заметок:

  • Мой пример демонстрирует как простые параметры (de_w, de_h), так и параметр массива (de_width_height).
  • Всегда дезинфицируйте ввод пользователя. В примере я использовал целые числа, потому что их легко дезинфицировать.
  • Вам не нужно $ _POST, nonces, check_admin_referer (), update_option () и т. Д. При использовании API настроек.
  • Сохранение происходит при следующей загрузке страницы, а не при выключении. Затем WP делает редирект на вашу страницу. Поэтому для отладки выведите некоторые выходные данные и вызовите wp_die () в одной из функций проверки.
  • Действие формы всегда "options.php." Вот как работает API настроек. Не используйте ничего другого. Ну, вы можете использовать admin_url ('options.php'), если хотите.
  • WP напечатает для вас сообщение о сохранении.
  • Улучшения, не включенные здесь: использование <label>для доступности. Использование add_settings_error (), settings_error (), которые обрабатывают сообщения, а также ошибки. Это часто единственная причина иметь отдельные функции проверки для каждой опции. Вы можете видеть ниже validate_w () и validate_h () может быть одной функцией. Я пытался абстрагироваться от сообщений, но, насколько я помню, вы не получаете достаточно информации в обратном вызове проверки. Как то, над чем вы работаете.
  • Функции обратного вызова проверки получают необработанное значение $ _POST из API настроек. Мне нравится называть параметр как таковой, $ raw. Для опции массива вы получаете массив, как по волшебству.
  • Изменить: $ это лучше, чем & $ this.

Код:

<?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;
}
}
Китчин
источник