translation 1092128 1920
Bild von falarcompaulo auf Pixabay

multilingualpress: ein Workaround für unstimmige Verknüpfungslinks bei übersetzten (Custom Rewrite) Taxonomy Slugs

Um Zeit zu sparen ( Kopie einer zu übersetzenden Site machen, und gleich schon alle Sprachverknüpfungen haben ) hatte ich die Idee, statt den kostenfreien Multisite Languages Switcher zu verwenden multilingualpress zu kaufen.

Ich stieß damit auf zwei grundlegende Probleme, die allerdings mit der Beschaffenheit und Komplexität des Projekts zusammenhingen. Das eine ist ein “Effekt”, der innerhalb der einzelnen Sprachumgebungen auftritt, das andere liegt in der Natur der Sache, wenn man mit Custom Rewrite Slugs für Taxonomien arbeitet, und für jede Sprachversion einen anderen Slug verwendet.

Erstmal zum Effekt, der vielleicht (k)ein Bug ist.

get_term_link()-Fehler bei Custom Rewrite Slugs

Laut Support ist der Effekt nicht nachvollziehbar. Doch davon ließ der sich nicht beeindrucken und blieb beharrlich, auch nachdem ich fast alles andere deaktiviert, das Theme gewechselt, und nochmal getestet hatte. Vielleicht sind die Umstände / Daten ja besonders, oder anders, und das passiert wirklich nur bei mir (bereits mit V2, mit V3 bedauerlicherweise keine Änderung).

Um Custom Post Types und Taxonomies zu registrieren verwende ich das vom Haus empfohlene Plugin Custom Post Type UI . Das ist wichtig, auch für den Workaround, denn wenn man Post Types und Taxonomien manuell registriert, hat man von einer Sprachversion aus keinen Zugriff auf die Taxonomie-Eigenschaften einer anderen Sprachversion (wo es vielleicht Übersetzungen des Rewrite-Slugs geben mag).

Doch erstmal zu get_term_link()-Problem. Das kommt im betroffenen Projekt zum Tragen, wenn man ein Taxonomy-Widget verwendet, das die einzelnen Links zu den Terms via get_term_link() holt. Im Post Type Archiv war noch alles richtig. Doch nach Klick auf einen Term waren sämtliche get_term_link() – URLs der Term-Liste falsch. Der Custom Rewrite Slug war duch den Taxonomy-Slug ($taxonomy->name) ersetzt (will nicht zu weit ausholen, wer selbst forschen mag: das passiert im Zuge des Aufrufts $this->fixTermBase($taxonomySlug); in de Zeile 180 unter mulilingualpress/src/multilingualpress/Translator/TermTranslator/.

Dieses Snippet löste das Problem global innerhalb der einzelnen Sprachversionen, sodass die übersetzten Slugs auch innerhalb der Term-Archive verfügbar sind.

function get_correct_term_link( $termlink, $term, $taxonomy ) {
	$tax 	= get_taxonomy( $term->taxonomy );
	$slug 	= $tax->name;
	$reslug = isset( $tax->rewrite['slug'] ) ? $tax->rewrite['slug'] : $slug;
	if ( false === strpos( $termlink, $reslug ) ) {
		$termlink = str_replace( $slug, $reslug, $termlink );
	} 
	return $termlink;	
}
add_filter( 'term_link', 'get_correct_term_link', 10, 3 );

Doch hilft diese Lösung nichts, wenn man den Übersetzungslink eines Term-Archivs holen möchte, bei dem je nach Sprachversion unterschiedliche Custom Rewrites im Spiel sind, und darum geht es hier eigentlich.

Zugriff auf Links mit Custom Rewrite-Slugs anderer Sprachversionen

Nun, hier kann man den Entwicklern lediglich vorwerfen, dass sie – im Gegensatz zu Custom Post Types – keine Übersetzungsoptionen für Custom Taxonomies anbieten. Als Reaktion auf meinen ersten Bugreport waren diese zwar noch angekündigt. Bei der nächsten wollte man davon aber schon nichts mehr wissen. Da für das Plugin immerhin fast EUR 200,00 / Jahr zu berappen sind, kann ich diese Unvollständigkeit nicht wirklich nachvollziehen.

Ungünstigerweise haben Taxonomien ja keine ID anhand derer sie identifizierbar sind, noch findet man mehr als ihren Slug (bei Terms die ihnen zugeordnet sind) in der Datenbank vor. Was eine Taxonomie einzigartig macht, ist ihr Name (gleichzeitig auch ihr Slug). Die WordPress-Standard-Taxonomien sind “category” (Kategorien) und “post_tag” (Schlagwörter). Sie heißen immer gleich, auch wenn ich in den Blogeinstellungen selbst definieren kann, wie der jeweilige Slug für Kategorien und Tags aussieht. z.B. steht da dann https://meinblog.at/kategorie/meine-kategorie.

Bei Custom Taxonomies die z.B. über ein Skript in der functions.php registriert werden, kann man natürlich auch eine rewrite-Slug anlegen, der übersetzbar ist.

Beispiel: https://deutsche-site.at/deutscherslug/mein-term wird https://english--site.at/deutscherslug/my-term, statt https://english-site.at/englishslug/my-term. Klick auf den vom Plugin gelieferten Sprachmenüeintrag führt also zu einem 404-Fehler.

Auf die “übersetzte” Version eines Slugs hat man allerdings nur Zugriff wenn man sich in der entsprechenden Sprachversion befindet. Mit switch_to_blog( $site_id ) kommt man da nicht heran.

Aus diesem Grund ist es also empfehlenswert, Custom Post Types und Taxonmies über ein Plugin zu registrieren, da die Objekteigenschaften der Taxonomien über dessen Einstellungen definiert werden. Auf die Einstellungen eines Plugins kann via switch_to_blog( $site_id ) zugegriffen werden. Folglich kommt man so auch an den Custom Rewrite Slug einer Taxonomie.

switch_to_blog( $site_id );
	$cptui_taxonomies = cptui_get_taxonomy_data();
	$lang_slug = $cptui_taxonomies[$taxonomy]['rewrite_slug'];
restore_current_blog();	

Aber nun endlich zum Workaround:

Schritt 1: Übersetzungen holen

function multilingualpress_get_translations() {

	$args = \Inpsyde\MultilingualPress\Framework\Api\TranslationSearchArgs::forContext(new \Inpsyde\MultilingualPress\Framework\WordpressContext())
		->forSiteId(get_current_blog_id())
		->includeBase();

	$translations = \Inpsyde\MultilingualPress\resolve(
		\Inpsyde\MultilingualPress\Framework\Api\Translations::class
	)->searchTranslations($args);

	return $translations;

}

Schritt 2: übersetzbare Menüeinträge vorsehen

function theme_menu_items_languages() {
	return array(
		'en' => __('English', 'theme_textdomain'),
		'de' => __('German', 'theme_textdomain'),
		'it' => __('Italian', 'theme_textdomain'),
		'es' => __('Spanish', 'theme_textdomain'),
		'fr' => __('French', 'theme_textdomain')
	);
}

Schritt 3: Array mit allen erforderlichen Link-Daten anlegen

function get_mlp_redirect_url_lang_links( $self = false ) {

	$translations = multilingualpress_get_translations();	
	$links = array();
	$langs = theme_menu_items_languages();
	$id = get_current_blog_id();
	foreach ( $translations as $translation ) {
		$site_id = $translation->remoteSiteId(); 
		$language = $translation->language();
		$language_iso_name = $language->isoName();
		$language_locale = $language->locale();
		$lang = substr($language_locale,0,2);
		$lang_menu_name = $langs[$lang];
		$mlp_url = $translation->remoteUrl();
		if ( $id === $site_id && $self === false ) break;
		$correct_url = $mlp_url;

		 if ( is_tax() ) {
			global $wp_query;
			$term = $wp_query->get_queried_object();
			$taxonomy = $term->taxonomy;
			$cptui_taxonomies = cptui_get_taxonomy_data();
			$slug = $cptui_taxonomies[$taxonomy]['rewrite_slug'];
			switch_to_blog( $site_id );
				$cptui_taxonomies = cptui_get_taxonomy_data();
				$lang_slug = $cptui_taxonomies[$taxonomy]['rewrite_slug'];
				$correct_url = str_replace( $slug, $lang_slug, $mlp_url );
			restore_current_blog();				
		} 

		if ( !empty( $correct_url ) ) $links[$lang] = array(
			'site_id' 	=> $site_id,
			'locale' 	=> $language_locale,
			'mlp' 		=> $mlp_url,
			'real' 		=> $correct_url,
			'lang_name' => $language_iso_name,
			'menu_name' => $lang_menu_name
		);
	}

	return $links;

}

Hier sind nicht die kompletten Sprachcodes inklusive Land erwünscht, sondern nur die Sprache, also en statt en_GB, de statt de_DE u.s.w., daher enthält der Key $links[$lang] nur 2 Stellen. Wer es anders braucht, hier einfach stattdessen $links[$language_locale ] eintragen. Die Funktion theme_menu_items_languages() dann entsprechend anpassen, damit die Namen der Menüeinträge stimmen.

Ggf. für Kategorien und Schlagwörter

Hier ist darauf zu achten, dass dann jede Sprachversion diese Einstellung hat, denn sonst könnte hier gar kein Slug im Kategorie-Link vorhanden sein, und ein Kategorielink sieht dann so aus https://meinblog.at/meine-kategorie und nicht: https://meinblog.at/kategorie/meine-kategorie. Das Überschreiben des Kategorien-Slugs wäre damit obsolet.

if ( is_category() ) {
	$slug = get_option('category_base');
	switch_to_blog( $site_id );
		$lang_slug = get_option('category_base');
		$correct_url = str_replace( $slug, $lang_slug, $mlp_url );
	restore_current_blog();
} elseif ( is_tag() ) {
	$slug = get_option('tag_base');
	switch_to_blog( $site_id );
		$lang_slug = get_option('tag_base');
		$correct_url = str_replace( $slug, $lang_slug, $mlp_url );
	restore_current_blog();
} 
WooCommerce Produkte (erst testen, hat nur auf einer Testplattform nicht funktioniert)
if ( is_tax('product_tag') ) {
	$options = wc_get_permalink_structure();
	$slug = $options['tag_base'];
	switch_to_blog( $site_id );
		$options = wc_get_permalink_structure();
		$lang_slug = $options['tag_base'];	
		$correct_url = str_replace( $slug, $lang_slug, $mlp_url );
	restore_current_blog();
} elseif ( is_tax('product_cat') ) {
	$options = wc_get_permalink_structure();
	$slug = $options['category_base'];
	switch_to_blog( $site_id );
		$options = wc_get_permalink_structure();
		$lang_slug = $options['category_base'];	
		$correct_url = str_replace( $slug, $lang_slug, $mlp_url );
	restore_current_blog();
} 

Schritt 4: Language Switcher – Menü-Einträge bilden

function print_mlp_redirect_url_change() {
	$lang_links = get_mlp_redirect_url_lang_links( false );
	$urls = '';

	foreach ( $lang_links as $lang => $link ) {
		$urls .= sprintf( '<li class="menu-item"><a rel="alternate" class="menu-link %1$s site-id-%2$s" href="%3$s">%4$s</a></li>', $lang, $link['site_id'], $link['real'], $link['menu_name'] );
	}
	return '' != $urls ? $urls : false;
}

Schritt 5: Language Switcher an Menü anhängen

Statt die Sprachlinks des Plugins zu verwenden, die man ins gewünschte Menü jeder Sprachversion einfügen müsste, werden die Sprachlinks zu den anderen Versionen automatisch ans gewünschte Menü gehängt (“main_menu”) in diesem Fall – zu ermitteln über die Menü-Registrierung des Themes, oder im Quellcode (an den Klassen).

function theme_add_languages_to_nav ( $items, $args ) {

	if ($args->theme_location == 'main_menu' && print_mlp_redirect_url_change( false ) !== false ) {

		$items .= '<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children dropdown"><a class="menu-link sf-with-ul" href="#"><span class="text-wrap">'.__( 'Languages', 'zimm' ).' <i class="nav-arrow icon-arrow-down"></i></span></a>';
		$items .= '<ul class="sub-menu">';  
		$items .= print_mlp_redirect_url_change();  
		$items .= '</ul></li>';   
	}   

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

Schritt 6: hreflang-Korrekturen (SEO)

function mlp_redirect_url_change($urls) {
	$lang_links = get_mlp_redirect_url_lang_links( true );
	if ( print_mlp_redirect_url_change( false ) === false ) return;
	$urls = array();
	foreach ( $lang_links as $lang => $link ) {
		$urls[$lang] = $link['real'];
	}
	return $urls;
}
add_filter( 'multilingualpress.hreflang_translations', 'mlp_redirect_url_change' );

Über Gabriele Lässer

WordPress Sorgen? - Nicht mit mir! Ich freue mich auf spannende Herausforderungen

Kommentar schreiben

E-Mail-Adresse wird nicht veröffentlicht.

Overlay background for modal content