Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworking how pixel events on redirect to cart are handled. #2671

Merged
merged 6 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 3 additions & 84 deletions facebook-commerce-events-tracker.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,8 @@ private function add_hooks() {
add_action( 'woocommerce_ajax_added_to_cart', array( $this, 'add_filter_for_add_to_cart_fragments' ) );
// AddToCart while using redirect to cart page
if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add', 'no' ) ) {
add_filter( 'woocommerce_add_to_cart_redirect', array( $this, 'set_last_product_added_to_cart_upon_redirect' ), 10, 2 );
add_action( 'woocommerce_ajax_added_to_cart', array( $this, 'set_last_product_added_to_cart_upon_ajax_redirect' ) );
add_action( 'woocommerce_after_cart', array( $this, 'inject_add_to_cart_redirect_event' ), 10, 2 );
add_action( 'wp_head', array( WC_Facebookcommerce_Utils::class, 'print_deferred_events' ) );
add_action( 'shutdown', array( WC_Facebookcommerce_Utils::class, 'save_deferred_events' ) );
}

// InitiateCheckout events
Expand Down Expand Up @@ -563,8 +562,8 @@ public function inject_add_to_cart_event( $cart_item_key, $product_id, $quantity
return;
}

// Cut off cart clones.
message-dimke marked this conversation as resolved.
Show resolved Hide resolved
$cart = WC()->cart;
// Check if we're dealing with cloned cart
if ( ! isset( $cart->cart_contents[ $cart_item_key ] ) ) {
return;
}
Expand Down Expand Up @@ -736,86 +735,6 @@ public function add_conditional_add_to_cart_event_fragment( $fragments ) {
return $fragments;
}


/**
* Sets last product added to cart to session when adding to cart a product and redirection to cart is enabled.
*
* @internal
*
* @since 1.10.2
*
* @param string $redirect URL redirecting to (usually cart)
* @param null|\WC_Product $product the product just added to the cart
* @return string
*/
public function set_last_product_added_to_cart_upon_redirect( $redirect, $product = null ) {

// Bail if the session variable has been set or WC()->session is null.
if ( ! isset( WC()->session ) || WC()->session->get( 'facebook_for_woocommerce_last_product_added_to_cart', 0 ) > 0 ) {
return $redirect;
}

$product_id = 0;

if ( $product instanceof \WC_Product ) {
$product_id = isset( $_POST['variation_id'] ) ? wc_clean( wp_unslash( $_POST['variation_id'] ) ) : $product->get_id();
} elseif ( isset( $_GET['add-to-cart'] ) && is_numeric( wc_clean( wp_unslash( $_GET['add-to-cart'] ) ) ) ) {
$product_id = wc_clean( wp_unslash( $_GET['add-to-cart'] ) );
}

WC()->session->set( 'facebook_for_woocommerce_last_product_added_to_cart', (int) $product_id );

return $redirect;

}


/**
* Sets last product added to cart to session when adding a product to cart from an archive page and both AJAX adding and redirection to cart are enabled.
*
* @internal
*
* @since 1.10.2
*
* @param null|int $product_id the ID of the product just added to the cart
*/
public function set_last_product_added_to_cart_upon_ajax_redirect( $product_id = null ) {

if ( ! $product_id ) {
facebook_for_woocommerce()->log( 'Cannot record AddToCart event because the product cannot be determined. Backtrace: ' . print_r( wp_debug_backtrace_summary(), true ) );
return;
}

$product = wc_get_product( $product_id );

if ( $product instanceof \WC_Product ) {
WC()->session->set( 'facebook_for_woocommerce_last_product_added_to_cart', $product->get_id() );
}
}


/**
* Triggers an AddToCart event when redirecting to the cart page.
*
* @internal
*/
public function inject_add_to_cart_redirect_event() {

if ( ! $this->is_pixel_enabled() ) {
return;
}

$last_product_id = WC()->session->get( 'facebook_for_woocommerce_last_product_added_to_cart', 0 );

if ( $last_product_id > 0 ) {

$this->inject_add_to_cart_event( '', $last_product_id, 1, 0 );

WC()->session->set( 'facebook_for_woocommerce_last_product_added_to_cart', 0 );
}
}


/**
* Triggers an InitiateCheckout event when customer reaches checkout page.
*
Expand Down
7 changes: 4 additions & 3 deletions facebook-commerce-pixel-event.php
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,16 @@ public function get_event_script( $event_name, $params, $method = 'track' ) {
* @param string $method Name of the pixel's fbq() function to call.
*/
public function inject_event( $event_name, $params, $method = 'track' ) {

// If we have add to cart redirect enabled, we must defer the events to render them the next page load.
$defer = 'yes' === get_option( 'woocommerce_cart_redirect_after_add', 'no' );
if ( \WC_Facebookcommerce_Utils::isWoocommerceIntegration() ) {
\WC_Facebookcommerce_Utils::wc_enqueue_js( $this->get_event_code( $event_name, self::build_params( $params, $event_name ), $method ) );
\WC_Facebookcommerce_Utils::wc_enqueue_js( $this->get_event_code( $event_name, self::build_params( $params, $event_name ), $method ), $defer );
} else {
// @TODO: if this one is ever used. Doubts have I.
message-dimke marked this conversation as resolved.
Show resolved Hide resolved
printf( $this->get_event_script( $event_name, self::build_params( $params, $event_name ), $method ) ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
}
}


/**
* Gets the JavaScript code to track a conditional event wrapped in <script> tag.
*
Expand Down
93 changes: 92 additions & 1 deletion includes/fbutils.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,90 @@ class WC_Facebookcommerce_Utils {
'female' => 1,
'unisex' => 1,
);

/**
* A deferred events storage.
*
* @var array
*
* @since x.x.x
*/
private static $deferred_events = [];

/**
* Prints deferred events into page header.
*
* @return void
*
* @since x.x.x
*/
public static function print_deferred_events() {
$deferred_events = static::load_deferred_events();
if ( ! empty( $deferred_events ) ) {
echo '<script>' . implode( PHP_EOL, $deferred_events ) . '</script>'; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped --- Printing hardcoded JS tracking code.
}
}

/**
* Loads deferred event from the storage.
*
* @return array
*
* @since x.x.x
*/
private static function load_deferred_events(): array {
$transient_key = static::get_deferred_events_transient_key();
if ( $transient_key ) {
message-dimke marked this conversation as resolved.
Show resolved Hide resolved
$deferred_events = get_transient( $transient_key );
if ( $deferred_events ) {
delete_transient( $transient_key );
return $deferred_events;
}
}
return array();
}

/**
* Adds event into the list of events to be saved/rendered.
*
* @param string $code Generated JS code string w/o a script tag.
*
* @return void
*
* @since x.x.x
*/
private static function add_deferred_event( string $code ): void {
static::$deferred_events[] = $code;
}

/**
* Saves deferred events into the storage.
*
* @return void
*
* @since x.x.x
*/
public static function save_deferred_events() {
message-dimke marked this conversation as resolved.
Show resolved Hide resolved
$transient_key = static::get_deferred_events_transient_key();
if ( ! empty( static::$deferred_events ) ) {
set_transient( $transient_key, static::$deferred_events, 60 * 60 * 24 );
message-dimke marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* Returns the transient key for deferred events based on user session.
*
* @return string
*
* @since x.x.x
*/
private static function get_deferred_events_transient_key(): string {
if ( is_object( WC()->session ) ) {
return 'pinterest_for_woocommerce_async_events_' . md5( WC()->session->get_customer_id() );
message-dimke marked this conversation as resolved.
Show resolved Hide resolved
}
return '';
}

/**
* WooCommerce 2.1 support for wc_enqueue_js
*
Expand All @@ -51,9 +135,16 @@ class WC_Facebookcommerce_Utils {
* @param string $code
* @return void
*/
public static function wc_enqueue_js( $code ) {
public static function wc_enqueue_js( $code, $defer = false ) {
message-dimke marked this conversation as resolved.
Show resolved Hide resolved
global $wc_queued_js;

// Saves for later output with the next page render.
if ( $defer ) {
static::add_deferred_event( $code );
return;
}

// Immediately renders code in the footer.
if ( function_exists( 'wc_enqueue_js' ) && empty( $wc_queued_js ) ) {
wc_enqueue_js( $code );
} else {
Expand Down
Loading