Changeset 3447263
- Timestamp:
- 01/26/2026 05:16:34 PM (2 months ago)
- Location:
- salon-booking-system/trunk
- Files:
-
- 3 added
- 6 edited
-
js/admin/deactivation-survey.js (added)
-
readme.txt (modified) (2 diffs)
-
salon.php (modified) (4 diffs)
-
src/SLN/Action/Init.php (modified) (2 diffs)
-
src/SLN/Admin/DeactivationSurvey.php (added)
-
src/SLN/Metabox/Abstract.php (modified) (1 diff)
-
src/SLN/Wrapper/Abstract.php (modified) (6 diffs)
-
src/SLN/Wrapper/Booking.php (modified) (3 diffs)
-
views/admin/deactivation-survey-modal.php (added)
Legend:
- Unmodified
- Added
- Removed
-
salon-booking-system/trunk/readme.txt
r3446244 r3447263 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4.8 7 Stable tag: 10.30.1 27 Stable tag: 10.30.13 8 8 License: GPLv2 or later 9 9 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 409 409 == Changelog == 410 410 411 26.01.2026 - 10.30.13 412 413 * Minor fixes implemented 414 411 415 24.01.2026 - 10.30.12 412 416 -
salon-booking-system/trunk/salon.php
r3446244 r3447263 4 4 Plugin Name: Salon Booking System - Free Version 5 5 Description: Let your customers book you services through your website. Perfect for hairdressing salons, barber shops and beauty centers. 6 Version: 10.30.1 26 Version: 10.30.13 7 7 Plugin URI: http://salonbookingsystem.com/ 8 8 Author: Salon Booking System … … 46 46 define('SLN_PLUGIN_DIR', untrailingslashit(dirname(__FILE__))); 47 47 define('SLN_PLUGIN_URL', untrailingslashit(plugins_url('', __FILE__))); 48 define('SLN_VERSION', '10.30.1 2');48 define('SLN_VERSION', '10.30.13'); 49 49 define('SLN_STORE_URL', 'https://salonbookingsystem.com'); 50 50 define('SLN_AUTHOR', 'Salon Booking'); … … 250 250 251 251 register_activation_hook(__FILE__, function () { 252 // Record activation time for churn analysis 253 if (!get_option('sln_activation_time')) { 254 update_option('sln_activation_time', current_time('timestamp')); 255 } 256 252 257 // Track activation to salonbookingsystem.com 253 258 wp_remote_post('https://www.salonbookingsystem.com/wp-json/sbs-tracker/v1/activation', array( … … 267 272 268 273 register_deactivation_hook(__FILE__, function () { 269 // Track deactivation to salonbookingsystem.com 274 // Track deactivation to salonbookingsystem.com with survey data 270 275 try { 276 // Get survey data if available (set by AJAX handler) 277 $survey_data = get_transient('sln_deactivation_survey_data'); 278 279 // Calculate activation metrics 280 $activation_time = get_option('sln_activation_time', current_time('timestamp')); 281 $days_active = floor((current_time('timestamp') - $activation_time) / DAY_IN_SECONDS); 282 283 // Prepare payload 284 $payload = array( 285 'version' => defined('SLN_VERSION_PAY') && SLN_VERSION_PAY ? 'pro' : 'free', 286 'plugin_version' => SLN_VERSION, 287 'site_hash' => hash('sha256', home_url()), 288 'days_active' => intval($days_active) 289 ); 290 291 // Add survey data if available 292 if ($survey_data) { 293 $payload['deactivation_reason'] = isset($survey_data['reason']) ? $survey_data['reason'] : 'skipped'; 294 $payload['deactivation_feedback'] = isset($survey_data['feedback']) ? $survey_data['feedback'] : ''; 295 $payload['deactivation_rating'] = isset($survey_data['rating']) ? intval($survey_data['rating']) : 0; 296 $payload['setup_progress'] = isset($survey_data['setup_progress']) ? intval($survey_data['setup_progress']) : 0; 297 $payload['completed_first_booking'] = isset($survey_data['completed_first_booking']) ? (bool) $survey_data['completed_first_booking'] : false; 298 } else { 299 // No survey data - user skipped 300 $payload['deactivation_reason'] = 'skipped'; 301 $payload['deactivation_feedback'] = ''; 302 $payload['deactivation_rating'] = 0; 303 $payload['setup_progress'] = 0; 304 $payload['completed_first_booking'] = false; 305 } 306 271 307 wp_remote_post('https://www.salonbookingsystem.com/wp-json/sbs-tracker/v1/deactivation', array( 272 308 'blocking' => false, 273 309 'timeout' => 2, 274 310 'sslverify' => true, 275 'body' => array( 276 'version' => defined('SLN_VERSION_PAY') && SLN_VERSION_PAY ? 'pro' : 'free', 277 'plugin_version' => SLN_VERSION, 278 'site_hash' => hash('sha256', home_url()) 279 ) 311 'body' => $payload 280 312 )); 313 314 // Clean up transient 315 delete_transient('sln_deactivation_survey_data'); 316 281 317 } catch (Error $e) { 282 318 // Fail silently - don't break deactivation -
salon-booking-system/trunk/src/SLN/Action/Init.php
r3446244 r3447263 43 43 $p = $this->plugin; 44 44 if(!defined("SLN_VERSION_CODECANYON") && defined("SLN_VERSION_PAY") && SLN_VERSION_PAY ) { $this->initLicense(); } 45 46 // CRITICAL DEBUG: Log ALL booking status transitions to catch status reversion 47 // Only logs when plugin debug mode is enabled (respects sln_debug_enabled option) 48 add_action('transition_post_status', function($new_status, $old_status, $post) { 49 if ($post->post_type === SLN_Plugin::POST_TYPE_BOOKING) { 50 // Get the call stack to see what's triggering the status change 51 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10); 52 $caller_info = array(); 53 foreach ($backtrace as $i => $trace) { 54 if (isset($trace['file']) && isset($trace['line'])) { 55 $caller_info[] = basename($trace['file']) . ':' . $trace['line']; 56 } 57 } 58 59 $context_flags = array(); 60 if (defined('DOING_AJAX') && DOING_AJAX) $context_flags[] = 'AJAX'; 61 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) $context_flags[] = 'AUTOSAVE'; 62 if (defined('DOING_CRON') && DOING_CRON) $context_flags[] = 'CRON'; 63 $context = !empty($context_flags) ? ' [' . implode(',', $context_flags) . ']' : ''; 64 65 // Use plugin's standard logging (respects debug mode setting) 66 SLN_Plugin::addLog(sprintf( 67 'BOOKING STATUS TRANSITION: #%d: %s → %s%s | Caller: %s', 68 $post->ID, 69 $old_status, 70 $new_status, 71 $context, 72 implode(' → ', array_slice($caller_info, 0, 3)) 73 )); 74 } 75 }, 10, 3); 45 76 46 77 … … 98 129 new SLN_Admin_Reports($p); 99 130 new SLN_Admin_Settings($p); 131 new SLN_Admin_DeactivationSurvey($p); 100 132 101 133 // Cache Warmer Setup Notice -
salon-booking-system/trunk/src/SLN/Metabox/Abstract.php
r3185641 r3447263 80 80 public function wp_insert_post_data($data, $postarr) 81 81 { 82 // CRITICAL FIX: Prevent paid bookings from being reverted to auto-draft 83 // This happens when WordPress auto-save tries to restore cached status 84 if (isset($postarr['ID']) && $postarr['ID'] > 0) { 85 $post = get_post($postarr['ID']); 86 87 if ($post && $post->post_type === SLN_Plugin::POST_TYPE_BOOKING) { 88 $current_status = get_post_status($postarr['ID']); 89 $new_status = isset($data['post_status']) ? $data['post_status'] : ''; 90 91 // If booking is currently paid/confirmed, don't allow reverting to auto-draft/draft 92 if (in_array($current_status, ['sln-b-paid', 'sln-b-confirmed'])) { 93 if (in_array($new_status, ['auto-draft', 'draft'])) { 94 // Log this attempted reversion (only when debug mode enabled) 95 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5); 96 $caller = isset($backtrace[1]) ? basename($backtrace[1]['file'] ?? 'unknown') . ':' . ($backtrace[1]['line'] ?? '?') : 'unknown'; 97 98 $context_flags = array(); 99 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) $context_flags[] = 'AUTOSAVE'; 100 if (defined('DOING_AJAX') && DOING_AJAX) $context_flags[] = 'AJAX'; 101 $context = !empty($context_flags) ? ' [' . implode(',', $context_flags) . ']' : ''; 102 103 // Use plugin's standard logging (respects sln_debug_enabled option) 104 SLN_Plugin::addLog(sprintf( 105 '🛑 BLOCKED STATUS REVERSION! Booking #%d: %s → %s (attempted)%s | Caller: %s', 106 $postarr['ID'], 107 $current_status, 108 $new_status, 109 $context, 110 $caller 111 )); 112 113 // Keep the current paid status instead 114 $data['post_status'] = $current_status; 115 } 116 } 117 } 118 } 119 82 120 return $data; 83 121 } -
salon-booking-system/trunk/src/SLN/Wrapper/Abstract.php
r3437523 r3447263 87 87 public function setStatus($status) 88 88 { 89 // #region agent log89 // Debug logging (only when debug mode enabled) 90 90 $currentStatusBeforeCheck = $this->object->post_status; 91 91 $postObject = get_post($this->getId()); 92 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Abstract.php:89','message'=>'setStatus() ENTRY','data'=>['booking_id'=>$this->getId(),'target_status'=>$status,'current_status_from_object'=>$currentStatusBeforeCheck,'current_status_from_db'=>($postObject ? $postObject->post_status : 'null'),'post_date_from_db'=>($postObject ? $postObject->post_date : 'null'),'post_date_gmt_from_db'=>($postObject ? $postObject->post_date_gmt : 'null')],'sessionId'=>'debug-session','hypothesisId'=>'B,C']) . "\n", FILE_APPEND); 93 // #endregion 92 SLN_Plugin::addLog(sprintf( 93 'setStatus() called for Booking #%d: %s → %s | DB status: %s, post_date_gmt: %s', 94 $this->getId(), 95 $currentStatusBeforeCheck, 96 $status, 97 $postObject ? $postObject->post_status : 'null', 98 $postObject ? $postObject->post_date_gmt : 'null' 99 )); 94 100 95 101 $post = array(); … … 108 114 $post['post_date_gmt'] = $now_gmt; 109 115 110 // #region agent log 111 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Abstract.php:104','message'=>'AUTO-DRAFT FIX TRIGGERED','data'=>['booking_id'=>$this->getId(),'current_status'=>$currentStatus,'target_status'=>$status,'post_date_set'=>$now,'post_date_gmt_set'=>$now_gmt],'sessionId'=>'debug-session','hypothesisId'=>'B']) . "\n", FILE_APPEND); 112 // #endregion 116 // Debug logging (only when debug mode enabled) 117 SLN_Plugin::addLog(sprintf( 118 'AUTO-DRAFT FIX TRIGGERED for Booking #%d: Setting post_date=%s, post_date_gmt=%s', 119 $this->getId(), 120 $now, 121 $now_gmt 122 )); 113 123 114 124 // Log the transition for debugging … … 121 131 )); 122 132 } 123 } else { 124 // #region agent log 125 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Abstract.php:113','message'=>'AUTO-DRAFT FIX NOT TRIGGERED','data'=>['booking_id'=>$this->getId(),'current_status'=>$currentStatus,'target_status'=>$status,'condition_check'=>'currentStatus='.$currentStatus.' === auto-draft? '.($currentStatus === 'auto-draft' ? 'YES' : 'NO')],'sessionId'=>'debug-session','hypothesisId'=>'B']) . "\n", FILE_APPEND); 126 // #endregion 127 } 128 129 // #region agent log 130 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Abstract.php:116','message'=>'BEFORE wp_update_post()','data'=>['booking_id'=>$this->getId(),'post_array'=>$post],'sessionId'=>'debug-session','hypothesisId'=>'C']) . "\n", FILE_APPEND); 131 // #endregion 133 } 132 134 133 135 $result = wp_update_post($post); 134 135 // #region agent log136 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Abstract.php:120','message'=>'AFTER wp_update_post()','data'=>['booking_id'=>$this->getId(),'wp_update_post_result'=>$result,'is_wp_error'=>is_wp_error($result),'result_is_zero'=>($result === 0),'status_from_db_after'=>get_post_status($this->getId())],'sessionId'=>'debug-session','hypothesisId'=>'C']) . "\n", FILE_APPEND);137 // #endregion138 136 139 137 // CRITICAL: If wp_update_post fails, use direct database update as fallback … … 151 149 } 152 150 153 // #region agent log154 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Abstract.php:145','message'=>'wp_update_post FAILED - attempting direct DB update','data'=>['booking_id'=>$this->getId(),'wp_error'=>is_wp_error($result),'result'=>$result],'sessionId'=>'debug-session','hypothesisId'=>'D']) . "\n", FILE_APPEND);155 // #endregion156 157 151 // Attempt direct database update as fallback 158 152 global $wpdb; … … 176 170 array('%d') 177 171 ); 178 179 // #region agent log180 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Abstract.php:170','message'=>'Direct DB update result','data'=>['booking_id'=>$this->getId(),'wpdb_result'=>$directResult,'wpdb_last_error'=>$wpdb->last_error,'status_from_db_after'=>get_post_status($this->getId())],'sessionId'=>'debug-session','hypothesisId'=>'D']) . "\n", FILE_APPEND);181 // #endregion182 172 183 173 if ($directResult !== false) { … … 205 195 )); 206 196 } 207 208 // #region agent log209 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Abstract.php:200','message'=>'CRITICAL: Both update methods failed','data'=>['booking_id'=>$this->getId(),'wpdb_last_error'=>$wpdb->last_error],'sessionId'=>'debug-session','hypothesisId'=>'D']) . "\n", FILE_APPEND);210 // #endregion211 197 } 212 198 } -
salon-booking-system/trunk/src/SLN/Wrapper/Booking.php
r3446244 r3447263 551 551 public function markPaid($transactionId, $remainedAmount = 0) 552 552 { 553 // #region agent log 554 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Booking.php:495','message'=>'markPaid() ENTRY','data'=>['booking_id'=>$this->getId(),'current_status'=>$this->getStatus(),'transaction_id'=>$transactionId,'remained_amount'=>$remainedAmount],'sessionId'=>'debug-session','hypothesisId'=>'A']) . "\n", FILE_APPEND); 555 // #endregion 553 // Debug logging (only when debug mode enabled) 554 SLN_Plugin::addLog(sprintf( 555 'markPaid() called for Booking #%d: current_status=%s, transaction_id=%s', 556 $this->getId(), 557 $this->getStatus(), 558 $transactionId 559 )); 556 560 557 561 $transactions = $this->getTransactionId(); … … 586 590 } 587 591 588 // #region agent log589 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Booking.php:505','message'=>'BEFORE setStatus(PAID)','data'=>['booking_id'=>$this->getId(),'current_status'=>$this->getStatus(),'target_status'=>SLN_Enum_BookingStatus::PAID],'sessionId'=>'debug-session','hypothesisId'=>'A']) . "\n", FILE_APPEND);590 // #endregion591 592 592 // Only change status if not already paid/confirmed 593 593 if (!in_array($this->getStatus(), [SLN_Enum_BookingStatus::PAID, SLN_Enum_BookingStatus::CONFIRMED])) { … … 605 605 )); 606 606 } 607 608 // #region agent log609 file_put_contents('/Users/macbookpro/Desktop/Salon Booking System/development/bitbucket/.cursor/debug.log', json_encode(['timestamp'=>time()*1000,'location'=>'Wrapper/Booking.php:508','message'=>'AFTER setStatus(PAID)','data'=>['booking_id'=>$this->getId(),'status_from_object'=>$this->getStatus(),'status_from_db'=>get_post_status($this->getId())],'sessionId'=>'debug-session','hypothesisId'=>'A,D']) . "\n", FILE_APPEND);610 // #endregion611 607 612 608 do_action('sln_booking_mark_paid_after', $this);
Note: See TracChangeset
for help on using the changeset viewer.