PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.0.2
Jetpack – WP Security, Backup, Speed, & Growth v13.0.2
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / woocommerce-analytics / classes / class-jetpack-woocommerce-analytics-trait.php
jetpack / modules / woocommerce-analytics / classes Last commit date
class-jetpack-woocommerce-analytics-checkout-flow.php 2 years ago class-jetpack-woocommerce-analytics-my-account.php 2 years ago class-jetpack-woocommerce-analytics-trait.php 2 years ago class-jetpack-woocommerce-analytics-universal.php 2 years ago
class-jetpack-woocommerce-analytics-trait.php
571 lines
1 <?php
2 /**
3 * Jetpack_WooCommerce_Analytics_Trait
4 *
5 * @package automattic/jetpack
6 * @author Automattic
7 */
8
9 /**
10 * Bail if accessed directly
11 */
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Jetpack_WooCommerce_Analytics_Trait
18 * Common functionality for WooCommerce Analytics classes.
19 */
20 trait Jetpack_WooCommerce_Analytics_Trait {
21
22 /**
23 * Saves whether the cart/checkout templates are in use based on WC Blocks version.
24 *
25 * @var bool true if the templates are in use.
26 */
27 protected $cart_checkout_templates_in_use;
28
29 /**
30 * The content of the cart page or where the cart page is ultimately derived from if using a template.
31 *
32 * @var string
33 */
34 protected $cart_content_source = '';
35
36 /**
37 * The content of the checkout page or where the cart page is ultimately derived from if using a template.
38 *
39 * @var string
40 */
41 protected $checkout_content_source = '';
42
43 /**
44 * Tracks any additional blocks loaded on the Cart page.
45 *
46 * @var array
47 */
48 protected $additional_blocks_on_cart_page;
49
50 /**
51 * Tracks any additional blocks loaded on the Checkout page.
52 *
53 * @var array
54 */
55 protected $additional_blocks_on_checkout_page;
56
57 /**
58 * Format Cart Items or Order Items to an array
59 *
60 * @param array|WC_Order_Item[] $items Cart Items or Order Items.
61 */
62 protected function format_items_to_json( $items ) {
63 $products = array();
64
65 foreach ( $items as $item ) {
66 if ( $item instanceof WC_Order_Item_Product ) {
67 $product = wc_get_product( $item->get_product_id() );
68 } else {
69 $product = $item['data'];
70 }
71 $data = $this->get_product_details( $product );
72 if ( $item instanceof WC_Order_Item_Product ) {
73 $data['pq'] = $item->get_quantity();
74 } else {
75 $data['pq'] = $item['quantity'];
76 }
77 $products[] = $data;
78 }
79
80 return wp_json_encode( $products );
81 }
82
83 /**
84 * Get Cart/Checkout page view shared data
85 */
86 protected function get_cart_checkout_shared_data() {
87 $cart = WC()->cart;
88
89 $guest_checkout = ucfirst( get_option( 'woocommerce_enable_guest_checkout', 'No' ) );
90 $create_account = ucfirst( get_option( 'woocommerce_enable_signup_and_login_from_checkout', 'No' ) );
91
92 $coupons = $cart->get_coupons();
93 $coupon_used = 0;
94 if ( is_countable( $coupons ) ) {
95 $coupon_used = count( $coupons ) ? 1 : 0;
96 }
97
98 $enabled_payment_options = array_filter(
99 WC()->payment_gateways->get_available_payment_gateways(),
100 function ( $payment_gateway ) {
101 if ( ! $payment_gateway instanceof WC_Payment_Gateway ) {
102 return false;
103 }
104
105 return $payment_gateway->is_available();
106 }
107 );
108
109 $enabled_payment_options = array_keys( $enabled_payment_options );
110
111 $shared_data = array(
112 'products' => $this->format_items_to_json( $cart->get_cart() ),
113 'create_account' => $create_account,
114 'guest_checkout' => $guest_checkout,
115 'express_checkout' => 'null', // TODO: not solved yet.
116 'products_count' => $cart->get_cart_contents_count(),
117 'order_value' => $cart->get_cart_total(),
118 'shipping_options_count' => 'null', // TODO: not solved yet.
119 'coupon_used' => $coupon_used,
120 'payment_options' => $enabled_payment_options,
121 );
122
123 return $shared_data;
124 }
125
126 /**
127 * Gets the content of the cart/checkout page or where the cart/checkout page is ultimately derived from if using a template.
128 * This method sets the class properties $checkout_content_source and $cart_content_source.
129 *
130 * @return void Does not return, but sets class properties.
131 */
132 public function find_cart_checkout_content_sources() {
133
134 /**
135 * The steps we take to find the content are:
136 * 1. Check the transient, if that contains content and is not expired, return that.
137 * 2. Check if the cart/checkout templates are in use. If *not in use*, get the content from the pages and
138 * return it, there is no need to dig further.
139 * 3. If the templates *are* in use, check if the `page-content-wrapper` block is in use. If so, get the content
140 * from the pages (same as step 2) and return it.
141 * 4. If the templates are in use but `page-content-wrapper` is not, then get the content directly from the
142 * template and return it.
143 * 5. At the end of each step, assign the found content to the relevant class properties and save them in a
144 * transient with a 1-day lifespan. This will prevent us from having to do this work on every page load.
145 */
146
147 $cart_checkout_content_cache_transient_name = 'jetpack_woocommerce_analytics_cart_checkout_content_sources';
148
149 $transient_value = get_transient( $cart_checkout_content_cache_transient_name );
150
151 if (
152 false !== $transient_value &&
153 ! empty( $transient_value['checkout_content_source'] ) &&
154 ! empty( $transient_value['cart_content_source'] )
155 ) {
156 $this->cart_content_source = $transient_value['cart_content_source'];
157 $this->checkout_content_source = $transient_value['checkout_content_source'];
158 return;
159 }
160
161 $this->cart_checkout_templates_in_use = wp_is_block_theme() && class_exists( 'Automattic\WooCommerce\Blocks\Package' ) && version_compare( Automattic\WooCommerce\Blocks\Package::get_version(), '10.6.0', '>=' );
162
163 // Cart/Checkout *pages* are in use if the templates are not in use. Return their content and do nothing else.
164 if ( ! $this->cart_checkout_templates_in_use ) {
165 $cart_page = get_post( wc_get_page_id( 'cart' ) );
166 $checkout_page = get_post( wc_get_page_id( 'checkout' ) );
167
168 if ( $cart_page && isset( $cart_page->post_content ) ) {
169 $this->cart_content_source = $cart_page->post_content;
170 }
171
172 if ( $checkout_page && isset( $checkout_page->post_content ) ) {
173 $this->checkout_content_source = $checkout_page->post_content;
174 }
175
176 set_transient(
177 $cart_checkout_content_cache_transient_name,
178 array(
179 'cart_content_source' => $this->cart_content_source,
180 'checkout_content_source' => $this->checkout_content_source,
181 ),
182 DAY_IN_SECONDS
183 );
184 return;
185 }
186
187 // We are in a Block theme - so we need to find out if the templates are being used.
188 if ( function_exists( 'get_block_template' ) ) {
189 $checkout_template = get_block_template( 'woocommerce/woocommerce//page-checkout' );
190 $cart_template = get_block_template( 'woocommerce/woocommerce//page-cart' );
191
192 if ( ! $checkout_template ) {
193 $checkout_template = get_block_template( 'woocommerce/woocommerce//checkout' );
194 }
195
196 if ( ! $cart_template ) {
197 $cart_template = get_block_template( 'woocommerce/woocommerce//cart' );
198 }
199 }
200
201 if ( function_exists( 'gutenberg_get_block_template' ) ) {
202 $checkout_template = gutenberg_get_block_template( 'woocommerce/woocommerce//page-checkout' );
203 $cart_template = gutenberg_get_block_template( 'woocommerce/woocommerce//page-cart' );
204
205 if ( ! $checkout_template ) {
206 $checkout_template = gutenberg_get_block_template( 'woocommerce/woocommerce//checkout' );
207 }
208
209 if ( ! $cart_template ) {
210 $cart_template = gutenberg_get_block_template( 'woocommerce/woocommerce//cart' );
211 }
212 }
213
214 if ( ! empty( $checkout_template->content ) ) {
215 // Checkout template is in use, but we need to see if the page-content-wrapper is in use, or if the template is being used directly.
216 $this->checkout_content_source = $checkout_template->content;
217 $is_using_page_content = str_contains( $checkout_template->content, '<!-- wp:woocommerce/page-content-wrapper {"page":"checkout"}' );
218
219 if ( $is_using_page_content ) {
220 // The page-content-wrapper is in use, so we need to get the page content.
221 $checkout_page = get_post( wc_get_page_id( 'checkout' ) );
222
223 if ( $checkout_page && isset( $checkout_page->post_content ) ) {
224 $this->checkout_content_source = $checkout_page->post_content;
225 }
226 }
227 }
228
229 if ( ! empty( $cart_template->content ) ) {
230 // Cart template is in use, but we need to see if the page-content-wrapper is in use, or if the template is being used directly.
231 $this->cart_content_source = $cart_template->content;
232 $is_using_page_content = str_contains( $cart_template->content, '<!-- wp:woocommerce/page-content-wrapper {"page":"cart"}' );
233
234 if ( $is_using_page_content ) {
235 // The page-content-wrapper is in use, so we need to get the page content.
236 $cart_page = get_post( wc_get_page_id( 'cart' ) );
237
238 if ( $cart_page && isset( $cart_page->post_content ) ) {
239 $this->cart_content_source = $cart_page->post_content;
240 }
241 }
242 }
243
244 set_transient(
245 $cart_checkout_content_cache_transient_name,
246 array(
247 'cart_content_source' => $this->cart_content_source,
248 'checkout_content_source' => $this->checkout_content_source,
249 ),
250 DAY_IN_SECONDS
251 );
252 }
253
254 /**
255 * Default event properties which should be included with all events.
256 *
257 * @return array Array of standard event props.
258 */
259 public function get_common_properties() {
260 $site_info = array(
261 'blog_id' => Jetpack::get_option( 'id' ),
262 'ui' => $this->get_user_id(),
263 'url' => home_url(),
264 'woo_version' => WC()->version,
265 'store_admin' => in_array( 'administrator', wp_get_current_user()->roles, true ) ? 1 : 0,
266 'device' => wp_is_mobile() ? 'mobile' : 'desktop',
267 'template_used' => $this->cart_checkout_templates_in_use ? '1' : '0',
268 'additional_blocks_on_cart_page' => $this->additional_blocks_on_cart_page,
269 'additional_blocks_on_checkout_page' => $this->additional_blocks_on_checkout_page,
270 'store_currency' => get_woocommerce_currency(),
271 );
272 $cart_checkout_info = $this->get_cart_checkout_info();
273 return array_merge( $site_info, $cart_checkout_info );
274 }
275
276 /**
277 * Render tracks event properties as string of JavaScript object props.
278 *
279 * @param array $properties Array of key/value pairs.
280 * @return string String of the form "key1: value1, key2: value2, " (etc).
281 */
282 private function render_properties_as_js( $properties ) {
283 $js_args_string = '';
284 foreach ( $properties as $key => $value ) {
285 if ( is_array( $value ) ) {
286 $js_args_string = $js_args_string . "'$key': " . wp_json_encode( $value ) . ',';
287 } else {
288 $js_args_string = $js_args_string . "'$key': '" . esc_js( $value ) . "', ";
289 }
290 }
291 return $js_args_string;
292 }
293
294 /**
295 * Record an event with optional product and custom properties.
296 *
297 * @param string $event_name The name of the event to record.
298 * @param array $properties Optional array of (key => value) event properties.
299 * @param integer $product_id The id of the product relating to the event.
300 *
301 * @return string|void
302 */
303 public function record_event( $event_name, $properties = array(), $product_id = null ) {
304 $js = $this->process_event_properties( $event_name, $properties, $product_id );
305 wc_enqueue_js( "_wca.push({$js});" );
306 }
307
308 /**
309 * Gather relevant product information
310 *
311 * @param \WC_Product $product product.
312 * @return array
313 */
314 public function get_product_details( $product ) {
315 return array(
316 'pi' => $product->get_id(),
317 'pn' => $product->get_title(),
318 'pc' => $this->get_product_categories_concatenated( $product ),
319 'pp' => $product->get_price(),
320 'pt' => $product->get_type(),
321 );
322 }
323
324 /**
325 * Gets product categories or varation attributes as a formatted concatenated string
326 *
327 * @param object $product WC_Product.
328 * @return string
329 */
330 public function get_product_categories_concatenated( $product ) {
331
332 if ( ! $product instanceof WC_Product ) {
333 return '';
334 }
335
336 $variation_data = $product->is_type( 'variation' ) ? wc_get_product_variation_attributes( $product->get_id() ) : '';
337 if ( is_array( $variation_data ) && ! empty( $variation_data ) ) {
338 $line = wc_get_formatted_variation( $variation_data, true );
339 } else {
340 $out = array();
341 $categories = get_the_terms( $product->get_id(), 'product_cat' );
342 if ( $categories ) {
343 foreach ( $categories as $category ) {
344 $out[] = $category->name;
345 }
346 }
347 $line = implode( '/', $out );
348 }
349 return $line;
350 }
351
352 /**
353 * Compose event properties.
354 *
355 * @param string $event_name The name of the event to record.
356 * @param array $properties Optional array of (key => value) event properties.
357 * @param integer $product_id Optional id of the product relating to the event.
358 *
359 * @return string|void
360 */
361 public function process_event_properties( $event_name, $properties = array(), $product_id = null ) {
362
363 // Only set product details if we have a product id.
364 if ( $product_id ) {
365 $product = wc_get_product( $product_id );
366 if ( ! $product instanceof WC_Product ) {
367 return;
368 }
369 $product_details = $this->get_product_details( $product );
370 }
371
372 /**
373 * Allow defining custom event properties in WooCommerce Analytics.
374 *
375 * @module woocommerce-analytics
376 *
377 * @since 12.5
378 *
379 * @param array $all_props Array of event props to be filtered.
380 */
381 $all_props = apply_filters(
382 'jetpack_woocommerce_analytics_event_props',
383 array_merge(
384 $properties,
385 $this->get_common_properties()
386 )
387 );
388
389 $js = "{'_en': '" . esc_js( $event_name ) . "'";
390
391 if ( isset( $product_details ) ) {
392 $all_props = array_merge( $all_props, $product_details );
393 }
394
395 $js .= ',' . $this->render_properties_as_js( $all_props ) . '}';
396
397 return $js;
398 }
399
400 /**
401 * Get the current user id
402 *
403 * @return int
404 */
405 public function get_user_id() {
406 if ( is_user_logged_in() ) {
407 $blogid = Jetpack::get_option( 'id' );
408 $userid = get_current_user_id();
409 return $blogid . ':' . $userid;
410 }
411 return 'null';
412 }
413
414 /**
415 * Gets the IDs of additional blocks on the Cart/Checkout pages or templates.
416 *
417 * @param string $cart_or_checkout Whether to get blocks on the cart or checkout page.
418 * @return array All inner blocks on the page.
419 */
420 public function get_additional_blocks_on_page( $cart_or_checkout = 'cart' ) {
421
422 $additional_blocks_on_page_transient_name = 'jetpack_woocommerce_analytics_additional_blocks_on_' . $cart_or_checkout . '_page';
423 $additional_blocks_on_page = get_transient( $additional_blocks_on_page_transient_name );
424
425 if ( false !== $additional_blocks_on_page ) {
426 return $additional_blocks_on_page;
427 }
428
429 $content = $this->cart_content_source;
430
431 if ( 'checkout' === $cart_or_checkout ) {
432 $content = $this->checkout_content_source;
433 }
434
435 $parsed_blocks = parse_blocks( $content );
436 $other_blocks = array_filter(
437 $parsed_blocks,
438 function ( $block ) use ( $cart_or_checkout ) {
439 if ( ! isset( $block['blockName'] ) ) {
440 return false;
441 }
442
443 if ( 'woocommerce/classic-shortcode' === $block['blockName'] ) {
444 return false;
445 }
446
447 if ( 'core/shortcode' === $block['blockName'] ) {
448 return false;
449 }
450
451 if ( 'checkout' === $cart_or_checkout && 'woocommerce/checkout' !== $block['blockName'] ) {
452 return true;
453 }
454
455 if ( 'cart' === $cart_or_checkout && 'woocommerce/cart' !== $block['blockName'] ) {
456 return true;
457 }
458
459 return false;
460 }
461 );
462
463 $all_inner_blocks = array();
464
465 // Loop over each "block group". In templates the blocks are grouped up.
466 foreach ( $other_blocks as $block ) {
467
468 // This check is necessary because sometimes this is null when using templates.
469 if ( ! empty( $block['blockName'] ) ) {
470 $all_inner_blocks[] = $block['blockName'];
471 }
472
473 if ( ! isset( $block['innerBlocks'] ) || ! is_array( $block['innerBlocks'] ) || 0 === count( $block['innerBlocks'] ) ) {
474 continue;
475 }
476
477 foreach ( $block['innerBlocks'] as $inner_content ) {
478 $all_inner_blocks = array_merge( $all_inner_blocks, $this->get_inner_blocks( $inner_content ) );
479 }
480 }
481 set_transient( $additional_blocks_on_page_transient_name, $all_inner_blocks, DAY_IN_SECONDS );
482 return $all_inner_blocks;
483 }
484
485 /**
486 * Gets an array containing the block or shortcode use properties for the Cart page.
487 *
488 * @return array An array containing the block or shortcode use properties for the Cart page.
489 */
490 public function get_cart_page_block_usage() {
491 $new_info = array();
492
493 $content = $this->cart_content_source;
494 $block_presence = str_contains( $content, '<!-- wp:woocommerce/cart' );
495 $shortcode_presence = str_contains( $content, '[woocommerce_cart]' );
496 $classic_shortcode_presence = str_contains( $content, '<!-- wp:woocommerce/classic-shortcode' );
497
498 $new_info['cart_page_contains_cart_block'] = $block_presence ? '1' : '0';
499 $new_info['cart_page_contains_cart_shortcode'] = $shortcode_presence || $classic_shortcode_presence ? '1' : '0';
500 return $new_info;
501 }
502
503 /**
504 * Gets an array containing the block or shortcode use properties for the Checkout page.
505 *
506 * @return array An array containing the block or shortcode use properties for the Checkout page.
507 */
508 public function get_checkout_page_block_usage() {
509 $new_info = array();
510
511 $content = $this->checkout_content_source;
512 $block_presence = str_contains( $content, '<!-- wp:woocommerce/checkout' );
513 $shortcode_presence = str_contains( $content, '[woocommerce_checkout]' );
514 $classic_shortcode_presence = str_contains( $content, '<!-- wp:woocommerce/classic-shortcode' );
515
516 $new_info['checkout_page_contains_checkout_block'] = $block_presence ? '1' : '0';
517 $new_info['checkout_page_contains_checkout_shortcode'] = $shortcode_presence || $classic_shortcode_presence ? '1' : '0';
518 return $new_info;
519 }
520
521 /**
522 * Get info about the cart & checkout pages, in particular
523 * whether the store is using shortcodes or Gutenberg blocks.
524 * This info is cached in a transient.
525 *
526 * Note: similar code is in a WooCommerce core PR:
527 * https://github.com/woocommerce/woocommerce/pull/25932
528 *
529 * @return array
530 */
531 public function get_cart_checkout_info() {
532 $info = array_merge(
533 $this->get_cart_page_block_usage(),
534 $this->get_checkout_page_block_usage()
535 );
536 return $info;
537 }
538
539 /**
540 * Search a specific post for text content.
541 *
542 * Note: similar code is in a WooCommerce core PR:
543 * https://github.com/woocommerce/woocommerce/pull/25932
544 *
545 * @param integer $post_id The id of the post to search.
546 * @param string $text The text to search for.
547 * @return integer 1 if post contains $text (otherwise 0).
548 */
549 public function post_contains_text( $post_id, $text ) {
550 global $wpdb;
551
552 // Search for the text anywhere in the post.
553 $wildcarded = "%{$text}%";
554
555 // No better way to search post content without having filters expanding blocks.
556 // This is already cached up in the parent function.
557 $result = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
558 $wpdb->prepare(
559 "
560 SELECT COUNT( * ) FROM {$wpdb->prefix}posts
561 WHERE ID=%d
562 AND {$wpdb->prefix}posts.post_content LIKE %s
563 ",
564 array( $post_id, $wildcarded )
565 )
566 );
567
568 return ( '0' !== $result ) ? 1 : 0;
569 }
570 }
571