2026年7月22日
2026年7月22日
Polylangのエラーを解決する方法
はじめに
Polylangで翻訳済みの投稿URLにアクセスすると404エラーになる・フロントエンドに言語切替ウィジェットが表示されない・投稿を更新しても翻訳ページに変更が反映されない・WooCommerceで商品の翻訳が作れないといった問題は、パーマリンク設定・言語ページのパス設定・Polylangの翻訳同期設定が原因です。
症状・原因
- 日本語投稿は表示されるが
/en/パスの英語翻訳にアクセスすると404になる - ウィジェットエリアに言語切替(Language Switcher)を追加したが表示されない
- 日本語投稿のカスタムフィールドを更新しても英語翻訳には反映されない
- WooCommerce商品の翻訳を作ろうとしても翻訳追加ボタンが表示されない
解決手順
ステップ1:Polylangの状態を確認する
# Polylangの設定と言語を確認
wp eval "
// バージョン確認
if (defined('POLYLANG_VERSION')) {
echo 'Polylang version: ' . POLYLANG_VERSION . PHP_EOL;
}
// 登録済み言語を確認
\$languages = pll_languages_list(['fields' => []]);
echo 'Languages: ' . PHP_EOL;
foreach (\$languages as \$lang) {
printf(' %s (%s) | Slug: %s | Home URL: %s' . PHP_EOL,
\$lang->name, \$lang->locale, \$lang->slug, pll_home_url(\$lang->slug));
}
// 設定を確認
\$options = get_option('polylang', []);
echo 'Hide default language: ' . (\$options['hide_default'] ?? '0') . PHP_EOL;
echo 'Rewrite: ' . (\$options['rewrite'] ?? '0') . PHP_EOL;
echo 'Default language: ' . (\$options['default_lang'] ?? 'not set') . PHP_EOL;
// 翻訳済みの投稿数を確認
\$post = get_posts(['post_type' => 'post', 'numberposts' => 1]);
if (\$post) {
\$translations = pll_get_post_translations(\$post[0]->ID);
printf('Sample post #%d translations: %s' . PHP_EOL, \$post[0]->ID, implode(', ', array_keys(\$translations)));
}
"
# パーマリンクをリセット
wp rewrite flush --hard
echo "Rewrite rules flushed"
ステップ2:翻訳の取得と管理をカスタマイズする
// functions.php: Polylang翻訳管理
// ① 現在の言語で翻訳投稿を取得
function get_translated_post(int $post_id, string $lang = ''): int {
$lang = $lang ?: pll_current_language();
return (int) pll_get_post($post_id, $lang);
}
// 使用例: 英語版の投稿IDを取得
$en_post_id = get_translated_post($ja_post_id, 'en');
// ② カスタムフィールドを翻訳間で同期
add_action('pll_save_post', function(int $post_id, \WP_Post $post, array $translations): void {
// 同期するカスタムフィールドのキー
$sync_metas = ['_product_sku', '_custom_price', 'seo_noindex'];
foreach ($translations as $lang => $translated_id) {
if ($translated_id === $post_id) continue; // 自身はスキップ
foreach ($sync_metas as $meta_key) {
$value = get_post_meta($post_id, $meta_key, true);
if ($value !== '') {
update_post_meta($translated_id, $meta_key, $value);
}
}
}
}, 10, 3);
// ③ 言語切替URLを手動で生成
function get_language_switcher_urls(): array {
$languages = pll_languages_list(['fields' => []]);
$urls = [];
foreach ($languages as $lang) {
$translated_id = pll_get_post(get_the_ID(), $lang->slug);
$urls[$lang->slug] = [
'name' => $lang->name,
'url' => $translated_id ? get_permalink($translated_id) : pll_home_url($lang->slug),
'active' => ($lang->slug === pll_current_language()),
'flag' => $lang->flag_url,
];
}
return $urls;
}
ステップ3:プログラムで文字列と言語を登録する
// functions.php: Polylang文字列翻訳
// ① カスタム文字列を翻訳可能に登録
add_action('init', function(): void {
if (!function_exists('pll_register_string')) return;
// テーマ固有の文字列を登録
pll_register_string('theme', 'ご購入はこちら', 'My Theme');
pll_register_string('theme', 'もっと見る', 'My Theme');
pll_register_string('theme', 'カートに追加', 'My Theme');
pll_register_string('theme', 'お問い合わせ', 'My Theme');
});
// テンプレートでの使用
// echo pll__('ご購入はこちら');
// ② 特定のパスで言語を強制設定
add_filter('pll_get_post_language', function(string $lang, \WP_Post $post): string {
// /en/ パスで始まるURLは英語強制
if (str_starts_with($_SERVER['REQUEST_URI'] ?? '', '/en/')) {
return 'en';
}
return $lang;
}, 10, 2);
// ③ 言語別にメニューを切り替え
add_filter('wp_nav_menu_args', function(array $args): array {
$lang = pll_current_language();
// 言語別のメニュースラッグを設定
$menu_map = [
'ja' => 'main-menu-ja',
'en' => 'main-menu-en',
];
if (isset($menu_map[$lang]) && $args['theme_location'] === 'primary') {
$args['menu'] = $menu_map[$lang];
}
return $args;
});
ステップ4:WooCommerceとの連携を設定する
// functions.php: Polylang + WooCommerce連携
// ① 商品翻訳のURLを言語別に生成
add_filter('woocommerce_get_cart_url', function(string $url): string {
$lang = pll_current_language();
$cart_id = pll_get_post(wc_get_page_id('cart'), $lang);
return $cart_id ? get_permalink($cart_id) : $url;
});
// ② WooCommerceメールを言語別に送信
add_filter('woocommerce_email_subject_new_order', function(string $subject, \WC_Order $order): string {
$customer_lang = get_user_meta($order->get_customer_id(), 'pll_filter_lang', true);
if ($customer_lang === 'en') {
return 'New Order #' . $order->get_id();
}
return $subject; // デフォルト(日本語)
}, 10, 2);
// ③ 言語別のホームURLを取得
function get_localized_home_url(string $lang = ''): string {
$lang = $lang ?: pll_current_language();
return pll_home_url($lang);
}
// ④ REST APIで言語フィルターを追加
add_filter('rest_post_query', function(array $args, \WP_REST_Request $request): array {
$lang = $request->get_param('lang');
if ($lang && function_exists('pll_get_post_language')) {
$args['lang'] = sanitize_key($lang);
}
return $args;
}, 10, 2);
ステップ5:翻訳の一括操作とデバッグ
# 翻訳の整合性を確認
wp eval "
// 翻訳が欠けている投稿を確認
\$all_posts = get_posts([
'post_type' => 'post',
'posts_per_page' => 50,
'post_status' => 'publish',
]);
\$languages = pll_languages_list(['fields' => 'slug']);
\$missing = [];
foreach (\$all_posts as \$post) {
\$translations = pll_get_post_translations(\$post->ID);
foreach (\$languages as \$lang) {
if (!isset(\$translations[\$lang])) {
\$missing[] = ['post_id' => \$post->ID, 'lang' => \$lang, 'title' => \$post->post_title];
}
}
}
echo 'Posts missing translations: ' . count(\$missing) . PHP_EOL;
foreach (array_slice(\$missing, 0, 10) as \$m) {
printf(' Post #%d | Missing: %s | Title: %s' . PHP_EOL, \$m['post_id'], \$m['lang'], \$m['title']);
}
"
# 言語割り当てなしの投稿を確認
wp eval "
global \$wpdb;
\$posts_without_lang = \$wpdb->get_results(\"
SELECT p.ID, p.post_title
FROM {\$wpdb->posts} p
LEFT JOIN {\$wpdb->term_relationships} tr
ON p.ID = tr.object_id
LEFT JOIN {\$wpdb->term_taxonomy} tt
ON tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'language'
WHERE p.post_type = 'post'
AND p.post_status = 'publish'
AND tt.taxonomy IS NULL
LIMIT 10
\");
echo 'Posts without language: ' . count(\$posts_without_lang) . PHP_EOL;
"
注意事項
- Polylangで翻訳ページが404になる場合、「設定 → パーマリンク」を一度保存するだけで解決することがほとんどです。Polylangはリライトルールを動的に追加するため、プラグインの有効化後や設定変更後は必ずパーマリンクの再保存が必要です
- WooCommerce + Polylangの組み合わせでは「Polylang for WooCommerce」(有料)プラグインを使用することを強く推奨します。無料版のPolylangでもWooCommerceの基本的な多言語化は可能ですが、カート・チェックアウト・注文完了ページの言語別URLは有料版が必要です
pll_register_string()で登録した文字列の翻訳は「言語 → 文字列の翻訳」画面で行います。登録後にこの画面に表示されない場合は一度ページをリロードしてください
まとめ
Polylang修復は①pll_languages_list()で言語一覧・URLを確認・wp rewrite flushでパーマリンクリセット、②pll_get_post()で翻訳投稿IDを取得・pll_save_postフックでカスタムフィールドを翻訳間同期、③pll_register_string()でテーマ文字列を翻訳可能に登録・wp_nav_menu_argsフィルターで言語別メニュー切替、④woocommerce_get_cart_urlフィルターで言語別カートURL・rest_post_queryフィルターでREST APIの言語フィルタリング、⑤翻訳欠けチェッククエリ・言語未割当投稿の診断SQLで整合性を管理する手順で解決します。