WPML の Ajax 処理で現在の言語が取得できない場合

WPMLで多言語化しているサイトでデフォルトではない言語に切り替えているとき、Ajax の処理で言語をうまく取得できません。

そんなときには WordPress のダッシュボードで

WPML > 翻訳

と移動し、「AJAX オペレーション用にフィルタする言語」(Language filtering for AJAX operations)という項目の「AJAX用の言語フィルタに対応するために言語クッキーを保存する」(Store a language cookie to support language filtering for AJAX)にチェックをつけると Ajax の処理でも現在の言語がうまく切り替わります。

ログインしていないときは。

ログインしているときにはこの機能は有効にならず、Ajax の処理はデフォルトの言語のままです。
このような仕様になっていることには何か理由があるものと思ってその理由探してみましたが、見つけることができませんでした。

WooCommerce で EC サイトを構築中にこの問題に直面したときには、アカウント登録したユーザーがログインしている場合は問題ではありませんでした。
なぜなら、そのサイトはユーザーはアカウント登録しない仕様だったからです。

運用者がログイン状態でサイトの動作を確認しているときに Ajax の動作で mini-cart が呼び出された場合が問題でした。
運用者にそのような仕様であることをドキュメンテーションして周知しておけば問題無いかもしれませんが、そのような細かい注意事項は年月が経過して担当者が変われば(あるいは変わらなくても)、忘れられてしまいます。

そしてインシデントが発生し工数を取られてしまうものです。

可能であれば、非ログインと同じ動作にしたいのですが、そもそもこれは WPML の仕様であり、通常の API では解決が難しいものです。

どうやって解決したか

仕方なく、Ajax の呼び出し元 URL から言語を取得し、Ajax の処理の最初にセットすることにしました。
本来であれば、呼び出し元からのパラメータで判断したいところですがプラグイン自体の JavaScript コードを変更するわけにもいかず、リファラを利用しています。

今回は WooCommerce の mini-cart の表示でしたので、mini-cart の最初に呼び出されるアクションフックで言語をセットしています。

function my_woocommerce_before_mini_cart() {
    if(is_user_logged_in() && isset($_SERVER['HTTP_REFERER'])){
        $referer = $_SERVER['HTTP_REFERER'];
        $pattern = '/^https?:\/\/.*?\/([a-z]*?)\/.*$/';
        $result = preg_match($pattern, $referer, $matches);
        if(1 === $result){
            $referer_lang = $matches[1];
            do_action( 'wpml_switch_language', $referer_lang);
        }
    }
}
add_action( 'woocommerce_before_mini_cart', 'my_woocommerce_before_mini_cart' );

正規表現で呼び出し元 URL の一部である言語コードを取得しています。
実際にユーザーが利用する場面では、URL から取得した言語が WPML で設定している言語のリストに含まれるのか、チェックする必要があるかもしれません。(存在しない言語の場合は WPML が勝手にデフォルトの言語にしてくれるようですが)
今回は運用者の操作時だけなので、何かしらのURLの改ざんや、ブラウザの仕様でリファラが取得できないイレギュラーケースを除外しています。

また、上記のコードでは、第一階層のディレクトリが言語となる設定の場合です。
サブドメインや他のケースではこのままでは動作しませんので、ご注意ください。