WordPress zeigt die Auswahl für Page-Template nicht an

Problem: die Auswahl für das Seiten-Template wird von WordPress nicht angezeigt:

Links: erwarteter Inhalt der Meta-Box, rechts: tatsächliche Darstellung ohne die Template-Auswahl

Stackoverflow ist voll mit Lösungsvorschlägen (Beispiel 1, Beispiel 2). Wenn das alles nichts hilft, kann man auch mal prüfen, ob es sich bei der aktuell im Editor geladenen Seite um die sogenannte „Beitragsseite“ handelt, also die Seite, welche alle Posts chronologisch darstellt. Auf dieser ist nämlich die Auswahl des Seitentemplates auch deaktiviert:

Für die Beitragsseite ist keine Template-Auswahl möglich.

Das Styling geschieht in diesem Fall über das Template home.php (falls vorhanden) bzw. index.php (Fallback).

Fontello – Custom Icon-Fonts schnell erstellt

Font Awesome ist zu schwer wenn man nur mal schnell eine Hand voll Icons benötigt? Bei Entypo oder Typicons ist nicht das richtige Icon dabei?

Kein Problem, mit Fontello lassen sich Glyphen aus einer ganzen Reihe von Icon-Fonts auswählen und zu einem neuen Font zusammen stellen. Ein Klick und man bekommt die Schriftart in verschiedenen Formaten samt der benötigten CSS-Datei direkt auf die Festplatte heruntergeladen.

Je nach benötigtem Umfang kommt man so mit wenigen Kilobytes aus – eine satte Einsparung gegenüber z. B. dem recht schwergewichtigen Font Awesome in Vollausstattung.

Bestimmten und reproduzierbaren Anteil von Datensätzen für Verarbeitung selektieren

Ich tat mich sehr schwer mit der Überschrift dieses Beitrags, da das Problem nicht in einem kurzen Satz zu beschreiben ist. Daher noch mal in Ruhe:

Problemstellung

Gegeben sei eine große Zahl von Bildern, welche mit verhältnismäßig hohem Aufwand an Ressourcen skaliert werden sollen. Das alles muss on-demand passieren, wenn ein Webbrowser ein Bild aufruft.

Ist ein Bild einmal skaliert, wird das Ergebnis zwischengespeichert, ein erneuter Aufruf erzeugt also keinen relevanten Aufwand. Da die Bilder in großer Zahl parallel aufgerufen werden, soll nur ein gewisser Anteil die Skalierung durchlaufen und es sollen auch immer die selben Bilder sein. Eine zufällige Auswahl scheidet also aus.

Nach und nach kann der Prozentwert erhöht werden, bis irgendwann alle Bilder skaliert sind.

Lösung

Ich habe das Problem auf die folgende Art gelöst:

  1. Wenn der Zielwert 100 % ist, wird das Bild sofort in die Weiterverarbeitung gegeben, die folgende Prüfung findet nicht statt
  2. Wenn der Zielwert 0 % ist, wird das Bild nicht weiterverarbeitet, die folgende Prüfung findet nicht statt
  3. Für alle Zielwerte größer 0 % und kleiner 100 % wird die CRC32-Checksumme der Bild-URL (die URL ist das Identifikationsmerkmal des Bildes) berechnet, das Ergebnis ist ein 32 Bit-Integer
  4. Berechnung von Checksumme Modulo 100 (ergibt die letzen beiden Stellen der Checksumme)
  5. Prüfen, ob das Ergebnis aus dem vorherigen Schritt kleiner als der angestrebte Prozentwert des Anteils zu skalierender Bilder ist, falls ja Skalierung starten, sonst übergehen

Die Verteilung der der CRC32-Checksummen im Raum der 32-Bit-Integer-Zahlen ist für diesen Zweck halbwegs gleichmäßig und zufällig. Die letzten beiden Stellen der Zahl sind also auch ausreichend gleichverteilt zwischen 0 und 100. Man kann mit dieser Methode daher relativ genau und mit wenig Aufwand einen bestimmten und reproduzierbaren Anteil der Datensätze (Bilder) selektieren.

Beispiel

Es sollen 20 % aller Bild-URLs skaliert werden.

Gegeben sei die folgende Bild-URL:

https://www.marcusjaschen.de/wp-content/uploads/2019/03/2019-03-31-DJI_0147.jpg

Die CRC32-Checksumme dieser URL ist 3556399431. Modulo 100 ergibt sich ein Ergebnis von 31.

31 ist nicht kleiner als der Zielwert 20, das Bild wird also nicht skaliert.

Eine andere Bild-URL wäre:

https://www.marcusjaschen.de/wp-content/uploads/2019/03/2019-03-31-DJI_0150.jpg

Hier lautet die Checksumme 2860930802. Modulo 100 erhält man 2, was kleiner als 20 ist, dieses Bild würde also weiterverarbeitet werden.

phpbrew mit macOS 10.14 Mojave

Seit Mojave baut phpbrew auf meinen Rechnern die Binaries nicht mehr, sondern bricht mit einer Fehlermeldung ab:

% phpbrew -d install -j 4 7.2.13 \
+default \
+iconv \
+icu \
+bz2 \
+zlib \
+curl

[...]

checking for BZip2 in default path... not found
configure: error: Please reinstall the BZip2 distribution

Das Problem betrifft neben bzip2 auch noch weitere Libraries wie iconv, zlib und curl und entsteht vermutlich im Zusammenhang mit Homebrew. Die benötigten Includes werden im Homebrew-Universum gesucht, statt auf die vom System bereitgestellten zurückzugreifen. Hat man die entsprechenden Libraries nicht per Homebrew installiert, kommt es zu diesen Fehlern.

Das Problem lässt sich allerdings sehr einfach beheben, indem man zum einen die benötigten Libraries per Homebrew installiert:

% brew install zlib bzip2 libiconv curl

Zum anderen gibt man phpbrew nun die passenden Include-Pfade mit:

% phpbrew -d install -j 4 7.2.13 \
+default \
+iconv=/usr/local/opt/libiconv \
+icu \
+bz2=/usr/local/opt/bzip2 \
+zlib=/usr/local/opt/zlib \
+curl=/usr/local/opt/curl

[...]

Congratulations! Now you have PHP with 7.2.13 as php-7.2.13

PHP-Extensions benötigen unter Umständen ebenfalls ein paar Extra-Infos zum Kompilieren, für gd nutze ich z. B. folgendes Kommando:

% phpbrew use 7.2.13 && phpbrew ext install gd -- \
--with-zlib-dir=/usr/local/opt/zlib

Bilder von Remote laden in WordPress-Entwicklungsumgebung

Eben stolperte ich über einen Blogpost, in dem erklärt wird, wie man in WordPress die Bilder von einem anderen Host als dem aktuellen einbindet. Normalerweise geht WordPress davon aus, dass die hochgeladenen Medien auf dem aktuellen Host unterhalb von /wp-content/uploads/ zu finden sind.

Beispiel: Dieses Blog läuft auf https:/www.marcusjaschen.de/ und die hochgeladenen Bilder sind normalerweise irgendwo unterhalb von https:/www.marcusjaschen.de/wp-content/uploads/ zu finden.

Holt man sich jetzt die WordPress-Installation in eine Entwicklungsumgebung, möchte man unter Umständen nicht alle Bilder und Medien mitkopieren, denn das können je nach Website schnell einige Gigabytes werden. Die Medien sollen aber natürlich trotzdem angezeigt werden.

Der erwähnte Blogpost beschreibt eine Lösung, die darauf beruht, die Basis-URL für das Uploads-Verzeichnis über eine versteckte Config-Option in WordPress zu ändern. WordPress schreibt dann automatisch alle Medien-URLs um, so dass der Browser diese von ihrer originalen Position lädt (oder aus einem CDN).

Diese Config-Option war mir bis eben unbekannt. Ich habe das Problem bisher auf eine andere Art und Weise gelöst. In meinen nginx-Konfigurationen habe ich jeweils eine Rewrite-Regel, die einfach die Requests umschreibt:

location /wp-content/uploads/ {
    rewrite ^(/wp-content/uploads/.*)$ https://www.marcusjaschen.de/$1 last;
}

Der beobachtete Effekt ist bei beiden Lösungen identisch.

Mein erstes veröffentlichtes WordPress-Plugin

Ich habe im Laufe der Zeit unzählige WordPress-Plugins entwickelt, bisher ausschließlich aber für die interne Verwendung in Projekten wie z. B. MTB-News.de.

Eine Veröffentlichung im Plugin-Verzeichnis auf wordpress.org kam bisher nicht in Frage, da die Einsatzzwecke sehr eng an spezielle Setups gebunden waren und die Plugins damit für jede andere Website schlicht nicht von Nutzen wären.

Nun war es an der Zeit, auch mal ein Plugin zu veröffentlichen, welches durchaus weitere Nutzer haben könnte. Es stellt die Verbindung zwischen zwei anderen beliebten Plugins her:

  • Better Internal Link Search verbessert die Suchfunktion beim Verlinken auf bestehende Inhalte
  • WP Subtitle erweitert WordPress-Artikel um eine zweite Überschrift („Subtitle“, „Dachzeile“)

Better Internal Link Search findet bei der Suche keine Artikel, die den Suchbegriff im Subtitle enthalten. Es bietet allerdings an der richtigen Stelle einen Filter-Hook, den ich genutzt habe, um die Suche entsprechend zu erweitern.

Die Suche ohne das Plugin findet keine Ergebnisse, da der Suchbegriff nur in einem Subtitle vorkommt.

Mit aktiviertem Plugin wird der gesuchte Artikel sofort gefunden.

Das Plugin ist momentan bei MTB-News.de, eMTB-News.de und Rennrad-News.de im Einsatz und ich habe mir versichern lassen, dass es eine große Hilfe in der täglichen Arbeit der Redaktion ist.

Alle Infos zum Plugin gibt es im Plugin-Verzeichnis von WordPress. Der Source Code ist bei Github zu finden.

Entwickler oder Entwicklerinnen die sich besonders schlau vorkommen …

… bauen gerne mal Konstrukte der folgenden Art:

$path = ltrim( end( @explode( get_template(), str_replace( '\\', '/', dirname( __FILE__ ) ) ) ), '/' );

Sortiert sieht es dann so aus:

$path = ltrim(
    end(
        @explode(
            get_template(),
            str_replace('\\', '/', dirname(__FILE__))
        )
    ), 
    '/'
);

Zum Kontext: diese Zeile stammt aus einem kommerziellen WordPress-Template und es soll der letzte Teil des Pfadnamens des aktuell ausgeführten Skripts bestimmt werden. Aus /var/www/wordpress/wp-content/themes/valenti/option-tree soll also option-tree werden.

Von innen nach außen:

  • dirname(__FILE__) liefert den Pfadanteil des aktuell ausgeführten PHP-Skriptes; aus /var/www/wordpress/wp-content/themes/valenti/option-tree/ot-loader.php wird also /var/www/wordpress/wp-content/themes/valenti/option-tree
  • str_replace('\\', '/', …) ersetzt den Backslash (vermutlich als Workaround für Windows-Systeme) mit einem Slash, der Pfad bleibt auf einem unixoiden System also erstmal unverändert (es sei denn, er enthält tatsächlich den Backslash)
  • get_template() liefert den Namen des aktiven WordPress-Templates, in diesem Fall valenti
  • explode() trennt den Pfadnamen in einzelne Teile, und zwar an jeder Stelle an der der String valenti vorkommt; man erhält also dieses Array: [0 => '/var/www/wordpress/wp-content/themes/', 1 => '/option-tree']
  • end() liefert den Wert des letzten Elements des Arrays: /option-tree
  • ltrim(…, '/') entfernt zum Schluss den Slash am Anfang des Strings, so dass wir das Ergebnis erhalten: option-tree

Soweit, so gut.

Diese Variante hat unter Umständen einige Probleme, Backslashes im Pfadnamen könnten eines davon sein. Unterdrückte Fehlermeldungen mit dem @-Operator könnte zu weiteren Hässlichkeiten beim Debugging führen.

Aber das Hauptproblem ist, dass der Entwickler oder die Entwicklerin hier eine komplexe Lösung für ein einfaches Problem geschaffen hat. PHP löst die gegebene Fragestellung nämlich mit Bordmitteln viel eleganter und zudem fehlerunanfällig und OS-unabhängig:

$path = basename(__DIR__);

Keine Ursache.