Blog

  • <?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();
    
  • Hello world!

    Welcome to WordPress. This is your first post. Edit or delete it, then start writing!