How to Connect the OpenAI API to WordPress Using PHP and wp_remote_post()


Introduction

Artificial intelligence (AI) is becoming an important part of modern web development. WordPress developers can use AI to generate content, summarize articles, build chatbots, analyze text, and automate repetitive tasks.

But do you need to install a large third-party plugin every time you want to add AI functionality to a WordPress website?

No. You can connect WordPress directly to the OpenAI API using PHP and WordPress’s built-in wp_remote_post() function.

This approach gives you greater control over your implementation, reduces dependencies, and helps you understand how AI integrations work behind the scenes.

In this tutorial, you’ll learn how to:

  • Understand how the OpenAI API works.
  • Create an OpenAI API key.
  • Store your API key securely in wp-config.php.
  • Send API requests using wp_remote_post().
  • Handle API responses and errors.
  • Configure timeouts and manage failed requests.
  • Build a reusable PHP function for future WordPress projects.

By the end, you’ll have a working foundation that you can extend into custom WordPress AI plugins and applications.

1. What Is the OpenAI API?

The OpenAI API allows your applications to send data to an AI model and receive a generated response.

For example, your WordPress website could send a prompt asking the model to summarize a blog post. The API processes the request and returns the generated text, which your PHP code can then display or save.

A typical request follows this process:

  1. A WordPress function receives some input.
  2. PHP prepares the API request.
  3. WordPress sends the request to OpenAI.
  4. OpenAI processes the input and returns a response.
  5. PHP checks the response and extracts the generated text.

For direct text generation, this tutorial uses the OpenAI Responses API.

API endpoint:

https://api.openai.com/v1/responses

Official documentation: https://developers.openai.com/api/docs/guides/text

2. What Is wp_remote_post()?

WordPress provides several HTTP API functions for communicating with external services.

The wp_remote_post() function sends an HTTP POST request and returns either a response array or a WP_Error object.

Its basic syntax is:

$response = wp_remote_post(
    $url,
    $args
);

The $url parameter specifies the API endpoint, while $args contains the request configuration.

Common options include:

  • headers — authentication and content type.
  • body — the data sent to the API.
  • timeout — the maximum time to wait for a response.
  • redirection — the maximum number of redirects to follow.

WordPress also provides helper functions such as wp_remote_retrieve_body() and wp_remote_retrieve_response_code() to process the returned response.

Reference: https://developer.wordpress.org/reference/functions/wp_remote_post/

3. Requirements Before Getting Started

Before writing the code, make sure you have:

  • A working WordPress website.
  • Basic PHP knowledge.
  • Access to your WordPress installation files.
  • An OpenAI API account with API access.
  • An API key and an API project with the necessary access and billing configuration.

Important: ChatGPT subscriptions and API usage are separate. Having a ChatGPT subscription does not automatically mean you have API credits.

You can access the API platform here:

https://platform.openai.com

4. Create an OpenAI API Key

Follow these steps:

  1. Sign in to the OpenAI API platform.
  2. Open the API key management section.
  3. Create a new secret API key for your project.
  4. Copy the key and store it securely.

Never publish your API key in a blog post, public GitHub repository, HTML page, or frontend JavaScript file.

If your key is exposed, revoke it and create a replacement.

5. Store the API Key in wp-config.php

Instead of writing your API key directly inside a PHP function, store it in the WordPress configuration file.

Open wp-config.php in your WordPress root directory.

Add the following line before the comment that says “That’s all, stop editing!”:

define(
    'OPENAI_API_KEY',
    'your-secret-api-key-here'
);

Replace your-secret-api-key-here with your actual API key.

For example, your configuration may look like this:

define(
    'OPENAI_API_KEY',
    'sk-your-actual-secret-key'
);

/* That's all, stop editing! Happy publishing. */

The example key is a placeholder; do not use it as a real credential.

Why is this approach better?

Keeping the key in configuration separates sensitive credentials from your application logic.

For production environments, a server environment variable or dedicated secrets manager can be even more suitable. Make sure your configuration file is not accidentally committed to a public repository or exposed through a server misconfiguration.

6. Make Your First API Request Using PHP

Now let’s write a simple function that sends a prompt to OpenAI and returns the generated text.

You can put this code into a small custom plugin or, for a quick local experiment, your child theme’s functions.php file.

For a reusable integration, a custom plugin is the better option.

function divphp_openai_generate_text( $prompt ) {

    // Check whether the API key is configured.
    if ( ! defined( 'OPENAI_API_KEY' ) || empty( OPENAI_API_KEY ) ) {
        return new WP_Error(
            'missing_api_key',
            'OpenAI API key is not configured.'
        );
    }

    // Prevent empty prompts.
    if ( ! is_string( $prompt ) || '' === trim( $prompt ) ) {
        return new WP_Error(
            'invalid_prompt',
            'Please provide a valid prompt.'
        );
    }

    // Prepare the API request.
    $request_body = array(
        'model' => 'gpt-4.1-mini',
        'input' => $prompt,
        'max_output_tokens' => 300,
    );

    // Send the request to OpenAI.
    $response = wp_remote_post(
        'https://api.openai.com/v1/responses',
        array(
            'headers' => array(
                'Authorization' => 'Bearer ' . OPENAI_API_KEY,
                'Content-Type'  => 'application/json',
            ),
            'body'        => wp_json_encode( $request_body ),
            'timeout'     => 30,
            'redirection' => 0,
        )
    );

    // Handle WordPress HTTP errors.
    if ( is_wp_error( $response ) ) {
        return new WP_Error(
            'openai_request_failed',
            'Unable to connect to the OpenAI API.'
        );
    }

    // Get the HTTP status code.
    $status_code = wp_remote_retrieve_response_code( $response );

    // Get and decode the response body.
    $body = wp_remote_retrieve_body( $response );
    $data = json_decode( $body, true );

    // Handle unsuccessful HTTP responses.
    if ( $status_code < 200 || $status_code >= 300 ) {
        return new WP_Error(
            'openai_api_error',
            'The OpenAI API returned an unsuccessful response.',
            array(
                'status' => $status_code,
            )
        );
    }

    // Validate the JSON response.
    if ( ! is_array( $data ) || ! empty( $data['error'] ) ) {
        return new WP_Error(
            'openai_invalid_response',
            'The API returned an invalid or unsuccessful response.'
        );
    }

    // Extract generated text from the Responses API output.
    $generated_text = '';

    if ( ! empty( $data['output'] ) && is_array( $data['output'] ) ) {

        foreach ( $data['output'] as $output_item ) {

            if (
                isset( $output_item['type'] ) &&
                'message' === $output_item['type'] &&
                ! empty( $output_item['content'] ) &&
                is_array( $output_item['content'] )
            ) {
                foreach ( $output_item['content'] as $content_item ) {

                    if (
                        isset( $content_item['type'] ) &&
                        'output_text' === $content_item['type'] &&
                        isset( $content_item['text'] )
                    ) {
                        $generated_text .= $content_item['text'];
                    }
                }
            }
        }
    }

    // Ensure that usable text was returned.
    if ( '' === trim( $generated_text ) ) {
        return new WP_Error(
            'openai_empty_output',
            'The API did not return any generated text.'
        );
    }

    return trim( $generated_text );
}

Understanding the function

Let’s examine the important parts of this implementation.

Step 1: Check the API key

The function checks whether OPENAI_API_KEY exists before attempting a request. This prevents unnecessary API calls when the configuration is missing.

Step 2: Validate the prompt

An empty or invalid prompt should not be sent to the API. Input validation also helps prevent accidental or unnecessary usage.

Step 3: Prepare the request body

The request contains the selected model, the input prompt, and an output-token limit.

The example uses gpt-4.1-mini. Model availability, capabilities, and pricing can change, so confirm that your chosen model is available to your API project before using the code.

Step 4: Send the HTTP request

wp_remote_post() sends the JSON request to the Responses API. The Authorization header carries the API key, while Content-Type tells the server that the body contains JSON.

Step 5: Handle connection errors

WordPress may return a WP_Error if it cannot complete the request. The is_wp_error() function lets us detect this condition.

Step 6: Check the HTTP status code

A request can reach the API successfully but still receive an error response. Checking the HTTP status code helps distinguish successful responses from authentication, quota, rate-limit, and other API errors.

Step 7: Extract the generated text

The Responses API returns an output structure. The function iterates over its message content and collects text entries rather than assuming the first output item will always contain the answer.

Official response reference: https://developers.openai.com/api/reference/resources/responses/methods/create

7. Test the Function in WordPress

Now let’s call the function with a simple prompt.

Add the following temporary test code after the function:

add_action( 'admin_notices', function () {

    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }

    // Run only when explicitly requested.
    if ( ! isset( $_GET['test_openai'] ) ) {
        return;
    }

    $result = divphp_openai_generate_text(
        'Explain WordPress hooks in three short bullet points.'
    );

    echo '<div class="notice notice-info"><p>';

    if ( is_wp_error( $result ) ) {

        echo esc_html( $result->get_error_message() );

    } else {

        echo '<strong>OpenAI response:</strong><br>';
        echo nl2br( esc_html( $result ) );

    }

    echo '</p></div>';
} );

After adding the code, sign in as an administrator and open this URL on your website:

https://yourwebsite.com/wp-admin/?test_openai=1

Replace yourwebsite.com with your site’s domain.

This temporary test runs the API call only when the query parameter is present and the current user has the manage_options capability.

Important: This is a development test, not a permanent admin tool. Remove the test code after verifying the integration. For a permanent test button, use a nonce-protected admin action instead.

If the request succeeds, you should see a short explanation of WordPress hooks in the admin area.

If the request fails, check your API key, API project access, billing configuration, server connectivity, and PHP error logs.

8. Understanding API Errors

External API requests can fail for several reasons. Your application should handle failures without exposing credentials or internal details to visitors.

Status or errorPossible reasonWhat to check
WP_ErrorNetwork, DNS, SSL, or timeout issueServer connectivity and WordPress HTTP settings
400Invalid request or unsupported parameterJSON body, model, and API schema
401Authentication failedAPI key and project credentials
403Access or permission restrictionProject permissions and model availability
429Rate limit or quota/billing issueRate limits, usage, and billing
5xxTemporary server-side problemRetry cautiously and check service status

These are common examples, not an exhaustive list. Consult the API error details and official documentation for the exact reason.

Official reference: https://developers.openai.com/api/reference/overview

Should you display the raw API error to visitors?

No. The example function returns generic errors so the caller can handle them safely.

In production, log only the diagnostic information you need, such as a status code or request identifier. Never log the API key or unnecessarily store prompts and personal data.

9. Why Is Timeout Management Important?

External services may respond slowly or become temporarily unavailable. A timeout helps prevent a PHP request from waiting indefinitely for an API response.

In our example, we used:

'timeout' => 30,

This sets a 30-second timeout for the HTTP request.

Choose a timeout that fits your use case. A short text-generation request may need less time, while a more complex task may need longer.

However, increasing the timeout does not solve every performance problem. If an AI operation takes too long for a normal page request, consider background processing, an asynchronous job, or a scheduled task.

10. Important Security Best Practices

A working API integration is only the first step. Before using it on a live website, follow these practices.

Keep the API key on the server

Never expose the key in JavaScript, HTML, shortcodes, or frontend network requests. The browser should communicate with your WordPress backend, and the backend should communicate with OpenAI.

Validate user input

If your function receives prompts from visitors, validate the input and impose reasonable length limits before sending it to the API.

Protect AJAX and REST endpoints

If you later expose this function through AJAX or a REST endpoint, use appropriate nonces, capability checks where relevant, authentication where necessary, and server-side rate limiting. Remember that a WordPress nonce is not a substitute for authorization or abuse prevention.

Control API usage

Set appropriate limits on input size and output tokens. Monitor usage and apply request limits to public-facing features to reduce abuse and unexpected costs.

Escape output

If you display generated text in WordPress HTML, escape it for the correct output context. For plain text, functions such as esc_html() are useful. Do not treat model output as trusted HTML.

Handle retries carefully

Temporary failures can sometimes be retried, but do not retry every error automatically. Use a limited retry policy with backoff for appropriate transient errors, and take care not to duplicate requests or increase costs unnecessarily.

11. When Should You Use This Approach?

Calling the OpenAI API directly from WordPress is useful when you want to build:

  • AI-powered content summarizers.
  • Custom WordPress chatbots.
  • AI-assisted SEO metadata tools.
  • Automatic image alt-text generators.
  • AI-based content classification.
  • Custom plugin features that process text.

For simple integrations, WordPress’s native HTTP API is often sufficient. A dedicated SDK or a more elaborate architecture may become useful as your application grows.

12. Common Mistakes to Avoid

Putting the API key in frontend JavaScript: This exposes your credentials to visitors.

Assuming every API response is successful: Always check both the WordPress HTTP result and the API status code.

Assuming the generated text is always at output[0]: The Responses API can return different output items. Iterate through the response structure.

Ignoring timeout errors: A failed request should be handled gracefully, with a useful message and appropriate diagnostics.

Calling the API on every page load: Make requests only when needed. For repeatable requests, caching may help reduce latency and API usage.

Trusting AI-generated content without review: Generated text can be incorrect, incomplete, or unsuitable for publication. Validate important outputs before saving or publishing them.

Conclusion

You can connect WordPress to OpenAI without installing a dedicated AI plugin. By combining wp_remote_post(), secure API-key configuration, request validation, error handling, and sensible timeout settings, you can create a reusable foundation for custom AI-powered WordPress features.

The next step is to improve this function with caching so repeated requests do not unnecessarily consume API usage.

Continue learning: In the next tutorial, we’ll explore how to cache OpenAI responses using the WordPress Transients API.

Frequently Asked Questions

1. Can I connect OpenAI to WordPress without a plugin?

Yes. You can call the OpenAI API directly from PHP using WordPress’s HTTP API. For functionality you want to reuse or maintain, placing the code in a custom plugin is generally preferable to modifying a parent theme.

2. Is wp_remote_post() better than cURL?

For typical WordPress integrations, wp_remote_post() is a convenient choice because it uses WordPress’s HTTP API and integrates with its existing HTTP handling. Direct cURL can work, but it is usually unnecessary for this example.

3. Is the OpenAI API free?

API usage is billed separately from ChatGPT subscriptions. Check the current API pricing, available credits, and project billing configuration before running requests.

4. Can I use this function to generate WordPress blog posts?

Yes. The function can return generated text that your application uses to prepare a draft. Before saving or publishing content, validate the output and use the appropriate WordPress permissions and APIs. Do not automatically publish unreviewed AI content without considering accuracy and quality.

5. Can I use this function inside a custom WordPress plugin?

Yes. You can move the function into your plugin’s PHP file and call it from an admin action, a protected AJAX handler, a REST endpoint, or another appropriate WordPress hook. Any public-facing entry point should include suitable validation, authorization, abuse prevention, and error handling.

6. Where can I learn more about the WordPress HTTP API?

Read the official WordPress developer documentation:


Related Tutorials