Snippets & Beispiele

Eine Sammlung kurzer Rezepte, die zeigen, wie sich der Multisite Language Switcher in ein Theme oder ein anderes Plugin einfügt. Jedes Snippet ist absichtlich minimal gehalten. Behandeln Sie es als Startpunkt: kopieren Sie es in Ihre functions.php oder in ein kleines mu-Plugin und passen Sie es an Ihre Menü-Positionen, Post Types und Locales an.

Die verwendeten Funktionen sind auf der Seite API-Funktionen beschrieben, die Filter in der Hook-Referenz.

Die aktuelle Sprache ermitteln

In den meisten Fällen sollten Sie die WordPress-Funktion get_locale() verwenden, wenn Sie die Sprache des aktuellen Blogs brauchen. Das Plugin bietet über seine Blog-Collection eine nahezu gleichwertige Alternative, die zusätzlich auf en_US zurückfällt, wenn der Wert leer ist, und liefert den zweibuchstabigen Code separat.

$blog     = msls_blog_collection()->get_current_blog();
$language = $blog->get_language(); // en_US
$alpha2   = $blog->get_alpha2();   // en

Den Umschalter im Template ausgeben

Der Einzeiler für Theme-Dateien. Der function_exists()-Test sorgt dafür, dass das Template auch bei deaktiviertem Plugin durchläuft.

if ( function_exists( 'msls_the_switcher' ) ) {
	msls_the_switcher();
}

Wenn Sie das Markup als String brauchen, etwa um es in eine eigene Komponente einzubetten, nehmen Sie msls_get_switcher() und übergeben optional die Tags:

$markup = msls_get_switcher(
	array(
		'before_output' => '<ul class="lang">',
		'after_output'  => '</ul>',
		'before_item'   => '<li>',
		'after_item'    => '</li>',
	)
);

Das Navigationsmenü erweitern

Die Klasse Frontend\Output ist der richtige Einstieg, wenn Sie den Sprachumschalter in ein Navigationsmenü einhängen wollen. Das folgende Beispiel gibt die Links als reine Flaggen aus und hängt sie nur an das primäre Menü an.

Auch hier gilt: Fragen Sie lieber die Funktion msls_output() ab, als die Klasse direkt zu referenzieren. So bleibt das Theme bei deaktiviertem Plugin funktionsfähig.

function my_custom_menu_item( $items, $args ) {
	if ( function_exists( 'msls_output' ) && 'primary' === $args->theme_location ) {
		$arr = msls_output()->get( 2 );
		if ( ! empty( $arr ) ) {
			$items .= '<li>' . implode( '</li><li>', $arr ) . '</li>';
		}
	}

	return $items;
}
add_filter( 'wp_nav_menu_items', 'my_custom_menu_item', 10, 2 );

Die Zahl, die an get() übergeben wird, wählt die Darstellungsvariante des Links:

/* Link: Flaggenbild und Text */
$arr = msls_output()->get( 0 );

/* TextOnly: nur der Sprachtext */
$arr = msls_output()->get( 1 );

/* ImageOnly: nur das Flaggenbild */
$arr = msls_output()->get( 2 );

/* TextImage: Text und Flaggenbild */
$arr = msls_output()->get( 3 );

Wenn Sie das nicht selbst schreiben wollen: Genau das macht das Add-on MslsMenu, inklusive Einstellungsseite.

Über die Blogs iterieren

Wenn Sie für jeden Blog, den das Plugin verwaltet, etwas tun wollen (alternative Links ausgeben, ein eigenes Menü bauen, eine Sitemap füllen), iterieren Sie direkt über die Collection:

function my_print_something() {
	foreach ( msls_blog_collection()->get() as $blog ) {
		printf(
			'<link rel="alternate" hreflang="%1$s" href="http://%1$s.example.com/" />',
			esc_attr( $blog->get_language() )
		);
	}
}
add_action( 'wp_head', 'my_print_something' );

Beachten Sie: msls_blog_collection()->get() liefert alle Blogs außer dem aktuellen. Wenn Sie die vollständige Liste brauchen, verwenden Sie get_objects().

Auf eine einzelne Übersetzung verlinken

msls_get_permalink() ist die richtige Wahl, wenn Sie einen direkten Link auf genau eine Sprache setzen oder Ihr eigenes Umschalter-Markup bauen. Das optionale zweite Argument wird zurückgegeben, wenn keine Übersetzung existiert. Der Aufruf ist damit auch inline sicher:

$de_url = msls_get_permalink( 'de_DE', home_url( '/' ) );
echo '<a href="' . esc_url( $de_url ) . '">Deutsche Version</a>';

Den hreflang-Wert anpassen

Der Filter msls_head_hreflang bestimmt den Wert des hreflang-Attributs, das im <head> ausgegeben wird. Nutzen Sie ihn, wenn Sie aus SEO-Gründen eine regionale Schreibweise erzwingen wollen, etwa en-US statt eines bloßen en:

add_filter( 'msls_head_hreflang', function ( string $language ): string {
	return 'en_US' === $language ? 'en-US' : $language;
} );

Post Types ein- und ausschließen

Standardmäßig behandelt das Plugin post, page und alle öffentlichen eigenen Post Types als übersetzbar. Mit msls_supported_post_types nehmen Sie einzelne davon heraus, zum Beispiel einen feedback-CPT, der einsprachig bleiben soll:

add_filter( 'msls_supported_post_types', function ( array $types ): array {
	return array_values( array_diff( $types, array( 'feedback' ) ) );
} );

Der Filter msls_supported_taxonomies tut dasselbe für Taxonomien.

Das Markup der Sprachlinks überschreiben

msls_output_get läuft für jedes gerenderte Sprachelement, kurz bevor es in das Ausgabe-Array wandert. Der Filter bekommt die Ziel-URL (nicht das fertige Anker-Element), das LinkInterface-Objekt und die Information, ob das Element auf den aktuellen Blog zeigt. Der Rückgabewert muss das vollständige HTML dieses Elements sein.

Das Link-Objekt trägt seine Werte in drei magischen Eigenschaften: txt ist die Beschreibung des Blogs, src die URL des Flaggen-Icons und alt das Locale. Die Umwandlung in ein <img> beziehungsweise in Text übernimmt __toString(), abhängig von der gewählten Variante.

Das Beispiel setzt hreflang und aria-current und lässt das Markup ansonsten schlicht:

add_filter( 'msls_output_get', function ( string $url, $link, bool $is_current_blog ): string {
	$current_attr = $is_current_blog ? ' aria-current="page"' : '';

	return sprintf(
		'<a href="%s" hreflang="%s"%s>%s</a>',
		esc_url( $url ),
		esc_attr( str_replace( '_', '-', (string) $link->alt ) ),
		$current_attr,
		(string) $link
	);
}, 10, 3 );

Solange kein Callback an diesem Filter hängt, erzeugt das Plugin sein eigenes Standard-Anker-Element, inklusive class="current_language" und aria-current="page" auf der aktiven Sprache.

Hinweis auf Übersetzungen im Beitragstext

Das Plugin kann über oder unter dem Beitrag einen Hinweis einblenden, dass der Text auch in anderen Sprachen vorliegt. Mit msls_filter_string ersetzen Sie die Formatvorlage dafür. Der Filter bekommt zusätzlich das Array der Sprachlinks, sodass Ihre eigene Fassung sie weiterverwenden kann:

add_filter( 'msls_filter_string', function ( string $format, array $links ): string {
	return '<p class="msls-hint">Diesen Artikel gibt es auch auf: %s</p>';
}, 10, 2 );

Wenn keine Übersetzung existiert

Findet das Plugin nichts auszugeben, liefert Output::__toString() einen leeren String. Über msls_output_no_translation_found machen Sie daraus einen Hinweis:

add_filter( 'msls_output_no_translation_found', function ( string $empty ): string {
	return '<p class="msls-none">Dieser Beitrag liegt noch nicht in Ihrer Sprache vor.</p>';
} );

Für das Widget gibt es dafür den eigenen Filter msls_widget_alternative_content.

Flaggen aus eigener Quelle laden

Wenn die Flaggen aus Ihrem Theme oder von einem CDN kommen sollen, biegen Sie das Verzeichnis um. Einzelne Dateinamen regelt der zweite Filter:

add_filter( 'msls_options_get_flag_url', function ( string $url ): string {
	return get_stylesheet_directory_uri() . '/img/flags';
} );

add_filter( 'msls_options_get_flag_icon', function ( string $icon, string $language ): string {
	return 'de_AT' === $language ? 'at.svg' : $icon;
}, 10, 2 );

Den Status der per Quick Create angelegten Übersetzungen setzen

Der REST-Endpunkt hinter Quick Create legt neue Übersetzungen als Entwurf an. Über msls_quick_create_post_data übernehmen Sie stattdessen den Status des Ausgangsbeitrags:

add_filter( 'msls_quick_create_post_data', function ( array $post_data, \WP_Post $source ): array {
	$post_data['post_status'] = $source->post_status;

	return $post_data;
}, 10, 2 );

An demselben Hook hängt standardmäßig lloc\Msls\RestApi\RestApi::prefix_source_language() und stellt dem Titel des neuen Beitrags das Locale der Quelle voran. Wenn das in Ihrem Workflow störend ist, hängen Sie den Callback ab:

remove_filter(
	'msls_quick_create_post_data',
	array( \lloc\Msls\RestApi\RestApi::class, 'prefix_source_language' ),
	10
);

Nach dem Anlegen einer Übersetzung eigene Daten kopieren

Die Action msls_quick_create_after_insert feuert, nachdem der neue Beitrag im Ziel-Blog angelegt wurde, und zwar noch innerhalb des switch_to_blog()-Kontexts. Der richtige Ort, um eigene Meta-Felder mitzunehmen oder eine Benachrichtigung anzustoßen:

add_action(
	'msls_quick_create_after_insert',
	function ( int $new_post_id, \WP_Post $source, int $source_blog_id, int $target_blog_id ): void {
		update_post_meta( $new_post_id, '_my_source_post', $source->ID );
		update_post_meta( $new_post_id, '_my_source_blog', $source_blog_id );
	},
	10,
	4
);

An dieser Action hängt das Plugin selbst RestApi::remember_source_blog(), das sich den zuletzt verwendeten Quell-Blog pro Benutzer merkt, damit die Auswahl beim nächsten Mal vorbelegt ist.

Die Berechtigung für Quick Create anpassen

msls_quick_create_capability filtert das Ergebnis der Berechtigungsprüfung. Sie bekommen die Standardentscheidung, die Beitrags-ID der Quelle (0 bei Listen-Abfragen), die IDs von Quell- und Ziel-Blog sowie einen Kontext: read beim Zugriff auf die Quelle, create beim Anlegen im Ziel. So darf ein Übersetzer ohne Konto im Quell-Blog trotzdem Beiträge in seinen Blog spiegeln:

add_filter(
	'msls_quick_create_capability',
	function ( bool $allowed, int $source_post_id, int $source_blog_id, int $target_blog_id, string $context ): bool {
		if ( 'read' === $context && current_user_can( 'edit_posts' ) ) {
			return true;
		}

		return $allowed;
	},
	10,
	5
);

Weiterlesen

  • API-Funktionen: die vollständige Referenz aller msls_*-Funktionen
  • Hook-Referenz: alle Actions und Filter, die das Plugin bereitstellt

Der Artikel ist auch in English verfügbar.