Child Plugins: Filter in Plugins verwenden

Eigentlich müsste ich ja heute gar keinen Artikel schreiben, denn meine Schuldigkeit für das #projekt52 habe ich eigentlich mit meinem englischen Artikel über das WordCamp Bilbao schon getan. Aber ich möchte natürlich meine deutschsprachigen Leser nicht enttäuschen und meine Artikelreihe zu Child Plugins fortführen 🙂

Filter in Plugins nutzen

Im letzten Beitrag ging es ja um Actions und wie man diese findet. Die Funktion, die man dabei im Code suchen musste war die do_action() Funktion. Da die Funktionsnamen bei Filters und Actions sehr ähnlich sind, könnte man nun auf die Idee kommen, nach do_filter() zu suchen. Leider werdet ihr damit keinen Erfolg haben, denn die Funktion, die ihr suchen müsst lautet apply_filters() und man erkennt schon am Namen den Unterschied zwischen den beiden Hooks, die ich euch im vorletzten Artikel erklärt habe. Filter verändern einen übergebenen Wert (und das können eben mehrere Veränderungen sein, daher der Plural im Funktionsname), wohingegen Actions etwas ausführen, was in der Regel eine Ausgabe von HTML-Code oder ein anderer Seiteneffekt ist.

Filter im Plugincode identifizieren

Ein Filter kann sowohl in Template-Dateien, als auch in sonstigen Funktionen vorkommen. Gemeinsam ist dabei, dass die Funktion nicht direkt zu einer Ausgabe führt, sondern das Ergebnis weiterverwendet wird (das könnte aber natürlich auch eine Ausgabe sein). Hier habe ich mal ein Beispiel eines Filters aus dem Yoast SEO Plugin für euch, der die Funktionsweise und den Nutzen sehr gut zeigt:

class WPSEO_Admin_Stop_Words {

	// ...

	public function list_stop_words() {
		
		$stopwords = explode( ',', __( "a,about,above,...", 'wordpress-seo' ) );

		/**
		 * Allows filtering of the stop words list. Especially useful 
		 * for users on a language in which WPSEO is  not available
		 * yet and/or users who want to turn off stop word filtering.
		 *
		 * @api  array  $stopwords  Array of all lowercase stop words
		 *                          to check and/or remove from slug
		 */
		$stopwords = apply_filters( 'wpseo_stopwords', $stopwords );

		return $stopwords;
	}
}

Bei Suchen gibt es oft eine Liste sogenannter Stopwords, die von einer Suche ignoriert werden sollen, da sie zur normalen Sprache gehören und keine besondere Bedeutung für die Suche haben sollen. Im deutschen wären das z.B. Wörter wie „aber, als, am, an, auch, auf, aus, bei, …“. Ich denke ihr versteht das Prinzip. Für das Yoast SEO Plugin wird über eine Übersetzungsdatei eine Liste solcher Wörter für jede Sprache, in der das Plugin verfügbar ist, angeboten. Dieser übersetzte String (im Beispielcode verkürzt) wird dann mit der explode() Funktion in ein Array überführt.

Filter verwenden

Möchte man nun diese Liste an Stopwords erweitern oder einige davon entfernen, kann man den Filter wpseo_stopwords verwenden, den die Plugin-Autoren des Yoast SEO Plugins zur Verfügung stellen. Eine Verwendung des Filters könnte dabei wie folgt aussehen:

/**
 * @param array $stopwords Array of all lowercase stop words.
 *
 * @return array
 */
function add_custom_stop_words( $stopwords ) {
	$stopwords[] = 'über';
	return $stopwords;
}
add_filter( 'wpseo_stopwords', 'add_custom_stop_words' );

Die Liste in der deutschen Übersetzungsdatei des Yoast SEO Plugin ist ziemlich gut, es fehlt aber das Wort „über“, das einige Suchmaschinen ebenfalls als Stoppwort definiert haben. Mit dem oben gezeigten Code könnt ihr dieses Wort nun sehr einfach der Liste hinzufügen.

Filter mit mehreren Parametern

Schon im letzten Beitrag habe ich euch ja gesagt, dass ein Hook immer mindestens einem Parameter übergeben bekommt. Es kann aber oft sinnvoll sein, mehrere Parameter an eine Callback-Funktion zu übergeben. Hier ein weiteres Beispiel aus dem Yoast SEO Plugin:

class WPSEO_Sitemap_Image_Parser {

	// ..

	private function parse_matched_images( $matches, $post ) {

		$return = array();

		foreach ( $matches as $img ) {

			// ...

			/**
			 * Filter image data to be included in XML sitemap for the post.
			 *
			 * @param array $image {
			 *     Array of image data.
			 *
			 *     @type string $src Image URL.
			 *     @type string $title Image title attribute (optional).
			 *     @type string $alt Image alt attribute (optional).
			 * }
			 * @param object $post  Post object.
			 */
			$image    = apply_filters( 'wpseo_xml_sitemap_img', $image, $post );
			$return[] = $image;

			unset( $match, $src );
		}

		return $return;
	}

	// ...
}

In diesem Beispiel werden an den Filter zwei Parameter übergeben. Ein Array mit Bildeigenschaften und das Post Objekt. Es wird erwartet, dass der Filter nur den ersten Parameter wieder zurückgibt, also das veränderte $image Array. Wieso wird dann also ein Parameter übergeben, der gar nicht zurückgegeben wird? Die Plugin-Autoren haben erkannt, dass ein Entwickler, der diesen Filter verwendet, die Bildeigenschaften eventuell abhängig von der Seite, auf der der Filter verwendet wird, unterschiedlich verändern möchte. Indem das Post Objekt übergeben wird, kann der Entwickler hierüber sehr einfach eine entsprechende Bedingung in der Callback-Funktion definieren.

Damit dies funktioniert, muss bei der Verwendung darauf geachtet werden, die korrekte Anzahl an Parametern anzugeben. In diesem Fall müsste man also den Filter wie folgt nutzen:

/**
 * Filter image data to be included in XML sitemap for the post.
 *
 * @param array $image {
 *     Array of image data.
 *
 *     @type string $src Image URL.
 *     @type string $title Image title attribute (optional).
 *     @type string $alt Image alt attribute (optional).
 * }
 * @param object $post  Post object.
 */
function custom_wpseo_xml_sitemap_img_filter( $images, $post ) {

	if ( 'private' === get_post_status ( $post->ID ) ) {
		$image['src'] = plugins_url( 'image-for-private-posts.png', __FILE__ );
	}
	
	return $image;

}
add_filter( 'wpseo_xml_sitemap_img', 'custom_wpseo_xml_sitemap_img_filter', 10, 2 );

In diesem Beispielcode wird nun die zweite Variable verwendet, um für Seiten, die den Status „private“ haben, ein anders Bild zu verwenden. Auch wenn das nur ein ausgedachtes Beispiel ist, solltet ihr damit das Prinzip und den Zweck von zusätzlichen Parametern verstehen können.

Wichtig ist hier neben der Angabe beider Parameter in der Funktionsdefinition auch der vierte Parameter in der add_filter() Funktion. Lässt man diesen beispielsweise leer, wird ein Wert von 1 angenommen. Die Callback-Funktion des Filters wird dann zwar aufgerufen, der Parameter $post ist dann aber leer und somit macht die Funktion nicht das, was sie tun sollte.

Spezielle Rückgabewerte für Filter

Manchmal werden Filter auch angeboten, um Funktionen zu deaktivieren, wenn der entsprechende Filter einen bestimmten Wahrheitswert zurückliefert. Hier ein Beispiel für einen solchen Einsatz eines Filters:

class WPSEO_Sitemaps {

	// ..
	
	public static function ping_search_engines( $url = null ) {

		/**
		 * Filter: 'wpseo_allow_xml_sitemap_ping' - Check if pinging
		 * is not allowed (allowed by default)
		 *
		 * @api boolean $allow_ping The boolean that is set to true by default.
		 */
		if ( apply_filters( 'wpseo_allow_xml_sitemap_ping', true ) === false ) {
			return;
		}
		
		// ..
	}
	
	// ..
}

In diesem Beispiel wird ein Filter angeboten, mit dem man das „Pinging“ von Suchmaschinen erlauben oder unterbinden kann. Der Filter wird anstelle einer Variablen mit dem Wert true aufgerufen. Möchte der Entwickler nun das Pinging deaktivieren, so muss er eine Callback-Funktion schreiben, die false zurückgibt. Man könnte diese Funktion also wie folgt schreiben:

function deactivate_search_engine_pinging( $allow_ping ) {
	return false;
}
add_filter( 'wpseo_allow_xml_sitemap_ping', 'deactivate_search_engine_pinging' );

Das ist eigentlich schon ziemlich wenig Code und sehr einfach geschrieben. Die Funktion gibt einfach immer false zurück. Aber es geht noch viel einfacher. WordPress bietet einige vordefinierte Strings als Ersatz für den Namen einer Callback-Funktion an. Hier das vereinfachte Beispiel:

add_filter( 'wpseo_allow_xml_sitemap_ping', '__return_false' );

Das ist doch schon viel kürzer, oder etwa nicht? 🙂 Ein weiterer Vorteil von diesen Strings: Man sieht sofort, dass hier immer false zurückgegeben wird. Man muss also nicht erst die Callback-Funktion dazu ansehen, um dies zu erkennen. Neben dem Rückgabewert von false gibt es noch folgende Funktionen: __return_true, __return_zero, __return_empty_array, __return_null, __return_empty_string. Mit dem String __return_empty_array könnten wird beispielsweise den Stoppwort-Filter aus dem ersten Beispiel deaktivieren.

Fazit

Der Artikel ist schon wieder recht lang geworden. Zeit also, für heute das Thema erneut zu beenden. Ich hoffe ihr habt verstanden, was Filter sind und wie man diese einsetzen kann. Ich hoffe ebenfalls, dass die Pluginentwickler unter euch eine Idee dafür bekommen haben, wie sie selbst Filter in ihre Plugins einbauen könnten.

In der nächsten Woche werde ich die Child Plugin Artikelreihe aussetzen. Zum einen werde ich am Sonntag auf dem WordCamp Europe unterwegs sein und daher wohl keine Zeit finden, einen Artikel zu schreiben. Aber der eigentliche Grund ist, dass ihr schon am Dienstag mit einem neuen Beitrag von mir rechnen könnt. Vielleicht weiß der ein oder andere ja bereits, was euch an diesem speziellen Tag erwarten wird 😉

Weitere Artikel zu Themenreihe

Dies ist der vierte Teil der Themenreihe „Child Plugins“. Hier findest du die anderen Beiträge:

Veröffentlicht von

Bernhard ist fest angestellter Webentwickler, entwickelt in seiner Freizeit Plugins, schreibt in seinem Blog über WordPress und andere Themen, treibt sich gerne bei den WP Meetups in Berlin und Potsdam herum und läuft nach Feierabend den ein oder anderen Halbmarathon.

Schreibe einen Kommentar

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