Erstellen von SVG-Sprites in Kombination mit wordpress/scripts

In einem meiner Adventskalender 2016 Beiträgen habe ich darüber geschrieben, wie man ein SVG-Sprite mit SVG-Symbolen mit Hilfe eines Gulp-Scripts erstellen kann. Nachdem Gutenberg ein essentieller Bestandteil von WordPress geworden ist, habe ich das Paket wordpress/scripts zuletzt sehr häufig verwendet. Nun musste ich vor Kurzem wieder in einem Projekt einen solchen SVG-Sprite erstellen, aber mit gefiel es nicht, hierfür noch zusätzlich Gulp verwenden zu müssen, und so habe ich mich auf die Suche nach einer Alternativen gemacht, die stattdessen wordpress/scripts verwendet.

SVG Spritemap Webpack Plugin

Nach einer kurzen Suche bin ich auf svg-spritemap-webpack-plugin gestoßen, was wirklich sehr vielversprechend aussah. Es verwendet webpack (was in wordpress/scripts enthalten ist) und es wird wie folgt verwendet:

Weiterlesen →

Download-Button für Audio und Video Blöcke ausblenden

Letzte Woche wurde ich im Hilfe bei einem Website-Projekt gebeten. Auf der Seite gab es einige Einbindungen von Audio-Dateien in die Seite. Dieses tolle Feature von WordPress ermöglicht es seht einfach Mediendateien in die Seite einzubetten. Aber manche mögen es nicht, dass man die Dateien in einigen Browsern dann so einfach runterladen kann.

Der „Herunterladen“-Button in Chrome

Im Chrome browser ist es noch einfacher als in anderen Browsern. Dort wird standardmäßig bei jedem Audio und Video Tag ein „Herunterladen“-Button in den Optionen (den drei Punkten neben den Steuerelementen) angeboten. In diesem speziellen Projekt gab es nun den Wunsch diesen Button zu entfernen, um es zumindest etwas schwerer zu machen, die Dateien herunterzuladen und niemanden dazu zu „ermutigen“.

Ausblenden des Buttons mit dem „controlList“ Attribut

Chrome ist der einzige Browser (der mir bekannt ist), der einen solchen Button hat, aber glücklicherweise gibt es auch einen einfach Weg, ihn zu deaktivieren: das controlList Attribut. Das Attribute kann unterschiedliche/mehrere Werte haben, und einer davon ist nodownload, der den Button ausblendet.

Nun könnte man auf die Idee kommen, dieses Attribut einfach über den „Als HTML bearbeiten“ Modus hinzuzufügen, aber sobald man dann über „Visuell bearbeiten“ wieder zurück wechselt ist der Block defekt und man kann nur auswählen den Block zu reparieren (was das Attribut wieder entfernt), oder aber den Block in HTML zu konvertieren.

Einen Feature-Request für Gutenberg erstellen

Da dieses Problem sicher nicht neu ist habe ich mich auf die Suche nach existierenden Tickets gemacht und zwei gefunden. Im ersten wurde darum gebeten einen Schalter einzubauen, der den Button ausblendet. Dieses Ticket verwies auf ein zweites Ticket, in dem generell darüber diskutiert wurde, den Button zu deaktivieren, ebenfalls mit einem Schalter.

In diesem zweiten Ticket wurden gute Argumente aufgeführt, wie ein solcher Schalter nicht gut wäre. Da nur der Chrome Browser diesen Button anzeigt würde auch nur hier der Schalter „funktioniere“. Er würde aber auch hier nicht wirklich funktionieren. Denn auch das Attribut verhindert nicht den Download.

Wenn Audio oder Video-Dateien aus der Mediathek über einen Audio oder Video HTML Tag eingebunden werden, dann können sie auch runtergeladen werden. Sie werden im Grunde auch automatisch „runtergeladen“, sobald sie abgespielt werden.

Den Button still mit einem Plugin entfernen

Wenn ihr den Download also nicht wirklich verhindern könnte, aber wenigsten den Button entfernen möchtet, dann könnt ihr einen Filter verwenden, der beim Rendern des Block das Attribut hinzufügt. Das würde in der einfachsten Form wie folgt aussehen:

function hide_download_buttons_on_embeds_render_block( $block_content, $block ) {
	if ( 'core/audio' === $block['blockName'] ) {
		$block_content = str_replace(
			'<audio ',
			'<audio controlsList="nodownload" ',
			$block_content
		);
	}
	if ( 'core/video' === $block['blockName'] ) {
		$block_content = str_replace(
			'<video ',
			'<video controlsList="nodownload" ',
			$block_content
		);
	}

	return $block_content;
}
add_filter( 'render_block', 'hide_download_buttons_on_embeds_render_block', 10, 2 );

Ihr müsst eventuell etwas mehr Code schreiben, falls der HTML Tag in eurer WordPress-Installation bereits das Attribut mit anderen Werten hat.

Fazit

Obwohl es nicht möglich ist den Download von Audio und Video-Dateien aus der Mediathek in dieser Weise zu verhindern, könnte es für euch vielleicht dennoch interessant sein.

Wenn ihr hingegeben explizit wollt, dass Downloads möglich sind – beispielsweise für eine Episode eures Podcasts – dann solltet ihr stattdessen aktiv einen Download-Button über den „Datei“ Block hinzufügen. Damit habt ihr nicht nur einen Button, der konsistent in allen Browsern gleich aussieht, es macht den Download auch einfacher, intuitiver und barrierefreier möglich.

Wie immer findet ihr den Code zu diesem Blogbeitrag als GIST, wo ihr es auch als ZIP-Datei runterladen und dann als Plugin installieren könnt.

Barrierefreiheit ist kein Feature

Der jährliche Global Accessibility Awareness Day ist erst in ein paar Wochen – dieses Jahr feiern wir ihn am 20. Mai 2021 – aber einige neuerliche Diskussionen haben mich dazu gebracht heute zu diesem Thema zu schreiben.

Es ist nicht nur eine Zahl, es sind Menschen!

In einer Diskussion ging es vor Kurzem um die Luca App zur Corona-Kontaktnachverfolgung und mal wieder darum wie wichtig es ist, dass eine solche App barrierefrei sein muss. Ich kann euch gar nicht sagen, wie oft ich Aussagen wie diese schon lesen musste:

Weiterlesen →

WordPress Datenbank reparieren

Anfang der Woche konnte eine Website nicht mehr aufgerufen werden. Der Fehler wies darauf hin, dass die Verbindung zur Datenbank nicht möglich war. Dieser Fehler tritt eigentlich auf, wenn die Zugangsdaten falsch sind. Aber diese wurden nicht verändert und auch in der Konfiguration waren sie noch immer korrekt. Nach der Aktivierung des WPD_EBUG Modus konnte ich dann den Fehler finden. Die Datenbank war korrupt/defekt.

Reparieren der Datenbank mit der WP-CLI

Mein erster Ansatz war die Verwendung der WP-CLI. Hier gibt es eine Option, mit der man die Tabellen einer Datenbank optimieren kann. Hierdurch können auch manchmal Fehler behoben werden:

wp db optimize

Dieses Kommando wird vor allem dann verwendet, wenn sehr viele Zeilen gelöscht wurden, sich dir Größe der Tabelle aber nicht verringert. Es korrigiert aber nicht immer Fehler in Tabellen. Glücklicherweise gibt es ein anderes Kommando für diese Aufgabe:

Weiterlesen →

Kommentare von privaten Beiträgen im Kommentare Widget anzeigen

Im September 2017 hatte ich einen Blogbeitrag dazu geschrieben, wie man Schlagwörter von privaten Beiträgen in der Tag-Cloud anzeigen lassen kann. Vor drei Wochen wurde in einem Kommentar gefragt ob etwas ähnliches auch für Kommentare aus privaten Beiträgen im Kommentare-Widget möglich sei. In diesem Beitrag möchte ich euch zu dieser Fragestellung eine kleine Lösung präsentieren.

Argumente für die Kommentare-Query filtern

Standardmäßig zeigt das Kommentare-Widget nur die letzten fünf Kommentare von öffentlichen Beiträgen an. Die Argumente der Query sehen wie folgt aus:

Weiterlesen →

Detailliert Download-Statistiken für Plugins abrufen

Vor kurzem habe ich die Download-Zahlen für ein Plugin im offiziellen WordPress.org Plugin-Directory nachgeschlagen. Unter „Erweiterte Ansicht“ eines jeden Plugins findet man eine Grafik mit den „Downloads pro Tag“ und den Zahlen aus den letzten 267 Tagen. Sehen wir uns diesen Graphen für das beliebte Antispam Bee Plugin an:

Downloads pro Tag für Antispam Bee

Wenn ihr mit der Maus über den Graphen fahrt, dann findet ihr zu jedem Tag die entsprechenden Downloads von diesem Tag. Ich wollte aber die Summe der Downloads aus den letzten paar Wochen nach der letzten Veröffentlichung wissen (die Spitze im Graphen) und diese manuell niederzuschreiben und zusammenzurechnen wäre dann doch ein wenig zu viel Arbeit gewesen. Wie komme ich also leichter an diese Zahlen heran?

Weiterlesen →

Bessere Sicherheit für WordPress mit sicheren Server-Headern

Es gibt viele Möglichkeiten eine WordPress Website sicherer zu machen. Für manches davon würdet ihr vermutlich zusätzliche Plugins verwenden. Aber es gibt auch einfache Wege zur Erhöhung der Sicherheit, bei denen ihr nur ein paar Server-Einstellungen ändern müsst. Aber bevor ich ins Detail gehe möchte ich erst einmal zeigen, wie man den aktuellen Stand der Sicherheit eurer Seite herausfinden kann.

Mozilla Observatory

Ein hervorragendes Tool zum Testen der Sicherheit einer Website ist das Mozilla Observatory Tool. Dieses Tool scannt nicht nur die Header, die der Server sendet, es analysiert auch TLS und SSH Einstellungen und verwendet einige dritte Tools für einen guten Überblick. Ein Ergebnis eines solchen Scan, bevor Anpassungen gemacht werden, könnte wie folgt aussehen:

Weiterlesen →

Speicherverbrauch debuggen

Letzte Woche wurde ein Problem mit einer Seite berichtet. Dort wurde manchmal auf einer Seite ein 500er Fehler angezeigt, aber leider nicht immer. Nach der Aktivierung des WP_DEBUG Modus konnte ich sehr schnell feststellen, dass das Speicherlimit überschritten wurde. Die einzige Lösung war es, das Speicherlimit zu erhöhen, da die Funktionalität auf dieser Seite viel Speicher brauchte und es keine schnelle Optimierung gab.

In solchen Fällen wäre es dann schön, wenn man rausfinden könnte, wie hoch das Limit erhöht werden muss. Wie viel Speicher verbraucht also eine Seite normalerweise. Es gibt mehre Wege, dies herauszufinden.

Der gefährliche Weg

Eine sehr einfache Lösung wäre es das Speicherlimit erst einmal zu verringern, bis der Fehler jedes Mal auftritt. Dann erhöht man das Limit schrittweise, bis der Fehler nur noch selten auftritt. Dies ist der Wert, um den herum sich der eigentliche Verbrauch bewegen wird. Zu diesem Wert fügt man noch etwas Puffer hinzu, und prüft, ob der Fehler nun nicht mehr auftritt.

Weiterlesen →

Das Debug-Level mit error_reporting setzen

Jeder von euch kennt vermutlich das Problem. Ihr arbeitet an einer Website und es gibt Fehler. Manchmal ist es sogar ein kritischer und ihr seht das hier:

Aber in manchen Fällen tritt der Fehler nicht in jedem Request auf. Dann solltet ihr den Debug-Modus aktivieren und alle Fehler protokollieren lassen.

Den Debug-Modus aktivieren

Um den Debug-Modus von WordPress zu aktivieren, müsst ihr lediglich ein paar Konstanten in der wp-config.php setzen. Das hier sind die Standardwerte:

Weiterlesen →

Das Löschen von eingebundenen Post-Type-Einträgen verhindern

Dies ist sicher ein Problem, in das einige von euch auch bereits gerannt sind. Ihr habt einen Post-Type-Eintrag in eine Seite oder einen Beitrag eingefügt und diesen dann später gelöscht, ohne zu wissen, dass dieser noch irgendwo eingebunden war. In diesen Beitrag will ich am beliebten Kontakt-Formular-Plugin „Contact Form 7“ demonstrieren, wie das verhindert werden kann. Es funktioniert aber natürlich auch mit jedem anderen Inhaltstyp.

Vorbereitung

Wir installieren das Contact Form 7 Plugin, erstellen ein Formular und fügen dieses in eine Seite mit dem mitgelieferten Gutenberg Block ein. Der Inhalt der Seite sieht dann in etwa wie folgt aus:

<!-- wp:contact-form-7/contact-form-selector {"id":39,"title":"Contact form 1"} -->
<div class="wp-block-contact-form-7-contact-form-selector">[contact-form-7 id="39" title="Contact form 1"]</div>
<!-- /wp:contact-form-7/contact-form-selector -->

Wir sehen hier die ID des Post-Types wpcf7_contact_form, die einmal in den Block-Attributen und einmal im inneren Shortcode verwendet wird, den das Plugin noch immer verwendet.

Löschen eines Post-Type-Eintrags

Wenn wir nun zu „Formulare -> Kontaktformulare“ navigieren können wir über die „Mehrfachaktionen“ das Kontaktformular löschen. Öffnen wir im Anschluss die Seite, auf der wir das Formular eingebunden haben im Frontend, erhalten wir folgendes, ziemlich witzige, Resultat:

[contact-form-7 404 "Nicht gefunden"]

Anstelle des Kontakformulars wird also ein „defekter Shortcode“ angezeigt. Für andere Post-Types wird die „Fehlerbehandlung“ eventuell anders aussehen oder im schlimmsten falsche eure Seite zerschießen.

Post-Type-Einträge vor einer Löschung schützen

Wie können wir also nun vermeiden, dass ein Eintrag gelöscht wird, der noch wo anders eingebunden ist? Nun, hierzu müssten wir alle andern Post-Types nach einem solchen Eintrag durchsuchen. Wenn wir hierzu den „Post-Content“ nach Markup durchsuchen, wird das eine recht teure Operation sein. Für manche Einbindungen wird es wohl auch nicht so einfach funktionieren. Wir holen uns daher ein wenig Hilfe, um die Operation schneller und zuverlässiger zu machen.

Verwendung einer „Hilfstaxonomy“

Wir führen eine Taxonomie ein, die uns beim Verhindern einer Löschung hilft. Diese Taxonomie benötigt kein UI und muss auch nicht öffentlich sein. Daher reichen wenige Zeilen aus, um sie zu registrieren:

function deletion_prevention_register_taxonomy() {
	register_taxonomy(
		'deletion_prevention_tax',
		array( 'post' ),
		array(
			'hierarchical' => false,
			'public'       => false,
		)
	);
}
add_action( 'init', 'deletion_prevention_register_taxonomy' );

Wie müssen sie auch nicht für jeden Post-Type registrieren, mit dem wir sei verwenden wollen, die Registrierung für Beiträge reicht aus. Nun können wir diese Taxonomie hinzufügen.

Hilfstaxonomie zu Seiten und Beiträgen hinzufügen

Für unser Beispiel parsen wir jedes Mal, wenn ein Post-Type gespeichert wird alle Blöcke. Finden wir hierbei einen Kontaktformular Block, dann verwenden wir dessen ID als der Namen des Terms:

function deletion_prevention_save_post( $post_ID, $post, $update ) {
	if ( ! in_array( $post->post_type, array( 'post', 'page', true ) ) ) {
		return;
	}

	$blocks = parse_blocks( $post->post_content );

	$forms = array();
	foreach ( $blocks as $block ) {
		if ( 'contact-form-7/contact-form-selector' === $block['blockName'] ) {
			$forms[] = (string) $block['attrs']['id'];
		}
	}

	wp_set_object_terms( $post_ID, $forms, 'deletion_prevention_tax' );
}
add_action( 'save_post', 'deletion_prevention_save_post', 10, 3 );

In der Callback-Funktion limitieren wir die Überprüfung auf Beiträge und Seiten und suchen nach dem contact-form-7/contact-form-selector Block. Wenn ihr das Löschen mehrerer eingebundener Post-Types verhindern wollt, könnten ihr zusätzliche Taxonomien verwenden, einen anderen Namen für den Term oder Metadaten.

Indem wir nun diese Taxonomie speichern, können wir sehr einfach und genau feststellen, wo Kontaktformulare eingebunden wurden. Wollen wir ein solches Formular löschen, können wir dann diese Seiten und Beiträge sehr schnell finden.

Verhinderung der Löschung

Jedes Mal, wenn ein Post-Type-Eintrag gelöscht wird, werden eine Reihe von Actions ausgelöst. Eine davon wird kurz vor der eigentlichen Löschung ausgeführt und hier können wir uns einhängen:

function deletion_prevention_delete_check( $delete, $post, $force_delete ) {
	deletion_prevention_check( $post );
}
add_action( 'pre_delete_post', 'deletion_prevention_delete_check', 10, 3 );

Einige Inhaltstypen unterstützen das Verschieben von Einträgen in den Papierkorb (Contact Form 7 unterstützt dies nicht), es kann also hilfreich sein, auch dies abzufangen:

function deletion_prevention_trash_check( $trash, $post ) {
	deletion_prevention_check( $post );
}
add_action( 'pre_trash_post', 'deletion_prevention_trash_check', 10, 2 );

Jetzt seht ihr auch, weshalb ich eine weiter Funktion für die Überprüfung verwendet habe.

Überprüfung auch aktuelle Einbindungen eines Eintrags

Jetzt sind wir im letzten Schritt. Wir suchen mit Hilfe einer Taxonomy-Query nach Einbettungen des zu löschenden Eintrags in Seiten und Beiträgen, indem wir dessen ID als Term-Slug verwenden:

function deletion_prevention_check( $post ) {
	$args = array(
		'post_type'      => array( 'post', 'page' ),
		'post_status'    => array(
			'publish',
			'pending',
			'draft',
			'future',
			'private',
		),
		'tax_query'      => array(
			array(
				'taxonomy' => 'deletion_prevention_tax',
				'field'    => 'slug',
				'terms'    => (string) $post->ID,
			),
		),
		'posts_per_page' => 1,
		'fields'         => 'ids',

	);
	$posts = get_posts( $args );

	if ( ! empty( $posts ) ) {
		wp_die(
			wp_kses_post(
				sprintf(
					__(
						/* translators: %1$s: link to a filtered posts list, %2$s: link to a filtered pages list */
						'This item as it is still used in <a href="%1$s">posts</a> or <a href="%2$s">pages</a>.',
						'deletion-prevention'
					),
					admin_url( 'edit.php?post_type=post&taxonomy=deletion_prevention_tax&term=' . $post->ID ),
					admin_url( 'edit.php?taxonomy=deletion_prevention_tax&term=' . $post->ID )
				)
			)
		);
	}
}

Wenn diese Query mindestens einen Beitrag oder eine Seite zurück liefert, dann wissen wird, dass der Post-Type-Eintrag noch immer verwendet wird. In diesem Fall unterbrechen wir den aktuellen Request mit einem wp_die, was auch die Löschung unterbindet. In der Nachricht sind zwei Links enthalten, die auf die Listen von Beiträgen bzw. Seiten verweisen, in denen der Eintrag eingebunden ist. Hiermit kann man ihn dann schnell dort entfernen und anschließend gefahrlos löschen.

Fazit

Es passiert sehr leicht, dass man aus Versehen einen Eintrag eines Post-Types löscht, der noch an anderer Stelle verwendet wird. Im Core gibt es leider keine Möglichkeit, so etwas einfach zu verhindern. Durch unsere Hilfstaxonomie können wir dies nun sehr einfach absichern. Der gleiche Ansatz würde auch funktionieren, um das Ändern des Status eines Eintrags in einen „nicht öffentlichen“ Status zu verhindern. Das Löschen von Medieninhalten lässt sich hiermit leider nicht direkt abfangen (obwohl diese auch ein Post-Type sind). Ich hoffe dieser letzte Beitrag für 2020 hilft euch ebenfalls in einem Projekt weiter. Den Quellcode dieses Beitrags findet ihr als Plugin in einem GIST, welches ihr gerne ausprobieren oder für eure Anforderungen anpassen könnt.