Changeset 3404859
- Timestamp:
- 11/28/2025 08:25:39 AM (4 months ago)
- Location:
- firstpromoter
- Files:
-
- 203 added
- 4 edited
-
tags/0.2.1 (added)
-
tags/0.2.1/assets (added)
-
tags/0.2.1/assets/css (added)
-
tags/0.2.1/assets/css/admin.css (added)
-
tags/0.2.1/assets/css/index.php (added)
-
tags/0.2.1/assets/index.php (added)
-
tags/0.2.1/assets/js (added)
-
tags/0.2.1/assets/js/admin.js (added)
-
tags/0.2.1/assets/js/index.php (added)
-
tags/0.2.1/composer.json (added)
-
tags/0.2.1/firstpromoter.php (added)
-
tags/0.2.1/includes (added)
-
tags/0.2.1/includes/class-fp-helpers.php (added)
-
tags/0.2.1/includes/class-fp-settings-page.php (added)
-
tags/0.2.1/includes/index.php (added)
-
tags/0.2.1/index.php (added)
-
tags/0.2.1/integrations (added)
-
tags/0.2.1/integrations/class-fp-integration-base.php (added)
-
tags/0.2.1/integrations/class-fp-integration-contactform7.php (added)
-
tags/0.2.1/integrations/class-fp-integration-memberpress.php (added)
-
tags/0.2.1/integrations/class-fp-integration-optimizepress.php (added)
-
tags/0.2.1/integrations/class-fp-integration-woocommerce.php (added)
-
tags/0.2.1/integrations/index.php (added)
-
tags/0.2.1/readme.txt (added)
-
tags/0.2.1/vendor (added)
-
tags/0.2.1/vendor/autoload.php (added)
-
tags/0.2.1/vendor/composer (added)
-
tags/0.2.1/vendor/composer/ClassLoader.php (added)
-
tags/0.2.1/vendor/composer/InstalledVersions.php (added)
-
tags/0.2.1/vendor/composer/LICENSE (added)
-
tags/0.2.1/vendor/composer/autoload_classmap.php (added)
-
tags/0.2.1/vendor/composer/autoload_files.php (added)
-
tags/0.2.1/vendor/composer/autoload_namespaces.php (added)
-
tags/0.2.1/vendor/composer/autoload_psr4.php (added)
-
tags/0.2.1/vendor/composer/autoload_real.php (added)
-
tags/0.2.1/vendor/composer/autoload_static.php (added)
-
tags/0.2.1/vendor/composer/installed.json (added)
-
tags/0.2.1/vendor/composer/installed.php (added)
-
tags/0.2.1/vendor/composer/platform_check.php (added)
-
tags/0.2.1/vendor/guzzlehttp (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/CHANGELOG.md (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/LICENSE (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/README.md (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/UPGRADING.md (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/composer.json (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/BodySummarizer.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/BodySummarizerInterface.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Client.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/ClientInterface.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/ClientTrait.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Cookie (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/InvalidArgumentException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/HandlerStack.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/MessageFormatter.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/MessageFormatterInterface.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Middleware.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Pool.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/RequestOptions.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/TransferStats.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/Utils.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/functions.php (added)
-
tags/0.2.1/vendor/guzzlehttp/guzzle/src/functions_include.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/CHANGELOG.md (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/LICENSE (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/README.md (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/composer.json (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/AggregateException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/CancellationException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/Coroutine.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/Create.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/Each.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/EachPromise.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/FulfilledPromise.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/Is.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/Promise.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/PromiseInterface.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/PromisorInterface.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/RejectedPromise.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/RejectionException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/TaskQueue.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/TaskQueueInterface.php (added)
-
tags/0.2.1/vendor/guzzlehttp/promises/src/Utils.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7 (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/CHANGELOG.md (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/LICENSE (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/README.md (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/composer.json (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/AppendStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/BufferStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/CachingStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/DroppingStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Exception (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Exception/MalformedUriException.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/FnStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Header.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/HttpFactory.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/InflateStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/LazyOpenStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/LimitStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Message.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/MessageTrait.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/MimeType.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/MultipartStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/NoSeekStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/PumpStream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Query.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Request.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Response.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Rfc7230.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/ServerRequest.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Stream.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/StreamWrapper.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/UploadedFile.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Uri.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/UriComparator.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/UriNormalizer.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/UriResolver.php (added)
-
tags/0.2.1/vendor/guzzlehttp/psr7/src/Utils.php (added)
-
tags/0.2.1/vendor/psr (added)
-
tags/0.2.1/vendor/psr/http-client (added)
-
tags/0.2.1/vendor/psr/http-client/CHANGELOG.md (added)
-
tags/0.2.1/vendor/psr/http-client/LICENSE (added)
-
tags/0.2.1/vendor/psr/http-client/README.md (added)
-
tags/0.2.1/vendor/psr/http-client/composer.json (added)
-
tags/0.2.1/vendor/psr/http-client/src (added)
-
tags/0.2.1/vendor/psr/http-client/src/ClientExceptionInterface.php (added)
-
tags/0.2.1/vendor/psr/http-client/src/ClientInterface.php (added)
-
tags/0.2.1/vendor/psr/http-client/src/NetworkExceptionInterface.php (added)
-
tags/0.2.1/vendor/psr/http-client/src/RequestExceptionInterface.php (added)
-
tags/0.2.1/vendor/psr/http-factory (added)
-
tags/0.2.1/vendor/psr/http-factory/LICENSE (added)
-
tags/0.2.1/vendor/psr/http-factory/README.md (added)
-
tags/0.2.1/vendor/psr/http-factory/composer.json (added)
-
tags/0.2.1/vendor/psr/http-factory/src (added)
-
tags/0.2.1/vendor/psr/http-factory/src/RequestFactoryInterface.php (added)
-
tags/0.2.1/vendor/psr/http-factory/src/ResponseFactoryInterface.php (added)
-
tags/0.2.1/vendor/psr/http-factory/src/ServerRequestFactoryInterface.php (added)
-
tags/0.2.1/vendor/psr/http-factory/src/StreamFactoryInterface.php (added)
-
tags/0.2.1/vendor/psr/http-factory/src/UploadedFileFactoryInterface.php (added)
-
tags/0.2.1/vendor/psr/http-factory/src/UriFactoryInterface.php (added)
-
tags/0.2.1/vendor/psr/http-message (added)
-
tags/0.2.1/vendor/psr/http-message/CHANGELOG.md (added)
-
tags/0.2.1/vendor/psr/http-message/LICENSE (added)
-
tags/0.2.1/vendor/psr/http-message/README.md (added)
-
tags/0.2.1/vendor/psr/http-message/composer.json (added)
-
tags/0.2.1/vendor/psr/http-message/docs (added)
-
tags/0.2.1/vendor/psr/http-message/docs/PSR7-Interfaces.md (added)
-
tags/0.2.1/vendor/psr/http-message/docs/PSR7-Usage.md (added)
-
tags/0.2.1/vendor/psr/http-message/src (added)
-
tags/0.2.1/vendor/psr/http-message/src/MessageInterface.php (added)
-
tags/0.2.1/vendor/psr/http-message/src/RequestInterface.php (added)
-
tags/0.2.1/vendor/psr/http-message/src/ResponseInterface.php (added)
-
tags/0.2.1/vendor/psr/http-message/src/ServerRequestInterface.php (added)
-
tags/0.2.1/vendor/psr/http-message/src/StreamInterface.php (added)
-
tags/0.2.1/vendor/psr/http-message/src/UploadedFileInterface.php (added)
-
tags/0.2.1/vendor/psr/http-message/src/UriInterface.php (added)
-
tags/0.2.1/vendor/ralouphie (added)
-
tags/0.2.1/vendor/ralouphie/getallheaders (added)
-
tags/0.2.1/vendor/ralouphie/getallheaders/LICENSE (added)
-
tags/0.2.1/vendor/ralouphie/getallheaders/README.md (added)
-
tags/0.2.1/vendor/ralouphie/getallheaders/composer.json (added)
-
tags/0.2.1/vendor/ralouphie/getallheaders/src (added)
-
tags/0.2.1/vendor/ralouphie/getallheaders/src/getallheaders.php (added)
-
tags/0.2.1/vendor/symfony (added)
-
tags/0.2.1/vendor/symfony/deprecation-contracts (added)
-
tags/0.2.1/vendor/symfony/deprecation-contracts/CHANGELOG.md (added)
-
tags/0.2.1/vendor/symfony/deprecation-contracts/LICENSE (added)
-
tags/0.2.1/vendor/symfony/deprecation-contracts/README.md (added)
-
tags/0.2.1/vendor/symfony/deprecation-contracts/composer.json (added)
-
tags/0.2.1/vendor/symfony/deprecation-contracts/function.php (added)
-
trunk/firstpromoter.php (modified) (2 diffs)
-
trunk/integrations/class-fp-integration-base.php (modified) (10 diffs)
-
trunk/integrations/class-fp-integration-woocommerce.php (modified) (7 diffs)
-
trunk/readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
firstpromoter/trunk/firstpromoter.php
r3402820 r3404859 3 3 Plugin Name: FirstPromoter 4 4 Description: FirstPromoter tracking scripts with WooCommerce, OptimizePress, Contact Form 7 & MemberPress 5 Version: 0.2. 05 Version: 0.2.1 6 6 Author: FirstPromoter 7 7 Author URI: https://firstpromoter.com … … 23 23 24 24 // Define plugin constants 25 define('FIRSTPROMOTER_VERSION', '0.2. 0');25 define('FIRSTPROMOTER_VERSION', '0.2.1'); 26 26 define('FIRSTPROMOTER_PLUGIN_PATH', plugin_dir_path(__FILE__)); 27 27 define('FIRSTPROMOTER_PLUGIN_URL', plugin_dir_url(__FILE__)); -
firstpromoter/trunk/integrations/class-fp-integration-base.php
r3399291 r3404859 15 15 { 16 16 $this->integration_settings = $integration_settings; 17 $this->base_settings = get_option('firstpromoter_base_settings');17 $this->base_settings = get_option('firstpromoter_base_settings'); 18 18 add_action('wp_ajax_nopriv_firstpromoter_track_api_fallback', [$this, 'handle_api_fallback']); 19 19 add_action('wp_ajax_firstpromoter_track_api_fallback', [$this, 'handle_api_fallback']); … … 25 25 protected function track_referral($email, $userId = null) 26 26 { 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 139 147 } 140 148 } … … 142 150 protected function add_referral_tracking_scripts($data) 143 151 { 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 167 183 } 168 184 } … … 170 186 protected function track_sale_via_api($email, $uid, $event_id, $amount, $plan = '', $couponCode = '', $tid = '', $ref_id = '') 171 187 { 172 if (defined('WP_DEBUG') && WP_DEBUG){173 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode174 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 mode182 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 mode188 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 : null202 ], 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 mode210 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 214 230 $client = new \GuzzleHttp\Client(); 215 231 $response = $client->request('POST', $baseUrl, [ … … 252 268 } 253 269 254 255 270 protected function track_signup_via_api($email, $uid) 256 271 { 257 if (defined('WP_DEBUG') && WP_DEBUG){258 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode259 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 mode267 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 mode273 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 mode283 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 mode299 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 303 318 $client = new \GuzzleHttp\Client(); 304 319 $response = $client->request('POST', $baseUrl, [ … … 341 356 } 342 357 343 344 358 public function handle_api_fallback() 345 359 { 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 356 378 } 357 379 … … 361 383 /** 362 384 * Track refund via FirstPromoter v2 API 363 * 385 * 364 386 * @param string $email Customer email 365 387 * @param string $uid Customer unique identifier … … 373 395 protected function track_refund_via_api($email, $uid, $event_id, $amount, $quantity = '', $sale_event_id = '', $skip_email_notification = true) 374 396 { 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 mode381 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_notification394 ], 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 401 423 $client = new \GuzzleHttp\Client(); 402 424 $response = $client->request('POST', $baseUrl, [ … … 429 451 /** 430 452 * Track cancellation via FirstPromoter v2 API 431 * 453 * 432 454 * @param string $email Customer email 433 455 * @param string $uid Customer unique identifier … … 436 458 protected function track_cancellation_via_api($email, $uid) 437 459 { 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 mode444 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 459 481 $client = new \GuzzleHttp\Client(); 460 482 $response = $client->request('POST', $baseUrl, [ -
firstpromoter/trunk/integrations/class-fp-integration-woocommerce.php
r3399288 r3404859 68 68 public function track_checkout($order_id) 69 69 { 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 } 85 92 } 86 93 87 94 public function order_payment_successful($order_id) 88 95 { 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 135 151 } 136 152 } … … 138 154 public function track_sale($order_id) 139 155 { 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 209 233 if (defined('WP_DEBUG') && WP_DEBUG) { 210 234 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Only logs in debug mode … … 255 279 error_log('FirstPromoter Integration WooCommerce Stack trace: ' . $e->getTraceAsString()); 256 280 } 281 // Silently fail to ensure order processing is not affected 257 282 } 258 283 } … … 266 291 public function track_refund($order_id, $refund_id) 267 292 { 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 cents281 $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 284 309 $response = $this->track_refund_via_api( 285 310 $email, … … 297 322 $refund->save(); 298 323 } 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 305 331 } 306 332 } … … 313 339 public function track_order_cancellation($order_id) 314 340 { 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) { 326 352 $response = $this->track_cancellation_via_api($email, $customerId); 327 353 … … 330 356 $order->save(); 331 357 } 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 338 365 } 339 366 } -
firstpromoter/trunk/readme.txt
r3402820 r3404859 4 4 Requires at least: 5.0 5 5 Tested up to: 6.8 6 Stable tag: 0.2. 06 Stable tag: 0.2.1 7 7 Requires PHP: 7.2 8 8 License: GPLv2 or later … … 151 151 == Changelog == 152 152 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 153 158 = 0.2.0 = 154 159 * New: Contact Form 7 integration - track form submissions with automatic email capture … … 178 183 == Upgrade Notice == 179 184 185 = 0.2.1 = 186 Critical bug fix: Ensure all FirstPromoter API calls Fail gracefully. 187 180 188 = 0.2.0 = 181 189 New 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.