Plugin Directory

Changeset 3404859


Ignore:
Timestamp:
11/28/2025 08:25:39 AM (4 months ago)
Author:
maxwellfp
Message:

Bug Fixes

Location:
firstpromoter
Files:
203 added
4 edited

Legend:

Unmodified
Added
Removed
  • firstpromoter/trunk/firstpromoter.php

    r3402820 r3404859  
    33Plugin Name: FirstPromoter
    44Description: FirstPromoter tracking scripts with WooCommerce, OptimizePress, Contact Form 7 & MemberPress
    5 Version: 0.2.0
     5Version: 0.2.1
    66Author: FirstPromoter
    77Author URI: https://firstpromoter.com
     
    2323
    2424// Define plugin constants
    25 define('FIRSTPROMOTER_VERSION', '0.2.0');
     25define('FIRSTPROMOTER_VERSION', '0.2.1');
    2626define('FIRSTPROMOTER_PLUGIN_PATH', plugin_dir_path(__FILE__));
    2727define('FIRSTPROMOTER_PLUGIN_URL', plugin_dir_url(__FILE__));
  • firstpromoter/trunk/integrations/class-fp-integration-base.php

    r3399291 r3404859  
    1515    {
    1616        $this->integration_settings = $integration_settings;
    17         $this->base_settings = get_option('firstpromoter_base_settings');
     17        $this->base_settings        = get_option('firstpromoter_base_settings');
    1818        add_action('wp_ajax_nopriv_firstpromoter_track_api_fallback', [$this, 'handle_api_fallback']);
    1919        add_action('wp_ajax_firstpromoter_track_api_fallback', [$this, 'handle_api_fallback']);
     
    2525    protected function track_referral($email, $userId = null)
    2626    {
    27         if (empty($email) && empty($userId)) {
    28             return;
    29         }
    30 
    31         $email = sanitize_email($email);
    32         if (!is_email($email)) {
    33             return;
    34         }
    35 
    36         $data = [
    37             'email' => $email,
    38         ];
    39 
    40         if (!empty($userId)) {
    41             $data['uid'] = sanitize_text_field($userId);
    42         }
    43 
    44         // Check if wp_enqueue_scripts has already fired
    45         if (did_action('wp_enqueue_scripts')) {
    46             // Too late for wp_enqueue_scripts, use wp_footer instead
    47             add_action('wp_footer', function () use ($data) {
    48                 $this->add_referral_tracking_scripts($data);
    49             }, 20);
    50         } else {
    51             // Normal case - wp_enqueue_scripts hasn't fired yet
    52             add_action('wp_enqueue_scripts', function () use ($data) {
    53                 $this->add_referral_tracking_scripts($data);
    54             }, 20);
    55         }
    56 
    57         // Check if force tracking is enabled
    58         $force_tracking_enabled = isset($this->base_settings['force_referral_tracking_when_adblockers']) && $this->base_settings['force_referral_tracking_when_adblockers'] == 1;
    59 
    60         if (!$force_tracking_enabled) {
    61             return;
    62         }
    63 
    64         // If we have the fallback cookie but not the main cookies, make a direct API call
    65         $has_fallback_cookie = isset($_COOKIE["_fprom_ref_fallback"]);
    66         $has_main_ref_cookie = isset($_COOKIE["_fprom_ref"]);
    67         $has_tid_cookie = isset($_COOKIE["_fprom_tid"]);
    68 
    69         if ($has_fallback_cookie && !$has_main_ref_cookie) {
    70             // Fallback cookie exists but main cookie doesn't - ad blocker likely blocking cookies
    71             // Make direct server-side API call
    72             if (defined('WP_DEBUG') && WP_DEBUG) {
    73                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    74                 error_log('FirstPromoter: Fallback cookie detected without main cookies. Making direct API call for signup tracking.');
    75             }
    76             $this->track_signup_via_api($email, $userId);
    77             return;
    78         }
    79 
    80         // If we already have the main cookies, no need for fallback
    81         if ($has_main_ref_cookie || $has_tid_cookie) {
    82             return;
    83         }
    84 
    85         // No cookies at all - add JavaScript fallback that will check again client-side
    86         // Check if wp_enqueue_scripts has already fired for fallback too
    87         if (did_action('wp_enqueue_scripts')) {
    88             add_action('wp_footer', function () use ($email, $userId) {
    89                 wp_enqueue_script('firstpromoter-ajax-fallback', '', array(), FIRSTPROMOTER_VERSION, true);
    90 
    91                 // Localize script for AJAX URL and nonce
    92                 wp_localize_script('firstpromoter-ajax-fallback', 'firstpromoter_ajax', array(
    93                     'ajax_url' => admin_url('admin-ajax.php'),
    94                     'nonce' => wp_create_nonce('firstpromoter_ajax')
    95                 ));
    96 
    97                 $inline_script = '
    98                     (function() {
    99                         setTimeout(function() {
    100                             if (window.fprom_loaded) {
    101                                 return;
    102                             }
    103                             var xhr = new XMLHttpRequest();
    104                             xhr.open("POST", firstpromoter_ajax.ajax_url, true);
    105                             xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    106                             xhr.send("action=firstpromoter_track_api_fallback&email=' . esc_js($email) . '&uid=' . esc_js($userId) . '&nonce=" + firstpromoter_ajax.nonce);
    107                         }, 100);
    108                     })();
    109                 ';
    110 
    111                 wp_add_inline_script('firstpromoter-ajax-fallback', $inline_script);
    112             }, 30);
    113         } else {
    114             add_action('wp_enqueue_scripts', function () use ($email, $userId) {
    115                 wp_enqueue_script('firstpromoter-ajax-fallback', '', array(), FIRSTPROMOTER_VERSION, true);
    116 
    117                 // Localize script for AJAX URL and nonce
    118                 wp_localize_script('firstpromoter-ajax-fallback', 'firstpromoter_ajax', array(
    119                     'ajax_url' => admin_url('admin-ajax.php'),
    120                     'nonce' => wp_create_nonce('firstpromoter_ajax')
    121                 ));
    122 
    123                 $inline_script = '
    124                     (function() {
    125                         setTimeout(function() {
    126                             if (window.fprom_loaded) {
    127                                 return;
    128                             }
    129                             var xhr = new XMLHttpRequest();
    130                             xhr.open("POST", firstpromoter_ajax.ajax_url, true);
    131                             xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    132                             xhr.send("action=firstpromoter_track_api_fallback&email=' . esc_js($email) . '&uid=' . esc_js($userId) . '&nonce=" + firstpromoter_ajax.nonce);
    133                         }, 100);
    134                     })();
    135                 ';
    136 
    137                 wp_add_inline_script('firstpromoter-ajax-fallback', $inline_script);
    138             }, 30);
     27        try {
     28            if (empty($email) && empty($userId)) {
     29                return;
     30            }
     31
     32            $email = sanitize_email($email);
     33            if (! is_email($email)) {
     34                return;
     35            }
     36
     37            $data = [
     38                'email' => $email,
     39            ];
     40
     41            if (! empty($userId)) {
     42                $data['uid'] = sanitize_text_field($userId);
     43            }
     44
     45            // Check if wp_enqueue_scripts has already fired
     46            if (did_action('wp_enqueue_scripts')) {
     47                // Too late for wp_enqueue_scripts, use wp_footer instead
     48                add_action('wp_footer', function () use ($data) {
     49                    $this->add_referral_tracking_scripts($data);
     50                }, 20);
     51            } else {
     52                // Normal case - wp_enqueue_scripts hasn't fired yet
     53                add_action('wp_enqueue_scripts', function () use ($data) {
     54                    $this->add_referral_tracking_scripts($data);
     55                }, 20);
     56            }
     57
     58            // Check if force tracking is enabled
     59            $force_tracking_enabled = isset($this->base_settings['force_referral_tracking_when_adblockers']) && $this->base_settings['force_referral_tracking_when_adblockers'] == 1;
     60
     61            if (! $force_tracking_enabled) {
     62                return;
     63            }
     64
     65            // If we have the fallback cookie but not the main cookies, make a direct API call
     66            $has_fallback_cookie = isset($_COOKIE["_fprom_ref_fallback"]);
     67            $has_main_ref_cookie = isset($_COOKIE["_fprom_ref"]);
     68            $has_tid_cookie      = isset($_COOKIE["_fprom_tid"]);
     69
     70            if ($has_fallback_cookie && ! $has_main_ref_cookie) {
     71                // Fallback cookie exists but main cookie doesn't - ad blocker likely blocking cookies
     72                // Make direct server-side API call
     73                if (defined('WP_DEBUG') && WP_DEBUG) {
     74                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     75                    error_log('FirstPromoter: Fallback cookie detected without main cookies. Making direct API call for signup tracking.');
     76                }
     77                $this->track_signup_via_api($email, $userId);
     78                return;
     79            }
     80
     81            // If we already have the main cookies, no need for fallback
     82            if ($has_main_ref_cookie || $has_tid_cookie) {
     83                return;
     84            }
     85
     86            // No cookies at all - add JavaScript fallback that will check again client-side
     87            // Check if wp_enqueue_scripts has already fired for fallback too
     88            if (did_action('wp_enqueue_scripts')) {
     89                add_action('wp_footer', function () use ($email, $userId) {
     90                    wp_enqueue_script('firstpromoter-ajax-fallback', '', [], FIRSTPROMOTER_VERSION, true);
     91
     92                    // Localize script for AJAX URL and nonce
     93                    wp_localize_script('firstpromoter-ajax-fallback', 'firstpromoter_ajax', [
     94                        'ajax_url' => admin_url('admin-ajax.php'),
     95                        'nonce'    => wp_create_nonce('firstpromoter_ajax'),
     96                    ]);
     97
     98                    $inline_script = '
     99                        (function() {
     100                            setTimeout(function() {
     101                                if (window.fprom_loaded) {
     102                                    return;
     103                                }
     104                                var xhr = new XMLHttpRequest();
     105                                xhr.open("POST", firstpromoter_ajax.ajax_url, true);
     106                                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
     107                                xhr.send("action=firstpromoter_track_api_fallback&email=' . esc_js($email) . '&uid=' . esc_js($userId) . '&nonce=" + firstpromoter_ajax.nonce);
     108                            }, 100);
     109                        })();
     110                    ';
     111
     112                    wp_add_inline_script('firstpromoter-ajax-fallback', $inline_script);
     113                }, 30);
     114            } else {
     115                add_action('wp_enqueue_scripts', function () use ($email, $userId) {
     116                    wp_enqueue_script('firstpromoter-ajax-fallback', '', [], FIRSTPROMOTER_VERSION, true);
     117
     118                    // Localize script for AJAX URL and nonce
     119                    wp_localize_script('firstpromoter-ajax-fallback', 'firstpromoter_ajax', [
     120                        'ajax_url' => admin_url('admin-ajax.php'),
     121                        'nonce'    => wp_create_nonce('firstpromoter_ajax'),
     122                    ]);
     123
     124                    $inline_script = '
     125                        (function() {
     126                            setTimeout(function() {
     127                                if (window.fprom_loaded) {
     128                                    return;
     129                                }
     130                                var xhr = new XMLHttpRequest();
     131                                xhr.open("POST", firstpromoter_ajax.ajax_url, true);
     132                                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
     133                                xhr.send("action=firstpromoter_track_api_fallback&email=' . esc_js($email) . '&uid=' . esc_js($userId) . '&nonce=" + firstpromoter_ajax.nonce);
     134                            }, 100);
     135                        })();
     136                    ';
     137
     138                    wp_add_inline_script('firstpromoter-ajax-fallback', $inline_script);
     139                }, 30);
     140            }
     141        } catch (\Exception $e) {
     142            if (defined('WP_DEBUG') && WP_DEBUG) {
     143                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     144                error_log('FirstPromoter track_referral error: ' . $e->getMessage());
     145            }
     146            // Silently fail to ensure application functionality is not affected
    139147        }
    140148    }
     
    142150    protected function add_referral_tracking_scripts($data)
    143151    {
    144         if (is_admin()) {
    145             return;
    146         }
    147 
    148         if (! is_array($data) || empty($data)) {
    149             return;
    150         }
    151 
    152         $json_data = wp_json_encode($data);
    153         if (false === $json_data) {
    154             return;
    155         }
    156 
    157         // Check if we're being called from wp_footer (after wp_enqueue_scripts)
    158         if (doing_action('wp_footer')) {
    159             // Output script directly since we're already in the footer
    160             // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $json_data is already safely encoded via wp_json_encode()
    161             echo '<script type="text/javascript">fpr("referral", ' . $json_data . ');</script>' . "\n";
    162         } else {
    163             // Normal enqueue method
    164             wp_enqueue_script('firstpromoter-referral-tracking', '', array(), FIRSTPROMOTER_VERSION, true);
    165             $inline_script = 'fpr("referral", ' . $json_data . ');';
    166             wp_add_inline_script('firstpromoter-referral-tracking', $inline_script);
     152        try {
     153            if (is_admin()) {
     154                return;
     155            }
     156
     157            if (! is_array($data) || empty($data)) {
     158                return;
     159            }
     160
     161            $json_data = wp_json_encode($data);
     162            if (false === $json_data) {
     163                return;
     164            }
     165
     166            // Check if we're being called from wp_footer (after wp_enqueue_scripts)
     167            if (doing_action('wp_footer')) {
     168                // Output script directly since we're already in the footer
     169                // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $json_data is already safely encoded via wp_json_encode()
     170                echo '<script type="text/javascript">fpr("referral", ' . $json_data . ');</script>' . "\n";
     171            } else {
     172                // Normal enqueue method
     173                wp_enqueue_script('firstpromoter-referral-tracking', '', [], FIRSTPROMOTER_VERSION, true);
     174                $inline_script = 'fpr("referral", ' . $json_data . ');';
     175                wp_add_inline_script('firstpromoter-referral-tracking', $inline_script);
     176            }
     177        } catch (\Exception $e) {
     178            if (defined('WP_DEBUG') && WP_DEBUG) {
     179                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     180                error_log('FirstPromoter add_referral_tracking_scripts error: ' . $e->getMessage());
     181            }
     182            // Silently fail to ensure application functionality is not affected
    167183        }
    168184    }
     
    170186    protected function track_sale_via_api($email, $uid, $event_id, $amount, $plan = '', $couponCode = '', $tid = '', $ref_id = '')
    171187    {
    172         if (defined('WP_DEBUG') && WP_DEBUG) {
    173             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    174             error_log('FirstPromoter: track_sale_via_api called with email: ' . $email . ', uid: ' . ($uid ?: 'none') . ', event_id: ' . $event_id);
    175         }
    176 
    177         $apiKey = isset($this->base_settings['api_key']) ? $this->base_settings['api_key'] : '';
    178         $accountId = isset($this->base_settings['cid']) ? $this->base_settings['cid'] : '';
    179 
    180         if (defined('WP_DEBUG') && WP_DEBUG) {
    181             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    182             error_log('FirstPromoter: API Key present: ' . (!empty($apiKey) ? 'YES' : 'NO') . ', Account ID present: ' . (!empty($accountId) ? 'YES' : 'NO'));
    183         }
    184 
    185         if (empty($apiKey) || empty($accountId)) {
    186             if (defined('WP_DEBUG') && WP_DEBUG) {
    187                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    188                 error_log('FirstPromoter: API key or Account ID missing for v2 API');
    189             }
    190             return false;
    191         }
    192 
    193         $data = array_filter([
    194             'email'      => $email,
    195             'uid'        => isset($uid) && $uid != 0 ? (string)$uid : null,
    196             'event_id'   => $event_id,
    197             'amount'     => (string)$amount,
    198             'plan'       => ! empty($plan) ? $plan : null,
    199             'promo_code' => ! empty($couponCode) ? $couponCode : null,
    200             'tid'        => ! empty($tid) ? $tid : null,
    201             'ref_id'     => ! empty($ref_id) ? $ref_id : null
    202         ], function ($value) {
    203             return $value !== null;
    204         });
    205 
    206         $baseUrl = $this->base_api_v2_url . "/track/sale";
    207 
    208         if (defined('WP_DEBUG') && WP_DEBUG) {
    209             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    210             error_log('FirstPromoter: Sending POST to ' . $baseUrl . ' with data: ' . wp_json_encode($data));
    211         }
    212 
    213         try {
     188        try {
     189            if (defined('WP_DEBUG') && WP_DEBUG) {
     190                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     191                error_log('FirstPromoter: track_sale_via_api called with email: ' . $email . ', uid: ' . ($uid ?: 'none') . ', event_id: ' . $event_id);
     192            }
     193
     194            $apiKey    = isset($this->base_settings['api_key']) ? $this->base_settings['api_key'] : '';
     195            $accountId = isset($this->base_settings['cid']) ? $this->base_settings['cid'] : '';
     196
     197            if (defined('WP_DEBUG') && WP_DEBUG) {
     198                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     199                error_log('FirstPromoter: API Key present: ' . (! empty($apiKey) ? 'YES' : 'NO') . ', Account ID present: ' . (! empty($accountId) ? 'YES' : 'NO'));
     200            }
     201
     202            if (empty($apiKey) || empty($accountId)) {
     203                if (defined('WP_DEBUG') && WP_DEBUG) {
     204                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     205                    error_log('FirstPromoter: API key or Account ID missing for v2 API');
     206                }
     207                return false;
     208            }
     209
     210            $data = array_filter([
     211                'email'      => $email,
     212                'uid'        => isset($uid) && $uid != 0 ? (string) $uid : null,
     213                'event_id'   => $event_id,
     214                'amount'     => (string) $amount,
     215                'plan'       => ! empty($plan) ? $plan : null,
     216                'promo_code' => ! empty($couponCode) ? $couponCode : null,
     217                'tid'        => ! empty($tid) ? $tid : null,
     218                'ref_id'     => ! empty($ref_id) ? $ref_id : null,
     219            ], function ($value) {
     220                return $value !== null;
     221            });
     222
     223            $baseUrl = $this->base_api_v2_url . "/track/sale";
     224
     225            if (defined('WP_DEBUG') && WP_DEBUG) {
     226                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     227                error_log('FirstPromoter: Sending POST to ' . $baseUrl . ' with data: ' . wp_json_encode($data));
     228            }
     229
    214230            $client   = new \GuzzleHttp\Client();
    215231            $response = $client->request('POST', $baseUrl, [
     
    252268    }
    253269
    254 
    255270    protected function track_signup_via_api($email, $uid)
    256271    {
    257         if (defined('WP_DEBUG') && WP_DEBUG) {
    258             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    259             error_log('FirstPromoter: track_signup_via_api called with email: ' . $email . ', uid: ' . ($uid ?: 'none'));
    260         }
    261 
    262         $apiKey = isset($this->base_settings['api_key']) ? $this->base_settings['api_key'] : '';
    263         $accountId = isset($this->base_settings['cid']) ? $this->base_settings['cid'] : '';
    264 
    265         if (defined('WP_DEBUG') && WP_DEBUG) {
    266             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    267             error_log('FirstPromoter: API Key present: ' . (!empty($apiKey) ? 'YES' : 'NO') . ', Account ID present: ' . (!empty($accountId) ? 'YES' : 'NO'));
    268         }
    269 
    270         if (empty($apiKey) || empty($accountId)) {
    271             if (defined('WP_DEBUG') && WP_DEBUG) {
    272                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    273                 error_log('FirstPromoter: API key or Account ID missing for v2 API');
    274             }
    275             return false;
    276         }
    277 
    278         $tid = isset($_COOKIE["_fprom_tid"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_tid"])) : null;
    279         $ref_id = isset($_COOKIE["_fprom_ref"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_ref"])) : (isset($_COOKIE["_fprom_ref_fallback"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_ref_fallback"])) : null);
    280 
    281         if (defined('WP_DEBUG') && WP_DEBUG) {
    282             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    283             error_log('FirstPromoter: Cookies - tid: ' . ($tid ?: 'none') . ', ref_id: ' . ($ref_id ?: 'none'));
    284         }
    285 
    286         $data = array_filter([
    287             'email'  => $email,
    288             'uid'    => isset($uid) && $uid != 0 ? (string)$uid : null,
    289             'tid'    => $tid,
    290             'ref_id' => $ref_id,
    291         ], function ($value) {
    292             return $value !== null;
    293         });
    294 
    295         $baseUrl = $this->base_api_v2_url . "/track/signup";
    296 
    297         if (defined('WP_DEBUG') && WP_DEBUG) {
    298             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    299             error_log('FirstPromoter: Sending POST to ' . $baseUrl . ' with data: ' . wp_json_encode($data));
    300         }
    301 
    302         try {
     272        try {
     273            if (defined('WP_DEBUG') && WP_DEBUG) {
     274                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     275                error_log('FirstPromoter: track_signup_via_api called with email: ' . $email . ', uid: ' . ($uid ?: 'none'));
     276            }
     277
     278            $apiKey    = isset($this->base_settings['api_key']) ? $this->base_settings['api_key'] : '';
     279            $accountId = isset($this->base_settings['cid']) ? $this->base_settings['cid'] : '';
     280
     281            if (defined('WP_DEBUG') && WP_DEBUG) {
     282                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     283                error_log('FirstPromoter: API Key present: ' . (! empty($apiKey) ? 'YES' : 'NO') . ', Account ID present: ' . (! empty($accountId) ? 'YES' : 'NO'));
     284            }
     285
     286            if (empty($apiKey) || empty($accountId)) {
     287                if (defined('WP_DEBUG') && WP_DEBUG) {
     288                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     289                    error_log('FirstPromoter: API key or Account ID missing for v2 API');
     290                }
     291                return false;
     292            }
     293
     294            $tid    = isset($_COOKIE["_fprom_tid"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_tid"])) : null;
     295            $ref_id = isset($_COOKIE["_fprom_ref"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_ref"])) : (isset($_COOKIE["_fprom_ref_fallback"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_ref_fallback"])) : null);
     296
     297            if (defined('WP_DEBUG') && WP_DEBUG) {
     298                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     299                error_log('FirstPromoter: Cookies - tid: ' . ($tid ?: 'none') . ', ref_id: ' . ($ref_id ?: 'none'));
     300            }
     301
     302            $data = array_filter([
     303                'email'  => $email,
     304                'uid'    => isset($uid) && $uid != 0 ? (string) $uid : null,
     305                'tid'    => $tid,
     306                'ref_id' => $ref_id,
     307            ], function ($value) {
     308                return $value !== null;
     309            });
     310
     311            $baseUrl = $this->base_api_v2_url . "/track/signup";
     312
     313            if (defined('WP_DEBUG') && WP_DEBUG) {
     314                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     315                error_log('FirstPromoter: Sending POST to ' . $baseUrl . ' with data: ' . wp_json_encode($data));
     316            }
     317
    303318            $client   = new \GuzzleHttp\Client();
    304319            $response = $client->request('POST', $baseUrl, [
     
    341356    }
    342357
    343 
    344358    public function handle_api_fallback()
    345359    {
    346         // Check nonce for security
    347         if (!wp_verify_nonce(isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '', 'firstpromoter_ajax')) {
    348             wp_die('Security check failed', 'Security Error', 403);
    349         }
    350 
    351         $email = isset($_POST['email']) ? sanitize_email(wp_unslash($_POST['email'])) : '';
    352         $uid = isset($_POST['uid']) ? sanitize_text_field(wp_unslash($_POST['uid'])) : null;
    353 
    354         if (!empty($email) || !empty($uid)) {
    355             $this->track_signup_via_api($email, $uid);
     360        try {
     361            // Check nonce for security
     362            if (! wp_verify_nonce(isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '', 'firstpromoter_ajax')) {
     363                wp_die('Security check failed', 'Security Error', 403);
     364            }
     365
     366            $email = isset($_POST['email']) ? sanitize_email(wp_unslash($_POST['email'])) : '';
     367            $uid   = isset($_POST['uid']) ? sanitize_text_field(wp_unslash($_POST['uid'])) : null;
     368
     369            if (! empty($email) || ! empty($uid)) {
     370                $this->track_signup_via_api($email, $uid);
     371            }
     372        } catch (\Exception $e) {
     373            if (defined('WP_DEBUG') && WP_DEBUG) {
     374                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     375                error_log('FirstPromoter handle_api_fallback error: ' . $e->getMessage());
     376            }
     377            // Silently fail to ensure application functionality is not affected
    356378        }
    357379
     
    361383    /**
    362384     * Track refund via FirstPromoter v2 API
    363      * 
     385     *
    364386     * @param string $email Customer email
    365387     * @param string $uid Customer unique identifier
     
    373395    protected function track_refund_via_api($email, $uid, $event_id, $amount, $quantity = '', $sale_event_id = '', $skip_email_notification = true)
    374396    {
    375         $apiKey = isset($this->base_settings['api_key']) ? $this->base_settings['api_key'] : '';
    376         $accountId = isset($this->base_settings['cid']) ? $this->base_settings['cid'] : '';
    377 
    378         if (empty($apiKey) || empty($accountId)) {
    379             if (defined('WP_DEBUG') && WP_DEBUG) {
    380                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    381                 error_log('FirstPromoter: API key or Account ID missing for v2 API');
    382             }
    383             return false;
    384         }
    385 
    386         $data = array_filter([
    387             'email'                   => $email,
    388             'uid'                     => isset($uid) && $uid != 0 ? (string)$uid : null,
    389             'event_id'                => $event_id,
    390             'amount'                  => (string)$amount,
    391             'quantity'                => !empty($quantity) ? (string)$quantity : null,
    392             'sale_event_id'           => !empty($sale_event_id) ? $sale_event_id : null,
    393             'skip_email_notification' => $skip_email_notification
    394         ], function ($value) {
    395             return $value !== null;
    396         });
    397 
    398         $baseUrl = $this->base_api_v2_url . "/track/refund";
    399 
    400         try {
     397        try {
     398            $apiKey    = isset($this->base_settings['api_key']) ? $this->base_settings['api_key'] : '';
     399            $accountId = isset($this->base_settings['cid']) ? $this->base_settings['cid'] : '';
     400
     401            if (empty($apiKey) || empty($accountId)) {
     402                if (defined('WP_DEBUG') && WP_DEBUG) {
     403                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     404                    error_log('FirstPromoter: API key or Account ID missing for v2 API');
     405                }
     406                return false;
     407            }
     408
     409            $data = array_filter([
     410                'email'                   => $email,
     411                'uid'                     => isset($uid) && $uid != 0 ? (string) $uid : null,
     412                'event_id'                => $event_id,
     413                'amount'                  => (string) $amount,
     414                'quantity'                => ! empty($quantity) ? (string) $quantity : null,
     415                'sale_event_id'           => ! empty($sale_event_id) ? $sale_event_id : null,
     416                'skip_email_notification' => $skip_email_notification,
     417            ], function ($value) {
     418                return $value !== null;
     419            });
     420
     421            $baseUrl = $this->base_api_v2_url . "/track/refund";
     422
    401423            $client   = new \GuzzleHttp\Client();
    402424            $response = $client->request('POST', $baseUrl, [
     
    429451    /**
    430452     * Track cancellation via FirstPromoter v2 API
    431      * 
     453     *
    432454     * @param string $email Customer email
    433455     * @param string $uid Customer unique identifier
     
    436458    protected function track_cancellation_via_api($email, $uid)
    437459    {
    438         $apiKey = isset($this->base_settings['api_key']) ? $this->base_settings['api_key'] : '';
    439         $accountId = isset($this->base_settings['cid']) ? $this->base_settings['cid'] : '';
    440 
    441         if (empty($apiKey) || empty($accountId)) {
    442             if (defined('WP_DEBUG') && WP_DEBUG) {
    443                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    444                 error_log('FirstPromoter: API key or Account ID missing for v2 API');
    445             }
    446             return false;
    447         }
    448 
    449         $data = array_filter([
    450             'email' => $email,
    451             'uid'   => isset($uid) && $uid != 0 ? (string)$uid : null,
    452         ], function ($value) {
    453             return $value !== null;
    454         });
    455 
    456         $baseUrl = $this->base_api_v2_url . "/track/cancellation";
    457 
    458         try {
     460        try {
     461            $apiKey    = isset($this->base_settings['api_key']) ? $this->base_settings['api_key'] : '';
     462            $accountId = isset($this->base_settings['cid']) ? $this->base_settings['cid'] : '';
     463
     464            if (empty($apiKey) || empty($accountId)) {
     465                if (defined('WP_DEBUG') && WP_DEBUG) {
     466                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     467                    error_log('FirstPromoter: API key or Account ID missing for v2 API');
     468                }
     469                return false;
     470            }
     471
     472            $data = array_filter([
     473                'email' => $email,
     474                'uid'   => isset($uid) && $uid != 0 ? (string) $uid : null,
     475            ], function ($value) {
     476                return $value !== null;
     477            });
     478
     479            $baseUrl = $this->base_api_v2_url . "/track/cancellation";
     480
    459481            $client   = new \GuzzleHttp\Client();
    460482            $response = $client->request('POST', $baseUrl, [
  • firstpromoter/trunk/integrations/class-fp-integration-woocommerce.php

    r3399288 r3404859  
    6868    public function track_checkout($order_id)
    6969    {
    70 
    71         $order = wc_get_order($order_id);
    72         if (! $order) {
    73             return;
    74         }
    75         $email      = $order->get_billing_email();
    76         $customerId = $order->get_customer_id();
    77         if ($email || $customerId) {
    78             $this->track_referral($email, $customerId);
    79         }
    80         // Save cookies to order meta, including fallback if main cookie is not present
    81         $ref_id = isset($_COOKIE['_fprom_ref']) ? sanitize_text_field(wp_unslash($_COOKIE['_fprom_ref'])) : (isset($_COOKIE['_fprom_ref_fallback']) ? sanitize_text_field(wp_unslash($_COOKIE['_fprom_ref_fallback'])) : null);
    82         $order->update_meta_data('ref_id', $ref_id);
    83         $order->update_meta_data('tid', isset($_COOKIE['_fprom_tid']) ? sanitize_text_field(wp_unslash($_COOKIE['_fprom_tid'])) : null);
    84         $order->save();
     70        try {
     71            $order = wc_get_order($order_id);
     72            if (! $order) {
     73                return;
     74            }
     75            $email      = $order->get_billing_email();
     76            $customerId = $order->get_customer_id();
     77            if ($email || $customerId) {
     78                $this->track_referral($email, $customerId);
     79            }
     80            // Save cookies to order meta, including fallback if main cookie is not present
     81            $ref_id = isset($_COOKIE['_fprom_ref']) ? sanitize_text_field(wp_unslash($_COOKIE['_fprom_ref'])) : (isset($_COOKIE['_fprom_ref_fallback']) ? sanitize_text_field(wp_unslash($_COOKIE['_fprom_ref_fallback'])) : null);
     82            $order->update_meta_data('ref_id', $ref_id);
     83            $order->update_meta_data('tid', isset($_COOKIE['_fprom_tid']) ? sanitize_text_field(wp_unslash($_COOKIE['_fprom_tid'])) : null);
     84            $order->save();
     85        } catch (\Exception $e) {
     86            if (defined('WP_DEBUG') && WP_DEBUG) {
     87                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     88                error_log('FirstPromoter WooCommerce track_checkout error: ' . $e->getMessage());
     89            }
     90            // Silently fail to ensure checkout process is not affected
     91        }
    8592    }
    8693
    8794    public function order_payment_successful($order_id)
    8895    {
    89         if (defined('WP_DEBUG') && WP_DEBUG) {
    90             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    91             error_log('FirstPromoter: order_payment_successful hook fired for order #' . $order_id);
    92         }
    93 
    94         $order = wc_get_order($order_id);
    95         if (! $order) {
    96             if (defined('WP_DEBUG') && WP_DEBUG) {
    97                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    98                 error_log('FirstPromoter: Order not found for order #' . $order_id);
    99             }
    100             return;
    101         }
    102 
    103         $email      = $order->get_billing_email();
    104         $customerId = $order->get_customer_id();
    105         $order_status = $order->get_status();
    106 
    107         if (defined('WP_DEBUG') && WP_DEBUG) {
    108             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    109             error_log('FirstPromoter: Order #' . $order_id . ' status: ' . $order_status . ', email: ' . $email . ', customerId: ' . $customerId);
    110         }
    111 
    112         // Track referral for both processing and completed orders
    113         $valid_statuses = ['processing', 'completed'];
    114         if (in_array($order_status, $valid_statuses) && ($email || $customerId)) {
    115             if (defined('WP_DEBUG') && WP_DEBUG) {
    116                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    117                 error_log('FirstPromoter: Tracking referral for order #' . $order_id);
    118             }
    119             $this->track_referral($email, $customerId);
    120         }
    121 
    122         $sale_tracking_enabled = isset($this->integration_settings['woo_send_sale_to_firstpromoter_on_checkout']) && $this->integration_settings['woo_send_sale_to_firstpromoter_on_checkout'];
    123 
    124         if (defined('WP_DEBUG') && WP_DEBUG) {
    125             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    126             error_log('FirstPromoter: Sale tracking enabled: ' . ($sale_tracking_enabled ? 'YES' : 'NO'));
    127         }
    128 
    129         if ($sale_tracking_enabled) {
    130             if (defined('WP_DEBUG') && WP_DEBUG) {
    131                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    132                 error_log('FirstPromoter: Calling track_sale for order #' . $order_id);
    133             }
    134             $this->track_sale($order_id);
     96        try {
     97            if (defined('WP_DEBUG') && WP_DEBUG) {
     98                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     99                error_log('FirstPromoter: order_payment_successful hook fired for order #' . $order_id);
     100            }
     101
     102            $order = wc_get_order($order_id);
     103            if (! $order) {
     104                if (defined('WP_DEBUG') && WP_DEBUG) {
     105                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     106                    error_log('FirstPromoter: Order not found for order #' . $order_id);
     107                }
     108                return;
     109            }
     110
     111            $email      = $order->get_billing_email();
     112            $customerId = $order->get_customer_id();
     113            $order_status = $order->get_status();
     114
     115            if (defined('WP_DEBUG') && WP_DEBUG) {
     116                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     117                error_log('FirstPromoter: Order #' . $order_id . ' status: ' . $order_status . ', email: ' . $email . ', customerId: ' . $customerId);
     118            }
     119
     120            // Track referral for both processing and completed orders
     121            $valid_statuses = ['processing', 'completed'];
     122            if (in_array($order_status, $valid_statuses) && ($email || $customerId)) {
     123                if (defined('WP_DEBUG') && WP_DEBUG) {
     124                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     125                    error_log('FirstPromoter: Tracking referral for order #' . $order_id);
     126                }
     127                $this->track_referral($email, $customerId);
     128            }
     129
     130            $sale_tracking_enabled = isset($this->integration_settings['woo_send_sale_to_firstpromoter_on_checkout']) && $this->integration_settings['woo_send_sale_to_firstpromoter_on_checkout'];
     131
     132            if (defined('WP_DEBUG') && WP_DEBUG) {
     133                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     134                error_log('FirstPromoter: Sale tracking enabled: ' . ($sale_tracking_enabled ? 'YES' : 'NO'));
     135            }
     136
     137            if ($sale_tracking_enabled) {
     138                if (defined('WP_DEBUG') && WP_DEBUG) {
     139                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     140                    error_log('FirstPromoter: Calling track_sale for order #' . $order_id);
     141                }
     142                $this->track_sale($order_id);
     143            }
     144        } catch (\Exception $e) {
     145            // Log the error but don't break the payment process
     146            if (defined('WP_DEBUG') && WP_DEBUG) {
     147                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     148                error_log('FirstPromoter: Critical error in order_payment_successful for order #' . $order_id . ': ' . $e->getMessage());
     149            }
     150            // Silently fail to ensure WooCommerce payment completion is not affected
    135151        }
    136152    }
     
    138154    public function track_sale($order_id)
    139155    {
    140         if (defined('WP_DEBUG') && WP_DEBUG) {
    141             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    142             error_log('FirstPromoter: track_sale called for order #' . $order_id);
    143         }
    144 
    145         $order      = wc_get_order($order_id);
    146         $order_data = $order->get_data();
    147         $email      = $order->get_billing_email();
    148         $customerId = $order->get_customer_id() != 0 ? $order->get_customer_id() : null;
    149         $order_status = $order->get_status();
    150 
    151         if (defined('WP_DEBUG') && WP_DEBUG) {
    152             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    153             error_log('FirstPromoter: Order #' . $order_id . ' - Status: ' . $order_status . ', Email: ' . $email . ', Customer ID: ' . ($customerId ?: 'none'));
    154         }
    155 
    156         // Check if order is in a valid status for tracking (processing or completed)
    157         $valid_statuses = ['processing', 'completed'];
    158         if (!in_array($order_status, $valid_statuses)) {
    159             if (defined('WP_DEBUG') && WP_DEBUG) {
    160                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    161                 error_log('FirstPromoter: Order #' . $order_id . ' has invalid status (' . $order_status . '). Not tracking sale.');
    162             }
    163             return;
    164         }
    165 
    166         if (!$email && !$customerId) {
    167             if (defined('WP_DEBUG') && WP_DEBUG) {
    168                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    169                 error_log('FirstPromoter: Order #' . $order_id . ' has no email or customer ID. Not tracking sale.');
    170             }
    171             return;
    172         }
    173 
    174         // Check if sale was already tracked to prevent duplicates
    175         if ($order->get_meta('firstpromoter_sale_tracked_on_fp')) {
    176             if (defined('WP_DEBUG') && WP_DEBUG) {
    177                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    178                 error_log('FirstPromoter: Sale already tracked for order #' . $order_id);
    179             }
    180             return;
    181         }
    182 
    183         $event_id    = $order->get_id() . "-" . $order->get_date_created()->getTimestamp();
    184         $order_total = ($order_data['total'] - $order_data['total_tax']) * 100;
    185 
    186         $coupons     = $order->get_coupon_codes();
    187         $coupon_code = ! empty($coupons) ? $coupons[0] : '';
    188 
    189         $items = $order->get_items();
    190 
    191         $product_names = [];
    192         foreach ($items as $item) {
    193             $product_names[] = $item->get_name();
    194         }
    195         $plan = implode(', ', $product_names);
    196 
    197         // Get cookies with fallback support
    198         $ref_id = isset($_COOKIE["_fprom_ref"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_ref"])) : (isset($_COOKIE["_fprom_ref_fallback"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_ref_fallback"])) : null);
    199         $tid = isset($_COOKIE["_fprom_tid"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_tid"])) : null;
    200 
    201         if (defined('WP_DEBUG') && WP_DEBUG) {
    202             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    203             error_log('FirstPromoter: Order #' . $order_id . ' - Cookies - ref_id: ' . ($ref_id ?: 'none') . ', tid: ' . ($tid ?: 'none'));
    204             // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    205             error_log('FirstPromoter: Order #' . $order_id . ' - Sale data - event_id: ' . $event_id . ', amount: ' . $order_total . ', plan: ' . $plan);
    206         }
    207 
    208         try {
     156        try {
     157            if (defined('WP_DEBUG') && WP_DEBUG) {
     158                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     159                error_log('FirstPromoter: track_sale called for order #' . $order_id);
     160            }
     161
     162            $order = wc_get_order($order_id);
     163            if (!$order) {
     164                if (defined('WP_DEBUG') && WP_DEBUG) {
     165                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     166                    error_log('FirstPromoter: Order not found for order #' . $order_id);
     167                }
     168                return;
     169            }
     170
     171            $order_data = $order->get_data();
     172            $email      = $order->get_billing_email();
     173            $customerId = $order->get_customer_id() != 0 ? $order->get_customer_id() : null;
     174            $order_status = $order->get_status();
     175
     176            if (defined('WP_DEBUG') && WP_DEBUG) {
     177                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     178                error_log('FirstPromoter: Order #' . $order_id . ' - Status: ' . $order_status . ', Email: ' . $email . ', Customer ID: ' . ($customerId ?: 'none'));
     179            }
     180
     181            // Check if order is in a valid status for tracking (processing or completed)
     182            $valid_statuses = ['processing', 'completed'];
     183            if (!in_array($order_status, $valid_statuses)) {
     184                if (defined('WP_DEBUG') && WP_DEBUG) {
     185                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     186                    error_log('FirstPromoter: Order #' . $order_id . ' has invalid status (' . $order_status . '). Not tracking sale.');
     187                }
     188                return;
     189            }
     190
     191            if (!$email && !$customerId) {
     192                if (defined('WP_DEBUG') && WP_DEBUG) {
     193                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     194                    error_log('FirstPromoter: Order #' . $order_id . ' has no email or customer ID. Not tracking sale.');
     195                }
     196                return;
     197            }
     198
     199            // Check if sale was already tracked to prevent duplicates
     200            if ($order->get_meta('firstpromoter_sale_tracked_on_fp')) {
     201                if (defined('WP_DEBUG') && WP_DEBUG) {
     202                    // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     203                    error_log('FirstPromoter: Sale already tracked for order #' . $order_id);
     204                }
     205                return;
     206            }
     207
     208            $event_id    = $order->get_id() . "-" . $order->get_date_created()->getTimestamp();
     209            $order_total = ($order_data['total'] - $order_data['total_tax']) * 100;
     210
     211            $coupons     = $order->get_coupon_codes();
     212            $coupon_code = ! empty($coupons) ? $coupons[0] : '';
     213
     214            $items = $order->get_items();
     215
     216            $product_names = [];
     217            foreach ($items as $item) {
     218                $product_names[] = $item->get_name();
     219            }
     220            $plan = implode(', ', $product_names);
     221
     222            // Get cookies with fallback support
     223            $ref_id = isset($_COOKIE["_fprom_ref"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_ref"])) : (isset($_COOKIE["_fprom_ref_fallback"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_ref_fallback"])) : null);
     224            $tid = isset($_COOKIE["_fprom_tid"]) ? sanitize_text_field(wp_unslash($_COOKIE["_fprom_tid"])) : null;
     225
     226            if (defined('WP_DEBUG') && WP_DEBUG) {
     227                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     228                error_log('FirstPromoter: Order #' . $order_id . ' - Cookies - ref_id: ' . ($ref_id ?: 'none') . ', tid: ' . ($tid ?: 'none'));
     229                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     230                error_log('FirstPromoter: Order #' . $order_id . ' - Sale data - event_id: ' . $event_id . ', amount: ' . $order_total . ', plan: ' . $plan);
     231            }
     232
    209233            if (defined('WP_DEBUG') && WP_DEBUG) {
    210234                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     
    255279                error_log('FirstPromoter Integration WooCommerce Stack trace: ' . $e->getTraceAsString());
    256280            }
     281            // Silently fail to ensure order processing is not affected
    257282        }
    258283    }
     
    266291    public function track_refund($order_id, $refund_id)
    267292    {
    268         $order = wc_get_order($order_id);
    269         $refund = wc_get_order($refund_id);
    270        
    271         if (!$order || !$refund) {
    272             return;
    273         }
    274 
    275         $email = $order->get_billing_email();
    276         $customerId = $order->get_customer_id() != 0 ? $order->get_customer_id() : null;
    277 
    278         if ($email || $customerId) {
    279             $refund_event_id = $refund_id . "-" . time();
    280             $refund_amount = abs($refund->get_amount()) * 100; // Convert to cents
    281             $original_event_id = $order->get_meta('firstpromoter_event_id');
    282 
    283             try {
     293        try {
     294            $order = wc_get_order($order_id);
     295            $refund = wc_get_order($refund_id);
     296
     297            if (!$order || !$refund) {
     298                return;
     299            }
     300
     301            $email = $order->get_billing_email();
     302            $customerId = $order->get_customer_id() != 0 ? $order->get_customer_id() : null;
     303
     304            if ($email || $customerId) {
     305                $refund_event_id = $refund_id . "-" . time();
     306                $refund_amount = abs($refund->get_amount()) * 100; // Convert to cents
     307                $original_event_id = $order->get_meta('firstpromoter_event_id');
     308
    284309                $response = $this->track_refund_via_api(
    285310                    $email,
     
    297322                    $refund->save();
    298323                }
    299             } catch (\Exception $e) {
    300                 if (defined('WP_DEBUG') && WP_DEBUG) {
    301                     // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    302                     error_log('FirstPromoter WooCommerce refund tracking error: ' . $e->getMessage());
    303                 }
    304             }
     324            }
     325        } catch (\Exception $e) {
     326            if (defined('WP_DEBUG') && WP_DEBUG) {
     327                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     328                error_log('FirstPromoter WooCommerce refund tracking error: ' . $e->getMessage());
     329            }
     330            // Silently fail to ensure refund processing is not affected
    305331        }
    306332    }
     
    313339    public function track_order_cancellation($order_id)
    314340    {
    315         $order = wc_get_order($order_id);
    316        
    317         if (!$order) {
    318             return;
    319         }
    320 
    321         $email = $order->get_billing_email();
    322         $customerId = $order->get_customer_id() != 0 ? $order->get_customer_id() : null;
    323 
    324         if ($email || $customerId) {
    325             try {
     341        try {
     342            $order = wc_get_order($order_id);
     343
     344            if (!$order) {
     345                return;
     346            }
     347
     348            $email = $order->get_billing_email();
     349            $customerId = $order->get_customer_id() != 0 ? $order->get_customer_id() : null;
     350
     351            if ($email || $customerId) {
    326352                $response = $this->track_cancellation_via_api($email, $customerId);
    327353
     
    330356                    $order->save();
    331357                }
    332             } catch (\Exception $e) {
    333                 if (defined('WP_DEBUG') && WP_DEBUG) {
    334                     // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
    335                     error_log('FirstPromoter WooCommerce cancellation tracking error: ' . $e->getMessage());
    336                 }
    337             }
     358            }
     359        } catch (\Exception $e) {
     360            if (defined('WP_DEBUG') && WP_DEBUG) {
     361                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode
     362                error_log('FirstPromoter WooCommerce cancellation tracking error: ' . $e->getMessage());
     363            }
     364            // Silently fail to ensure order cancellation is not affected
    338365        }
    339366    }
  • firstpromoter/trunk/readme.txt

    r3402820 r3404859  
    44Requires at least: 5.0
    55Tested up to: 6.8
    6 Stable tag: 0.2.0
     6Stable tag: 0.2.1
    77Requires PHP: 7.2
    88License: GPLv2 or later
     
    151151== Changelog ==
    152152
     153= 0.2.1 =
     154* Fixed: Comprehensive error handling to prevent API failures from breaking payments
     155* Fixed: All FirstPromoter API calls now fail gracefully when API credentials are missing or invalid
     156* Improved: Enhanced error logging for debugging API issues without affecting store functionality
     157
    153158= 0.2.0 =
    154159* New: Contact Form 7 integration - track form submissions with automatic email capture
     
    178183== Upgrade Notice ==
    179184
     185= 0.2.1 =
     186Critical bug fix: Ensure all FirstPromoter API calls Fail gracefully.
     187
    180188= 0.2.0 =
    181189New integrations added! Contact Form 7 and MemberPress integrations now available for tracking form submissions and membership sales.
Note: See TracChangeset for help on using the changeset viewer.