Skip to content
This repository has been archived by the owner on Sep 7, 2020. It is now read-only.

1. WordPress Plugin für die THK Projektbörse

andreaspaulick edited this page Mar 20, 2019 · 5 revisions

Willkommen auf der Wiki-Seite zum Praxisprojekt "Datenmigration zwischen WordPress und der neuen Projekt- und Themenbörse der TH Köln". Hier werden die funktionalen- und technischen Details des WordPress Plugin erörtert.

Table of Contents

Hintergrund und Motivation

Problemstellung

Die ursprüngliche Projektbörse die sich an der TH Köln bisher im Produktiveinsatz befand und über die Dozenten diverse Projekte (Informatikprojekte, Praxisprojekte, Bachelor- und Masterarbeiten) für interessierte Studenten anbieten können, wurde nur wenig genutzt. Die Gründe dafür zu analysieren und eine neue, verbesserte Version dieser Projektbörse zu erstellen ist aktuell Gegenstand eines "Guided Project" im Master Studiengang.

Im Rahmen dieses Guided-Projects zur Neuauflage der Projekt- und Themenbörse[1] konnte durch Befragung verschiedener Dozenten festgestellt werden, dass unter anderem ein Grund für die Unbeliebtheit der alten Projektbörse der Umstand ist, dass Dozenten befürchten, dass der Bezug des von ihnen angebotenen Projektes zur eigenen Person leidet- bzw. verloren geht, wenn dieses nur auf der zentralen Projektbörse veröffentlicht wird. Es wurde der Wunsch geäußert, dass das Projekt auch noch zusätzlich auf der Webseite des jeweiligen Dozenten oder anderen System der TH Köln (z.B. Ilias) veröffentlicht werden soll.

Lösungsansatz

Dieser Umstand bringt nun die Unannehmlichkeit mit, dass der Dozent an zwei verschiedenen Stellen das gleiche Projekt einstellen muss. Hier setzt nun die Idee an, diesen Prozess zu vereinfachen und zu automatisieren. Ein Projekt soll mit möglichst wenig Aufwand von einem genutzten Content-Management-System in die Projektbörse übermittelt werden. Auch die andere Richtung (Projektbörse → CMS) soll möglich sein.

Analysephase

Probleme bei der Datenmigration

An der TH werden viele verschiedene Systeme zur Datenhaltung verwendet was die Migration der Daten zur Herausforderung machen kann. Gründe dafür können die folgenden sein:

  • Datenredundanzen: Zentrale Datenhaltung existiert nur bedingt
  • sich ändernde Schnittstellen
  • Schnittstellendaten sind nicht notwendigerweise uniform (JSON, HTML, XML etc.)
  • ein System welches die Migration der Daten übernimmt sollte "Out Of The Box" funktionieren
    • keine/wenige zusätzliche Abhängigkeiten (lose Kopplung)
    • Notwendigkeit der Installation zusätzlicher Software verringert die Akzeptanz
  • die Anpassung von Open-Source-Systemen kann aufwendig sein
  • Proprietäre Software kann gegebenenfalls nicht zur Verwendung angepasst werden
  • Autorisierung
    • es gibt viele verschiedene Autorisierungsarten
    • inkompatible- bzw. nicht unterstützte Autorisierungsarten zwischen zwei Systemen
    • zum Praxisprojektstart unklare Autorisierungssituation der Projektbörse
    • die Softwaresicherheit ist ein sehr umfangreiches Thema in der Informatik, Implementierungen sind mitunter aufwendig

An der TH genutzten Systeme

Durch Umfragen haben sich hauptsächlich folgende genutzte Datenhaltungssysteme an der TH Köln herauskristallisiert:

System Art Erweiterbar
WordPress Open Source Ja (Plugins)
Ilias Open Source Ja (Plugins)
PSSO Proprietär ?
HOPS ? ?

WordPress

WordPress ist ein kostenloses Werkzeug (ein sogenanntes "Content-Management-System") welches sich unter anderem für die Erstellung von Blogs, Webseiten, Fotoblogs und Business-Webseiten eignet.[2] Es bietet ein umfangreiches Plugin-System[3] und ist gut anpassbar. Seit der Version 4.7 ist die REST-API fester Bestandteil von WordPress (vorher nur über Plugin möglich).[4]

Ilias

Ilias ist das an der TH genutzte Learning Management System, welches unter anderem die Möglichkeit bietet, dass Dozenten Gruppen zu Modulen zu erstellen können, in denen sich die Studenten einschreiben können. Es kann Kursmaterial angeboten werden, oder es können Dateien eingestellt werden, die beispielsweise zur Benotung gedacht sind. Ilias ist Open-Source-Software und es ist Plugin-fähig.[5]

PSSO

PSSO ist das Hochschul-Informations-Service-Portal der TH Köln. Es handelt sich hier um ein System zur Studiums- und Prüfungsverwaltung. Der Student kann sich dort unter anderem eine Liste seiner Module ausgeben lassen, die zu seinem Studiengang und seiner Prüfungsordnung gehören.

HOPS

HOPS steht für "Hochschul-Planungs-System" und wurde TH-intern von Prof. Dr. Heide Faeskorn-Woyke und Andre Kaspers entwickelt. HOPS ist eine Datenbank die mittels Relationen die Beziehungen zwischen den verschiedenen, an der TH relevanten Daten (Module, Räume, Dozenten, Semester, Studiengang etc.) abbildet. Daraus können beispielsweise Stundenpläne, Raumpläne generiert werden. HOPS bietet APIs an, die auch von der Projektbörse genutzt werden können.

Auswahl des geeigneten Systems

Aufgrund der hohen Nutzungsrate, der Open-Source-Lizenz, der Möglichkeit die Programmfunktionalität durch Plugins zu erweitern, sowie dem Umstand, dass in einem zeitlich begrenzten Praxisprojekt nicht alle Systeme berücksichtigt werden können, habe ich mich hier nach Rücksprache mit meinem betreuenden Professor auf die Entwicklung einer geeigneten Softwarelösung für WordPress beschränkt.

Analyse des WordPress Ökosystem

Projekt Grundidee

Da WordPress eine umfangreiche Unterstützung für Plugins[3] bietet, soll nun die Erstellung von als Projekt ausgezeichneten Beiträgen durch ein solches Plugin ermöglicht werden. Die Datenübertragung erfolgt über REST-Schnittstellen im JSON-Format.

Die Idee aus Richtung des WordPress Plugins ist, dass man weiterhin mittels des gewohnten WordPress-Beitrags-Editors normale Beiträge (Posts) für alle Beiträge die keine Projekte darstellen, erstellen kann. Erstellt der Benutzer jedoch einen Beitrag, der ein Projekt beschreiben soll, so kann er diesen als "Projekt" auszeichnen. Als Projekt ausgezeichnete Beiträge können neben den von normalen Beiträgen gewohnten Eigenschaften wie "Titel" und "Inhalt" auch noch weitere, ganz individuelle Metadaten besitzen (denkbar wären etwa Attribute wie "Projektstatus", "Start-/Enddatum", "Modulzugehörigkeit", "Teilnehmerzahl" etc.). Diese Projektbeiträge werden nicht nur in die WordPress Beitragsdatenbank aufgenommen, sondern werden auch zusätzlich automatisch per REST-Aufruf an die entsprechende Schnittstelle der Projektbörse gesendet, wo das Projekt dann hinzugefügt wird.

WP REST API

Endpunkte und Permalinks

In WordPress v4.7+ ist die REST-API standardmäßig aktiviert.

In den WordPress Einstellungen unter dem Menüpunkt "Permalinks" kann der Benutzer auswählen, ob er "hübsche" oder Standardlinks zu seinen Beiträgen benutzen möchte.

Standard Permalink:

 http://example.com/?p=N

Hierbei steht N für die Beitrags-ID.

"Pretty Permalink":

 http://example.com/2012/12/30/post-name

Je nach Benutzereinstellung setzt sich der Link zu WordPress Beiträgen hier z.B. aus dem Beitragstitel und Beitragsdatum zusammen.

Die Standard-Permalinks funktionieren immer, die "Pretty Permalinks" können je nach Webserver nicht- oder nur nach zusätzlicher Konfiguration[6] funktionieren.

Die Einstellungen der Art der Beitragslinks hat direkte Auswirkung auf die URL zu der WordPress API.[7] Die folgende Tabelle stellt beispielhaft einige Endpunkte für eine lokale Installation für die verschiedenen Linktypen zusammen:

Standard Pretty Permalinks
Einstiegspunkt http://localhost/?rest_route=/ http://localhost/wp-json/
Posts http://localhost/?rest_route=/wp/v2/posts/ http://localhost/wp-json/wp/v2/posts
Kategorien http://localhost/?rest_route=/wp/v2/categories http://localhost/wp-json/wp/v2/categories
Tags http://localhost/?rest_route=/wp/v2/tags http://localhost/wp-json/wp/v2/tags

Eine vollständige Liste aller verfügbaren Endpunkte ist hier einsehbar.

WordPress Authentifizierungsarten

Um über die WordPress API kritische Anfragen (z.B. POST, DELETE etc.) auszuführen, muss sich der Nutzer- bzw. der Klient vor WordPress authentifizieren. WordPress unterstützt im Auslieferungszustand nur die Cookie-Authentifizierung[8], es können jedoch mehrere, verschiedene Authentifizierungsmechanismen über das Plugin-System hinzugefügt werden, welche autorisierte Zugriffe auf die API ermöglichen.

Nachfolgend seien hier die wichtigsten Autorisierung-Mechanismen genannt:

Authentifizierungsplugin: JSON Basic Authentication

Dieses Plugin wird von dem WordPress API Team zu Verfügung gestellt und ermöglicht die Standardautorisierung. Hierbei werden die WordPress-Zugangsdaten (Name, Passwort) bei jeder Anfrage im Header als Base64-String übermittelt. Diese Art der Autorisierung ist jedoch außerhalb von SSL-Verbindungen nicht sicher, und daher ist von einem Einsatz in Produktivumgebungen dringend abzuraten.

Link: Basic Auth Plugin

Authentifizierungsplugin: OAuth 1.0a

Dieses Plugin wird ebenfalls vom WordPress Team bereitgestellt. Es ermöglicht einen Zugriff auf die geschützten Serverbereiche über ein Zugangstoken, welches über einen wechselseitigen (Server-Client) Autorisierungsfluss generiert wird. Dieses Zugangstoken kann im Header jeder Anfrage übermittelt werden.

OAuth 1: Autorisierungsfluss

OAuth 1.0a WordPress Plugin: Installation

Das offizielle Plugin "WordPress REST API – OAuth 1.0a Server" kann über die WP-Plugins-Weboberfläche, oder per Konsole installiert werden.

Für eine Installation über die Konsole empfiehlt es sich, das Git-Repository zu klonen. Im WordPress Plugins-Verzeichnis wird dafür folgendes eingegeben:

git clone https://github.com/WP-API/OAuth1.git

Nachdem das Plugin installiert wurde, muss es noch in der Weboberfläche aktiviert werden: Plugins → Installed Plugins → "Activate" Ob die Installation erfolgreich war, kann über das Hauptverzeichnis der REST Schnittstelle geprüft werden:

Standard Pretty Permalinks
http://{hostname}/wordpress/?rest_route=/ http://{hostname}/wordpress/wp-json/
Unter dem Punkt "authentication" → "oauth1" sollten jetzt 3 Links (request/authorize/access) und die Versionsinformation sichtbar sein:

Schlüssel erzeugen: allgemeiner Ablauf

Für den OAuth Authentifizierungsablauf, muss zunächst einmal ein Klient in WordPress erstellt werden. Als WordPress Administrator kann im Dashbord dazu wie folgt vorgegangen werden:

  1. Users → Applications → "Add New"
  2. wähle einen Klienten-Namen, eine Beschreibung (optional) und eine Callback-URL (wird bei Erzeugung der temporären Zugangsdaten benötigt)
  3. nach Abschluss erhält man einen Klienten-Schlüssel und ein Klient-Geheimnis welche die Grundlage zur Erstellung einen Zugangstoken bilden
  4. um ein temporäres Schlüsselpaar zu erhalten, wird ein POST auf die Request-URL (.../oauth1/request) von WordPress mit dem aus dem vorigen Schritt erhaltenen Klient-Schlüssel und Klient-Geheimnis im Request-Header ausgeführt. Als Antwort erhalten wie die temporären Zugangsdaten (oauth_token, oauth_token_secret).
  5. oauth_token und oauth_token_secret müssen nun an den Autorisierungs-Endpunkt von WordPress gesendet werden. Hier dazu ein Beispiel: http://localhost/wordpress/oauth1/authorize?oauth_token=5FNKorhbeeB3OOuZYIdZ8Fsb&oauth_token_secret=FgcO4L4mjDnooggL3kC57bsfApjsWaUctApmYHF0kT7H8KOp
  6. im Folgenden wird der Klient durch den Benutzer autorisiert und man erhält das "Verifizierungstoken"
  7. das Verifizierungstoken aus dem vorherigen Schritt übergeben wir der .../oauth1/access URL von Wordpress als Parameter. Weiterhin geben wir als "Consumer Key" und "Consumer Secret" unsere in WordPress erhaltenen Token, und für "Access Token" und "Token Secret" die in Schritt 1 erhaltenen, temporären Token im Autorisierungs-Header des folgenden Requests ein und führen ein "POST" aus
  8. als Antwort erhalten wir nun unser permanentes Zugangstoken (Access-Token)
  9. nach dem vorherigen Schritt verlieren die temporären Token ihre Gültigkeit. Daher muss der Autorisierungsfluss komplett neu gestartet werden, sollte bis dahin ein Fehler im Ablauf aufgetreten sein
  10. mittels des permanenten Zugriffstoken können wir nun zum Beispiel Posts in WordPress über die REST Schnittstelle erzeugen. Dazu geben wir im Autorisierungs-Header den Consumer Key+Secret, unser permanentes Zugriffstoken + Secret, sowie als Body ein geeignetes JSON ein

Authentifizierungsplugin: OAuth2

Zum Zeitpunkt dieses Praxisprojekt wurde das offizielle OAuth2-WordPress-Plugin auf der Github-Seite als nicht funktionierende Beta-Version beschrieben[9]. Diese Aussage wurde am 14. Februar 2019 geändert[10], für mein Projekt dabei allerdings bereits nicht mehr berücksichtigt.

Authentifizierungsplugin: OAuth Single Sign On - SSO (OAuth client)

Um WordPress um OAuth2-Funktionalität zu erweitern, kann das Plugin "OAuth Single Sign On - SSO (OAuth client)" benutzt werden. Es ist aus der offiziellen Plugin-Datenbank von WordPress zu beziehen (Link am Ende dieses Abschnitts). Einige Funktionen sind der Bezahlversion vorenthalten. In der kostenlosen Grundversion unterstützt das Plugin lediglich eine Applikation, sowie eingeschränktes Attribut-Mapping und keine Rollen-Mappings.

Konfiguration

In Keycloak muss ein Client vom "Access-Type" "Confidential" angelegt werden:

Außerdem ist noch die Redirect-URI zu WordPress anzugeben:

Die Seite kann nun gespeichert werden. Daraufhin erscheint die Registrierkarte "Credentials" am oberen Bildschirmrand. In dieser Registrierkarte wählt man nun den Client Authenticator "Client-Id and Secret" aus und erhält das Geheimnis das wir später für die Konfiguration des WordPress-OAuth-Plugins benötigen. In der Registrierkarte "Roles" ist nun noch die Rolle "user" hinzuzufügen und zu speichern.

Über das WordPress Dashbord sind jetzt die Einstellungen für das OAuth2-Plugin vorzunehmen: Im Menü "miniOrange OAauth" klickt man nun auf "Configure OAuth" und danach auf "Add Application". Die folgenden Einstellungen sind anzupassen:

Die Pfade zu den geforderten Endpunkten können der Keycloak Dokumentation entnommen werden. Jetzt kann gespeichert werden. Sollten die Eingaben korrekt sein, sollte die Schaltfläche "Test Configuration" jetzt eine Tabelle mit Attributsnamen und Attributswerten des Keycloak Klienten angezeigt werden. Davon sind die Schlüsselnamen (nicht die Werte) für "Email" und "First Name" in das entsprechende Feld der Plugin-Einstellungen einzutragen:

Nach dem speichern muss jetzt noch das "miniOrange OAuth Widged" in die Blog-Sidebar gezogen werden. Dafür besucht man die Widgets-Seite von WordPress: Appearance → Widgets

Link zum Plugin

Authentifizierungsplugin: OpenID Connect Generic

Dieses Plugin bietet ähnliche Funktionalität wie das miniOrange Plugin. Bei der Konfiguration kann analog zu dem oben beschriebenen OAuth2-Plugin vorgegangen werden.

Das Einstellungsmenü ist über "Settings" → "OpenID Connect Client" in WordPress zu erreichen.

Link

Implementierung

WordPress Plugin auszeichnen

WordPress Plugins sind ganz normale PHP-Scripte mit spezieller Kommentarnotation im Kopf. Sobald diese definiert ist, wird das Plugin von WordPress erkannt, sobald es sich in dem Unterordner ../wp-content/plugins von WordPress befindet (üblicherweise in einem Unterordner der den gleichen Namen trägt wie das Plugin).

Der Kommentarkopf dient zusätzlich noch dazu, Informationen über das Plugin zu vermitteln. Eine vollständige Liste der erlaubten Schlüssel findet sich hier.

Für dieses Plugin sieht die Notation zum Beispiel wie folgt aus:

projektboerse.php:

<?php
/*
 * Plugin Name: TH Köln Projektbörse Beitragskloner
 * Description: Sendet als Projekt markierte Beiträge nach dem veröffentlichen automatisch an die Projektbörse der TH Köln.
 * Author: Andreas Paulick
 * Author URI: https://github.com/andreaspaulick
 * Version: 0.1
 * Plugin URI: 
 */

// Implementierung ...

API Aufruf nach Beitragsveröffentlichung

Die Kernfunktionalität dieses Plugin bildet die WordPress Aktion publish_post.[11] Sie führt immer dann eine angegebene Funktion aus, wenn ein WordPress Beitrag den Status "publish" (der Beitrag wird veröffentlicht) erhält. Die Funktion wird durch die Aktion add_action aufgerufen:

projektboerse.php:

 function post_published_api_call( $ID, $post) {
     // do something ...
 }
 add_action( 'publish_post', 'post_published_api_call', 10, 2);
Wenn ein Post veröffentlicht wird, so wird die Funktion post_published_api_call aufgerufen. Das dritte Argument von add_action ist die Ausführungsreihenfolge (hier Standardpriorität "10") und die Anzahl der Argumente der Funktion.

Die Aufgabe der Funktion post_published_api_call besitzt zwei Parameter. Die $ID bezieht sich auf die Beitrags-ID und $post ist eine Variable vom Typ WP_Post über die diverse Eigenschaften des aktuellen Beitrags abgerufen werden können.[12] Die Funktion liest z.B. Titel und Inhalt des aktuellen Beitrags aus

projektboerse.php:

 $title = $post->post_title;
 $content = wp_strip_all_tags($post->post_content);
(wp_strip_all_tags() wird benutzt, da ein WordPress-Beitrag eine eigene Formatierungssyntax benutzt, die keinem Standard entspricht und in der Projektbörse nutzlos wäre. Daher wird durch diese Funktion konsequent alle WP-Syntax entfernt)

Jetzt baut die Funktion daraus ein Array mit der Grundstruktur des späteren JSON

projektboerse.php:

 $post_data = array(
                'status' => 'publish',
                'title' => $title,
                'content' => $content,
                'course' => get_post_meta($post->ID, '_pb_wporg_meta_key1', true),
                'start' => get_post_meta($post->ID, '_pb_wporg_meta_key2', true),
                'end' => get_post_meta($post->ID, '_pb_wporg_meta_key3', true),
                'max_party' => get_post_meta($post->ID, '_pb_wporg_meta_key4', true),
                'tags' => wp_strip_all_tags(get_the_tag_list(, ',', , $post->ID)),
                'user_login' => wp_get_current_user()->user_login
            );
wandelt mittels json_encode() das Array in das JSON-Format um

projektboerse.php:

 $json_post = json_encode($post_data);
und sendet das JSON letztendlich mittels der WP-Funktion wp_remote_post() an die in den Einstellungen gespeicherte API (in diesem Beispiel ist der Server durch OpenID-Connect geschützt, weshalb im Header ein Bearer-Token mitgesendet wird)

projektboerse.php:

  $data = wp_remote_post($url, array(
                'headers' => array( 'Content-Type' => 'application/json; charset=utf-8',
                    'Authorization' => 'Bearer ' . $keycloak_access_token),
                'body' => $json_post,
                'method' => 'POST'
            ));

Projekt-Metadaten erfassen

Projekte zeichnen sich durch bestimmte Eigenschaften aus. Manche teilen sie sich mit normalen WordPress-Beiträgen (z.B. "Titel", "Inhalt" und "Status"), andere wiederum sind eher Projektspezifisch (z.B. "Teilnehmerzahl", "Starttermin", "Modul", "Studiengang" etc.). Da WordPress die Anforderung an TH-Projektbeiträge nicht unterstützt, werden die zusätzlichen Anforderungen hier durch sogenannte Metaboxen realisiert. Metaboxen können den eigenen Anforderungen nach modelliert werden. Der Vorteil von Metaboxen ist, dass die PHP-Kerndateien wie zum Beispiel der Beitragseditor nicht verändern werden muss. Metaboxen können in verschiedene Bereiche der Benutzeroberfläche eingefügt werden.

Eine Metabox definieren:

projektboerse.php:

 function pb_wporg_add_custom_box()
 {
     $screens = ['post', 'wporg_cpt'];         // Defines on what screens the Metaboxes are shown
     foreach ($screens as $screen) {
         add_meta_box(
             'studiengang_wporg_box_id',       // Unique ID
             'THK Projektbörse: Projektdaten', // Box title
             'pb_custom_box_html',             // Content callback, must be of type callable
             $screen                           // Post type
         );
     }
 }
 add_action('add_meta_boxes', 'pb_wporg_add_custom_box');
In diesem Fall wird die Metabox über die Aktion add_meta_boxes hinzugefügt. In der Funktion pb_wporg_add_custom_box() werden die grundlegenden Eigenschaften definiert. Zuerst auf welchen Seiten sie von WordPress dargestellt werden sollen (in diesem Fall "post" und "wporg_cpt"). Danach wird die ID, der angezeigte Titel, die Callback-Funktion und der Post-Typ festgelegt.

Anschließend wird die Callback-Funktion pb_custom_box_html() aufgerufen, welche die Darstellung der in der Metabox vorkommenden Elemente übernimmt. Es handelt sich um übliches HTML, welches in bestimmten Bereichen um PHP-Funktionalität erweitert wird.

projektboerse.php:

 function pb_custom_box_html($post)
 {
     $meta = get_post_meta( $post->ID );
     $checkbox_value = ( isset( $meta['checkbox_value'][0] ) &&  '1' === $meta['checkbox_value'][0] ) ? 1 : 0;
     ?>
     <p>
         <label><input type="checkbox" name="checkbox_value" value="1" <?php checked( $checkbox_value, 1 ); ?> />Kopie dieses Beitrags an Projektbörse senden?</label>
     </p>
     <hr>
     <p>
         <label for="pb_wporg_course">Studiengang</label>
         <select name="pb_wporg_course[]" id="pb_wporg_course" class="postbox" multiple="multiple" size="6">
             <?php
                 $data = get_pb_courses();  // get all the courses via REST-API
                 foreach($data as $key => $item){
             ?>
                 <option value="<?php echo $key;?>"><?php echo $item; ?></option>
             <?php
                 }
             ?>
         </select>
     </p>
     <p>
         <?php   ?>
         <label for="pb_wporg_project_start">Projektstart:</label>
         <input type="date" name="pb_wporg_project_start" id="pb_wporg_project_start" value="<?php echo get_post_meta($post->ID, '_pb_wporg_meta_key2', true);  ?>">
     </p>
     <p>
         <label for="pb_wporg_project_end">Projektende:</label>
         <input type="date" name="pb_wporg_project_end" id="pb_wporg_project_end" value="<?php echo get_post_meta($post->ID, '_pb_wporg_meta_key3', true);  ?>">
     </p>
     <p>
         <label for="pb_wporg_project_max_participants">Teilnehmerbegrenzung:</label>
         <input type="number" name="pb_wporg_project_max_participants" id="pb_wporg_project_max_participants" value="<?php echo get_post_meta($post->ID, '_pb_wporg_meta_key4', true);  ?>" size="2" min="1" max="999">
     </p>
     <?php
 }
Es wird eine Checkbox definiert, die steuert ob der Beitrag auch an die Projektbörse gesendet werden soll. Anschließend wird über eine REST-API der Projektbörse die Liste der verfügbaren Studiengänge eingeholt, aufbereitet und in einem Mehrfachauswahl-Dropdown-Feld angezeigt. Es folgen noch diverse Beispiele für weitere Eingaben (Start-/Enddatum, Teilnehmerbegrenzung).

Metadaten speichern

Die Metadaten müssen einzeln in sogenannte "Meta-Keys" gespeichert werden. Um dies zu ermöglichen, definiert man am besten eine Funktion und führt sie immer genau dann aus, wenn auch die Basisfunktion des Plugin auslöst (hier: wenn Beiträge den Status "publish" erhalten:

projektboerse.php:

function pb_wporg_save_postdata($post_id)
{
   // save code here ...
}
add_action('publish_post', 'pb_wporg_save_postdata', 9);
Wichtig ist hier die Priorität (in unserem Fall "9"). Die Priorität regelt die Ausführungsreihenfolge der Aktion. Die Aktion publish_post wird zusätzlich auch noch in der bereits beschriebenen Funktion post_published_api_call benutzt und schickt letztendlich alle Daten an eine REST-API. Die Metadaten müssen aber erst abschließend erfasst und gespeichert werden, um dann versendet werden zu können. Daher müssen wir der Funktion pb_wporg_save_postdata eine höhere Priorität als post_published_api_call zumessen. Aktionen mit kleineren Prioritäten werden eher ausgeführt als Aktionen mit höheren Werten.


Der folgende Quellcode zeigt die Speicherung verschiedener HTML Elemente (Checkbox, Input-Fields etc.). Dazu wird die Funktion update_post_meta(<PostID>,<Meta-Key>,<$_POST-Input-Variable>) benutzt:

projektboerse.php:

function pb_wporg_save_postdata($post_id)
{

    // checkbox
    $checkbox_value = ( isset( $_POST['checkbox_value'] ) && '1' === $_POST['checkbox_value'] ) ? 1 : 0; // Input var okay.
    update_post_meta( $post_id, '_pb_wporg_meta_key0', esc_attr( $checkbox_value ) );

    // study course
    if (array_key_exists('pb_wporg_course', $_POST)) {
        update_post_meta(
            $post_id,
            '_pb_wporg_meta_key1',
            implode(', ', $_POST['pb_wporg_course']) // array to single string
        );
    }

    // project start
    if (array_key_exists('pb_wporg_project_start', $_POST)) {
        update_post_meta(
            $post_id,
            '_pb_wporg_meta_key2',
            $_POST['pb_wporg_project_start']
        );
    }

    // project end
    if (array_key_exists('pb_wporg_project_end', $_POST)) {
        update_post_meta(
            $post_id,
            '_pb_wporg_meta_key3',
            $_POST['pb_wporg_project_end']
        );
    }

    // project maximum participants
    if (array_key_exists('pb_wporg_project_max_participants', $_POST)) {
        update_post_meta(
            $post_id,
            '_pb_wporg_meta_key4',
            sanitize_text_field($_POST['pb_wporg_project_max_participants'])
        );
    }

}
add_action('publish_post', 'pb_wporg_save_postdata', 9);

Metadaten auslesen

Um die Meta-Keys auszulesen wird die Funktion get_post_meta() benutzt:

get_post_meta($post->ID, '_pb_wporg_meta_key1', true),
Der erste Parameter bezieht sich auf den aktuellen Beitrag, der zweite Parameter gibt den Namen des gewünschten Meta-Schlüssels an und der dritte Parameter besagt, dass es sich um einen einzelnen Wert handelt (bei "false" wird ein Array mit allen für den Schlüssel gespeicherten Werten zurückgegeben).

Beiträge als Projekte auszeichnen

Zu Beginn des Projektes war die Idee dem Beitragseditor eine Schaltfläche hinzuzufügen, die zwei Zustände unterschied: "An" und "Aus". Wurde die Schaltfläche aktiviert, so wurde der Beitrag als Projekt ausgezeichnet und an die Projektbörse gesandt. Dies hatte diverse Nachteile:

  1. eine Implementierung gelang mir nur bei dem alten Editor (TinyMCE). Ab WordPress Version 5 ist jedoch im Auslieferungszustand der neue Beitragseditor "Gutenberg" an Bord, für den zum Zeitpunkt dieses Projekts noch keine umfangreiche Dokumentation vorlag
  2. für die Schaltflächenlogik musste eine JavaScript-Datei hinzugefügt werden
  3. der Datenaustausch zwischen dem serverseitigen PHP und dem klientseitigen JavaScript ist nicht trivial, jedoch zwingend notwendig (Zustand der JavaScript-Schaltfläche muss an PHP übermittelt werden).
Aus den soeben genannten Gründen wurde die abgeschlossene Umsetzung der "Projektauszeichnung eines Beitrages durch die JavaScript Schaltfläche" verworfen, und durch eine Checkbox in der Metabox ersetzt. Vorteilhaft daran ist, dass die Metabox nur einmal definiert werden muss, sie aber unabhängig vom dem durch den Benutzer verwendeten Beitragseditor funktioniert.

Der Vollständigkeit halber hier die Implementierung einer TinyMCE-Schaltfläche innerhalb des WordPress-Beitragseditorfensters:

Deaktivierung des Gutenberg-Editors (falls dieser in WordPress Versionen >=5.0 verwendet wird):

projektboerse.php:

 // disable gutenberg for posts
    add_filter('use_block_editor_for_post', '__return_false', 10);
  // disable gutenberg for post types
    add_filter('use_block_editor_for_post_type', '__return_false', 10);

Den Button definieren:

projektboerse.php:

 add_action( 'init', 'pb_buttons' );  // on plugin initialization, call "pb_buttons" function
 function pb_buttons() {
     add_filter( "mce_external_plugins", "pboerse_add_button" ); // hook for TinyMCE Plugins
     add_filter( 'mce_buttons', 'pboerse_register_button' );     // hook for TinyMCE Buttons
 }
 function pboerse_add_button( $plugin_array ) {
     $plugin_array['pboerse'] = plugin_dir_url() . '/pb_button.js'; // link to button-javascript
     return $plugin_array;
 }
 function pboerse_register_button( $buttons ) {
     array_push( $buttons, 'pb_button1' );    // register new button
     return $buttons;
 }

Buttonlogik

pb_button.js:

 (function() {
    tinymce.create('tinymce.plugins.pboerse', {
        init : function(ed, url) {
            var state; 
            
             ed.addButton('pb_button1', {
                text : 'PB',
                title : 'Auf Projektbörse veröffentlichen?',
                cmd : 'pb_button1',
                onclick: function () {
                },
                onpostrender: function() {
                    var btn = this;
                    ed.on('pb_button1', function(e) {
                        btn.active(e.state);
                    });
                }
            });
            ed.addCommand('pb_button1', function() {
                state = !state; /* Switching state */
                ed.fire('pb_button1', {state: state});
                if (state){
                    /* Button active */
                    document.getElementById("i-am-hidden").value = "1";
                }
                else {
                    /* Button inactive */
                    document.getElementById("i-am-hidden").value = "0";
                }
            });
        },
        createControl : function(n, cm) {
            return null;
        },
        getInfo : function() {
            return {
                longname : 'PB Buttons',
                author : 'A. Paulick',
                authorurl : 'https://github.com/andreaspaulick',
                infourl : ,
                version : "0.1"
            };
        }
    });
    // Register plugin
    tinymce.PluginManager.add( 'pboerse', tinymce.plugins.pboerse );
 })();

Um den Zustand der JavaScript-Schaltfläche auszulesen ist es empfehlenswert, ein verstecktes Eingabefeld zu definieren. Dazu ändern wir in der JavaScript Datei den Wert von "i-am-hidden" je nach Zustand (siehe Code oben).

projektboerse.php:

add_action( 'post_submitbox_misc_actions', 'wpse325418_my_custom_hidden_field' );
function wpse325418_my_custom_hidden_field() {
    echo "<input id='i-am-hidden' name='publish-to-somewhere' type='hidden' value='0' />";
}
Der Wert des versteckten Eingabefeldes kann in PHP nun mittels $_POST Variable ausgelesen werden:
$_POST['publish-to-somewhere']

Studiengänge aus Projektbörse ermitteln

Ein Projekt soll einem Studiengang zugeordnet werden können. Da die Studiengang-Datenhaltung nicht Aufgabe dieses Plugins ist, werden sämtliche, externe Metadaten bei Bedarf aus der Projektbörse ermittelt. Hierzu gehören unter anderem auch die Studiengänge. In der folgenden Funktion werden die später benötigten Daten für ein Multi-Dropdown Feld in der Metabox ermittelt und aufbereitet:

projektboerse.php:

function get_pb_courses() {
    $url = rtrim(get_option('pb_api_url', array('pb_api_url' => DEFAULT_API_URL))['pb_url'], '/') . '/studyCourses';

    $response = wp_remote_get($url); // get study courses from PB API
    $response_body = json_decode($response['body'], TRUE); // we only need the body of the response
    if($response_body['status']===404) // if status=404 the api was not found
        return array("ERROR: Could not retrieve API data...");

    $courses = array_column_recursive($response_body,'name'); // go get all study courses
    $degree = array_column_recursive($response_body, 'academicDegree'); // get the academic degree of all couses

    $id = array();

    // dirty implementation to get the ID of each course (which in fact is the self href in the projektbörse api)
    for ($i = 0; $i < count($courses); $i++) {
        array_push($id, $response_body['_embedded']['studyCourses'][$i]['_links']['self']['href']);
    }

    // we substitute the index number-key (0, 1, 2, ...) of the course array with the "href-ID" of the API as the key
    for ($i = 0; $i < count($courses); $i++) {
        $courses[$i] = $courses[$i].' ('.$degree[$i].')'; // course name + academic degree = new full course name

        // key substitution:
        $courses[$id[$i]] = $courses[$i];
        unset($courses[$i]);
    }

   return $courses;
}

In dieser Implementierung wird die Antwort der Projektbörse-API gespeichert und die notwendigen Daten (Namen aller Studiengänge, der dazugehörige akademische Grad, sowie URL+UUID) extrahiert. Um die Server-Antwort nach Schlüssel-Werte-Paaren zu durchforsten, kann die PHP-Funktion array_column() nicht verwendet werden, da das Antwort-JSON in ein mehrfach-verschachteltes PHP-Array umgewandelt wird und array_column liefert nur Werte bis zur Tiefe 1. Um dieses Problem zu umgehen greife ich auf die rekursive Implementierung von Nino Skopac array_column_recursive[13] zurück:

projektboerse.php:

function array_column_recursive(array $haystack, $needle) {
    $found = [];
    array_walk_recursive($haystack, function($value, $key) use (&$found, $needle) {
        if ($key == $needle)
            $found[] = $value;
    });
    return $found;
}
Mithilfe dieser Implementierung werden alle Schlüssel-Werte-Paare ermittelt.

Abschließend gibt die Funktion get_pb_courses() ein Array mit dem Aufbau ID => Studiengang (AKADEMISCHER GRAD) zurück.

WordPress Tags entfernen

Die WordPress-Beitrags-Syntax unterscheidet sich stark von üblichen Auszeichnungselementen wie etwa HTML. Daher ist es notwendig diese spezielle Syntax entweder auf die speziellen Bedürfnisse der Projektbörse anzupassen, oder aber komplett zu entfernen und nur unformatierten Text zu übermitteln. In diesem Plugin werden beide Wege berücksichtigt.

Anpassung der Syntax:

projektboerse.php:

function wp_post_to_html($wp_post_content){
    $remove_tags = str_replace("","", str_replace("","", $wp_post_content));
    $replace_line_breaks = str_replace("\n","", str_replace("\n\n", "<br />", $remove_tags));
    $remove_p = str_replace("</p>","", str_replace("<p>", "", $replace_line_breaks));
    return $remove_p;
}
Dies ist eine nicht vollständige, rekursive Beispielimplementierung zur Umwandlung der WordPress Syntax in HTML Elemente. Nicht berücksichtigt wird hier beispielsweise die Syntax um Bilder in den Beitrag einzubetten.

Letztendlich habe ich mich dazu entschlossen, alle Tags komplett zu entfernen. Der Grund dafür ist, dass zum Zeitpunkt dieses Praxisprojekts noch nicht absehbar ist, welche Syntax für welches Element in der finalen Version der Projektbörse verwendet wird. Um Beiträge komplett von Formatierungen zu befreien, bietet WordPress die Funktion wp_strip_all_tags. Eine Beispielimplementierung wäre folgende:

$content = wp_strip_all_tags($post->post_content);
Dies hat allerdings auch zur Folge, dass in den Beitrag eingebettete Bilder nicht an die Projektbörse gesendet werden.

OpenID-Connect geschützte Server

Auf lange Sicht sollen alle an der TH existierenden Dienste durch eine Single-Sign-On Lösung geschützt werden. Dazu soll Keycloak verwendet werden. Aus diesem Grund soll das WordPress-Plugin fähig sein, mit dieser Autorisierungstechnologie umzugehen. Aktuell werden die Benutzer-Zugangsdaten sowie der Klient-Name und der OpenID-Connect Token-Endpoint in den Plugin-Einstellungen hinterlegt. Wird die OIDC-Funktion aktiviert, so versucht das Plugin sich am Token-Endpoint von Keycloak zu autorisieren, um im Austausch ein Zugangstoken zu erlangen. Dieses Zugangstoken wird dann bei jeder Anfrage an die durch OIDC geschützte Projektbörse im Header mitgegeben. Somit ist es möglich, auf die geschützten Bereiche des Servers zuzugreifen.

Es sei hier noch angemerkt, dass die offizielle Testinstanz der Projektbörse zum Zeitpunkt dieses Projekts noch keinerlei Autorisierungsmechanismen implementiert hat. Aus diesem Grund wurde für dieses Projekt eine Projektbörse mit den elementarsten Funktionen nachgebildet.[14] Eine Unterstützung für Keycloak ist vorhanden.

Access Token erhalten

Um das Access-Token anzufordern, muss eine HTTP-Anfrage mit den Zugangsdaten im Body an den Token-Endpoint von Keycloak gesendet werden:

projektboerse.php:

function get_keycloak_token_response(){

    $kc_url = get_option('token_api_url', array('token_url' => DEFAULT_KEYCLOAK_API_URL))['token_url'];
    $kc_clientid = get_option('token_api_clientid')['token_clientid'];
    $kc_username = get_option('token_api_username')['token_username'];
    $kc_password = get_option('token_api_password')['token_password'];

    // if URL does not start with 'http' return error message
    if(strpos($kc_url,"http" )===false)
        return "URL_MALFORMED";

    $request_body = array(
        'client_id' => $kc_clientid,
        'username' => $kc_username,
        'password' => $kc_password,
        'grant_type' => 'password'
    );

    $response = wp_remote_post($kc_url, array(
        'headers' => array( 'Content-Type' => 'application/x-www-form-urlencoded'),
        'body' => http_build_query($request_body),
        'method' => 'POST'
    ));

    if ( is_wp_error( $response ) ) {
        $error_message = $response->get_error_message();
        return $error_message;
    }
    else if($response['response']['code']!==200)
        return "TOKEN_REQUEST_ERROR";

    return $response;
}

Aus der Serverantwort kann jetzt nach Bedarf das "Access-Token" oder das "Refresh-Token" extrahiert werden. Hier wird in erster Linie das "Access-Token" benötigt:

projektboerse.php:

function extract_keycloak_access_token($response){

    if($response==="TOKEN_REQUEST_ERROR")
        return $response;

    $kc_response = json_decode($response['body']); // JSON to array

    return $kc_response->access_token; // return access-token
}

Wurde der Projekt-Beitrag gesendet, sollte die Keycloak Session zurückgesetzt werden. Dafür wird das "Refresh-Token" benötigt. Um die Session zu beenden muss der Klientname und das Refresh-Token im Body der Anfrage an den "logout" Endpunkt des Keycloak Server via HTTP-Anfrage gesendet werden:

projektboerse.php:

function keycloak_session_logout($keycloak_token_response) {

    if($keycloak_token_response==="TOKEN_REQUEST_ERROR")
        return $keycloak_token_response;

    $kc_clientid = get_option('token_api_clientid')['token_clientid'];
    $refresh_token = json_decode($keycloak_token_response['body'])->refresh_token;  // get refresh-token

    $url = preg_replace("/\btoken$/","logout", get_option('token_api_url', array('token_url' => DEFAULT_KEYCLOAK_API_URL))['token_url']); // replace "token" endpoint with "logout" endpoint from Token-URL

    $data = wp_remote_post($url, array(
        'headers' => array( 'Content-Type' => 'application/x-www-form-urlencoded'),
        'body' => http_build_query(array(
            'client_id' => $kc_clientid,
            'refresh_token' => $refresh_token)),
        'method' => 'POST'
    ));
}

Access Token verwenden

Beispiel zur Verwendung des Access-Tokens zur Autorisierung einer Anfrage unter Verwendung der oben beschriebenen Funktionen:

$token_response = get_keycloak_token_response();
$keycloak_access_token = extract_keycloak_access_token($token_response);

$data = wp_remote_post($url, array(
   'headers' => array( 'Content-Type' => 'application/json; charset=utf-8',
                       'Authorization' => 'Bearer ' . $keycloak_access_token),
   'body' =>  // body goes here
   'method' => 'POST'
));

//logout session
keycloak_session_logout($token_response);

Plugin-Einstellungen

WordPress bietet Entwicklern die Möglichkeit, Einstellungsseiten zu definieren auf denen der Benutzer das Plugin nach den eigenen Wünschen und Bedürfnissen konfigurieren kann.

Man kann den Code dafür entweder in derselben Datei schreiben, in der auch die Plugin-Funktionalität implementiert ist, oder aber man definiert dafür eine separate PHP-Datei. Der Übersichtlichkeit halber habe ich mich hier für die zweite Möglichkeit entschieden.

Einstellungen in einer separaten Datei

Die PHP-Datei mit den Einstellungen (pb_options.php) wird hier im gleichen Verzeichnis abgelegt, wie die Haupt-Plugin-Datei (projektboerse.php). Jetzt wird nur noch das Script mit den Einstellungen importiert:

projektboerse.php:

include 'pb_options.php';
// ...

Formular definieren

Wir definieren ein HTML-Formularfeld:

pb_options.php:

<?php
function pb_options_page_html($post_data)
{
    // check user capabilities
    if (!current_user_can('manage_options')) {
        return;
    }
    ?>
    <div class="wrap">
        <h1><?= esc_html(get_admin_page_title()); // get Page Title ?></h1>  
        <form action="options.php" method="post">
            <?php
            settings_fields( 'pb_settings_input' );
            do_settings_sections( 'pb_settings_input' );
            //submit_button( 'Speichern' );

            submit_button( 'Einstellungen Speichern' );
            ?>
        </form>
        <form action="<?php echo admin_url( 'admin-post.php' ); ?>" onsubmit="target_popup(this)">
            <input type="hidden" name="action" value="tokencheck534547">
            <?php submit_button( 'Teste Tokenanforderung', 'secondary', "" ,false ); ?>
        </form>
        <script>
            function target_popup(form) {
                window.open(, 'formpopup', 'width=400,height=400,resizeable,scrollbars');
                form.target = 'formpopup';
            }
        </script>
    </div>
    <?php
}
add_action( 'admin_post_tokencheck534547', 'tokencheck534547_test' );

settings_fields und do_settings_sections definiert ein Einstellungsfeld und einen Einstellungsabschnitt unter dem übergebenen Namen. An dieser Stelle werden später die HTML-Elemente aus anderen Funktionen angezeigt, die unter diesem Namen registriert sind.

Mittels des Submit-Button werden die Benutzereingaben von WordPress intern gespeichert.

Der zweite Submit-Button ("Teste Tokenanforderung") triggert ein JavaScript-Popup, indem man die Ergebnisse der Tokencheck-Funktion ausgibt.

Tokencheck

Wird der Tokencheck-Submit-Button gedrückt, so wird durch die Aktion

add_action( 'admin_post_tokencheck534547', 'tokencheck534547_test' );
die Tokencheck-Funktion tokencheck534547_test ausgeführt, und dessen Rückgabewert in dem JavaScript-Popup dargestellt.

pb_options.php:

unction tokencheck534547_test() {

    $keycloak_token_response = get_keycloak_token_response();

    if($keycloak_token_response==="TOKEN_REQUEST_ERROR")
        echo    "TOKEN_REQUEST_ERROR<br><br>
                Es konnte kein Token angefordert werden.<br><br>
                Stellen Sie sicher, dass die Einstellungen vorher gespeichert wurden und überprüfen Sie die Eingaben!";
    else if ($keycloak_token_response==="URL_MALFORMED")
        echo "MALFORMED_TOKEN_URL";
    else if (!is_array($keycloak_token_response) && strpos($keycloak_token_response, 'cURL error 7:') !== false)
        echo "ERROR: Keycloak Server is unreachable";
    else {
        echo "ERFOLG!<br><br>Keycloak Access Token erfolgreich erhalten.";

        //logout session
        keycloak_session_logout($keycloak_token_response);
    }
}

In dieser Funktion wird versucht, über die gespeicherten Benutzerdaten (deren Implementierung später in dieser Dokumentation beschrieben wird) ein Access-Token über den Keycloak-Token-Endpunkt zu erhalten. Abhängig von dem Resultat wird ein bestimmter Text im Popup angezeigt.

Einstellungsseite in WordPress einbetten

Damit die Einstellungsseite in WordPress erreichbar ist, wird sie über die Aktion "admin_menu" im Menü des WordPress Dashbord eingebettet:

pp_options.php:

function pb_options_page()
{
    add_submenu_page(
        'options-general.php', // in welchem Menü im Dashbord soll der Link zu den Einstellungen positioniert werden?
        'TH Köln Projektbörse Einstellungen', // Name der Einstellungsseite
        'THK Projektbörse', // Name des Links im WordPress-Einstellungsmenü
        'manage_options', // wozu ist die Seite befähigt?
        'pboerse', // Namenskürzel
        'pb_options_page_html' // welche Funktion soll nach Klick aufgerufen werden?
    );
}
add_action('admin_menu', 'pb_options_page');

Einstellungen registrieren

pp_options.php:

add_action('admin_init', 'plugin_admin_init');
function plugin_admin_init()
{
    // Path to Projektbörse API
    register_setting('pb_settings_input', 'pb_api_url');
    add_settings_section('plugin_main', 'Pfad zur Projektbörse API', 'plugin_section_text', 'pb_settings_input');
    add_settings_field('pb_url', 'URL:', 'pb_api_url2432425', 'pb_settings_input', 'plugin_main');
   
    // weitere Implementierung zusätzlicher Elemente...
}
register_settings

Um Interaktions-Elemente hinzuzufügen, starten wir eine Funktion mit der Aktion admin_init und registrieren mit register_setting('pb_settings_input', 'pb_api_url'); die Einstellung

pb_settings_input bezieht sich auf die vorher definierte Einstellungsgruppe (wie in settings_fields) und pb_api_url ist der Name der Einstellung.


add_settings_section

add_settings_section(<id>, <title>, <callback>, <page>); definiert einen konkreten Abschnitt zu den Einstellungen. Alle Elemente/Felder die in diesen Abschnitt hineinsollen, müssen die ID dieses Abschnittes angeben. Die Funktion add_settings_section muss für jeden Abschnitt nur einmalig angegeben werden.

id: ist der Name des Abschnitts. Auf diesen Namen bezieht man sich, wenn eine Funktion einem Abschnitt zugeordnet wird

title: ist die auf der HTML-Einstellungsseite angezeigte Abschnittsüberschrift

callback: Zusätzlich kann man noch Funktionen definieren, die nichts weiter tun als eine textuelle Beschreibung des definierten Abschnitts zu liefern. Hier ein Beispiel:

pp_options.php:

function plugin_section_text() {
    echo '<p>Geben Sie die URL zu der Projektbörse-API der TH Köln an.<br>Wird ein neuer Wordpress-Beitrag erstellt, so wird dieser direkt an die Projektbörse API gesendet, die ein JSON über eine REST Schnittstelle konsumiert</p>';
}

page: bezieht sich auf die vormals definierte Sektion in do_settings_sections


add_settings_field

Um das eigentliche HTML-Element welches die Benutzereinstellungen entgegen nimmt zu initialisieren, benutzen wir add_settings_field(<id>, <title>, <callback>, <page>, <section>)

id: die ID der Einstellung. Unter dieser ID wird der referenzierte Wert dieser Einstellung gespeichert, sowie ausgelesen

title: Kurzbeschreibung/Label der Einstellung

callback: der Name der Funktion, die das HTML-Input-Element definiert und die Speicherung der eingegebenen Werte vornimmt. Eine genaue Beschreibung wie eine solche Funktion aussieht und was sie tut, folgt

page: bezieht sich auf die vormals definierte Sektion in do_settings_sections

section: definiert die Zugehörigkeit zu einem Abschnitt der in add_settings_section definiert wurde

HTML Einstellungs-Element implementieren

Die beschriebene Callback-Funktion in add_settings_field ist die Funktion, welche das eigentliche HTML-Input-Element implementiert. Eine Beispielimplementierung für pb_api_url2432425 sieht so aus:

pp_options.php:

function pb_api_url2432425() {
    //delete_option('pb_api_url');
    $options = get_option('pb_api_url', array('pb_url' => DEFAULT_API_URL));
    echo "<input id='pb_url' name='pb_api_url[pb_url]' size='80' type='text' value='{$options['pb_url']}' />";

}

Hier wird die URL zur Projektbörse-API gespeichert. Mit $options = get_option('pb_api_url', array('pb_url' => DEFAULT_API_URL)); wird per get_option der bisher gespeicherte Wert aus der Datenbank in die Variable $options gespeichert (sollte kein Wert für diese Einstellungs-ID vorhanden sein, wird ein Standardwert genommen). Danach wird das Input-Element definiert. Wie im Beispiel muss id den Schlüsselnamen enthalten, name muss den Namen des Einstellungsarrays haben und auf den Schlüsselnamen verweisen. Um den bisher gespeicherten Eintrag anzuzeigen, lädt man unter value den entsprechenden Eintrag den wir vorher in $options gespeichert haben.

Ausblick

Mit dem Abschluss dieses Projekts steht die Kernfunktionalität des WordPress Plugins. Das Plugin erfüllt die an das Projekt gestellten Anforderungen. Es sind jedoch noch weitere Merkmale denkbar, die die Benutzbarkeit und den Funktionsumfang verbessern können. Es sollen die Projekt-Metadaten nicht nur in der Projektbörse innerhalb der Beiträge angezeigt werden, sondern auch in WordPress. Außerdem soll klarwerden, um welche Projektart es sich handelt (Praxisprojekt/Bachelorarbeit/Masterarbeit). Die wichtigste Erweiterung soll jedoch eine Art Synchronisationsmöglichkeit sein: es soll möglich sein, Projekte unter bestimmten Bedingungen aus der Projektbörse zu importieren. Weiterhin soll möglich sein, eigene Projekte aus WordPress (und gegebenenfalls aus der Projektbörse) gleichzeitig zu löschen.

Mit diesen Verbesserungen soll sich die an dieses Projekt anschließende Bachelorarbeit befassen.

Einzelnachweise

  1. ^ Projekt- und Themenbörse an der TH Köln: https://blogs.gm.fh-koeln.de/bente/forschung-entwicklung/projektboerse-des-campus-gummersbach/
  2. ^ https://de.wordpress.org/about/features/
  3. a b WordPress Plugin Handbook: https://developer.wordpress.org/plugins
  4. ^ WordPress 4.7 "Vaughan": https://wordpress.org/news/2016/12/vaughan/
  5. ^ https://docu.ilias.de/ilias.php?ref_id=42&obj_id=27029&cmd=layout&cmdClass=illmpresentationgui&cmdNode=2c&baseClass=ilLMPresentationGUI
  6. ^ Using Permalinks - Fixing Other Issues: https://codex.wordpress.org/Using_Permalinks#Fixing_Other_Issues
  7. ^ Routes & Endpoints: https://developer.wordpress.org/rest-api/#routes-endpoints
  8. ^ https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/#cookie-authentication
  9. ^ OAuth 2.0 for WordPress https://github.com/WP-API/OAuth2
  10. ^ github-commit "Alter "beta" warning" https://github.com/WP-API/OAuth2/commit/213ad0df428330f14f742fcd6b8ed6520df4d82b
  11. ^ Plugin API/Action Reference/publish post https://codex.wordpress.org/Plugin_API/Action_Reference/publish_post
  12. ^ Class Reference/WP Post https://codex.wordpress.org/Class_Reference/WP_Post
  13. ^ array_column_recursive https://github.com/NinoSkopac/array_column_recursive
  14. ^ Dummy Projektbörse auf Github https://github.com/andreaspaulick/dummyProjektboerse