2026年10月5日
2026年10月5日
WordPressのFacadeパターンで複雑なAPIをシンプルに使う方法
外部サービスとの通信や他のプラグインの関数を、テーマやプラグインのあちこちから直接呼んでいると、仕様が変わったときに修正箇所が散らばり、エラー処理も場所ごとにばらつきます。Facade(ファサード)パターンは、その複雑な手順を1つのクラスにまとめ、使う側には「何がしたいか」だけを表す短いメソッドを見せる設計です。この記事では、WordPress の HTTP API とキャッシュをまとめる例と、他のプラグインへの依存をまとめる例を通して、Facade の作り方と、作りすぎないための判断基準を説明します。
Facade パターンとは
Facade は「正面の窓口」という意味です。裏側では複数の関数やクラスが連携していても、使う側は窓口の1メソッドを呼ぶだけで済むようにします。
たとえば外部の顧客管理サービスから顧客情報を取ってくる処理は、実際には次の手順の組み合わせです。
- 認証ヘッダーを付けてリクエストを送る
- 通信エラーと HTTP ステータスを確認する
- JSON を解析し、想定どおりの形かを確かめる
- 必要な項目だけを取り出して整える
- 何度も問い合わせないようにキャッシュする
これを呼び出し元ごとに書くと、どこかで手順が抜けます。Facade にまとめれば、呼び出し側は $crm->get_contact( 42 ) と書くだけになり、手順の抜けや重複がなくなります。
Laravel の「Facade」とは別物
PHP では、Laravel の「Facade」(Cache::get() のように静的メソッドで呼ぶ仕組み)を思い浮かべる方も多いかもしれません。あれは裏にあるサービスへ静的呼び出しを中継する仕組みで、デザインパターンとしての Facade とは目的が異なります。この記事で扱うのは後者、「複雑な手順を単純な窓口にまとめる」という意味の Facade です。WordPress で Laravel 風の静的中継を自作すると、依存が見えにくくなりテストもしにくくなるため、まずは普通のクラスとして作ることをおすすめします。
例1:HTTP API とキャッシュをまとめる
WordPress には wp_remote_get() などの HTTP API と、一時的なデータを保存する Transients API があります。どちらも便利ですが、エラー処理を含めると呼び出し側のコードが長くなります。これを1つのクラスにまとめます。
コードは子テーマの functions.php ではなく、専用のプラグインか mu-plugin に置いてください。テーマを変えても動き続けるようにするためです。
<?php
namespace MyPlugin;
final class CrmClient {
private const CACHE_TTL = 10 * MINUTE_IN_SECONDS;
private string $base_url;
private string $api_key;
public function __construct( string $base_url, string $api_key ) {
$this->base_url = untrailingslashit( $base_url );
$this->api_key = $api_key;
}
/**
* 顧客情報を取得する。
*
* @return array{id:int,name:string,email:string}|\WP_Error
*/
public function get_contact( int $id ) {
$cache_key = 'myplugin_contact_' . $id;
$cached = get_transient( $cache_key );
if ( is_array( $cached ) ) {
return $cached;
}
$response = wp_remote_get(
$this->base_url . '/contacts/' . $id,
array(
'timeout' => 10,
'headers' => array(
'Authorization' => 'Bearer ' . $this->api_key,
'Accept' => 'application/json',
),
)
);
if ( is_wp_error( $response ) ) {
return $response; // 通信そのものの失敗
}
$code = (int) wp_remote_retrieve_response_code( $response );
if ( 200 !== $code ) {
return new \WP_Error( 'myplugin_crm_http', 'CRM API error', array( 'status' => $code ) );
}
$data = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! is_array( $data ) || ! isset( $data['id'] ) ) {
return new \WP_Error( 'myplugin_crm_format', 'Unexpected CRM response' );
}
$contact = array(
'id' => (int) $data['id'],
'name' => sanitize_text_field( $data['name'] ?? '' ),
'email' => sanitize_email( $data['email'] ?? '' ),
);
set_transient( $cache_key, $contact, self::CACHE_TTL );
return $contact;
}
}
設計のポイントは3つあります。
- 戻り値の形を決める:成功なら決まった形の配列、失敗なら
WP_Errorを返します。外部 API がどんな JSON を返しても、呼び出し側が受け取る形は変わりません。外部サービスの仕様変更は、このクラスの中だけを直せば吸収できます - 入ってきたデータを整える:外部から来た値は信頼せず、
sanitize_text_field()などで整えてから返します。表示するときには、さらに出力先に合わせてエスケープします - 失敗はキャッシュしない:エラー時に Transient を保存すると、障害が直ったあとも一定時間エラー状態が続いてしまいます
API キーはコードに直接書かず、wp-config.php に定数として定義するか、環境変数から読み込みます。定数名や値は例であり、実際のキーをリポジトリに含めないようにしてください。
<?php
// wp-config.php 側: define( 'MYPLUGIN_CRM_API_KEY', 'your-api-key' );
add_action( 'plugins_loaded', function () {
if ( ! defined( 'MYPLUGIN_CRM_API_KEY' ) ) {
return; // 設定がなければ機能ごと無効にする
}
$crm = new MyPlugin\CrmClient( 'https://api.example.com/v1', MYPLUGIN_CRM_API_KEY );
add_shortcode( 'crm_contact_name', function ( $atts ) use ( $crm ) {
$atts = shortcode_atts( array( 'id' => 0 ), $atts );
$contact = $crm->get_contact( absint( $atts['id'] ) );
if ( is_wp_error( $contact ) ) {
return ''; // 訪問者にはエラー内容を見せない
}
return esc_html( $contact['name'] );
} );
} );
呼び出し側は「ID を渡して名前を表示する」ことだけを書いており、通信やキャッシュの事情を知りません。これが Facade の効果です。
例2:他のプラグインへの依存をまとめる
テーマが ACF(Advanced Custom Fields)などのプラグインの関数を直接呼んでいると、そのプラグインを停止しただけで、関数が存在しないという致命的エラーが出ます。プラグインの関数をテンプレートのあちこちで呼ぶのではなく、窓口を1つ用意して、存在確認をそこに集めます。
<?php
namespace MyTheme;
final class Fields {
public static function text( string $name, $post_id = false ): string {
if ( ! function_exists( 'get_field' ) ) {
return ''; // プラグインが無効でもサイトを止めない
}
$value = get_field( $name, $post_id );
return is_string( $value ) ? $value : '';
}
}
// テンプレート側
// echo esc_html( \MyTheme\Fields::text( 'subtitle' ) );
将来、別のカスタムフィールドの仕組みに移行することになっても、このクラスの中身を書き換えるだけで済みます。ここでは使い勝手を優先して静的メソッドにしていますが、単体テストで差し替えたい場合は、例1のようにインスタンスを渡す形にするとよいでしょう。
Facade を作りすぎないための判断基準
Facade は便利ですが、何にでも被せると、薄いだけのクラスが増えて読みにくくなります。次のどれかに当てはまるときに作ると効果があります。
- 同じ手順(認証、エラー処理、キャッシュなど)を3か所以上で書いている
- 外部サービスや他のプラグインなど、自分で管理できない仕様に依存している
- 呼び出し側に知らせたくない複雑さ(再試行、形式の変換など)がある
逆に、get_option() を1回呼ぶだけの処理を包むような、手順が単純なものには不要です。また、Facade が多くの機能を抱え込んで巨大になってきたら、「顧客」「注文」のように関心ごとに分けるサインです。
Facade は「依存をまとめる窓口」で、依存を「どう渡すか」は別の問題です。例1では Facade のインスタンスを起動処理で作ってショートコードに渡しています。依存の渡し方については、Service Locator と DI を比較した別記事で扱っています。
導入時の確認
既存のコードを Facade に置き換えるときは、バックアップを取り、ステージング環境で次の点を確かめてから本番に反映します。
- 外部 API が止まった・遅いときに、ページ全体が止まらず空表示などで済むか(
timeoutの値も確認する) - 依存先のプラグインを停止しても致命的エラーにならないか
- キャッシュの有効期限が、データの更新頻度に合っているか
なお、WordPress の HTTP API や Transients API は長く使われている安定した仕組みですが、外部サービス側の認証方式や API のバージョンは変わります(2026年10月現在)。仕様変更の告知は、利用しているサービスの開発者向けドキュメントで確認してください。
まとめ
- Facade は複雑な手順を1つのクラスにまとめ、使う側には目的を表す短いメソッドだけを見せる設計
- Laravel の静的な Facade とは別物。WordPress ではまず普通のクラスとして作る
- HTTP API の例では、戻り値の形を固定し、外部データを整え、失敗はキャッシュしない
- 他のプラグインの関数は窓口に集めて
function_exists()で確認し、停止時もサイトを止めない - 同じ手順の繰り返しや管理できない依存があるときに作り、単純な処理には被せない