Randy Apps


Convenient Apps changing tomorrow.

【WordPress】qTranslate-XT環境で「The SEO Framework」の多言語メタデータを正常化する方法


これまで当サイトでは、多言語化プラグイン「qTranslate-XT」を使用して日本語と英語のページを作成してきましたが、SEO関連のプラグインは一切入れていませんでした。
サイトの最適化を目指し、軽量で評判の良い「The SEO Framework」を導入してみたのですが、多言語環境ならではの壁にぶつかりました。

本記事では、qTranslate-XTとThe SEO Frameworkを併用した際の不具合を、functions.phpのカスタマイズで解決した際の実践的な方法を備忘録としてまとめます。

1. 発生した問題:メタデータに英語タグ([:en])がそのまま出力される

The SEO Frameworkを有効化して確認したところ、日本語ページの meta description[:en]English description...[:ja]日本語の説明...[:] という言語タグがそのまま出力されてしまう状態になりました。

これは単純に、The SEO Framework が qTranslate-XT の独自タグ([:en]など)を認識できず、データベースに保存された生のテキストをそのまま出力してしまうことが原因です。qTranslate-XT の翻訳処理は、デフォルトのままでは The SEO Framework のメタデータ領域には適用されません。

2. WPSSOの検討と、The SEO Frameworkへのこだわり

この問題を解決するために、多言語対応が手厚い「WPSSO」という別のSEOプラグインの導入も検討しました。WPSSOはqTranslate-XTにも標準で対応しているとのことで、非常に魅力的な選択肢でした。

しかし、すでにThe SEO Frameworkの「圧倒的な動作の軽さ」と「シンプルな設定」に魅了されていた私は、どうしてもこのプラグインのまま問題をクリアできないかと模索することにしました。

そこで、プラグインを乗り換えるのではなく、自力で functions.php をカスタマイズして、The SEO Frameworkの出力にqTranslate-XTの翻訳処理を割り込ませる道を選びました。

3. 【前提条件】自作テーマや子テーマでの作業を推奨

ここからの解決策は functions.php に直接コードを追記していく形になります。記述を少しでも間違えるとサイトが真っ白になる(Fatal Errorになる)リスクがあるため、自身でテーマファイルを作成している環境、もしくは子テーマを使用している環境の方におすすめします。

必ず事前にファイルのバックアップを取ってから作業を行ってください。

4. 解決策:functions.phpへのコード追記

試行錯誤の結果、処理を「テキスト用」と「画像用」の2つにスッキリまとめ、表示速度を落とすことなく正常にメタタグを出力することが可能になりました。

① テキスト関連の修正(タイトル、ディスクリプション、抜粋など)

まずは、最終出力されるテキストや、The SEO Frameworkが文字数をトリミングする前のデータに対して、一括で翻訳処理(現在の言語の切り抜き)を適用するコードです。

/**
 * ====================================================================
 * The SEO Framework と qTranslate-XT の連携カスタマイズ
 * ====================================================================
 */

/**
 * 1. テキスト関連の翻訳処理(タイトル、ディスクリプション、抜粋など)
 */
function my_tsf_qtranslate_apply_translation( $text ) {
    // qTranslate-XT が有効、かつテキストが空ではない場合のみ翻訳処理を実行する
    if ( function_exists( 'qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage' ) && ! empty( $text ) ) {
        return qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage( $text );
    }
    return $text;
}

// 翻訳処理を割り込ませる The SEO Framework の介入ポイント(フック)を一覧にする
$tsf_text_filters = array(
    // --- 最終出力されるデータ ---
    'the_seo_framework_custom_field_description',
    'the_seo_framework_generated_description',
    'the_seo_framework_description_output',
    'the_seo_framework_title_from_custom_field',
    'the_seo_framework_title_from_generation',
    'the_seo_framework_title_output',
    
    // --- OGP・Twitterカード関連(SNSシェア用テキスト) ---
    'the_seo_framework_ogtitle_output',
    'the_seo_framework_ogdescription_output',
    'the_seo_framework_twittertitle_output',
    'the_seo_framework_twitterdescription_output',
    
    // --- 固定ページ等の抜粋が文字数でトリミングされる前の元データ ---
    'the_seo_framework_get_excerpt',
    'the_seo_framework_description_excerpt',
    'the_seo_framework_fetched_description_excerpt',
);

// 上記のリスト(配列)をループ処理して、一気に翻訳機能を適用する
foreach ( $tsf_text_filters as $filter ) {
    add_filter( $filter, 'my_tsf_qtranslate_apply_translation', 10, 1 );
}

② OGP画像(ソーシャル画像)抽出元の修正

次に、SNSでシェアされた際の画像(og:image 等)も、現在の言語の本文ブロックから抽出するように修正します。

/**
 * 2. 画像関連の抽出処理(現在の言語の画像を優先させる)
 */
function my_tsf_qtranslate_image_generator( $params, $args, $context ) {
    // ソーシャル画像(og:image, twitter:image 等)の生成時のみ実行する
    if ( 'social' !== $context ) {
        return $params;
    }

    // 記事や固定ページを表示している場合のみ介入する
    if ( null === $args && is_singular() ) {
        $new_cbs = array();
        
        // TSF が持っているデフォルトの画像検索ルールをループ処理
        foreach ( $params['cbs'] as $key => $cb ) {
            // 'content' (本文からの自動抽出) の直前に、独自の翻訳抽出ルールを割り込ませる
            if ( $key === 'content' ) {
                $new_cbs['qtranslate_content'] = 'my_tsf_qtranslate_image_yield';
            }
            $new_cbs[ $key ] = $cb;
        }
        $params['cbs'] = $new_cbs;
    }

    return $params;
}
add_filter( 'the_seo_framework_image_generation_params', 'my_tsf_qtranslate_image_generator', 10, 3 );

// 実際に現在の言語の本文から画像を抽出して TSF に渡す処理
function my_tsf_qtranslate_image_yield( $args = null ) {
    // qTranslate-XT が有効かチェック
    if ( ! function_exists( 'qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage' ) ) {
        return;
    }

    $post = get_post();
    if ( ! $post ) {
        return;
    }

    // ① 本文を「現在見ている言語」のブロックだけに切り抜く
    $translated_content = qtranxf_useCurrentLanguageIfNotFoundUseDefaultLanguage( $post->post_content );

    // ② 翻訳後の純粋な本文から、最初の画像タグ(img)のURLを探す
    if ( preg_match( '/<img[^>]+src=[\'"]([^\'"]+)[\'"][^>]*>/i', $translated_content, $matches ) ) {
        $image_url = $matches[1];
        $attachment_id = attachment_url_to_postid( $image_url );

        // ③ 画像のURLとIDを「この画像を使って!」と TSF に渡す
        yield array(
            'url' => $image_url,
            'id'  => $attachment_id ? $attachment_id : 0,
        );
    }
}

5. まとめ

最終的に、The SEO Frameworkの圧倒的な軽さを維持したまま、qTranslate-XTの多言語メタデータ(OGP含む)を完璧に出力できるようになりました。

プラグインを切り替えることなく、気になるようなスピードダウンも全くなく、以前とほぼ変わらない速度でページを開くことができています

同じように「多言語化 × SEO × 表示速度」のジレンマで悩んでいる開発者の方の参考になれば幸いです!