PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.3
WooCommerce v10.9.3
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Internal / Admin / CustomerEffortScoreTracks.php
woocommerce / src / Internal / Admin Last commit date
Agentic 4 months ago BlockTemplates 4 weeks ago EmailImprovements 1 year ago EmailPreview 4 weeks ago Emails 1 year ago ImportExport 1 year ago Logging 1 year ago Marketing 2 years ago Notes 4 weeks ago Onboarding 5 months ago Orders 4 weeks ago ProductForm 2 years ago ProductReviews 4 weeks ago RemoteFreeExtensions 4 weeks ago Schedulers 4 weeks ago Settings 5 days ago Suggestions 4 weeks ago WCPayPromotion 10 months ago ActivityPanels.php 3 years ago Analytics.php 4 weeks ago CategoryLookup.php 4 years ago Coupons.php 1 year ago CouponsMovedTrait.php 5 months ago CustomerEffortScoreTracks.php 7 months ago Events.php 2 months ago FeaturePlugin.php 4 months ago Homescreen.php 1 month ago Loader.php 4 weeks ago Marketing.php 1 year ago Marketplace.php 5 months ago MobileAppBanner.php 4 years ago OrderMilestoneEasterEgg.php 4 weeks ago RemoteInboxNotifications.php 3 years ago Settings.php 5 days ago ShippingLabelBanner.php 1 year ago ShippingLabelBannerDisplayRules.php 1 year ago SiteHealth.php 3 years ago Survey.php 4 years ago SystemStatusReport.php 1 year ago Translations.php 1 year ago WCAdminAssets.php 5 days ago WCAdminSharedSettings.php 1 year ago WCAdminUser.php 9 months ago WcPayWelcomePage.php 1 year ago
CustomerEffortScoreTracks.php
655 lines
1 <?php
2 /**
3 * WooCommerce Customer effort score tracks
4 *
5 * @package WooCommerce\Admin\Features
6 */
7
8 namespace Automattic\WooCommerce\Internal\Admin;
9
10 defined( 'ABSPATH' ) || exit;
11
12 /**
13 * Triggers customer effort score on several different actions.
14 */
15 class CustomerEffortScoreTracks {
16 /**
17 * Option name for the CES Tracks queue.
18 */
19 const CES_TRACKS_QUEUE_OPTION_NAME = 'woocommerce_ces_tracks_queue';
20
21 /**
22 * Option name for the clear CES Tracks queue for page.
23 */
24 const CLEAR_CES_TRACKS_QUEUE_FOR_PAGE_OPTION_NAME =
25 'woocommerce_clear_ces_tracks_queue_for_page';
26
27 /**
28 * Option name for the set of actions that have been shown.
29 */
30 const SHOWN_FOR_ACTIONS_OPTION_NAME = 'woocommerce_ces_shown_for_actions';
31
32 /**
33 * Action name for product add/publish.
34 */
35 const PRODUCT_ADD_PUBLISH_ACTION_NAME = 'product_add_publish';
36
37 /**
38 * Action name for product update.
39 */
40 const PRODUCT_UPDATE_ACTION_NAME = 'product_update';
41
42 /**
43 * Action name for shop order update.
44 */
45 const SHOP_ORDER_UPDATE_ACTION_NAME = 'shop_order_update';
46
47 /**
48 * Action name for settings change.
49 */
50 const SETTINGS_CHANGE_ACTION_NAME = 'settings_change';
51
52 /**
53 * Action name for add product categories.
54 */
55 const ADD_PRODUCT_CATEGORIES_ACTION_NAME = 'add_product_categories';
56
57 /**
58 * Action name for add product tags.
59 */
60 const ADD_PRODUCT_TAGS_ACTION_NAME = 'add_product_tags';
61
62 /*
63 * Action name for add product attributes.
64 */
65 const ADD_PRODUCT_ATTRIBUTES_ACTION_NAME = 'add_product_attributes';
66
67 /**
68 * Action name for import products.
69 */
70 const IMPORT_PRODUCTS_ACTION_NAME = 'import_products';
71
72 /**
73 * Action name for search.
74 */
75 const SEARCH_ACTION_NAME = 'ces_search';
76
77 /**
78 * Label for the snackbar that appears when a user submits the survey.
79 *
80 * @var string
81 */
82 private $onsubmit_label;
83
84 /**
85 * Constructor. Sets up filters to hook into WooCommerce.
86 */
87 public function __construct() {
88 $this->enable_survey_enqueing_if_tracking_is_enabled();
89 }
90
91 /**
92 * Add actions that require woocommerce_allow_tracking.
93 */
94 private function enable_survey_enqueing_if_tracking_is_enabled() {
95 // Only hook up the action handlers if in wp-admin.
96 if ( ! is_admin() ) {
97 return;
98 }
99
100 // Do not hook up the action handlers if a mobile device is used.
101 if ( wp_is_mobile() ) {
102 return;
103 }
104
105 // Only enqueue a survey if tracking is allowed.
106 $allow_tracking = 'yes' === get_option( 'woocommerce_allow_tracking', 'no' );
107 if ( ! $allow_tracking ) {
108 return;
109 }
110
111 add_action( 'admin_init', array( $this, 'maybe_clear_ces_tracks_queue' ) );
112 add_action( 'woocommerce_update_options', array( $this, 'run_on_update_options' ), 10, 3 );
113 add_action( 'product_cat_add_form', array( $this, 'add_script_track_product_categories' ), 10, 3 );
114 add_action( 'product_tag_add_form', array( $this, 'add_script_track_product_tags' ), 10, 3 );
115 add_action( 'woocommerce_attribute_added', array( $this, 'run_on_add_product_attributes' ), 10, 3 );
116 add_action( 'load-edit.php', array( $this, 'run_on_load_edit_php' ), 10, 3 );
117 add_action( 'product_page_product_importer', array( $this, 'run_on_product_import' ), 10, 3 );
118 // Only hook up the transition_post_status action handler
119 // if on the edit page.
120 global $pagenow;
121 if ( 'post.php' === $pagenow ) {
122 add_action(
123 'transition_post_status',
124 array(
125 $this,
126 'run_on_transition_post_status',
127 ),
128 10,
129 3
130 );
131 }
132 $this->onsubmit_label = __( 'Thank you for your feedback!', 'woocommerce' );
133 }
134
135 /**
136 * Returns a generated script for tracking tags added on edit-tags.php page.
137 * CES survey is triggered via direct access to wc/customer-effort-score store
138 * via wp.data.dispatch method.
139 *
140 * Due to lack of options to directly hook ourselves into the ajax post request
141 * initiated by edit-tags.php page, we infer a successful request by observing
142 * an increase of the number of rows in tags table
143 *
144 * @param string $action Action name for the survey.
145 * @param string $title Title for the snackbar.
146 * @param string $first_question The text for the first question.
147 * @param string $second_question The text for the second question.
148 *
149 * @return string Generated JavaScript to append to page.
150 */
151 private function get_script_track_edit_php( $action, $title, $first_question, $second_question ) {
152 return sprintf(
153 "(function( $ ) {
154 'use strict';
155 // Hook on submit button and sets a 1000ms interval function
156 // to determine successful add tag or otherwise.
157 $('#addtag #submit').on( 'click', function() {
158 const initialCount = $('.tags tbody > tr').length;
159 const interval = setInterval( function() {
160 if ( $('.tags tbody > tr').length > initialCount ) {
161 // New tag detected.
162 clearInterval( interval );
163 wp.data.dispatch('wc/customer-effort-score').addCesSurvey({ action: '%s', title: '%s', firstQuestion: '%s', secondQuestion: '%s', onsubmitLabel: '%s' });
164 } else {
165 // Form is no longer loading, most likely failed.
166 if ( $( '#addtag .submit .spinner.is-active' ).length < 1 ) {
167 clearInterval( interval );
168 }
169 }
170 }, 1000 );
171 });
172 })( jQuery );",
173 esc_js( $action ),
174 esc_js( $title ),
175 esc_js( $first_question ),
176 esc_js( $second_question ),
177 esc_js( $this->onsubmit_label )
178 );
179 }
180
181 /**
182 * Get the current published product count.
183 *
184 * @return integer The current published product count.
185 */
186 private function get_product_count() {
187 $query = new \WC_Product_Query(
188 array(
189 'limit' => 1,
190 'paginate' => true,
191 'return' => 'ids',
192 'status' => array( 'publish' ),
193 )
194 );
195 $products = $query->get_products();
196 $product_count = intval( $products->total );
197
198 return $product_count;
199 }
200
201 /**
202 * Get the current shop order count.
203 *
204 * @return integer The current shop order count.
205 */
206 private function get_shop_order_count() {
207 $query = new \WC_Order_Query(
208 array(
209 'limit' => 1,
210 'paginate' => true,
211 'return' => 'ids',
212 )
213 );
214 $shop_orders = $query->get_orders();
215 $shop_order_count = intval( $shop_orders->total );
216
217 return $shop_order_count;
218 }
219
220 /**
221 * Return whether the action has already been shown.
222 *
223 * @param string $action The action to check.
224 *
225 * @return bool Whether the action has already been shown.
226 */
227 private function has_been_shown( $action ) {
228 $shown_for_features = get_option( self::SHOWN_FOR_ACTIONS_OPTION_NAME, array() );
229 $has_been_shown = in_array( $action, $shown_for_features, true );
230
231 return $has_been_shown;
232 }
233
234 /**
235 * Enqueue the item to the CES tracks queue.
236 *
237 * @param array $item The item to enqueue.
238 */
239 private function enqueue_to_ces_tracks( $item ) {
240 $queue = get_option(
241 self::CES_TRACKS_QUEUE_OPTION_NAME,
242 array()
243 );
244
245 $queue = is_array( $queue ) ? $queue : array();
246
247 $has_duplicate = array_filter(
248 $queue,
249 function ( $queue_item ) use ( $item ) {
250 return $queue_item['action'] === $item['action'];
251 }
252 );
253 if ( $has_duplicate ) {
254 return;
255 }
256
257 $queue[] = $item;
258
259 update_option(
260 self::CES_TRACKS_QUEUE_OPTION_NAME,
261 $queue
262 );
263 }
264
265 /**
266 * Enqueue the CES survey on using search dynamically.
267 *
268 * @param string $search_area Search area such as "product" or "shop_order".
269 * @param string $page_now Value of window.pagenow.
270 * @param string $admin_page Value of window.adminpage.
271 */
272 public function enqueue_ces_survey_for_search( $search_area, $page_now, $admin_page ) {
273 if ( $this->has_been_shown( self::SEARCH_ACTION_NAME ) ) {
274 return;
275 }
276
277 $this->enqueue_to_ces_tracks(
278 array(
279 'action' => self::SEARCH_ACTION_NAME,
280 'title' => __(
281 'How easy was it to use search?',
282 'woocommerce'
283 ),
284 'firstQuestion' => __(
285 'The search feature in WooCommerce is easy to use.',
286 'woocommerce'
287 ),
288 'secondQuestion' => __(
289 'The search\'s functionality meets my needs.',
290 'woocommerce'
291 ),
292 'onsubmit_label' => $this->onsubmit_label,
293 'pagenow' => $page_now,
294 'adminpage' => $admin_page,
295 'props' => (object) array(
296 'search_area' => $search_area,
297 ),
298 )
299 );
300 }
301
302 /**
303 * Hook into the post status lifecycle, to detect relevant user actions
304 * that we want to survey about.
305 *
306 * @param string $new_status The new status.
307 * @param string $old_status The old status.
308 * @param Post $post The post.
309 */
310 public function run_on_transition_post_status(
311 $new_status,
312 $old_status,
313 $post
314 ) {
315 if ( 'product' === $post->post_type ) {
316 $this->maybe_enqueue_ces_survey_for_product( $new_status, $old_status );
317 } elseif ( 'shop_order' === $post->post_type ) {
318 $this->enqueue_ces_survey_for_edited_shop_order();
319 }
320 }
321
322 /**
323 * Maybe enqueue the CES survey, if product is being added or edited.
324 *
325 * @param string $new_status The new status.
326 * @param string $old_status The old status.
327 */
328 private function maybe_enqueue_ces_survey_for_product(
329 $new_status,
330 $old_status
331 ) {
332 if ( 'publish' !== $new_status ) {
333 return;
334 }
335
336 if ( 'publish' !== $old_status ) {
337 $this->enqueue_ces_survey_for_new_product();
338 } else {
339 $this->enqueue_ces_survey_for_edited_product();
340 }
341 }
342
343 /**
344 * Enqueue the CES survey trigger for a new product.
345 */
346 private function enqueue_ces_survey_for_new_product() {
347 if ( $this->has_been_shown( self::PRODUCT_ADD_PUBLISH_ACTION_NAME ) ) {
348 return;
349 }
350
351 $this->enqueue_to_ces_tracks(
352 array(
353 'action' => self::PRODUCT_ADD_PUBLISH_ACTION_NAME,
354 'title' => __(
355 '🎉 Congrats on adding your first product!',
356 'woocommerce'
357 ),
358 'firstQuestion' => __(
359 'The product creation screen is easy to use.',
360 'woocommerce'
361 ),
362 'secondQuestion' => __(
363 'The product creation screen\'s functionality meets my needs.',
364 'woocommerce'
365 ),
366 'onsubmit_label' => $this->onsubmit_label,
367 'pagenow' => 'product',
368 'adminpage' => 'post-php',
369 'props' => array(
370 'product_count' => $this->get_product_count(),
371 ),
372 )
373 );
374 }
375
376 /**
377 * Enqueue the CES survey trigger for an existing product.
378 */
379 private function enqueue_ces_survey_for_edited_product() {
380 if ( $this->has_been_shown( self::PRODUCT_UPDATE_ACTION_NAME ) ) {
381 return;
382 }
383
384 $this->enqueue_to_ces_tracks(
385 array(
386 'action' => self::PRODUCT_UPDATE_ACTION_NAME,
387 'title' => __(
388 'How easy was it to edit your product?',
389 'woocommerce'
390 ),
391 'firstQuestion' => __(
392 'The product update process is easy to complete.',
393 'woocommerce'
394 ),
395 'secondQuestion' => __(
396 'The product update process meets my needs.',
397 'woocommerce'
398 ),
399 'onsubmit_label' => $this->onsubmit_label,
400 'pagenow' => 'product',
401 'adminpage' => 'post-php',
402 'props' => array(
403 'product_count' => $this->get_product_count(),
404 ),
405 )
406 );
407 }
408
409 /**
410 * Enqueue the CES survey trigger for an existing shop order.
411 */
412 private function enqueue_ces_survey_for_edited_shop_order() {
413 if ( $this->has_been_shown( self::SHOP_ORDER_UPDATE_ACTION_NAME ) ) {
414 return;
415 }
416
417 $this->enqueue_to_ces_tracks(
418 array(
419 'action' => self::SHOP_ORDER_UPDATE_ACTION_NAME,
420 'title' => __(
421 'How easy was it to update an order?',
422 'woocommerce'
423 ),
424 'firstQuestion' => __(
425 'The order details screen is easy to use.',
426 'woocommerce'
427 ),
428 'secondQuestion' => __(
429 'The order details screen\'s functionality meets my needs.',
430 'woocommerce'
431 ),
432 'onsubmit_label' => $this->onsubmit_label,
433 'pagenow' => 'shop_order',
434 'adminpage' => 'post-php',
435 'props' => array(
436 'order_count' => $this->get_shop_order_count(),
437 ),
438 )
439 );
440 }
441
442 /**
443 * Maybe clear the CES tracks queue, executed on every page load. If the
444 * clear option is set it clears the queue. In practice, this executes a
445 * page load after the queued CES tracks are displayed on the client, which
446 * sets the clear option.
447 */
448 public function maybe_clear_ces_tracks_queue() {
449 $clear_ces_tracks_queue_for_page = get_option(
450 self::CLEAR_CES_TRACKS_QUEUE_FOR_PAGE_OPTION_NAME,
451 false
452 );
453
454 if ( ! $clear_ces_tracks_queue_for_page ) {
455 return;
456 }
457
458 $queue = get_option(
459 self::CES_TRACKS_QUEUE_OPTION_NAME,
460 array()
461 );
462
463 $queue = is_array( $queue ) ? $queue : array();
464
465 $remaining_items = array_filter(
466 $queue,
467 function ( $item ) use ( $clear_ces_tracks_queue_for_page ) {
468 return $clear_ces_tracks_queue_for_page['pagenow'] !== $item['pagenow']
469 || $clear_ces_tracks_queue_for_page['adminpage'] !== $item['adminpage'];
470 }
471 );
472
473 update_option(
474 self::CES_TRACKS_QUEUE_OPTION_NAME,
475 array_values( $remaining_items )
476 );
477 update_option( self::CLEAR_CES_TRACKS_QUEUE_FOR_PAGE_OPTION_NAME, false );
478 }
479
480 /**
481 * Appends a script to footer to trigger CES on adding product categories.
482 */
483 public function add_script_track_product_categories() {
484 if ( $this->has_been_shown( self::ADD_PRODUCT_CATEGORIES_ACTION_NAME ) ) {
485 return;
486 }
487
488 $handle = 'wc-tracks-customer-effort-score-product-categories';
489 wp_register_script( $handle, '', array( 'jquery' ), WC_VERSION, true );
490 wp_enqueue_script( $handle );
491 wp_add_inline_script(
492 $handle,
493 $this->get_script_track_edit_php(
494 self::ADD_PRODUCT_CATEGORIES_ACTION_NAME,
495 __( 'How easy was it to add product category?', 'woocommerce' ),
496 __( 'The product category details screen is easy to use.', 'woocommerce' ),
497 __( "The product category details screen's functionality meets my needs.", 'woocommerce' )
498 )
499 );
500 }
501
502 /**
503 * Appends a script to footer to trigger CES on adding product tags.
504 */
505 public function add_script_track_product_tags() {
506 if ( $this->has_been_shown( self::ADD_PRODUCT_TAGS_ACTION_NAME ) ) {
507 return;
508 }
509
510 $handle = 'wc-tracks-customer-effort-score-product-tags';
511 wp_register_script( $handle, '', array( 'jquery' ), WC_VERSION, true );
512 wp_enqueue_script( $handle );
513 wp_add_inline_script(
514 $handle,
515 $this->get_script_track_edit_php(
516 self::ADD_PRODUCT_TAGS_ACTION_NAME,
517 __( 'How easy was it to add a product tag?', 'woocommerce' ),
518 __( 'The product tag details screen is easy to use.', 'woocommerce' ),
519 __( "The product tag details screen's functionality meets my needs.", 'woocommerce' )
520 )
521 );
522 }
523
524 /**
525 * Maybe enqueue the CES survey on product import, if step is done.
526 */
527 public function run_on_product_import() {
528 // We're only interested in when the importer completes.
529 if ( empty( $_GET['step'] ) || 'done' !== $_GET['step'] ) { // phpcs:ignore CSRF ok.
530 return;
531 }
532
533 if ( $this->has_been_shown( self::IMPORT_PRODUCTS_ACTION_NAME ) ) {
534 return;
535 }
536
537 $this->enqueue_to_ces_tracks(
538 array(
539 'action' => self::IMPORT_PRODUCTS_ACTION_NAME,
540 'title' => __(
541 'How easy was it to import products?',
542 'woocommerce'
543 ),
544 'firstQuestion' => __(
545 'The product import process is easy to complete.',
546 'woocommerce'
547 ),
548 'secondQuestion' => __(
549 'The product import process meets my needs.',
550 'woocommerce'
551 ),
552 'onsubmit_label' => $this->onsubmit_label,
553 'pagenow' => 'product_page_product_importer',
554 'adminpage' => 'product_page_product_importer',
555 'props' => (object) array(),
556 )
557 );
558 }
559
560 /**
561 * Enqueue the CES survey trigger for setting changes.
562 */
563 public function run_on_update_options() {
564 // $current_tab is set when WC_Admin_Settings::save_settings is called.
565 global $current_tab;
566 global $current_section;
567
568 if ( $this->has_been_shown( self::SETTINGS_CHANGE_ACTION_NAME ) ) {
569 return;
570 }
571
572 $props = array(
573 'settings_area' => $current_tab,
574 );
575
576 if ( $current_section ) {
577 $props['settings_section'] = $current_section;
578 }
579
580 $this->enqueue_to_ces_tracks(
581 array(
582 'action' => self::SETTINGS_CHANGE_ACTION_NAME,
583 'title' => __(
584 'How easy was it to update your settings?',
585 'woocommerce'
586 ),
587 'firstQuestion' => __(
588 'The settings screen is easy to use.',
589 'woocommerce'
590 ),
591 'secondQuestion' => __(
592 'The settings screen\'s functionality meets my needs.',
593 'woocommerce'
594 ),
595 'onsubmit_label' => $this->onsubmit_label,
596 'pagenow' => 'woocommerce_page_wc-settings',
597 'adminpage' => 'woocommerce_page_wc-settings',
598 'props' => (object) $props,
599 )
600 );
601 }
602
603 /**
604 * Enqueue the CES survey on adding new product attributes.
605 */
606 public function run_on_add_product_attributes() {
607 if ( $this->has_been_shown( self::ADD_PRODUCT_ATTRIBUTES_ACTION_NAME ) ) {
608 return;
609 }
610
611 $this->enqueue_to_ces_tracks(
612 array(
613 'action' => self::ADD_PRODUCT_ATTRIBUTES_ACTION_NAME,
614 'title' => __(
615 'How easy was it to add a product attribute?',
616 'woocommerce'
617 ),
618 'firstQuestion' => __(
619 'Product attributes are easy to use.',
620 'woocommerce'
621 ),
622 'secondQuestion' => __(
623 'Product attributes\' functionality meets my needs.',
624 'woocommerce'
625 ),
626 'onsubmit_label' => $this->onsubmit_label,
627 'pagenow' => 'product_page_product_attributes',
628 'adminpage' => 'product_page_product_attributes',
629 'props' => (object) array(),
630 )
631 );
632 }
633
634 /**
635 * Determine on initiating CES survey on searching for product or orders.
636 */
637 public function run_on_load_edit_php() {
638 $allowed_types = array( 'product', 'shop_order' );
639 $post_type = get_current_screen()->post_type;
640
641 // We're only interested for certain post types.
642 if ( ! in_array( $post_type, $allowed_types, true ) ) {
643 return;
644 }
645
646 // Determine whether request is search by "s" GET parameter.
647 if ( empty( $_GET['s'] ) ) { // phpcs:disable WordPress.Security.NonceVerification.Recommended
648 return;
649 }
650
651 $page_now = 'edit-' . $post_type;
652 $this->enqueue_ces_survey_for_search( $post_type, $page_now, 'edit-php' );
653 }
654 }
655