プロジェクト

全般

プロフィール

操作

Wiki » 履歴 » リビジョン 1

リビジョン 1/4 | 次 »
廣瀬 僚一, 2026/06/01 17:05


MainWP 更新履歴 Redmine 自動連携

概要

MainWP でプラグイン・テーマ・WordPress 本体を更新した際に、Redmine へ自動でチケットを作成する仕組み。

  • 対象サーバー: MainWP ダッシュボードサーバー
  • 方式: MU-Plugins に WordPress フックを記述し、Redmine REST API へ直接 POST
  • WP Webhooks プラグインは不使用(Basic 認証・IP 制限の影響を避けるため)

ファイル構成

/wp-content/mu-plugins/mainwp-webhook.php   ← メインファイル
/wp-content/mainwp-redmine-debug.log        ← デバッグログ(確認後削除可)

設置ファイル

/wp-content/mu-plugins/mainwp-webhook.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} / {$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 );
}, 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_infowpversion
WP 本体更新前バージョン $website->wp_upgradescurrent
WP 本体更新後バージョン $website->wp_upgradesnew

調査過程でわかったこと

  • 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 する構成が必要

デバッグログの確認

cat /var/www/html/wp-content/mainwp-redmine-debug.log

status=201 であれば Redmine へのチケット作成成功。確認後はログ出力コードを削除してよい。

廣瀬 僚一 さんが5日前に更新 · 4件の履歴