跳到主要内容

暴露你的数据

问题

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

解决方案

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

基本用法

您可以通过注册两个函数,schema_callbackdata_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_callbackschema_callback 抛出异常或错误,或者您传递了不正确的参数类型给 register_endpoint_data,那么该错误将被捕获并记录到 WooCommerce 错误日志中。如果当前用户是商店管理员或管理员,并且启用了 WP_DEBUG,则该错误将显示在前端。

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

为了减少破坏客户端代码或传递错误类型的可能性,并保持一致的 REST API 响应,诸如 data_callbackschema_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 格式化工具 文档