Skip to main content

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']);
note

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'],
]);
KeySets
base_uriPrefix for every path passed to a verb
content_typeContent-Type header
headersRequest headers
bodyRaw body string
form_paramsURL-encoded form body
jsonJSON body; also sets the content type
multipartMultipart 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.

Never allowlist a host from request data

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.

note

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.