{"id":6,"date":"2025-11-26T11:24:25","date_gmt":"2025-11-26T11:24:25","guid":{"rendered":"https:\/\/test.effecttoxic.xyz\/?p=6"},"modified":"2025-11-26T11:24:25","modified_gmt":"2025-11-26T11:24:25","slug":"6","status":"publish","type":"post","link":"https:\/\/test.effecttoxic.xyz\/?p=6","title":{"rendered":""},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>&lt;?php\n\/*\nPlugin Name: Auto Pro Article Generator\nDescription: Generate professional-style articles automatically using OpenAI and WP-Cron. Saves as draft by default.\nVersion: 1.0\nAuthor: ChatGPT\n*\/\n\nif ( ! defined( 'ABSPATH' ) ) exit;\n\nclass AutoProArticleGenerator {\n    private $option_name = 'apag_settings';\n    private $cron_hook = 'apag_generate_post_cron';\n\n    public function __construct(){\n        add_action('admin_menu', &#91;$this,'admin_menu']);\n        add_action('admin_init', &#91;$this,'register_settings']);\n        add_action('plugins_loaded', &#91;$this,'setup_cron']);\n        add_action($this->cron_hook, &#91;$this,'generate_and_insert_post']);\n        add_action('admin_post_apag_generate_now', &#91;$this,'handle_generate_now']);\n    }\n\n    \/* Admin menu *\/\n    public function admin_menu(){\n        add_options_page('Auto Pro Article', 'Auto Pro Article', 'manage_options', 'apag-settings', &#91;$this,'settings_page']);\n    }\n\n    \/* Register settings *\/\n    public function register_settings(){\n        register_setting($this->option_name, $this->option_name, &#91;$this,'sanitize']);\n    }\n\n    public function sanitize($input){\n        $output = &#91;];\n        $output&#91;'api_key'] = sanitize_text_field($input&#91;'api_key'] ?? '');\n        $output&#91;'category'] = intval($input&#91;'category'] ?? 0);\n        $output&#91;'interval'] = sanitize_text_field($input&#91;'interval'] ?? 'daily');\n        $output&#91;'prompt_template'] = wp_kses_post($input&#91;'prompt_template'] ?? $this->default_prompt());\n        $output&#91;'post_status'] = in_array($input&#91;'post_status'] ?? 'draft', &#91;'draft','publish']) ? $input&#91;'post_status'] : 'draft';\n        $output&#91;'max_tokens'] = intval($input&#91;'max_tokens'] ?? 800);\n        return $output;\n    }\n\n    private function default_prompt(){\n        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.\";\n    }\n\n    \/* Settings page *\/\n    public function settings_page(){\n        if (!current_user_can('manage_options')) wp_die('Unauthorized');\n        $opts = get_option($this->option_name, &#91;]);\n        ?>\n        &lt;div class=\"wrap\">\n            &lt;h1>Auto Pro Article Settings&lt;\/h1>\n            &lt;form method=\"post\" action=\"options.php\">\n            &lt;?php settings_fields($this->option_name); do_settings_sections($this->option_name); ?>\n            &lt;table class=\"form-table\">\n                &lt;tr>\n                    &lt;th>OpenAI API Key&lt;\/th>\n                    &lt;td>&lt;input type=\"password\" name=\"&lt;?php echo esc_attr($this->option_name); ?>&#91;api_key]\" value=\"&lt;?php echo esc_attr($opts&#91;'api_key'] ?? ''); ?>\" style=\"width:400px\" \/>&lt;\/td>\n                &lt;\/tr>\n                &lt;tr>\n                    &lt;th>Default Category&lt;\/th>\n                    &lt;td>&lt;?php wp_dropdown_categories(&#91;\n                        'name' => $this->option_name . '&#91;category]',\n                        'selected' => $opts&#91;'category'] ?? 0,\n                        'show_option_none' => '-- Choose category --'\n                    ]); ?>&lt;\/td>\n                &lt;\/tr>\n                &lt;tr>\n                    &lt;th>Interval (WP-Cron)&lt;\/th>\n                    &lt;td>\n                        &lt;select name=\"&lt;?php echo esc_attr($this->option_name); ?>&#91;interval]\">\n                            &lt;option value=\"hourly\" &lt;?php selected($opts&#91;'interval'] ?? 'daily','hourly'); ?>>Hourly&lt;\/option>\n                            &lt;option value=\"twicedaily\" &lt;?php selected($opts&#91;'interval'] ?? 'daily','twicedaily'); ?>>Twice Daily&lt;\/option>\n                            &lt;option value=\"daily\" &lt;?php selected($opts&#91;'interval'] ?? 'daily','daily'); ?>>Daily&lt;\/option>\n                        &lt;\/select>\n                    &lt;\/td>\n                &lt;\/tr>\n                &lt;tr>\n                    &lt;th>Post Status&lt;\/th>\n                    &lt;td>\n                        &lt;select name=\"&lt;?php echo esc_attr($this->option_name); ?>&#91;post_status]\">\n                            &lt;option value=\"draft\" &lt;?php selected($opts&#91;'post_status'] ?? 'draft','draft'); ?>>Draft (recommended)&lt;\/option>\n                            &lt;option value=\"publish\" &lt;?php selected($opts&#91;'post_status'] ?? 'draft','publish'); ?>>Publish immediately&lt;\/option>\n                        &lt;\/select>\n                    &lt;\/td>\n                &lt;\/tr>\n                &lt;tr>\n                    &lt;th>Max tokens \/ length&lt;\/th>\n                    &lt;td>&lt;input type=\"number\" min=\"200\" max=\"2000\" name=\"&lt;?php echo esc_attr($this->option_name); ?>&#91;max_tokens]\" value=\"&lt;?php echo esc_attr($opts&#91;'max_tokens'] ?? 800); ?>\" \/>&lt;\/td>\n                &lt;\/tr>\n                &lt;tr>\n                    &lt;th>Prompt Template&lt;\/th>\n                    &lt;td>&lt;textarea name=\"&lt;?php echo esc_attr($this->option_name); ?>&#91;prompt_template]\" rows=\"6\" cols=\"80\">&lt;?php echo esc_textarea($opts&#91;'prompt_template'] ?? $this->default_prompt()); ?>&lt;\/textarea>\n                    &lt;p class=\"description\">Use {topic} placeholder for topic. Keep instructions clear for professional tone.&lt;\/p>&lt;\/td>\n                &lt;\/tr>\n            &lt;\/table>\n            &lt;?php submit_button(); ?>\n            &lt;\/form>\n\n            &lt;h2>Manual generation&lt;\/h2>\n            &lt;form method=\"post\" action=\"&lt;?php echo esc_url(admin_url('admin-post.php')); ?>\">\n                &lt;?php wp_nonce_field('apag_generate_now'); ?>\n                &lt;input type=\"hidden\" name=\"action\" value=\"apag_generate_now\" \/>\n                &lt;input type=\"text\" name=\"topic\" placeholder=\"Topic (e.g. Cara merawat smartphone)\" style=\"width:400px\" required \/>\n                &lt;button class=\"button button-primary\" type=\"submit\">Generate Now&lt;\/button>\n            &lt;\/form>\n        &lt;\/div>\n        &lt;?php\n    }\n\n    \/* Handle manual generate *\/\n    public function handle_generate_now(){\n        if (!current_user_can('manage_options')) wp_die('Unauthorized');\n        check_admin_referer('apag_generate_now');\n        $topic = sanitize_text_field($_POST&#91;'topic'] ?? '');\n        $this->generate_and_insert_post($topic);\n        wp_redirect(admin_url('options-general.php?page=apag-settings'));\n        exit;\n    }\n\n    \/* Setup WP-Cron *\/\n    public function setup_cron(){\n        $opts = get_option($this->option_name, &#91;]);\n        $interval = $opts&#91;'interval'] ?? 'daily';\n        \/\/ clear existing then schedule\n        wp_clear_scheduled_hook($this->cron_hook);\n        if (!wp_next_scheduled($this->cron_hook)) {\n            wp_schedule_event(time()+60, $interval, $this->cron_hook);\n        }\n    }\n\n    \/* Core: generate content and insert post *\/\n    public function generate_and_insert_post($manual_topic = null){\n        $opts = get_option($this->option_name, &#91;]);\n        if (empty($opts&#91;'api_key'])) return;\n\n        \/\/ Choose topic: either manual param or simple helper (you can expand this)\n        $topic = $manual_topic ? sanitize_text_field($manual_topic) : $this->pick_topic();\n\n        if (!$topic) return;\n\n        $prompt = str_replace('{topic}', $topic, $opts&#91;'prompt_template']);\n\n        $generated = $this->call_openai($opts&#91;'api_key'], $prompt, $opts&#91;'max_tokens'] ?? 800);\n        if (!$generated) return;\n\n        \/\/ Parse for SEO suggestion: simple split. If response includes \"Suggested SEO title:\" we'll try to extract - otherwise fallback.\n        $title = $this->extract_between($generated, \"Suggested SEO title:\", \"\\n\") ?: wp_trim_words($topic, 8, '');\n        $content = $generated;\n\n        $post = &#91;\n            'post_title'   => wp_strip_all_tags($title),\n            'post_content' => wp_kses_post($content),\n            'post_status'  => $opts&#91;'post_status'] ?? 'draft',\n            'post_category'=> $opts&#91;'category'] ? &#91;$opts&#91;'category']] : &#91;],\n            'post_author'  => get_current_user_id(),\n        ];\n\n        wp_insert_post($post);\n    }\n\n    private function pick_topic(){\n        \/\/ Simple placeholder: pick recent tag\/topic or random. You should replace with your topic source or keywords list.\n        $topics = &#91;\n            'Tren teknologi 2025 untuk UMKM',\n            'Cara mengoptimalkan SEO on-page 2025',\n            'Tips memilih laptop untuk content creator',\n            'Panduan dasar monetisasi blog',\n        ];\n        return $topics&#91;array_rand($topics)];\n    }\n\n    private function extract_between($text, $start, $end){\n        $s = strpos($text, $start);\n        if ($s === false) return null;\n        $s += strlen($start);\n        $e = strpos($text, $end, $s);\n        if ($e === false) $e = strlen($text);\n        return trim(substr($text, $s, $e-$s));\n    }\n\n    \/* Call OpenAI using wp_remote_post *\/\n    private function call_openai($api_key, $prompt, $max_tokens=800){\n        $endpoint = 'https:\/\/api.openai.com\/v1\/chat\/completions';\n        $body = &#91;\n            'model' => 'gpt-4o-mini', \/\/ change if you prefer another\n            'messages' => &#91;\n                &#91;'role' => 'system', 'content' => 'You are an expert content writer. Produce long-form articles in Indonesian with a professional tone.'],\n                &#91;'role' => 'user', 'content' => $prompt]\n            ],\n            'max_tokens' => intval($max_tokens),\n            'temperature' => 0.2,\n            'top_p' => 1,\n        ];\n\n        $response = wp_remote_post($endpoint, &#91;\n            'headers' => &#91;\n                'Authorization' => 'Bearer ' . $api_key,\n                'Content-Type' => 'application\/json',\n            ],\n            'body' => wp_json_encode($body),\n            'timeout' => 60,\n        ]);\n\n        if (is_wp_error($response)) {\n            error_log('APAG OpenAI error: ' . $response->get_error_message());\n            return false;\n        }\n\n        $code = wp_remote_retrieve_response_code($response);\n        $body = wp_remote_retrieve_body($response);\n        $json = json_decode($body, true);\n        if ($code !== 200 || empty($json&#91;'choices']&#91;0]&#91;'message']&#91;'content'])) {\n            error_log('APAG OpenAI bad response: ' . $body);\n            return false;\n        }\n        return $json&#91;'choices']&#91;0]&#91;'message']&#91;'content'];\n    }\n}\n\nnew AutoProArticleGenerator();\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-6","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=\/wp\/v2\/posts\/6","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6"}],"version-history":[{"count":1,"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=\/wp\/v2\/posts\/6\/revisions"}],"predecessor-version":[{"id":8,"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=\/wp\/v2\/posts\/6\/revisions\/8"}],"wp:attachment":[{"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/test.effecttoxic.xyz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}