Originally published at kalyna.pro
Adding an AI chatbot or content assistant to WordPress doesn't require a developer — if you pick the right plugin. But if you want full control over the UX, conversation history, and logic, a custom PHP integration beats any off-the-shelf plugin. This guide covers both paths: the fastest no-code route (AI Engine plugin), and a custom PHP shortcode that calls the OpenAI API directly.
Option 1: No-Code — AI Engine Plugin
AI Engine by Jordy Meow handles API calls, conversation history, rate limiting, and UI. Install → connect your OpenAI key → drop a shortcode.
[mwai_chatbot
ai_name="Assistant"
start_sentence="Hi! How can I help?"
model="gpt-4o-mini"
context="You are a helpful assistant for a WordPress developer blog."
]
Limits: can't deeply customize UI, conversation data lives in plugin tables, adding logic requires hooks.
Option 2: Custom PHP — Direct API Call
Store your key in wp-config.php:
define( 'OPENAI_API_KEY', 'sk-...' );
Simple chat shortcode using wp_remote_post():
<?php
function ai_chat_shortcode( $atts ) {
$atts = shortcode_atts( [
'model' => 'gpt-4o-mini',
'system' => 'You are a helpful assistant.',
'title' => 'Ask me anything',
], $atts );
$answer = '';
if ( isset( $_POST['ai_question'] ) && wp_verify_nonce( $_POST['ai_nonce'], 'ai_chat' ) ) {
$question = sanitize_text_field( wp_unslash( $_POST['ai_question'] ) );
$answer = ai_chat_ask( $question, $atts['model'], $atts['system'] );
}
ob_start(); ?>
<div class="ai-chat-widget">
<h3><?php echo esc_html( $atts['title'] ); ?></h3>
<form method="post">
<?php wp_nonce_field( 'ai_chat', 'ai_nonce' ); ?>
<textarea name="ai_question" rows="3" placeholder="Type your question..."
style="width:100%;padding:8px;box-sizing:border-box"></textarea>
<button type="submit" style="margin-top:8px;padding:8px 16px">Ask</button>
</form>
<?php if ( $answer ) : ?>
<div style="margin-top:16px;padding:12px;background:#f5f5f5;border-radius:4px">
<?php echo wp_kses_post( nl2br( $answer ) ); ?>
</div>
<?php endif; ?>
</div>
<?php
return ob_get_clean();
}
add_shortcode( 'ai_chat', 'ai_chat_shortcode' );
function ai_chat_ask( string $question, string $model, string $system ): string {
$response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', [
'timeout' => 30,
'headers' => [
'Authorization' => 'Bearer ' . OPENAI_API_KEY,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode( [
'model' => $model,
'messages' => [
[ 'role' => 'system', 'content' => $system ],
[ 'role' => 'user', 'content' => $question ],
],
'max_tokens' => 500,
] ),
] );
if ( is_wp_error( $response ) ) {
return 'Error: ' . $response->get_error_message();
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return $body['choices'][0]['message']['content'] ?? 'No response.';
}
Use: [ai_chat title="Ask about WordPress" system="You are a WordPress expert." model="gpt-4o-mini"]
REST API Endpoint
<?php
add_action( 'rest_api_init', function () {
register_rest_route( 'ai/v1', '/chat', [
'methods' => 'POST',
'callback' => 'ai_rest_chat',
'permission_callback' => '__return_true',
'args' => [
'message' => [ 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ],
],
] );
} );
function ai_rest_chat( WP_REST_Request $request ): WP_REST_Response {
$message = $request->get_param( 'message' );
$response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', [
'timeout' => 30,
'headers' => [
'Authorization' => 'Bearer ' . OPENAI_API_KEY,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode( [
'model' => 'gpt-4o-mini',
'messages' => [
[ 'role' => 'system', 'content' => 'You are a helpful assistant.' ],
[ 'role' => 'user', 'content' => $message ],
],
'max_tokens' => 500,
] ),
] );
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return new WP_REST_Response( [ 'reply' => $body['choices'][0]['message']['content'] ?? '' ] );
}
const res = await fetch('/wp-json/ai/v1/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: 'What is prompt caching?' }),
});
const data = await res.json();
console.log(data.reply);
Using Claude API Instead
<?php
function claude_chat_ask( string $question, string $system = '' ): string {
$response = wp_remote_post( 'https://api.anthropic.com/v1/messages', [
'timeout' => 30,
'headers' => [
'x-api-key' => ANTHROPIC_API_KEY,
'anthropic-version' => '2023-06-01',
'Content-Type' => 'application/json',
],
'body' => wp_json_encode( [
'model' => 'claude-sonnet-5',
'max_tokens' => 500,
'system' => $system,
'messages' => [ [ 'role' => 'user', 'content' => $question ] ],
] ),
] );
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return $body['content'][0]['text'] ?? 'No response.';
}
Note the difference: Claude returns content[0].text, OpenAI returns choices[0].message.content.
Security Checklist
- Never expose API keys in JavaScript or HTML — all calls go server-side
- Use
wp_verify_nonce()on every form - Rate-limit public REST endpoints
- Sanitize all input with
sanitize_text_field() - Cap
max_tokensto avoid timeouts and cost blowout - Store API keys in
wp-config.php, not the database
Summary
-
No-code: AI Engine plugin +
[mwai_chatbot]— live in 5 minutes -
Custom PHP:
wp_remote_post()as shortcode or REST route — full control, no dependencies - Session history: store messages in PHP session, pass full array on each call
- Claude instead of ChatGPT: URL + header + response path change, logic stays the same
- Batch jobs: WP-CLI + OpenAI for bulk content generation
Related:
Top comments (0)