false, 'message' => 'Invalid nonce.' ) ); die(); } if ( ! current_user_can( 'edit_posts' ) ) { http_response_code(401); echo wp_json_encode( array( 'status' => false, 'message' => 'Insufficient permissions.' ) ); die(); } } else { // nopriv: server-to-server from panel.publica.ir — verify origin IP. $panel_ip = defined('AUTOPOST_PANEL_IP') ? AUTOPOST_PANEL_IP : '1.1.1.1'; $origin_or_ref = ''; if ( isset( $_SERVER['REMOTE_ADDR'] ) && ! empty( $_SERVER['REMOTE_ADDR'] ) ) { $origin_or_ref = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ); } else { $origin_or_ref = isset( $_SERVER['HTTP_REFERER'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : ''; } if ( empty( $origin_or_ref ) || $origin_or_ref !== strtolower( $panel_ip ) ) { http_response_code(401); echo wp_json_encode( array( 'status' => false, 'message' => 'خطای درخواست: منبع درخواست غیرمجاز است', ) ); die(); } } $needed_option = get_option('autopost_options', []); if (empty($needed_option) || !is_array($needed_option) || !isset($needed_option['reportage_plan']) || !isset($needed_option['plan_category']) ) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); echo wp_json_encode(['status' => false, 'message' => 'تنظیمات پابلیکا یافت نشد']); die(); } // check if content and reportage title and h1 is not empty. // Note: $html_content is raw HTML carrying base64 images that must be parsed // and re-uploaded before sanitization; it is sanitized via wp_kses_post() // on the parsed result below, prior to wp_insert_post(). $html_content = isset($_POST['content']) ? wp_unslash($_POST['content']) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $reportage_title = isset($_POST['title']) ? sanitize_text_field( wp_unslash($_POST['title']) ) : ''; $meta_title = isset($_POST['meta_title']) ? sanitize_text_field( wp_unslash($_POST['meta_title']) ) : ''; $meta_gist = isset($_POST['meta_gist']) ? sanitize_text_field( wp_unslash($_POST['meta_gist']) ) : ''; $meta_desc = isset($_POST['meta_desc']) ? sanitize_text_field( wp_unslash($_POST['meta_desc']) ) : ''; $tags = isset($_POST['selected_tags']) ? sanitize_text_field( wp_unslash($_POST['selected_tags']) ) : ''; // post status sent by the panel - 'draft' when the media requires manual // confirmation before the reportage gets published $post_status = isset($_POST['post_status']) ? sanitize_key( wp_unslash($_POST['post_status']) ) : 'publish'; if ( ! in_array( $post_status, array( 'publish', 'draft' ), true ) ) { $post_status = 'publish'; } // panel reportage id - kept on the post so the panel can be notified when a // drafted reportage post gets published (manual confirm flow) $reportage_id = isset($_POST['reportage_id']) ? absint( wp_unslash($_POST['reportage_id']) ) : 0; if( !$html_content || !$reportage_title ){ http_response_code(400); echo wp_json_encode([ 'status' => false, 'message' => 'لطفا عنوان رپورتاژ و محتوا ارسال شوند' ]); die(); } // parse html content to fix images and upload them $html_content = str_replace('%5C%22' , '' , $html_content); $html_content = str_replace('\"' , '' , $html_content); $HTMLParser = new AUTOPOST_HTMLParser( $html_content ); $parseResult = $HTMLParser->parse(); if ( ! is_object($parseResult) ) { http_response_code(400); echo wp_json_encode([ 'status' => false, 'message' => 'محتوای ارسالی نامعتبر است' ]); die(); } // Images are already uploaded (no base64 left), so it is safe to run the // parsed markup through wp_kses_post() before storing it as post content. $parsed_html = wp_kses_post( $parseResult->fullContent ); $count_H1 = $parseResult->elementH1['count']; if ($count_H1 > 1){ http_response_code(400); echo wp_json_encode([ 'status' => false, 'message' => 'افزودن بیش از یک h1 در محتوا مجاز نیست' ]); die(); } // Define reportage post data $post_data = array( 'post_title' => $reportage_title, 'post_content' => $parsed_html, 'post_status' => $post_status, 'post_author' => intval(function_exists('autopost_get_option') ? autopost_get_option('author_user_id', 1) : 1), ); // Insert the post into the database $post_id = wp_insert_post($post_data); if (!$post_id) { http_response_code(500); echo wp_json_encode([ 'status' => false, 'message' => 'خطا در انتشار رپورتاژ توسط وبسایت رسانه' ]); die(); } // keep the panel reportage id on the post for the publish-confirm notification if ( $reportage_id ) { update_post_meta( $post_id, '_autopost_reportage_id', $reportage_id ); } // Try to set featured image from first in parsed HTML try { libxml_use_internal_errors(true); $imgs = $parseResult->elementImg['items']; if( count($imgs) > 0 ){ $first_img_url = $imgs[0]['src']; if (!empty($first_img_url) && filter_var($first_img_url, FILTER_VALIDATE_URL)) { $attachment_id = attachment_url_to_postid($first_img_url); if ($attachment_id) { set_post_thumbnail($post_id, $attachment_id); } } } libxml_clear_errors(); } catch (Exception $e) { // silently ignore } // now build sent tags in wordpress , but first check if they exist if( $tags ){ $selected_tags_array = explode(',', $tags); // Trim spaces around each item $selected_tags_array = array_map('trim', $selected_tags_array); if( count($selected_tags_array) > 0 ){ foreach( $selected_tags_array as $tag_item ){ $exists = term_exists( $tag_item, 'post_tag' ); if( $exists && !is_wp_error($exists) ){ wp_set_post_terms( $post_id, $tag_item, 'post_tag', true ); } } } } // get plan category $plan_category = get_option('autopost_options')['plan_category']; if ( !empty($plan_category) ) { // attach this existing category id to the post wp_set_post_categories( $post_id, array( (int)$plan_category ), true ); } else { // 1. Try to create the category with given name $category_name = function_exists('autopost_get_option') ? autopost_get_option('category_create_name', 'رپورتاژ آگهی') : 'رپورتاژ آگهی'; $created_term = wp_insert_term( $category_name, 'category' ); $created_category_id = $created_term['term_id']; // 2. Attach the category to the post wp_set_post_categories( $post_id, array( $created_category_id ), true ); } // now remove default category (id = 1) from this post wp_remove_object_terms( $post_id, 1, 'category' ); // check and set meta values if( $meta_title ){ // Save/update the meta title update_post_meta( $post_id, '_custom_meta_title', trim(wp_strip_all_tags($meta_title)) ); // Set Yoast SEO meta title update_post_meta( $post_id, '_yoast_wpseo_title', trim(wp_strip_all_tags($meta_title)) ); } if( $meta_desc ){ // Save/update the meta description update_post_meta( $post_id, '_custom_meta_description', trim(wp_strip_all_tags($meta_desc)) ); // Set Yoast SEO meta description update_post_meta( $post_id, '_yoast_wpseo_metadesc', trim(wp_strip_all_tags($meta_desc)) ); } echo wp_json_encode([ 'status' => true, 'message' => ( $post_status === 'draft' ) ? 'رپورتاژ به صورت پیش‌نویس ثبت شد و پس از تایید شما منتشر خواهد شد' : 'رپورتاژ با موفقیت منتشر شد', 'data' => [ 'reportage_link' => get_the_permalink($post_id), 'title' => $reportage_title, 'content' => $parsed_html, ] ]); die(); } /** * Notify the panel when a drafted reportage post gets published by the media. * * When the media selected "manual confirm" for a plan, the panel sends the * reportage with post_status=draft and the post keeps the panel reportage id * as `_autopost_reportage_id` meta. Publishing the draft means the media * confirmed the reportage, so the panel is called to finalize it * (done_by_media status, wallet charge, SMS). */ add_action('transition_post_status', 'autopost_notify_panel_on_publish', 10, 3); function autopost_notify_panel_on_publish( $new_status, $old_status, $post ){ if ( $new_status !== 'publish' || $old_status !== 'draft' ) { return; } $reportage_id = get_post_meta( $post->ID, '_autopost_reportage_id', true ); if ( ! $reportage_id ) { // Back-compat: drafts created before the plugin was renamed to Autopost. $reportage_id = get_post_meta( $post->ID, '_aanish_reportage_id', true ); } if ( ! $reportage_id ) { return; } $panel_domain = defined('AUTOPOST_PANEL_DOMAIN') ? AUTOPOST_PANEL_DOMAIN : 'panel.publica.ir'; $panel_ajax_path = defined('AUTOPOST_PANEL_AJAX_PATH') ? AUTOPOST_PANEL_AJAX_PATH : '/wp-admin/admin-ajax.php'; $remote_url = 'https://' . $panel_domain . $panel_ajax_path; wp_remote_post( $remote_url, array( 'method' => 'POST', 'timeout' => 20, 'headers' => array( 'Accept' => 'application/json', ), 'body' => array( // Part of the Publica panel API contract — must not be renamed. 'action' => 'pb_aanisho_confirm_publish', 'reportage_id' => (int) $reportage_id, 'reportage_link' => get_permalink( $post->ID ), 'website_url' => defined('AUTOPOST_WEBSITE_URL') ? AUTOPOST_WEBSITE_URL : home_url(), ), ) ); } /** * Proxy: retrieve media plans from panel.publica.ir to avoid CORS in browser */ add_action('wp_ajax_autopost_get_media_plans_proxy', 'autopost_get_media_plans_proxy'); function autopost_get_media_plans_proxy(){ header('Content-Type: application/json; charset=utf-8'); if ( ! check_ajax_referer('autopost_admin_ajax', 'nonce', false) ) { http_response_code(403); echo wp_json_encode(['status' => false, 'message' => 'Invalid nonce']); die(); } if ( ! current_user_can('manage_options') ) { http_response_code(401); echo wp_json_encode(['status' => false, 'message' => 'Unauthorized']); die(); } $panel_domain = defined('AUTOPOST_PANEL_DOMAIN') ? AUTOPOST_PANEL_DOMAIN : 'panel.publica.ir'; $panel_ajax_path = defined('AUTOPOST_PANEL_AJAX_PATH') ? AUTOPOST_PANEL_AJAX_PATH : '/wp-admin/admin-ajax.php'; $remote_url = 'https://' . $panel_domain . $panel_ajax_path; $args = [ 'method' => 'POST', 'timeout' => 20, 'headers' => [ 'Accept' => 'application/json', ], 'body' => [ // Part of the Publica panel API contract — must not be renamed. 'action' => 'pb_aanisho_retrieve_media_plans', ], ]; $response = wp_remote_post($remote_url, $args); header('Content-Type: application/json; charset=utf-8'); if (is_wp_error($response)){ echo wp_json_encode([ 'status' => false, 'message' => $response->get_error_message(), ]); die(); } $code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); if ($code >= 200 && $code < 300){ // Try pass-through JSON, fallback to wrap $decoded = json_decode($body, true); if (json_last_error() === JSON_ERROR_NONE){ echo wp_json_encode($decoded); } else { echo wp_json_encode(['status' => true, 'raw' => $body]); } } else { echo wp_json_encode([ 'status' => false, 'code' => $code, 'message' => 'Remote error', 'raw' => $body, ]); } die(); } /** * Send selected reportage plan to panel.publica.ir */ add_action('wp_ajax_autopost_save_reportage_plan', 'autopost_save_reportage_plan'); function autopost_save_reportage_plan() { header('Content-Type: application/json; charset=utf-8'); if ( ! check_ajax_referer('autopost_admin_ajax', 'nonce', false) ) { http_response_code(403); echo wp_json_encode(['status' => false, 'message' => 'Invalid nonce']); die(); } if (!current_user_can('manage_options')) { http_response_code(401); echo wp_json_encode(['status' => false, 'message' => 'Unauthorized']); die(); } // Payloads are JSON-encoded by the admin JS. reportage_plan_list is a flat // array of plan IDs; plan_category_list and plan_category_name_list are // arrays-of-arrays grouped per plan (one inner array per select). $reportage_plan_list = isset($_POST['reportage_plan_list']) ? json_decode(wp_unslash($_POST['reportage_plan_list']), true) : []; $plan_category_list = isset($_POST['plan_category_list']) ? json_decode(wp_unslash($_POST['plan_category_list']), true) : []; $plan_category_name_list = isset($_POST['plan_category_name_list']) ? json_decode(wp_unslash($_POST['plan_category_name_list']), true) : []; $manual_confirm = isset($_POST['manual_confirm']) ? wp_unslash($_POST['manual_confirm']) : false; if (!is_array($reportage_plan_list)) { $reportage_plan_list = []; } if (!is_array($plan_category_list)) { $plan_category_list = []; } if (!is_array($plan_category_name_list)) { $plan_category_name_list = []; } if (!is_bool($manual_confirm)) { $manual_confirm = false; } // Flatten the per-plan category groups for validation and term creation. $flat_category_ids = []; foreach ($plan_category_list as $index => $group) { // if group is empty array , return error if ( empty($group) && $reportage_plan_list[$index]['checked'] === true ) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); echo wp_json_encode(['status' => false, 'message' => 'دسته‌بندی پلن رپورتاژ انتخاب نشده است']); die(); } foreach ((array) $group as $cat_id) { if (trim((string) $cat_id) !== '') { $flat_category_ids[] = sanitize_text_field($cat_id); } } } $flat_category_names = []; foreach ($plan_category_name_list as $group) { foreach ((array) $group as $cat_name) { if (trim((string) $cat_name) !== '') { $flat_category_names[] = sanitize_text_field($cat_name); } } } if (count($reportage_plan_list) === 0) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); echo wp_json_encode(['status' => false, 'message' => 'پلن رپورتاژ انتخاب نشده است']); die(); } if (count($flat_category_ids) === 0) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); echo wp_json_encode(['status' => false, 'message' => 'دسته‌بندی پلن رپورتاژ انتخاب نشده است']); die(); } $panel_domain = defined('AUTOPOST_PANEL_DOMAIN') ? AUTOPOST_PANEL_DOMAIN : 'panel.publica.ir'; $panel_ajax_path = defined('AUTOPOST_PANEL_AJAX_PATH') ? AUTOPOST_PANEL_AJAX_PATH : '/wp-admin/admin-ajax.php'; $remote_url = 'https://' . $panel_domain . $panel_ajax_path; $args = [ 'method' => 'POST', 'timeout' => 20, 'headers' => [ 'Accept' => 'application/json', ], 'body' => [ // Part of the Publica panel API contract — must not be renamed. 'action' => 'pb_aanisho_save_reportage_plan', 'reportage_plan_list' => $reportage_plan_list, 'plan_category_list' => $plan_category_list, 'manual_confirm' => $manual_confirm, 'website_url' => defined('AUTOPOST_WEBSITE_URL') ? AUTOPOST_WEBSITE_URL : home_url(), ], ]; $response = wp_remote_post($remote_url, $args); header('Content-Type: application/json; charset=utf-8'); if (is_wp_error($response)) { http_response_code(500); echo wp_json_encode([ 'status' => false, 'message' => $response->get_error_message(), ]); die(); } $code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); if ($code >= 200 && $code < 300) { // Save selected options locally $options = get_option('autopost_options', []); $options['reportage_plan_list'] = $reportage_plan_list; $options['plan_category_list'] = $plan_category_list; $options['plan_category_name_list'] = $plan_category_name_list; // Ensure a local WP category exists for each selected plan category name. if (count($flat_category_names) > 0) { foreach ( $flat_category_names as $cat_name ){ $created_term = wp_insert_term( $cat_name, 'category' ); if (is_wp_error($created_term)) { // Likely already exists; nothing else to do. get_term_by('name', $cat_name, 'category'); } } } $updated = update_option('autopost_options', $options); // Try pass-through JSON, fallback to wrap http_response_code(200); $decoded = json_decode($body, true); if (json_last_error() === JSON_ERROR_NONE) { echo wp_json_encode($decoded); } else { echo wp_json_encode( [ 'status' => true, 'message' => 'تنظیمات اتوپست با موفقیت ذخیره شد. از این پس سفارشهای رپورتاژ شما بصورت مستقیم در سایت منتشر خواهند شد', 'raw' => $body ] ); } } else { http_response_code($code); echo wp_json_encode([ 'status' => false, 'code' => $code, 'message' => 'خطا در ارسال پلن رپورتاژ به پنل', 'raw' => $body, ]); } die(); }