こんにちは。GMOペパボ株式会社の西田です。
WordPressは、非常に人気のあるコンテンツ管理システムの1つで、世界中のウェブサイトで利用されています。この記事では「アップデートしたらサイトが壊れる」という一風変わったプラグインを紹介しつつ、それを実現するWordPressの仕組みについて解説したいと思います。
この記事は GMOインターネットグループ Advent Calendar 2024 4日目の記事です。
目次
アップデートしたらサイトが壊れるプラグイン
今回実装したプラグインはこちらです。
https://github.com/kinosuke01/wp-update-breaker
これをWordPress製のサイトにインストールすると、コントロールパネルにアップデート通知が出ます。そこで「更新」をクリックしてプラグインをアップデートすると。

以下のように、サイトの表示が著しく崩れます。

なぜ作ったのか?
ある社内業務にて「WordPressのプラグインをアップデートしたらサイトが壊れた」を再現する必要があったためです。
WordPressのプラグインアップデートはワンクリックで済むことが多いですが、サイトが壊れたときの復旧が大変という側面があります。なので、WordPressを運用管理している企業の社員研修で、サイトが壊れたときの訓練用途としても使えるかもしれません。
どのように設計したのか?
一般的にWordPressプラグインのアップデートは以下のような流れで実現されます。

このアップデートを仕組みに載るには、wordpress.orgのプラグイン登録審査が必要になります。しかし、社内業務のためだけに、WordPress公式からの承認を得る必要性については検討する必要がありました。
そこで今回は「このプラグインに関してはアップデートのフローが変わるように、プラグイン自体で拡張する」というアプローチを取りました。プラグインのホスト先にはGithubPagesを用いることで、コストもかからないようにしました。

あとは、新しいバージョンのプラグインにのみ、レイアウトを崩すCSSを仕込んでおけば、「アップデートしたらサイトが壊れる」プラグインが完成します。
どのように実装したのか?
ここから実装したコードを見ていきますが、その前にWordPressのフックについて説明をしたいと思います。WordPressはブラウザからのアクセスを契機に複数の処理が実行され、htmlとしてレスポンスを返します。この複数の処理には、それぞれ「フック」が設けられており、プラグインは任意のフックに対して関数を追加することで、WordPressの挙動を拡張することが可能になります。

プラグインアップデートに関する実装は、以下のようになりました。
<?php
if ( ! function_exists( 'get_plugin_data' ) ) {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
}
class WP_Update_Breaker_Updater {
private $plugin_data;
private $api_url;
private $plugin_slug;
private $version;
public function __construct() {
$plugin_file = WP_PLUGIN_DIR . '/wp-update-breaker/wp-update-breaker.php';
$plugin_data = get_plugin_data($plugin_file);
$this->plugin_slug = strtolower(str_replace(' ', '-', $plugin_data['Name']));
$this->version = $plugin_data['Version'];
$this->api_url = $plugin_data['UpdateURI'];
add_filter('site_transient_update_plugins', [$this, 'check_for_plugin_update']);
add_filter('plugins_api', [$this, 'plugin_info'], 10, 3);
}
public function check_for_plugin_update($transient) {
if (empty($transient->checked)) {
return $transient;
}
// Check cache
$cache_key = 'wp_update_breaker_api_response';
$api_response = get_site_transient($cache_key);
if ($api_response === false) {
// Only request API if cache does not exist
$response = wp_remote_get($this->api_url);
if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
$api_response = json_decode(wp_remote_retrieve_body($response), true);
// Save cache for 24 hours
set_site_transient($cache_key, $api_response, 24 * HOUR_IN_SECONDS);
}
}
// Check update information if API response is valid
if ($api_response) {
if (version_compare($this->version, $api_response['version'], '<')) {
$plugin_data = [
'slug' => $this->plugin_slug,
'new_version' => $api_response['version'],
'package' => $api_response['download_link'],
];
$transient->response[$this->plugin_slug . '/' . $this->plugin_slug . '.php'] = (object) $plugin_data;
}
}
return $transient;
}
// Provide detailed information about the plugin
public function plugin_info($false, $action, $args) {
if ($action !== 'plugin_information' || $args->slug !== $this->plugin_slug) {
return false;
}
// Retrieve detailed plugin information from the API
$response = wp_remote_get($this->api_url);
if (is_wp_error($response)) {
return false;
}
$api_response = json_decode(wp_remote_retrieve_body($response), true);
if (!$api_response) {
return false;
}
// Return detailed plugin information
return (object) [
'name' => $api_response['name'],
'slug' => $api_response['slug'],
'version' => $api_response['version'],
'author' => $api_response['author'],
'download_link' => $api_response['download_link'],
'sections' => $api_response['sections'],
];
}
}
// Start update check when the plugin is loaded
new WP_Update_Breaker_Updater();ポイントとなるフックは「plugins_api 」と「site_transient_update_plugins」の2点です。順に見ていきましょう。
plugins_api
WordPressには、引数で渡したプラグインの情報をwordpress.org APIから取得するplugin_apiというフックと同じ名前の関数があります。これは主にプラグインの情報を管理ページで表示する目的で使われているものです。plugin_apiフックは、plugins_api関数の中で呼ばれていて、処理を上書きできるものになります。なおこの挙動は、WordPress本体のソースコードに丁寧にコメントで記載されています。
今回の実装では、自作したプラグイン名が引数でわたってきたときだけ、自身が準備したサイトにアクセスしてプラグイン情報を取得するように変更しています。

site_transient_update_plugins
このフックについて説明する前に、WordPressのtransientというキャッシュ機構について説明します。transientは、外部のAPIから取得したデータをキャッシュすることにも使用される機構で、プラグインのアップデートの有無は、 update_plugins をキーとした transient に保持されています。このtransientは get_site_transient (‘update_plugins’) のような実装で値を取り出すことが可能で、WordPressは随所でこれを呼び出して、プラグインアップデートの有り無しを判定しています。
さて、site_transient_update_pluginsフックですが、get_site_transient (‘update_plugins’)の結果に対して、変更や追記削除ができるフィルターとして機能するものになります。WordPressのソースコードの該当箇所を読むことでその挙動が把握できます。
今回の実装では、キャッシュされているプラグインアップデート情報を取り出したときに、自作プラグインのアップデート情報を追記することで、WordPressにアップデート情報を与えています。

ここまで記載したところで疑問を持った方もいらっしゃるかと思います。
「プラグインのアップデートの有無を、update_plugins をキーとしたtransient に保持しているといったが、このキャッシュを生成するときに、自作プラグインの情報を含むようにしたらよいのでは?」
その疑問はごもっともです。しかし残念ながら、このアプローチを取ることはできませんでした。キャッシュに保存する処理は wp_update_plugins という関数で実行されているのですが、そこにはhookの実装がないためです。そこでハック気味な使い方にはなるのですが、site_transient_update_plugins フックを活用したという経緯になります。
まとめ
「アップデートしたらサイトが壊れる」という一風変わったWordPressプラグインの紹介をしました。さらに、そのプラグインを紐解くことで、WordPressのフックの仕組みについても解説しました。この記事が、WordPressをより深く活用していきたい方々の一助になれば幸いです。
ブログの著者欄
採用情報
関連記事
KEYWORD
CATEGORY
-
技術情報(596)
-
イベント(237)
-
カルチャー(60)
-
デザイン(70)
TAG
- 5G
- AI
- AI TALK
- AI 機械学習強化学習
- AI/機械学習
- AIエージェント
- AIコーディング
- AI人財
- AI駆動
- Behind the Scenes
- BIT VALLEY
- blockchain
- ChatGPT
- ChatGPT Team
- Claude Team
- cloudflare
- cloudnative
- CNDO
- CNDT
- CODE BLUE
- ConoHa
- ConoHa VPS
- CSS
- CTF
- Designship
- developer
- DevRel
- DevSecOpsThon
- Docker
- DTF
- Engineering Journey
- expert
- EXPERT CROSS
- GMO AI&ロボティクス商事
- GMO AIR
- GMO DESIGN AWARD
- GMO Developers Day
- GMO Developers Night
- GMO Flatt Security
- GMO GPUクラウド
- GMO Hacking Night
- GMO kitaQ
- GMO SONIC
- GMOアドパートナーズ
- GMOアドマーケティング
- GMOインターネット
- GMOインターネットグループ
- GMOインターネットグループ陸上部
- GMOグローバルサイン
- GMOコネクト
- GMOサイバーセキュリティ byイエラエ
- GMOデジキッズ
- GMOブランドセキュリティ
- GMOペイメントゲートウェイ
- GMOペパボ
- GMOメディア
- GMO大会議
- GMO天秤AI
- Go
- GPUクラウド
- GTB
- Hack-1グランプリ
- IETF
- iOS
- IoT
- ISUCON
- Japan Drone
- JapanDrone
- Java
- JJUG
- K8s
- Kaigi on Rails
- Kids VALLEY
- LLM
- MCP
- MetaMask
- MySQL
- NFT
- OpenStack
- Perl
- PHP
- PHPcon
- PHPerKaigi
- Python
- RFC
- RPA
- Ruby
- SECCON
- Selenium
- Spectrum Tokyo Meetup
- splunk
- SRE
- Takumi byGMO
- Terraform
- TypeScript
- UI/UX
- vibe
- VPN
- VS Code
- XSS
- ZTNA
- アドベントカレンダー
- インターンシップ
- インハウス
- お名前.com
- クリエイターインタビュー
- クリエイティブ
- コンテナ
- サイバーセキュリティ
- サマーインターン
- スクラム
- スペシャリスト
- セキュリティ
- ソフトウェアサプライチェーン
- チームビルディング
- デザイン
- ネットのセキュリティもGMO
- ハーネスエンジニアリング
- バックエンド
- ヒューマノイド
- ヒューマノイドロボット
- プログラミング教育
- ブロックチェーン
- フロントエンド
- ペアリング暗号
- ゆめみらいワーク
- リモートワーク
- レンタルサーバー
- ロボット
- 京大ミートアップ
- 国際ロボット展
- 国際標準化
- 基礎
- 多拠点開発
- 宮崎オフィス
- 応用
- 技育プロジェクト
- 技術広報
- 技術書典
- 新卒
- 新卒研修
- 映像
- 映像クリエイター
- 暗号
- 業務効率化
- 機械学習
- 決済
- 生成AI
- 耐量子暗号
- 脆弱性診断
- 開発者
PICKUP
-
【EXPERT CROSS #2】暗号技術の可能性を未来につなぐ、「暗号のおねぇさん」の歩み(後編)
技術情報
-
【EXPERT CROSS #2】「暗号のおねぇさん」が国際標準化の場で残していく、インターネットへの「爪痕」(前編)
技術情報
-
デザインカンファレンス「Yoitoi Summit 2026」をGMOYours・フクラスにて開催!
デザイン
-
攻撃者優位の時代に問われる「使命感」 GMO Flatt Security&GMOサイバーセキュリティ byイエラエが描く、AI時代のセキュリティ構想(後編)ーEngineering Journey
技術情報
-
頂上と裾野の両方から「底上げ」 GMO Flatt Security&GMO サイバーセキュリティ byイエラエが支える、日本のサイバーセキュリティ(前編)ーEngineering Journey
技術情報
-
【開催レポート】八幡小学校 社会科見学 at GMO kitaQ
カルチャー