Einstellungs-API mit Beispiel für Arrays

32

Ich verwende das Wrox WordPress-Plugin-Entwicklungsbuch als Hauptreferenz für die ersten Schritte mit einem neuen Plugin und ich verstehe, dass alle Einstellungen als 1 Array gespeichert werden können, aber das Buch gibt kein Beispiel dafür und all das, was ich bin Das Finden im Web scheint von Beispiel zu Beispiel so unterschiedlich zu sein. Die zweite Hälfte eines Beitrags von Konstantin bringt mich näher, aber ich würde wirklich gerne ein vollständigeres Beispiel mit mehreren Feldern sehen.

Björn
quelle

Antworten:

32

Kurze Antwort: Ihre nameAttributwerte müssen das Schema verwenden option_name[array_key]. Also, wenn Sie verwenden ...

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

… Erhalten Sie in Ihrer Validierungsfunktion ein Array als Optionswert:

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

PHP erledigt das für Sie, dies ist keine WordPress-Funktion. :)

Wie funktioniert das mit der Einstellungs-API?

Angenommen, wir möchten diese Optionsseite, und alle Werte sollten in einer Option gespeichert und in einer Funktion validiert werden.

Bildbeschreibung hier eingeben

Die Optionsseite

Wir brauchen den Hook admin_menuund zwei Funktionen: eine zum Registrieren der Seite, eine zum Rendern der Ausgabe.

add_action( 'admin_menu', 't5_sae_add_options_page' );

function t5_sae_add_options_page()
{
    add_options_page(
        'T5 Settings API Example', // $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
}

Das Formular actionmuss sein options.php, sonst wird die Validierung nicht aufgerufen. Schauen Sie sich die PHP-Quelle von an wp-admin/options-permalink.php- es gibt eine versteckte Falle do_settings_sections('permalink');- aber es kann nicht funktionieren, weil das Formular actionfalsch ist.

Nun zurück zu unserer benutzerdefinierten Seite. Wir machen es besser als WordPress.

Registrieren Sie Einstellungen, Abschnitte und Felder

Wir melden admin_init uns bei Bedarf an und rufen eine Registrierungsfunktion auf.

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

Der wichtige Teil hier ist: $GLOBALS['pagenow']muss entweder options-general.php(für die Ausgabe) oder options.php(für die Validierung) sein. Rufen Sie nicht bei jeder Anforderung den gesamten folgenden Code auf. Die meisten Tutorials und fast alle Plugins verstehen das falsch.

Okay, lass uns registrieren wie verrückt:

  1. Wir rufen die Optionswerte für unsere Seite ab und analysieren sie anhand einiger Standardwerte. Ziemlich einfach.

  2. Wir registrieren eine Einstellungsgruppe mit dem Namen plugin:t5_sae_option_group. Ich mag Präfixnamen, sie sind einfacher zu sortieren und auf diese Weise zu verstehen.

  3. Dann registrieren wir zwei Abschnitte, 1 und 2.

  4. Und wir fügen drei Abschnitte hinzu, zwei für den ersten Abschnitt und einen für den zweiten. Wir übergeben den Optionsnamen und den maskierten Wert an die Rückruffunktionen für jedes Feld. Ausgabehandler sollten keine Daten ändern, sondern nur HTML hinzufügen.

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

    // Fetch existing options.
    $option_values = get_option( $option_name );

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

    // Parse option values into predefined keys, throw the rest away.
    $data = shortcode_atts( $default_values, $option_values );

    register_setting(
        'plugin:t5_sae_option_group', // group, used for settings_fields()
        $option_name,  // option name, used as key in database
        't5_sae_validate_option'      // validation callback
    );

    /* No argument has any relation to the prvious register_setting(). */
    add_settings_section(
        'section_1', // ID
        'Some text fields', // Title
        't5_sae_render_section_1', // print output
        't5_sae_slug' // menu slug, see t5_sae_add_options_page()
    );

    add_settings_field(
        'section_1_field_1',
        'A Number',
        't5_sae_render_section_1_field_1',
        't5_sae_slug',  // menu slug, see t5_sae_add_options_page()
        'section_1',
        array (
            'label_for'   => 'label1', // makes the field name clickable,
            'name'        => 'number', // value for 'name' attribute
            'value'       => esc_attr( $data['number'] ),
            'option_name' => $option_name
        )
    );
    add_settings_field(
        'section_1_field_2',
        'Select',
        't5_sae_render_section_1_field_2',
        't5_sae_slug',  // menu slug, see t5_sae_add_options_page()
        'section_1',
        array (
            'label_for'   => 'label2', // makes the field name clickable,
            'name'        => 'color', // value for 'name' attribute
            'value'       => esc_attr( $data['color'] ),
            'options'     => array (
                'blue'  => 'Blue',
                'red'   => 'Red',
                'black' => 'Black'
            ),
            'option_name' => $option_name
        )
    );

    add_settings_section(
        'section_2', // ID
        'Textarea', // Title
        't5_sae_render_section_2', // print output
        't5_sae_slug' // menu slug, see t5_sae_add_options_page()
    );

    add_settings_field(
        'section_2_field_1',
        'Notes',
        't5_sae_render_section_2_field_1',
        't5_sae_slug',  // menu slug, see t5_sae_add_options_page()
        'section_2',
        array (
            'label_for'   => 'label3', // makes the field name clickable,
            'name'        => 'long', // value for 'name' attribute
            'value'       => esc_textarea( $data['long'] ),
            'option_name' => $option_name
        )
    );
}

Alle diese Callback-Handler für die Abschnitte und Felder werden automatisch aufgerufen, wenn wir do_settings_sections( 't5_sae_slug' );unsere Seite aufrufen. Das haben wir schon gemacht, also müssen wir nur ...

Drucken Sie die Felder aus

Beachten Sie, wie die nameAttribute aufgebaut sind: Der übergebene Teil option_nameist der erste Teil, der Array-Schlüssel folgt in eckigen Klammern [].

function t5_sae_render_section_1()
{
    print '<p>Pick a number between 1 and 1000, and choose a color.</p>';
}
function t5_sae_render_section_1_field_1( $args )
{
    /* Creates this 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>Makes some notes.</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']
    );
}

Oh, ich habe eine Funktion eingeführt t5_sae_debug_var(). Hier ist es:

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

Nützlich, um zu sehen, ob wir das bekommen haben, was wir erwartet hatten.

Das funktioniert ganz gut, wir brauchen nur eins:

Überprüfen Sie das Optionsarray

Da wir die Klammernotation verwendet haben, ist unser Wert ein Array. Wir müssen nur durch jedes Element gehen und es validieren.

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

    if ( ! is_array( $values ) ) // some bogus data
        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',
                        'Number must be between 1 and 1000.'
                    );
                elseif ( 1000 < $values[ $key ] )
                    add_settings_error(
                        'plugin:t5_sae_option_group',
                        'number-too-high',
                        'Number must be between 1 and 1000.'
                    );
                else
                    $out[ $key ] = $values[ $key ];
            }
            elseif ( 'long' === $key )
            {
                $out[ $key ] = trim( $values[ $key ] );
            }
            else
            {
                $out[ $key ] = $values[ $key ];
            }
        }
    }

    return $out;
}

Das ist ziemlich hässlich; Ich würde solchen Code nicht in der Produktion verwenden. Aber es tut, was es sollte: Es gibt ein validiertes Array von Werten zurück. WordPress serialisiert das Array, speichert es unter unserem Optionsnamen in der Datenbank und gibt es unserialisiert zurück, wenn wir anrufen get_option().


All dies funktioniert, aber es ist unnötig kompliziert, wir bekommen Markup von 1998 ( <tr valign="top">) und viele Redundanzen.

Verwenden Sie die Einstellungs-API, wenn Sie müssen. Alternativ können Sie admin_url( 'admin-post.php' )als Formularaktion (siehe Quelle) die vollständige Einstellungsseite mit Ihrem eigenen, wahrscheinlich eleganteren Code erstellen.

Tatsächlich müssen Sie dies tun, wenn Sie ein Netzwerk-Plugin schreiben, da die Einstellungs-API dort nicht funktioniert.

Es gibt auch einige Randfälle und unvollständige Teile, die ich hier nicht erwähnt habe - Sie werden sie finden, wenn Sie sie brauchen. :)

fuxia
quelle
Wow, danke. Das ist sehr hilfreich. In keinem der anderen Posts, die ich gelesen habe, wurde etwas über Netzwerk-Plugins erwähnt. Dies ist ein wichtiger Hinweis, den ich für die Zukunft berücksichtigen werde.
Bjorn
Nur ein Nachtrag dazu. Wenn Sie versuchen, Kontrollkästchen anzuzeigen / zu speichern, habe ich den Rückrufcode folgendermaßen geändert: '<input type = "checkbox" id = "% 3 $ s" name = "% 1 $ s [% 2 $ s] value =" % 4 $ s "'. Checked (' on ', $ args [' value '], false).' /> '
joesk
Überprüfung der Antwort Ich bin verwundert über die Verwendung des Plugins: t5_sae_option_group, das einen einzelnen Doppelpunkt enthält. Ich habe mich eingehend umgesehen und keine Erklärung für diese Syntax gefunden. Könnten Sie bitte auf eine Erklärung in der PHP-Dokumentation verweisen? Thanks
@ user50909: diese sehen für mich wie einfache String-Bezeichner aus. PHP-Syntax sollte kein Faktor sein.
s_ha_dum
1
@Dan Try basename( $_SERVER['REQUEST_URI'] ).
Fuxia