DEV Community

Cover image for Integrating Claude AI Into Your WordPress Plugins
El Condorito
El Condorito

Posted on

Integrating Claude AI Into Your WordPress Plugins

I'll be honest with you: when I first considered integrating AI into WordPress plugins, I thought it was overkill. Another buzzword-driven feature that clients would never use. Then I built a project estimator for my woocommerce agency, and everything changed.

That simple tool—asking clients natural language questions about their WordPress project and generating accurate estimates—has become one of my best lead qualification mechanisms. No more back-and-forth emails trying to understand vague requirements. No more wildly inaccurate ballpark figures.

In this article, I'll show you exactly how to integrate Claude AI into your WordPress plugins using the official PHP SDK, with real, production-ready examples you can use today.

Why Claude for WordPress?

Before we dive into code, let's address the elephant in the room: why Claude specifically?

I've tested OpenAI's GPT models, Google's Gemini, and a few others. Here's why Claude won for my WordPress projects:

  • Longer context windows: Claude can handle massive amounts of context (200K+ tokens). Perfect for analyzing entire plugin configurations or customer requirements.
  • Better instruction following: When I tell Claude to output JSON in a specific format, it actually does it consistently.
  • Reasonable pricing: For typical WordPress use cases (a few hundred requests per day), you're looking at $5-20/month. Not free, but far from breaking the bank.
  • Excellent PHP SDK: The community-maintained SDK is clean, well-documented, and actively maintained.

Setting up the Claude PHP SDK

First, install the SDK via Composer. If you're building a WordPress plugin that will be distributed, you'll want to include the vendor directory or use Mozart to prefix dependencies.

composer require claude-php/claude-php-sdk
Enter fullscreen mode Exit fullscreen mode

For our examples, I'll assume you're building a custom plugin for your own site or clients. Here's the basic setup:

<?php
/**
 * Plugin Name: Claude Integration Examples
 * Description: Real-world Claude AI integration for WordPress
 * Version: 1.0.0
 */

// Include Composer autoloader
require_once plugin_dir_path(__FILE__) . 'vendor/autoload.php';

use ClaudePHP\Client;

class Claude_WP_Integration {

    private $client;

    public function __construct() {
        $api_key = defined('CLAUDE_API_KEY') ? CLAUDE_API_KEY : '';

        if (empty($api_key)) {
            add_action('admin_notices', [$this, 'missing_api_key_notice']);
            return;
        }

        $this->client = new Client($api_key);

        // Hook into WordPress
        add_action('wp_ajax_estimate_project', [$this, 'estimate_project']);
        add_action('wp_ajax_nopriv_estimate_project', [$this, 'estimate_project']);
    }

    public function missing_api_key_notice() {
        echo '<div class="notice notice-error"><p>';
        echo 'Claude API key is missing. Add CLAUDE_API_KEY to your wp-config.php';
        echo '</p></div>';
    }
}

new Claude_WP_Integration();
Enter fullscreen mode Exit fullscreen mode

Important: Never hardcode your API key in your plugin. Add it to wp-config.php:

define('CLAUDE_API_KEY', 'sk-ant-api03-your-key-here');
Enter fullscreen mode Exit fullscreen mode

Real-world example #1: Intelligent project estimator

This is the use case that sold me on Claude integration. A potential client fills out a form describing their project in plain English, and Claude analyzes it to provide a detailed estimate.

Here's the complete implementation:

public function estimate_project() {
    check_ajax_referer('project_estimate_nonce', 'nonce');

    $project_description = sanitize_textarea_field($_POST['description']);
    $budget_range = sanitize_text_field($_POST['budget']);
    $timeline = sanitize_text_field($_POST['timeline']);

    // Build the prompt with context about your agency
    $prompt = $this->build_estimator_prompt($project_description, $budget_range, $timeline);

    try {
        $response = $this->client->messages()->create([
            'model' => 'claude-sonnet-4-20250514',
            'max_tokens' => 2048,
            'messages' => [
                [
                    'role' => 'user',
                    'content' => $prompt
                ]
            ]
        ]);

        // Extract the text content
        $estimate = $response['content'][0]['text'];

        // Store in database for follow-up
        $this->save_estimate_to_db($project_description, $estimate);

        wp_send_json_success([
            'estimate' => $estimate,
            'tokens_used' => $response['usage']['input_tokens'] + $response['usage']['output_tokens']
        ]);

    } catch (Exception $e) {
        error_log('Claude API Error: ' . $e->getMessage());
        wp_send_json_error('Unable to generate estimate. Please try again.');
    }
}

private function build_estimator_prompt($description, $budget, $timeline) {
    return "You are an experienced WordPress/WooCommerce developer providing project estimates.

AGENCY CONTEXT:
- We specialize in custom WordPress and WooCommerce solutions
- We don't use page builders; everything is custom coded
- Our hourly rate is €80-120 depending on complexity
- We handle complex projects that other agencies abandon

CLIENT PROJECT DESCRIPTION:
{$description}

BUDGET INDICATED: {$budget}
DESIRED TIMELINE: {$timeline}

Please analyze this project and provide:

1. A breakdown of the main components/features required
2. Estimated hours for each component
3. Total estimated cost range
4. Realistic timeline
5. Potential risks or challenges
6. Questions we should ask the client for clarity

Format your response in clear sections. Be honest about complexity - we'd rather lose a bad-fit project than overpromise.";
}

private function save_estimate_to_db($description, $estimate) {
    global $wpdb;

    $wpdb->insert(
        $wpdb->prefix . 'project_estimates',
        [
            'description' => $description,
            'estimate' => $estimate,
            'created_at' => current_time('mysql'),
            'user_ip' => $_SERVER['REMOTE_ADDR']
        ],
        ['%s', '%s', '%s', '%s']
    );
}
Enter fullscreen mode Exit fullscreen mode

The frontend form (simplified):

jQuery(document).ready(function($) {
    $('#project-estimate-form').on('submit', function(e) {
        e.preventDefault();

        const formData = {
            action: 'estimate_project',
            nonce: claude_ajax.nonce,
            description: $('#project-description').val(),
            budget: $('#budget-range').val(),
            timeline: $('#timeline').val()
        };

        $('#estimate-result').html('<p>Analyzing your project...</p>');

        $.post(claude_ajax.ajax_url, formData, function(response) {
            if (response.success) {
                $('#estimate-result').html(
                    '<div class="estimate-box">' + 
                    response.data.estimate.replace(/\n/g, '<br>') + 
                    '</div>'
                );
                console.log('Tokens used:', response.data.tokens_used);
            } else {
                $('#estimate-result').html('<p class="error">' + response.data + '</p>');
            }
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

What this gets you

When a client submits:

"We need an e-commerce site for selling custom furniture. Customers should be able to choose wood type, dimensions, and finishes. We need 3D previews if possible. Budget around €15,000."

Claude responds with something like:

PROJECT BREAKDOWN:

1. WooCommerce Base Setup (8-12 hours)
   - Custom theme development
   - Product structure for configurable furniture
   - Payment gateway integration

2. Product Configurator (40-60 hours)
   - Custom field system for wood types, dimensions, finishes
   - Dynamic pricing calculation
   - Configuration save/load functionality

3. 3D Preview System (60-80 hours) ⚠️ CHALLENGE
   - Integration with Three.js or similar
   - 3D model generation based on configurations
   - This is the most complex part and might push budget

ESTIMATED TOTAL: €12,000 - €18,000
REALISTIC TIMELINE: 8-12 weeks

BUDGET ASSESSMENT:
Your €15,000 budget is in the right range, but the 3D preview feature 
is ambitious. We should discuss either simplifying to 2D renders or 
allocating additional budget.

QUESTIONS FOR CLIENT:
- Do you have existing 3D models of your furniture pieces?
- How many product variations are we talking about?
- Do you need inventory management integration?
Enter fullscreen mode Exit fullscreen mode

This level of detail, from a simple form submission, immediately positions you as thorough and professional.

Real-world example #2: Smart content validation

Here's a less obvious but incredibly useful application: using Claude to validate and enhance user-submitted content.

Imagine you run a directory site where businesses submit listings. Instead of just checking for required fields, you can use Claude to:

  • Detect spam or low-quality submissions
  • Suggest improvements
  • Flag potential policy violations
public function validate_business_listing() {
    check_ajax_referer('listing_validation_nonce', 'nonce');

    $business_name = sanitize_text_field($_POST['business_name']);
    $description = sanitize_textarea_field($_POST['description']);
    $category = sanitize_text_field($_POST['category']);

    $validation_prompt = "You are validating business listing submissions for a local directory.

SUBMISSION:
Business Name: {$business_name}
Category: {$category}
Description: {$description}

Please analyze this submission and respond in JSON format:

{
  \"is_valid\": true/false,
  \"quality_score\": 1-10,
  \"issues\": [\"array of issues found\"],
  \"suggestions\": [\"array of improvement suggestions\"],
  \"spam_probability\": 0-100
}

Look for:
- Generic/spammy descriptions
- Keyword stuffing
- Inappropriate content
- Missing key information
- Category mismatch";

    try {
        $response = $this->client->messages()->create([
            'model' => 'claude-sonnet-4-20250514',
            'max_tokens' => 1024,
            'messages' => [
                ['role' => 'user', 'content' => $validation_prompt]
            ]
        ]);

        $result_text = $response['content'][0]['text'];

        // Claude sometimes wraps JSON in markdown code blocks
        $result_text = preg_replace('/```

json\n?|\n?

```/', '', $result_text);
        $validation = json_decode($result_text, true);

        if ($validation['quality_score'] < 5 || $validation['spam_probability'] > 70) {
            wp_send_json_error([
                'message' => 'Your listing needs improvement',
                'issues' => $validation['issues'],
                'suggestions' => $validation['suggestions']
            ]);
        } else {
            wp_send_json_success([
                'message' => 'Listing looks good!',
                'quality_score' => $validation['quality_score']
            ]);
        }

    } catch (Exception $e) {
        // Fallback to basic validation if API fails
        wp_send_json_success(['message' => 'Validation complete']);
    }
}
Enter fullscreen mode Exit fullscreen mode

This approach has saved me countless hours of manual moderation. Low-quality submissions get flagged immediately with specific, actionable feedback.

Real-world example #3: Natural language admin queries

This one is pure developer convenience. Instead of remembering complex WP_Query arguments, just ask Claude to build them for you.

public function natural_language_query() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error('Unauthorized');
    }

    check_ajax_referer('nl_query_nonce', 'nonce');

    $query_text = sanitize_text_field($_POST['query']);

    $prompt = "Convert this natural language query into WordPress WP_Query arguments.

QUERY: {$query_text}

Respond with ONLY valid JSON that can be passed directly to WP_Query. Include comments explaining your choices.

Example format:
{
  \"post_type\": \"post\",
  \"posts_per_page\": 10,
  \"meta_query\": [...],
  \"_explanation\": \"Why you chose these parameters\"
}";

    try {
        $response = $this->client->messages()->create([
            'model' => 'claude-sonnet-4-20250514',
            'max_tokens' => 1024,
            'messages' => [
                ['role' => 'user', 'content' => $prompt]
            ]
        ]);

        $query_json = $response['content'][0]['text'];
        $query_json = preg_replace('/```

json\n?|\n?

```/', '', $query_json);
        $query_args = json_decode($query_json, true);

        // Remove our explanation field before running query
        $explanation = $query_args['_explanation'] ?? '';
        unset($query_args['_explanation']);

        // Execute the query
        $wp_query = new WP_Query($query_args);

        $results = [];
        while ($wp_query->have_posts()) {
            $wp_query->the_post();
            $results[] = [
                'id' => get_the_ID(),
                'title' => get_the_title(),
                'date' => get_the_date()
            ];
        }
        wp_reset_postdata();

        wp_send_json_success([
            'explanation' => $explanation,
            'query_args' => $query_args,
            'results' => $results,
            'found_posts' => $wp_query->found_posts
        ]);

    } catch (Exception $e) {
        wp_send_json_error('Query generation failed');
    }
}
Enter fullscreen mode Exit fullscreen mode

Now you can type: "Show me all WooCommerce orders from customers in Paris placed in the last 30 days with a total over €500" and get instant results.

Best practices and gotchas

After integrating Claude into multiple production WordPress sites, here are the lessons I've learned the hard way:

1. Cache everything you can

private function get_cached_response($cache_key, $prompt, $ttl = 3600) {
    $cached = get_transient($cache_key);

    if ($cached !== false) {
        return $cached;
    }

    $response = $this->client->messages()->create([
        'model' => 'claude-sonnet-4-20250514',
        'max_tokens' => 1024,
        'messages' => [
            ['role' => 'user', 'content' => $prompt]
        ]
    ]);

    $result = $response['content'][0]['text'];
    set_transient($cache_key, $result, $ttl);

    return $result;
}
Enter fullscreen mode Exit fullscreen mode

For the project estimator, identical descriptions should return cached results. No need to pay for the same API call twice.

2. Implement rate limiting

private function check_rate_limit($user_identifier) {
    $requests_key = 'claude_requests_' . $user_identifier;
    $requests = get_transient($requests_key);

    if ($requests === false) {
        set_transient($requests_key, 1, HOUR_IN_SECONDS);
        return true;
    }

    if ($requests >= 10) { // 10 requests per hour
        return false;
    }

    set_transient($requests_key, $requests + 1, HOUR_IN_SECONDS);
    return true;
}
Enter fullscreen mode Exit fullscreen mode

Without this, a malicious user (or a buggy script) could rack up your API costs quickly.

3. Always have a fallback

Never let your entire feature fail if the Claude API is down:

try {
    $response = $this->client->messages()->create([...]);
    $result = $response['content'][0]['text'];
} catch (Exception $e) {
    error_log('Claude API error: ' . $e->getMessage());

    // Fallback to basic functionality
    $result = $this->basic_estimation_logic($project_description);

    // Or inform the user gracefully
    wp_send_json_error('AI analysis temporarily unavailable. Please try again in a few minutes.');
}
Enter fullscreen mode Exit fullscreen mode

4. Monitor your costs

Add this to your WordPress dashboard:

public function display_api_usage_widget() {
    $monthly_usage = get_option('claude_monthly_usage', [
        'requests' => 0,
        'tokens' => 0,
        'estimated_cost' => 0
    ]);

    echo '<div class="claude-usage-widget">';
    echo '<h3>Claude API Usage (This Month)</h3>';
    echo '<p>Requests: ' . number_format($monthly_usage['requests']) . '</p>';
    echo '<p>Tokens: ' . number_format($monthly_usage['tokens']) . '</p>';
    echo '<p>Estimated Cost: $' . number_format($monthly_usage['estimated_cost'], 2) . '</p>';
    echo '</div>';
}

// Update after each API call
private function track_usage($tokens_used) {
    $usage = get_option('claude_monthly_usage', [
        'requests' => 0,
        'tokens' => 0,
        'estimated_cost' => 0
    ]);

    $usage['requests']++;
    $usage['tokens'] += $tokens_used;

    // Claude Sonnet pricing: ~$3 per million input tokens, ~$15 per million output
    // Rough estimate assuming 50/50 split
    $usage['estimated_cost'] += ($tokens_used / 1000000) * 9;

    update_option('claude_monthly_usage', $usage);
}
Enter fullscreen mode Exit fullscreen mode

For my project estimator, I average about 300 requests per month, which costs roughly $8-12. Totally worth it for the lead qualification value.

5. Sanitize Claude's output

Never trust AI output completely, especially if you're inserting it into your database or displaying it to users:

$claude_response = $response['content'][0]['text'];

// If displaying to users
$safe_output = wp_kses_post($claude_response);

// If storing in database
$safe_output = sanitize_textarea_field($claude_response);

// If expecting JSON, validate the structure
$decoded = json_decode($claude_response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
    throw new Exception('Invalid JSON response from Claude');
}
Enter fullscreen mode Exit fullscreen mode

Complete working example: GitHub repository

I've put together a complete, working plugin that demonstrates all these concepts:

github.com/condorito/claude-wordpress-examples

The repository includes:

  • Database schema for storing estimates and usage data
  • Complete admin interface
  • Frontend form examples
  • Error handling and logging
  • PHPUnit tests
  • Installation instructions

To get started:

  1. Clone the repository
  2. Run composer install
  3. Add your Claude API key to wp-config.php
  4. Activate the plugin
  5. Check out /wp-admin/admin.php?page=claude-examples

Real-world results

Since implementing the project estimator on my agency site three months ago:

  • Lead quality improved dramatically: Self-filtering happens before they even contact me
  • 32% increase in qualified leads: The detailed estimate builds trust immediately
  • Time saved: Roughly 4-5 hours per week not writing manual estimates
  • API costs: Averaging $11/month (totally worth it)

The content validation system for a client's directory site:

  • Spam reduced by 78%: Caught before human moderation
  • Quality improved: Specific suggestions help legitimate users write better listings
  • Moderation time cut in half: Only reviewing flagged submissions

Other use cases worth exploring

Once you have Claude integrated, you'll start seeing opportunities everywhere:

  • Smart email responders: Analyze customer support emails and suggest responses
  • SEO content optimization: Real-time suggestions as users write blog posts
  • Code review assistant: Analyze custom CSS/JS submissions in theme customizers
  • Accessibility checker: Scan content for potential accessibility issues
  • Translation quality: Validate WPML translations for context and accuracy

Final thoughts

AI integration in WordPress isn't about replacing developers or automating everything. It's about augmenting your capabilities and providing genuinely better user experiences.

The project estimator didn't replace my sales process—it made it more efficient and transparent. The content validator didn't eliminate moderation—it made moderators more effective.

Start small. Pick one feature where AI could add real value. Implement it properly with caching, rate limiting, and fallbacks. Measure the results. Then expand.

The Claude PHP SDK makes this integration straightforward enough that you can have a working prototype in an afternoon. The hard part is identifying the right use cases for your specific project.

What would you build? Drop a comment below (or contact me on my website) with your use case ideas—I'd love to hear them.


Top comments (0)