WPML
Status
Behoben
Typ
Wird nicht behoben
Gemeldet für
WPML Multilingual CMS 5.0
Themen-Tags
Compatibility

Übersicht über das Problem

Seit WPML 5.0 sind Sprachwechsel verschachtelt. Jeder Sprachcode öffnet einen neuen Scope, und nur null schließt ihn.

Plugins, die für WPML 4.x geschrieben wurden, wechseln oft zurück, indem sie die gespeicherte Sprache benennen:

$current = apply_filters( 'wpml_current_language', null );

do_action( 'wpml_switch_language', 'de' );
// ...
do_action( 'wpml_switch_language', $current ); // Meant as "and back".

WPML 4.x hat dies toleriert. Es behielt einen Sprach-Slot bei, sodass die aktuelle Sprache am Ende stimmte und der unbalancierte Wechsel unbemerkt blieb. Dies war nie die korrekte Methode, einen Wechsel abzuschließen. WPML 5.0 fängt dies nicht mehr ab: Der letzte Aufruf öffnet einen zweiten Scope, anstatt den ersten zu schließen, und WPML meldet weiterhin, dass die Sprache gewechselt wurde.

WPML kann dies nicht erkennen, da derselbe Aufruf auch ein gültiger Wechsel in die Sprache ist, aus der der umgebende Code stammt.

Das Symptom tritt verzögert auf. Direkt nach dem Paar ist die aktuelle Sprache korrekt, sodass ein Test, der nur dies prüft, erfolgreich ist. Der nächste korrekte Restore-Aufruf in der Umgebung schließt dann Ihren offenen Scope anstelle seines eigenen, und dieser Code wird in der falschen Sprache ausgeführt. Dies zeigt sich bei E-Mails, REST-Antworten und Bildschirmen im Admin-Bereich.

Ein Wechsel ohne Restore-Aufruf oder mit einem leeren Sprachcode lässt einen Scope auf die gleiche Weise offen.

Problemumgehung

Schließen Sie jeden Scope mit null in einem finally-Block:

do_action( 'wpml_switch_language', 'de' );

try {
	// ...your work in German...
} finally {
	do_action( 'wpml_switch_language', null ); // Closes the scope above.
}

Support für WPML 4.x und 5.0 in einer Version

Kopieren Sie diese Hilfsfunktionen hinein und benennen Sie das Präfix um:

// Opens a scope. Returns the value for the close helper, or false if none opened.
function myplugin_wpml_open_language_switch( $language_code ) {
	// '', false and 0 open a scope without changing the language. Only null closes one.
	if ( ! $language_code ) {
		return false;
	}
	$previous = apply_filters( 'wpml_current_language', '' );
	do_action( 'wpml_switch_language', $language_code );
	return $previous;
}

// Closes the scope the open helper opened. WPML 4.x has no stack: there null
// means "the language before the FIRST switch", so restore by name.
function myplugin_wpml_close_language_switch( $previous ) {
	if ( ! $previous ) {
		return;
	}
	$has_stack = defined( 'ICL_SITEPRESS_VERSION' )
		&& version_compare( ICL_SITEPRESS_VERSION, '5.0', '>=' );
	do_action( 'wpml_switch_language', $has_stack ? null : $previous );
}

Jede Aufrufstelle wird dann zu:

$previous = myplugin_wpml_open_language_switch( 'de' );
try {
	// ... work ...
} finally {
	myplugin_wpml_close_language_switch( $previous );
}

Führen Sie grep -rn "wpml_switch_language" . aus, um jede Aufrufstelle zu finden. Jede benötigt einen passenden Abschluss. Stellen Sie die Sprache niemals anhand des Namens wieder her und schalten Sie niemals auf einen Code um, der leer sein kann.

Die E-Mail-Hooks sind ebenfalls verschachtelt: Rufen Sie wpml_restore_language_from_email einmal für jedes wpml_switch_language_for_email auf.

Alle bekannten Probleme →