Wiki » 履歴 » リビジョン 2
リビジョン 1 (廣瀬 僚一, 2026/06/01 17:05) → リビジョン 2/4 (廣瀬 僚一, 2026/06/01 17:19)
# サイトアップデート方法 MainWP 更新履歴 Redmine 自動連携 以下のサイトにアクセス ## 概要 MainWP でプラグイン・テーマ・WordPress 本体を更新した際に、Redmine へ自動でチケットを作成する仕組み。 - **対象サーバー**: MainWP ダッシュボードサーバー https://manage.ooda.biz/wp-admin - **方式**: MU-Plugins に WordPress フックを記述し、Redmine REST API へ直接 POST - **WP Webhooks プラグインは不使用**(Basic 認証・IP 制限の影響を避けるため) basic認証:cld --- ## ファイル構成 ``` /wp-content/mu-plugins/mainwp-webhook.php ← メインファイル /wp-content/mainwp-redmine-debug.log ← デバッグログ(確認後削除可) ``` --- ## 設置ファイル ### `/wp-content/mu-plugins/mainwp-webhook.php` ```php <?php /** * MainWP更新後にRedmineへ直接通知 * 設置場所: /wp-content/mu-plugins/mainwp-webhook.php */ define( 'REDMINE_URL', 'https://your-redmine.example.com' ); define( 'REDMINE_API_KEY', 'YOUR_REDMINE_API_KEY' ); define( 'REDMINE_PROJECT', 'wordpress-updates' ); // ===== プラグイン・テーマ・翻訳の更新後 ===== add_action( 'mainwp_install_update_actions', function( $website, $action, $data, $type ) { if ( 'updated' !== $action ) return; if ( ! in_array( $type, array( 'plugin', 'theme', 'trans' ) ) ) return; $type_label = [ 'plugin' => 'プラグイン', 'theme' => 'テーマ', 'trans' => '翻訳', ][ $type ] ?? $type; $site = $website->url ?? '不明'; $datetime = ( new DateTime( 'now', new DateTimeZone( 'Asia/Tokyo' ) ) )->format( 'Y-m-d H:i:s' ); // WPバージョン取得 $site_info = json_decode( $website->site_info ?? '{}', true ); $wp_version = $site_info['wpversion'] ?? '不明'; // 更新内容を取得 $updated_data = isset( $data['updated_data'] ) ? $data['updated_data'] : array(); $details = ''; if ( is_array( $updated_data ) && ! empty( $updated_data ) ) { foreach ( $updated_data as $item ) { $name = $item['name'] ?? $item['slug'] ?? '不明'; $old = $item['old_version'] ?? '?'; $new = $item['version'] ?? '?'; $details .= "- {$name}: {$old} → {$new}\n"; } } if ( empty( $details ) ) return; $subject = "[WP更新] {$site} / cld {$type_label}"; $body = "## 更新情報\n\n" . "- **サイト:** {$site}\n" . "- **種別:** {$type_label}\n" . "- **WPバージョン:** {$wp_version}\n" . "- **作業日時:** {$datetime}\n\n" . "## 更新内容\n\n{$details}"; mainwp_post_to_redmine( $subject, $body ); ※IP制限かけています。クリアデザイン社内からのアクセス以外は拒否 }, 10, 4 ); // ===== WordPress本体の更新後 ===== add_action( 'mainwp_after_wp_update', function( $information, $website ) { $site = $website->url ?? '不明'; $datetime = ( new DateTime( 'now', new DateTimeZone( 'Asia/Tokyo' ) ) )->format( 'Y-m-d H:i:s' ); // wp_upgradesから更新前後バージョンを取得 $wp_upgrades = json_decode( $website->wp_upgrades ?? '{}', true ); $old = $wp_upgrades['current'] ?? $information['old_version'] ?? '?'; $new = $wp_upgrades['new'] ?? $information['new_version'] ?? '?'; $subject = "[WP更新] {$site} / WordPress本体"; $body = "## 更新情報\n\n" . "- **サイト:** {$site}\n" . "- **種別:** WordPress本体\n" . "- **更新前:** {$old}\n" . "- **更新後:** {$new}\n" . "- **作業日時:** {$datetime}\n"; mainwp_post_to_redmine( $subject, $body ); }, 10, 2 ); // ===== Redmine API へ直接POST ===== function mainwp_post_to_redmine( $subject, $body ) { $data = [ 'issue' => [ 'project_id' => REDMINE_PROJECT, 'subject' => $subject, 'description' => $body, 'tracker_id' => 2, 'status_id' => 5, // 終了 'done_ratio' => 100, ] ]; $ch = curl_init( REDMINE_URL . '/issues.json' ); curl_setopt_array( $ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode( $data ), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Redmine-API-Key: ' . REDMINE_API_KEY, ], CURLOPT_TIMEOUT => 15, ] ); $response = curl_exec( $ch ); $status = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); curl_close( $ch ); // デバッグログ(確認後削除してOK) file_put_contents( WP_CONTENT_DIR . '/mainwp-redmine-debug.log', date('Y-m-d H:i:s') . " status={$status} response={$response}\n", FILE_APPEND ); } ``` --- ## アップデート手順 設定値 | 定数 | 説明 |  |------|------| | `REDMINE_URL` | Redmine の URL(末尾スラッシュなし) | | `REDMINE_API_KEY` | Redmine の個人 API キー(マイアカウント画面で確認) | | `REDMINE_PROJECT` | Redmine のプロジェクト識別子 |  ### Redmine チケット設定  | 項目 | 値 | 説明 | |------|----|------| | `tracker_id` | `2` | トラッカー ID(環境に合わせて変更) | | `status_id` | `5` | 終了ステータス | | `done_ratio` | `100` | 進捗率 100% | --- ## 動作する WordPress フック | フック名 | タイミング | 引数 | |----------|-----------|------| | `mainwp_install_update_actions` | プラグイン・テーマ・翻訳の更新後 | `$website, $action, $data, $type` | | `mainwp_after_wp_update` | WordPress 本体の更新後 | `$information, $website` | ### バージョン情報の取得元 | 情報 | 取得元 | |------|--------| | プラグイン更新前バージョン | `$data['updated_data'][]['old_version']` | | プラグイン更新後バージョン | `$data['updated_data'][]['version']` | | WP バージョン | `$website->site_info` の `wpversion` | | WP 本体更新前バージョン | `$website->wp_upgrades` の `current` | | WP 本体更新後バージョン | `$website->wp_upgrades` の `new` | --- ## 調査過程でわかったこと - `mainwp_after_plugin_theme_translation_update` フックは存在するが、**引数 `$information` が空で渡ってくる**ため使用不可 - バージョン情報は `$information` ではなく `$data['updated_data']` に格納されている - `mainwp_install_update_actions` フックが正しいバージョン情報を持つ唯一のフック - WP Webhooks プラグインの無料版では `WordPress hook fired` が使えない(Pro 限定) - Basic 認証・IP 制限がかかった環境では `wp_remote_post` による自サーバーへの HTTP リクエストが 401 で弾かれるため、中継 PHP ファイルを経由せず Redmine API へ直接 POST する構成が必要 --- ## デバッグログの確認 ```bash cat /var/www/html/wp-content/mainwp-redmine-debug.log ``` `status=201` であれば Redmine へのチケット作成成功。確認後はログ出力コードを削除してよい。