WordPress多国語サイト構築:Polylang、資料請求フォーム、SEO対策、生成AIクローラー対応まで


はじめに

本記事では、WordPressテーマ開発において実装した多国語対応、SEO対策(PDF・ダウンロードページのnoindex設定)、生成AIクローラー対策、その他の特筆すべき実装について解説します。

多国語対応の実装

言語別フォント設定

Polylangプラグインを使用した多言語サイトにおいて、言語ごとに最適なフォントスタックを適用する実装を行いました。日本語、英語、台湾華語、タイ語の4言語に対応しています。

// 言語別のフォントスタック定義
$font_stacks = array(
  'ja' => array(
    'sans' => '-apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "ヒラギノ角ゴ ProN W3", "ヒラギノ角ゴ Pro W3", "Hiragino Sans", "游ゴシック", "Yu Gothic", "游ゴシック体", "YuGothic", "Meiryo", "メイリオ", "MS Pゴシック", "MS PGothic", sans-serif',
    'serif' => '"游明朝", YuMincho, "ヒラギノ明朝 ProN W3", "Hiragino Mincho ProN", "HG明朝E", "MS P明朝", "MS 明朝", serif'
  ),
  'en' => array(
    'sans' => '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
    'serif' => 'Georgia, "Times New Roman", Times, serif'
  ),
  'zh' => array(
    'sans' => '-apple-system, BlinkMacSystemFont, "Microsoft JhengHei", "微軟正黑體", "Microsoft YaHei", "微软雅黑", "SimHei", "黑体", "PingFang SC", "Hiragino Sans GB", sans-serif',
    'serif' => '"STSong", "华文宋体", "SimSun", "宋体", serif'
  ),
  'th' => array(
    'sans' => '"Noto Sans Thai", "Sarabun", "Kanit", "Sathu", "Sukhumvit Set", "Thonburi", "Krungthep", -apple-system, BlinkMacSystemFont, sans-serif',
    'serif' => '"Noto Serif Thai", "Sarabun", serif'
  )
);

// 現在の言語を取得
$current_lang = get_current_language();
$current_font = isset($font_stacks[$current_lang]) ? $font_stacks[$current_lang] : $font_stacks['ja'];

// 言語別のフォントを適用
$custom_css .= 'body{font-family: ' . $current_font['sans'] . ';}';

各言語に適したフォントを自動的に適用することで、可読性とユーザー体験を向上させています。

1.2 サーバー側キャッシュの無効化

Polylangプラグインを使用した多言語サイトでは、サーバー側のキャッシュ機能(ページキャッシュ、オブジェクトキャッシュなど)を無効にすることを推奨します。

理由

  1. 言語ごとのコンテンツ表示の正確性:Polylangは、ユーザーの言語設定やURLパラメータに基づいて異なる言語のコンテンツを動的に表示します。サーバー側キャッシュが有効だと、最初にアクセスした言語のコンテンツがキャッシュされ、他の言語のユーザーにも同じコンテンツが表示される可能性があります。
  2. セッション・Cookieベースの言語判定の不具合:Polylangは、セッションやCookieを使用してユーザーの言語設定を保持します。サーバー側キャッシュが有効だと、これらの情報が正しく処理されず、意図しない言語のコンテンツが表示される可能性があります。
  3. 動的な言語切り替えの阻害:ユーザーが言語を切り替えた際に、キャッシュされた古い言語のコンテンツが表示され続ける可能性があり、ユーザー体験が損なわれます。
  4. URLパラメータの無視:多くのキャッシュシステムは、URLパラメータを無視して同じURLを同じコンテンツとして扱います。PolylangがURLパラメータを使用して言語を判定している場合、キャッシュによって正しく機能しない可能性があります。

推奨事項

  • レンタルサーバーのキャッシュ機能:多くのレンタルサーバー(エックスサーバー、さくらのレンタルサーバー、ロリポップ、ConoHa WINGなど)は、独自のキャッシュ機能を提供しています。これらのサーバー側キャッシュ機能は、通常すべてのユーザーに対して同じコンテンツをキャッシュするため、多言語サイトでは言語ごとに異なるコンテンツが正しく表示されない可能性があります。レンタルサーバーの管理画面でキャッシュ機能を無効にするか、多言語サイトのURLパターンをキャッシュ対象から除外する設定を行ってください。
  • ページキャッシュプラグイン:WP Super Cache、W3 Total Cache、WP Rocketなどのページキャッシュプラグインを使用している場合、Polylangと互換性のある設定にするか、多言語ページをキャッシュ対象から除外する設定を行ってください。
  • CDN・プロキシキャッシュ:Cloudflare、VarnishなどのCDNやプロキシキャッシュを使用している場合、多言語サイトのURLパターンをキャッシュ対象から除外するか、言語ごとに異なるキャッシュキーを設定する必要があります。
  • オブジェクトキャッシュ:Redis、Memcachedなどのオブジェクトキャッシュは、通常問題ありませんが、言語設定が正しく反映されることを確認してください。

フォームエラーメッセージの多言語翻訳

WPFormsのエラーメッセージを多言語対応させるため、サーバーサイドで翻訳処理を実装しました。特に、台湾華語とタイ語のエラーメッセージを自動的に翻訳します。

function translate_wpforms_validation_error( $fields, $entry, $form_data ) {
  // フォーム翻訳対象ページでない場合は処理しない
  if ( !is_example_page() ) {
    return $fields;
  }
  
  // 現在の言語を取得
  $current_lang = get_current_language();
  
  // 日本語・英語の場合は翻訳しない
  if ( $current_lang === 'ja' || $current_lang === 'en' ) {
    return $fields;
  }
  
  // エラーメッセージの翻訳マップ(台湾華語・タイ語のみ)
  $error_translations = array(
    'zh' => '此欄位為必填。', // 台湾華語
    'th' => 'กรุณากรอกข้อมูลในช่องนี้' // タイ語
  );
  
  $translated_message = isset($error_translations[$current_lang]) 
    ? $error_translations[$current_lang] 
    : null;
  
  // 翻訳メッセージが存在する場合のみ翻訳
  if ( $translated_message && is_array( $fields ) ) {
    foreach ( $fields as $field_id => $field ) {
      if ( !empty( $field['error'] ) && $field['error'] === 'This field is required.' ) {
        $fields[$field_id]['error'] = $translated_message;
      }
    }
  }
  
  return $fields;
}
add_filter( 'wpforms_process_validate', 'translate_wpforms_validation_error', 10, 3 );

多言語対応のリファラーチェック

ダウンロードページへのアクセス制限においても、多言語対応を実装しています。この実装により、セキュリティとユーザー導線の管理を強化しています。

アクセス制限の仕組み

この実装では、以下のようなアクセス制限を行っています:

  1. 直接URL入力によるアクセスの防止:ユーザーがブラウザのアドレスバーに直接ダウンロードページのURLを入力しても、ダウンロードページは表示されません。リファラー(参照元)が資料請求ページでない場合、自動的に資料請求ページにリダイレクトされます。
  2. フォーム送信後のアクセス許可:資料請求ページで顧客情報をフォームに送信した場合のみ、資料ダウンロードページへのアクセスが許可されます。これにより、適切な導線を経由したユーザーのみが資料をダウンロードできるようになります。
  3. 多言語対応のリダイレクト:リファラーが無効な場合、現在の言語に応じた適切な資料請求ページにリダイレクトします。日本語、英語、台湾華語、タイ語の各言語に対応しており、ユーザーが選択している言語に応じたページへ誘導されます。
function check_download_page_referer_access() {
  $current_url = isset($_SERVER['REQUEST_URI']) ? esc_url_raw($_SERVER['REQUEST_URI']) : '';
  if (strpos($current_url, 'example-download') === false && !is_page_template('page-download.php')) {
    return;
  }
  
  $referer = isset($_SERVER['HTTP_REFERER']) ? esc_url_raw($_SERVER['HTTP_REFERER']) : '';
  
  // リファラーが指定ページを含むかチェック
  if (!empty($referer) && strpos($referer, '/example-page') !== false) {
    return; // アクセス許可
  }
  
  // リファラーが無効な場合は、現在の言語に応じたページにリダイレクト
  $allowed_langs = array('ja', 'en', 'zh', 'th');
  $current_lang = 'ja';
  if (function_exists('pll_current_language')) {
    $lang = pll_current_language('slug');
    if (!empty($lang) && in_array($lang, $allowed_langs, true)) {
      $current_lang = $lang;
    }
  }
  
  // 言語に応じたページのURLを生成
  if ($current_lang === 'ja') {
    $redirect_url = home_url('example-page/');
  } else {
    $redirect_url = home_url($current_lang . '/example-page-' . $current_lang . '/');
  }
  
  wp_redirect($redirect_url);
  exit;
}
add_action('template_redirect', 'check_download_page_referer_access', 1);

この実装により、以下のような動作が実現されます:

  • 直接アクセスの防止https://example.com/example-download/ のようなURLを直接入力しても、資料請求ページ(https://example.com/example-page/)にリダイレクトされます
  • フォーム送信後のアクセス許可:資料請求ページからフォームを送信した場合、HTTPリファラーに資料請求ページのURLが含まれるため、ダウンロードページへのアクセスが許可されます
  • 多言語対応:ユーザーが英語ページ(/en/example-page-en/)からアクセスしようとした場合、英語の資料請求ページにリダイレクトされます

この仕組みにより、資料の適切な配布管理とセキュリティの向上を実現しています。

ダウンロード資料PDFのnoindex設定

ダウンロードページで配布されるPDFファイルが検索エンジンにインデックスされないよう、.htaccessファイルでX-Robots-Tagヘッダーを追加しています。これにより、すべてのPDFファイルに対して自動的にnoindex, nofollowが設定され、検索エンジンによるインデックスを防止します。

# PDFファイルにX-Robots-Tagヘッダーを追加
<FilesMatch "\.pdf$">
  Header set X-Robots-Tag "noindex, nofollow"
</FilesMatch>

この実装により、サイト内のすべてのPDFファイルに対して自動的にX-Robots-Tag: noindex, nofollowヘッダーが設定され、検索エンジンによるインデックスを防止します。.htaccessファイルでの設定により、PHPの処理を経由せずにサーバーレベルでヘッダーを追加できるため、パフォーマンスの面でも有利です。

PDFファイルのnoindex設定

PDFファイル自体も検索エンジンにインデックスされないよう、robots.txtファイルでDisallowディレクティブを使用してクロールをブロックしています。

# PDFファイルをすべてのクローラーからブロック
User-agent: *
Disallow: /wp-content/uploads/*.pdf

この実装により、以下のような効果が得られます:

  • PDFファイルのクロール防止wp-content/uploads/配下のPDFファイルもクロール対象から除外されます
  • すべてのクローラーに適用User-agent: *により、すべての検索エンジンクローラーに対して適用されます

robots.txtファイルでの設定により、PHPの処理を経由せずにサーバーレベルでクロールを制御できるため、効率的にSEO対策を実現できます。

生成AIクローラー対策

生成AIクローラー(GPTBot、ChatGPT-User、CCBotなど)がPDFファイルにアクセスできないよう、robots.txtファイルと.htaccessファイルの両方でUser-Agentベースでブロックする実装を行いました。これにより、機密情報を含むダウンロード資料が生成AIの学習データに含まれることを防止します。

.htaccessによる強制的なブロック

より確実にブロックするため、.htaccessファイルでUser-Agentをチェックし、生成AIクローラーからのPDFファイルへのアクセスに対して403エラーを返す実装を追加しました。

# 生成AIクローラーと検索エンジンをPDFファイルからブロック
<IfModule mod_rewrite.c>
  # PDFへのアクセス
  RewriteCond %{REQUEST_URI} \.pdf$ [NC]
  # 明確にクローラーを対象にする
  RewriteCond %{HTTP_USER_AGENT} (facebookexternalhit|facebot|GPTBot|ChatGPT-User|CCBot|Claude-Web|Google-Extended|PerplexityBot|Googlebot|bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|Sogou|Exabot|AhrefsBot|SemrushBot|MJ12bot|DotBot|BLEXBot|PetalBot) [NC]
  # クローラーには403
  RewriteRule .* - [F,L]
</IfModule>

この実装により、以下のような効果が得られます:

  • 強制的なブロック.htaccessでの実装により、robots.txtを無視するクローラーに対しても、サーバーレベルで強制的に403エラーを返すことができます
  • PDFファイルのブロック:各生成AIクローラーに対してPDFファイルへのアクセスをブロックします。サイト全体ではなく、機密情報を含む可能性のあるPDFファイルのみを対象とすることで、他のコンテンツへのアクセスは許可しつつ、セキュリティを確保しています
  • 主要な生成AIクローラーに対応:GPTBot(OpenAI)、ChatGPT-User、CCBot(Common Crawl)、anthropic-ai、Claude-Web、Google-Extended、PerplexityBot、Applebot-Extendedなど、主要な生成AIクローラーを網羅しています
  • サーバーレベルでの制御.htaccessファイルでの設定により、PHPの処理を経由せずにサーバーレベルでアクセスを制御できるため、効率的にセキュリティ対策を実現できます

robots.txt.htaccessの両方を併用することで、より確実に生成AIクローラーからのPDFファイルへのアクセスを防止できます。

その他特筆すべき実装

カスタム投稿タイプのnofollow設定

特定のカスタム投稿タイプ(product)の個別ページをnofollow化することで、検索エンジンへの評価の流れを制御しています。WordPress標準のwp_robotsフィルターとYoast SEOプラグインの両方に対応しています。

// ---------productカスタム投稿タイプの個別ページをnofollow化-------------
// productカスタム投稿タイプの個別ページのrobotsメタタグをnoindex, nofollowに書き換え
// WordPress標準のwp_robotsフィルターを使用
function change_product_robots_to_nofollow( $robots ) {
  if ( is_singular( 'product' ) ) {
    // noindexとnofollowを明示的に設定(検索エンジンと生成AIのインデックスを防止)
    $robots['noindex'] = true;
    $robots['nofollow'] = true;
  }
  return $robots;
}
add_filter( 'wp_robots', 'change_product_robots_to_nofollow', 10, 1 );

// Yoast SEOプラグインを使用している場合の対応
function change_product_yoast_robots_to_nofollow( $robots ) {
  if ( is_singular( 'product' ) ) {
    // productカスタム投稿タイプの個別ページは常にnoindex, nofollowを返す(検索エンジンと生成AIのインデックスを防止)
    return 'noindex, nofollow';
  }
  return $robots;
}
// 優先度を高くして、他のフィルターより後に実行されるようにする
add_filter( 'wpseo_robots', 'change_product_yoast_robots_to_nofollow', 99, 1 );

まとめ

本記事では、WordPressテーマ開発において実装した以下の技術的な機能について解説しました:

  • 多国語対応:言語別フォント設定、フォームエラーメッセージの翻訳、多言語対応のリファラーチェック
  • ダウンロード資料PDFのnoindex設定:.htaccessファイルによるX-Robots-Tagヘッダーの追加によるPDFファイルのインデックス防止
  • ダウンロードページのnoindex設定:robots.txtファイルによるDisallowディレクティブでのクロールブロック
  • 生成AIクローラー対策:robots.txtファイルによるUser-AgentベースでのPDFファイルのブロック
  • その他特筆すべき実装:カスタム投稿タイプのnofollow設定

これらの実装により、多言語対応、SEO対策、セキュリティの面で高品質なWordPressテーマを実現できました。特に、多言語対応とセキュリティ対策の組み合わせは、グローバルなWebサイトにおいて重要な要素となります。

FAQ

Polylangプラグイン以外の多言語プラグイン(WPML、Weglotなど)でも同じ実装方法が使えますか?

基本的な考え方は同じですが、プラグインごとにAPIが異なるため、実装方法を調整する必要があります。例えば、WPMLの場合はICL_LANGUAGE_CODE、Weglotの場合はweglot_get_current_language()などの関数を使用します。言語取得の関数を変更すれば、同様の実装が可能です。

言語別フォント設定で、特定の言語だけ異なるフォントを適用したい場合はどうすればよいですか?

$font_stacks配列に該当する言語のエントリを追加または修正してください。例えば、韓国語を追加する場合は、'ko' => array(...)を追加し、get_current_language()関数が返す言語コードに'ko'を含めるように設定します。

フォームエラーメッセージの翻訳で、他のエラーメッセージ(例:「無効なメールアドレスです」)も翻訳したい場合はどうすればよいですか?

$error_translations配列に追加のエラーメッセージとその翻訳を追加してください。translate_wpforms_validation_error関数内で、$field['error']の値をチェックし、該当するエラーメッセージがあれば翻訳を適用するように条件分岐を追加します。

レンタルサーバーのキャッシュ機能を無効にすると、サイトのパフォーマンスが低下しませんか?

パフォーマンスへの影響はありますが、多言語サイトでは正確なコンテンツ表示が優先されます。パフォーマンスを維持したい場合は、言語ごとに異なるキャッシュキーを設定できるキャッシュプラグイン(WP Rocketの多言語対応機能など)を使用するか、CDNレベルで言語ごとのキャッシュを設定することを検討してください。

robots.txtでDisallowを設定しても、既にインデックスされているページはどうなりますか?

robots.txtのDisallowは、今後クロールされないようにする設定であり、既にインデックスされているページは自動的には削除されません。既存のインデックスを削除したい場合は、Google Search Consoleの「URL削除ツール」を使用するか、該当ページにnoindexメタタグを追加して再クロールを待つ必要があります。

.htaccessでPDFファイルにX-Robots-Tagを追加する方法と、robots.txtでDisallowを設定する方法の違いは何ですか?

.htaccessでのX-Robots-Tagヘッダーは、HTTPレスポンスヘッダーとして送信されるため、より確実に検索エンジンに指示を伝えられます。一方、robots.txtDisallowは、クローラーが最初に参照するファイルですが、すべてのクローラーが従うとは限りません。両方を併用することで、より確実にインデックスを防止できます。

robots.txtで生成AIクローラーをブロックしても、実際にアクセスを防げますか?

robots.txtはクローラーへの「お願い」であり、法的な強制力はありません。多くの主要な生成AIクローラー(GPTBot、CCBotなど)はrobots.txtを尊重しますが、100%の保証はありません。より確実にブロックしたい場合は、.htaccessでUser-Agentをチェックして403エラーを返す実装を追加することを検討してください。

生成AIクローラーをブロックすると、サイトの検索結果での表示に影響しますか?

サイト全体をブロックする場合は影響がありますが、PDFファイルのみをブロックする場合は、通常の検索エンジンクローラー(Googlebotなど)は影響を受けないため、検索結果への表示には影響しません。記事で紹介している実装は、PDFファイルのみをブロックするため、通常のSEOには影響しません。

リファラーチェックの実装で、リファラーが偽造される可能性はありませんか?

HTTPリファラーはクライアント側で送信されるため、技術的には偽造可能です。ただし、一般的なユーザーがリファラーを偽造することは困難です。より厳格なセキュリティが必要な場合は、セッション変数やトークンベースの認証を併用することを推奨します。

多言語サイトで、検索エンジンごとに異なる言語のページをインデックスさせたい場合はどうすればよいですか?

hreflangタグを使用して、言語ごとのページの関係を検索エンジンに伝える必要があります。Polylangプラグインにはhreflangタグの自動生成機能があるため、プラグインの設定で有効化してください。また、各言語のページが正しくリンクされていることを確認してください。