Tell me for any kind of development solution

Edit Template

How to Create a WordPress Content Generation Plugin with Free Google Gemini API

Creating high-quality content consistently is one of the biggest challenges for website owners and content managers. The Google Gemini API offers a powerful solution to this problem, and in this guide, we’ll walk you through creating a WordPress Content Generation Plugin that leverages this technology for automated content generation.

How to Create a WordPress Content Generation Plugin with Free Google Gemini API

What You’ll Learn

  • Setting up a WordPress Content Generation Plugin structure for Gemini integration
  • Implementing the Google Gemini API for content generation
  • Creating an intuitive admin interface
  • Managing API responses and content formatting
  • Adding draft post creation functionality

Prerequisites

Before we begin, ensure you have:

  • A WordPress development environment
  • Basic knowledge of PHP and WordPress plugin development
  • A Google Gemini API key from Google AI Studio
  • Understanding of JavaScript and jQuery

WordPress Content Generation Plugin Structure Overview

Our WordPress Content Generation Plugin follows a well-organized structure to maintain code clarity and separation of concerns. The structure includes:

wp-content/plugins/gemini-content-generator/
├── gemini-content-generator.php
├── assets/
│   ├── css/
│   │   └── admin-style.css
│   └── js/
│       └── admin-script.js
├── includes/
│   ├── class-gemini-api-handler.php
│   └── class-gemini-content-generator.php
└── templates/
    ├── admin-main-page.php
    └── admin-settings-page.php

Step 1: Setting Up the Plugin Base (gemini-content-generator.php)

The main plugin file initializes the plugin, defines constants, and sets up the basic plugin structure. This file acts as the entry point for our plugin.

<?php
/**
* Plugin Name: WordPress Content Generation Plugin
* Description: A WordPress plugin that generates content using Google's Gemini AI
* Version: 1.0.0
* Author: Your Name
* License: GPL v2 or later
*/

if (!defined('ABSPATH')) exit;

// Define plugin constants
define('GEMINI_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('GEMINI_PLUGIN_URL', plugin_dir_url(__FILE__));

// Require necessary files
require_once GEMINI_PLUGIN_PATH . 'includes/class-gemini-content-generator.php';

class Gemini_Plugin {
    private static $instance = null;
    private $content_generator;
   
    public static function getInstance() {
        if (self::$instance == null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
   
    private function __construct() {
        // Initialize components
        $this->content_generator = new Gemini_Content_Generator();
       
        // Add menu items
        add_action('admin_menu', array($this, 'add_admin_menu'));
       
        // Add settings
        add_action('admin_init', array($this, 'register_settings'));
    }
   
    public function add_admin_menu() {
        add_menu_page(
            'Gemini Content Generator',
            'Gemini AI',
            'manage_options',
            'gemini-content-generator',
            array($this, 'display_main_page'),
            'dashicons-text-page',
            30
        );
       
        add_submenu_page(
            'gemini-content-generator',
            'Settings',
            'Settings',
            'manage_options',
            'gemini-content-settings',
            array($this, 'display_settings_page')
        );
    }
   
    public function register_settings() {
        register_setting('gemini_content_settings', 'gemini_api_key');
    }
   
    public function display_main_page() {
        require_once GEMINI_PLUGIN_PATH . 'templates/admin-main-page.php';
    }
   
    public function display_settings_page() {
        require_once GEMINI_PLUGIN_PATH . 'templates/admin-settings-page.php';
    }
}

// Initialize the plugin
function init_gemini_plugin() {
    Gemini_Plugin::getInstance();
}
add_action('plugins_loaded', 'init_gemini_plugin');

Key components:

  • Defines plugin constants for paths and URLs
  • Implements singleton pattern for plugin instance
  • Sets up admin menu and submenu pages
  • Registers plugin settings

Step 2: Styling the Admin Interface (admin-style.css)

The CSS file provides styling for the admin interface, including form layouts and loading states.

/* assets/css/admin-style.css */

.gemini-form-container {
    max-width: 800px;
    margin: 20px 0;
}

.gemini-form-field {
    margin-bottom: 20px;
}

.gemini-form-field label {
    display: block;
    font-weight: 600;
    margin-bottom: 5px;
}

.gemini-form-field textarea {
    width: 100%;
    min-height: 100px;
}

.gemini-form-field select {
    min-width: 200px;
}

.gemini-loading {
    display: none;
    padding: 20px;
    text-align: center;
}

.gemini-loading .spinner {
    float: none;
    margin: 0 10px 0 0;
}

.gemini-generated-content {
    margin-top: 20px;
    padding: 15px;
    background: #fff;
    border: 1px solid #ddd;
    border-radius: 4px;
}

.gemini-error {
    color: #dc3232;
    padding: 10px;
    border-left: 4px solid #dc3232;
    margin: 20px 0;
}





.dynamic-content {
    font-family: Arial, sans-serif;
    line-height: 1.6;
    padding: 20px;
    background-color: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.section-heading {
    font-size: 1.8em;
    color: #1a73e8;
    margin-bottom: 15px;
    border-bottom: 2px solid #ddd;
    padding-bottom: 5px;
}

.subsection-heading {
    font-size: 1.5em;
    color: #333;
    margin-top: 20px;
    margin-bottom: 10px;
}

.custom-list {
    margin: 10px 0;
    padding-left: 20px;
}

.custom-list li {
    margin-bottom: 5px;
}

.custom-ordered-list {
    margin: 10px 0;
    padding-left: 20px;
}

Key styling features:

  • Responsive form container with proper spacing
  • Loading animation styles
  • Error and success message formatting
  • Dynamic content display formatting

Step 3: Adding Interactive Features (admin-script.js)

The JavaScript file handles:

  • Form submissions via AJAX
  • Loading state management
  • Response handling
  • Draft post creation
// assets/js/admin-script.js
jQuery(document).ready(function($) {
    $('#gemini-generate-form').on('submit', function(e) {
        e.preventDefault();
       
        const $form = $(this);
        const $submitButton = $form.find('button[type="submit"]');
        const $loading = $('.gemini-loading');
        const $result = $('.gemini-generated-content');
       
        // Show loading
        $loading.show();
        $submitButton.prop('disabled', true);
       
        // Collect form data
        const formData = {
            action: 'generate_content',
            prompt: $('#content-prompt').val(),
            tone: $('#content-tone').val(),
            length: $('#content-length').val(),
            nonce: geminiAjax.nonce
        };
       
        // Make AJAX request
        $.post(geminiAjax.ajaxurl, formData, function(response) {
            if (response.success) {
                $result.html(response.data.content);
               
                // Add Create Draft button
                const createDraftButton = $('<button>', {
                    class: 'button button-secondary',
                    text: 'Create Draft Post',
                    style: 'margin-top: 15px;'
                }).on('click', function(e) {
                    e.preventDefault();
                    const $button = $(this);
                    $button.prop('disabled', true).text('Creating draft...');
                   
                    $.ajax({
                        url: geminiAjax.ajaxurl,
                        type: 'POST',
                        data: {
                            action: 'create_draft_post',
                            content: $result.html(),
                            title: $('#content-prompt').val(),
                            nonce: geminiAjax.nonce
                        },
                        success: function(response) {
                            $button.prop('disabled', false).text('Create Draft Post');
                            if (response.success) {
                                const successMessage = $('<div>', {
                                    class: 'notice notice-success',
                                    html: `<p>Draft created successfully!
                                          <a href="${response.data.edit_url}" target="_blank">Edit Post</a> |
                                          <a href="${response.data.preview_url}" target="_blank">Preview Post</a></p>`
                                });
                                $('button.button-secondary').after(successMessage);
                            } else {
                                const errorMessage = $('<div>', {
                                    class: 'notice notice-error',
                                    html: `<p>Error: ${response.data.message}</p>`
                                });
                                $('button.button-secondary').after(errorMessage);
                            }
                        },
                        error: function(xhr, status, error) {
                            $button.prop('disabled', false).text('Create Draft Post');
                            const errorMessage = $('<div>', {
                                class: 'notice notice-error',
                                html: `<p>Error creating draft: ${error}</p>`
                            });
                            $result.prepend(errorMessage);
                        }
                    });
                });
               
                $result.append(createDraftButton);
            } else {
                $result.html('<div class="notice notice-error"><p>' + response.data.message + '</p></div>');
            }
        })
        .fail(function() {
            $result.html('<div class="notice notice-error"><p>Error connecting to server</p></div>');
        })
        .always(function() {
            $loading.hide();
            $submitButton.prop('disabled', false);
        });
    });
});

Key functionalities:

  • AJAX form submission with loading states
  • Dynamic content updates
  • Error handling and display
  • Draft post creation with success/error notifications

Step 4: API Handler Implementation (class-gemini-api-handler.php)

This class manages all communications with the Google Gemini API.

<?php
// includes/class-gemini-api-handler.php

if (!defined('ABSPATH')) exit;

class Gemini_API_Handler {
    private $api_key;
    private $api_url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent';
   
    public function __construct() {
        $this->api_key = get_option('gemini_api_key');
    }
   
    public function generate_content($prompt, $tone, $length) {
        if (empty($this->api_key)) {
            return new WP_Error('no_api_key', 'Gemini API key is not configured');
        }
       
        // Enhance prompt based on tone and length
        $enhanced_prompt = $this->enhance_prompt($prompt, $tone, $length);
       
        // Prepare the request
        $response = wp_remote_post(
            $this->api_url . '?key=' . $this->api_key,
            array(
                'headers' => array(
                    'Content-Type' => 'application/json',
                ),
                'body' => json_encode(array(
                    'contents' => array(
                        array(
                            'parts' => array(
                                array(
                                    'text' => $enhanced_prompt
                                )
                            )
                        )
                    ),
                    'generationConfig' => array(
                        'temperature' => 0.7,
                        'topK' => 40,
                        'topP' => 0.95,
                        'maxOutputTokens' => $this->get_max_tokens($length),
                    ),
                )),
                'timeout' => 30,
            )
        );
       
        if (is_wp_error($response)) {
            return $response;
        }
       
        $body = json_decode(wp_remote_retrieve_body($response), true);
       
        if (empty($body) || isset($body['error'])) {
            return new WP_Error(
                'api_error',
                isset($body['error']['message']) ? $body['error']['message'] : 'Unknown API error'
            );
        }
       
        try {
            return $this->format_content($this->parse_response($body));
        } catch (Exception $e) {
            return new WP_Error('parse_error', $e->getMessage());
        }
    }
   
    private function enhance_prompt($prompt, $tone, $length) {
        $tone_instructions = array(
            'professional' => 'Write in a professional and business-appropriate tone.',
            'casual' => 'Write in a casual, conversational tone.',
            'friendly' => 'Write in a warm and approachable tone.',
            'formal' => 'Write in a formal and academic tone.'
        );
       
        return sprintf(
            "Please write content with the following requirements:\n" .
            "Topic/Brief: %s\n" .
            "Tone: %s\n" .
            "Additional Instructions: Write well-structured content suitable for a website or blog. " .
            "Use markdown formatting with ## for main headings and ### for subheadings. " .
            "Use proper spacing between sections.",
            $prompt,
            $tone_instructions[$tone]
        );
    }
   
    private function get_max_tokens($length) {
        $token_limits = array(
            'short' => 250,
            'medium' => 500,
            'long' => 800
        );
       
        return $token_limits[$length] ?? 500;
    }
   
    private function parse_response($response) {
        if (!isset($response['candidates'][0]['content']['parts'][0]['text'])) {
            throw new Exception('Unexpected API response format');
        }
       
        return $response['candidates'][0]['content']['parts'][0]['text'];
    }

   
    private function format_content($content) {
        // Basic sanitization while preserving markdown
        $content = wp_kses_post($content);
       
        $content = preg_replace('/\n#\n/', "\n", $content);
        $content = preg_replace('/^#\s*$/m', '', $content);
       
        if (function_exists('wpautop')) {
            $content = preg_replace('/^## (.*?)$/m', '<h2>$1</h2>', $content);
            $content = preg_replace('/^### (.*?)$/m', '<h3>$1</h3>', $content);
           
            $content = wpautop($content);
           
            $content = preg_replace('/\*\*(.*?)\*\*/', '<strong>$1</strong>', $content);
           
            $content = preg_replace('/- (.*?)\n/', '<ul><li>$1</li></ul>', $content);
            $content = preg_replace('/<\/ul>\s*<ul>/', '', $content);
           
            $content = preg_replace('/<p>\s*<h([23])/', '<h$1', $content);
            $content = preg_replace('/<\/h([23])>\s*<\/p>/', '</h$1>', $content);
        }
       
        return $content;
    }   
}   

Key features:

  • API request formatting and sending
  • Response parsing and error handling
  • Content enhancement based on tone and length
  • Output formatting and sanitization

Step 5: Core Plugin Class (class-gemini-content-generator.php)

The main class handling plugin functionality.

<?php
if (!defined('ABSPATH')) exit;

class Gemini_Content_Generator {
    private $api_handler;
   
    public function __construct() {
        require_once GEMINI_PLUGIN_PATH . 'includes/class-gemini-api-handler.php';
        $this->api_handler = new Gemini_API_Handler();
       
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
        add_action('wp_ajax_generate_content', array($this, 'handle_generate_content'));
        add_action('wp_ajax_create_draft_post', array($this, 'handle_create_draft_post'));
    }
   
    public function enqueue_admin_assets($hook) {
        if (strpos($hook, 'gemini-content') === false) {
            return;
        }
       
        wp_enqueue_style(
            'gemini-admin-style',
            GEMINI_PLUGIN_URL . 'assets/css/admin-style.css',
            array(),
            '1.0.0'
        );
       
        wp_enqueue_script(
            'gemini-admin-script',
            GEMINI_PLUGIN_URL . 'assets/js/admin-script.js',
            array('jquery'),
            '1.0.0',
            true
        );
       
        wp_localize_script('gemini-admin-script', 'geminiAjax', array(
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('gemini_generate_nonce') // Updated nonce name
        ));
    }
   
    public function handle_generate_content() {
        check_ajax_referer('gemini_generate_nonce', 'nonce');
       
        if (!current_user_can('edit_posts')) {
            wp_send_json_error(array('message' => 'Permission denied'));
        }
       
        $prompt = sanitize_textarea_field($_POST['prompt'] ?? '');
        $tone = sanitize_text_field($_POST['tone'] ?? 'professional');
        $length = sanitize_text_field($_POST['length'] ?? 'medium');
       
        if (empty($prompt)) {
            wp_send_json_error(array('message' => 'Please provide a content prompt.'));
        }
       
        // Generate content using API
        $content = $this->api_handler->generate_content($prompt, $tone, $length);
       
        if (is_wp_error($content)) {
            wp_send_json_error(array(
                'message' => $content->get_error_message()
            ));
        }
       
        wp_send_json_success(array('content' => $content));
    }

    public function handle_create_draft_post() {
        check_ajax_referer('gemini_generate_nonce', 'nonce');
       
        if (!current_user_can('edit_posts')) {
            wp_send_json_error(['message' => 'Permission denied']);
            return;
        }
       
        // Get and sanitize the content
        $content = isset($_POST['content']) ? wp_kses_post(stripslashes($_POST['content'])) : '';
        $title = isset($_POST['title']) ? sanitize_text_field(stripslashes($_POST['title'])) : 'Generated Content ' . date('Y-m-d H:i:s');
       
        if (empty($content)) {
            wp_send_json_error(['message' => 'No content provided']);
            return;
        }
       
        // Create post object
        $post_data = array(
            'post_title'    => $title,
            'post_content'  => $content,
            'post_status'   => 'draft',
            'post_author'   => get_current_user_id(),
            'post_type'     => 'post'
        );
       
        // Insert the post into the database
        $post_id = wp_insert_post($post_data);
       
        if ($post_id && !is_wp_error($post_id)) {
            $edit_url = admin_url('post.php?post=' . $post_id . '&action=edit');
            $preview_url = get_preview_post_link($post_id);
           
            wp_send_json_success([
                'message' => 'Draft created successfully',
                'post_id' => $post_id,
                'edit_url' => $edit_url,
                'preview_url' => $preview_url
            ]);
        } else {
            wp_send_json_error([
                'message' => is_wp_error($post_id) ? $post_id->get_error_message() : 'Failed to create draft'
            ]);
        }
    }
}

Important functions:

  • Asset enqueuing
  • AJAX handlers for content generation
  • Draft post creation
  • Security implementations

Step 6: Admin Interface Templates

Main Page Template (admin-main-page.php)

Creates the content generation interface.

<?php
// templates/admin-main-page.php

if (!defined('ABSPATH')) exit;
?>
<div class="wrap">
    <h1>Gemini Content Generator</h1>
   
    <?php if (!get_option('gemini_api_key')): ?>
        <div class="notice notice-warning">
            <p>Please configure your Gemini API key in the <a href="<?php echo admin_url('admin.php?page=gemini-content-settings'); ?>">settings page</a> first.</p>
        </div>
    <?php else: ?>
        <div class="gemini-form-container">
            <form id="gemini-generate-form" method="post">
                <div class="gemini-form-field">
                    <label for="content-prompt">What would you like to write about?</label>
                    <textarea
                        id="content-prompt"
                        name="prompt"
                        class="large-text"
                        rows="4"
                        required
                        placeholder="Enter your content brief here. Be specific about what you want to generate."
                    ></textarea>
                </div>
               
                <div class="gemini-form-field">
                    <label for="content-tone">Content Tone</label>
                    <select id="content-tone" name="tone" class="regular-text">
                        <option value="professional">Professional</option>
                        <option value="casual">Casual</option>
                        <option value="friendly">Friendly</option>
                        <option value="formal">Formal</option>
                    </select>
                </div>
               
                <div class="gemini-form-field">
                    <label for="content-length">Content Length</label>
                    <select id="content-length" name="length" class="regular-text">
                        <option value="short">Short (~150 words)</option>
                        <option value="medium">Medium (~300 words)</option>
                        <option value="long">Long (~500 words)</option>
                    </select>
                </div>
               
                <div class="gemini-form-field">
                    <?php wp_nonce_field('gemini_generate_nonce', 'gemini_nonce'); ?>
                    <button type="submit" class="button button-primary">Generate Content</button>
                </div>
            </form>
           
            <div class="gemini-loading">
                <span class="spinner is-active"></span> Generating content...
            </div>
           
            <div class="gemini-generated-content"></div>
        </div>
    <?php endif; ?>
</div>

Features:

  • Content generation form
  • Tone and length selection
  • Loading indicators
  • Generated content display

Settings Page Template (admin-settings-page.php)

Manages WordPress Content Generation Plugin configuration.

<?php
// templates/admin-settings-page.php

if (!defined('ABSPATH')) exit;
?>
<div class="wrap">
    <h1>Gemini Content Generator Settings</h1>
   
    <form method="post" action="options.php">
        <?php
        settings_fields('gemini_content_settings');
        do_settings_sections('gemini_content_settings');
        ?>
        <table class="form-table">
            <tr>
                <th scope="row">
                    <label for="gemini_api_key">Gemini API Key</label>
                </th>
                <td>
                    <input type="password"
                          id="gemini_api_key"
                          name="gemini_api_key"
                          value="<?php echo esc_attr(get_option('gemini_api_key')); ?>"
                          class="regular-text">
                    <p class="description">
                        Enter your Gemini API key here. You can get one from
                        <a href="https://makersuite.google.com/app/apikey" target="_blank">Google AI Studio</a>.
                    </p>
                </td>
            </tr>
        </table>
        <?php submit_button(); ?>
    </form>
</div>

Includes:

  • API key management
  • Security nonce implementation
  • Settings form with proper validation

How to use

  • Go to plugins and activate the WordPress Content Generation Plugin
  • Then go to Gemini Ai from the sidebar of the WordPress admin
  • First, go to settings and save your API key (If not then create new one)
  • Then start creating content

Security Implementations

The plugin implements several security measures:

  • Nonce verification for all AJAX requests
  • Capability checking for user permissions
  • Input sanitization and validation
  • Secure API key storage

Testing and Deployment

Before deploying the plugin:

  • Test the API integration thoroughly
  • Verify error handling
  • Check compatibility with different WordPress versions
  • Ensure proper sanitization of inputs and outputs

Future Enhancements

Consider adding these features in future updates:

  • Content templates
  • Bulk content generation
  • Custom post type support
  • Content scheduling
  • SEO optimization suggestions

Conclusion

You now have a fully functional WordPress Content Generation Plugin that leverages the power of Google’s Gemini AI for content generation. This tool can significantly streamline your content creation workflow while maintaining quality and relevance.

Share Article:

© 2025 Created by ArtisansTech