Block Patterns für neue Einträge eines Custom Post Types nutzen

In Projekten nutze ich sehr häufig Custom Post Types (CPT). In einem neuen Projekt wurde der Inhalt der Einträge komplett mit Core-Blöcken gebaut. Hierzu habe ich in der Vergangenheit normalerweise Post-Meta-Felder und ein festes Seitentemplate verwendet. Aber da die Erstellung solch komplexer Inhalte für einen CPT recht viel Arbeit und auch sehr fehleranfällig ist, wollte ich für die neuen Einträge ein Template verwenden.

Erstellung eines Block Pattern

Die einfachste Art ein Pattern für einen Post-Type zu erstellen ist es, den Inhalt zuerst mit dem Block-Editor zu erstellen und das HTML Markup dann über die „Kompletten Inhalt kopieren“ in die Zwischenablage kopieren:

Jetzt könnt ihr dieses Markup verwenden, um ein Block Pattern mit diesem Standardinhalt für neue Inhalte zu erstellen:

function cpt_register_block_pattern() {
	register_block_pattern(
		'my-cpt/my-cpt-pattern',
		array(
			'title'       => __( 'My CPT pattern', 'my-cpt' ),
			'description' => _x( 'The custom template for my_cpt', 'Block pattern description', 'my-cpt' ),
			'content'     => '
<!-- wp:paragraph {"placeholder":"Custom Post Type ..."} -->
<p></p>
<!-- /wp:paragraph -->

<!-- wp:columns -->
<div class="wp-block-columns"><!-- wp:column -->
<div class="wp-block-column"><!-- wp:image -->
<figure class="wp-block-image"><img alt=""/></figure>
<!-- /wp:image --></div>
<!-- /wp:column -->

<!-- wp:column -->
<div class="wp-block-column"><!-- wp:heading {"placeholder":"Name ..."} -->
<h2></h2>
<!-- /wp:heading -->

<!-- wp:paragraph {"placeholder":"Phone ..."} -->
<p></p>
<!-- /wp:paragraph --></div>
<!-- /wp:column --></div>
<!-- /wp:columns -->',
		)
	);
}
add_action( 'init', 'cpt_register_block_pattern' );

Erstellung eines Templates für neue Einträge

Wenn man einen neuen CPT registriert, dann kann man auch Standardinhalte definieren, indem man das template Argument verwendet und darin in einem mehrdimensionalen Array ein Template definiert:

function cpt_register_post_type() {
	register_post_type(
		'my_cpt',
		array(
			'label'                 => __( 'Custom Post Type', 'my-cpt' ),
			'supports'              => array( 'title', 'editor' ),
			'public'                => true,
			'show_ui'               => true,
			// ... other settings
			'has_archive'           => true,
			'show_in_rest'          => true,
			'template'              => array(
				array(
					'core/paragraph',
					array(
						'placeholder' => __( 'Custom Post Type ...', 'my-cpt' ),
					),
				),
				array(
					'core/columns',
					array(),
					array(
						array(
							'core/column',
							array(),
							array(
								array(
									'core/image',
								),
							),
						),
						array(
							'core/column',
							array(),
							array(
								array(
									'core/heading',
									array(
										'level'       => 2,
										'placeholder' => __( 'Name ...', 'my-cpt' ),
									),
								),
								array(
									'core/paragraph',
									array(
										'placeholder' => __( 'Phone ...', 'my-cpt' ),
									),
								),
							),
						),
					),
				),
			),
		)
	);
}
add_action( 'init', 'cpt_register_post_type' );

Wie ihr schon an diesem kleinen Beispiel erkennen könnt, kann ein solches Array schnell sehr komplex, unleserlich und schwer zu pflegen werden. Ihr müsstet außerdem das HTML des Block Pattern in das PHP Array Format konvertieren. Jede Änderung am Pattern würde also eine doppelte Anpassung notwendig machen, bei der man schnell mal einen Fehler macht.

Block Patterns und Custom-Post-Types kombinieren

Da mir die Lösung mit dem PHP Array nicht wirklich gefallen hat (das Template in dem Projekt war noch viel komplexer als das aus dem Beispiel oben), habe ich zuerst das folgende versucht:

// ...
'template'              => array(
	array(
		'my-cpt/my-cpt-pattern',
	),
),
// ...

Ich hatte gedacht, dass ich vielleicht einfach ein Block Pattern im template verwenden kann und nicht nur Blöcke. Aber leider hat das nicht funktioniert. Bei der Suche nach einer Lösung bin ich auf verschiedene GitHub issues gestoßen. Dort habe ich den core/pattern Block gefunden, mit dem es dann ganz einfach war:

'template'              => array(
	array(
		'core/pattern',
		array(
			'slug' => 'my-cpt/my-cpt-pattern',
		),
	),
),

Leider ist der core/pattern Block aber noch nicht in WordPress 5.8 vorhanden. Man kann ihn aber einsetzen, indem man das Gutenberg Plugin installiert und aktiviert. Ich hoffe aber sehr, dass es mit WordPress 5.9 verfügbar sein wird, was nächsten Monat erwartet wird.

Fazit

Block Patterns und Templates sind bei der Arbeit mit Custom-Post-Types wirklich hilfreich. Wann man beide mit dem core/pattern Block kombiniert, dann kann es die Arbeit wirklich sehr erleichtern.

PHP Funktionen in WordPress debuggen

Wenn man ein Plugin oder Theme entwickelt, dann möchte man manchmal eine spezielle Funktion debuggen. Diese Funktion wird eventuell in einem größeren Kontext verwendet, was das Debuggen recht schwer und/oder langsam macht. Schauen wir uns hierzu das folgende Beispiel für eine Callback-Funktion eines Shortcode (oder „Server-Side-Rendered“ Blocks an):

function my_shortcode_callback( $atts ) {
	$atts = shortcode_atts( array(
		'post_id' => '',
		// ...
	), $atts, 'my_shortcode' );

	$result = my_function_to_debug( $atts );

	return sprintf(
		__( 'Posted on %1$s by %2$s', 'my-textdomain' ),
		date_i18n( get_option( 'date_format' ), $result['date'] ),
		get_the_author_meta( 'display_name', $result['author'] )
	);
}
add_shortcode( 'my_shortcode', 'my_shortcode_callback' );

In diesem Callback rufen wir die Funktion auf, die wir debuggen wollen. Diese Funktion kann sehr einfach, aber auch sehr komplex sein. Nehmen wir einfach einmal diese hier als Beispiel:

function my_function_to_debug( $atts ) {
	$post = get_post( (int) $atts['post_id'] );
	// Maybe do something with the post and create some result
	// ...

	// Dummy result: select two values from the post
	$result = [
		'date'   => $post->post_date,
		'author' => $post->post_author,
	];

	return $result;
}

Wenn man das auf den Weg würde man nun eine Seite oder einen Beitrag anlegen und dort den Shortcode einbinden, damit die Funktion, die wir debuggen wollen, aufgerufen wird. Nehmen wir mal an ihr wollt dabei den Aufruf der Funktion mit verschiedenen Parametern testen. Dann müsstet ihr mehrere Shortcodes in Seite oder Beitrag einfügen oder sogar mehrere Seiten/Beiträge anlegen.

Debuggen mit der WP-CLI

Eine Methode, sich ich in einem solchen Fall gerne verwende, ist die Nutzung der WP-CLI. Hier kann man beliebigen Code mit wp shell Befehl „in einer WordPress-Umgebung“ ausführen lassen. So könnte das aussehen:

$ wp shell
wp> my_function_to_debug( [ 'post_id' => 1 ] );
=> array(2) {
  ["date"]=>
  string(19) "2021-09-26 21:57:32"
  ["author"]=>
  string(1) "1"
}

Nach dem Starten der Shell rufen wir einfach die Funktion auf und übergeben direkt die passenden Argumente, die wir für unseren Test benötigen. Da die Funktion ein Array zurückgibt, erhalten wir ein Ergebnis in Form einer var_dump Visualisierung.

In gleicher Weise können wir natürlich auch die Callback-Funktion des Shortcodes selbst, aber auch jede andere Funktion eines Plugins/Themes oder des WordPress Core ausführen:

$ wp shell
wp> my_shortcode_callback( [ 'post_id' => 1 ] );
=> string(34) "Posted on 5 December 2021 by wapuu"

Der Vorteil des Debuggings mit dieser Technik ist, dass hierbei keine (Frontend) Seite gerendert werden muss. Es lädt stattdessen „nur“ die WordPress-Umgebung und führt die Funktion direkt aus. Das ist also sehr viel einfacher und schneller. Es muss eben auch keine Seite erstellt und der Shortcode darin eingefügt werden.

Debugging der Funktion mit einem AJAX Callback

Das einzige Problem an diesem Ansatz ist, dass es nicht (einfach) möglich ist, beim Debugging auch XDEBUG zu verwenden, da XDEBUG in der Regel nur in Verbindung mit einem HTTP-Request funktioniert. Ihr könntet zwar einen solchen Request mit curl auch in einem Terminal ausführen, aber dann müsstet ihr noch immer eine Seite oder einen Beitrag erstellen und dort den Shortode mit den Parametern einfügen. Stattdessen könnt ihr einen AJAX-Callback „missbrauchen“, um die Funktion in einem HTTP-Request auszuführen:

function my_ajax_callback() {
	$result = my_function_to_debug( [ 'post_id' => 1 ] );
	var_dump( $result );
}
add_action( 'wp_ajax_my_ajax_action', 'my_ajax_callback' );

Wenn ihr nun einen HTTP-Request auf die URL /wp-admin/admin-ajax.php?action=my_ajax_action macht (entweder im Browser oder im Terminal), dann erhaltet ihr die gleiche var_dump Ausgabe. Dieses Mal könnt ihr dann Breakpoint für XDEBUG für das Debugging setzen.

Fazit

Das Debugging von Funktionen benötigt nicht immer ein komplexes Anlegen von Seiten/Beiträgen, um die zu testende Funktion aufzurufen. Mit Hilfe der hervorragenden WP-CLI oder einem AJAX-Callback könnt ihr dies viel einfacher und schneller erledigen.

Video-Dokumentation einer WordPress-Installation im Backend

Während ich letzte Woche an einer Website gearbeitet habe ist mir etwas aufgefallen, dass ich gerne mich euch teilen möchte. Auf dem Dashboard habe ich ein Widget entdeckt, in das ein YouTube-Video einer aufgezeichneten Schulung eingebunden war.

Hinzufügen eines Videos zum Dashboard

Die Lösung auf dieser Seite war ein eigenes Dashboard-Widgets. Die URL zum Video wurde hierbei auf einer Einstellungsseite der Agentur eingetragen, auf der auch viele andere Einstellungen für die vielen Features der Installation gesteuert werden konnten.

Ich fand dieses Video eine super Idee und mein erst Impuls war es natürlich, selbst so etwas zu programmieren. Aber „leider“ gibt es ja für fast alles in WordPress bereits von jemand anderem ein Plugin. Statt also ein eigenes Plugin zu programmieren habe ich potenzielle Plugins für eine solche Funktionalität gefunden. Das einfachste ist Video Dashboard von Brian Johnson. Hier kann man bis zu 50 Videos von YouTube oder Vimeo einstellen und auch festlegen, welche Rolle jemand haben muss, um die Videos sehen zu können. Ein ähnliches Plugin ist Videos on Admin Dashboard. Hier können aber nur zwei Videos von YouTube oder Vimeo eingestellt werden, ebenfalls mit einer Steuerung der Rolle. Interessanterweise verwendet dieses Plugin wohl die gleichen Namen für die Einstellungen, denn hatte man beim anderen Plugin bereits Video-URLs hinterlegt, dann werden diese auch in diesem Plugin verwendet.

Fazit

Ein Video auf dem Dashboard zu platzieren ist eine ziemlich clevere Art den Menschen, die eine WordPress-Installation verwenden müssen, bei der Arbeit zu helfen. Wenn ihr dabei eine Plattform wie YouTube oder Vimeo nutzt, dann solltet ihr bei (individuellen) Videos sicherstellen, dass diese „nicht gelistet“ sind oder sogar nur auch einer bestimmten URL angesehen werden können (z.B. mit Vimeo Pro).

Wie bietet ihr Dokumentationen für WordPress-Installationen an? Verwendet ihr auch (gehostete) Video, ein anderes Dokumentations-Plugin oder ein externes Dokumentations-Tool?

Den „Registrieren“ Link überschreiben

In einem früheren Blogbeitrag habe ich euch berichtet, wie ich Gravity Forms für die Benutzerregistrierung verwendet habe. Dies wurde auf einer statischen Seite anstelle der normalen WordPress Registrierungsseite umgesetzt. Wenn ihr also möchtet, dass sich Benutzer auf einer solchen Seite registrieren, dann solltet ihr auch von vielen Stellen aus dorthin verlinken. In diesem Blogbeitrag möchte ich euch zeigen, wie ihr einen Link zu dieser Seite von der Login-Seite aus setzen könnt.

Die WordPress Login-Seite

Unter „Einstellungen › Allgemein“ könnt ihr bei „Mitgliedschaft“ die Option „Jeder kann sich registrieren“ aktivieren. Damit findet dann jeder auf der Login-Seite einen Link zur normalen Regstrieungsseite:

Die WordPress Login-Seite

Wenn ihr lediglich die URL für diesen Link überschreiben möchtet, dann könnt ihr einen Filter verwenden. Dieser erhält als Übergabe den HTML Code für den Link, den ihr dann wie folgt überschreiben könnt:

function custom_register_link( $link ) {
	return sprintf(
		'<a href="%s">%s</a>',
		esc_url( '/register/' ),
		esc_html__( 'Register' )
	);
}
add_filter( 'register', 'custom_register_link' );

Dies setzt einen Link auf die statische URL /register/ unter Verwendung des normalen Linktexts.

Dieser Ansatz funktioniert nur dann, wenn ihr auch zuvor die Registrierung aktiviert habt. Aber hierdurch wird auch das normale Registrierungsformular verfügbar. Falls ihr die Registrierung nicht aktiviert habt, könnt ihr dennoch mit Gravity Forms (und vermutlich auch mit anderen Plugins) Benutzer registrieren. Da aber der „Registrieren“ komplett verschwindet, könnt ihr dann auch nicht mehr einfach die URL überschreiben. Stattdessen könnt ihr aber mit dem folgenden Code einen zusätzlichen Link an einer anderen Stelle einfügen:

function custom_login_site_html_link( $home_link ) {
	$register_link = sprintf(
		'<a href="%s">%s</a>',
		esc_url( '/register/' ),
		esc_html__( 'Register' )
	);

	return sprintf(
		'%s<br /><br />%s',
		$register_link,
		$home_link
	);
}
add_filter( 'login_site_html_link', 'custom_login_site_html_link' );

Dieser Filter hängt sich normalerweise in den „← Zurück zu <Seitenname>“ link. Dies ist die einzige Stelle, an der wir unseren eigenen Link einfügen können. Das Ergebnis sieht dann in etwa wie folgt aus:

Die WordPress Login-Seitemit eigenem „Registrieren“ Link

Durch diese Platzierung ist der Link vielleicht sogar besser sichtbar als an seiner ursprünglichen Stelle neben dem „Passwort vergessen?“ Link.

Fazit

Eine Selbstregistrierung kann wirklich vorteilhaft sein. Wenn ihr eine solche umsetzt, dann solltet ihr aber sicherstellen, dass ihr immer auf dieses eigene Formular verlinkt.

Den „Illegal mix of collations“ WordPress-Datenbank-Fehler beheben

Wenn ich Projekte aktualisiere, dann schaue ich mir auch immer die Logfiles an. In einem Projekt das ich warte habe ich dabei den folgenden Fehler im Logfile gefunden, der mit zuvor noch nie untergekommen war:

WordPress-Datenbank-Fehler Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8mb4_unicode_520_ci,COERCIBLE) for operation 'like' ...

Da WordPress nicht besonders strikt ist mit den Kollationen könnte auch in euer WordPress Website mehr als eine Kollation für die verschiedenen Tabellen verwendet werden. In diesem Project waren es sechs Kollationen!

Konvertieren der Kollationen

Um diesen Fehler zu beheben müssen wir alle Tabellen auf kompatible Kollationen konvertieren. Dabei ist es natürlich am besten, wenn wir für alle Tabellen die gleiche Kollation verwenden. Mit WordPress 4.2.0 wurde utf8mb4 der neue Standard. Alle Datenbank-Tabelle die danach erstellt werden, haben dann eine der Varianten davon. Für unsere neue Kollation verwenden wir also eine davon.

Datenbank sichern!

STOPP! Bevor wir anfangen irgendetwas an der Datenbank zu ändern, machen wir erst einmal ein Backup. Das Ändern der Kollation sollte eigentlich kein Problem darstellen, aber für den Fall der Fälle macht man am besten immer ein Backup. Ihr könnt dabei das Tool eurer Wahl verwenden. Ich verwende in der Regel die WP-CLI dafür:

wp db export

Jetzt können wir gefahrlos die Änderungen machen und im Notfall wieder das Backup einspielen.

Ändern der Kollation einer Tabelle

Wenn man etwas an einer Datenbank oder einer Tabelle ändern möchte, dann verwendet man das ALTER Statement, welches wir auch hier wie folgt verwenden:

ALTER DATABASE wp_project_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;

Dieses erste Statement ändert wert einmal die Kollation der gesamten Datenbank. Wenn ihr also danach mit einem Datenbank-Tool eine Tabelle erstellt, dann wird es diese Kollation verwenden. Das Statement ändert aber nichts an den Tabellen der Datenbank. Hierzu müsste ihr die Tabellen wie folgt verändern:

ALTER TABLE wp_project_name.wp_posts CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;

Dieses eine Statement würde die Tabelle wp_posts anpassen. Wiederholt das also nun für alle anderen Tabellen in euer Datenbank.

Aktualisierung einer Datenbank mit vielen Tabellen

In dem Projekt mit dem beschriebenen Fehler gab es 12 Sites mit 344 Tabellen! Da macht es natürlich keinen Spaß jede Tabelle einzeln zu aktualisieren. Glücklicherweise konnte ich einen kleinen Trick finden, der mir alle ALTER TABLE Statements für alle Tabellen generiert hat:

SELECT CONCAT("ALTER TABLE ",TABLE_SCHEMA,".",TABLE_NAME," CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;") 
FROM information_schema.TABLES
WHERE TABLE_SCHEMA="wp_project_name";

Setzt einfach in der letzten Zeile euren Datenbanknamen ein und führt den Befehl aus. Dann kopiert ihr euch die „generierten“ Queries und führt diese aus. Dabei könntet ihr eventuell einen Fehler wie den folgenden erhalten:

Invalid default value for 'comment_date'

In diesem Fall könntet ihr dann den sql_mode temporär anpassen, indem ihr vor den ganzen ALTER TABLE Statements die folgende Zeile einfügt:

SET sql_mode = '';

Nachdem ihr alle Statements ausgeführt habt sollten nun alle Tabellen die gleiche Kollation habe. In diesem Beispiel verwende ich die Kollation utf8mb4_unicode_520_ci, auf eurem Server könnte es aber eine andere Variante sein.

Aktualisierung der Kollationen mit einem Plugin

Beim Schreiben dieses Beitrags bin ich über das Plugin Database Collation Fix gestoplert. Wenn ihr also keinen Zugriff auf eine Datenbank-Tool habt oder es such nicht zutraut, dann kann euch das Plugin dabei helfen. Der einzige „Nachteil“ ist, dass hier Tabellen nur in die Kollation utf8mb4_unicode_ci (oder eine von drei Alternativen) nicht aber in die neuere utf8mb4_unicode_520_ci Kollation konvertiert wird. Das sollte aber in der Regel kein Problem darstellen.

Fazit

Auch nach vielen Jahren Arbeit mit WordPress gibt es noch immer Fehler, die mir zuvor noch nicht untergekommen sind. In diesem Fall ist es nicht einmal ein spezifisches WordPress-Problem, aber da WordPress nicht sehr streng beim Umgang mit Kollationen ist, kann das Problem wohl häufiger mal auftreten. Vor allem dann, wenn die Installation schon etwas älter ist (beispielsweise vor Version 4.2.0 installiert). Wenn ihr also einen ähnlichen Fehler bei euch im Logfile findet, dann habt ihr jetzt hoffentlich eine Idee bekommen, wie ihr es lösen könnt. Und falls ihr schon lange nicht mehr in die Logfiles gesehen habt, dann ist diese Blogbeitrag vielleicht eine Erinnerung, das mal wieder zu tun.

Dynamische Benutzernamen mit dem Gravity Forms User Registration Add-On in einer Multisite erzeugen

Wie ich schon in einigen frühen Blogbeiträgen erwähnt habe, nutze ich sehr häufig Gravity Forms bei der Erstellung von Formularen. Hierzu gibt es auch einige tolle Add-Ons. Eines davon ist die User Registation Erweiterung. Damit ist es möglich nach dem Absenden des Formulars ein neues Benutzerkonto zu erstellen.

Das „username“ Feld

Ihr erstellt im Grunde erst einmal ein ganz normales Formular. Darin fragt ihr dann einige notwendig Felder ab, die ihr für neue Benutzer benötigt. Das absolute Minimum sollte hierbei wohl die E-Mail-Adresse sein, damit neue Benutzer auch ihre Zugänge bestätigen können. Ein anders Feld könnte der Benutzername sein. Das Add-On bietet hierfür auch ein eigenes Feld ein. Wenn also neue Benutzer ihren Benutzernamen selbst wählen können sollen, dass wäre dies das perfekte Feld.

Verwendung des „email“ Feldes

Da es WordPress erlaubt sich mit Benutzername oder alternativ mit E-Mail-Adresse anzumelden, müssten die Benutzer noch nicht einmal ihre Benutzernamen kennen. Wenn ihr also einen „Feed“ zum Erstellen neuer Benutzer erstellt, könnt ihr auch einfach das E-Mail-Feld verwenden. Es sei denn, ihr erstellt neue Zugänge zu einer Multisite.

Einen dynamischen Benutzernamen aus anderen Feldern erstellen

In einer Multisite-Installation dürfen Benutzernamen nur aus Kleinbuchstaben und Zahlen bestehen. Der Grund dafür ist, dass dieser Benutzername verwendet werden „kann“, um eine Unterseite pro Benutzer zu erstellen. Selbst wenn ihr keine Seite pro Benutzer erstellen wollt (was das Add-On auch erledigen kann), gilt die Einschränkung für die erlaubten Zeichen dennoch. Wie gehen wir also damit um, ohne die Benutzer zu bitten, sich selbst einen Benutzernamen auszusuchen? Ich könnt einfach einen Benutzernamen dynamisch aus anderen Feldern erzeugen.

Verwendung der Felder für Vor- und Nachnamen

Auf vielen Plattformen wird der Benutzername automatisch aus der Kombination von Vor- und Nachname erstellt. Wir können daher einen Filter verwenden, um einen solchen Benutzernamen zu erstellen. Da dieser Benutzername aber noch immer ungültige Zeichen enthalten könnte, müssen wir diesen Namen noch „sanitizen“. Glücklicherweise bietet WordPress genau hierfür eine Funktion an. Und da zwei Personen die gleiche Vor- und Nachnamen haben können, müssen wir auch noch einen Weg finden, mit diesem Problem umzugehen. Aber fangen wir erst einmal mit der Callback-Funktion zu dem Gravity Forms Hook an:

function gf_ms_uf_set_username( $username, $feed, $form, $entry ) {
        // Get first and last name from the form submission.
        $first_name = rgar( $entry, rgars( $feed, 'meta/first_name' ) );
        $last_name  = rgar( $entry, rgars( $feed, 'meta/last_name' ) );

        // Generate a new username making it compatible with multisite constraints.
        $new_username = gf_ms_get_unique_username( sanitize_user( $first_name . $last_name ) );

        if ( ! empty ( $new_username ) ) {
                $username = $new_username;
        }

        return $username;
}
add_filter( 'gform_username', 'gf_ms_uf_set_username', 10, 4 );

Wir verwenden hier den Hook gform_username, der für das spezielle Username Feld verwendet wird. In der Callback-Funktion lesen wir die Werte aus den Feldern für Vor- und Nachname aus und übergeben diese an eine andere Funktion, die dann einen einmaligen Benutzernamen generiert. Erhalten wir einen solchen neuen Namen, geben wir diesen zurück.

Erstellen eines eindeutigen Benutzernamens

Wie erstellen wir nun einen Benutzernamen, der noch nicht existiert? Nun, wie verwenden hierzu eine Funktion, die ähnlich funktioniert wie die Funktionen, mit denen WordPress eindeutige Permalink für Beiträge/Seiten/Terms mit gleichen Namen erzeugt. Wir verwenden einen „Zähler-Präfix“, der so lange hochzählt, bis der Name einmalig ist:

function gf_ms_get_unique_username( $username ) {
        $number            = 2;
        $original_username = $username;

        while ( username_exists( $username ) || gf_ms_signup_exists( $username ) ) {
                $username = $original_username . $number ++;
        }

        return $username;
}

function gf_ms_signup_exists( $username ) {
        global $wpdb;

        return $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM $wpdb->signups WHERE user_login = %s",
                $username
            )
        );
}

In der while-Schleife prüfen wird, ob der Benutzename bereits existiert und weiterhin, ob eine Registrierung existiert, die den Namen verwendet, die aber noch nicht über den Bestätigungslink aus der E-Mail aktiviert wurde. Dies prüfen wir mit einer weiteren Hilfsfunktion, die ähnliche zu der aus dem Core aussieht.

Fazit

WordPress bietet selbst einen Weg an, um neue Registrierungen zu ermöglich – für eine Single- oder Multisite. Wenn ihr aber für die neuen Benutzer auch noch weitere Informationen abfragen wollt, dann kann ein Add-On wie das für Gravity Forms sehr hilfreich sein, um den Registrierungsprozess zu vereinfachen. Die Registrierung für eine Multisite ist dabei etwas schwierigen, aber mit ein paar Hilfsfunktionen ebenfalls möglich. Selbstverständlich findet ihr den Code zu diesem Beitrag auch wieder in einem GIST und könnt ihn dort als ZIP-Datei runterladen und als Plugin installieren.

Wie verwende ein eigenes Menü pro Seite?

In meinem letzten Blogbeitrag habe ich euch gezeigt, wie ihr ein einfaches Seiten-Template für Landing Pages erstellen könnt. Darin habe ich auch erwähnt, dass ihr vielleicht für jede dieser Seiten ein eigenes Menü verwenden möchtet. In diesem Beitrag möchte ich euch zeigen, wie ihr das umsetzen könnt.

Erstellen eines Menüs für die Landing Page

Zuerst einmal müsst ihr ein eigenes Menü für die Landing Page erstellen. Das könnt ihr entweder im Customizer oder unter „Design ->Menüs“ im Backend tun. Hier verwendet ihr für den Namen des neuen Menüs am besten genau den gleichen Namen, den auch der Seitenname hat. Das macht es später einfacher, das neue Menü zu verwenden.

Überschreiben des Menüs mit einem eigenen Menü

Nachdem wir das neue Menü mit dem Seitennamen erstellt haben, können wir dieses neue Menü dynamisch laden. Jeder Menüeintrag wird in der Datenbank als nav_menu_item Post-Type gespeichert. Das eigentliche Menü wird als Term für die nav_menu Taxonomie gespeichert. Wenn WordPress nun versucht für eine Menü-Position ein Menü zu laden, dann wird eine Query auf diese Taxonomie verwendet. Genau hier können wir über einen Filter ansetzen um unser eigenes Menü zu bekommen. Hierzu könnt ihr folgenden Code verwenden:

function current_page_wp_get_nav_menu_object( $menu_obj, $menu ) {
	if ( $menu_obj instanceof WP_Term && 'primary' == $menu_obj->slug ) {
		$current_slug  = get_post_field( 'post_name', get_the_ID() );
		$page_menu_obj = get_term_by( 'slug', $current_slug, 'nav_menu' );

		if ( $page_menu_obj ) {
			$menu_obj = $page_menu_obj;
		}
	}

	return $menu_obj;
}
add_filter( 'wp_get_nav_menu_object', 'current_page_wp_get_nav_menu_object', 11, 2 );

In Zeile 2 prüfen wir erst einmal, ob wir uns an der richtigen Menü-Position befinden. Falls wir diesen Schritt vergessen würden, dann würden wir alle Menüs auf der Seite überschreiben. Also zum Beispiel aus eines im Footer, ein Social-Media-Menü usw. In diesem Fall prüfen wird, ob die Menü-Position primary, ist. Die Hauptmenü-Position könnte in eurem Theme aber einen anderen Namen haben.

Nach dieser Prüfung können wir dann den aktuellen Seitennamen verwenden und versuchen einen nav_menu Term mit diesem Namen zu finden. Wurde ein solcher gefunden, dann überschreiben wir das Original $menu_object mit unserem eigenen Seitenmemü.

Fazit

Das Überschreiben von Templates-Files ist wirklich einfach. Ein Menü an einer bestimmten Stelle dynamisch zu überschreiben ist nicht mehr ganz so einfach. Aber mit dem richtigen Filter ist auch das ohne Probleme möglich. Mit diesem kleinen Code-Schnipsel könnt ihr also nun eigene Menüs für das Landing Page Seitentemplate aus dem vorherigen Blogbeitrag erstellen. Wenn ihr stattdessen immer das gleiche Menü für alle Seiten verwenden möchtet, die dieses Landing Page Seiten-Template verwendet, dann könntet ihr innerhalb des Filters eben prüfen, ob dieses Template verwendet wird und dann entsprechend immer ein anderes Menü laden.

Wie erstelle ich Landing Pages ohne Plugins?

In einem neuen Projekt wurden mehrere WordPress Plugins verwendet um „Landing Pages“ zu erstellen. Einige dieser Plugins wurden aus dem Plugin-Verzeichnis entfernt, erhalten also somit keine (Sicherheits-)Updates mehr. In einem Telefonat wurde sehr schnell klar, dass es eine unterschiedliche Vorstellung davon gab, was eine Landing Page überhaupt ist.

Was ist eine Landing Page

Es gibt nicht die eine perfekte Definition für eine Landing Page. Für mich kann es im einfachsten Fall eine einzelne statische Seite auf einer Website sein, die alle Informationen präsentiert, um das Hauptziel zu erreichen. Die Seite wird über einen Permalink erreicht, der entweder über die passenden Suchbegriffe in einer Suchmaschine gefunden wird, oder der in sozialen Netzwerken verbreitet wird.

Landing Pages können auch sehr viel komplexer werden, abhängig von den Zielen, die sie erreichen wollen (Dinge, verkaufen, neue Registrierungen erhalten, etc.) und hierzu können verschiedene Techniken eingesetzt werden, um diesen Erfolg zu messen.

Eine einfache Landing Page

Viele würde argumentieren, dass eine Landing Page keine, oder nur eine sehr eingeschränkte Navigation hat, und auf der Seite eher über sogenannte „Call to Action Buttons“ (z.B. zu Shop, Bestellung, Registrierung, etc.) navigiert wird. Auf komplexeren Seiten mit einer langen Navigation, einer Sidebar und einem großen Footer, möchte man diese Elemente eventuell entfernen. Aber hierzu ist nicht immer ein Plugin notwendig, denn WordPress bringt eine sehr viel einfacherer Methode mit.

Erstellen eines „Landing Page“ Templates

Wenn ihr eine Seite erstellt, dann könnte ihr ein „Template“ im „Seite“ (oder „Beitrag“) Tab im Block-Editor auswählen. Diese Templates werden von eurem Theme zur Verfügung gestellt (falls dieses welche hat), ihr könnt aber auch in eurem Child-Theme selbst welche anlegen. Mehr Informationen zum Anlegen von Seite-Templates findet ihr im Theme Handbook, aber oft reicht es aus, wenn ihr die page.php, singular.php oder index.php Datei in euer Child-Theme kopiert, dieser einen neuen Namen gebt (hier wird oft „page-“ als Präfix davor geschrieben) und dann am Anfang der Datei einen Kommentar mit dem Namen einfügt:

<?php
/**
* Template Name: Landing Page
*/

Genau darunter findet man in der Regel einen Aufruf für get_header() was dazu dient die header.php Datei aus dem Theme zu laden. An dieser Stelle können wir ebenfalls ansetzen, um das Seiten-Template ein wenig anzupassen und einen anderen Header zu laden. Hierzu übergebt ihr an die Funktion einen String:

get_header( 'landing-page' );

Wenn ihr die Funktion in dieser Weise aufruft, dann wird WordPress versuchen eine Datei header-landing-page.php anstelle der Standarddatei zu laden. Hierzu kopiert ihr wieder die header.php Datei aus und benennt diese entsprechend um. Nun könnt ihr euch in dieser Datei austoben. Ihr könnt die Navigation komplett entfernen, eine andere Navigations-Position nutzen oder selbst Dinge wie das Logo oder anderes in diesem Template ändern.

Erstellen von Inhalten für die Landing Page

Nachdem wir mit diesem Schritt fertig sind und unseren neuen (und vielleicht reduzierten) Header erstellt haben, können wir uns um die Inhalte der Seite kümmern. Aber das ist wirklich einfach, denn der Block-Editor liefert eigentlich schon die wichtigsten Elemente mit, die man für eine Landing Page braucht, inklusive einfach zu verwendender Buttons.

Die Zukunft von Landing Pages

Während dieser Ansatz noch immer eigenen Coder erfordert, ist eine neue Art der Umsetzung von Landing Pages schon in Sicht: Full-Site-Editing! Sobald es in WordPress (und Themes) verfügbar ist, müsst ihr keine Seiten-Templates mehr in einem Child-Theme erstellen. Ihr könnt dann einfach das gesamte Layout der Seite anpassen. Das Hinzufügen/Entfernen von Navigations-Menüs wird dann so einfach wie das Bearbeiten der Inhalte der Seite. Dann werden es spezielle Landing Page Plugins wirklich schwer haben es zu rechtfertigen, dass man noch ein zusätzliches Plugin benötigt.

Überprüfe deine Domain-Sicherheit mit Mozilla Observatory

In den letzten beiden Beiträgen habe ich euch zwei Tools vorgestellt, die ich oft nutze. Heute möchte ich mit einem dritten Tool weitermachen, das ist bisher im Beitrag Bessere Sicherheit für WordPress mit sicheren Server-Headern nur kurz erwähnt habe: das Mozilla Observatory Tool.

HTTP Observatory

Wenn ihr das Tool zum ersten mal für eine Domain ausführt, dann erhaltet ihr zuerst eine Übersicht zur HTTP-Sicherheit. Über diesen Teil habe ich auch schon in meinem vorherigen Beitrag geschrieben. Die Scan Summary könnt hierbei wie folgt aussehen:

Weiterlesen →

Generiere deine eigene nginx Konfiguration

In meinem letzten Blogbeitrag habe ich euch ein Tool vorgestellt, mit dem du „Die perfekte SSL-Konfiguration für deinen Server“ erstellen konntest. Diese Woche möchte ich über ein anderes Tool sprechen, das ich häufiger verwende, um eine gute nginx Konfiguration zu bekommen. Das Tool war früher unter der Domain nginxconfig.io zu finden (welche noch immer umleitet) und ist nun als DigitalOcean Community Tools – NGINXConfig zu finden.

Die Basics

Das Tool präsentiert sich mit ein paar Grundeinstellungen. Es ist auf PHP eingestellt und nutzt example.com als Domain. Das ist vermutlich die erste Einstellung die ihr ändern wollt. Über „Add site“ könnt ihr gleich für mehrer Seiten gleichzeitig Konfigurationen erstellen lassen, die dann im Ergebnis zu mehreren „Per-website“ Konfigurationsdateien führen.

Die Basiseinstellung mit den Konfigurationsoptionen für die Technologie und den Hostnamen

In den Voreinstellungen (Presets) könnt ihr unter verschiedenen Technologien die passende aussuchen. Wenn ihr hinter dem nginx eine WordPress-Installation betreiben wollt, dann findet ihr hierfür eine passende Voreinstellung. Diese generiert dann beispielsweise die passenden Rewrite-Rules sowie einige Sicherheitsregeln.

Voreinstellungen (Presets)

In diesem Abschnitt könnt ihr den Hostname eintragen und die Sub-Domain die ihr verwenden (oder nicht verwenden) möchtet, sowie den Serverpfad. Ihr könnt auch angeben, ob ihr Let’s Encrypt verwendet, um eure Zertifikate zu erhalten (oder eigene Einstellungen setzen). Weiterhin könnt ihr den PHP Server/Socket (sowie einen backup) angeben und noch ein paar andere fortgeschrittene Optionen.

Globale Einstellungen (Global config)

In den Gruppe der HTTPS-Einstellungen findest ihr die SSL-Profile wieder, über die ich in meinem letzten Beitrag geschrieben habe. Hier solltet ihr die Voreinstellung bei „Mozilla Intermediate“ belassen. Wenn ihr das Tool verwendet, um eine Konfiguration für eine WordPress-Website zu erstellen, dann schaut euch auf jeden Fall den Abschnitt „Security | Content-Security-Policy“ an. Da WordPress CSS und JS inline in die Seite einbindet muss dies erlaubt werden. Falls die Einstellung hier zu streng eingestellt ist, wird eure Website ansonsten nicht richtig funktionieren. Wenn ihr in den Presets WordPress ausgewählt habt, dann schlägt euch das Tool in einer Meldung auch eine solche Einstellung vor.

Eine weitere Gruppe von Einstellungen, die ihr euch ansehen solltet findet ihr im „Performance“ Tab. Die „Expiration“ ist hier jeweils nur auf eine Woche eingestellt. Da WordPress aber ein sehr gutes Cache-Invalidation-Handling hat (indem es die Versionsnummer von Plugin, Theme oder WordPress anhängt), könnt ihr hier vermutlich eine größere Dauer einstellen. Wenn ihr aber mehrere unterschiedliche Systeme hinter dem nginx betreibt, solltet ihr hier etwas vorsichtiger sein.

Eure Einstellungen speichern

Jedes Mal, wenn ich eine Einstellung anpasst, dann ändert sich die URL im Browser. Diese URL findet ihr auch im Abschnitt „Tools“ im Feld „Share configuration“. Ich kann euch nur empfehlen diese URL zu speichern oder ein Lesezeichen zu machen. Ihr findet die URL aber auch in der nginx.conf Datei im resultierenden Paket.

Eure Konfiguration anwenden

Nachdem ihr alle Anpassungen an der Konfiguration gemacht habt könnt die den weitern Anweisungen in der „Setup“ Sektion folgen. Dabei werdet ihr vermutlich damit anfangen das Paket runterzuladen, um es anschließend auf euren Server zu laden und dort zu entpacken. Falls ihr noch keine lauffähige Let’s Encrypt Installation habt, dann findet ihr auch hierzu ein paar Befehle, die euch dabei helfen.

Eure Konfiguration testen

Wie ich auch schon in meinem letzten Beitrag geschrieben hatte, solltet ihr niemals einfach eine Konfiguration per Copy/Paste blind übernehmen, sondern immer zuvor prüfen, bevor ihr sie auf einen laufenden Server anwendet. In der wordpress.conf Datei wird zum Beispiel der Zugriff auf der Datei xmlrpc.php blockiert. Das kann eine angemessene Einstellung sein, um Brute-Force-Attacken auf XML-RPC zu blockieren. Wenn ihr aber die offiziellen WordPress Apps verwendet, dann darf diese Datei nicht blockiert werden. Nachdem ihr also die Einstellungen angewendet habt solltet ihr die wichtigsten Seiten sowohl im Frontend, als auch im Backend testen.

Helft mit, das Tool zu verbessern

Da dies ein Community-Tool ist, kann man im GitHub-Repository des Projekts Fehler melden oder Verbesserungen vorschlagen. Ich habe das auch schon zweimal gemacht. Einen Fehler fand ich nach der letzten Aktualisierung meiner Konfiguration. Dabei wurde durch eine Sicherheitsregel der Zugriff auf die wp-comments-post.php Datei blockiert. Damit war es dann nicht mehr möglich auf meinem Blog zu kommentieren. Wenn ihr also etwas findet, dann helft dabei mit, das Tool für alle noch besser zu machen.

Fazit

Einen nginx-Server aufzusetzen ist wirklich schwer, gerade dann, wenn es nicht zu eurer täglichen Arbeit gehört. Ich ändere die Konfiguration für meinen Server wirklich nur sehr selten und muss dabei oft einfache Dinge immer wieder nachschlagen (ich warte sehr viel häufiger Apache Webserver bei der Arbeit). Tools wie dieses helfen mit bei der Arbeit wirklich sehr und ich konnte damit gute Voreinstellungen und Best-Practices finden. Eine andere gute Ressource für solche Best-Practices sind die Konfigurationen der HTML5 Boilerplate. Hier findet ihr nicht nur Beispielkonfigurationen für nginx, sondern auch für viele andere Server. Aber dieser sind eher für erfahrene Admins gedacht, da sie kein Konfigurationstool anbieten.