跳到主要内容

动态更新购物车

问题

您是一位扩展开发者,您的扩展在客户端输入(例如,购物者在购物车侧边栏的输入框中填写内容,然后点击一个按钮)的触发下,执行一些服务器端处理。

这种服务器端处理会导致购物车状态发生变化,您希望更新客户端购物车或结账模块中显示的数据。

您不能直接更新客户端购物车状态。这是为了防止功能出现问题的扩展意外地使用格式错误或无效的数据更新它,这会导致整个模块崩溃。

解决方案

ExtendSchema 提供了扩展注册回调函数的机制,这些函数将在客户端购物车或结账模块发出信号时执行。

WooCommerce Blocks 还提供一个名为 extensionCartUpdate 的前端函数,客户端代码可以调用它。这将向 cart/extensions 端点发送数据(您在调用 extensionCartUpdate 时指定)。当该端点被访问时,会执行所有相关的回调函数(基于传递给 extensionCartUpdate 的命名空间),然后将最新的服务器端购物车数据返回,并使用这些新数据更新模块。

基本用法

在您的扩展的服务器端集成代码中:

add_action('woocommerce_blocks_loaded', function() {
woocommerce_store_api_register_update_callback(
[
'namespace' => 'extension-unique-namespace',
'callback' => /* 在此处添加您的可调用函数 */
]
);
} );

在客户端:

const { extensionCartUpdate } = wc.blocksCheckout;
const { processErrorResponse } = wc.wcBlocksData;

extensionCartUpdate( {
namespace: 'extension-unique-namespace',
data: {
key: 'value',
another_key: 100,
third_key: {
fourth_key: true,
},
},
} ).then( () => {
// 购物车已更新。
} ).catch( ( error ) => {
// 处理错误。
processErrorResponse(error);
} );

需要注意的事项

扩展不能直接更新客户端购物车状态

您可能想知道为什么不能为您的扩展创建一个自定义的 AJAX 端点来更新购物车。如前所述,扩展不允许直接更新客户端购物车的状态,因为这样做不正确会导致整个模块崩溃,从而阻止用户继续结账。相反,您_必须_通过 extensionCartUpdate 函数来执行此操作。

对于给定的命名空间,只能注册一个回调函数

考虑到这一点,如果您的扩展程序有多个客户端交互,导致服务器端执行不同的代码路径,您可能希望通过 extensionCartUpdate 函数传递额外的 数据。例如,如果用户可以执行两个 操作,一个用于添加 折扣,另一个用于移除 折扣,您可能希望将一个名为 action 的键以及其他 数据 一起传递给 extensionCartUpdate 函数。然后在您的回调函数中,您可以检查此 价值 以区分应该执行哪个代码路径。

示例:

<?php
function add_discount() {
/* 在此处执行一些处理 */
}

function remove_discount() {
/* 在此处执行一些处理 */
}

add_action('woocommerce_blocks_loaded', function() {
woocommerce_store_api_register_update_callback(
[
'namespace' => 'extension-unique-namespace',
'callback' => function( $data ) {
if ( $data['action'] === 'add' ) {
add_discount( );
}
if ( $data['action'] === 'remove' ) {
remove_discount();
}
}
]
);
} );

如果您尝试在相同的命名空间下再次 注册,则先前 注册 的回调函数将被覆盖。

API 定义

PHP

ExtendSchema::register_update_callback: 用于注册一个回调函数,当 cart/extensions 接口接收到指定命名空间的数据时,该回调函数会被执行。它接收一个参数数组。

属性类型必需描述
namespacestring您的扩展的命名空间。 这用于确定应该执行哪个扩展的回调函数。
callbackCallablecart/extensions 接口接收到与提供的命名空间匹配的数据时,将要执行的函数/方法(或可调用对象)。 该可调用对象应该接受一个参数。 通过该参数传递给回调函数的数据将是一个数组,其中包含您选择传递的任何数据。 可调用对象不需要返回任何值,如果它返回了值,则该返回值将不被使用。

JavaScript

extensionCartUpdate: 用于通知系统,您希望执行已注册的回调函数,并向回调函数传递数据。它接受一个对象作为唯一的参数。

属性类型必需描述
namespacestring您的扩展程序的命名空间。 这用于确定应执行哪个扩展程序的的回调函数。
dataObject您想要传递给回调函数的数据。 data 键中的任何内容都将作为第一个(也是唯一)参数传递给您的回调函数,以关联数组的形式。
overwriteDirtyCustomerDataboolean是否覆盖客户端中的客户数据,使用从服务器返回的数据,即使该数据尚未推送到服务器。

综合应用

您是开发一个扩展程序的作者,该扩展程序允许购物者使用他们在您的网站上赚取的积分,以获得其订单的折扣。 存在一个文本字段,购物者可以在其中输入他们想要兑换的积分数量,还有一个提交按钮,用于应用兑换。

您的扩展程序使用 DiscountsMeta 插槽,将这些 UI 元素添加到购物车和结账块的侧边栏中。

有关如何使用插槽的更多信息,请参阅我们的 插槽和填充文档

实现后,侧边栏会添加一个控件,如下所示:

image

"兑换" 按钮

在您的 UI 中,您正在使用 React useState 变量跟踪购物者在 "输入金额" 框中输入的值。 在此示例中,该变量应称为 pointsInputValue

当 "兑换" 按钮被点击时,您需要告诉服务器要将多少积分应用于购物者的购物车,基于他们输入到框中的内容,应用相关的折扣,更新服务器端的购物车,然后将更新后的价格显示在客户端的侧边栏中。

为此,您需要使用 extensionCartUpdate 来告诉服务器您希望执行您的回调函数,并加载新的购物车状态到 UI 中。 按钮的 onClick 处理程序可能如下所示:

const { extensionCartUpdate } = window.wc.blocksCheckout;

const buttonClickHandler = () => {
extensionCartUpdate( {
namespace: 'super-coupons',
data: {
pointsInputValue,
},
} );
};

注册一个回调函数,当 cart/extensions 接口被访问时执行

到目前为止,我们还没有在 WooCommerce Blocks 中注册任何回调函数,因此,当 extensionCartUpdate 触发 cart/extensions 接口时,不会发生任何操作。

类似于向 Store API 添加数据(在 在 Store API 中暴露您的数据 中有更详细的描述),我们可以通过在 WooCommerce Blocks 中的 ExtendSchema 类上调用 register_update_callback 方法来添加回调函数。

我们编写了一个名为 redeem_points 的函数,该函数将折扣应用于 WooCommerce 购物车。 该函数不返回任何值。 请注意,此函数的实际实现不是本文档的重点,因此已省略。 重要的是要注意的是,它会修改 WooCommerce 购物车。

<?php
function redeem_points( $points ) {
/* 在此处进行一些处理,根据 $points 的值将折扣应用于 WC 购物车 */
}

add_action('woocommerce_blocks_loaded', function() {
woocommerce_store_api_register_update_callback(
[
'namespace' => 'super-coupons',
'callback' => function( $data ) {
redeem_points( $data['points'] );
},
]
);
} );

现在,该回调函数已注册,当按下按钮时,cart/extensions 接口将被访问,并且由于 namespacesuper-coupons,我们的 redeem_points 函数将被执行。 在此处理完成后,WooCommerce Blocks 将更新客户端购物车。