Lass mal schnell ’nen Blog erstellen…

…so oder zumindest so ähnlich muss ich mich wohl angehört haben, als ich Tobias von meiner neuen Idee erzählte. 😉 Da es mittlerweile einige fachliche Beiträge zu lesen gibt, ist es nun an der Zeit, mal ein paar Worte über die Entstehung dieses Blogs zu schreiben. Insbesondere soll es darum gehen, welche Fragen wir uns stellen mussten und welche Problemchen es zwischenzeitlich zu lösen galt. Der gestandene WordPress Experte wird hier und da vielleicht etwas die Stirn runzeln, die hier beschriebenen Themen sind aber eher für Einsteiger gedacht.

Auswahl des CMS

Eigentlich müsste man an dieser Stelle erst mal einen ausgiebigen Vergleich machen, welche Content Management Systeme es so gibt und was diese jeweils leisten. Diesen Schritt habe ich direkt übersprungen: Da meine Frau als Lehrerin gleichzeitig auch die Schul-Webseite betreut, fiel die Wahl direkt auf WordPress, damit ich in Zukunft die eine oder andere ihrer Fragen dazu mal etwas fachgerechter beantworten kann. 😀

Installation und erste Schritte

WordPress wirbt mit einer einfachen Installation in weniger als 5 Minuten. Das kann ich bestätigen. Natürlich sollte man sich vorher um einen Webspace kümmern und die Installationsdateien herunterladen. Dann braucht man kaum mehr zu tun, als den Datenbank-Login einzugeben und schon präsentiert sich die neue Webseite im Standard-Theme.

An dieser Stelle habe ich mir dann sofort die Frage gestellt, wie die Seite denn etwa aussehen soll. Tobias uns ich haben uns schnell darauf geeinigt, dass das Design eher schlicht und in blau-grau Tönen sein soll. Dann ging also die große Suche los. Die Auswahl ist wirklich riesig. Zwar kann man z.B. nach „Blog“ filtern, aber was genau bedeuten Filter wie „Raster-Layout“ oder „Beitrag oben halten“ und wollen wir eher „Zwei Spalten“ oder „Vier Spalten“? Da es auch schlicht an der konkreten Vorstellung mangelte, scrollte ich einfach grob durch alle Designs durch und installierte etliche für den späteren Vergleich. Irgendwann bemühte ich dann sogar mal Google und fand einen Aussage, dass das Theme GeneratePress eine gute Wahl sei. Den genauen Link dazu habe ich aber nicht mehr.

Dann stieß ich auf Begriffe wie Classic Themes und Block Themes. Hier möchte ich nicht zu sehr ins Detail gehen, da ich erstens – wie oben bereits angedeutet – ein WordPress Anfänger bin und zweitens, es dazu wirklich genügend Informationen gibt.1 Jedenfalls werden Block Themes als die Zukunft von WordPress beworben, sie wären flexibler und schneller. Somit fiel der Großteil der zuvor installierten Themes wieder raus. Leider ist auch GeneratePress ein Classic Theme. Übrig blieben eine Hand voll Block Themes und schließlich haben wir uns für Charta entschieden, welches rein von der Optik recht nah an GeneratePress liegt.

Danach ging es an die Anpassungen. Mit dem WordPress Website-Editor geht das nach kurzer Zeit relativ einfach: Wie soll der Blog-Index aussehen, welche Metadaten sollen angezeigt werden? Was soll in Header und Footer stehen? Welche Widgets wollen wir haben? All diese Einstellungen ließen sich recht komfortabel anpassen. Trotzdem ist dabei ein Fehler passiert, dessen Konsequenzen wir noch nicht hundertprozentig abschätzen können. Es wird quasi in jeder Anleitung zur Anpassung eines WordPress Themes erwähnt und dennoch haben wir es falsch gemacht: Man sollte vorher ein Child Theme erstellen, damit die vorgenommenen Änderungen bei Aktualisierung des Themes nicht verloren gehen.2 Aber diesem Problem können wir uns auch noch widmen, wenn es soweit ist.

Bisher hatte alles Spaß gemacht, aber dann wurde es etwas trockener…

Impressum und Datenschutzerklärung

Soweit ich weiß, ist für rein private Webseiten kein Impressum erforderlich, was z.B. auch diese Seite bestätigt. Dort steht aber ebenfalls:

Andererseits fordern sowohl § 5 DDG (ehemals TMG) als auch § 18 MStV im Hinblick auf journalistisch-redaktionelle Inhalte die Angabe eines Verantwortlichen für den Inhalt der Website. Blogger und Forenbetreiber sollten deshalb über ein Impressum verfügen.

Wenn die Faktenlage so schwammig ist, sollte man lieber kein Risiko eingehen. Mit der Pflicht zur Datenschutzerklärung verhält es sich ähnlich:

Danach findet die DSGVO keine Anwendung auf die Verarbeitung personenbezogener Daten durch natürliche Personen zur Ausübung ausschließlich persönlicher oder familiärer Tätigkeiten. Da es sich hierbei jedoch um eine Ausnahme von der Regel handelt, ist die Anwendung restriktiv zu handhaben:

  • Unter persönliche Tätigkeiten fallen alle Tätigkeiten, die der eigenen Selbstentfaltung und Freiheitsausübung dienen oder der privaten Sphäre zuzuordnen sind.
  • Rein familiäre Tätigkeiten erfassen die Pflege familiärer Beziehungen und des familiären Zusammenhalts.

Ich würde zwar durchaus interpretieren, dass dieser Blog unter Tätigkeiten der eigenen Selbstentfaltung und Freiheitsausübung fällt und unserer privaten Sphäre zuzuordnen ist, sicher bin ich mir da aber nicht. Deshalb musste auch eine Datenschutzerklärung her. Hier bin ich auf den Datenschutz-Generator von Dr. Thomas Schwenke aufmerksam geworden. Man kann mit einigen Klicks verschiedene Module an- und abwählen und erhält so eine angepasste Datenschutzerklärung für den eigenen Webauftritt. Wie rechtssicher das wirklich ist, kann ich nicht beurteilen. Für einen rein privaten Blog sollte es aber hoffentlich ausreichend sein.

Für die Angabe meiner Kontaktdaten im Impressum wollte ich eigentlich den Contact Info Block verwenden. Diesen wollte mir der Block-Editor aber partout nicht ausspucken. Nach einer kurzen Google-Suche fand ich diesen Beitrag. Der Contact Info Block ist nur für WordPress.com verfügbar. Das ist ein kommerziell gehosteter Blogging-Dienst von Automattic und keinesfalls mit der quelloffenen Software WordPress.org zum selbst hosten zu verwechseln… 😤

Lightbox-Animation für Bilder

Leider haben eingebundene Bilder in WordPress nicht automatisch diesen schicken Lightbox-Swipe-Effekt. Hierfür gibt es allerdings Massen an Plugins. Wir haben uns letztendlich für das Plugin von Arno Welzel entschieden, das bisher gute Dienste tut. Nur anfangs gab es ein paar Startschwierigkeiten, was aber schlicht daran lag, dass wir die Doku nicht richtig gelesen haben:

Just make sure that you link the image or gallery directly to the media and not the attachment page.

Diesen Hinweis sollte man ernst nehmen, sonst geht es nicht. 😉 Das Bild muss im Block-Editor mit der Option „Link zur Bilddatei“ verlinkt werden.

Hier noch eine Demo:

Abbildung 1: Lightbox Demo

P.s.: Mittlerweile hat WordPress die Verlinkungsoption „Mit Klick erweitern“ nachgerüstet. Wir bleiben trotzdem beim genannten Plugin.

Noch ein paar kleine Extras

An dieser Stelle war der Blog dann in einem ganz guten Zustand und bereit für die ersten Inhalte. Wenn man aber mal schaut, was andere Blogs noch so an netten Funktionen haben, gibt es doch schnell noch ein paar weitere Punkte auf der Wunschliste. So gefielen uns beispielsweise diese Icons für Kategorien, Tags, Kommentare usw. ziemlich gut:

Abbildung 2: Blog Icons

Nach einer kurzen Google Suche stieß ich auf Font Awesome, welches ich voller Begeisterung integrierte – hierfür gibt es ein WordPress Plugin. Als ich dann versuchte, dieses Plugin in die Datenschutzerklärung zu integrieren, wurde ich stutzig… Der Datenschutz-Generator bot mir nur das folgende Modul an: Font Awesome (Bereitstellung auf eigenem Server). Genau das ist aber nur mit der Bezahlversion des Plugins möglich. Wenn man die kostenlose Version nutzen möchte, kann man die Fonts ausschließlich über das Font Awesome Content Delivery Network einbinden. Über die Suchfunktion fand ich dann auch das Modul Font Awesome (Bezug vom Server des Anbieters), das aber nur in der Premium-Version des Datenschutz-Generators zur Verfügung steht. Das war komisch…

Schließlich konnte ich Licht ins Dunkel bringen: Die DSGVO verbietet grundsätzlich alle Datenübertragungen in Nicht-EU-Länder. Ausnahme: Der Empfänger der Datenübertragung unterwirft sich dem EU-US-Privacy-Shield Abkommen und damit den Europäischen Datenschutzstandards (gilt für US-Firmen). Das Unternehmen Fonticons hat genau das aber nicht getan. Das Ganze könnte man theoretisch wohl noch mit einem direkten Vertrag mit Fonticons kompensieren3, aber wer macht das schon?! Also: Wenn man nicht gerade die kostenpflichtige Font Awesome Variante zum Selbsthosting verwenden möchte, ist dieses Plugin derzeit ein No Go. Finger weg! Stattdessen kann man aber Google Fonts verwenden, denn mit Google besteht ein Privacy-Shield Abkommen. Die Google Fonts kann man aber auch kostenfrei selbst hosten. Dafür haben wir uns dann entschieden. Das Ergebnis sieht man nun am Anfang und am Ende eines jeden Beitrags.

Ein Problem blieb dann noch: Während es ein Leichtes war, die Kategorien und Schlagwörter neben den Icons anzuzeigen, gab es leider keinen vorgefertigten Block, der ausschließlich die Anzahl der Kommentare zum jeweiligen Beitrag anzeigen konnte. Hier musste ich tatsächlich ein wenig programmieren. WordPress bietet Hooks, mit denen man einfach individuellen Code an der richtigen Stelle zur Ausführung bringen kann. Außerdem kann man sogenannte Shortcodes definieren, die man dann einfach mit [shortcode] im Block-Editor verwenden kann. Zum Glück hatten derartige Probleme aber schon andere vor mir, sodass ich hier sehr schnell zu einer Lösung kam.4 Die Lösung funktionierte zwar auf der Beitragsseite selbst, nicht aber im WordPress Query Loop (= Block zur Auflistung aller Beiträge). Aber auch das hatten andere schon gelöst.5

Schauen wir uns das doch einfach mal an:

add_shortcode("post_comment_count", function($atts = array(), $content = null, $tag = "") {	if(isset($atts["postid"]) && is_numeric($atts["postid"])) {		$post = get_post($atts["postid"]);	}	else {		global $post;	}	$args = array(		"status" => "approve",		"post_id" => $post->ID,		"type" => "comment"	);	$comments = get_comments($args);	return count($comments);}); add_filter("render_block", function($block_content, $block) {	// add this class to target block	$block_class = "post-comment-count";	if (	!empty($block["attrs"]["className"]) && 		$block_class === $block["attrs"]["className"]) { 		// build and return my shortcode		$short_code = "[post_comment_count postid='" . get_the_ID() . "']";		return do_shortcode($short_code);  	}	return $block_content;}, 10, 2);

Zuerst wird mit add_shortcode ein Shortcode definiert, dessen Funktion anschließend durch Verwendung von [ post_comment_count ] aufgerufen werden kann – irgendwie muss ich WordPress ja mitteilen, wo meine Kommentaranzahl ausgegeben werden soll. Dann erfolgt eine Fallunterscheidung, die mit der Frage zusammenhängt, ob der Shortcode im Query Loop (if) oder direkt auf der Beitragsseite (else) aufgerufen wird (dazu später mehr). Anschließend wird die WordPress Funktion get_comments passend parametrisiert (nur freigegebene Kommentare zählen) und aufgerufen. Und schon hat man die Anzahl der Kommentare für den entsprechenden Beitrag. Bleibt die Frage, wo dieser Shortcode nun hin gehört…

Ab Zeile 19 hängen wir uns mit add_filter an den Hook render_block, welcher immer dann ausgeführt wird, wenn eben ein Block gerendert wird. Und natürlich soll der Shortcode nicht bei jedem gerenderten Block ausgeführt werden, sondern nur bei ausgewählten Blöcken. Und diese definieren sich einfach dadurch, dass sie von mir im Block-Editor eine zusätzliche CSS-Klasse post-comment-count erhalten haben. Wann immer also gerade ein Block gerendert wird, der diese Klasse hat, soll an dieser Stelle der Shortcode [ post_comment_count ] ausgeführt werden. Und das macht do_shortcode. Das Ergebnis – einen modifizierten $block_content – gebe ich an den Hook zurück (Zeile 28). Das return in Zeile 31 kommt nur zur Ausführung, wenn der gerade gerenderte Block nicht die oben genannte CSS-Klasse hat. Also sehr oft! In diesem Fall wird der $block_content unverändert zurückgegeben.

Nun zur Besonderheit, ob der Shortcode im Query Loop oder auf der Beitragsseite aufgerufen wird: Ist letzteres der Fall, existiert eine globale PHP-Variable $post, aus der man einfach die Beitrags-ID entnehmen kann. Ist dies nicht der Fall, muss im Query Loop die ID des aktuell verarbeiteten Beitrags mit get_the_ID abgerufen werden. Diese kann man dann einfach als Shortcode-Parameter an die Shortcode-Funktion übergeben. Hierfür habe ich den passenden Namen postid gewählt (Zeile 27) und genau darauf bezieht sich auch die Prüfung in Zeile 2: Wenn der Shortcode [ post_comment_count ] einen Parameter postid hat, wird dieser verwendet, andernfalls erfolgt der Zugriff auf die Beitrags-ID über die globale Variable $post. So war es nun endlich möglich, die Anzahl von Kommentaren zu einem Beitrag anzuzeigen. 🎆

Beitragsbilder

Beitragsbilder hatten wir von Beginn an abgewählt. Weder sind wir selbst gute Fotografen, noch wollten wir Geld für Fotos ausgeben. Und so startete der Blog zuerst auch ohne. Im Laufe der Zeit sind wir dann aber auf Unsplash aufmerksam geworden. Die dort verfügbaren Bilder von Fotografen aus aller Welt sind dauerhaft kostenlos und genehmigungsfrei für kommerzielle und nicht-kommerzielle Zwecke nutzbar. Eine Urheberangabe ist dennoch gern gesehen und würdigt die Arbeit der Fotografen.

Wie viele Besucher hat unser Blog eigentlich?

Diese Frage begannen wir uns recht bald zu stellen… Außerdem wäre es ganz toll, wenn unsere Besucher den Blog auch abonnieren könnten. Ein oder zwei Besucherzähler-Plugins haben wir ausprobiert, u.a. Statify. Diese wirkten aber eher rudimentär. Dann sind wir relativ schnell auf Jetpack gestoßen. Hierbei handelt es sich um ein ziemlich umfangreiches WordPress Plugin von Automattic, das weit mehr als nur Website-Statistiken und eine Abonnement-Funktionen mit sich bringt. Dazu zählen unter anderem ein übersichtliches Aktivitätenprotokoll, eine Backup-Funktion in die Jetpack-Cloud, Schwachstellen-Scans, ein Brute-Force-Schutz für den WordPress Admin-Login, eine verbesserte Website-Suche, Social Media Plugins und vieles mehr. Außerdem bringt es eine Menge neuer Blöcke mit sich, wie z.B. den Contact Info Block von WordPress.com, über den ich oben bereits geschrieben habe. Damit das alles ordentlich funktioniert, sollte man ein WordPress.com-Konto anlegen und dieses mit dem Jetpack Plugin verbinden:6

Jetpack is a plugin that allows you to use features we developed on WordPress.com on your self-hosted website through the Jetpack plugin. Since these features were built for WordPress.com sites, we need to connect your site via the Jetpack plugin to a WordPress.com account.

Natürlich sind die meisten dieser Funktionen kostenpflichtig, für unsere Zwecke – eine rein private Webseite – reicht die kostenfreie Variante bisher aber aus. Jedenfalls haben wir nun ein paar Besucherstatistiken und einen ansprechenden Newsletter.

Verwendung von SVG-Dateien

In der WordPress Mediathek ist das Hochladen von SVG-Grafiken out of the Box nicht möglich. Hierfür gibt es zwar eine Handvoll Plugins, das schien uns aber übertrieben. Und tatsächlich gab es wieder eine schlanke PHP-Lösung:7

add_filter("upload_mimes", function($mimes) {	$mimes["svg"] = "image/svg+xml";	return $mimes;}, 10, 1);

Auch hier wird wieder eine Callback-Funktion verwendet, welche diesmal an den Hook upload_mimes gebunden wird. Und dort passiert dann wirklich keine Magie: Das Array erlaubter MIME-Typen wird um einen Eintrag erweitert und zurückgegeben. Das war alles.

Code-Block mit Zeilennummern

Ein Code-Block mit Zeilennummern ist für einen IT-Blog einfach notwendig. Leider hat WordPress auch hier nichts passendes an Bord. Bei WordPress.com gibt es das zwar unter dem Namen SyntaxHighlighter Code Block, dieses Feature bringt Jetpack aber leider nicht mit in die WordPress.org-Welt. Auch hierfür gibt es wieder viele Plugins mit etlichen Einstellungsmöglichkeiten. Trotzdem entschieden wir uns für den Code-Block der Marke Eigenbau. 😉 Und der ist jetzt zum dritten Mal in diesem Beitrag zu sehen. Er stammt, wie viele Code-Snippets, von StackOverflow. Die dort genannten Anforderungen passten einfach gut zu unseren Vorstellungen. Und es sollte auch niemals um vollständiges Syntax Highlighting gehen.

Nun musste nur noch der passende HTML-Code in WordPress erzeugt werden:

add_filter("render_block", function($block_content, $block) {	// add this class to target block	$block_class = "code-with-numbers";	if (	$block["blockName"] === "core/code" &&		!empty($block["attrs"]["className"]) &&		$block_class === $block["attrs"]["className"]) {		$block_content = preg_replace("/<\/*code>/", "", $block_content);		$matches = array();		preg_match("/(<[^\/>]*>)(.*)(<[^>]*>)/s", $block_content, $matches);		$block_content = "";		$lines = explode(PHP_EOL, $matches[2]);		$lineCount = count($lines);		for($i = 1; $i <= $lineCount; $i++) {			$parity = $i%2 == 0 ? "even" : "odd";			if($i == 1) {				$parity = "first-row " . $parity;			}			if($i == $lineCount) {				$parity = "last-row " . $parity;			}			$block_content .= "<span class=\"tr " . $parity . "-row\"><span class=\"th\"></span><code>" . $lines[$i-1] . "</code></span>";		}		$block_content = $matches[1] . $block_content . $matches[3];	}	return $block_content;}, 10, 2);

Kurz ein paar Worte zur Funktion: Erneut hängen wir uns an den Hook render_block. In der Callback-Funktion erfolgt die Prüfung, ob es sich beim aktuellen Block um einen Block vom Typ core/code handelt. Zusätzlich muss der Block die Klasse code-with-numbers haben, denn es sollen auch weiterhin Code-Blöcke ohne Nummerierung existieren können.

Danach muss der WordPress Code-Block ein Bisschen geparsed werden, um die blanken Textzeilen zu extrahieren. Diese werden schließlich wieder in einem passenden Format ausgegeben. Dabei wird noch zwischen geraden und ungeraden Zeilen sowie zwischen erster und letzter Zeile unterschieden, um diese verschieden mit CSS ansprechen zu können:

pre.code-with-numbers {  display: table;  table-layout: fixed;  width: 100%;  white-space: pre-wrap;  padding: 0;}pre.code-with-numbers::before {  counter-reset: linenum;}pre.code-with-numbers span.tr {  display: table-row;  counter-increment: linenum;}pre.code-with-numbers span.th {  display: table-cell;  user-select: none;  -moz-user-select: none;  -webkit-user-select: none;}pre.code-with-numbers span.first-row span.th {  padding-top: 0.2em;}pre.code-with-numbers span.last-row span.th {  padding-bottom: 0.2em;}pre.code-with-numbers span.odd-row code {}pre.code-with-numbers span.even-row code {  background-color: #f0f8ff;}pre.code-with-numbers span.th::before {  content: counter(linenum);  text-align: right;  display: block;}pre.code-with-numbers span.th {  width: 2em;  background-color: #e5e5e5;  padding-right: 0.5em;}pre.code-with-numbers code {  display: table-cell;  padding-left: 0.5em;}

Wie sich später herausstellte, hat der Code-Block aber noch ein Problem: Beim Kopieren von Zeilen aus dem Block, wird durch Firefox nach jeder Zeile eine Leerzeile eingefügt (siehe mein Kommentar unter dieser Antwort). Der Autor Pedro hat dafür aktuell keine Lösung, ist sich aber sicher, dass das mal korrekt funktionierte und dass das Fehlverhalten erst mit einer bestimmten Firefox-Version dazugekommen ist. Aktuell ist das für uns akzeptabel. Eventuell findet sich ja noch eine Lösung… Beispielsweise könnte man noch einen „Kopieren“-Link in der Ecke des Code-Blocks implementieren, der die Leerzeilen rausnimmt. Aber das hat derzeit keine Priorität. Dennoch: Über Hinweise, wie man das Problem noch lösen könnte, wären wir dankbar!

So bindet man übrigens ein eigenes Stylesheet in WordPress ein:

wp_enqueue_style("bb4l.css", "/wp-content/themes/bb4l.css");

Diese Zeile steht in unserer Datei bb4l.php, welche ebenfalls von WordPress geladen werden muss. Das macht man am besten in der functions.php des jeweiligen (Child-)Themes:

require get_template_directory() . '/../bb4l.php';

Alles keine Raketenwissenschaft. Nur wissen muss man es.

Fazit

Ganz so schnell ging das mit dem Blog also doch nicht… WordPress bietet viele Möglichkeiten: Einerseits gibt es Unmengen an Plugins für unbedarfte Nutzer, andererseits hat man auch die Möglichkeit, Anpassungen direkt mit PHP vorzunehmen. Hier muss man immer schauen, welche Voraussetzungen man selbst mitbringt und was man eigentlich genau haben möchte. Wir sind mit der Entscheidung für WordPress aber nach wie vor zufrieden. Im Großen und Ganzen konnten wir all unsere Wünsche umsetzen, wenn auch hier und da ein Bisschen Handarbeit nötig war.

Wie schon eingangs angedeutet, wird der WordPress Experte kaum etwas Neues in diesem Beitrag gefunden haben. Vielmehr ging es uns aber darum, die mühsam zusammengesuchten Details nochmal kompakt darzustellen. Vielleicht hilft es ja jemandem! 🙂

Foto von Luke Stackpoole auf Unsplash

  1. https://www.elmastudio.de/was-sind-wordpress-block-themes/
    https://jetpack.com/blog/wordpress-switch-from-classic-to-block-theme/ ↩︎
  2. https://kinsta.com/de/blog/wordpress-theme-aktualisiert/#update-custom-theme ↩︎
  3. https://www.einfach-abmahnsicher.de/drittdienste/fontawesome ↩︎
  4. https://www.flomei.de/blog/2014/03/03/wordpress-anzahl-der-kommentare-zu-einem-artikel-ermitteln/ ↩︎
  5. https://wordpress.org/support/topic/custom-field-via-shortcode-inside-query-loop-block/
    https://wordpress.org/support/topic/get-postid-of-posts-included-in-query-loop/ ↩︎
  6. https://jetpack.com/support/why-the-wordpress-com-connection-is-important-for-jetpack/ ↩︎
  7. https://www.sven-hoerig.de/ratgeber/wordpress-svg-upload-aktivieren/ ↩︎
folder
chat 0

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert