Go to settings', 'rapidtextai'); ?>

'rapidtextai-block-editor', )); } add_action('init', 'rapidtextai_register_gutenberg_block'); // AJAX handler for generating AI content add_action('wp_ajax_rapidtextai_generate_content', 'rapidtextai_generate_content_callback'); add_action('wp_ajax_nopriv_rapidtextai_generate_content', 'rapidtextai_generate_content_callback'); function rapidtextai_generate_content_callback() { if (isset($_POST['prompt']) && isset($_POST['post_id']) && isset($_POST['instance_id'])) { $prompt = sanitize_text_field($_POST['prompt']); $postid = intval($_POST['post_id']); $instance_id = sanitize_text_field($_POST['instance_id']); // Call the existing function to generate text $generated_text = rapidtextai_generate_text($prompt, $postid, $instance_id); // Send the generated content as a response if ($generated_text) { wp_send_json_success(array('generated_text' => $generated_text)); } else { wp_send_json_error('Error generating content'); } } else { wp_send_json_error('Invalid request'); } } add_action('wp_ajax_rapidtextai_generate_content_block', 'rapidtextai_generate_content_callback_block'); add_action('wp_ajax_nopriv_rapidtextai_generate_content_block', 'rapidtextai_generate_content_callback_block'); function rapidtextai_generate_content_callback_block() { if (isset($_POST['prompt'])) { $prompt = sanitize_text_field($_POST['prompt']); // Call the AI text generation function $generated_text = rapidtextai_generate_text($prompt, 0, ''); // Return the generated content if ($generated_text) { wp_send_json_success(array('generated_text' => $generated_text)); } else { wp_send_json_error('Error generating content'); } } else { wp_send_json_error('Invalid request'); } } function rapidtextai_is_wp_bakery_active() { return class_exists('Vc_Manager'); } function rapidtextai_settings_menu() { add_menu_page( 'Rapidtextai Settings', 'RapidTextAI', 'manage_options', 'rapidtextai-settings', 'rapidtextai_settings_page', 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTAyNCIgem9vbUFuZFBhbj0ibWFnbmlmeSIgdmlld0JveD0iMCAwIDc2OCA3NjcuOTk5OTk0IiBoZWlnaHQ9IjEwMjQiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiIHZlcnNpb249IjEuMCI+PGRlZnM+PGcvPjxjbGlwUGF0aCBpZD0iZWM4NTZjNWVlZSI+PHBhdGggZD0iTSAxMjUgNzYuODAwNzgxIEwgNjUyLjk0OTIxOSA3Ni44MDA3ODEgTCA2NTIuOTQ5MjE5IDQyOSBMIDEyNSA0MjkgWiBNIDEyNSA3Ni44MDA3ODEgIiBjbGlwLXJ1bGU9Im5vbnplcm8iLz48L2NsaXBQYXRoPjxjbGlwUGF0aCBpZD0iZWMzNTNkNGRjMCI+PHBhdGggZD0iTSAxMTUuMTk5MjE5IDM1MyBMIDY0MyAzNTMgTCA2NDMgNTY3IEwgMTE1LjE5OTIxOSA1NjcgWiBNIDExNS4xOTkyMTkgMzUzICIgY2xpcC1ydWxlPSJub256ZXJvIi8+PC9jbGlwUGF0aD48Y2xpcFBhdGggaWQ9ImM2MDFlY2Q5M2QiPjxwYXRoIGQ9Ik0gMzkyIDU3MiBMIDQ4MCA1NzIgTCA0ODAgNjkxLjA1MDc4MSBMIDM5MiA2OTEuMDUwNzgxIFogTSAzOTIgNTcyICIgY2xpcC1ydWxlPSJub256ZXJvIi8+PC9jbGlwUGF0aD48Y2xpcFBhdGggaWQ9IjIzOThiMDkzZDYiPjxwYXRoIGQ9Ik0gMjg4IDU3MiBMIDM3NiA1NzIgTCAzNzYgNjkxLjA1MDc4MSBMIDI4OCA2OTEuMDUwNzgxIFogTSAyODggNTcyICIgY2xpcC1ydWxlPSJub256ZXJvIi8+PC9jbGlwUGF0aD48L2RlZnM+PGcgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzNzYuNzE2NjM1LCAyNDguMzIwMDA5KSI+PGc+PHBhdGggZD0iTSA1LjM3NSAwLjI2NTYyNSBDIDQuNDg4MjgxIDAuMjY1NjI1IDMuNzE4NzUgMC4xMDE1NjIgMy4wNjI1IC0wLjIxODc1IEMgMi40MTQwNjIgLTAuNTUwNzgxIDEuOTE0MDYyIC0xLjAzMTI1IDEuNTYyNSAtMS42NTYyNSBDIDEuMjE4NzUgLTIuMjgxMjUgMS4wNDY4NzUgLTMuMDM1MTU2IDEuMDQ2ODc1IC0zLjkyMTg3NSBDIDEuMDQ2ODc1IC00Ljc0MjE4OCAxLjIxODc1IC01LjQyOTY4OCAxLjU2MjUgLTUuOTg0Mzc1IEMgMS45MTQwNjIgLTYuNTM1MTU2IDIuNDU3MDMxIC02Ljk4ODI4MSAzLjE4NzUgLTcuMzQzNzUgQyAzLjkyNTc4MSAtNy42OTUzMTIgNC44OTA2MjUgLTcuOTY4NzUgNi4wNzgxMjUgLTguMTU2MjUgQyA2Ljg5ODQzOCAtOC4yODkwNjIgNy41MjM0MzggLTguNDM3NSA3Ljk1MzEyNSAtOC41OTM3NSBDIDguMzc4OTA2IC04Ljc1IDguNjY0MDYyIC04LjkyNTc4MSA4LjgxMjUgLTkuMTI1IEMgOC45Njg3NSAtOS4zMzIwMzEgOS4wNDY4NzUgLTkuNTg1OTM4IDkuMDQ2ODc1IC05Ljg5MDYyNSBDIDkuMDQ2ODc1IC0xMC4zMzU5MzggOC44OTA2MjUgLTEwLjY3NTc4MSA4LjU3ODEyNSAtMTAuOTA2MjUgQyA4LjI3MzQzOCAtMTEuMTQ0NTMxIDcuNzY1NjI1IC0xMS4yNjU2MjUgNy4wNDY4NzUgLTExLjI2NTYyNSBDIDYuMjg1MTU2IC0xMS4yNjU2MjUgNS41NTQ2ODggLTExLjA5Mzc1IDQuODU5Mzc1IC0xMC43NSBDIDQuMTcxODc1IC0xMC40MDYyNSAzLjU3MDMxMiAtOS45NTMxMjUgMy4wNjI1IC05LjM5MDYyNSBMIDIuODEyNSAtOS4zOTA2MjUgTCAxLjM1OTM3NSAtMTEuNTc4MTI1IEMgMi4wNTQ2ODggLTEyLjM1OTM3NSAyLjkxMDE1NiAtMTIuOTYwOTM4IDMuOTIxODc1IC0xMy4zOTA2MjUgQyA0LjkyOTY4OCAtMTMuODI4MTI1IDYuMDMxMjUgLTE0LjA0Njg3NSA3LjIxODc1IC0xNC4wNDY4NzUgQyA5LjAzOTA2MiAtMTQuMDQ2ODc1IDEwLjM1OTM3NSAtMTMuNjU2MjUgMTEuMTcxODc1IC0xMi44NzUgQyAxMS45OTIxODggLTEyLjEwMTU2MiAxMi40MDYyNSAtMTEuMDAzOTA2IDEyLjQwNjI1IC05LjU3ODEyNSBMIDEyLjQwNjI1IC0zLjU5Mzc1IEMgMTIuNDA2MjUgLTIuOTc2NTYyIDEyLjY3NTc4MSAtMi42NzE4NzUgMTMuMjE4NzUgLTIuNjcxODc1IEMgMTMuNDI1NzgxIC0yLjY3MTg3NSAxMy42Mjg5MDYgLTIuNzA3MDMxIDEzLjgyODEyNSAtMi43ODEyNSBMIDE0LjAxNTYyNSAtMi43MzQzNzUgTCAxNC4yNjU2MjUgLTAuMzI4MTI1IEMgMTQuMDY2NDA2IC0wLjIwMzEyNSAxMy43OTY4NzUgLTAuMDk3NjU2MiAxMy40NTMxMjUgLTAuMDE1NjI1IEMgMTMuMTE3MTg4IDAuMDU0Njg3NSAxMi43NDIxODggMC4wOTM3NSAxMi4zMjgxMjUgMC4wOTM3NSBDIDExLjUwMzkwNiAwLjA5Mzc1IDEwLjg1OTM3NSAtMC4wNjI1IDEwLjM5MDYyNSAtMC4zNzUgQyA5LjkyOTY4OCAtMC42ODc1IDkuNjAxNTYyIC0xLjE3OTY4OCA5LjQwNjI1IC0xLjg1OTM3NSBMIDkuMTQwNjI1IC0xLjg5MDYyNSBDIDguNDcyNjU2IC0wLjQ1MzEyNSA3LjIxODc1IDAuMjY1NjI1IDUuMzc1IDAuMjY1NjI1IFogTSA2LjQ2ODc1IC0yLjMyODEyNSBDIDcuMjY5NTMxIC0yLjMyODEyNSA3LjkxMDE1NiAtMi41OTM3NSA4LjM5MDYyNSAtMy4xMjUgQyA4Ljg2NzE4OCAtMy42NjQwNjIgOS4xMDkzNzUgLTQuNDE0MDYyIDkuMTA5Mzc1IC01LjM3NSBMIDkuMTA5Mzc1IC02Ljc2NTYyNSBMIDguODc1IC02LjgyODEyNSBDIDguNjY0MDYyIC02LjY2MDE1NiA4LjM5MDYyNSAtNi41MTk1MzEgOC4wNDY4NzUgLTYuNDA2MjUgQyA3LjcxMDkzOCAtNi4yODkwNjIgNy4yMjY1NjIgLTYuMTc5Njg4IDYuNTkzNzUgLTYuMDc4MTI1IEMgNS44NDM3NSAtNS45NTMxMjUgNS4zMDA3ODEgLTUuNzM0Mzc1IDQuOTY4NzUgLTUuNDIxODc1IEMgNC42NDQ1MzEgLTUuMTE3MTg4IDQuNDg0Mzc1IC00LjY5MTQwNiA0LjQ4NDM3NSAtNC4xNDA2MjUgQyA0LjQ4NDM3NSAtMy41NDY4NzUgNC42NTYyNSAtMy4wOTM3NSA1IC0yLjc4MTI1IEMgNS4zNTE1NjIgLTIuNDc2NTYyIDUuODQzNzUgLTIuMzI4MTI1IDYuNDY4NzUgLTIuMzI4MTI1IFogTSA2LjQ2ODc1IC0yLjMyODEyNSAiLz48L2c+PC9nPjwvZz48cGF0aCBmaWxsPSIjNzM3MzczIiBkPSJNIDUxMy43NzM0MzggMzkxLjQ4NDM3NSBDIDUxMy43NzM0MzggNDEwLjg5MDYyNSA0OTguMDM1MTU2IDQyNi42NjQwNjIgNDc4LjU4OTg0NCA0MjYuNjY0MDYyIEMgNDU5LjE0NDUzMSA0MjYuNjY0MDYyIDQ0My40MDYyNSA0MTAuOTI5Njg4IDQ0My40MDYyNSAzOTEuNDg0Mzc1IEMgNDQzLjQwNjI1IDM3Mi4wMzkwNjIgNDU5LjE0NDUzMSAzNTYuMzAwNzgxIDQ3OC41ODk4NDQgMzU2LjMwMDc4MSBDIDQ5OC4wMzUxNTYgMzU2LjMwMDc4MSA1MTMuNzczNDM4IDM3Mi4wMzkwNjIgNTEzLjc3MzQzOCAzOTEuNDg0Mzc1IFogTSA1MTMuNzczNDM4IDM5MS40ODQzNzUgIiBmaWxsLW9wYWNpdHk9IjEiIGZpbGwtcnVsZT0ibm9uemVybyIvPjxwYXRoIGZpbGw9IiM3MzczNzMiIGQ9Ik0gMjg5LjQ0NTMxMiAzNTYuMzAwNzgxIEMgMzA4Ljg1MTU2MiAzNTYuMzAwNzgxIDMyNC42Mjg5MDYgMzcyLjAzOTA2MiAzMjQuNjI4OTA2IDM5MS40ODQzNzUgQyAzMjQuNjI4OTA2IDQxMC44OTA2MjUgMzA4Ljg5MDYyNSA0MjYuNjY0MDYyIDI4OS40NDUzMTIgNDI2LjY2NDA2MiBDIDI3MCA0MjYuNjY0MDYyIDI1NC4yNjE3MTkgNDEwLjg5MDYyNSAyNTQuMjYxNzE5IDM5MS40ODQzNzUgQyAyNTQuMjYxNzE5IDM3Mi4wMzkwNjIgMjcwIDM1Ni4zMDA3ODEgMjg5LjQ0NTMxMiAzNTYuMzAwNzgxIFogTSAyODkuNDQ1MzEyIDM1Ni4zMDA3ODEgIiBmaWxsLW9wYWNpdHk9IjEiIGZpbGwtcnVsZT0ibm9uemVybyIvPjxnIGNsaXAtcGF0aD0idXJsKCNlYzg1NmM1ZWVlKSI+PHBhdGggZmlsbD0iIzczNzM3MyIgZD0iTSA1OTYuODk4NDM4IDQyOC45NTcwMzEgTCA2NTIuNjE3MTg4IDQyOC45NTcwMzEgQyA2NTIuNjUyMzQ0IDQyNy43MTg3NSA2NTIuNzk2ODc1IDQyNi41MTk1MzEgNjUyLjc5Njg3NSA0MjUuMzIwMzEyIEwgNjUyLjc5Njg3NSAzNTcuNjA5Mzc1IEMgNjUyLjc5Njg3NSAyNzkuNjQ0NTMxIDU4OS4zNzUgMjE2LjIyMjY1NiA1MTEuNDEwMTU2IDIxNi4yMjI2NTYgTCAzOTYuNTkzNzUgMjE2LjIyMjY1NiBMIDM5Ni41OTM3NSAxNTUuNjMyODEyIEMgNDEyLjczMDQ2OSAxNTAuMjg5MDYyIDQyNC40Njg3NSAxMzUuMjc3MzQ0IDQyNC40Njg3NSAxMTcuMzU5Mzc1IEMgNDI0LjQ2ODc1IDk1LjAwNzgxMiA0MDYuMzMyMDMxIDc2Ljg3MTA5NCAzODMuOTgwNDY5IDc2Ljg3MTA5NCBDIDM2MS42Mjg5MDYgNzYuODcxMDk0IDM0My40OTIxODggOTUuMDA3ODEyIDM0My40OTIxODggMTE3LjM1OTM3NSBDIDM0My40OTIxODggMTM1LjI3NzM0NCAzNTUuMjMwNDY5IDE1MC4zMjQyMTkgMzcxLjM2NzE4OCAxNTUuNjMyODEyIEwgMzcxLjM2NzE4OCAyMTYuMjU3ODEyIEwgMjU2LjU4NTkzOCAyMTYuMjU3ODEyIEMgMTk3LjY2Nzk2OSAyMTYuMjU3ODEyIDE0Ny4xMTMyODEgMjUyLjUzMTI1IDEyNS44ODY3MTkgMzAzLjg1MTU2MiBMIDE5MC4wMzUxNTYgMzAzLjg1MTU2MiBDIDIwNS43MzgyODEgMjg0LjQ0MTQwNiAyMjkuNzI2NTYyIDI3MS45NzY1NjIgMjU2LjU4NTkzOCAyNzEuOTc2NTYyIEwgNTExLjQ0NTMxMiAyNzEuOTc2NTYyIEMgNTU4LjY2MDE1NiAyNzEuOTc2NTYyIDU5Ny4wNzgxMjUgMzEwLjM5NDUzMSA1OTcuMDc4MTI1IDM1Ny42MDkzNzUgTCA1OTcuMDc4MTI1IDQyNS4zMjAzMTIgQyA1OTcuMDc4MTI1IDQyNi41NTg1OTQgNTk2LjkzMzU5NCA0MjcuNzU3ODEyIDU5Ni44OTg0MzggNDI4Ljk1NzAzMSBaIE0gMzgwLjUyNzM0NCA5OS45MTQwNjIgQyAzODAuNTI3MzQ0IDEwNi4yMzgyODEgMzc1LjQwMjM0NCAxMTEuMzYzMjgxIDM2OS4wNzgxMjUgMTExLjM2MzI4MSBDIDM2Mi43NTM5MDYgMTExLjM2MzI4MSAzNTcuNjI4OTA2IDEwNi4yMzgyODEgMzU3LjYyODkwNiA5OS45MTQwNjIgQyAzNTcuNjI4OTA2IDkzLjU4OTg0NCAzNjIuNzUzOTA2IDg4LjQ2NDg0NCAzNjkuMDc4MTI1IDg4LjQ2NDg0NCBDIDM3NS40MDIzNDQgODguNDY0ODQ0IDM4MC41MjczNDQgOTMuNjI1IDM4MC41MjczNDQgOTkuOTE0MDYyIFogTSAzODAuNTI3MzQ0IDk5LjkxNDA2MiAiIGZpbGwtb3BhY2l0eT0iMSIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9nPjxnIGNsaXAtcGF0aD0idXJsKCNlYzM1M2Q0ZGMwKSI+PHBhdGggZmlsbD0iIzczNzM3MyIgZD0iTSAxMTUuNDE3OTY5IDM1My45NzI2NTYgTCAxNzEuMTcxODc1IDM1My45NzI2NTYgQyAxNzEuMTM2NzE5IDM1NS4yMTA5MzggMTcwLjk5MjE4OCAzNTYuNDEwMTU2IDE3MC45OTIxODggMzU3LjYwOTM3NSBMIDE3MC45OTIxODggNDI1LjMyMDMxMiBDIDE3MC45OTIxODggNDcyLjUzNTE1NiAyMDkuNDEwMTU2IDUxMC45NTMxMjUgMjU2LjYyNSA1MTAuOTUzMTI1IEwgNTExLjQ4NDM3NSA1MTAuOTUzMTI1IEMgNTM4LjM0Mzc1IDUxMC45NTMxMjUgNTYyLjMzMjAzMSA0OTguNDg0Mzc1IDU3OC4wMzUxNTYgNDc5LjA3ODEyNSBMIDY0Mi4xODM1OTQgNDc5LjA3ODEyNSBDIDYyMC45OTYwOTQgNTMwLjQzMzU5NCA1NzAuNDAyMzQ0IDU2Ni42NzE4NzUgNTExLjQ4NDM3NSA1NjYuNjcxODc1IEwgMjU2LjU4NTkzOCA1NjYuNjcxODc1IEMgMTc4LjYyNSA1NjYuNjcxODc1IDExNS4xOTkyMTkgNTAzLjI0NjA5NCAxMTUuMTk5MjE5IDQyNS4yODUxNTYgTCAxMTUuMTk5MjE5IDM1Ny42MDkzNzUgQyAxMTUuMTk5MjE5IDM1Ni4zNzEwOTQgMTE1LjM4MjgxMiAzNTUuMTcxODc1IDExNS40MTc5NjkgMzUzLjk3MjY1NiBaIE0gMTE1LjQxNzk2OSAzNTMuOTcyNjU2ICIgZmlsbC1vcGFjaXR5PSIxIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L2c+PGcgY2xpcC1wYXRoPSJ1cmwoI2M2MDFlY2Q5M2QpIj48cGF0aCBmaWxsPSIjNzM3MzczIiBkPSJNIDQ3OS40MjU3ODEgNTg2Ljc2OTUzMSBMIDQ3OS40MjU3ODEgNjc2LjY5MTQwNiBMIDQ2Mi45MjU3ODEgNjkxLjEyMTA5NCBMIDM5Mi4xOTUzMTIgNjQ2LjMwNDY4OCBMIDM5Mi4xOTUzMTIgNjE3LjEyMTA5NCBMIDQ2Mi45MjU3ODEgNTcyLjMwNDY4OCBaIE0gNDc5LjQyNTc4MSA1ODYuNzY5NTMxICIgZmlsbC1vcGFjaXR5PSIxIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L2c+PGcgY2xpcC1wYXRoPSJ1cmwoIzIzOThiMDkzZDYpIj48cGF0aCBmaWxsPSIjNzM3MzczIiBkPSJNIDM3NS44Mzk4NDQgNjE3LjEyMTA5NCBMIDM3NS44Mzk4NDQgNjQ2LjMwNDY4OCBMIDMwNS4xMDkzNzUgNjkxLjEyMTA5NCBMIDI4OC42MDkzNzUgNjc2LjY5MTQwNiBMIDI4OC42MDkzNzUgNTg2Ljc2OTUzMSBMIDMwNS4xMDkzNzUgNTcyLjMwNDY4OCBaIE0gMzc1LjgzOTg0NCA2MTcuMTIxMDk0ICIgZmlsbC1vcGFjaXR5PSIxIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L2c+PHBhdGggZmlsbD0iIzczNzM3MyIgZD0iTSAzNzguMjAzMTI1IDYxNy40NDkyMTkgTCAzODkuODMyMDMxIDYxNy40NDkyMTkgTCAzODkuODMyMDMxIDY0NS45ODA0NjkgTCAzNzguMjAzMTI1IDY0NS45ODA0NjkgWiBNIDM3OC4yMDMxMjUgNjE3LjQ0OTIxOSAiIGZpbGwtb3BhY2l0eT0iMSIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+', ); } add_action('admin_menu', 'rapidtextai_settings_menu'); function rapidtextai_settings_page() { if (!current_user_can('manage_options')) { return; } // Retrieve the current API key $current_api_key = get_option('rapidtextai_api_key', ''); $connection = get_option('rapidtextai_connection', array()); rapidtextai_react_app_root(array( 'page' => 'settings', 'data' => array( 'api_key' => $current_api_key, 'api_key_set' => ! empty( $current_api_key ), 'site_url' => home_url(), 'site_name' => get_bloginfo( 'name' ), 'connection' => is_array( $connection ) ? $connection : array(), ), )); } add_action('wp_ajax_rapidtextai_save_api_key', 'rapidtextai_save_api_key'); function rapidtextai_save_api_key() { if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => 'Permission denied.')); } if (!isset($_POST['_wpnonce']) || !wp_verify_nonce(sanitize_text_field($_POST['_wpnonce']), 'rapidtextai_save_api_key_nonce')) { wp_send_json_error(array('message' => 'Nonce verification failed.')); } $api_key = sanitize_text_field($_POST['api_key']); update_option('rapidtextai_api_key', $api_key); // Bind this site to the account that owns the key. A failure here must not // undo the key that was just saved. $link_note = ''; if (function_exists('rapidtextai_connect_link_site_for_key')) { $linked = rapidtextai_connect_link_site_for_key($api_key); if (is_wp_error($linked)) { $link_note = $linked->get_error_message(); } } wp_send_json_success(array( 'message' => 'API Key saved successfully.', 'linked' => ('' === $link_note), 'link_note' => $link_note, )); } /** * WP Bakery */ if(rapidtextai_is_wp_bakery_active()){ function rapidtextai_ai_text_block_vc_element() { vc_map(array( 'name' => __('AI Text Block', 'rapidtextai'), 'base' => 'rapidtextai_ai_text_block', 'category' => __('Content', 'rapidtextai'), 'params' => array( array( 'type' => 'textarea', 'heading' => esc_html__('Prompt', 'rapidtextai'), 'param_name' => 'wpb_input_text', 'description' => esc_html__('Enter the prompt to generate AI text, i.e Write an about use section for my company which manufacture light bulbs', 'rapidtextai') ), array( "type" => "textarea", "heading" => esc_html__( "Prompt Output", 'rapidtextai'), "param_name" => "wpb_input_text_output", 'description' => esc_html__('Prompt response will be here, edit here if needed', 'rapidtextai'), ), ), 'shortcode' => 'rapidtextai_ai_text_block_shortcode', )); } add_action('vc_before_init', 'rapidtextai_ai_text_block_vc_element'); function rapidtextai_ai_text_block_shortcode($atts, $sc_content = null,$instance_id) { extract(shortcode_atts(array( 'wpb_input_text' => '', 'wpb_input_text_output' => '', ), $atts)); $postid = get_the_ID(); global $post; $new_value = ''; $shortcode = 'rapidtextai_ai_text_block'; // Define the attribute you want to update $attribute_to_update = 'wpb_input_text_output'; $content = $post->post_content; // Use a regular expression to find all instances of the shortcode $pattern = get_shortcode_regex([$shortcode]); preg_match_all('/' . $pattern . '/s', $content, $matches); if (isset($matches[0]) && isset($atts['wpb_input_text']) && trim($atts['wpb_input_text']) != '') { foreach ($matches[0] as $shortcode_instance) { $attribute_pattern = '/' . $attribute_to_update . '=["\'](.*?)["\']/'; preg_match($attribute_pattern, $shortcode_instance, $attribute_match); // // Check if the attribute was found if (!isset($attribute_match[1])) { $new_value = rapidtextai_generate_text($atts['wpb_input_text'],$postid,$instance_id);; $updated_shortcode = str_replace('rapidtextai_ai_text_block','rapidtextai_ai_text_block wpb_input_text_output="'.$new_value.'"', $shortcode_instance); $content = str_replace($shortcode_instance, $updated_shortcode, $content); } } } wp_update_post(array('ID'=>$postid,'post_content'=>$content)); return isset($atts['wpb_input_text_output']) ? $atts['wpb_input_text_output'] : $new_value; } // func add_shortcode('rapidtextai_ai_text_block', 'rapidtextai_ai_text_block_shortcode'); } /*** * Elementor */ // Hook to ensure Elementor is fully loaded before registering the widget add_action('elementor/init', 'rapidtextai_is_elementor_active'); function rapidtextai_is_elementor_active(){ // Register the custom widget add_action( 'elementor/widgets/widgets_registered', function() { class rapidtextai_AITextBlock_Elementor_Widget extends \Elementor\Widget_Base { public function get_name() { return 'rapidtextai-ai-text-block'; } public function get_title() { return __('AI Text Block', 'rapidtextai'); } protected function register_controls() { $this->start_controls_section( 'content_section', [ 'label' => esc_html__('Content', 'rapidtextai'), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, ] ); $this->add_control( 'input_text', [ 'label' => esc_html__('Prompt', 'rapidtextai-ai-text-block-elementor'), 'type' => \Elementor\Controls_Manager::TEXTAREA, 'placeholder' => esc_html__('Write an about use section for my company which manufacture light bulbs.', 'rapidtextai-ai-text-block-elementor'), 'input_type' => 'text', 'label_block' => true, 'attributes' => [ 'class' => 'rapidtextai-prompt-textarea', // Custom class to identify the textarea ], ] ); $this->add_control( 'input_text_output', [ 'label' => esc_html__( 'Prompt Output', 'rapidtextai-ai-text-block-elementor' ), 'description' => esc_html__('Prompt response will be here, edit here if needed', 'rapidtextai'), 'type' => \Elementor\Controls_Manager::TEXTAREA ] ); $this->end_controls_section(); } // function public function render() { $postid = get_the_ID(); $settings = $this->get_settings_for_display(); $jsonelem_str = get_metadata('post',$postid, '_elementor_data', true ); $jsonelem_arr = $jsonelem_str ? json_decode( $jsonelem_str, true ) : false; $instance_id = $this->get_id(); if($jsonelem_arr){ $input_text = $settings['input_text']; $input_text_output = $settings['input_text_output']; $generated_text = ''; if($input_text_output && trim($input_text_output) != '') $generated_text = $input_text_output; else{ if($input_text && trim($input_text) != ''){ $generated_text = rapidtextai_generate_text($input_text,$postid,$instance_id); foreach ($jsonelem_arr as $key => $value) { if($value['elements'][0]['elements'][0]['id'] == $instance_id){ $jsonelem_arr[$key]['elements'][0]['elements'][0]['settings']['input_text_output'] = $generated_text; $jsonvalue = wp_slash( wp_json_encode( $jsonelem_arr ) ); update_metadata( 'post', $postid, '_elementor_data', $jsonvalue ); break; } // if($value['elements'][0 } // foreach } // if($input_text && trim($input_text } // ELSE of if($input_text_output && echo wp_kses_post($generated_text); } // $jsonelem_arr } // func // protected function content_template() {} // public function render_plain_content( $instance = [] ) {} } // clASS // Register the widget in Elementor \Elementor\Plugin::instance()->widgets_manager->register_widget_type( new \rapidtextai_AITextBlock_Elementor_Widget() ); }); //add_action( 'elementor/widgets/register', 'rapidtextai_register_block_widget' ); } function rapidtextai_generate_text($prompt,$postid,$instance_id){ $apikey = get_option('rapidtextai_api_key','c52ec1-5c73cd-e411e2-d8dc2d-491514'); // Define the URL with query parameters $url = "https://app.rapidtextai.com/openai/detailedarticle-v2?gigsixkey=" . $apikey; $request_data = array( 'type' => 'custom_prompt', 'toneOfVoice' => '', // Assuming tone is sent as POST data 'language' => '', // Assuming language is sent as POST data 'text' => '', 'temperature' => '0.7', // Assuming temperature is sent as POST data 'custom_prompt' => $prompt, ); $json_data = wp_json_encode($request_data); $response = wp_remote_post($url, array( 'body' => $json_data, 'method' => 'POST', //'timeout' => 45, //'redirection' => 5, //'httpversion' => '1.0', //'blocking' => true, 'sslverify' => false, 'headers' => array('Content-Type' => 'multipart/form-data'), )); if (!is_wp_error($response)) { $http_code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); if ($http_code === 200) { $content = rapidtextai_simple_markdown_to_html($body); return $content; } else return 'Unauthorized Access, check your Rapidtextai.com Key'; } } function rapidtextai_simple_markdown_to_html($markdown) { // Convert headers (we'll use a callback inside preg_replace_callback instead of preg_replace) $markdown = preg_replace_callback('/^(#{1,6})\s*(.*?)\s*#*\s*(?:\n+|$)/m', function($matches) { $level = strlen($matches[1]); return "{$matches[2]}"; }, $markdown); // Convert bold (**text** or __text__) $markdown = preg_replace('/\*\*(.*?)\*\*/', '$1', $markdown); $markdown = preg_replace('/__(.*?)__/', '$1', $markdown); // Convert italic (*text* or _text_) $markdown = preg_replace('/\*(.*?)\*/', '$1', $markdown); $markdown = preg_replace('/_(.*?)_/', '$1', $markdown); // Convert links [text](url) $markdown = preg_replace('/\[([^\[]+)\]\((.*?)\)/', '$1', $markdown); // Convert unordered lists $markdown = preg_replace('/^\s*[\*\+\-]\s+(.*)/m', '
  • $1
  • ', $markdown); $markdown = preg_replace('/(
  • .*<\/li>)/s', '', $markdown); // Convert ordered lists $markdown = preg_replace('/^\d+\.\s+(.*)/m', '
  • $1
  • ', $markdown); $markdown = preg_replace('/(
  • .*<\/li>)/s', '
      $1
    ', $markdown); // Convert blockquotes $markdown = preg_replace('/^\s*>\s+(.*)/m', '
    $1
    ', $markdown); // Convert code blocks $markdown = preg_replace('/```(.*?)```/s', '
    $1
    ', $markdown); // Convert inline code $markdown = preg_replace('/`([^`]+)`/', '$1', $markdown); // Convert newlines to paragraphs $markdown = preg_replace('/\n\n/', '

    ', $markdown); $markdown = '

    ' . $markdown . '

    '; // Wrap with paragraph tags // Cleanup multiple paragraph tags $markdown = str_replace('

    ', '', $markdown); return $markdown; } // Add Auto Blogging feature function rapidtextai_add_auto_blogging_menu() { add_submenu_page( 'rapidtextai-settings', // Parent menu slug 'Auto Blogging', // Page title 'Auto Blogging', // Menu title 'manage_options', // Capability 'rapidtextai-auto-blogging', // Menu slug 'rapidtextai_auto_blogging_page' // Callback function ); } add_action('admin_menu', 'rapidtextai_add_auto_blogging_menu'); // Migration function to convert old settings to campaign-based structure function rapidtextai_migrate_to_campaigns() { // Check if migration is needed if (get_option('rapidtextai_campaigns_migrated')) { return; // Already migrated } // Get old settings $old_settings = get_option('rapidtextai_auto_blogging', array()); // If old settings exist, create a default campaign if (!empty($old_settings)) { $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); // Create default campaign from old settings $default_campaign = array( 'id' => 'campaign_' . time(), 'name' => 'Default Campaign', 'enabled' => isset($old_settings['enabled']) ? $old_settings['enabled'] : 0, 'schedule' => isset($old_settings['schedule']) ? $old_settings['schedule'] : 'daily', 'post_status' => isset($old_settings['post_status']) ? $old_settings['post_status'] : 'draft', 'post_author' => isset($old_settings['post_author']) ? $old_settings['post_author'] : get_current_user_id(), 'topics' => isset($old_settings['topics']) ? $old_settings['topics'] : '', 'model' => isset($old_settings['model']) ? $old_settings['model'] : 'gpt-3.5-turbo', 'tone' => isset($old_settings['tone']) ? $old_settings['tone'] : 'informative', 'post_category' => isset($old_settings['post_category']) ? $old_settings['post_category'] : array(1), 'generate_tags' => isset($old_settings['generate_tags']) ? $old_settings['generate_tags'] : 1, 'tags_count' => isset($old_settings['tags_count']) ? $old_settings['tags_count'] : 5, 'excerpt_length' => isset($old_settings['excerpt_length']) ? $old_settings['excerpt_length'] : 55, 'taxonomy_limit' => isset($old_settings['taxonomy_limit']) ? $old_settings['taxonomy_limit'] : 5, 'include_images' => isset($old_settings['include_images']) ? $old_settings['include_images'] : 1, 'include_featured_image' => isset($old_settings['include_featured_image']) ? $old_settings['include_featured_image'] : 0, 'max_images' => isset($old_settings['max_images']) ? $old_settings['max_images'] : 5, 'enable_logging' => isset($old_settings['enable_logging']) ? $old_settings['enable_logging'] : 0, 'created' => current_time('mysql'), ); $campaigns[$default_campaign['id']] = $default_campaign; update_option('rapidtextai_auto_blogging_campaigns', $campaigns); // Keep old settings for backward compatibility but mark as migrated update_option('rapidtextai_campaigns_migrated', true); } else { // No old settings, just mark as migrated update_option('rapidtextai_campaigns_migrated', true); } } // Run migration on plugin load add_action('plugins_loaded', 'rapidtextai_migrate_to_campaigns'); // Auto Blogging settings page function rapidtextai_auto_blogging_page() { if (!current_user_can('manage_options')) { return; } // Handle campaign actions if (isset($_GET['action']) && isset($_GET['campaign_id']) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'rapidtextai_campaign_action')) { $campaign_id = sanitize_text_field($_GET['campaign_id']); $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); $redirect_url = admin_url('admin.php?page=rapidtextai-auto-blogging'); switch ($_GET['action']) { case 'delete': if (isset($campaigns[$campaign_id])) { // Clear the campaign's cron job wp_clear_scheduled_hook('rapidtextai_auto_blogging_cron_' . $campaign_id); unset($campaigns[$campaign_id]); update_option('rapidtextai_auto_blogging_campaigns', $campaigns); $redirect_url = add_query_arg('message', 'deleted', $redirect_url); } break; case 'toggle': if (isset($campaigns[$campaign_id])) { $campaigns[$campaign_id]['enabled'] = !$campaigns[$campaign_id]['enabled']; update_option('rapidtextai_auto_blogging_campaigns', $campaigns); // Update cron if ($campaigns[$campaign_id]['enabled']) { rapidtextai_schedule_campaign_cron($campaign_id, $campaigns[$campaign_id]); } else { wp_clear_scheduled_hook('rapidtextai_auto_blogging_cron_' . $campaign_id); } $status = $campaigns[$campaign_id]['enabled'] ? 'enabled' : 'disabled'; $redirect_url = add_query_arg('message', $status, $redirect_url); } break; } // Redirect to prevent action from being processed again if (!headers_sent()) { wp_redirect($redirect_url); exit; } else { // Use JavaScript redirect if headers already sent echo ''; exit; } } // Display admin messages if (isset($_GET['message'])) { $message = sanitize_text_field($_GET['message']); $messages = array( 'deleted' => 'Campaign deleted successfully.', 'enabled' => 'Campaign enabled successfully.', 'disabled' => 'Campaign disabled successfully.', 'created' => 'Campaign created successfully.', 'updated' => 'Campaign updated successfully.', ); if (isset($messages[$message])) { echo '

    ' . esc_html($messages[$message]) . '

    '; } } // Save campaign settings if (isset($_POST['rapidtextai_save_campaign']) && isset($_POST['rapidtextai_campaign_nonce']) && wp_verify_nonce($_POST['rapidtextai_campaign_nonce'], 'rapidtextai_save_campaign')) { $campaign_id = isset($_POST['campaign_id']) && !empty($_POST['campaign_id']) ? sanitize_text_field($_POST['campaign_id']) : 'campaign_' . time(); $is_new = !isset($_POST['campaign_id']) || empty($_POST['campaign_id']); $campaign = array( 'id' => $campaign_id, 'name' => sanitize_text_field($_POST['campaign_name']), 'enabled' => isset($_POST['rapidtextai_auto_blogging_enabled']) ? 1 : 0, 'schedule' => sanitize_text_field($_POST['rapidtextai_schedule']), 'post_status' => sanitize_text_field($_POST['rapidtextai_post_status']), 'post_author' => intval($_POST['rapidtextai_post_author']), 'topics' => sanitize_textarea_field($_POST['rapidtextai_topics']), 'model' => sanitize_text_field($_POST['rapidtextai_model']), 'tone' => sanitize_text_field($_POST['rapidtextai_tone']), 'post_category' => isset($_POST['rapidtextai_post_category']) ? array_map('intval', $_POST['rapidtextai_post_category']) : array(), 'generate_tags' => isset($_POST['rapidtextai_generate_tags']) ? 1 : 0, 'tags_count' => intval($_POST['rapidtextai_tags_count']), 'excerpt_length' => intval($_POST['rapidtextai_excerpt_length']), 'taxonomy_limit' => intval($_POST['rapidtextai_taxonomy_limit']), 'include_images' => isset($_POST['rapidtextai_include_images']) ? 1 : 0, 'include_featured_image' => isset($_POST['rapidtextai_include_featured_image']) ? 1 : 0, 'max_images' => intval($_POST['rapidtextai_max_images']), 'enable_logging' => isset($_POST['rapidtextai_enable_logging']) ? 1 : 0, ); if ($is_new) { $campaign['created'] = current_time('mysql'); } else { $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); if (isset($campaigns[$campaign_id]['created'])) { $campaign['created'] = $campaigns[$campaign_id]['created']; } } $campaign['updated'] = current_time('mysql'); $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); $campaigns[$campaign_id] = $campaign; update_option('rapidtextai_auto_blogging_campaigns', $campaigns); // Handle cron job scheduling for this campaign wp_clear_scheduled_hook('rapidtextai_auto_blogging_cron_' . $campaign_id); if ($campaign['enabled']) { rapidtextai_schedule_campaign_cron($campaign_id, $campaign); } // Maintain backward compatibility with old option // If this is the first/default campaign, also update the old option $all_campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); if (count($all_campaigns) === 1 || strpos($campaign['name'], 'Default') !== false) { update_option('rapidtextai_auto_blogging', $campaign); } // Redirect to campaign list with success message $redirect_url = add_query_arg('message', $is_new ? 'created' : 'updated', admin_url('admin.php?page=rapidtextai-auto-blogging')); if (!headers_sent()) { wp_redirect($redirect_url); exit; } else { echo ''; exit; } } // Get current campaigns $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); // Get campaign to edit $editing_campaign = null; if (isset($_GET['edit_campaign'])) { $edit_id = sanitize_text_field($_GET['edit_campaign']); if (isset($campaigns[$edit_id])) { $editing_campaign = $campaigns[$edit_id]; } } // Default settings for new campaign if ($editing_campaign) { $settings = $editing_campaign; } else { $settings = array( 'id' => '', 'name' => '', 'enabled' => 0, 'schedule' => 'daily', 'post_status' => 'draft', 'post_author' => get_current_user_id(), 'topics' => '', 'model' => 'gpt-3.5-turbo', 'tone' => 'informative', 'post_category' => array(1), 'generate_tags' => 1, 'tags_count' => 5, 'excerpt_length' => 55, 'taxonomy_limit' => 5, 'include_images' => 1, 'include_featured_image' => 0, 'max_images' => 5, 'enable_logging' => 0, ); } // Get all authors $authors = get_users(array('role__in' => array('administrator', 'editor', 'author'))); // Get all categories $categories = get_categories(array('hide_empty' => 0)); $author_list = array_map(function ($u) { return array('id' => (int) $u->ID, 'name' => $u->display_name); }, $authors); $category_list = array_map(function ($c) { return array('id' => (int) $c->term_id, 'name' => $c->name); }, $categories); rapidtextai_react_app_root(array( 'page' => 'auto-blogging', 'data' => array( 'authors' => array_values($author_list), 'categories' => array_values($category_list), ), )); // Handle manual post generation for a campaign if (isset($_POST['rapidtextai_generate_post_now']) && isset($_POST['rapidtextai_generate_now_nonce']) && wp_verify_nonce($_POST['rapidtextai_generate_now_nonce'], 'rapidtextai_generate_now')) { $campaign_id = isset($_POST['campaign_id']) ? sanitize_text_field($_POST['campaign_id']) : ''; rapidtextai_generate_auto_blog_post($campaign_id); echo '

    Post generation triggered for selected campaign.

    '; } } // Helper function to schedule campaign cron function rapidtextai_schedule_campaign_cron($campaign_id, $campaign) { $hook_name = 'rapidtextai_auto_blogging_cron_' . $campaign_id; if (!wp_next_scheduled($hook_name)) { $schedule = isset($campaign['schedule']) ? $campaign['schedule'] : 'daily'; if ($schedule == 'hourly') { wp_schedule_event(time(), 'hourly', $hook_name); } elseif ($schedule == 'twicedaily') { wp_schedule_event(time(), 'twicedaily', $hook_name); } elseif ($schedule == 'daily') { wp_schedule_event(time(), 'daily', $hook_name); } elseif ($schedule == 'weekly') { wp_schedule_event(time(), 'weekly', $hook_name); } } // Register the action for this specific campaign add_action($hook_name, function() use ($campaign_id) { rapidtextai_generate_auto_blog_post($campaign_id); }); } // rapidtextai_improve_topics add_action('wp_ajax_rapidtextai_improve_topics', 'rapidtextai_improve_topics_callback'); add_action('wp_ajax_nopriv_rapidtextai_improve_topics', 'rapidtextai_improve_topics_callback'); function rapidtextai_improve_topics_callback() { // Check nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'rapidtextai_improve_topics_nonce')) { wp_send_json_error(array('message' => 'Security check failed.')); return; } // Check if topics were provided if (empty($_POST['topics'])) { wp_send_json_error(array('message' => 'No topics provided.')); return; } $topics = sanitize_textarea_field($_POST['topics']); $topics_array = explode("\n", $topics); $topics_array = array_map('trim', $topics_array); $topics_array = array_filter($topics_array); // Limit to prevent abuse if (count($topics_array) > 50) { $topics_array = array_slice($topics_array, 0, 50); } $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { wp_send_json_error(array('message' => 'API key not found. Please set up your RapidTextAI authentication.')); return; } // Create prompt for improving topics $prompt = "I have a list of blog post topics that need improvement to make them more specific, engaging, and SEO-friendly. Please improve each of these topics:\n\n"; $prompt .= implode("\n", $topics_array); $prompt .= "\n\nIMPORTANT FORMATTING RULES:\n"; $prompt .= "1. Each improved topic MUST be on a SINGLE LINE (no line breaks within a topic)\n"; $prompt .= "2. Use semicolons (;) to separate different parts within the same topic\n"; $prompt .= "3. Separate different topics with a blank line (double newline)\n"; $prompt .= "4. Include: Topic, Keywords, Tone, Audience, Length, and CTA\n"; $prompt .= "5. Use the same language as the input topics\n\n"; $prompt .= "FORMAT EXAMPLE:\n"; $prompt .= "Topic: Complete Guide to Sustainable Gardening for Beginners; Keywords: sustainable gardening, eco-friendly plants, organic fertilizer, water conservation, composting methods; Tone: friendly and informative; Audience: homeowners and gardening beginners; Length: 2500-3000 words; CTA: Download our free sustainable gardening checklist\n\n"; $prompt .= "Topic: Another Topic Here; Keywords: keyword1, keyword2, keyword3; Tone: professional; Audience: business owners; Length: 1500-2000 words; CTA: Contact us for consultation\n\n"; $prompt .= "Return each improved topic on ONE SINGLE LINE, separated by blank lines. Do NOT add line breaks within a topic."; // Call RapidTextAI API using the chat completions endpoint $chat_endpoint = 'https://app.rapidtextai.com/openai/v1/chat/completions?gigsixkey=' . $api_key; $chat_body = [ 'model' => 'gpt-3.5-turbo', 'messages' => [ [ 'role' => 'system', 'content' => "You are a helpful assistant that improves blog post topics." ], [ 'role' => 'user', 'content' => $prompt ] ], 'max_tokens' => 500, 'temperature' => 0.7 ]; $response = wp_remote_post($chat_endpoint, [ 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $api_key, ], 'body' => json_encode($chat_body), 'timeout' => 30, ]); if (is_wp_error($response)) { wp_send_json_error(array('message' => 'Error connecting to RapidTextAI: ' . $response->get_error_message())); return; } $http_code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); if ($http_code !== 200) { wp_send_json_error(array('message' => 'API request failed with code ' . $http_code)); return; } // Process the response $response_data = json_decode($body, true); if (!isset($response_data['choices'][0]['message']['content'])) { wp_send_json_error(array('message' => 'Invalid response from API')); return; } $improved_topics = trim($response_data['choices'][0]['message']['content']); // Clean up the response to ensure proper format $improved_topics = preg_replace('/^\d+\.\s+/m', '', $improved_topics); // Remove numbering $improved_topics = preg_replace('/^- /m', '', $improved_topics); // Remove bullet points wp_send_json_success(array( 'message' => 'Topics improved successfully!', 'improved_topics' => $improved_topics )); } // Schedule the cron job - Main entry point add_action('rapidtextai_auto_blogging_cron', 'rapidtextai_generate_auto_blog_post'); // Register action hooks for all campaign-specific cron hooks on every page load // This is required because dynamic add_action() calls inside rapidtextai_schedule_campaign_cron() // only run when saving campaigns, not when WP-Cron fires the hook. add_action('plugins_loaded', 'rapidtextai_register_campaign_cron_hooks'); function rapidtextai_register_campaign_cron_hooks() { $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); if (empty($campaigns)) { return; } foreach ($campaigns as $campaign_id => $campaign) { $hook_name = 'rapidtextai_auto_blogging_cron_' . $campaign_id; add_action($hook_name, function() use ($campaign_id) { rapidtextai_generate_auto_blog_post($campaign_id); }); } } // Cron 2: Polish + Headings + Title + Create post add_action('rapidtextai_refine_and_publish', 'rapidtextai_refine_and_publish_handler', 10, 1); // Cron 3: Tags, images, featured image, final publish status add_action('rapidtextai_finalize_post', 'rapidtextai_finalize_post_handler', 10, 1); /** * Agent Mode Auto-Blogging Pipeline (3 cron events): * * Cron 1 — rapidtextai_generate_auto_blog_post() * Stage 1 - Draft: Streams article via completionsarticle-stream (campaign model) * → saves draft to transient, schedules Cron 2 * * Cron 2 — rapidtextai_refine_and_publish_handler() * Stage 1.5 - Polish: Refines draft via completions-stream (deepseek-v4-flash) * Stage 1.75- Headings: Builds {heading → image query} map via completions-stream * Stage 2 - Title: Generates SEO title via completions API * Stage 3 - Create: Inserts WordPress post (draft), stores meta * → schedules Cron 3 * * Cron 3 — rapidtextai_finalize_post_handler() * Stage 4 - Finalize: Tags, content images, featured image, final publish status */ /** * Stream content from API using Server-Sent Events (SSE) * * SSE Format Example: * data: {"id":"123","object":"chat.completion.chunk","choices":[{"delta":{"content":"Hello"}}]} * * data: {"id":"123","object":"chat.completion.chunk","choices":[{"delta":{"content":" world"}}]} * * data: [DONE] */ function rapidtextai_stream_content_via_sse($api_url, $post_data) { $accumulated_content = ''; $buffer = ''; $chunk_count = 0; $settings = get_option('rapidtextai_auto_blogging', array()); if (!empty($settings['enable_logging'])) { error_log('RapidTextAI: Stream: Starting SSE stream'); } // Initialize cURL for streaming $ch = curl_init($api_url); curl_setopt_array($ch, array( CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($post_data), CURLOPT_HTTPHEADER => array( 'Content-Type: application/json', 'Accept: text/event-stream', ), CURLOPT_RETURNTRANSFER => false, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_TIMEOUT => 300, // 5 minutes max CURLOPT_CONNECTTIMEOUT => 30, CURLOPT_BUFFERSIZE => 128, // Small buffer for real-time processing CURLOPT_WRITEFUNCTION => function($curl, $data) use (&$accumulated_content, &$buffer, &$chunk_count) { $buffer .= $data; // Process complete SSE events (separated by \n\n) while (($double_newline_pos = strpos($buffer, "\n\n")) !== false) { $event_block = substr($buffer, 0, $double_newline_pos); $buffer = substr($buffer, $double_newline_pos + 2); // Parse the event block $lines = explode("\n", $event_block); foreach ($lines as $line) { // SSE format: "data: {json}" if (strpos($line, 'data: ') === 0) { $json_data = trim(substr($line, 6)); // Check for stream end signal if ($json_data === '[DONE]') { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: Stream: Received [DONE] signal'); continue; } // Decode JSON chunk $chunk = json_decode($json_data, true); // Check for JSON decode errors if (json_last_error() !== JSON_ERROR_NONE) { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: Stream: JSON decode error: ' . json_last_error_msg() . ' - Data: ' . substr($json_data, 0, 200)); continue; } // Extract content from delta (OpenAI streaming format) if (isset($chunk['choices'][0]['delta']['content'])) { $content_piece = $chunk['choices'][0]['delta']['content']; $accumulated_content .= $content_piece; $chunk_count++; // Log progress every 50 chunks if ($chunk_count % 50 === 0 && !empty($settings['enable_logging'])) { error_log("RapidTextAI Stream: Processed {$chunk_count} chunks, " . strlen($accumulated_content) . " chars"); } } else { // Log when expected structure is not found if ($chunk_count < 5 && !empty($settings['enable_logging'])) { // Only log first few to avoid spam error_log('RapidTextAI: Stream: Chunk missing delta.content - Structure: ' . json_encode($chunk)); } } } } } return strlen($data); } )); // Execute the streaming request $result = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curl_error = curl_error($ch); curl_close($ch); // Validate results if ($result === false || !empty($curl_error)) { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: Stream: cURL error - ' . $curl_error); return false; } if ($http_code !== 200) { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: Stream: HTTP error code ' . $http_code); return false; } if (empty($accumulated_content)) { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: Stream: No content received from stream. Chunks processed: ' . $chunk_count . ', Buffer remaining: ' . strlen($buffer)); return false; } if(!empty($settings['enable_logging'])) error_log("RapidTextAI Stream: SUCCESS! Received {$chunk_count} chunks, total " . strlen($accumulated_content) . " characters"); return $accumulated_content; } // Stage 1: Stream article content and save to transient function rapidtextai_generate_auto_blog_post($campaign_id = '') { // Get campaign settings if (empty($campaign_id)) { $settings = get_option('rapidtextai_auto_blogging', array()); $campaign_id = 'default'; } else { $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); if (!isset($campaigns[$campaign_id])) { error_log('RapidTextAI: Campaign not found: ' . $campaign_id); return; } $settings = $campaigns[$campaign_id]; } if (empty($settings) || empty($settings['enabled'])) { return; } $user_limits_check = rapidtextai_check_user_limits(); if (!$user_limits_check) { if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] User limits exceeded, auto blogging skipped.'); return false; } $topics = array_filter(array_map('trim', explode("\n", $settings['topics']))); if (empty($topics)) { if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] No topics available for auto blogging.'); return; } $selected_topic = $topics[array_rand($topics)]; $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] API key not found.'); return; } // ── Stage 1: Draft ──────────────────────────────────────────────────────── if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1 (Draft): Starting for topic: ' . $selected_topic); $draft_model = $settings['model']; $post_data = array( 'model' => $draft_model, 'messages' => array(array( 'role' => 'user', 'content' => "Write a comprehensive article about: " . $selected_topic . "\n\nThe tone should be " . $settings['tone'] . ".", )), 'chatsession' => 'agent_' . $draft_model . '_' . time() . '_' . wp_rand(), 'stream' => true, ); if (strpos($draft_model, 'gpt-5') !== false) { $post_data['max_completion_tokens'] = 4000; $post_data['reasoning_effort'] = 'minimal'; } else { $post_data['max_tokens'] = $user_limits_check['response_code'] == 1 ? null : 4000; $post_data['temperature'] = 0.7; } $api_url = "https://app.rapidtextai.com/openai/v1/chat/completionsarticle-stream?gigsixkey=" . urlencode($api_key); $content = rapidtextai_stream_content_via_sse($api_url, $post_data); if ($content === false) { if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1 (Draft): Streaming failed for topic: ' . $selected_topic); return; } if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1 (Draft): Got ' . strlen($content) . ' chars'); // Save draft to transient (expires in 2 hours) $transient_key = 'rapidtextai_content_' . md5($campaign_id . $selected_topic . time()); set_transient($transient_key, array( 'content' => $content, 'topic' => $selected_topic, 'settings' => $settings, 'campaign_id' => $campaign_id, 'created' => current_time('mysql'), ), 2 * HOUR_IN_SECONDS); // Schedule Cron 2: refine + publish wp_schedule_single_event(time() + 2, 'rapidtextai_refine_and_publish', array($transient_key)); if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1 (Draft): Scheduled refine-and-publish job'); } // Cron 2: Polish → Heading map → Title → Create post function rapidtextai_refine_and_publish_handler($transient_key) { $data = get_transient($transient_key); if ($data === false || empty($data['content'])) { error_log('RapidTextAI: Cron 2: Transient missing or expired: ' . $transient_key); return; } $campaign_id = isset($data['campaign_id']) ? $data['campaign_id'] : 'default'; $settings = $data['settings']; $content = $data['content']; $selected_topic = $data['topic']; $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { delete_transient($transient_key); return; } // ── Stage 1.5: Polish ───────────────────────────────────────────────────── if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish): Polishing draft'); $polish_prompt = "Polish the following article draft to be fully publication-ready for a WordPress blog. Remove any placeholder text like [INSERT ...], [ADD ...], [YOUR ...], etc. Ensure all sections are complete, professional, and reader-ready. Preserve all headings, structure, and Markdown formatting. Output ONLY the polished article. Do not include any introductory sentences, explanations, summaries, or separators before or after the article.\n\nArticle:\n" . $content; $polished = rapidtextai_stream_agent_completion( $api_key, array( array('role' => 'system', 'content' => 'You are a professional blog editor. Output ONLY the polished article content. Never include any preamble, commentary, meta-notes, or separators like "---". Do not explain what you did. Return the article text and nothing else.'), array('role' => 'user', 'content' => $polish_prompt) ), 'RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish)' ); if ($polished !== false) { $content = $polished; if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish): Done (' . strlen($content) . ' chars)'); } else { if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish): Failed, using original draft'); } // ── Stage 1.75: Heading Optimization ───────────────────────────────────── if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.75 (Headings): Generating image query map'); $heading_prompt = 'Extract every H2, H3, and H4 heading from the article below. For each heading, generate a concise, highly specific image search query (2-5 words, visual and descriptive). Return ONLY a valid JSON object in the format {"heading text": "image search query", ...}. Skip headings that are exactly "Conclusion", "Introduction", or "Summary".' . "\n\nArticle:\n" . $content; $heading_map_raw = rapidtextai_stream_agent_completion( $api_key, array(array('role' => 'user', 'content' => $heading_prompt)), 'RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.75 (Headings)' ); $heading_map = array(); if ($heading_map_raw !== false) { preg_match('/\{[\s\S]*\}/', $heading_map_raw, $json_match); if (!empty($json_match[0])) { $decoded = json_decode($json_match[0], true); if (is_array($decoded)) { $heading_map = $decoded; } } } if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.75 (Headings): Map has ' . count($heading_map) . ' entries'); // ── Stage 2: Generate Title ─────────────────────────────────────────────── if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2 (Title): Generating SEO title'); $title_data = array( 'model' => 'gpt-3.5-turbo', 'messages' => array( array('role' => 'system', 'content' => 'You are a title generator. Generate only an SEO-optimized, engaging title for the article in language same as content language. Return ONLY the title, nothing else.'), array('role' => 'user', 'content' => "Generate a compelling title for this article in language same as content language:\n\n" . substr($content, 0, 1000)), ), 'max_tokens' => 100, 'temperature' => 0.8, ); $title_response = wp_remote_post( "https://app.rapidtextai.com/openai/v1/chat/completions?gigsixkey=" . urlencode($api_key), array('timeout' => 60, 'headers' => array('Content-Type' => 'application/json'), 'body' => json_encode($title_data)) ); $title = $selected_topic; // fallback if (!is_wp_error($title_response)) { $title_result = json_decode(wp_remote_retrieve_body($title_response), true); if (!empty($title_result['choices'][0]['message']['content'])) { $title = trim($title_result['choices'][0]['message']['content'], '"\' '); } } if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2 (Title): "' . $title . '"'); // ── Stage 3: Create Post ────────────────────────────────────────────────── $post_content = rapidtextai_simple_markdown_to_html($content); $excerpt_length = isset($settings['excerpt_length']) && $settings['excerpt_length'] > 0 ? $settings['excerpt_length'] : 55; $excerpt = wp_trim_words(wp_strip_all_tags($post_content), $excerpt_length, '...'); $post_id = wp_insert_post(array( 'post_title' => $title, 'post_content' => $post_content, 'post_excerpt' => $excerpt, 'post_status' => 'draft', 'post_author' => $settings['post_author'], )); delete_transient($transient_key); if (is_wp_error($post_id)) { if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3 (Create): Failed - ' . $post_id->get_error_message()); return; } if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3 (Create): Created post ID ' . $post_id); update_post_meta($post_id, '_rapidtextai_topic', $selected_topic); update_post_meta($post_id, '_rapidtextai_settings', $settings); update_post_meta($post_id, '_rapidtextai_campaign_id', $campaign_id); update_post_meta($post_id, '_rapidtextai_raw_content', $content); update_post_meta($post_id, '_rapidtextai_status', 'created'); update_post_meta($post_id, '_rapidtextai_started', $data['created']); if (!empty($heading_map)) { update_post_meta($post_id, '_rapidtextai_heading_map', $heading_map); } // Schedule Cron 3: Finalize (images, tags, featured image, publish) wp_schedule_single_event(time() + 2, 'rapidtextai_finalize_post', array($post_id)); if (!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3 (Create): Scheduled finalization for post ' . $post_id); } /** * Helper: Stream a chat completion from the completions-stream endpoint (Agent Mode). * Returns the accumulated content string, or false on failure. */ function rapidtextai_stream_agent_completion($api_key, array $messages, $log_prefix = '') { $post_data = array( 'model' => 'deepseek-v4-flash', 'messages' => $messages, 'stream' => true, 'chatsession' => 'agent_deepseek_' . time() . '_' . wp_rand(), 'max_tokens' => 4000, 'temperature' => 0.7, ); $api_url = 'https://app.rapidtextai.com/openai/v1/chat/completions-stream?gigsixkey=' . urlencode($api_key); $result = rapidtextai_stream_content_via_sse($api_url, $post_data); if ($result === false && !empty($log_prefix)) { error_log($log_prefix . ': completions-stream call failed.'); } return $result; } // Stage 1.5: Polish the draft function rapidtextai_polish_post_handler($transient_key) { $data = get_transient($transient_key); if ($data === false || empty($data['content'])) { error_log('RapidTextAI: Stage 1.5 (Polish): Transient missing or expired: ' . $transient_key); return; } $campaign_id = isset($data['campaign_id']) ? $data['campaign_id'] : 'default'; $settings = $data['settings']; $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { return; } if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish): Polishing draft (' . strlen($data['content']) . ' chars)'); $polish_prompt = "Polish the following article draft to be fully publication-ready for a WordPress blog. Remove any placeholder text like [INSERT ...], [ADD ...], [YOUR ...], etc. Ensure all sections are complete, professional, and reader-ready. Preserve all headings, structure, and Markdown formatting. Output ONLY the polished article. Do not include any introductory sentences, explanations, summaries, or separators before or after the article.\n\nArticle:\n" . $data['content']; $polished = rapidtextai_stream_agent_completion( $api_key, array( array('role' => 'system', 'content' => 'You are a professional blog editor. Output only the polished article content with absolutely no commentary, explanations, preamble, or closing remarks. Do not say things like "Here is the polished version" or "I have made the following changes". Return only the final article text, ready to publish.'), array('role' => 'user', 'content' => $polish_prompt), ), 'RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish)' ); if ($polished === false) { // Fall back to original draft if polish fails $polished = $data['content']; if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish): Failed, using original draft.'); } else { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish): Done (' . strlen($polished) . ' chars)'); } // Remove any content up to and including a leading "---" separator (e.g. YAML front matter) if (preg_match('/^.*?---\s*\n(.*)/s', $polished, $matches)) { $polished = trim($matches[1]); } // Remove any preamble before the first Markdown heading (e.g. "Here is the polished version:\n\n# Title") if (preg_match('/(#{1,6}\s.+)/s', $polished, $matches)) { $polished = trim($matches[1]); } $data['content'] = $polished; set_transient($transient_key, $data, 2 * HOUR_IN_SECONDS); // Schedule Stage 1.75: Optimize headings wp_schedule_single_event(time() + 2, 'rapidtextai_optimize_headings', array($transient_key)); if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.5 (Polish): Scheduled heading optimization job'); } // Stage 1.75: Generate optimized image search queries for each heading function rapidtextai_optimize_headings_handler($transient_key) { $data = get_transient($transient_key); if ($data === false || empty($data['content'])) { error_log('RapidTextAI: Stage 1.75 (Headings): Transient missing or expired: ' . $transient_key); return; } $campaign_id = isset($data['campaign_id']) ? $data['campaign_id'] : 'default'; $settings = $data['settings']; $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { return; } if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.75 (Headings): Generating heading image queries'); $heading_prompt = 'Extract every H2, H3, and H4 heading from the article below. For each heading, generate a concise, highly specific image search query (2-5 words, visual and descriptive). Return ONLY a valid JSON object in the format {"heading text": "image search query", ...}. Skip headings that are exactly "Conclusion", "Introduction", or "Summary".' . "\n\nArticle:\n" . $data['content']; $heading_map_raw = rapidtextai_stream_agent_completion( $api_key, array(array('role' => 'user', 'content' => $heading_prompt)), 'RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.75 (Headings)' ); $heading_map = array(); if ($heading_map_raw !== false) { preg_match('/\{[\s\S]*\}/', $heading_map_raw, $json_match); if (!empty($json_match[0])) { $decoded = json_decode($json_match[0], true); if (is_array($decoded)) { $heading_map = $decoded; } } } if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.75 (Headings): Generated map with ' . count($heading_map) . ' entries'); $data['heading_map'] = $heading_map; set_transient($transient_key, $data, 2 * HOUR_IN_SECONDS); // Schedule Stage 2: Generate title wp_schedule_single_event(time() + 2, 'rapidtextai_generate_title', array($transient_key)); if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 1.75 (Headings): Scheduled title generation job'); } // Stage 2: Generate title using completion API function rapidtextai_generate_title_handler($transient_key) { $settings = get_option('rapidtextai_auto_blogging', array()); // Get content from transient $data = get_transient($transient_key); if ($data === false || empty($data['content'])) { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: Stage 2: Transient data not found or empty: ' . $transient_key); return; } $campaign_id = isset($data['campaign_id']) ? $data['campaign_id'] : 'default'; if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2: Generating title from transient: ' . $transient_key); $content = $data['content']; $topic = $data['topic']; $settings = $data['settings']; // Get API key $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2: API key not found'); delete_transient($transient_key); return; } if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2: Requesting title generation for content (' . strlen($content) . ' chars)'); // Use completion API to generate title $title_data = array( 'model' => 'gpt-3.5-turbo', 'messages' => array( array( 'role' => 'system', 'content' => 'You are a title generator. Generate only an SEO-optimized, engaging title for the article in language same as content language. Return ONLY the title, nothing else.' ), array( 'role' => 'user', 'content' => "Generate a compelling title for this article in language same as content language:\n\n" . substr($content, 0, 1000) ) ), 'max_tokens' => 100, 'temperature' => 0.8, ); $api_url = "https://app.rapidtextai.com/openai/v1/chat/completions?gigsixkey=" . urlencode($api_key); $response = wp_remote_post($api_url, array( 'timeout' => 60, 'headers' => array('Content-Type' => 'application/json'), 'body' => json_encode($title_data), )); if (is_wp_error($response)) { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2: Title generation failed - ' . $response->get_error_message()); delete_transient($transient_key); return; } $response_body = wp_remote_retrieve_body($response); $result = json_decode($response_body, true); if (empty($result['choices'][0]['message']['content'])) { if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2: No title returned from API'); delete_transient($transient_key); return; } $title = trim($result['choices'][0]['message']['content']); // Remove quotes if present $title = trim($title, '"\''); if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2: Generated title: "' . $title . '"'); // Update transient with title $data['title'] = $title; set_transient($transient_key, $data, HOUR_IN_SECONDS); // Schedule Stage 3: Create post wp_schedule_single_event(time() + 2, 'rapidtextai_create_post', array($transient_key)); if(!empty($settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 2: Scheduled post creation job'); } // Stage 3: Create post with title and content function rapidtextai_create_post_handler($transient_key) { $log_settings = get_option('rapidtextai_auto_blogging', array()); // Get data from transient $data = get_transient($transient_key); if ($data === false || empty($data['content']) || empty($data['title'])) { if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: Stage 3: Missing data in transient: ' . $transient_key); return; } $campaign_id = isset($data['campaign_id']) ? $data['campaign_id'] : 'default'; if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3: Creating post from transient: ' . $transient_key); $content = $data['content']; $title = $data['title']; $topic = $data['topic']; $settings = $data['settings']; if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3: Creating post with title: "' . $title . '"'); // Convert markdown to HTML $post_content = rapidtextai_simple_markdown_to_html($content); // Generate excerpt $excerpt_length = isset($settings['excerpt_length']) && $settings['excerpt_length'] > 0 ? $settings['excerpt_length'] : 55; $excerpt = wp_trim_words(wp_strip_all_tags($post_content), $excerpt_length, '...'); // Create the post $post_id = wp_insert_post(array( 'post_title' => $title, 'post_content' => $post_content, 'post_excerpt' => $excerpt, 'post_status' => 'draft', 'post_author' => $settings['post_author'], )); if (is_wp_error($post_id)) { if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3: Failed to create post - ' . $post_id->get_error_message()); delete_transient($transient_key); return; } if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3: Created post ID ' . $post_id); // Store metadata update_post_meta($post_id, '_rapidtextai_topic', $topic); update_post_meta($post_id, '_rapidtextai_settings', $settings); update_post_meta($post_id, '_rapidtextai_campaign_id', $campaign_id); update_post_meta($post_id, '_rapidtextai_raw_content', $content); update_post_meta($post_id, '_rapidtextai_status', 'created'); update_post_meta($post_id, '_rapidtextai_started', $data['created']); // Store heading_map in post meta so Stage 4 can use optimized image queries $heading_map = isset($data['heading_map']) ? $data['heading_map'] : array(); if (!empty($heading_map)) { update_post_meta($post_id, '_rapidtextai_heading_map', $heading_map); } // Delete transient (no longer needed) delete_transient($transient_key); if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3: Post created successfully, scheduling finalization'); // Schedule Stage 4: Finalize (add images, tags, publish) wp_schedule_single_event(time() + 2, 'rapidtextai_finalize_post', array($post_id)); if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 3: Scheduled finalization job for post ' . $post_id); } // Stage 4: Finalize post (tags, images, status) function rapidtextai_finalize_post_handler($post_id) { $log_settings = get_option('rapidtextai_auto_blogging', array()); $settings = get_post_meta($post_id, '_rapidtextai_settings', true); $campaign_id = get_post_meta($post_id, '_rapidtextai_campaign_id', true); if (empty($campaign_id)) { $campaign_id = 'default'; } if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Finalizing post ' . $post_id); $raw_content = get_post_meta($post_id, '_rapidtextai_raw_content', true); $post = get_post($post_id); if (empty($settings) || !$post) { if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Missing data for post ' . $post_id); update_post_meta($post_id, '_rapidtextai_status', 'failed'); return; } update_post_meta($post_id, '_rapidtextai_status', 'finalizing'); // Generate tags if enabled if ($settings['generate_tags']) { if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Generating tags for post ' . $post_id); $api_key = get_option('rapidtextai_api_key', ''); $tag_prompt = "Generate only {$settings['tags_count']} comma-separated tags for this content in content language: " . substr($raw_content, 0, 1000); $tag_data = array( 'model' => 'gpt-3.5-turbo', 'messages' => array( array( 'role' => 'system', 'content' => 'Generate only keywords as tags, keep them simple and relevant.' ), array( 'role' => 'user', 'content' => $tag_prompt ) ), 'temperature' => 0.5, 'max_tokens' => 100 ); $api_url = "https://app.rapidtextai.com/openai/v1/chat/completions?gigsixkey=" . urlencode($api_key); $tag_response = wp_remote_post($api_url, array( 'body' => json_encode($tag_data), 'headers' => array('Content-Type' => 'application/json'), 'timeout' => 30, 'sslverify' => false )); if (!is_wp_error($tag_response)) { $tag_body = wp_remote_retrieve_body($tag_response); $tag_result = json_decode($tag_body, true); if (isset($tag_result['choices'][0]['message']['content'])) { $tags = explode(',', $tag_result['choices'][0]['message']['content']); $tags = array_map('trim', $tags); $tags = array_slice($tags, 0, $settings['tags_count']); wp_set_post_tags($post_id, $tags, false); if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Added ' . count($tags) . ' tags to post ' . $post_id); } } } // Add images if enabled if ($settings['include_images']) { if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Adding images to post ' . $post_id); $post_content = $post->post_content; preg_match_all('/]*>(.*?)<\/h[2-4]>/i', $post_content, $headings); $images_added = 0; // Retrieve heading map from Agent Mode pipeline (optimized image queries) $heading_map = get_post_meta($post_id, '_rapidtextai_heading_map', true); if (!is_array($heading_map)) { $heading_map = array(); } delete_post_meta($post_id, '_rapidtextai_heading_map'); if (!empty($headings[1])) { foreach ($headings[1] as $heading) { if (stripos($heading, 'conclusion') !== false || stripos($heading, 'introduction') !== false || stripos($heading, 'summary') !== false) { continue; } // Use optimized query from heading map if available, otherwise use raw heading $search_query = !empty($heading_map[$heading]) ? $heading_map[$heading] : $heading; $image_data = rapidtextai_get_image_for_heading($search_query); if ($image_data) { $images_added++; $image_html = '
    '; $image_html .= '' . esc_attr($heading) . ''; $image_html .= '
    Source: ' . esc_html($image_data['display_link']) . '
    '; $image_html .= '
    '; $heading_pattern = '/]*>' . preg_quote($heading, '/') . '<\/h[2-4]>/i'; $replacement = $image_html . '$0'; $post_content = preg_replace($heading_pattern, $replacement, $post_content, 1); if ($images_added >= $settings['max_images']) { break; } } } if ($images_added > 0) { wp_update_post(array( 'ID' => $post_id, 'post_content' => $post_content )); if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Added ' . $images_added . ' images to post ' . $post_id); } } } // Set featured image if enabled if (isset($settings['include_featured_image']) && $settings['include_featured_image']) { if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Setting featured image for post ' . $post_id); $topic = get_post_meta($post_id, '_rapidtextai_topic', true); $featured_image_data = rapidtextai_get_featured_image_for_topic($topic); if ($featured_image_data && !empty($featured_image_data['link'])) { $image_url = $featured_image_data['link']; $image_response = wp_remote_get($image_url, array( 'timeout' => 30, 'user-agent' => 'WordPress/' . get_bloginfo('version') . '; ' . get_bloginfo('url') )); if (!is_wp_error($image_response) && wp_remote_retrieve_response_code($image_response) === 200) { $image_data = wp_remote_retrieve_body($image_response); $image_type = wp_remote_retrieve_header($image_response, 'content-type'); $extension = 'jpg'; if (strpos($image_type, 'png') !== false) { $extension = 'png'; } elseif (strpos($image_type, 'gif') !== false) { $extension = 'gif'; } elseif (strpos($image_type, 'webp') !== false) { $extension = 'webp'; } $filename = sanitize_file_name(substr($post->post_title, 0, 50)) . '.' . $extension; $upload = wp_upload_bits($filename, null, $image_data); if (!$upload['error']) { $wp_filetype = wp_check_filetype($upload['file']); $attachment = array( 'post_mime_type' => $wp_filetype['type'], 'post_title' => sanitize_text_field($post->post_title), 'post_content' => '', 'post_status' => 'inherit' ); $attach_id = wp_insert_attachment($attachment, $upload['file'], $post_id); if (!is_wp_error($attach_id)) { require_once(ABSPATH . 'wp-admin/includes/image.php'); $attach_data = wp_generate_attachment_metadata($attach_id, $upload['file']); wp_update_attachment_metadata($attach_id, $attach_data); set_post_thumbnail($post_id, $attach_id); if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Set featured image for post ' . $post_id); } } } } } // Set categories if (!empty($settings['post_category'])) { wp_set_post_categories($post_id, $settings['post_category']); } // Update post status to final status wp_update_post(array( 'ID' => $post_id, 'post_status' => $settings['post_status'] )); // Clean up temporary metadata delete_post_meta($post_id, '_rapidtextai_raw_content'); delete_post_meta($post_id, '_rapidtextai_settings'); // Mark as completed update_post_meta($post_id, '_rapidtextai_status', 'completed'); update_post_meta($post_id, '_rapidtextai_completed', current_time('mysql')); if(!empty($log_settings['enable_logging'])) { error_log('RapidTextAI: [Campaign: ' . $campaign_id . '] Stage 4: Successfully completed post ' . $post_id . ' - "' . $post->post_title . '"'); } } // Rest of the existing code continues below... // Function to get image for heading function rapidtextai_get_image_for_heading($heading) { $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { return false; } $response = wp_remote_get("https://app.rapidtextai.com/openai/customsearch?gigsixkey={$api_key}&searchType=image&q=" . urlencode($heading) . "&num=1"); if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (!empty($data['items']) && !empty($data['items'][0])) { return array( 'link' => $data['items'][0]['link'], 'context_link' => $data['items'][0]['image']['contextLink'], 'display_link' => $data['items'][0]['displayLink'] ); } } return false; } // ajax callback for featured image generation based on topic add_action('wp_ajax_rapidtextai_get_featured_image', 'rapidtextai_get_featured_image_for_topic'); add_action('wp_ajax_nopriv_rapidtextai_get_featured_image', 'rapidtextai_get_featured_image_for_topic'); // Function to get featured image for post topic function rapidtextai_get_featured_image_for_topic($topic) { $ajax = false; // Only verify nonce if topic is not provided as argument (i.e., when called via AJAX) if (!$topic) { if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'rapidtextai_nonce')) { wp_send_json_error(array('message' => 'Security check failed.')); return; } $topic = isset($_POST['topic']) ? sanitize_text_field($_POST['topic']) : ''; $ajax = true; } $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { return false; } // Generate search query using AI $search_query = rapidtextai_generate_search_query_for_featured($topic); if (!$search_query) { return false; } // Use the existing function to get image $image_data = rapidtextai_get_image_for_heading($search_query); if ($ajax) { if ($image_data) { wp_send_json_success($image_data); } else { wp_send_json_error(array('message' => 'No image found for this topic.')); } return; } return $image_data; } // AJAX handler for uploading image from URL add_action('wp_ajax_rapidtextai_upload_image_from_url', 'rapidtextai_upload_image_from_url_callback'); add_action('wp_ajax_nopriv_rapidtextai_upload_image_from_url', 'rapidtextai_upload_image_from_url_callback'); function rapidtextai_upload_image_from_url_callback() { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'rapidtextai_nonce')) { wp_send_json_error(array('message' => 'Security check failed.')); return; } // Check user permissions if (!current_user_can('upload_files')) { wp_send_json_error(array('message' => 'Permission denied.')); return; } // Validate and sanitize URL $image_url = isset($_POST['image_url']) ? esc_url_raw($_POST['image_url']) : ''; if (empty($image_url) || !filter_var($image_url, FILTER_VALIDATE_URL)) { wp_send_json_error(array('message' => 'Invalid image URL provided.')); return; } // Optional: Get post ID if provided $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0; // Get image filename or generate one $filename = isset($_POST['filename']) ? sanitize_file_name($_POST['filename']) : ''; if (empty($filename)) { $filename = basename(parse_url($image_url, PHP_URL_PATH)); if (empty($filename)) { $filename = 'rapidtextai-image-' . time(); } } // Download the image $response = wp_remote_get($image_url, array( 'timeout' => 30, 'user-agent' => 'WordPress/' . get_bloginfo('version') . '; ' . get_bloginfo('url') )); if (is_wp_error($response)) { wp_send_json_error(array('message' => 'Failed to download image: ' . $response->get_error_message())); return; } // Check response code if (wp_remote_retrieve_response_code($response) !== 200) { wp_send_json_error(array('message' => 'Failed to download image. HTTP status: ' . wp_remote_retrieve_response_code($response))); return; } // Get image data and content type $image_data = wp_remote_retrieve_body($response); $content_type = wp_remote_retrieve_header($response, 'content-type'); // Validate that it's actually an image if (strpos($content_type, 'image/') !== 0) { wp_send_json_error(array('message' => 'URL does not point to a valid image.')); return; } // Determine file extension from content type $extension = ''; switch ($content_type) { case 'image/jpeg': case 'image/jpg': $extension = 'jpg'; break; case 'image/png': $extension = 'png'; break; case 'image/gif': $extension = 'gif'; break; case 'image/webp': $extension = 'webp'; break; default: // Try to get extension from URL $path_info = pathinfo(parse_url($image_url, PHP_URL_PATH)); $extension = isset($path_info['extension']) ? $path_info['extension'] : 'jpg'; } // Ensure filename has proper extension if (!preg_match('/\.' . $extension . '$/i', $filename)) { $filename = pathinfo($filename, PATHINFO_FILENAME) . '.' . $extension; } // Upload the file to WordPress media library $upload = wp_upload_bits($filename, null, $image_data); if ($upload['error']) { wp_send_json_error(array('message' => 'Failed to upload image: ' . $upload['error'])); return; } // Get file type $wp_filetype = wp_check_filetype($upload['file']); // Prepare attachment data $attachment = array( 'post_mime_type' => $wp_filetype['type'], 'post_title' => sanitize_text_field(pathinfo($filename, PATHINFO_FILENAME)), 'post_content' => '', 'post_status' => 'inherit' ); // Insert attachment $attach_id = wp_insert_attachment($attachment, $upload['file'], $post_id); if (is_wp_error($attach_id)) { wp_send_json_error(array('message' => 'Failed to create attachment: ' . $attach_id->get_error_message())); return; } // Generate attachment metadata require_once(ABSPATH . 'wp-admin/includes/image.php'); $attach_data = wp_generate_attachment_metadata($attach_id, $upload['file']); wp_update_attachment_metadata($attach_id, $attach_data); // Get attachment URL $attachment_url = wp_get_attachment_url($attach_id); // Return success response wp_send_json_success(array( 'message' => 'Image uploaded successfully.', 'attachment_id' => $attach_id, 'attachment_url' => $attachment_url, 'attachment_title' => get_the_title($attach_id), 'file_path' => $upload['file'] )); } // Function to generate search query for featured image using AI function rapidtextai_generate_search_query_for_featured($topic) { $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { return false; } $log_settings = get_option('rapidtextai_auto_blogging', array()); // Create prompt for generating search query $prompt = "Based on this blog post topic, generate a short and specific search query (2-4 words) that would find the best featured image for this article. Focus on the main concept or subject matter.\n\nTopic: " . $topic . "\n\nReturn only the search query, nothing else."; // Set up request data $request_data = array( 'model' => 'gpt-3.5-turbo', 'messages' => [ [ 'role' => 'system', 'content' => 'You are a helpful assistant that generates concise image search queries. Return only the search terms, no explanations.' ], [ 'role' => 'user', 'content' => $prompt ] ], 'max_tokens' => 20, 'temperature' => 0.3 ); // API endpoint $api_url = "https://app.rapidtextai.com/openai/v1/chat/completions?gigsixkey=" . urlencode($api_key); // Make API request $response = wp_remote_post($api_url, array( 'body' => json_encode($request_data), 'headers' => array( 'Content-Type' => 'application/json', ), 'timeout' => 30, )); if (is_wp_error($response)) { if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: Failed to generate search query: ' . $response->get_error_message()); return false; } $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if (!isset($data['choices'][0]['message']['content'])) { if(!empty($log_settings['enable_logging'])) error_log('RapidTextAI: Invalid response when generating search query'); return false; } $search_query = trim($data['choices'][0]['message']['content']); // Clean up the search query (remove quotes, extra punctuation) $search_query = preg_replace('/["\']/', '', $search_query); $search_query = preg_replace('/[^\w\s-]/', '', $search_query); return $search_query; } // Add a dashboard widget to show auto blogging status add_action('wp_dashboard_setup', 'rapidtextai_add_dashboard_widget'); function rapidtextai_add_dashboard_widget() { wp_add_dashboard_widget( 'rapidtextai_dashboard_widget', 'RapidTextAI Auto Blogging Status', 'rapidtextai_dashboard_widget_content' ); } function rapidtextai_dashboard_widget_content() { $settings = get_option('rapidtextai_auto_blogging', array()); if (empty($settings) || empty($settings['enabled'])) { echo '

    Auto blogging is currently disabled. Enable it here.

    '; return; } $next_run = wp_next_scheduled('rapidtextai_auto_blogging_cron'); echo '

    Status: Enabled

    '; echo '

    Schedule: ' . ucfirst($settings['schedule']) . '

    '; echo '

    Post Status: ' . ucfirst($settings['post_status']) . '

    '; echo '

    Next scheduled run: ' . ($next_run ? date_i18n('F j, Y, g:i a', $next_run) : 'Not scheduled') . '

    '; echo '

    Manage Settings

    '; } // Register activation and deactivation hooks register_activation_hook(__FILE__, 'rapidtextai_activate_auto_blogging'); register_deactivation_hook(__FILE__, 'rapidtextai_deactivate_auto_blogging'); register_deactivation_hook(__FILE__, 'rapidtextai_v2_clear_all_schedules'); function rapidtextai_activate_auto_blogging() { // Run migration rapidtextai_migrate_to_campaigns(); // Schedule crons for all enabled campaigns $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); foreach ($campaigns as $campaign_id => $campaign) { if (!empty($campaign['enabled'])) { rapidtextai_schedule_campaign_cron($campaign_id, $campaign); } } // Backward compatibility: also check old settings $old_settings = get_option('rapidtextai_auto_blogging', array()); if (!empty($old_settings) && !empty($old_settings['enabled'])) { if (!wp_next_scheduled('rapidtextai_auto_blogging_cron')) { wp_schedule_event(time(), $old_settings['schedule'], 'rapidtextai_auto_blogging_cron'); } } } function rapidtextai_deactivate_auto_blogging() { // Clear all campaign-specific cron jobs $campaigns = get_option('rapidtextai_auto_blogging_campaigns', array()); foreach ($campaigns as $campaign_id => $campaign) { wp_clear_scheduled_hook('rapidtextai_auto_blogging_cron_' . $campaign_id); } // Also clear old cron hook for backward compatibility wp_clear_scheduled_hook('rapidtextai_auto_blogging_cron'); } // Add AJAX handlers for logs functionality add_action('wp_ajax_rapidtextai_get_logs', 'rapidtextai_get_logs_callback'); add_action('wp_ajax_rapidtextai_clear_logs', 'rapidtextai_clear_logs_callback'); function rapidtextai_get_logs_callback() { ini_set('display_errors', 1); ini_set('log_errors', 1); error_reporting(E_ALL); // Verify nonce if (!isset($_GET['nonce']) || !wp_verify_nonce($_GET['nonce'], 'rapidtextai_get_logs_nonce')) { wp_send_json_error(array('message' => 'Security check failed.')); return; } // Check user permissions if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => 'Permission denied.')); return; } $logs = rapidtextai_read_error_logs(); wp_send_json_success(array('logs' => $logs)); } // AJAX handler for getting usage data add_action('wp_ajax_rapidtextai_get_usage_data', 'rapidtextai_get_usage_data_callback'); function rapidtextai_get_usage_data_callback() { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'rapidtextai_nonce')) { wp_send_json_error(array('message' => 'Security check failed.')); return; } // Get API key $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { wp_send_json_error(array('message' => 'API key not found. Please set up your RapidTextAI authentication.')); return; } // Call the usage API endpoint $api_url = 'https://app.rapidtextai.com/api?gigsixkey=' . urlencode($api_key); $response = wp_remote_get($api_url, array( 'timeout' => 30, 'sslverify' => false, )); if (is_wp_error($response)) { wp_send_json_error(array('message' => 'Error connecting to RapidTextAI: ' . $response->get_error_message())); return; } $http_code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); if ($http_code !== 200) { wp_send_json_error(array('message' => 'API request failed with code ' . $http_code)); return; } // Decode the response $usage_data = json_decode($body, true); if (!$usage_data) { wp_send_json_error(array('message' => 'Invalid response from API')); return; } wp_send_json_success($usage_data); } function rapidtextai_clear_logs_callback() { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'rapidtextai_clear_logs_nonce')) { wp_send_json_error(array('message' => 'Security check failed.')); return; } // Check user permissions if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => 'Permission denied.')); return; } $cleared = rapidtextai_clear_error_logs(); if ($cleared) { wp_send_json_success(array('message' => 'Logs cleared successfully.')); } else { wp_send_json_error(array('message' => 'Failed to clear logs.')); } } function rapidtextai_read_error_logs() { $logs = array(); // Get PHP error log file path $log_file = ini_get('error_log'); // If not set, try default locations if (empty($log_file) || !file_exists($log_file)) { $possible_paths = array( ABSPATH . 'wp-content/debug.log', ABSPATH . 'error_log', WP_CONTENT_DIR . '/debug.log', '/var/log/php_errors.log', '/var/log/apache2/error.log', $_SERVER['DOCUMENT_ROOT'] . '/logs/php_error.log' ); foreach ($possible_paths as $path) { if (file_exists($path)) { $log_file = $path; break; } } } if (!empty($log_file) && file_exists($log_file) && is_readable($log_file)) { // Check file size first $file_size = filesize($log_file); $max_size = 50 * 1024 * 1024; // 50MB limit if ($file_size > $max_size) { // For large files, read from the end $handle = fopen($log_file, 'r'); if ($handle) { // Seek to near the end of file fseek($handle, max(0, $file_size - $max_size)); // Skip the first incomplete line fgets($handle); while (($line = fgets($handle)) !== false) { if (strpos($line, 'RapidTextAI:') !== false) { $log_entry = rapidtextai_parse_log_line($line); if ($log_entry) { $logs[] = $log_entry; } } } fclose($handle); } } else { // For smaller files, use the original method $file_content = file_get_contents($log_file); $lines = explode("\n", $file_content); foreach ($lines as $line) { if (strpos($line, 'RapidTextAI:') !== false) { $log_entry = rapidtextai_parse_log_line($line); if ($log_entry) { $logs[] = $log_entry; } } } } // Reverse to show newest first $logs = array_reverse($logs); // Limit to last 100 entries $logs = array_slice($logs, 0, 100); } return $logs; } function rapidtextai_parse_log_line($line) { // Parse typical PHP error log format: [timestamp] message $pattern = '/^\[([^\]]+)\].*?RapidTextAI:\s*(.+)$/'; if (preg_match($pattern, $line, $matches)) { $timestamp = $matches[1]; $message = trim($matches[2]); // Determine log level based on message content $level = 'info'; if (stripos($message, 'error') !== false || stripos($message, 'failed') !== false) { $level = 'error'; } elseif (stripos($message, 'warning') !== false || stripos($message, 'warn') !== false) { $level = 'warning'; } elseif (stripos($message, 'success') !== false) { $level = 'success'; } return array( 'timestamp' => $timestamp, 'message' => $message, 'level' => $level ); } return null; } function rapidtextai_clear_error_logs() { // Get PHP error log file path $log_file = ini_get('error_log'); // If not set, try default locations if (empty($log_file) || !file_exists($log_file)) { $possible_paths = array( ABSPATH . 'wp-content/debug.log', ABSPATH . 'error_log', WP_CONTENT_DIR . '/debug.log' ); foreach ($possible_paths as $path) { if (file_exists($path)) { $log_file = $path; break; } } } if (!empty($log_file) && file_exists($log_file) && is_writable($log_file)) { // Read current log content $content = file_get_contents($log_file); $lines = explode("\n", $content); // Filter out RapidTextAI logs $filtered_lines = array(); foreach ($lines as $line) { if (strpos($line, 'RapidTextAI:') === false) { $filtered_lines[] = $line; } } // Write back the filtered content $filtered_content = implode("\n", $filtered_lines); return file_put_contents($log_file, $filtered_content) !== false; } return false; } /** * Deactivation Feedback — asks user for reason when deactivating the plugin. */ add_action('admin_enqueue_scripts', 'rapidtextai_enqueue_deactivate_feedback'); function rapidtextai_enqueue_deactivate_feedback($hook) { if ($hook !== 'plugins.php') return; wp_enqueue_style( 'rapidtextai-deactivate-feedback', RAPIDTEXTAI_PLUGIN_URL . 'assets/css/deactivate-feedback.css', array(), '4.2.0' ); wp_enqueue_script( 'rapidtextai-deactivate-feedback', RAPIDTEXTAI_PLUGIN_URL . 'assets/js/deactivate-feedback.js', array('jquery'), '4.2.0', true ); wp_localize_script('rapidtextai-deactivate-feedback', 'rapidtextai_deactivate', array( 'ajaxurl' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('rapidtextai_deactivate_feedback'), )); } add_action('wp_ajax_rapidtextai_deactivate_feedback', 'rapidtextai_deactivate_feedback_handler'); function rapidtextai_deactivate_feedback_handler() { if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'rapidtextai_deactivate_feedback')) { wp_send_json_error(array('message' => 'Security check failed.')); } $reason = isset($_POST['reason']) ? sanitize_text_field($_POST['reason']) : 'unspecified'; $user_message = isset($_POST['user_message']) ? sanitize_textarea_field($_POST['user_message']) : $reason; $api_key = get_option('rapidtextai_api_key', ''); if (empty($api_key)) { $api_key = '0'; } $report_url = 'https://app.rapidtextai.com/api'; $report_url = add_query_arg(array( 'gigsixkey' => urlencode($api_key), 'action' => 'report', 'message' => urlencode('[Plugin Deactivation] Reason: ' . $reason), 'user_message' => urlencode($user_message), ), $report_url); $response = wp_remote_get($report_url, array( 'timeout' => 10, 'sslverify' => false, )); if (is_wp_error($response)) { wp_send_json_success(array('message' => 'Feedback recorded locally (API unreachable).')); } wp_send_json_success(array('message' => 'Feedback sent. Thank you!')); }