@@ -25,6 +25,23 @@ class WooCommerce extends Conversion_Events_Provider {
2525
2626 const CONVERSION_EVENT_PROVIDER_SLUG = 'woocommerce ' ;
2727
28+ /**
29+ * Avaialble products on the page.
30+ *
31+ * @var Array
32+ *
33+ * @since n.e.x.t
34+ */
35+ protected $ products = array ();
36+
37+ /**
38+ * Current product added to the cart.
39+ *
40+ * @since n.e.x.t
41+ * @var WC_Product
42+ */
43+ protected $ add_to_cart ;
44+
2845 /**
2946 * Checks if the WooCommerce plugin is active.
3047 *
@@ -77,6 +94,31 @@ public function register_script() {
7794 public function register_hooks () {
7895 $ input = $ this ->context ->input ();
7996
97+ add_filter (
98+ 'woocommerce_loop_add_to_cart_link ' ,
99+ function ( $ button , $ product ) {
100+ $ this ->products [] = $ this ->get_formatted_product ( $ product );
101+
102+ return $ button ;
103+ },
104+ 10 ,
105+ 2
106+ );
107+
108+ add_action (
109+ 'woocommerce_add_to_cart ' ,
110+ function ( $ cart_item_key , $ product_id , $ quantity , $ variation_id , $ variation ) {
111+ $ this ->add_to_cart = $ this ->get_formatted_product (
112+ wc_get_product ( $ product_id ),
113+ $ variation_id ,
114+ $ variation ,
115+ $ quantity
116+ );
117+ },
118+ 10 ,
119+ 5
120+ );
121+
80122 add_action (
81123 'woocommerce_thankyou ' ,
82124 function ( $ order_id ) use ( $ input ) {
@@ -102,12 +144,168 @@ function ( $order_id ) use ( $input ) {
102144 $ order ->update_meta_data ( '_googlesitekit_ga_purchase_event_tracked ' , 1 );
103145 $ order ->save ();
104146
147+ wp_add_inline_script (
148+ 'googlesitekit-events-provider- ' . self ::CONVERSION_EVENT_PROVIDER_SLUG ,
149+ join (
150+ "\n" ,
151+ array (
152+ 'window._googlesitekit.wcdata = window._googlesitekit.wcdata || {}; ' ,
153+ sprintf ( 'window._googlesitekit.wcdata.purchase = %s; ' , wp_json_encode ( $ this ->get_formatted_order ( $ order ) ) ),
154+ )
155+ ),
156+ 'before '
157+ );
158+
105159 // Output the script tag to track the purchase event in
106160 // Analytics.
107161 BC_Functions::wp_print_inline_script_tag ( "window?._googlesitekit?.gtagEvent?.( 'purchase' ); " );
108162 },
109163 10 ,
110164 1
111165 );
166+
167+ add_action (
168+ 'wp_footer ' ,
169+ function () {
170+ $ script_slug = 'googlesitekit-events-provider- ' . self ::CONVERSION_EVENT_PROVIDER_SLUG ;
171+
172+ $ inline_script = join (
173+ "\n" ,
174+ array (
175+ 'window._googlesitekit.wcdata = window._googlesitekit.wcdata || {}; ' ,
176+ sprintf ( 'window._googlesitekit.wcdata.products = %s; ' , wp_json_encode ( $ this ->products ) ),
177+ sprintf ( 'window._googlesitekit.wcdata.add_to_cart = %s; ' , wp_json_encode ( $ this ->add_to_cart ) ),
178+ sprintf ( 'window._googlesitekit.wcdata.currency = "%s"; ' , esc_js ( get_woocommerce_currency () ) ),
179+ )
180+ );
181+
182+ wp_add_inline_script ( $ script_slug , $ inline_script , 'before ' );
183+ }
184+ );
185+ }
186+
187+ /**
188+ * Returns an array of product data in the required format.
189+ * Adapted from https://github.com/woocommerce/woocommerce-google-analytics-integration
190+ *
191+ * @since n.e.x.t
192+ *
193+ * @param WC_Product $product The product to format.
194+ * @param int $variation_id Variation product ID.
195+ * @param array|bool $variation An array containing product variation attributes to include in the product data.
196+ * For the "variation" type products, we'll use product->get_attributes.
197+ * @param bool|int $quantity Quantity to include in the formatted product object.
198+ *
199+ * @return array
200+ */
201+ public function get_formatted_product ( $ product , $ variation_id = 0 , $ variation = false , $ quantity = false ) {
202+ $ product_id = $ product ->is_type ( 'variation ' ) ? $ product ->get_parent_id () : $ product ->get_id ();
203+ $ price = $ product ->get_price ();
204+
205+ // Get product price from chosen variation if set.
206+ if ( $ variation_id ) {
207+ $ variation_product = wc_get_product ( $ variation_id );
208+ if ( $ variation_product ) {
209+ $ price = $ variation_product ->get_price ();
210+ }
211+ }
212+
213+ // Integration with Product Bundles.
214+ // Get the minimum price, as `get_price` may return 0 if the product is a bundle and the price is potentially a range.
215+ // Even a range containing a single value.
216+ if ( $ product ->is_type ( 'bundle ' ) && is_callable ( array ( $ product , 'get_bundle_price ' ) ) ) {
217+ $ price = $ product ->get_bundle_price ( 'min ' );
218+ }
219+
220+ $ formatted = array (
221+ 'id ' => $ product_id ,
222+ 'name ' => $ product ->get_title (),
223+ 'categories ' => array_map (
224+ fn ( $ category ) => array ( 'name ' => $ category ->name ),
225+ wc_get_product_terms ( $ product_id , 'product_cat ' , array ( 'number ' => 5 ) )
226+ ),
227+ 'price ' => $ this ->get_formatted_price ( $ price ),
228+ );
229+
230+ if ( $ quantity ) {
231+ $ formatted ['quantity ' ] = (int ) $ quantity ;
232+ }
233+
234+ if ( $ product ->is_type ( 'variation ' ) ) {
235+ $ variation = $ product ->get_attributes ();
236+ }
237+
238+ if ( is_array ( $ variation ) ) {
239+ $ formatted ['variation ' ] = implode (
240+ ', ' ,
241+ array_map (
242+ function ( $ attribute , $ value ) {
243+ return sprintf (
244+ '%s: %s ' ,
245+ str_replace ( 'attribute_ ' , '' , $ attribute ),
246+ $ value
247+ );
248+ },
249+ array_keys ( $ variation ),
250+ array_values ( $ variation )
251+ )
252+ );
253+ }
254+
255+ return $ formatted ;
256+ }
257+
258+ /**
259+ * Returns an array of order data in the required format.
260+ * Adapted from https://github.com/woocommerce/woocommerce-google-analytics-integration
261+ *
262+ * @since n.e.x.t
263+ *
264+ * @param WC_Abstract_Order $order An instance of the WooCommerce Order object.
265+ *
266+ * @return array
267+ */
268+ public function get_formatted_order ( $ order ) {
269+ return array (
270+ 'id ' => $ order ->get_id (),
271+ 'affiliation ' => get_bloginfo ( 'name ' ),
272+ 'totals ' => array (
273+ 'currency_code ' => $ order ->get_currency (),
274+ 'tax_total ' => $ this ->get_formatted_price ( $ order ->get_total_tax () ),
275+ 'shipping_total ' => $ this ->get_formatted_price ( $ order ->get_total_shipping () ),
276+ 'total_price ' => $ this ->get_formatted_price ( $ order ->get_total () ),
277+ ),
278+ 'items ' => array_map (
279+ function ( $ item ) {
280+ return array_merge (
281+ $ this ->get_formatted_product ( $ item ->get_product () ),
282+ array (
283+ 'quantity ' => $ item ->get_quantity (),
284+ 'price_after_coupon_discount ' => $ this ->get_formatted_price ( $ item ->get_total () ),
285+ )
286+ );
287+ },
288+ array_values ( $ order ->get_items () ),
289+ ),
290+ );
291+ }
292+
293+ /**
294+ * Formats a price the same way WooCommerce Blocks does.
295+ * Taken from https://github.com/woocommerce/woocommerce-google-analytics-integration
296+ *
297+ * @since n.e.x.t
298+ *
299+ * @param mixed $value The price value for format.
300+ *
301+ * @return int
302+ */
303+ public function get_formatted_price ( $ value ) {
304+ return intval (
305+ round (
306+ ( (float ) wc_format_decimal ( $ value ) ) * ( 10 ** absint ( wc_get_price_decimals () ) ),
307+ 0
308+ )
309+ );
112310 }
113311}
0 commit comments