
Gravity Forms PDFで合計金額が倍になる原因と修正方法
Gravity Forms で作成したフォームから PDF を出力するプラグイン「PDF Invoices for Gravity Forms」を使っていて、テンプレート内で get_total() メソッドを複数回呼び出すと合計金額が呼び出し回数に応じて倍々に膨らんでしまう現象は、静的変数 self::$total が各呼び出しのたびに加算され続ける設計になっているのが原因だ。直すにはヘルパークラスを子テーマから拡張し、get_total() の内部で毎回リセットして再計算させる変更を加える。
合計金額が倍になる現象はどのようなときに起こるのか

たとえば請求書のテンプレートに「小計」と「総合計」を別々の位置に表示したい場合、PDF_Invoices_For_GravityForms_Helpers::get_total() を2回呼ぶことになる。ところがイベント参加登録や商品注文フォームなどで実際にこの処理を通すと、2回目の呼び出し時には1回目に加算された値にさらに同じ計算が上乗せされ、本来 10,000 円のところが 20,000 円になるといった不具合が起きる。
なぜ get_total() を複数回呼ぶと値が積み上がるのか

問題の根本は class-pcafe-gfpi-helpers.php ファイル内の get_total() メソッドにある。このメソッドは静的変数 self::$total を使い、内部で次のように加算している。
public static function get_total(){
self::$total += self::get_subtotal();
self::$total += self::$shipping;
return self::$total;
}静的変数はリクエストの間ずっと値を保持するため、同じ処理中に get_total() が呼ばれるたびに前回の合計に小計と送料が足されていく。2回呼べば「小計 + 送料」が2倍になり、3回なら3倍になる。通常、こうした合計取得メソッドは毎回ゼロから計算し直すべきであり、内部で継ぎ足す構造は意図したものでない可能性が高い。
変数 self::$total が 10,500 を保持したまま
2回目呼び出し: 変数をリセット後 再計算 → total=10,500
上の図のように、2回目で合計が倍になる。特に「小計」「消費税」「総合計」など複数の金額を PDF テンプレートに配置する場合にこの問題が顕在化しやすい。
get_total() 修正の基本的な考え方

プラグイン本体のファイルを直接編集してしまうと、アップデートのたびに修正が上書きされて消える。そのため子テーマの functions.php を使い、プラグインのヘルパークラスを拡張した独自クラスを用意する方法をとる。拡張クラスでは get_total() メソッドをオーバーライドし、計算前に self::$total を強制的に 0 にリセットしてから小計と送料を加算する。
子テーマでヘルパークラスを拡張して修正する手順

独自ヘルパークラスを作成する
まず子テーマの functions.php に、プラグインのヘルパークラスを継承したクラスを定義する。子テーマがない場合は、Code Snippets プラグインを使うか、wp-content/themes/(現在のテーマ)/functions.php に追記する形でもよい。コードは以下のようになる。
class Custom_GFPI_Helpers extends PDF_Invoices_For_GravityForms_Helpers {
public static function get_total() {
self::$total = 0; // 計算前に必ずリセットする
self::$total += self::get_subtotal();
self::$total += self::$shipping;
return self::$total;
}
}テンプレート内でカスタムクラスを呼び出す
拡張クラスを作っただけでは既存のテンプレートには反映されない。PDF テンプレート内で PDF_Invoices_For_GravityForms_Helpers::get_total() を呼んでいる箇所を、先ほど定義した Custom_GFPI_Helpers::get_total() に置き換える。
テンプレートファイルは多くの場合 wp-content/uploads/pdf-invoices-for-gravity-forms/templates/ 以下にカスタムテンプレートとして配置されている。該当の .php ファイルを開き、以下のように書き換える。
<?php
// 修正前
// echo PDF_Invoices_For_GravityForms_Helpers::get_total();
// 修正後
echo Custom_GFPI_Helpers::get_total();
?>これでテンプレート内のどの場所から呼び出しても、毎回リセット後に計算が走るため合計が積み上がることはなくなる。
変更後にキャッシュと動作を確認する
変更を加えたあとは、必ず PDF を生成し直して合計金額が正しいか確認する。Gravity Forms のエントリーから「PDFを表示」ボタンで実際の請求書を開き、同じ合計が要求された位置すべてに正しく表示されているかをチェックする。サイトでキャッシュプラグインを使っている場合は、キャッシュを全削除してから確認すると確実だ。
よくある質問
プラグイン本体のファイルを直接修正してもよいか
推奨しない。プラグインがアップデートされるたびに修正が上書きされ、その都度同じ変更を加えなければならなくなる。子テーマや Code Snippets を使う方法なら、アップデートに影響されず継続的に動作する。
他の金額表示(税額や値引き額)も倍増している場合の対処は
同じヘルパークラス内で定義されている get_tax() や get_discount() にも同様の静的変数の加算構造がある可能性が高い。それらのメソッドも同じ要領でカスタムクラス内にオーバーライドし、内部で該当の静的変数をリセットする処理を加えるとよい。
子テーマを使っていない場合でも対応できるか
子テーマがない場合は Code Snippets プラグインが便利だ。スニペットとしてクラス定義を追加すれば、テーマに依存せず同じ修正を適用できる。テンプレートの書き換えは手動で行う必要があるが、クラスの読み込み自体はスニペット経由で問題なく動作する。
修正後に PDF が真っ白になる場合の確認点は
クラス名やメソッド名のスペルミス、オートローダーがカスタムクラスを見つけられていないケースが考えられる。まず PHP のエラーログを確認し、クラスが見つからないという趣旨の致命的エラーが出ていないか調べる。出ている場合はクラス定義の記述ミスか、定義のタイミングが早すぎる可能性があるため、init フックなどで定義を遅らせると改善することがある。
この記事のポイント
get_total()の多重呼び出しで合計が倍増するのは、静的変数self::$totalが加算され続ける設計のため- プラグイン本体を直接修正せず、子テーマの functions.php でカスタムクラスを定義する
- カスタムクラス内で
get_total()をオーバーライドし、計算前にself::$total = 0;でリセットする - PDF テンプレート側の呼び出しをカスタムクラスに差し替え、キャッシュ削除後に動作確認する
- 同様の構造を持つ
get_tax()やget_discount()も併せて修正を検討する

・ Reddit、Stack Overflow、WordPress.org フォーラムを日々巡回し、現場の悩みを拾い上げて記事化
・ WordPress、WooCommerce、Next.js などモダンWeb制作領域のトラブルシューティングが専門
・ 「検索しても答えが見つからなかった」を一つでも減らすことが目標
・ エラーメッセージから根本原因にたどり着く粘り強い調査が得意
・ 初心者がつまずきやすい箇所を先回りで解決する記事作りを心がけている

WooCommerce 11.0でget_queried_object()がショップページでもWP_Postを返す改善
WooCommerce 11.0より、ショップページで get_queried_object() を呼び出した際の戻り値の型が WP_Post_Type から WP_Post に統一される。これまでショップページだけが例外的に商品の投稿タイプオブジェクトを返していたが、今回の変更でWordPress標準の挙動と一貫性が保たれることになる。
この修正は、WooCommerceが内部的に管理するクエリの取り扱いをWordPressコアに合わせるもので、テーマやプラグインの開発者が「ショップページかどうか」を意識せずに get_queried_object() を扱えるようにする狙いがある。フロントページにショップページを設定している場合も同様の挙動となる。
WooCommerce 11.0のショップページ改善

get_queried_object() は現在のWordPressクエリに対応するオブジェクトを取得する標準関数だ。通常の固定ページや投稿ページでは WP_Post オブジェクトを返すが、これまでのWooCommerceではショップページに限り WP_Post_Type オブジェクト、つまり商品(product)の投稿タイプ情報を返していた。この不一致が開発者にとって混乱の元となっていた。
WooCommerce Developer Blogの説明によれば、ショップページで get_queried_object() を呼び出して「商品アーカイブであること」を判定するコードを書いていた場合、この変更の影響を受ける可能性がある。逆に言えば、今回の修正で is_shop() のような条件分岐タグと get_queried_object() の戻り値の関係が整理され、より直感的なコードが書けるようになる。
この変更の背景には、WordPressの「投稿ページ」設定と同様にショップページでも WP_Post を返すべき、という設計上の判断がある。WooCommerce 11.0ではこの長年の不一致が解消され、より予測しやすいAPIへと改善された。
影響を受けるコードの判断方法

自作のテーマやプラグインでショップページのクエリオブジェクトを参照している場合、以下のいずれかの関数やプロパティを使用していないか確認する必要がある。
get_queried_object()を呼び出しているget_queried_object_id()を呼び出している$query->queried_objectに直接アクセスしている$query->queried_object_idに直接アクセスしている
これらのコードがショップページ上で実行され、戻り値として WP_Post_Type オブジェクトを期待しているなら、WooCommerce 11.0へのアップデート後に動作が変わる可能性が高い。とくに、queried_object->labels->name などのプロパティに依存している場合は要注意だ。
Before / After コードの比較
具体的なコードの違いを見てみよう。以下はショップページでの get_queried_object() の戻り値の変化を示している。
// WooCommerce 10.x まで Shopページのみ例外
get_queried_object(); // → WP_Post_Type
get_post_type_object( 'product' ); // → WP_Post_Type
// その他の固定ページ
get_queried_object(); // → WP_Post
get_post_type_object( 'product' ); // → WP_Post_Type// WooCommerce 11.0 以降 Shopページも含めて統一
get_queried_object(); // → WP_Post
get_post_type_object( 'product' ); // → WP_Post_Typeこの変更の影響を受けないケース
次のような状況では、WooCommerce 11.0の変更による影響はなく、既存のコードはそのまま動作する。
- 単一の商品ページ(
single-product)では引き続き商品のWP_Postオブジェクトが返る - 商品カテゴリやタグ、ブランド、属性などのタクソノミーページでは
WP_Termオブジェクトが返る - その他の投稿タイプアーカイブや個別ページはもともと変更の対象外
is_shop()やis_archive()、is_post_type_archive( 'product' )といった条件分岐関数の挙動は従来どおり変わらない
開発者が取るべき具体的な対応

もし既存のコードがショップページで get_queried_object() の戻り値を WP_Post_Type として扱っている場合、WooCommerce 11.0へのアップデートに備えて改修が必要だ。修正の基本方針は「オブジェクトの型をチェックしてからプロパティにアクセスする」ことにある。
商品の投稿タイプ情報を取得する推奨方法
商品の WP_Post_Type オブジェクトが必要な場合は、get_post_type_object() を使うのが安全で推奨される方法だ。この関数はWooCommerceのバージョンに関係なく常に正しいオブジェクトを返す。
$product_post_type = get_post_type_object( 'product' );
if ( $product_post_type instanceof WP_Post_Type ) {
// 商品のWP_Post_Typeオブジェクトは
// get_post_type_object() から引き続き取得できる
$singular_name = $product_post_type->labels->singular_name;
}ショップページのWP_Post情報を扱うコード例
ショップページ自体の情報(ページタイトルやスラッグなど)を取得したい場合は、WooCommerce 11.0以降は get_queried_object() から直接 WP_Post としてアクセスできるようになる。以下はその典型的な使用例だ。
$shop_page = get_queried_object();
if ( $shop_page instanceof WP_Post ) {
// WooCommerce 11.0以降、ショップページでも
// WP_Postとして扱える
$shop_title = $shop_page->post_title;
$shop_slug = $shop_page->post_name;
}get_queried_object() / $query->queried_object を使っている箇所を特定するWP_Post_Type として使っているか確認する( instanceof や型チェックをしていない場合)get_post_type_object( 'product' ) で商品の投稿タイプ情報を個別に取得し、既存コードを書き換える重要なのは、get_queried_object() の戻り値に依存した条件分岐を書く前に、必ず instanceof でオブジェクトの型をチェックする習慣をつけることだ。これにより、WooCommerceの将来のアップデートや他のプラグインとの競合にも強いコードになる。
この記事のポイント
- WooCommerce 11.0ではショップページの
get_queried_object()がWP_Postを返すように統一される - 商品の投稿タイプ情報が欲しい場合は
get_post_type_object( 'product' )を使用する is_shop()などの条件分岐関数の挙動は変わらないため、ページ判定ロジックの修正は不要- 影響を受けるコードは、おもにショップページでクエリオブジェクトのプロパティに直接アクセスしている箇所
- アップデート前に
instanceofによる型チェックを追加し、テスト環境で検証するのが安全な移行手順

・ 複数業界における17年間のデジタルビジネス開発経験
・ ウェブサイト開発のためのHTML、PHP、CSS、JavaScript等の実用的知識
・ 15ヶ国語対応の多言語SaaSの開発経験
・ 17年間にも及ぶ、Eコマース長期運営経験
・ 幅広い業界でのSEO最適化の豊富な経験

WooCommerce更新後に重大なエラーが発生した時の原因と直し方
WooCommerce 10.9.1 への更新後に「このサイトで重大なエラーが発生しました」と表示されたり、管理画面にアクセスできなくなったりした場合、対処の第一歩はサーバー側の PHP OPcache をクリアすることだ。更新中にオートローダーが古いキャッシュを参照して必要なファイルを読み込めず、致命的エラーが発生しているケースが多い。キャッシュをリセットし PHP プロセスを再起動すれば、多くの場合はそのまま復旧する。
なぜ WooCommerce 更新後に「重大なエラー」が発生するのか

このエラーの根本原因は、WooCommerce が内部で使っている Jetpack オートローダーのクラス読み込みに失敗している点にある。class-php-autoloader.php の102行目で Settings.php ファイルを要求しようとしたが、ファイルが存在しないかパスが解決できず、E_ERROR が発生している。
スタックトレースを見ると、REST API の初期化から管理画面の設定データを構築するまでの一連の処理でエラーが連鎖している。通常これは WooCommerce の更新が完了しない中途状態で発生する一時的な不具合で、新しいバージョンのコードが正しく配置された後もサーバーが古い OPcache を参照し続けるために起こる。
実際の環境は WordPress 7.0、テーマ Flatsome 3.20.7、PHP 8.3.31 と非常に新しいバージョン構成であり、各要素の互換性が原因ではなく、更新プロセスの瞬間的なファイル整合性の乱れがトリガーになっている。
オートローダー 存在しないファイルを要求 → 致命的エラー
管理画面 「このサイトで重大なエラーが発生しました」と表示
オートローダー 正しいファイルを見つけて読み込み成功
管理画面 通常通りアクセス可能に
最初に試すべき復旧手順「PHP OPcache のクリア」

管理画面にアクセスできずエラーメールだけが届いている状況では、サーバー側で PHP の OPcache をリセットするのが最も即効性のある対処だ。OPcache は PHP の実行速度を上げるためにスクリプトのコンパイル結果をメモリ上に保持する仕組みだが、プラグイン更新後はこのキャッシュが古くなり、実際には存在するファイルを「見つからない」と誤認させる。
共用サーバーで OPcache をクリアする方法
多くの国内共用サーバーでは、管理パネル(cPanel や独自パネル)の「PHP 設定」や「PHP セレクター」の中に「OPcache のリセット」ボタンが用意されている。このボタンを押すだけでサーバー側のキャッシュが即座に消去され、PHP プロセスが新しいコードを読み直す。
もし管理パネルに専用ボタンが見あたらない場合は、PHP のバージョンを一度別のバージョンに切り替えてから元に戻す操作でも OPcache がクリアされる。たとえば PHP 8.3 から 8.2 に変更し、数分後に再び 8.3 に戻すといった方法だ。この操作はサーバーの設定変更として扱われるため、内部で PHP-FPM の再起動が走り OPcache がリセットされる。
SSH が使える場合のコマンドライン操作
VPS やクラウドサーバーで SSH アクセス権があるなら、ターミナルから直接 PHP-FPM を再起動することで OPcache をクリアできる。よく使われるコマンドは以下の通りだ。
sudo systemctl restart php8.3-fpmサーバーによっては php-fpm のサービス名が異なるため、systemctl list-units | grep php で正確なサービス名を確認してから実行する。OPcache 専用の CLI コマンド opcache_reset() を直接呼ぶ方法もあるが、PHP-FPM 再起動のほうが確実で手間もかからない。
それでも直らない場合の追加手順

OPcache をクリアしても WordPress 管理画面にアクセスできない場合や、「このサイトで重大なエラーが発生しました」というメッセージが消えない場合は、手動でのファイル修復とプラグインのリセットを試す。
FTP で WooCommerce プラグインを手動再配置する
更新中の通信断やタイムアウトで一部のファイルが書き込まれなかった可能性もある。FTP クライアントでサーバーに接続し、/wp-content/plugins/woocommerce/ ディレクトリをいったん削除またはリネームし、WordPress.org からダウンロードした最新の WooCommerce 10.9.1 の ZIP を解凍してアップロードし直す。この操作でオートローダーが参照する Settings.php を含むすべてのファイルが正しく配置される。
この手順を行う前には、必ずサイト全体のバックアップを取っておくこと。WooCommerce のデータベーステーブルはプラグインファイルの差し替えでは影響を受けないが、カスタマイズが入っている場合は注意が必要だ。
管理画面にすらアクセスできない場合の緊急リセット
管理画面が完全にダウンしていて FTP しか使えない状況では、WooCommerce プラグインのフォルダ名を一時的に変更する手段が有効だ。/wp-content/plugins/woocommerce/ を woocommerce_tmp などにリネームする。WordPress は存在しないプラグインディレクトリを無効化するため、WooCommerce に依存しない管理画面の基本機能が復活する。
管理画面にログインできたら、プラグイン一覧で WooCommerce が「無効」になっていることを確認し、その後フォルダ名を元に戻してからプラグイン一覧で再有効化する。この一連の流れで、オートローダーの読み込みエラーがリセットされることが多い。
エラーを未然に防ぐための更新前チェックリスト

WooCommerce のような大規模プラグインの更新は、事前にいくつかの準備をしておくだけで致命的エラーのリスクを大幅に下げられる。
- 更新前に必ずサイト全体とデータベースのバックアップを取得する
- 可能であればステージング環境で先に更新をテストする
- 更新中はブラウザを閉じず、更新完了のメッセージが表示されるまで待つ
- 更新直後に管理画面から「設定」→「パーマリンク設定」を開き「変更を保存」を押してキャッシュをリフレッシュする
更新のタイミングも重要だ。アクセスの少ない深夜帯やメンテナンスモードを有効にした状態で行うと、万一エラーが発生してもユーザーへの影響を最小限に抑えられる。
よくある質問
WooCommerce の更新中にブラウザを閉じてしまったらどうすればいいか
更新中に切断しても、ファイルのダウンロードと展開が完了していれば問題ないことが多い。管理画面にアクセスできるならプラグイン一覧でバージョンを確認し、古いバージョンのままなら再度更新を実行する。管理画面に入れない場合は OPcache クリアか手動再配置を試す。
エラーメールに記載されたファイルが本当に存在しないのか確認する方法は
FTP でサーバーに接続し、/wp-content/plugins/woocommerce/src/Admin/API/Settings.php が実際に存在するか確認する。ファイルが存在するのにエラーが出ているなら、OPcache の問題と判断できる。存在しない場合は手動再配置が必要だ。
OPcache をクリアしてもエラーが繰り返し発生するのはなぜか
他のプラグインやテーマが WooCommerce の REST API 初期化にフックしており、競合が起きている可能性がある。すべてのプラグインを一時的に無効化し、標準テーマに切り替えてから WooCommerce のみを有効にして原因を特定する。
PHP のバージョンを上げた直後にエラーが出た場合の対処は
PHP 8.3 では一部の古いプラグインやテーマが非互換を起こす。WooCommerce 10.9.1 自体は PHP 8.3 に対応しているが、他のプラグインが同バージョンに対応しているか確認し、必要に応じて PHP 8.2 に一時的に戻して様子を見る。
エラーが表示されず画面が真っ白になるだけの場合は
「このサイトで重大なエラーが発生しました」の代わりに真っ白な画面(ホワイトスクリーン)になるのは、PHP のエラー表示が無効になっているためだ。wp-config.php に define('WP_DEBUG', true); と define('WP_DEBUG_LOG', true); を追加すると /wp-content/debug.log にエラー詳細が出力される。
この記事のポイント
- WooCommerce 更新後のオートローダーエラーは PHP OPcache のクリアでほぼ解決する
- 管理パネルの「OPcache リセット」ボタンか PHP 再起動で対処する
- 直らない場合は FTP でプラグインファイルを手動再配置する
- 緊急時は WooCommerce フォルダを一時的にリネームして管理画面に復帰する
- 更新前のバックアップとステージングテストでリスクを下げられる

・ Reddit、Stack Overflow、WordPress.org フォーラムを日々巡回し、現場の悩みを拾い上げて記事化
・ WordPress、WooCommerce、Next.js などモダンWeb制作領域のトラブルシューティングが専門
・ 「検索しても答えが見つからなかった」を一つでも減らすことが目標
・ エラーメッセージから根本原因にたどり着く粘り強い調査が得意
・ 初心者がつまずきやすい箇所を先回りで解決する記事作りを心がけている

WooCommerce処理中注文を未払いのまま請求書プラグインに連携する方法
WooCommerceで銀行振込(BACS)や後払い決済を使う場合、注文を「処理中」にした途端に、外部の請求書発行プラグインがその注文を「支払い済み」と認識してしまうことがある。この原因は、WooCommerceが処理中ステータスに遷移する際に支払い日(_date_paid)を自動で記録し、多くのプラグインがそのメタデータを支払い完了の合図として読み取るからだ。ここではこの仕組みを詳しく解説し、後払い注文を未払いのまま連携させる確実な修正方法を紹介する。
なぜ処理中になった注文が「支払い済み」扱いになるのか

WooCommerceの内部動作として、注文が「処理中(processing)」または「完了(completed)」に切り替わると、maybe_set_date_paid()というメソッドが呼ばれ、現在の日時を_postmetaテーブルの_date_paidに保存する。この動作は、クレジットカード決済など即時払いが完了した瞬間を記録するためにある。ところが銀行振込(BACS)は標準で「保留中(on-hold)」になるが、運用上「処理中」に手動変更したり、コードで処理中に固定すると、実際には入金前でも支払い日が書き込まれてしまう。
請求書発行プラグイン(WooCommerce PDF Invoicesや会計連携プラグインなど)は、通常この_date_paidをもとに「支払い済み」かどうかを判断する。さらに、WC_Orderクラスのis_paid()メソッドは内部的に「処理中」「完了」といったステータスを見てtrueを返す設計のため、_date_paidが空でも「支払い済み」と扱われるケースも多い。結果として、入金前の後払い注文が会計ソフト上で「支払い済み請求書」として取り込まれてしまうのだ。
上図のように、_date_paidの書き込みを止めるか、支払い済み判定のロジック自体を書き換えることで、請求書が正しく「未払い」で連携されるようになる。次に、具体的にどう対処すればよいかを方法別に紹介する。
支払い済み判定のメカニズムを特定する

修正に入る前に、自分が使っている請求書発行プラグインがどのタイミングで「支払い済み」と判断しているかを知っておくと無駄な試行錯誤が減る。大きく分けると以下の3パターンがあり、フィルターの効き方が変わる。
- _date_paidのメタデータを直接 get_post_meta() や$order->get_meta(‘_date_paid’) で読み取っている
- WC_Order::get_date_paid() メソッドを呼び出している(フィルターフック posible)
- WC_Order::is_paid() メソッドで判定している(ステータスベース)
多くのプラグインは最後のis_paid()や、直接メタデータを読む形をとる。get_date_paid()フィルターだけでは直らなかった場合、is_paid()の返り値を書き換えるか、そもそも_date_paid自体を保存させないアプローチが有効だ。
強制的に未払いにする3つの方法

方法1. _date_paidが記録されるのを根本から防ぐ
WooCommerceが処理中ステータスに変わったときに_date_paidをセットするのは、maybe_set_date_paid()の中で「このステータスは支払い完了とみなす」という配列に「processing」が含まれているからだ。この配列はwoocommerce_payment_complete_order_statusフィルターで変更できる。以下のコードをテーマのfunctions.phpまたはCode Snippetsプラグインで追加すれば、BACS(bank transfer)決済の注文でのみ「processing」を支払い完了ステータスから外せる。
add_filter('woocommerce_payment_complete_order_status', function($statuses, $order) {
if ($order instanceof WC_Order && 'bacs' === $order->get_payment_method()) {
$statuses = array_filter($statuses, function($s) {
return $s !== 'processing';
});
}
return $statuses;
}, 10, 2);これにより、BACSの注文が「処理中」に移行しても、WooCommerceは「これは支払い完了ステータスではない」と認識し、_date_paidを一切書き込まない。注文メモなどに残る変わったログも出ず、動作は非常にクリーンだ。結果として、請求書プラグインが_date_paidを見ている限り、未払いのままとなる。
方法2. is_paid()の返り値を上書きする
もし日付メタデータを消してもなお請求書が「支払い済み」になってしまう場合は、プラグインがWC_Order::is_paid()メソッドを使っている可能性が高い。このメソッドは内部的にwc_get_is_paid_statuses()が返すステータス配列(デフォルトでは’processing’と’completed’)と照合し、trueを返す。こちらもフィルターでBACSだけ処理中を除外できる。
add_filter('woocommerce_order_is_paid_statuses', function($statuses, $order) {
if ($order instanceof WC_Order && 'bacs' === $order->get_payment_method()) {
$statuses = array_diff($statuses, array('processing'));
}
return $statuses;
}, 10, 2);このコードを追加すると、is_paid()は見かけ上「処理中」でもfalseを返すため、請求書プラグインは「未払い」と判断する。方法1と併用すれば、_date_paidの直接読み取りもis_paid()経由の判定も両方ブロックできる。
方法3. プラグイン側のエクスポートフィルターを利用する
どうしても上記のフィルターで直らない、あるいは他プラグインとの兼ね合いで処理中ステータスを支払い完了扱いのままにしたい場合は、請求書発行プラグインが用意しているデータ書き換え用のフックを使う。たとえば、WooCommerce PDF Invoices & Packing Slips であれば wpo_wcpdf_document_data や wpo_wcpdf_invoice_data といったフィルターがある。請求書に含める「支払い済み」フラグや日付を、注文の支払い方法がBACSのときだけ空にすることで解決できる。
プラグインのフィルター一覧は開発元のドキュメントで確認する必要があるが、一般に「Paid = 1」や「paid_date」といったキーを書き換えることが多い。次のサンプルは、WooCommerce PDF Invoicesで支払い状況を未払いに戻す例だ。
add_filter('wpo_wcpdf_invoice_data', function($data, $document) {
if ($document->order instanceof WC_Order && 'bacs' === $document->order->get_payment_method()) {
$data['paid'] = 0;
$data['date_paid'] = '';
}
return $data;
}, 10, 2);なお、プラグインが読み取るフィールド名は製品によって異なるため、実際のソースコードや開発元への問い合わせで正確なキー名を調べるのが確実だ。
カスタム注文ステータスで処理中と区別する方法

根本的に「後払い専用の処理中ステータス」をWooCommerceに追加するという手もある。標準の処理中ステータスは、支払い完了後の発送準備として使われる場面が多い。これに対し、後払いは「入金確認前だが、すでに注文を受け付け、請求書を発行したい」という微妙な状態だ。そこで「後払い処理中」のようなカスタムステータスを作れば、WooCommerceの支払いロジックに干渉せず、かつ請求書プラグインも処理中ではないため誤って支払い済み扱いしなくなる。
function register_custom_order_status_invoice_processing() {
register_post_status('wc-invoice-processing', array(
'label' => '後払い処理中',
'public' => true,
'show_in_admin_status_list' => true,
'show_in_admin_all_list' => true,
'exclude_from_search' => false,
'label_count' => _n_noop('後払い処理中 (%s)', '後払い処理中 (%s)')
));
}
add_action('init', 'register_custom_order_status_invoice_processing');
add_filter('wc_order_statuses', function($order_statuses) {
$order_statuses['wc-invoice-processing'] = '後払い処理中';
return $order_statuses;
});
このステータスをBACSの注文に割り当てれば、標準の処理中ルートを通らずに済む。ただし、配送プラグインや在庫連動がこのカスタムステータスを「処理中」同様に扱うよう追加のフックが必要になるケースもある。その場合は、woocommerce_order_is_paid_statusesフィルターなどで「wc-invoice-processing」も支払い完了とみなしたい処理にだけ含めると調整できる。
よくある質問
この修正を適用すると、クレジットカードの処理中注文まで未払いになりませんか
紹介したコードはいずれも if 文で’ bacs ‘決済に限定しているため、クレジットカードや他の即時決済には影響しない。条件を厳密に書けば、安全に導入できる。
後払い注文のステータスをカスタムステータスにしたら、WooCommerceの標準メールは飛びますか
新規ステータスを追加しただけでは自動的にメールは送信されない。woocommerce_order_status_invoice-processing のようなアクションフックを利用して、独自のメールテンプレートをトリガーするか、処理中と同じメールを送るように設定する必要がある。
どの方法を選ぶべきかの判断基準は
まずは方法1と方法2を組み合わせて適用してみるのが最も手軽で汎用性が高い。それで解決しない場合はプラグイン固有のフィルターを探す。長期的に後払いワークフローを整理したいならカスタムステータスがおすすめだ。
この記事のポイント
- 処理中へのステータス変更で_date_paidが自動保存される仕様が原因
- woocommerce_payment_complete_order_statusフィルターで_date_paid書き込みをBACSだけ無効化できる
- is_paid()の返り値を上書きすれば、日付以外の「支払い済み」判定もブロック可能
- 請求書プラグイン固有のフィルターがあれば、そこからも支払い情報を空にできる
- 後払い専用のカスタム注文ステータスを導入すれば、処理中と混同せずに管理できる

・ Reddit、Stack Overflow、WordPress.org フォーラムを日々巡回し、現場の悩みを拾い上げて記事化
・ WordPress、WooCommerce、Next.js などモダンWeb制作領域のトラブルシューティングが専門
・ 「検索しても答えが見つからなかった」を一つでも減らすことが目標
・ エラーメッセージから根本原因にたどり着く粘り強い調査が得意
・ 初心者がつまずきやすい箇所を先回りで解決する記事作りを心がけている

WooCommerce 10.9でデュアルAPI登場、PHPコードからGraphQLを自動生成
WooCommerce 10.9で、PHPコードからGraphQL APIを自動生成する「デュアルAPI」が実験的に導入された。AutomatticのRadical Speed Monthイニシアチブの一環として開発されたこの機能は、開発者がPHPクラスに属性(アトリビュート)を付与するだけで、REST APIとGraphQL APIの両方を提供できるようにするものだ。
本記事では、デュアルAPIの技術的な仕組みと、プラグイン開発者にとっての具体的なメリット、現時点での制限と注意点を詳しく解説する。PHP 8.1以上が必須となるため、サーバー環境のバージョンアップを検討している運営者にも役立つ情報をまとめた。
WooCommerceデュアルAPIの概要と狙い

デュアルAPIの3つの構成要素
WooCommerce Developer Blogの記事によれば、デュアルAPIは大きく3つのパーツで成り立っている。1つ目は、PHP属性で装飾されたプレーンなPHPクラスで表現される「コードAPI」だ。これはコマンドパターンで実行可能なクラスか、データ転送オブジェクト(DTO)として定義される。2つ目は、そのコードAPIから自動生成される「GraphQL API」。そして3つ目が、開発時にコードからGraphQLパートを生成する「ビルドスクリプト」である。
なぜGraphQL APIを自動生成するのか
従来のWooCommerce REST APIは、決められたエンドポイントから必要なデータを取得する方式だった。一方、GraphQLはクライアントが必要なフィールドだけをリクエストできるため、オーバーフェッチやアンダーフェッチを防げる。モバイルアプリやヘッドレスコマース構成との相性も良い。しかし、APIを二重にメンテナンスする手間は大きい。そこで、PHPコードを信頼できる唯一の情報源(ソースオブトゥルース)とし、GraphQL側を自動生成することで、開発効率と一貫性を両立させる狙いがある。
コードからGraphQLを自動生成する仕組み
PHPクラスに定義した属性や型情報が、GraphQLスキーマのクエリ名、引数、返却型へと自動的にマッピングされる。開発者はPHPコードだけを書けば、対応するGraphQLエンドポイントが手に入る仕組みだ。
PHP属性によるメタデータの付与
この仕組みの中核が、PHP 8.0で導入された「属性(アトリビュート)」だ。クラスやメソッド、プロパティに #[Name('coupon')] や #[Description('...')] といった形でメタデータを埋め込める。このメタデータをビルドスクリプトが読み取り、GraphQLの型定義やドキュメントを自動構築する。PHPのコードベースがそのままAPIの仕様書になるわけだ。
コマンドクラスとDTOの変換ルール
実行可能なコマンドクラスはGraphQLのクエリやミューテーションに変換される。引数には #[Description] 属性付きで説明がつき、デフォルト値やnull許容もスキーマに反映される。DTOはGraphQLのインプットタイプやアウトプットタイプになる。PHPの列挙型(enum)や #[ArrayOf('int')] のようなカスタム属性を使えば、スカラー型の配列や独自型も正確に表現できる。
ビルドスクリプトの役割
ビルドスクリプトは開発時に一度だけ実行する。WooCommerceコアに同梱されており、プラグイン開発者も自分のコードに対して実行可能だ。スクリプトがコードAPIを解析し、GraphQLスキーマをファイルとして出力する。実行時にはそのスキーマに従ってリクエストが処理されるため、本番環境で毎回コードを解析する必要はない。
プラグイン開発におけるデュアルAPIの活用方法

独自のデュアルAPIを作成する手順
WooCommerce Developer Blogの記事では、プラグイン開発者がこのインフラを再利用して独自のデュアルAPIを構築できる点が強調されている。手順はシンプルだ。まず、プラグイン内にコマンドクラスとDTOを定義し、必要な属性を付与する。次に、WooCommerceのビルドスクリプトを開発時に走らせると、GraphQLパートが自動生成される。最後に rest_api_init フックを使い、ユーティリティメソッドで任意のエンドポイントURLにGraphQL APIを登録すれば完了する。
認証・認可のカスタマイズと拡張ポイント
コアのインフラは、クラスリゾルバ(デフォルトではWooCommerceのDIコンテナ)や、認証用のプリンシパルクラス、認可用の #[RequiredCapability] 属性を提供している。これらはそのまま使うことも、独自の認証・認可ロジックに置き換えることも可能だ。例えば、外部サービスと連携するプラグインであれば、カスタムのプリンシパルクラスを差し込んでAPIキー認証を実装できる。柔軟な拡張性が意識された設計である。
現時点での制限と実験的機能の注意点

後方互換性の保証がない理由
このデュアルAPIは実験的な機能であり、明示的に有効化しない限り動作しない。WooCommerce Developer Blogの記事でも、インフラ部分とコアAPIのいずれについても、将来のリリースで後方互換性のない変更が加えられる可能性があると明言されている。特に、より徹底したテストの過程で、属性の命名規則やクラス構成に破壊的変更が入るかもしれない。本番環境への導入は、安定版となるまで控えたほうが無難だ。
コアAPIのプルーフオブコンセプト
WooCommerce 10.9に同梱されるコアAPIは、製品とクーポンをカバーする限定的なものだ。記事では、これはあくまで「プルーフオブコンセプト(概念実証)」であり、今後のバージョンでクラスやクエリが大幅に変更されるか、まったく別のものに置き換わる可能性があるとされている。現時点では、開発環境やステージング環境でのテスト利用が推奨される。
PHP 7環境の安全性とバージョンアップの必要性

PHP 8.1依存の技術的理由
デュアルAPIはPHP 8.1以上を要求する。これは、PHP属性と列挙型(enum)に依存しているためだ。属性がなければGraphQLスキーマを自動生成できず、enumがなければDTOの厳密な型表現が難しくなる。WooCommerceとしても、公式にPHP 8.1以上を推奨しており、PHP 7.4や8.0のサポートは将来的に終了する方針が示されている。
PHP 7環境での影響と注意点
WooCommerce Developer Blogの記事によると、PHP 8.1固有のコードは、この機能が無効の場合やサーバーがPHP 7.4/8.0で動作している場合には一切実行されない設計になっている。したがって、機能を誤って有効化しようとしてもエラーは発生せず、GraphQLエンドポイントが機能しないだけだ。ただし、プラグインやカスタムコードから src/Api 配下のクラスを直接呼び出すと、PHP 7環境ではエラーになるため注意が必要である。
将来のPHPバージョンサポート計画
WooCommerceは過去にPHP 7.2/7.3のサポートを段階的に終了してきた。今回のデュアルAPI導入は、PHP 8.1移行を加速させる呼び水となるだろう。WordPress 7.0がPHP 7.2/7.3のサポートを打ち切り、PHP 8互換がベータを脱したことも追い風だ。ECサイト運営者は、セキュリティ面とパフォーマンス面からも、早めのPHPバージョンアップを検討すべき局面を迎えている。
この記事のポイント
- WooCommerce 10.9で実験的デュアルAPIが導入され、PHPコードからGraphQL APIを自動生成できるようになった
- PHP属性とDTOによってコードがAPI仕様を兼ね、プラグイン開発者も独自のデュアルAPIを構築可能
- 現時点では後方互換性が保証されない実験的機能であり、本番利用は避け、テスト環境での検証が推奨される
- PHP 8.1以上が必須で、PHP 7環境では機能が無効化されるが、安全面でのリスクは低い
- PHPバージョンアップの必要性が高まっており、ECサイトの将来的な安定稼働に向けて計画的な移行が望ましい

・ 複数業界における17年間のデジタルビジネス開発経験
・ ウェブサイト開発のためのHTML、PHP、CSS、JavaScript等の実用的知識
・ 15ヶ国語対応の多言語SaaSの開発経験
・ 17年間にも及ぶ、Eコマース長期運営経験
・ 幅広い業界でのSEO最適化の豊富な経験

WordPress開発の転換点:PHPのみでGutenbergブロックを構築する方法
WordPressのブロックエディタ(Gutenberg)が登場して以来、カスタムブロックの開発にはReactやNode.jsといったJavaScriptベースの技術習得が不可欠だった。しかし、最新のアップデートにより、PHPコードのみでブロックを構築・管理できる手法が確立された。この変更は、従来のPHP中心のWordPress開発者にとって、学習コストを劇的に下げる重要な転換点となる。
Gutenberg 21.8以降で導入されたこの機能により、サーバーサイドのJavaScript環境を構築することなく、PHPの関数だけでエディタとフロントエンドの両方にブロックを表示できる。ビルドプロセスの複雑さを排除し、保守性の高いサイト制作を可能にするのが「PHP-onlyブロック」だ。
本記事では、PHPのみでブロックを登録する具体的な手順から、管理画面UIの自動生成、さらには既存のショートコードをブロック化する実践的なテクニックまでを詳しく解説する。この記事を読むことで、最新のWordPress標準に準拠した効率的な開発手法を習得できるはずだ。
PHP-onlyブロックの概要と導入のメリット

これまで、カスタムブロックを作成するには、Reactの知識に加え、WebpackやNPM(Node Package Manager)を用いたビルド環境の構築が必須であった。これは、主にサーバーサイドのPHPでサイトを構築してきた開発者にとって、非常に高い参入障壁となっていた。PHP-onlyブロックは、この障壁を取り払うために設計された仕組みだ。
なぜPHPだけでブロックが作れるようになったのか
WordPress開発チームは、ブロックエディタの普及をさらに加速させるため、従来のPHP開発者が慣れ親しんだ手法でブロックを作成できる環境を整えた。具体的には、サーバー側で登録されたメタデータをエディタ(JavaScript側)へ自動的に受け渡す「auto_register」機能が実装されたことが大きい。これにより、エディタ用のJSファイルを手動で記述する必要がなくなったのだ。
開発者にとっての3つの主要な利点
第一の利点は、学習コストの圧倒的な低減だ。ReactやNode.jsの複雑なエコシステムを学ぶ時間を、サイトの機能向上やデザインのブラッシュアップに充てることができる。第二に、フロントエンドのパフォーマンス向上が挙げられる。不要なJavaScriptの読み込みを削減できるため、ページの読み込み速度を最適化しやすい。第三に、保守性の向上だ。PHPコード一箇所でブロックの定義と出力(レンダリング)を管理できるため、コードの可読性が高まり、バグの混入を防ぎやすくなる。
基本的なPHP-onlyブロックの作り方

PHP-onlyブロックの作成は、従来の「動的ブロック(Dynamic Blocks)」の登録方法と似ているが、最大の違いはエディタ用のスクリプトを指定せずに、特定のフラグを有効にする点にある。元記事の著者は、最小限のコードでブロックを動作させる手法を示している。
register_block_type と auto_register の役割
ブロックの登録には、WordPress標準の `register_block_type` 関数を使用する。この関数の `supports` 配列内に `’auto_register’ => true` を含めることが、PHP-onlyブロックとして動作させるための鍵となる。このフラグが有効な場合、WordPressは `ServerSideRender` というコンポーネントを自動的に使用し、管理画面上でもPHPで生成されたHTMLをプレビュー表示する。
最小構成のコード例
以下は、プラグインやテーマの `functions.php` に記述することで動作する、最もシンプルなPHP-onlyブロックのコードだ。
/**
* レンダリング用コールバック関数
*/
function my_simple_php_block_render( $attributes ) {
return '<div style="padding: 20px; background: #f0f0f0; border: 2px solid #0073aa;">
<h3>🚀 PHP-only ブロック</h3>
<p>このブロックはPHPのみで生成されています。</p>
</div>';
}
/**
* ブロックの登録
*/
add_action( 'init', function() {
register_block_type( 'my-custom/php-block', array(
'title' => 'シンプルなPHPブロック',
'icon' => 'admin-plugins',
'category' => 'text',
'render_callback' => 'my_simple_php_block_render',
'supports' => array(
'auto_register' => true,
),
) );
});🚀 PHP-only ブロック
このブロックはPHPのみで生成されています。
このコードを有効にすると、ブロックエディタの追加メニューに「シンプルなPHPブロック」が表示され、設置すると即座にグレーの枠線で囲まれたプレビューが表示される。これがPHP-only開発の第一歩だ。
属性(Attributes)を活用した管理画面UIの自動生成

単にHTMLを出力するだけでなく、ユーザーがエディタ上でテキストを変更したり、オプションを選択したりできるようにするには「属性(Attributes)」を定義する必要がある。最新のGutenbergでは、PHPで定義した属性に基づいて、サイドパネル(インスペクター)の入力フィールドを自動生成する機能が追加されている。
属性の定義と入力フィールドの対応関係
属性のデータ型(type)を指定することで、WordPressは適切なUIコンポーネントを割り当てる。著者によれば、現在のところ以下のマッピングがサポートされている。
- string: テキスト入力フィールド
- number / integer: 数値入力フィールド
- boolean: チェックボックス(またはトグル)
- enum(string内): セレクトボックス(ドロップダウン)
実践的な属性付きブロックのコード
以下の例では、タイトル、表示数、有効/無効の切り替え、サイズ選択の4つの属性を持つブロックを定義している。これらはすべて、JavaScriptを一行も書かずに管理画面のサイドバーに表示される。
register_block_type( 'my-plugin/advanced-php-block', array(
'title' => '設定付きPHPブロック',
'attributes' => array(
'blockTitle' => array( 'type' => 'string', 'default' => 'デフォルトタイトル' ),
'itemCount' => array( 'type' => 'integer', 'default' => 5 ),
'isEnabled' => array( 'type' => 'boolean', 'default' => true ),
'displaySize' => array(
'type' => 'string',
'enum' => array( 'small', 'medium', 'large' ),
'default' => 'medium',
),
),
'render_callback' => 'my_advanced_render_func',
'supports' => array( 'auto_register' => true ),
) );この仕組みの導入により、複雑なReactコンポーネント(TextControlやSelectControlなど)を組み合わせて `edit.js` を作成する手間が省ける。ただし、現時点ではリッチテキストエディタ(RichText)や高度なカラーピッカーなど、一部の複雑なコントロールはJS側での定義が必要な場合がある点には注意が必要だ。
実践例:カスタマイズ可能な価格表ブロックの構築

より実用的な例として、Web制作の現場で頻繁に求められる「価格表(料金テーブル)」ブロックをPHPのみで作成する手法を解説する。ここでは、WordPress標準のスタイル機能(色、間隔、タイポグラフィ)を統合する方法が重要となる。
get_block_wrapper_attributes によるネイティブ機能の統合
PHP-onlyブロックで最も強力な武器となるのが `get_block_wrapper_attributes()` 関数だ。この関数は、ユーザーがエディタのサイドバーで設定した背景色、文字色、パディング、マージンなどのスタイル情報をクラス名やインラインスタイルとして一括生成してくれる。これをメインの `div` タグに出力するだけで、自作ブロックがWordPressの標準デザインツールに完全対応する。
価格表ブロックのレンダリング設計
著者が提案する「Smart Pricing Widget」の例では、プラン名、価格、ボタンテキストなどの属性に加え、`supports` 配列で `color`, `spacing`, `typography`, `shadow`, `border` を有効にしている。これにより、エンジニアがCSSを細かく調整しなくても、運用者がエディタ上で自由に見た目をカスタマイズできるようになる。
function render_smart_pricing_block( $attributes ) {
// 属性の取得
$plan_name = esc_html( $attributes['planName'] );
$price = intval( $attributes['price'] );
// スタイル属性の生成
$wrapper_attributes = get_block_wrapper_attributes( array(
'class' => 'my-pricing-card',
) );
return sprintf(
'<div %s>
<h3>%s</h3>
<div class="price">¥%d</div>
<a href="#" class="btn">申し込む</a>
</div>',
$wrapper_attributes,
$plan_name,
$price
);
}プロフェッショナル
PHPのみで作成され、エディタの色設定が反映される価格表ブロックのイメージ
既存のショートコードをブロックへ変換する方法

PHP-onlyブロックの最も現実的かつ即効性のある活用シーンは、古いサイトで多用されている「ショートコード」のブロック化だ。ショートコードは入力が煩雑でプレビューも困難だが、PHP-onlyブロックでラップすることで、直感的な操作感へとアップグレードできる。
ショートコードをラップするメリット
ショートコードをそのまま使い続けるのではなく、ブロックとして再定義することで、ユーザーは「`[my_shortcode type=”info”]`」のような文字列を打ち込む必要がなくなる。代わりに、サイドバーのドロップダウンから「情報」「警告」「エラー」を選択するだけで済むようになる。内部的には既存のショートコード関数を呼び出すため、ロジックを書き直す必要もない。
do_shortcode を使ったレンダリング手法
実装方法は非常にシンプルだ。ブロックの `render_callback` 内で、受け取った属性を基にショートコード文字列を組み立て、WordPress標準の `do_shortcode()` 関数に渡すだけである。記事によれば、これにより管理画面上でもショートコードの実行結果がリアルタイムにプレビューされ、編集体験が劇的に向上するという。
function render_shortcode_wrapper_block( $attributes ) {
$type = esc_attr( $attributes['alertType'] );
$msg = esc_attr( $attributes['message'] );
// 既存のショートコードを動的に生成
$shortcode = sprintf( '[my_alert type="%s"]%s[/my_alert]', $type, $msg );
return sprintf(
'<div %s>%s</div>',
get_block_wrapper_attributes(),
do_shortcode( $shortcode )
);
}WordPress開発の未来とPHP-onlyブロックの立ち位置

PHP-onlyブロックは現在、非常に強力なツールとして進化を続けているが、すべてのJavaScript開発を置き換えるものではない。高度なインタラクションや、複雑な状態管理が必要なUI(例:ドラッグ&ドロップを伴う高度なレイアウトエディタなど)には、依然としてReactによる開発が適している。
しかし、中小規模のWebサイト制作や、社内向けのカスタム機能の実装においては、PHP-onlyブロックで十分なケースが大半だ。著者も指摘するように、この機能は「ブロックエコシステムを、高度なJavaScriptを操る層以外にも広げる」ための重要な架け橋となるだろう。今後は、より多くの管理画面コントロールがPHPから定義可能になり、JSを書く必要性はさらに低下していくと予想される。
我々Web制作に携わる者にとって、技術の選択肢が増えることは歓迎すべきことだ。プロジェクトの予算、納期、そして保守を担当するチームのスキルセットに合わせて、ReactベースのブロックとPHP-onlyブロックを適切に使い分ける「ハイブリッドな開発スタイル」が、これからのスタンダードになると考えられる。
この記事のポイント
- React/Node.js不要: 複雑なビルド環境なしでカスタムブロックが作成可能。
- auto_registerフラグ: PHPで定義した属性から管理画面のUIを自動生成できる。
- 保守性の向上: PHPコード一箇所で定義と出力を管理でき、コードの可読性が高い。
- ショートコードの進化: 既存のショートコードを簡単に、プレビュー可能なブロックへ変換できる。
- ネイティブ機能の統合: `get_block_wrapper_attributes` でWordPress標準のスタイル設定に即座に対応可能。
出典
- Kinsta Blog「How to build PHP-only Gutenberg blocks」(2026年3月19日)

・ 複数業界における17年間のデジタルビジネス開発経験
・ ウェブサイト開発のためのHTML、PHP、CSS、JavaScript等の実用的知識
・ 15ヶ国語対応の多言語SaaSの開発経験
・ 17年間にも及ぶ、Eコマース長期運営経験
・ 幅広い業界でのSEO最適化の豊富な経験

WP Rigで始めるWordPressテーマ開発——現代的なワークフローと学習環境
WP Rigは無料のWordPressテーマ開発ツールキットだ。スターターテーマとしての機能に加え、ComposerやNode.jsを統合した現代的な開発環境を提供する。2026年3月時点でバージョン3が公開されており、従来のクラシックテーマからブロックベースのテーマ、ハイブリッドなアプローチまで幅広く対応している。
プロジェクトの現在の管理者はRob Ruiz氏である。氏は2026年3月4日に公開されたWP Tavernのポッドキャストで、WP Rigの現状と将来像について語った。このツールキットは、テーマ開発の学習からプロダクション環境での利用まで、多様なユーザー層をサポートすることを目指している。
WordPressのエコシステムがブロックエディタとフルサイト編集(FSE)へと移行する中で、テーマ開発の在り方も変化している。WP Rigはこうした変化に対応し、開発者が最新のベストプラクティスを学びながら実践できる環境を整備した。
WP Rigとは何か——スターターテーマと開発ツールキット

WP Rigは「スターターテーマ」と「開発ツールキット」の両方の性格を持つ。Underscoresのような最小限のテーマ基盤を提供する一方で、現代的なフロントエンド開発に必要なツール群をあらかじめ統合している点が特徴だ。
コアとなる機能と統合ツール
WP Rigのプロジェクトをクローンすると、Node.jsとComposerの依存関係が自動的に解決される。これにより、開発者はすぐにコーディング作業に取りかかれる。統合されている主なツールは以下の通りだ。
- CSS処理: Lightning CSS(旧PostCSS)による最新CSS機能の先行利用とブラウザ互換コードへの変換
- JavaScript処理: esbuildによるTypeScriptのトランスパイルとバンドル
- コード品質: PHPCS(PHP Coding Standards)とWordPressコーディング標準(WPCS)に基づく自動チェック
- 開発サーバー: ファイル変更の監視と自動ビルド
これらのツールは、開発者が個別に設定する必要がなく、WP Rigの設定ファイルを介して一元的に管理される。これにより、開発環境の構築にかかる時間を大幅に短縮できる。
従来のスターターテーマとの違い
従来のスターターテーマは、主にテンプレートファイルのひな形を提供することに焦点が当てられていた。一方、WP Rigは開発「プロセス」そのものを標準化することを目指している。コードの書き方からビルド、品質チェックまで、一連のワークフローをツールが支援する。
Rob Ruiz氏はポッドキャストで、このアプローチについて次のように説明している。「WP Rigは単なるファイルの集合ではない。ベストプラクティスを学び、適用するためのガードレールを提供するものだ」。特にチーム開発では、この標準化されたワークフローがコードの一貫性を保ち、レビュー工数を削減する効果がある。
誰のためのツールか——学習者からプロフェッショナルまで

WP Rigの対象ユーザーは幅広い。WordPress管理画面でのサイト構築に慣れたユーザーが、次のステップとしてコードベースのカスタマイズに挑戦する場合にも適している。一方、経験豊富な開発者が新規プロジェクトを効率的に立ち上げるためにも利用できる。
ページビルダーユーザーからの移行
ページビルダーやブロックエディタによるビジュアル編集には限界がある。デザインの細かい調整や、最新のCSS機能をすぐに利用したい場合、コードを直接編集する方が柔軟性が高い。WP Rigは、こうしたユーザーがローカル開発環境を整え、段階的にテーマ開発を学ぶための足がかりとなる。
Ruiz氏はポッドキャストで、コードによる制御の利点を強調した。「データベースに保存された設定値を一つずつ変更するのではなく、CSSファイルを一行修正するだけでサイト全体の見た目を変えられる。これがコードの持つ『超能力』だ」。WP Rigは、この「超能力」を安全に習得するための学習環境を提供する。
エージェンシーとチーム開発での活用
カスタムテーマをクライアントに提供するWeb制作会社では、開発プロセスの標準化が重要だ。WP Rigをプロジェクトの基盤とすることで、複数の開発者が同じコーディング規約とビルドプロセスを共有できる。新規メンバーのオンボーディングも容易になる。
また、WP Rigにはテーマの「バンドル」機能が備わっている。開発が完了したテーマを配布用にパッケージ化する際、すべてのソースコード内の「WP Rig」という文字列がテーマ名に置換される。これにより、エンドユーザーが基盤技術を意識することなく、完成したテーマを利用できる。
開発環境の構築とワークフロー

WP Rigを利用するには、ローカルマシンに特定のソフトウェアをインストールする必要がある。リモートサーバーではなく、ローカル環境でテーマ開発を行うのが基本だ。
必要な事前準備
WP Rigを動作させるための最小限の環境は以下の通りだ。
- Node.js: JavaScriptの実行環境。バージョン管理ツール(nvmやfnm)でのインストールが推奨される。
- Composer: PHPの依存関係管理ツール。グローバルにインストールする。
- ローカル開発環境: Local WP、WordPress Studio、Dockerベースのwp-envなど、任意の環境を選択可能。
これらのツールをインストールした後、WP RigのGitHubリポジトリをクローンし、依存関係をインストールする。プロジェクトルートでnpm installとcomposer installを実行すれば、開発環境の準備は完了だ。
開発からバンドルまでの流れ
WP Rigを使った典型的な開発ワークフローは以下のステップで構成される。
- 1. 開発サーバーの起動:
npm startでファイル監視と自動ビルドが開始される。 - 2. コーディング: CSS、JavaScript、PHPファイルを編集する。変更は自動的に反映される。
- 3. コードチェック:
npm run lintでPHPとJavaScriptのコード品質を検証できる。 - 4. ビルド:
npm run buildで本番用の最適化されたアセットを生成する。 - 5. バンドル:
npm run bundleで配布用のテーマパッケージを作成する。
このワークフローの中で、開発者は複雑なビルド設定を意識する必要がない。ツールの更新が必要な場合も、WP Rigのバージョンアップに追随するだけで済む。
ブロックエディタ時代のテーマ開発

WordPressのフルサイト編集(FSE)とブロックベースのテーマが普及する中で、クラシックなテーマ開発の価値が問われている。WP Rigはこの変化を先取りし、複数の開発パラダイムをサポートするように進化した。
3つのテーマパラダイムへの対応
WP Rigは、一つのコードベースから以下の3種類のテーマを生成できる。
- クラシックテーマ: 従来通りのPHPテンプレートファイルを使用する。
- ユニバーサルテーマ: クラシックテーマとブロックテーマの機能を併用する。
- ブロックテーマ: HTMLテンプレートファイルとtheme.jsonで構成される。
プロジェクトの初期化後、コマンドラインからnpm run configureを実行すると、対話形式でテーマの種類を選択できる。選択に応じて、必要なファイルが自動的に生成または変換される。
テーマレベルでのブロック開発
WP Rigの特徴的な機能の一つが、テーマ内でのカスタムブロック開発をサポートしている点だ。通常、カスタムブロックはプラグインとして開発されるが、テーマに密接に関連するブロック(例: 特化したナビゲーションブロック)をテーマ内に実装できる。
ただし、この方法で開発したテーマをWordPress.orgの公式テーマリポジトリに投稿することはできない。リポジトリのガイドラインでは、ブロックの提供はプラグインに限定されているためだ。クライアントワークや自社サイトでの利用が主な用途となる。
Ruiz氏はこの機能について、「境界線を曖昧にすることを厭わない」と表現した。テーマとプラグインの役割分担に縛られず、プロジェクトの要件に最適な技術的選択を可能にする姿勢が反映されている。
教育資源としてのWP Rig

WP Rigの公式サイト(wprig.io)には、ツールの使い方だけでなく、WordPressテーマ開発そのものを学ぶための資源が豊富に用意されている。これはプロジェクトの重要な側面だ。
学習コンテンツの構成
サイトの「Learn」セクションには、以下のような教育資源が整理されている。
- ビデオチュートリアル: YouTubeチャンネルで基礎から応用までを解説
- 技術文書: CSS、JavaScript、PHPの各言語におけるベストプラクティス
- サンプルコード: 実際のユースケースに基づいた実装例
- 開発ガイド: ローカル環境構築からデプロイまでの手順
これらの資源は、単にWP Rigの使い方を教えるだけでなく、現代的なWeb開発の概念そのものを伝えることを目的としている。例えば、CSSのカスケードや詳細度、PHPの名前空間といった基礎概念も丁寧に説明されている。
コミュニティと貢献の機会
WP Rigはオープンソースプロジェクトであり、GitHub上で開発が進められている。バグ報告や機能提案はIssuesを通じて受け付けている。また、Discordサーバーでは開発者同士の交流が行われている。
Ruiz氏はポッドキャストで、コミュニティの重要性を強調した。「WordPress自体がコントリビューターに依存している。テーマ開発を学ぶ人が増え、やがてコアへの貢献者になる——そんな好循環を生み出したい」。WP Rigは、その入り口となることを目指している。
この記事のポイント
- WP Rigはテーマ開発のスターターキットであり、現代的な開発ツールを統合している。
- ローカル環境での開発を前提とし、Node.jsとComposerが必要だ。
- クラシック、ユニバーサル、ブロックテーマの3パラダイムに対応する。
- コード品質チェックや自動ビルドなど、チーム開発での標準化を支援する。
- 教育資源が豊富で、テーマ開発の学習環境としても機能する。
出典
- WP Tavern「#207 – Rob Ruiz on WP Rig and the Future of Theme Development」(2026年3月4日)

・ 複数業界における17年間のデジタルビジネス開発経験
・ ウェブサイト開発のためのHTML、PHP、CSS、JavaScript等の実用的知識
・ 15ヶ国語対応の多言語SaaSの開発経験
・ 17年間にも及ぶ、Eコマース長期運営経験
・ 幅広い業界でのSEO最適化の豊富な経験



