Exemplu de Settings API cu array-uri

20 mai 2013, 03:51:31
Vizualizări: 26.1K
Voturi: 40

Folosesc cartea Wrox despre dezvoltarea plugin-urilor WordPress ca referință principală pentru a începe un nou plugin și înțeleg că toate setările pot fi salvate într-un singur array, dar cartea nu oferă un exemplu în acest sens, iar toate exemplele pe care le găsesc pe web par foarte diferite unul de altul. A doua jumătate a articolului lui Konstantin mă ajută să mă apropii de ce am nevoie, dar mi-ar plăcea să văd un exemplu mai complet cu câmpuri multiple.

0
Toate răspunsurile la întrebare 1
10
43

Răspuns scurt: valorile atributului name trebuie să folosească schema option_name[array_key]. Deci, când folosești...

<input name="option_name[key1]">
<input name="option_name[key2]">

... obții un array ca valoare a opțiunii în funcția de validare:

array (
    'key1' => 'some value',
    'key2' => 'some other value'
)

PHP face asta pentru tine, nu este o funcționalitate WordPress. :)

Cum să faci asta să funcționeze cu Settings API?

Să presupunem că vrem această pagină de setări, iar toate valorile ar trebui stocate într-o singură opțiune și validate într-o singură funcție.

Descriere imagine aici

Pagina de opțiuni

Avem nevoie de hook-ul admin_menu și două funcții: una pentru înregistrarea paginii, una pentru afișarea conținutului.

add_action( 'admin_menu', 't5_sae_add_options_page' );

function t5_sae_add_options_page()
{
    add_options_page(
        'Exemplu T5 Settings API', // $page_title,
        'T5 SAE',                  // $menu_title,
        'manage_options',          // $capability,
        't5_sae_slug',             // $menu_slug
        't5_sae_render_page'       // Callback
    );
}

function t5_sae_render_page()
{
    ?>
    <div class="wrap">
        <h2><?php print $GLOBALS['title']; ?></h2>
        <form action="options.php" method="POST">
            <?php 
            settings_fields( 'plugin:t5_sae_option_group' );
            do_settings_sections( 't5_sae_slug' ); 
            submit_button(); 
            ?>
        </form>
    </div>
    <?php
}

Atributul action al formularului trebuie să fie options.php, altfel validarea nu va fi apelată. Uită-te la codul sursă PHP din wp-admin/options-permalink.php – există o capcană ascunsă do_settings_sections('permalink'); – dar nu poate funcționa pentru că atributul action al formularului este greșit.

Acum, înapoi la pagina noastră personalizată. O facem mai bună decât WordPress.

Înregistrarea setărilor, secțiunilor și câmpurilor

Folosim hook-ul admin_init când avem nevoie și apelăm o funcție de înregistrare.

if ( ! empty ( $GLOBALS['pagenow'] )
    and ( 'options-general.php' === $GLOBALS['pagenow']
        or 'options.php' === $GLOBALS['pagenow']
    )
)
{
    add_action( 'admin_init', 't5_sae_register_settings' );
}

Partea importantă aici este: $GLOBALS['pagenow'] trebuie să fie fie options-general.php (pentru afișare) fie options.php (pentru validare). Nu apela tot codul următor la fiecare cerere. Majoritatea tutorialelor și aproape toate plugin-urile greșesc acest lucru.

Bine, hai să înregistrăm ca nebunii:

  1. Preluăm valorile opțiunilor pentru pagina noastră și le comparăm cu niște valori implicite. Destul de simplu.

  2. Înregistrăm un grup de setări cu numele plugin:t5_sae_option_group. Îmi plac numele prefixate, sunt mai ușor de sortat și de înțeles în acest fel.

  3. Apoi înregistrăm două secțiuni, 1 și 2.

  4. Și adăugăm trei câmpuri, două pentru prima secțiune, unul pentru a doua. Transmitem numele opțiunii și valoarea escaped către funcțiile callback pentru fiecare câmp. Handlerele de output nu ar trebui să modifice datele, doar să adauge niște HTML.

function t5_sae_register_settings()
{
    $option_name   = 'plugin:t5_sae_option_name';

    // Preluăm opțiunile existente.
    $option_values = get_option( $option_name );

    $default_values = array (
        'number' => 500,
        'color'  => 'blue',
        'long'   => ''
    );

    // Parsăm valorile opțiunilor în chei predefinite, aruncăm restul.
    $data = shortcode_atts( $default_values, $option_values );

    register_setting(
        'plugin:t5_sae_option_group', // grup, folosit pentru settings_fields()
        $option_name,  // numele opțiunii, folosit ca cheie în baza de date
        't5_sae_validate_option'      // callback de validare
    );

    /* Niciun argument nu are legătură cu register_setting() anterior. */
    add_settings_section(
        'section_1', // ID
        'Câteva câmpuri text', // Titlu
        't5_sae_render_section_1', // afișează output
        't5_sae_slug' // menu slug, vezi t5_sae_add_options_page()
    );

    add_settings_field(
        'section_1_field_1',
        'Un număr',
        't5_sae_render_section_1_field_1',
        't5_sae_slug',  // menu slug, vezi t5_sae_add_options_page()
        'section_1',
        array (
            'label_for'   => 'label1', // face numele câmpului clickable,
            'name'        => 'number', // valoare pentru atributul 'name'
            'value'       => esc_attr( $data['number'] ),
            'option_name' => $option_name
        )
    );
    add_settings_field(
        'section_1_field_2',
        'Selectare',
        't5_sae_render_section_1_field_2',
        't5_sae_slug',  // menu slug, vezi t5_sae_add_options_page()
        'section_1',
        array (
            'label_for'   => 'label2', // face numele câmpului clickable,
            'name'        => 'color', // valoare pentru atributul 'name'
            'value'       => esc_attr( $data['color'] ),
            'options'     => array (
                'blue'  => 'Albastru',
                'red'   => 'Roșu',
                'black' => 'Negru'
            ),
            'option_name' => $option_name
        )
    );

    add_settings_section(
        'section_2', // ID
        'Textarea', // Titlu
        't5_sae_render_section_2', // afișează output
        't5_sae_slug' // menu slug, vezi t5_sae_add_options_page()
    );

    add_settings_field(
        'section_2_field_1',
        'Note',
        't5_sae_render_section_2_field_1',
        't5_sae_slug',  // menu slug, vezi t5_sae_add_options_page()
        'section_2',
        array (
            'label_for'   => 'label3', // face numele câmpului clickable,
            'name'        => 'long', // valoare pentru atributul 'name'
            'value'       => esc_textarea( $data['long'] ),
            'option_name' => $option_name
        )
    );
}

Toate acele handlere callback pentru secțiuni și câmpuri vor fi apelate automat când apelăm do_settings_sections( 't5_sae_slug' ); în pagina noastră. Am făcut asta deja, așa că trebuie doar să...

Afișăm câmpurile

Observă cum sunt construite atributul name: option_name transmis este prima parte, urmată de cheia array-ului în paranteze pătrate [].

function t5_sae_render_section_1()
{
    print '<p>Alege un număr între 1 și 1000 și alege o culoare.</p>';
}
function t5_sae_render_section_1_field_1( $args )
{
    /* Creează acest markup:
    /* <input name="plugin:t5_sae_option_name[number]"
     */
    printf(
        '<input name="%1$s[%2$s]" id="%3$s" value="%4$s" class="regular-text">',
        $args['option_name'],
        $args['name'],
        $args['label_for'],
        $args['value']
    );
    // t5_sae_debug_var( func_get_args(), __FUNCTION__ );
}
function t5_sae_render_section_1_field_2( $args )
{
    printf(
        '<select name="%1$s[%2$s]" id="%3$s">',
        $args['option_name'],
        $args['name'],
        $args['label_for']
    );

    foreach ( $args['options'] as $val => $title )
        printf(
            '<option value="%1$s" %2$s>%3$s</option>',
            $val,
            selected( $val, $args['value'], FALSE ),
            $title
        );

    print '</select>';

    // t5_sae_debug_var( func_get_args(), __FUNCTION__ );
}
function t5_sae_render_section_2()
{
    print '<p>Fă niște note.</p>';
}

function t5_sae_render_section_2_field_1( $args )
{
    printf(
        '<textarea name="%1$s[%2$s]" id="%3$s" rows="10" cols="30" class="code">%4$s</textarea>',
        $args['option_name'],
        $args['name'],
        $args['label_for'],
        $args['value']
    );
}

A, am introdus o funcție t5_sae_debug_var(). Iat-o:

function t5_sae_debug_var( $var, $before = '' )
{
    $export = esc_html( var_export( $var, TRUE ) );
    print "<pre>$before = $export</pre>";
}

Folositoare pentru a vedea dacă am obținut ceea ce ne așteptam.

Acum, asta funcționează destul de bine, avem nevoie doar de un lucru:

Validarea array-ului de opțiuni

Pentru că am folosit notația cu paranteze pătrate, valoarea noastră este un array. Trebuie doar să parcurgem fiecare element și să-l validăm.

function t5_sae_validate_option( $values )
{
    $default_values = array (
        'number' => 500,
        'color'  => 'blue',
        'long'   => ''
    );

    if ( ! is_array( $values ) ) // niște date dubioase
        return $default_values;

    $out = array ();

    foreach ( $default_values as $key => $value )
    {
        if ( empty ( $values[ $key ] ) )
        {
            $out[ $key ] = $value;
        }
        else
        {
            if ( 'number' === $key )
            {
                if ( 0 > $values[ $key ] )
                    add_settings_error(
                        'plugin:t5_sae_option_group',
                        'number-too-low',
                        'Numărul trebuie să fie între 1 și 1000.'
                    );
                elseif ( 1000 < $values[ $key ] )
                    add_settings_error(
                        'plugin:t5_sae_option_group',
                        'number-too-high',
                        'Numărul trebuie să fie între 1 și 1000.'
                    );
                else
                    $out[ $key ] = $values[ $key ];
            }
            elseif ( 'long' === $key )
            {
                $out[ $key ] = trim( $values[ $key ] );
            }
            else
            {
                $out[ $key ] = $values[ $key ];
            }
        }
    }

    return $out;
}

Asta e destul de urât; nu aș folosi un astfel de cod în producție. Dar face ce trebuie: returnează un array de valori validate. WordPress va serializa array-ul, îl va stoca sub numele opțiunii noastre în baza de date și îl va returna deserializat când apelăm get_option().


Toate acestea funcționează, dar sunt inutil de complicate, obținem markup din 1998 (<tr valign="top">), și multe redundanțe.

Folosește Settings API când trebuie. Ca alternativă, folosește admin_url( 'admin-post.php' ) ca acțiune a formularului (uită-te la codul sursă) și creează pagina de setări completă cu propriul tău cod, probabil mai elegant.

De fapt, trebuie să faci asta când scrii un plugin de rețea, pentru că Settings API nu funcționează acolo.

Există și câteva cazuri limită și părți incomplete pe care nu le-am menționat aici – le vei găsi când vei avea nevoie de ele. :)

21 mai 2013 02:17:42
Comentarii

Wow, mulțumesc. Aceasta este o informație foarte utilă. Niciunul dintre celelalte articole pe care le-am citit nu a menționat nimic despre plugin-urile de rețea, ceea ce este un aspect important pe care îl voi ține minte pentru viitor.

Bjorn Bjorn
21 mai 2013 08:37:58

Doar o completare la acest lucru. Dacă încercați să afișați/stocați căsuțe de bifat, am modificat codul de callback pentru a fi: '<input type="checkbox" id="%3$s" name="%1$s[%2$s] value="%4$s" ' . checked('on', $args['value'], false) . '/>'

joesk joesk
10 apr. 2014 19:25:41

Revizuind răspunsul, sunt nedumerit de utilizarea plugin:t5_sae_option_group care include un singur două puncte. Am căutat exhaustiv și nu am găsit nicio explicație pentru această sintaxă. Puteți indica o explicație pentru aceasta în documentația PHP, vă rog? Mulțumesc

User User
27 apr. 2014 17:41:47

@user50909 : acestea par a fi simpli identificatori de șiruri pentru mine. Sintaxa PHP nu ar trebui să fie un factor.

s_ha_dum s_ha_dum
27 apr. 2014 18:04:13

@user50909 Doua puncte sunt doar un marcator în șir. Fac mai ușor să găsești toate opțiunile mele în baza de date.

fuxia fuxia
27 apr. 2014 18:06:52

Pentru multisite, $GLOBALS['pagenow'] pare să fie întotdeauna gol. Ce ar trebui să verificăm înainte de a lega admin_init pentru a înregistra setările?

Dan Dan
26 mai 2014 16:45:11

@Dan Încearcă basename( $_SERVER['REQUEST_URI'] ).

fuxia fuxia
26 mai 2014 16:48:48

Mulțumesc! Șirul de interogare strica lucrurile așa că a trebuit să-l elimin înainte să funcționeze, dar în rest perfect.

Dan Dan
26 mai 2014 18:03:08

Este minunat, foarte bine structurat!

Mike C Mike C
22 feb. 2023 18:09:57

Salut @fuxia, ai menționat despre evitarea înregistrării setărilor atunci când nu ești pe pagina necesară și ai spus că majoritatea dezvoltatorilor greșesc și le înregistrează întotdeauna. Poți să elaborezi? Evitarea execuției de cod care nu este necesar pe pagina curentă sună ca ceva pozitiv. Totuși, nu ar fi și asta o practică proastă care rupe funcționalitatea de bază? Funcția register_option() adaugă opțiunea într-o variabilă globală WordPress care poate fi obținută prin get_registered_settings(). De ce ar adăuga ei o astfel de funcție dacă nu ar trebui să ne înregistrăm întotdeauna setările? Mulțumesc :)

Gerard Reches Gerard Reches
9 ian. 2024 04:38:25
Arată celelalte 5 comentarii