| 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&tab=account&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§ion=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 |
|