WordPress HTTP API
Introduction
When developing WordPress plugins, you'll often need to interact with external services, fetch remote data, or communicate with third-party APIs. The WordPress HTTP API provides a standardized and secure way to make HTTP requests from your plugins without having to write low-level code or manage complex dependencies.
Instead of using PHP's native functions like file_get_contents()
or requiring external libraries, WordPress offers a robust set of functions that handle common HTTP operations while managing errors, timeouts, and other complexities automatically.
In this tutorial, we'll explore how to use the WordPress HTTP API to make various types of requests, handle responses, and implement typical use cases in plugin development.
Why Use the WordPress HTTP API?
Before diving into the code, it's important to understand the benefits of using WordPress's built-in HTTP functions:
- Compatibility: Works across different hosting environments
- Security: Handles sanitization and validation automatically
- Flexibility: Supports various methods (GET, POST, PUT, etc.)
- Error handling: Robust error detection and reporting
- Standardization: Consistent interface for all HTTP operations
Basic HTTP Requests
Making a Simple GET Request
The most common HTTP request is GET, used to retrieve data from an external URL.
function my_plugin_get_remote_data() {
$api_url = 'https://api.example.com/data';
// Basic GET request
$response = wp_remote_get($api_url);
// Check if the request was successful
if (is_wp_error($response)) {
return 'Error: ' . $response->get_error_message();
}
// Get response code
$response_code = wp_remote_retrieve_response_code($response);
if ($response_code === 200) {
// Get the body of the response
$body = wp_remote_retrieve_body($response);
return $body;
} else {
return 'Error: Received response code ' . $response_code;
}
}
Understanding the Response
The wp_remote_get()
function returns either a WP_Error object (if the request failed) or an array containing:
headers
: Response headersbody
: The response contentresponse
: HTTP status code and messagecookies
: Any cookies set in the responsefilename
: Only if 'stream' => true was set
Here's how to access each part of the response:
function my_plugin_parse_response($response) {
if (is_wp_error($response)) {
return 'Error: ' . $response->get_error_message();
}
// Get response code (e.g., 200, 404, 500)
$code = wp_remote_retrieve_response_code($response);
// Get response message (e.g., "OK", "Not Found")
$message = wp_remote_retrieve_response_message($response);
// Get headers as an array
$headers = wp_remote_retrieve_headers($response);
// Get individual header
$content_type = wp_remote_retrieve_header($response, 'content-type');
// Get body content
$body = wp_remote_retrieve_body($response);
return [
'code' => $code,
'message' => $message,
'content_type' => $content_type,
'body' => $body
];
}
Advanced HTTP Requests
POST Requests
When you need to send data to a remote API, you'll typically use POST requests:
function my_plugin_post_data() {
$api_url = 'https://api.example.com/submit';
$body = [
'username' => 'john_doe',
'email' => '[email protected]',
'message' => 'Hello from my WordPress plugin!'
];
$args = [
'body' => $body,
'timeout' => 30, // 30-second timeout
];
$response = wp_remote_post($api_url, $args);
if (is_wp_error($response)) {
return 'Error: ' . $response->get_error_message();
}
$response_code = wp_remote_retrieve_response_code($response);
if ($response_code === 201 || $response_code === 200) {
return 'Success! Data submitted.';
} else {
return 'Error: Received response code ' . $response_code;
}
}
Other HTTP Methods
For other HTTP methods like PUT, DELETE, or PATCH, you can use the more generic wp_remote_request()
function:
function my_plugin_update_resource($resource_id, $data) {
$api_url = 'https://api.example.com/resources/' . $resource_id;
$args = [
'method' => 'PUT',
'body' => $data,
'headers' => [
'Content-Type' => 'application/json',
],
];
$response = wp_remote_request($api_url, $args);
// Process response as usual
// ...
}
Working with JSON APIs
Most modern APIs use JSON for data exchange. Here's how to work with JSON APIs:
function my_plugin_fetch_json_api() {
$api_url = 'https://api.example.com/products';
$args = [
'headers' => [
'Accept' => 'application/json',
],
];
$response = wp_remote_get($api_url, $args);
if (is_wp_error($response)) {
return 'Error: ' . $response->get_error_message();
}
$body = wp_remote_retrieve_body($response);
// Convert JSON to PHP array/object
$data = json_decode($body, true); // true to get associative array
if (json_last_error() !== JSON_ERROR_NONE) {
return 'Error parsing JSON: ' . json_last_error_msg();
}
// Now $data contains the PHP representation of the JSON
return $data;
}
Authentication Methods
Many APIs require authentication. Here are common ways to authenticate:
Basic Authentication
function my_plugin_basic_auth_request() {
$api_url = 'https://api.example.com/protected-resource';
$username = 'api_user';
$password = 'api_password';
$args = [
'headers' => [
'Authorization' => 'Basic ' . base64_encode($username . ':' . $password),
],
];
$response = wp_remote_get($api_url, $args);
// Process response as usual
// ...
}
API Key Authentication
function my_plugin_api_key_request() {
$api_url = 'https://api.example.com/data';
$api_key = 'your_api_key_here';
// API key in header
$args = [
'headers' => [
'X-API-Key' => $api_key,
],
];
// Or API key in URL (less secure)
// $api_url = add_query_arg('api_key', $api_key, $api_url);
$response = wp_remote_get($api_url, $args);
// Process response as usual
// ...
}
OAuth Authentication
OAuth is more complex. Here's a simplified example:
function my_plugin_oauth_request() {
$api_url = 'https://api.example.com/data';
$access_token = get_option('my_plugin_oauth_token');
$args = [
'headers' => [
'Authorization' => 'Bearer ' . $access_token,
],
];
$response = wp_remote_get($api_url, $args);
// Check for unauthorized error (token expired)
if (wp_remote_retrieve_response_code($response) === 401) {
$access_token = my_plugin_refresh_oauth_token();
// Try again with new token
$args['headers']['Authorization'] = 'Bearer ' . $access_token;
$response = wp_remote_get($api_url, $args);
}
// Process response as usual
// ...
}
Additional Request Options
The WordPress HTTP API supports many options to customize requests:
function my_plugin_advanced_request() {
$api_url = 'https://api.example.com/large-file';
$args = [
'timeout' => 60, // 60 second timeout
'redirection' => 5, // Maximum 5 redirects
'httpversion' => '1.1', // Use HTTP/1.1
'user-agent' => 'My Plugin/1.0; ' . get_bloginfo('url'), // Custom user agent
'blocking' => true, // Wait for response
'headers' => [], // Custom headers
'cookies' => [], // Custom cookies
'body' => null, // Request body
'compress' => false, // Don't compress
'decompress' => true, // Decompress if compressed
'sslverify' => true, // Verify SSL certificate
'stream' => false, // Don't stream to file
'filename' => null // Filename if streaming
];
$response = wp_remote_get($api_url, $args);
// Process response as usual
// ...
}
Real-World Examples
Example 1: Fetching Weather Data
Let's create a function that fetches weather data from a public API:
function my_weather_plugin_get_forecast($city) {
$api_key = get_option('my_weather_plugin_api_key');
$api_url = 'https://api.weatherapi.com/v1/forecast.json';
$args = [
'q' => $city,
'key' => $api_key,
'days' => 3
];
$request_url = add_query_arg($args, $api_url);
$response = wp_remote_get($request_url);
if (is_wp_error($response)) {
return [
'success' => false,
'message' => $response->get_error_message()
];
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (!$data || isset($data['error'])) {
return [
'success' => false,
'message' => isset($data['error']['message']) ? $data['error']['message'] : 'Unknown error'
];
}
// Process the weather data
$forecast = [];
foreach ($data['forecast']['forecastday'] as $day) {
$forecast[] = [
'date' => $day['date'],
'max_temp' => $day['day']['maxtemp_c'],
'min_temp' => $day['day']['mintemp_c'],
'condition' => $day['day']['condition']['text']
];
}
return [
'success' => true,
'city' => $data['location']['name'],
'country' => $data['location']['country'],
'forecast' => $forecast
];
}
Example 2: Posting to a CRM System
This example shows how to submit a lead to a CRM system:
function my_crm_plugin_create_lead($lead_data) {
$api_url = 'https://api.mycrm.com/v1/leads';
$api_key = get_option('my_crm_plugin_api_key');
// Prepare data in format expected by the CRM
$body = [
'lead' => [
'first_name' => sanitize_text_field($lead_data['first_name']),
'last_name' => sanitize_text_field($lead_data['last_name']),
'email' => sanitize_email($lead_data['email']),
'phone' => sanitize_text_field($lead_data['phone']),
'source' => 'WordPress Website'
]
];
$args = [
'body' => json_encode($body),
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $api_key
],
'timeout' => 45,
'data_format' => 'body'
];
$response = wp_remote_post($api_url, $args);
if (is_wp_error($response)) {
error_log('CRM Lead Creation Error: ' . $response->get_error_message());
return false;
}
$response_code = wp_remote_retrieve_response_code($response);
$response_body = json_decode(wp_remote_retrieve_body($response), true);
if ($response_code === 201 || $response_code === 200) {
// Save the CRM lead ID to WordPress for future reference
if (isset($response_body['lead']['id'])) {
return $response_body['lead']['id'];
}
return true;
} else {
error_log('CRM Error: ' . json_encode($response_body));
return false;
}
}
Error Handling and Best Practices
Proper Error Handling
Always check for errors using is_wp_error()
:
function my_plugin_safe_request($url) {
$response = wp_remote_get($url);
if (is_wp_error($response)) {
// Log the error
error_log('API Request Error: ' . $response->get_error_message());
// Maybe notify admin
if (current_user_can('manage_options')) {
add_action('admin_notices', function() use ($response) {
echo '<div class="error"><p>API Error: ' .
esc_html($response->get_error_message()) .
'</p></div>';
});
}
return false;
}
$response_code = wp_remote_retrieve_response_code($response);
if ($response_code < 200 || $response_code >= 300) {
// Log the error
error_log('API HTTP Error: ' . $response_code);
return false;
}
return wp_remote_retrieve_body($response);
}
Caching API Responses
For better performance and to avoid hitting rate limits:
function my_plugin_cached_api_request($endpoint) {
// Generate a unique cache key
$cache_key = 'my_plugin_api_' . md5($endpoint);
// Try to get cached response
$cached_response = get_transient($cache_key);
if ($cached_response !== false) {
return $cached_response;
}
// Make the actual request
$api_url = 'https://api.example.com/' . $endpoint;
$response = wp_remote_get($api_url);
if (is_wp_error($response)) {
return false;
}
$data = wp_remote_retrieve_body($response);
// Cache the result (for 1 hour)
set_transient($cache_key, $data, HOUR_IN_SECONDS);
return $data;
}
Rate Limiting
To prevent hitting API rate limits:
function my_plugin_rate_limited_request($endpoint) {
$last_request_time = get_option('my_plugin_last_api_request', 0);
$current_time = time();
// Ensure we wait at least 1 second between requests
if ($current_time - $last_request_time < 1) {
// Wait a bit
sleep(1);
}
// Make the request
$response = wp_remote_get('https://api.example.com/' . $endpoint);
// Update the last request time
update_option('my_plugin_last_api_request', time());
return $response;
}
Security Considerations
When working with the WordPress HTTP API, keep these security practices in mind:
-
Never expose API keys in client-side code - Always make requests server-side
-
Validate and sanitize all data - Both data sent to APIs and received from them
-
Use HTTPS - Make requests to HTTPS URLs only
-
Set timeouts - Prevent long-hanging requests from affecting performance:
$args = [
'timeout' => 15, // 15 seconds max
];
$response = wp_remote_get($url, $args);
- Verify SSL - Keep the
sslverify
parameter true in production:
$args = [
'sslverify' => true, // Default, but good to be explicit
];
Summary
The WordPress HTTP API provides a powerful and standardized way to interact with external services from your plugins. By using functions like wp_remote_get()
, wp_remote_post()
, and wp_remote_request()
, you can:
- Send data to external APIs
- Retrieve data from third-party services
- Interact with web services securely
- Handle responses and errors gracefully
- Implement caching for better performance
This built-in functionality helps you develop plugins that integrate with external services without needing to reinvent the wheel or rely on additional libraries.
Additional Resources
- WordPress HTTP API Documentation
- WordPress Developer Reference: wp_remote_get()
- WordPress Developer Reference: wp_remote_post()
Exercises
-
Create a function that fetches posts from a remote WordPress site using the WordPress REST API.
-
Build a weather widget that displays the current temperature for a user's location using a free weather API.
-
Create a contact form that submits data to a third-party CRM system using their API.
-
Implement a caching system for API responses that invalidates the cache when certain actions occur in WordPress.
-
Create a function that posts updates to social media platforms whenever a new post is published on your WordPress site.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)