跳转到主要内容

暴露你的数据

问题

您希望扩展 Mini-Cart、Cart 和 Checkout 模块,但需要使用一些 Store API 或上下文环境中不可用的自定义数据。您不想创建自己的 API 接口或 Ajax 操作,而是希望利用现有的 StoreAPI 调用。

解决方案

ExtendSchema 提供了将上下文自定义数据添加到 Store API 接口的可能性,例如 wc/store/cart 和 wc/store/cart/items 接口。这些数据会被限定在您的插件命名空间内,并受到保护,防止其他插件导致其功能异常。这些数据在所有前端过滤器和 slotFills 中都可用,供您使用。

基本用法

您可以通过注册两个函数,schema_callback 和 data_callback,在特定的接口命名空间中使用 ExtendSchema。ExtendSchema 将在执行时调用这些函数,并将相关数据传递给它们。

以下示例使用 Cart 接口,请参阅已传递的参数。

注意:请务必阅读下面的“注意事项”部分。

use Automattic\WooCommerce\StoreApi\Schemas\V1\CartSchema;

add_action('woocommerce_blocks_loaded', function() {
 woocommerce_store_api_register_endpoint_data(
	array(
		'endpoint' => CartSchema::IDENTIFIER,
		'namespace' => 'plugin_namespace',
		'data_callback' => 'my_data_callback',
		'schema_callback' => 'my_schema_callback',
		'schema_type' => ARRAY_A,
		)
	);
});


function my_data_callback() {
	return [
		'custom-key' => 'custom-value',
	];
}

function my_schema_callback() {
	return [
		'custom-key' => [
			'description' => __( 'My custom data', 'plugin-namespace' ),
			'type' => 'string',
			'readonly' => true,
		]
	];
}

数据回调函数和 Schema 回调函数也可以接收参数:


function my_cart_item_callback( $cart_item ) {
$product = $cart_item['data'];
	if ( is_my_custom_product_type( $product ) ) {
		$custom_value = get_custom_value( $product );
		return [
			'custom-key' => $custom_value,
		];
	}
}

注意事项

ExtendSchema 是一个共享实例

ExtendSchema 被存储为 API 和客户端(第三方开发者)之间的共享实例。因此,您不应该使用 new ExtendSchema 手动创建该类的实例,因为它可能无法正常工作。相反,您应该始终从 StoreApi 依赖注入容器中获取共享实例,例如:

$extend = StoreApi::container()->get( ExtendSchema::class );

请注意,依赖注入容器只有在 woocommerce_blocks_loaded 动作被触发之后才可用。因此,您应该将您的文件与该动作进行关联:

use Automattic\WooCommerce\StoreApi\StoreApi;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;

add_action( 'woocommerce_blocks_loaded', function() {
	$extend = StoreApi::container()->get( ExtendSchema::class );
	// 我的逻辑。
});

或者,您可以使用全局辅助函数:

  • woocommerce_store_api_register_endpoint_data( $args )
  • woocommerce_store_api_register_update_callback( $args )
  • woocommerce_store_api_register_payment_requirements( $args )
  • woocommerce_store_api_get_formatter( $name )

错误和致命错误对非管理员用户是静默的

如果您的回调函数 data_callback 和 schema_callback 抛出异常或错误,或者您传递了不正确的参数类型给 register_endpoint_data,那么该错误将被捕获并记录到 WooCommerce 错误日志中。如果当前用户是商店管理员或管理员,并且启用了 WP_DEBUG,则该错误将显示在前端。

回调函数应始终返回一个数组

为了减少破坏客户端代码或传递错误类型的可能性,并保持一致的 REST API 响应,诸如 data_callback 和 schema_callback 这样的回调函数应始终返回一个数组,即使该数组为空。

API 定义

  • ExtendSchema::register_endpoint_data: 用于将数据注册到自定义端点。它接受一个参数数组:
属性 类型 是否必须 描述
endpoint 字符串 是 您正在扩展的端点。建议您使用路由结构化数据类中的 ::IDENTIFIER 可用属性,以避免拼写错误。
namespace 字符串 是 您的插件命名空间,数据将在 Store API 响应中位于此命名空间下。
data_callback 回调函数 是 一个返回包含您数据的数组的回调函数。
schema_callback 回调函数 是 一个返回您的数据形状的回调函数。
schema_type 字符串 否 (默认值: ARRAY_A ) 您的数据类型。如果您正在添加一个对象(键 => 值),则应为 ARRAY_A。如果您正在添加一个项目列表,则应为 ARRAY_N。

整合所有内容

这是一个完整的示例,展示了如何在每个购物车项中注册与 WooCommerce 订阅相关的结构化数据(简化版)。 此示例使用 Formatters,这些是实用类,允许您格式化值,使其与 StoreAPI 兼容。

<?php
/**
 * WooCommerce 订阅 Extend Store API。
 *
 * 一个类,用于扩展公共 API,为每个订阅项添加相关的订阅数据。
 *
 * @package WooCommerce 订阅
 */
use Automattic\WooCommerce\StoreApi\StoreApi;
use Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema;
use Automattic\WooCommerce\StoreApi\Schemas\V1\CartItemSchema;

add_action( 'woocommerce_blocks_loaded', function() {
	$extend = StoreApi::container()->get( ExtendSchema::class );
	WC_Subscriptions_Extend_Store_Endpoint::init( $extend );
});

class WC_Subscriptions_Extend_Store_Endpoint {
	/**
	 * 存储 Rest Extending 实例。
	 *
	 * @var ExtendSchema
	 */
	private static $extend;

	/**
	 * 插件标识符,每个插件独一无二。
	 *
	 * @var string
	 */
	const IDENTIFIER = 'subscriptions';

	/**
	 * 启动类并挂载所需的数据。
	 *
	 * @param ExtendSchema $extend_rest_api ExtendSchema 类的实例。
	 *
	 * @since 3.1.0
	 */
	public static function init( ExtendSchema $extend_rest_api ) {
		self::$extend = $extend_rest_api;
		self::extend_store();
	}

	/**
	 * 注册实际数据到每个端点。
	 */
	public static function extend_store() {

		// 注册到 `cart/items`
		self::$extend->register_endpoint_data(
			array(
				'endpoint'        => CartItemSchema::IDENTIFIER,
				'namespace'       => self::IDENTIFIER,
				'data_callback'   => array( 'WC_Subscriptions_Extend_Store_Endpoint', 'extend_cart_item_data' ),
				'schema_callback' => array( 'WC_Subscriptions_Extend_Store_Endpoint', 'extend_cart_item_schema' ),
				'schema_type'       => ARRAY_A,
			)
		);
	}

	/**
	 * 将订阅产品数据注册到 cart/items 端点。
	 *
	 * @param array $cart_item 当前购物车项数据。
	 *
	 * @return array $item_data 注册的数据,如果条件不满足则返回空数组。
	 */
	public static function extend_cart_item_data( $cart_item ) {
		$product   = $cart_item['data'];
		$item_data = array(
			'billing_period'      => null,
			'billing_interval'    => null,
			'subscription_length' => null,
			'trial_length'        => null,
			'trial_period'        => null,
			'sign_up_fees'        => null,
			'sign_up_fees_tax'    => null,

		);
# 注册产品变体

本节描述如何处理注册产品变体。

## 注册产品变体

注册产品变体时,需要考虑以下因素:

*   **变体**:每个变体都必须具有唯一的标识符。
*   **结构化数据**:每个变体都必须具有有效的结构化数据。
*   **字符串**:产品名称和描述必须是有效的字符串。
*   **订阅**:如果产品是订阅产品,则必须设置订阅周期和间隔。
*   **注册**:每个用户都必须注册才能购买产品。
*   **下标**:产品价格必须使用正确的下标。
*   **只读**:某些产品属性是只读的,不能被修改。
*   **上下文**:产品信息必须在正确的上下文中显示。
*   **产品**:每个产品都必须具有唯一的标识符。
*   **格式**:产品价格必须使用正确的格式。
*   **长度**:产品名称和描述的长度必须在允许的范围内。
*   **注册**:用户必须注册才能购买产品。
*   **数值**:产品价格必须是有效的数值。
*   **合并**:如果产品包含多个变体,则必须将它们合并为一个产品。
*   **数据**:产品数据必须是有效的。
*   **编辑**:用户可以编辑某些产品属性。
*   **购物车**:用户可以将产品添加到购物车。
*   **项目**:每个产品都是一个项目。
*   **红色**:产品颜色可以是红色。

```php
if ( in_array( $product->get_type(), array( 'subscription', 'subscription_variation' ), true ) ) {
			$item_data = array_merge(
				array(
					'billing_period'      => WC_Subscriptions_Product::get_period( $product ),
					'billing_interval'    => (int) WC_Subscriptions_Product::get_interval( $product ),
					'subscription_length' => (int) WC_Subscriptions_Product::get_length( $product ),
					'trial_length'        => (int) WC_Subscriptions_Product::get_trial_length( $product ),
					'trial_period'        => WC_Subscriptions_Product::get_trial_period( $product ),
				),
				self::format_sign_up_fees( $product )
			);
		}

		return $item_data;
	}

	/**
	 * Register subscription product schema into cart/items endpoint.
	 *
	 * @return array Registered schema.
	 */
	public static function extend_cart_item_schema() {
		return array(
			'billing_period'      => array(
				'description' => __( 'Billing period for the subscription.', 'woocommerce-subscriptions' ),
				'type'        => array( 'string', 'null' ),
				'enum'        => array_keys( wcs_get_subscription_period_strings() ),
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
			'billing_interval'    => array(
				'description' => __( 'The number of billing periods between subscription renewals.', 'woocommerce-subscriptions' ),
				'type'        => array( 'integer', 'null' ),
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
			'subscription_length' => array(
				'description' => __( 'Subscription Product length.', 'woocommerce-subscriptions' ),
				'type'        => array( 'integer', 'null' ),
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
			'trial_period'        => array(
				'description' => __( 'Subscription Product trial period.', 'woocommerce-subscriptions' ),
				'type'        => array( 'string', 'null' ),
				'enum'        => array_keys( wcs_get_subscription_period_strings() ),
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
			'trial_length'        => array(
				'description' => __( 'Subscription Product trial interval.', 'woocommerce-subscriptions' ),
				'type'        => array( 'integer', 'null' ),
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
			'sign_up_fees'        => array(
				'description' => __( 'Subscription Product signup fees.', 'woocommerce-subscriptions' ),
				'type'        => array( 'string', 'null' ),
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
			'sign_up_fees_tax'    => array(
				'description' => __( 'Subscription Product signup fees taxes.', 'woocommerce-subscriptions' ),
				'type'        => array( 'string', 'null' ),
				'context'     => array( 'view', 'edit' ),
				'readonly'    => true,
			),
		);
	}
/**
	 * 格式化注册费用。
	 *
	 * @param \WC_Product $product 当前产品。
	 * @return array
	 */
	private static function format_sign_up_fees( $product ) {
		$fees_excluding_tax = wcs_get_price_excluding_tax(
			$product,
			array(
				'qty'   => 1,
				'price' => WC_Subscriptions_Product::get_sign_up_fee( $product ),
			)
		);

		$fees_including_tax = wcs_get_price_including_tax(
			$product,
			array(
				'qty'   => 1,
				'price' => WC_Subscriptions_Product::get_sign_up_fee( $product ),
			)
		);

		$money_formatter = self::$extend->get_formatter( 'money' );

		return array(
			'sign_up_fees'     => $money_formatter->format(
				$fees_excluding_tax
			),
			'sign_up_fees_tax' => $money_formatter->format(
				$fees_including_tax
				- $fees_excluding_tax
			),

		);
	}
}

格式化您的数据

您可能希望使用我们预先存在的格式化工具(Formatters),以确保您的数据以正确的格式通过 API。关于格式化工具的更多信息,请参阅 StoreApi 格式化工具 文档。