HTTP Client
Introduction
Http is a fluent wrapper over WordPress's HTTP API. It builds the payload, sends the request through wp_safe_remote_request(), and decodes a JSON response for you:
use YourPlugin\Deps\BitApps\WPKit\Http\Client\Http;
$response = Http::get('https://api.example.com/users/1');
The response is the decoded JSON when the body parses as JSON, the raw body string when it doesn't, and a WP_Error when the request itself failed.
Verbs
get, post, put, patch, delete, head and options are available on a client instance:
use YourPlugin\Deps\BitApps\WPKit\Http\Client\HttpClient;
$client = new HttpClient(['base_uri' => 'https://api.example.com/']);
$client->get('users');
$client->post('users');
$client->put('users/1');
$client->delete('users/1');
On the Http facade the same verbs take the URL plus the request data:
Http::post('https://api.example.com/users', ['name' => 'Jane']);
Http::get() requires at least two arguments — the URL and the data — because it forwards to request(). For a bare GET, pass an empty array, or use HttpClient where the verbs take just a path.
Configuring the client
Pass defaults to the constructor:
$client = new HttpClient([
'base_uri' => 'https://api.example.com/',
'content_type' => 'application/json',
'headers' => ['Authorization' => 'Bearer ' . $token],
'json' => ['name' => 'Jane'],
]);
| Key | Sets |
|---|---|
base_uri | Prefix for every path passed to a verb |
content_type | Content-Type header |
headers | Request headers |
body | Raw body string |
form_params | URL-encoded form body |
json | JSON body; also sets the content type |
multipart | Multipart body for file uploads |
Every key has a matching setter, so the same thing can be built up fluently:
$client->setBaseUri('https://api.example.com/')
->setHeader('Authorization', 'Bearer ' . $token)
->setJson(['name' => 'Jane']);
Request bodies
Pick the body type that matches the endpoint — each one sets the right content type:
$client->setJson(['name' => 'Jane']); // application/json
$client->setFormParams(['name' => 'Jane']); // form-encoded
$client->setMultipart([...]); // multipart/form-data
$client->setBody('raw string'); // sent as-is
Multipart uses standards-compliant boundaries and CRLF framing. It cannot be combined with JSON, form params or a raw body, and field names, filenames and part headers reject control characters.
Query parameters
Query parameters are separate from the body and are appended to the URL:
$client->setQueryParams(['page' => 2, 'per_page' => 50]);
$client->setQueryParam('search', 'flows');
$client->get('users'); // https://api.example.com/users?page=2&per_page=50&search=flows
Headers
$client->setHeaders(['Accept' => 'application/json']);
$client->setHeader('X-Request-Id', $id);
$client->getHeader('Accept');
$client->getHeaders();
Reading the response
$data = $client->get('users');
$client->getResponseCode(); // HTTP status
$client->getResponseHeaders(); // response headers
Because a failed request returns a WP_Error, check before using the result:
$response = Http::get('https://api.example.com/users/1', []);
if (is_wp_error($response)) {
return $response; // becomes an error envelope — see Error Handling
}
Options
Anything wp_remote_request() accepts can be passed through, which is how you change the timeout:
$client->setOptions(['timeout' => 60, 'sslverify' => true]);
The client's own defaults are method, headers, body and a 30-second timeout.
Internal hosts
The client uses wp_safe_remote_request(), which refuses private, loopback and otherwise unsafe addresses. Reaching an internal endpoint takes an explicit allowlist of exact hosts:
$client = (new HttpClient())
->allowUnsafeUrls(true, ['10.0.0.20', 'internal-api.example']);
$client->getAllowedUnsafeHosts();
$client->setAllowedUnsafeHosts(['internal-api.example']);
Authorization is host-only: the URL must be HTTP or HTTPS, but any port or path on an allowlisted host is reachable. Unsafe requests never follow redirects.
Hosts belong in this list only when an administrator configured them. Deriving one from user input turns the client into an SSRF proxy.
Since 2.4.0, calling allowUnsafeUrls(true) without hosts fails closed: the request returns a WP_Error with code unsafe_url_not_allowed and never reaches the transport.
There is no retry, backoff, or connection pooling. A slow endpoint blocks the PHP request for the full timeout, so move third-party calls that are not needed for the response into a background job.