How to secure a WordPress AI integration

Last month a client with a busy e-commerce site called me. A developer had built some AI features for them (automated product descriptions and a chatbot), but the admin panel had slowed to a crawl. What worried them most was security, specifically how those AI services were being called. They were right to worry. This was not a caching problem, it was a problem with the whole WordPress AI integration.

When I looked at what they had, my stomach dropped a little. They were calling the AI API straight from the front end, with a hardcoded API key sitting in a JavaScript file. Anyone with basic dev tools could grab that key. Performance was suffering too, because every request was a synchronous block.

A safer way to build a WordPress AI integration

The quick “fix” people reach for is to throw a cache on it. That does cut the number of calls, but it does nothing for security. And if your AI responses need to be dynamic or personalized, caching turns into a liability that serves up stale data. The fix that actually matters for a serious WordPress AI integration is at the architectural level: you need a secure, server-side proxy.

Your WordPress site becomes the middleman. The front end talks to your WordPress backend, and the backend talks to the external AI API. Your API keys stay on your server, in environment variables or the WordPress options table, never in public-facing code. WordPress already has the tools for this: the REST API and wp_remote_post.

<?php
/**
 * Register a custom REST API endpoint for AI integration.
 */
function bbioon_register_ai_api_route() {
    register_rest_route( 'bbioon/v1', '/ai-request', array(
        'methods' => 'POST',
        'callback' => 'bbioon_handle_ai_request',
        'permission_callback' => function() {
            return current_user_can( 'edit_posts' ); // Or a more specific capability
        },
    ) );
}
add_action( 'rest_api_init', 'bbioon_register_ai_api_route' );

/**
 * Handle the AI request securely on the server side.
 *
 * @param WP_REST_Request $request Full data about the request.
 * @return WP_REST_Response
 */
function bbioon_handle_ai_request( $request ) {
    $api_key = get_option( 'bbioon_ai_api_key' ); // Fetch API key securely
    if ( empty( $api_key ) ) {
        return new WP_REST_Response( array( 'message' => 'AI API Key not configured.' ), 500 );
    }

    $prompt = $request->get_param( 'prompt' );
    if ( empty( $prompt ) ) {
        return new WP_REST_Response( array( 'message' => 'Prompt is required.' ), 400 );
    }

    $api_url = 'https://api.external-ai.com/v1/generate'; // Replace with actual AI service endpoint
    $body = json_encode( array(
        'prompt' => $prompt,
        'model'  => 'text-davinci-003', // Example model
    ) );

    $args = array(
        'body'        => $body,
        'headers'     => array(
            'Content-Type'  => 'application/json',
            'Authorization' => 'Bearer ' . $api_key,
        ),
        'method'      => 'POST',
        'timeout'     => 45, // Increase timeout for potentially long AI responses
        'data_format' => 'body',
    );

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

    if ( is_wp_error( $response ) ) {
        return new WP_REST_Response( array( 'message' => 'Error communicating with AI service: ' . $response->get_error_message() ), 500 );
    }

    $body = wp_remote_retrieve_body( $response );
    $data = json_decode( $body, true );

    // Process the AI response as needed
    if ( isset( $data['choices'][0]['text'] ) ) {
        return new WP_REST_Response( array( 'ai_response' => $data['choices'][0]['text'] ), 200 );
    } else {
        return new WP_REST_Response( array( 'message' => 'Unexpected AI response format.', 'raw_response' => $data ), 500 );
    }
}

// Example of how to add the API key to options (e.g., from an admin settings page)
// update_option( 'bbioon_ai_api_key', 'YOUR_ACTUAL_AI_API_KEY' );
?>

This snippet sets up a custom REST API endpoint in WordPress. Your JavaScript, handled safely on your side, hits /wp-json/bbioon/v1/ai-request with the user’s prompt. The backend takes that prompt, adds your secret API key, calls the external AI service, and returns the result. The API key never reaches the client side. Reading through the Core AI chat summaries, like the one from September 4, 2025 on make.wordpress.org/ai, the community is clearly settling on standardized ways to handle this, with initiatives like the PHP AI Client and WordPress AI Client. All of it rests on server-side architecture.

Fix the architecture, not the symptoms

The lesson is simple: do not chase quick fixes for what are really architectural flaws. It is tempting to just get something working, but with external APIs, and AI services in particular, security and performance are not optional. Build it right from the start and use WordPress’s own server-side capabilities to manage your API calls. That locks down your credentials and gives you control over rate limiting, error handling, and how data is processed before anything reaches the client. Trust me, it saves you a lot of pain later.

This stuff gets complicated fast. If you are tired of debugging someone else’s mess and just want your site to work, drop my team a line. We have probably seen it before.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.