• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » WordPress Development Recipe: Secure token-based API authentication for OpenAI Completion API in custom plugins

WordPress Development Recipe: Secure token-based API authentication for OpenAI Completion API in custom plugins

Securing OpenAI API Access in WordPress Plugins

Integrating powerful AI capabilities, such as OpenAI’s Completion API, into custom WordPress plugins requires a robust and secure authentication strategy. Relying on hardcoded API keys or insecurely stored credentials is a significant security risk, exposing your application and potentially your users to unauthorized access and abuse. This recipe outlines a production-ready approach for token-based authentication, leveraging WordPress’s built-in options API for secure storage and a well-defined process for API interaction.

Storing API Keys Securely with WordPress Options API

The WordPress Options API provides a standardized and secure method for storing plugin-specific settings, including sensitive API keys. It’s crucial to avoid storing these directly in your plugin’s code. Instead, we’ll use `add_option()` and `update_option()` to manage the API key, ensuring it’s not exposed in version control and can be managed through the WordPress admin interface.

For enhanced security, consider using environment variables or a dedicated secrets management system for production deployments, fetching the key at runtime. However, for a self-contained WordPress plugin recipe, the Options API is the recommended approach. We’ll define a specific option name to avoid conflicts with other plugins or WordPress core.

Implementing API Key Storage and Retrieval

The following PHP snippet demonstrates how to create a settings page (or integrate into an existing one) to allow users to input and save their OpenAI API key. It also includes functions to retrieve the key securely.

Plugin Activation Hook for Initial Option Setup

When your plugin is activated, it’s good practice to set a default value for your API key option, perhaps an empty string or a placeholder, to ensure the option exists. This prevents errors when trying to retrieve it before it’s been set by the user.

<?php
/**
 * Plugin activation hook.
 * Sets up default options if they don't exist.
 */
function my_openai_plugin_activate() {
    // Ensure the OpenAI API key option is set.
    if ( false === get_option( 'my_openai_api_key' ) ) {
        add_option( 'my_openai_api_key', '', '', 'yes' ); // 'yes' for autoload
    }
}
register_activation_hook( __FILE__, 'my_openai_plugin_activate' );

/**
 * Retrieves the OpenAI API key from WordPress options.
 *
 * @return string|false The API key, or false if not set.
 */
function get_my_openai_api_key() {
    return get_option( 'my_openai_api_key', false );
}
?>

Admin Settings Page for API Key Input

This code snippet illustrates a basic WordPress settings page structure. You would typically register this page using the `admin_menu` hook and then use `settings_fields()` and `do_settings_sections()` within your page callback function.

<?php
/**
 * Registers the admin menu page and settings.
 */
function my_openai_plugin_admin_menu() {
    add_options_page(
        __( 'OpenAI API Settings', 'my-openai-plugin' ),
        __( 'OpenAI API', 'my-openai-plugin' ),
        'manage_options',
        'my-openai-plugin-settings',
        'my_openai_plugin_settings_page_callback'
    );

    // Register settings
    register_setting( 'my_openai_plugin_options_group', 'my_openai_api_key', 'my_openai_plugin_sanitize_api_key' );
    add_settings_section(
        'my_openai_plugin_main_section',
        __( 'OpenAI API Configuration', 'my-openai-plugin' ),
        'my_openai_plugin_main_section_callback',
        'my-openai-plugin-settings'
    );
    add_settings_field(
        'my_openai_api_key_field',
        __( 'OpenAI API Key', 'my-openai-plugin' ),
        'my_openai_api_key_field_callback',
        'my-openai-plugin-settings',
        'my_openai_plugin_main_section'
    );
}
add_action( 'admin_menu', 'my_openai_plugin_admin_menu' );

/**
 * Callback for the main settings section description.
 */
function my_openai_plugin_main_section_callback() {
    echo '<p>' . __( 'Enter your OpenAI API key below. This key is used to authenticate requests to the OpenAI API.', 'my-openai-plugin' ) . '</p>';
}

/**
 * Callback for the API key input field.
 */
function my_openai_api_key_field_callback() {
    $api_key = get_option( 'my_openai_api_key', '' );
    echo '<input type="password" name="my_openai_api_key" value="' . esc_attr( $api_key ) . '" class="regular-text" />';
    echo '<p class="description">' . __( 'Get your API key from the OpenAI platform dashboard.', 'my-openai-plugin' ) . '</p>';
}

/**
 * Sanitize the API key before saving.
 *
 * @param string $input The raw input from the user.
 * @return string The sanitized API key.
 */
function my_openai_plugin_sanitize_api_key( $input ) {
    // Basic sanitization: remove whitespace.
    // For production, consider more robust validation if OpenAI provides a format.
    return sanitize_text_field( trim( $input ) );
}

/**
 * Callback function for the settings page.
 */
function my_openai_plugin_settings_page_callback() {
    ?>
    <div class="wrap">
        <h1><?php echo get_admin_page_title(); ?></h1>
        <form action="options.php" method="post">
            <?php
            settings_fields( 'my_openai_plugin_options_group' );
            do_settings_sections( 'my-openai-plugin-settings' );
            submit_button();
            ?>
        </form>
    </div>
    <?php
}
?>

Making Secure API Calls to OpenAI

Once the API key is securely stored, we can proceed to make authenticated requests to the OpenAI Completion API. This involves constructing the correct HTTP request, including the authorization header and the request payload. We’ll use WordPress’s `wp_remote_post()` function, which is designed for making secure HTTP requests and handles many underlying complexities.

Constructing the API Request

The OpenAI API requires an `Authorization` header with the format `Bearer YOUR_API_KEY`. The request body should be a JSON object containing the model, prompt, and other parameters as per the OpenAI API documentation.

<?php
/**
 * Sends a request to the OpenAI Completion API.
 *
 * @param string $prompt The text prompt for the AI.
 * @param array  $args   Additional arguments for the API call (e.g., model, max_tokens).
 * @return array|WP_Error An array containing the API response, or a WP_Error object on failure.
 */
function call_openai_completion_api( $prompt, $args = array() ) {
    $api_key = get_my_openai_api_key();

    if ( ! $api_key ) {
        return new WP_Error( 'openai_api_error', __( 'OpenAI API key is not configured.', 'my-openai-plugin' ) );
    }

    $api_url = 'https://api.openai.com/v1/completions'; // Or 'v1/chat/completions' for chat models

    $default_args = array(
        'model'      => 'text-davinci-003', // Default model, adjust as needed
        'prompt'     => $prompt,
        'max_tokens' => 150,
        'temperature' => 0.7,
    );

    $request_args = wp_parse_args( $args, $default_args );

    $body = json_encode( $request_args );

    $headers = array(
        'Authorization' => 'Bearer ' . $api_key,
        'Content-Type'  => 'application/json',
    );

    $response = wp_remote_post( $api_url, array(
        'method'  => 'POST',
        'headers' => $headers,
        'body'    => $body,
        'timeout' => 60, // Set a reasonable timeout
    ) );

    if ( is_wp_error( $response ) ) {
        return $response; // Return the WP_Error object
    }

    $response_code = wp_remote_retrieve_response_code( $response );
    $response_body = wp_remote_retrieve_body( $response );
    $decoded_body  = json_decode( $response_body, true );

    if ( $response_code !== 200 || ! $decoded_body ) {
        $error_message = isset( $decoded_body['error']['message'] ) ? $decoded_body['error']['message'] : __( 'An unknown error occurred.', 'my-openai-plugin' );
        return new WP_Error( 'openai_api_error', sprintf( __( 'OpenAI API Error (%d): %s', 'my-openai-plugin' ), $response_code, $error_message ) );
    }

    return $decoded_body;
}
?>

Handling API Responses and Errors

The `call_openai_completion_api` function returns either a decoded JSON response array or a `WP_Error` object. It’s crucial to check for `is_wp_error()` before attempting to process the response data. The function also attempts to extract specific error messages from the OpenAI API response for better debugging.

Example Usage in a Custom WordPress Plugin Feature

Here’s a practical example of how you might use the `call_openai_completion_api` function within a shortcode or a backend process. This example demonstrates generating a product description based on keywords.

Shortcode Example: Generating Product Descriptions

This shortcode allows users to input keywords and get an AI-generated product description.

<?php
/**
 * Shortcode to generate product descriptions using OpenAI.
 * Usage: [generate_product_description keywords="eco-friendly, sustainable, bamboo"]
 */
function generate_product_description_shortcode( $atts ) {
    $atts = shortcode_atts( array(
        'keywords' => '',
    ), $atts, 'generate_product_description' );

    if ( empty( $atts['keywords'] ) ) {
        return '<p>' . __( 'Please provide keywords for the product description.', 'my-openai-plugin' ) . '</p>';
    }

    $prompt = sprintf( __( 'Generate a compelling and concise product description for an item with the following keywords: %s. Focus on benefits and unique selling points.', 'my-openai-plugin' ), esc_html( $atts['keywords'] ) );

    $api_response = call_openai_completion_api( $prompt, array(
        'model'      => 'text-davinci-003', // Or 'gpt-3.5-turbo' if using chat completions endpoint
        'max_tokens' => 200,
        'temperature' => 0.8,
    ) );

    if ( is_wp_error( $api_response ) ) {
        return '<p style="color: red;">' . sprintf( __( 'Error generating description: %s', 'my-openai-plugin' ), $api_response->get_error_message() ) . '</p>';
    }

    // Assuming the response structure for text-davinci-003
    if ( isset( $api_response['choices'][0]['text'] ) ) {
        $description = trim( $api_response['choices'][0]['text'] );
        return '<div class="product-description"><p>' . nl2br( esc_html( $description ) ) . '</p></div>';
    } else {
        return '<p style="color: orange;">' . __( 'Could not retrieve a valid description from OpenAI.', 'my-openai-plugin' ) . '</p>';
    }
}
add_shortcode( 'generate_product_description', 'generate_product_description_shortcode' );
?>

Advanced Considerations and Best Practices

Rate Limiting and Usage Monitoring

OpenAI imposes rate limits on API usage. Implement client-side or server-side logic to manage these limits. This could involve caching responses for identical prompts, implementing exponential backoff for retries, or displaying user-friendly messages when limits are reached. WordPress’s Transients API can be invaluable for caching.

Error Handling and User Feedback

Provide clear and actionable feedback to users when API calls fail. Instead of generic error messages, inform them if their API key is invalid, if they’ve exceeded rate limits, or if there’s a temporary service issue. Logging these errors server-side using `error_log()` or a dedicated logging plugin is essential for debugging.

Security Hardening

Always sanitize and validate any user-provided input that is used in API prompts. Never expose your API key directly in client-side JavaScript. For highly sensitive applications, consider using a proxy service or a serverless function to abstract the API key from the WordPress environment entirely, adding another layer of security.

Model Selection and Cost Management

Different OpenAI models have varying costs and capabilities. Clearly document which models your plugin uses and provide options for users to select models if appropriate. Educate users about potential costs associated with API usage, especially for high-volume applications.

Using the Chat Completions API (v1/chat/completions)

For newer models like GPT-3.5 Turbo and GPT-4, you’ll need to use the Chat Completions API. The structure of the request and response differs slightly. The `messages` parameter replaces `prompt`, and it’s an array of message objects with `role` and `content` keys.

<?php
/**
 * Sends a request to the OpenAI Chat Completions API.
 *
 * @param array $messages An array of message objects (e.g., [{'role': 'user', 'content': 'Hello'}]).
 * @param array $args     Additional arguments for the API call (e.g., model, temperature).
 * @return array|WP_Error An array containing the API response, or a WP_Error object on failure.
 */
function call_openai_chat_completion_api( $messages, $args = array() ) {
    $api_key = get_my_openai_api_key();

    if ( ! $api_key ) {
        return new WP_Error( 'openai_api_error', __( 'OpenAI API key is not configured.', 'my-openai-plugin' ) );
    }

    $api_url = 'https://api.openai.com/v1/chat/completions';

    $default_args = array(
        'model'      => 'gpt-3.5-turbo', // Default chat model
        'messages'   => $messages,
        'max_tokens' => 150,
        'temperature' => 0.7,
    );

    $request_args = wp_parse_args( $args, $default_args );

    $body = json_encode( $request_args );

    $headers = array(
        'Authorization' => 'Bearer ' . $api_key,
        'Content-Type'  => 'application/json',
    );

    $response = wp_remote_post( $api_url, array(
        'method'  => 'POST',
        'headers' => $headers,
        'body'    => $body,
        'timeout' => 60,
    ) );

    if ( is_wp_error( $response ) ) {
        return $response;
    }

    $response_code = wp_remote_retrieve_response_code( $response );
    $response_body = wp_remote_retrieve_body( $response );
    $decoded_body  = json_decode( $response_body, true );

    if ( $response_code !== 200 || ! $decoded_body ) {
        $error_message = isset( $decoded_body['error']['message'] ) ? $decoded_body['error']['message'] : __( 'An unknown error occurred.', 'my-openai-plugin' );
        return new WP_Error( 'openai_api_error', sprintf( __( 'OpenAI API Error (%d): %s', 'my-openai-plugin' ), $response_code, $error_message ) );
    }

    return $decoded_body;
}

// Example usage for chat completions:
/*
$chat_messages = array(
    array('role' => 'system', 'content' => 'You are a helpful assistant.'),
    array('role' => 'user', 'content' => 'Tell me a short story about a brave knight.'),
);
$chat_response = call_openai_chat_completion_api( $chat_messages, array('max_tokens' => 300) );

if ( ! is_wp_error( $chat_response ) && isset( $chat_response['choices'][0]['message']['content'] ) ) {
    echo '<p>' . esc_html( $chat_response['choices'][0]['message']['content'] ) . '</p>';
} else {
    echo '<p style="color: red;">' . ( is_wp_error( $chat_response ) ? $chat_response->get_error_message() : __( 'Failed to get story.', 'my-openai-plugin' ) ) . '</p>';
}
*/
?>

By implementing these strategies, you can securely integrate OpenAI’s powerful AI capabilities into your custom WordPress plugins, providing advanced features while maintaining a strong security posture.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Step-by-Step Guide to building a custom real-time audit dashboard block for Gutenberg using Svelte standalone templates
  • Designing audit logs for enterprise WordPress setups tracking internal user modifications to custom product catalogs
  • Troubleshooting broken WP-Cron schedules in production when using modern Classic Core PHP wrappers
  • WordPress Development Recipe: Leveraging PHP 8.x Attributes to build type-safe, auto-wired hooks
  • Debugging Guide: Diagnosing broken WP-Cron schedules in multi-site network environments with modern tools

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (43)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (136)
  • WordPress Plugin Development (148)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • Step-by-Step Guide to building a custom real-time audit dashboard block for Gutenberg using Svelte standalone templates
  • Designing audit logs for enterprise WordPress setups tracking internal user modifications to custom product catalogs
  • Troubleshooting broken WP-Cron schedules in production when using modern Classic Core PHP wrappers

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala