From 7e94e1a31e685bd56a81b8483d74fef8a89303ae Mon Sep 17 00:00:00 2001 From: Iyut Date: Tue, 31 Dec 2024 10:57:21 +0700 Subject: [PATCH] use blocks integration to add notice in blocks --- .../class-wc-connect-blocks-integration.php | 118 ++++++++++++++++++ .../class-wc-connect-taxjar-integration.php | 23 ++-- client/checkout-notices/index.js | 106 ++++++++-------- woocommerce-services.php | 51 ++++++-- 4 files changed, 227 insertions(+), 71 deletions(-) create mode 100644 classes/class-wc-connect-blocks-integration.php diff --git a/classes/class-wc-connect-blocks-integration.php b/classes/class-wc-connect-blocks-integration.php new file mode 100644 index 000000000..6a04d6207 --- /dev/null +++ b/classes/class-wc-connect-blocks-integration.php @@ -0,0 +1,118 @@ +register_scripts(); + } + + /** + * Returns an array of script handles to enqueue in the frontend context. + * + * @return string[] + */ + public function get_script_handles(): array { + return array( 'woocommerce-services-checkout-' . WC_Connect_Loader::get_wcs_version() ); + } + + /** + * Returns an array of script handles to enqueue in the editor context. + * + * @return string[] + */ + public function get_editor_script_handles(): array { + return array(); + } + + /** + * An array of key, value pairs of data made available to the block on the client side. + * + * @return array + */ + public function get_script_data(): array { + return array(); + } + + /** + * Registers the scripts and styles for the integration. + */ + public function register_scripts() { + + foreach ( $this->get_script_handles() as $handle ) { + $this->register_script( $handle ); + } + } + + /** + * Register a script for the integration. + * + * @param string $handle Script handle. + */ + protected function register_script( string $handle ) { + $script_path = $handle . '.js'; + $script_url = WC_Connect_Loader::get_wc_connect_base_url() . $script_path; + + $script_asset_path = WC_Connect_Loader::get_wc_connect_base_path() . $handle . '.asset.php'; + $script_asset = file_exists( $script_asset_path ) + ? require $script_asset_path // nosemgrep: audit.php.lang.security.file.inclusion-arg --- This is a safe file inclusion. + : array( + 'dependencies' => array(), + 'version' => $this->get_file_version( WC_Connect_Loader::get_wc_connect_base_path() . $script_path ), + ); + + wp_register_script( + $handle, + $script_url, + $script_asset['dependencies'], + $script_asset['version'], + true + ); + + wp_set_script_translations( + $handle, + 'woocommerce-services', + WC_Connect_Loader::get_wcs_abs_path() . 'i18n/languages' + ); + } + + /** + * Get the file modified time as a cache buster if we're in dev mode. + * + * @param string $file Local path to the file. + * + * @return string The cache buster value to use for the given file. + */ + protected function get_file_version( string $file ): string { + if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists( $file ) ) { + return filemtime( $file ); + } + + return WC_Connect_Loader::get_wcs_version(); + } +} diff --git a/classes/class-wc-connect-taxjar-integration.php b/classes/class-wc-connect-taxjar-integration.php index 867c4232e..39865135b 100644 --- a/classes/class-wc-connect-taxjar-integration.php +++ b/classes/class-wc-connect-taxjar-integration.php @@ -398,25 +398,32 @@ public function _log( $message ) { $this->logger->log( $formatted_message, 'WCS Tax' ); } + /** + * Display notice in cart or checkout page. + * + * @param string|array $message Error message. + */ public function _notice( $message ) { - $formatted_message = is_scalar( $message ) ? $message : json_encode( $message ); + $formatted_message = is_scalar( $message ) ? $message : wp_json_encode( $message ); // if on checkout page load (not ajax), don't set an error as it prevents checkout page from displaying if ( ( is_cart() || ( is_checkout() && is_ajax() ) ) || ( WC_Connect_Functions::has_cart_or_checkout_block() || WC_Connect_functions::is_store_api_call() ) ) { - $this->maybe_add_notice_error( $message, 'notice' ); + $this->maybe_add_error_notice( $message, 'notice' ); } return; } /** - * @param $message + * Display error on cart or checkout page. + * + * @param string|array $message Error message. */ public function _error( $message ) { - $formatted_message = is_scalar( $message ) ? $message : json_encode( $message ); + $formatted_message = is_scalar( $message ) ? $message : wp_json_encode( $message ); // ignore error messages caused by customer input $state_zip_mismatch = false !== strpos( $formatted_message, 'to_zip' ) && false !== strpos( $formatted_message, 'is not used within to_state' ); @@ -442,7 +449,7 @@ public function _error( $message ) { ( is_cart() || ( is_checkout() && is_ajax() ) ) || ( WC_Connect_Functions::has_cart_or_checkout_block() || WC_Connect_functions::is_store_api_call() ) ) { - $this->maybe_add_notice_error( $message, 'error' ); + $this->maybe_add_error_notice( $message, 'error' ); } return; @@ -1469,15 +1476,15 @@ public function smartcalcs_request( $json ) { } } - public function maybe_add_notice_error( $message, $type = 'error' ) { + public function maybe_add_error_notice( $message, $type = 'error' ) { if ( ! wc_has_notice( $message, $type ) ) { wc_add_notice( $message, $type ); } - $this->add_notice_error( $message, $type ); + $this->add_error_notice( $message, $type ); } - public function add_notice_error( $message, $type = 'error' ) { + public function add_error_notice( $message, $type = 'error' ) { $notices = WC()->session->get( self::NOTICE_KEY ); if ( ! is_array( $notices ) ) { diff --git a/client/checkout-notices/index.js b/client/checkout-notices/index.js index 88f488cdb..e49bb04f8 100644 --- a/client/checkout-notices/index.js +++ b/client/checkout-notices/index.js @@ -6,68 +6,68 @@ * @package WooCommerce_Services */ -window.addEventListener("load", () => { - const { useSelect } = window.wp.data; - const { registerPlugin } = window.wp.plugins; - const { ExperimentalOrderShippingPackages, StoreNotice } = window.wc.blocksCheckout; - const { RawHTML } = window.wp.element; +const { useSelect } = window.wp.data; +const { registerPlugin } = window.wp.plugins; +const { ExperimentalOrderShippingPackages, StoreNotice } = window.wc.blocksCheckout; +const { RawHTML } = window.wp.element; - const createStoreNotice = ( notice, index, type = 'info' ) => { - if ( 'debug' === type ) { - type = 'info'; - } - - const message = {notice}; +const createStoreNotice = ( notice, index, type = 'info' ) => { + if ( 'debug' === type ) { + type = 'info'; + } - return ( - - {message} - - ); - }; + // eslint-ignore-nextline + const message = {notice}; - const Notices = ({ messages }) => { - if ( ! messages['notice'] ) { - return null; - } + return ( + + {message} + + ); +}; - const currentMessage = messages['notice']; +const Notices = ({ messages }) => { + if ( ! messages['notice'] ) { + return null; + } - return ( -
- {createStoreNotice( currentMessage, 0, 'info' )} -
- ); - }; + const currentMessage = messages['notice']; - const render = () => { - const { errorNotices } = useSelect((select) => { - const storeCartData = select( 'wc/store/cart' ).getCartData(); + return ( +
+ {createStoreNotice( currentMessage, 0, 'info' )} +
+ ); +}; - if ( ! storeCartData.extensions && ! storeCartData.extensions['woocommerce_services'] && ! storeCartData.extensions['woocommerce_services'].error_notices ) { - return {}; - } - const errorNotices = storeCartData.extensions['woocommerce_services'].error_notices; +const render = () => { + const { errorNotices } = useSelect((select) => { + const storeCartData = select( 'wc/store/cart' ).getCartData(); - return { - errorNotices, - }; - }, []); - - // Ensure we only show abort messages if no shipping rates are available. - if ( ! errorNotices ) { - return null; + if ( ! storeCartData.extensions || ! storeCartData.extensions['woocommerce_services'] || ! storeCartData.extensions['woocommerce_services'].error_notices ) { + return {}; } + + const errorNotices = storeCartData.extensions['woocommerce_services'].error_notices; + + return { + errorNotices, + }; + }, []); + + // Ensure we only show abort messages if no shipping rates are available. + if ( ! errorNotices ) { + return null; + } - return ( - - - - ); - }; + return ( + + + + ); +}; - registerPlugin('woocommerce-services-notices', { - render, - scope: 'woocommerce-checkout', - }); +registerPlugin('woocommerce-services-notices', { + render, + scope: 'woocommerce-checkout', }); diff --git a/woocommerce-services.php b/woocommerce-services.php index b218d6a5c..3f1a42443 100644 --- a/woocommerce-services.php +++ b/woocommerce-services.php @@ -333,7 +333,7 @@ public static function get_wcs_version() { * * @return string */ - private static function get_wc_connect_base_url() { + public static function get_wc_connect_base_url() { return trailingslashit( defined( 'WOOCOMMERCE_CONNECT_DEV_SERVER_URL' ) ? WOOCOMMERCE_CONNECT_DEV_SERVER_URL : plugins_url( 'dist/', __FILE__ ) ); } @@ -359,6 +359,24 @@ public static function get_wcs_admin_style_url() { } } + /** + * Get plugin absolute path. + * + * @return string + */ + public static function get_wcs_abs_path() { + return __DIR__ . '/'; + } + + /** + * Get plugin distribution path. + * + * @return string + */ + public static function get_wc_connect_base_path() { + return __DIR__ . '/dist/'; + } + public function __construct() { $this->wc_connect_base_url = self::get_wc_connect_base_url(); add_action( @@ -663,6 +681,7 @@ function () { } add_action( 'before_woocommerce_init', array( $this, 'pre_wc_init' ) ); + add_action( 'woocommerce_blocks_loaded', array( $this, 'register_blocks_integration' ) ); add_action( 'woocommerce_blocks_loaded', array( $this, 'extend_store_api' ) ); } @@ -701,7 +720,6 @@ public function pre_wc_init() { return; } - add_action( 'wp_enqueue_scripts', array( $this, 'frontend_enqueue_scripts' ) ); add_action( 'woocommerce_init', array( $this, 'after_wc_init' ) ); } @@ -897,6 +915,27 @@ public function attach_hooks() { } } + /** + * Register blocks integration. + */ + public function register_blocks_integration() { + require_once __DIR__ . '/classes/class-wc-connect-blocks-integration.php'; + + add_action( + 'woocommerce_blocks_cart_block_registration', + function ( $integration_registry ) { + $integration_registry->register( new WC_Connect_Blocks_Integration() ); + } + ); + + add_action( + 'woocommerce_blocks_checkout_block_registration', + function ( $integration_registry ) { + $integration_registry->register( new WC_Connect_Blocks_Integration() ); + } + ); + } + /** * Extend the store API. */ @@ -1616,14 +1655,6 @@ public function admin_enqueue_scripts() { ); } - public function frontend_enqueue_scripts() { - $plugin_version = self::get_wcs_version(); - - if ( WC_Connect_Functions::has_cart_or_checkout_block() ) { - wp_enqueue_script( 'wc_services_checkout', $this->wc_connect_base_url . 'woocommerce-services-checkout-' . $plugin_version . '.js', array(), null ); - } - } - public function get_active_shipping_services() { global $wpdb; $active_shipping_services = array();