WordPress Plugin Entwicklung Tutorial #2

WordPress Plugin Entwicklung Tutorial Teil 1

WordPress Plugin Entwicklung Tutorial #2

Im ersten Teil dieses Tutorials haben wir uns mit einigen Grundlagen von WordPress-Plugins auseinandergesetzt. Dabei sind wir kurz auf das WordPress Plugin Boilerplate eingegangen. In diesem Teil wollen wir nun eine Einstellungs-Seite für das Plugin erstellen. Um dem Tutorial besser folgen zu können, stellen wir euch den Quellcode in diesem Git-Repository zur Verfügung. Dieses Repository werden wir mit den zukünftigen Beiträgen dieser Reihe weiterentwickeln.

Was ist eine Einstellungs-Seite?

Bei einer Einstellungs-Seite handelt es sich um eine Ansicht, mit der vordefinierte Einstellungen vorgenommen werden können.
Hierzu wird bei WordPress ein Formular verwendet, das seine Felder beim Absenden an die options.php aus dem WordPress-Framework sendet. In dieser werden die Feld-Werte entgegen genommen und ein Validierungsprozess gestartet. Die validierten Felder werden dann in einem neuen Eintrag in der wp_options-Tabelle festgehalten.
Alternativ könnte man auch ein eigenes Formular in HTML erstellen und ausgeben. Dafür muss als Form-Action einfach „options.php“ angegeben werden. Wenn ihr dies ausprobiert, werdet ihr aber schnell feststellen, dass die Einstellungen nicht in der Datenbank persistiert werden. Ihr müsst eure Einstellungen zunächst bei WordPress registrieren und einen Validierungs-Callback angeben. Dafür wird die funktion register_setting aus der Settings-API verwendet. Diese API bietet euch noch weitere Funktionen, deren Nutzung die Erstellung von Einstellungs-Seiten vereinfacht und auch sicherer macht.

Die WordPress Settings-API

WordPress stellt eine ganze Sammlung von Funktionen zur Verfügung, um das Erstellen von Einstellungs-Seiten zu vereinheitlichen und viele der Prozesse zu abstrahieren. Die Verwendung dieser Funktionen bietet eine Reihe von Vorteilen, auf die wir hier zunächst einmal eingehen wollen.

Vereinheitlichung: Die Funktionen erstellen standardisierte Strukturen, die man bereits aus dem WordPress Backend kennt. Zusätzlich werden die Standard-Eingabeüberprüfungen von WordPress automatisch angewandt.

Zeitersparnis: Anstatt ein eigenes Formular zu erstellen und zu stylen, kann man mit der Verwendung von wenigen Funktionen komplexe Einstellungs-Formulare erstellen.

Sicherheit: Eingabefelder bringen immer ein kleines Risiko mit sich, da sie eine simple Schnittstelle zum Server darstellen. Es gibt viele rudimentäre Angriffsstrategien, die versuchen über Freitextfelder Skripte auf dem Server auszulösen. Im WordPress-Core werden daher auf alle Eingaben Filterfunktionen angewandt, die solche unsicheren Eingaben herausfiltern. Die Settings-API bietet simple Möglichkeiten, eine Validierung und ein Bereinigen der Eingaben zu realisieren.

Settings Struktur

Die Settings-API verwendet zur Verwaltung der Einstellungen drei Strukturen: Fields, Sections und Settings. Diese sind hierarchisch aufgebaut und ermöglichen es, die Optionen vernünftig zu gruppieren.

Settings: Die Settings gruppieren eine Sammlung von einzelnen Einstellungen in ein zusammenhängendes Gerüst. Es ist die oberste Ebene der Settings-API. Gleichzeitig stellen sie die Referenz für die Einstellungen dar. Im Regelfall hat man einen Settings-Eintrag pro Einstellungs-Seite.

Sections: Die Sections stellen eine logische bzw. semantische Gruppierung von Einstellungen dar. Sie werden visuell von einander abgehoben und können ineinander verschachtelt werden, um das Formular zu strukturieren. Jede Einstellungs-Seite hat mindestens eine Section.

Fields: Die Fields sind die einzelnen Eingabefelder und werden einer Section zugeordnet. Gleichzeitig stellen sie die einzelnen Werte der Einstellungen dar.

Verwendung der Settings-API

Jetzt haben wir einen kleinen Überblick über die Settings-API bekommen und wollen diese nun auch in unserem Plugin verwenden. Bleiben wir bei dem Beispiel eines Sliders für Beiträge mit eigenen Inhaltstypen. Ihr solltet euch zunächst einmal Gedanken darüber machen, welche Einstellungen der Anwender unseres Plugins vornehmen können soll.
Als Eingabefelder möchten wir ein Textfeld für den Inhaltstypen, eine Checkbox für automatisches Sliden und ein Textfeld für das Timing des automatischen Slidens anbieten. Dies sind unsere Fields.
Nun gruppieren wir diese Fields logisch und definieren somit die Sections. In diesem Fall bietet es sich an, die beiden Felder für das automatische Sliden einer Gruppe zuzuordnen. Auf diesem Weg bekommt das Textfeld für den Inhaltstyp eine eigene Section.

Anlegen einer Plugin Optionsseite

Bevor wir die Einstellungen hinzufügen, registrieren wir zunächst eine Optionsseite bei WordPress. Es gibt verschiedene Stellen, an denen man eine Optionsseite hinzufügen kann. In diesem Fall beschränken wir uns auf eine Unterseite des Plugin Menüs. Hierfür verwenden wir die Funktion add_plugins_page und fügen zwei Methoden in der Klasse Pm_Example_Admin (/admin/class-pm-example-admin.php) hinzu.

/**
 * Register the settings page in admin area.
 *
 * @since    1.0.0
 */
public function add_settings_page(){
  add_plugins_page(
    'The P&M example settings page',
    'P&M Example Settings',
    'manage_options',
    $this->plugin_name,
    array( $this, 'display_settings_page' ) );
}

/**
 * Display the settings page in admin area.
 *
 * @since    1.0.0
 */
public function display_settings_page(){
  ?>
  <div class="wrap">
    <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
    <?php settings_errors(); ?>
    <form action="options.php" method="post">
  
    </form>
  </div>
  <?php
}

Die Methode display_settings_page wird hier verwendet, um ein HTML-Grundgerüst für die Einstellungsseite zu erzeugen. Dieses müssen wir später noch um die Einstellungs-Felder erweitern. Die Klasse wrap sorgt dafür, dass alle Elemente des Formulars die bekannte Darstellung aus dem WordPress-Backend erhalten.

Wenn ihr jetzt das Backend neu ladet, werdet ihr feststellen, dass die Optionsseite nicht in der Admin-Sidebar unter dem Punkt Plugins erscheint. Das liegt daran, dass WordPress noch keine Aufforderung erhalten hat, diese Methode auch aufzurufen. Hierfür müssen wir einen sogenannten Hook verwenden. Hooks sind vordefinierte Einstiegspunkte, an die man Funktionen binden kann. In einem späteren Teil dieser Reihe werden wir noch genauer auf die Hooks eingehen. Für die Generierung des Admin-Menüs gibt es beispielsweise den Hook admin_menu. Mit diesem kann die Admin-Sidebar erweitert werden, bevor sie fertig generiert wird. Das Plugin Boilerplate bietet die Methode define_admin_hooks in der Klasse Pm_Example (/includes/class-pm-example.php). Diese erweitern wir um folgende Zeile:

$this->loader->add_action( 'admin_menu', $plugin_admin, 'add_settings_page' );

Nun wird beim Aufbau der Admin-Sidebar unsere Optionsseite registriert und sollte jetzt auch als Unterseite im Plugins-Menüpunkt erscheinen. Als nächstes können wir die Einstellungen mit Hilfe der Settings-API anlegen.

Anlegen von Einstellungen

Wir definieren zuallererst eine neue Methode add_settings in der Admin-Klasse, mit der wir die Registrierung von Sections, Fields und Settings handhaben. In dieser wollen wir zunächst einen Options-Eintrag in der Datenbank anlegen und die Settings registrieren.

/**
 * Register all the settings, fields and sections.
 *
 * @since    1.0.0
 */
public function add_settings(){
  // Create the option first if not done already.
  add_option( 'pm_example_settings_group' );

  // register settings in WP
  register_setting(
    'pm_example_settings_group',
    'pm_example_settings_name'
  );
}

Mit dem Aufruf von add_option legen wir einen Eintrag für die Options-Gruppe pm_example_settings_group in der Datenbank für die Einstellungen an. Dieser Gruppe können wir im Folgenden Sections und Fields zuweisen. Der Aufruf von register_setting weist der Gruppe eine Option mit dem Namen pm_example_settings_name zu.

Damit diese Methode auch aufgerufen wird, müssen wir wieder einen Hook verwenden. In diesem Fall verwenden wir admin_init. Dieser wird immer angewandt, wenn das Backend geladen wird. Die define_admin_hooks sieht nun wie folgt aus:

private function define_admin_hooks() {

    $plugin_admin = new Pm_Example_Admin( $this->get_plugin_name(), $this->get_version() );

    $this->loader->add_action( 
'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
    $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
    $this->loader->add_action( 'admin_menu', $plugin_admin, 'add_settings_page' );
    $this->loader->add_action( 'admin_init', $plugin_admin, 'add_settings' );

  }

Anlegen von Sections

Jetzt, nachdem wir die Optionen angelegt haben, beginnen wir mit dem Hinzufügen einer Section. Hierfür wird die Funktion add_settings_section verwendet. Diese rufen wir in der add_settings-Methode der Admin-Klasse auf, nachdem die Options-Gruppe registriert wurde.

public function add_settings(){
    // Create the option first if not done already.
    add_option( 'pm_example_settings_group' );

    // add settings section for post-type
    add_settings_section(
      'pm_example_posttype_section',
      'Inhaltstyp',
      array( $this, 'render_settings_section' ),
      'pm_example_settings_group'
    );

    // register all sections and fields in WP
    register_setting(
      'pm_example_settings_group',
      'pm_example_settings_name'
    );

}

Der erste Parameter stellt hierbei eine Referenz auf die Section dar, der zweite Parameter ist die Überschrift der Section. Das Array des dritten Parameters wird als Callback verwendet, um zwischen der Überschrift und den Feldern der Section noch zusätzliche Inhalte zu erzeugen. Es wird hier ein Array verwendet, um eine Objektmethode zu referenzieren. Diese Methode muss demnach in der Admin-Klasse ergänzt werden und kann für dieses Beispiel erst einmal leer bleiben. Der letzte Parameter ordnet die Section einer Optionsgruppe zu.

Damit unsere Section nun auch angezeigt wird, müssen wir die Methode display_settings_page noch ein wenig erweitern und dort die registrierten Einstellungen laden.

/**
 * Display the settings page in admin area.
 *
 * @since    1.0.0
 */
public function display_settings_page(){
  ?>
  <div class="wrap">
    <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
    <?php settings_errors(); ?>
    <form action="options.php" method="post">
      <?php
      settings_fields( 'pm_example_settings_group' );

      do_settings_sections( 'pm_example_settings_group' );

      submit_button( 'Save Settings' );
      ?>
    </form>
  </div>
  <?php
}

Anlegen von Fields

Diese so erstellte Section kann nun dazu verwendet werden, Einstellungsfelder zu gruppieren und anzuzeigen. Für das Erstellen eines Fields bietet die Settings-API die Funktion add_settings_field.

// add the field for a post-type input
add_settings_field(
  'slider_posttype',
  'Inhaltstyp für den Slider',
  array( $this, 'render_text_input' ),
  'pm_example_settings_group',
  'pm_example_posttype_section',
  array(
    'option'    => 'slider_posttype'
  )
);

Diese Funktion ist nahezu identisch mit der add_settings_section, bietet aber zwei zusätzliche Parameter. Der erste neue Parameter stellt eine Zuordnung zu einer Section dar (hier mit dem Wert ‚pm_example_posttype_section‘). Der letzte Parameter ermöglicht es der Funktion zum Rendern des Fields zusätzliche Daten in Form eines Arrays bekannt zu geben. Hier übergeben wir den Optionsnamen, um eine generische Funktion für das Erstellen von Text-Inputs zu ermöglichen.

/**
 * Renders input for a text field.
 *
 * This uses the parameter exposed to the callback of add_settings_field to get the option name.
 *
 * @since    1.0.0
 */
public function render_text_input( $args ) {
  $options = get_option( 'pm_example_settings_name' );
  $value = ( isset( $options[ $args['option'] ] )? $options[ $args['option'] ] : '' );
  $html = '<input type="text" id="pm_example_settings_name['. $args['option'] .']" name="pm_example_settings_name['. $args['option'] .']" value="'. $value .'"/>';

  echo $html;
}

Die Funktion zum Erstellen des Texteingabe-Feldes zieht sich zunächst über get_option die bisher gespeicherten Einstellungen. Dies ist in unserem Fall ein assoziatives Array mit dem Feldnamen als Schlüssel. Den Feldnamen bekommen wir über den Schlüssel ‚option‘ aus dem $args-Array. Nun können wir prüfen, ob es bereits einen Wert für das Feld gibt und dann ein input-Feld erstellen. Der Name muss hier mit angegeben werden, damit der Bezug zu der registrierten Settings-Gruppe und dem entsprechenden Feld hergestellt werden kann.

Wordpress Plugin Entwicklung - Beispiel Settings Page

Zusammenfassung

Wir haben unser erstes funktionierendes Einstellungs-Feld angelegt und können auch auf die Einstellung zugreifen. Den Quellcode für die zweite Section und die noch fehlenden Fields könnt ihr unserem Repository entnehmen. In diesem Teil haben wir bewusst auf komplexere Eingabe-Elemente und eine eigene Validierungs-Methode verzichtet. In einem späteren Teil dieser Reihe werden wir aber noch einmal auf die Einstellungs-Seite zurück kommen und diese verfeinern. Zuerst werden wir uns aber weiter mit dem WordPress-Framework vertraut machen und unser Beispiel-Plugin weiter entwickeln.

Ausblick

In Teil 3 unserer Reihe werden wir uns mit den posttypes, der wichtigsten Datenstruktur von WordPress, beschäftigen und auch eigene posttypes anlegen.

P&M Agentur – Softwareentwicklung & IT Consulting