enrich
3 weeks ago
event-definitions
4 months ago
events
1 week ago
formEvents
1 year ago
logger
4 months ago
views
1 week ago
class-consent.php
6 months ago
class-custom-event-factory.php
1 year ago
class-custom-event.php
3 weeks ago
class-event-definitions.php
4 months ago
class-event-id-generator.php
5 years ago
class-events-manager-ajax_hook.php
3 weeks ago
class-events-manager.php
3 weeks ago
class-fixed-notices.php
1 year ago
class-optin-notices.php
1 year ago
class-pixel.php
7 years ago
class-plugin-updater.php
9 months ago
class-plugin.php
7 years ago
class-pys.php
1 week ago
class-settings.php
4 months ago
functions-admin.php
3 weeks ago
functions-buttons.php
1 year ago
functions-common.php
3 weeks ago
functions-custom-event.php
1 week ago
functions-edd.php
2 years ago
functions-gdpr.php
11 months ago
functions-license.php
3 weeks ago
functions-migrate.php
9 months ago
functions-promo-notices.php
1 year ago
functions-system-report.php
7 years ago
functions-update-plugin.php
6 years ago
functions-woo.php
3 weeks ago
options_defaults.json
3 weeks ago
options_fields.json
3 weeks ago
class-events-manager-ajax_hook.php
280 lines
| 1 | <?php |
| 2 | namespace PixelYourSite; |
| 3 | |
| 4 | if ( ! defined( 'ABSPATH' ) ) { |
| 5 | exit; // Exit if accessed directly. |
| 6 | } |
| 7 | |
| 8 | |
| 9 | class AjaxHookEventManager { |
| 10 | |
| 11 | public static $DIV_ID_FOR_AJAX_EVENTS = "pys_ajax_events"; |
| 12 | private static $_instance; |
| 13 | |
| 14 | static function addPendingEvent($name,$event) { |
| 15 | $events = WC()->session->get( 'pys_events', array() ); |
| 16 | $events[$name] = $event; |
| 17 | WC()->session->set( 'pys_events', $events ); |
| 18 | WC()->session->save_data(); |
| 19 | } |
| 20 | |
| 21 | /** |
| 22 | * @param $name |
| 23 | * @param $slug |
| 24 | * @return mixed|null |
| 25 | */ |
| 26 | static function getPendingEvent($name,$unset) { |
| 27 | if ( function_exists( 'WC' ) ) { |
| 28 | if(!WC()->session) return null; |
| 29 | $session_data = WC()->session->get_session_data(); |
| 30 | $events = isset( $session_data['pys_events'] ) ? WC()->session->get( 'pys_events', array() ) : array(); |
| 31 | if (isset($events[$name])) { |
| 32 | $event = $events[$name]; |
| 33 | if ($unset) { |
| 34 | unset($events[$name]); |
| 35 | WC()->session->set('pys_events', $events); |
| 36 | WC()->session->save_data(); |
| 37 | } |
| 38 | return $event; |
| 39 | } |
| 40 | return null; |
| 41 | } |
| 42 | return null; |
| 43 | } |
| 44 | |
| 45 | public static function instance() { |
| 46 | |
| 47 | if ( is_null( self::$_instance ) ) { |
| 48 | self::$_instance = new self(); |
| 49 | } |
| 50 | |
| 51 | return self::$_instance; |
| 52 | |
| 53 | } |
| 54 | |
| 55 | public function __construct() { |
| 56 | |
| 57 | } |
| 58 | |
| 59 | public function addHooks() { |
| 60 | |
| 61 | |
| 62 | if(EventsWoo()->isEnabled()) { |
| 63 | |
| 64 | // use for fb server only because ajax request cause bugs in woo |
| 65 | |
| 66 | |
| 67 | if ( PYS()->getOption('woo_add_to_cart_on_button_click') |
| 68 | && isEventEnabled('woo_add_to_cart_enabled') |
| 69 | ) |
| 70 | { |
| 71 | if(PYS()->getOption('woo_add_to_cart_catch_method') == "add_cart_hook") { |
| 72 | add_action( 'wp_footer', array( __CLASS__, 'addDivForAjaxPixelEvent') ); |
| 73 | add_action( 'woocommerce_add_to_cart',array(__CLASS__, 'trackWooAddToCartEvent'),40, 6); |
| 74 | if (wp_doing_ajax()) { |
| 75 | add_filter('woocommerce_add_to_cart_fragments', array(__CLASS__, 'addPixelCodeToAddToCartFragment')); |
| 76 | } else { |
| 77 | add_action("wp_footer",array(__CLASS__, 'printEvent')); |
| 78 | } |
| 79 | } else { |
| 80 | add_action( 'woocommerce_after_add_to_cart_button', 'PixelYourSite\EventsManager::setupWooSingleProductData' ); |
| 81 | } |
| 82 | |
| 83 | |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | |
| 88 | |
| 89 | } |
| 90 | |
| 91 | |
| 92 | static function trackWooAddToCartEvent($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data) { |
| 93 | |
| 94 | if(isset($cart_item_data['woosb_parent_id'])) return; // fix for WPC Product Bundles for WooCommerce (Premium) product |
| 95 | |
| 96 | $is_ajax_request = wp_doing_ajax(); |
| 97 | if( isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'yith_wacp_add_item_cart') { |
| 98 | $is_ajax_request = true; |
| 99 | } |
| 100 | |
| 101 | $standardParams = getStandardParams( $product_id ); |
| 102 | |
| 103 | PYS()->getLog()->debug('trackWooAddToCartEvent is_hook_request '.$is_ajax_request); |
| 104 | $dataList = []; |
| 105 | // Generate ONE shared eventID for the entire add-to-cart action so that |
| 106 | // all pixels receive the same ID for server-side deduplication. |
| 107 | $sharedEventId = EventIdGenerator::guidv4(); |
| 108 | foreach ( PYS()->getRegisteredPixels() as $pixel ) { |
| 109 | |
| 110 | if ( !Consent()->checkConsent( $pixel->getSlug() ) ) { |
| 111 | continue; |
| 112 | } |
| 113 | |
| 114 | if( !empty($variation_id) |
| 115 | && $variation_id > 0 |
| 116 | && (($pixel->getSlug() === 'ga' && !GATags()->getOption( 'woo_variable_as_simple')) || |
| 117 | ($pixel->getSlug() === "facebook" && Facebook\Helpers\isDefaultWooContentIdLogic() && !Facebook()->getOption( 'woo_variable_as_simple') ) || |
| 118 | (!in_array($pixel->getSlug(), ['ga', 'facebook']) && !$pixel->getOption( 'woo_variable_as_simple' )) |
| 119 | ) |
| 120 | ) { |
| 121 | $_product_id = $variation_id; |
| 122 | } else { |
| 123 | $_product_id = $product_id; |
| 124 | } |
| 125 | |
| 126 | |
| 127 | $event = new SingleEvent('woo_add_to_cart_on_button_click',EventTypes::$STATIC,'woo'); |
| 128 | $event->args = ['productId' => $_product_id,'quantity' => $quantity]; |
| 129 | $event->addPayload(['eventID' => $sharedEventId]); |
| 130 | $events = $pixel->generateEvents( $event ); |
| 131 | |
| 132 | if ( empty($events) ) { |
| 133 | continue; // event is disabled or not supported for the pixel |
| 134 | } |
| 135 | $event = $events[0]; |
| 136 | |
| 137 | // add standard params |
| 138 | $slug = $pixel->getSlug(); |
| 139 | if( $slug !== "reddit" ) { |
| 140 | $event->addParams($standardParams); |
| 141 | } |
| 142 | |
| 143 | // prepare event data |
| 144 | $eventData = $event->getData(); |
| 145 | $eventData = EventsManager::filterEventParams($eventData,"woo",['event_id'=>$event->getId(),'pixel'=>$pixel->getSlug()]); |
| 146 | |
| 147 | $dataList[$pixel->getSlug()] = $eventData; |
| 148 | if(!PYS()->is_user_agent_bot()){ |
| 149 | if($pixel->getSlug() === "facebook" && Facebook()->isServerApiEnabled()) { |
| 150 | FacebookServer()->sendEventsNow([$event]); |
| 151 | } |
| 152 | |
| 153 | if($pixel->getSlug() === "pinterest" && Pinterest()->isServerApiEnabled()) { |
| 154 | PinterestServer()->sendEventsNow(array($event)); |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | } |
| 159 | AjaxHookEventManager::addPendingEvent("woo_add_to_cart_on_button_click",$dataList); |
| 160 | } |
| 161 | |
| 162 | public static function printEvent() { |
| 163 | $pixelsEventData = self::getPendingEvent("woo_add_to_cart_on_button_click",true); |
| 164 | if( !is_null($pixelsEventData) ) { |
| 165 | PYS()->getLog()->debug('trackWooAddToCartEvent printEvent is footer'); |
| 166 | echo "<div id='pys_late_event' style='display:none' dir='".json_encode($pixelsEventData,JSON_HEX_APOS)."'></div>"; |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | public static function addDivForAjaxPixelEvent(){ |
| 171 | |
| 172 | echo self::getDivForAjaxPixelEvent(); |
| 173 | ?> |
| 174 | <script> |
| 175 | var node = document.getElementsByClassName('woocommerce-message')[0]; |
| 176 | if(node && document.getElementById('pys_late_event')) { |
| 177 | var messageText = node.textContent.trim(); |
| 178 | if(!messageText) { |
| 179 | node.style.display = 'none'; |
| 180 | } |
| 181 | } |
| 182 | </script> |
| 183 | <?php |
| 184 | } |
| 185 | |
| 186 | public static function getDivForAjaxPixelEvent($content = ''){ |
| 187 | return "<div id='".self::$DIV_ID_FOR_AJAX_EVENTS."'>" . $content . "</div>"; |
| 188 | } |
| 189 | |
| 190 | public static function addPixelCodeToAddToCarMessage($message, $products, $show_qty) { |
| 191 | $pixelsEventData = self::getPendingEvent("woo_add_to_cart_on_button_click",true); |
| 192 | if( !is_null($pixelsEventData) ){ |
| 193 | $message .= "<div id='pys_late_event' dir='".json_encode($pixelsEventData,JSON_HEX_APOS)."'></div>"; |
| 194 | } |
| 195 | return $message; |
| 196 | } |
| 197 | |
| 198 | public static function addPixelCodeToAddToCartFragment($fragments) { |
| 199 | |
| 200 | |
| 201 | $pixelsEventData = self::getPendingEvent("woo_add_to_cart_on_button_click",true); |
| 202 | if( !is_null($pixelsEventData) ){ |
| 203 | PYS()->getLog()->debug('addPixelCodeToAddToCartFragment send data with fragment'); |
| 204 | $pixel_code = self::generatePixelCode($pixelsEventData); |
| 205 | $fragments['#'.self::$DIV_ID_FOR_AJAX_EVENTS] = |
| 206 | self::getDivForAjaxPixelEvent($pixel_code); |
| 207 | } |
| 208 | |
| 209 | return $fragments; |
| 210 | } |
| 211 | |
| 212 | public static function generatePixelCode($pixelsEventData){ |
| 213 | |
| 214 | ob_start(); |
| 215 | //$cartHashKey = apply_filters( 'woocommerce_cart_hash_key', 'wc_cart_hash_' . md5( get_current_blog_id() . '_' . get_site_url( get_current_blog_id(), '/' ) . get_template() ) ); |
| 216 | ?> |
| 217 | <script> |
| 218 | function pys_getCookie(name) { |
| 219 | var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); |
| 220 | return v ? v[2] : null; |
| 221 | } |
| 222 | function pys_setCookie(name, value, days) { |
| 223 | var d = new Date; |
| 224 | d.setTime(d.getTime() + 24*60*60*1000*days); |
| 225 | document.cookie = name + "=" + value + ";path=/;expires=" + d.toGMTString(); |
| 226 | } |
| 227 | var name = 'pysAddToCartFragmentId'; |
| 228 | var cartHash = "<?=WC()->cart->get_cart_hash()?>"; |
| 229 | |
| 230 | if(pys_getCookie(name) != cartHash) { // prevent re send event if user update page |
| 231 | <?php |
| 232 | // Extract the shared eventID and unique e_id keys from PHP event data (set once |
| 233 | // in trackWooAddToCartEvent before the pixel loop, so all pixels carry the same UUID). |
| 234 | $sharedEventId = ''; |
| 235 | $uniqueEIds = []; |
| 236 | foreach ($pixelsEventData as $slug => $eventData) { |
| 237 | if (empty($sharedEventId) && !empty($eventData['eventID'])) { |
| 238 | $sharedEventId = $eventData['eventID']; |
| 239 | } |
| 240 | $eId = !empty($eventData['custom_event_post_id']) |
| 241 | ? $eventData['custom_event_post_id'] |
| 242 | : ($eventData['e_id'] ?? ''); |
| 243 | if (!empty($eId) && !in_array($eId, $uniqueEIds, true)) { |
| 244 | $uniqueEIds[] = $eId; |
| 245 | } |
| 246 | } |
| 247 | ?> |
| 248 | // Use the PHP-generated shared eventID; fall back to a JS token if absent. |
| 249 | var pys_action_event_id = '<?= esc_js($sharedEventId) ?>' || pys_generate_token(); |
| 250 | |
| 251 | <?php if (!empty($uniqueEIds)) : ?> |
| 252 | // Sync the uniqueId cache once per event type so generateUniqueId() |
| 253 | // returns the same fresh ID even when ajaxForServerStaticEvent=true. |
| 254 | if (window.pys && window.pys.setEventUniqueId) { |
| 255 | <?php foreach ($uniqueEIds as $eId) : ?> |
| 256 | window.pys.setEventUniqueId('<?= esc_js($eId) ?>', pys_action_event_id); |
| 257 | <?php endforeach; ?> |
| 258 | } |
| 259 | <?php endif; ?> |
| 260 | |
| 261 | <?php foreach ($pixelsEventData as $slug => $eventData) : ?> |
| 262 | var pixel = getPixelBySlag('<?= $slug ?>'); |
| 263 | var event = <?= json_encode($eventData) ?>; |
| 264 | event.eventID = pys_action_event_id; |
| 265 | pixel.fireEvent(event.name, event); |
| 266 | <?php endforeach; ?> |
| 267 | pys_setCookie(name,cartHash,90) |
| 268 | } |
| 269 | </script> |
| 270 | <?php |
| 271 | |
| 272 | $code = ob_get_clean(); |
| 273 | return $code; |
| 274 | } |
| 275 | |
| 276 | |
| 277 | |
| 278 | |
| 279 | } |
| 280 |