Initial commit.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* WooCommerceBlocks Integration class.
|
||||
*
|
||||
* @package Automattic\WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\Integrations;
|
||||
|
||||
use Automattic\WCServices\StoreApi\StoreApiExtendSchema;
|
||||
use Automattic\WCServices\Utils;
|
||||
use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* WooCommerceBlocks Integration class.
|
||||
*/
|
||||
class WooCommerceBlocksIntegration implements IntegrationInterface {
|
||||
|
||||
/**
|
||||
* The base URL to use for loading assets.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $base_url;
|
||||
|
||||
public function __construct( string $wc_connect_base_url ) {
|
||||
$this->base_url = $wc_connect_base_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the integration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name(): string {
|
||||
return StoreApiExtendSchema::IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* When called invokes any initialization/setup for the integratidon.
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->register_scripts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of script handles to enqueue in the frontend context.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_script_handles(): array {
|
||||
$script_handles = array();
|
||||
|
||||
$script_handles[] = 'woocommerce-services-store-notices';
|
||||
|
||||
return $script_handles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
$plugin_version = Utils::get_wcservices_version();
|
||||
$script_name = "$handle-$plugin_version.js";
|
||||
$script_path = $this->base_url . $script_name;
|
||||
$script_url = Utils::get_enqueue_base_url() . $script_name;
|
||||
$script_asset_path = $this->base_url . $handle . '.asset.php';
|
||||
$script_asset = file_exists( $script_asset_path )
|
||||
? require $script_asset_path : array(); // nosemgrep: audit.php.lang.security.file.inclusion-arg --- This is a safe file inclusion.
|
||||
$script_dependencies = $script_asset['dependencies'] ?? array();
|
||||
|
||||
wp_register_script(
|
||||
$handle,
|
||||
$script_url,
|
||||
$script_dependencies,
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* Abstract Store API Extension class.
|
||||
*
|
||||
* Provides a base class for extending the Store API.
|
||||
*
|
||||
* @package Automattic/WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\StoreApi;
|
||||
|
||||
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
|
||||
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema;
|
||||
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;
|
||||
use Automattic\WooCommerce\StoreApi\Schemas\V1\CheckoutSchema;
|
||||
use Automattic\WooCommerce\StoreApi\Schemas\V1\ProductSchema;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Interface StoreApiExtensionInterface
|
||||
*/
|
||||
abstract class AbstractStoreApiExtension {
|
||||
|
||||
/**
|
||||
* Stores the Store API Extend Schema instance.
|
||||
*
|
||||
* @var ExtendSchema
|
||||
*/
|
||||
protected static ExtendSchema $extend_schema;
|
||||
|
||||
/**
|
||||
* Stores the possible endpoints to extend.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static array $endpoints = array(
|
||||
'cart-item' => CartItemSchema::IDENTIFIER,
|
||||
'cart' => CartSchema::IDENTIFIER,
|
||||
'checkout' => CheckoutSchema::IDENTIFIER,
|
||||
'product' => ProductSchema::IDENTIFIER,
|
||||
|
||||
);
|
||||
|
||||
/**
|
||||
* Stores the possible schema types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static array $schema_types = array(
|
||||
'array_a' => 'ARRAY_A',
|
||||
'array_n' => 'ARRAY_N',
|
||||
);
|
||||
|
||||
/**
|
||||
* AbstractStoreApiExtension constructor.
|
||||
*
|
||||
* @param ExtendSchema $extend_schema The ExtendSchema instance.
|
||||
*/
|
||||
public function __construct( ExtendSchema $extend_schema ) {
|
||||
self::$extend_schema = $extend_schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the namespace for the extension.
|
||||
*/
|
||||
public function get_namespace(): string {
|
||||
return StoreApiExtendSchema::IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the endpoint to extend.
|
||||
*
|
||||
* Should return one of the keys from the $endpoints array.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function get_endpoint(): string;
|
||||
|
||||
/**
|
||||
* The data callback method.
|
||||
*
|
||||
* This is where you can define the data this endpoint should return.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function data_callback(): array;
|
||||
|
||||
/**
|
||||
* The schema callback method.
|
||||
*
|
||||
* This is where you can define the schema for the endpoint.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function schema_callback(): array;
|
||||
|
||||
/**
|
||||
* The update callback method.
|
||||
*
|
||||
* This is where you can listen for updates to the endpoint and handle accordingly.
|
||||
*
|
||||
* @param array $data Data to update.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function update_callback( array $data ): void;
|
||||
|
||||
/**
|
||||
* Get the schema type to extend the endpoint with.
|
||||
*
|
||||
* Should return one of the keys from the $schema_types array.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function get_schema_type(): string;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* StoreNoticesExtension class.
|
||||
*
|
||||
* Extends the WooCommerce Store API to add address validation to the cart and checkout blocks.
|
||||
*
|
||||
* @package Automattic/WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\StoreApi\Extensions;
|
||||
|
||||
use Automattic\WCServices\StoreNotices\StoreNoticesNotifier;
|
||||
use Automattic\WCServices\StoreNotices\StoreNotice;
|
||||
use Automattic\WCServices\StoreApi\AbstractStoreApiExtension;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class StoreNoticesExtension
|
||||
*/
|
||||
class StoreNoticesExtension extends AbstractStoreApiExtension {
|
||||
|
||||
/**
|
||||
* Get the endpoint to extend.
|
||||
*
|
||||
* Should return one of the keys from the $endpoints array.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_endpoint(): string {
|
||||
return self::$endpoints['cart'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The data callback method.
|
||||
*
|
||||
* This is where you can define the data this endpoint should return.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_callback(): array {
|
||||
$data = array(
|
||||
'notices' => array(),
|
||||
);
|
||||
|
||||
// Get notices from the StoreNoticesNotifier.
|
||||
$notices = StoreNoticesNotifier::get_notices();
|
||||
StoreNoticesNotifier::clear_notices();
|
||||
|
||||
if ( empty( $notices ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Get the HTML formatter.
|
||||
$html_formatter = self::$extend_schema->get_formatter( 'html' );
|
||||
|
||||
// Format the notices.
|
||||
foreach ( $notices as $type => $messages ) {
|
||||
foreach ( $messages as $notice_data ) {
|
||||
// Create a StoreNotice object.
|
||||
$notice = new StoreNotice(
|
||||
$notice_data['message'],
|
||||
$type,
|
||||
! empty( $notice_data['data'] ) ? array( 'details' => $notice_data['data'] ) : null
|
||||
);
|
||||
|
||||
$notice_message = $notice->get_message();
|
||||
$notice_details = $notice->get_data();
|
||||
|
||||
// Format the message with the HTML formatter.
|
||||
$notice->set_message( $html_formatter->format( $notice_message ) );
|
||||
|
||||
if ( ! empty( $notice_details ) ) {
|
||||
$notice->set_data( $notice_details );
|
||||
}
|
||||
|
||||
$data['notices'][] = $notice->to_array();
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* The schema callback method.
|
||||
*
|
||||
* This is where you can define the schema for the endpoint.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function schema_callback(): array {
|
||||
return array(
|
||||
'notices' => array(
|
||||
'description' => __( 'WC Services store notices', 'woocommerce-services' ),
|
||||
'type' => array( 'array' ),
|
||||
'context' => array( 'view' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the schema type to extend the endpoint with.
|
||||
*
|
||||
* Should return one of the keys from the $schema_types array.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_schema_type(): string {
|
||||
return self::$schema_types['array_a'];
|
||||
}
|
||||
|
||||
/**
|
||||
* The update callback method.
|
||||
*
|
||||
* This is where you can listen for updates to the endpoint and handle accordingly.
|
||||
*
|
||||
* @param array $data Data to update.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_callback( array $data ): void {
|
||||
// TODO: Implement update_callback() method.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* StoreApiExtendSchema class.
|
||||
*
|
||||
* Wrapper class for the ExtendSchema instance.
|
||||
*
|
||||
* @package Automattic/WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\StoreApi;
|
||||
|
||||
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
|
||||
use Automattic\WooCommerce\StoreApi\StoreApi;
|
||||
use Exception;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* StoreApiExtendSchema class.
|
||||
*/
|
||||
class StoreApiExtendSchema {
|
||||
/**
|
||||
* Stores Store API ExtendSchema instance.
|
||||
*
|
||||
* @var ExtendSchema
|
||||
*/
|
||||
private static ExtendSchema $instance;
|
||||
|
||||
/**
|
||||
* Plugin Identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const IDENTIFIER = 'woocommerce-services';
|
||||
|
||||
/**
|
||||
* ExtendSchemaService constructor.
|
||||
*/
|
||||
private function __construct() {
|
||||
try {
|
||||
self::$instance = StoreApi::container()->get( ExtendSchema::class );
|
||||
} catch ( Exception $e ) {
|
||||
wc_get_logger()->debug( 'Failed to get ExtendSchema instance.', array( 'exception' => $e ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ExtendSchema instance.
|
||||
*/
|
||||
public static function instance(): ExtendSchema {
|
||||
if ( ! isset( self::$instance ) ) {
|
||||
new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
/**
|
||||
* Store API Extension Controller.
|
||||
*
|
||||
* A class that manages all the Store API extensions for WooCommerce Shipping.
|
||||
*
|
||||
* @package Automattic/WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\StoreApi;
|
||||
|
||||
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
|
||||
use Exception;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Store API Extension Controller.
|
||||
*/
|
||||
class StoreApiExtensionController {
|
||||
|
||||
/**
|
||||
* Stores the Store API Extend Schema instance.
|
||||
*
|
||||
* @var ExtendSchema
|
||||
*/
|
||||
private static ExtendSchema $extend_schema;
|
||||
|
||||
/**
|
||||
* Stores the registered extensions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $registered_extensions = array();
|
||||
|
||||
/**
|
||||
* StoreApiExntensionController constructor.
|
||||
*
|
||||
* @param ExtendSchema $extend_schema The StoreApiExtendSchema instance.
|
||||
*/
|
||||
public function __construct( ExtendSchema $extend_schema ) {
|
||||
self::$extend_schema = $extend_schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an extension.
|
||||
*
|
||||
* @param AbstractStoreApiExtension $extension The extension to register.
|
||||
*/
|
||||
public function register_extension( AbstractStoreApiExtension $extension ) {
|
||||
$this->registered_extensions[] = $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registered extensions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_registered_extensions(): array {
|
||||
return $this->registered_extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the data into each endpoint.
|
||||
*/
|
||||
public function extend_store() {
|
||||
$registered_extensions = $this->get_registered_extensions();
|
||||
|
||||
if ( empty( $registered_extensions ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $registered_extensions as $extension ) {
|
||||
$this->register_endpoint_data( $extension );
|
||||
$this->register_update_callback( $extension );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the endpoint data for an extension.
|
||||
*
|
||||
* @param AbstractStoreApiExtension $extension The extension to register.
|
||||
*/
|
||||
public function register_endpoint_data( AbstractStoreApiExtension $extension ) {
|
||||
try {
|
||||
self::$extend_schema->register_endpoint_data(
|
||||
array(
|
||||
'endpoint' => $extension->get_endpoint(),
|
||||
'namespace' => $extension->get_namespace(),
|
||||
'data_callback' => array( $extension, 'data_callback' ),
|
||||
'schema_callback' => array( $extension, 'schema_callback' ),
|
||||
'schema_type' => $extension->get_schema_type(),
|
||||
)
|
||||
);
|
||||
} catch ( Exception $e ) {
|
||||
wc_get_logger()->debug( 'Failed to register endpoint data for extension', array( 'error', $e->getMessage() ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the update callback for an extension.
|
||||
*
|
||||
* @param AbstractStoreApiExtension $extension The extension to register.
|
||||
*/
|
||||
public function register_update_callback( AbstractStoreApiExtension $extension ) {
|
||||
try {
|
||||
self::$extend_schema->register_update_callback(
|
||||
array(
|
||||
'namespace' => $extension->get_namespace(),
|
||||
'callback' => array( $extension, 'update_callback' ),
|
||||
)
|
||||
);
|
||||
} catch ( Exception $e ) {
|
||||
wc_get_logger()->debug( 'Failed to register update callback for extension', array( 'error', $e->getMessage() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* StoreNotice class.
|
||||
*
|
||||
* @package Automattic/WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\StoreNotices;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class StoreNotice
|
||||
*/
|
||||
class StoreNotice {
|
||||
/**
|
||||
* The notice message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $message;
|
||||
|
||||
/**
|
||||
* The notice type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $type;
|
||||
|
||||
/**
|
||||
* The notice data.
|
||||
*
|
||||
* @var array|null
|
||||
*/
|
||||
private ?array $data;
|
||||
|
||||
/**
|
||||
* StoreNotice constructor.
|
||||
*
|
||||
* @param string $message The notice message.
|
||||
* @param string $type The notice type.
|
||||
* @param array|null $data The notice data.
|
||||
*/
|
||||
public function __construct( string $message, string $type, array $data = null ) {
|
||||
$this->message = $message;
|
||||
$this->type = $type;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notice message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_message(): string {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the notice message.
|
||||
*
|
||||
* @param string $message The notice message.
|
||||
*/
|
||||
public function set_message( string $message ) {
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notice type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_type(): string {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the notice type.
|
||||
*
|
||||
* @param string $type The notice type.
|
||||
*/
|
||||
public function set_type( string $type ) {
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notice data.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function get_data(): ?array {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the notice data.
|
||||
*
|
||||
* @param array|null $data The notice data.
|
||||
*/
|
||||
public function set_data( ?array $data ) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* To array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'message' => $this->message,
|
||||
'type' => $this->type,
|
||||
'data' => $this->data,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* StoreNoticeTypes class.
|
||||
*
|
||||
* Class to define the types of store notices.
|
||||
*
|
||||
* @package Automattic/WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\StoreNotices;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class StoreNoticeTypes
|
||||
*/
|
||||
class StoreNoticeTypes {
|
||||
|
||||
/**
|
||||
* The notice type for a success.
|
||||
*/
|
||||
const SUCCESS = 'success';
|
||||
|
||||
/**
|
||||
* The notice type for an error.
|
||||
*/
|
||||
const ERROR = 'error';
|
||||
|
||||
/**
|
||||
* The notice type for an info notice.
|
||||
*/
|
||||
const INFO = 'info';
|
||||
|
||||
/**
|
||||
* The notice type for a warning.
|
||||
*/
|
||||
const WARNING = 'warning';
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* StoreNoticesController class.
|
||||
*
|
||||
* Controller class for store notices-related hooks.
|
||||
*
|
||||
* @package Automattic/WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\StoreNotices;
|
||||
|
||||
use WC_Cart;
|
||||
use WP_Error;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class StoreNoticesController
|
||||
*/
|
||||
class StoreNoticesController {
|
||||
|
||||
/**
|
||||
* Notifier instance.
|
||||
*
|
||||
* @var StoreNoticesNotifier
|
||||
*/
|
||||
private StoreNoticesNotifier $notifier;
|
||||
|
||||
/**
|
||||
* StoreNoticesController constructor.
|
||||
*
|
||||
* @param StoreNoticesNotifier $notifier The WC_Connect_Logger instance.
|
||||
*/
|
||||
public function __construct( StoreNoticesNotifier $notifier ) {
|
||||
$this->notifier = $notifier;
|
||||
|
||||
add_action( 'woocommerce_after_calculate_totals', array( $this, 'maybe_display_notices' ), 30 );
|
||||
add_filter( 'woocommerce_store_api_cart_errors', array( $this, 'add_store_api_cart_errors' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe display address validation notices.
|
||||
*/
|
||||
public function maybe_display_notices() {
|
||||
if ( ! self::is_classic_checkout() && ! self::is_classic_cart() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->notifier->print_notices();
|
||||
$this->notifier::clear_notices();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the page contains the classic cart.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function is_classic_cart(): bool {
|
||||
if (
|
||||
! function_exists( 'is_cart' )
|
||||
|| ! function_exists( 'has_block' )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return is_cart() && ! has_block( 'woocommerce/cart' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the page contains the classic checkout.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function is_classic_checkout(): bool {
|
||||
if (
|
||||
! function_exists( 'is_checkout' )
|
||||
|| ! function_exists( 'has_block' )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing --- No need to verify nonce here.
|
||||
return ! empty( $_POST ) && is_checkout() && ! has_block( 'woocommerce/checkout' );
|
||||
}
|
||||
|
||||
/**
|
||||
* If there are error notices, we need to block the block checkout to prevent proceeding with checkout.
|
||||
*
|
||||
* @param WP_Error $cart_errors List of errors in the cart.
|
||||
* @param WC_Cart $cart Cart object.
|
||||
* @return WP_Error
|
||||
*/
|
||||
public function add_store_api_cart_errors( $cart_errors, $cart ) {
|
||||
// Get notices from StoreNoticesNotifier.
|
||||
$notices = StoreNoticesNotifier::get_notices();
|
||||
|
||||
// Check if there are any error notices.
|
||||
if ( ! empty( $notices['error'] ) ) {
|
||||
foreach ( $notices['error'] as $notice ) {
|
||||
// Add each error notice to the $cart_errors object to block checkout.
|
||||
$cart_errors->add( 'wcservices_validation', $notice['message'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $cart_errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
/**
|
||||
* Notifier class.
|
||||
*
|
||||
* This class handles the collection and display of notices on the frontend.
|
||||
*
|
||||
* @package Automattic/WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices\StoreNotices;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Notifier class.
|
||||
*/
|
||||
class StoreNoticesNotifier {
|
||||
|
||||
/**
|
||||
* WC Session variable key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const WC_SESSION_KEY = 'wcservices_store_notices';
|
||||
|
||||
/**
|
||||
* Valid notice types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static array $valid_notice_types = array( StoreNoticeTypes::ERROR, StoreNoticeTypes::SUCCESS, StoreNoticeTypes::INFO );
|
||||
|
||||
/**
|
||||
* Is debug enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private bool $is_debug_enabled;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param bool $is_debug_enabled Is debug enabled.
|
||||
*/
|
||||
public function __construct( bool $is_debug_enabled ) {
|
||||
$this->is_debug_enabled = $is_debug_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a debug notice.
|
||||
* Debug notices are only displayed if debug is enabled and the user has the manage_options capability.
|
||||
*
|
||||
* @param string $message Message to display.
|
||||
* @param string $type Type of notice - either error, success or notice.
|
||||
* @param array $data Additional data to pass.
|
||||
* @param string $group Optional. Group to categorize notices.
|
||||
*/
|
||||
public function debug( string $message, string $type = 'notice', array $data = array(), string $group = '' ): void {
|
||||
if ( ! $this->is_debug_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only display debug notices to users with manage_options capability.
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $this->sanitize_type( $type );
|
||||
|
||||
$this->maybe_add_notice( $message, $type, $data, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if debug is enabled.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_debug_enabled(): bool {
|
||||
return $this->is_debug_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize notice type.
|
||||
*
|
||||
* If an invalid notice type is passed, it will default to 'notice'.
|
||||
*
|
||||
* @param string $type Type of notice - either error, success or notice.
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function sanitize_type( string $type ) {
|
||||
if ( ! in_array( $type, self::$valid_notice_types, true ) ) {
|
||||
$type = 'notice';
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add notice if not already added.
|
||||
*
|
||||
* If an invalid notice type is passed, it will default to 'notice'.
|
||||
*
|
||||
* @param string $message Message to display.
|
||||
* @param string $type Type of notice - either error, success or notice.
|
||||
* @param array $data Additional data to pass.
|
||||
* @param string $group Optional. Group to categorize notices.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_add_notice( string $message, string $type = 'notice', array $data = array(), string $group = '' ): void {
|
||||
|
||||
if ( $this->has_notice( $message, $type, $data, $group ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $this->sanitize_type( $type );
|
||||
|
||||
// Add a custom notice so that we can pull only WooCommerce Services related notices when needed.
|
||||
$this->add_notice( $message, $type, $data, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a notice has already been added.
|
||||
*
|
||||
* @param string $message The text to display in the notice.
|
||||
* @param string $type Optional. The name of the notice type - either error, success or notice.
|
||||
* @param array $data Optional. Additional data to pass.
|
||||
* @param string $group Optional. Group to categorize notices.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_notice( string $message, string $type = 'notice', array $data = array(), string $group = '' ): bool {
|
||||
$notices = WC()->session->get( self::WC_SESSION_KEY, array() );
|
||||
|
||||
$notices = $notices[ $type ] ?? array();
|
||||
|
||||
$notice = $this->format_notice( $message, $data, $group );
|
||||
|
||||
return in_array( $notice, $notices, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a notice.
|
||||
*
|
||||
* @param string $message Message to display.
|
||||
* @param array $data Additional data to pass.
|
||||
* @param string $group Group to categorize notices.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function format_notice( string $message, array $data, string $group ): array {
|
||||
return array(
|
||||
'message' => $message,
|
||||
'data' => $data ? print_r( $data, true ) : '', //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r -- print_r use for debug log formatting.
|
||||
'group' => $group,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a notice.
|
||||
*
|
||||
* @param string $message Message to display.
|
||||
* @param string $type Type of notice - either error, success or notice.
|
||||
* @param array $data Additional data to pass.
|
||||
* @param string $group Optional. Group to categorize notices.
|
||||
*/
|
||||
private function add_notice( string $message, string $type, array $data = array(), string $group = '' ): void {
|
||||
if ( ! self::wc_session_exists() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $this->sanitize_type( $type );
|
||||
|
||||
$notice = $this->format_notice( $message, $data, $group );
|
||||
|
||||
$notices = WC()->session->get( self::WC_SESSION_KEY, array() );
|
||||
|
||||
if ( ! isset( $notices[ $type ] ) ) {
|
||||
$notices[ $type ] = array();
|
||||
}
|
||||
|
||||
$notices[ $type ][] = $notice;
|
||||
|
||||
WC()->session->set( self::WC_SESSION_KEY, $notices );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WC Session exists.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function wc_session_exists(): bool {
|
||||
return ! empty( WC()->session );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an info notice.
|
||||
*
|
||||
* @param string $message Message to display.
|
||||
* @param array $data Additional data to pass.
|
||||
* @param string $group Optional. Group to categorize notices.
|
||||
*/
|
||||
public function info( string $message, array $data = array(), string $group = '' ) {
|
||||
$this->maybe_add_notice( $message, StoreNoticeTypes::INFO, $data, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error notice.
|
||||
*
|
||||
* @param string $message Message to display.
|
||||
* @param array $data Additional data to pass.
|
||||
* @param string $group Optional. Group to categorize notices.
|
||||
*/
|
||||
public function error( string $message, array $data = array(), string $group = '' ) {
|
||||
$this->maybe_add_notice( $message, StoreNoticeTypes::ERROR, $data, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a success notice.
|
||||
*
|
||||
* @param string $message Message to display.
|
||||
* @param array $data Additional data to pass.
|
||||
* @param string $group Optional. Group to categorize notices.
|
||||
*/
|
||||
public function success( string $message, array $data = array(), string $group = '' ) {
|
||||
$this->maybe_add_notice( $message, StoreNoticeTypes::SUCCESS, $data, $group );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print all notices.
|
||||
*/
|
||||
public function print_notices(): void {
|
||||
$notices = self::get_notices();
|
||||
|
||||
if ( empty( $notices ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $notices as $type => $messages ) {
|
||||
foreach ( $messages as $notice ) {
|
||||
$formatted_message = $this->maybe_get_formatted_message( $notice['message'], $notice['data'] );
|
||||
|
||||
if ( wc_has_notice( $formatted_message, $type ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wc_add_notice( $formatted_message, $type );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all notices.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_notices(): array {
|
||||
return self::wc_session_exists() ? WC()->session->get( self::WC_SESSION_KEY, array() ) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all notices.
|
||||
*
|
||||
* @param string $group Optional. Group of notices to clear.
|
||||
*/
|
||||
public static function clear_notices( string $group = '' ): void {
|
||||
if ( ! self::wc_session_exists() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear all notices.
|
||||
if ( empty( $group ) ) {
|
||||
WC()->session->set( self::WC_SESSION_KEY, array() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$notices = WC()->session->get( self::WC_SESSION_KEY, array() );
|
||||
if ( ! is_array( $notices ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$updated_notices = array();
|
||||
|
||||
// Clear notices by group.
|
||||
foreach ( self::$valid_notice_types as $type ) {
|
||||
if ( empty( $notices[ $type ] ) || ! is_array( $notices[ $type ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $notices[ $type ] as $notice ) {
|
||||
if ( $notice['group'] === $group ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$updated_notices[ $type ][] = $notice;
|
||||
}
|
||||
}
|
||||
|
||||
WC()->session->set( self::WC_SESSION_KEY, $updated_notices );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe get formatted message.
|
||||
*
|
||||
* @param string $message Message to display.
|
||||
* @param string $data Additional data to pass.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function maybe_get_formatted_message( string $message, string $data = '' ): string {
|
||||
if ( ! empty( $data ) ) {
|
||||
$formatted_message = '<details><summary style="line-height:1.8;">' . $message . '</summary><div style="overflow: auto; max-height:50vh;"><pre style="font-size:0.8rem; line-height:1.4;">' . $data . '</pre></div></details>';
|
||||
} else {
|
||||
$formatted_message = $message;
|
||||
}
|
||||
|
||||
return $formatted_message;
|
||||
}
|
||||
}
|
||||
72
wp-content/plugins/woocommerce-services/src/Utils.php
Normal file
72
wp-content/plugins/woocommerce-services/src/Utils.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* General Automattic\WCServices utils.
|
||||
*
|
||||
* Provides utility functions useful for multiple parts of WCServices.
|
||||
*
|
||||
* @package Automattic\WCServices
|
||||
*/
|
||||
|
||||
namespace Automattic\WCServices;
|
||||
|
||||
use WC_Connect_Loader;
|
||||
|
||||
/**
|
||||
* Automattic\WCServices utils class.
|
||||
*/
|
||||
class Utils {
|
||||
/**
|
||||
* Get WooCommerce Services plugin version.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_wcservices_version() {
|
||||
return WC_Connect_Loader::get_wcs_version();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base URL for enqueuing assets.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_enqueue_base_url(): string {
|
||||
return trailingslashit( defined( 'WOOCOMMERCE_CONNECT_DEV_SERVER_URL' ) ? WOOCOMMERCE_CONNECT_DEV_SERVER_URL : WCSERVICES_PLUGIN_DIST_URL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin directory path.
|
||||
* This is a helper function to get the plugin directory path for either the main plugin or the WooCommerce plugin.
|
||||
*
|
||||
* @param bool $for_woocommerce Whether to get the path for the WooCommerce plugin.
|
||||
* @return string The plugin directory path.
|
||||
*/
|
||||
public static function get_plugin_path( $for_woocommerce = false ) {
|
||||
return $for_woocommerce ? plugin_dir_path( WC_PLUGIN_FILE ) : plugin_dir_path( WCSERVICES_PLUGIN_FILE );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static function get_file_version( string $file ): string {
|
||||
if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists( $file ) ) {
|
||||
return (string) filemtime( $file );
|
||||
}
|
||||
|
||||
return self::get_wcservices_version();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sanitized request data.
|
||||
*
|
||||
* @param string $key The key to get the data for.
|
||||
* @param string $default The default value to return if the key is not set.
|
||||
* @return string The sanitized data as a string.
|
||||
*/
|
||||
public static function get_sanitized_request_data( string $key, string $default = '' ): string {
|
||||
return sanitize_text_field( wp_unslash( $_REQUEST[ $key ] ?? $default ) );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user