2026年8月3日
2026年8月3日
WordPressのHTTP APIで外部APIを呼ぶ方法(wp_remote_get/postの引数とエラー処理)
WordPress のテーマやプラグインから外部の API を呼ぶときは、PHP の cURL 関数を直接使わずに、WordPress の HTTP API(wp_remote_get() や wp_remote_post() など)を使います。サーバーの環境差を吸収し、プロキシ設定やフィルターによる差し替えにも対応できるためです。この記事では、GET と POST の書き方、主な引数の既定値、エラー処理、キャッシュ、テスト時の差し替えまでを順に説明します。動作は WordPress 6.9 で確認しています(2026年10月時点)。
HTTP APIの関数一覧
| 関数 | 用途 |
|---|---|
wp_remote_get( $url, $args ) |
GET リクエスト |
wp_remote_post( $url, $args ) |
POST リクエスト |
wp_remote_head( $url, $args ) |
HEAD リクエスト(本文なしでステータスやヘッダーだけ確認) |
wp_remote_request( $url, $args ) |
method 引数で PUT・PATCH・DELETE なども送れる汎用版 |
wp_safe_remote_get() など wp_safe_ 付きの関数 |
URL の検証を有効にした版(後述) |
戻り値は、成功時は headers・body・response・cookies などを持つ配列、通信そのものに失敗したときは WP_Error です。配列から値を取り出すときは、次の関数を使います。
wp_remote_retrieve_response_code( $response ): ステータスコード(200、404 など)wp_remote_retrieve_body( $response ): 本文(文字列)wp_remote_retrieve_header( $response, 'content-type' ): 指定したヘッダーの値wp_remote_retrieve_headers( $response ): ヘッダー全体
主な引数と既定値
第2引数の配列で、リクエストの動きを変えられます。既定値は WP_Http::request() で決まっています。
| 引数 | 既定値 | 意味 |
|---|---|---|
timeout |
5(秒) |
応答を待つ秒数 |
redirection |
5 |
リダイレクトをたどる回数(HEAD は0) |
httpversion |
'1.0' |
HTTP のバージョン |
headers |
空の配列 | 送るリクエストヘッダー |
body |
null |
送る本文(配列ならフォーム形式、文字列ならそのまま) |
sslverify |
true |
SSL 証明書を検証するか |
blocking |
true |
false にすると応答を待たずに戻る |
reject_unsafe_urls |
false |
URL を検証して危険な宛先を拒否するか(wp_safe_ 系では true) |
user-agent |
WordPress/バージョン; サイトURL |
送る User-Agent |
timeout の既定値5秒は、応答の遅い API では足りないことがあります。ただし長くしすぎると、API が止まったときにページの表示まで待たされます。ページ表示中に呼ぶなら10秒程度までにし、結果をキャッシュするのが現実的です。
GETリクエストでJSONを取得する
エラー処理まで含めた、使い回せる関数の例です。子テーマの functions.php か自作プラグインに置きます。
<?php
/**
* 外部APIからJSONを取得して配列で返す。
*
* @param string $url リクエスト先のURL。
* @param array $args wp_remote_get() に渡す追加の引数。
* @return array|WP_Error
*/
function my_fetch_json( $url, $args = array() ) {
$args = wp_parse_args(
$args,
array(
'timeout' => 10,
'headers' => array( 'Accept' => 'application/json' ),
)
);
$response = wp_remote_get( $url, $args );
// 1. 通信そのものの失敗(DNS、接続、タイムアウト、SSL など)
if ( is_wp_error( $response ) ) {
return $response;
}
// 2. HTTP ステータスの確認(404 や 500 は WP_Error にならない)
$code = (int) wp_remote_retrieve_response_code( $response );
if ( $code < 200 || $code >= 300 ) {
return new WP_Error(
'my_http_status',
sprintf( 'HTTP %d が返りました。', $code ),
array( 'status' => $code )
);
}
// 3. 本文を JSON として解釈
$data = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! is_array( $data ) ) {
return new WP_Error( 'my_http_json', '応答を JSON として読めませんでした。' );
}
return $data;
}
ポイントは、失敗の種類が2つあることです。
- 通信の失敗: 接続できない、タイムアウトした、証明書が検証できないといった場合は
WP_Errorが返ります。$response->get_error_message()で理由が分かります。 - HTTP のエラー: 404 や 500 は通信としては成功しているため、通常の配列で返ります。ステータスコードを自分で確認しないと、エラーページの HTML を JSON として読もうとしてしまいます。
クエリパラメーターを付けるときは、文字列を連結せずに add_query_arg() を使うと、URL の組み立て間違いを防げます。値に日本語や記号が入る場合は rawurlencode() で変換してから渡します。
$url = add_query_arg(
array(
'q' => rawurlencode( '東京' ),
'limit' => 10,
),
'https://api.example.com/v1/search'
);
$data = my_fetch_json( $url );
POSTリクエストでJSONを送る
body に配列を渡すと、application/x-www-form-urlencoded のフォーム形式で送られます。JSON を受け付ける API には、wp_json_encode() で文字列にし、Content-Type ヘッダーを付けて送ります。
function my_post_json( $url, array $payload, $token ) {
$response = wp_remote_post(
$url,
array(
'timeout' => 15,
'headers' => array(
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $token,
),
'body' => wp_json_encode( $payload ),
)
);
if ( is_wp_error( $response ) ) {
return $response;
}
return array(
'code' => (int) wp_remote_retrieve_response_code( $response ),
'body' => json_decode( wp_remote_retrieve_body( $response ), true ),
);
}
PUT や DELETE は wp_remote_request() の method で指定します。
$response = wp_remote_request(
'https://api.example.com/v1/items/' . rawurlencode( $id ),
array(
'method' => 'DELETE',
'headers' => array( 'Authorization' => 'Bearer ' . $token ),
)
);
APIキーやトークンの扱い
API キーやトークンは、コードに直接書かず wp-config.php の定数や環境変数に置き、コードからは定数名だけを参照します。
// wp-config.php(「編集が必要なのはここまで」の行より上)
define( 'MY_API_TOKEN', 'ここに発行されたトークン' );
$result = my_post_json( 'https://api.example.com/v1/items', array( 'name' => 'test' ), MY_API_TOKEN );
error_log() などでログを取るときは、エラーメッセージだけを書き、リクエストのヘッダーやトークンは記録しないでください。
sslverifyはfalseにしない
証明書エラーが出たときに 'sslverify' => false で回避する例を見かけますが、これは通信相手が本物かどうかを確かめない設定です。なりすましたサーバーにトークンや個人情報を送ってしまう恐れがあるため、本番では使いません。
証明書エラーの主な原因は次のとおりです。
- 接続先の証明書の期限切れや、中間証明書の設定漏れ(接続先側で直す)
- サーバーの CA 証明書が古い(OS のパッケージ更新で直す。WordPress は
wp-includes/certificates/ca-bundle.crtも同梱しています) - サーバーの時計がずれている
ローカル開発環境の自己署名証明書だけが問題なら、その環境の wp-config.php か開発用プラグインに限って対応し、本番に持ち込まないようにします。
結果をトランジェントでキャッシュする
ページを表示するたびに外部 API を呼ぶと、表示が遅くなり、API の回数制限にもかかりやすくなります。トランジェントで一定時間保存し、その間は保存した値を使います。
function my_get_items_cached() {
$key = 'my_api_items_v1';
$items = get_transient( $key );
if ( false !== $items ) {
return $items;
}
$items = my_fetch_json( 'https://api.example.com/v1/items' );
if ( is_wp_error( $items ) ) {
error_log( 'my_api: ' . $items->get_error_message() );
// 失敗した結果は短時間だけ覚えて、API への連続アクセスを避ける
set_transient( $key, array(), MINUTE_IN_SECONDS );
return array();
}
set_transient( $key, $items, 15 * MINUTE_IN_SECONDS );
return $items;
}
失敗したときも空の配列を1分だけ保存しているのは、API が落ちている間にアクセスのたびに再接続して、ページ表示が毎回タイムアウトまで待たされるのを防ぐためです。表示するときは、取得した値を esc_html() や esc_url() でエスケープしてから出力します。
更新頻度が低いデータなら、ページ表示中に取得せず、WP-Cron で定期的に取得してオプションに保存する方法もあります。
利用者が入力したURLにはwp_safe_remote_getを使う
フォームの入力など、利用者が指定した URL にサーバーからリクエストを送る場合は、wp_safe_remote_get() などの wp_safe_ 付きの関数を使います。reject_unsafe_urls が有効になり、127.0.0.1 やプライベートIPアドレスなど内部向けの宛先へのリクエストが拒否されます(SSRF と呼ばれる攻撃への対策です)。
$response = wp_safe_remote_get( $user_supplied_url, array( 'timeout' => 5 ) );
if ( is_wp_error( $response ) ) {
// 内部向けの宛先は「A valid URL was not provided.」などのエラーになる
}
サーバー全体で外部への通信を制限する
wp-config.php に次の定数を書くと、WordPress の HTTP API からの外部リクエストをまとめて止め、許可したホストにだけ通信させられます。
define( 'WP_HTTP_BLOCK_EXTERNAL', true );
define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,*.github.com,api.example.com' );
WP_ACCESSIBLE_HOSTS はカンマ区切りで、* を使ったワイルドカードも書けます。api.wordpress.org を外すと、本体・プラグインの更新確認ができなくなるため注意してください。
テストやデバッグで通信を差し替える
pre_http_request フィルターで配列を返すと、実際の通信をせずにその値が応答として使われます。外部 API に依存しない単体テストや、API 側が未完成のときの開発に使えます。
add_filter(
'pre_http_request',
function ( $pre, $args, $url ) {
if ( 0 !== strpos( $url, 'https://api.example.com/' ) ) {
return $pre; // 対象外の URL は通常どおり通信する
}
return array(
'headers' => array( 'content-type' => 'application/json' ),
'body' => wp_json_encode( array( 'items' => array( 'a', 'b' ) ) ),
'response' => array( 'code' => 200, 'message' => 'OK' ),
'cookies' => array(),
'filename' => null,
);
},
10,
3
);
また、すべてのリクエストの引数は http_request_args フィルターで、応答は http_api_debug アクションで確認できます。本番に残すとログが増えるため、調査が終わったら外してください。
うまくいかないときの確認
cURL error 28(タイムアウト):timeoutを延ばす前に、サーバーから接続先に到達できるか(ファイアウォールや送信制限)を確認します。cURL error 60など証明書のエラー: 上の「sslverifyはfalseにしない」の項目を確認します。- 401・403: 認証ヘッダーの形式(Bearer か Basic か)や、API キーの権限を確認します。
- ステータスは200なのにデータが空:
wp_remote_retrieve_body()の中身を一時的にログに出し、JSON の構造とコードの参照しているキーが合っているかを確認します。 - 一部のサーバーだけ失敗する:
WP_HTTP_BLOCK_EXTERNALが設定されていないか、プロキシ設定(WP_PROXY_HOSTなど)が必要な環境でないかを確認します。
まとめ
- 外部 API は
wp_remote_get()・wp_remote_post()・wp_remote_request()で呼び、値はwp_remote_retrieve_*()で取り出す。 - 通信の失敗は
is_wp_error()、HTTP のエラーはステータスコードで、分けて確認する。 - JSON を送るときは
wp_json_encode()とContent-Type: application/jsonを使う。 sslverifyは無効にせず、トークンは定数に置き、結果はトランジェントでキャッシュする。- 利用者が指定した URL には
wp_safe_remote_get()を使う。
関連記事: