<?php
/*
Plugin Name: Auto Pro Article Generator
Description: Generate professional-style articles automatically using OpenAI and WP-Cron. Saves as draft by default.
Version: 1.0
Author: ChatGPT
*/

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

class AutoProArticleGenerator {
    private $option_name = 'apag_settings';
    private $cron_hook = 'apag_generate_post_cron';

    public function __construct(){
        add_action('admin_menu', [$this,'admin_menu']);
        add_action('admin_init', [$this,'register_settings']);
        add_action('plugins_loaded', [$this,'setup_cron']);
        add_action($this->cron_hook, [$this,'generate_and_insert_post']);
        add_action('admin_post_apag_generate_now', [$this,'handle_generate_now']);
    }

    /* Admin menu */
    public function admin_menu(){
        add_options_page('Auto Pro Article', 'Auto Pro Article', 'manage_options', 'apag-settings', [$this,'settings_page']);
    }

    /* Register settings */
    public function register_settings(){
        register_setting($this->option_name, $this->option_name, [$this,'sanitize']);
    }

    public function sanitize($input){
        $output = [];
        $output['api_key'] = sanitize_text_field($input['api_key'] ?? '');
        $output['category'] = intval($input['category'] ?? 0);
        $output['interval'] = sanitize_text_field($input['interval'] ?? 'daily');
        $output['prompt_template'] = wp_kses_post($input['prompt_template'] ?? $this->default_prompt());
        $output['post_status'] = in_array($input['post_status'] ?? 'draft', ['draft','publish']) ? $input['post_status'] : 'draft';
        $output['max_tokens'] = intval($input['max_tokens'] ?? 800);
        return $output;
    }

    private function default_prompt(){
        return "Write a professional, well-structured article in Indonesian about the topic: {topic}. Length: about 600-800 words. Include an engaging introduction, 3-5 informative subheadings, and a concise conclusion. Use an authoritative, friendly tone. Add suggested SEO title and meta description.";
    }

    /* Settings page */
    public function settings_page(){
        if (!current_user_can('manage_options')) wp_die('Unauthorized');
        $opts = get_option($this->option_name, []);
        ?>
        <div class="wrap">
            <h1>Auto Pro Article Settings</h1>
            <form method="post" action="options.php">
            <?php settings_fields($this->option_name); do_settings_sections($this->option_name); ?>
            <table class="form-table">
                <tr>
                    <th>OpenAI API Key</th>
                    <td><input type="password" name="<?php echo esc_attr($this->option_name); ?>[api_key]" value="<?php echo esc_attr($opts['api_key'] ?? ''); ?>" style="width:400px" /></td>
                </tr>
                <tr>
                    <th>Default Category</th>
                    <td><?php wp_dropdown_categories([
                        'name' => $this->option_name . '[category]',
                        'selected' => $opts['category'] ?? 0,
                        'show_option_none' => '-- Choose category --'
                    ]); ?></td>
                </tr>
                <tr>
                    <th>Interval (WP-Cron)</th>
                    <td>
                        <select name="<?php echo esc_attr($this->option_name); ?>[interval]">
                            <option value="hourly" <?php selected($opts['interval'] ?? 'daily','hourly'); ?>>Hourly</option>
                            <option value="twicedaily" <?php selected($opts['interval'] ?? 'daily','twicedaily'); ?>>Twice Daily</option>
                            <option value="daily" <?php selected($opts['interval'] ?? 'daily','daily'); ?>>Daily</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <th>Post Status</th>
                    <td>
                        <select name="<?php echo esc_attr($this->option_name); ?>[post_status]">
                            <option value="draft" <?php selected($opts['post_status'] ?? 'draft','draft'); ?>>Draft (recommended)</option>
                            <option value="publish" <?php selected($opts['post_status'] ?? 'draft','publish'); ?>>Publish immediately</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <th>Max tokens / length</th>
                    <td><input type="number" min="200" max="2000" name="<?php echo esc_attr($this->option_name); ?>[max_tokens]" value="<?php echo esc_attr($opts['max_tokens'] ?? 800); ?>" /></td>
                </tr>
                <tr>
                    <th>Prompt Template</th>
                    <td><textarea name="<?php echo esc_attr($this->option_name); ?>[prompt_template]" rows="6" cols="80"><?php echo esc_textarea($opts['prompt_template'] ?? $this->default_prompt()); ?></textarea>
                    <p class="description">Use {topic} placeholder for topic. Keep instructions clear for professional tone.</p></td>
                </tr>
            </table>
            <?php submit_button(); ?>
            </form>

            <h2>Manual generation</h2>
            <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                <?php wp_nonce_field('apag_generate_now'); ?>
                <input type="hidden" name="action" value="apag_generate_now" />
                <input type="text" name="topic" placeholder="Topic (e.g. Cara merawat smartphone)" style="width:400px" required />
                <button class="button button-primary" type="submit">Generate Now</button>
            </form>
        </div>
        <?php
    }

    /* Handle manual generate */
    public function handle_generate_now(){
        if (!current_user_can('manage_options')) wp_die('Unauthorized');
        check_admin_referer('apag_generate_now');
        $topic = sanitize_text_field($_POST['topic'] ?? '');
        $this->generate_and_insert_post($topic);
        wp_redirect(admin_url('options-general.php?page=apag-settings'));
        exit;
    }

    /* Setup WP-Cron */
    public function setup_cron(){
        $opts = get_option($this->option_name, []);
        $interval = $opts['interval'] ?? 'daily';
        // clear existing then schedule
        wp_clear_scheduled_hook($this->cron_hook);
        if (!wp_next_scheduled($this->cron_hook)) {
            wp_schedule_event(time()+60, $interval, $this->cron_hook);
        }
    }

    /* Core: generate content and insert post */
    public function generate_and_insert_post($manual_topic = null){
        $opts = get_option($this->option_name, []);
        if (empty($opts['api_key'])) return;

        // Choose topic: either manual param or simple helper (you can expand this)
        $topic = $manual_topic ? sanitize_text_field($manual_topic) : $this->pick_topic();

        if (!$topic) return;

        $prompt = str_replace('{topic}', $topic, $opts['prompt_template']);

        $generated = $this->call_openai($opts['api_key'], $prompt, $opts['max_tokens'] ?? 800);
        if (!$generated) return;

        // Parse for SEO suggestion: simple split. If response includes "Suggested SEO title:" we'll try to extract - otherwise fallback.
        $title = $this->extract_between($generated, "Suggested SEO title:", "\n") ?: wp_trim_words($topic, 8, '');
        $content = $generated;

        $post = [
            'post_title'   => wp_strip_all_tags($title),
            'post_content' => wp_kses_post($content),
            'post_status'  => $opts['post_status'] ?? 'draft',
            'post_category'=> $opts['category'] ? [$opts['category']] : [],
            'post_author'  => get_current_user_id(),
        ];

        wp_insert_post($post);
    }

    private function pick_topic(){
        // Simple placeholder: pick recent tag/topic or random. You should replace with your topic source or keywords list.
        $topics = [
            'Tren teknologi 2025 untuk UMKM',
            'Cara mengoptimalkan SEO on-page 2025',
            'Tips memilih laptop untuk content creator',
            'Panduan dasar monetisasi blog',
        ];
        return $topics[array_rand($topics)];
    }

    private function extract_between($text, $start, $end){
        $s = strpos($text, $start);
        if ($s === false) return null;
        $s += strlen($start);
        $e = strpos($text, $end, $s);
        if ($e === false) $e = strlen($text);
        return trim(substr($text, $s, $e-$s));
    }

    /* Call OpenAI using wp_remote_post */
    private function call_openai($api_key, $prompt, $max_tokens=800){
        $endpoint = 'https://api.openai.com/v1/chat/completions';
        $body = [
            'model' => 'gpt-4o-mini', // change if you prefer another
            'messages' => [
                ['role' => 'system', 'content' => 'You are an expert content writer. Produce long-form articles in Indonesian with a professional tone.'],
                ['role' => 'user', 'content' => $prompt]
            ],
            'max_tokens' => intval($max_tokens),
            'temperature' => 0.2,
            'top_p' => 1,
        ];

        $response = wp_remote_post($endpoint, [
            'headers' => [
                'Authorization' => 'Bearer ' . $api_key,
                'Content-Type' => 'application/json',
            ],
            'body' => wp_json_encode($body),
            'timeout' => 60,
        ]);

        if (is_wp_error($response)) {
            error_log('APAG OpenAI error: ' . $response->get_error_message());
            return false;
        }

        $code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        $json = json_decode($body, true);
        if ($code !== 200 || empty($json['choices'][0]['message']['content'])) {
            error_log('APAG OpenAI bad response: ' . $body);
            return false;
        }
        return $json['choices'][0]['message']['content'];
    }
}

new AutoProArticleGenerator();

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *