✉️

レンタルサーバー内のWordPressを探してユーザー情報を一括変更する

2024/10/30に公開

TL;DR

  • 契約ディレクトリ配下に複数のWordPressを設置しているような環境
  • 一括で何かを処理したい場合(今回はユーザーのメールアドレス変更)
  • 一応実行ログも残るように設定

はじめに

契約しているレンタルサーバー内に単一クライアント用のウェブサイトをホストして管理していることが一般的だと思いますが、様々な事情から複数のサイトを単一契約内で管理する事もあるかと思います。
また WordPress もそのように管理するケースがあるかと思います。最近では設置データベース数やファイル容量もほぼ制限がなく、詰めるだけ詰め込んだ WordPress ホスティング弁当も作りやすくなったと思います。

そのような方たちのために Webの相談所さんにて、以下記事が共有されていました。

レンタルサーバーにインストールされているWordPressの情報を一括で取得するスクリプトを作りました。
https://web-soudan.co.jp/topics/4892/

本記事はこのスクリプトを少し変えただけですが、目的の動作を行うためには少し変更する必要があったりしています。このスクリプトは前述のスクリプトをベースに、Claude を利用して目的の動作を実現したものです。一通り動作テストを行っていますが、もし不備があればご指摘頂けますと幸いです

要件

  • ルートディレクトリから再帰的に走査可能なディレクトリ構成のホスティング
  • 複数の WordPress がホスティングされている
  • SSH で接続可能
  • wp cli が動作可能
    上記前提で動作します

コード

#!/bin/bash

# スクリプトのディレクトリを取得
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# ログファイルを絶対パスで指定
log_file="${SCRIPT_DIR}/email_change_log.txt"

# 設定
search_dir="$1"
single_mode=false

# ログ関数
log_message() {
    local message="$1"
    echo "$message"
    echo "$message" >> "$log_file"
}

# コマンドラインオプションの処理
while [[ $# -gt 0 ]]; do
    case $1 in
        --single)
            single_mode=true
            shift
            ;;
        *)
            if [ -z "$search_dir" ]; then
                search_dir="$1"
            fi
            shift
            ;;
    esac
done

# メールアドレスのマッピング
declare -A email_mapping
email_mapping["admin@example.com"]="admin@example.co.jp"
email_mapping["editor@example.com"]="editor@example.co.jp"
email_mapping["author@example.com"]="author@example.co.jp"

# WordPress管理者メールアドレスの設定
old_admin_email="info@example.com"
new_admin_email="info@example.co.jp"

# 引数チェック
if [ -z "$search_dir" ]; then
    echo "エラー: 対象ディレクトリを引数でセットしてください" | tee -a "$log_file"
    echo "Usage: $0 <search_directory> [--single]" | tee -a "$log_file"
    echo "Options:" | tee -a "$log_file"
    echo "  --single    最初の1件のみ実行" | tee -a "$log_file"
    exit 1
fi

# ログファイルの初期化
{
    echo "実行日時: $(date)"
    echo "実行モード: $([ "$single_mode" = true ] && echo '単件実行' || echo '全件実行')"
    echo "検索開始ディレクトリ: $search_dir"
    echo "----------------------------------------"
} | tee "$log_file"

# 実行するWPコマンドを関数化
execute_wp_commands() {
    local wp_dir=$1
    local current_domain=$(basename "$wp_dir")

    # カレントディレクトリに移動
    cd "$wp_dir"

    # WordPress管理者メールアドレスの更新
    current_admin_email=$(wp option get admin_email)
    if [ "$current_admin_email" = "$old_admin_email" ]; then
        if wp option update admin_email "$new_admin_email" --quiet; then
            {
                echo "Success: $current_domain (管理者メールアドレス)"
                echo "更新前管理者メールアドレス: $old_admin_email"
                echo "更新後管理者メールアドレス: $new_admin_email"
                echo "----------------------------------------"
            } | tee -a "$log_file"
        fi
    fi

    # 各メールアドレスに対して処理を実行
    for old_email in "${!email_mapping[@]}"; do
        new_email="${email_mapping[$old_email]}"

        # ユーザー検索とJSONパース
        user_info=$(wp user list --search="$old_email" --fields=ID,user_email,roles --format=json)
        if [ $? -eq 0 ] && [ "$(echo "$user_info" | grep -c "$old_email")" -gt 0 ]; then
            # JSONから情報を抽出
            user_id=$(echo "$user_info" | sed 's/.*"ID":\([0-9]*\).*/\1/')
            user_roles=$(echo "$user_info" | sed 's/.*"roles":"\([^"]*\)".*/\1/')

            if [ -n "$user_id" ]; then
                # メールアドレス更新
                if wp user update "$user_id" --user_email="$new_email" --quiet; then
                    {
                        echo "Success: $current_domain"
                        echo "ユーザー権限: $user_roles"
                        echo "更新前メールアドレス: $old_email"
                        echo "更新後メールアドレス: $new_email"
                        echo "----------------------------------------"
                    } | tee -a "$log_file"
                fi
            fi
        fi
    done
}

# メイン処理
echo "検索開始..." | tee -a "$log_file"
if [ "$single_mode" = true ]; then
    echo "単件実行モード: 最初の1件のみ処理します" | tee -a "$log_file"
    # 絶対パスで検索
    first_wp=$(cd "$search_dir" && find "$(pwd)" -type f -name "wp-config.php" | head -n 1)
    if [ -n "$first_wp" ]; then
        wp_dir=$(dirname "$first_wp")
        execute_wp_commands "$wp_dir"
    else
        echo "WordPressインストールが見つかりませんでした" | tee -a "$log_file"
    fi
else
    echo "全件実行モード" | tee -a "$log_file"
    # 再帰的にwp-config.phpが存在するディレクトリを検索(絶対パスで)
    cd "$search_dir" && find "$(pwd)" -type f -name "wp-config.php" | while read wp_config; do
        # wp-config.phpが存在するディレクトリを取得
        wp_dir=$(dirname "$wp_config")

        # WPコマンドを実行する関数を呼び出し
        execute_wp_commands "$wp_dir"
    done
fi

echo "----------------------------------------" | tee -a "$log_file"
echo "処理が完了しました。結果は $log_file に保存されています。" | tee -a "$log_file"

単件実行モードと全件実行モードを備えています。
単件は指定のディレクトリのうち、最初の WordPress サイトのみを対象として単サイトのみ処理を行います。テスト的にひとつのサイトで実行して確認し、問題なければ全件実行を行うのが良いかと思います。

changeEmailSetting.sh
のようにファイルを保存した場合、

chmod 700 changeEmailSetting.sh
./changeEmailSetting.sh targetPath --single

のようにして単件モードで実行します。
全件モードは

./changeEmailSetting.sh targetPath

です。

実行が終わると、同ディレクトリに email_change_log.txt が設置され、動作中のものとほぼ同じ内容がログとして記録されます。

email_mapping
ここで検索対象のメールアドレスと、変更したいメールアドレスを設定します。
ユーザーで設定してあるメールアドレスを検索し、マッチしたら、それを指定のメールアドレスに変更します。
またWordPress管理者のメールアドレスも変更します。

このスクリプトは業務上必要になったので作成したのですが、備忘録がわりに、またこれをベースにカスタマイズしやすいかと思って残しておきます

Discussion