2026年7月17日

2026年7月17日

WPMLの翻訳が表示されない・エラーを解決する方法

はじめに

WPMLで翻訳ページが404エラーになる・言語スイッチャーが表示されない・特定言語でメニューが崩れる・翻訳コンテンツが正しく取得できないといった問題は、WPMLの言語設定・URLフォーマット・キャッシュの不整合が主な原因です。

症状・原因

  • 英語版ページにアクセスすると404エラーになる
  • 言語スイッチャーをクリックしても言語が切り替わらない
  • get_permalink()が現在の言語のURLを返さない
  • 翻訳コンテンツの投稿IDが取得できない

解決手順

ステップ1:WPML設定と言語状態を確認する

# WPMLのバージョンとアクティブ言語を確認
wp eval "
if (defined('ICL_SITEPRESS_VERSION')) {
    echo 'WPML version: ' . ICL_SITEPRESS_VERSION . PHP_EOL;
}
global \$sitepress;
if (isset(\$sitepress)) {
    \$active_langs = \$sitepress->get_active_languages();
    foreach (\$active_langs as \$code => \$lang) {
        echo 'Language: ' . \$code . ' - ' . \$lang['display_name'] . PHP_EOL;
    }
    echo 'Default language: ' . \$sitepress->get_default_language() . PHP_EOL;
    echo 'Current language: ' . \$sitepress->get_current_language() . PHP_EOL;
}
"

# URLフォーマット設定を確認
wp eval "
\$url_format = apply_filters('wpml_setting', null, 'language_negotiation_type');
// 1=ディレクトリ /en/, 2=ドメイン en.example.com, 3=パラメータ ?lang=en
echo 'URL format: ' . \$url_format . PHP_EOL;
"

# 特定投稿の翻訳状態を確認
wp eval "
\$post_id = 123;
// 他言語の翻訳IDを取得
\$ja_id = apply_filters('wpml_object_id', \$post_id, 'post', false, 'ja');
\$en_id = apply_filters('wpml_object_id', \$post_id, 'post', false, 'en');
echo 'JA post: ' . (\$ja_id ?: 'not found') . PHP_EOL;
echo 'EN post: ' . (\$en_id ?: 'not found') . PHP_EOL;
"

ステップ2:翻訳URLとパーマリンクを修正する

# WPMLのパーマリンクキャッシュをリセット
wp eval "
do_action('wpml_update_all_post_types_languages', 'post');
wp_cache_flush();
echo 'WPML permalink cache cleared' . PHP_EOL;
"

# rewriteルールを再生成
wp rewrite flush --hard

# WPML言語ディレクトリのrewriteルールを確認
wp eval "
global \$wp_rewrite;
\$rules = \$wp_rewrite->rules;
foreach (\$rules as \$pattern => \$rewrite) {
    if (strstr(\$pattern, 'en/') || strstr(\$pattern, 'ja/')) {
        echo \$pattern . ' => ' . \$rewrite . PHP_EOL;
    }
}
"
// functions.php: WPML対応の投稿URL・コンテンツ取得

// ① 現在の言語で正しいURLを取得
function get_wpml_permalink(int $post_id, string $lang = ''): string {
    if ($lang) {
        // 特定言語のURLを取得
        $url = apply_filters('wpml_permalink', get_permalink($post_id), $lang);
        return $url ?: get_permalink($post_id);
    }
    return get_permalink($post_id);
}

// ② 他言語の投稿IDを取得
function get_translated_post_id(int $post_id, string $post_type, string $lang): ?int {
    $translated_id = apply_filters('wpml_object_id', $post_id, $post_type, false, $lang);
    return $translated_id ?: null;
}

// ③ 現在の言語を取得・設定
function get_current_wpml_lang(): string {
    return apply_filters('wpml_current_language', null) ?? 'ja';
}

ステップ3:WP_QueryにWPMLを対応させる

// functions.php: WPML対応のカスタムクエリ

// ① 特定言語の投稿を取得
function get_posts_in_language(string $lang, string $post_type = 'post', int $limit = 10): array {
    // WPMLの言語フィルターを一時的に変更
    do_action('wpml_switch_language', $lang);

    $posts = get_posts([
        'post_type'      => $post_type,
        'posts_per_page' => $limit,
        'post_status'    => 'publish',
        'suppress_filters' => false,  // WPMLフィルターを有効にする
    ]);

    // 元の言語に戻す
    do_action('wpml_switch_language', null);

    return $posts;
}

// ② WP_Queryで全言語の投稿を取得(言語フィルターを無効化)
function get_all_language_posts(array $args = []): WP_Query {
    $args = array_merge([
        'post_type'        => 'post',
        'posts_per_page'   => 10,
        'suppress_filters' => false,
    ], $args);

    // WPML言語フィルターを無効化
    add_filter('wpml_suppress_filters', '__return_true');
    $query = new WP_Query($args);
    remove_filter('wpml_suppress_filters', '__return_true');

    return $query;
}

// ③ カスタム投稿タイプの翻訳を有効化
add_action('init', function(): void {
    // WPMLに翻訳可能として登録
    $translatable_post_types = ['portfolio', 'product', 'event'];
    foreach ($translatable_post_types as $post_type) {
        if (function_exists('wpml_get_setting_filter')) {
            // WPML設定で翻訳対象に追加する場合はダッシュボードから
        }
    }
});

ステップ4:メニューと翻訳同期を設定する

// functions.php: WPMLメニューと言語スイッチャーの設定

// ① 言語スイッチャーをカスタム表示
function render_wpml_language_switcher(): string {
    $languages = apply_filters('wpml_active_languages', null, [
        'skip_missing' => false,
        'link_empty_to' => trailingslashit(home_url()),
    ]);

    if (empty($languages)) return '';

    $html = '<ul class="lang-switcher">';
    foreach ($languages as $lang) {
        $active = $lang['active'] ? ' class="active"' : '';
        $html .= sprintf(
            '<li%s><a href="%s" hreflang="%s">%s</a></li>',
            $active,
            esc_url($lang['url']),
            esc_attr($lang['language_code']),
            esc_html($lang['native_name'])
        );
    }
    $html .= '</ul>';
    return $html;
}

// ② hreflangタグを自動出力(SEO対策)
add_action('wp_head', function(): void {
    $languages = apply_filters('wpml_active_languages', null, ['skip_missing' => false]);
    if (empty($languages)) return;

    foreach ($languages as $lang) {
        printf(
            '<link rel="alternate" hreflang="%s" href="%s">' . PHP_EOL,
            esc_attr($lang['language_code']),
            esc_url($lang['url'])
        );
    }
    // x-default(デフォルト言語)を追加
    $default_lang = array_filter($languages, fn($l) => $l['default_locale']);
    if ($default_lang) {
        printf(
            '<link rel="alternate" hreflang="x-default" href="%s">' . PHP_EOL,
            esc_url(reset($default_lang)['url'])
        );
    }
});

ステップ5:WPMLキャッシュとデータベースを修正する

# WPMLの翻訳テーブルを確認
wp eval "
global \$wpdb;
// 翻訳テーブルの件数を確認
\$count = \$wpdb->get_var(\"SELECT COUNT(*) FROM {\$wpdb->prefix}icl_translations\");
echo 'Translation entries: ' . \$count . PHP_EOL;

// 孤立した翻訳エントリを確認
\$orphans = \$wpdb->get_var(\"
    SELECT COUNT(*) FROM {\$wpdb->prefix}icl_translations t
    LEFT JOIN {\$wpdb->posts} p ON t.element_id = p.ID
    WHERE t.element_type = 'post_post'
    AND p.ID IS NULL
\");
echo 'Orphan entries: ' . \$orphans . PHP_EOL;
"

# WPMLの翻訳同期ツールを実行(管理画面から)
wp eval "
// WPML言語チェッカーを実行
if (class_exists('WPML_Translation_Status_Display')) {
    echo 'WPML Translation Status class available' . PHP_EOL;
}
do_action('wpml_reload_page_builders');
wp_cache_flush();
echo 'WPML cache flushed' . PHP_EOL;
"

注意事項

  • get_permalink()get_the_title()などのWordPress標準関数はWPMLにより自動的に現在の言語に対応したコンテンツを返しますが、直接$wpdbでクエリする場合は言語フィルターが適用されません。WP_Queryにsuppress_filters => falseを設定してWPMLフィルターを必ず有効にしてください
  • WPMLのURLフォーマットを「サブディレクトリ」から「ドメイン」に変更する場合は、.htaccessとサーバーの設定変更が必要です。また既存のURLが全て変わるため、Google Search Consoleでの再インデックスが必要になります
  • wpml_object_idフィルターで翻訳IDを取得する際、翻訳が存在しない場合の第3引数($return_original_if_missing)をtrueにするとオリジナルIDが返ります。falseだとnullが返るため用途に応じて使い分けてください

まとめ

WPMLエラーの解決は①sitepress->get_active_languages()wpml_object_idフィルターで翻訳状態を診断、②wp rewrite flush --hardでパーマリンクを再生成しWPMLのURLディレクトリルールを復旧、③do_action('wpml_switch_language', $lang)で言語を切り替えてWP_Queryにsuppress_filters=>falseを設定、④wpml_active_languagesフィルターで言語スイッチャーを出力しhreflangタグをwp_headに追加、⑤icl_translationsテーブルの孤立エントリを確認してキャッシュをフラッシュする手順で解決します。

お気軽にご相談ください

お見積りへ お問い合わせへ