':'';
}
// Combine the keywords into a comma-separated list
$keywords_list = implode(', ', $keywords);
$_cats = array();
foreach($cats as $cat){
$term = get_term_by('name', $cat, 'category');
if(!$term){
$term = wp_insert_term(
$cat,
'category',
);
if(!is_wp_error($term)){
$_cats[] = $term['term_id'];
}
}else{
$_cats[] = $term->term_id;
}
}
// Insert post if requested
$created_url = '';
if ($this->ws4agpt_get_settings('is_wp_post') === 'yes' && $is_wp_post === 'yes') {
$post_data = [
'post_title' => $title,
'post_content' => $content, // This content can be generated by using the keywords together
'post_type' => $this->ws4agpt_get_settings('ws4agpt_post_type') ?: 'post',
'post_status' => $this->ws4agpt_get_settings('ws4agpt_publish') === 'yes' ? 'publish' : 'draft',
'post_category'=> $_cats,
// Add the keywords as post tags (comma-separated)
'tags_input' => $keywords_list, // Here we use the combined list
];
$post_id = wp_insert_post($post_data);
if (is_wp_error($post_id)) {
$error_message = esc_html($post_id->get_error_message());
// $result['error'] = $error_message;
$result['error'] = "Failed to post article on Wordpress";
}else{
$result['success'] = "Article generated successfully.";
unset($result['error']);
}
$created_url = get_edit_post_link($post_id);
}
ob_clean();
return $result;
}
private function ws4agpt_generate_long_article_in_chunks($title, $keywords, $cats, $company, $length, $density = 1)
{
$chunk_word_count = 1000;
$total_chunks = ceil($length / $chunk_word_count);
// Step 1: Generate outline (only top-level subtopics)
$outline_prompt = "Generate a detailed outline with {$total_chunks} unique subtopics for an article titled: \"{$title}\". Each topic must be unique, specific, and suitable for expanding into 1000 words. Return as a numbered plain list.";
$outline_response = $this->ws4agpt_get_api_completions($outline_prompt, $length);
$outline_json = json_decode($outline_response);
$outline_text = $outline_json->choices[0]->message->content ?? '';
// Parse only top-level numbered items (ignore nested bullets)
preg_match_all('/^\d+\.\s*(.+)$/m', $outline_text, $matches);
$outline_topics = $matches[1] ?? [];
if (empty($outline_topics)) {
$this->ws4agpt_log_error('ws4agpt_generate_long_article_in_chunks', $outline_json);
return '';
}
$covered_topics = [];
$previous_summaries = [];
$final_content = [];
for ($i = 0; $i < count($outline_topics); $i++) {
$part = $i + 1;
$sub_topics = trim($outline_topics[$i]);
$subtopic = str_replace('*', '', $sub_topics);
$is_last = ($part === count($outline_topics));
// Append subtopic to prompt title
$custom_title = "{$title} - {$subtopic}";
// Generate prompt using your cleaned function
$prompt = $this->ws4agpt_prepare_prompt($custom_title, $keywords, $cats, $company, $chunk_word_count, $density);
// Add anti-duplication logic
if (!empty($previous_summaries)) {
$prompt .= "\n\n== Previous Summaries ==\n";
foreach ($previous_summaries as $idx => $sum) {
$prompt .= "Part " . ($idx + 1) . " Summary:\n{$sum}\n";
}
}
if (!empty($covered_topics)) {
$prompt .= "\n== Do NOT Repeat These Subtopics ==\n";
foreach (array_unique($covered_topics) as $topic) {
$prompt .= "- {$topic}\n";
}
}
// Add section logic
$prompt .= "\n\nWrite Part {$part} of the article. Focus only on the topic: \"{$subtopic}\".\n Use subheadings. Do not repeat previous ideas.\n";
// Request content
$response = $this->ws4agpt_get_api_completions($prompt, $length);
$result = json_decode($response);
$content = $result->choices[0]->message->content ?? '';
if ( empty( $content ) ) {
$this->ws4agpt_log_error( 'ws4agpt_generate_long_article_in_chunks', 'Chunk ' . $part . ' returned empty content.' );
return ''; // Stop execution and return error immediately
}
// Track topics (subheadings)
preg_match_all('/]*>(.*?)<\/h[2-4]>|^(#+\s*)(.*)/m', $content, $matches);
$headings = array_filter(array_map('trim', array_merge($matches[1], $matches[3])));
$covered_topics = array_merge($covered_topics, $headings);
// Summarize this chunk (light summary logic)
$summary_prompt = "Summarize this section in 2-3 sentences:\n\n{$content}";
$summary_response = $this->ws4agpt_get_api_completions($summary_prompt, $length);
// Append content
$final_content[] = $content;
}
return implode("\n\n", $final_content);
}
private function ws4agpt_prepare_prompt($title, $keywords, $cats, $company = '', $length = 1000, $density = 1) {
// Convert length and density to integers to prevent string multiplication
$length = intval($length);
$density = intval($density);
// Calculate keyword frequency using integers
$keyword_frequency = (int)(($length * $density) / 100);
// Sanitize title
$title = htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
// Prepare keyword phrase
if (is_array($keywords)) {
$keywords = implode('", "', array_values($keywords));
}
$prompt = "Write an engaging, well-structured article with the following specifications:\n";
$prompt .= "- Length: Up to {$length} words.\n";
$prompt .= "- Title: \"{$title}\" (but do NOT include this title at the top of the article).\n";
$prompt .= "Writing rules:\n";
$prompt .= "- Use a clear introduction, body, and conclusion.\n";
$prompt .= "- Organize with proper paragraphs (
) and logical flow.\n";
$prompt .= "- The content must be unique, informative, and engaging.\n";
$prompt .= "- Avoid keyword stuffing. Use synonyms and natural variations.\n";
$prompt .= "- Write in a conversational but professional tone.\n\n";
// Keyword handling (dynamic)
$prompt .= "Keyword usage rules:\n";
$prompt .= "- Exact Keyword Phrase: Use the exact keyword phrase \"{$keywords}\" exactly as provided and it must always appear inside complete sentences or paragraphs. The phrase \"{$keywords}\" must appear exactly {$keyword_frequency} times in the article.\n";
$prompt .= "IMPORTANT: NEVER use the keyword phrase(s) as a heading, subheading, bold line, bullet point, or standalone text.\n";
$prompt .= "- Do not wrap the keyword phrase(s) in
,
,
, or make them separate titles or links.\n";
$prompt .= "- Spread the keyword phrase(s) naturally across the article, without repetition in close proximity.\n\n";
$prompt .= "- Maintain readability, flow, and natural language as the top priority.\n";
// Include categories if provided
if (is_array($cats) && !empty($cats)) {
$categories = implode('", "', $cats);
$prompt .= "- Mention the category terms \"{$categories}\" naturally at least twice in the article body.\n";
// $prompt .= "- In the content, ensure the phrase \"{$categories}\" is mentioned at least twice within the body in the article.\n";
} elseif (!empty($cats)) {
$prompt .= "- Mention the category term \"{$cats}\" naturally at least twice in the article body.\n";
// $prompt .= "- In the content, ensure the phrase \"{$cats}\" is mentioned at least twice within the body in the article.\n";
}
// Include company name if provided
if (!empty($company)) {
$prompt .= "- Include the company name \"{$company}\" exactly twice in the article in natural, meaningful sentences. Do not use variations or additional words.\n";
}
// Strong instruction to avoid hashes
$prompt .= "- DO NOT use the hash (#) symbol anywhere. All headings, subheadings, titles, and paragraphs must be plain text only. Do NOT use Markdown-style headers like '### Heading'.\n";
$prompt .= "- Use only plain text headings and subheadings. Numbered or bulleted lists are allowed as plain text (e.g., '1. Heading', 'A. Subheading').\n";
$prompt .= "Ensure that the exact keyword phrase \"{$keywords}\" is used precisely as provided, without any consideration for grammar or sentence structure. The keyword phrase must be used exactly {$keyword_frequency} times throughout the article.\n";
$prompt .= "Remember, the keyword phrase \"{$keywords}\" must be inserted exactly as provided, regardless of its impact on the readability or grammar of the content. This requirement is non-negotiable, and the keyword phrase should be used exactly {$keyword_frequency} times, even if it does not make grammatical sense.";
$prompt .= "- DO NOT use hash (#) symbols anywhere in the article, including in subheadings or titles. This includes Markdown-style headers (e.g., `### Heading`).\n";
// Log the generated prompt for debugging
return $prompt;
}
private function ws4agpt_get_api_completions($prompt, $length) {
// Retrieve API key and other settings
$key = get_option('ws4agpt_aeS25_wsfa_wsfa');
$iv = substr($key, 0, 16);
$apiKey = openssl_decrypt($this->ws4agpt_get_settings('ws4agpt_api_key'), 'AES-256-CBC', $key, 0, $iv); // phpcs:ignore
$model = $this->ws4agpt_get_settings('ws4agpt_gpt-model');
$top_p = $this->ws4agpt_get_settings('ws4agpt_top_p');
$temperature = $this->ws4agpt_get_settings('ws4agpt_temprature');
$presence_penalty = $this->ws4agpt_get_settings('ws4agpt_presence_penalty');
$frequency_penalty = $this->ws4agpt_get_settings('ws4agpt_frequency_penalty');
$api_n = $this->ws4agpt_get_settings('ws4agpt_api_n');
$best_of = $this->ws4agpt_get_settings('ws4agpt_best_of');
$max_tokens = $this->ws4agpt_get_settings('ws4agpt_max_tokens');
// Set the request headers
$headers = array(
"Content-Type: application/json",
"Authorization: Bearer " . $apiKey,
);
$gpt_3_models = array('gpt-3.5-turbo', 'gpt-3.5-turbo-16k');
$gpt_4_models = array('gpt-4', 'gpt-4-turbo', 'gpt-4-turbo-32k');
$gpt_4_mini_models = array('gpt-4o-mini');
if ( in_array( $model, $gpt_3_models ) ) {
$url = "https://api.openai.com/v1/chat/completions";
$message = new stdClass();
$message->role = 'user';
$message->content = $prompt;
$gpt3_max_tokens = 3900;
$data = array(
"model" => $model,
"messages" => array($message),
"temperature" => (float) $temperature,
"top_p" => (float) $top_p,
"frequency_penalty" => (float) $frequency_penalty,
"presence_penalty" => (float) $presence_penalty,
"n" => (int) $api_n,
"max_tokens" => (int) $gpt3_max_tokens,
);
} elseif (in_array($model, $gpt_4_models)) {
$url = "https://api.openai.com/v1/chat/completions";
$message = new stdClass();
$message->role = 'user';
$message->content = $prompt;
$gpt4_max_tokens = 3900;
$data = array(
"model" => $model,
"messages" => array($message),
"temperature" => (float) $temperature,
"top_p" => (float) $top_p,
"frequency_penalty" => (float) $frequency_penalty,
"presence_penalty" => (float) $presence_penalty,
"n" => (int) $api_n,
"max_tokens" => (int) $gpt4_max_tokens,
);
} elseif (in_array($model, ['gpt-4o'])) {
$url = "https://api.openai.com/v1/chat/completions";
$message = new stdClass();
$message->role = 'user';
$message->content = $prompt;
$max_tokens = 5000;
$data = array(
"model" => $model,
"messages" => array($message),
"temperature" => (float) $temperature,
"top_p" => (float) $top_p,
"frequency_penalty" => (float) $frequency_penalty,
"presence_penalty" => (float) $presence_penalty,
"n" => (int) $api_n,
"max_tokens" => (int) $max_tokens,
);
} elseif (in_array($model, ['gpt-4o-mini'])) {
$url = "https://api.openai.com/v1/chat/completions";
$message = new stdClass();
$message->role = 'user';
$message->content = $prompt;
$gpt4mini_max_tokens = (int) ceil($length * 1.1);
$data = array(
"model" => $model,
"messages" => array($message),
"temperature" => (float) $temperature,
"top_p" => (float) $top_p,
"frequency_penalty" => (float) $frequency_penalty,
"presence_penalty" => (float) $presence_penalty,
"n" => (int) $api_n,
"max_tokens" => (int) $gpt4mini_max_tokens,
);
} else {
$url = "https://api.openai.com/v1/completions";
$data = array(
"model" => $model,
"prompt" => $prompt,
"temperature" => (float) $temperature,
"top_p" => (float) $top_p,
"frequency_penalty" => (float) $frequency_penalty,
"presence_penalty" => (float) $presence_penalty,
"n" => (int) $api_n,
"best_of" => (int) $best_of,
"max_tokens" => (int) $max_tokens,
);
}
// Log the request data for debugging
//$this->ws4agpt_log_error('ws4agpt_get_api_completions $data', $data);
$response = $this->ws4agpt_process_request($url, $apiKey, $data, true);
return $response;
}
function ws4agpt_process_request($url, $apiKey, $data = array(), $post = false) {
$headers = array(
'Authorization' => 'Bearer ' . $apiKey,
'Content-Type' => 'application/json',
);
$args = array(
'method' => $post ? 'POST' : 'GET',
'timeout' => 120,
'headers' => $headers,
'body' => !empty($data) ? wp_json_encode($data) : null,
);
$response = wp_remote_request($url, $args);
if (is_wp_error($response)) {
return new WP_Error('request_failed', 'Failed to make the API request', $response->get_error_message());
}
return wp_remote_retrieve_body($response);
}
function ws4agpt_insert_term($term_type, $term_name, $link1='', $link2='', $term_parent=0) {
$result = array();
$term_name = sanitize_text_field(trim($term_name));
if (!empty($term_name)) {
$term = get_term_by('name', $term_name, $term_type);
if (!$term) {
$term = wp_insert_term(
$term_name,
$term_type,
array('parent' => $term_parent)
);
if (!is_wp_error($term)) {
$result['term_id'] = $term['term_id'];
} else {
$result['error'] = $term->get_error_message();
return $result; // Return early if there's an error
}
} else {
$result['term_id'] = $term->term_id;
}
} else {
$result['error'] = "Term name is empty.";
return $result; // Return early if the term name is empty
}
if (isset($result['term_id'])) {
$option_key = 'ws4agpt_taxonomy_' . $result['term_id'];
$term_meta = get_option( $option_key, array() ); // default is array, no warning
if ( ! is_array( $term_meta ) ) {
$term_meta = array();
}
// $term_meta = get_option("ws4agpt_taxonomy_" . $result['term_id']);
$term_meta['keyword_link1'] = $link1;
$term_meta['keyword_link2'] = $link2;
update_option( $option_key, $term_meta );
}
return $result;
}
function ws4agpt_is_turbo_model($model){
// List of turbo models
$turbo_models = array(
'gpt-3.5-turbo',
'gpt-3.5-turbo-0301',
'gpt-4',
'gpt-4-turbo',
'gpt-4-turbo-32k',
'gpt-4o',
'gpt-4o-mini'
);
return in_array($model, $turbo_models);
}
/* Add custom cron schedules.
* The default supported recurrences are hourly, twicedaily, daily and weekly.
*/
function ws4agpt_add_schedules( $schedules ) {
$schedules['minute'] = array(
'interval' => 60,
'display' => __( 'Every Minute', 'ai-auto-seo' ),
);
$schedules['everytwominutes'] = array(
'interval' => 120,
'display' => __( 'Every two minutes', 'ai-auto-seo' ),
);
$schedules['everyfiveminutes'] = array(
'interval' => 300,
'display' => __('Every five minutes', 'ai-auto-seo')
);
$schedules['sixtimesaweek'] = array(
'interval' => 100800,
'display' => __('Six times a Week', 'ai-auto-seo')
);
$schedules['fivetimesaweek'] = array(
'interval' => 120960,
'display' => __('Five times a Week', 'ai-auto-seo')
);
$schedules['fourtimesaweek'] = array(
'interval' => 151200,
'display' => __('Four times a Week', 'ai-auto-seo')
);
$schedules['thriceweekly'] = array(
'interval' => 201600,
'display' => __('Thrice a Week', 'ai-auto-seo')
);
$schedules['twiceweekly'] = array(
'interval' => 302400,
);
$schedules['thricemonthly'] = array(
'interval' => 864000,
'display' => __('Thrice a Month', 'ai-auto-seo')
);
$schedules['twicemonthly'] = array(
'interval' => 1296000,
'display' => __('Twice a Month', 'ai-auto-seo')
);
$schedules['monthly'] = array(
'interval' => 2592000,
'display' => __('Once a Month', 'ai-auto-seo')
);
return $schedules;
}
public function ws4agpt_dismiss_notice(){
// Verify the nonce before processing form data
$nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : ''; // phpcs:ignore
if (!wp_verify_nonce($nonce, 'ws4agpt_dismiss_notices')) {
wp_send_json_error();
}
// Check if notice_id exists and unslash it
$notice_id = isset($_POST['notice_id']) ? sanitize_text_field(wp_unslash($_POST['notice_id'])) : '';
if (empty($notice_id)) {
wp_send_json_error();
}
$user_id = get_current_user_id();
update_user_meta($user_id, $notice_id, time());
wp_send_json_success();
}
public static function ws4agpt_admin_notice(){
global $pagenow;
$post_type = isset($_GET['post_type']) ? sanitize_text_field(wp_unslash($_GET['post_type'])) : ''; // phpcs:ignore
$page_type = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : ''; // phpcs:ignore
$ws4agpt_page_types = [
'ws4agpt_gpt_image_options',
'ws4agpt_gpt_single_options',
'ws4agpt_gpt_bulk_options',
'ws4agpt_gpt_settings',
];
$ws4agpt_user_id = get_current_user_id();
$ws4agpt_notice_id = 'ws4agpt_promo_notice';
// Check dismissal timestamp
$last_dismissed = get_user_meta($ws4agpt_user_id, $ws4agpt_notice_id, true);
if ($last_dismissed && (time() - intval($last_dismissed)) < 86400) {
return; // less than 1 day, don't show
}
$is_plugin_screen = ( ($pagenow === 'edit.php' && $post_type === 'ws4agpt_gpt_post') || in_array($page_type, $ws4agpt_page_types) );
if (get_option('ws4agpt_auto_seo_pro_active') !== 'yes' && $is_plugin_screen) {
// Get current stored text
$stored_promo = array(
'heading' => get_option('ws4agpt_promo_heading',
__('qqGet the Pro Version and Build Content and Links Across Social Media and Other Sites Now!', 'ai-auto-seo')),
'subtext' => get_option('ws4agpt_promo_subtext',
__('Bulk Schedule, Local Posts, and more!', 'ai-auto-seo')),
'image' => get_option('ws4agpt_promo_image', ''),
'link' => get_option('ws4agpt_promo_link', 'https://websiteservice4all.com')
);
// Try to get server text with increased timeout
$args = array(
'headers' => array(
'Cache-Control' => 'no-cache', // Prevent caching
'Pragma' => 'no-cache', // Prevent caching
),
'timeout' => 10
);
$response = wp_remote_get('https://autoseoguys.com/wp-json/free-plugin-message/v1/data?timestamp=' . time(), $args);
// Log error if request fails
if (is_wp_error($response)) {
// Production code should use proper logging mechanism instead of error_log
} elseif (200 === wp_remote_retrieve_response_code($response)) {
$promo_data = json_decode(wp_remote_retrieve_body($response), true);
if ($promo_data &&
isset($promo_data['heading']) &&
isset($promo_data['subtext']) &&
isset($promo_data['image']) &&
isset($promo_data['link'])) {
$server_promo = array(
'heading' => sanitize_text_field($promo_data['heading']),
'subtext' => sanitize_text_field($promo_data['subtext']),
'image' => esc_url_raw($promo_data['image']),
'link' => esc_url_raw($promo_data['link'])
);
// Compare and update if different
if ($stored_promo['heading'] !== $server_promo['heading'] ||
$stored_promo['subtext'] !== $server_promo['subtext'] ||
$stored_promo['image'] !== $server_promo['image'] ||
$stored_promo['link'] !== $server_promo['link']) {
update_option('ws4agpt_promo_heading', $server_promo['heading']);
update_option('ws4agpt_promo_subtext', $server_promo['subtext']);
update_option('ws4agpt_promo_image', $server_promo['image']);
update_option('ws4agpt_promo_link', $server_promo['link']);
$stored_promo = $server_promo;
}
}
}
// Build the notice HTML
$notice_html = '
';
// Add image if exists
if (!empty($stored_promo['image'])) {
$notice_html .= '';// phpcs:ignore
}
$notice_html .= '