Changeset 3462401
- Timestamp:
- 02/16/2026 10:44:24 AM (6 weeks ago)
- Location:
- clearpost-simple-ai-auto-post
- Files:
-
- 10 edited
- 1 copied
-
tags/2.0.10 (copied) (copied from clearpost-simple-ai-auto-post/trunk)
-
tags/2.0.10/includes/cron-trigger.php (modified) (3 diffs)
-
tags/2.0.10/includes/scheduler.php (modified) (5 diffs)
-
tags/2.0.10/includes/trial.php (modified) (7 diffs)
-
tags/2.0.10/readme.txt (modified) (1 diff)
-
tags/2.0.10/simple-ai-auto-post.php (modified) (2 diffs)
-
trunk/includes/cron-trigger.php (modified) (3 diffs)
-
trunk/includes/scheduler.php (modified) (5 diffs)
-
trunk/includes/trial.php (modified) (7 diffs)
-
trunk/readme.txt (modified) (1 diff)
-
trunk/simple-ai-auto-post.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
clearpost-simple-ai-auto-post/tags/2.0.10/includes/cron-trigger.php
r3460182 r3462401 95 95 } 96 96 97 // Check our specific event's status BEFORE running cron. 98 $saiap_event_before = saiap_get_scheduler_event_info(); 99 97 100 // Run cron - this executes due events directly. 98 101 wp_cron(); … … 110 113 } 111 114 115 // Check our specific event's status AFTER running cron. 116 $saiap_event_after = saiap_get_scheduler_event_info(); 117 112 118 $events_processed = max( 0, $due_before - $due_after ); 119 120 // Determine if our event ran by comparing timestamps. 121 $saiap_event_ran = false; 122 if ( $saiap_event_before['exists'] && $saiap_event_after['exists'] ) { 123 // If timestamp changed, the event ran and was rescheduled. 124 $saiap_event_ran = ( $saiap_event_before['next_run_utc'] !== $saiap_event_after['next_run_utc'] ); 125 } 113 126 114 127 return rest_ensure_response( … … 119 132 'events_remaining' => $due_after, 120 133 'timestamp' => $now, 134 'saiap_scheduler' => array( 135 'event_exists' => $saiap_event_after['exists'], 136 'event_ran' => $saiap_event_ran, 137 'next_run_utc' => $saiap_event_after['next_run_utc'], 138 'next_run_local' => $saiap_event_after['next_run_local'], 139 'seconds_until' => $saiap_event_after['seconds_until'], 140 'was_due' => $saiap_event_before['was_due'], 141 'timezone' => $saiap_event_after['timezone'], 142 ), 121 143 ) 122 144 ); 123 145 } 146 147 /** 148 * Get detailed info about the scheduler event. 149 * 150 * @return array Event information. 151 */ 152 function saiap_get_scheduler_event_info() { 153 $next_scheduled = wp_next_scheduled( 'saiap_generate_scheduled_post' ); 154 $now = time(); 155 $timezone = wp_timezone_string(); 156 157 if ( false === $next_scheduled ) { 158 return array( 159 'exists' => false, 160 'next_run_utc' => null, 161 'next_run_local' => null, 162 'seconds_until' => null, 163 'was_due' => false, 164 'timezone' => $timezone, 165 ); 166 } 167 168 // Convert to local time for display. 169 $dt_utc = new DateTime( '@' . $next_scheduled ); 170 $dt_local = new DateTime( '@' . $next_scheduled ); 171 $dt_local->setTimezone( new DateTimeZone( $timezone ) ); 172 173 return array( 174 'exists' => true, 175 'next_run_utc' => $dt_utc->format( 'Y-m-d H:i:s' ) . ' UTC', 176 'next_run_local' => $dt_local->format( 'Y-m-d H:i:s' ) . ' ' . $timezone, 177 'seconds_until' => $next_scheduled - $now, 178 'was_due' => ( $next_scheduled <= $now ), 179 'timezone' => $timezone, 180 ); 181 } -
clearpost-simple-ai-auto-post/tags/2.0.10/includes/scheduler.php
r3455493 r3462401 485 485 $license_key = get_option( 'saiap_license_key' ); 486 486 $domain = saiap_get_server_host(); 487 $run_id = wp_generate_uuid4(); 488 $start_time = microtime( true ); 489 490 // Report scheduler start to premium backend. 491 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 492 'event' => 'scheduler_started', 493 'run_id' => $run_id, 494 'php_version' => PHP_VERSION, 495 'wp_version' => get_bloginfo( 'version' ), 496 'memory_limit' => ini_get( 'memory_limit' ), 497 'max_execution_time' => ini_get( 'max_execution_time' ), 498 ) ); 487 499 488 500 // 1. Fetch today's scheduled prompts … … 497 509 $response = wp_remote_get( $url, array( 'timeout' => 15 ) ); 498 510 499 if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) { 500 // Exit if unable to fetch scheduled prompts 511 if ( is_wp_error( $response ) ) { 512 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 513 'event' => 'scheduler_error', 514 'run_id' => $run_id, 515 'error' => 'fetch_failed', 516 'message' => $response->get_error_message(), 517 'duration_ms' => round( ( microtime( true ) - $start_time ) * 1000 ), 518 ) ); 519 return; 520 } 521 522 $status_code = wp_remote_retrieve_response_code( $response ); 523 if ( 200 !== $status_code ) { 524 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 525 'event' => 'scheduler_error', 526 'run_id' => $run_id, 527 'error' => 'fetch_non_200', 528 'status_code' => $status_code, 529 'body' => substr( wp_remote_retrieve_body( $response ), 0, 500 ), 530 'duration_ms' => round( ( microtime( true ) - $start_time ) * 1000 ), 531 ) ); 501 532 return; 502 533 } … … 504 535 $prompts = json_decode( wp_remote_retrieve_body( $response ), true ); 505 536 if ( empty( $prompts['prompts'] ) ) { 537 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 538 'event' => 'scheduler_completed', 539 'run_id' => $run_id, 540 'prompts_found' => 0, 541 'posts_generated' => 0, 542 'posts_failed' => 0, 543 'duration_ms' => round( ( microtime( true ) - $start_time ) * 1000 ), 544 ) ); 506 545 return; 507 546 } 547 548 // Track results for heartbeat. 549 $posts_generated = 0; 550 $posts_failed = 0; 551 $prompt_count = count( $prompts['prompts'] ); 508 552 509 553 // 2. Loop through prompts and generate posts … … 642 686 } 643 687 688 // Track success/failure for heartbeat. 689 if ( 'failed' === $status_to_set ) { 690 $posts_failed++; 691 } else { 692 $posts_generated++; 693 } 694 644 695 // 3. Update the prompt status on the premium service 645 696 $update_url = SAIAP_PREMIUM_API_URL . '/api/prompts/update/' . $prompt['id'] . '/status'; … … 662 713 ) ); 663 714 } 715 716 // Report scheduler completion to premium backend. 717 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 718 'event' => 'scheduler_completed', 719 'run_id' => $run_id, 720 'prompts_found' => $prompt_count, 721 'posts_generated' => $posts_generated, 722 'posts_failed' => $posts_failed, 723 'duration_ms' => round( ( microtime( true ) - $start_time ) * 1000 ), 724 ) ); 664 725 } 665 726 add_action( 'saiap_generate_scheduled_post', 'saiap_do_generate_scheduled_post' ); 727 728 /** 729 * Report scheduler heartbeat to premium backend for diagnostics. 730 * 731 * Fire-and-forget - we don't wait for response or handle errors. 732 * 733 * @param string $domain Site domain. 734 * @param string $license_key License key. 735 * @param array $data Heartbeat data. 736 */ 737 function saiap_report_scheduler_heartbeat( $domain, $license_key, $data ) { 738 $url = SAIAP_PREMIUM_API_URL . '/api/scheduler/heartbeat'; 739 740 $payload = array_merge( 741 array( 742 'domain' => $domain, 743 'license_key' => $license_key, 744 'timestamp' => gmdate( 'c' ), 745 ), 746 $data 747 ); 748 749 // Fire and forget - don't block on response. 750 wp_remote_post( 751 $url, 752 array( 753 'headers' => array( 'Content-Type' => 'application/json' ), 754 'body' => wp_json_encode( $payload ), 755 'timeout' => 5, 756 'blocking' => false, 757 ) 758 ); 759 } 666 760 667 761 /** -
clearpost-simple-ai-auto-post/tags/2.0.10/includes/trial.php
r3460635 r3462401 40 40 } 41 41 42 // Use server-provided expires_at if available. 43 $trial_expires = get_option( 'saiap_trial_expires_at', '' ); 44 if ( ! empty( $trial_expires ) ) { 45 return time() < strtotime( $trial_expires ); 46 } 47 48 // Fallback: calculate from started_at + 7 days (backwards compatibility). 42 49 $trial_started = get_option( 'saiap_trial_started_at', 0 ); 43 50 if ( empty( $trial_started ) ) { … … 110 117 */ 111 118 function saiap_get_trial_expires_at() { 119 // Use server-provided expires_at if available. 120 $trial_expires = get_option( 'saiap_trial_expires_at', '' ); 121 if ( ! empty( $trial_expires ) ) { 122 return $trial_expires; 123 } 124 125 // Fallback: calculate from started_at + 7 days (backwards compatibility). 112 126 $trial_started = get_option( 'saiap_trial_started_at', '' ); 113 127 if ( empty( $trial_started ) ) { … … 179 193 */ 180 194 function saiap_get_user_scenario() { 181 // Check paid status first (license key trumps everything).182 $license_key = get_option( 'saiap_license_key', '' );183 if ( ! empty( $license_key ) ) {184 return 'paid'; // Optimistic - server validates on actual API calls.185 }186 187 195 $trial_status = get_option( 'saiap_trial_status', 'none' ); 188 189 // Check trial status (already updated by saiap_maybe_expire_trial if needed). 196 $license_key = get_option( 'saiap_license_key', '' ); 197 198 // Check trial status FIRST - trial users have license keys for API auth. 199 if ( 'active' === $trial_status ) { 200 return 'active_trial'; 201 } 202 190 203 if ( 'expired' === $trial_status ) { 191 204 return 'expired_trial'; 192 205 } 193 206 194 if ( 'active' === $trial_status ) { 195 // If we get here with 'active' status, trial is still within window. 196 // (saiap_maybe_expire_trial should have been called to update if needed). 197 return 'active_trial'; 198 } 199 200 // No trial started (status is 'none') - check for API keys. 207 // No active/expired trial - license key means paid. 208 if ( ! empty( $license_key ) ) { 209 return 'paid'; 210 } 211 212 // No trial, no license - check for BYOK API keys. 201 213 $has_api_keys = ! empty( get_option( 'saiap_openai_api_key', '' ) ) 202 214 || ! empty( get_option( 'saiap_anthropic_api_key', '' ) ) … … 250 262 } 251 263 252 // On success responses, clear anyerror flags.264 // On success responses, sync trial status and clear error flags. 253 265 if ( isset( $response['isValid'] ) && $response['isValid'] ) { 254 266 delete_option( 'saiap_license_invalid' ); 267 268 // Sync trial data from server response. 269 if ( isset( $response['trial'] ) ) { 270 $trial = $response['trial']; 271 272 // Sync status. 273 if ( isset( $trial['status'] ) ) { 274 $server_status = $trial['status']; 275 if ( 'active' === $server_status ) { 276 update_option( 'saiap_trial_status', 'active' ); 277 } elseif ( 'expired' === $server_status ) { 278 update_option( 'saiap_trial_status', 'expired' ); 279 } elseif ( 'converted' === $server_status ) { 280 // Converted trial = paid user, clear trial status. 281 update_option( 'saiap_trial_status', 'none' ); 282 } 283 } 284 285 // Sync expires_at (server is source of truth for trial end date). 286 if ( isset( $trial['expires_at'] ) ) { 287 update_option( 'saiap_trial_expires_at', $trial['expires_at'] ); 288 } 289 } 255 290 } 256 291 … … 404 439 update_option( 'saiap_trial_status', 'active' ); 405 440 update_option( 'saiap_trial_started_at', $validation['trial']['started_at'] ); 441 if ( isset( $validation['trial']['expires_at'] ) ) { 442 update_option( 'saiap_trial_expires_at', $validation['trial']['expires_at'] ); 443 } 406 444 } 407 445 return array( … … 428 466 update_option( 'saiap_trial_status', 'active' ); 429 467 update_option( 'saiap_trial_started_at', $body['trial']['started_at'] ); 468 if ( isset( $body['trial']['expires_at'] ) ) { 469 update_option( 'saiap_trial_expires_at', $body['trial']['expires_at'] ); 470 } 430 471 } 431 472 … … 606 647 } 607 648 608 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : ''; 649 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : ''; 650 if ( empty( $email ) ) { 651 // Fall back to WordPress admin email if JS didn't provide one. 652 $email = get_option( 'admin_email', '' ); 653 } 609 654 $result = saiap_start_trial( $email ); 610 655 -
clearpost-simple-ai-auto-post/tags/2.0.10/readme.txt
r3460833 r3462401 4 4 Requires at least: 5.0 5 5 Tested up to: 6.9 6 Stable tag: 2.0. 96 Stable tag: 2.0.10 7 7 Requires PHP: 7.2 8 8 License: GPLv2 or later -
clearpost-simple-ai-auto-post/tags/2.0.10/simple-ai-auto-post.php
r3460833 r3462401 4 4 Description: Your AI Agent for SEO, in WordPress. An AI content marketer that knows your site, then schedules and generates posts every day. 5 5 Plugin URI: https://clearpostplugin.com/ 6 Version: 2.0. 96 Version: 2.0.10 7 7 License: GPLv2 or later 8 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 18 18 19 19 // Define plugin version 20 define( 'SAIAP_VERSION', '2.0. 9' );20 define( 'SAIAP_VERSION', '2.0.10' ); 21 21 22 22 // Define premium API URL -
clearpost-simple-ai-auto-post/trunk/includes/cron-trigger.php
r3460182 r3462401 95 95 } 96 96 97 // Check our specific event's status BEFORE running cron. 98 $saiap_event_before = saiap_get_scheduler_event_info(); 99 97 100 // Run cron - this executes due events directly. 98 101 wp_cron(); … … 110 113 } 111 114 115 // Check our specific event's status AFTER running cron. 116 $saiap_event_after = saiap_get_scheduler_event_info(); 117 112 118 $events_processed = max( 0, $due_before - $due_after ); 119 120 // Determine if our event ran by comparing timestamps. 121 $saiap_event_ran = false; 122 if ( $saiap_event_before['exists'] && $saiap_event_after['exists'] ) { 123 // If timestamp changed, the event ran and was rescheduled. 124 $saiap_event_ran = ( $saiap_event_before['next_run_utc'] !== $saiap_event_after['next_run_utc'] ); 125 } 113 126 114 127 return rest_ensure_response( … … 119 132 'events_remaining' => $due_after, 120 133 'timestamp' => $now, 134 'saiap_scheduler' => array( 135 'event_exists' => $saiap_event_after['exists'], 136 'event_ran' => $saiap_event_ran, 137 'next_run_utc' => $saiap_event_after['next_run_utc'], 138 'next_run_local' => $saiap_event_after['next_run_local'], 139 'seconds_until' => $saiap_event_after['seconds_until'], 140 'was_due' => $saiap_event_before['was_due'], 141 'timezone' => $saiap_event_after['timezone'], 142 ), 121 143 ) 122 144 ); 123 145 } 146 147 /** 148 * Get detailed info about the scheduler event. 149 * 150 * @return array Event information. 151 */ 152 function saiap_get_scheduler_event_info() { 153 $next_scheduled = wp_next_scheduled( 'saiap_generate_scheduled_post' ); 154 $now = time(); 155 $timezone = wp_timezone_string(); 156 157 if ( false === $next_scheduled ) { 158 return array( 159 'exists' => false, 160 'next_run_utc' => null, 161 'next_run_local' => null, 162 'seconds_until' => null, 163 'was_due' => false, 164 'timezone' => $timezone, 165 ); 166 } 167 168 // Convert to local time for display. 169 $dt_utc = new DateTime( '@' . $next_scheduled ); 170 $dt_local = new DateTime( '@' . $next_scheduled ); 171 $dt_local->setTimezone( new DateTimeZone( $timezone ) ); 172 173 return array( 174 'exists' => true, 175 'next_run_utc' => $dt_utc->format( 'Y-m-d H:i:s' ) . ' UTC', 176 'next_run_local' => $dt_local->format( 'Y-m-d H:i:s' ) . ' ' . $timezone, 177 'seconds_until' => $next_scheduled - $now, 178 'was_due' => ( $next_scheduled <= $now ), 179 'timezone' => $timezone, 180 ); 181 } -
clearpost-simple-ai-auto-post/trunk/includes/scheduler.php
r3455493 r3462401 485 485 $license_key = get_option( 'saiap_license_key' ); 486 486 $domain = saiap_get_server_host(); 487 $run_id = wp_generate_uuid4(); 488 $start_time = microtime( true ); 489 490 // Report scheduler start to premium backend. 491 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 492 'event' => 'scheduler_started', 493 'run_id' => $run_id, 494 'php_version' => PHP_VERSION, 495 'wp_version' => get_bloginfo( 'version' ), 496 'memory_limit' => ini_get( 'memory_limit' ), 497 'max_execution_time' => ini_get( 'max_execution_time' ), 498 ) ); 487 499 488 500 // 1. Fetch today's scheduled prompts … … 497 509 $response = wp_remote_get( $url, array( 'timeout' => 15 ) ); 498 510 499 if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) { 500 // Exit if unable to fetch scheduled prompts 511 if ( is_wp_error( $response ) ) { 512 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 513 'event' => 'scheduler_error', 514 'run_id' => $run_id, 515 'error' => 'fetch_failed', 516 'message' => $response->get_error_message(), 517 'duration_ms' => round( ( microtime( true ) - $start_time ) * 1000 ), 518 ) ); 519 return; 520 } 521 522 $status_code = wp_remote_retrieve_response_code( $response ); 523 if ( 200 !== $status_code ) { 524 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 525 'event' => 'scheduler_error', 526 'run_id' => $run_id, 527 'error' => 'fetch_non_200', 528 'status_code' => $status_code, 529 'body' => substr( wp_remote_retrieve_body( $response ), 0, 500 ), 530 'duration_ms' => round( ( microtime( true ) - $start_time ) * 1000 ), 531 ) ); 501 532 return; 502 533 } … … 504 535 $prompts = json_decode( wp_remote_retrieve_body( $response ), true ); 505 536 if ( empty( $prompts['prompts'] ) ) { 537 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 538 'event' => 'scheduler_completed', 539 'run_id' => $run_id, 540 'prompts_found' => 0, 541 'posts_generated' => 0, 542 'posts_failed' => 0, 543 'duration_ms' => round( ( microtime( true ) - $start_time ) * 1000 ), 544 ) ); 506 545 return; 507 546 } 547 548 // Track results for heartbeat. 549 $posts_generated = 0; 550 $posts_failed = 0; 551 $prompt_count = count( $prompts['prompts'] ); 508 552 509 553 // 2. Loop through prompts and generate posts … … 642 686 } 643 687 688 // Track success/failure for heartbeat. 689 if ( 'failed' === $status_to_set ) { 690 $posts_failed++; 691 } else { 692 $posts_generated++; 693 } 694 644 695 // 3. Update the prompt status on the premium service 645 696 $update_url = SAIAP_PREMIUM_API_URL . '/api/prompts/update/' . $prompt['id'] . '/status'; … … 662 713 ) ); 663 714 } 715 716 // Report scheduler completion to premium backend. 717 saiap_report_scheduler_heartbeat( $domain, $license_key, array( 718 'event' => 'scheduler_completed', 719 'run_id' => $run_id, 720 'prompts_found' => $prompt_count, 721 'posts_generated' => $posts_generated, 722 'posts_failed' => $posts_failed, 723 'duration_ms' => round( ( microtime( true ) - $start_time ) * 1000 ), 724 ) ); 664 725 } 665 726 add_action( 'saiap_generate_scheduled_post', 'saiap_do_generate_scheduled_post' ); 727 728 /** 729 * Report scheduler heartbeat to premium backend for diagnostics. 730 * 731 * Fire-and-forget - we don't wait for response or handle errors. 732 * 733 * @param string $domain Site domain. 734 * @param string $license_key License key. 735 * @param array $data Heartbeat data. 736 */ 737 function saiap_report_scheduler_heartbeat( $domain, $license_key, $data ) { 738 $url = SAIAP_PREMIUM_API_URL . '/api/scheduler/heartbeat'; 739 740 $payload = array_merge( 741 array( 742 'domain' => $domain, 743 'license_key' => $license_key, 744 'timestamp' => gmdate( 'c' ), 745 ), 746 $data 747 ); 748 749 // Fire and forget - don't block on response. 750 wp_remote_post( 751 $url, 752 array( 753 'headers' => array( 'Content-Type' => 'application/json' ), 754 'body' => wp_json_encode( $payload ), 755 'timeout' => 5, 756 'blocking' => false, 757 ) 758 ); 759 } 666 760 667 761 /** -
clearpost-simple-ai-auto-post/trunk/includes/trial.php
r3460635 r3462401 40 40 } 41 41 42 // Use server-provided expires_at if available. 43 $trial_expires = get_option( 'saiap_trial_expires_at', '' ); 44 if ( ! empty( $trial_expires ) ) { 45 return time() < strtotime( $trial_expires ); 46 } 47 48 // Fallback: calculate from started_at + 7 days (backwards compatibility). 42 49 $trial_started = get_option( 'saiap_trial_started_at', 0 ); 43 50 if ( empty( $trial_started ) ) { … … 110 117 */ 111 118 function saiap_get_trial_expires_at() { 119 // Use server-provided expires_at if available. 120 $trial_expires = get_option( 'saiap_trial_expires_at', '' ); 121 if ( ! empty( $trial_expires ) ) { 122 return $trial_expires; 123 } 124 125 // Fallback: calculate from started_at + 7 days (backwards compatibility). 112 126 $trial_started = get_option( 'saiap_trial_started_at', '' ); 113 127 if ( empty( $trial_started ) ) { … … 179 193 */ 180 194 function saiap_get_user_scenario() { 181 // Check paid status first (license key trumps everything).182 $license_key = get_option( 'saiap_license_key', '' );183 if ( ! empty( $license_key ) ) {184 return 'paid'; // Optimistic - server validates on actual API calls.185 }186 187 195 $trial_status = get_option( 'saiap_trial_status', 'none' ); 188 189 // Check trial status (already updated by saiap_maybe_expire_trial if needed). 196 $license_key = get_option( 'saiap_license_key', '' ); 197 198 // Check trial status FIRST - trial users have license keys for API auth. 199 if ( 'active' === $trial_status ) { 200 return 'active_trial'; 201 } 202 190 203 if ( 'expired' === $trial_status ) { 191 204 return 'expired_trial'; 192 205 } 193 206 194 if ( 'active' === $trial_status ) { 195 // If we get here with 'active' status, trial is still within window. 196 // (saiap_maybe_expire_trial should have been called to update if needed). 197 return 'active_trial'; 198 } 199 200 // No trial started (status is 'none') - check for API keys. 207 // No active/expired trial - license key means paid. 208 if ( ! empty( $license_key ) ) { 209 return 'paid'; 210 } 211 212 // No trial, no license - check for BYOK API keys. 201 213 $has_api_keys = ! empty( get_option( 'saiap_openai_api_key', '' ) ) 202 214 || ! empty( get_option( 'saiap_anthropic_api_key', '' ) ) … … 250 262 } 251 263 252 // On success responses, clear anyerror flags.264 // On success responses, sync trial status and clear error flags. 253 265 if ( isset( $response['isValid'] ) && $response['isValid'] ) { 254 266 delete_option( 'saiap_license_invalid' ); 267 268 // Sync trial data from server response. 269 if ( isset( $response['trial'] ) ) { 270 $trial = $response['trial']; 271 272 // Sync status. 273 if ( isset( $trial['status'] ) ) { 274 $server_status = $trial['status']; 275 if ( 'active' === $server_status ) { 276 update_option( 'saiap_trial_status', 'active' ); 277 } elseif ( 'expired' === $server_status ) { 278 update_option( 'saiap_trial_status', 'expired' ); 279 } elseif ( 'converted' === $server_status ) { 280 // Converted trial = paid user, clear trial status. 281 update_option( 'saiap_trial_status', 'none' ); 282 } 283 } 284 285 // Sync expires_at (server is source of truth for trial end date). 286 if ( isset( $trial['expires_at'] ) ) { 287 update_option( 'saiap_trial_expires_at', $trial['expires_at'] ); 288 } 289 } 255 290 } 256 291 … … 404 439 update_option( 'saiap_trial_status', 'active' ); 405 440 update_option( 'saiap_trial_started_at', $validation['trial']['started_at'] ); 441 if ( isset( $validation['trial']['expires_at'] ) ) { 442 update_option( 'saiap_trial_expires_at', $validation['trial']['expires_at'] ); 443 } 406 444 } 407 445 return array( … … 428 466 update_option( 'saiap_trial_status', 'active' ); 429 467 update_option( 'saiap_trial_started_at', $body['trial']['started_at'] ); 468 if ( isset( $body['trial']['expires_at'] ) ) { 469 update_option( 'saiap_trial_expires_at', $body['trial']['expires_at'] ); 470 } 430 471 } 431 472 … … 606 647 } 607 648 608 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : ''; 649 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : ''; 650 if ( empty( $email ) ) { 651 // Fall back to WordPress admin email if JS didn't provide one. 652 $email = get_option( 'admin_email', '' ); 653 } 609 654 $result = saiap_start_trial( $email ); 610 655 -
clearpost-simple-ai-auto-post/trunk/readme.txt
r3460833 r3462401 4 4 Requires at least: 5.0 5 5 Tested up to: 6.9 6 Stable tag: 2.0. 96 Stable tag: 2.0.10 7 7 Requires PHP: 7.2 8 8 License: GPLv2 or later -
clearpost-simple-ai-auto-post/trunk/simple-ai-auto-post.php
r3460833 r3462401 4 4 Description: Your AI Agent for SEO, in WordPress. An AI content marketer that knows your site, then schedules and generates posts every day. 5 5 Plugin URI: https://clearpostplugin.com/ 6 Version: 2.0. 96 Version: 2.0.10 7 7 License: GPLv2 or later 8 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 18 18 19 19 // Define plugin version 20 define( 'SAIAP_VERSION', '2.0. 9' );20 define( 'SAIAP_VERSION', '2.0.10' ); 21 21 22 22 // Define premium API URL
Note: See TracChangeset
for help on using the changeset viewer.