PluginProbe
Shop as Client for WooCommerce – Manual, Phone & Email Orders / 8.0.1
Shop as Client for WooCommerce – Manual, Phone & Email Orders v8.0.1
8.2 8.1 8.0.2 8.0.1 trunk 0.1 0.2 0.3 0.4 0.5 0.6 1.0 1.0.1 1.0.2 1.0.3 1.3.0 1.4.0 1.5.0 1.5.1 1.5.2 1.5.3 1.6.0 1.6.2 1.6.3 1.6.4 All 71 releases
shop-as-client / shop-as-client.php

shop-as-client.php in Shop as Client for WooCommerce – Manual, Phone & Email Orders 8.0.1, at shop-as-client.php

805 lines 31.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Shop as Client for WooCommerce - Manual, Phone & Email Orders
4 * Plugin URI: https://nakedcatplugins.com/product/shop-as-client-for-woocommerce-pro-add-on/
5 * Description: Create manual, phone, POS, or email orders in WooCommerce. Shop admins and staff can place customer orders directly from the frontend checkout.
6 * Version: 8.0.1
7 * Author: Naked Cat Plugins (by Webdados)
8 * Author URI: https://nakedcatplugins.com/
9 * Text Domain: shop-as-client
10 * Domain Path: /languages
11 * Requires at least: 6.4
12 * Tested up to: 7.0
13 * Requires PHP: 7.4
14 * WC requires at least: 9.0
15 * WC tested up to: 10.9
16 * Requires Plugins: woocommerce
17 * License: GPLv3
18 **/
19
20 /* WooCommerce CRUD ready */
21
22 if ( ! defined( 'ABSPATH' ) ) {
23 exit; // Exit if accessed directly
24 }
25
26 if ( ! defined( 'SHOPASCLIENT_REQUIRED_WC' ) ) {
27 define( 'SHOPASCLIENT_REQUIRED_WC', '9.0' );
28 }
29 define( 'SHOPASCLIENT_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
30 define( 'SHOPASCLIENT_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
31 define( 'SHOPASCLIENT_PRO_OUT_LINK', 'https://nakedcatplugins.com/product/shop-as-client-for-woocommerce-pro-add-on/?utm_source=' . rawurlencode( esc_url( home_url( '/' ) ) ) . '&utm_medium=link&utm_campaign=shop_as_client_plugin' );
32
33 // If Pro is also active, we need at least this version of it
34 define( 'SHOPASCLIENT_FREE_REQUIRED_PRO', '8.0' );
35
36 /**
37 * Check if WooCommerce is active
38 * plugins_loaded is too soon for code in functions.php to run - This needs to be addressed, but it probably won't work because on the initialization of blocks
39 */
40 add_action(
41 'plugins_loaded',
42 function () {
43 if ( class_exists( 'WooCommerce' ) && defined( 'WC_VERSION' ) && version_compare( WC_VERSION, SHOPASCLIENT_REQUIRED_WC, '>=' ) ) {
44
45 if ( function_exists( '\Webdados\ShopAsClientPro\init' ) ) {
46 // SHOPASCLIENT_PRO_PLUGIN_FILE is only defined at plugins_loaded priority 9.
47 // Read the version directly from the file header instead.
48 $pro_path = WP_PLUGIN_DIR . '/shop-as-client-pro/shop-as-client-pro.php';
49 if ( file_exists( $pro_path ) ) {
50 if ( ! function_exists( 'get_plugin_data' ) ) {
51 include ABSPATH . '/wp-admin/includes/plugin.php';
52 }
53 $pro_data = get_plugin_data( $pro_path, false, false );
54 $pro_version = $pro_data['Version'] ?? '';
55 if ( $pro_version && version_compare( $pro_version, SHOPASCLIENT_FREE_REQUIRED_PRO, '<' ) ) {
56 add_action(
57 'admin_notices',
58 function () use ( $pro_version ) {
59 ?>
60 <div class="notice notice-error">
61 <p>
62 <?php
63 echo wp_kses_post(
64 sprintf(
65 /* translators: %1$s: plugin name, %2$s: required version, %3$s: current version */
66 __( '%1$s requires at least version %2$s of the PRO add-on. You have version %3$s. Please update or disable the PRO add-on.', 'shop-as-client' ),
67 '<strong>Shop as Client</strong>',
68 SHOPASCLIENT_FREE_REQUIRED_PRO,
69 $pro_version
70 )
71 );
72 ?>
73 </p>
74 </div>
75 <?php
76 }
77 );
78 // Get out of here — can't run with an old PRO version.
79 return;
80 }
81 }
82 }
83
84 /**
85 * Version
86 */
87 if ( ! function_exists( 'get_plugin_data' ) ) {
88 include ABSPATH . '/wp-admin/includes/plugin.php';
89 }
90 $temp_plugin_data = get_plugin_data( __FILE__, false, false );
91 define( 'SHOPASCLIENT_VERSION', $temp_plugin_data['Version'] );
92
93 /**
94 * Languages and scripts
95 * Do not change this function name as is needed for the PRO add-on to work properly
96 */
97 function shop_as_client_init() {
98 // Load scripts
99 add_action( 'wp_enqueue_scripts', 'shop_as_client_enqueue_classic_scripts' );
100 }
101 add_action( 'init', 'shop_as_client_init' ); // Used to be plugins_loaded, but init makes more sense
102
103 /**
104 * Fake settings link
105 *
106 * @param array $links The current links.
107 */
108 function shop_as_client_add_settings_link( $links ) {
109 $action_links = array(
110 sprintf(
111 '<a href="admin.php?page=wc-settings&amp;tab=account&amp;section=shop_as_client">%s</a>',
112 __( 'Settings', 'shop-as-client' )
113 ),
114 );
115 return array_merge( $links, $action_links );
116 }
117 add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'shop_as_client_add_settings_link' );
118
119 /**
120 * Register the section under Accounts & Privacy
121 */
122 add_filter(
123 'woocommerce_get_sections_account',
124 function ( $sections ) {
125 $sections['shop_as_client'] = __( 'Shop as Client', 'shop-as-client' );
126 return $sections;
127 }
128 );
129
130 /**
131 * Settings - Free plugin only (hidden when PRO is active)
132 */
133 function shop_as_client_get_settings() {
134 $description = sprintf(
135 /* translators: %1$s: link open, %2$s: link close */
136 __( 'Available on the %1$sPRO Add-on%2$s', 'shop-as-client' ),
137 '<a href="' . esc_url( SHOPASCLIENT_PRO_OUT_LINK ) . '" target="_blank">',
138 '</a>'
139 );
140 return array(
141 array(
142 'title' => __( 'Shop as Client', 'shop-as-client' ) . sprintf(
143 ' (Free %s)',
144 SHOPASCLIENT_VERSION
145 ),
146 'type' => 'title',
147 'id' => 'shop_as_client_options',
148 ),
149 // Disabled fields here (shop as client default, create user field default, search on orders, update customer, clear checkout fields, Handler)
150 array(
151 'title' => __( 'Shop as client field default', 'shop-as-client' ),
152 'id' => 'shop_as_client_pro_shop_as_client_default',
153 'type' => 'select',
154 'options' => array(
155 'yes' => __( 'Yes', 'shop-as-client' ),
156 'no' => __( 'No', 'shop-as-client' ),
157 ),
158 'default' => 'yes',
159 'desc' => $description,
160 'custom_attributes' => array(
161 'disabled' => 'disabled',
162 ),
163 ),
164 array(
165 'title' => __( 'Create user field default', 'shop-as-client' ),
166 'id' => 'shop_as_client_pro_create_user_default',
167 'type' => 'select',
168 'options' => array(
169 'yes' => __( 'Yes', 'shop-as-client' ),
170 'no' => __( 'No', 'shop-as-client' ),
171 ),
172 'default' => 'yes',
173 'desc' => $description,
174 'custom_attributes' => array(
175 'disabled' => 'disabled',
176 ),
177 ),
178 array(
179 'title' => __( 'Search on orders', 'shop-as-client' ),
180 'desc' => __( 'By default, the search is only performed on registered users by their registration and billing email, but if you enable this option it will also be done on orders (if not found as user), so you can get data from guest customers.', 'shop-as-client' ) . '<br/>' . $description,
181 'id' => 'shop_as_client_pro_search_orders',
182 'type' => 'select',
183 'options' => array(
184 'yes' => __( 'Yes', 'shop-as-client' ),
185 'no' => __( 'No', 'shop-as-client' ),
186 ),
187 'default' => 'yes',
188 'custom_attributes' => array(
189 'disabled' => 'disabled',
190 ),
191 ),
192 array(
193 'title' => __( 'Update customer', 'shop-as-client' ),
194 'desc' => __( 'Update the customer details on his profile', 'shop-as-client' ) . '<br/>' . $description,
195 'id' => 'shop_as_client_pro_update_customer',
196 'type' => 'select',
197 'options' => array(
198 'yes' => __( 'Yes', 'shop-as-client' ),
199 'no' => __( 'No', 'shop-as-client' ),
200 ),
201 'default' => 'yes',
202 'custom_attributes' => array(
203 'disabled' => 'disabled',
204 ),
205 ),
206 array(
207 'title' => __( 'Clear checkout fields', 'shop-as-client' ),
208 'desc' => (
209 __( 'Default all checkout fields to blank for Administrators and Shop Managers', 'shop-as-client' )
210 .
211 '<br/>'
212 .
213 __( 'Only on the classic checkout', 'shop-as-client' ) . '<br/>' . $description
214 ),
215 'id' => 'shop_as_client_pro_empty_checkout',
216 'type' => 'select',
217 'options' => array(
218 'yes' => __( 'Yes', 'shop-as-client' ),
219 'no' => __( 'No', 'shop-as-client' ),
220 ),
221 'default' => 'yes',
222 'custom_attributes' => array(
223 'disabled' => 'disabled',
224 ),
225 ),
226 array(
227 'title' => __( 'Handler on orders list', 'shop-as-client' ),
228 'desc' => __( 'Add a column with the order handler and allow filtering by handler on the admin orders list', 'shop-as-client' ) . '<br/>' . $description,
229 'id' => 'shop_as_client_pro_handler_order_list',
230 'type' => 'select',
231 'options' => array(
232 'yes' => __( 'Yes', 'shop-as-client' ),
233 'no' => __( 'No', 'shop-as-client' ),
234 ),
235 'default' => 'yes',
236 'custom_attributes' => array(
237 'disabled' => 'disabled',
238 ),
239 ),
240 array(
241 'type' => 'sectionend',
242 'id' => 'shop_as_client_options',
243 ),
244 );
245 }
246 add_filter(
247 'woocommerce_get_settings_account',
248 function ( $settings, $current_section ) {
249 if ( 'shop_as_client' === $current_section && ! defined( 'SHOPASCLIENT_PRO_PLUGIN_FILE' ) ) {
250 return shop_as_client_get_settings();
251 }
252 return $settings;
253 },
254 10,
255 2
256 );
257
258 /**
259 * Can checkout with shop as client? - Should be used for both classic and blocks checkout
260 *
261 * @param integer $user_id The user ID to check or null to check the current logged-in user.
262 */
263 function shop_as_client_can_checkout( $user_id = null ) {
264 if ( is_null( $user_id ) ) {
265 // The shop_as_client_allow_checkout filter can be used to allow other user roles to use this functionality - Use carefully and wisely
266 return current_user_can( 'manage_options' ) || current_user_can( 'manage_woocommerce' ) || apply_filters( 'shop_as_client_allow_checkout', false, null );
267 } elseif ( intval( $user_id ) > 0 ) {
268 return user_can( intval( $user_id ), 'manage_options' ) || user_can( intval( $user_id ), 'manage_woocommerce' ) || apply_filters( 'shop_as_client_allow_checkout', false, $user_id );
269 }
270 return false;
271 }
272
273 /**
274 * Our field - Classic checkout only - Blocks checkout in includes/class-shop-as-client-checkout-blocks.php
275 *
276 * @param array $fields The fields.
277 */
278 function shop_as_client_init_woocommerce_checkout_fields( $fields ) {
279 if ( shop_as_client_can_checkout() ) {
280 $priority = apply_filters( 'shop_as_client_field_priority', 990 );
281 // Shop as client?
282 $fields['billing']['billing_shop_as_client'] = array(
283 'label' => __( 'Shop as client', 'shop-as-client' ),
284 'required' => true,
285 'class' => apply_filters( 'shop_as_client_field_class', array( 'form-row-wide' ) ),
286 'input_class' => apply_filters( 'shop_as_client_field_input_class', array() ),
287 'label_class' => apply_filters( 'shop_as_client_field_label_class', array() ),
288 'clear' => true,
289 'priority' => $priority,
290 'type' => 'select',
291 'options' => array(
292 'yes' => __( 'Yes', 'shop-as-client' ),
293 'no' => __( 'No', 'shop-as-client' ),
294 ),
295 'default' => apply_filters( 'shop_as_client_default_shop_as_client', 'yes' ),
296 );
297 $priority++;
298 // Create user if it doesn't exist?
299 $fields['billing']['billing_shop_as_client_create_user'] = array(
300 'label' => __( 'Create user (if not found by email)?', 'shop-as-client' ),
301 'required' => true,
302 'class' => apply_filters( 'shop_as_client_create_user_field_class', array( 'form-row-wide' ) ),
303 'input_class' => apply_filters( 'shop_as_client_create_user_field_input_class', array() ),
304 'label_class' => apply_filters( 'shop_as_client_create_user_field_label_class', array() ),
305 'clear' => true,
306 'priority' => $priority,
307 'type' => 'select',
308 'options' => array(
309 'yes' => __( 'Yes', 'shop-as-client' ),
310 'no' => __( 'No (leave as guest)', 'shop-as-client' ),
311 ),
312 'default' => apply_filters( 'shop_as_client_default_create_user', 'no' ),
313 );
314 }
315 return $fields;
316 }
317 add_filter( 'woocommerce_checkout_fields', 'shop_as_client_init_woocommerce_checkout_fields', PHP_INT_MAX );
318
319 /**
320 * Enqueue scripts - Classic checkout only - Blocks checkout in includes/class-shop-as-client-checkout-blocks.php
321 */
322 function shop_as_client_enqueue_classic_scripts() {
323 if (
324 function_exists( 'is_checkout' )
325 &&
326 is_checkout()
327 &&
328 ( ! has_block( 'woocommerce/checkout' ) ) // Not on the Blocks checkout
329 ) {
330 wp_enqueue_script( 'shop-as-client', plugins_url( 'js/functions.js', __FILE__ ), array( 'jquery' ), '1.3.0', true );
331 wp_localize_script(
332 'shop-as-client',
333 'shop_as_client',
334 array(
335 'txt_pro' => sprintf(
336 '<p><a href="%s" target="_blank">%s</a></p>',
337 esc_url( SHOPASCLIENT_PRO_OUT_LINK ),
338 __( 'Do you want to load the customer details automatically?<br/>Get the PRO add-on!', 'shop-as-client' )
339 ),
340 )
341 );
342 }
343 }
344
345 /**
346 * Force our field defaults - Shop as Client
347 */
348 function shop_as_client_default_checkout_billing_shop_as_client() {
349 return apply_filters( 'shop_as_client_default_shop_as_client', 'yes' );
350 }
351 add_filter( 'default_checkout_billing_shop_as_client', 'shop_as_client_default_checkout_billing_shop_as_client', 10, 0 );
352
353 /**
354 * Force our field defaults - Create user
355 */
356 function shop_as_client_default_checkout_billing_shop_as_client_create_user() {
357 return apply_filters( 'shop_as_client_default_create_user', 'no' );
358 }
359 add_filter( 'default_checkout_billing_shop_as_client_create_user', 'shop_as_client_default_checkout_billing_shop_as_client_create_user', 10, 0 );
360
361 /**
362 * Get order "shop as client"
363 *
364 * @param WC_Order $order The order.
365 */
366 function shop_as_client_get_order_status( $order ) {
367 return 'yes' === $order->get_meta( '_billing_shop_as_client' );
368 }
369
370 /**
371 * Return yes to woocommerce_registration_generate_password
372 *
373 * @param string $value If the password should be generated.
374 */
375 function shop_as_client_woocommerce_registration_generate_password( $value ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
376 return 'yes';
377 }
378
379 /**
380 * Set order user - Inspiration: https://gist.github.com/twoelevenjay/80294a635969a54e4693
381 * Classic checkout only - Blocks alternative missing - https://github.com/woocommerce/woocommerce/issues/44530
382 *
383 * @param integer $user_id The original order user ID.
384 * @throws Exception Error message.
385 */
386 function shop_as_client_woocommerce_checkout_customer_id( $user_id ) {
387 // WooCommerce took care of nonces
388 // phpcs:disable WordPress.Security.NonceVerification.Missing
389 if ( shop_as_client_can_checkout() ) {
390 $billing_shop_as_client = isset( $_POST['billing_shop_as_client'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['billing_shop_as_client'] ) ) ) : '';
391 if ( 'yes' === $billing_shop_as_client ) {
392 $user_id = 0;
393 // Check if an exisiting user already uses this email address.
394 $user_email = isset( $_POST['billing_email'] ) ? sanitize_email( wp_unslash( $_POST['billing_email'] ) ) : '';
395 if ( empty( $user_email ) ) {
396 $user_email = apply_filters( 'shop_as_client_user_email_if_empty', $user_email, $_POST );
397 }
398 // Get user by profile email
399 $user = get_user_by( 'email', $user_email );
400 if ( $user ) {
401 // User found
402 $user_id = $user->ID;
403 // Should we update the user details? - This is by WooCommerce on WC_Checkout process_customer - Working on Blocks too
404 } elseif (
405 ( ! empty( $user_email ) )
406 &&
407 ( $users = get_users( // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.Found, Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
408 // Get user by WooCommerce billing email
409 array(
410 'meta_key' => 'billing_email', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
411 'meta_value' => $user_email, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
412 'meta_compare' => '=',
413 )
414 ) )
415 ) {
416 // User found - We should check for more than one... (There's no real solution for this)
417 $user_id = $users[0]->ID;
418 } else {
419 // Create user or guest?
420 $billing_shop_as_client_create_user = isset( $_POST['billing_shop_as_client_create_user'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['billing_shop_as_client_create_user'] ) ) ) : '';
421 if ( 'yes' === $billing_shop_as_client_create_user ) {
422 $billing_first_name = isset( $_POST['billing_first_name'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['billing_first_name'] ) ) ) : '';
423 $billing_last_name = isset( $_POST['billing_last_name'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['billing_last_name'] ) ) ) : '';
424 $temp_user_id = shop_as_client_create_customer( $user_email, $billing_first_name, $billing_last_name );
425 if ( ! is_wp_error( $temp_user_id ) ) {
426 $user_id = $temp_user_id;
427 } else {
428 $message = sprintf(
429 /* translators: %s: error message */
430 __( 'Shop as Client failed to create user: %s', 'shop-as-client' ),
431 $temp_user_id->get_error_message()
432 );
433 throw new Exception( esc_html( $message ) );
434 }
435 }
436 }
437 }
438 }
439 return $user_id;
440 // phpcs:enable WordPress.Security.NonceVerification.Missing
441 }
442 add_filter( 'woocommerce_checkout_customer_id', 'shop_as_client_woocommerce_checkout_customer_id' );
443
444 /**
445 * Create the user/customer - Should be used for both classic and blocks checkout
446 *
447 * @param string $user_email The user email.
448 * @param string $user_first_name The user first name.
449 * @param string $user_last_name The user last name.
450 */
451 function shop_as_client_create_customer( $user_email, $user_first_name, $user_last_name ) {
452 // Username
453 if ( 'yes' === get_option( 'woocommerce_registration_generate_username' ) ) {
454 $username = '';
455 } else {
456 $username = $user_email;
457 }
458 // Force password generation by WooCommerce (and sending via email), even if the option is not set
459 if ( apply_filters( 'shop_as_client_email_password', true ) ) {
460 add_filter( 'option_woocommerce_registration_generate_password', 'shop_as_client_woocommerce_registration_generate_password' );
461 $password = '';
462 } else {
463 $password = wp_generate_password();
464 }
465 $user_id = wc_create_new_customer( $user_email, $username, $password );
466 if ( apply_filters( 'shop_as_client_email_password', true ) ) {
467 remove_filter( 'option_woocommerce_registration_generate_password', 'shop_as_client_woocommerce_registration_generate_password' );
468 }
469 if ( ! is_wp_error( $user_id ) ) {
470 wp_update_user(
471 array(
472 'ID' => $user_id,
473 'first_name' => $user_first_name,
474 'last_name' => $user_last_name,
475 'display_name' => trim( $user_first_name . ' ' . $user_last_name ),
476 // phpcs:ignore Squiz.PHP.CommentedOutCode.Found
477 // 'role' => 'customer',
478 )
479 );
480 } else {
481 $message = 'Shop as Client failed to create user: ' . $user_id->get_error_message();
482 // We should notify the admin user somehow - WooCommerce already does that
483 }
484 return $user_id;
485 }
486
487 /**
488 * Prevent logged in user to be updated
489 * Not running on the blocks checkout but it seems not to be necessary as only the target user is being updated and not the logged-in one
490 */
491 function shop_as_client_woocommerce_checkout_process() {
492 if ( shop_as_client_can_checkout() ) {
493 // WooCommerce took care of nonces
494 // phpcs:ignore WordPress.Security.NonceVerification.Missing
495 $billing_shop_as_client = isset( $_POST['billing_shop_as_client'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['billing_shop_as_client'] ) ) ) : '';
496 if ( 'yes' === $billing_shop_as_client ) {
497 if ( ! apply_filters( 'shop_as_client_update_customer_data', false ) ) {
498 add_filter( 'woocommerce_checkout_update_customer_data', '__return_false' );
499 }
500 }
501 }
502 }
503 add_action( 'woocommerce_checkout_process', 'shop_as_client_woocommerce_checkout_process' );
504
505 /**
506 * Save logged in user id as order handler - Classic checkout only - Blocks alternative missing
507 *
508 * @param integer $order_id The order ID.
509 * @param array $data The checkout data.
510 */
511 function shop_as_client_woocommerce_checkout_update_order_meta( $order_id, $data ) {
512 // The "correct" way to check for our fields
513 $billing_shop_as_client = isset( $data['billing_shop_as_client'] ) ? trim( $data['billing_shop_as_client'] ) : '';
514 if ( empty( $billing_shop_as_client ) ) {
515 // Because when using Funnelkit our fields are not present on the $data array
516 // WooCommerce took care of nonces
517 // phpcs:ignore WordPress.Security.NonceVerification.Missing
518 $billing_shop_as_client = isset( $_POST['billing_shop_as_client'] ) ? trim( sanitize_text_field( wp_unslash( $_POST['billing_shop_as_client'] ) ) ) : '';
519 }
520 if ( shop_as_client_can_checkout() && 'yes' === $billing_shop_as_client ) {
521 $order = wc_get_order( $order_id );
522 $order->update_meta_data( '_billing_shop_as_client_handler_user_id', get_current_user_id() );
523 $order->update_meta_data( '_billing_shop_as_client_checkout', 'classic' );
524 $order->save();
525 }
526 }
527 add_action( 'woocommerce_checkout_update_order_meta', 'shop_as_client_woocommerce_checkout_update_order_meta', 10, 2 );
528
529 /**
530 * Information on the order edit screen
531 *
532 * @param WC_Order $order The order.
533 */
534 /**
535 * Render the Shop as Client metabox content.
536 *
537 * @param WP_Post|WC_Order $post_or_order Post object (posts mode) or order object (HPOS mode).
538 */
539 function shop_as_client_order_metabox( $post_or_order ) {
540 $order = $post_or_order instanceof \WP_Post ? wc_get_order( $post_or_order->ID ) : $post_or_order;
541 if ( ! $order || ! shop_as_client_get_order_status( $order ) ) {
542 return;
543 }
544 ?>
545 <p>
546 <strong><?php esc_html_e( 'Shop as client', 'shop-as-client' ); ?>:</strong>
547 <br>
548 <?php esc_html_e( 'Yes', 'shop-as-client' ); ?>
549 </p>
550 <?php
551 $user_id = $order->get_meta( '_billing_shop_as_client_handler_user_id' );
552 if ( $user_id ) {
553 ?>
554 <p>
555 <strong><?php esc_html_e( 'Order handled by', 'shop-as-client' ); ?>:</strong>
556 <br>
557 <?php
558 $user = get_user_by( 'ID', $user_id );
559 if ( $user ) {
560 echo wp_kses_post(
561 sprintf(
562 '<a href="%s" target="_blank">%s</a>',
563 esc_url( add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ) ),
564 sprintf(
565 '%s (%s)',
566 $user->display_name,
567 $user->nickname
568 )
569 )
570 );
571 } else {
572 echo esc_html(
573 sprintf(
574 /* translators: %d: user id */
575 __( 'User %d', 'shop-as-client' ),
576 $user_id
577 )
578 );
579 }
580 do_action( 'shop_as_client_after_order_handler', $order, $user_id );
581 ?>
582 </p>
583 <?php
584 }
585 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
586 $checkout = $order->get_meta( '_billing_shop_as_client_checkout' );
587 ?>
588 <p>
589 <strong><?php esc_html_e( 'Checkout', 'shop-as-client' ); ?>:</strong>
590 <br>
591 <?php echo esc_html( $checkout ); ?>
592 </p>
593 <?php
594 }
595 do_action( 'shop_as_client_after_order_details', $order );
596 }
597 add_action(
598 'add_meta_boxes',
599 function () {
600 foreach ( array( 'shop_order', 'woocommerce_page_wc-orders' ) as $screen ) {
601 add_meta_box(
602 'shop-as-client',
603 __( 'Shop as Client', 'shop-as-client' ),
604 'shop_as_client_order_metabox',
605 $screen,
606 'side',
607 'default'
608 );
609 }
610 }
611 );
612
613 /**
614 * Thank you page warning - https://github.com/woocommerce/woocommerce/pull/38983/
615 *
616 * @param string|null $tag The shortcode tag, used to detect the checkout shortcode. Ignored when $is_checkout_shortcode is set.
617 * @param bool|null $is_checkout_shortcode Pass true when the caller already knows this is the checkout (e.g. the woocommerce/classic-shortcode block).
618 */
619 function shop_as_client_is_our_checkout_order_received( $tag = null, $is_checkout_shortcode = null ) {
620 if ( is_null( $is_checkout_shortcode ) ) {
621 $is_checkout_shortcode = ( $tag === apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) );
622 }
623 if ( $is_checkout_shortcode && is_order_received_page() && shop_as_client_can_checkout() ) {
624 global $wp;
625 if ( isset( $wp->query_vars['order-received'] ) && intval( $wp->query_vars['order-received'] ) > 0 ) {
626 $order = wc_get_order( $wp->query_vars['order-received'] );
627 if ( $order ) {
628 $key = isset( $_GET['key'] ) ? sanitize_text_field( wp_unslash( $_GET['key'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
629 if ( hash_equals( $order->get_order_key(), $key ) ) {
630 $order_customer_id = $order->get_customer_id();
631 if ( $order_customer_id && get_current_user_id() !== $order_customer_id ) {
632 // We're pretty sure there's no access right now, so we need also to make sure it's a shop as client order and the handler is logged in
633 if ( $order->get_meta( '_billing_shop_as_client' ) === 'yes' && intval( $order->get_meta( '_billing_shop_as_client_handler_user_id' ) ) === intval( get_current_user_id() ) ) {
634 // We dealt with the order
635 return $order;
636 }
637 }
638 }
639 }
640 }
641 }
642 return false;
643 }
644 add_filter( 'do_shortcode_tag', 'shop_as_client_checkout_order_received', 10, 2 );
645 add_filter( 'render_block_woocommerce/classic-shortcode', 'shop_as_client_checkout_order_received_block', 10, 2 );
646
647 /**
648 * Markup for the "Order received" notice shown to the order handler
649 * when WooCommerce 7.8.1+ hides the order details from non-owners.
650 */
651 function shop_as_client_checkout_order_received_notice_html() {
652 ob_start();
653 ?>
654 <div class="woocommerce-error">
655 <a href="<?php echo esc_url( SHOPASCLIENT_PRO_OUT_LINK ); ?>" class="button wc-forward" target="_blank">
656 <?php esc_html_e( 'Get the PRO add-on to fix this', 'shop-as-client' ); ?>
657 </a>
658 <?php echo wp_kses_post( __( '<strong>Shop as client</strong><br/>Since WooCommerce 7.8.1 only the order owner/customer is able to see the "Order received" details.', 'shop-as-client' ) ); ?>
659 </div>
660 <?php
661 return ob_get_clean();
662 }
663
664 /**
665 * Filters the [woocommerce_checkout] shortcode output, on the
666 * "Order received" page, to prepend the notice from
667 * shop_as_client_checkout_order_received_notice_html() when the
668 * current user is the order's handler but not its owner.
669 *
670 * @param string $output Shortcode output.
671 * @param string $tag Shortcode tag.
672 * @return string Filtered shortcode output.
673 */
674 function shop_as_client_checkout_order_received( $output, $tag ) {
675 $order = shop_as_client_is_our_checkout_order_received( $tag );
676 if ( $order ) {
677 $output = shop_as_client_checkout_order_received_notice_html() . $output;
678 }
679 return $output;
680 }
681
682 /**
683 * Same notice as shop_as_client_checkout_order_received(), but for
684 * Checkout pages built with the woocommerce/classic-shortcode block,
685 * which renders WC_Shortcode_Checkout::output() directly and never
686 * fires do_shortcode_tag.
687 *
688 * @param string $block_content Rendered block HTML.
689 * @param array $block Parsed block, including attrs.
690 */
691 function shop_as_client_checkout_order_received_block( $block_content, $block ) {
692 if ( isset( $block['attrs']['shortcode'] ) && 'checkout' === $block['attrs']['shortcode'] ) {
693 $order = shop_as_client_is_our_checkout_order_received( null, true );
694 if ( $order ) {
695 $block_content = shop_as_client_checkout_order_received_notice_html() . $block_content;
696 }
697 }
698 return $block_content;
699 }
700
701 if ( function_exists( 'woocommerce_store_api_register_update_callback' ) ) {
702
703 /* Blocks */
704 add_action(
705 'woocommerce_blocks_loaded',
706 function () {
707 require_once __DIR__ . '/includes/class-shop-as-client-checkout-blocks.php';
708
709 add_action(
710 'woocommerce_blocks_checkout_block_registration',
711 function ( $integration_registry ) {
712 $integration_registry->register( new \ShopAsClient_Checkout_Blocks() );
713 }
714 );
715 }
716 );
717
718 /* Blocks - Extend Store endpoint */
719 add_action(
720 'woocommerce_blocks_loaded',
721 function () {
722 require_once __DIR__ . '/includes/class-shop-as-client-extend-store-endpoint.php';
723
724 ( new ShopAsClient_Extend_Store_Endpoint() )->initialize();
725 }
726 );
727
728 }
729
730 /* Simple Order Approval nag */
731 add_action(
732 'admin_init',
733 function () {
734 if (
735 // Not for PRO add-on users
736 ( ! class_exists( 'Shop_As_Client_Pro' ) )
737 &&
738 // Not for users that already have the nag loaded for any reason
739 ( ! defined( 'PTWOO_SIMPLE_ORDER_APPROVAL_NAG' ) )
740 &&
741 // Not for users that already have the advertised plugin
742 ( ! class_exists( '\PTWooPlugins\SWOA\SWOA' ) )
743 &&
744 // Check if dismissed by this user in the last 365 days
745 ( intval( get_user_meta( get_current_user_id(), 'ptwoo_simple_order_approval_nag_dismiss_until', true ) ) < time() )
746 &&
747 // Check if 90-day dismissal is active - Legacy support
748 empty( get_transient( 'ptwoo_simple_order_approval_nag' ) )
749 // Removed by filter
750 &&
751 apply_filters( 'shop_as_client_ptwoo_simple_order_approval_nag', true )
752 ) {
753 define( 'PTWOO_SIMPLE_ORDER_APPROVAL_NAG', true );
754 require_once 'simple_order_approval_nag/simple_order_approval_nag.php';
755 }
756 }
757 );
758 }
759 },
760 6
761 );
762
763 /* HPOS & Blocks Checkout Compatible */
764 add_action(
765 'before_woocommerce_init',
766 function () {
767 \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
768 \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', __FILE__, true );
769 }
770 );
771
772 /**
773 * On activation, set a transient so we can redirect to the settings page.
774 */
775 register_activation_hook(
776 __FILE__,
777 function () {
778 set_transient( 'shop_as_client_activation_redirect_' . get_current_user_id(), true, 30 );
779 }
780 );
781
782 /**
783 * Redirect to the settings page after single (non-bulk) activation.
784 */
785 add_action(
786 'admin_init',
787 function () {
788 // Do not redirect during AJAX requests.
789 if ( wp_doing_ajax() ) {
790 return;
791 }
792 $transient_key = 'shop_as_client_activation_redirect_' . get_current_user_id();
793 if ( get_transient( $transient_key ) ) {
794 delete_transient( $transient_key );
795 // Do not redirect on bulk activation.
796 if ( ! isset( $_GET['activate-multi'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
797 wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=account&section=shop_as_client' ) );
798 exit;
799 }
800 }
801 }
802 );
803
804 /* If you're reading this you must know what you're doing ;-) Greetings from sunny Portugal! */
805