WPML
ステータス
解決済み
タイプ
修正予定なし
報告対象
WPML Multilingual CMS 5.0
トピックタグ
Compatibility

問題の概要

WPML 5.0以降、言語の切り替えはネストされます。すべての言語コードは新しいスコープを開き、nullのみがそれを閉じます。

WPML 4.x用に作成されたプラグインは、保存した言語を指定して元に戻すことがよくあります。

$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ではこれが許容されていました。言語スロットを1つだけ保持していたため、最終的に現在の言語は正しくなり、対応の取れていない切り替えは表面化しませんでした。これは決して切り替えを終了する正しい方法ではありませんでした。WPML 5.0はもはやこれを吸収しません。最後の呼び出しは最初のスコープを閉じるのではなく2番目のスコープを開き、WPMLは言語が切り替えられた状態であると報告し続けます。

同じ呼び出しは、周囲のコードの元の言語への有効な切り替えでもあるため、WPMLはこれを検出できません。

症状は遅れて現れます。ペアの直後は現在の言語が正しい状態であるため、それのみを確認するテストはパスします。その後、後続の正しい復元処理が、自身のスコープではなく開かれたままのスコープを閉じてしまい、そのコードは誤った言語で実行されます。この問題は、メール、RESTレスポンス、および管理画面に現れます。

復元処理のない切り替え、または空の言語コードでの切り替えも、同様にスコープを開いたままにします。

回避策

finallyブロック内で、nullを使用してすべてのスコープを閉じます。

do_action( 'wpml_switch_language', 'de' );

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

1つのリリースでのWPML 4.xおよび5.0のサポート

これらのヘルパーをコピーし、プレフィックスの名前を変更します。

// 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 );
}

これにより、各呼び出し元は次のようになります。

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

grep -rn "wpml_switch_language" .を実行して、すべての呼び出し元を検索します。それぞれに対応するクローズ処理が必要です。言語名を指定して復元しないでください。また、空になる可能性のあるコードで切り替えないでください。

メールのフックもネストします。wpml_switch_language_for_emailごとに、wpml_restore_language_from_emailを1回呼び出します。

すべての既知の問題 →