From bffc224ffa360e2bee6c7bcbe4c7137db5fc9a07 Mon Sep 17 00:00:00 2001 From: dkoo Date: Tue, 3 Sep 2024 18:30:15 -0600 Subject: [PATCH 1/3] fix: required billing fields in My Account --- .../class-woocommerce-my-account.php | 124 +++++++++++++++--- 1 file changed, 106 insertions(+), 18 deletions(-) diff --git a/includes/reader-revenue/my-account/class-woocommerce-my-account.php b/includes/reader-revenue/my-account/class-woocommerce-my-account.php index 4d456a7699..0812e1182b 100644 --- a/includes/reader-revenue/my-account/class-woocommerce-my-account.php +++ b/includes/reader-revenue/my-account/class-woocommerce-my-account.php @@ -29,7 +29,8 @@ class WooCommerce_My_Account { */ public static function init() { \add_filter( 'woocommerce_account_menu_items', [ __CLASS__, 'my_account_menu_items' ], 1000 ); - \add_filter( 'woocommerce_billing_fields', [ __CLASS__, 'edit_address_required_fields' ] ); + \add_filter( 'woocommerce_default_address_fields', [ __CLASS__, 'required_address_fields' ] ); + \add_filter( 'woocommerce_billing_fields', [ __CLASS__, 'required_address_fields' ] ); // Reader Activation mods. if ( Reader_Activation::is_enabled() ) { @@ -348,10 +349,20 @@ public static function is_user_verified() { * Do not redirect if this request is a membership cancellation. */ public static function redirect_to_account_details() { - $resubscribe_request = isset( $_REQUEST['resubscribe'] ) ? 'shop_subscription' === \get_post_type( absint( $_REQUEST['resubscribe'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended - $cancel_membership_request = isset( $_REQUEST['cancel_membership'] ) ? true : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + // phpcs:disable WordPress.Security.NonceVerification.Recommended + $is_resubscribe_request = isset( $_REQUEST['resubscribe'] ) ? 'shop_subscription' === \get_post_type( absint( $_REQUEST['resubscribe'] ) ) : false; + $is_renewal_request = isset( $_REQUEST['subscription_renewal'] ) ? true : false; + $is_cancel_membership_request = isset( $_REQUEST['cancel_membership'] ) ? true : false; + // phpcs:enable WordPress.Security.NonceVerification.Recommended - if ( \is_user_logged_in() && Reader_Activation::is_enabled() && function_exists( 'wc_get_page_permalink' ) && ! $resubscribe_request && ! $cancel_membership_request ) { + if ( + \is_user_logged_in() && + Reader_Activation::is_enabled() && + function_exists( 'wc_get_page_permalink' ) && + ! $is_resubscribe_request && + ! $is_renewal_request && + ! $is_cancel_membership_request + ) { global $wp; $current_url = \home_url( $wp->request ); $my_account_page_permalink = \wc_get_page_permalink( 'myaccount' ); @@ -413,6 +424,89 @@ public static function verify_saved_account_details() { } } + /** + * Check if the given URL is a My Account page or subpage. + * + * @param string $url URL to check. + * + * @return bool True if the URL is verifiably a My Account page or subpage, false otherwise. + */ + public static function is_my_account_url( $url ) { + if ( ! function_exists( 'wc_get_page_id' ) ) { + return false; + } + $my_account_url = \get_permalink( \wc_get_page_id( 'myaccount' ) ); + if ( ! $my_account_url ) { + return false; + } + return false !== strpos( $url, rtrim( $my_account_url, '/\\' ) ); + } + + /** + * Detect if the current checkout page is coming from a My Account referrer. + * + * @return bool True if the current checkout page is coming from a My Account referrer, false otherwise. + */ + public static function is_from_my_account() { + // If we got posted a `is_my_account` param, return true. + $is_my_account_param = filter_input( INPUT_POST, 'is_my_account', FILTER_SANITIZE_NUMBER_INT ); + if ( $is_my_account_param ) { + return true; + } + + $referrer = \wp_get_referer(); + + // If we can't get the referrer directly, it may have been a POST request. + if ( ! $referrer ) { + $referrer = filter_input( INPUT_POST, '_wp_http_referer', FILTER_SANITIZE_URL ); + } + if ( ! $referrer ) { + return false; + } + + // Ensure the URL is a full URL and not a slug. + if ( 0 !== strpos( $referrer, \get_home_url() ) ) { + $referrer = \home_url( $referrer ); + } + + return self::is_my_account_url( $referrer ); + } + + /** + * Ensure that only billing address fields enabled in Reader Revenue settings are required. + * + * @param array $fields Billing fields. + * + * @return array Filtered billing fields. + */ + public static function get_required_fields( $fields ) { + $billing_fields = apply_filters( 'newspack_blocks_donate_billing_fields_keys', [] ); + if ( empty( $billing_fields ) ) { + return $fields; + } + + foreach ( $fields as $field_name => $field_config ) { + if ( + ! in_array( $field_name, $billing_fields, true ) && + ! in_array( 'billing_' . $field_name, $billing_fields, true ) && + is_array( $field_config ) + ) { + $field_config['required'] = false; + $fields[ $field_name ] = $field_config; + } + } + + // Add a hidden field so we can pass this onto subsequent pages in the Checkout flow. + if ( ! isset( $fields['is_my_account'] ) ) { + $fields['is_my_account'] = [ + 'type' => 'hidden', + 'default' => 1, + ]; + } + + return $fields; + } + /** * Ensure that only billing address fields enabled in Reader Revenue settings * are required in My Account edit billing address page. @@ -420,23 +514,17 @@ public static function verify_saved_account_details() { * @param array $fields Address fields. * @return array Filtered address fields. */ - public static function edit_address_required_fields( $fields ) { + public static function required_address_fields( $fields ) { global $wp; if ( - ! function_exists( 'is_account_page' ) || - ! \is_account_page() || // Only on My Account page. - ! isset( $wp->query_vars['edit-address'] ) || // Only when editing address. - 'billing' !== $wp->query_vars['edit-address'] // Only when editing billing address. - ) { - return $fields; - } - - $required_fields = Donations::get_billing_fields(); - foreach ( $fields as $field_name => $field_config ) { - if ( ! in_array( $field_name, $required_fields, true ) ) { - $fields[ $field_name ]['required'] = false; - } + self::is_from_my_account() && // Only when coming from My Account. + ( + ( function_exists( 'is_checkout' ) && is_checkout() ) || // If on the checkout page. + ( isset( $wp->query_vars['edit-address'] ) && 'billing' === $wp->query_vars['edit-address'] ) // If editing billing address. + ) + ) { + $fields = self::get_required_fields( $fields ); } return $fields; From 146917fb25b1b36368fe92f50adc9c2574330f6f Mon Sep 17 00:00:00 2001 From: dkoo Date: Thu, 5 Sep 2024 17:15:55 -0600 Subject: [PATCH 2/3] fix: use query param instead of only referrer --- .../class-woocommerce-my-account.php | 67 +++++++++---------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/includes/reader-revenue/my-account/class-woocommerce-my-account.php b/includes/reader-revenue/my-account/class-woocommerce-my-account.php index 0812e1182b..e78e526f17 100644 --- a/includes/reader-revenue/my-account/class-woocommerce-my-account.php +++ b/includes/reader-revenue/my-account/class-woocommerce-my-account.php @@ -31,6 +31,8 @@ public static function init() { \add_filter( 'woocommerce_account_menu_items', [ __CLASS__, 'my_account_menu_items' ], 1000 ); \add_filter( 'woocommerce_default_address_fields', [ __CLASS__, 'required_address_fields' ] ); \add_filter( 'woocommerce_billing_fields', [ __CLASS__, 'required_address_fields' ] ); + \add_filter( 'woocommerce_get_checkout_url', [ __CLASS__, 'get_checkout_url' ] ); + \add_filter( 'woocommerce_get_checkout_payment_url', [ __CLASS__, 'get_checkout_url' ] ); // Reader Activation mods. if ( Reader_Activation::is_enabled() ) { @@ -353,6 +355,7 @@ public static function redirect_to_account_details() { $is_resubscribe_request = isset( $_REQUEST['resubscribe'] ) ? 'shop_subscription' === \get_post_type( absint( $_REQUEST['resubscribe'] ) ) : false; $is_renewal_request = isset( $_REQUEST['subscription_renewal'] ) ? true : false; $is_cancel_membership_request = isset( $_REQUEST['cancel_membership'] ) ? true : false; + $is_checkout_request = isset( $_REQUEST['my_account_checkout'] ) ? true : false; // phpcs:enable WordPress.Security.NonceVerification.Recommended if ( @@ -361,7 +364,8 @@ public static function redirect_to_account_details() { function_exists( 'wc_get_page_permalink' ) && ! $is_resubscribe_request && ! $is_renewal_request && - ! $is_cancel_membership_request + ! $is_cancel_membership_request && + ! $is_checkout_request ) { global $wp; $current_url = \home_url( $wp->request ); @@ -424,24 +428,6 @@ public static function verify_saved_account_details() { } } - /** - * Check if the given URL is a My Account page or subpage. - * - * @param string $url URL to check. - * - * @return bool True if the URL is verifiably a My Account page or subpage, false otherwise. - */ - public static function is_my_account_url( $url ) { - if ( ! function_exists( 'wc_get_page_id' ) ) { - return false; - } - $my_account_url = \get_permalink( \wc_get_page_id( 'myaccount' ) ); - if ( ! $my_account_url ) { - return false; - } - return false !== strpos( $url, rtrim( $my_account_url, '/\\' ) ); - } - /** * Detect if the current checkout page is coming from a My Account referrer. * @@ -449,27 +435,40 @@ public static function is_my_account_url( $url ) { */ public static function is_from_my_account() { // If we got posted a `is_my_account` param, return true. - $is_my_account_param = filter_input( INPUT_POST, 'is_my_account', FILTER_SANITIZE_NUMBER_INT ); + $is_my_account_param = rest_sanitize_boolean( $_REQUEST['my_account_checkout'] ?? false ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( $is_my_account_param ) { return true; } $referrer = \wp_get_referer(); - - // If we can't get the referrer directly, it may have been a POST request. - if ( ! $referrer ) { - $referrer = filter_input( INPUT_POST, '_wp_http_referer', FILTER_SANITIZE_URL ); - } - if ( ! $referrer ) { - return false; + if ( $referrer ) { + $referrer_query = \wp_parse_url( $referrer, PHP_URL_QUERY ); + \wp_parse_str( $referrer_query, $referrer_query_params ); + if ( ! empty( $referrer_query_params['my_account_checkout'] ) ) { + return true; + } } - // Ensure the URL is a full URL and not a slug. - if ( 0 !== strpos( $referrer, \get_home_url() ) ) { - $referrer = \home_url( $referrer ); - } + return false; + } - return self::is_my_account_url( $referrer ); + /** + * On My Account pages, append a query param to the checkout URL to indicate the user is coming from My Account. + * + * @param string $url Checkout URL. + * + * @return string + */ + public static function get_checkout_url( $url ) { + if ( \is_account_page() || self::is_from_my_account() ) { + return \add_query_arg( + [ + 'my_account_checkout' => 1, + ], + $url + ); + } + return $url; } /** @@ -497,8 +496,8 @@ public static function get_required_fields( $fields ) { } // Add a hidden field so we can pass this onto subsequent pages in the Checkout flow. - if ( ! isset( $fields['is_my_account'] ) ) { - $fields['is_my_account'] = [ + if ( ! isset( $fields['my_account_checkout'] ) ) { + $fields['my_account_checkout'] = [ 'type' => 'hidden', 'default' => 1, ]; From 183e4e4be1ea06c8d73584a36707a60ee8edc5d0 Mon Sep 17 00:00:00 2001 From: dkoo Date: Fri, 6 Sep 2024 10:47:46 -0600 Subject: [PATCH 3/3] fix: editing billing address --- .../my-account/class-woocommerce-my-account.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/includes/reader-revenue/my-account/class-woocommerce-my-account.php b/includes/reader-revenue/my-account/class-woocommerce-my-account.php index e78e526f17..67e73c15cd 100644 --- a/includes/reader-revenue/my-account/class-woocommerce-my-account.php +++ b/includes/reader-revenue/my-account/class-woocommerce-my-account.php @@ -434,12 +434,18 @@ public static function verify_saved_account_details() { * @return bool True if the current checkout page is coming from a My Account referrer, false otherwise. */ public static function is_from_my_account() { - // If we got posted a `is_my_account` param, return true. + // If we're in My Account. + if ( \is_account_page() ) { + return true; + } + + // If we have an `is_my_account` param in POST or GET. $is_my_account_param = rest_sanitize_boolean( $_REQUEST['my_account_checkout'] ?? false ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized if ( $is_my_account_param ) { return true; } + // If the referrer URL had a `my_account_checkout` param. $referrer = \wp_get_referer(); if ( $referrer ) { $referrer_query = \wp_parse_url( $referrer, PHP_URL_QUERY ); @@ -460,7 +466,7 @@ public static function is_from_my_account() { * @return string */ public static function get_checkout_url( $url ) { - if ( \is_account_page() || self::is_from_my_account() ) { + if ( self::is_from_my_account() ) { return \add_query_arg( [ 'my_account_checkout' => 1,