How to Create a WordPress Plugin to Generate Featured Images Using AI
Home » WordPress » How to Create a WordPress Plugin to Generate Featured Images Using AI

How to Create a WordPress Plugin to Generate Featured Images Using AI

How to Create a WordPress Plugin to Generate Featured Images Using AI – In this guide, we’ll walk through the process of creating a WordPress plugin called ZeroByteCode AI Featured Image Generator.

This plugin leverages OpenAI’s Dall-E 3 AI to generate featured images for posts based on the content provided.

We’ll cover the essential components of the plugin, including setting up the plugin, creating settings pages, registering REST API routes, and handling the image generation process.

The ZeroByteCode AI Featured Image Generator plugin includes:

  1. A settings page for entering the OpenAI API key and configuring other settings.
  2. A meta box in the post editor for generating the featured image.
  3. A REST API endpoint for generating images using OpenAI’s Dall-E 3.
  4. Functions for securely handling API keys, validating user permissions, and uploading generated images to the WordPress media library.

Let’s break down the plugin parts, one-by-one, in order to create a fully working WordPress plugin that can automatically generate and set a featured image for your post using the OpenAI’s Dall-E 3 AI.

0. Create Plugin Files and Folders

First, let’s start by creating the plugin main folder. For example, let’s name it to zerobytecode-featured-image-generator. Enter the folder and create a new PHP file, this time, name it to something like zerobytecode-featured-image-generator.php.

Inside the same folder, create a new folder and let’s name it to js for better files organization. Enter the js folder and create a new file and name it to admin.js.

Right now, let’s start with the zerobytecode-featured-image-generator.php PHP file.

1. Plugin Setup and Security

Main Plugin File:

The main plugin file (zerobytecode-featured-image-generator.php) includes the plugin header, security measures, and function WordPress hooks.

<?php

/*
* Plugin Name: ZeroByteCode AI Featured Image Generator
* Plugin URI: https://zerobytecode.com/create-a-wordpress-plugin-to-generate-featured-images-using-ai/
* Description: One-click generate and set WordPress post featured image using OpenAI\'s Dalle 3 AI.
* Version: 1.0
* Author: ZeroByteCode
* Author URI: https://zerobytecode.com/
* Text Domain: zerobytecode
*/

// Prevent direct file access
if (!defined('WPINC')) {
    die;
}

2. Registering the Options Page

The options page allows administrators to enter the OpenAI API key and configure the prompt template.

function zerobytecode_register_options_page()
{
    add_options_page(
        __('ZeroByteCode Featured Image Generator Settings', 'zerobytecode'),
        __('ZeroByteCode AI', 'zerobytecode'),
        'manage_options',
        'zerobytecode-ai-settings',
        'zerobytecode_options_page_html'
    );
}
add_action('admin_menu', 'zerobytecode_register_options_page');

Activation Hook:

This hook sets default options upon plugin activation.

function zerobytecode_activate_plugin()
{
    $default_template = 'Based on the user’s input, you must generate a single sentence, detailed prompt to generate an image using an AI image generation. The image is the thumbnail for the blog post, and the content the user passes in is portions of that blog post. Distill a single concept or topic based on the user’s input, then create the prompt for image generation.';

    if (get_option('zerobytecode_content_template') === false) {
        update_option('zerobytecode_content_template', $default_template);
    }
}
register_activation_hook(__FILE__, 'zerobytecode_activate_plugin');

Options Page HTML:

This function renders the options page HTML.

function zerobytecode_options_page_html()
{
    if (!current_user_can('manage_options')) {
        return;
    }

    if (isset($_GET['settings-updated'])) {
        add_settings_error('zerobytecode_messages', 'zerobytecode_message', __('Settings Saved', 'zerobytecode'), 'updated');
    }

    settings_errors('zerobytecode_messages');
?>
    <div class="wrap">
        <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
        <form action="options.php" method="post">
            <?php
            settings_fields('zerobytecode_settings');
            do_settings_sections('zerobytecode-ai-settings');
            submit_button(__('Save Settings', 'zerobytecode'));
            ?>
        </form>
    </div>
<?php
}

3. Registering the Settings

Register the settings for the API key and content template.

function zerobytecode_register_settings()
{
    register_setting('zerobytecode_settings', 'zerobytecode_openai_api_key', 'sanitize_text_field');
    register_setting('zerobytecode_settings', 'zerobytecode_content_template', 'sanitize_textarea_field');

    add_settings_section(
        'zerobytecode_settings_section',
        __('OpenAI API Settings', 'zerobytecode'),
        'zerobytecode_settings_section_callback',
        'zerobytecode-ai-settings'
    );

    add_settings_field(
        'zerobytecode_openai_api_key',
        __('OpenAI API Key', 'zerobytecode'),
        'zerobytecode_openai_api_key_render',
        'zerobytecode-ai-settings',
        'zerobytecode_settings_section'
    );

    add_settings_field(
        'zerobytecode_content_template',
        __('Content Template', 'zerobytecode'),
        'zerobytecode_content_template_render',
        'zerobytecode-ai-settings',
        'zerobytecode_settings_section'
    );
}
add_action('admin_init', 'zerobytecode_register_settings');

function zerobytecode_settings_section_callback()
{
    echo '<p>' . __('Enter your OpenAI API settings below.', 'zerobytecode') . '</p>';
}

function zerobytecode_openai_api_key_render()
{
    $openai_api_key = get_option('zerobytecode_openai_api_key');
?>
    <input type="text" name="zerobytecode_openai_api_key" value="<?php echo esc_attr($openai_api_key); ?>" size="50">
<?php
}

Rendering Content Template Field:

This field allows users to set a custom template for generating prompts.

function zerobytecode_content_template_render()
{
    $content_template = get_option('zerobytecode_content_template');
?>
    <textarea name="zerobytecode_content_template" rows="10" cols="50"><?php echo esc_textarea($content_template); ?></textarea>
<?php
}

4. Enqueuing Admin Scripts

Enqueue JavaScript for the admin area, which will handle the image generation button click event.

function zerobytecode_enqueue_scripts($hook)
{
    if (!in_array($hook, ['post.php', 'post-new.php'], true)) {
        return;
    }

    wp_enqueue_script(
        'zerobytecode-admin-js',
        plugin_dir_url(__FILE__) . 'js/admin.js',
        ['jquery'],
        '1.0',
        true
    );

    wp_localize_script('zerobytecode-admin-js', 'zerobytecode', [
        'nonce' => wp_create_nonce('wp_rest'),
        'rest_url' => '/zerobytecode/v1/generate-image/'
    ]);
}
add_action('admin_enqueue_scripts', 'zerobytecode_enqueue_scripts');

5. Registering the Meta Box

The meta box contains the “Generate Image” button.

function zerobytecode_register_meta_box()
{
    add_meta_box(
        'zerobytecode_featured_image_generator',
        __('Generate Featured Image', 'zerobytecode'),
        'zerobytecode_display_generator_button',
        null,
        'side',
        'high'
    );
}
add_action('add_meta_boxes', 'zerobytecode_register_meta_box');

Displaying the Meta Box Content:

function zerobytecode_display_generator_button($post)
{
?>
    <button type="button" id="zerobytecode_generate_btn" data-postid="<?php echo esc_attr($post->ID); ?>" class="button button-primary button-large">
        <?php esc_html_e('Generate Image', 'zerobytecode'); ?>
    </button>
<?php
}

6. Registering REST API Route

The REST API route handles image generation requests.

function zerobytecode_register_rest_route()
{
    register_rest_route('zerobytecode/v1', '/generate-image/(?P<id>\d+)', [
        'methods' => 'POST',
        'callback' => 'zerobytecode_handle_generate_image',
        'permission_callback' => 'zerobytecode_check_permissions',
        'args' => [
            'id' => [
                'required' => true,
                'validate_callback' => 'is_numeric',
            ],
        ],
    ]);
}
add_action('rest_api_init', 'zerobytecode_register_rest_route');

function zerobytecode_check_permissions(WP_REST_Request $request)
{
    return current_user_can('edit_post', $request['id']);
}

7. Handling Image Generation

The function zerobytecode_handle_generate_image processes the REST API request, generates a prompt, and retrieves the image URL.

function zerobytecode_handle_generate_image(WP_REST_Request $request)
{
    // Verify the nonce
    $nonce = $request->get_param('_wpnonce');
    if (!wp_verify_nonce($nonce, 'wp_rest')) {
        return new WP_Error('rest_cookie_invalid_nonce', __('Cookie check failed', 'zerobytecode'), ['status' => 403]);
    }

    $post_id = $request['id'];
    $post_data = get_post($post_id);
    $excerpt = !empty($post_data->post_excerpt) ? $post_data->post_excerpt : wp_trim_words($post_data->post_content, 100);
    $api_key = get_option('zerobytecode_openai_api_key');
    $content_template = get_option('zerobytecode_content_template');

    if (empty($api_key)) {
        return new WP_Error('missing_api_key', __('Missing OpenAI API key.', 'zerobytecode'));
    }

    // Generate image prompt using OpenAI chat completions
    $prompt_response =

 wp_remote_post(
        'https://api.openai.com/v1/chat/completions',
        [
            'headers' => [
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . $api_key,
            ],
            'body' => wp_json_encode([
                'model' => 'gpt-3.5-turbo',
                'messages' => [
                    [
                        'role' => 'system',
                        'content' => sanitize_textarea_field($content_template),
                    ],
                    [
                        'role' => 'user',
                        'content' => sanitize_text_field($excerpt),
                    ],
                ],
            ]),
            'timeout' => 60,
        ]
    );

    if (is_wp_error($prompt_response) || wp_remote_retrieve_response_code($prompt_response) !== 200) {
        return new WP_Error('api_error', __('Error communicating with OpenAI API.', 'zerobytecode'));
    }

    $prompt_data = json_decode(wp_remote_retrieve_body($prompt_response), true);
    $prompt = $prompt_data['choices'][0]['message']['content'] ?? '';

    if (empty($prompt)) {
        return new WP_Error('prompt_error', __('Unable to generate image prompt.', 'zerobytecode'));
    }

    // Generate image using Dalle 3 API
    $image_response = wp_remote_post(
        'https://api.openai.com/v1/images/generations',
        [
            'headers' => [
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . $api_key,
            ],
            'body' => wp_json_encode([
                'model' => 'dall-e-3',
                'prompt' => sanitize_text_field($prompt),
                'n' => 1,
                'size' => '1792x1024',
            ]),
            'timeout' => 60,
        ]
    );

    if (is_wp_error($image_response) || wp_remote_retrieve_response_code($image_response) !== 200) {
        return new WP_Error('api_error', __('Error generating image with Dalle 3 API.', 'zerobytecode'));
    }

    $image_data = json_decode(wp_remote_retrieve_body($image_response), true);
    $image_url = $image_data['data'][0]['url'] ?? '';

    if (empty($image_url)) {
        return new WP_Error('image_error', __('Unable to get image URL.', 'zerobytecode'));
    }

    // Upload image to media library and set as featured image
    $image_id = zerobytecode_upload_image_to_media_library($image_url, $post_id);

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

    set_post_thumbnail($post_id, $image_id);

    return rest_ensure_response(['success' => true]);
}

8. Uploading the Image to the Media Library

The function zerobytecode_upload_image_to_media_library handles the image upload process.

function zerobytecode_upload_image_to_media_library($image_url, $post_id)
{
    require_once(ABSPATH . 'wp-admin/includes/file.php');
    require_once(ABSPATH . 'wp-admin/includes/media.php');
    require_once(ABSPATH . 'wp-admin/includes/image.php');

    add_filter('upload_mimes', 'zerobytecode_custom_upload_mimes');

    $tmp = zerobytecode_custom_download_image($image_url);

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

    // Extract the file extension directly from the URL
    $file_ext = pathinfo(parse_url($image_url, PHP_URL_PATH), PATHINFO_EXTENSION);
    $file_name = sanitize_file_name($post_id . '-' . time() . '.' . $file_ext);

    $file_array = [
        'name' => $file_name,
        'tmp_name' => $tmp,
    ];

    $id = media_handle_sideload($file_array, $post_id, __('Generated featured image', 'zerobytecode'));

    if (is_wp_error($id)) {
        @unlink($file_array['tmp_name']);
        return $id;
    }

    return $id;
}

9. Custom MIME Types for Uploads

The custom MIME types function ensures that the correct file types are supported.

function zerobytecode_custom_upload_mimes($mimes)
{
    $mimes['png'] = 'image/png';
    return $mimes;
}

10. Custom Image Download Function

This function handles the download of images from the generated URL.

function zerobytecode_custom_download_image($image_url)
{
    if (!filter_var($image_url, FILTER_VALIDATE_URL)) {
        return new WP_Error('invalid_url', __('Invalid image URL.', 'zerobytecode'));
    }

    $response = wp_remote_get($image_url, [
        'timeout' => 60,
        'sslverify' => true,
    ]);

    if (is_wp_error($response)) {
        return new WP_Error('download_error', __('Error downloading image.', 'zerobytecode'));
    }

    $body = wp_remote_retrieve_body($response);

    if (empty($body)) {
        return new WP_Error('empty_body', __('Downloaded image data is empty.', 'zerobytecode'));
    }

    $file_ext = pathinfo(parse_url($image_url, PHP_URL_PATH), PATHINFO_EXTENSION);
    $file_ext = sanitize_file_name($file_ext);
    $tmp_fname = wp_tempnam($image_url);

    if (!$tmp_fname) {
        return new WP_Error('temp_file_error', __('Unable to create a temporary file.', 'zerobytecode'));
    }

    file_put_contents($tmp_fname, $body);

    return $tmp_fname;
}

The Full Main PHP File Code

Now at this point, we have the following code inside the plugin’s main file:

<?php

/*
* Plugin Name:       ZeroByteCode AI Featured Image Generator
* Plugin URI:        https://zerobytecode.com/create-a-wordpress-plugin-to-generate-featured-images-using-ai/
* Description:       One-click generate and set WordPress post featured image using OpenAI\'s Dalle 3 AI.
* Version:           1.0
* Author:            ZeroByteCode
* Author URI:        https://zerobytecode.com/
* Text Domain:       zerobytecode
*/

if (!defined('WPINC')) {
    die;
}

// Registering the Options Page
function zerobytecode_register_options_page()
{
    add_options_page(
        __('ZeroByteCode Featured Image Generator Settings', 'zerobytecode'),
        __('ZeroByteCode AI', 'zerobytecode'),
        'manage_options',
        'zerobytecode-ai-settings',
        'zerobytecode_options_page_html'
    );
}
add_action('admin_menu', 'zerobytecode_register_options_page');

// Set default options on plugin activation
function zerobytecode_activate_plugin()
{
    $default_template = 'Based on the user\'s input, you must generate a single sentence, detailed prompt to generate an image using an AI image generation. The image is the thumbnail for the blog post, and the content the user passes in is portions of that blog post. Distill a single concept or topic based on the user\'s input, then create the prompt for image generation.';

    if (get_option('zerobytecode_content_template') === false) {
        update_option('zerobytecode_content_template', $default_template);
    }
}
register_activation_hook(__FILE__, 'zerobytecode_activate_plugin');

// Displaying the Options Page
function zerobytecode_options_page_html()
{
    if (!current_user_can('manage_options')) {
        return;
    }

    if (isset($_GET['settings-updated'])) {
        add_settings_error('zerobytecode_messages', 'zerobytecode_message', __('Settings Saved', 'zerobytecode'), 'updated');
    }

    settings_errors('zerobytecode_messages');
?>
    <div class="wrap">
        <h1><?php echo esc_html(get_admin_page_title()); ?></h1>
        <form action="options.php" method="post">
            <?php
            settings_fields('zerobytecode_settings');
            do_settings_sections('zerobytecode-ai-settings');
            submit_button(__('Save Settings', 'zerobytecode'));
            ?>
        </form>
    </div>
<?php
}

// Registering the Settings
function zerobytecode_register_settings()
{
    register_setting('zerobytecode_settings', 'zerobytecode_openai_api_key', 'sanitize_text_field');
    register_setting('zerobytecode_settings', 'zerobytecode_content_template', 'sanitize_textarea_field');

    add_settings_section(
        'zerobytecode_settings_section',
        __('OpenAI API Settings', 'zerobytecode'),
        'zerobytecode_settings_section_callback',
        'zerobytecode-ai-settings'
    );

    add_settings_field(
        'zerobytecode_openai_api_key',
        __('OpenAI API Key', 'zerobytecode'),
        'zerobytecode_openai_api_key_render',
        'zerobytecode-ai-settings',
        'zerobytecode_settings_section'
    );

    add_settings_field(
        'zerobytecode_content_template',
        __('Content Template', 'zerobytecode'),
        'zerobytecode_content_template_render',
        'zerobytecode-ai-settings',
        'zerobytecode_settings_section'
    );
}
add_action('admin_init', 'zerobytecode_register_settings');

function zerobytecode_settings_section_callback()
{
    echo '<p>' . __('Enter your OpenAI API settings below.', 'zerobytecode') . '</p>';
}

function zerobytecode_openai_api_key_render()
{
    $openai_api_key = get_option('zerobytecode_openai_api_key');
?>
    <input type="text" name="zerobytecode_openai_api_key" value="<?php echo esc_attr($openai_api_key); ?>" size="50">
<?php
}

// Enqueue scripts for the admin area
function zerobytecode_enqueue_scripts($hook)
{
    // Check if we are on post.php or post-new.php on the admin side
    if (!in_array($hook, ['post.php', 'post-new.php'], true)) {
        return;
    }

    wp_enqueue_script(
        'zerobytecode-admin-js',
        plugin_dir_url(__FILE__) . 'js/admin.js',
        ['jquery'],
        '1.0',
        true
    );

    // Localize the script with nonce and correct endpoint
    wp_localize_script('zerobytecode-admin-js', 'zerobytecode', [
        'nonce' => wp_create_nonce('wp_rest'), // Ensure the correct nonce action name
        'rest_url' => '/zerobytecode/v1/generate-image/'
    ]);
}
add_action('admin_enqueue_scripts', 'zerobytecode_enqueue_scripts');

// Register the meta box for generating images
function zerobytecode_register_meta_box()
{
    add_meta_box(
        'zerobytecode_featured_image_generator',
        __('Generate Featured Image', 'zerobytecode'),
        'zerobytecode_display_generator_button',
        null,
        'side',
        'high'
    );
}
add_action('add_meta_boxes', 'zerobytecode_register_meta_box');

// Display the generator button in the meta box
function zerobytecode_display_generator_button($post)
{
?>
    <button type="button" id="zerobytecode_generate_btn" data-postid="<?php echo esc_attr($post->ID); ?>" class="button button-primary button-large">
        <?php esc_html_e('Generate Image', 'zerobytecode'); ?>
    </button>
<?php
}

// Register REST API route
function zerobytecode_register_rest_route()
{
    register_rest_route('zerobytecode/v1', '/generate-image/(?P<id>\d+)', [
        'methods' => 'POST',
        'callback' => 'zerobytecode_handle_generate_image',
        'permission_callback' => 'zerobytecode_check_permissions',
        'args' => [
            'id' => [
                'required' => true,
                'validate_callback' => 'is_numeric',
            ],
        ],
    ]);
}
add_action('rest_api_init', 'zerobytecode_register_rest_route');

// Check user permissions for generating image
function zerobytecode_check_permissions(WP_REST_Request $request)
{
    return current_user_can('edit_post', $request['id']);
}

function zerobytecode_content_template_render()
{
    $content_template = get_option('zerobytecode_content_template', 'Based on the user\'s input, you must generate a single sentence, detailed prompt to generate an image using an AI image generation. The image is the thumbnail for the blog post, and the content the user passes in is portions of that blog post. Distill a single concept or topic based on the user\'s input, then create the prompt for image generation.');
?>
    <textarea name="zerobytecode_content_template" rows="10" cols="50"><?php echo esc_textarea($content_template); ?></textarea>
<?php
}

// Handle the REST API request to generate an image
function zerobytecode_handle_generate_image(WP_REST_Request $request)
{

    // Verify the nonce
    $nonce = $request->get_param('_wpnonce');
    if (!wp_verify_nonce($nonce, 'wp_rest')) {
        return new WP_Error('rest_cookie_invalid_nonce', __('Cookie check failed', 'zerobytecode'), ['status' => 403]);
    }

    $post_id = $request['id'];
    $post_data = get_post($post_id);
    $excerpt = !empty($post_data->post_excerpt) ? $post_data->post_excerpt : wp_trim_words($post_data->post_content, 100);
    $api_key = get_option('zerobytecode_openai_api_key');
    $content_template = get_option('zerobytecode_content_template', 'Based on the user\'s input, you must generate a single sentence, detailed prompt to generate an image using an AI image generation. The image is the thumbnail for the blog post, and the content the user passes in is portions of that blog post. Distill a single concept or topic based on the user\'s input, then create the prompt for image generation.');

    if (empty($api_key)) {
        return new WP_Error('missing_api_key', __('Missing OpenAI API key.', 'zerobytecode'));
    }

    // Generate image prompt using OpenAI chat completions
    $prompt_response = wp_remote_post(
        'https://api.openai.com/v1/chat/completions',
        [
            'headers' => [
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . $api_key,
            ],
            'body' => wp_json_encode([
                'model' => 'gpt-3.5-turbo',
                'messages' => [
                    [
                        'role' => 'system',
                        'content' => sanitize_textarea_field($content_template),
                    ],
                    [
                        'role' => 'user',
                        'content' => sanitize_text_field($excerpt),
                    ],
                ],
            ]),
            'timeout' => 60,
        ]
    );

    if (is_wp_error($prompt_response) || wp_remote_retrieve_response_code($prompt_response) !== 200) {
        return new WP_Error('api_error', __('Error communicating with OpenAI API.', 'zerobytecode'));
    }

    $prompt_data = json_decode(wp_remote_retrieve_body($prompt_response), true);
    $prompt = $prompt_data['choices'][0]['message']['content'] ?? '';

    if (empty($prompt)) {
        return new WP_Error('prompt_error', __('Unable to generate image prompt.', 'zerobytecode'));
    }

    // Generate image using Dalle 3 API
    $image_response = wp_remote_post(
        'https://api.openai.com/v1/images/generations',
        [
            'headers' => [
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . $api_key,
            ],
            'body' => wp_json_encode([
                'model' => 'dall-e-3',
                'prompt' => sanitize_text_field($prompt),
                'n' => 1,
                'size' => '1792x1024',
            ]),
            'timeout' => 60,
        ]
    );

    if (is_wp_error($image_response) || wp_remote_retrieve_response_code($image_response) !== 200) {
        return new WP_Error('api_error', __('Error generating image with Dalle 3 API.', 'zerobytecode'));
    }

    $image_data = json_decode(wp_remote_retrieve_body($image_response), true);
    $image_url = $image_data['data'][0]['url'] ?? '';

    if (empty($image_url)) {
        return new WP_Error('image_error', __('Unable to get image URL.', 'zerobytecode'));
    }

    // Upload image to media library and set as featured image
    $image_id = zerobytecode_upload_image_to_media_library($image_url, $post_id);

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

    set_post_thumbnail($post_id, $image_id);

    return rest_ensure_response(['success' => true]);
}

// Upload image to media library
function zerobytecode_upload_image_to_media_library($image_url, $post_id)
{
    require_once(ABSPATH . 'wp-admin/includes/file.php');
    require_once(ABSPATH . 'wp-admin/includes/media.php');
    require_once(ABSPATH . 'wp-admin/includes/image.php');

    add_filter('upload_mimes', 'zerobytecode_custom_upload_mimes');

    $tmp = zerobytecode_custom_download_image($image_url);

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

    // Extract the file extension directly from the URL
    $file_ext = pathinfo(parse_url($image_url, PHP_URL_PATH), PATHINFO_EXTENSION);
    $file_name = sanitize_file_name($post_id . '-' . time() . '.' . $file_ext);

    $file_array = [
        'name' => $file_name,
        'tmp_name' => $tmp,
    ];

    $id = media_handle_sideload($file_array, $post_id, __('Generated featured image', 'zerobytecode'));

    if (is_wp_error($id)) {
        @unlink($file_array['tmp_name']);
        return $id;
    }

    return $id;
}

// Custom MIME types for uploads
function zerobytecode_custom_upload_mimes($mimes)
{
    $mimes['png'] = 'image/png';
    return $mimes;
}

/**
 * Custom download function for images.
 *
 * @param string $image_url URL of the image to download.
 * @return string|WP_Error Path to the temporary file or WP_Error on failure.
 */
function zerobytecode_custom_download_image($image_url)
{
    if (!filter_var($image_url, FILTER_VALIDATE_URL)) {
        return new WP_Error('invalid_url', __('Invalid image URL.', 'zerobytecode'));
    }

    $response = wp_remote_get($image_url, [
        'timeout' => 60,
        'sslverify' => true,
    ]);

    if (is_wp_error($response)) {
        return new WP_Error('download_error', __('Error downloading image.', 'zerobytecode'));
    }

    $body = wp_remote_retrieve_body($response);

    if (empty($body)) {
        return new WP_Error('empty_body', __('Downloaded image data is empty.', 'zerobytecode'));
    }

    $file_ext = pathinfo(parse_url($image_url, PHP_URL_PATH), PATHINFO_EXTENSION);
    $file_ext = sanitize_file_name($file_ext);
    $tmp_fname = wp_tempnam($image_url);

    if (!$tmp_fname) {
        return new WP_Error('temp_file_error', __('Unable to create a temporary file.', 'zerobytecode'));
    }

    file_put_contents($tmp_fname, $body);

    return $tmp_fname;
}

Let’s make sure to also have the admin.js file.

11. Admin JavaScript File (admin.js)

The JavaScript file handles the client-side logic for triggering the image generation.

document.addEventListener('DOMContentLoaded', function() {
    const generateBtn = document.getElementById('zerobytecode_generate_btn');
    if (generateBtn) {
        generateBtn.addEventListener('click', function(e) {
            e.preventDefault();
            const postId = generateBtn.dataset.postid;

            // Update button to show loading state
            generateBtn.textContent = 'Generating...';
            generateBtn.disabled = true;

            // Call WordPress REST API to generate the image
            wp.apiRequest({
                path: zerobytecode.rest_url + postId,
                method: 'POST',
                data: {
                    _wpnonce: zerobytecode.nonce
                }
            }).done(function(response) {
                if (response.success) {
                    alert('Featured Image Generated Successfully!');
                    location.reload();
                } else {
                    alert('Error: ' + (response.data.message || 'Something went wrong'));
                }
            }).fail(function(error) {
                alert('Request failed: ' + error.message);
            }).always(function() {
                // Reset button after operation
                generateBtn.textContent = 'Generate Image';
                generateBtn.disabled = false;
            });
        });
    }
});

Now is the most fun step.

Testing the newly created ZeroByteCode AI Featured Image Generator plugin is crucial to ensure it functions correctly and integrates seamlessly with WordPress.

This involves verifying that the plugin’s features, such as settings management, REST API endpoints, and image generation, work as expected. This guide outlines the steps and best practices for testing the plugin.

Key Areas to Test

  1. Plugin Activation and Deactivation
  2. Settings Page Functionality
  3. Meta Box Integration and UI Elements
  4. REST API Endpoint and Permissions
  5. Image Generation Process
  6. Error Handling and Edge Cases

1. Plugin Activation and Deactivation

Activation
  • Check Default Settings: Ensure that upon activation, default settings (such as the content template) are correctly set.
  • Database Options: Verify that the plugin adds necessary options in the WordPress database, such as API keys and templates.

Test Steps:

  1. Activate the plugin via the WordPress admin dashboard.
  2. Check the database or use a plugin like “WP Options” to verify that default options are set.
  3. Ensure no errors or warnings are displayed during activation.
Deactivation
  • Option Removal: Test if the plugin cleans up options if necessary, especially if there’s an option to remove settings on deactivation.

Test Steps:

  1. Deactivate the plugin.
  2. Check if specific options are retained or removed based on plugin configuration.
  3. Re-activate the plugin and ensure it initializes correctly.

2. Settings Page Functionality

ZeroByteCode Featured Image Generator Settings

The settings page is where administrators can enter the OpenAI API key and configure the prompt template.

Test Steps:

  1. Navigate to the plugin’s settings page under “Settings > ZeroByteCode AI.”
  2. Enter a valid OpenAI API key and a custom content template.
  3. Save the settings and verify that the changes persist.
  4. Refresh the page and confirm that the saved settings are correctly displayed.
  5. Test the validation for the API key and content template fields (e.g., ensure no HTML or invalid characters are allowed).

3. Meta Box Integration and UI Elements

Generate Image Meta Box

The meta box allows users to generate a featured image directly from the post editing screen.

Test Steps:

  1. Edit an existing post or create a new one.
  2. Locate the “Generate Featured Image” meta box on the right side of the editor.
  3. Ensure the “Generate Image” button is displayed and functional.
  4. Check if the button is disabled/enabled correctly during the image generation process.

4. REST API Endpoint and Permissions

The REST API endpoint is responsible for handling the image generation requests.

Test Steps:

  1. Use a tool like Postman or cURL to test the REST API endpoint.
  2. Ensure the endpoint responds correctly to POST requests, including validation of the post ID and permissions.
  3. Test with a user who lacks the edit_post capability to ensure they cannot generate an image.
  4. Check the API response for valid and invalid requests, ensuring proper error messages are returned.

5. Image Generation Process

success

This step verifies the core functionality of the plugin—generating images using OpenAI’s Dall-E 3.

Test Steps:

  1. Click the “Generate Image” button and verify that the plugin sends a request to the OpenAI API.
  2. Check the network activity in the browser’s developer tools to ensure the correct API endpoints are called with the expected parameters.
  3. Verify that an image URL is returned and the image is uploaded to the WordPress media library.
  4. Ensure the image is set as the post’s featured image and appears correctly in the post editor.

The result of the generated featured images using OpenAI’s Dall-E 3 AI is really not bad. This is the sample:

Create a WordPress Plugin to Generate Featured Images Using AI Sample Image

Not bad, right?

6. Error Handling and Edge Cases

Testing should cover potential issues such as invalid API keys, network failures, and user input errors.

Test Steps:

  1. Enter an invalid API key and attempt to generate an image. Verify that the plugin correctly handles the error and displays an appropriate message.
  2. Simulate network issues (e.g., by disconnecting from the internet) and test how the plugin responds.
  3. Check the plugin’s behavior with long or complex post content to ensure it generates appropriate prompts.

Additional Considerations

  • Cross-Browser Testing: Ensure the plugin works across different browsers (Chrome, Firefox, Safari, Edge) and on various devices (desktop, tablet, mobile).
  • Accessibility: Verify that the plugin’s UI elements are accessible to all users, including those using screen readers or keyboard navigation.
  • Security: Test for potential security vulnerabilities, such as XSS or SQL injection, especially in user-input areas like the settings page.

Thorough testing of the ZeroByteCode AI Featured Image Generator plugin ensures it functions correctly, provides a good user experience, and integrates seamlessly with WordPress.

By following the steps outlined above, you can identify and address any issues, making the plugin reliable and robust for all users.

Extending the Plugin

We got some ideas of how to extending the plugin to make it more complete, as follows:

  • Add more AI image generators that provide API key.
  • Customize the prompt, or even add another field in the meta box section to add custom prompt to generate the image instead of just relying on the post content (excerpt).
  • Add various image styles to choose from.

Wrapping Up: Creating Your First AI WordPress Plugin Only Took Several Minutes

This guide provides a comprehensive overview of building a WordPress plugin that uses OpenAI’s Dall-E 3 API to generate featured images for posts.

The plugin includes functionality for setting API keys, configuring prompt templates, generating images, and securely handling uploads.

This setup serves as a solid foundation for more advanced features, such as customizing image sizes, adding more image generation options, or integrating with other media services.

Similar Posts