2013-08-09 16:11:15 +00:00
< ? php
/**
2015-11-03 13:31:20 +00:00
* Handle frontend forms .
2013-08-09 16:11:15 +00:00
*
2019-02-04 15:31:35 +00:00
* @ package WooCommerce / Classes /
2018-06-22 11:39:06 +00:00
*/
defined ( 'ABSPATH' ) || exit ;
/**
* WC_Form_Handler class .
2013-08-09 16:11:15 +00:00
*/
class WC_Form_Handler {
/**
2015-11-03 13:31:20 +00:00
* Hook in methods .
2013-08-09 16:11:15 +00:00
*/
2014-05-28 13:52:50 +00:00
public static function init () {
2016-06-24 14:06:01 +00:00
add_action ( 'template_redirect' , array ( __CLASS__ , 'redirect_reset_password_link' ) );
2014-05-28 13:52:50 +00:00
add_action ( 'template_redirect' , array ( __CLASS__ , 'save_address' ) );
add_action ( 'template_redirect' , array ( __CLASS__ , 'save_account_details' ) );
2015-01-05 14:43:01 +00:00
add_action ( 'wp_loaded' , array ( __CLASS__ , 'checkout_action' ), 20 );
add_action ( 'wp_loaded' , array ( __CLASS__ , 'process_login' ), 20 );
add_action ( 'wp_loaded' , array ( __CLASS__ , 'process_registration' ), 20 );
2015-01-21 14:15:49 +00:00
add_action ( 'wp_loaded' , array ( __CLASS__ , 'process_lost_password' ), 20 );
2015-01-05 14:43:01 +00:00
add_action ( 'wp_loaded' , array ( __CLASS__ , 'process_reset_password' ), 20 );
add_action ( 'wp_loaded' , array ( __CLASS__ , 'cancel_order' ), 20 );
add_action ( 'wp_loaded' , array ( __CLASS__ , 'update_cart_action' ), 20 );
add_action ( 'wp_loaded' , array ( __CLASS__ , 'add_to_cart_action' ), 20 );
2015-02-10 12:23:15 +00:00
2016-03-08 18:54:19 +00:00
// May need $wp global to access query vars.
2015-02-10 12:23:15 +00:00
add_action ( 'wp' , array ( __CLASS__ , 'pay_action' ), 20 );
add_action ( 'wp' , array ( __CLASS__ , 'add_payment_method_action' ), 20 );
2016-05-26 13:50:22 +00:00
add_action ( 'wp' , array ( __CLASS__ , 'delete_payment_method_action' ), 20 );
add_action ( 'wp' , array ( __CLASS__ , 'set_default_payment_method_action' ), 20 );
2013-08-09 16:11:15 +00:00
}
2016-06-24 14:06:01 +00:00
/**
2018-02-06 17:24:26 +00:00
* Remove key and user ID ( or user login , as a fallback ) from query string , set cookie , and redirect to account page to show the form .
2016-06-24 14:06:01 +00:00
*/
public static function redirect_reset_password_link () {
2019-02-04 15:31:35 +00:00
if ( is_account_page () && isset ( $_GET [ 'key' ] ) && ( isset ( $_GET [ 'id' ] ) || isset ( $_GET [ 'login' ] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
2018-02-06 17:24:26 +00:00
2019-01-21 16:02:28 +00:00
// If available, get $user_id from query string parameter for fallback purposes.
2019-02-04 15:31:35 +00:00
if ( isset ( $_GET [ 'login' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$user = get_user_by ( 'login' , sanitize_user ( wp_unslash ( $_GET [ 'login' ] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
2019-01-21 16:02:28 +00:00
$user_id = $user ? $user -> ID : 0 ;
2018-02-14 13:59:25 +00:00
} else {
2019-01-21 16:02:28 +00:00
$user_id = absint ( $_GET [ 'id' ] );
2018-02-14 13:59:25 +00:00
}
2018-02-06 17:24:26 +00:00
2019-02-04 15:31:35 +00:00
$value = sprintf ( '%d:%s' , $user_id , wp_unslash ( $_GET [ 'key' ] ) ); // phpcs:ignore
2016-06-24 14:06:01 +00:00
WC_Shortcode_My_Account :: set_reset_password_cookie ( $value );
wp_safe_redirect ( add_query_arg ( 'show-reset-form' , 'true' , wc_lostpassword_url () ) );
exit ;
}
}
2013-08-09 16:11:15 +00:00
/**
2016-03-08 18:54:19 +00:00
* Save and and update a billing or shipping address if the
2013-08-09 16:11:15 +00:00
* form was submitted through the user account page .
*/
2014-05-28 13:52:50 +00:00
public static function save_address () {
global $wp ;
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
$nonce_value = wc_get_var ( $_REQUEST [ 'woocommerce-edit-address-nonce' ], wc_get_var ( $_REQUEST [ '_wpnonce' ], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce ( $nonce_value , 'woocommerce-edit_address' ) ) {
2013-08-09 16:11:15 +00:00
return ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2018-03-13 14:16:56 +00:00
if ( empty ( $_POST [ 'action' ] ) || 'edit_address' !== $_POST [ 'action' ] ) {
2013-08-09 16:11:15 +00:00
return ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2017-08-07 10:02:02 +00:00
2013-08-09 16:11:15 +00:00
$user_id = get_current_user_id ();
2014-02-07 18:35:30 +00:00
if ( $user_id <= 0 ) {
2013-09-19 13:39:49 +00:00
return ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2019-02-14 15:22:36 +00:00
$customer = new WC_Customer ( $user_id );
if ( ! $customer ) {
return ;
}
2014-10-22 10:26:09 +00:00
$load_address = isset ( $wp -> query_vars [ 'edit-address' ] ) ? wc_edit_address_i18n ( sanitize_title ( $wp -> query_vars [ 'edit-address' ] ), true ) : 'billing' ;
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
if ( ! isset ( $_POST [ $load_address . '_country' ] ) ) {
return ;
}
$address = WC () -> countries -> get_address_fields ( wc_clean ( wp_unslash ( $_POST [ $load_address . '_country' ] ) ), $load_address . '_' );
2013-08-09 16:11:15 +00:00
2013-09-19 13:39:49 +00:00
foreach ( $address as $key => $field ) {
2014-02-07 18:35:30 +00:00
if ( ! isset ( $field [ 'type' ] ) ) {
2013-09-19 13:39:49 +00:00
$field [ 'type' ] = 'text' ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2016-03-08 18:54:19 +00:00
// Get Value.
2019-02-04 15:31:35 +00:00
if ( 'checkbox' === $field [ 'type' ] ) {
$value = ( int ) isset ( $_POST [ $key ] );
} else {
$value = isset ( $_POST [ $key ] ) ? wc_clean ( wp_unslash ( $_POST [ $key ] ) ) : '' ;
2013-09-19 13:39:49 +00:00
}
2013-08-09 16:11:15 +00:00
2016-03-08 18:54:19 +00:00
// Hook to allow modification of value.
2019-02-04 15:31:35 +00:00
$value = apply_filters ( 'woocommerce_process_myaccount_field_' . $key , $value );
2013-08-09 16:11:15 +00:00
2016-03-08 18:54:19 +00:00
// Validation: Required fields.
2019-02-04 15:31:35 +00:00
if ( ! empty ( $field [ 'required' ] ) && empty ( $value ) ) {
/* translators: %s: Field name. */
2016-10-24 07:33:32 +00:00
wc_add_notice ( sprintf ( __ ( '%s is a required field.' , 'woocommerce' ), $field [ 'label' ] ), 'error' );
2014-02-07 18:35:30 +00:00
}
2013-09-19 13:39:49 +00:00
2019-02-04 15:31:35 +00:00
if ( ! empty ( $value ) ) {
2019-02-14 15:22:36 +00:00
// Validation and formatting rules.
2014-06-20 09:28:04 +00:00
if ( ! empty ( $field [ 'validate' ] ) && is_array ( $field [ 'validate' ] ) ) {
foreach ( $field [ 'validate' ] as $rule ) {
switch ( $rule ) {
2019-02-04 15:31:35 +00:00
case 'postcode' :
2019-04-24 11:23:48 +00:00
$country = wc_clean ( wp_unslash ( $_POST [ $load_address . '_country' ] ) );
$value = wc_format_postcode ( $value , $country );
if ( '' !== $value && ! WC_Validation :: is_postcode ( $value , $country ) ) {
switch ( $country ) {
case 'IE' :
$postcode_validation_notice = __ ( 'Please enter a valid Eircode.' , 'woocommerce' );
break ;
default :
$postcode_validation_notice = __ ( 'Please enter a valid postcode / ZIP.' , 'woocommerce' );
}
wc_add_notice ( $postcode_validation_notice , 'error' );
2014-06-20 09:28:04 +00:00
}
2016-09-13 22:13:12 +00:00
break ;
2019-02-04 15:31:35 +00:00
case 'phone' :
2019-04-24 11:23:48 +00:00
if ( '' !== $value && ! WC_Validation :: is_phone ( $value ) ) {
2019-02-04 15:31:35 +00:00
/* translators: %s: Phone number. */
2016-10-26 16:35:52 +00:00
wc_add_notice ( sprintf ( __ ( '%s is not a valid phone number.' , 'woocommerce' ), '<strong>' . $field [ 'label' ] . '</strong>' ), 'error' );
2014-06-20 09:28:04 +00:00
}
2016-09-13 22:13:12 +00:00
break ;
2019-02-04 15:31:35 +00:00
case 'email' :
$value = strtolower ( $value );
2013-09-19 13:39:49 +00:00
2019-02-04 15:31:35 +00:00
if ( ! is_email ( $value ) ) {
/* translators: %s: Email address. */
2016-10-26 16:35:52 +00:00
wc_add_notice ( sprintf ( __ ( '%s is not a valid email address.' , 'woocommerce' ), '<strong>' . $field [ 'label' ] . '</strong>' ), 'error' );
2014-06-20 09:28:04 +00:00
}
2016-09-13 22:13:12 +00:00
break ;
2014-06-20 09:28:04 +00:00
}
2013-09-19 13:39:49 +00:00
}
}
}
2013-08-09 16:11:15 +00:00
2019-02-18 20:25:25 +00:00
try {
// Set prop in customer object.
if ( is_callable ( array ( $customer , " set_ $key " ) ) ) {
$customer -> { " set_ $key " }( $value );
} else {
$customer -> update_meta_data ( $key , $value );
}
} catch ( WC_Data_Exception $e ) {
// Set notices. Ignore invalid billing email, since is already validated.
if ( 'customer_invalid_billing_email' !== $e -> getErrorCode () ) {
wc_add_notice ( $e -> getMessage (), 'error' );
}
2019-02-14 15:22:36 +00:00
}
}
2017-07-05 11:21:46 +00:00
2019-02-14 15:22:36 +00:00
/**
* Hook : woocommerce_after_save_address_validation .
*
* Allow developers to add custom validation logic and throw an error to prevent save .
*
* @ param int $user_id User ID being saved .
* @ param string $load_address Type of address e . g . billing or shipping .
* @ param array $address The address fields .
* @ param WC_Customer $customer The customer object being saved . @ since 3.6 . 0
*/
do_action ( 'woocommerce_after_save_address_validation' , $user_id , $load_address , $address , $customer );
if ( 0 < wc_notice_count ( 'error' ) ) {
return ;
}
2017-07-05 11:21:46 +00:00
2019-02-14 15:22:36 +00:00
$customer -> save ();
2013-08-09 16:11:15 +00:00
2019-02-14 15:22:36 +00:00
wc_add_notice ( __ ( 'Address changed successfully.' , 'woocommerce' ) );
2013-08-09 16:11:15 +00:00
2019-02-14 15:22:36 +00:00
do_action ( 'woocommerce_customer_save_address' , $user_id , $load_address );
2013-08-09 16:11:15 +00:00
2019-02-14 15:22:36 +00:00
wp_safe_redirect ( wc_get_endpoint_url ( 'edit-address' , '' , wc_get_page_permalink ( 'myaccount' ) ) );
exit ;
2013-08-09 16:11:15 +00:00
}
/**
* Save the password / account details and redirect back to the my account page .
*/
2014-05-28 13:52:50 +00:00
public static function save_account_details () {
2019-02-04 15:31:35 +00:00
$nonce_value = wc_get_var ( $_REQUEST [ 'save-account-details-nonce' ], wc_get_var ( $_REQUEST [ '_wpnonce' ], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce ( $nonce_value , 'save_account_details' ) ) {
2013-08-09 16:11:15 +00:00
return ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2018-03-13 14:16:56 +00:00
if ( empty ( $_POST [ 'action' ] ) || 'save_account_details' !== $_POST [ 'action' ] ) {
2013-08-09 16:11:15 +00:00
return ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2017-08-07 10:02:02 +00:00
2018-01-09 17:50:43 +00:00
$user_id = get_current_user_id ();
2013-08-09 16:11:15 +00:00
2018-01-09 17:50:43 +00:00
if ( $user_id <= 0 ) {
2013-08-09 16:11:15 +00:00
return ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
$account_first_name = ! empty ( $_POST [ 'account_first_name' ] ) ? wc_clean ( wp_unslash ( $_POST [ 'account_first_name' ] ) ) : '' ;
$account_last_name = ! empty ( $_POST [ 'account_last_name' ] ) ? wc_clean ( wp_unslash ( $_POST [ 'account_last_name' ] ) ) : '' ;
$account_display_name = ! empty ( $_POST [ 'account_display_name' ] ) ? wc_clean ( wp_unslash ( $_POST [ 'account_display_name' ] ) ) : '' ;
$account_email = ! empty ( $_POST [ 'account_email' ] ) ? wc_clean ( wp_unslash ( $_POST [ 'account_email' ] ) ) : '' ;
2019-06-13 15:49:10 +00:00
$pass_cur = ! empty ( $_POST [ 'password_current' ] ) ? $_POST [ 'password_current' ] : '' ; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
$pass1 = ! empty ( $_POST [ 'password_1' ] ) ? $_POST [ 'password_1' ] : '' ; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
$pass2 = ! empty ( $_POST [ 'password_2' ] ) ? $_POST [ 'password_2' ] : '' ; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
2018-02-22 00:34:38 +00:00
$save_pass = true ;
2018-02-22 00:52:45 +00:00
// Current user data.
$current_user = get_user_by ( 'id' , $user_id );
$current_first_name = $current_user -> first_name ;
$current_last_name = $current_user -> last_name ;
$current_email = $current_user -> user_email ;
// New user data.
2019-02-04 15:31:35 +00:00
$user = new stdClass ();
$user -> ID = $user_id ;
$user -> first_name = $account_first_name ;
$user -> last_name = $account_last_name ;
$user -> display_name = $account_display_name ;
2018-02-22 00:52:45 +00:00
// Prevent display name to be changed to email.
2017-11-28 00:56:36 +00:00
if ( is_email ( $account_display_name ) ) {
2017-11-22 08:20:49 +00:00
wc_add_notice ( __ ( 'Display name cannot be changed to email address due to privacy concern.' , 'woocommerce' ), 'error' );
}
2018-02-22 00:52:45 +00:00
2018-01-09 17:50:43 +00:00
// Handle required fields.
2019-02-04 15:31:35 +00:00
$required_fields = apply_filters (
'woocommerce_save_account_details_required_fields' ,
array (
'account_first_name' => __ ( 'First name' , 'woocommerce' ),
'account_last_name' => __ ( 'Last name' , 'woocommerce' ),
'account_display_name' => __ ( 'Display name' , 'woocommerce' ),
'account_email' => __ ( 'Email address' , 'woocommerce' ),
)
);
2015-09-07 14:21:54 +00:00
foreach ( $required_fields as $field_key => $field_name ) {
2016-10-19 11:45:50 +00:00
if ( empty ( $_POST [ $field_key ] ) ) {
2019-02-04 15:31:35 +00:00
/* translators: %s: Field name. */
2016-10-26 16:35:52 +00:00
wc_add_notice ( sprintf ( __ ( '%s is a required field.' , 'woocommerce' ), '<strong>' . esc_html ( $field_name ) . '</strong>' ), 'error' );
2015-09-07 14:21:54 +00:00
}
2014-02-07 18:35:30 +00:00
}
2017-12-13 08:51:54 +00:00
2015-09-07 14:21:54 +00:00
if ( $account_email ) {
2016-10-19 11:45:50 +00:00
$account_email = sanitize_email ( $account_email );
2015-09-07 14:21:54 +00:00
if ( ! is_email ( $account_email ) ) {
wc_add_notice ( __ ( 'Please provide a valid email address.' , 'woocommerce' ), 'error' );
} elseif ( email_exists ( $account_email ) && $account_email !== $current_user -> user_email ) {
wc_add_notice ( __ ( 'This email address is already registered.' , 'woocommerce' ), 'error' );
}
$user -> user_email = $account_email ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2014-04-22 19:01:57 +00:00
if ( ! empty ( $pass_cur ) && empty ( $pass1 ) && empty ( $pass2 ) ) {
wc_add_notice ( __ ( 'Please fill out all password fields.' , 'woocommerce' ), 'error' );
$save_pass = false ;
} elseif ( ! empty ( $pass1 ) && empty ( $pass_cur ) ) {
wc_add_notice ( __ ( 'Please enter your current password.' , 'woocommerce' ), 'error' );
$save_pass = false ;
} elseif ( ! empty ( $pass1 ) && empty ( $pass2 ) ) {
2013-11-13 04:29:03 +00:00
wc_add_notice ( __ ( 'Please re-enter your password.' , 'woocommerce' ), 'error' );
2014-04-22 19:01:57 +00:00
$save_pass = false ;
2015-04-30 05:07:34 +00:00
} elseif ( ( ! empty ( $pass1 ) || ! empty ( $pass2 ) ) && $pass1 !== $pass2 ) {
wc_add_notice ( __ ( 'New passwords do not match.' , 'woocommerce' ), 'error' );
2014-04-22 19:01:57 +00:00
$save_pass = false ;
2016-08-04 10:27:38 +00:00
} elseif ( ! empty ( $pass1 ) && ! wp_check_password ( $pass_cur , $current_user -> user_pass , $current_user -> ID ) ) {
wc_add_notice ( __ ( 'Your current password is incorrect.' , 'woocommerce' ), 'error' );
$save_pass = false ;
2014-04-22 19:01:57 +00:00
}
if ( $pass1 && $save_pass ) {
$user -> user_pass = $pass1 ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
// Allow plugins to return their own errors.
2018-01-09 17:50:43 +00:00
$errors = new WP_Error ();
2015-07-10 10:11:51 +00:00
do_action_ref_array ( 'woocommerce_save_account_details_errors' , array ( & $errors , & $user ) );
2013-08-09 16:11:15 +00:00
2014-02-07 18:35:30 +00:00
if ( $errors -> get_error_messages () ) {
foreach ( $errors -> get_error_messages () as $error ) {
2013-11-13 04:29:03 +00:00
wc_add_notice ( $error , 'error' );
2014-02-07 18:35:30 +00:00
}
}
2013-08-09 16:11:15 +00:00
2014-04-22 19:01:57 +00:00
if ( wc_notice_count ( 'error' ) === 0 ) {
2016-09-02 02:00:46 +00:00
wp_update_user ( $user );
2013-08-09 16:11:15 +00:00
2018-01-09 17:50:43 +00:00
// Update customer object to keep data in sync.
$customer = new WC_Customer ( $user -> ID );
if ( $customer ) {
// Keep billing data in sync if data changed.
if ( is_email ( $user -> user_email ) && $current_email !== $user -> user_email ) {
$customer -> set_billing_email ( $user -> user_email );
}
if ( $current_first_name !== $user -> first_name ) {
$customer -> set_billing_first_name ( $user -> first_name );
}
if ( $current_last_name !== $user -> last_name ) {
$customer -> set_billing_last_name ( $user -> last_name );
}
$customer -> save ();
}
2013-11-13 04:32:29 +00:00
wc_add_notice ( __ ( 'Account details changed successfully.' , 'woocommerce' ) );
2013-08-09 16:11:15 +00:00
do_action ( 'woocommerce_save_account_details' , $user -> ID );
2015-02-15 19:13:22 +00:00
wp_safe_redirect ( wc_get_page_permalink ( 'myaccount' ) );
2013-08-09 16:11:15 +00:00
exit ;
}
}
/**
* Process the checkout form .
*/
2014-05-28 13:52:50 +00:00
public static function checkout_action () {
2019-02-04 15:31:35 +00:00
if ( isset ( $_POST [ 'woocommerce_checkout_place_order' ] ) || isset ( $_POST [ 'woocommerce_checkout_update_totals' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2013-08-09 16:11:15 +00:00
2015-05-14 21:18:53 +00:00
if ( WC () -> cart -> is_empty () ) {
2019-08-29 07:45:41 +00:00
wp_safe_redirect ( wc_get_cart_url () );
2013-08-09 16:11:15 +00:00
exit ;
}
2017-09-05 19:52:39 +00:00
wc_maybe_define_constant ( 'WOOCOMMERCE_CHECKOUT' , true );
2013-08-09 16:11:15 +00:00
2014-05-28 13:52:50 +00:00
WC () -> checkout () -> process_checkout ();
2013-08-09 16:11:15 +00:00
}
}
/**
* Process the pay form .
2019-03-01 11:25:31 +00:00
*
* @ throws Exception On payment error .
2013-08-09 16:11:15 +00:00
*/
2014-05-28 13:52:50 +00:00
public static function pay_action () {
2013-08-09 16:11:15 +00:00
global $wp ;
2019-02-04 15:31:35 +00:00
if ( isset ( $_POST [ 'woocommerce_pay' ], $_GET [ 'key' ] ) ) {
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2018-03-13 14:16:56 +00:00
$nonce_value = wc_get_var ( $_REQUEST [ 'woocommerce-pay-nonce' ], wc_get_var ( $_REQUEST [ '_wpnonce' ], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce ( $nonce_value , 'woocommerce-pay' ) ) {
return ;
}
2013-08-09 16:11:15 +00:00
ob_start ();
2019-02-04 15:31:35 +00:00
// Pay for existing order.
$order_key = wp_unslash ( $_GET [ 'key' ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$order_id = absint ( $wp -> query_vars [ 'order-pay' ] );
$order = wc_get_order ( $order_id );
2014-04-24 21:18:41 +00:00
2019-01-21 16:02:28 +00:00
if ( $order_id === $order -> get_id () && hash_equals ( $order -> get_order_key (), $order_key ) && $order -> needs_payment () ) {
2013-08-09 16:11:15 +00:00
2016-02-05 18:44:55 +00:00
do_action ( 'woocommerce_before_pay_action' , $order );
2019-02-04 15:31:35 +00:00
WC () -> customer -> set_props (
array (
'billing_country' => $order -> get_billing_country () ? $order -> get_billing_country () : null ,
'billing_state' => $order -> get_billing_state () ? $order -> get_billing_state () : null ,
'billing_postcode' => $order -> get_billing_postcode () ? $order -> get_billing_postcode () : null ,
'billing_city' => $order -> get_billing_city () ? $order -> get_billing_city () : null ,
)
);
2016-03-09 20:49:02 +00:00
WC () -> customer -> save ();
2015-10-06 11:33:45 +00:00
if ( ! empty ( $_POST [ 'terms-field' ] ) && empty ( $_POST [ 'terms' ] ) ) {
2018-04-06 10:43:30 +00:00
wc_add_notice ( __ ( 'Please read and accept the terms and conditions to proceed with your order.' , 'woocommerce' ), 'error' );
2015-10-06 11:33:45 +00:00
return ;
}
2019-02-04 15:31:35 +00:00
// Update payment method.
2013-10-16 13:14:15 +00:00
if ( $order -> needs_payment () ) {
2019-03-01 11:25:31 +00:00
try {
$payment_method_id = isset ( $_POST [ 'payment_method' ] ) ? wc_clean ( wp_unslash ( $_POST [ 'payment_method' ] ) ) : false ;
2013-08-09 16:11:15 +00:00
2019-03-01 11:25:31 +00:00
if ( ! $payment_method_id ) {
throw new Exception ( __ ( 'Invalid payment method.' , 'woocommerce' ) );
}
2015-10-06 11:33:45 +00:00
2019-03-01 11:25:31 +00:00
$available_gateways = WC () -> payment_gateways -> get_available_payment_gateways ();
$payment_method = isset ( $available_gateways [ $payment_method_id ] ) ? $available_gateways [ $payment_method_id ] : false ;
2013-08-09 16:11:15 +00:00
2019-03-01 11:25:31 +00:00
if ( ! $payment_method ) {
throw new Exception ( __ ( 'Invalid payment method.' , 'woocommerce' ) );
}
$order -> set_payment_method ( $payment_method );
$order -> save ();
2013-08-09 16:11:15 +00:00
2019-03-01 11:25:31 +00:00
$payment_method -> validate_fields ();
2013-08-09 16:11:15 +00:00
2019-03-01 11:25:31 +00:00
if ( 0 === wc_notice_count ( 'error' ) ) {
2013-08-09 16:11:15 +00:00
2019-03-01 11:25:31 +00:00
$result = $payment_method -> process_payment ( $order_id );
2013-08-09 16:11:15 +00:00
2019-03-01 11:25:31 +00:00
// Redirect to success/confirmation/payment page.
if ( isset ( $result [ 'result' ] ) && 'success' === $result [ 'result' ] ) {
$result = apply_filters ( 'woocommerce_payment_successful_result' , $result , $order_id );
2013-08-09 16:11:15 +00:00
2019-03-01 11:25:31 +00:00
wp_redirect ( $result [ 'redirect' ] ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
exit ;
}
2013-08-09 16:11:15 +00:00
}
2019-03-01 11:25:31 +00:00
} catch ( Exception $e ) {
wc_add_notice ( $e -> getMessage (), 'error' );
2013-08-09 16:11:15 +00:00
}
} else {
2019-02-04 15:31:35 +00:00
// No payment was required for order.
2013-08-09 16:11:15 +00:00
$order -> payment_complete ();
wp_safe_redirect ( $order -> get_checkout_order_received_url () );
exit ;
}
2016-02-05 18:44:55 +00:00
do_action ( 'woocommerce_after_pay_action' , $order );
}
2013-08-09 16:11:15 +00:00
}
}
2013-11-01 17:08:44 +00:00
/**
* Process the add payment method form .
*/
2014-05-28 13:52:50 +00:00
public static function add_payment_method_action () {
2018-03-13 14:16:56 +00:00
if ( isset ( $_POST [ 'woocommerce_add_payment_method' ], $_POST [ 'payment_method' ] ) ) {
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2018-03-13 14:16:56 +00:00
$nonce_value = wc_get_var ( $_REQUEST [ 'woocommerce-add-payment-method-nonce' ], wc_get_var ( $_REQUEST [ '_wpnonce' ], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce ( $nonce_value , 'woocommerce-add-payment-method' ) ) {
return ;
}
2013-11-01 17:08:44 +00:00
ob_start ();
2017-08-07 11:39:16 +00:00
$payment_method_id = wc_clean ( wp_unslash ( $_POST [ 'payment_method' ] ) );
2013-11-01 17:08:44 +00:00
$available_gateways = WC () -> payment_gateways -> get_available_payment_gateways ();
2017-08-07 11:39:16 +00:00
if ( isset ( $available_gateways [ $payment_method_id ] ) ) {
$gateway = $available_gateways [ $payment_method_id ];
if ( ! $gateway -> supports ( 'add_payment_method' ) && ! $gateway -> supports ( 'tokenization' ) ) {
wc_add_notice ( __ ( 'Invalid payment gateway.' , 'woocommerce' ), 'error' );
return ;
}
$gateway -> validate_fields ();
if ( wc_notice_count ( 'error' ) > 0 ) {
return ;
}
$result = $gateway -> add_payment_method ();
2016-09-07 22:32:24 +00:00
if ( 'success' === $result [ 'result' ] ) {
2017-08-07 11:39:16 +00:00
wc_add_notice ( __ ( 'Payment method successfully added.' , 'woocommerce' ) );
}
if ( 'failure' === $result [ 'result' ] ) {
wc_add_notice ( __ ( 'Unable to add payment method to your account.' , 'woocommerce' ), 'error' );
}
if ( ! empty ( $result [ 'redirect' ] ) ) {
2019-02-04 15:31:35 +00:00
wp_redirect ( $result [ 'redirect' ] ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
2013-11-01 21:14:00 +00:00
exit ();
2013-11-01 17:08:44 +00:00
}
}
}
}
2016-05-26 13:50:22 +00:00
/**
* Process the delete payment method form .
*/
public static function delete_payment_method_action () {
global $wp ;
if ( isset ( $wp -> query_vars [ 'delete-payment-method' ] ) ) {
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2016-05-26 13:50:22 +00:00
$token_id = absint ( $wp -> query_vars [ 'delete-payment-method' ] );
2017-03-03 13:18:07 +00:00
$token = WC_Payment_Tokens :: get ( $token_id );
2016-05-26 13:50:22 +00:00
2019-02-04 15:31:35 +00:00
if ( is_null ( $token ) || get_current_user_id () !== $token -> get_user_id () || ! isset ( $_REQUEST [ '_wpnonce' ] ) || false === wp_verify_nonce ( wp_unslash ( $_REQUEST [ '_wpnonce' ] ), 'delete-payment-method-' . $token_id ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2016-10-11 01:39:13 +00:00
wc_add_notice ( __ ( 'Invalid payment method.' , 'woocommerce' ), 'error' );
2017-03-03 13:18:07 +00:00
} else {
2016-05-26 13:50:22 +00:00
WC_Payment_Tokens :: delete ( $token_id );
wc_add_notice ( __ ( 'Payment method deleted.' , 'woocommerce' ) );
}
2019-02-04 15:31:35 +00:00
wp_safe_redirect ( wc_get_account_endpoint_url ( 'payment-methods' ) );
2016-05-26 13:50:22 +00:00
exit ();
}
}
/**
* Process the delete payment method form .
*/
public static function set_default_payment_method_action () {
global $wp ;
if ( isset ( $wp -> query_vars [ 'set-default-payment-method' ] ) ) {
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2016-05-26 13:50:22 +00:00
$token_id = absint ( $wp -> query_vars [ 'set-default-payment-method' ] );
2017-03-03 13:18:07 +00:00
$token = WC_Payment_Tokens :: get ( $token_id );
2016-05-26 13:50:22 +00:00
2019-02-04 15:31:35 +00:00
if ( is_null ( $token ) || get_current_user_id () !== $token -> get_user_id () || ! isset ( $_REQUEST [ '_wpnonce' ] ) || false === wp_verify_nonce ( wp_unslash ( $_REQUEST [ '_wpnonce' ] ), 'set-default-payment-method-' . $token_id ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2016-10-11 01:39:13 +00:00
wc_add_notice ( __ ( 'Invalid payment method.' , 'woocommerce' ), 'error' );
2017-03-03 13:18:07 +00:00
} else {
2016-05-26 13:50:22 +00:00
WC_Payment_Tokens :: set_users_default ( $token -> get_user_id (), intval ( $token_id ) );
wc_add_notice ( __ ( 'This payment method was successfully set as your default.' , 'woocommerce' ) );
}
2019-02-04 15:31:35 +00:00
wp_safe_redirect ( wc_get_account_endpoint_url ( 'payment-methods' ) );
2016-05-26 13:50:22 +00:00
exit ();
}
}
2013-08-09 16:11:15 +00:00
/**
* Remove from cart / update .
*/
2014-05-28 13:52:50 +00:00
public static function update_cart_action () {
2017-08-07 10:02:02 +00:00
if ( ! ( isset ( $_REQUEST [ 'apply_coupon' ] ) || isset ( $_REQUEST [ 'remove_coupon' ] ) || isset ( $_REQUEST [ 'remove_item' ] ) || isset ( $_REQUEST [ 'undo_item' ] ) || isset ( $_REQUEST [ 'update_cart' ] ) || isset ( $_REQUEST [ 'proceed' ] ) ) ) {
return ;
}
2013-12-31 14:02:50 +00:00
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2016-09-02 03:15:49 +00:00
2018-03-13 14:16:56 +00:00
$nonce_value = wc_get_var ( $_REQUEST [ 'woocommerce-cart-nonce' ], wc_get_var ( $_REQUEST [ '_wpnonce' ], '' ) ); // @codingStandardsIgnoreLine.
2017-08-07 10:02:02 +00:00
if ( ! empty ( $_POST [ 'apply_coupon' ] ) && ! empty ( $_POST [ 'coupon_code' ] ) ) {
2019-03-06 11:44:27 +00:00
WC () -> cart -> add_discount ( wc_format_coupon_code ( wp_unslash ( $_POST [ 'coupon_code' ] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2013-12-31 14:02:50 +00:00
2016-09-02 03:15:49 +00:00
} elseif ( isset ( $_GET [ 'remove_coupon' ] ) ) {
2019-03-06 11:44:27 +00:00
WC () -> cart -> remove_coupon ( wc_format_coupon_code ( urldecode ( wp_unslash ( $_GET [ 'remove_coupon' ] ) ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2013-12-31 14:02:50 +00:00
2018-03-13 14:16:56 +00:00
} elseif ( ! empty ( $_GET [ 'remove_item' ] ) && wp_verify_nonce ( $nonce_value , 'woocommerce-cart' ) ) {
$cart_item_key = sanitize_text_field ( wp_unslash ( $_GET [ 'remove_item' ] ) );
$cart_item = WC () -> cart -> get_cart_item ( $cart_item_key );
2013-08-09 16:11:15 +00:00
2018-03-13 14:16:56 +00:00
if ( $cart_item ) {
2015-02-16 11:31:33 +00:00
WC () -> cart -> remove_cart_item ( $cart_item_key );
2013-08-09 16:11:15 +00:00
2015-02-16 11:31:33 +00:00
$product = wc_get_product ( $cart_item [ 'product_id' ] );
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
/* translators: %s: Item name. */
WIP - Product CRUD (#12065)
* Created function to get the catalog visibility options
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Sanitize ids later
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Bump template version
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* Made abstract function useful
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* Allow WP_Query to preload post data, and meta in wc_get_products()
Allow WP_Query to bulk query for post data and meta if more than
just IDs are requested from wc_get_products(). Reduces query count
significantly.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Sanitize ids later
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Bump template version
* Made abstract function useful
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* Prevent notices
* Handle image_id from parent
* Fix error
* Remove _wc_save_product_price
* Remove todo
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* [Product CRUD] Abstract todos (#12305)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Revert "[Product CRUD] Abstract todos (#12305)"
This reverts commit 9a6136fcf88fec16f97457b7c8a4388f7587bfa2.
* Remove deprecated get_variation_id()
* New default attributes method
* [Product CRUD] Product Datastore (#12317)
* Fix up tests in the product/* folder.
* Handle data store updates for grouped, variable, external, simple, and general data store updates for products.
* Variations & variable changes.
* Update -functions.php calls to use data store.
* Add an interface for the public product data store methods.
* Finished product factory tests
* Correctly delete in the api, fix up some comments, and implement an interface for the public variable methods.
* Fix up delete in all versions of the api
* Handle feedback
* Match protected decloration to parent
* Product crud abstract todos (#12316)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Fix up store
* Fixed method returning in write context
* Fix error in variation admin
* Check for parent value - fixes tax class
* Remove old/complete todos
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* Remove deprecated get_variation_id()
* New default attributes method
* Fixed method returning in write context
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed coding standards
* TODO is not accurate.
* Should pass WC_Product instancies to WC_Comments methods (#12327)
* Use new method in abstract order class to prevent headers sent issue in tests
* Fixed variable description in REST API
* Updated how create initial product variation
* Fixed a few fatal errors and warnings in Products CRUD (#12329)
* Fixed a few fatal errors and warnings in Products CRUD
* Fixed sync functions
* Add variations CRUD to legacy API (#12331)
* Apply crud to variable products in legacy API v1
* New REST API do not need fallback for default attributes
* Apply variations CRUD to legacy API v2
* Legacy v2 - save default attributes
* Variations in legacy API v2 do not have descriptions
* Fixed legacy API v2 variations params
* Applied variations CRUD to legacy API v3
* Sync before save in legacy apis
* Punc
* Removed API todos
* Removed test
* Products endpoint tweaks (#12354)
* Var type already normalized on CRUD
* Let Product CRUD handle with validation, sanitization and conditional checks
* Set downloads using WC_Product_Download
* Stop try catch exceptions more than one time
* Handle WC_Data_Exception in legacy API
* Complete remove products when fails on creating
* On creating I mean!
* Already have a method to complete delete products
* Fixed standards using WP CodeSniffer
* get_the_terms() returns false when empty
* get_manage_stock returns boolean
@claudiosanches
* Merge conflict
* Variations API endpoint fixes
* Product CRUD improvements (#12359)
* args is not used any more - remove todo
* Added test for attributes
* wc_get_price_excluding_tax usage
* parent usage
* Fix rating counts
* Test fixes
* Cleanup after tests
* Make sure status transition code runs even during API calls, not just in admin.
* Default visibility
* Fix attribute setting in API
* Use get name instead of get title
* variation id usage
* Improved cross sell templates
* variation_data
* Grouped product sync
* Notices
* Sync is not needed in API
* Delete
* Rename interfaces
* Update counts in data store
2016-11-16 12:38:24 +00:00
$item_removed_title = apply_filters ( 'woocommerce_cart_item_removed_title' , $product ? sprintf ( _x ( '“%s”' , 'Item name in quotes' , 'woocommerce' ), $product -> get_name () ) : __ ( 'Item' , 'woocommerce' ), $cart_item );
2015-09-11 08:22:09 +00:00
// Don't show undo link if removed item is out of stock.
2018-02-02 10:56:24 +00:00
if ( $product && $product -> is_in_stock () && $product -> has_enough_stock ( $cart_item [ 'quantity' ] ) ) {
2018-03-13 14:16:56 +00:00
/* Translators: %s Product title. */
2016-04-25 12:07:38 +00:00
$removed_notice = sprintf ( __ ( '%s removed.' , 'woocommerce' ), $item_removed_title );
2017-12-07 19:16:54 +00:00
$removed_notice .= ' <a href="' . esc_url ( wc_get_cart_undo_url ( $cart_item_key ) ) . '" class="restore-item">' . __ ( 'Undo?' , 'woocommerce' ) . '</a>' ;
2015-09-11 08:22:09 +00:00
} else {
2018-03-13 14:16:56 +00:00
/* Translators: %s Product title. */
2016-04-25 12:07:38 +00:00
$removed_notice = sprintf ( __ ( '%s removed.' , 'woocommerce' ), $item_removed_title );
2015-09-11 08:22:09 +00:00
}
2016-04-25 12:07:38 +00:00
2019-06-27 13:54:35 +00:00
wc_add_notice ( $removed_notice , apply_filters ( 'woocommerce_cart_item_removed_notice_type' , 'success' ) );
2015-02-16 11:31:33 +00:00
}
2014-11-18 16:31:06 +00:00
2019-02-04 15:31:35 +00:00
$referer = wp_get_referer () ? remove_query_arg ( array ( 'remove_item' , 'add-to-cart' , 'added-to-cart' , 'order_again' , '_wpnonce' ), add_query_arg ( 'removed_item' , '1' , wp_get_referer () ) ) : wc_get_cart_url ();
2013-08-09 16:11:15 +00:00
wp_safe_redirect ( $referer );
exit ;
2013-12-31 14:02:50 +00:00
2018-03-13 14:16:56 +00:00
} elseif ( ! empty ( $_GET [ 'undo_item' ] ) && isset ( $_GET [ '_wpnonce' ] ) && wp_verify_nonce ( $nonce_value , 'woocommerce-cart' ) ) {
2016-09-02 03:15:49 +00:00
2018-03-13 14:16:56 +00:00
// Undo Cart Item.
$cart_item_key = sanitize_text_field ( wp_unslash ( $_GET [ 'undo_item' ] ) );
2014-11-18 16:31:06 +00:00
2015-01-07 18:52:17 +00:00
WC () -> cart -> restore_cart_item ( $cart_item_key );
2014-11-18 16:31:06 +00:00
2019-02-04 15:31:35 +00:00
$referer = wp_get_referer () ? remove_query_arg ( array ( 'undo_item' , '_wpnonce' ), wp_get_referer () ) : wc_get_cart_url ();
2014-11-18 16:31:06 +00:00
wp_safe_redirect ( $referer );
exit ;
2016-09-02 03:15:49 +00:00
2014-11-18 16:31:06 +00:00
}
2018-03-13 14:16:56 +00:00
// Update Cart - checks apply_coupon too because they are in the same form.
if ( ( ! empty ( $_POST [ 'apply_coupon' ] ) || ! empty ( $_POST [ 'update_cart' ] ) || ! empty ( $_POST [ 'proceed' ] ) ) && wp_verify_nonce ( $nonce_value , 'woocommerce-cart' ) ) {
2013-08-09 16:11:15 +00:00
2013-12-31 14:02:50 +00:00
$cart_updated = false ;
2018-03-13 14:16:56 +00:00
$cart_totals = isset ( $_POST [ 'cart' ] ) ? wp_unslash ( $_POST [ 'cart' ] ) : '' ; // PHPCS: input var ok, CSRF ok, sanitization ok.
2013-08-09 16:11:15 +00:00
2015-05-14 21:18:53 +00:00
if ( ! WC () -> cart -> is_empty () && is_array ( $cart_totals ) ) {
2013-08-09 16:11:15 +00:00
foreach ( WC () -> cart -> get_cart () as $cart_item_key => $values ) {
$_product = $values [ 'data' ];
2018-03-13 14:16:56 +00:00
// Skip product if no updated quantity was posted.
2014-10-09 15:50:42 +00:00
if ( ! isset ( $cart_totals [ $cart_item_key ] ) || ! isset ( $cart_totals [ $cart_item_key ][ 'qty' ] ) ) {
2013-08-09 16:11:15 +00:00
continue ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2018-03-13 14:16:56 +00:00
// Sanitize.
$quantity = apply_filters ( 'woocommerce_stock_amount_cart_item' , wc_stock_amount ( preg_replace ( '/[^0-9\.]/' , '' , $cart_totals [ $cart_item_key ][ 'qty' ] ) ), $cart_item_key );
2013-08-09 16:11:15 +00:00
2017-08-22 09:53:34 +00:00
if ( '' === $quantity || $quantity === $values [ 'quantity' ] ) {
2013-08-09 16:11:15 +00:00
continue ;
2017-03-07 20:24:24 +00:00
}
2013-08-09 16:11:15 +00:00
2018-03-13 14:16:56 +00:00
// Update cart validation.
$passed_validation = apply_filters ( 'woocommerce_update_cart_validation' , true , $cart_item_key , $values , $quantity );
2013-08-09 16:11:15 +00:00
2018-03-13 14:16:56 +00:00
// is_sold_individually.
2013-08-09 16:11:15 +00:00
if ( $_product -> is_sold_individually () && $quantity > 1 ) {
2018-03-13 14:16:56 +00:00
/* Translators: %s Product title. */
WIP - Product CRUD (#12065)
* Created function to get the catalog visibility options
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Sanitize ids later
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Bump template version
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* Made abstract function useful
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* Allow WP_Query to preload post data, and meta in wc_get_products()
Allow WP_Query to bulk query for post data and meta if more than
just IDs are requested from wc_get_products(). Reduces query count
significantly.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Sanitize ids later
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Bump template version
* Made abstract function useful
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* Prevent notices
* Handle image_id from parent
* Fix error
* Remove _wc_save_product_price
* Remove todo
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* [Product CRUD] Abstract todos (#12305)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Revert "[Product CRUD] Abstract todos (#12305)"
This reverts commit 9a6136fcf88fec16f97457b7c8a4388f7587bfa2.
* Remove deprecated get_variation_id()
* New default attributes method
* [Product CRUD] Product Datastore (#12317)
* Fix up tests in the product/* folder.
* Handle data store updates for grouped, variable, external, simple, and general data store updates for products.
* Variations & variable changes.
* Update -functions.php calls to use data store.
* Add an interface for the public product data store methods.
* Finished product factory tests
* Correctly delete in the api, fix up some comments, and implement an interface for the public variable methods.
* Fix up delete in all versions of the api
* Handle feedback
* Match protected decloration to parent
* Product crud abstract todos (#12316)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Fix up store
* Fixed method returning in write context
* Fix error in variation admin
* Check for parent value - fixes tax class
* Remove old/complete todos
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* Remove deprecated get_variation_id()
* New default attributes method
* Fixed method returning in write context
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed coding standards
* TODO is not accurate.
* Should pass WC_Product instancies to WC_Comments methods (#12327)
* Use new method in abstract order class to prevent headers sent issue in tests
* Fixed variable description in REST API
* Updated how create initial product variation
* Fixed a few fatal errors and warnings in Products CRUD (#12329)
* Fixed a few fatal errors and warnings in Products CRUD
* Fixed sync functions
* Add variations CRUD to legacy API (#12331)
* Apply crud to variable products in legacy API v1
* New REST API do not need fallback for default attributes
* Apply variations CRUD to legacy API v2
* Legacy v2 - save default attributes
* Variations in legacy API v2 do not have descriptions
* Fixed legacy API v2 variations params
* Applied variations CRUD to legacy API v3
* Sync before save in legacy apis
* Punc
* Removed API todos
* Removed test
* Products endpoint tweaks (#12354)
* Var type already normalized on CRUD
* Let Product CRUD handle with validation, sanitization and conditional checks
* Set downloads using WC_Product_Download
* Stop try catch exceptions more than one time
* Handle WC_Data_Exception in legacy API
* Complete remove products when fails on creating
* On creating I mean!
* Already have a method to complete delete products
* Fixed standards using WP CodeSniffer
* get_the_terms() returns false when empty
* get_manage_stock returns boolean
@claudiosanches
* Merge conflict
* Variations API endpoint fixes
* Product CRUD improvements (#12359)
* args is not used any more - remove todo
* Added test for attributes
* wc_get_price_excluding_tax usage
* parent usage
* Fix rating counts
* Test fixes
* Cleanup after tests
* Make sure status transition code runs even during API calls, not just in admin.
* Default visibility
* Fix attribute setting in API
* Use get name instead of get title
* variation id usage
* Improved cross sell templates
* variation_data
* Grouped product sync
* Notices
* Sync is not needed in API
* Delete
* Rename interfaces
* Update counts in data store
2016-11-16 12:38:24 +00:00
wc_add_notice ( sprintf ( __ ( 'You can only have 1 %s in your cart.' , 'woocommerce' ), $_product -> get_name () ), 'error' );
2013-08-09 16:11:15 +00:00
$passed_validation = false ;
}
2014-02-07 18:35:30 +00:00
if ( $passed_validation ) {
2014-02-07 18:27:07 +00:00
WC () -> cart -> set_quantity ( $cart_item_key , $quantity , false );
2014-11-07 10:16:37 +00:00
$cart_updated = true ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
}
2014-02-26 12:14:50 +00:00
}
2018-03-13 14:16:56 +00:00
// Trigger action - let 3rd parties update the cart if they need to and update the $cart_updated variable.
2014-03-03 15:15:32 +00:00
$cart_updated = apply_filters ( 'woocommerce_update_cart_action_cart_updated' , $cart_updated );
2013-08-19 14:19:44 +00:00
2014-03-03 15:15:32 +00:00
if ( $cart_updated ) {
2013-08-19 14:19:44 +00:00
WC () -> cart -> calculate_totals ();
2013-08-09 16:11:15 +00:00
}
if ( ! empty ( $_POST [ 'proceed' ] ) ) {
2015-10-28 17:56:31 +00:00
wp_safe_redirect ( wc_get_checkout_url () );
2013-08-09 16:11:15 +00:00
exit ;
2013-12-31 14:02:50 +00:00
} elseif ( $cart_updated ) {
2019-07-09 20:22:41 +00:00
wc_add_notice ( __ ( 'Cart updated.' , 'woocommerce' ), apply_filters ( 'woocommerce_cart_updated_notice_type' , 'success' ) );
2017-03-16 11:18:15 +00:00
$referer = remove_query_arg ( array ( 'remove_coupon' , 'add-to-cart' ), ( wp_get_referer () ? wp_get_referer () : wc_get_cart_url () ) );
2013-08-09 16:11:15 +00:00
wp_safe_redirect ( $referer );
exit ;
}
}
}
/**
* Place a previous order again .
2018-06-22 11:39:06 +00:00
*
* @ deprecated 3.5 . 0 Logic moved to cart session handling .
2013-08-09 16:11:15 +00:00
*/
2014-05-28 13:52:50 +00:00
public static function order_again () {
2018-06-22 11:39:06 +00:00
wc_deprecated_function ( 'WC_Form_Handler::order_again' , '3.5' , 'This method should not be called manually.' );
2013-08-09 16:11:15 +00:00
}
/**
* Cancel a pending order .
*/
2014-05-28 13:52:50 +00:00
public static function cancel_order () {
2017-09-21 00:08:06 +00:00
if (
isset ( $_GET [ 'cancel_order' ] ) &&
isset ( $_GET [ 'order' ] ) &&
isset ( $_GET [ 'order_id' ] ) &&
2019-02-04 15:31:35 +00:00
( isset ( $_GET [ '_wpnonce' ] ) && wp_verify_nonce ( wp_unslash ( $_GET [ '_wpnonce' ] ), 'woocommerce-cancel_order' ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2017-09-21 00:08:06 +00:00
) {
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
$order_key = wp_unslash ( $_GET [ 'order' ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2013-12-03 14:07:11 +00:00
$order_id = absint ( $_GET [ 'order_id' ] );
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $order_id );
2013-12-03 14:07:11 +00:00
$user_can_cancel = current_user_can ( 'cancel_order' , $order_id );
2019-05-14 15:52:54 +00:00
$order_can_cancel = $order -> has_status ( apply_filters ( 'woocommerce_valid_order_statuses_for_cancel' , array ( 'pending' , 'failed' ), $order ) );
2019-02-04 15:31:35 +00:00
$redirect = isset ( $_GET [ 'redirect' ] ) ? wp_unslash ( $_GET [ 'redirect' ] ) : '' ; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
if ( $user_can_cancel && $order_can_cancel && $order -> get_id () === $order_id && hash_equals ( $order -> get_order_key (), $order_key ) ) {
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
// Cancel the order + restore stock.
2016-08-22 15:57:54 +00:00
WC () -> session -> set ( 'order_awaiting_payment' , false );
$order -> update_status ( 'cancelled' , __ ( 'Order cancelled by customer.' , 'woocommerce' ) );
2013-08-09 16:11:15 +00:00
2014-03-26 09:58:51 +00:00
wc_add_notice ( apply_filters ( 'woocommerce_order_cancelled_notice' , __ ( 'Your order was cancelled.' , 'woocommerce' ) ), apply_filters ( 'woocommerce_order_cancelled_notice_type' , 'notice' ) );
2013-08-09 16:11:15 +00:00
2016-08-05 14:56:23 +00:00
do_action ( 'woocommerce_cancelled_order' , $order -> get_id () );
2013-08-09 16:11:15 +00:00
2013-12-03 14:07:11 +00:00
} elseif ( $user_can_cancel && ! $order_can_cancel ) {
wc_add_notice ( __ ( 'Your order can no longer be cancelled. Please contact us if you need assistance.' , 'woocommerce' ), 'error' );
} else {
2013-11-13 04:29:03 +00:00
wc_add_notice ( __ ( 'Invalid order.' , 'woocommerce' ), 'error' );
2013-12-03 14:07:11 +00:00
}
2013-08-09 16:11:15 +00:00
2013-12-30 14:09:46 +00:00
if ( $redirect ) {
wp_safe_redirect ( $redirect );
exit ;
}
2013-12-03 14:07:11 +00:00
}
2013-08-09 16:11:15 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* Add to cart action .
2013-08-09 16:11:15 +00:00
*
* Checks for a valid request , does validation ( via hooks ) and then redirects if valid .
*
2019-02-04 15:31:35 +00:00
* @ param bool $url ( default : false ) URL to redirect to .
2013-08-09 16:11:15 +00:00
*/
2014-05-28 13:52:50 +00:00
public static function add_to_cart_action ( $url = false ) {
2019-02-04 15:31:35 +00:00
if ( ! isset ( $_REQUEST [ 'add-to-cart' ] ) || ! is_numeric ( wp_unslash ( $_REQUEST [ 'add-to-cart' ] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2013-08-09 16:11:15 +00:00
return ;
2014-02-07 18:35:30 +00:00
}
2013-08-09 16:11:15 +00:00
2017-11-08 15:07:00 +00:00
wc_nocache_headers ();
2017-08-07 10:02:02 +00:00
2019-02-04 15:31:35 +00:00
$product_id = apply_filters ( 'woocommerce_add_to_cart_product_id' , absint ( wp_unslash ( $_REQUEST [ 'add-to-cart' ] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$was_added_to_cart = false ;
$adding_to_cart = wc_get_product ( $product_id );
2015-08-24 14:28:57 +00:00
if ( ! $adding_to_cart ) {
return ;
}
WIP - Product CRUD (#12065)
* Created function to get the catalog visibility options
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Sanitize ids later
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Bump template version
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* Made abstract function useful
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* Allow WP_Query to preload post data, and meta in wc_get_products()
Allow WP_Query to bulk query for post data and meta if more than
just IDs are requested from wc_get_products(). Reduces query count
significantly.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Sanitize ids later
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Bump template version
* Made abstract function useful
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* Prevent notices
* Handle image_id from parent
* Fix error
* Remove _wc_save_product_price
* Remove todo
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* [Product CRUD] Abstract todos (#12305)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Revert "[Product CRUD] Abstract todos (#12305)"
This reverts commit 9a6136fcf88fec16f97457b7c8a4388f7587bfa2.
* Remove deprecated get_variation_id()
* New default attributes method
* [Product CRUD] Product Datastore (#12317)
* Fix up tests in the product/* folder.
* Handle data store updates for grouped, variable, external, simple, and general data store updates for products.
* Variations & variable changes.
* Update -functions.php calls to use data store.
* Add an interface for the public product data store methods.
* Finished product factory tests
* Correctly delete in the api, fix up some comments, and implement an interface for the public variable methods.
* Fix up delete in all versions of the api
* Handle feedback
* Match protected decloration to parent
* Product crud abstract todos (#12316)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Fix up store
* Fixed method returning in write context
* Fix error in variation admin
* Check for parent value - fixes tax class
* Remove old/complete todos
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* Remove deprecated get_variation_id()
* New default attributes method
* Fixed method returning in write context
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed coding standards
* TODO is not accurate.
* Should pass WC_Product instancies to WC_Comments methods (#12327)
* Use new method in abstract order class to prevent headers sent issue in tests
* Fixed variable description in REST API
* Updated how create initial product variation
* Fixed a few fatal errors and warnings in Products CRUD (#12329)
* Fixed a few fatal errors and warnings in Products CRUD
* Fixed sync functions
* Add variations CRUD to legacy API (#12331)
* Apply crud to variable products in legacy API v1
* New REST API do not need fallback for default attributes
* Apply variations CRUD to legacy API v2
* Legacy v2 - save default attributes
* Variations in legacy API v2 do not have descriptions
* Fixed legacy API v2 variations params
* Applied variations CRUD to legacy API v3
* Sync before save in legacy apis
* Punc
* Removed API todos
* Removed test
* Products endpoint tweaks (#12354)
* Var type already normalized on CRUD
* Let Product CRUD handle with validation, sanitization and conditional checks
* Set downloads using WC_Product_Download
* Stop try catch exceptions more than one time
* Handle WC_Data_Exception in legacy API
* Complete remove products when fails on creating
* On creating I mean!
* Already have a method to complete delete products
* Fixed standards using WP CodeSniffer
* get_the_terms() returns false when empty
* get_manage_stock returns boolean
@claudiosanches
* Merge conflict
* Variations API endpoint fixes
* Product CRUD improvements (#12359)
* args is not used any more - remove todo
* Added test for attributes
* wc_get_price_excluding_tax usage
* parent usage
* Fix rating counts
* Test fixes
* Cleanup after tests
* Make sure status transition code runs even during API calls, not just in admin.
* Default visibility
* Fix attribute setting in API
* Use get name instead of get title
* variation id usage
* Improved cross sell templates
* variation_data
* Grouped product sync
* Notices
* Sync is not needed in API
* Delete
* Rename interfaces
* Update counts in data store
2016-11-16 12:38:24 +00:00
$add_to_cart_handler = apply_filters ( 'woocommerce_add_to_cart_handler' , $adding_to_cart -> get_type (), $adding_to_cart );
2013-08-09 16:11:15 +00:00
2017-09-06 15:47:48 +00:00
if ( 'variable' === $add_to_cart_handler || 'variation' === $add_to_cart_handler ) {
2015-08-20 22:41:56 +00:00
$was_added_to_cart = self :: add_to_cart_handler_variable ( $product_id );
} elseif ( 'grouped' === $add_to_cart_handler ) {
$was_added_to_cart = self :: add_to_cart_handler_grouped ( $product_id );
2016-08-27 04:47:24 +00:00
} elseif ( has_action ( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ) {
2017-09-06 15:47:48 +00:00
do_action ( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler , $url ); // Custom handler.
2015-08-20 22:41:56 +00:00
} else {
$was_added_to_cart = self :: add_to_cart_handler_simple ( $product_id );
}
2014-02-07 18:27:07 +00:00
2015-08-20 22:41:56 +00:00
// If we added the product to the cart we can now optionally do a redirect.
2017-09-06 12:44:30 +00:00
if ( $was_added_to_cart && 0 === wc_notice_count ( 'error' ) ) {
2019-02-04 15:31:35 +00:00
$url = apply_filters ( 'woocommerce_add_to_cart_redirect' , $url , $adding_to_cart );
if ( $url ) {
2015-08-20 22:41:56 +00:00
wp_safe_redirect ( $url );
exit ;
2017-08-22 09:53:34 +00:00
} elseif ( 'yes' === get_option ( 'woocommerce_cart_redirect_after_add' ) ) {
2015-10-28 17:56:31 +00:00
wp_safe_redirect ( wc_get_cart_url () );
2015-08-20 22:41:56 +00:00
exit ;
}
}
}
2014-02-07 18:27:07 +00:00
2015-08-20 22:41:56 +00:00
/**
2015-11-03 13:31:20 +00:00
* Handle adding simple products to the cart .
2017-09-06 15:47:48 +00:00
*
* @ since 2.4 . 6 Split from add_to_cart_action .
* @ param int $product_id Product ID to add to the cart .
2015-08-20 22:41:56 +00:00
* @ return bool success or not
*/
private static function add_to_cart_handler_simple ( $product_id ) {
2019-02-04 15:31:35 +00:00
$quantity = empty ( $_REQUEST [ 'quantity' ] ) ? 1 : wc_stock_amount ( wp_unslash ( $_REQUEST [ 'quantity' ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$passed_validation = apply_filters ( 'woocommerce_add_to_cart_validation' , true , $product_id , $quantity );
2014-02-07 18:27:07 +00:00
2017-08-22 09:53:34 +00:00
if ( $passed_validation && false !== WC () -> cart -> add_to_cart ( $product_id , $quantity ) ) {
2016-01-20 11:32:49 +00:00
wc_add_to_cart_message ( array ( $product_id => $quantity ), true );
2015-08-20 22:41:56 +00:00
return true ;
}
return false ;
}
2014-02-07 18:27:07 +00:00
2015-08-20 22:41:56 +00:00
/**
2015-11-03 13:31:20 +00:00
* Handle adding grouped products to the cart .
2017-09-06 15:47:48 +00:00
*
* @ since 2.4 . 6 Split from add_to_cart_action .
* @ param int $product_id Product ID to add to the cart .
2015-08-20 22:41:56 +00:00
* @ return bool success or not
*/
private static function add_to_cart_handler_grouped ( $product_id ) {
$was_added_to_cart = false ;
$added_to_cart = array ();
2019-02-04 15:31:35 +00:00
$items = isset ( $_REQUEST [ 'quantity' ] ) && is_array ( $_REQUEST [ 'quantity' ] ) ? wp_unslash ( $_REQUEST [ 'quantity' ] ) : array (); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
if ( ! empty ( $items ) ) {
2015-08-20 22:41:56 +00:00
$quantity_set = false ;
2019-02-04 15:31:35 +00:00
foreach ( $items as $item => $quantity ) {
2015-08-20 22:41:56 +00:00
if ( $quantity <= 0 ) {
continue ;
2013-08-09 16:11:15 +00:00
}
2015-08-20 22:41:56 +00:00
$quantity_set = true ;
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
// Add to cart validation.
$passed_validation = apply_filters ( 'woocommerce_add_to_cart_validation' , true , $item , $quantity );
2013-08-09 16:11:15 +00:00
2017-08-01 11:36:46 +00:00
// Suppress total recalculation until finished.
remove_action ( 'woocommerce_add_to_cart' , array ( WC () -> cart , 'calculate_totals' ), 20 , 0 );
2017-08-22 09:53:34 +00:00
if ( $passed_validation && false !== WC () -> cart -> add_to_cart ( $item , $quantity ) ) {
2019-02-04 15:31:35 +00:00
$was_added_to_cart = true ;
2016-01-20 11:32:49 +00:00
$added_to_cart [ $item ] = $quantity ;
2013-08-09 16:11:15 +00:00
}
2017-08-01 11:36:46 +00:00
add_action ( 'woocommerce_add_to_cart' , array ( WC () -> cart , 'calculate_totals' ), 20 , 0 );
2013-11-18 13:35:38 +00:00
}
2013-08-09 16:11:15 +00:00
2015-08-20 22:41:56 +00:00
if ( ! $was_added_to_cart && ! $quantity_set ) {
wc_add_notice ( __ ( 'Please choose the quantity of items you wish to add to your cart…' , 'woocommerce' ), 'error' );
} elseif ( $was_added_to_cart ) {
wc_add_to_cart_message ( $added_to_cart );
2017-08-01 11:36:46 +00:00
WC () -> cart -> calculate_totals ();
2015-08-20 22:41:56 +00:00
return true ;
}
} elseif ( $product_id ) {
/* Link on product archives */
wc_add_notice ( __ ( 'Please choose a product to add to your cart…' , 'woocommerce' ), 'error' );
}
return false ;
}
2013-08-09 16:11:15 +00:00
2015-08-20 22:41:56 +00:00
/**
2015-11-03 13:31:20 +00:00
* Handle adding variable products to the cart .
2017-09-06 15:47:48 +00:00
*
* @ since 2.4 . 6 Split from add_to_cart_action .
2019-02-04 15:31:35 +00:00
* @ throws Exception If add to cart fails .
2017-09-06 15:47:48 +00:00
* @ param int $product_id Product ID to add to the cart .
2015-08-20 22:41:56 +00:00
* @ return bool success or not
*/
private static function add_to_cart_handler_variable ( $product_id ) {
2017-09-06 16:05:21 +00:00
try {
2019-02-04 15:31:35 +00:00
$variation_id = empty ( $_REQUEST [ 'variation_id' ] ) ? '' : absint ( wp_unslash ( $_REQUEST [ 'variation_id' ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
$quantity = empty ( $_REQUEST [ 'quantity' ] ) ? 1 : wc_stock_amount ( wp_unslash ( $_REQUEST [ 'quantity' ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
2017-09-06 16:05:21 +00:00
$missing_attributes = array ();
$variations = array ();
$adding_to_cart = wc_get_product ( $product_id );
if ( ! $adding_to_cart ) {
return false ;
}
2016-04-20 11:35:06 +00:00
2017-09-06 16:05:21 +00:00
// If the $product_id was in fact a variation ID, update the variables.
if ( $adding_to_cart -> is_type ( 'variation' ) ) {
$variation_id = $product_id ;
$product_id = $adding_to_cart -> get_parent_id ();
$adding_to_cart = wc_get_product ( $product_id );
2016-04-20 11:35:06 +00:00
2017-09-06 16:05:21 +00:00
if ( ! $adding_to_cart ) {
return false ;
}
}
2018-01-26 16:11:53 +00:00
// Gather posted attributes.
$posted_attributes = array ();
foreach ( $adding_to_cart -> get_attributes () as $attribute ) {
if ( ! $attribute [ 'is_variation' ] ) {
continue ;
}
$attribute_key = 'attribute_' . sanitize_title ( $attribute [ 'name' ] );
2019-02-04 15:31:35 +00:00
if ( isset ( $_REQUEST [ $attribute_key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
2018-01-26 16:11:53 +00:00
if ( $attribute [ 'is_taxonomy' ] ) {
// Don't use wc_clean as it destroys sanitized characters.
2019-02-04 15:31:35 +00:00
$value = sanitize_title ( wp_unslash ( $_REQUEST [ $attribute_key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
2018-01-26 16:11:53 +00:00
} else {
2019-02-04 15:31:35 +00:00
$value = html_entity_decode ( wc_clean ( wp_unslash ( $_REQUEST [ $attribute_key ] ) ), ENT_QUOTES , get_bloginfo ( 'charset' ) ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification
2018-01-26 16:11:53 +00:00
}
$posted_attributes [ $attribute_key ] = $value ;
}
}
2017-09-06 16:05:21 +00:00
// If no variation ID is set, attempt to get a variation ID from posted attributes.
if ( empty ( $variation_id ) ) {
$data_store = WC_Data_Store :: load ( 'product' );
2018-01-26 16:11:53 +00:00
$variation_id = $data_store -> find_matching_product_variation ( $adding_to_cart , $posted_attributes );
2017-09-06 16:05:21 +00:00
}
2018-01-26 16:11:53 +00:00
// Do we have a variation ID?
2016-10-17 10:33:43 +00:00
if ( empty ( $variation_id ) ) {
throw new Exception ( __ ( 'Please choose product options…' , 'woocommerce' ) );
2015-08-20 22:41:56 +00:00
}
WIP - Product CRUD (#12065)
* Created function to get the catalog visibility options
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Sanitize ids later
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Bump template version
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* Made abstract function useful
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* Allow WP_Query to preload post data, and meta in wc_get_products()
Allow WP_Query to bulk query for post data and meta if more than
just IDs are requested from wc_get_products(). Reduces query count
significantly.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Sanitize ids later
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Bump template version
* Made abstract function useful
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* Prevent notices
* Handle image_id from parent
* Fix error
* Remove _wc_save_product_price
* Remove todo
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* [Product CRUD] Abstract todos (#12305)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Revert "[Product CRUD] Abstract todos (#12305)"
This reverts commit 9a6136fcf88fec16f97457b7c8a4388f7587bfa2.
* Remove deprecated get_variation_id()
* New default attributes method
* [Product CRUD] Product Datastore (#12317)
* Fix up tests in the product/* folder.
* Handle data store updates for grouped, variable, external, simple, and general data store updates for products.
* Variations & variable changes.
* Update -functions.php calls to use data store.
* Add an interface for the public product data store methods.
* Finished product factory tests
* Correctly delete in the api, fix up some comments, and implement an interface for the public variable methods.
* Fix up delete in all versions of the api
* Handle feedback
* Match protected decloration to parent
* Product crud abstract todos (#12316)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Fix up store
* Fixed method returning in write context
* Fix error in variation admin
* Check for parent value - fixes tax class
* Remove old/complete todos
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* Remove deprecated get_variation_id()
* New default attributes method
* Fixed method returning in write context
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed coding standards
* TODO is not accurate.
* Should pass WC_Product instancies to WC_Comments methods (#12327)
* Use new method in abstract order class to prevent headers sent issue in tests
* Fixed variable description in REST API
* Updated how create initial product variation
* Fixed a few fatal errors and warnings in Products CRUD (#12329)
* Fixed a few fatal errors and warnings in Products CRUD
* Fixed sync functions
* Add variations CRUD to legacy API (#12331)
* Apply crud to variable products in legacy API v1
* New REST API do not need fallback for default attributes
* Apply variations CRUD to legacy API v2
* Legacy v2 - save default attributes
* Variations in legacy API v2 do not have descriptions
* Fixed legacy API v2 variations params
* Applied variations CRUD to legacy API v3
* Sync before save in legacy apis
* Punc
* Removed API todos
* Removed test
* Products endpoint tweaks (#12354)
* Var type already normalized on CRUD
* Let Product CRUD handle with validation, sanitization and conditional checks
* Set downloads using WC_Product_Download
* Stop try catch exceptions more than one time
* Handle WC_Data_Exception in legacy API
* Complete remove products when fails on creating
* On creating I mean!
* Already have a method to complete delete products
* Fixed standards using WP CodeSniffer
* get_the_terms() returns false when empty
* get_manage_stock returns boolean
@claudiosanches
* Merge conflict
* Variations API endpoint fixes
* Product CRUD improvements (#12359)
* args is not used any more - remove todo
* Added test for attributes
* wc_get_price_excluding_tax usage
* parent usage
* Fix rating counts
* Test fixes
* Cleanup after tests
* Make sure status transition code runs even during API calls, not just in admin.
* Default visibility
* Fix attribute setting in API
* Use get name instead of get title
* variation id usage
* Improved cross sell templates
* variation_data
* Grouped product sync
* Notices
* Sync is not needed in API
* Delete
* Rename interfaces
* Update counts in data store
2016-11-16 12:38:24 +00:00
2018-01-26 16:11:53 +00:00
// Check the data we have is valid.
WIP - Product CRUD (#12065)
* Created function to get the catalog visibility options
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Sanitize ids later
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Bump template version
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* Made abstract function useful
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* Allow WP_Query to preload post data, and meta in wc_get_products()
Allow WP_Query to bulk query for post data and meta if more than
just IDs are requested from wc_get_products(). Reduces query count
significantly.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Sanitize ids later
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Bump template version
* Made abstract function useful
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* Prevent notices
* Handle image_id from parent
* Fix error
* Remove _wc_save_product_price
* Remove todo
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* [Product CRUD] Abstract todos (#12305)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Revert "[Product CRUD] Abstract todos (#12305)"
This reverts commit 9a6136fcf88fec16f97457b7c8a4388f7587bfa2.
* Remove deprecated get_variation_id()
* New default attributes method
* [Product CRUD] Product Datastore (#12317)
* Fix up tests in the product/* folder.
* Handle data store updates for grouped, variable, external, simple, and general data store updates for products.
* Variations & variable changes.
* Update -functions.php calls to use data store.
* Add an interface for the public product data store methods.
* Finished product factory tests
* Correctly delete in the api, fix up some comments, and implement an interface for the public variable methods.
* Fix up delete in all versions of the api
* Handle feedback
* Match protected decloration to parent
* Product crud abstract todos (#12316)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Fix up store
* Fixed method returning in write context
* Fix error in variation admin
* Check for parent value - fixes tax class
* Remove old/complete todos
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* Remove deprecated get_variation_id()
* New default attributes method
* Fixed method returning in write context
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed coding standards
* TODO is not accurate.
* Should pass WC_Product instancies to WC_Comments methods (#12327)
* Use new method in abstract order class to prevent headers sent issue in tests
* Fixed variable description in REST API
* Updated how create initial product variation
* Fixed a few fatal errors and warnings in Products CRUD (#12329)
* Fixed a few fatal errors and warnings in Products CRUD
* Fixed sync functions
* Add variations CRUD to legacy API (#12331)
* Apply crud to variable products in legacy API v1
* New REST API do not need fallback for default attributes
* Apply variations CRUD to legacy API v2
* Legacy v2 - save default attributes
* Variations in legacy API v2 do not have descriptions
* Fixed legacy API v2 variations params
* Applied variations CRUD to legacy API v3
* Sync before save in legacy apis
* Punc
* Removed API todos
* Removed test
* Products endpoint tweaks (#12354)
* Var type already normalized on CRUD
* Let Product CRUD handle with validation, sanitization and conditional checks
* Set downloads using WC_Product_Download
* Stop try catch exceptions more than one time
* Handle WC_Data_Exception in legacy API
* Complete remove products when fails on creating
* On creating I mean!
* Already have a method to complete delete products
* Fixed standards using WP CodeSniffer
* get_the_terms() returns false when empty
* get_manage_stock returns boolean
@claudiosanches
* Merge conflict
* Variations API endpoint fixes
* Product CRUD improvements (#12359)
* args is not used any more - remove todo
* Added test for attributes
* wc_get_price_excluding_tax usage
* parent usage
* Fix rating counts
* Test fixes
* Cleanup after tests
* Make sure status transition code runs even during API calls, not just in admin.
* Default visibility
* Fix attribute setting in API
* Use get name instead of get title
* variation id usage
* Improved cross sell templates
* variation_data
* Grouped product sync
* Notices
* Sync is not needed in API
* Delete
* Rename interfaces
* Update counts in data store
2016-11-16 12:38:24 +00:00
$variation_data = wc_get_product_variation_attributes ( $variation_id );
2017-09-06 16:05:21 +00:00
foreach ( $adding_to_cart -> get_attributes () as $attribute ) {
2016-10-17 10:33:43 +00:00
if ( ! $attribute [ 'is_variation' ] ) {
continue ;
}
2013-08-09 16:11:15 +00:00
2017-11-15 16:29:04 +00:00
// Get valid value from variation data.
2018-01-26 16:11:53 +00:00
$attribute_key = 'attribute_' . sanitize_title ( $attribute [ 'name' ] );
2019-02-04 15:31:35 +00:00
$valid_value = isset ( $variation_data [ $attribute_key ] ) ? $variation_data [ $attribute_key ] : '' ;
2013-08-09 16:11:15 +00:00
2017-11-15 16:29:04 +00:00
/**
* If the attribute value was posted , check if it ' s valid .
*
* If no attribute was posted , only error if the variation has an 'any' attribute which requires a value .
*/
2018-01-26 16:11:53 +00:00
if ( isset ( $posted_attributes [ $attribute_key ] ) ) {
$value = $posted_attributes [ $attribute_key ];
2013-08-09 16:11:15 +00:00
2016-10-17 10:33:43 +00:00
// Allow if valid or show error.
2017-06-07 10:13:28 +00:00
if ( $valid_value === $value ) {
2018-01-26 16:11:53 +00:00
$variations [ $attribute_key ] = $value ;
2019-02-04 15:31:35 +00:00
} elseif ( '' === $valid_value && in_array ( $value , $attribute -> get_slugs (), true ) ) {
2017-09-06 15:47:48 +00:00
// If valid values are empty, this is an 'any' variation so get all possible values.
2018-01-26 16:11:53 +00:00
$variations [ $attribute_key ] = $value ;
2016-10-17 10:33:43 +00:00
} else {
2019-02-04 15:31:35 +00:00
/* translators: %s: Attribute name. */
2016-10-17 10:33:43 +00:00
throw new Exception ( sprintf ( __ ( 'Invalid value posted for %s' , 'woocommerce' ), wc_attribute_label ( $attribute [ 'name' ] ) ) );
}
2017-11-15 16:29:04 +00:00
} elseif ( '' === $valid_value ) {
2016-10-17 10:33:43 +00:00
$missing_attributes [] = wc_attribute_label ( $attribute [ 'name' ] );
2013-08-09 16:11:15 +00:00
}
}
2016-10-17 10:33:43 +00:00
if ( ! empty ( $missing_attributes ) ) {
2019-02-04 15:31:35 +00:00
/* translators: %s: Attribute name. */
2017-09-06 15:47:48 +00:00
throw new Exception ( sprintf ( _n ( '%s is a required field' , '%s are required fields' , count ( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items ( $missing_attributes ) ) );
2016-10-17 10:33:43 +00:00
}
} catch ( Exception $e ) {
wc_add_notice ( $e -> getMessage (), 'error' );
return false ;
2015-08-20 22:41:56 +00:00
}
2013-08-09 16:11:15 +00:00
2018-01-26 16:11:53 +00:00
$passed_validation = apply_filters ( 'woocommerce_add_to_cart_validation' , true , $product_id , $quantity , $variation_id , $variations );
2013-08-09 16:11:15 +00:00
2017-08-22 09:53:34 +00:00
if ( $passed_validation && false !== WC () -> cart -> add_to_cart ( $product_id , $quantity , $variation_id , $variations ) ) {
2016-10-17 10:33:43 +00:00
wc_add_to_cart_message ( array ( $product_id => $quantity ), true );
return true ;
2014-02-07 18:27:07 +00:00
}
2016-10-17 10:33:43 +00:00
2015-08-20 22:41:56 +00:00
return false ;
2013-08-09 16:11:15 +00:00
}
/**
* Process the login form .
2019-02-04 15:31:35 +00:00
*
* @ throws Exception On login error .
2013-08-09 16:11:15 +00:00
*/
2014-05-28 13:52:50 +00:00
public static function process_login () {
2017-12-18 04:43:51 +00:00
// The global form-login.php template used `_wpnonce` in template versions < 3.3.0.
2018-03-13 14:16:56 +00:00
$nonce_value = wc_get_var ( $_REQUEST [ 'woocommerce-login-nonce' ], wc_get_var ( $_REQUEST [ '_wpnonce' ], '' ) ); // @codingStandardsIgnoreLine.
2016-06-08 12:19:30 +00:00
2019-02-04 15:31:35 +00:00
if ( isset ( $_POST [ 'login' ], $_POST [ 'username' ], $_POST [ 'password' ] ) && wp_verify_nonce ( $nonce_value , 'woocommerce-login' ) ) {
2013-08-09 16:11:15 +00:00
try {
2016-08-02 17:28:31 +00:00
$creds = array (
2019-02-04 15:31:35 +00:00
'user_login' => trim ( wp_unslash ( $_POST [ 'username' ] ) ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2019-04-24 22:35:34 +00:00
'user_password' => $_POST [ 'password' ], // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
2019-02-04 15:31:35 +00:00
'remember' => isset ( $_POST [ 'rememberme' ] ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2016-08-02 17:28:31 +00:00
);
2013-12-29 13:11:54 +00:00
2013-11-13 11:49:34 +00:00
$validation_error = new WP_Error ();
2019-02-04 15:31:35 +00:00
$validation_error = apply_filters ( 'woocommerce_process_login_errors' , $validation_error , $creds [ 'user_login' ], $creds [ 'user_password' ] );
2013-11-13 11:49:34 +00:00
2014-01-03 11:06:28 +00:00
if ( $validation_error -> get_error_code () ) {
2016-10-24 07:33:32 +00:00
throw new Exception ( '<strong>' . __ ( 'Error:' , 'woocommerce' ) . '</strong> ' . $validation_error -> get_error_message () );
2014-01-03 11:06:28 +00:00
}
2013-08-09 16:11:15 +00:00
2017-10-20 16:21:07 +00:00
if ( empty ( $creds [ 'user_login' ] ) ) {
2016-10-24 07:33:32 +00:00
throw new Exception ( '<strong>' . __ ( 'Error:' , 'woocommerce' ) . '</strong> ' . __ ( 'Username is required.' , 'woocommerce' ) );
2014-01-03 11:06:28 +00:00
}
2013-11-13 11:49:34 +00:00
2016-08-02 17:28:31 +00:00
// On multisite, ensure user exists on current site, if not add them before allowing login.
if ( is_multisite () ) {
2017-10-20 16:21:07 +00:00
$user_data = get_user_by ( is_email ( $creds [ 'user_login' ] ) ? 'email' : 'login' , $creds [ 'user_login' ] );
2016-08-02 17:28:31 +00:00
if ( $user_data && ! is_user_member_of_blog ( $user_data -> ID , get_current_blog_id () ) ) {
add_user_to_blog ( get_current_blog_id (), $user_data -> ID , 'customer' );
}
}
2019-02-04 15:31:35 +00:00
// Perform the login.
2016-08-02 17:28:31 +00:00
$user = wp_signon ( apply_filters ( 'woocommerce_login_credentials' , $creds ), is_ssl () );
2013-08-09 16:11:15 +00:00
if ( is_wp_error ( $user ) ) {
2015-06-26 12:15:31 +00:00
$message = $user -> get_error_message ();
2017-10-20 16:21:07 +00:00
$message = str_replace ( '<strong>' . esc_html ( $creds [ 'user_login' ] ) . '</strong>' , '<strong>' . esc_html ( $creds [ 'user_login' ] ) . '</strong>' , $message );
2015-06-26 12:15:31 +00:00
throw new Exception ( $message );
2013-08-09 16:11:15 +00:00
} else {
if ( ! empty ( $_POST [ 'redirect' ] ) ) {
2019-02-04 15:31:35 +00:00
$redirect = wp_unslash ( $_POST [ 'redirect' ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2017-07-04 11:05:21 +00:00
} elseif ( wc_get_raw_referer () ) {
$redirect = wc_get_raw_referer ();
2013-08-09 16:11:15 +00:00
} else {
2015-02-15 19:13:22 +00:00
$redirect = wc_get_page_permalink ( 'myaccount' );
2013-08-09 16:11:15 +00:00
}
2019-02-04 15:31:35 +00:00
wp_redirect ( wp_validate_redirect ( apply_filters ( 'woocommerce_login_redirect' , remove_query_arg ( 'wc_error' , $redirect ), $user ), wc_get_page_permalink ( 'myaccount' ) ) ); // phpcs:ignore
2013-08-09 16:11:15 +00:00
exit ;
}
2016-04-27 15:00:30 +00:00
} catch ( Exception $e ) {
2016-09-02 01:51:31 +00:00
wc_add_notice ( apply_filters ( 'login_errors' , $e -> getMessage () ), 'error' );
2016-09-08 09:06:16 +00:00
do_action ( 'woocommerce_login_failed' );
2013-08-09 16:11:15 +00:00
}
}
}
2015-01-21 14:15:49 +00:00
/**
2015-11-03 13:31:20 +00:00
* Handle lost password form .
2015-01-21 14:15:49 +00:00
*/
public static function process_lost_password () {
2018-03-13 14:16:56 +00:00
if ( isset ( $_POST [ 'wc_reset_password' ], $_POST [ 'user_login' ] ) ) {
$nonce_value = wc_get_var ( $_REQUEST [ 'woocommerce-lost-password-nonce' ], wc_get_var ( $_REQUEST [ '_wpnonce' ], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce ( $nonce_value , 'lost_password' ) ) {
return ;
}
2016-04-27 15:00:30 +00:00
$success = WC_Shortcode_My_Account :: retrieve_password ();
2017-04-28 21:29:58 +00:00
// If successful, redirect to my account with query arg set.
2016-04-27 15:00:30 +00:00
if ( $success ) {
2019-02-04 15:31:35 +00:00
wp_safe_redirect ( add_query_arg ( 'reset-link-sent' , 'true' , wc_get_account_endpoint_url ( 'lost-password' ) ) );
2016-04-27 15:00:30 +00:00
exit ;
}
2015-01-21 14:15:49 +00:00
}
}
2013-08-09 16:11:15 +00:00
/**
2015-11-03 13:31:20 +00:00
* Handle reset password form .
2013-08-09 16:11:15 +00:00
*/
2014-05-28 13:52:50 +00:00
public static function process_reset_password () {
2019-02-04 15:31:35 +00:00
$nonce_value = wc_get_var ( $_REQUEST [ 'woocommerce-reset-password-nonce' ], wc_get_var ( $_REQUEST [ '_wpnonce' ], '' ) ); // @codingStandardsIgnoreLine.
if ( ! wp_verify_nonce ( $nonce_value , 'reset_password' ) ) {
return ;
}
2018-03-13 14:16:56 +00:00
$posted_fields = array ( 'wc_reset_password' , 'password_1' , 'password_2' , 'reset_key' , 'reset_login' );
2013-08-09 16:11:15 +00:00
2015-01-21 14:15:49 +00:00
foreach ( $posted_fields as $field ) {
if ( ! isset ( $_POST [ $field ] ) ) {
return ;
}
2019-06-13 15:49:10 +00:00
if ( in_array ( $field , array ( 'password_1' , 'password_2' ) ) ) {
// Don't unslash password fields
2019-07-01 07:31:10 +00:00
// @see https://github.com/woocommerce/woocommerce/issues/23922.
2019-06-13 15:49:10 +00:00
$posted_fields [ $field ] = $_POST [ $field ]; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
} else {
$posted_fields [ $field ] = wp_unslash ( $_POST [ $field ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
}
2015-01-21 14:15:49 +00:00
}
2013-08-09 16:11:15 +00:00
2015-01-21 14:59:44 +00:00
$user = WC_Shortcode_My_Account :: check_password_reset_key ( $posted_fields [ 'reset_key' ], $posted_fields [ 'reset_login' ] );
2013-08-09 16:11:15 +00:00
2015-01-21 14:59:44 +00:00
if ( $user instanceof WP_User ) {
if ( empty ( $posted_fields [ 'password_1' ] ) ) {
wc_add_notice ( __ ( 'Please enter your password.' , 'woocommerce' ), 'error' );
}
2013-08-09 16:11:15 +00:00
2016-08-27 03:23:21 +00:00
if ( $posted_fields [ 'password_1' ] !== $posted_fields [ 'password_2' ] ) {
2015-01-21 14:59:44 +00:00
wc_add_notice ( __ ( 'Passwords do not match.' , 'woocommerce' ), 'error' );
}
2013-08-09 16:11:15 +00:00
2015-01-21 14:59:44 +00:00
$errors = new WP_Error ();
2013-10-18 01:24:06 +00:00
2015-01-21 14:59:44 +00:00
do_action ( 'validate_password_reset' , $errors , $user );
2013-08-09 16:11:15 +00:00
2015-01-21 14:59:44 +00:00
wc_add_wp_error_notices ( $errors );
2013-08-09 16:11:15 +00:00
2015-01-21 14:59:44 +00:00
if ( 0 === wc_notice_count ( 'error' ) ) {
WC_Shortcode_My_Account :: reset_password ( $user , $posted_fields [ 'password_1' ] );
2013-08-09 16:11:15 +00:00
2015-01-21 14:59:44 +00:00
do_action ( 'woocommerce_customer_reset_password' , $user );
2013-08-09 16:11:15 +00:00
2019-02-04 15:31:35 +00:00
wp_safe_redirect ( add_query_arg ( 'password-reset' , 'true' , wc_get_page_permalink ( 'myaccount' ) ) );
2015-01-21 14:59:44 +00:00
exit ;
}
2013-08-09 16:11:15 +00:00
}
}
/**
* Process the registration form .
2019-02-04 15:31:35 +00:00
*
* @ throws Exception On registration error .
2013-08-09 16:11:15 +00:00
*/
2014-05-28 13:52:50 +00:00
public static function process_registration () {
2019-02-04 15:31:35 +00:00
$nonce_value = isset ( $_POST [ '_wpnonce' ] ) ? wp_unslash ( $_POST [ '_wpnonce' ] ) : '' ; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.NoNonceVerification
$nonce_value = isset ( $_POST [ 'woocommerce-register-nonce' ] ) ? wp_unslash ( $_POST [ 'woocommerce-register-nonce' ] ) : $nonce_value ; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.NoNonceVerification
2016-06-08 12:19:30 +00:00
2019-02-04 15:31:35 +00:00
if ( isset ( $_POST [ 'register' ], $_POST [ 'email' ] ) && wp_verify_nonce ( $nonce_value , 'woocommerce-register' ) ) {
$username = 'no' === get_option ( 'woocommerce_registration_generate_username' ) && isset ( $_POST [ 'username' ] ) ? wp_unslash ( $_POST [ 'username' ] ) : '' ; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2019-06-13 12:54:17 +00:00
$password = 'no' === get_option ( 'woocommerce_registration_generate_password' ) && isset ( $_POST [ 'password' ] ) ? $_POST [ 'password' ] : '' ; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
2019-02-04 15:31:35 +00:00
$email = wp_unslash ( $_POST [ 'email' ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
2014-04-02 02:45:25 +00:00
2014-01-03 11:06:28 +00:00
try {
2019-06-19 21:09:28 +00:00
$validation_error = new WP_Error ();
$validation_error = apply_filters ( 'woocommerce_process_registration_errors' , $validation_error , $username , $password , $email );
$validation_errors = $validation_error -> get_error_messages ();
2014-01-03 11:06:28 +00:00
2019-06-19 21:09:28 +00:00
if ( 1 === count ( $validation_errors ) ) {
2015-01-20 16:05:08 +00:00
throw new Exception ( $validation_error -> get_error_message () );
2019-06-19 21:09:28 +00:00
} elseif ( $validation_errors ) {
foreach ( $validation_errors as $message ) {
wc_add_notice ( '<strong>' . __ ( 'Error:' , 'woocommerce' ) . '</strong> ' . $message , 'error' );
}
throw new Exception ();
2014-01-03 11:06:28 +00:00
}
2013-08-09 16:11:15 +00:00
2015-01-20 16:05:08 +00:00
$new_customer = wc_create_new_customer ( sanitize_email ( $email ), wc_clean ( $username ), $password );
2013-08-09 16:11:15 +00:00
2015-01-20 16:05:08 +00:00
if ( is_wp_error ( $new_customer ) ) {
throw new Exception ( $new_customer -> get_error_message () );
}
2013-08-09 16:11:15 +00:00
2019-02-04 15:49:10 +00:00
if ( 'yes' === get_option ( 'woocommerce_registration_generate_password' ) ) {
wc_add_notice ( __ ( 'Your account was created successfully and a password has been sent to your email address.' , 'woocommerce' ) );
2017-09-22 03:50:45 +00:00
} else {
2019-02-04 15:49:10 +00:00
wc_add_notice ( __ ( 'Your account was created successfully. Your login details have been sent to your email address.' , 'woocommerce' ) );
2017-09-22 03:50:45 +00:00
}
2019-02-04 15:49:10 +00:00
// Only redirect after a forced login - otherwise output a success notice.
if ( apply_filters ( 'woocommerce_registration_auth_new_customer' , true , $new_customer ) ) {
wc_set_customer_auth_cookie ( $new_customer );
if ( ! empty ( $_POST [ 'redirect' ] ) ) {
$redirect = wp_sanitize_redirect ( wp_unslash ( $_POST [ 'redirect' ] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
} elseif ( wc_get_raw_referer () ) {
$redirect = wc_get_raw_referer ();
} else {
$redirect = wc_get_page_permalink ( 'myaccount' );
}
2013-08-09 16:11:15 +00:00
2019-02-04 15:49:10 +00:00
wp_redirect ( wp_validate_redirect ( apply_filters ( 'woocommerce_registration_redirect' , $redirect ), wc_get_page_permalink ( 'myaccount' ) ) ); //phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
exit ;
}
2015-01-20 16:05:08 +00:00
} catch ( Exception $e ) {
2019-06-19 21:09:28 +00:00
if ( $e -> getMessage () ) {
wc_add_notice ( '<strong>' . __ ( 'Error:' , 'woocommerce' ) . '</strong> ' . $e -> getMessage (), 'error' );
}
2013-08-09 16:11:15 +00:00
}
}
}
}
2014-05-28 13:52:50 +00:00
WC_Form_Handler :: init ();