2026年5月21日

2026年5月21日

WP Migrate DBのエラーを解決する方法

はじめに

WP Migrate DB(旧WP Migrate DB Pro)でデータベースのエクスポート中に「接続エラー」「タイムアウト」が発生する・URLの置換が不完全でシリアライズデータが壊れる・移行後にサイトが真っ白になる・大容量DBのエクスポートが途中で止まるといった問題は、PHPのタイムアウト設定・シリアライズデータの不正置換・サーバーのアップロードサイズ制限が原因です。

症状・原因

  • 「Migration failed: Could not connect to the remote server」エラーが出る
  • エクスポートしたSQLをインポートすると一部のオプションやメタデータが壊れる
  • 移行後にサイトにアクセスすると管理画面・フロントエンドともに白画面になる
  • 500MBを超えるDBのエクスポートが50〜60%で止まる

解決手順

ステップ1:移行前の状態確認とDB最適化

# DBサイズとテーブル状況を確認
wp eval "
global \$wpdb;

// テーブルサイズを確認
\$tables = \$wpdb->get_results('
    SELECT table_name, 
           ROUND(data_length/1024/1024, 2) AS data_mb,
           ROUND(index_length/1024/1024, 2) AS index_mb,
           table_rows
    FROM information_schema.tables
    WHERE table_schema = DATABASE()
    ORDER BY data_length DESC
    LIMIT 15
');

echo 'DB Tables (by size):' . PHP_EOL;
foreach (\$tables as \$t) {
    printf('  %-40s %6.2f MB (%d rows)' . PHP_EOL,
        \$t->table_name, \$t->data_mb, \$t->table_rows);
}

// 総サイズ
\$total = \$wpdb->get_var('
    SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2)
    FROM information_schema.tables
    WHERE table_schema = DATABASE()
');
echo 'Total DB size: ' . \$total . ' MB' . PHP_EOL;
"

# DB最適化(移行前に実行推奨)
wp db optimize
wp db repair

# WP Migrate DBのバージョン確認
wp eval "
if (class_exists('WPMDB_Base')) {
    echo 'WP Migrate version: ' . WPMDB_BASE_VERSION . PHP_EOL;
}
"

ステップ2:WP-CLIを使ったURL置換(シリアライズ対応)

# WP-CLIのsearch-replaceコマンドでURL置換(シリアライズデータに対応)
wp search-replace 'https://staging.example.com' 'https://example.com' \
    --all-tables \
    --precise \
    --skip-columns=guid \
    --report-changed-only

# プレビューのみ(実際には変更しない)
wp search-replace 'https://staging.example.com' 'https://example.com' \
    --all-tables \
    --precise \
    --dry-run

# 特定テーブルのみ置換
wp search-replace 'http://localhost:8080' 'https://example.com' \
    wp_options wp_postmeta wp_usermeta \
    --precise \
    --report-changed-only

# 置換結果を確認
wp eval "
// siteurl と home が正しく設定されているか確認
echo 'siteurl: ' . get_option('siteurl') . PHP_EOL;
echo 'home: '    . get_option('home') . PHP_EOL;
echo 'upload_path: ' . get_option('upload_path') . PHP_EOL;
"

ステップ3:シリアライズデータを安全に修復する

// functions.php: シリアライズデータ修復ユーティリティ

// ① 壊れたシリアライズデータを検出・修復
function fix_serialized_option(string $option_name, string $old_url, string $new_url): bool {
    $value = get_option($option_name);
    if (!is_string($value)) return false;

    // シリアライズされているか確認
    if (!is_serialized($value)) {
        // 通常の文字列置換
        $new_value = str_replace($old_url, $new_url, $value);
        return update_option($option_name, $new_value);
    }

    // アンシリアライズして置換
    $unserialized = @unserialize($value);
    if ($unserialized === false) {
        // シリアライズが壊れている場合はバイト数修正を試みる
        $fixed = preg_replace_callback(
            '/s:(\d+):"(.*?)"/s',
            function(array $matches): string {
                $str = $matches[2];
                return 's:' . strlen($str) . ':"' . $str . '"';
            },
            $value
        );
        update_option($option_name . '_broken_backup', $value);
        return update_option($option_name, $fixed);
    }

    // 再帰的にURL置換
    $replaced = replace_in_value($unserialized, $old_url, $new_url);
    return update_option($option_name, $replaced);
}

// ② 再帰的な値置換
function replace_in_value(mixed $value, string $old, string $new): mixed {
    if (is_string($value)) {
        return str_replace($old, $new, $value);
    }
    if (is_array($value)) {
        return array_map(fn($v) => replace_in_value($v, $old, $new), $value);
    }
    if (is_object($value)) {
        foreach (get_object_vars($value) as $prop => $val) {
            $value->$prop = replace_in_value($val, $old, $new);
        }
    }
    return $value;
}

ステップ4:大容量DBの移行をタイムアウトなしで実行する

# WP-CLIで大容量DBをエクスポート(タイムアウトなし)
wp db export backup-$(date +%Y%m%d).sql --add-drop-table

# 圧縮してエクスポート
wp db export - | gzip > backup-$(date +%Y%m%d).sql.gz

# テーブル別に分割エクスポート(大容量DB対策)
for table in $(wp db tables --all-tables --format=csv | tr ',' '\n'); do
    wp db export --tables=$table ${table}.sql
    echo "Exported: $table"
done

# MySQLコマンドで直接インポート(phpMyAdminのタイムアウト回避)
mysql -u DB_USER -p DB_NAME < backup.sql

# gzip圧縮ファイルのインポート
gunzip < backup.sql.gz | mysql -u DB_USER -p DB_NAME
// functions.php: 移行後の確認・修復

// ① 移行後のURLを一括確認
function audit_site_urls(): array {
    $issues = [];
    $old_url = 'https://staging.example.com'; // 移行前のURL

    // wp_options の主要オプションを確認
    $options_to_check = ['siteurl', 'home', 'blogdescription', 'upload_path', 'upload_url_path'];
    foreach ($options_to_check as $opt) {
        $value = get_option($opt, '');
        if (str_contains($value, $old_url)) {
            $issues[] = "Option '{$opt}' still contains old URL: {$value}";
        }
    }

    // アクティブなプラグインの設定を確認
    $active_plugins = get_option('active_plugins', []);
    foreach ($active_plugins as $plugin) {
        $plugin_option = str_replace(['.php', '/'], ['', '_'], $plugin) . '_settings';
        $value = maybe_serialize(get_option($plugin_option, ''));
        if (str_contains($value, $old_url)) {
            $issues[] = "Plugin option '{$plugin_option}' contains old URL";
        }
    }

    return $issues;
}

ステップ5:移行後のチェックリスト

# 移行後の動作確認チェックリスト
wp eval "
echo '=== 移行後チェックリスト ===' . PHP_EOL;

// ① URL設定
echo '① URL設定' . PHP_EOL;
echo '  siteurl: ' . get_option('siteurl') . PHP_EOL;
echo '  home: '    . get_option('home') . PHP_EOL;

// ② パーマリンクリセット
\$result = flush_rewrite_rules(true);
echo '② パーマリンク: ' . (empty(\$result) ? 'OK(リセット済み)' : 'NG') . PHP_EOL;

// ③ アップロードディレクトリ
\$upload = wp_upload_dir();
echo '③ アップロードDir: ' . (\$upload['error'] ? 'ERROR: ' . \$upload['error'] : 'OK') . PHP_EOL;

// ④ DBテーブル整合性
global \$wpdb;
\$errors = \$wpdb->get_results('CHECK TABLE ' . \$wpdb->options . ', ' . \$wpdb->posts . ', ' . \$wpdb->postmeta);
\$ok = true;
foreach (\$errors as \$e) {
    if (\$e->Msg_type === 'error') { \$ok = false; echo '  ERROR: ' . \$e->Msg_text . PHP_EOL; }
}
echo '④ DBテーブル: ' . (\$ok ? 'OK' : 'ERROR(要修復)') . PHP_EOL;

// ⑤ キャッシュクリア
wp_cache_flush();
echo '⑤ キャッシュ: クリア完了' . PHP_EOL;
"

注意事項

  • WP Migrate DBでURL置換を行う際、シリアライズされたデータ(Elementorのページデータ・ACFのフィールド設定など)は単純な文字列置換では壊れます。WP Migrate DB ProまたはWP-CLIのwp search-replace --preciseオプションを使用してください。--preciseオプションはシリアライズデータを一度展開してから置換します
  • 大容量DB(300MB以上)の移行はphpMyAdminではなく、WP-CLIやMySQLコマンドを直接使用することを強く推奨します。phpMyAdminはサーバーのPHP実行時間(max_execution_time)の制限を受けるため、途中でタイムアウトします
  • 移行後に必ずパーマリンクの再保存(「設定 → パーマリンク → 変更を保存」)を行ってください。リライトルールがリセットされないと、固定ページや投稿URLが404になります

まとめ

WP Migrate DB修復は①information_schemaでDBサイズ・テーブルサイズを確認・wp db optimizeで最適化、②wp search-replace --all-tables --preciseでシリアライズデータに対応したURL置換、③is_serialized()unserialize()→再帰置換→update_option()でシリアライズデータを安全に修復・バイト数ズレをregex修正、④wp db exportmysqlコマンドで大容量DBをタイムアウトなしで移行・gzip圧縮で転送サイズ削減、⑤移行後のsiteurl/home確認・パーマリンクリセット・DBテーブルCHECK・キャッシュクリアで動作を検証する手順で解決します。

お気軽にご相談ください

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