auto-patch 638-dev-dev01-2024-05-14T20_44_36
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
<?php
|
||||
namespace Automattic\WooCommerce\Blocks\Domain;
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Blocks\Assets\Api as AssetApi;
|
||||
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
|
||||
use Automattic\WooCommerce\Blocks\AssetsController;
|
||||
use Automattic\WooCommerce\Blocks\BlockPatterns;
|
||||
use Automattic\WooCommerce\Blocks\BlockTemplatesRegistry;
|
||||
use Automattic\WooCommerce\Blocks\BlockTemplatesController;
|
||||
use Automattic\WooCommerce\Blocks\BlockTypesController;
|
||||
use Automattic\WooCommerce\Blocks\QueryFilters;
|
||||
@@ -27,13 +29,7 @@ use Automattic\WooCommerce\Blocks\Payments\Integrations\Cheque;
|
||||
use Automattic\WooCommerce\Blocks\Payments\Integrations\PayPal;
|
||||
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
|
||||
use Automattic\WooCommerce\Blocks\Registry\Container;
|
||||
use Automattic\WooCommerce\Blocks\Templates\CartTemplate;
|
||||
use Automattic\WooCommerce\Blocks\Templates\CheckoutHeaderTemplate;
|
||||
use Automattic\WooCommerce\Blocks\Templates\CheckoutTemplate;
|
||||
use Automattic\WooCommerce\Blocks\Templates\ClassicTemplatesCompatibility;
|
||||
use Automattic\WooCommerce\Blocks\Templates\OrderConfirmationTemplate;
|
||||
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
|
||||
use Automattic\WooCommerce\Blocks\Templates\ProductSearchResultsTemplate;
|
||||
use Automattic\WooCommerce\StoreApi\RoutesController;
|
||||
use Automattic\WooCommerce\StoreApi\SchemaController;
|
||||
use Automattic\WooCommerce\StoreApi\StoreApi;
|
||||
@@ -151,13 +147,8 @@ class Bootstrap {
|
||||
// regular rest requests to maintain compatibility with the store editor.
|
||||
$this->container->get( BlockPatterns::class );
|
||||
$this->container->get( BlockTypesController::class );
|
||||
$this->container->get( BlockTemplatesController::class );
|
||||
$this->container->get( ProductSearchResultsTemplate::class );
|
||||
$this->container->get( ProductAttributeTemplate::class );
|
||||
$this->container->get( CartTemplate::class );
|
||||
$this->container->get( CheckoutTemplate::class );
|
||||
$this->container->get( CheckoutHeaderTemplate::class );
|
||||
$this->container->get( OrderConfirmationTemplate::class );
|
||||
$this->container->get( BlockTemplatesRegistry::class )->init();
|
||||
$this->container->get( BlockTemplatesController::class )->init();
|
||||
$this->container->get( ClassicTemplatesCompatibility::class );
|
||||
$this->container->get( ArchiveProductTemplatesCompatibility::class )->init();
|
||||
$this->container->get( SingleProductTemplateCompatibility::class )->init();
|
||||
@@ -190,11 +181,12 @@ class Bootstrap {
|
||||
function() {
|
||||
echo '<div class="error"><p>';
|
||||
printf(
|
||||
/* translators: %1$s is the install command, %2$s is the build command, %3$s is the watch command. */
|
||||
esc_html__( 'WooCommerce Blocks development mode requires files to be built. From the plugin directory, run %1$s to install dependencies, %2$s to build the files or %3$s to build the files and watch for changes.', 'woocommerce' ),
|
||||
'<code>npm install</code>',
|
||||
'<code>npm run build</code>',
|
||||
'<code>npm start</code>'
|
||||
/* translators: %1$s is the node install command, %2$s is the install command, %3$s is the build command, %4$s is the watch command. */
|
||||
esc_html__( 'WooCommerce Blocks development mode requires files to be built. From the root directory, run %1$s to ensure your node version is aligned, run %2$s to install dependencies, %3$s to build the files or %4$s to build the files and watch for changes.', 'woocommerce' ),
|
||||
'<code>nvm use</code>',
|
||||
'<code>pnpm install</code>',
|
||||
'<code>pnpm --filter="@woocommerce/plugin-woocommerce" build</code>',
|
||||
'<code>pnpm --filter="@woocommerce/plugin-woocommerce" watch:build</code>'
|
||||
);
|
||||
echo '</p></div>';
|
||||
}
|
||||
@@ -256,46 +248,16 @@ class Bootstrap {
|
||||
return new BlockTypesController( $asset_api, $asset_data_registry );
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
BlockTemplatesRegistry::class,
|
||||
function ( Container $container ) {
|
||||
return new BlockTemplatesRegistry();
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
BlockTemplatesController::class,
|
||||
function ( Container $container ) {
|
||||
return new BlockTemplatesController( $container->get( Package::class ) );
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
ProductSearchResultsTemplate::class,
|
||||
function () {
|
||||
return new ProductSearchResultsTemplate();
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
ProductAttributeTemplate::class,
|
||||
function () {
|
||||
return new ProductAttributeTemplate();
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
CartTemplate::class,
|
||||
function () {
|
||||
return new CartTemplate();
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
CheckoutTemplate::class,
|
||||
function () {
|
||||
return new CheckoutTemplate();
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
CheckoutHeaderTemplate::class,
|
||||
function () {
|
||||
return new CheckoutHeaderTemplate();
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
OrderConfirmationTemplate::class,
|
||||
function () {
|
||||
return new OrderConfirmationTemplate();
|
||||
return new BlockTemplatesController();
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
@@ -311,7 +273,6 @@ class Bootstrap {
|
||||
return new ArchiveProductTemplatesCompatibility();
|
||||
}
|
||||
);
|
||||
|
||||
$this->container->register(
|
||||
SingleProductTemplateCompatibility::class,
|
||||
function () {
|
||||
@@ -387,28 +348,28 @@ class Bootstrap {
|
||||
$this->container->register(
|
||||
'Automattic\WooCommerce\Blocks\StoreApi\Formatters',
|
||||
function( Container $container ) {
|
||||
$this->deprecated_dependency( 'Automattic\WooCommerce\Blocks\StoreApi\Formatters', '7.2.0', 'Automattic\WooCommerce\StoreApi\Formatters', '7.4.0' );
|
||||
$this->deprecated_dependency( 'Automattic\WooCommerce\Blocks\StoreApi\Formatters', '6.4.0', 'Automattic\WooCommerce\StoreApi\Formatters', '6.5.0' );
|
||||
return $container->get( StoreApi::class )->container()->get( \Automattic\WooCommerce\StoreApi\Formatters::class );
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
'Automattic\WooCommerce\Blocks\Domain\Services\ExtendRestApi',
|
||||
function( Container $container ) {
|
||||
$this->deprecated_dependency( 'Automattic\WooCommerce\Blocks\Domain\Services\ExtendRestApi', '7.2.0', 'Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema', '7.4.0' );
|
||||
$this->deprecated_dependency( 'Automattic\WooCommerce\Blocks\Domain\Services\ExtendRestApi', '6.4.0', 'Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema', '6.5.0' );
|
||||
return $container->get( StoreApi::class )->container()->get( \Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema::class );
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
'Automattic\WooCommerce\Blocks\StoreApi\SchemaController',
|
||||
function( Container $container ) {
|
||||
$this->deprecated_dependency( 'Automattic\WooCommerce\Blocks\StoreApi\SchemaController', '7.2.0', 'Automattic\WooCommerce\StoreApi\SchemaController', '7.4.0' );
|
||||
$this->deprecated_dependency( 'Automattic\WooCommerce\Blocks\StoreApi\SchemaController', '6.4.0', 'Automattic\WooCommerce\StoreApi\SchemaController', '6.5.0' );
|
||||
return $container->get( StoreApi::class )->container()->get( SchemaController::class );
|
||||
}
|
||||
);
|
||||
$this->container->register(
|
||||
'Automattic\WooCommerce\Blocks\StoreApi\RoutesController',
|
||||
function( Container $container ) {
|
||||
$this->deprecated_dependency( 'Automattic\WooCommerce\Blocks\StoreApi\RoutesController', '7.2.0', 'Automattic\WooCommerce\StoreApi\RoutesController', '7.4.0' );
|
||||
$this->deprecated_dependency( 'Automattic\WooCommerce\Blocks\StoreApi\RoutesController', '6.4.0', 'Automattic\WooCommerce\StoreApi\RoutesController', '6.5.0' );
|
||||
return $container->get( StoreApi::class )->container()->get( RoutesController::class );
|
||||
}
|
||||
);
|
||||
@@ -479,7 +440,7 @@ class Bootstrap {
|
||||
}
|
||||
|
||||
// If the $trigger_error_version was not yet reached, only log the error.
|
||||
if ( version_compare( $this->package->get_version(), $trigger_error_version, '<' ) ) {
|
||||
if ( version_compare( Constants::get_constant( 'WC_VERSION' ), $trigger_error_version, '<' ) ) {
|
||||
$log_error = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,12 @@ class Package {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the plugin.
|
||||
* Returns the version of WooCommerce Blocks.
|
||||
*
|
||||
* Note: since Blocks was merged into WooCommerce Core, the version of
|
||||
* WC Blocks doesn't update anymore. Use
|
||||
* `Constants::get_constant( 'WC_VERSION' )` when possible to get the
|
||||
* WooCommerce Core version.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -65,7 +70,7 @@ class Package {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the plugin stored in the database.
|
||||
* Returns the version of WooCommerce Blocks stored in the database.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -74,12 +79,11 @@ class Package {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the version of the plugin stored in the database.
|
||||
* Sets the version of WooCommerce Blocks in the database.
|
||||
* This is useful during the first installation or after the upgrade process.
|
||||
*/
|
||||
public function set_version_stored_on_db() {
|
||||
update_option( Options::WC_BLOCK_VERSION, $this->get_version() );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,7 @@ class CheckoutFieldsAdmin {
|
||||
add_filter( 'woocommerce_admin_billing_fields', array( $this, 'admin_address_fields' ), 10, 3 );
|
||||
add_filter( 'woocommerce_admin_billing_fields', array( $this, 'admin_contact_fields' ), 10, 3 );
|
||||
add_filter( 'woocommerce_admin_shipping_fields', array( $this, 'admin_address_fields' ), 10, 3 );
|
||||
add_filter( 'woocommerce_admin_shipping_fields', array( $this, 'admin_additional_fields' ), 10, 3 );
|
||||
add_filter( 'woocommerce_admin_shipping_fields', array( $this, 'admin_order_fields' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +73,9 @@ class CheckoutFieldsAdmin {
|
||||
* @param \WC_Order $order The order to update the field for.
|
||||
*/
|
||||
public function update_callback( $key, $value, $order ) {
|
||||
$this->checkout_fields_controller->persist_field_for_order( $key, $value, $order, false );
|
||||
list( $group, $key ) = explode( '/', $key, 2 );
|
||||
$group = CheckoutFields::get_group_name( $group );
|
||||
$this->checkout_fields_controller->persist_field_for_order( $key, $value, $order, $group, false );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,11 +91,11 @@ class CheckoutFieldsAdmin {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$group = doing_action( 'woocommerce_admin_billing_fields' ) ? 'billing' : 'shipping';
|
||||
$additional_fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'address', $group, $context );
|
||||
$group_name = doing_action( 'woocommerce_admin_billing_fields' ) ? 'billing' : 'shipping';
|
||||
$additional_fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'address', $group_name, $context );
|
||||
foreach ( $additional_fields as $key => $field ) {
|
||||
$group_key = '/' . $group . '/' . $key;
|
||||
$additional_fields[ $key ] = $this->format_field_for_meta_box( $field, $group_key );
|
||||
$prefixed_key = CheckoutFields::get_group_key( $group_name ) . $key;
|
||||
$additional_fields[ $key ] = $this->format_field_for_meta_box( $field, $prefixed_key );
|
||||
}
|
||||
|
||||
array_splice(
|
||||
@@ -123,16 +125,14 @@ class CheckoutFieldsAdmin {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$additional_fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'contact', '', $context );
|
||||
$additional_fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'contact', 'other', $context );
|
||||
|
||||
return array_merge(
|
||||
$fields,
|
||||
array_map(
|
||||
array( $this, 'format_field_for_meta_box' ),
|
||||
$additional_fields,
|
||||
array_keys( $additional_fields )
|
||||
)
|
||||
);
|
||||
foreach ( $additional_fields as $key => $field ) {
|
||||
$prefixed_key = CheckoutFields::get_group_key( 'other' ) . $key;
|
||||
$additional_fields[ $key ] = $this->format_field_for_meta_box( $field, $prefixed_key );
|
||||
}
|
||||
|
||||
return array_merge( $fields, $additional_fields );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,20 +143,18 @@ class CheckoutFieldsAdmin {
|
||||
* @param string $context The context to show the fields for.
|
||||
* @return array
|
||||
*/
|
||||
public function admin_additional_fields( $fields, $order = null, $context = 'edit' ) {
|
||||
public function admin_order_fields( $fields, $order = null, $context = 'edit' ) {
|
||||
if ( ! $order instanceof \WC_Order ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$additional_fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'additional', '', $context );
|
||||
$additional_fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'order', 'other', $context );
|
||||
|
||||
return array_merge(
|
||||
$fields,
|
||||
array_map(
|
||||
array( $this, 'format_field_for_meta_box' ),
|
||||
$additional_fields,
|
||||
array_keys( $additional_fields )
|
||||
)
|
||||
);
|
||||
foreach ( $additional_fields as $key => $field ) {
|
||||
$prefixed_key = CheckoutFields::get_group_key( 'other' ) . $key;
|
||||
$additional_fields[ $key ] = $this->format_field_for_meta_box( $field, $prefixed_key );
|
||||
}
|
||||
|
||||
return array_merge( $fields, $additional_fields );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class CheckoutFieldsFrontend {
|
||||
public function init() {
|
||||
// Show custom checkout fields on the order details page.
|
||||
add_action( 'woocommerce_order_details_after_customer_address', array( $this, 'render_order_address_fields' ), 10, 2 );
|
||||
add_action( 'woocommerce_order_details_after_customer_details', array( $this, 'render_order_additional_fields' ), 10 );
|
||||
add_action( 'woocommerce_order_details_after_customer_details', array( $this, 'render_order_other_fields' ), 10 );
|
||||
|
||||
// Show custom checkout fields on the My Account page.
|
||||
add_action( 'woocommerce_my_account_after_my_address', array( $this, 'render_address_fields' ), 10, 1 );
|
||||
@@ -87,10 +87,10 @@ class CheckoutFieldsFrontend {
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
*/
|
||||
public function render_order_additional_fields( $order ) {
|
||||
public function render_order_other_fields( $order ) {
|
||||
$fields = array_merge(
|
||||
$this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'contact', '', 'view' ),
|
||||
$this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'additional', '', 'view' ),
|
||||
$this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'contact', 'other', 'view' ),
|
||||
$this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'order', 'other', 'view' ),
|
||||
);
|
||||
|
||||
if ( ! $fields ) {
|
||||
@@ -122,7 +122,7 @@ class CheckoutFieldsFrontend {
|
||||
|
||||
foreach ( $fields as $key => $field ) {
|
||||
$value = $this->checkout_fields_controller->format_additional_field_value(
|
||||
$this->checkout_fields_controller->get_field_from_customer( $key, $customer, $address_type ),
|
||||
$this->checkout_fields_controller->get_field_from_object( $key, $customer, $address_type ),
|
||||
$field
|
||||
);
|
||||
|
||||
@@ -160,8 +160,10 @@ class CheckoutFieldsFrontend {
|
||||
$fields = $this->checkout_fields_controller->get_fields_for_location( 'contact' );
|
||||
|
||||
foreach ( $fields as $key => $field ) {
|
||||
$field_key = CheckoutFields::get_group_key( 'other' ) . $key;
|
||||
$form_field = $field;
|
||||
$form_field['value'] = $this->checkout_fields_controller->get_field_from_customer( $key, $customer, 'contact' );
|
||||
$form_field['id'] = $field_key;
|
||||
$form_field['value'] = $this->checkout_fields_controller->get_field_from_object( $key, $customer, 'contact' );
|
||||
|
||||
if ( 'select' === $field['type'] ) {
|
||||
$form_field['options'] = array_column( $field['options'], 'label', 'value' );
|
||||
@@ -189,12 +191,13 @@ class CheckoutFieldsFrontend {
|
||||
$additional_fields = $this->checkout_fields_controller->get_fields_for_location( 'contact' );
|
||||
$field_values = array();
|
||||
|
||||
foreach ( $additional_fields as $key => $field ) {
|
||||
if ( ! isset( $_POST[ $key ] ) ) {
|
||||
foreach ( array_keys( $additional_fields ) as $key ) {
|
||||
$post_key = CheckoutFields::get_group_key( 'other' ) . $key;
|
||||
if ( ! isset( $_POST[ $post_key ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$field_value = $this->checkout_fields_controller->sanitize_field( $key, wc_clean( wp_unslash( $_POST[ $key ] ) ) );
|
||||
$field_value = $this->checkout_fields_controller->sanitize_field( $key, wc_clean( wp_unslash( $_POST[ $post_key ] ) ) );
|
||||
$validation = $this->checkout_fields_controller->validate_field( $key, $field_value );
|
||||
|
||||
if ( is_wp_error( $validation ) && $validation->has_errors() ) {
|
||||
@@ -207,11 +210,11 @@ class CheckoutFieldsFrontend {
|
||||
|
||||
// Persist individual additional fields to customer.
|
||||
foreach ( $field_values as $key => $value ) {
|
||||
$this->checkout_fields_controller->persist_field_for_customer( $key, $value, $customer );
|
||||
$this->checkout_fields_controller->persist_field_for_customer( $key, $value, $customer, 'other' );
|
||||
}
|
||||
|
||||
// Validate all fields for this location.
|
||||
$location_validation = $this->checkout_fields_controller->validate_fields_for_location( $field_values, 'contact' );
|
||||
$location_validation = $this->checkout_fields_controller->validate_fields_for_location( $field_values, 'contact', 'other' );
|
||||
|
||||
if ( is_wp_error( $location_validation ) && $location_validation->has_errors() ) {
|
||||
wc_add_notice( $location_validation->get_error_message(), 'error' );
|
||||
@@ -233,9 +236,9 @@ class CheckoutFieldsFrontend {
|
||||
$fields = $this->checkout_fields_controller->get_fields_for_location( 'address' );
|
||||
|
||||
foreach ( $fields as $key => $field ) {
|
||||
$field_key = "/{$address_type}/{$key}";
|
||||
$field_key = CheckoutFields::get_group_key( $address_type ) . $key;
|
||||
$address[ $field_key ] = $field;
|
||||
$address[ $field_key ]['value'] = $this->checkout_fields_controller->get_field_from_customer( $key, $customer, $address_type );
|
||||
$address[ $field_key ]['value'] = $this->checkout_fields_controller->get_field_from_object( $key, $customer, $address_type );
|
||||
|
||||
if ( 'select' === $field['type'] ) {
|
||||
$address[ $field_key ]['options'] = array_column( $field['options'], 'label', 'value' );
|
||||
@@ -266,8 +269,8 @@ class CheckoutFieldsFrontend {
|
||||
$additional_fields = $this->checkout_fields_controller->get_fields_for_location( 'address' );
|
||||
$field_values = array();
|
||||
|
||||
foreach ( $additional_fields as $key => $field ) {
|
||||
$post_key = "/{$address_type}/{$key}";
|
||||
foreach ( array_keys( $additional_fields ) as $key ) {
|
||||
$post_key = CheckoutFields::get_group_key( $address_type ) . $key;
|
||||
|
||||
if ( ! isset( $_POST[ $post_key ] ) ) {
|
||||
continue;
|
||||
@@ -286,7 +289,7 @@ class CheckoutFieldsFrontend {
|
||||
|
||||
// Persist individual additional fields to customer.
|
||||
foreach ( $field_values as $key => $value ) {
|
||||
$this->checkout_fields_controller->persist_field_for_customer( "/{$address_type}/{$key}", $value, $customer );
|
||||
$this->checkout_fields_controller->persist_field_for_customer( $key, $value, $customer, $address_type );
|
||||
}
|
||||
|
||||
// Validate all fields for this location.
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
namespace Automattic\WooCommerce\Blocks\Domain\Services;
|
||||
|
||||
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
|
||||
use Automattic\WooCommerce\StoreApi\RoutesController;
|
||||
use Automattic\WooCommerce\StoreApi\SchemaController;
|
||||
use Automattic\WooCommerce\StoreApi\StoreApi;
|
||||
|
||||
/**
|
||||
* Service class that handles hydration of API data for blocks.
|
||||
@@ -19,7 +22,7 @@ class Hydration {
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $cached_store_notices = [];
|
||||
protected $cached_store_notices = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -38,24 +41,162 @@ class Hydration {
|
||||
* @return array Response data.
|
||||
*/
|
||||
public function get_rest_api_response_data( $path = '' ) {
|
||||
$this->cache_store_notices();
|
||||
if ( ! str_starts_with( $path, '/wc/store' ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Allow-list only store API routes. No other request can be hydrated for safety.
|
||||
$available_routes = StoreApi::container()->get( RoutesController::class )->get_all_routes( 'v1', true );
|
||||
$controller_class = $this->match_route_to_handler( $path, $available_routes );
|
||||
|
||||
/**
|
||||
* We disable nonce check to support endpoints such as checkout. The caveat here is that we need to be careful to only support GET requests. No other request type should be processed without nonce check. Additionally, no GET request can modify data as part of hydration request, for example adding items to cart.
|
||||
*
|
||||
* Long term, we should consider validating nonce here, instead of disabling it temporarily.
|
||||
*/
|
||||
$this->disable_nonce_check();
|
||||
|
||||
// Preload the request and add it to the array. It will be $preloaded_requests['path'] and contain 'body' and 'headers'.
|
||||
$preloaded_requests = rest_preload_api_request( [], $path );
|
||||
$this->cache_store_notices();
|
||||
|
||||
$preloaded_data = array();
|
||||
|
||||
if ( null !== $controller_class ) {
|
||||
try {
|
||||
$response = $this->get_response_from_controller( $controller_class, $path );
|
||||
if ( $response ) {
|
||||
$preloaded_data = array(
|
||||
'body' => $response->get_data(),
|
||||
'headers' => $response->get_headers(),
|
||||
);
|
||||
}
|
||||
} catch ( \Exception $e ) {
|
||||
// This is executing in frontend of the site, a failure in hydration should not stop the site from working.
|
||||
wc_get_logger()->warning(
|
||||
'Error in hydrating REST API request: ' . $e->getMessage(),
|
||||
array(
|
||||
'source' => 'blocks-hydration',
|
||||
'data' => array(
|
||||
'path' => $path,
|
||||
'controller' => $controller_class,
|
||||
),
|
||||
'backtrace' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Preload the request and add it to the array. It will be $preloaded_requests['path'] and contain 'body' and 'headers'.
|
||||
$preloaded_requests = rest_preload_api_request( array(), $path );
|
||||
$preloaded_data = $preloaded_requests[ $path ] ?? array();
|
||||
}
|
||||
|
||||
$this->restore_cached_store_notices();
|
||||
$this->restore_nonce_check();
|
||||
|
||||
// Returns just the single preloaded request, or an empty array if it doesn't exist.
|
||||
return $preloaded_requests[ $path ] ?? [];
|
||||
return $preloaded_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to generate GET response from a controller. Also fires the `rest_request_after_callbacks` for backward compatibility.
|
||||
*
|
||||
* @param string $controller_class Controller class FQN that will respond to the request.
|
||||
* @param string $path Request path regex.
|
||||
*
|
||||
* @return false|mixed|null Response
|
||||
*/
|
||||
private function get_response_from_controller( $controller_class, $path ) {
|
||||
if ( null === $controller_class ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$request = new \WP_REST_Request( 'GET', $path );
|
||||
$schema_controller = StoreApi::container()->get( SchemaController::class );
|
||||
$controller = new $controller_class(
|
||||
$schema_controller,
|
||||
$schema_controller->get( $controller_class::SCHEMA_TYPE, $controller_class::SCHEMA_VERSION )
|
||||
);
|
||||
|
||||
$controller_args = is_callable( array( $controller, 'get_args' ) ) ? $controller->get_args() : array();
|
||||
|
||||
if ( empty( $controller_args ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the handler that responds to read request.
|
||||
$handler = current(
|
||||
array_filter(
|
||||
$controller_args,
|
||||
function ( $method_handler ) {
|
||||
return is_array( $method_handler ) && isset( $method_handler['methods'] ) && \WP_REST_Server::READABLE === $method_handler['methods'];
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! $handler ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to WP core's `rest_dispatch_request` filter, this allows plugin to override hydrating the request.
|
||||
* Allows backward compatibility with the `rest_dispatch_request` filter by providing the same arguments.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*
|
||||
* @param mixed $hydration_result Result of the hydration. If not null, this will be used as the response.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
* @param string $path Request path matched for the request..
|
||||
* @param array $handler Route handler used for the request.
|
||||
*/
|
||||
$hydration_result = apply_filters( 'woocommerce_hydration_dispatch_request', null, $request, $path, $handler );
|
||||
|
||||
if ( null !== $hydration_result ) {
|
||||
$response = $hydration_result;
|
||||
} else {
|
||||
$response = call_user_func_array( $handler['callback'], array( $request ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to WP core's `rest_request_after_callbacks` filter, this allows to modify the response after it has been generated.
|
||||
* Allows backward compatibility with the `rest_request_after_callbacks` filter by providing the same arguments.
|
||||
*
|
||||
* @since 8.9.0
|
||||
*
|
||||
* @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client.
|
||||
* Usually a WP_REST_Response or WP_Error.
|
||||
* @param array $handler Route handler used for the request.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
*/
|
||||
$response = apply_filters( 'woocommerce_hydration_request_after_callbacks', $response, $handler, $request );
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspired from WP core's `match_request_to_handler`, this matches a given path from available route regexes.
|
||||
* However, unlike WP core, this does not check against query params, request method etc.
|
||||
*
|
||||
* @param string $path The path to match.
|
||||
* @param array $available_routes Available routes in { $regex1 => $contoller_class1, ... } format.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function match_route_to_handler( $path, $available_routes ) {
|
||||
$matched_route = null;
|
||||
foreach ( $available_routes as $route_path => $controller ) {
|
||||
$match = preg_match( '@^' . $route_path . '$@i', $path );
|
||||
if ( $match ) {
|
||||
$matched_route = $controller;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $matched_route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the nonce check temporarily.
|
||||
*/
|
||||
protected function disable_nonce_check() {
|
||||
add_filter( 'woocommerce_store_api_disable_nonce_check', [ $this, 'disable_nonce_check_callback' ] );
|
||||
add_filter( 'woocommerce_store_api_disable_nonce_check', array( $this, 'disable_nonce_check_callback' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +211,7 @@ class Hydration {
|
||||
* Restore the nonce check.
|
||||
*/
|
||||
protected function restore_nonce_check() {
|
||||
remove_filter( 'woocommerce_store_api_disable_nonce_check', [ $this, 'disable_nonce_check_callback' ] );
|
||||
remove_filter( 'woocommerce_store_api_disable_nonce_check', array( $this, 'disable_nonce_check_callback' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,6 +233,6 @@ class Hydration {
|
||||
return;
|
||||
}
|
||||
WC()->session->set( 'wc_notices', $this->cached_store_notices );
|
||||
$this->cached_store_notices = [];
|
||||
$this->cached_store_notices = array();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,12 +41,24 @@ class Notices {
|
||||
* Initialize notice hooks.
|
||||
*/
|
||||
public function init() {
|
||||
if ( wp_is_block_theme() ) {
|
||||
add_filter( 'woocommerce_kses_notice_allowed_tags', [ $this, 'add_kses_notice_allowed_tags' ] );
|
||||
add_filter( 'wc_get_template', [ $this, 'get_notices_template' ], 10, 5 );
|
||||
add_action( 'wp_head', [ $this, 'enqueue_notice_styles' ] );
|
||||
}
|
||||
add_action(
|
||||
'after_setup_theme',
|
||||
function() {
|
||||
/**
|
||||
* Allow classic theme developers to opt-in to using block notices.
|
||||
*
|
||||
* @since 8.8.0
|
||||
* @param bool $use_block_notices_in_classic_theme Whether to use block notices in classic theme.
|
||||
* @return bool
|
||||
*/
|
||||
if ( wp_is_block_theme() || apply_filters( 'woocommerce_use_block_notices_in_classic_theme', false ) ) {
|
||||
add_filter( 'wc_get_template', [ $this, 'get_notices_template' ], 10, 5 );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
add_filter( 'woocommerce_kses_notice_allowed_tags', [ $this, 'add_kses_notice_allowed_tags' ] );
|
||||
add_action( 'wp_head', [ $this, 'enqueue_notice_styles' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
use Automattic\WooCommerce\Blocks\Package;
|
||||
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
|
||||
|
||||
if ( ! function_exists( '__experimental_woocommerce_blocks_register_checkout_field' ) ) {
|
||||
if ( ! function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
|
||||
/**
|
||||
* Register a checkout field.
|
||||
*
|
||||
* @param array $options Field arguments. See CheckoutFields::register_checkout_field() for details.
|
||||
* @throws \Exception If field registration fails.
|
||||
*/
|
||||
function __experimental_woocommerce_blocks_register_checkout_field( $options ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
|
||||
function woocommerce_register_additional_checkout_field( $options ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
|
||||
|
||||
// Check if `woocommerce_blocks_loaded` ran. If not then the CheckoutFields class will not be available yet.
|
||||
// In that case, re-hook `woocommerce_blocks_loaded` and try running this again.
|
||||
@@ -18,8 +18,8 @@ if ( ! function_exists( '__experimental_woocommerce_blocks_register_checkout_fie
|
||||
if ( ! $woocommerce_blocks_loaded_ran ) {
|
||||
add_action(
|
||||
'woocommerce_blocks_loaded',
|
||||
function() use ( $options ) {
|
||||
__experimental_woocommerce_blocks_register_checkout_field( $options );
|
||||
function () use ( $options ) {
|
||||
woocommerce_register_additional_checkout_field( $options );
|
||||
}
|
||||
);
|
||||
return;
|
||||
@@ -27,7 +27,39 @@ if ( ! function_exists( '__experimental_woocommerce_blocks_register_checkout_fie
|
||||
$checkout_fields = Package::container()->get( CheckoutFields::class );
|
||||
$result = $checkout_fields->register_checkout_field( $options );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
throw new \Exception( $result->get_error_message() );
|
||||
throw new \Exception( esc_attr( $result->get_error_message() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( '__experimental_woocommerce_blocks_register_checkout_field' ) ) {
|
||||
|
||||
/**
|
||||
* Register a checkout field.
|
||||
*
|
||||
* @param array $options Field arguments. See CheckoutFields::register_checkout_field() for details.
|
||||
* @throws \Exception If field registration fails.
|
||||
* @deprecated 5.6.0 Use woocommerce_register_additional_checkout_field() instead.
|
||||
*/
|
||||
function __experimental_woocommerce_blocks_register_checkout_field( $options ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
|
||||
wc_deprecated_function( __FUNCTION__, '8.9.0', 'woocommerce_register_additional_checkout_field' );
|
||||
woocommerce_register_additional_checkout_field( $options );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( '__internal_woocommerce_blocks_deregister_checkout_field' ) ) {
|
||||
/**
|
||||
* Deregister a checkout field.
|
||||
*
|
||||
* @param string $field_id Field ID.
|
||||
* @throws \Exception If field deregistration fails.
|
||||
* @internal
|
||||
*/
|
||||
function __internal_woocommerce_blocks_deregister_checkout_field( $field_id ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
|
||||
$checkout_fields = Package::container()->get( CheckoutFields::class );
|
||||
$result = $checkout_fields->deregister_checkout_field( $field_id );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
throw new \Exception( esc_attr( $result->get_error_message() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user