Who This Guide Is For
This guide is for developers building a WordPress plugin that communicates with an external API — whether that is a SaaS platform, a data provider, an AI service, or your own backend. You understand WordPress plugin basics (hooks, filters, admin menus) and want to build a plugin that is reliable in production, handles API failures gracefully, caches responses intelligently, and follows the patterns that prevent the most common integration failures.
Before You Start
You should have a working WordPress development environment, familiarity with the WordPress plugin API (actions, filters, options API), and access to the external API you are integrating with including its documentation and credentials. This guide covers the plugin architecture and API communication patterns, not how to register a plugin or create admin menus from scratch. If you need those fundamentals, the WordPress Plugin Handbook covers them well.
You should also understand the external API’s rate limits, authentication method, and response format. These constraints directly shape your plugin’s architecture — a plugin that calls an API with a 60-request-per-minute limit needs a fundamentally different caching strategy than one calling an API with no rate limits.
Step 1: Structure the Plugin for Maintainability
A plugin that integrates with an external API has more moving parts than a typical WordPress plugin. Structure it to keep those parts separated and testable.
File organisation should separate concerns clearly. At minimum, maintain distinct areas for the main plugin bootstrap file (the file with the plugin header), an admin area for settings pages and admin-only functionality, a core area for the API client class and data processing logic, and if applicable a public-facing area for frontend output. Avoid putting everything in a single file — API integration plugins grow quickly, and a monolithic file becomes unmanageable.
The API client class is the single point of contact between your plugin and the external API. Every HTTP request to the API goes through this class. It handles authentication (adding API keys or tokens to requests), constructs URLs, sends requests using the WordPress HTTP API, parses responses, and translates API errors into a format your plugin can handle. No other part of the plugin should make HTTP requests directly.
This centralisation matters because when the API changes (and it will — endpoints move, authentication methods evolve, response formats change), you update one class rather than hunting through the codebase for scattered HTTP calls.
Settings management should use the WordPress Options API for storing configuration (API keys, connection preferences, feature toggles). Define sensible defaults for every setting so the plugin works in a degraded mode before the user configures it, rather than throwing errors.
Step 2: Implement API Communication Properly
WordPress provides a purpose-built HTTP API that handles the complexities of making external requests across different hosting environments. Use it rather than cURL or file_get_contents, which fail silently on many WordPress hosts.
Use wp_remote_get and wp_remote_post for all API requests. These functions handle SSL verification, follow redirects, respect proxy configurations, and work consistently across hosting environments that may have different PHP configurations. They return a standardised response format that includes the status code, headers, and body.
Set appropriate timeouts. The default timeout for WordPress HTTP requests is five seconds. For APIs that perform complex operations or return large responses, this may be too short. Set the timeout explicitly in your request arguments — 15 seconds is reasonable for most APIs, 30 seconds for operations you know are slow. But never set timeouts longer than 30 seconds for requests triggered by page loads, because the user is waiting.
Handle every response status. A successful response (200-299) should be parsed and returned. Client errors (400-499) indicate a problem with the request — log the error and return a meaningful message to the calling code. Server errors (500-599) indicate the API is having problems — log the error, return a failure indicator, and do not retry immediately (the API is already struggling). Connection failures (wp_remote_get returns a WP_Error) indicate network issues — log the error and ensure the plugin degrades gracefully rather than breaking the WordPress site.
Authentication management depends on the API’s auth method. For API key authentication, store the key using the Options API (encrypted if the API key grants write access or access to sensitive data). For OAuth, store the access token and refresh token, and implement automatic token refresh when the access token expires. Never log API keys or tokens — even in debug mode.
Step 3: Implement Response Caching
Uncached API calls on every page load will exhaust rate limits, slow down the site, and create a dependency on the external API’s availability for every page render. Caching is not optional for production plugins.
Use the WordPress Transients API for caching API responses. Transients are cached values with an expiration time, stored in the database (or in object cache if the site uses one). They are the WordPress-native way to cache temporary data and work across all hosting environments.
Set cache durations based on data volatility. Data that changes rarely (configuration, metadata) can be cached for 12 to 24 hours. Data that changes periodically (analytics, reports) should be cached for 15 minutes to an hour. Data that must be current (real-time status, live pricing) should have very short cache durations or should not be cached at all.
Cache at the right granularity. If your API returns a list of items and each item is displayed on a different page, cache each item individually rather than caching the entire list. This way, when one item is updated, you invalidate only that item’s cache rather than the entire dataset.
Implement cache invalidation for user-initiated actions. If the user triggers a sync or update from the plugin’s settings page, clear the relevant caches and fetch fresh data. Provide a manual cache-clearing option in the settings for situations where cached data is visibly stale.
Stale-while-revalidate is a powerful pattern for API plugins. When the cache expires, serve the stale cached data immediately (so the page loads fast) while triggering a background refresh. The next request gets the updated data. This prevents the API call from blocking page loads while still keeping data reasonably fresh. WordPress’s wp_schedule_single_event function can trigger the background refresh.
Step 4: Handle Activation, Deactivation, and Uninstall
Lifecycle hooks are where plugins commonly cut corners, and the result is leftover data, broken site states, and poor user experience.
Activation should verify that the environment meets the plugin’s requirements (PHP version, WordPress version, required extensions), create any database tables the plugin needs (using dbDelta for safe, idempotent table creation), set default option values, and schedule any cron events the plugin uses for background processing. Activation should not make API calls — the user may not have configured their API credentials yet.
Deactivation should clean up runtime state without destroying data. Clear scheduled cron events (use wp_clear_scheduled_hook for each event the plugin registered), flush caches and transients the plugin created, and deregister any custom rewrite rules (then flush rewrite rules). Do not delete the plugin’s options or database tables on deactivation — the user may reactivate the plugin later and expect their settings to be preserved.
Uninstall is where you remove everything. Delete all options (use delete_option for each option the plugin created), drop custom database tables, delete all transients with your plugin’s prefix, and remove any files the plugin created in the uploads directory. Implement this in an uninstall.php file (not a deactivation hook) so it only runs when the user explicitly deletes the plugin.
The distinction between deactivation and uninstall is important. Deactivation is “turn it off.” Uninstall is “remove it completely.” Conflating the two frustrates users who temporarily deactivate a plugin and lose all their configuration.
Step 5: Build the Settings Page
The settings page is the user’s primary interface with your plugin. For an API integration, it must handle credential management, connection status, and configuration.
Credential entry and validation should be the first thing the user sees. Provide fields for the API key or credentials, and a “Test Connection” button that makes a lightweight API call to verify the credentials work. Display a clear success or failure message. Store credentials only after successful validation.
Connection status display should be visible on the settings page at all times. Show whether the plugin is currently connected, when the last successful API call occurred, and whether there are any errors. This is the first place a user looks when something stops working.
Configuration options should be minimal and well-documented. For each option, show a label, a description of what it does, and the default value. Group related settings logically. Do not expose internal technical settings (cache durations, retry counts) unless the user genuinely needs to adjust them — sensible defaults are better than configuration overload.
Error display and logging should surface API errors in a way that helps the user (or their developer) diagnose issues. Show the most recent error on the settings page with a timestamp. For detailed diagnostics, log errors to a plugin-specific log file or to the WordPress debug log. Include the request URL (without credentials), the response status code, and a sanitised version of the error message.
Common Mistakes
- Using cURL directly instead of the WordPress HTTP API. cURL calls fail on many hosting environments due to SSL, proxy, or PHP configuration differences. The WordPress HTTP API handles these automatically.
- No caching. Calling the API on every page load exhausts rate limits, adds latency to every page, and means a five-minute API outage takes your site down. Cache responses with appropriate TTLs.
- Deleting data on deactivation. Users deactivate plugins temporarily for debugging, testing, or site maintenance. If the plugin deletes its settings on deactivation, they lose all configuration and must set it up again. Delete data only on uninstall.
- No timeout on HTTP requests. A request without a timeout will hang for the server’s default socket timeout (often 60 seconds or more), blocking the page load and potentially causing a white screen.
- Storing API keys in plain text in the database. While WordPress’s Options API does not natively encrypt values, sensitive credentials should be encrypted before storage using a library or at minimum stored in wp-config.php as constants.
What Good Looks Like
A well-built WordPress plugin with API integration has: a dedicated API client class that centralises all HTTP communication, response caching via transients with appropriate TTLs and invalidation, graceful degradation when the API is unavailable (cached data or informative messages rather than errors), clean activation and uninstall hooks that create and remove resources properly, a settings page with connection testing and status display, and error handling that logs diagnostics without breaking the site.
Next Steps
For the webhook patterns that let your API push updates to the plugin, How to Set Up Webhook Integrations covers the receiving side. For the API design behind the external service, How to Structure a REST API covers the design patterns. For WordPress site management over time, see How to Maintain a WordPress Site Long-Term.