Jakie są zalety interfejsu API ustawień?

13

Pozwólcie, że poprzedzę to stwierdzeniem, że prawie nigdy nie pracuję z WordPress - w rzeczywistości ostatni raz, gdy tworzyłem witrynę w WordPress, powróciłem w wersji 2.2. Wczoraj zepsułem wszystko i zadałem kilka pytań, próbując uruchomić podstawową wtyczkę menu.

Teraz mam wtyczkę w pełni funkcjonalną i zachowuję się dokładnie tak, jak się spodziewam, więc postanowiłem wprowadzić drobne zmiany tu i tam, aby dodać funkcjonalność i kompatybilność - w tym za pomocą interfejsu API ustawień. Jednak bardzo krótka chwila na zapoznanie się z samouczkami na temat tego interfejsu API i poczułem się dość zdezorientowany, potem zamieszanie to pogłębiło się, gdy czytałem dalej i próbowałem zaimplementować przykłady - co było jeszcze trudniejsze, ponieważ moja wtyczka została zaimplementowana jako klasa .

O ile nie zrobię czegoś złego, z tego, co rozumiem, aby korzystać z interfejsu API ustawień, należy utworzyć nową funkcję NA USTAWIENIE. Oznacza to 3-5 funkcji dla przeciętnej wtyczki i do setek dla bardziej zaawansowanych wtyczek. Śmiesznie wydaje się pisanie tak wielu funkcji (i opracowanie systemu nazewnictwa, aby nie pomylić ich), gdy równie łatwo można zaimportować wszystkie odpowiednie $_POSTzmienne do tablicy i zrezygnować z całego bałaganu.

Być może jestem staroświecki, ale chyba że coś z tego zyskam, nie widzę powodu, aby trzykrotnie zwiększyć czterokrotnie ilość pisanego kodu. Oto jak zarządzałem opcjami przed próbą dodania API ustawień:

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

Teraz z interfejsem API ustawień mam coś więcej:

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

Prawdopodobnie boleśnie wynika z pasków przewijania, że ​​kod jest już dłuższy z tylko dwiema opcjami. Z komentarzy wynika, że ​​nie do końca rozumiem, co robię. Potem jest kwestia posiadania 5 nowych funkcji (i usunięcia tylko 1), aby to wszystko osiągnąć.

Więc jaką korzyść czerpię z całej tej dodatkowej pracy?

stevendesu
źródło
Nie używaj ich w takich przypadkach. Myślę, że są one przeznaczone dla początkujących PHP, którzy potrzebują 3-4 opcji w swoich wtyczkach / motywach. Jest to jeden z „funkcji”, które nigdy nie powinny zostały wdrożone ... To w zasadzie API dla innego API :)
onetrickpony
3
Używam interfejsu API ustawień do wszystkiego, co piszę, wszystko zależy od tego, jak go używasz, pamiętaj, że możesz używać interfejsu API nawet bez użycia, add_settings_sectiona add_settings_fieldte dwie funkcje dodają nadmiar kodu do twojego kodu bardziej niż cokolwiek innego, unikaj go i unikaj wzdęcia.
t31os
1
Robię to samo co t3los: zarejestruj samo ustawienie, a następnie po prostu koduję w formularzach HTML na mojej stronie ustawień. Jeśli chcesz zobaczyć naprawdę łatwy sposób na zrobienie tego i zachowanie kodu na później, sprawdź wtyczkę SEO WordPress firmy Yoast.
chrisguitarguy

Odpowiedzi:

8

Moim zdaniem, głównym celem i zaletą interfejsu API ustawień jest struktura .

Pomaga zachować złożone ustawienia ustawień:

  • uporządkowany (logika rejestracji i sekcje);
  • bezpieczne (nonces, sprawdzanie poprawności);
  • rozszerzalny (zaczepianie do innej strony lub pozwalanie na zaczepienie).

Jak w przypadku każdego takiego narzutu strukturalnego, przynosi korzyść bardziej złożonym przypadkom użycia i przynosi korzyści mniej prostym przypadkom.

Możesz więc zaimplementować wszystko, co robi API ustawień bez jego używania. Pytanie brzmi, czy możesz to osiągnąć w sposób tak niezawodny, bezpieczny i rozszerzalny.

Rarst
źródło
Wreszcie moja strona ustawień działa z pomocą tego samouczka: alisothegeek.com/2011/01/wordpress-settings-api-tutorial-1, a za pomocą instrukcji switch i funkcji pomocniczych muszę powiedzieć, że wszystko jest teraz bardziej uporządkowane w moim kodzie (co jest miłe, ponieważ planuję przejść z moich dwóch ustawień testowych do 15-20 ustawień ogółem).
stevendesu
1
@steven_desu tak, działającym żartem jest to, że każdy, kto korzysta z interfejsu API ustawień, pisze dla niego strukturę. :) Kilka funkcji pomocniczych jest prawie nieuniknionych. Należy również pamiętać, że interfejs API ustawień nie jest uważany za sfinalizowany i istnieją (niejasne) plany jego ulepszenia w przyszłości (myślę, że wspomniano o nim w kontekście planów 3.3).
Rarst
1
Mam nadzieję, że to się poprawi. Szczerze mówiąc, nie widzę żadnych korzyści z interfejsu API ustawień, ale raczej każda korzyść, z której się teraz cieszę, jest wynikiem architektury, którą dla niego pożyczyłem. Podoba mi się, że wszystkie elementy formularza są teraz generowane dynamicznie z takim samym wyglądem ... ale to nie jest interfejs API ustawień. Podoba mi się, że ustawienia domyślne i ustawienia rejestracji są obsługiwane przez te same definicje ... ale to nie jest interfejs API ustawień. Podoba mi się, że jQuery nie tylko sprawia, że ​​formularze są ładne, ale jest stopniowo ulepszany - ale musiałem ręcznie kodować ulepszenie progresywne ...
stevendesu
5

Jeśli prawidłowo używasz wywołań zwrotnych, nie ma potrzeby stosowania całego nadmiarowego kodu. Oto, w jaki sposób implementuję interfejs API ustawień w sposób całkowicie skalowalny .

Zalety (między innymi):

  • Interfejs API ustawień wymusza odkażanie niezaufanych danych użytkownika.
  • Interfejs API ustawień wymusza rejestrację opcji jako tablicę opcji, co powoduje powstanie pojedynczego wpisu DB wp_options, a nie dyskretnych wpisów DB dla każdej opcji
  • Interfejs API ustawień ułatwia zabezpieczenie formularza ustawień
  • Interfejs API ustawień ułatwia interfejs administratora zgodny z podstawowym interfejsem administratora, co zapewnia lepszy interfejs użytkownika
Chip Bennett
źródło
Więc w zasadzie wymusza bezpieczeństwo i standardy estetyczne, które już przestrzegałem bez jego pomocy? Przeczytam jednak samouczek, który połączyłeś. Jeśli to sprawia, że API Ustawienia tak proste, jak ręcznie kodowanie formy (lub łatwiej) to będę zaakceptować tę odpowiedź
stevendesu
Czy zdajesz sobie sprawę, że kod źródłowy, który wskazałeś, implementuje funkcje oenology_get_settings_by_tab()i oenology_get_default_optionsbez ich wcześniejszego definiowania? Myślałem, że było wystarczająco źle przy 209 wierszach kodu (po usunięciu komentarzy i pustych wierszy), ale kiedy te funkcje zostaną zdefiniowane, będzie jeszcze dłużej ... Dla czterech opcji?
stevendesu
Są zdefiniowane gdzie indziej. To oenology_get_settings_by_tab()nie jest tak naprawdę związane z tym, co robisz. Ale ty masz do definiowania znaczników forma-field gdzieś , tak jak ty masz na działania użytkownika validate / zdezynfekować jakoś , więc jeśli robisz to dobrze, trzeba cały ten sam kod, jak również.
Chip Bennett
0

Dzięki za opublikowanie tego, zastanawiałem się dokładnie nad tym samym. Wiele funkcji.

Aby je zmniejszyć, możesz przechowywać swoje opcje jako tablice. Wordpress serializuje dane za Ciebie. Oszczędza to kod (lub i tak działa), ale pogarsza dane. Na przykład, jeśli chcesz sortować, ręcznie edytować, eksportować itp. Swoje tabele, będą miały te szeregowane wartości. Z drugiej strony wtyczka dodaje mniej pozycji do tabeli opcji i łatwiej je oczyścić.

Więc oto twój kod jest gotowy. Kilka uwag:

  • Mój przykład pokazuje zarówno proste opcje (de_w, de_h), jak i opcję tablicy (de_width_height).
  • Zawsze odkażaj dane wprowadzone przez użytkownika. W tym przykładzie użyłem liczb całkowitych, ponieważ są one łatwe do dezynfekcji.
  • Podczas korzystania z interfejsu API ustawień nie potrzebujesz $ _POST, nonces, check_admin_referer (), update_option () itp.
  • Zapis odbywa się przy ładowaniu następnej strony, a nie przy wyłączaniu. Następnie WP przekierowuje na twoją stronę. Aby debugować, wydrukuj dane wyjściowe i wywołaj wp_die () w jednej z funkcji sprawdzania poprawności.
  • Formą akcji jest zawsze „options.php”. Tak działa interfejs API ustawień. Nie używaj niczego innego. Cóż, możesz użyć admin_url ('options.php'), jeśli chcesz.
  • WP wydrukuje dla ciebie wiadomość zapisu.
  • Ulepszenia nieuwzględnione tutaj: korzystanie <label>z ułatwień dostępu. Korzystanie z add_settings_error (), settings_error (), które obsługują zarówno komunikaty, jak i błędy. To często jedyny powód posiadania osobnych funkcji sprawdzania poprawności dla każdej opcji. Możesz zobaczyć poniżej validate_w () i validate_h () może być jedną funkcją. Patrzyłem na próbę wyodrębnienia wiadomości, ale nie pamiętam wystarczająco dużo informacji w wywołaniu zwrotnym sprawdzania poprawności. Jak na jakiej dziedzinie pracujesz.
  • Funkcje zwrotne sprawdzania poprawności otrzymują surową wartość $ _POST z interfejsu API ustawień. Chciałbym nazwać parametr jako taki, $ raw. W przypadku opcji tablicy otrzymujesz tablicę, taką jak magia.
  • Edycja: $ to jest lepsze niż & $ to.

Kod:

<?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
źródło