プロジェクト

全般

プロフィール

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 
     ); 
 } 
 ``` 

 --- 

 ## アップデート手順 設定値 

 | 定数 | 説明 | 
 ![](%E3%82%B5%E3%82%A4%E3%83%88%E3%82%A2%E3%83%83%E3%83%95%E3%82%9A%E3%83%86%E3%82%99%E3%83%BC%E3%83%881.png) |------|------| 
 | `REDMINE_URL` | Redmine の URL(末尾スラッシュなし) | 
 | `REDMINE_API_KEY` | Redmine の個人 API キー(マイアカウント画面で確認) | 
 | `REDMINE_PROJECT` | Redmine のプロジェクト識別子 | 

 ![](%E3%82%B5%E3%82%A4%E3%83%88%E3%82%A2%E3%83%83%E3%83%95%E3%82%9A%E3%83%86%E3%82%99%E3%83%BC%E3%83%882.png) ### Redmine チケット設定 

 ![](%E3%82%B5%E3%82%A4%E3%83%88%E3%82%A2%E3%83%83%E3%83%95%E3%82%9A%E3%83%86%E3%82%99%E3%83%BC%E3%83%883.png) | 項目 | 値 | 説明 | 
 |------|----|------| 
 | `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 へのチケット作成成功。確認後はログ出力コードを削除してよい。