Changeset 3254205
- Timestamp:
- 03/11/2025 04:05:42 PM (13 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
snap-pixel/tags/1.8.0/includes/class-snap-pixel-core.php
r3252605 r3254205 9 9 // If this file is called directly, abort. 10 10 if ( ! defined( 'ABSPATH' ) ) { 11 exit;11 exit; 12 12 } 13 13 … … 17 17 class Snap_Pixel_Core { 18 18 19 /**20 * Pixel ID.21 *22 * @var string23 */24 private $pixel_id;25 26 /**27 * User email.28 *29 * @var string30 */31 private $user_email;32 33 /**34 * Settings for different page types.35 *36 * @var array37 */38 private $settings = array();39 40 /**41 * Flag to track if base pixel code has been output.42 *43 * @var bool44 */45 private $base_pixel_output = false;46 47 /**48 * Initialize the class and set its properties.49 */50 public function __construct() {51 $this->load_settings();52 53 // Add pixel code to appropriate pages54 add_action( 'template_redirect', array( $this, 'place_pixel_code' ) );55 56 // Register AJAX handler for product data57 add_action( 'wp_ajax_snapchat_product_data', array( $this, 'get_product_data' ) );58 add_action( 'wp_ajax_nopriv_snapchat_product_data', array( $this, 'get_product_data' ) );59 60 // Enqueue frontend assets61 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_assets' ) );62 63 // Set user email after WordPress is fully loaded64 add_action( 'init', array( $this, 'set_user_email' ) );65 }66 67 /**68 * Load settings from database.69 */70 private function load_settings() {71 $settings = get_option( 'snapchat_pixel_code', array() );72 73 $this->pixel_id = isset( $settings['pixel_id'] ) ? $settings['pixel_id'] : '';74 $this->user_email = isset( $settings['user_email'] ) ? $settings['user_email'] : get_option( 'admin_email' );75 76 // Load page type settings77 $this->settings = array(78 'homepage' => isset( $settings['homepage'] ) ? $settings['homepage'] : '',79 'pages' => isset( $settings['pages'] ) ? $settings['pages'] : '',80 'posts' => isset( $settings['posts'] ) ? $settings['posts'] : '',81 'search' => isset( $settings['search'] ) ? $settings['search'] : '',82 'categories' => isset( $settings['categories'] ) ? $settings['categories'] : '',83 'tags' => isset( $settings['tags'] ) ? $settings['tags'] : '',84 'viewcart' => isset( $settings['viewcart'] ) ? $settings['viewcart'] : '',85 'checkout' => isset( $settings['checkout'] ) ? $settings['checkout'] : '',86 'paymentinfo' => isset( $settings['paymentinfo'] ) ? $settings['paymentinfo'] : '',87 'addtocart' => isset( $settings['addtocart'] ) ? $settings['addtocart'] : '',88 'ajax_addtocart' => isset( $settings['ajax_addtocart'] ) ? $settings['ajax_addtocart'] : '',89 );90 }91 92 /**93 * Set user email after WordPress is fully loaded.94 */95 public function set_user_email() {96 // Override user email if user is logged in97 if ( function_exists( 'is_user_logged_in' ) && is_user_logged_in() ) {98 $current_user = wp_get_current_user();99 $this->user_email = $current_user->user_email;100 }101 }102 103 /**104 * Enqueue frontend assets.105 */106 public function enqueue_frontend_assets() {107 wp_register_script(108 'snap-pixel',109 SNAP_PIXEL_PLUGIN_URL . 'assets/js/snap-pixel.js',110 array( 'jquery' ),111 SNAP_PIXEL_VERSION,112 false // Load in header113 );114 115 wp_localize_script(116 'snap-pixel',117 'snappixel',118 array(119 'ajaxurl' => admin_url( 'admin-ajax.php' ),120 'nonce' => wp_create_nonce( 'snapchat_product_data' ),121 'prevent_duplicates' => true,122 )123 );124 125 wp_enqueue_script( 'snap-pixel' );126 }127 128 /**129 * Place pixel code on appropriate pages.130 */131 public function place_pixel_code() {132 global $post;133 134 // Don't proceed if pixel ID is not set135 if ( empty( $this->pixel_id ) ) {136 return;137 }138 139 $woo_active = $this->is_woocommerce_active();140 $woo_access = get_option( 'snapchat_pixel_wooacces', 'no' );141 142 // Track if we've added the base pixel code143 $base_pixel_added = false;144 145 // Homepage146 if ( ( is_home() || is_front_page() ) && 'checked' === $this->settings['homepage'] ) {147 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 );148 $base_pixel_added = true;149 }150 // Pages151 elseif ( is_page() && 'checked' === $this->settings['pages'] ) {152 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 );153 $base_pixel_added = true;154 155 // WooCommerce checkout page156 if ( $woo_active && 'yes' === $woo_access && function_exists( 'is_checkout' ) ) {157 $page_slug = $post->post_name;158 159 if ( 'checkout' === $page_slug ) {160 // This is checking for the existence of a URL parameter, not processing form data,161 // so nonce verification is not applicable here162 if ( ! isset( $_GET['key'] ) && 'checked' === $this->settings['checkout'] ) {163 add_action( 'wp_footer', array( $this, 'output_checkout_pixel_code' ) );164 } elseif ( 'checked' === $this->settings['paymentinfo'] ) {165 if ( is_wc_endpoint_url( 'order-received' ) ) {166 add_action( 'wp_footer', array( $this, 'output_purchase_pixel_code' ) );167 } else {168 add_action( 'wp_footer', array( $this, 'output_billing_pixel_code' ) );169 }170 }171 }172 }173 }174 // Posts175 elseif ( ( is_single() && 'checked' === $this->settings['posts'] ) || ( function_exists( 'is_product' ) && is_product() ) ) {176 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 );177 $base_pixel_added = true;178 179 // WooCommerce product page180 if ( $woo_active && 'yes' === $woo_access ) {181 add_action( 'wp_footer', array( $this, 'output_viewcontent_pixel_code' ) );182 }183 }184 // Search185 elseif ( is_search() && 'checked' === $this->settings['search'] ) {186 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 );187 $base_pixel_added = true;188 add_action( 'wp_footer', array( $this, 'output_search_pixel_code' ) );189 }190 // Category archives191 elseif ( is_category() && 'checked' === $this->settings['categories'] ) {192 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 );193 $base_pixel_added = true;194 }195 // Tag archives196 elseif ( is_tag() && 'checked' === $this->settings['tags'] ) {197 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 );198 $base_pixel_added = true;199 }200 201 // If we haven't added the base pixel code yet, but we're on a WooCommerce page that needs it202 if ( !$base_pixel_added && $woo_active && 'yes' === $woo_access ) {203 // Cart page204 if ( function_exists( 'is_cart' ) && is_cart() ) {205 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 );206 }207 // Checkout page not covered above208 elseif ( function_exists( 'is_checkout' ) && is_checkout() && !is_page() ) {209 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 );210 }211 }212 }213 214 /**215 * Output base pixel code.216 */217 public function output_base_pixel_code() {218 // Check if base pixel has already been output219 if ( $this->base_pixel_output ) {220 return;221 }222 223 // Set flag to prevent duplicate output224 $this->base_pixel_output = true;225 226 global $post;227 228 $product_id = '';229 230 // Check if we're on a product page231 if ( $this->is_woocommerce_active() && function_exists( 'is_product' ) && is_product() && $post ) {232 $product = wc_get_product( $post->ID );233 if ( $product ) {234 $product_id = $product->get_id();235 }236 }237 238 ?>239 <!-- Snapchat Pixel Code -->240 <script type='text/javascript'>241 (function(win, doc, sdk_url) {242 if (win.snaptr) return;243 var tr = win.snaptr = function() {244 tr.handleRequest ? tr.handleRequest.apply(tr, arguments) : tr.queue.push(arguments);245 };246 tr.queue = [];247 var s = 'script';248 var new_script_section = doc.createElement(s);249 new_script_section.async = !0;250 new_script_section.src = sdk_url;251 var insert_pos = doc.getElementsByTagName(s)[0];252 insert_pos.parentNode.insertBefore(new_script_section, insert_pos);253 })(window, document, 'https://sc-static.net/scevent.min.js');254 255 snaptr('init', '<?php echo esc_js( $this->pixel_id ); ?>', {256 'user_email': '<?php echo esc_js( $this->user_email ); ?>'257 });258 259 var item_ids = <?php if ( $product_id ) { ?> {'item_ids': ["<?php echo esc_js( $product_id ); ?>"]} <?php } else { echo "0"; } ?>;260 snaptr('track', 'PAGE_VIEW', item_ids);261 </script>262 <!-- End Snapchat Pixel Code -->263 <?php264 // Fire action for add-ons265 $event_data = array();266 if (isset($item_ids)) {267 $event_data['item_ids'] = $item_ids;268 }269 do_action( 'snap_pixel_event_fired', 'PAGE_VIEW', $event_data );270 ?>271 <?php272 }273 274 /**275 * Output search pixel code.276 */277 public function output_search_pixel_code() {278 global $wp_query;279 280 $search_term = get_search_query();281 282 ?>283 <!-- SEARCH pixel event by Snap Pixel Plugin -->284 <script>285 snaptr('track', 'SEARCH', {286 'search_string': "<?php echo esc_js( $search_term ); ?>"287 });288 </script>289 <!-- End SEARCH pixel event by Snap Pixel Plugin -->290 <?php291 // Fire action for add-ons292 $event_data = array(293 'search_string' => $search_term294 );295 do_action( 'snap_pixel_event_fired', 'SEARCH', $event_data );296 ?>297 <?php298 }299 300 /**301 * Output view content pixel code for product pages.302 */303 public function output_viewcontent_pixel_code() {304 global $post;305 306 if ( ! $this->is_woocommerce_active() ) {307 return;308 }309 310 $product = wc_get_product( $post->ID );311 if ( ! $product ) {312 return;313 }314 315 $product_id = $product->get_id();316 $product_price = $product->get_price();317 $product_currency = get_woocommerce_currency();318 319 // Get product category320 $terms = get_the_terms( $product_id, 'product_cat' );321 $product_category = '';322 323 if ( $terms && ! is_wp_error( $terms ) ) {324 $product_category = $terms[0]->name;325 }326 327 ?>328 <!-- VIEW_CONTENT pixel event by Snap Pixel Plugin -->329 <script>330 snaptr('track', 'VIEW_CONTENT', {331 'item_category': "<?php echo esc_js( $product_category ); ?>",332 'item_ids': ["<?php echo esc_js( $product_id ); ?>"],333 'price': <?php echo esc_js( $product_price ); ?>,334 'currency': "<?php echo esc_js( $product_currency ); ?>"335 });336 </script>337 <!-- End VIEW_CONTENT pixel event by Snap Pixel Plugin -->338 <?php339 // Fire action for add-ons340 $event_data = array(341 'item_category' => $product_category,342 'item_ids' => array($product_id),343 'price' => $product_price,344 'currency' => $product_currency345 );346 do_action( 'snap_pixel_event_fired', 'VIEW_CONTENT', $event_data );347 ?>348 <?php349 }350 351 /**352 * Output checkout pixel code.353 */354 public function output_checkout_pixel_code() {355 if ( ! $this->is_woocommerce_active() ) {356 return;357 }358 359 global $woocommerce;360 361 $price = $woocommerce->cart->total;362 $product_currency = get_woocommerce_currency();363 $num_items = $woocommerce->cart->get_cart_contents_count();364 $product_id = '';365 366 foreach ( WC()->cart->get_cart() as $cart_item ) {367 $product_id = $cart_item['product_id'];368 break;369 }370 371 ?>372 <!-- START_CHECKOUT pixel event by Snap Pixel Plugin -->373 <script>374 snaptr('track', 'START_CHECKOUT', {375 'currency': "<?php echo esc_js( $product_currency ); ?>",376 'price': <?php echo esc_js( $price ); ?>,377 'num_items': <?php echo esc_js( $num_items ); ?>,378 'item_ids': ["<?php echo esc_js( $product_id ); ?>"]379 });380 </script>381 <!-- End START_CHECKOUT pixel event by Snap Pixel Plugin -->382 <?php383 // Fire action for add-ons384 $event_data = array(385 'currency' => $product_currency,386 'price' => $price,387 'num_items' => $num_items,388 'item_ids' => array($product_id)389 );390 do_action( 'snap_pixel_event_fired', 'START_CHECKOUT', $event_data );391 ?>392 <?php393 }394 395 /**396 * Output purchase pixel code.397 */398 public function output_purchase_pixel_code() {399 if ( ! $this->is_woocommerce_active() ) {400 return;401 }402 403 global $woocommerce;404 405 // Check if key exists and verify nonce if it's from a form submission406 if ( isset( $_GET['key'] ) ) {407 $key = sanitize_text_field( wp_unslash( $_GET['key'] ) );408 409 // For WooCommerce order-received endpoint, the key is part of the URL and not from a form submission410 // so we don't need to verify a nonce in this specific case. This is a standard WooCommerce URL parameter411 // used for order identification and not for processing form submissions.412 } else {413 $key = '';414 }415 416 $order_id = $this->get_order_id_by_key( $key );417 418 if ( ! $order_id ) {419 return;420 }421 422 $order = wc_get_order( $order_id );423 if ( ! $order ) {424 return;425 }426 427 $order_total = $order->get_total();428 $product_currency = get_woocommerce_currency();429 $num_items = $woocommerce->cart->get_cart_contents_count();430 431 // Get product IDs from the order items432 $product_ids = array();433 foreach ( $order->get_items() as $item ) {434 // Access product_id directly from the item data435 $item_data = $item->get_data();436 $product_id = isset( $item_data['product_id'] ) ? $item_data['product_id'] : 0;437 438 if ( $product_id ) {439 $product_ids[] = $product_id;440 }441 }442 if(count($product_ids) > 0){443 $content_ids_string = $product_ids;444 } else {445 $content_ids_string = $order_id;446 }447 448 ?>449 <!-- PURCHASE pixel event by Snap Pixel Plugin -->450 <script>451 snaptr('track', 'PURCHASE', {452 'currency': "<?php echo esc_js( $product_currency ); ?>",453 'price': <?php echo esc_js( $order_total ); ?>,454 'transaction_id': "<?php echo esc_js( $order_id ); ?>",455 'item_ids': content_ids_string456 });457 458 snaptr('track', 'ADD_BILLING');459 </script>460 <!-- End PURCHASE pixel event by Snap Pixel Plugin -->461 <?php462 // Fire action for add-ons463 $event_data = array(464 'currency' => $product_currency,465 'price' => $order_total,466 'transaction_id' => $order_id,467 'item_ids' => $content_ids_string468 );469 do_action( 'snap_pixel_event_fired', 'PURCHASE', $event_data );470 471 // Fire action for ADD_BILLING event472 do_action( 'snap_pixel_event_fired', 'ADD_BILLING', array() );473 ?>474 <?php475 }476 477 /**478 * Output add to cart pixel code.479 */480 public function output_addtocart_pixel_code() {481 if ( ! $this->is_woocommerce_active() ) {482 return;483 }484 485 global $post;486 487 $product_currency = get_woocommerce_currency();488 $product_price = '';489 490 if ( $post && function_exists( 'wc_get_product' ) ) {491 $product = wc_get_product( $post->ID );492 if ( $product ) {493 $product_price = $product->get_price();494 }495 }496 497 ?>498 <!-- ADD_CART pixel event by Snap Pixel Plugin -->499 <script>500 jQuery('body').on('added_to_cart', function(e, h, w, button) {501 var product_id = button.data("product_id");502 var product_result = get_product_record(product_id);503 var product_price = "<?php echo esc_js( $product_price ); ?>";504 505 setTimeout(function() {506 product_price = jQuery("#return_response").val();507 snaptr('track', 'ADD_CART', {508 'currency': "<?php echo esc_js( $product_currency ); ?>",509 'price': product_price,510 'item_category': "",511 'item_ids': [product_id]512 });513 }, 1500);514 });515 </script>516 <!-- End ADD_CART pixel event by Snap Pixel Plugin -->517 <?php518 // Fire action for add-ons519 $event_data = array(520 'currency' => $product_currency,521 'price' => $product_price522 );523 do_action( 'snap_pixel_event_fired', 'ADD_CART', $event_data );524 ?>525 <?php526 }527 528 /**529 * Output billing pixel code.530 */531 public function output_billing_pixel_code() {532 ?>533 <script type='text/javascript'>534 snaptr('track', 'ADD_BILLING');535 </script>536 <?php537 // Fire action for add-ons538 do_action( 'snap_pixel_event_fired', 'ADD_BILLING', array() );539 }540 541 /**542 * AJAX handler for getting product data.543 */544 public function get_product_data() {545 // Verify nonce if provided, but don't require it for backward compatibility546 if ( isset( $_REQUEST['_wpnonce'] ) &&! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'snapchat_product_data' ) ) {547 wp_send_json_error( 'Invalidsecurity token' );548 wp_die();549 }550 551 if ( isset( $_REQUEST['snap_product_id'] ) && ! empty( $_REQUEST['snap_product_id'] ) ) {552 $product_id = absint( $_REQUEST['snap_product_id'] );553 554 if ( function_exists( 'wc_get_product' ) ) {555 $product = wc_get_product( $product_id );556 557 if ( $product ) {558 $product_price = $product->get_price();559 wp_send_json_success( $product_price );560 wp_die();561 }562 }563 }564 565 wp_send_json_error( 'Error' );566 wp_die();567 }568 569 /**570 * Get order ID by order key.571 *572 * @param string $key Order key.573 * @return int|bool Order ID or false if not found.574 */575 private function get_order_id_by_key( $key ) {576 if ( empty( $key ) ) {577 return false;578 }579 580 // Check cache first581 $cache_key = 'snap_pixel_order_' . md5($key);582 $order_id = wp_cache_get( $cache_key, 'snap_pixel' );583 584 if ( false !== $order_id ) {585 return $order_id;586 }587 588 global $wpdb;589 590 $result = $wpdb->get_row(591 $wpdb->prepare(592 "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key='_order_key' AND meta_value=%s ORDER BY meta_id DESC LIMIT 1",593 $key594 )595 );596 597 if ( $result ) {598 // Cache the result for future use599 wp_cache_set( $cache_key, $result->post_id, 'snap_pixel', 3600 ); // Cache for 1 hour600 return $result->post_id;601 }602 603 // Cache the negative result as well604 wp_cache_set( $cache_key, 0, 'snap_pixel', 3600 ); // Cache for 1 hour605 return false;606 }607 608 /**609 * Check if WooCommerce is active.610 *611 * @return bool612 */613 private function is_woocommerce_active() {614 return in_array(615 'woocommerce/woocommerce.php',616 apply_filters( 'active_plugins', get_option( 'active_plugins' ) )617 );618 }19 /** 20 * Pixel ID. 21 * 22 * @var string 23 */ 24 private $pixel_id; 25 26 /** 27 * User email. 28 * 29 * @var string 30 */ 31 private $user_email; 32 33 /** 34 * Settings for different page types. 35 * 36 * @var array 37 */ 38 private $settings = array(); 39 40 /** 41 * Flag to track if base pixel code has been output. 42 * 43 * @var bool 44 */ 45 private $base_pixel_output = false; 46 47 /** 48 * Initialize the class and set its properties. 49 */ 50 public function __construct() { 51 $this->load_settings(); 52 53 // Add pixel code to appropriate pages 54 add_action( 'template_redirect', array( $this, 'place_pixel_code' ) ); 55 56 // Register AJAX handler for product data 57 add_action( 'wp_ajax_snapchat_product_data', array( $this, 'get_product_data' ) ); 58 add_action( 'wp_ajax_nopriv_snapchat_product_data', array( $this, 'get_product_data' ) ); 59 60 // Enqueue frontend assets 61 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_assets' ) ); 62 63 // Set user email after WordPress is fully loaded 64 add_action( 'init', array( $this, 'set_user_email' ) ); 65 } 66 67 /** 68 * Load settings from database. 69 */ 70 private function load_settings() { 71 $settings = get_option( 'snapchat_pixel_code', array() ); 72 73 $this->pixel_id = isset( $settings['pixel_id'] ) ? $settings['pixel_id'] : ''; 74 $this->user_email = isset( $settings['user_email'] ) ? $settings['user_email'] : get_option( 'admin_email' ); 75 76 // Load page type settings 77 $this->settings = array( 78 'homepage' => isset( $settings['homepage'] ) ? $settings['homepage'] : '', 79 'pages' => isset( $settings['pages'] ) ? $settings['pages'] : '', 80 'posts' => isset( $settings['posts'] ) ? $settings['posts'] : '', 81 'search' => isset( $settings['search'] ) ? $settings['search'] : '', 82 'categories' => isset( $settings['categories'] ) ? $settings['categories'] : '', 83 'tags' => isset( $settings['tags'] ) ? $settings['tags'] : '', 84 'viewcart' => isset( $settings['viewcart'] ) ? $settings['viewcart'] : '', 85 'checkout' => isset( $settings['checkout'] ) ? $settings['checkout'] : '', 86 'paymentinfo' => isset( $settings['paymentinfo'] ) ? $settings['paymentinfo'] : '', 87 'addtocart' => isset( $settings['addtocart'] ) ? $settings['addtocart'] : '', 88 'ajax_addtocart' => isset( $settings['ajax_addtocart'] ) ? $settings['ajax_addtocart'] : '', 89 ); 90 } 91 92 /** 93 * Set user email after WordPress is fully loaded. 94 */ 95 public function set_user_email() { 96 // Override user email if user is logged in 97 if ( function_exists( 'is_user_logged_in' ) && is_user_logged_in() ) { 98 $current_user = wp_get_current_user(); 99 $this->user_email = $current_user->user_email; 100 } 101 } 102 103 /** 104 * Enqueue frontend assets. 105 */ 106 public function enqueue_frontend_assets() { 107 wp_register_script( 108 'snap-pixel', 109 SNAP_PIXEL_PLUGIN_URL . 'assets/js/snap-pixel.js', 110 array( 'jquery' ), 111 SNAP_PIXEL_VERSION, 112 false // Load in header 113 ); 114 115 wp_localize_script( 116 'snap-pixel', 117 'snappixel', 118 array( 119 'ajaxurl' => admin_url( 'admin-ajax.php' ), 120 'nonce' => wp_create_nonce( 'snapchat_product_data' ), 121 'prevent_duplicates' => true, 122 ) 123 ); 124 125 wp_enqueue_script( 'snap-pixel' ); 126 } 127 128 /** 129 * Place pixel code on appropriate pages. 130 */ 131 public function place_pixel_code() { 132 global $post; 133 134 // Don't proceed if pixel ID is not set 135 if ( empty( $this->pixel_id ) ) { 136 return; 137 } 138 139 $woo_active = $this->is_woocommerce_active(); 140 $woo_access = get_option( 'snapchat_pixel_wooacces', 'no' ); 141 142 // Track if we've added the base pixel code 143 $base_pixel_added = false; 144 145 // Homepage 146 if ( ( is_home() || is_front_page() ) && 'checked' === $this->settings['homepage'] ) { 147 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 ); 148 $base_pixel_added = true; 149 } 150 // Pages 151 elseif ( is_page() && 'checked' === $this->settings['pages'] ) { 152 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 ); 153 $base_pixel_added = true; 154 155 // WooCommerce checkout page 156 if ( $woo_active && 'yes' === $woo_access && function_exists( 'is_checkout' ) ) { 157 $page_slug = $post->post_name; 158 159 if ( 'checkout' === $page_slug ) { 160 // This is checking for the existence of a URL parameter, not processing form data, 161 // so nonce verification is not applicable here 162 if ( ! isset( $_GET['key'] ) && 'checked' === $this->settings['checkout'] ) { 163 add_action( 'wp_footer', array( $this, 'output_checkout_pixel_code' ) ); 164 } elseif ( 'checked' === $this->settings['paymentinfo'] ) { 165 if ( is_wc_endpoint_url( 'order-received' ) ) { 166 add_action( 'wp_footer', array( $this, 'output_purchase_pixel_code' ) ); 167 } else { 168 add_action( 'wp_footer', array( $this, 'output_billing_pixel_code' ) ); 169 } 170 } 171 } 172 } 173 } 174 // Posts 175 elseif ( ( is_single() && 'checked' === $this->settings['posts'] ) || ( function_exists( 'is_product' ) && is_product() ) ) { 176 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 ); 177 $base_pixel_added = true; 178 179 // WooCommerce product page 180 if ( $woo_active && 'yes' === $woo_access ) { 181 add_action( 'wp_footer', array( $this, 'output_viewcontent_pixel_code' ) ); 182 } 183 } 184 // Search 185 elseif ( is_search() && 'checked' === $this->settings['search'] ) { 186 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 ); 187 $base_pixel_added = true; 188 add_action( 'wp_footer', array( $this, 'output_search_pixel_code' ) ); 189 } 190 // Category archives 191 elseif ( is_category() && 'checked' === $this->settings['categories'] ) { 192 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 ); 193 $base_pixel_added = true; 194 } 195 // Tag archives 196 elseif ( is_tag() && 'checked' === $this->settings['tags'] ) { 197 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 ); 198 $base_pixel_added = true; 199 } 200 201 // If we haven't added the base pixel code yet, but we're on a WooCommerce page that needs it 202 if ( !$base_pixel_added && $woo_active && 'yes' === $woo_access ) { 203 // Cart page 204 if ( function_exists( 'is_cart' ) && is_cart() ) { 205 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 ); 206 } 207 // Checkout page not covered above 208 elseif ( function_exists( 'is_checkout' ) && is_checkout() && !is_page() ) { 209 add_action( 'wp_head', array( $this, 'output_base_pixel_code' ), 2 ); 210 } 211 } 212 } 213 214 /** 215 * Output base pixel code. 216 */ 217 public function output_base_pixel_code() { 218 // Check if base pixel has already been output 219 if ( $this->base_pixel_output ) { 220 return; 221 } 222 223 // Set flag to prevent duplicate output 224 $this->base_pixel_output = true; 225 226 global $post; 227 228 $product_id = ''; 229 230 // Check if we're on a product page 231 if ( $this->is_woocommerce_active() && function_exists( 'is_product' ) && is_product() && $post ) { 232 $product = wc_get_product( $post->ID ); 233 if ( $product ) { 234 $product_id = $product->get_id(); 235 } 236 } 237 238 ?> 239 <!-- Snapchat Pixel Code --> 240 <script type='text/javascript'> 241 (function(win, doc, sdk_url) { 242 if (win.snaptr) return; 243 var tr = win.snaptr = function() { 244 tr.handleRequest ? tr.handleRequest.apply(tr, arguments) : tr.queue.push(arguments); 245 }; 246 tr.queue = []; 247 var s = 'script'; 248 var new_script_section = doc.createElement(s); 249 new_script_section.async = !0; 250 new_script_section.src = sdk_url; 251 var insert_pos = doc.getElementsByTagName(s)[0]; 252 insert_pos.parentNode.insertBefore(new_script_section, insert_pos); 253 })(window, document, 'https://sc-static.net/scevent.min.js'); 254 255 snaptr('init', '<?php echo esc_js( $this->pixel_id ); ?>', { 256 'user_email': '<?php echo esc_js( $this->user_email ); ?>' 257 }); 258 259 var item_ids = <?php if ( $product_id ) { ?> {'item_ids': ["<?php echo esc_js( $product_id ); ?>"]} <?php } else { echo "0"; } ?>; 260 snaptr('track', 'PAGE_VIEW', item_ids); 261 </script> 262 <!-- End Snapchat Pixel Code --> 263 <?php 264 // Fire action for add-ons 265 $event_data = array(); 266 if (isset($item_ids)) { 267 $event_data['item_ids'] = $item_ids; 268 } 269 do_action( 'snap_pixel_event_fired', 'PAGE_VIEW', $event_data ); 270 ?> 271 <?php 272 } 273 274 /** 275 * Output search pixel code. 276 */ 277 public function output_search_pixel_code() { 278 global $wp_query; 279 280 $search_term = get_search_query(); 281 282 ?> 283 <!-- SEARCH pixel event by Snap Pixel Plugin --> 284 <script> 285 snaptr('track', 'SEARCH', { 286 'search_string': "<?php echo esc_js( $search_term ); ?>" 287 }); 288 </script> 289 <!-- End SEARCH pixel event by Snap Pixel Plugin --> 290 <?php 291 // Fire action for add-ons 292 $event_data = array( 293 'search_string' => $search_term 294 ); 295 do_action( 'snap_pixel_event_fired', 'SEARCH', $event_data ); 296 ?> 297 <?php 298 } 299 300 /** 301 * Output view content pixel code for product pages. 302 */ 303 public function output_viewcontent_pixel_code() { 304 global $post; 305 306 if ( ! $this->is_woocommerce_active() ) { 307 return; 308 } 309 310 $product = wc_get_product( $post->ID ); 311 if ( ! $product ) { 312 return; 313 } 314 315 $product_id = $product->get_id(); 316 $product_price = $product->get_price(); 317 $product_currency = get_woocommerce_currency(); 318 319 // Get product category 320 $terms = get_the_terms( $product_id, 'product_cat' ); 321 $product_category = ''; 322 323 if ( $terms && ! is_wp_error( $terms ) ) { 324 $product_category = $terms[0]->name; 325 } 326 327 ?> 328 <!-- VIEW_CONTENT pixel event by Snap Pixel Plugin --> 329 <script> 330 snaptr('track', 'VIEW_CONTENT', { 331 'item_category': "<?php echo esc_js( $product_category ); ?>", 332 'item_ids': ["<?php echo esc_js( $product_id ); ?>"], 333 'price': <?php echo esc_js( $product_price ); ?>, 334 'currency': "<?php echo esc_js( $product_currency ); ?>" 335 }); 336 </script> 337 <!-- End VIEW_CONTENT pixel event by Snap Pixel Plugin --> 338 <?php 339 // Fire action for add-ons 340 $event_data = array( 341 'item_category' => $product_category, 342 'item_ids' => array($product_id), 343 'price' => $product_price, 344 'currency' => $product_currency 345 ); 346 do_action( 'snap_pixel_event_fired', 'VIEW_CONTENT', $event_data ); 347 ?> 348 <?php 349 } 350 351 /** 352 * Output checkout pixel code. 353 */ 354 public function output_checkout_pixel_code() { 355 if ( ! $this->is_woocommerce_active() ) { 356 return; 357 } 358 359 global $woocommerce; 360 361 $price = $woocommerce->cart->total; 362 $product_currency = get_woocommerce_currency(); 363 $num_items = $woocommerce->cart->get_cart_contents_count(); 364 $product_id = ''; 365 366 foreach ( WC()->cart->get_cart() as $cart_item ) { 367 $product_id = $cart_item['product_id']; 368 break; 369 } 370 371 ?> 372 <!-- START_CHECKOUT pixel event by Snap Pixel Plugin --> 373 <script> 374 snaptr('track', 'START_CHECKOUT', { 375 'currency': "<?php echo esc_js( $product_currency ); ?>", 376 'price': <?php echo esc_js( $price ); ?>, 377 'num_items': <?php echo esc_js( $num_items ); ?>, 378 'item_ids': ["<?php echo esc_js( $product_id ); ?>"] 379 }); 380 </script> 381 <!-- End START_CHECKOUT pixel event by Snap Pixel Plugin --> 382 <?php 383 // Fire action for add-ons 384 $event_data = array( 385 'currency' => $product_currency, 386 'price' => $price, 387 'num_items' => $num_items, 388 'item_ids' => array($product_id) 389 ); 390 do_action( 'snap_pixel_event_fired', 'START_CHECKOUT', $event_data ); 391 ?> 392 <?php 393 } 394 395 /** 396 * Output purchase pixel code. 397 */ 398 public function output_purchase_pixel_code() { 399 if ( ! $this->is_woocommerce_active() ) { 400 return; 401 } 402 403 global $woocommerce; 404 405 // Check if key exists and verify nonce if it's from a form submission 406 if ( isset( $_GET['key'] ) ) { 407 $key = sanitize_text_field( wp_unslash( $_GET['key'] ) ); 408 409 // For WooCommerce order-received endpoint, the key is part of the URL and not from a form submission 410 // so we don't need to verify a nonce in this specific case. This is a standard WooCommerce URL parameter 411 // used for order identification and not for processing form submissions. 412 } else { 413 $key = ''; 414 } 415 416 $order_id = $this->get_order_id_by_key( $key ); 417 418 if ( ! $order_id ) { 419 return; 420 } 421 422 $order = wc_get_order( $order_id ); 423 if ( ! $order ) { 424 return; 425 } 426 427 $order_total = $order->get_total(); 428 $product_currency = get_woocommerce_currency(); 429 $num_items = $woocommerce->cart->get_cart_contents_count(); 430 431 // Get product IDs from the order items 432 $product_ids = array(); 433 foreach ( $order->get_items() as $item ) { 434 // Access product_id directly from the item data 435 $item_data = $item->get_data(); 436 $product_id = isset( $item_data['product_id'] ) ? $item_data['product_id'] : 0; 437 438 if ( $product_id ) { 439 $product_ids[] = $product_id; 440 } 441 } 442 if(count($product_ids) > 0){ 443 $content_ids_string = $product_ids; 444 } else { 445 $content_ids_string = $order_id; 446 } 447 448 ?> 449 <!-- PURCHASE pixel event by Snap Pixel Plugin --> 450 <script> 451 snaptr('track', 'PURCHASE', { 452 'currency': "<?php echo esc_js( $product_currency ); ?>", 453 'price': <?php echo esc_js( $order_total ); ?>, 454 'transaction_id': "<?php echo esc_js( $order_id ); ?>", 455 'item_ids': content_ids_string 456 }); 457 458 snaptr('track', 'ADD_BILLING'); 459 </script> 460 <!-- End PURCHASE pixel event by Snap Pixel Plugin --> 461 <?php 462 // Fire action for add-ons 463 $event_data = array( 464 'currency' => $product_currency, 465 'price' => $order_total, 466 'transaction_id' => $order_id, 467 'item_ids' => $content_ids_string 468 ); 469 do_action( 'snap_pixel_event_fired', 'PURCHASE', $event_data ); 470 471 // Fire action for ADD_BILLING event 472 do_action( 'snap_pixel_event_fired', 'ADD_BILLING', array() ); 473 ?> 474 <?php 475 } 476 477 /** 478 * Output add to cart pixel code. 479 */ 480 public function output_addtocart_pixel_code() { 481 if ( ! $this->is_woocommerce_active() ) { 482 return; 483 } 484 485 global $post; 486 487 $product_currency = get_woocommerce_currency(); 488 $product_price = ''; 489 490 if ( $post && function_exists( 'wc_get_product' ) ) { 491 $product = wc_get_product( $post->ID ); 492 if ( $product ) { 493 $product_price = $product->get_price(); 494 } 495 } 496 497 ?> 498 <!-- ADD_CART pixel event by Snap Pixel Plugin --> 499 <script> 500 jQuery('body').on('added_to_cart', function(e, h, w, button) { 501 var product_id = button.data("product_id"); 502 var product_result = get_product_record(product_id); 503 var product_price = "<?php echo esc_js( $product_price ); ?>"; 504 505 setTimeout(function() { 506 product_price = jQuery("#return_response").val(); 507 snaptr('track', 'ADD_CART', { 508 'currency': "<?php echo esc_js( $product_currency ); ?>", 509 'price': product_price, 510 'item_category': "", 511 'item_ids': [product_id] 512 }); 513 }, 1500); 514 }); 515 </script> 516 <!-- End ADD_CART pixel event by Snap Pixel Plugin --> 517 <?php 518 // Fire action for add-ons 519 $event_data = array( 520 'currency' => $product_currency, 521 'price' => $product_price 522 ); 523 do_action( 'snap_pixel_event_fired', 'ADD_CART', $event_data ); 524 ?> 525 <?php 526 } 527 528 /** 529 * Output billing pixel code. 530 */ 531 public function output_billing_pixel_code() { 532 ?> 533 <script type='text/javascript'> 534 snaptr('track', 'ADD_BILLING'); 535 </script> 536 <?php 537 // Fire action for add-ons 538 do_action( 'snap_pixel_event_fired', 'ADD_BILLING', array() ); 539 } 540 541 /** 542 * AJAX handler for getting product data. 543 */ 544 public function get_product_data() { 545 // Verify nonce - required for security 546 if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'snapchat_product_data' ) ) { 547 wp_send_json_error( 'Invalid or missing security token' ); 548 wp_die(); 549 } 550 551 if ( isset( $_REQUEST['snap_product_id'] ) && ! empty( $_REQUEST['snap_product_id'] ) ) { 552 $product_id = absint( $_REQUEST['snap_product_id'] ); 553 554 if ( function_exists( 'wc_get_product' ) ) { 555 $product = wc_get_product( $product_id ); 556 557 if ( $product ) { 558 $product_price = $product->get_price(); 559 wp_send_json_success( $product_price ); 560 wp_die(); 561 } 562 } 563 } 564 565 wp_send_json_error( 'Error' ); 566 wp_die(); 567 } 568 569 /** 570 * Get order ID by order key. 571 * 572 * @param string $key Order key. 573 * @return int|bool Order ID or false if not found. 574 */ 575 private function get_order_id_by_key( $key ) { 576 if ( empty( $key ) ) { 577 return false; 578 } 579 580 // Check cache first 581 $cache_key = 'snap_pixel_order_' . md5($key); 582 $order_id = wp_cache_get( $cache_key, 'snap_pixel' ); 583 584 if ( false !== $order_id ) { 585 return $order_id; 586 } 587 588 global $wpdb; 589 590 $result = $wpdb->get_row( 591 $wpdb->prepare( 592 "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key='_order_key' AND meta_value=%s ORDER BY meta_id DESC LIMIT 1", 593 $key 594 ) 595 ); 596 597 if ( $result ) { 598 // Cache the result for future use 599 wp_cache_set( $cache_key, $result->post_id, 'snap_pixel', 3600 ); // Cache for 1 hour 600 return $result->post_id; 601 } 602 603 // Cache the negative result as well 604 wp_cache_set( $cache_key, 0, 'snap_pixel', 3600 ); // Cache for 1 hour 605 return false; 606 } 607 608 /** 609 * Check if WooCommerce is active. 610 * 611 * @return bool 612 */ 613 private function is_woocommerce_active() { 614 return in_array( 615 'woocommerce/woocommerce.php', 616 apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) 617 ); 618 } 619 619 }
Note: See TracChangeset
for help on using the changeset viewer.