2026年5月20日

2026年5月20日

WordPressのページのリンク切れを検出する方法

はじめに

リンク切れ(404エラー)はSEOと UXの両方に悪影響を与えます。内部リンクが切れると検索エンジンのクロールが滞り、外部リンク切れはユーザー体験を損ないます。定期的な検出・修正がサイト品質の維持に不可欠です。

症状・原因

  • Google Search Consoleで「404(見つかりません)」のURLが大量に表示されている
  • ページを削除・移動したが内部リンクを更新していない
  • 外部サイトのURLが変更・削除されて外部リンクが切れている
  • リダイレクト設定が不完全でリンクが古いURLのまま

解決手順

ステップ1:Google Search Consoleで404エラーを確認する

Google Search Console での確認手順:
1. Search Console → 「ページ」レポートを開く
2. 「除外」タブ → 「見つかりません(404)」を選択
3. 対象URLリストをCSVでエクスポート
4. 「参照元ページ」列でどのページからリンクされているか確認

また:
カバレッジ → エラー → 「送信済みURL が見つかりません(404)」
→ サイトマップ経由でGoogleに送信された404を特定

ステップ2:プラグインでリンク切れを自動検出する

【Broken Link Checker プラグイン】
管理画面 → ツール → リンクチェッカー

設定:
・リンクの確認間隔: 72時間
・メール通知: 有効
・どのコンテンツをチェック: 投稿・固定ページ・コメント

注意: サーバーリソースを消費するため
本番環境では確認後に無効化推奨
// wp-config.php: Broken Link Checker の負荷を軽減
define('BLC_SAFE_MODE', true);  // バックグラウンド処理を制限

// または WP-CLI でリンクチェック(サーバーサイド)
// wp blc postmeta --all  ← プラグインがWP-CLI対応の場合

ステップ3:WP-CLIでリンク切れを検出する

# 全投稿の内部リンクを取得してリンク切れチェック
wp post list --post_type=post,page --post_status=publish \
    --fields=ID,post_title,guid --format=json > /tmp/posts.json

# 特定ドメインの内部リンクを抽出
wp post list --post_status=publish --format=ids | \
xargs -I{} wp post get {} --field=post_content | \
grep -oP 'href="https?://example\.com[^"]*"' | \
sort -u > /tmp/internal_links.txt

# curlで各リンクのHTTPステータスをチェック
while IFS= read -r url; do
    clean_url=$(echo "$url" | sed 's/href="//;s/"//')
    status=$(curl -s -o /dev/null -w "%{http_code}" \
        --max-time 10 --location "$clean_url")
    if [ "$status" = "404" ] || [ "$status" = "410" ]; then
        echo "BROKEN [$status]: $clean_url"
    fi
done < /tmp/internal_links.txt
# Apacheアクセスログから404を抽出
grep ' 404 ' /var/log/apache2/access.log | \
    awk '{print $7}' | sort | uniq -c | sort -rn | head -30

# Nginxアクセスログから404を抽出
grep '"GET.*" 404' /var/log/nginx/access.log | \
    awk -F'"' '{print $2}' | awk '{print $2}' | \
    sort | uniq -c | sort -rn | head -30

ステップ4:Screaming FrogでサイトをクロールしてリンクチェックするPHP

// functions.php: 404エラーをログに記録するカスタム実装

add_action('wp', function(): void {
    if (!is_404()) {
        return;
    }

    $request_uri = $_SERVER['REQUEST_URI'] ?? '';
    $referer     = $_SERVER['HTTP_REFERER'] ?? '(direct)';
    $user_agent  = $_SERVER['HTTP_USER_AGENT'] ?? '';

    // ボットは除外
    if (str_contains(strtolower($user_agent), 'bot')) {
        return;
    }

    // データベースに記録
    global $wpdb;
    $wpdb->insert(
        $wpdb->prefix . '404_log',
        [
            'request_url' => esc_url_raw($request_uri),
            'referer'     => esc_url_raw($referer),
            'created_at'  => current_time('mysql'),
        ]
    );
});

// テーブル作成(プラグイン有効化時)
function create_404_log_table(): void {
    global $wpdb;
    $table = $wpdb->prefix . '404_log';
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE IF NOT EXISTS {$table} (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        request_url VARCHAR(2048) NOT NULL,
        referer VARCHAR(2048) NOT NULL,
        created_at DATETIME NOT NULL,
        INDEX (created_at)
    ) {$charset_collate};";

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta($sql);
}
register_activation_hook(__FILE__, 'create_404_log_table');

ステップ5:定期的な自動リンクチェックを設定する

// functions.php: 週次でリンク切れをメール通知

add_action('wp_scheduled_link_check', 'run_link_check');

function run_link_check(): void {
    $posts = get_posts([
        'post_type'      => ['post', 'page'],
        'post_status'    => 'publish',
        'posts_per_page' => -1,
        'fields'         => 'ids',
    ]);

    $broken = [];

    foreach ($posts as $post_id) {
        $content = get_post_field('post_content', $post_id);
        preg_match_all('/href=["\']([^"\']+)["\']/', $content, $matches);

        foreach ($matches[1] as $url) {
            if (!str_starts_with($url, 'http')) {
                continue;
            }
            $response = wp_remote_head($url, ['timeout' => 10, 'redirection' => 3]);
            $code = wp_remote_retrieve_response_code($response);
            if ($code === 404 || $code === 410) {
                $broken[] = "Post {$post_id}: [{$code}] {$url}";
            }
        }
    }

    if (!empty($broken)) {
        wp_mail(
            get_option('admin_email'),
            'リンク切れ検出レポート',
            implode("\n", $broken)
        );
    }
}

if (!wp_next_scheduled('wp_scheduled_link_check')) {
    wp_schedule_event(time(), 'weekly', 'wp_scheduled_link_check');
}

注意事項

  • Broken Link Checkerプラグインは便利ですが、サーバーリソースを大量消費することがあります。チェック完了後は無効化するか、スケジュール間隔を長めに設定してください
  • 外部リンクのチェックは相手サーバーへのリクエストが多くなりすぎると、アクセス拒否される場合があります。間隔を空けてチェックするようにしてください
  • 404ログを蓄積する場合、テーブルサイズが肥大化しないよう定期的に古いレコードを削除してください

まとめ

リンク切れ検出は①Google Search ConsoleのカバレッジレポートでGoogleが検出した404を確認、②Broken Link Checkerプラグインで自動スキャン、③WP-CLIとcurlで内部リンクの一括チェック、④Apacheログから実際のユーザーが踏んだ404を抽出、⑤wp_headis_404()フックでリアルタイムログ記録、の組み合わせで効率よく把握できます。

お気軽にご相談ください

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