<?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();
Blog
-
-
Hello world!
Welcome to WordPress. This is your first post. Edit or delete it, then start writing!