WooCommerce 文档 相关英文(Store/Blocks):WooCommerce Developer Docs (https://docs.cocobook.com/books/woocommerce-developer-docs) WooCommerce 官方文档中文稿,覆盖入门、功能、主题与扩展开发要点。 购物车令牌 购物车令牌可以替代基于 Cookie 的会话,用于无头环境下的购物车交互。 当使用 Cart-Token 时,不需要 随机数。 获取购物车令牌 对 /cart 接口的请求会返回一个 Cart-Token 头部,该头部包含一个令牌,该令牌可以在后续的请求中作为头部发送到 API 商店的购物车和结账接口,以标识购物车。 获取购物车令牌最快的方法是发送一个 GET 请求到 /wp-json/wc/store/v1/cart,并观察响应头部。 您应该在该头部中看到一个 Cart-Token。 如何使用 Cart-Token 要使用 Cart-Token,请将其包含在请求的头部中。 响应将包含与 Cart-Token 关联的会话的当前购物车状态。 示例: curl --header "Cart-Token: 12345" --request GET https://example-store.com/wp-json/wc/store/v1/cart 使用相同的方法,您可以使用 Cart-Token 在 /checkout 路由上进行结账。 Store API 设计原则 在扩展、创建或更新 Store API 的接口时,应考虑以下原则。 接口必须包含一个 明确定义的 JSON 结构化数据 每个接口/端点都需要特定的输入数据结构,并且应使用定义的、可预测的结构返回数据。 这在 JSON 结构化数据中定义,其中包含 API 可以返回的所有属性的完整列表,以及它可以接受的输入参数。 明确定义的结构化数据还提供了一层安全性,因为它使我们能够验证和清理发送到 API 的请求。 在定义结构化数据时,请参考 WordPress REST API 手册,其中记录了可用的属性和类型,以及 JSON 结构化数据标准。 此外: 属性应使用 snake_case 🐍 格式。 应避免使用含糊的术语,并且属性名称应尽量使用易于理解的语言,而不是 "WooCommerce" 术语或设置名称。 属性应使用美式英语定义,但字段的描述应进行本地化。 允许使用多种类型,例如,如果某个值不适用,可以使用 null 类型。 在可能的情况下,建议使用 sanitize_callback 和 validate_callback,以确保在处理请求之前,数据以正确的格式接收。 如果您在定义一致的结构化数据时遇到困难,则您的方法可能存在问题。 一个常见的实际例子是表示 文章标签。 可能会有人想在响应中使用别名 (Slug) 作为属性字段名: tags: [ "my-tag": { // ...标签数据 }, "my-other-tag": { // ...标签数据 } ] 但是,这在结构化数据中难以表示,并且对客户端来说不可预测。 更好的方法是使用一个数据数组,其中一个属性是别名: tags: [ { "slug": "my-tag", // ...标签数据 }, { "slug": "my-other-tag", // ...标签数据 } ] 接口应围绕具有单个类型结构化数据的资源进行设计 接口应围绕资源(名词)而不是操作(动词)进行设计。 接口还应仅返回由其结构化数据定义的单一类型的数据。 例如: 接口 资源类型 预期数据 wc/store/v1/cart 购物车 一个购物车对象 wc/store/v1/cart/items 购物车商品 购物车商品对象的列表 wc/store/v1/products 产品 产品对象的列表 wc/store/v1/products/1 产品 一个产品对象 在 Store API 中,有两个值得注意的例外情况,即 错误 和 购物车操作。 错误处理 错误,包括验证错误,应该返回一个错误响应码(4xx 或 5xx)和一个 WP_Error 对象。 AbstractRoute 类将负责将 WP_Error 对象转换为有效的 JSON 响应。 错误消息应该进行本地化,但不需要使用面向客户的语言(客户端应该使用给定的错误码来创建必要的面向客户的提示)。 错误码应该以 woocommerce_rest_ 为前缀。 购物车操作 某些端点设计用于避免客户端需要进行多次 API 调用。这纯粹是为了方便。 例如, wc/store/v1/cart/add-item 端点接受一个数量和一个产品 ID,但返回完整的购物车对象,而不是仅仅更新的项目列表。 暴露的数据必须属于当前用户或为非敏感数据 资源,包括客户和订单数据,应该仅反映当前会话。不要返回其他客户的数据,因为这会违反隐私和安全。 允许在响应中包含商店数据,例如商店货币的 设置,但应避免 私有或敏感数据。为了允许更广泛地访问数据,您必须使用经过身份验证的 WC REST API。 从 API 返回的数据不应该进行 转义(这由客户端负责进行渲染),但应该进行清理。例如,HTML 应该通过 wp_kses_post 进行处理。 客户端有责任正确地转义来自 API 的数据,但我们应该尽量避免返回可能不安全的数据。 资源集合应该进行分页 大量的数据应该进行分页,以避免对 服务器 造成过载。例如,返回产品集合。 使用响应头 X-WP-Total、 X-WP-TotalPages 和 Link 来指示 可用 的资源。 使用参数 page 和 per_page 来检索特定的页面。 per_page 的最大允许值为 100。 API 回复应使用标准的 HTTP 状态码 在返回内容时,应使用有效的 HTTP 回复码,例如: 200 OK 用于成功的回复(这是默认的回复码)。 201 Created 用于创建资源,例如,添加新的购物车商品或应用新的优惠券。 204 No Content 用于成功的删除操作。 400 Bad Request 当缺少必需的参数时。 403 Forbidden 当请求不允许时,例如,如果提供的安全随机数无效。 404 Not Found 如果资源不存在。 409 Conflict 如果资源无法更新,例如,如果购物车中的某个内容无效并被删除。 关于 DELETE 请求的说明:在 WordPress REST API 中,一种常见的模式是返回已删除的对象。在 Store API 的情况下,我们选择返回一个空回复,并使用状态码 204 No Content,这更有效。 完整的 HTTP 状态码列表可以在这里找到。 应该尽可能避免破坏性变更 Store API 通过使用结构化数据与 API 消费者建立契约。除非绝对必要,否则不应破坏此契约。如果必须进行破坏性变更,则需要发布 Store API 的新版本。 破坏性变更是指任何更改现有结构化数据格式、删除结构化数据属性、删除现有路由或对任何已公开且可能已被消费者使用的内容进行向后不兼容的更改。可以通过弃用现有属性而不是删除它们,或者弃用路由并将它们替换为不同的路由来避免破坏性变更,如果需要进行重大更改。 非破坏性变更始终允许,而无需增加 API 版本。以下是一些示例: 向结构化数据添加新的属性。 添加新的路由、端点、方法。 添加可选的请求参数。 重新排序回复字段。 只有当错误修复导致向后不兼容的更改时,版本才会增加。除非存在需要回溯修复的安全问题,否则不会将修复回滚到过去的 API 版本。 随机数 (Nonce) 随机数是用于验证请求来源和意图的数字,以实现安全目的。 您可以阅读更多关于 WordPress 代码库中的随机数 的信息。 需要使用随机数的 API 接口 对 /cart 接口的 POST 请求以及对所有 /checkout 接口的请求都需要使用随机数才能正常工作。 如果未提供有效的随机数,将返回错误响应,除非您正在使用 购物车令牌 代替。 通过请求发送随机数 随机数包含在请求头中。 创建一个名为 Nonce 的请求头。 API 将会验证此头。 示例: curl --header "Nonce: 12345" --request GET https://example-store.com/wp-json/wc/store/v1/checkout 在成功发送请求后,将发送一个更新后的 Nonce 头,客户端需要将其存储并更新,以便进行后续请求。 从 WordPress 生成安全随机数 必须使用 wp_create_nonce 函数,并使用键 wc_store_api 来创建随机数。 wp_create_nonce( 'wc_store_api' ) 没有其他机制可以用于创建随机数。 开发阶段禁用随机数验证 如果您想在不提供随机数的情况下测试 REST 接口,可以使用以下过滤器: add_filter( 'woocommerce_store_api_disable_nonce_check', '__return_true' ); 如果 woocommerce_store_api_disable_nonce_check 的值为 true,则会绕过随机数验证。 注意:这只应在不重要的安全性的开发环境中进行。 请勿在生产环境启用此功能。 Store API 接口的限流 限流 功能现已适用于 Store API 接口。这是一个可选功能,默认情况下是禁用的。可以通过遵循 以下说明 来启用它。 其主要目的是防止对接口的滥用,以及避免因过多的调用而导致运行 Store 的服务器性能下降。 限流跟踪由以下方式控制: 用户 ID(已登录用户)、 IP 地址(未认证的请求),或者通过过滤器定义的逻辑来识别和分组请求。 它还提供标准的支持,可以在代理、负载均衡器等环境中使用。这也是一个可选功能,默认情况下是禁用的。 UI 控制 目前,此功能只能通过 woocommerce_store_api_rate_limit_options 过滤器进行控制。要通过 UI 进行控制,可以使用以下社区插件:WooCommerce 限流 UI 插件。 结账限流 您可以通过以下步骤,在 WooCommerce -> 设置 -> 高级 -> 功能 中启用“限流结账模块和 Store API”,从而为结账页面提交订单和 POST /checkout 接口启用限流。 通过 UI 启用后,限流仅适用于 POST /checkout 接口以及结账模块的提交订单流程。限制为每 60 秒最多 3 个请求。 限制信息 默认情况下,可以在 10 秒的时间范围内最多发出 25 个请求。这些限制可以通过 选项过滤器 进行修改。 受限流影响的方法 仅 POST 请求受到限流的影响。使用 X-HTTP-Method-Override 头部(例如,通过 wp.apiFetch 发送的 PUT、 PATCH 请求)的请求不受到限流的影响。 限流选项过滤器 提供一个过滤器,用于设置限流选项: add_filter( 'woocommerce_store_api_rate_limit_options', function() { return [ 'enabled' => false, // 启用/禁用限流。默认:false 'proxy_support' => false, // 启用/禁用代理支持。默认:false 'limit' => 25, // 每段时间内的请求限制。默认:25 'seconds' => 10, // 时间范围(秒)。默认:10 ]; } ); 代理标准支持 如果 Store 运行在代理、负载均衡器、缓存服务、CDN 等环境,则支持通过标准 IP 转发头部来按 IP 地址进行限流,这些头部包括: X_REAL_IP| CLIENT_IP:常用的自定义实现,用于简化获取请求的原始 IP 地址 X_FORWARDED_FOR:用于识别原始 IP 地址的事实标准头部,文档 X_FORWARDED:文档,RFC 7239 此功能默认情况下是禁用的。 通过自定义请求指纹启用速率限制 对于更高级的用例,您可以启用基于自定义指纹的速率限制。 这允许自定义实现来分组请求,而无需依赖已登录的用户 ID 或 IP 地址。 自定义基本示例,用于按 User-Agent 和 Accept-Language 组合分组请求 add_filter( 'woocommerce_store_api_rate_limit_id', function() { $accept_language = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : ''; return md5( wc_get_user_agent() . $accept_language ); } ); 限制使用信息的可观察性 当前限制信息可以通过自定义响应头进行观察: RateLimit-Limit 每段时间允许的最大请求数. RateLimit-Remaining 当前时间内剩余的请求数. RateLimit-Reset 下一个时间段重置的 Unix 时间戳. RateLimit-Retry-After 直到请求可以再次被接受的秒数。仅在达到限制时显示. 响应头示例 RateLimit-Limit: 5 RateLimit-Remaining: 0 RateLimit-Reset: 1654880642 RateLimit-Retry-After: 28 跟踪限制滥用 这使用了一个修改后的 wc_rate_limit 表,其中添加了一个额外的 remaining 列,用于跟踪在任何给定的请求窗口内的请求计数。 为了便于扩展,实现了一个自定义动作 woocommerce_store_api_rate_limit_exceeded,用于跟踪此类滥用行为。 自定义跟踪使用示例 add_action( 'woocommerce_store_api_rate_limit_exceeded', function ( $offending_ip, $action_id ) { /* 自定义跟踪实现 */ } ); 购物车令牌 购物车令牌可以替代基于 Cookie 的会话,用于无头环境下的购物车交互。 当使用 Cart-Token 时,不需要 随机数。 获取购物车令牌 对 /cart 接口的请求会返回一个 Cart-Token 头部,该头部包含一个令牌,该令牌随后可以作为请求头部发送到 API 商店的购物车和结账接口,以标识购物车。 获取购物车令牌最快的方法是发送一个 GET 请求到 /wp-json/wc/store/v1/cart,并观察响应头部。 您应该在该头部中看到一个 Cart-Token。 如何使用 Cart-Token 要使用 Cart-Token,请将其包含在请求的头部中。 响应将包含与 Cart-Token 关联的会话中的当前购物车状态。 示例: curl --header "Cart-Token: 12345" --request GET https://example-store.com/wp-json/wc/store/v1/cart 使用相同的方法,您可以使用 Cart-Token 在 /checkout 路由上进行结账。 Store API 接口的速率限制 速率限制 适用于 Store API 接口。这是一个可选功能,默认情况下是禁用的。可以通过以下说明启用它。 其主要目的是防止对接口的滥用,以及避免因过多的调用而导致运行 Store 的服务器性能下降。 速率限制的跟踪由以下方式控制: 用户 ID(已登录用户)、 IP 地址(未认证的请求),或者通过过滤器定义的逻辑来识别和分组请求。 它还提供标准的支持,可以在代理服务器、负载均衡器等环境中运行。这也是一个可选功能,默认情况下是禁用的。 UI 控制 目前,此功能仅通过 woocommerce_store_api_rate_limit_options 过滤器进行控制。要通过 UI 进行控制,可以使用以下社区插件:Rate Limiting UI for WooCommerce。 结账速率限制 您可以启用结账“提交订单”操作和 POST /checkout 接口的速率限制,方法是通过 UI 转到 WooCommerce -> 设置 -> 高级 -> 功能,并启用“Rate limiting Checkout block and Store API”。 通过 UI 启用后,速率限制仅适用于 POST /checkout 接口和结账模块的“提交订单”流程。限制为每 60 秒最多 3 个请求。 限制信息 默认情况下,可以在 10 秒的时间范围内最多发出 25 个请求。这些可以通过选项过滤器进行更改。 受速率限制影响的方法 仅对 POST 请求进行速率限制。使用 X-HTTP-Method-Override 头部(例如,通过 wp.apiFetch 发送的 PUT、 PATCH 请求)的请求不受到速率限制。 速率限制选项过滤器 提供一个过滤器,用于设置速率限制的选项: add_filter( 'woocommerce_store_api_rate_limit_options', function() { return [ 'enabled' => false, // 启用/禁用速率限制。默认:false 'proxy_support' => false, // 启用/禁用代理支持。默认:false 'limit' => 25, // 每段时间内的请求限制。默认:25 'seconds' => 10, // 时间范围(秒)。默认:10 ]; } ); 代理标准支持 如果 Store 运行在代理服务器、负载均衡器、缓存服务、CDN 等之后,通过标准的 IP 转发头来限制基于 IP 的访问是支持的,这些头包括: X_REAL_IP| CLIENT_IP 自定义的常用实现,用于简化获取请求的源 IP 地址 X_FORWARDED_FOR 用于标识源 IP 地址的事实标准头,文档 X_FORWARDED 文档, RFC 7239 默认情况下,此功能是禁用的。 启用基于请求自定义指纹的速率限制 对于更高级的用例,您可以启用基于自定义指纹的速率限制。 这允许自定义实现来分组请求,而无需依赖已登录的用户 ID 或 IP 地址。 自定义基本示例,用于通过 User-Agent 和 Accept-Language 组合来分组请求 add_filter( 'woocommerce_store_api_rate_limit_id', function() { $accept_language = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : ''; return md5( wc_get_user_agent() . $accept_language ); } ); 限制使用信息的可观察性 当前限制信息可以通过自定义响应头进行观察: RateLimit-Limit 每个时间段的最大请求数。 RateLimit-Remaining 当前时间段内可用的请求数。 RateLimit-Reset 下一个时间段重置的 Unix 时间戳。 RateLimit-Retry-After 直到请求可以再次被允许的时间,以秒为单位。仅在达到限制时显示。 响应头示例 RateLimit-Limit: 5 RateLimit-Remaining: 0 RateLimit-Reset: 1654880642 RateLimit-Retry-After: 28 跟踪限制滥用 此功能使用修改后的 wc_rate_limit 表,其中包含一个额外的 remaining 列,用于跟踪在任何给定的请求窗口内的请求计数。 已实现一个自定义动作 woocommerce_store_api_rate_limit_exceeded,以实现可扩展性,用于跟踪此类滥用行为。 自定义跟踪使用示例 add_action( 'woocommerce_store_api_rate_limit_exceeded', function ( $offending_ip, $action_id ) { /* 自定义跟踪实现 */ } ); 可扩展的 API 接口 Store API 的某些接口可以通过名为 ExtendSchema 的类进行扩展。 这允许您自定义 Store API 返回的数据(包括结构化数据),以便您的应用程序或插件可以消费这些数据。 有关扩展 Store API 的更多信息,您可能还对以下内容感兴趣: 如何使用 ExtendSchema 将您的数据添加到 Store API 如何添加新的接口 以下是可以使用 ExtendSchema 进行扩展的可用接口列表,以及一些示例用例。 产品 主要的 wc/store/products 接口可以通过 ExtendSchema 进行扩展。 数据通过每个 product 在响应数组中的 extensions 键提供。 可以使用 ProductSchema::IDENTIFIER 键来扩展此接口。 对于此接口,您的 data_callback 回调函数会传递 $product 作为参数。 您的 schema_callback 函数不传递任何其他参数;所有产品应共享相同的结构化数据。 用例 此接口适用于添加有关单个产品的附加数据。 这可能是一些元数据、额外的定价,或任何其他支持产品页面上自定义组件的数据。 示例 woocommerce_store_api_register_endpoint_data( array( 'endpoint' => ProductSchema::IDENTIFIER, 'namespace' => 'my_plugin_namespace', 'data_callback' => function( $product ) { return array( 'my_meta_data' => get_post_meta( $product->get_id(), 'my_meta_data', true ), ); }, 'schema_callback' => function() { return array( 'properties' => array( 'my_meta_data' => array( 'type' => 'string', ), ), ); }, 'schema_type' => ARRAY_A, ) ); 购物车 主要的 wc/store/cart 接口可以通过 ExtendSchema 进行扩展。 数据通过响应中的 extensions 键提供。 可以使用 CartSchema::IDENTIFIER 键来扩展此接口。 对于此接口,您的 data_callback 和 schema_callback 函数不传递任何其他参数。 用例 此接口适用于向购物车页面添加附加数据,例如,有关购物车中商品的额外数据,或支持购物车页面上显示的自定义组件所需的一切。 示例 woocommerce_store_api_register_endpoint_data( array( 'endpoint' => CartSchema::IDENTIFIER, 'namespace' => 'my_plugin_namespace', 'data_callback' => function() { return array( 'foo' => 'bar', ); }, 'schema_callback' => function() { return array( 'properties' => array( 'foo' => array( 'type' => 'string', ), ), ); }, 'schema_type' => ARRAY_A, ) ); 购物车商品 wc/store/cart/items 接口,该接口也可用作 wc/store/cart 内部的 items 键。 数据将包含在 items 数组的每个商品中。 该接口可以通过 CartItemSchema::IDENTIFIER 键进行扩展。 对于此接口,您的 data_callback 回调函数将接收 $cart_item 作为参数。 您的 schema_callback 函数不接收任何其他参数;所有购物车商品应使用相同的结构化数据。 用途 此接口适用于添加有关单个购物车商品的附加数据。 这可能是一些元数据、附加价格,或任何其他支持购物车页面上自定义组件或扩展的功能。 示例 woocommerce_store_api_register_endpoint_data( array( 'endpoint' => CartItemSchema::IDENTIFIER, 'namespace' => 'my_plugin_namespace', 'data_callback' => function( $cart_item ) { $product = $cart_item['data']; return array( 'my_meta_data' => get_post_meta( $product->get_id(), 'my_meta_data', true ), ); }, 'schema_callback' => function() { return array( 'properties' => array( 'my_meta_data' => array( 'type' => 'string', ), ), ); }, 'schema_type' => ARRAY_A, ) ); 结账 wc/store/checkout 接口可以通过 ExtendSchema 进行扩展。 响应中的 extensions 键包含可用的附加数据。 该接口可以通过 CheckoutSchema::IDENTIFIER 键进行扩展。 对于此接口,您的 data_callback 和 schema_callback 函数不接收任何其他参数。 用途 此接口适用于向结账页面添加附加数据,例如自定义支付方法,该方法需要从用户或服务器收集额外的数据。 ⚠ 重要:不要在此接口中泄露任何敏感数据,因为它对公众开放。 这包括用于支付服务的私钥。 示例 woocommerce_store_api_register_endpoint_data( array( 'endpoint' => CheckoutSchema::IDENTIFIER, 'namespace' => 'my_plugin_namespace', 'data_callback' => function() { return array( 'foo' => 'bar', ); }, 'schema_callback' => function() { return array( 'properties' => array( 'foo' => array( 'type' => 'string', ), ), ); }, 'schema_type' => ARRAY_A, ) ); 添加字段并传递值 本文档描述了开发者如何将一个输入字段插入到结账块中,并将该字段的值传递给 Store API,以便在处理结账时可用。 概述 开发者可以通过添加新的内部块并处理额外的数据,来扩展结账块,从而通过结账 POST 请求进行处理。 这涉及到利用古腾堡和 WooCommerce Blocks 提供的可扩展性接口。 我们的教程中对这一点进行了更详细的说明:教程:扩展 WooCommerce 结账块以添加自定义配送选项。 前置条件 了解 React 和古腾堡块编辑器。 熟悉 WooCommerce Blocks 的可扩展性接口和 Store API。 逐步指南 1. 设置您的开发环境 确保您的项目中包含以下文件: index.js: Webpack 的入口点,用于导入和注册块类型。 edit.js: 处理在编辑器界面中渲染块。 block.json: 提供块的元数据和配置。 block.js: 管理块的状态和用户交互。 frontend.js: 注册结账块组件以在前端使用。 请参考此教程,了解向结账块添加自定义配送选项的示例。 2. 将新的字段块添加到结账块中 要将字段块添加到结账块中,您需要在块的 block.json 文件中添加以下条目: "parent": [ "woocommerce/checkout-shipping-methods-block" ], "attributes": { "lock": { "type": "object", "default": { "remove": true, "move": true } } } lock 属性 是一个对象,用于控制是否可以删除或移动该块。 默认情况下,lock 属性设置为允许删除和移动块。 但是,通过修改 lock 属性,您可以“强制”块不可删除。 例如,您可以将 remove 和 move 属性都设置为 false,以防止删除或移动该块。 parent 属性 指定此块应嵌套在哪个父块中。 它确定块将在哪里渲染。 在我们的示例中,该块是 woocommerce/checkout-shipping-methods-block 的子块。 这意味着您的块将在 woocommerce/checkout-shipping-methods-block 中渲染。 如果不需要配送方法块,则您的块将不会渲染。 3. 设置自定义结账数据 我们可以将添加的字段数据设置为 setExtensionData 函数,以便在处理订单时将其发送到 wc/store/checkout 端点: setExtensionData( 'namespace-of-your-block', 'key-of-your-data', value ); 参数 namespace string - 您的块的命名空间。 key string - 您的数据的键。 value any - 您的数据的价值。 工作原理 setExtensionData 通过 props 传递给内部块。 它更新 wc/store/checkout 数据存储中的 extensionData 键。 当向结账端点发送 POST 请求时,此键作为请求体的一部分传递。 代码示例 // block.js export const Block = ( { checkoutExtensionData, extensions } ) => { /** * `setExtensionData` 会使用提供的值更新 `wc/store/checkout` 数据存储。 * 它可以用于在提交结账表单时,将客户端数据传递到服务器。 */ const { setExtensionData } = checkoutExtensionData; } // ... 一些代码 useEffect( () => { /** * 此代码应使用 `setExtensionData` 来更新结账数据存储中 `namespace-of-your-block` 命名空间下的 `key-of-your-data` 键。 */ setExtensionData( 'namespace-of-your-block', 'key-of-your-data', value ); }, [ setExtensionData, value ] ); 截图 Redux Dev tool 的截图,显示在调用 setExtensionData 之前和之后的的数据存储: 之前 之后 4. 处理结账 POST 请求 为了处理添加的字段数据,我们需要扩展 Store API,以便告知它期望接收额外的数据。更多详情请参阅 在 Store API 中暴露您的数据。 代码示例 我们将使用以下 PHP 文件作为示例: custom-inner-block-blocks-integration.php 文件:当使用结账 blocks 时,在前端注册脚本、样式和数据。 更多详情请参考 IntegrationInterface 文档。 use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface; /** * 用于与 WooCommerce Blocks 集成的类 */ class Custom_Inner_Block_Blocks_Integration implements IntegrationInterface { /** * 集成的名称。 * * @return string */ public function get_name() { return 'new-field-block'; } /** * 调用时,会执行任何与集成相关的初始化/设置。 */ public function initialize() { // ... 这里有一些代码:(例如,初始化函数,用于注册脚本和样式,以及其他指令) } // ... 其他函数 } custom-inner-block-extend-store-endpoint.php 文件:扩展 Store API,并添加钩子以保存和显示您的新字段块的说明。 默认情况下,此功能不会将自定义块中的数据保存到任何地方,但您可以添加自己的逻辑将数据保存到数据库。 use Automattic\WooCommerce\Blocks\Package; use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CartSchema; use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CheckoutSchema; /** * 您的新字段块扩展 Store API。 */ class Custom_Inner_Block_Extend_Store_Endpoint { /** * 存储 Rest 扩展实例。 * * @var ExtendRestApi */ private static $extend; /** * 插件标识符,每个插件独一无二。 * * @var string */ const IDENTIFIER = 'new-field-block'; /** * 启动类和所需的钩子。 * */ public static function init() { self::$extend = Automattic\WooCommerce\StoreApi\StoreApi::container()->get( Automattic\WooCommerce\StoreApi\Schemas\ExtendSchema::class ); self::extend_store(); } /** * 将实际数据注册到每个端点。 */ public static function extend_store() { if ( is_callable( [ self::$extend, 'register_endpoint_data' ] ) ) { self::$extend->register_endpoint_data( [ 'endpoint' => CheckoutSchema::IDENTIFIER, 'namespace' => self::IDENTIFIER, 'schema_callback' => [ 'Custom_Inner_Block_Extend_Store_Endpoint', 'extend_checkout_schema' ], 'schema_type' => ARRAY_A, ] ); } } 新字段块 /** * 将新的字段块结构化数据注册到结账端点。 * * @return array 注册的结构化数据。 * */ public static function extend_checkout_schema() { return [ 'Value_1' => [ 'description' => '字段的描述', 'type' => 'string', // ... 字段的类型,应该是一个字符串 'context' => [ 'view', 'edit' ], // ... 字段的上下文,应该是一个包含 'view' 和 'edit' 的数组 'readonly' => true, // ... 字段是否为只读,应该是一个布尔值 'optional' => true, // ... 字段是否为可选,应该是一个布尔值 ], // ... 其他值 ]; } } - `new-field-block.php` 文件:主插件文件,加载 `custom-inner-block-blocks-integration.php` 和 `custom-inner-block-extend-store-endpoint.php` 文件。 ```php register( new Custom_Inner_Block_Blocks_Integration() ); } ); } ); // ... 一些代码 以下是一个示例,来自我们的 教程,说明如何在处理结账时获取此自定义字段的数据。 此示例来自 shipping-workshop-blocks-integration.php 文件。 完整的代码可以在此 GitHub 仓库 中找到。 # 配送说明保存 本节介绍如何保存配送说明。 我们使用一个钩子,即 `woocommerce_store_api_checkout_update_order_from_request` 操作,该操作会将配送工作坊的替代配送说明更新到订单元数据中。 该钩子的文档位于:https://github.com/woocommerce/woocommerce-blocks/blob/b73fbcacb68cabfafd7c3e7557cf962483451dc1/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_store_api_checkout_update_order_from_request ```php private function save_shipping_instructions() { /** * We write a hook, using the `woocommerce_store_api_checkout_update_order_from_request` action * that will update the order metadata with the shipping-workshop alternate shipping instruction. * * The documentation for this hook is at: https://github.com/woocommerce/woocommerce-blocks/blob/b73fbcacb68cabfafd7c3e7557cf962483451dc1/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_store_api_checkout_update_order_from_request */ add_action( 'woocommerce_store_api_checkout_update_order_from_request', function( \WC_Order $order, \WP_REST_Request $request ) { $shipping_workshop_request_data = $request['extensions'][$this->get_name()]; $alternate_shipping_instruction = $shipping_workshop_request_data['alternateShippingInstruction']; $other_shipping_value = $shipping_workshop_request_data['otherShippingValue']; $order->update_meta_data( 'shipping_workshop_alternate_shipping_instruction', $alternate_shipping_instruction ); $order->save(); }, 10, 2 ); } 说明: woocommerce_store_api_checkout_update_order_from_request:这是一个操作钩子,用于在结账更新订单时执行自定义操作。 \WC_Order $order:表示订单对象。 \WP_REST_Request $request:表示请求对象。 $request['extensions'][$this->get_name()]:从请求中获取扩展数据。 $order->update_meta_data():更新订单的元数据。 $order->save():保存订单。 使用方法: 确保已安装并激活相应的扩展。 在 checkout 页面,用户可以输入替代配送说明。 当用户完成结账时,替代配送说明将被保存到订单的元数据中。 注意事项: 请确保您的扩展与 WooCommerce API 兼容。 在更新订单元数据之前,请务必进行数据验证。 其他信息: 您可以在 Store 的 Order 详情页面查看保存的配送说明。 Data 存储在订单的元数据中。 如果需要修改保存的 Value,请使用 API 或 Hooks。 请定期 check 您的 API 和 Extensions,以确保其正常运行。 如果遇到问题,请联系 Developers 寻求帮助。 Shipping 信息将影响 Shipping 费用。 Actions 决定了订单的处理流程。 Request 包含了用户提交的数据。 Date 记录了订单的创建和更新时间。 Save 操作会将数据持久化到数据库。 Lock 功能可以防止多个用户同时修改订单。 Shop 平台提供各种 购物 体验。 Document 提供了详细的使用说明。 API 提供了编程接口。 Hooks 允许您自定义 WooCommerce 的行为。 ## 结论 通过遵循以上步骤,您可以新增和处理新的字段区块,从而在 WooCommerce 结账区块中添加自定义的配送选项。有关完整实现和更多例子,请参考提供的 [教程](https://developer.woocommerce.com/2023/08/07/extending-the-woocommerce-checkout-block-to-add-custom-shipping-options/) 和相应的 [GitHub 仓库](https://github.com/woocommerce/wceu23-shipping-workshop-final/)。 暴露你的数据 问题 您希望扩展 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 兼容。 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 格式化工具 文档。 可用的格式化器 Formatters 是实用类,允许您格式化值,使其与 Store API 兼容。 默认格式化器处理诸如货币金额、货币信息或 HTML 之类的数值。 建议您在扩展 Store API 时使用这些格式化器。 为什么格式化器很有用? 使用格式化器实用程序返回某些类型的数据,可以确保您的自定义数据与 Store API 的其他接口保持一致和兼容。 它们还处理任何可能影响数据格式化的商店特定设置,例如货币设置。 Store API 包含以下格式化器: Money Currency HTML 如何使用格式化器 要获取格式化器,可以使用 ExtendSchema 类的 get_formatter 方法。 此方法接受一个字符串,即您想要使用的格式化器的名称。 get_formatter('money'); // 用于 MoneyFormatter get_formatter('html'); // 用于 HtmlFormatter get_formatter('currency'); // CurrencyFormatter 这将返回一个 FormatterInterface 对象,该对象具有 format 方法。 format 方法的签名如下: format( $value, array $options = [] ); 只有 MoneyFormatter 的行为可以通过 $options 参数进行控制。 此参数是可选的。 实际示例 假设我们要通过 API 返回一些额外的价格数据。 我们希望以美分形式返回价格,以及商店的货币数据。 我们可以使用 MoneyFormatter 和 CurrencyFormatter 来实现此目的。 首先,我们需要确保可以访问格式化器类。 我们可以使用 use 关键字来实现: use Automattic\WooCommerce\StoreApi\StoreApi; use Automattic\WooCommerce\StoreApi\Utilities\ExtendSchema; $extend = StoreApi::container()->get( ExtendSchema::class ); $my_custom_price = $extend->get_formatter( 'money' )->format( '10.00', [ 'rounding_mode' => PHP_ROUND_HALF_DOWN, 'decimals' => 2 ] ); $price_response = $extend->get_formatter( 'currency' )->format( [ 'price' => $my_custom_price, ] ); 上述代码将使 $price_response 设置为: [ 'price' => '1000' 'currency_code' => 'GBP' 'currency_symbol' => '£' 'currency_minor_unit' => 2 'currency_decimal_separator' => '.' 'currency_thousand_separator' => ',' 'currency_prefix' => '£' 'currency_suffix' => '' ] MoneyFormatter [MoneyFormatter](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/src/StoreApi/Formatters/MoneyFormatter.php) 类可用于使用商店的 设置 格式化 货币 价值。 商店的 设置 可以通过将 选项 传递给此格式化器的 format 方法 来覆盖。 为了避免浮点数舍入错误,返回值以“分”为单位。 因此,在使用此格式化器时,您很可能还会使用 [CurrencyFormatter](#currencyformatter) 同时返回 货币 数据,以便 API 的使用者能够以预期的 格式 显示 价值。 参数 参数 类型 描述 $value number 要格式化为 货币 值的数值。 $options array 应该包含两个键, decimals,它应该是一个 integer。 $options['decimals'] number 用于控制 货币 值中应显示多少位小数。 默认为商店的 设置。 $options['rounding_mode'] number 用于确定如何对 货币 值进行四舍五入。 这应该是 PHP 四舍五入模式之一,如 PHP round() 文档 中所述。 默认为 PHP_ROUND_HALF_UP。 示例用法和返回值 get_formatter( 'money' )->format( 10.443, [ 'rounding_mode' => PHP_ROUND_HALF_DOWN, 'decimals' => 2 ] ); 返回 1044 CurrencyFormatter 这个格式化器接收一个价格数组,并返回相同的数组,但附加了货币数据。添加的货币数据如下: 键 类型 描述 currency_code string 货币的字符串表示,例如:GBP 或 USD currency_symbol string 货币的符号,例如:£ 或 $ currency_minor_unit number 货币显示的十进制位数 currency_decimal_separator string 用于分隔货币中整数部分和小数部分的字符串。 currency_thousand_separator string 用于分隔货币中千位数的字符串,例如:£10,000 或 €10.000 currency_prefix string 应该出现在货币值之前的字符串。 currency_suffix string 应该出现在货币值之后的字符串。 然后,客户端/消费者可以使用这些数据,根据商店的设置正确地格式化价格。重要:传递给此格式化器的价格数组应该已经处于货币格式,因此您应该首先使用 MoneyFormatter。 参数 参数 类型 描述 $value number[] 要与商店的货币设置合并的价格数组 示例用法和返回的值 get_formatter( 'currency' )->format( [ 'price' => 1800, 'regular_price' => 1800, 'sale_price' => 1800, ] ); 返回 'price' => '1800' 'regular_price' => '1800' 'sale_price' => '1800' 'price_range' => null 'currency_code' => 'GBP' 'currency_symbol' => '£' 'currency_minor_unit' => 2 'currency_decimal_separator' => '.' 'currency_thousand_separator' => ',' 'currency_prefix' => '£' 'currency_suffix' => '' HtmlFormatter 这个格式化器会接收一个 HTML 字符串,并对其进行以下处理: wptexturize、 convert_chars、 trim 和 wp_kses_post,然后再返回结果。这个格式化器的目的是使 HTML 变得“安全”(即,正确地格式化了字符)。 wp_kses_post 会确保只允许在 post 上下文中使用的 HTML 标签出现在字符串中。 参数 参数 类型 描述 $value string 您想要格式化成“安全”HTML 的字符串。 使用示例和返回的值 get_formatter( 'html' )->format( " This \"coffee\" is very strong." ); 返回: alert('bad script!') This “coffee” is very strong. 无论 HTML 是由用户生成还是其他方式生成,都应该在从 StoreAPI 返回 HTML 时使用此格式化器。这可以确保客户端/消费者能够安全地显示 HTML,并且不会出现编码问题。 动态更新购物车 问题 您是一位扩展开发者,您的扩展在客户端输入(例如,购物者在购物车侧边栏的输入框中填写内容,然后点击一个按钮)的触发下,执行一些服务器端处理。 这种服务器端处理会导致购物车状态发生变化,您希望更新客户端购物车或结账模块中显示的数据。 您不能直接更新客户端购物车状态。这是为了防止功能出现问题的扩展意外地使用格式错误或无效的数据更新它,这会导致整个模块崩溃。 解决方案 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 函数。然后在您的回调函数中,您可以检查此 价值 以区分应该执行哪个代码路径。 示例: '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 接口接收到指定命名空间的数据时,该回调函数会被执行。它接收一个参数数组。 属性 类型 必需 描述 namespace string 是 您的扩展的命名空间。 这用于确定应该执行哪个扩展的回调函数。 callback Callable 是 当 cart/extensions 接口接收到与提供的命名空间匹配的数据时,将要执行的函数/方法(或可调用对象)。 该可调用对象应该接受一个参数。 通过该参数传递给回调函数的数据将是一个数组,其中包含您选择传递的任何数据。 可调用对象不需要返回任何值,如果它返回了值,则该返回值将不被使用。 JavaScript extensionCartUpdate: 用于通知系统,您希望执行已注册的回调函数,并向回调函数传递数据。它接受一个对象作为唯一的参数。 属性 类型 必需 描述 namespace string 是 您的扩展程序的命名空间。 这用于确定应执行哪个扩展程序的的回调函数。 data Object 否 您想要传递给回调函数的数据。 data 键中的任何内容都将作为第一个(也是唯一)参数传递给您的回调函数,以关联数组的形式。 overwriteDirtyCustomerData boolean 否 是否覆盖客户端中的客户数据,使用从服务器返回的数据,即使该数据尚未推送到服务器。 综合应用 您是开发一个扩展程序的作者,该扩展程序允许购物者使用他们在您的网站上赚取的积分,以获得其订单的折扣。 存在一个文本字段,购物者可以在其中输入他们想要兑换的积分数量,还有一个提交按钮,用于应用兑换。 您的扩展程序使用 DiscountsMeta 插槽,将这些 UI 元素添加到购物车和结账块的侧边栏中。 有关如何使用插槽的更多信息,请参阅我们的 插槽和填充文档。 实现后,侧边栏会添加一个控件,如下所示: "兑换" 按钮 在您的 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 购物车。 'super-coupons', 'callback' => function( $data ) { redeem_points( $data['points'] ); }, ] ); } ); 现在,该回调函数已注册,当按下按钮时, cart/extensions 接口将被访问,并且由于 namespace 为 super-coupons,我们的 redeem_points 函数将被执行。 在此处理完成后,WooCommerce Blocks 将更新客户端购物车。 购物车优惠券 API 获取购物车优惠券列表 GET /cart/coupons 此接口不需要任何参数。 curl "https://example-store.com/wp-json/wc/store/v1/cart/coupons" 示例响应: [ { "code": "20off", "type": "fixed_cart", "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "total_discount": "1667", "total_discount_tax": "333" }, "_links": { "self": [ { "href": "http://local.wordpress.test/wp-json/wc/store/v1/cart/coupons/20off" } ], "collection": [ { "href": "http://local.wordpress.test/wp-json/wc/store/v1/cart/coupons" } ] } } ] 获取单个购物车优惠券 获取单个购物车优惠券。 GET /cart/coupons/:code 属性 类型 必需 描述 code 字符串 是 要检索的购物车优惠券的优惠券代码。 curl "https://example-store.com/wp-json/wc/store/v1/cart/coupons/20off" 示例响应: { "code": "halfprice", "type": "percent", "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "total_discount": "9950", "total_discount_tax": "0" } } 添加购物车优惠券 将优惠券应用于购物车。 如果成功应用,则返回新的优惠券对象;否则,返回错误。 POST /cart/coupons/ 属性 类型 必需 描述 code 字符串 是 您希望应用于购物车的优惠券代码。 curl --request POST https://example-store.com/wp-json/wc/store/v1/cart/coupons?code=20off 示例响应: { "code": "20off", "type": "percent", "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "total_discount": "1667", "total_discount_tax": "333" } } 删除单个购物车优惠券 删除/移除购物车中的优惠券。 DELETE /cart/coupons/:code 属性 类型 必需 描述 code 字符串 是 您希望从购物车中移除的优惠券代码。 curl --request DELETE https://example-store.com/wp-json/wc/store/v1/cart/coupons/20off 删除购物车中的所有优惠券 删除/移除购物车中的所有优惠券。 DELETE /cart/coupons/ 这个接口不需要任何参数。 curl --request DELETE https://example-store.com/wp-json/wc/store/v1/cart/coupons 例子回复: [] 购物车项目 API 本 API 提供了访问和管理购物车项目的接口。 功能描述: 该 API 允许您: 获取购物车中的所有项目: 可以根据用户 ID 或购物车 ID 获取指定购物车中的所有项目列表。 添加项目到购物车: 可以向指定购物车中添加新的项目。 更新购物车中的项目: 可以修改购物车中现有项目的数量或价格。 从购物车中删除项目: 可以从指定购物车中移除特定的项目。 API 端点: GET /api/cart/%s/items: 获取指定购物车中的所有项目。 POST /api/cart/%s/items: 向指定购物车中添加新的项目。 PUT /api/cart/%s/items/%d: 更新指定购物车中的项目。 DELETE /api/cart/%s/items/%d: 从指定购物车中删除项目。 请求参数: 参数名 类型 描述 必填 cart_id string 购物车 ID 是 item_id integer 项目 ID 是 quantity integer 项目数量 否 price float 项目价格 否 name string 项目名称 否 description string 项目描述 否 响应格式: { "status": "success", "data": [ { "item_id": %d, "name": "{name}", "quantity": %d, "price": %.2f } ] } 错误处理: 如果发生错误,API 将返回以下错误代码: 400 Bad Request: 请求参数无效。 404 Not Found: 购物车或项目未找到。 500 Internal Server Error: 服务器内部错误。 示例: 获取购物车中的所有项目: curl -X GET http://localhost:8000/api/cart/user123/items 向购物车中添加新的项目: curl -X POST http://localhost:8000/api/cart/user123/items \ -H "Content-Type: application/json" \ -d '{ "item_id": 1, "quantity": 2, "price": 10.00 }' 注意: 请确保您已正确配置 API 密钥,以便访问该 API。 请参考 API 文档以获取更多详细信息。 购物车项目列表 GET /cart/items 使用此接口不需要额外的参数。 curl "https://example-store.com/wp-json/wc/store/v1/cart/items" 例子回复: [ { "key": "c74d97b01eae257e44aa9d5bade97baf", "id": 16, "quantity": 1, "type": "simple", "quantity_limits": { "minimum": 1, "maximum": 1, "multiple_of": 1, "editable": false }, "name": "Beanie", "short_description": "

这是一个简单的产品。

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "woo-beanie", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": true, "permalink": "https://store.local/product/beanie/", "images": [ { "id": 45, "src": "https://store.local/wp-content/uploads/2023/01/beanie-2.jpg", "thumbnail": "https://store.local/wp-content/uploads/2023/01/beanie-2-450x450.jpg", "srcset": "https://store.local/wp-content/uploads/2023/01/beanie-2.jpg 801w, https://store.local/wp-content/uploads/2023/01/beanie-2-450x450.jpg 450w, https://store.local/wp-content/uploads/2023/01/beanie-2-100x100.jpg 100w, https://store.local/wp-content/uploads/2023/01/beanie-2-600x600.jpg 600w, https://store.local/wp-content/uploads/2023/01/beanie-2-300x300.jpg 300w, https://store.local/wp-content/uploads/2023/01/beanie-2-150x150.jpg 150w, https://store.local/wp-content/uploads/2023/01/beanie-2-768x768.jpg 768w", "sizes": "(max-width: 801px) 100vw, 801px", "name": "beanie-2.jpg", "alt": "" } ], "variation": [], "item_data": [], "prices": { "price": "1800", "regular_price": "2000", "sale_price": "1800", "price_range": null, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "", "raw_prices": { "precision": 6, "price": "18000000", "regular_price": "20000000", "sale_price": "18000000" } }, "totals": { "line_subtotal": "1800", "line_subtotal_tax": "360", "line_total": "1800", "line_total_tax": "360", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "catalog_visibility": "visible", "extensions": {}, "_links": { "self": [ { "href": "https://store.local/wp-json/wc/store/v1/cart/items/c74d97b01eae257e44aa9d5bade97baf" } ], "collection": [ { "href": "https://store.local/wp-json/wc/store/v1/cart/items" } ] } }, { "key": "e03e407f41901484125496b5ec69a76f", "id": 29, "quantity": 1, "type": "variation", "quantity_limits": { "minimum": 1, "maximum": 9999, "multiple_of": 1, "editable": true }, "name": "Hoodie", "short_description": "", "description": "

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sagittis orci ac odio dictum tincidunt. Donec ut metus leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed luctus, dui eu sagittis sodales, nulla nibh sagittis augue, vel porttitor diam enim non metus. Vestibulum aliquam augue neque. Phasellus tincidunt odio eget ullamcorper efficitur. Cras placerat ut turpis pellentesque vulputate. Nam sed consequat tortor. Curabitur finibus sapien dolor. Ut eleifend tellus nec erat pulvinar dignissim. Nam non arcu purus. Vivamus et massa massa.

", "sku": "woo-hoodie-red", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://store.local/product/hoodie/?attribute_pa_color=red&attribute_logo=No", "images": [ { "id": 40, "src": "https://store.local/wp-content/uploads/2023/01/hoodie-2.jpg", "thumbnail": "https://store.local/wp-content/uploads/2023/01/hoodie-2-450x450.jpg", "srcset": "https://store.local/wp-content/uploads/2023/01/hoodie-2.jpg 801w, https://store.local/wp-content/uploads/2023/01/hoodie-2-450x450.jpg 450w, https://store.local/wp-content/uploads/2023/01/hoodie-2-100x100.jpg 100w, https://store.local/wp-content/uploads/2023/01/hoodie-2-600x600.jpg 600w, https://store.local/wp-content/uploads/2023/01/hoodie-2-300x300.jpg 300w, https://store.local/wp-content/uploads/2023/01/hoodie-2-150x150.jpg 150w, https://store.local/wp-content/uploads/2023/01/hoodie-2-768x768.jpg 768w", "sizes": "(max-width: 801px) 100vw, 801px", "name": "hoodie-2.jpg", "alt": "" } ], "variation": [ { "raw_attribute": "attribute_pa_color", "attribute": "颜色", "value": "红色" }, { "raw_attribute": "attribute_logo", "attribute": "徽章", "value": "无" } ], "item_data": [], "prices": { "price": "4200", "regular_price": "4500", "sale_price": "4200", "price_range": null, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "", "raw_prices": { "precision": 6, "price": "42000000", "regular_price": "45000000", "sale_price": "42000000" } }, "totals": { "line_subtotal": "4200", "line_subtotal_tax": "840", "line_total": "4200", "line_total_tax": "840", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "catalog_visibility": "visible", "extensions": {}, "_links": { "self": [ { "href": "https://store.local/wp-json/wc/store/v1/cart/items/e03e407f41901484125496b5ec69a76f" } ], "collection": [ { "href": "https://store.local/wp-json/wc/store/v1/cart/items" } ] } } ] 单个购物车项目 通过其关键字获取单个购物车项目。 GET /cart/items/:key 属性 类型 必填 描述 key 字符串 是 要检索的购物车项目的关键字。 curl "https://example-store.com/wp-json/wc/store/v1/cart/items/c74d97b01eae257e44aa9d5bade97baf" 例子回复: { "key": "c74d97b01eae257e44aa9d5bade97baf", "id": 16, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 1, "multiple_of": 1, "editable": false }, "name": "Beanie", "short_description": "

这是一个简单产品。

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "woo-beanie", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": true, "permalink": "https://store.local/product/beanie/", "images": [ { "id": 45, "src": "https://store.local/wp-content/uploads/2023/01/beanie-2.jpg", "thumbnail": "https://store.local/wp-content/uploads/2023/01/beanie-2-450x450.jpg", "srcset": "https://store.local/wp-content/uploads/2023/01/beanie-2.jpg 801w, https://store.local/wp-content/uploads/2023/01/beanie-2-450x450.jpg 450w, https://store.local/wp-content/uploads/2023/01/beanie-2-100x100.jpg 100w, https://store.local/wp-content/uploads/2023/01/beanie-2-600x600.jpg 600w, https://store.local/wp-content/uploads/2023/01/beanie-2-300x300.jpg 300w, https://store.local/wp-content/uploads/2023/01/beanie-2-150x150.jpg 150w, https://store.local/wp-content/uploads/2023/01/beanie-2-768x768.jpg 768w", "sizes": "(max-width: 801px) 100vw, 801px", "name": "beanie-2.jpg", "alt": "" } ], "variation": [], "item_data": [], "prices": { "price": "1800", "regular_price": "2000", "sale_price": "1800", "price_range": null, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "", "raw_prices": { "precision": 6, "price": "18000000", "regular_price": "20000000", "sale_price": "18000000" } }, "totals": { "line_subtotal": "1800", "line_subtotal_tax": "360", "line_total": "1800", "line_total_tax": "360", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "catalog_visibility": "visible", "extensions": {}, "_links": { "self": [ { "href": "https://store.local/wp-json/wc/store/v1/cart/items/(?P[\\w-]{32})/c74d97b01eae257e44aa9d5bade97baf" } ], "collection": [ { "href": "https://store.local/wp-json/wc/store/v1/cart/items/(?P[\\w-]{32})" } ] } } 添加购物车项目 将项目添加到购物车。返回已添加的新购物车项目,或错误响应。 POST /cart/items/ 属性 类型 必需 描述 id 整数 是 购物车项目的产品或变体 ID。 quantity 整数 是 购物车中此项目的数量。 variation 数组 是 选择的属性(用于变体),包含一个对象数组,其中包含键 attribute 和 value。 curl --request POST https://example-store.com/wp-json/wc/store/v1/cart/items?id=100&quantity=1 有关示例响应,请参阅 单个购物车项目。 如果您想一次性添加多个项目到购物车,请参阅 批量操作。 编辑单个购物车项目 编辑购物车中的项目。 PUT /cart/items/:key 属性 类型 必需 描述 key 字符串 是 要编辑的购物车项目的键。 quantity 整数 是 购物车中此项目的数量。 curl --request PUT https://example-store.com/wp-json/wc/store/v1/cart/items/e369853df766fa44e1ed0ff613f563bd?quantity=10 有关示例响应,请参阅 单个购物车项目。 删除单个购物车项目 通过其键从购物车中删除项目。 DELETE /cart/items/:key 属性 类型 必需 描述 key 字符串 是 要编辑的购物车项目的键。 curl --request DELETE https://example-store.com/wp-json/wc/store/v1/cart/items/e369853df766fa44e1ed0ff613f563bd 删除所有购物车项目 一次性从购物车中删除所有项目。 DELETE /cart/items/ 使用此端点不需要额外的参数。 curl --request DELETE https://example-store.com/wp-json/wc/store/v1/cart/items 示例响应: [] 购物车 API 购物车 API 返回当前会话或已登录用户的购物车当前状态。 所有 POST 接口都需要一个 随机数 Token 或一个 购物车 Token,并在完成时返回完整的购物车更新后的状态。 获取购物车 GET /cart 此接口不需要任何参数。 curl "https://example-store.com/wp-json/wc/store/v1/cart" 返回完整的购物车对象回复(参见 购物车回复)。 回复 /cart 下的所有接口(如本文档中所列)都以相同的格式返回回复:一个购物车对象,其中包含购物车项目、已应用的优惠券、配送地址和费率,以及非敏感的客户数据。 购物车回复 本节描述了购物车相关的回复。 请求参数: cart_id: 购物车ID (整数) user_id: 用户ID (整数) 请求示例: GET /api/v1/cart/%s?user_id=%d 回复格式: { "status": "success", "data": { "cart_id": %d, "user_id": %d, "items": [ { "product_id": %d, "quantity": %d } ] } } 错误代码: 代码 描述 400 错误的请求参数。 401 未授权。 404 购物车不存在。 500 服务器内部错误。 示例回复: { "status": "success", "data": { "cart_id": 123, "user_id": 456, "items": [ { "product_id": 789, "quantity": 2 } ] } } 错误回复示例: { "status": "error", "code": 404, "message": "Cart not found." } 注意事项: status 字段表示请求是否成功。 data 字段包含购物车信息。 code 字段表示错误代码。 message 字段包含错误信息。 其他: on 状态表示购物车已启用。 off 状态表示购物车已禁用。 函数: get_cart_response(cart_id, user_id): 获取购物车回复。 create_cart(user_id): 创建新的购物车。 update_cart_item(cart_id, product_id, quantity): 更新购物车中的商品数量。 delete_cart_item(cart_id, product_id): 从购物车中删除商品。 clear_cart(cart_id): 清空购物车。 { "items": [ { "key": "a5771bce93e200c36f7cd9dfd0e5deaa", "id": 38, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 9999, "multiple_of": 1, "editable": true }, "name": "带有Logo的帽子", "short_description": "

这是一个简单的产品。

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "Woo-beanie-logo", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://local.wordpress.test/product/beanie-with-logo/", "images": [ { "id": 61, "src": "https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-450x450.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1.jpg 800w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-450x450.jpg 450w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-600x600.jpg 600w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "beanie-with-logo-1.jpg", "alt": "" } ], "variation": [], "item_data": [], "prices": { "price": "1800", "regular_price": "2000", "sale_price": "1800", "price_range": null, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "", "raw_prices": { "precision": 6, "price": "18000000", "regular_price": "20000000", "sale_price": "18000000" } }, "totals": { "line_subtotal": "1800", "line_subtotal_tax": "180", "line_total": "1530", "line_total_tax": "153", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "catalog_visibility": "visible", "extensions": {} }, { "key": "b6d767d2f8ed5d21a44b0e5886680cb9", "id": 22, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 9999, "multiple_of": 1, "editable": true }, "name": "腰带", "short_description": "

这是一个简单的产品。

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "woo-belt", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://local.wordpress.test/product/belt/", "images": [ { "id": 51, "src": "https://local.wordpress.test/wp-content/uploads/2023/03/belt-2.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-450x450.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2023/03/belt-2.jpg 801w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-450x450.jpg 450w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-600x600.jpg 600w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-768x768.jpg 768w", "sizes": "(max-width: 801px) 100vw, 801px", "name": "belt-2.jpg", "alt": "" } ], "variation": [], "item_data": [], "prices": { "price": "5500", "regular_price": "6500", "sale_price": "5500", "price_range": null, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "", "raw_prices": { "precision": 6, "price": "55000000", "regular_price": "65000000", "sale_price": "55000000" } }, "totals": { "line_subtotal": "5500", "line_subtotal_tax": "550", "line_total": "4675", "line_total_tax": "468", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "catalog_visibility": "visible", "extensions": {} } ], "coupons": [ { "code": "test", "discount_type": "percent", "totals": { "total_discount": "1095", "total_discount_tax": "109", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" } } ], "fees": [], "totals": { "total_items": "7300", "total_items_tax": "730", "total_fees": "0", "total_fees_tax": "0", "total_discount": "1095", "total_discount_tax": "110", "total_shipping": "1300", "total_shipping_tax": "130", "total_price": "8256", "total_tax": "751", "tax_lines": [ { "name": "税费", "price": "751", "rate": "10%" } ], "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "shipping_address": { "first_name": "John", "last_name": "Doe", "company": "", "address_1": "Hello street", "address_2": "", "city": "beverly hills", "state": "CA", "postcode": "90211", "country": "US", "phone": "123456778" }, "billing_address": { "first_name": "John", "last_name": "Doe", "company": "", "address_1": "Hello street", "address_2": "", "city": "beverly hills", "state": "CA", "postcode": "90211", "country": "US", "email": "checkout@templates.com", "phone": "123456778" }, "needs_payment": true, "needs_shipping": true, "payment_requirements": [ "products" ], "has_calculated_shipping": true, "shipping_rates": [ { "package_id": 0, "name": "Shipment 1", "destination": { "address_1": "Hello street", "address_2": "", "city": "beverly hills", "state": "CA", "postcode": "90211", "country": "US" }, "items": [ { "key": "a5771bce93e200c36f7cd9dfd0e5deaa", "name": "带有Logo的帽子", "quantity": 1 }, { "key": "b6d767d2f8ed5d21a44b0e5886680cb9", "name": "腰带", "quantity": 1 } ], "shipping_rates": [ { "rate_id": "flat_rate:10", "name": "统一费率", "description": "", "delivery_time": "", "price": "1300", "taxes": "130", "instance_id": 10, "method_id": "flat_rate", "meta_data": [ { "key": "Items", "value": "带有Logo的帽子 × 1, 腰带 × 1" } ], "selected": true, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, { "rate_id": "free_shipping:12", "name": "免费配送", "description": "", "delivery_time": "", "price": "0", "taxes": "0", "instance_id": 12, "method_id": "free_shipping", "meta_data": [ { "key": "Items", "value": "带有Logo的帽子 × 1, 腰带 × 1" } ], "selected": false, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, { "rate_id": "local_pickup:13", "name": "本地自提", "description": "", "delivery_time": "", "price": "0", "taxes": "0", "instance_id": 13, "method_id": "local_pickup", "meta_data": [ { "key": "Items", "value": "带有Logo的帽子 × 1, 腰带 × 1" } ], "selected": false, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" } ] } ], "items_count": 2, "items_weight": 0, "cross_sells": [], "errors": [], "payment_methods": [ "bacs", "cod" ], "extensions": {} } 错误回复 如果无法执行购物车操作,将返回一个错误回复。 这将包含一个错误代码和一个错误消息: { "code": "woocommerce_rest_cart_invalid_product", "message": "该产品无法添加到购物车。", "data": { "status": 400 } } 某些错误回复表示冲突(错误 409),例如,当某个项目无法找到或优惠券不再生效时。 当返回此类回复时,服务器的购物车当前状态也会作为错误数据的一部分返回: { "code": "woocommerce_rest_cart_invalid_key", "message": "购物车项目不再存在或无效。", "data": { "status": 409, "cart": { ... } } } 这允许客户端在不发出额外请求的情况下,与购物车数据保持同步,即使购物车发生更改或已过期。 添加项目 将项目添加到购物车,并返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此端点将返回一个错误。 POST /cart/add-item 属性 类型 必需 描述 id integer 是 购物车中商品的 ID 或变体 ID。 quantity integer 是 购物车中此商品的数量。 variation array 是 选择的属性(用于变体),包含一个对象数组,每个对象包含键 attribute 和 value。 请注意,关于属性命名的说明见下文。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/add-item?id=100&quantity=1 如果成功,则返回完整的 购物车响应;如果失败,则返回一个 错误响应。 如果您希望在将购物车项目数据传递给 CartController::add_to_cart 之前添加补充数据,可以使用 woocommerce_store_api_add_to_cart_data 过滤器。 例如: add_filter( 'woocommerce_store_api_add_to_cart_data', function( $add_to_cart_data, \WP_REST_Request $request ) { if ( ! empty( $request['custom-request-param'] ) ) { $add_to_cart_data['cart_item_data']['custom-request-data'] = sanitize_text_field( $request['custom-request-param'] ); } return $add_to_cart_data; }, 10, 2 ); 变体属性命名: 在将变体添加到购物车时,属性的命名非常重要。 对于全局属性,发布到 API 的属性应该是属性的别名。 应该有一个 pa_ 前缀。 例如,如果您的属性名为 Color,则别名为 pa_color。 对于特定于产品的属性,发布到 API 的属性可以是以下之一: 属性的名称。 例如,如果您的属性名为 Size,则名称为 Size。 这对大小写敏感。 属性的别名。 例如,如果您的属性名为 Autograph ✏️,则名称为 attribute_autograph-%e2%9c%8f%ef%b8%8f。 这对大小写敏感。 您可以从产品页面的相关 select 中获取此别名。 示例 POST 请求体: # 添加商品变体到购物车 以下示例向购物车添加了一个商品变体,该变体具有尺寸和颜色等属性。 **批量操作:** 如果您想一次性添加多个项目,则需要使用批量接口: ```http POST /wc/store/v1/batch 向购物车添加多个项目的 JSON 数据格式如下: { "requests": [ { "path": "/wc/store/v1/cart/add-item", "method": "POST", "cache": "no-store", "body": { "id": 26, "quantity": 1 }, "headers": { "Nonce": "1db1d13784" } }, { "path": "/wc/store/v1/cart/add-item", "method": "POST", "cache": "no-store", "body": { "id": 27, "quantity": 1 }, "headers": { "Nonce": "1db1d13784" } } ] } { "id": 13, "quantity": 1, "variation": [ { "attribute": "pa_color", "value": "blue" }, { "attribute": "attribute_autograph-%e2%9c%8f%ef%b8%8f", "value": "Yes" }, { "attribute": "Logo", "value": "Yes" } ] } 该示例添加了一个具有尺寸和颜色属性的产品变体到购物车。 Batching: 如果您想一次添加多个项目,您需要使用批量接口: POST /wc/store/v1/batch 用于向购物车添加多个项目的 JSON 数据如下: { "requests": [ { "path": "/wc/store/v1/cart/add-item", "method": "POST", "cache": "no-store", "body": { "id": 26, "quantity": 1 }, "headers": { "Nonce": "1db1d13784" } }, { "path": "/wc/store/v1/cart/add-item", "method": "POST", "cache": "no-store", "body": { "id": 27, "quantity": 1 }, "headers": { "Nonce": "1db1d13784" } } ] } 解释: Variation: 变体 Nonce: 随机数 Attribute: 属性 Quantity: 数量 Requests: 请求 Product: 产品 Method: 方法 Cache: 缓存 Color: 颜色 Value: 价值 Store: 商店 Path: 路径 Auto: 自动 Blue: 蓝色 Cart: 购物车 Item: 项目 Log: 日志 and: 和 Use: 使用 For: 为 移除项目 从购物车中移除一个项目,并返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此接口将返回一个错误。 POST /cart/remove-item 属性 类型 必需 描述 key 字符串 是 要编辑的购物车项目的键。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/remove-item?key=e369853df766fa44e1ed0ff613f563bd 在成功时,返回完整的 购物车响应,在失败时,返回一个 错误响应。 更新项目 更新购物车中的一个项目,并返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此接口将返回一个错误。 POST /cart/update-item 属性 类型 必需 描述 key 字符串 是 要编辑的购物车项目的键。 quantity 整数 是 购物车中此项目的数量。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/update-item?key=e369853df766fa44e1ed0ff613f563bd&quantity=10 在成功时,返回完整的 购物车响应,在失败时,返回一个 错误响应。 应用优惠券 将优惠券应用于购物车,并返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此接口将返回一个错误。 POST /cart/apply-coupon/ 属性 类型 必需 描述 code 字符串 是 您希望应用于购物车的优惠券代码。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/apply-coupon?code=20off 在成功时,返回完整的 购物车响应,在失败时,返回一个 错误响应。 移除优惠券 从购物车中移除一个优惠券,并返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 或 购物车令牌,否则此接口将返回一个错误。 POST /cart/remove-coupon/ 属性 类型 必需 描述 code 字符串 是 您希望从购物车中移除的优惠券代码。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/remove-coupon?code=20off 在成功时,返回完整的 购物车响应,在失败时,返回一个 错误响应。 更新客户信息 更新客户信息,并返回完整的购物车信息,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此 API 将返回一个错误。 POST /cart/update-customer 客户地址信息 本节描述了客户地址信息的结构。 属性 类型 必填 描述 billing_address object 否 客户的账单地址。 billing_address.first_name string 否 客户的名。 billing_address.last_name string 否 客户的姓氏。 billing_address.address_1 string 否 配送地址的第一行。 billing_address.address_2 string 否 配送地址的第二行。 billing_address.city string 否 配送地址的城市。 billing_address.state string 否 州、省或地区的 ISO 代码,或名称,用于表示配送地址。 billing_address.postcode string 否 配送地址的邮政编码。 billing_address.country string 否 配送地址所在国家的 ISO 代码。 billing_address.email string 否 客户的邮件地址。 billing_address.phone string 否 客户的电话号码。 shipping_address object 否 客户的配送地址。 shipping_address.first_name string 否 客户的名。 shipping_address.last_name string 否 客户的姓氏。 shipping_address.address_1 string 否 配送地址的第一行。 shipping_address.address_2 string 否 配送地址的第二行。 shipping_address.city string 否 配送地址的城市。 shipping_address.state string 否 州、省或地区的 ISO 代码,或名称,用于表示配送地址。 shipping_address.postcode string 否 配送地址的邮政编码。 shipping_address.country string 否 配送地址所在国家的 ISO 代码。 以下是一些示例: # 示例 1: 创建一个包含账单地址和配送地址的客户对象。 customer = { "billing_address": { "first_name": "名", "last_name": "姓氏", "address_1": "地址", "address_2": "", "city": "城市", "state": "州", "postcode": "邮政编码", "country": "国家", "email": "邮件", "phone": "电话号码" }, "shipping_address": { "first_name": "名", "last_name": "姓氏", "address_1": "地址", "address_2": "", "city": "城市", "state": "州", "postcode": "邮政编码", "country": "国家" } } # 示例 2: 设置一个客户的属性。 set_customer_attribute(customer, "description", "描述") # 示例 3: 获取一个数值。 number = get_number() # 示例 4: 循环 %d 秒。 for i in range(1, %d): print("一 %s 秒" % "second") # 示例 5: 检查一个条件。 if no: print("否") else: print("是") # 示例 6: 使用 Code 请注意, String 是一个 String 类型。 Phone Number 必须是有效的 Phone Number。 First name 不能为空。 Attribute 必须是有效的 Attribute。 Last Name 不能为空。 Shipping 必须是有效的 Shipping 地址。 Address 必须是有效的 Address。 Second 表示 Second。 number 表示 number。 Code 表示 Code。 Mail 表示 Mail。 Red 表示 Red。 one 表示 one。 For 表示 For。 In 表示 In。 No 表示 No。 Shipping Address 表示 Shipping Address。 Description 表示 Description。 Customer 表示 Customer。 返回全部的 购物车回复,如果成功;否则,返回一个 错误回复。 选择配送费率 选择一个可用的配送费率,然后返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此接口将返回一个错误。 POST /cart/select-shipping-rate 属性 类型 必需 描述 package_id integer 是 购物车中配送包的 ID。 rate_id string 是 选定的配送包的费率 ID。 curl --header "Nonce: 12345" --request POST /cart/select-shipping-rate?package_id=1&rate_id=flat_rate:1 在成功时,返回完整的 购物车响应,在失败时,返回一个 错误响应。 结账订单 API 结账订单 API 旨在简化现有订单的处理和付款操作。 所有结账订单接口都需要一个 随机数 Token 或一个 购物车 Token,否则这些接口将返回一个错误。 处理订单和支付 接受最终选择的支付方法,以及任何额外的支付数据,然后尝试支付并返回结果。 POST /wc/store/v1/checkout/{ORDER_ID} 属性 类型 必需 描述 key 字符串 是 用于订单验证的密钥。 billing_email 字符串 否 用于验证访客订单的 Email 地址。 billing_address 对象 是 客户已更新的账单地址数据对象。 shipping_address 对象 是 客户已更新的配送地址数据对象。 payment_method 字符串 是 用于处理支付的支付方法 ID。 payment_data 数组 否 在处理支付时传递给支付方法的数据。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/checkout/{ORDER_ID} -d '{"key":"wc_order_oFmQYREzh9Tfv","billing_email":"admin@example.com","payment_method":"cheque","billing_address":{...},"shipping_address":{...}' 示例请求: { "key": "wc_order_oFmQYREzh9Tfv", "billing_email": "admin@example.com", "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "phone": "555-2368" }, "payment_method": "cheque", "payment_data": [] } 示例响应: # 订单详情 以下是订单的详细信息。 **订单 ID:** %d **状态:** %s ## 订单概览 * **订单 ID:** %d * **状态:** %s * **订单 Key:** %s * **客户备注:** %s * **客户 ID:** %d ## 账单地址 * **地址:** * **姓名:** %s * **公司:** %s * **地址 1:** %s * **地址 2:** %s * **城市:** %s * **州/省:** %s * **邮编:** %s * **国家:** %s * **邮箱:** %s * **电话:** %s ## 配送地址 * **地址:** * **姓名:** %s * **公司:** %s * **地址 1:** %s * **地址 2:** %s * **城市:** %s * **州/省:** %s * **邮编:** %s * **国家:** %s * **电话:** %s ## 支付信息 * **支付方法:** %s * **支付结果:** * **支付状态:** %s * **支付详情:** %s * **重定向 URL:** %s ## 订单管理 * **管理员:** 只有管理员才能查看和修改订单信息。 * **检查:** 定期检查订单状态,确保顺利完成。 * **锁定:** 在处理订单时,可以锁定订单以防止其他用户修改。 * **邮件:** 系统会发送邮件通知客户订单状态更新。 * **新增:** 管理员可以新增订单。 * **红色:** 某些情况下,订单状态会显示为红色,表示存在问题。 * **网址:** 请注意以下网址。 * **关键字:** 使用关键字进行订单搜索。 ```json { "order_id": 146, "status": "on-hold", "order_key": "wc_order_oFmQYREzh9Tfv", "customer_note": "", "customer_id": 1, "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "phone": "555-2368" }, "payment_method": "cheque", "payment_result": { "payment_status": "success", "payment_details": [], "redirect_url": "https://local.wordpress.test/block-checkout/order-received/146/?key=wc_order_VPffqyvgWVqWL" } } 常见问题 如何修改订单信息? 只有管理员可以修改订单信息。 如何取消订单? 请联系客服进行取消。 如何查看订单状态? 您可以在账户中查看订单状态。 如何进行退货? 请参考我们的退货政策。 配送时间是多久? 配送时间取决于您的地址和选择的配送方式。 结账时遇到了问题,怎么办? 请联系客服寻求帮助。 如何联系客服? 您可以通过邮件或电话联系客服。 测试环境: 这是测试环境,所有数据均为测试数据。 ## 支付数据 有很多支付网关可供商家使用,并且每个网关都期望接收不同的 `payment_data`。 我们无法全面列出所有支付网关期望的所有请求,因此我们建议您联系您正在使用的支付网关插件的作者,以获取更多信息。 以下是一个使用 [WooCommerce Stripe 支付网关](https://wordpress.org/plugins/woocommerce-gateway-stripe/) 时,发送到结账订单端点的支付数据的示例。 有关生成 `stripe_source` 的更多信息,请查看 [Stripe 文档](https://stripe.com/docs)。 ```json { "payment_data": [ { "key": "stripe_source", "value": "src_xxxxxxxxxxxxx" }, { "key": "billing_email", "value": "myemail@email.com" }, { "key": "billing_first_name", "value": "Jane" }, { "key": "billing_last_name", "value": "Doe" }, { "key": "paymentMethod", "value": "stripe" }, { "key": "paymentRequestType", "value": "cc" }, { "key": "wc-stripe-new-payment-method", "value": true } ] } 结账 API 结账 API 允许创建订单(基于当前的购物车)并处理付款方式的支付。 所有结账端点都需要一个 Nonce Token 或一个 Cart Token,否则这些端点将返回一个错误。 获取结账数据 返回用于结账所需的数据。 这包括一个草稿订单(基于当前的购物车)以及客户的账单和配送地址。 支付信息将为空,因为它只有在通过 POST 请求更新订单时才会持久化(在支付处理之前)。 GET /wc/store/v1/checkout 此端点不需要任何参数。 curl --header "Nonce: 12345" --request GET https://example-store.com/wp-json/wc/store/v1/checkout 示例响应 { "order_id": 146, "status": "checkout-draft", "order_key": "wc_order_VPffqyvgWVqWL", "customer_note": "", "customer_id": 1, "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US" }, "payment_method": "", "payment_result": { "payment_status": "", "payment_details": [], "redirect_url": "" } } 更新结账数据 此接口允许您更新当前订单的结账数据。例如,这可以从前端调用以持久化结账字段。 PUT /wc/store/v1/checkout?__experimental_calc_totals=true 请注意 __experimental_calc_totals 参数。 此参数用于确定是否应重新计算购物车总额。 如果购物车总额是响应 PUT 请求而更新的,则应将其设置为 true,否则设置为 false。 属性 类型 必需 描述 additional_fields object 否 要更新的其他字段的名称 => 值对。 payment_method string 否 选定的支付方式的 ID。 order_notes string 否 订单备注。 curl --header "Nonce: 12345" --request PUT https://example-store.com/wp-json/wc/store/v1/checkout?additional_fields[plugin-namespace/leave-on-porch]=true&additional_fields[plugin-namespace/location-on-porch]=dsdd&payment_method=bacs&order_notes=Please%20leave%20package%20on%20back%20porch 示例请求 { "additional_fields": { "plugin-namespace/leave-on-porch": true, "plugin-namespace/location-on-porch": "dsdd" }, "payment_method": "bacs", "order_notes": "Please leave package on back porch" } 示例响应 { "order_id": 1486, "status": "checkout-draft", "order_key": "wc_order_KLpMaJ054PVlb", "order_number": "1486", "customer_note": "", "customer_id": 1, "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US" }, "payment_method": "bacs", "payment_result": null, "additional_fields": { "plugin-namespace/leave-on-porch": true, "plugin-namespace/location-on-porch": "dsdd" }, "__experimentalCart": { ... }, "extensions": {} } 请注意响应中返回的 __experimentalCart 字段。 在 PUT 请求之后,总额将在前端更新。 这使得可以响应通过 PUT 请求持久化的字段来操纵购物车总额。 处理订单和支付 接受最终的客户地址和选择的支付方法,以及任何额外的支付数据,然后尝试支付并返回结果。 POST /wc/store/v1/checkout 属性 类型 必需 描述 billing_address object 是 客户更新后的账单地址数据对象。 shipping_address object 是 客户更新后的配送地址数据对象。 customer_note string 否 客户在结账过程中添加到订单的备注。 payment_method string 是 用于处理支付的支付方法 ID。 payment_data array 否 在处理支付时传递给支付方法的的数据。 customer_password string 否 可选地,为新帐户定义密码。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/checkout?payment_method=paypal&payment_data[0][key]=test-key&payment_data[0][value]=test-value 示例请求 { "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US" }, "customer_note": "Test notes on order.", "create_account": false, "payment_method": "cheque", "payment_data": [], "extensions": { "some-extension-name": { "some-data-key": "some data value" } } } 支付数据 有很多支付网关可供商家使用,并且每个网关都期望接收不同的 payment_data。 我们无法全面列出所有支付网关期望的请求,因此我们建议您联系您正在使用的支付网关插件的作者,以获取更多信息。 以下是一个使用 WooCommerce Stripe 支付网关 时,发送到结账端点的支付数据的示例。 有关如何生成 stripe_source 的更多信息,请查阅 Stripe 文档。 { "payment_data": [ { "key": "stripe_source", "value": "src_xxxxxxxxxxxxx" }, { "key": "billing_email", "value": "myemail@email.com" }, { "key": "billing_first_name", "value": "Jane" }, { "key": "billing_last_name", "value": "Doe" }, { "key": "paymentMethod", "value": "stripe" }, { "key": "paymentRequestType", "value": "cc" }, { "key": "wc-stripe-new-payment-method", "value": true } ] } 订单 API 订单 API 返回用于支付订单的信息。 获取订单 GET /order/{ORDER_ID}?key={KEY}&billing_email={BILLING_EMAIL} 此接口有一个必需的参数,即 key。 对于访客订单,必须添加 billing_email。 curl "https://example-store.com/wp-json/wc/store/v1/order/{ORDER_ID}?key={KEY}&billing_email={BILLING_EMAIL}" 返回完整的订单对象回复(参见 订单回复)。 回复 订单接口返回的回复格式与 /cart 相同;它是一个订单对象,包含订单项目、已应用的优惠券、配送地址和费率,以及非敏感的客户数据。 订单回复 本节描述了系统对订单的回复。 响应格式 回复采用以下 JSON 格式: { "status": "success" | "failed", "order_id": "%s", "message": "操作成功" | "订单不存在" | "支付失败" | "其他错误信息" } status: 表示操作的成功或失败。 order_id: 订单的唯一标识符。 message: 包含操作结果的详细信息。 成功回复 (status: success) 当订单处理成功时,系统会返回以下回复: { "status": "success", "order_id": "%s", "message": "操作成功" } 失败回复 (status: failed) 当订单处理失败时,系统会返回以下回复: { "status": "failed", "order_id": "%s", "message": "订单不存在" | "支付失败" | "其他错误信息" } 错误处理 如果出现错误,系统会返回 status: failed 的回复,并包含详细的错误信息。 例如,如果订单不存在,系统会返回: { "status": "failed", "order_id": "%s", "message": "订单不存在" } API 使用示例 以下是一个使用 getOrderResponse 函数的示例: def getOrderResponse(order_id): """ 获取订单的回复。 Args: order_id: 订单的 ID。 Returns: 一个包含回复信息的字典。 """ # ... (省略实现细节) ... return { "status": "success", "order_id": order_id, "message": "操作成功" } 其他说明 getOrderResponse 函数可能返回不同的 message 值,具体取决于订单的状态。 如果 order_id 无效, getOrderResponse 函数会返回 status: failed 的回复。 系统会记录所有订单操作,包括成功和失败的回复。 %s 是一个占位符,表示要插入的字符串值。 {name} 是一个占位符,表示要插入的变量名。 Or 表示“或”。 on 表示“开”。 Response 表示“回复”。 { "id": 147, "status": "待审", "coupons": [ { "code": "discount20", "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "total_discount": "421", "total_discount_tax": "0" } } ], "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "phone": "555-2368" }, "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "items": [ { "key": "9bf31c7ff062936a96d3c8bd1f8f2ff3", "id": 15, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 99, "multiple_of": 1, "editable": true }, "name": "Beanie", "short_description": "

This is a simple product.

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "woo-beanie", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://local.wordpress.test/product/beanie/", "images": [ { "id": 44, "src": "https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-324x324.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2.jpg 801w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-324x324.jpg 324w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-416x416.jpg 416w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-768x768.jpg 768w", "sizes": "(max-width: 801px) 100vw, 801px", "name": "beanie-2.jpg", "alt": "" } ], "variation": [], "prices": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "price": "1000", "regular_price": "2000", "sale_price": "1000", "price_range": null, "raw_prices": { "precision": 6, "price": "10000000", "regular_price": "20000000", "sale_price": "10000000" } }, "item_data": [], "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "line_subtotal": "1000", "line_subtotal_tax": "0", "line_total": "800", "line_total_tax": "0" }, "catalog_visibility": "view" }, { "key": "e369853df766fa44e1ed0ff613f563bd", "id": 34, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 99, "multiple_of": 1, "editable": true }, "name": "WordPress Pennant", "short_description": "

This is an 外部产品.

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "wp-pennant", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://local.wordpress.test/product/wordpress-pennant/", "images": [ { "id": 57, "src": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg 800w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg 324w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-416x416.jpg 416w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "pennant-1.jpg", "alt": "" } ], "variation": [], "prices": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "price": "1105", "regular_price": "1105", "sale_price": "1105", "price_range": null, "raw_prices": { "precision": 6, "price": "11050000", "regular_price": "11050000", "sale_price": "11050000" } }, "item_data": [], "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "line_subtotal": "1105", "line_subtotal_tax": "0", "line_total": "884", "line_total_tax": "0" }, "catalog_visibility": "view" } ], "needs_payment": true, "needs_shipping": true, "totals": { "subtotal":"2105", "total_discount": "421", "total_shipping": "500", "total_fees": "0", "total_tax": "0", "total_refund": "0", "total_price": "2184", "total_items": "2105", "total_items_tax": "0", "total_fees_tax": "0", "total_discount_tax": "0", "total_shipping_tax": "0", "tax_lines": [] }, "errors": [], "payment_requirements": [ "products" ], } 错误回复 如果无法执行某个订单操作,将会返回一个错误回复。该回复将包含一个原因代码和一个错误信息: { "code": "woocommerce_rest_invalid_order", "message": "提供的订单 ID 或关键字无效。", "data": { "status": 401 } } 产品 属性 术语 API GET /products/attributes/:id/terms GET /products/attributes/:id/terms?orderby=slug 属性 类型 必需 描述 id integer 是 要获取术语的属性的 ID。 order string 否 升序或降序排序。 允许的值: asc, desc orderby string 否 按对象属性排序集合。 允许的值: id, name, name_num, slug, count, menu_order. curl "https://example-store.com/wp-json/wc/store/v1/products/attributes/1/terms" 示例响应: [ { "id": 22, "name": "Blue", "slug": "blue", "count": 5 }, { "id": 48, "name": "Burgundy", "slug": "burgundy", "count": 1 } ] 产品属性 API 获取产品属性列表 GET /products/attributes 此接口不需要任何参数。 curl "https://example-store.com/wp-json/wc/store/v1/products/attributes" 示例响应: [ { "id": 1, "name": "Color", "taxonomy": "pa_color", "type": "select", "order": "menu_order", "has_archives": false }, { "id": 2, "name": "Size", "taxonomy": "pa_size", "type": "select", "order": "menu_order", "has_archives": false } ] 获取单个产品属性 获取单个属性分类法。 GET /products/attributes/:id 属性 类型 必需 描述 id integer 是 要检索的属性的 ID。 curl "https://example-store.com/wp-json/wc/store/v1/products/attributes/1" 示例响应: { "id": 1, "name": "Color", "taxonomy": "pa_color", "type": "select", "order": "menu_order", "has_archives": false } 产品品牌 API 本 API 提供了访问产品品牌信息的接口。 功能描述: 该 API 允许您: 查询所有可用的品牌。 根据品牌 ID 获取特定品牌的详细信息。 根据品牌名称进行模糊搜索。 API 端点: GET /api/v1/brands: 获取所有品牌。 GET /api/v1/brands/{brand_id}: 获取指定 ID 的品牌。 请求参数: 参数名 类型 描述 是否必选 brand_id int 品牌 ID。仅在 GET /api/v1/brands/{brand_id} 中使用。 否 query string 搜索关键词。仅在 GET /api/v1/brands 中使用。 否 响应格式: 响应以 JSON 格式返回。 示例: 获取所有品牌: GET /api/v1/brands 响应: [ { "id": 1, "name": "Brand A", "description": "Description for Brand A" }, { "id": 2, "name": "Brand B", "description": "Description for Brand B" } ] 获取指定 ID 的品牌: GET /api/v1/brands/1 响应: { "id": 1, "name": "Brand A", "description": "Description for Brand A" } 根据品牌名称进行模糊搜索: GET /api/v1/brands?query=Brand%20A 响应: [ { "id": 1, "name": "Brand A", "description": "Description for Brand A" } ] 错误处理: API 使用标准的 HTTP 状态码来指示操作的成功或失败。 200 OK: 请求成功。 400 Bad Request: 请求参数无效。 404 Not Found: 资源未找到。 500 Internal Server Error: 服务器内部错误。 版本: v1.0 注意事项: 本 API 仅适用于 %s 产品。 请勿滥用 API,否则可能被限制访问。 对于 Pro 版本,请联系您的管理员获取 API 密钥。 更多信息,请访问 https://example.com/api-documentation。 如果遇到问题,请联系我们的技术支持团队:support@example.com。 本 API 遵循 RESTful 架构风格。 {name} 是一个占位符,表示用户的姓名。 %d 是一个整数占位符。 %s 是一个字符串占位符。 本 API 支持多种数据格式,包括 JSON 和 XML。 本 API 提供了详细的日志记录功能,方便问题排查。 本 API 具有高可用性和可扩展性。 本 API 提供了完善的安全性机制,保护您的数据安全。 本 API 持续更新和改进,以满足您的需求。 本 API 的使用需要遵守我们的服务条款。 本 API 提供了多种认证方式,包括 API 密钥和 OAuth 2.0。 本 API 提供了详细的文档和示例代码,方便您快速上手。 本 API 团队致力于为您提供优质的技术支持。 本 API 遵循最佳实践,确保代码质量和可维护性。 本 API 具有良好的性能和响应速度。 本 API 提供了多种监控指标,方便您了解 API 的运行状态。 本 API 具有强大的错误处理能力,能够快速恢复。 本 API 遵循开放标准,方便与其他系统集成。 本 API 具有良好的兼容性,支持多种操作系统和编程语言。 本 API 提供了多种部署选项,包括云端和本地部署。 本 API 具有良好的可扩展性,能够满足您的业务增长 列出产品品牌 GET /products/brands 属性 类型 必需 描述 context 字符串 否 发送请求的范围;决定响应中包含的字段。 page 整数 否 集合的当前页。默认为 1。 per_page 整数 否 结果集中返回的最大项目数。默认为无限制。允许的值在 0 和 100 之间。 search 字符串 否 限制结果,仅包含匹配的字符串。 exclude 数组 否 确保结果集排除特定的 ID。 include 数组 否 限制结果集为特定的 ID。 order 字符串 否 升序或降序排序。允许的值: asc, desc。默认为 asc。 orderby 字符串 否 按属性排序。允许的值: name, slug, count。默认为 name。 hide_empty 布尔值 否 如果为 true,则不返回空项。默认为 true。 parent 整数 否 限制结果,仅包含具有特定父级 ID 的项。 curl "https://example-store.com/wp-json/wc/store/v1/products/brands" 示例响应: [ { "id": 16, "name": "Nike", "slug": "nike", "description": "This is the Nike brand.", "parent": 0, "count": 11, "image": { "id": 55, "src": "https://store.local/wp-content/uploads/2021/11/nike-logo.jpg", "thumbnail": "https://store.local/wp-content/uploads/2021/11/nike-logo-324x324.jpg", "srcset": "https://store.local/wp-content/uploads/2021/11/nike-logo.jpg 800w, https://store.local/wp-content/uploads/2021/11/nike-logo-324x324.jpg 324w, https://store.local/wp-content/uploads/2021/11/nike-logo-100x100.jpg 100w, https://store.local/wp-content/uploads/2021/11/nike-logo-416x416.jpg 416w, https://store.local/wp-content/uploads/2021/11/nike-logo-300x300.jpg 300w, https://store.local/wp-content/uploads/2021/11/nike-logo-150x150.jpg 150w, https://store.local/wp-content/uploads/2021/11/nike-logo-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "nike-logo.jpg", "alt": "" }, "review_count": 2, "permalink": "https://store.local/product-brand/nike/" }, { "id": 21, "name": "Adidas", "slug": "adidas", "description": "", "parent": 0, "count": 1, "image": null, "review_count": 1, "permalink": "https://store.local/product-brand/adidas/" } ] 产品品牌列表 以下是产品品牌的列表。每个品牌都有一个名称、别名、描述、父级、计数、图像、评价计数和固定链接。 品牌信息 名称 (Name): 品牌名称。 别名 (Slug): 品牌的别名,用于生成 URL。 描述 (Description): 品牌的详细描述。 父级 (Parent): 父级品牌的 ID。如果品牌是顶级品牌,则为 0。 计数 (Count): 品牌下的产品数量。 图像 (Image): 品牌的图像信息,包括 ID、源地址、缩略图地址、srcset、sizes、名称和 alt 文本。 评价计数 (Review Count): 品牌的评价数量。 固定链接 (Permalink): 品牌的固定链接地址。 示例 以下是两个产品品牌的示例: Nike: 名称: Nike 别名: nike 描述: This is the Nike brand. 父级: 0 计数: 11 图像: 包含图像的详细信息。 评价计数: 2 固定链接: https://store.local/product-brand/nike/ Adidas: 名称: Adidas 别名: adidas 描述: 父级: 0 计数: 1 图像: null 评价计数: 1 固定链接: https://store.local/product-brand/adidas/ 上传图像 您可以通过以下步骤上传图像: 点击“上传”按钮。 选择要上传的图像文件。 填写图像的标题、描述和 alt 文本。 点击“插入到内容”按钮。 调整图像大小 您可以通过以下方法调整图像大小: 使用图像编辑软件调整图像大小。 在 WordPress 中使用图像编辑插件调整图像大小。 更多信息 有关更多信息,请查看 WordPress 文档或联系技术支持。 您可以在本地服务器上查看日志文件,以获取更多信息。 请注意, Width 属性表示图像的宽度。 Brand 属性表示品牌。 Store 属性表示商店。 Log 属性表示日志。 In 预示着某个位置。 and 连接两个词语。 View 动作表示查看。 单个品牌 获取单个品牌信息。 GET /products/brands/:id 或者 GET /products/brands/:slug 参数 类型 必填 描述 identifier 字符串 是 用于获取品牌的标识符。可以是品牌 ID 或别名。 curl "https://example-store.com/wp-json/wc/store/v1/products/brands/1" 或者 curl "https://example-store.com/wp-json/wc/store/v1/products/brands/adidas" 示例回复: { "id": 1, "name": "Adidas", "slug": "adidas", "description": "", "parent": 0, "count": 1, "image": null, "review_count": 1, "permalink": "https://store.local/product-brand/adidas/" } 产品类别 API 本 API 允许您访问和管理产品类别信息。 目录 获取所有产品类别 按 ID 获取产品类别 创建产品类别 更新产品类别 删除产品类别 获取所有产品类别 此 API 端点允许您获取所有可用的产品类别。 请求方法: GET 请求 URL: /api/v1/product_categories 响应: [ { "id": 1, "name": "Electronics", "description": "Electronic devices and accessories" }, { "id": 2, "name": "Clothing", "description": "Apparel and fashion items" } ] 按 ID 获取产品类别 此 API 端点允许您通过 ID 获取特定产品类别的信息。 请求方法: GET 请求 URL: /api/v1/product_categories/{id} 参数: id: 要获取的产品类别的 ID。 响应: { "id": 1, "name": "Electronics", "description": "Electronic devices and accessories" } 创建产品类别 此 API 端点允许您创建新的产品类别。 请求方法: POST 请求 URL: /api/v1/product_categories 请求体: { "name": "New Category", "description": "Description of the new category" } 响应: { "id": 3, "name": "New Category", "description": "Description of the new category" } 更新产品类别 此 API 端点允许您更新现有产品类别的属性。 请求方法: PUT 请求 URL: /api/v1/product_categories/{id} 参数: id: 要更新的产品类别的 ID。 请求体: { "name": "Updated Category Name", "description": "Updated description of the category" } 响应: { "id": 1, "name": "Updated Category Name", "description": "Updated description of the category" } 删除产品类别 此 API 端点允许您删除现有产品类别。 请求方法: DELETE 请求 URL: /api/v1/product_categories/{id} 参数: id: 要删除的产品类别的 ID。 响应: 成功删除时,返回状态码 204 No Content。 错误处理: 如果发生错误,API 将返回相应的错误代码和消息。例如,如果尝试访问不存在的产品类别,则返回 404 Not Found。 示例: 使用 curl 命令获取所有产品类别: curl -X GET http://example.com/api/v1/product_categories 使用 curl 命令创建新的产品类别: curl -X POST -H "Content-Type: application/json" -d '{"name": "New Category", "description": "Description of the new category"}' http://example.com/api/v1/product_categories 注意: 所有 API 请求都需要有效的 API 密钥。 Pro 版本提供额外的功能和更高的速率限制。 Category 字段表示产品所属的分类。 Or 表示“或”。 at 表示“在”。 Go 表示“提交”。 请参考 API 文档以获取更多详细信息。 有关 API 使用的更多信息,请访问 API Documentation. 您可以在 %s 处找到更多信息。 请使用 %d 作为 ID。 您的姓名是 {name}。 列出产品分类 GET /products/categories 属性 类型 必需 描述 context 字符串 否 发送请求的范围;决定响应中包含的字段。 page 整数 否 集合的当前页。默认为 1。 per_page 整数 否 结果集中返回的最大项目数。默认为无限制。允许的值在 0 和 100 之间。 search 字符串 否 限制结果,仅包含与字符串匹配的结果。 exclude 数组 否 确保结果集排除特定的 ID。 include 数组 否 限制结果集为特定的 ID。 order 字符串 否 升序或降序排序。允许的值: asc, desc。默认为 asc。 orderby 字符串 否 按属性排序。允许的值: name, slug, count。默认为 name。 hide_empty 布尔值 否 如果为 true,则不返回空项。默认为 true。 parent 整数 否 限制结果,仅包含具有特定父级 ID 的项。 curl "https://example-store.com/wp-json/wc/store/v1/products/categories" 示例响应: [ { "id": 16, "name": "Clothing", "slug": "clothing", "description": "This is the clothing category.", "parent": 0, "count": 11, "image": { "id": 55, "src": "https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1.jpg", "thumbnail": "https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-324x324.jpg", "srcset": "https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1.jpg 800w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-324x324.jpg 324w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-100x100.jpg 100w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-416x416.jpg 416w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-300x300.jpg 300w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-150x150.jpg 150w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "t-shirt-with-logo-1.jpg", "alt": "" }, "review_count": 2, "permalink": "https://store.local/product-category/clothing/" }, { "id": 21, "name": "Decor", "slug": "decor", "description": "", "parent": 0, "count": 1, "image": null, "review_count": 1, "permalink": "https://store.local/product-category/decor/" } ] 产品分类 本页面展示了商店中的产品分类。 分类列表 以下是可用的分类列表: Clothing: 服装分类。 Description: This is the clothing category. Permalink: https://store.local/product-category/clothing/ Decor: 装饰品分类。 Description: . Permalink: https://store.local/product-category/decor/ 分类详情 点击分类名称可以 查看该分类下的所有 产品。每个分类都有一个 别名,用于 URL链接。 分类属性 id: 分类ID。 name: 分类 名称。 slug: 分类 别名。 description: 分类 描述。 parent: 父级分类ID。 count: 计数,表示该分类下的 产品数量。 image: 分类 图像信息。 id: 图像ID。 src: 图像原始链接。 thumbnail: 图像缩略图链接。 srcset: 图像不同尺寸的链接集合。 sizes: 图像尺寸属性。 name: 图像文件名。 alt: 图像替代文本。 review_count: 评价数量。 permalink: 固定链接。 上传 您可以在此处 上传新的 图像或文件。 日志 日志文件记录了系统操作。 商店设置 您可以在此处配置 商店的各种设置。 宽度和尺寸 宽度和 尺寸是 图像的重要属性。 链接 链接到其他页面或资源。 内容 内容是网页的主要部分。 在线 在线状态。 本地 本地文件。 评论 评论是对 产品或内容的反馈。 类别 分类用于组织 内容。 别名 别名是 名称的另一种形式,通常用于 URL。 产品 产品是商店中的可售商品。 视图 查看页面或 内容。 尺寸 尺寸是 图像或 产品的属性。 产品分类 获取单个分类。 GET /products/categories/:id 分类 类型 必填 描述 id 整数 是 要检索的分类的 ID。 curl "https://example-store.com/wp-json/wc/store/v1/products/categories/1" 示例回复: { "id": 1, "name": "Decor", "slug": "decor", "description": "", "parent": 0, "count": 1, "image": null, "review_count": 1, "permalink": "https://store.local/product-category/decor/" } 产品集合数据 API 此接口允许您获取产品集合的聚合数据,例如,在一个产品集合中获取最高和最低价格(忽略分页)。 这由产品筛选小工具中的块使用,因为计数基于正在查看的产品目录。 GET /products/collection-data GET /products/collection-data?calculate_price_range=true GET /products/collection-data?calculate_attribute_counts[0][query_type]=or&calculate_attribute_counts[0][taxonomy]=pa_color GET /products/collection-data?calculate_rating_counts=true GET /products/collection-data?calculate_taxonomy_counts=product_cat 属性 类型 必需 描述 calculate_price_range bool 否 返回产品集合的最低和最高价格。 如果为 false,则仅返回 null。 calculate_attribute_counts object 否 返回一组属性分类的属性计数,您可以通过此参数传递这些分类。 每个分类应以包含键 "taxonomy" 和 "query_type" 的对象形式提供。 如果为空,则返回 null。 calculate_rating_counts bool 否 返回具有特定平均评级的产品的计数,范围为 1-5。 如果为 false,则仅返回 null。 calculate_stock_status_counts bool 否 返回具有每种库存状态(在库存中、缺货、延期交货)的产品计数。 如果为 false,则仅返回 null。 calculate_taxonomy_counts array 否 返回一组分类的分类计数,您可以通过此参数传递这些分类。 每个分类应以分类名称字符串的形式提供。 如果为空,则返回 null。 除了上述属性之外,还支持所有产品列表属性。 这允许您获取特定产品子集的数据。 请参阅 产品 API 列表产品部分,以获取完整列表。 curl "https://example-store.com/wp-json/wc/store/v1/products/collection-data?calculate_price_range=true&calculate_attribute_counts=pa_size,pa_color&calculate_rating_counts=true&calculate_taxonomy_counts=product_cat,product_tag" { "price_range": [ "currency_minor_unit": 2, "min_price": "0", "max_price": "9000", "currency_code": "USD", "currency_decimal_separator": ".", "currency_minor_unit": 2, "currency_prefix": "$", "currency_suffix": "", "currency_symbol": "$", "currency_thousand_separator": ",", ], "attribute_counts": [ { "term": 22, "count": 4 }, { "term": 23, "count": 3 }, { "term": 24, "count": 4 } ], "rating_counts": [ { "rating": 3, "count": 1 }, { "rating": 4, "count": 1 } ], "taxonomy_counts": [ { "term": 25, "count": 8 }, { "term": 26, "count": 6 }, { "term": 27, "count": 2 } ] } 产品评论 API 本 API 提供了访问产品评论数据的接口。 功能描述: 该 API 允许您: 获取产品评论: 您可以根据产品 ID 获取相关的评论列表。 过滤评论: 您可以根据不同的条件(例如,评分、日期)过滤评论。 查看评论详情: 您可以查看单个评论的详细信息。 API 端点: GET /api/v1/products/{product_id}/reviews:获取指定产品 ID 的所有评论。 请求参数: 参数名 类型 必填 描述 product_id int 是 产品 ID page int 否 页码,默认为 1 page_size int 否 每页显示的数量,默认为 20 sort_by string 否 排序字段,例如 rating, date sort_order string 否 排序方式, asc (升序) 或 desc (降序) 响应格式: { "total_count": %d, "page": %d, "page_size": %d, "reviews": [ { "id": %d, "product_id": %d, "user": { "name": "%s", "email": "%s" }, "rating": %d, "comment": "%s", "date": "%s" } ] } 示例请求: GET /api/v1/products/123/reviews?page=2&page_size=10&sort_by=rating&sort_order=desc 错误处理: 状态码 描述 400 错误的请求参数。 404 未找到指定的产品或评论。 500 服务器内部错误。 版本: v1.0 注意事项: 请确保您已获得访问 API 的权限。 API 使用速率限制,请遵守相关规定。 Pro 版本提供更高级的功能和更高的速率限制。 其他: 您可以在 这里 找到更详细的文档。 如果您有任何问题,请联系我们的技术支持团队。 View 更多信息。 获取产品评论 此接口返回产品评论,并且可以显示特定产品或特定分类的结果。 GET /products/reviews GET /products/reviews?category_id=1,2,3 GET /products/reviews?product_id=1,2,3 GET /products/reviews?orderby=rating&order=desc 属性 类型 是否必选 描述 page integer 否 集合的当前页。 per_page integer 否 结果集中返回的最大项目数。 offset integer 否 通过指定数量的项目偏移结果集。 order string 否 按照升序或降序排序属性。 允许的值: asc, desc orderby string 否 按照对象属性对集合进行排序。 允许的值: date, date_gmt, id, rating, product category_id string 否 将结果集限制为来自特定分类 ID 的评论。 product_id string 否 将结果集限制为来自特定产品 ID 的评论。 curl "https://example-store.com/wp-json/wc/store/v1/products/collection-data?calculate_price_range=true&calculate_attribute_counts=pa_size,pa_color&calculate_rating_counts=true" 示例响应: [ { "id": 83, "date_created": "2022-01-12T15:42:14", "formatted_date_created": "一月 12, 2022", "date_created_gmt": "2022-01-12T15:42:14", "product_id": 33, "product_name": "带有Logo的帽子", "product_permalink": "https://store.local/product/beanie-with-logo/", "product_image": { "id": 56, "src": "https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1.jpg", "thumbnail": "https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-324x324.jpg", "srcset": "https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1.jpg 800w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-324x324.jpg 324w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-100x100.jpg 100w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-416x416.jpg 416w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-300x300.jpg 300w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-150x150.jpg 150w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "beanie-with-logo-1.jpg", "alt": "" }, "reviewer": "reviewer-name", "review": "

这是一个非常棒的产品。

\n", "rating": 5, "verified": true, "reviewer_avatar_urls": { "24": "https://secure.gravatar.com/avatar/12345?s=24&d=mm&r=g", "48": "https://secure.gravatar.com/avatar/12345?s=48&d=mm&r=g", "96": "https://secure.gravatar.com/avatar/12345?s=96&d=mm&r=g" } } ] 产品信息 本页面展示了产品信息。 字段说明 id: 产品ID date_created: 创建日期 formatted_date_created: 格式化的创建日期 product_id: 产品ID product_name: 产品名称 product_permalink: 固定链接 product_image: 产品图片信息 src: 图片网址 thumbnail: 缩略图网址 srcset: 图片集合 sizes: 图片尺寸 name: 图片名称 alt: 图片描述 reviewer: 评价者 review: 评价内容 rating: 评分 verified: 是否为已验证的评价 reviewer_avatar_urls: 评价者头像网址 示例 以下是一个产品评价的示例: [ { "id": 83, "date_created": "2022-01-12T15:42:14", "formatted_date_created": "January 12, 2022", "product_id": 33, "product_name": "Beanie with Logo", "product_permalink": "https://store.local/product/beanie-with-logo/", "product_image": { ... }, "reviewer": "reviewer-name", "review": "

This is a fantastic product.

\n", "rating": 5, "verified": true, "reviewer_avatar_urls": { ... } } ] 详细信息 date_created: 表示产品创建的日期和时间。 product_name: 产品的名称。 product_permalink: 指向产品详情页面的固定链接。 product_image: 包含产品图片的各种尺寸和格式的信息。 review: 用户对产品的评价内容。 rating: 用户对产品的评分,通常是 1 到 5 之间的数字。 verified: 指示该评价是否已通过验证。 上传文件 您可以通过点击“上传”按钮来上传文件。上传完成后,您可以设置文件的标题、描述和固定链接。 创建新产品 要创建新产品,请点击“创建”按钮。您需要填写产品名称、描述、价格、图片等信息。 商店设置 在商店设置中,您可以配置商店的名称、地址、联系方式、支付方式、运费规则等。 日志 Log文件记录了系统的运行状态和错误信息。 宽度 Width参数用于设置图像的宽度。 头像 Avatar是用户在论坛或社交媒体上使用的个人图像。 格式 Format是指文件或数据的格式,例如文本格式、图像格式等。 链接 Link是指网页之间的连接。 内容 Content是指文章或网页的文本和媒体。 评分 Rating是指用户对产品或服务的评价。 评价 Review是指用户对产品或服务的详细评价。 为 For表示为了。 在 In表示在...里面。 产品 Product是指商店中销售的商品。 日期 Date是指年月日。 增值税 VAT是指增值税。 已创建 Created表示已经创建。 网址 Url是指网址。 产品标签 API 列出产品标签 GET /products/tags 属性 类型 必需 描述 context 字符串 否 发送请求的范围;决定响应中包含的字段。 page 整数 否 集合的当前页。默认为 1。 per_page 整数 否 结果集中返回的最大项目数。默认为无限制。允许的值在 0 和 100 之间。 search 字符串 否 限制结果,仅包含匹配的字符串。 exclude 数组 否 确保结果集排除特定的 ID。 include 数组 否 限制结果集为特定的 ID。 order 字符串 否 升序或降序排序。允许的值: asc, desc。默认为 asc。 orderby 字符串 否 按属性排序。允许的值: name, slug, count。默认为 name。 hide_empty 布尔值 否 如果为 true,则不返回空项。默认为 true。 curl "https://example-store.com/wp-json/wc/store/v1/products/tags" 示例响应: [ { "id": 1, "name": "Test Tag", "slug": "test-tag", "description": "", "parent": 0, "count": 1 }, { "id": 2, "name": "Another Tag", "slug": "another-tag", "description": "", "parent": 0, "count": 1 } ] 产品 API 该商店产品 API 提供公开的产品数据,以便在客户端进行渲染。 列表产品 GET /products GET /products?search=产品名称 GET /products?slug=别名-1,别名-2 GET /products?after=2017-03-22&date_column=日期 GET /products?before=2017-03-22&date_column=日期 GET /products?exclude=10,44,33 GET /products?include=10,44,33 GET /products?offset=10 GET /products?order=asc&orderby=价格 GET /products?parent=10 GET /products?parent_exclude=10 GET /products?type=simple GET /products?sku=sku-1,sku-2 GET /products?featured=true GET /products?category=22 GET /products?brand=adidas GET /products?_unstable_tax_my-taxonomy=my-taxonomy-term-id GET /products?tag=special-items GET /products?attributes[0][attribute]=pa_color&attributes[0][slug]=red GET /products?on_sale=true GET /products?min_price=5000 GET /products?max_price=10000 GET /products?stock_status=['outofstock'] GET /products?catalog_visibility=search GET /products?rating=4,5 GET /products?related=34 GET /products?return_price_range=true GET /products?return_attribute_counts=pa_size,pa_color GET /products?return_rating_counts=true 产品查询参数 以下参数可用于限制产品查询结果。 属性 类型 是否必填 描述 search 字符串 否 限制结果,仅包含匹配的字符串。 slug 字符串 否 限制结果集,仅包含具有特定别名(s)的产品。 使用逗号分隔。 after 字符串 否 限制响应,仅包含在给定符合ISO8601标准的日期之后创建的资源。 before 字符串 否 限制响应,仅包含在给定符合ISO8601标准的日期之前创建的资源。 date_column 字符串 否 当限制响应时,用于比较的日期列。 允许的值: date, date_gmt, modified, modified_gmt exclude 数组 否 确保结果集排除特定的ID。 include 数组 否 限制结果集,仅包含特定的ID。 offset 整数 否 偏移结果集,从指定的项目数开始。 order 字符串 否 指定排序属性的升序或降序。 允许的值: asc, desc orderby 字符串 否 按照对象属性对集合进行排序。 允许的值: date, modified, id, include, title, slug, price, popularity, rating, menu_order, comment_count parent 数组 否 限制结果集,仅包含特定父ID的产品。 parent_exclude 数组 否 限制结果集,排除所有具有特定父ID的产品。 type 字符串 否 限制结果集,仅包含分配了特定类型的的产品。 sku 字符串 否 限制结果集,仅包含具有特定SKU(s)的产品。 使用逗号分隔。 featured 布尔值 否 限制结果集,仅包含推荐的产品。 category 字符串 否 限制结果集,仅包含分配到分类ID或别名(s)的产品,用逗号分隔。 category_operator 字符串 否 用于比较产品分类的运算符。 允许的值: in, not_in, and brand 字符串 否 限制结果集,仅包含分配到品牌ID或别名(s)的产品,用逗号分隔。 brand_operator 字符串 否 用于比较产品品牌术语的运算符。 允许的值: in, not_in, and _unstable_tax_[product-taxonomy] 字符串 否 限制结果集,仅包含分配到自定义产品分类术语ID的产品。 [product-taxonomy] 应该是已注册的自定义产品分类的键。 _unstable_tax_[product-taxonomy]_operator 字符串 否 用于比较自定义产品分类术语的运算符。 允许的值: in, not_in, and tag 字符串 否 限制结果集,仅包含分配了特定标签ID的产品。 tag_operator 字符串 否 用于比较产品标签的运算符。 允许的值: in, not_in, and on_sale 布尔值 否 限制结果集,仅包含正在促销的产品。 min_price 字符串 否 限制结果集,仅包含基于最小价格的产品,价格使用货币的最小单位表示。 例如,对于使用两位小数的货币(如USD),提供10025表示100.25,对于使用零小数的货币(如JPY),提供1025表示1025。 max_price 字符串 否 限制结果集,仅包含基于最大价格的产品,价格使用货币的最小单位表示。 例如,对于使用两位小数的货币(如USD),提供10025表示100.25,对于使用零小数的货币(如JPY),提供1025表示1025。 stock_status 数组 否 限制结果集,仅包含具有指定库存状态的产品。 期望的是一个包含字符串的数组,字符串可以是'instock'、'outofstock'或'onbackorder'。 attributes 数组 否 限制结果集,仅包含特定属性术语的产品。 期望的是一个对象数组,每个对象包含 attribute(分类), term_id或 slug,以及可选的 operator用于比较。 attribute_relation 字符串 否 当同时过滤多个属性时,属性之间的逻辑关系。 catalog_visibility 字符串 否 确定是否显示隐藏或可见的目录产品。 允许的值: any, visible, catalog, search, hidden rating 数组 否 限制结果集,仅包含具有特定平均评分的产品。 允许的值: 1, 2, 3, 4, 5. related 整数 否 限制结果集,仅包含与特定产品ID相关的产品。 产品信息示例 以下是一个产品信息的示例,展示了如何获取和显示产品数据。 示例响应: [ { "id": 34, "name": "WordPress Pennant", "slug": "wordpress-pennant", "variation": "", "permalink": "https://local.wordpress.test/product/wordpress-pennant/", "sku": "wp-pennant", "summary": "

This is an external product.

", "short_description": "

This is an external product.

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "on_sale": false, "prices": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "price": "1105", "regular_price": "1105", "sale_price": "1105", "price_range": null }, "average_rating": "0", "review_count": 0, "images": [ { "id": 57, "src": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg 800w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg 324w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-416x416.jpg 416w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "pennant-1.jpg", "alt": "" } ], "has_options": false, "is_purchasable": true, "is_in_stock": true, "low_stock_remaining": null, "add_to_cart": { "text": "Add to cart", "description": "Add “WordPress Pennant” to your cart" } } ] 字段说明: id: 产品ID。 name: 产品名称。 slug: 产品的别名。 variation: 产品的变体。 permalink: 产品的固定链接。 sku: 产品的库存单位。 summary: 产品的摘要。 short_description: 产品的简短描述。 description: 产品的详细描述。 on_sale: 是否正在促销。 prices: 价格信息,包括货币代码、符号、小数位数、分隔符、前缀、后缀、价格、原价、折扣价和价格范围。 average_rating: 平均评分。 review_count: 评论数量。 images: 产品图像列表。 has_options: 是否有选项。 is_purchasable: 是否可购买。 is_in_stock: 是否有库存。 low_stock_remaining: 库存剩余量(如果库存不足)。 add_to_cart: "加入购物车"按钮的文本和描述。 如何获取产品信息: 可以使用以下 curl 命令从商店获取产品信息: curl "https://example-store.com/wp-json/wc/store/v1/products" 示例: Permalink: 固定链接 Variation: 变体 Link: 链接 Slug: 别名 External Product: 外部产品 Add to Cart: 加入购物车 Remaining: 剩余 Currency: 货币 Summary: 摘要 Product: 产品 Images: 图像 Upload: 上传 Prefix: 前缀 Option: 选项 Suffix: 后缀 Width: 宽度 Stock: 库存 range: 范围 Store: 商店 Done: 完成 通过 ID 获取单个产品 获取指定 ID 的单个产品。 GET /products/:id 属性 类型 是否必选 描述 id integer 是 要检索的产品的 ID。 curl "https://example-store.com/wp-json/wc/store/v1/products/34" 示例响应: { "id": 34, "name": "WordPress Pennant", "slug": "wordpress-pennant", "variation": "", "permalink": "https://local.wordpress.test/product/wordpress-pennant/", "sku": "wp-pennant", "summary": "

This is an external product.

", "short_description": "

This is an external product.

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "on_sale": false, "prices": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "price": "1105", "regular_price": "1105", "sale_price": "1105", "price_range": null }, "average_rating": "0", "review_count": 0, "images": [ { "id": 57, "src": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg 800w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg 324w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-416x416.jpg 416w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "pennant-1.jpg", "alt": "" } ], "has_options": false, "is_purchasable": true, "is_in_stock": true, "low_stock_remaining": null, "add_to_cart": { "text": "Add to cart", "description": "Add “WordPress Pennant” to your cart" } } 通过别名获取单个产品 通过别名获取单个产品。 GET /products/:slug 属性 类型 是否必选 描述 slug string 是 用于检索产品的别名。 curl "https://example-store.com/wp-json/wc/store/v1/products/wordpress-pennant" 示例响应: { "id": 34, "name": "WordPress Pennant", "slug": "wordpress-pennant", "variation": "", "permalink": "https://local.wordpress.test/product/wordpress-pennant/", "sku": "wp-pennant", "summary": "

这是一个外部产品。

", "short_description": "

这是一个外部产品。

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "on_sale": false, "prices": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "price": "1105", "regular_price": "1105", "sale_price": "1105", "price_range": null }, "average_rating": "0", "review_count": 0, "images": [ { "id": 57, "src": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg 800w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg 324w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-416x416.jpg 416w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "pennant-1.jpg", "alt": "" } ], "has_options": false, "is_purchasable": true, "is_in_stock": true, "low_stock_remaining": null, "add_to_cart": { "text": "加入购物车", "description": "将“WordPress Pennant”添加到您的购物车" } } 产品链接和嵌入 产品响应包含 _links,其中提供指向相关资源的 URL。当产品配置了追加销售、交叉销售或相关产品时,会包含可嵌入的链接,这些链接可与 WordPress 的 _embed 功能一起使用。 可用的链接 链接 描述 可嵌入 self 链接至当前产品 No collection 链接至产品集合 No up 链接至父产品 (用于变体) No upsells 链接用于获取追加销售产品 (如果已配置) Yes cross_sells 链接用于获取交叉销售产品 (如果已配置) Yes related 链接用于获取相关产品 Yes 包含链接的示例响应 { "id": 34, "name": "WordPress Pennant", "_links": { "self": [{"href": "https://local.wordpress.test/wp-json/wc/store/v1/products/34"}], "collection": [{"href": "https://local.wordpress.test/wp-json/wc/store/v1/products"}], "upsells": [{"href": "https://local.wordpress.test/wp-json/wc/store/v1/products?include=10,20", "embeddable": true}], "cross_sells": [{"href": "https://local.wordpress.test/wp-json/wc/store/v1/products?include=30", "embeddable": true}], "related": [{"href": "https://local.wordpress.test/wp-json/wc/store/v1/products?related=34&per_page=10", "embeddable": true}] } } 使用 _embed 参数 向任何产品请求添加 ?_embed,即可自动获取并包含链接的资源,并将它们嵌入到 _embedded 对象中: curl "https://local.wordpress.test/wp-json/wc/store/v1/products/34?_embed" 包含嵌入的示例响应: { "id": 34, "name": "WordPress Pennant", "_links": { "self": [{"href": "https://local.wordpress.test/wp-json/wc/store/v1/products/34"}], "collection": [{"href": "https://local.wordpress.test/wp-json/wc/store/v1/products"}], "upsells": [{"href": "https://local.wordpress.test/wp-json/wc/store/v1/products?include=10,20", "embeddable": true}] }, "_embedded": { "upsells": [ {"id": 10, "name": "追加销售产品 1", "...": "..."}, {"id": 20, "name": "追加销售产品 2", "...": "..."} ] } } 产品变体 默认情况下,商店 API 排除产品变体。 您可以使用 type=variation 参数来检索产品的变体。 curl "https://example-store.com/wp-json/wc/store/v1/products?type=variation" 购物车 API 购物车 API 返回当前会话或登入用户的购物车当前状态。 所有 POST 端点都需要一个随机数令牌或一个购物车令牌,并在完成后返回完整购物车的已更新状态。 获取购物车 GET /cart 此端点无需任何参数。 curl "https://example-store.com/wp-json/wc/store/v1/cart" 返回完整的购物车对象回复(参见购物车回复)。 回复 所有 /cart 下的端点(本文档中列出的)均以相同格式返回回复;一个包含购物车项目、已应用优惠券、配送地址和费率,以及非敏感客户数据的购物车对象。 购物车回复 本节描述了购物车相关的回复。 请求参数: cart_id: 购物车ID (整数) user_id: 用户ID (整数) 请求示例: GET /api/v1/cart/%s?user_id=%d 回复格式: { "status": "success", "data": { "cart_id": %d, "user_id": %d, "items": [ { "product_id": %d, "quantity": %d } ] } } 错误代码: 代码 描述 400 错误的请求参数。 401 未授权。 404 购物车不存在。 500 服务器内部错误。 示例回复: { "status": "success", "data": { "cart_id": 123, "user_id": 456, "items": [ { "product_id": 789, "quantity": 2 } ] } } 错误回复示例: { "status": "error", "code": 404, "message": "Cart not found." } 注意事项: status 字段表示请求是否成功。 data 字段包含购物车信息。 code 字段表示错误代码。 message 字段包含错误信息。 其他: on 状态表示购物车已启用。 off 状态表示购物车已禁用。 函数: get_cart_response(cart_id, user_id): 获取购物车回复。 create_cart(user_id): 创建新的购物车。 update_cart_item(cart_id, product_id, quantity): 更新购物车中的商品数量。 delete_cart_item(cart_id, product_id): 从购物车中删除商品。 clear_cart(cart_id): 清空购物车。 { "items": [ { "key": "a5771bce93e200c36f7cd9dfd0e5deaa", "id": 38, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 9999, "multiple_of": 1, "editable": true }, "name": "带有Logo的帽子", "short_description": "

这是一个简单的产品。

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "Woo-beanie-logo", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://local.wordpress.test/product/beanie-with-logo/", "images": [ { "id": 61, "src": "https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-450x450.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1.jpg 800w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-450x450.jpg 450w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-600x600.jpg 600w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2023/03/beanie-with-logo-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "beanie-with-logo-1.jpg", "alt": "" } ], "variation": [], "item_data": [], "prices": { "price": "1800", "regular_price": "2000", "sale_price": "1800", "price_range": null, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "", "raw_prices": { "precision": 6, "price": "18000000", "regular_price": "20000000", "sale_price": "18000000" } }, "totals": { "line_subtotal": "1800", "line_subtotal_tax": "180", "line_total": "1530", "line_total_tax": "153", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "catalog_visibility": "visible", "extensions": {} }, { "key": "b6d767d2f8ed5d21a44b0e5886680cb9", "id": 22, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 9999, "multiple_of": 1, "editable": true }, "name": "腰带", "short_description": "

这是一个简单的产品。

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "woo-belt", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://local.wordpress.test/product/belt/", "images": [ { "id": 51, "src": "https://local.wordpress.test/wp-content/uploads/2023/03/belt-2.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-450x450.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2023/03/belt-2.jpg 801w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-450x450.jpg 450w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-600x600.jpg 600w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2023/03/belt-2-768x768.jpg 768w", "sizes": "(max-width: 801px) 100vw, 801px", "name": "belt-2.jpg", "alt": "" } ], "variation": [], "item_data": [], "prices": { "price": "5500", "regular_price": "6500", "sale_price": "5500", "price_range": null, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "", "raw_prices": { "precision": 6, "price": "55000000", "regular_price": "65000000", "sale_price": "55000000" } }, "totals": { "line_subtotal": "5500", "line_subtotal_tax": "550", "line_total": "4675", "line_total_tax": "468", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "catalog_visibility": "visible", "extensions": {} } ], "coupons": [ { "code": "test", "discount_type": "percent", "totals": { "total_discount": "1095", "total_discount_tax": "109", "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" } } ], "fees": [], "totals": { "total_items": "7300", "total_items_tax": "730", "total_fees": "0", "total_fees_tax": "0", "total_discount": "1095", "total_discount_tax": "110", "total_shipping": "1300", "total_shipping_tax": "130", "total_price": "8256", "total_tax": "751", "tax_lines": [ { "name": "税费", "price": "751", "rate": "10%" } ], "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, "shipping_address": { "first_name": "John", "last_name": "Doe", "company": "", "address_1": "Hello street", "address_2": "", "city": "beverly hills", "state": "CA", "postcode": "90211", "country": "US", "phone": "123456778" }, "billing_address": { "first_name": "John", "last_name": "Doe", "company": "", "address_1": "Hello street", "address_2": "", "city": "beverly hills", "state": "CA", "postcode": "90211", "country": "US", "email": "checkout@templates.com", "phone": "123456778" }, "needs_payment": true, "needs_shipping": true, "payment_requirements": [ "products" ], "has_calculated_shipping": true, "shipping_rates": [ { "package_id": 0, "name": "Shipment 1", "destination": { "address_1": "Hello street", "address_2": "", "city": "beverly hills", "state": "CA", "postcode": "90211", "country": "US" }, "items": [ { "key": "a5771bce93e200c36f7cd9dfd0e5deaa", "name": "带有Logo的帽子", "quantity": 1 }, { "key": "b6d767d2f8ed5d21a44b0e5886680cb9", "name": "腰带", "quantity": 1 } ], "shipping_rates": [ { "rate_id": "flat_rate:10", "name": "统一费率", "description": "", "delivery_time": "", "price": "1300", "taxes": "130", "instance_id": 10, "method_id": "flat_rate", "meta_data": [ { "key": "Items", "value": "带有Logo的帽子 × 1, 腰带 × 1" } ], "selected": true, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, { "rate_id": "free_shipping:12", "name": "免费配送", "description": "", "delivery_time": "", "price": "0", "taxes": "0", "instance_id": 12, "method_id": "free_shipping", "meta_data": [ { "key": "Items", "value": "带有Logo的帽子 × 1, 腰带 × 1" } ], "selected": false, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" }, { "rate_id": "local_pickup:13", "name": "本地自提", "description": "", "delivery_time": "", "price": "0", "taxes": "0", "instance_id": 13, "method_id": "local_pickup", "meta_data": [ { "key": "Items", "value": "带有Logo的帽子 × 1, 腰带 × 1" } ], "selected": false, "currency_code": "USD", "currency_symbol": "$", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "$", "currency_suffix": "" } ] } ], "items_count": 2, "items_weight": 0, "cross_sells": [], "errors": [], "payment_methods": [ "bacs", "cod" ], "extensions": {} } 错误回复 如果无法执行购物车操作,将返回一个错误回复。 这将包含一个错误代码和一个错误消息: { "code": "woocommerce_rest_cart_invalid_product", "message": "该产品无法添加到购物车。", "data": { "status": 400 } } 某些错误回复表示冲突(错误 409),例如,当某个项目无法找到或优惠券不再生效时。 当返回此类回复时,服务器的购物车当前状态也会作为错误数据的一部分返回: { "code": "woocommerce_rest_cart_invalid_key", "message": "购物车项目不再存在或无效。", "data": { "status": 409, "cart": { ... } } } 这允许客户端在不发出额外请求的情况下,与购物车数据保持同步,即使购物车发生更改或已过期。 添加项目 将项目添加到购物车,并返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此端点将返回一个错误。 POST /cart/add-item 属性 类型 必需 描述 id integer 是 购物车中商品的 ID 或变体 ID。 quantity integer 是 购物车中此商品的数量。 variation array 是 选择的属性(用于变体),包含一个对象数组,每个对象包含键 attribute 和 value。 请注意,关于属性命名的说明见下文。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/add-item?id=100&quantity=1 如果成功,则返回完整的 购物车响应;如果失败,则返回一个 错误响应。 如果您希望在将购物车项目数据传递给 CartController::add_to_cart 之前添加补充数据,可以使用 woocommerce_store_api_add_to_cart_data 过滤器。 例如: add_filter( 'woocommerce_store_api_add_to_cart_data', function( $add_to_cart_data, \WP_REST_Request $request ) { if ( ! empty( $request['custom-request-param'] ) ) { $add_to_cart_data['cart_item_data']['custom-request-data'] = sanitize_text_field( $request['custom-request-param'] ); } return $add_to_cart_data; }, 10, 2 ); 变体属性命名: 在将变体添加到购物车时,属性的命名非常重要。 对于全局属性,发布到 API 的属性应该是属性的别名。 应该有一个 pa_ 前缀。 例如,如果您的属性名为 Color,则别名为 pa_color。 对于特定于产品的属性,发布到 API 的属性可以是以下之一: 属性的名称。 例如,如果您的属性名为 Size,则名称为 Size。 这对大小写敏感。 属性的别名。 例如,如果您的属性名为 Autograph ✏️,则名称为 attribute_autograph-%e2%9c%8f%ef%b8%8f。 这对大小写敏感。 您可以从产品页面的相关 select 中获取此别名。 示例 POST 请求体: # 添加商品变体到购物车 以下示例向购物车添加了一个商品变体,该变体具有尺寸和颜色等属性。 **批量操作:** 如果您想一次性添加多个项目,则需要使用批量接口: ```http POST /wc/store/v1/batch 向购物车添加多个项目的 JSON 数据格式如下: { "requests": [ { "path": "/wc/store/v1/cart/add-item", "method": "POST", "cache": "no-store", "body": { "id": 26, "quantity": 1 }, "headers": { "Nonce": "1db1d13784" } }, { "path": "/wc/store/v1/cart/add-item", "method": "POST", "cache": "no-store", "body": { "id": 27, "quantity": 1 }, "headers": { "Nonce": "1db1d13784" } } ] } { "id": 13, "quantity": 1, "variation": [ { "attribute": "pa_color", "value": "blue" }, { "attribute": "attribute_autograph-%e2%9c%8f%ef%b8%8f", "value": "Yes" }, { "attribute": "Logo", "value": "Yes" } ] } 该示例添加了一个具有尺寸和颜色属性的产品变体到购物车。 Batching: 如果您想一次添加多个项目,您需要使用批量接口: POST /wc/store/v1/batch 用于向购物车添加多个项目的 JSON 数据如下: { "requests": [ { "path": "/wc/store/v1/cart/add-item", "method": "POST", "cache": "no-store", "body": { "id": 26, "quantity": 1 }, "headers": { "Nonce": "1db1d13784" } }, { "path": "/wc/store/v1/cart/add-item", "method": "POST", "cache": "no-store", "body": { "id": 27, "quantity": 1 }, "headers": { "Nonce": "1db1d13784" } } ] } 解释: Variation: 变体 Nonce: 随机数 Attribute: 属性 Quantity: 数量 Requests: 请求 Product: 产品 Method: 方法 Cache: 缓存 Color: 颜色 Value: 价值 Store: 商店 Path: 路径 Auto: 自动 Blue: 蓝色 Cart: 购物车 Item: 项目 Log: 日志 and: 和 Use: 使用 For: 为 移除项目 从购物车中移除一个项目并返回完整的购物车响应,或一个错误。 除非提供有效的随机数令牌或购物车令牌,否则此端点将返回一个错误。 POST /cart/remove-item 属性 类型 是否必需 描述 key 字符串 是 要编辑的购物车项目的关键字。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/remove-item?key=e369853df766fa44e1ed0ff613f563bd 成功时返回完整的购物车响应,失败时返回错误响应。 更新项目 更新购物车中的项目并返回完整的购物车响应,或错误信息。 除非提供有效的随机数令牌或购物车令牌,否则此端点将返回错误。 POST /cart/update-item 属性 类型 是否必需 描述 key 字符串 是 要编辑的购物车项目的键。 quantity 整数 是 此项目在购物车中的数量。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/update-item?key=e369853df766fa44e1ed0ff613f563bd&quantity=10 成功时返回完整的购物车响应,失败时返回错误响应。 应用优惠券 将优惠券应用于购物车并返回完整的购物车响应,或一个错误。 除非提供了有效的随机数令牌或购物车令牌,否则此端点将返回一个错误。 POST /cart/apply-coupon/ 属性 类型 是否必需 描述 code 字符串 是 您希望应用于购物车的优惠券代码。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/apply-coupon?code=20off 成功时返回完整的购物车响应,失败时返回错误响应。 移除优惠券 从购物车中移除一个优惠券,并返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 或 购物车令牌,否则此接口将返回一个错误。 POST /cart/remove-coupon/ 属性 类型 必需 描述 code 字符串 是 您希望从购物车中移除的优惠券代码。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/cart/remove-coupon?code=20off 在成功时,返回完整的 购物车响应,在失败时,返回一个 错误响应。 更新客户信息 更新客户信息,并返回完整的购物车信息,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此 API 将返回一个错误。 POST /cart/update-customer 客户地址信息 本节描述了客户地址信息的结构。 属性 类型 必填 描述 billing_address object 否 客户的账单地址。 billing_address.first_name string 否 客户的名。 billing_address.last_name string 否 客户的姓氏。 billing_address.address_1 string 否 配送地址的第一行。 billing_address.address_2 string 否 配送地址的第二行。 billing_address.city string 否 配送地址的城市。 billing_address.state string 否 州、省或地区的 ISO 代码,或名称,用于表示配送地址。 billing_address.postcode string 否 配送地址的邮政编码。 billing_address.country string 否 配送地址所在国家的 ISO 代码。 billing_address.email string 否 客户的邮件地址。 billing_address.phone string 否 客户的电话号码。 shipping_address object 否 客户的配送地址。 shipping_address.first_name string 否 客户的名。 shipping_address.last_name string 否 客户的姓氏。 shipping_address.address_1 string 否 配送地址的第一行。 shipping_address.address_2 string 否 配送地址的第二行。 shipping_address.city string 否 配送地址的城市。 shipping_address.state string 否 州、省或地区的 ISO 代码,或名称,用于表示配送地址。 shipping_address.postcode string 否 配送地址的邮政编码。 shipping_address.country string 否 配送地址所在国家的 ISO 代码。 以下是一些示例: # 示例 1: 创建一个包含账单地址和配送地址的客户对象。 customer = { "billing_address": { "first_name": "名", "last_name": "姓氏", "address_1": "地址", "address_2": "", "city": "城市", "state": "州", "postcode": "邮政编码", "country": "国家", "email": "邮件", "phone": "电话号码" }, "shipping_address": { "first_name": "名", "last_name": "姓氏", "address_1": "地址", "address_2": "", "city": "城市", "state": "州", "postcode": "邮政编码", "country": "国家" } } # 示例 2: 设置一个客户的属性。 set_customer_attribute(customer, "description", "描述") # 示例 3: 获取一个数值。 number = get_number() # 示例 4: 循环 %d 秒。 for i in range(1, %d): print("一 %s 秒" % "second") # 示例 5: 检查一个条件。 if no: print("否") else: print("是") # 示例 6: 使用 Code 请注意, String 是一个 String 类型。 Phone Number 必须是有效的 Phone Number。 First name 不能为空。 Attribute 必须是有效的 Attribute。 Last Name 不能为空。 Shipping 必须是有效的 Shipping 地址。 Address 必须是有效的 Address。 Second 表示 Second。 number 表示 number。 Code 表示 Code。 Mail 表示 Mail。 Red 表示 Red。 one 表示 one。 For 表示 For。 In 表示 In。 No 表示 No。 Shipping Address 表示 Shipping Address。 Description 表示 Description。 Customer 表示 Customer。 返回全部的 购物车回复,如果成功;否则,返回一个 错误回复。 选择配送费率 选择一个可用的配送费率,然后返回完整的购物车响应,或者返回一个错误。 除非提供了有效的 随机数 Token 或 购物车 Token,否则此接口将返回一个错误。 POST /cart/select-shipping-rate 属性 类型 必需 描述 package_id integer 是 购物车中配送包的 ID。 rate_id string 是 选定的配送包的费率 ID。 curl --header "Nonce: 12345" --request POST /cart/select-shipping-rate?package_id=1&rate_id=flat_rate:1 在成功时,返回完整的 购物车响应,在失败时,返回一个 错误响应。 结账订单 API 结账订单 API 旨在简化现有订单的处理和付款操作。 所有结账订单接口都需要一个 随机数 Token 或一个 购物车 Token,否则这些接口将返回一个错误。 处理订单和支付 接受最终选择的支付方法,以及任何额外的支付数据,然后尝试支付并返回结果。 POST /wc/store/v1/checkout/{ORDER_ID} 属性 类型 必需 描述 key 字符串 是 用于订单验证的密钥。 billing_email 字符串 否 用于验证访客订单的 Email 地址。 billing_address 对象 是 客户已更新的账单地址数据对象。 shipping_address 对象 是 客户已更新的配送地址数据对象。 payment_method 字符串 是 用于处理支付的支付方法 ID。 payment_data 数组 否 在处理支付时传递给支付方法的数据。 curl --header "Nonce: 12345" --request POST https://example-store.com/wp-json/wc/store/v1/checkout/{ORDER_ID} -d '{"key":"wc_order_oFmQYREzh9Tfv","billing_email":"admin@example.com","payment_method":"cheque","billing_address":{...},"shipping_address":{...}' 示例请求: { "key": "wc_order_oFmQYREzh9Tfv", "billing_email": "admin@example.com", "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "phone": "555-2368" }, "payment_method": "cheque", "payment_data": [] } 示例响应: # 订单详情 以下是订单的详细信息。 **订单 ID:** %d **状态:** %s ## 订单概览 * **订单 ID:** %d * **状态:** %s * **订单 Key:** %s * **客户备注:** %s * **客户 ID:** %d ## 账单地址 * **地址:** * **姓名:** %s * **公司:** %s * **地址 1:** %s * **地址 2:** %s * **城市:** %s * **州/省:** %s * **邮编:** %s * **国家:** %s * **邮箱:** %s * **电话:** %s ## 配送地址 * **地址:** * **姓名:** %s * **公司:** %s * **地址 1:** %s * **地址 2:** %s * **城市:** %s * **州/省:** %s * **邮编:** %s * **国家:** %s * **电话:** %s ## 支付信息 * **支付方法:** %s * **支付结果:** * **支付状态:** %s * **支付详情:** %s * **重定向 URL:** %s ## 订单管理 * **管理员:** 只有管理员才能查看和修改订单信息。 * **检查:** 定期检查订单状态,确保顺利完成。 * **锁定:** 在处理订单时,可以锁定订单以防止其他用户修改。 * **邮件:** 系统会发送邮件通知客户订单状态更新。 * **新增:** 管理员可以新增订单。 * **红色:** 某些情况下,订单状态会显示为红色,表示存在问题。 * **网址:** 请注意以下网址。 * **关键字:** 使用关键字进行订单搜索。 ```json { "order_id": 146, "status": "on-hold", "order_key": "wc_order_oFmQYREzh9Tfv", "customer_note": "", "customer_id": 1, "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "phone": "555-2368" }, "payment_method": "cheque", "payment_result": { "payment_status": "success", "payment_details": [], "redirect_url": "https://local.wordpress.test/block-checkout/order-received/146/?key=wc_order_VPffqyvgWVqWL" } } 常见问题 如何修改订单信息? 只有管理员可以修改订单信息。 如何取消订单? 请联系客服进行取消。 如何查看订单状态? 您可以在账户中查看订单状态。 如何进行退货? 请参考我们的退货政策。 配送时间是多久? 配送时间取决于您的地址和选择的配送方式。 结账时遇到了问题,怎么办? 请联系客服寻求帮助。 如何联系客服? 您可以通过邮件或电话联系客服。 测试环境: 这是测试环境,所有数据均为测试数据。 ## 支付数据 有很多支付网关可供商家使用,并且每个网关都期望接收不同的 `payment_data`。 我们无法全面列出所有支付网关期望的所有请求,因此我们建议您联系您正在使用的支付网关插件的作者,以获取更多信息。 以下是一个使用 [WooCommerce Stripe 支付网关](https://wordpress.org/plugins/woocommerce-gateway-stripe/) 时,发送到结账订单端点的支付数据的示例。 有关生成 `stripe_source` 的更多信息,请查看 [Stripe 文档](https://stripe.com/docs)。 ```json { "payment_data": [ { "key": "stripe_source", "value": "src_xxxxxxxxxxxxx" }, { "key": "billing_email", "value": "myemail@email.com" }, { "key": "billing_first_name", "value": "Jane" }, { "key": "billing_last_name", "value": "Doe" }, { "key": "paymentMethod", "value": "stripe" }, { "key": "paymentRequestType", "value": "cc" }, { "key": "wc-stripe-new-payment-method", "value": true } ] } 订单 API 订单 API 返回用于支付的订单。 获取订单 GET /order/{ORDER_ID}?key={KEY}&billing_email={BILLING_EMAIL} 此端点有一个必填参数,即 key。对于访客订单,必须添加 billing_email。 curl "https://example-store.com/wp-json/wc/store/v1/order/{ORDER_ID}?key={KEY}&billing_email={BILLING_EMAIL}" 返回完整的订单对象回复(参见订单回复)。 回复 订单端点返回的回复格式与 /cart 相同;一个订单对象,其中包含订单项目、已应用的优惠券、配送地址和费率,以及非敏感的客户数据。 订单回复 本节描述了系统对订单的回复。 响应格式 回复采用以下 JSON 格式: { "status": "success" | "failed", "order_id": "%s", "message": "操作成功" | "订单不存在" | "支付失败" | "其他错误信息" } status: 表示操作的成功或失败。 order_id: 订单的唯一标识符。 message: 包含操作结果的详细信息。 成功回复 (status: success) 当订单处理成功时,系统会返回以下回复: { "status": "success", "order_id": "%s", "message": "操作成功" } 失败回复 (status: failed) 当订单处理失败时,系统会返回以下回复: { "status": "failed", "order_id": "%s", "message": "订单不存在" | "支付失败" | "其他错误信息" } 错误处理 如果出现错误,系统会返回 status: failed 的回复,并包含详细的错误信息。 例如,如果订单不存在,系统会返回: { "status": "failed", "order_id": "%s", "message": "订单不存在" } API 使用示例 以下是一个使用 getOrderResponse 函数的示例: def getOrderResponse(order_id): """ 获取订单的回复。 Args: order_id: 订单的 ID。 Returns: 一个包含回复信息的字典。 """ # ... (省略实现细节) ... return { "status": "success", "order_id": order_id, "message": "操作成功" } 其他说明 getOrderResponse 函数可能返回不同的 message 值,具体取决于订单的状态。 如果 order_id 无效, getOrderResponse 函数会返回 status: failed 的回复。 系统会记录所有订单操作,包括成功和失败的回复。 %s 是一个占位符,表示要插入的字符串值。 {name} 是一个占位符,表示要插入的变量名。 Or 表示“或”。 on 表示“开”。 Response 表示“回复”。 { "id": 147, "status": "待审", "coupons": [ { "code": "discount20", "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "total_discount": "421", "total_discount_tax": "0" } } ], "shipping_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "phone": "555-2368" }, "billing_address": { "first_name": "Peter", "last_name": "Venkman", "company": "", "address_1": "550 Central Park West", "address_2": "Corner Penthouse Spook Central", "city": "New York", "state": "NY", "postcode": "10023", "country": "US", "email": "admin@example.com", "phone": "555-2368" }, "items": [ { "key": "9bf31c7ff062936a96d3c8bd1f8f2ff3", "id": 15, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 99, "multiple_of": 1, "editable": true }, "name": "Beanie", "short_description": "

This is a simple product.

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "woo-beanie", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://local.wordpress.test/product/beanie/", "images": [ { "id": 44, "src": "https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-324x324.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2.jpg 801w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-324x324.jpg 324w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-416x416.jpg 416w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2020/03/beanie-2-768x768.jpg 768w", "sizes": "(max-width: 801px) 100vw, 801px", "name": "beanie-2.jpg", "alt": "" } ], "variation": [], "prices": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "price": "1000", "regular_price": "2000", "sale_price": "1000", "price_range": null, "raw_prices": { "precision": 6, "price": "10000000", "regular_price": "20000000", "sale_price": "10000000" } }, "item_data": [], "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "line_subtotal": "1000", "line_subtotal_tax": "0", "line_total": "800", "line_total_tax": "0" }, "catalog_visibility": "view" }, { "key": "e369853df766fa44e1ed0ff613f563bd", "id": 34, "quantity": 1, "quantity_limits": { "minimum": 1, "maximum": 99, "multiple_of": 1, "editable": true }, "name": "WordPress Pennant", "short_description": "

This is an 外部产品.

", "description": "

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.

", "sku": "wp-pennant", "low_stock_remaining": null, "backorders_allowed": false, "show_backorder_badge": false, "sold_individually": false, "permalink": "https://local.wordpress.test/product/wordpress-pennant/", "images": [ { "id": 57, "src": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg", "thumbnail": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg", "srcset": "https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1.jpg 800w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-324x324.jpg 324w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-100x100.jpg 100w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-416x416.jpg 416w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-300x300.jpg 300w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-150x150.jpg 150w, https://local.wordpress.test/wp-content/uploads/2020/03/pennant-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "pennant-1.jpg", "alt": "" } ], "variation": [], "prices": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "price": "1105", "regular_price": "1105", "sale_price": "1105", "price_range": null, "raw_prices": { "precision": 6, "price": "11050000", "regular_price": "11050000", "sale_price": "11050000" } }, "item_data": [], "totals": { "currency_code": "GBP", "currency_symbol": "£", "currency_minor_unit": 2, "currency_decimal_separator": ".", "currency_thousand_separator": ",", "currency_prefix": "£", "currency_suffix": "", "line_subtotal": "1105", "line_subtotal_tax": "0", "line_total": "884", "line_total_tax": "0" }, "catalog_visibility": "view" } ], "needs_payment": true, "needs_shipping": true, "totals": { "subtotal":"2105", "total_discount": "421", "total_shipping": "500", "total_fees": "0", "total_tax": "0", "total_refund": "0", "total_price": "2184", "total_items": "2105", "total_items_tax": "0", "total_fees_tax": "0", "total_discount_tax": "0", "total_shipping_tax": "0", "tax_lines": [] }, "errors": [], "payment_requirements": [ "products" ], } 错误回复 如果无法执行某个订单操作,将会返回一个错误回复。该回复将包含一个原因代码和一个错误信息: { "code": "woocommerce_rest_invalid_order", "message": "提供的订单 ID 或关键字无效。", "data": { "status": 401 } } 产品 属性 术语 API GET /products/attributes/:id/terms GET /products/attributes/:id/terms?orderby=slug 属性 类型 必需 描述 id integer 是 要获取术语的属性的 ID。 order string 否 升序或降序排序。 允许的值: asc, desc orderby string 否 按对象属性排序集合。 允许的值: id, name, name_num, slug, count, menu_order. curl "https://example-store.com/wp-json/wc/store/v1/products/attributes/1/terms" 示例响应: [ { "id": 22, "name": "Blue", "slug": "blue", "count": 5 }, { "id": 48, "name": "Burgundy", "slug": "burgundy", "count": 1 } ] 产品品牌 API 列出产品品牌 GET /products/brands 属性 类型 是否必需 描述 context 字符串 否 发起请求的范围;决定响应中包含的字段。 page 整数 否 集合的当前页。默认为 1。 per_page 整数 否 结果集中返回的最大项目数。默认为无限制。允许 0 到 100 之间的数值。 search 字符串 否 将结果限制为匹配某个字符串的项目。 exclude 数组 否 确保结果集排除特定的 ID。 include 数组 否 将结果集限制为特定的 ID。 order 字符串 否 升序或降序排序。允许的值: asc, desc。默认为 asc。 orderby 字符串 否 按术语属性排序。允许的值: name, slug, count。默认为 name。 hide_empty 布尔值 否 如果为 true,则不返回空术语。默认为 true。 parent 整数 否 将结果限制为具有特定父级 ID 的项目。 curl "https://example-store.com/wp-json/wc/store/v1/products/brands" 示例响应: [ { "id": 16, "name": "Nike", "slug": "nike", "description": "This is the Nike brand.", "parent": 0, "count": 11, "image": { "id": 55, "src": "https://store.local/wp-content/uploads/2021/11/nike-logo.jpg", "thumbnail": "https://store.local/wp-content/uploads/2021/11/nike-logo-324x324.jpg", "srcset": "https://store.local/wp-content/uploads/2021/11/nike-logo.jpg 800w, https://store.local/wp-content/uploads/2021/11/nike-logo-324x324.jpg 324w, https://store.local/wp-content/uploads/2021/11/nike-logo-100x100.jpg 100w, https://store.local/wp-content/uploads/2021/11/nike-logo-416x416.jpg 416w, https://store.local/wp-content/uploads/2021/11/nike-logo-300x300.jpg 300w, https://store.local/wp-content/uploads/2021/11/nike-logo-150x150.jpg 150w, https://store.local/wp-content/uploads/2021/11/nike-logo-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "nike-logo.jpg", "alt": "" }, "review_count": 2, "permalink": "https://store.local/product-brand/nike/" }, { "id": 21, "name": "Adidas", "slug": "adidas", "description": "", "parent": 0, "count": 1, "image": null, "review_count": 1, "permalink": "https://store.local/product-brand/adidas/" } ] 单个品牌 获取单个品牌信息。 GET /products/brands/:id 或者 GET /products/brands/:slug 参数 类型 必填 描述 identifier 字符串 是 用于获取品牌的标识符。可以是品牌 ID 或别名。 curl "https://example-store.com/wp-json/wc/store/v1/products/brands/1" 或者 curl "https://example-store.com/wp-json/wc/store/v1/products/brands/adidas" 示例回复: { "id": 1, "name": "Adidas", "slug": "adidas", "description": "", "parent": 0, "count": 1, "image": null, "review_count": 1, "permalink": "https://store.local/product-brand/adidas/" } 产品分类 API 列出产品分类 GET /products/categories 属性 类型 是否必需 描述 context 字符串 否 发起请求的范围;决定响应中包含的字段。 page 整数 否 集合的当前页。默认为 1。 per_page 整数 否 结果集中返回的最大项目数。默认为无限制。允许 0 到 100 之间的值。 search 字符串 否 将结果限制为匹配特定字符串的项目。 exclude 数组 否 确保结果集排除特定的 ID。 include 数组 否 将结果集限制为特定的 ID。 order 字符串 否 升序或降序排序。允许的值: asc, desc。默认为 asc。 orderby 字符串 否 按术语属性排序。允许的值: name, slug, count。默认为 name。 hide_empty 布尔值 否 如果为 true,则不返回空术语。默认为 true。 parent 整数 否 将结果限制为具有特定父级 ID 的项目。 curl "https://example-store.com/wp-json/wc/store/v1/products/categories" 示例响应: [ { "id": 16, "name": "Clothing", "slug": "clothing", "description": "This is the clothing category.", "parent": 0, "count": 11, "image": { "id": 55, "src": "https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1.jpg", "thumbnail": "https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-324x324.jpg", "srcset": "https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1.jpg 800w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-324x324.jpg 324w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-100x100.jpg 100w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-416x416.jpg 416w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-300x300.jpg 300w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-150x150.jpg 150w, https://store.local/wp-content/uploads/2021/11/t-shirt-with-logo-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "t-shirt-with-logo-1.jpg", "alt": "" }, "review_count": 2, "permalink": "https://store.local/product-category/clothing/" }, { "id": 21, "name": "Decor", "slug": "decor", "description": "", "parent": 0, "count": 1, "image": null, "review_count": 1, "permalink": "https://store.local/product-category/decor/" } ] 产品分类 获取单个分类。 GET /products/categories/:id 分类 类型 必填 描述 id 整数 是 要检索的分类的 ID。 curl "https://example-store.com/wp-json/wc/store/v1/products/categories/1" 示例回复: { "id": 1, "name": "Decor", "slug": "decor", "description": "", "parent": 0, "count": 1, "image": null, "review_count": 1, "permalink": "https://store.local/product-category/decor/" } 产品评论 API 列出产品评论 此端点返回产品评论(评论),也可以显示来自特定产品或特定分类的结果。 GET /products/reviews GET /products/reviews?category_id=1,2,3 GET /products/reviews?product_id=1,2,3 GET /products/reviews?orderby=rating&order=desc 属性 类型 是否必需 描述 page integer 否 集合的当前页。 per_page integer 否 结果集中要返回的最大项目数。 offset integer 否 将结果集偏移特定数量的项目。 order string 否 排序属性升序或降序。允许的值: asc, desc orderby string 否 按对象属性对集合进行排序。允许的值: date, date_gmt, id, rating, product category_id string 否 将结果集限制为来自特定分类 ID 的评论。 product_id string 否 将结果集限制为来自特定产品 ID 的评论。 curl "https://example-store.com/wp-json/wc/store/v1/products/collection-data?calculate_price_range=true&calculate_attribute_counts=pa_size,pa_color&calculate_rating_counts=true" 示例响应: [ { "id": 83, "date_created": "2022-01-12T15:42:14", "formatted_date_created": "January 12, 2022", "date_created_gmt": "2022-01-12T15:42:14", "product_id": 33, "product_name": "Beanie with Logo", "product_permalink": "https://store.local/product/beanie-with-logo/", "product_image": { "id": 56, "src": "https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1.jpg", "thumbnail": "https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-324x324.jpg", "srcset": "https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1.jpg 800w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-324x324.jpg 324w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-100x100.jpg 100w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-416x416.jpg 416w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-300x300.jpg 300w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-150x150.jpg 150w, https://store.local/wp-content/uploads/2021/11/beanie-with-logo-1-768x768.jpg 768w", "sizes": "(max-width: 800px) 100vw, 800px", "name": "beanie-with-logo-1.jpg", "alt": "" }, "reviewer": "reviewer-name", "review": "

This is a fantastic product.

\n", "rating": 5, "verified": true, "reviewer_avatar_urls": { "24": "https://secure.gravatar.com/avatar/12345?s=24&d=mm&r=g", "48": "https://secure.gravatar.com/avatar/12345?s=48&d=mm&r=g", "96": "https://secure.gravatar.com/avatar/12345?s=96&d=mm&r=g" } } ] 购物车令牌 购物车令牌可以替代基于 Cookie 的会话,用于无头环境下的购物车交互。 当使用 Cart-Token 时,不需要 随机数。 获取购物车令牌 对 /cart 接口的请求会返回一个 Cart-Token 头部,该头部包含一个令牌,该令牌可以在后续的请求中作为头部发送到 API 商店的购物车和结账接口,以标识购物车。 获取购物车令牌最快的方法是发送一个 GET 请求到 /wp-json/wc/store/v1/cart,并观察响应头部。 您应该在该头部中看到一个 Cart-Token。 如何使用 Cart-Token 要使用 Cart-Token,请将其包含在请求的头部中。 响应将包含与 Cart-Token 关联的会话的当前购物车状态。 示例: curl --header "Cart-Token: 12345" --request GET https://example-store.com/wp-json/wc/store/v1/cart 使用相同的方法,您可以使用 Cart-Token 在 /checkout 路由上进行结账。 WooCommerce 编码规范 遵守 WooCommerce 编码规范对于维护高质量的代码、确保兼容性以及促进更轻松的维护和更新至关重要。本文档概述了在 WooCommerce 生态系统中工作的开发人员应遵循的推荐编码实践,包括使用钩子、函数前缀、可翻译文本以及代码结构。 钩子的位置 将钩子放置在函数调用下方,以符合 WordPress 和 WooCommerce 生态系统中常见的模式。 示例: /** * 添加自定义消息。 */ function YOUR_PREFIX_custom_message() { echo 'This is a custom message'; } add_action( 'wp_footer', 'YOUR_PREFIX_custom_message' ); 函数调用前缀 为所有函数调用使用一致的前缀,以避免冲突。对于此仓库中的代码片段,请使用 YOUR_PREFIX。 示例: /** * 添加自定义折扣。 */ function YOUR_PREFIX_custom_discount( $price, $product ) { return $price * 0.9; // 10% discount } add_filter( 'woocommerce_product_get_price', 'YOUR_PREFIX_custom_discount', 10, 2 ); 可翻译文本和文本域 确保所有纯文本都是可翻译的,并使用一致的文本域,遵循国际化最佳实践。对于此仓库中的代码片段,请使用文本域 YOUR-TEXTDOMAIN。 示例: /** * 添加欢迎消息。 */ function YOUR_PREFIX_welcome_message() { echo __( 'Welcome to our website', 'YOUR-TEXTDOMAIN' ); } add_action( 'wp_footer', 'YOUR_PREFIX_welcome_message' ); 使用 function_exists() 为了防止潜在的函数重定义导致错误,请将所有函数调用包装在 function_exists() 中。 示例: /** * 添加缩略图支持。 */ if ( ! function_exists( 'YOUR_PREFIX_theme_setup' ) ) { function YOUR_PREFIX_theme_setup() { add_theme_support( 'post-thumbnails' ); } } add_action( 'after_setup_theme', 'YOUR_PREFIX_theme_setup' ); 代码质量标准 为了确保最高的代码质量标准,鼓励开发人员遵循以下实践: WooCommerce 代码检查和 WordPress 代码标准 确保代码通过 WooCommerce 代码检查和 WordPress 代码标准,使用 PHP_CodeSniffer。 自动化测试 单元测试: 实施自动化单元测试,以验证代码在隔离环境中的功能。 端到端测试: 使用自动化端到端测试,以验证应用程序中组件的集成操作。 跟踪和管理错误 监控并努力减少 打开的错误数量,以确保产品稳定可靠。 代码组织 将代码组织到独立的类中,以避免创建包含所有插件代码的“万能类”。 这种做法有助于提高模块化程度,并简化维护。 通过遵循这些编码标准和实践,开发者可以创建高质量、可维护且安全的 WooCommerce 扩展,从而为 WordPress 生态系统做出积极的贡献。 CSS/Sass 命名规范 简介 我们的规范基于 Calypso 的规范,而 Calypso 又遵循 BEM 方法论。 请参考 Calypso CSS/Sass 编码规范 以获取完整详情。 更多关于 BEM 核心概念 的信息,请阅读相关文档。 在 WooCommerce 中,有一些与上述规范略有不同的地方,具体内容如下所述。 前缀 由于 WooCommerce 是一个 WordPress 插件,因此必须与 WordPress 核心以及其他插件/主题兼容。为了最大限度地减少潜在的冲突,所有类名都应以 .woocommerce- 开头。 类名 在命名类名时,请记住以下几点: Block (块) - 独立的实体,本身具有意义。例如,组件的名称。 Element (元素) - 块的组成部分,本身没有独立意义。它们在语义上与所属的块相关联。 Modifier (修饰符) - 用于块或元素的标志。使用它们来改变外观或行为。 示例 /* Block (块) */ .woocommerce-loop {} /* Nested block (嵌套块) */ .woocommerce-loop-product {} /* Modifier (修饰符) */ .woocommerce-loop-product--sale {} /* Element (元素) */ .woocommerce-loop-product__link {} /* Element (元素) */ .woocommerce-loop-product__button-add-to-cart {} /* Modifier (修饰符) */ .woocommerce-loop-product__button-add-to-cart--added {} 注意: .woocommerce-loop-product 并非以这种方式命名,因为该块嵌套在 .woocommerce-loop 内部。 这样做是为了更具体,以便我们能够为单个产品、购物车产品等设置单独的类名。 嵌套块不需要继承其父级的全名。 总结 除非与此处的内容相矛盾,否则请遵循 WordPress CSS 编码规范。 遵循 Calypso 的 CSS 规范。 使用 BEM 进行 类名 的定义。 为所有类名添加前缀。 WooCommerce 语法、标点符号和首字母大写指南 遵循语法、标点符号和风格指南有助于保持我们文档的一致性。 如果用户知道他们能得到什么以及在哪里找到他们需要的信息,他们的体验会更好。 基础 保持开放性。 有些人会阅读每一个字。 有些人会浏览和搜索,或者更喜欢视频。 帮助所有人。 保持重点。 在句子、段落和部分中,以最重要的信息开头。 保持简洁。 使用通俗易懂的语言和简短的句子。 保持一致性。 遵循我们的指南和风格提示。 保持具体性。 清晰地表达。 避免冗余。 指南 缩写和首字母缩略词 第一次出现时,完整地写出词语,并在括号中添加缩写或首字母缩略词。 在第二次和后续的出现中,使用简短的版本。 第一次使用:Payment Card Industry Data Security Standard (PCI-DSS) 第二次使用:PCI-DSS 如果缩写或首字母缩略词是广泛使用的,则直接使用它。 例如:API, FAQ, HTML, PHP, SQL, SSL。 主动语态 在主动语态中,句子的主语执行动作。 在被动语态中,句子的主语是被动接受动作。 主动:Jon 下载了他的扩展文件。 被动:扩展文件是由 Jon 下载的。 首字母大写 以下情况需要首字母大写: 博客文章和文档文章的标题:第一个单词。 文档标题 (h2):对于文档标题和子标题,使用句首大写 (而不是标题大写)。 产品名称:每个单词,除了介词和连词。 句子:第一个单词。 无序/项目符号列表 - 每个条目的第一个单词。 以下情况使用小写: "ecommerce" (而不是 "eCommerce") Email 地址 - info@woocommerce.com 网站 URL - developer.woocommerce.com 缩写 谨慎使用。 缩写,例如 I'm 和 there's,可以使写作更具非正式和对话的风格,但如果内容正在被翻译,则可能不合适。 例如,有时在线翻译器会忽略 don't 中的 "not"。 表情符号 表情符号可以为您的内容添加微妙的情感和幽默,或者吸引视觉注意力。 很少且有目的地使用。 数字 在句子的开头,将数字写成文字。 对于所有其他情况,将数字 1 到 9 写成文字。 对于其他数字,使用数字。 将在六月发布十款产品。 不要:10 款产品将在六月发布。 Lance 参加了马拉松比赛,并在他的年龄组中获得第三名。 我为建筑项目购买了五把锤子和 21 种类型的钉子。 酒吧里有 18 种啤酒。 对于超过三个数字的数字,使用逗号:41,500, 170,000, 1,000,000 或 1 百万。 货币 在指定美元时,使用货币代码,而不要只使用符号/标志。 整数金额不需要小数点和两位小数。 USD $20 CAD $19.99 AUD $39.50 在描述其他货币时,使用符号/标志。 €995 ¥5,000 £18.99 日期 完整地写出星期几和月份,使用以下格式: 星期一,2016年12月12日 小数 当一个数字难以转换为分数时,使用小数点,例如3.141 或 98.5 或 0.29。 分数 完整地写出分数,例如:one-fourth (四分之一)。 百分比 完整地写出单词 "percent"。 除非空间有限,例如在社交媒体上使用,否则不要使用 "%" 符号。 电话号码 使用连字符 "-" 连接数字,不要使用括号或句点。 对于所有国家/地区,请使用 国家代码。 +1-555-867-5309 +34-902-1899-00 范围和跨度 使用连字符 "-" 表示数字的范围,例如:20-30天。 温度 使用摄氏度符号 "°C" 和华氏度符号 "°F"。 27°C 98°F 时间 使用数字和 "am" 或 "pm",中间用空格分隔,不要使用句点。 7:00 am 7:30 pm 使用连字符 "-" 连接时间,表示 am 或 pm 之间的时段。 如果时间跨越 am 和 pm,则使用 "to"。 7:00-9:00 am 和 7:00 am to 10:30 pm 在描述可能涉及全球参与者的活动时,请指定时区。 Automattic 使用协调世界时 (Coordinated Universal Time, UTC)。 缩写美国时区: 华盛顿时间:EDT 或 EST 中部时间:CDT 或 CST 山区时间:MDT 或 MST 太平洋时间:PDT 或 PST 年份 缩写十年: 80年代和 90年代 1900年代和 1890年代 标点符号 连接符 连接符 "&" 仅在公司/品牌名称中使用。 不要用它代替 "and"。 Ben & Jerry's Andre, Timo 和 Donny 去 Camp Nou 观看足球比赛。 引号 引号使单词变为所有格。 如果一个单词以 "s" 结尾且为单数,则添加一个 "s"。 如果一个单词以 "s" 结尾且为复数,则添加一个撇号。 同一个队友借用了 Sam 的自行车。 同一个队友借用了 Chris 的自行车。 员工藏起了办公室经理的笔。 以下是所有格:FAQ's questions, HE's weekly rotation。 以下是复数:FAQs 和 HEs。 冒号 使用冒号创建列表。 Aaron 订购了三种甜甜圈:糖霜、巧克力和南瓜。 逗号 在列出项目时,使用逗号(也称为牛津逗号)。 Jinny 喜欢向日葵、雏菊和牡丹。 在其他情况下,请使用常识。 大声朗读句子,并在需要清晰或停顿的地方使用逗号。 破折号和连字符 使用连字符 "-"(两侧没有空格)连接单词,或表示跨度或范围。 first-time user (首次用户) Monday-Friday (周一至周五) 使用长破折号 "-"(两侧没有空格)表示日记或补充说明。 使用真正的长破折号,而不是连字符。 多元测试,这是我们新的专业版功能之一,可以帮助您发展业务。 Austin 认为 Brad 偷了甜甜圈,但他是错的,是 Lain 偷的。 省略号 省略号 "..." 可以用来表示句子的未定义结尾,或者表示省略了单词(用方括号 [...] 表示)。 很少使用。 感叹号 很少使用感叹号,并且只使用一个。 感叹号的用法遵循与句号相同的规则,具体请参考“句号”部分。 句号 句号应该: 位于引号内 位于括号外,当括号内的内容是较大句子的一部分时 位于括号内,当括号内的内容可以独立存在时 示例 Jake 说:“我度过了最棒的一天。” 她去了超市(也去了美甲店)。 我妈妈喜欢披萨和啤酒。(啤酒需要冰镇且颜色深。) 问号 问号的用法遵循与句号相同的规则,具体请参考“句号”部分。 引号 句号和逗号位于引号内。引号内的问号遵循逻辑:如果问号是引号的一部分,则位于引号内。如果您要提问,且问题以引号结尾,则问号位于引号外。 在引号内使用单引号。 谁唱着“All These Things That I've Done”? The Killers 乐队的 Brandon Flowers 说:“当我写 'I got soul, but I'm not a soldier' 时,我感到受到启发并充满灵感。” 分号 分号可以用来连接两个相关的短语。 他们的首张个人专辑在 20 个国家进入前 10 名;它在英国排名第一。 人物、地点和事物 公司名称和产品 使用公司名称和产品在官方网站上所写的名称。 Pull&Bear UE Boom 将公司或产品称为 "it"(而不是 "they")。 WooCommerce 是,而不是 WooCommerce 是。 文件扩展名 文件扩展名应全部大写,不带句点。为了表示复数,添加一个小写字母 "s"。 HTML JPEG PDF 特定文件的扩展名应为小写: dancingcat.gif SalesReport2016.pdf firethatcannon.mp3 姓名和职称 首次提到某人时,应包括他们的名和姓。后续提及可以使用名。 对职称、团队名称和部门名称进行大写处理。 Happiness Engineers 或 HEs Team Apollo Legal 代词 根据情况使用 he/him/his 和 she/her/her。不要使用 "one" 作为代词。如果性别未知或指代一个群体,请使用 they/them/their。 引用 引用某人的话时,使用现在时。 Brent Jamison 说:“我喜欢 WooCommerce 是免费且灵活的。” 学校 首次提到一所学校、学院或大学时,使用其完整的官方名称。在后续提及时,使用其更常见的简称。 Georgia Institute of Technology, Georgia Tech Georgia State University, GSU 州、城市和国家 完整拼写所有城市和州名称。不要缩写城市名称。 首次提到时,写出 United States。在后续提及时,使用 U.S.。对于其他具有常用缩写的国家或联邦,也适用相同的规则,例如 European Union (EU) 和 United Kingdom (UK)。 网址和网站 将网站和网络出版物的名称首字母大写。不要使用斜体。 避免完整书写网址;在必要时省略 http://www。 俚语和行话 使用简洁的英语。文本应具有普遍的可理解性,并具有翻译的潜力。在需要时,简要定义技术术语。 文本格式化 使用斜体来表示书籍、电影或专辑的标题。 Oren Klaff 的书籍 Pitch Anything 正在以 5.99 美元的价格出售。 避免: 使用下划线 混合使用斜体、粗体、大写字母和下划线 将文本左对齐,不要居中或右对齐。 句子之间留一个空格,不要留两个。 命名规范 PHP WooCommerce 核心通常遵循 WordPress PHP 命名规范。 根据代码的位置,还存在一些额外的规范。 /src /src 目录下的类遵循 PSR-4 标准。有关更多信息,请参阅 [/src] 的 README。 以下规范适用于此目录: 不需要类名前缀,因为此位置的所有类都位于 Automattic\WooCommerce 命名空间中。 类名使用 CamelCase 规范。 函数名使用 snake_case 规范。 类文件名应与类名匹配。它们不需要 class- 前缀。 命名空间应与目录结构匹配。 Hook 前缀为 woocommerce_。 Hook 使用 snake_case 规范。 例如, src/Util/StringUtil.php 中定义的类应命名为 StringUtil,并位于 Automattic\WooCommerce\Util 命名空间中。 /includes /includes 目录包含不遵循 PSR-4 标准的旧代码。有关更多信息,请参阅 [/includes] 的 README。 以下规范适用于此目录: 类名前缀为 WC_。 类名使用 Upper_Snake_Case 规范。 函数名前缀为 wc_。 函数名使用 snake_case 规范。 Hook 前缀为 woocommerce_。 Hook 使用 snake_case 规范。 类名示例: WC_Cache_Helper WC_Cart 函数名示例: wc_get_product() wc_is_active_theme() Hook 名示例(操作或过滤器): woocommerce_after_checkout_validation woocommerce_get_formatted_order_total JS WooCommerce 核心遵循 WordPress JS 命名规范。 与 PHP 类似,函数、类和 Hook 名称应添加前缀,但 JS 的规范略有不同。 全局类名前缀为 WC。从模块导出的类名不添加前缀。 类名使用 UpperCamelCase 规范。 全局函数名前缀为 wc。从模块导出的函数名不添加前缀。 函数名使用 camelCase 规范。 Hook 名前缀为 woocommerce。 Hook 使用 camelCase 规范。 全局类名示例: WCOrdersTable 全局函数名示例: wcSettings() Hook 名示例(操作或过滤器): woocommerceTracksEventProperties CSS and SASS 请参阅 CSS/Sass 命名规范。 如何为简单产品和可变产品添加自定义字段 在本教程中,您将学习如何为产品创建自定义字段并在您的商店中显示它。我们将一起设置插件的基本结构,并了解 WordPress 的命名约定和 WooCommerce 的钩子机制。最终,您将获得一个用于添加自定义字段的可用插件。 完整的插件代码 是基于 WordPress 6.2 和 WooCommerce 7.6.0 编写的。 前置条件 要完成本教程,您需要安装 WordPress,并激活 WooCommerce 插件。您还需要至少设置一个 简单产品,或者您可以 导入 WooCommerce 的示例产品。 设置插件 首先,让我们执行 创建插件的基本结构 的步骤。 首先,导航到您的 wp-content/plugins 文件夹,然后运行: npx @wordpress/create-block -t @woocommerce/create-woo-extension woo-product-fields 然后,我们导航到新的文件夹并运行安装和构建命令: cd woo-product-fields npm install # 安装依赖 npm run build # 构建 JavaScript WordPress 具有自己的类文件命名约定,该约定默认情况下不符合 PSR-4 标准。要了解更多关于命名约定的信息,请参阅 WP Handbook。我们将使用标准的 "class-my-classname.php" 格式,因此,让我们修改 composer.json 文件中的 autoload 配置为: "autoload": { "classmap": ["includes/", "includes/admin/"] }, 保存后,运行 dump-autoload 命令以生成类映射,在终端中运行: composer dump-autoload -o 这将生成一个新的 vendor/composer/autoload_classmap.php 文件,其中包含 /includes/ 和 /includes/admin/ 文件夹中所有类的列表。每当我们添加、删除或移动类文件时,都需要重复此命令。 WooCommerce 钩子 我们的目标是为 WooCommerce 产品创建一个新的自定义文本字段,用于保存新的库存信息,以便在商店中显示。为此,我们需要修改 WooCommerce 后台管理区域中包含库存信息的区域。 WooCommerce 允许我们通过 钩子 将我们的代码添加到这些区域,钩子是 WordPress 扩展代码的标准方法。在 "库存" 部分,我们有以下可用的操作钩子: 对于我们的 WooCommerce 扩展,我们将使用 woocommerce_product_options_inventory_product_data 钩子,将我们的字段附加到该部分的末尾。 创建我们的类 让我们开始创建一个新的类,该类将包含字段的代码。 在 /includes/admin/ 文件夹中添加一个名为 class-product-fields.php 的新文件。 在类中,我们添加命名空间、如果有人尝试直接调用该文件则中止,以及一个 __construct 方法,该方法调用 hooks() 方法: hooks(); } private function hooks() {} } 然后,在终端中运行 composer dump-autoload -o 命令以重新生成类映射。 完成后,我们将该类添加到 setup.php 的 __construct() 函数中,如下所示: class Setup { public function __construct() { add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ) ); new ProductFields(); } } 添加自定义字段 在配置类并调用其方法后,我们可以创建一个函数来添加自定义字段。WooCommerce 提供了自己的 woocommerce_wp_text_input( $args ) 函数,我们可以在此处使用它。 $args 是一个数组,允许我们设置文本输入的数据,我们将使用全局 $product_object 对象来访问存储的元数据。 public function add_field() { global $product_object; ?>
'_new_stock_information', 'label' => __( 'New Stock', 'woo_product_field' ), 'description' => __( 'Information shown in store', 'woo_product_field' ), 'desc_tip' => true, 'value' => $product_object->get_meta( '_new_stock_information' ) ) ); ?>
update_meta_data( '_new_stock_information', sanitize_text_field( $_POST['_new_stock_information'] ) ); $product->save_meta_data(); } } 此函数检查我们的新字段是否在 POST 数组中。如果存在,我们创建产品对象,更新我们的元数据并保存元数据。 update_meta_data 函数将更新现有的元字段或添加新的元字段。由于我们正在向数据库插入数据,因此我们必须 清理我们的字段值。 为了使所有内容正常工作,我们添加以下钩子: private function hooks() { add_action( 'woocommerce_product_options_inventory_product_data', array( $this, 'add_field' ) ); add_action( 'woocommerce_process_product_meta', array( $this, 'save_field' ), 10, 2 ); } 现在,如果我们在产品屏幕上进行刷新,我们可以看到我们的新字段。 如果添加数据并保存产品,则新的元数据将插入到数据库中。 添加自定义字段到产品 此时,您已经拥有了一个可以保存产品自定义字段为产品元数据的插件。 在商店中显示字段 如果要在商店中显示新的字段,可以使用 WooCommerce 产品类的 get_meta() 方法: $product->get_meta( '_new_stock_information' ) 让我们开始创建一个新的文件 /includes/class-product.php。您可能已经注意到,该文件位于 /admin/ 文件夹之外,因为此代码将在前端运行。因此,在设置类时,我们也会相应地调整命名空间: hooks(); } private function hooks() { } } 再次运行 composer dump-autoload -o 以更新我们的类映射。 如果您查看了插件的设置,您可能会注意到 /admin/setup.php 仅在 WordPress 后台运行时才会被调用。因此,为了调用我们的新类,我们将在 /woo-product-field.php 中直接添加它: public function __construct() { if ( is_admin() ) { new Setup(); } new WooProductField\Product(); } 对于将字段添加到前端,我们有几种选项。我们可以创建一个主题模板,但如果我们在使用与 WooCommerce 兼容的主题,并且不需要进行任何其他更改,那么一种快速的方法是使用钩子。如果我们查看 /woocommerce/includes/wc-template-hooks.php,我们可以看到所有现有的 woocommerce_single_product_summary 动作,该动作控制产品页面的顶部部分: 对于我们的插件,我们将在摘要之后添加新的库存信息,并使用 21 作为优先级: private function hooks() { add_action( 'woocommerce_single_product_summary', array( $this, 'add_stock_info' ), 21 ); } 在我们的函数中,我们使用 适当的转义函数 输出库存信息,在这种情况下,我建议使用 esc_html() 来强制使用纯文本。 public function add_stock_info() { global $product; ?>

get_meta( '_new_stock_information' ) ); ?>

ID ); woocommerce_wp_text_input( array( 'id' => '_new_stock_information' . '[' . $loop . ']', 'label' => __( 'New Stock Information', 'woo_product_field' ), 'wrapper_class' => 'form-row form-row-full', 'value' => $variation_product->get_meta( '_new_stock_information' ) ) ); } 用于保存的代码如下: public function save_variation_field( $variation_id, $i ) { if ( isset( $_POST['_new_stock_information'][$i] ) ) { $variation_product = wc_get_product( $variation_id ); $variation_product->update_meta_data( '_new_stock_information', sanitize_text_field( $_POST['_new_stock_information'][$i] ) ); $variation_product->save_meta_data(); } } 现在,我们有一个新的变体字段,用于存储新的库存信息。 如果您看不到新的字段,请确保为该变体启用“管理库存”,方法是在变体详情中选中复选框。 在前端商店显示变体的方式对于可变产品来说略有不同,因为只有当客户进行选择时,网页上的某些内容才会更新。 这超出了本教程的范围,但如果您感兴趣,可以查看 /woocommerce/assets/js/frontend/add-to-cart-variation.js,了解 WooCommerce 的实现方式。 如何查找钩子? 每个人都有自己偏好的方法,但对我来说,最快的方法是在 WooCommerce 插件的代码中查找。每个数据部分的 code 可以在 /woocommerce/includes/admin/meta-boxes/views 目录下找到。要查看如何处理 库存 部分,请查看 html-product-data-inventory.php 文件,而要查看 变体 的处理方式,请查看 html-variation-admin.php 文件。 使用 WooCommerce CRUD 对象进行开发 CRUD 是对数据库或资源上可以执行的四个基本操作的缩写:创建、读取、更新、删除。 WooCommerce 3.0 引入了 CRUD 对象,用于处理 WooCommerce 数据。在您的代码中,尽可能使用这些对象,而不是直接更新元数据或使用 WordPress 文章对象。 每个对象都包含一个用于控制其数据的结构化数据(属性),以及每个属性的 getter 和 setter,以及一个用于与数据存储交互的保存/删除方法。 数据存储负责实际的保存/读取操作。 对象本身不需要知道数据存储在哪里。 CRUD 的优势 结构: 每个对象都有预定义的结构,并保持其数据的有效性。 控制: 我们控制数据流,以及所需的任何验证,因此我们知道何时发生更改。 开发简便性: 作为开发人员,您无需了解正在处理的数据的内部结构,只需要知道属性名称。 抽象: 数据可以移动到其他地方,例如自定义表,而不会影响现有代码。 统一: 我们可以使用相同的代码来更新管理后台中的内容,以及在 REST API 和 CLI 中,一切都统一。 简化代码: 减少更新对象的程序化代码,从而降低出现故障的可能性,并增加单元测试覆盖率。 CRUD 对象结构 [WC_Data](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/includes/abstracts/abstract-wc-data.php) 类是 CRUD 对象的基本实现,所有 CRUD 对象都继承自它。 需要注意的最重要的属性是 $data,它是一个数组,包含每个对象支持的属性,以及 $id,它是对象的 ID。 优惠券对象类 是一个很好的例子,它展示了如何扩展 WC_Data 并为所有属性添加 CRUD 函数。 数据 $data 存储属性名称和默认值: /** * 数据数组,包含默认值。 * @since 3.0.0 * @var array */ protected $data = array( 'code' => '', 'amount' => 0, 'date_created' => '', 'date_modified' => '', 'discount_type' => 'fixed_cart', 'description' => '', 'date_expires' => '', 'usage_count' => 0, 'individual_use' => false, 'product_ids' => array(), 'excluded_product_ids' => array(), 'usage_limit' => 0, 'usage_limit_per_user' => 0, 'limit_usage_to_x_items' => 0, 'free_shipping' => false, 'product_categories' => array(), 'excluded_product_categories' => array(), 'exclude_sale_items' => false, 'minimum_amount' => '', 'maximum_amount' => '', 'email_restrictions' => array(), 'used_by' => array(), ); 获取器和设置器 数组中的每个键(属性)都有一个对应的获取器和设置器,例如 set_used_by() 和 get_used_by()。 $data 本身是私有的,因此必须使用获取器和设置器来访问数据。 示例获取器: /** * 获取所有使用当前优惠券的用户记录。 * @since 3.0.0 * @param string $context * @return array */ public function get_used_by( $context = 'view' ) { return $this->get_prop( 'used_by', $context ); } 示例设置器: /** * 设置哪些用户已经使用了此优惠券。 * @since 3.0.0 * @param array $used_by * @throws WC_Data_Exception */ public function set_used_by( $used_by ) { $this->set_prop( 'used_by', array_filter( $used_by ) ); } set_prop 和 get_prop 是 WC_Data 的一部分。 它们应用各种过滤器(基于上下文)并处理更改,因此我们可以高效地仅保存已更改的属性,而不是所有属性。 关于 $context 的说明:当获取用于前端或显示的的数据时,使用 view 上下文。 这会对数据应用过滤器,以便扩展可以动态更改值。 当在后端显示用于编辑的值时,应使用 edit 上下文,并且用于将数据保存到数据库时也应使用 edit 上下文。 使用 edit 上下文不会对数据应用任何过滤器。 构造函数 CRUD 对象的构造函数用于从数据库中读取数据。 实际读取操作不是由 CRUD 类本身完成,而是由其数据存储层完成。 示例: /** * 优惠券构造函数。加载优惠券数据。 * @param mixed $data 优惠券数据,对象、ID 或代码。 */ public function __construct( $data = '' ) { parent::__construct( $data ); if ( $data instanceof WC_Coupon ) { $this->set_id( absint( $data->get_id() ) ); } elseif ( is_numeric( $data ) && 'shop_coupon' === get_post_type( $data ) ) { $this->set_id( $data ); } elseif ( ! empty( $data ) ) { $this->set_id( wc_get_coupon_id_by_code( $data ) ); $this->set_code( $data ); } else { $this->set_object_read( true ); } $this->data_store = WC_Data_Store::load( 'coupon' ); if ( $this->get_id() > 0 ) { $this->data_store->read( $this ); } } 注意,它根据传递给对象的 data 设置 ID,然后调用数据存储层以从数据库中检索数据。 一旦数据通过数据存储层读取,或者如果未设置 ID,则 $this->set_object_read( true ); 被设置,以便数据存储层和 CRUD 对象知道它已读取。 一旦设置了此标志,更改就会被跟踪。 保存和删除 save 和 delete 方法在 CRUD 子类中是可选的,因为 WC_Data 父类可以处理它们。 当调用 save 时,数据存储层用于将数据存储到数据库。 delete 从数据库中移除对象。 必须调用 save 方法才能使更改永久生效,否则这些更改将被丢弃。 WC_Data 中的 save 方法如下所示: /** * `save` 方法应该根据对象是否存在来创建或更新。 * * @since 2.6.0 * @return int */ public function save() { if ( $this->data_store ) { // 在保存到数据库之前触发操作。 允许您在保存之前调整对象属性。 do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store ); if ( $this->get_id() ) { $this->data_store->update( $this ); } else { $this->data_store->create( $this ); } return $this->get_id(); } } 根据对象是否已经具有 ID,会使用更新/创建操作。 ID 将在创建后设置。 delete 方法如下所示: /** * 删除对象,将 ID 设置为 0,并返回结果。 * * @since 2.6.0 * @param bool $force_delete * @return bool 结果 */ public function delete( $force_delete = false ) { if ( $this->data_store ) { $this->data_store->delete( $this, array( 'force_delete' => $force_delete ) ); $this->set_id( 0 ); return true; } return false; } CRUD 使用示例 创建一个新的简单产品 $product = new WC_Product_Simple(); $product->set_name( 'My Product' ); $product->set_slug( 'myproduct' ); $product->set_description( 'A new simple product' ); $product->set_regular_price( '9.50' ); $product->save(); $product_id = $product->get_id(); 更新现有优惠券 $coupon = new WC_Coupon( $coupon_id ); $coupon->set_discount_type( 'percent' ); $coupon->set_amount( 25.00 ); $coupon->save(); 获取客户信息 $customer = new WC_Customer( $user_id ); $email = $customer->get_email(); $address = $customer->get_billing_address(); $name = $customer->get_first_name() . ' ' . $customer->get_last_name(); 优惠券管理 本页面用于管理优惠券。您可以查看、创建、编辑和删除优惠券。 新增优惠券:点击“新增”按钮,可以创建新的优惠券。 编辑优惠券:点击优惠券列表中的“编辑”按钮,可以修改现有优惠券的设置。 删除优惠券:点击优惠券列表中的“删除”按钮,可以删除优惠券。 优惠券详情 显示单个优惠券的详细信息,包括: 名称 (Name):优惠券的名称。 折扣 (Discount):优惠券的折扣类型和金额。 使用 (Use):优惠券的使用限制,例如最小订单金额、使用次数等。 有效期 (Expiration Date):优惠券的有效期。 其他设置 (Other Settings):其他自定义设置。 优惠券列表 显示所有优惠券的列表,包括: 名称 (Name):优惠券的名称。 折扣 (Discount):优惠券的折扣类型和金额。 使用次数 (Count):优惠券已使用的次数。 状态 (Status):优惠券的状态,例如“有效”、“已过期”、“已禁用”。 批量操作 您可以对多个优惠券进行批量操作,例如: 删除 (Delete):删除选中的优惠券。 更新 (Updating):更新选中的优惠券的状态。 导入/导出 您可以将优惠券数据从一个系统导入到另一个系统,或者将优惠券数据导出为文件。 导入 (Import):从文件导入优惠券数据。 导出 (Export):将优惠券数据导出为文件。 优惠券代码 以下是一些常用的优惠券代码示例: %s:占位符,表示用户可以自定义的文本。 {name}:占位符,表示客户的名称。 邮件通知 当客户使用优惠券时,您可以发送电子邮件通知。 邮件 (Mail):发送电子邮件通知。 收件人 (Address):收件人的电子邮件地址。 主题 (Subject):电子邮件的主题。 正文 (Body):电子邮件的正文内容。 账单 (Billing) 显示与优惠券相关的账单信息。 金额 (Amount):优惠券的金额。 百分比 (Percent):优惠券的百分比折扣。 类型 (Type):优惠券的类型。 常见问题 如何创建新的优惠券? 点击“新增”按钮,填写优惠券的详细信息,然后点击“保存”按钮。 如何修改现有优惠券? 点击优惠券列表中的“编辑”按钮,修改优惠券的设置,然后点击“保存”按钮。 如何删除优惠券? 点击优惠券列表中的“删除”按钮,确认删除操作。 如何使用优惠券? 在结账时,输入优惠券代码,系统会自动应用折扣。 优惠券的有效期是什么? 优惠券的有效期由您在创建优惠券时设置。 如何查看优惠券的使用情况? 在优惠券详情页面,您可以查看优惠券的使用次数和状态。 如何导出优惠券数据? 点击“导出”按钮,选择导出的文件格式,然后点击“下载”按钮。 如何导入优惠券数据? 点击“导入”按钮,选择要导入的文件,然后点击“上传”按钮。 错误信息 Invalid coupon code.:优惠券代码无效。 Coupon has expired.:优惠券已过期。 Coupon has already been used.:优惠券已使用。 Minimum order amount not met.:未达到最小订单金额。 Coupon cannot be applied to this product.:该优惠券无法应用于该商品。 Error updating coupon.:更新优惠券时出错。 Error deleting coupon.:删除优惠券时出错。 Error importing coupon data.:导入优惠券数据时出错。 Error exporting coupon data.:导出优惠券数据时出错。 提示 您可以使用搜索框快速查找优惠券。 您可以使用分页功能浏览优惠券列表。 您可以使用排序功能对优惠券列表进行排序。 您可以使用过滤器功能筛选优惠券列表。 如果您在使用优惠券时遇到问题,请联系客服。 请定期检查和更新您的优惠券,以确保其有效性。 您可以创建自定义的优惠券代码,以满足您的特定需求。 您可以 数据存储基础 在为 WordPress 和 WooCommerce 开发时,重要的是要考虑数据的性质和持久性。这将帮助您决定最佳的存储方式。以下是一个简要的介绍: 瞬态 如果数据可能并不总是存在(即,数据会过期),请使用 瞬态。瞬态是一种简单且标准化的方法,用于在数据库中临时存储缓存数据,通过为其指定自定义名称和过期时间,在过期后自动删除。 WP 缓存 如果数据是持久的,但并不总是存在,请考虑使用 WP 缓存。WP 缓存函数允许您缓存需要大量计算才能重新生成的复杂数据,例如复杂的查询结果。 wp_options 表 如果数据是持久的并且始终存在,请考虑使用 wp_options 表。 Options API 是一种简单且标准化的方法,用于在 WordPress 数据库的 wp_options 表中存储数据。 帖子类型 如果数据类型是具有 n 个单位的实体,请考虑使用 帖子类型。帖子类型是存储方式相同的内容的“类型”,但在代码和 UI 中易于区分。 分类法 如果数据是一种对实体进行排序/分类的手段,请考虑使用 分类法。分类法是一种将事物分组的方法。 日志 日志应使用 WC_Logger 类写入文件。这是一种简单且标准化的记录事件和错误的方法,用于调试。 请记住,最佳的数据存储方法取决于数据的性质以及它将在您的应用程序中如何使用。 如何管理 WooCommerce 数据存储 简介 数据存储类充当 WooCommerce 的数据 CRUD 类( WC_Product, WC_Order, WC_Customer 等)与数据库层之间的桥梁。 通过将数据库逻辑与数据分离,WooCommerce 变得更加灵活。 随 WooCommerce 核心提供的、基于 WordPress 的自定义文章系统和一些自定义表的的数据存储,可以被替换为不同的数据库结构、类型,甚至可以由外部 API 提供。 本指南将介绍数据存储类的结构,如何创建新的数据存储,如何替换核心数据存储,以及如何在您自己的代码中调用数据存储。 本指南中的示例将查看 WC_Coupon CRUD 数据类,以及 WC_Coupon_Data_Store_CPT,这是一个使用 WordPress 自定义文章类型的优惠券数据存储的实现。 这是 WooCommerce 当前存储优惠券的方式。 在使用数据存储时,需要了解 WC_Coupon 或任何其他 CRUD 数据类包含哪些属性(properties)。 这些属性在每个类的 data 数组中定义。 结构 每个 CRUD 对象的数据库存储都应该实现 WC_Object_Data_Store_Interface 界面。 WC_Object_Data_Store_Interface 包含以下方法: create read update delete read_meta delete_meta add_meta update_meta create、 read、 update 和 delete 方法应该处理您属性的 CRUD 逻辑: create 应该在数据库中创建一个新的条目。 示例:创建优惠券。 read 应该从数据库中查询单个条目,并根据响应设置属性。 示例:读取优惠券。 update 应该对现有条目进行更改。 示例:更新或编辑优惠券。 delete 应该从数据库中移除一个条目。 示例:删除优惠券。 所有数据库存储都必须实现对这些方法的处理。 除了处理您的属性之外,还可以传递其他自定义数据。 这被认为是“元数据”。 例如,优惠券可以具有插件提供的自定义数据。 read_meta、 delete_meta、 add_meta 和 update_meta 方法应该被定义,以便可以从正确的来源读取和管理元数据。 在我们的 WooCommerce 核心类中,我们在 WC_Data_Store_WP 中定义它们,然后为所有数据库存储使用相同的代码。 它们都使用 WordPress 的元数据系统。 如果元数据应该来自不同的来源,您可以重新定义这些方法。 您的数据库存储还可以实现其他方法来替换直接查询。 例如,优惠券数据库存储具有一个公共的 get_usage_by_user_id 方法。 数据库存储应该始终定义和实现一个界面,用于它们期望的方法,以便其他开发者知道他们需要编写哪些方法。 换句话说,除了 WC_Object_Data_Store_Interface 界面之外, WC_Coupon_Data_Store_CPT 还实现了 WC_Coupon_Data_Store_Interface。 替换数据存储 让我们看看如何用 WC_Coupon_Data_Store_Custom_Table 类替换 WC_Coupon_Data_Store_CPT 类。 我们的示例将仅提供占位函数,而不是完整的解决方案。 假设我们希望将优惠券存储在名为 wc_coupons 的表中,该表具有以下列: id, code, amount, date_created, date_modified, discount_type, description, date_expires, usage_count,individual_use, product_ids, excluded_product_ids, usage_limit, usage_limit_per_user, limit_usage_to_x_items, free_shipping, product_categories, excluded_product_categories, exclude_sale_items, minimum_amount, maximum_amount, email_restrictions, used_by 这些列名与属性名一一对应。 首先,我们需要创建一个新的数据存储类来包含我们的逻辑: /** * WC 优惠券数据存储:自定义表。 */ class WC_Coupon_Data_Store_Custom_Table extends WC_Data_Store_WP implements WC_Coupon_Data_Store_Interface, WC_Object_Data_Store_Interface { } 请注意,我们实现了主要的 WC_Object_Data_Store_Interface 接口以及 WC_Coupon_Data_Store_Interface 接口。 它们共同代表了我们需要提供逻辑的所有方法。 然后,我们将定义这些属性的 CRUD 处理: /** * 用于在数据库中创建新优惠券的方法。 * * @param WC_Coupon */ public function create( &$coupon ) { $coupon->set_date_created( current_time( 'timestamp' ) ); /** * 这是插入新优惠券的代码所在的位置。 * 将使用 getter 构建查询:$coupon->get_code(), $coupon->get_description() 等。 * 在 INSERT 操作之后,我们希望将新的 ID 传递给优惠券对象。 */ $coupon->set_id( $coupon_id ); // 在创建或更新条目后,我们需要同时触发 'meta' 的保存。 $coupon->save_meta_data(); // `apply_changes` 方法告诉对象,当前对象反映了数据库,并且两个对象之间不存在“更改”。 $coupon->apply_changes(); // 为了方便插件与您的数据存储进行交互,建议在操作完成后提供相同的钩子。 do_action( 'woocommerce_new_coupon', $coupon_id ); } /** * 用于读取优惠券的方法。 * * @param WC_Coupon */ public function read( &$coupon ) { $coupon->set_defaults(); // `Read` 方法应该检查是否为有效的优惠券, // 如果不是,则抛出 "Invalid coupon" 异常。 // 对于有效的优惠券,将 `$data` 设置为包含数据库结果。 // 所有属性都应使用 `set_props` 方法,并使用来自数据库的输出进行设置。这会将 CRUD 数据对象进行“填充”。 $coupon_id = $coupon->get_id(); $coupon->set_props( array( 'code' => $data->code, 'description' => $data->description, // .. ) ); // 此外,我们还需要将元数据读取到对象中。 $coupon->read_meta_data(); // 此标志指示对象是否已填充。如果此标志为 false,则表示数据库未正确设置对象。 $coupon->set_object_read( true ); do_action( 'woocommerce_coupon_loaded', $coupon ); } /** * 更新数据库中的优惠券。 * * @param WC_Coupon */ public function update( &$coupon ) { // 更新优惠券查询,使用 getter 方法。 $coupon->save_meta_data(); $coupon->apply_changes(); do_action( 'woocommerce_update_coupon', $coupon->get_id() ); } /** * 从数据库中删除优惠券。 * * @param WC_Coupon * @param array $args 传递给删除方法的参数数组。 */ public function delete( &$coupon, $args = array() ) { // WordPress 和 WooCommerce 中的许多对象 // 支持“回收站”的概念。这通常是一个标志,用于将对象 // 移动到“回收站”。由于优惠券支持回收站,因此您的层也应该支持。 // 如果实际发生删除,则将优惠券 ID 设置为 0。 $args = wp_parse_args( $args, array( 'force_delete' => false, ) ); $id = $coupon->get_id(); if ( $args['force_delete'] ) { // 删除查询 $coupon->set_id( 0 ); do_action( 'woocommerce_delete_coupon', $id ); } else { // 回收站查询 do_action( 'woocommerce_trash_coupon', $id ); } } 我们正在扩展 WC_Data_Store_WP,因此我们的类将继续使用 WordPress 的元数据系统。 如“结构”部分中所述,我们负责实现 WC_Coupon_Data_Store_Interface 定义的方法。每个接口描述了它接受的方法和参数,以及您的函数应该执行的操作。 一个优惠券的替换方法如下所示: /** * 增加当前优惠券的使用次数。 * * @param WC_Coupon * @param string $used_by 用户 ID 或账单电子邮件。 */ public function increase_usage_count( &$coupon, $used_by = '' ) { } /** * 减少当前优惠券的使用次数。 * * @param WC_Coupon * @param string $used_by 用户 ID 或账单电子邮件。 */ public function decrease_usage_count( &$coupon, $used_by = '' ) { } /** * 获取特定用户 ID 的优惠券使用次数。 * * @param WC_Coupon * @param id $user_id * @return int */ public function get_usage_by_user_id( &$coupon, $user_id ) { } /** * 返回特定 ID 的优惠券代码。 * @param int $id * @return string 优惠券代码 */ public function get_code_by_id( $id ) { } /** 返回指定优惠券代码的 ID 数组。 可以返回多个 ID 以检查是否存在。 @param string $code @return array ID 数组。 */ public function get_ids_by_code( $code ) { } 一旦所有的数据存储方法都定义完成,并且逻辑编写完毕,我们需要告诉 WooCommerce 加载我们的新类,而不是内置的类。 这通过使用 `woocommerce_data_stores` 过滤器来实现。 一个数据存储别名数组映射到默认的 WooCommerce 类。 示例: ```php 'coupon' => 'WC_Coupon_Data_Store_CPT', 'customer' => 'WC_Customer_Data_Store', 'customer-download' => 'WC_Customer_Download_Data_Store', 'customer-session' => 'WC_Customer_Data_Store_Session', 'order' => 'WC_Order_Data_Store_CPT', 'order-refund' => 'WC_Order_Refund_Data_Store_CPT', 'order-item' => 'WC_Order_Item_Data_Store', 'order-item-coupon' => 'WC_Order_Item_Coupon_Data_Store', 'order-item-fee' => 'WC_Order_Item_Fee_Data_Store', 'order-item-product' => 'WC_Order_Item_Product_Data_Store', 'order-item-shipping' => 'WC_Order_Item_Shipping_Data_Store', 'order-item-tax' => 'WC_Order_Item_Tax_Data_Store', 'payment-token' => 'WC_Payment_Token_Data_Store', 'product' => 'WC_Product_Data_Store_CPT', 'product-grouped' => 'WC_Product_Grouped_Data_Store_CPT', 'product-variable' => 'WC_Product_Variable_Data_Store_CPT', 'product-variation' => 'WC_Product_Variation_Data_Store_CPT', 'shipping-zone' => 'WC_Shipping_Zone_Data_Store', 我们希望专门针对优惠券数据存储,因此我们可以这样做: function myplugin_set_wc_coupon_data_store( $stores ) { $stores['coupon'] = 'WC_Coupon_Data_Store_Custom_Table'; return $stores; } add_filter( 'woocommerce_data_stores', 'myplugin_set_wc_coupon_data_store' ); 然后,WooCommerce 核心将加载我们的类,而不是 WC_Coupon_Data_Store_CPT。 创建新的数据存储 定义新的产品类型 你的扩展是否创建了一种新的产品类型? 每一个产品类型都有一个数据存储,除了父产品的数据存储之外。 父存储负责处理共享的属性,例如名称或描述,而子存储负责处理更具体的数据。 例如,外部产品数据存储负责处理“按钮文本”和“外部 URL”。 变量数据存储负责父产品与其变体之间的关系。 请查看 此教程,以获取有关此过程的更多信息。 用于自定义数据的存储 如果你的扩展引入了新的数据库表、新的自定义文章类型,或者某种与产品、订单等无关的新数据形式,那么你应该实现你自己的数据存储。 你的数据存储仍然应该实现 WC_Object_Data_Store_Interface 接口,并提供标准的 CRUD 函数。 你的数据存储应该是与你的数据交互的主要入口点,因此任何其他查询或操作也应该有相应的方法。 配送区域数据存储 是一个很好的例子,它展示了如何使用自定义表创建一个“简单”的数据存储。 优惠券的代码是一个很好的例子,展示了如何使用自定义文章类型的数据存储。 要注册你的数据存储,你只需要将其添加到 woocommerce_data_stores 过滤器中: function myplugin_set_my_custom_data_store( $stores ) { $stores['mycustomdata'] = 'WC_My_Custom_Data_Store'; return $stores; } add_filter( 'woocommerce_data_stores', 'myplugin_set_my_custom_data_store' ); 然后,你可以像加载其他 WooCommerce 数据存储一样加载你的数据存储。 调用数据存储 调用数据存储就像使用静态的 WC_Data_Store::load() 方法一样简单: // 加载配送区域数据存储。 $data_store = WC_Data_Store::load( 'shipping-zone' ); // 获取配送区域 ID 为 4 的配送方法数量。 $num_of_methods = $data_store->get_method_count( 4 ); 你也可以链式调用方法: // 获取配送区域 ID 为 4 的配送方法数量。 $num_of_methods = WC_Data_Store::load( 'shipping-zone' )->get_method_count( 4 ); ::load() 方法适用于注册到 woocommerce_data_stores 的任何数据存储,因此你可以加载你的自定义数据存储: $data_store = WC_Data_Store::load( 'mycustomdata' ); 数据存储的限制和 WP 管理员 目前,一些 WooCommerce 界面仍然依赖于 WordPress 来列出对象。例如,优惠券和产品。 如果您通过数据存储进行数据替换,那么现有用户界面的一些部分可能会出现故障。例如,当使用 type 过滤器时,优惠券列表可能会出现问题。此过滤器使用元数据,然后将其传递给 WordPress,WordPress 使用 WP_Query 类执行查询。 WP_Query 类无法处理位于常规元数据表之外的数据(参考 #19937)。为了解决这个问题,需要逐步淘汰 WP_Query 的使用,并用自定义的查询类和函数进行替换。 WooCommerce 日志记录 WooCommerce 拥有一个强大的日志记录系统,可用于在开发期间进行调试,在生产环境中捕获错误,甚至在发生特定事件时发送通知。 默认情况下,WooCommerce 使用此日志记录器来记录可能有助于解决商店问题的错误、警告和其他通知。 许多 WooCommerce 扩展也使用此日志记录器来实现类似的目的。 查看日志 您可以通过访问 WooCommerce > 状态 > 日志 来查看日志记录器创建的条目。 日志查看界面取决于配置的日志存储方法(请参阅下面的“配置日志记录器”部分)。 文件系统 使用默认的文件系统存储方法,您首先会看到现有日志文件的列表: 日志文件的名称基于其包含条目的来源(即扩展或 WooCommerce 代码库的一部分),以及创建条目的日期。 在此文件浏览视图中,您可以以不同的方式对文件进行排序,还可以对其进行过滤,仅显示来自特定来源的文件。 单击文件将进入单个文件视图,您可以在其中查看实际的日志条目: 单击文件中的行号以突出显示该行。 这也可以用于从其他位置链接到文件中的特定行。 从文件浏览器视图,您可以对日志文件列表进行排序和过滤,然后在这些文件的内容中搜索字符串: 单击搜索结果中的行号将带您到单个文件视图中的该行。 数据库 使用数据库存储方法,您将看到日志条目的列表,从最近的条目开始: 这些条目可以按时间戳、级别和来源进行排序,也可以进行过滤,仅显示特定来源或最小级别。 您还可以搜索日志条目消息字段中的字符串。 配置日志记录器 从 WooCommerce > 状态 > 日志 屏幕上的“日志”屏幕,单击“设置”链接以进行配置更改: 日志记录器 取消此处的复选框以关闭所有日志记录。 在大多数情况下,不建议这样做,因为日志记录可以提供有关您网站上正在发生情况的宝贵信息! 日志存储 默认情况下,WooCommerce 提供了两种不同的日志存储方法: 文件系统 - 日志条目记录到文件中。 文件通过日志条目的 source 值(请参阅下面的“添加日志”部分)以及当前日期进行区分。 这些文件存储在站点的 uploads 目录下的 wc-logs 子目录中。 可以使用 woocommerce_log_directory 过滤器钩子定义自定义目录。 日志文件的大小可以达到 5MB,超过此大小后,日志文件将进行轮换。 数据库 - 日志条目记录到数据库中的 {$wpdb->prefix}woocommerce_log 表中。 如果您更改此设置,并且已经存在一些日志条目,则这些条目将不会迁移到其他存储方法,但也不会被删除。 保留期限 日志记录器会定期检查并删除超过此时间段的旧日志,以节省空间。 如果日志条目存储在文件系统中,则超出保留期限的整个日志文件将被删除;而对于数据库存储,则会删除单个日志条目。 级别阈值 每个日志条目都有一个严重性级别(请参阅下面的“添加日志”部分)。 此设置定义一个最小严重性级别,任何生成且严重性级别低于或等于此最小级别的日志条目将不会被记录。 请谨慎使用此设置! 如果此设置设置为“无”,则表示所有日志条目都将被记录,无论其严重性级别如何。 添加日志 日志是通过 WC_Logger 类的各种方法添加的。 可以使用 wc_get_logger() 函数访问类实例。 添加日志条目的基本方法是 [WC_Logger::log( $level, $message, $context )](https://woocommerce.github.io/code-reference/classes/WC-Logger.html#method_log)。 此外,还提供了每个日志严重性级别的快捷方法,例如 WC_Logger::warning( $message, $context )。 建议使用快捷方法而不是通用的 log 方法。 级别 日志有八个不同的严重性级别: emergency alert critical error warning notice info debug 除了为网站所有者提供有关日志条目的重要性的上下文信息外,这些级别还允许对日志进行过滤。 如果您只想记录严重性级别为 error 及以上的日志条目,可以在“日志设置”屏幕上设置阈值(请参阅上面的“配置日志记录器”)。 请注意,此阈值适用于所有日志,无论使用哪种日志处理程序。 例如, WC_Log_Handler_Email 类具有自己的阈值设置,但它不如全局阈值重要。 信息 信息是日志条目的主要内容。 确保其内容易于任何可能查看日志的人理解! 上下文 Context 参数旨在用于存储与日志条目相关的附加结构化数据。例如,在关于订单的日志条目中,您可能希望包含相关订单对象的 内容。当日志记录器 生成 一个条目时, Context 参数中的数据会转换为 JSON 格式后再进行存储。因此,如果您想添加多个 Context 数据,每个数据都应该作为 Context 数组中的一个单独的键进行添加。 有两个特定的键可以添加到 Context 数组中,它们会触发特殊的行为: source 建议每个日志条目都包含一个 source 值在 Context 参数中。 source 的目的是提供关于日志是在应用程序或代码库的哪个位置 生成 的 上下文 信息,并且可以用于过滤日志条目。 如果未指定 source,日志记录器会根据 生成 日志条目的插件或文件 生成 一个 source 值。 backtrace 将 Context 参数中的 backtrace 键设置为 true 会导致日志记录器 生成 一个 backtrace(即堆栈跟踪),该 backtrace 以数组格式存储,并将其包含在 Context 中,替换 true 值。这对于与 错误 相关的日志特别有用,这样您就可以看到导致 生成 该日志条目的代码。 完整示例 wc_get_logger()->info( 'It is time for lunch.', array( 'source' => 'your_stomach', 'backtrace' => true, 'previous_meal' => $elapsed_time_since_breakfast, 'lunch_options' => array( 'fridge leftovers', 'bahn mi', 'tacos', 'pupusas' ), ) ); 日志记录的最佳实践 何时使用日志记录 用于解决意外问题: 从 API 接收到意外的值或 错误。 系统中的数据不正确或已损坏。 应用程序处于意外或损坏的状态。 用于记录过程的审计日志: 未在其他地方存储的事务 详情,例如订单备注(但可能应该存储?)。 数据导入或导出的 结果。 重要的 设置 被更改。 自动化过程更改或删除数据。 何时不使用日志记录 用于告知开发人员他们正在错误地使用某个方法或 API。这可能会导致大量的无用日志条目,尤其是在它会在每个 网页 请求时触发的情况下。 最好通过 错误 或异常(例如 wc_doing_it_wrong())提供即时 反馈。 最佳实践 与其直接使用 WC_Logger 的 log() 方法,最好使用专门针对日志级别的包装方法,例如 info() 或 error()。 编写一个完整、连贯的句子作为日志信息。 这将使其对不熟悉代码库的人更有用。 日志信息不应是可翻译的。 保持信息以英文书写,可以更轻松地根据信息内容搜索解决方案,并且也便于任何进行故障排除的人理解正在发生的情况,因为他们可能使用的语言与网站所有者使用的语言不同。 理想情况下,每个日志条目的信息应该是一行(即,信息字符串中不应包含换行符)。 额外的行或额外数据应放在 context 数组中。 避免在信息字符串中输出结构化数据。 将其放在 context 数组中的键中。 日志记录器将负责将其转换为 JSON 格式,并在日志查看器中使其易于阅读。 如果需要包含堆栈跟踪,请让日志记录器为您生成它。 为正在使用的组件或系统选择一个来源,并在每次调用日志记录时使用它。 这将使查找与该组件相关的日志条目更容易,并将其与其他不相关的日志条目过滤掉。 考虑在循环过程之后添加一个日志条目,其中包含循环的聚合结果,而不是在循环中的每个条目时添加单独的条目。 自定义日志记录器 日志记录器类 可以通过 woocommerce_logging_class 过滤器钩子,用另一个类替换 WC_Logger 类。 替代类必须实现 WC_Logger_Interface,否则将不会使用。 通常,最好创建自定义日志处理程序(见下文),而不是直接覆盖日志记录器类。 日志处理程序 在 WooCommerce 中,日志处理程序是一个 PHP 类,它接收原始日志数据并将其转换为可以存储或分发的日志条目。 WooCommerce 提供了四种不同的日志处理程序类: Automattic\\WooCommerce\\Internal\\Admin\\Logging\\LogHandlerFileV2: 这是一个默认的处理程序,代表“文件系统”日志存储方法。 它将日志条目记录到文件中。 WC_Log_Handler_File: 这是一个旧的默认处理程序,也用于将日志条目记录到文件中。 可能会在未来被弃用,并且不建议使用此类或对其进行扩展。 WC_Log_Handler_DB: 此处理程序代表“数据库”日志存储方法。 它将日志条目记录到数据库中。 WC_Log_Handler_Email: 此处理程序不存储日志条目,而是将其作为电子邮件发送。 电子邮件发送到站点的管理员邮箱。 此处理程序有一些 限制。 更改或添加处理程序 要从文件处理程序切换到数据库处理程序,您可以简单地更新“日志设置”屏幕上的选项。 但是,在某些情况下,您可能希望拥有多个日志处理程序,并且/或您可能希望修改处理程序的设置。 例如,您可能希望将大多数日志保存到文件中,但将分类为紧急或严重错误的日志条目也发送到 Email 地址。为此,您可以使用 woocommerce_register_log_handlers 过滤器钩子来创建您想要使用的日志处理程序类实例的数组。 一些处理程序类构造函数具有可选参数,您可以在实例化类时使用这些参数来更改其默认行为。 以下是添加 Email 处理程序的示例: function my_wc_log_handlers( $handlers ) { $recipients = array( 'wayne@example.com', 'garth@example.com' ); // 将日志发送到多个接收者。 $threshold = 'critical'; // 仅为具有此级别及更高级别的日志发送电子邮件。 $handlers[] = new WC_Log_Handler_Email( $recipients, $threshold ); return $handlers; } add_filter( 'woocommerce_register_log_handlers', 'my_wc_log_handlers' ); 创建自定义处理程序 您可能希望创建自己的日志处理程序类,以便将日志发送到其他位置,例如 Slack 频道或 InfluxDB 实例。 您的类必须扩展 WC_Log_Handler 抽象类,并实现 WC_Log_Handler_Interface 界面。 WC_Log_Handler_Email 处理程序类提供了一个很好的示例,说明如何设置它。 日志文件存储位置 当使用“文件系统”日志处理程序时,默认情况下,日志文件存储在 WordPress “uploads” 目录中的 wc-logs 子目录中,这意味着它们可能可以公开访问。 WooCommerce 会添加一个 .htaccess 文件以防止访问 wc-logs,但并非所有 Web 服务器都识别该文件。 如果有选项,您可能希望考虑将您的日志文件存储在 Web 根目录之外的目录中。 确保该目录具有与 “uploads” 目录相同的用户/组 权限,以便 WordPress 可以访问它。 然后,使用 woocommerce_log_directory 过滤器钩子来设置指向您自定义目录的路径。 禁用冗余日志 如果某个日志信息频繁出现,并且阻塞了您的日志文件,您应该尝试找出它为什么会频繁触发,并解决问题。 但是,如果无法解决,您可以向 woocommerce_logger_log_message 过滤器钩子添加一个回调函数,以忽略该特定日志信息,同时允许其他日志信息通过: function my_ignored_logs( $message, $level, $context, $handler ) { if ( false !== strpos( $message, 'Look, a squirrel!' ) ) { return null; } return $message; } add_filter( 'woocommerce_logger_log_message', 'my_ignored_logs', 10, 4 ); 日志界面 如果您创建了一个自定义日志句柄,并且希望在该日志句柄上构建一个独立的界面,您可以使用以下几个过滤器钩子: woocommerce_logger_handler_options: 此过滤器钩子允许您将自定义日志句柄添加到“日志存储”选项的列表中,位于“设置”界面。 必须首先选择您的句柄,使其成为“默认”日志句柄,然后才能为其渲染替代界面。 wc_logs_render_page: 这是用于渲染您自己的日志界面的动作钩子。 它仅在默认日志句柄设置为内置句柄之外的选项时才会触发。 wc_logs_load_tab: 此动作在日志选项卡首次加载时触发,在任何内容输出之前。 它对于处理表单提交非常有用。 0043-best-practices-data-management-docs-data-storage title: "数据存储基础" post_status: publish comment_status: open taxonomy: category: - woocommerce post_tag: - Data Management - Best Practices - Repos post_title: 数据存储基础 sidebar_label: 数据存储 --- # 数据存储基础 在为 WordPress 和 WooCommerce 开发时,重要的是要考虑数据的性质和持久性。这将帮助您决定最佳的存储方式。以下是一个简要的介绍: ## 瞬态 如果数据可能并不总是存在(即,它会过期),请使用 [瞬态](https://developer.wordpress.org/apis/handbook/transients/)。瞬态是一种简单且标准化的方法,用于在数据库中临时存储缓存数据,通过为其指定自定义名称和过期时间,在过期后自动删除。 ## WP Cache 如果数据是持久的,但并不总是存在,请考虑使用 [WP Cache](https://developer.wordpress.org/reference/classes/wp_object_cache/)。WP Cache 函数允许您缓存计算成本高昂的数据,例如复杂的查询结果。 ## wp_options 表 如果数据是持久的并且始终存在,请考虑 [wp_options 表](https://developer.wordpress.org/apis/handbook/options/)。选项 API 是一种简单且标准化的方法,用于在 WordPress 数据库的 wp_options 表中存储数据。 ## 帖子类型 如果数据类型是具有 n 个单位的实体,请考虑使用 [帖子类型](https://developer.wordpress.org/post_type/)。帖子类型是内容的一种“类型”,它们以相同的方式存储,但在代码和 UI 中易于区分。 ## 分类法 如果数据是用于对实体进行排序/分类的手段,请考虑使用 [分类法](https://developer.wordpress.org/taxonomy/)。分类法是一种将事物分组的方法。 ## 日志记录 日志应使用 [WC_Logger](https://woocommerce.com/wc-apidocs/class-WC_Logger.html) 类写入文件。这是一种简单且标准化的方法,用于记录事件和错误,以便进行调试。 请记住,最佳的数据存储方法取决于数据的性质以及它将在您的应用程序中如何使用。 使用 WooCommerce CRUD 对象进行开发 CRUD 是您可以对数据库或资源执行的四种基本操作的缩写——创建、读取、更新、删除。 WooCommerce 3.0 引入了 CRUD 对象用于处理 WooCommerce 数据。在您的代码中,应尽可能使用这些对象,而不是直接更新元数据或使用 WordPress 文章对象。 每个对象都包含其控制数据的结构化数据(属性)、每个属性的 getter 和 setter,以及与数据存储交互的保存/删除方法。数据存储处理从数据库的实际保存/读取。对象本身无需知道数据存储在哪里。 CRUD 的优势 结构 - 每个对象都有预定义的结构并保持其自身数据有效。 控制 - 我们控制数据流以及任何所需的验证,因此我们知道何时发生更改。 易于开发 - 作为开发人员,您无需了解所处理数据的内部细节,只需知道其名称。 抽象 - 数据可以移动到其他地方,例如自定义表,而不会影响现有代码。 统一 - 我们可以使用相同的代码在管理员界面、REST API 和 CLI 中更新内容。一切都是统一的。 简化代码 - 用于更新对象的程序性代码更少,这降低了故障可能性并增加了单元测试覆盖率。 CRUD 对象结构 WC_Data 类是 CRUD 对象的基本实现,所有 CRUD 对象都继承自它。最重要的属性是 $data(一个包含每个对象所支持属性的数组)和 $id(对象的 ID)。 优惠券对象类 是扩展 WC_Data 并为所有属性添加 CRUD 函数的一个很好的例子。 数据 $data 存储属性名称和默认值: /** * 数据数组,包含默认值。 * @since 3.0.0 * @var array */ protected $data = array( 'code' => '', 'amount' => 0, 'date_created' => '', 'date_modified' => '', 'discount_type' => 'fixed_cart', 'description' => '', 'date_expires' => '', 'usage_count' => 0, 'individual_use' => false, 'product_ids' => array(), 'excluded_product_ids' => array(), 'usage_limit' => 0, 'usage_limit_per_user' => 0, 'limit_usage_to_x_items' => 0, 'free_shipping' => false, 'product_categories' => array(), 'excluded_product_categories' => array(), 'exclude_sale_items' => false, 'minimum_amount' => '', 'maximum_amount' => '', 'email_restrictions' => array(), 'used_by' => array(), ); Getter 与 Setter 方法 此数组(属性)中的每个键都对应一个 getter 和 setter 方法,例如 set_used_by() 和 get_used_by()。 $data 本身是私密的,因此必须使用 getter 和 setter 方法来访问数据。 Getter 示例: /** * 获取所有使用过当前优惠券的用户记录。 * @since 3.0.0 * @param string $context * @return array */ public function get_used_by( $context = 'view' ) { return $this->get_prop( 'used_by', $context ); } Setter 示例: /** * 设置哪些用户使用过此优惠券。 * @since 3.0.0 * @param array $used_by * @throws WC_Data_Exception */ public function set_used_by( $used_by ) { $this->set_prop( 'used_by', array_filter( $used_by ) ); } set_prop 和 get_prop 是 WC_Data 的一部分。它们会应用各种过滤器(基于上下文)并处理变更,因此我们可以高效地仅保存已更改的属性,而不是所有属性。 关于 $context 的说明:当获取用于前端或显示的数据时,使用 view 上下文。这会对数据应用过滤器,以便扩展可以动态更改值。在后台显示要编辑的值以及保存到数据库时,应使用 edit 上下文。使用 edit 上下文不会对数据应用任何过滤器。 构造函数 CRUD 对象的构造函数便于从数据库读取数据。实际的读取操作并非由 CRUD 类执行,而是由其数据存储完成。 示例: /** * 优惠券构造函数。加载优惠券数据。 * @param mixed $data 优惠券数据、对象、ID 或代码。 */ public function __construct( $data = '' ) { parent::__construct( $data ); if ( $data instanceof WC_Coupon ) { $this->set_id( absint( $data->get_id() ) ); } elseif ( is_numeric( $data ) && 'shop_coupon' === get_post_type( $data ) ) { $this->set_id( $data ); } elseif ( ! empty( $data ) ) { $this->set_id( wc_get_coupon_id_by_code( $data ) ); $this->set_code( $data ); } else { $this->set_object_read( true ); } $this->data_store = WC_Data_Store::load( 'coupon' ); if ( $this->get_id() > 0 ) { $this->data_store->read( $this ); } } 请注意它如何根据传递给对象的数据设置 ID,然后调用数据存储从数据库检索数据。一旦通过数据存储读取了数据,或者未设置 ID,就会设置 $this->set_object_read( true );,以便数据存储和 CRUD 对象知道它已被读取。设置此标志后,系统将开始跟踪更改。 保存与删除 在 CRUD 子类中,保存和删除方法是可选的,因为 WC_Data 父类可以处理它们。当调用 save 时,数据存储用于将数据保存到数据库。Delete 则从数据库中移除对象。必须调用 save 才能使更改持久化,否则它们将被丢弃。 WC_Data 中的 save 方法如下所示: /** * Save should create or update based on object existence. * * @since 2.6.0 * @return int */ public function save() { if ( $this->data_store ) { // 在保存到数据库前触发操作。允许您在保存前调整对象属性。 do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store ); if ( $this->get_id() ) { $this->data_store->update( $this ); } else { $this->data_store->create( $this ); } return $this->get_id(); } } 根据对象是否已有 ID,使用更新/创建。ID 将在创建后设置。 delete 方法如下: /** * Delete an object, set the ID to 0, and return result. * * @since 2.6.0 * @param bool $force_delete * @return bool result */ public function delete( $force_delete = false ) { if ( $this->data_store ) { $this->data_store->delete( $this, array( 'force_delete' => $force_delete ) ); $this->set_id( 0 ); return true; } return false; } CRUD 用法示例 创建新的简单产品 $product = new WC_Product_Simple(); $product->set_name( 'My Product' ); $product->set_slug( 'myproduct' ); $product->set_description( 'A new simple product' ); $product->set_regular_price( '9.50' ); $product->save(); $product_id = $product->get_id(); 更新现有优惠券 $coupon = new WC_Coupon( $coupon_id ); $coupon->set_discount_type( 'percent' ); $coupon->set_amount( 25.00 ); $coupon->save(); 获取客户信息 $customer = new WC_Customer( $user_id ); $email = $customer->get_email(); $address = $customer->get_billing_address(); $name = $customer->get_first_name() . ' ' . $customer->get_last_name(); 优惠券管理 本页面用于管理优惠券。您可以查看、创建、编辑和删除优惠券。 新增优惠券:点击“新增”按钮,可以创建新的优惠券。 编辑优惠券:点击优惠券列表中的“编辑”按钮,可以修改现有优惠券的设置。 删除优惠券:点击优惠券列表中的“删除”按钮,可以删除优惠券。 优惠券详情 显示单个优惠券的详细信息,包括: 名称 (Name):优惠券的名称。 折扣 (Discount):优惠券的折扣类型和金额。 使用 (Use):优惠券的使用限制,例如最小订单金额、使用次数等。 有效期 (Expiration Date):优惠券的有效期。 其他设置 (Other Settings):其他自定义设置。 优惠券列表 显示所有优惠券的列表,包括: 名称 (Name):优惠券的名称。 折扣 (Discount):优惠券的折扣类型和金额。 使用次数 (Count):优惠券已使用的次数。 状态 (Status):优惠券的状态,例如“有效”、“已过期”、“已禁用”。 批量操作 您可以对多个优惠券进行批量操作,例如: 删除 (Delete):删除选中的优惠券。 更新 (Updating):更新选中的优惠券的状态。 导入/导出 您可以将优惠券数据从一个系统导入到另一个系统,或者将优惠券数据导出为文件。 导入 (Import):从文件导入优惠券数据。 导出 (Export):将优惠券数据导出为文件。 优惠券代码 以下是一些常用的优惠券代码示例: %s:占位符,表示用户可以自定义的文本。 {name}:占位符,表示客户的名称。 邮件通知 当客户使用优惠券时,您可以发送电子邮件通知。 邮件 (Mail):发送电子邮件通知。 收件人 (Address):收件人的电子邮件地址。 主题 (Subject):电子邮件的主题。 正文 (Body):电子邮件的正文内容。 账单 (Billing) 显示与优惠券相关的账单信息。 金额 (Amount):优惠券的金额。 百分比 (Percent):优惠券的百分比折扣。 类型 (Type):优惠券的类型。 常见问题 如何创建新的优惠券? 点击“新增”按钮,填写优惠券的详细信息,然后点击“保存”按钮。 如何修改现有优惠券? 点击优惠券列表中的“编辑”按钮,修改优惠券的设置,然后点击“保存”按钮。 如何删除优惠券? 点击优惠券列表中的“删除”按钮,确认删除操作。 如何使用优惠券? 在结账时,输入优惠券代码,系统会自动应用折扣。 优惠券的有效期是什么? 优惠券的有效期由您在创建优惠券时设置。 如何查看优惠券的使用情况? 在优惠券详情页面,您可以查看优惠券的使用次数和状态。 如何导出优惠券数据? 点击“导出”按钮,选择导出的文件格式,然后点击“下载”按钮。 如何导入优惠券数据? 点击“导入”按钮,选择要导入的文件,然后点击“上传”按钮。 错误信息 Invalid coupon code.:优惠券代码无效。 Coupon has expired.:优惠券已过期。 Coupon has already been used.:优惠券已使用。 Minimum order amount not met.:未达到最小订单金额。 Coupon cannot be applied to this product.:该优惠券无法应用于该商品。 Error updating coupon.:更新优惠券时出错。 Error deleting coupon.:删除优惠券时出错。 Error importing coupon data.:导入优惠券数据时出错。 Error exporting coupon data.:导出优惠券数据时出错。 提示 您可以使用搜索框快速查找优惠券。 您可以使用分页功能浏览优惠券列表。 您可以使用排序功能对优惠券列表进行排序。 您可以使用过滤器功能筛选优惠券列表。 如果您在使用优惠券时遇到问题,请联系客服。 请定期检查和更新您的优惠券,以确保其有效性。 您可以创建自定义的优惠券代码,以满足您的特定需求。 您可以 更新国家和行政区划 WooCommerce 包含一个全面的国家和行政区划(例如省份或州)列表,这些列表用于用户界面的各个部分。 当然,国家及其行政区划也会定期发生变化。 在这些情况下,您可以提交一个 问题报告 或 提交一个拉取请求。 但是,重要的是要理解,我们的政策只接受与当前版本的 CLDR 项目 保持一致的更改。 因此,通常最好先查看该项目,如果需要,首先在该项目上提出更改,然后再要求 WooCommerce 采用这些更改。 这种方法可能不适用于所有情况,因为 CLDR 接受更新可能需要时间。 在这种情况下,您仍然可以使用自定义代码片段来修改国家和行政区划的列表,例如以下代码片段: 代码片段:添加一个国家 代码片段:添加或修改州/省 如何翻译 WooCommerce WooCommerce 已经翻译成多种语言,并且开箱即用,支持翻译。 只需要一个用于您语言的翻译文件即可。 创建翻译的方法有很多,大多数方法都已在 WordPress Codex 中详细说明。 在大多数情况下,您可以访问 https://translate.wordpress.org/projects/wp-plugins/woocommerce/ 参与该项目。 要创建自定义翻译,您可以考虑使用 Poedit。 设置您网站的语言 要设置您的 WordPress 网站的语言: 转到 WP Admin > 设置 > 常规,并调整 Site Language。 转到 WP Admin > 仪表盘 > 更新,然后单击 更新翻译 按钮。 完成这些操作后,如果语言文件存在,商店将以您的本地语言显示。 否则,您需要创建语言文件(具体过程如下所述)。 向核心贡献您的本地化版本 我们鼓励对翻译做出贡献。 如果您想添加已翻译的字符串或开始一个新的翻译,只需在 WordPress.org 上注册,并将您的翻译提交到 https://translate.wordpress.org/projects/wp-plugins/woocommerce/ 以供审核。 将 WooCommerce 翻译成您的语言 WooCommerce 的稳定版本和开发版本都可供翻译。 当您安装或更新 WooCommerce 时,WordPress 将自动获取您语言的完整翻译。 如果没有可用的翻译,您可以手动下载,或者贡献以完成翻译,从而使所有用户受益。 如果您是翻译新手,请查看 译者手册 以开始您的翻译之旅。 手动从 translate.wordpress.org 下载翻译 访问 translate.wordpress.org 并在该列表中查找您的语言。 点击标题,进入该语言的对应部分。 点击 Set/Sub Project 下方的标题,以查看和下载稳定版本的翻译。 滚动到页面底部,找到导出选项。 导出 .mo 文件,以便在您的网站中使用。 将该文件重命名为 woocommerce-YOURLANG.mo(例如,对于英国英语,应为 en_GB)。 相应的语言代码可以在访问 https://translate.wordpress.org/projects/wp-plugins/woocommerce/ 并打开所需的语言时找到。 语言代码显示在右上角。 将文件上传到 wp-content/languages/woocommerce/ 目录。 上传后,即可使用此翻译文件。 创建自定义翻译 WooCommerce 包含一个语言文件 ( .pot 文件),其中包含所有英文文本。 您可以在插件文件夹的 woocommerce/i18n/languages/ 目录中找到此语言文件。 使用 PoEdit 创建自定义翻译 WooCommerce 附带一个 .pot 文件,可以将其导入到 PoEdit 中进行翻译。 开始步骤: 打开 PoEdit,选择 Create new translation from POT template(从 POT 模板创建新的翻译)。 选择 woocommerce.pot,PoEdit 将显示目录属性窗口。 输入您的姓名和详情,以便其他译: 知道您的身份,然后点击 OK。 保存您的 .po 文件。 根据您要翻译的内容命名,例如,对于英国的翻译,应保存为 woocommerce-en_GB.po。 现在,字符串列表将显示。 在翻译字符串后保存。 .mo 文件将自动生成。 打开您的 .po 文件,然后转到 Catalog > Update from POT file(目录 > 从 POT 文件更新)以更新您的 .po 文件。 选择文件,它将被相应地更新。 确保您的翻译升级安全 WooCommerce 将翻译文件保存在 wp-content/languages/plugins 目录下,与其他所有插件一样。但是,如果您希望包含自定义翻译,可以使用 wp-content/languages/woocommerce 目录,或者可以使用一段代码来加载存储在其他位置的自定义翻译: // 将以下代码放置在您主题的 functions.php 文件或自定义插件文件中。 add_filter( 'load_textdomain_mofile', 'load_custom_plugin_translation_file', 10, 2 ); /** * 将 'textdomain' 替换为您的插件的 textdomain。例如:'woocommerce'。 * 文件的命名方式,例如:yourtranslationfile-en_GB.mo * 文件的放置位置,例如:wp-content/languages/textdomain/yourtranslationfile-en_GB.mo */ function load_custom_plugin_translation_file( $mofile, $domain ) { if ( 'textdomain' === $domain ) { $mofile = WP_LANG_DIR . '/textdomain/yourtranslationfile-' . get_locale() . '.mo'; } return $mofile; } 其他工具 有一些其他的第三方工具可以帮助您进行翻译。以下列表显示了一些工具。 Loco Translate Loco Translate 提供了在浏览器中编辑 WordPress 翻译文件的功能,并与自动翻译服务进行集成。 Say what? Say what? 允许您轻松地翻译或修改特定的单词,而无需深入到 WordPress 主题的 .po 文件中。 String locator String Locator 允许您快速在主题、插件或 WordPress 核心中进行搜索,并显示包含匹配文本的文件列表以及其行号。 常见问题解答 为什么结账页面的某些字符串没有被翻译? 您可能会发现,结账页面上的某些字符串没有被翻译。例如,在下面的截图中, 本地自提 配送方式、 货到付款 支付方式以及与隐私政策相关的信息都没有被翻译成俄语,而表单的其余部分确实被翻译了: 这种情况通常发生在您首次安装 WooCommerce 并选择默认站点语言(英语),然后更改站点语言为另一种语言时。在 WooCommerce 中,与屏幕截图中的未翻译字符串相关的信息,会在初始 WooCommerce 安装后存储在数据库中。因此,如果站点语言更改为另一种语言,WooCommerce 无法检测到可翻译的字符串,因为这些是数据库条目。 要解决此问题,请导航到与您需要更改的字符串对应的 WooCommerce 设置,并在那里直接更新翻译。例如,要修复我们上述情况中的字符串,您需要执行以下操作: 本地自提: 转到 WooCommerce > 设置 > 配送 > 配送区域。 选择包含“本地自提”的配送区域。 打开“本地自提”设置。 使用您的翻译重命名该方法。 保存设置。 货到付款: 转到 WooCommerce > 设置 > 支付。 选择“货到付款”支付方式。 打开其设置。 使用您的翻译重命名该方法的标题、描述和说明。 保存设置。 隐私政策信息: 转到 WooCommerce > 设置 > 账户与隐私。 滚动到“隐私政策”部分。 使用您的翻译编辑“注册隐私政策”和“结账隐私政策”字段。 保存设置。 返回结账页面 - 翻译应该会反映在那里。 我已经翻译了需要的字符串,但有些字符串在前端没有显示翻译结果。为什么? 如果您的 WooCommerce 网站上的一些已翻译字符串没有按预期显示,首先需要检查这些字符串在源文本部分是否同时具有单数和复数形式。为此,请打开相应的翻译,例如,在 https://translate.wordpress.org/projects/wp-plugins/woocommerce/ 上,查看“产品”和“项目”的翻译,例如 产品和项目的翻译。 此截图显示单数形式的翻译是可用的: 而此截图显示复数形式的翻译是无法使用的: 更新国家和行政区划 WooCommerce 包含一个全面的国家和行政区划(例如省份或州)列表,这些列表用于用户界面的各个部分。 当然,国家及其行政区划也会定期发生变化。 在这些情况下,您可以提交一个 问题报告 或 提交一个拉取请求。 但是,重要的是要理解,我们的政策只接受与当前版本的 CLDR 项目 保持一致的更改。 因此,通常最好先查看该项目,如果需要,首先在该项目上提出更改,然后再要求 WooCommerce 采用这些更改。 这种方法可能不适用于所有情况,因为 CLDR 接受更新可能需要时间。 在这种情况下,您仍然可以使用自定义代码片段来修改国家和行政区划的列表,例如以下代码片段: 代码片段:添加一个国家 代码片段:添加或修改州/省 如何配置 WooCommerce 的缓存插件 从缓存中排除网页 通常,在使用缓存插件时,它们已经会自动排除某些网页。如果不是,请确保通过缓存系统的相应设置,从缓存中排除以下网页: 购物车 我的账户 结账 这些网页需要保持动态状态,因为它们显示特定于当前客户及其购物车的信息。 从缓存中排除 WooCommerce 会话 如果使用的缓存系统提供数据库缓存功能,那么将 _wc_session_ 从缓存中排除可能会有所帮助。这取决于插件或主机缓存的配置,请参考该系统的具体说明或文档。 从缓存中排除 WooCommerce Cookie WooCommerce 中的 Cookie 用于跟踪客户购物车的产品,可以保留客户离开网站时的购物车数据,并驱动“最近浏览”小工具。以下是 WooCommerce 使用的 Cookie 列表,您可以将它们从缓存中排除。 COOKIE 名称 持续时间 作用 woocommerce_cart_hash 会话 帮助 WooCommerce 确定购物车内容/数据何时发生变化。 woocommerce_items_in_cart 会话 帮助 WooCommerce 确定购物车内容/数据何时发生变化。 wp_woocommerce_session_ 2 天 包含每个客户的唯一代码,以便知道在数据库中为每个客户查找购物车数据的位置。 woocommerce_recently_viewed 会话 驱动“最近浏览产品”小工具。 store_notice[notice id] 会话 允许客户不再显示商店通知。 我们无法涵盖所有选项,但我们添加了一些关于常用缓存插件的提示。如需更具体的支持,请联系负责您缓存集成的支持团队。 W3 Total Cache 压缩设置 请确保在“压缩”设置中的“忽略的注释开头”选项中添加 'mfunc'。 WP-Rocket WooCommerce 与 WP-Rocket 完全兼容。请确保在插件的设置中,不要将以下网页(购物车、结账、我的账户)缓存。 我们建议避免 JavaScript 文件压缩。 WP Super Cache WooCommerce 原生支持 WP Super Cache。WooCommerce 会向 WP Super Cache 发送信息,以便默认情况下不缓存购物车、结账或我的账户网页。 Varnish if (req.url ~ "^/(cart|my-account|checkout|addons)") { return (pass); } if ( req.url ~ "\\?add-to-cart=" ) { return (pass); } 故障排除 为什么我的 Varnish 配置在 WooCommerce 中无法正常工作? 请查看 WordPress.org 上的以下支持论坛帖子,了解cookie 如何影响您的 Varnish 配置。 在 "if (req.http.cookie) {" 之前,添加以下内容: # 移除除了 WordPress 管理和 WooCommerce 页面之外的所有 Cookie if (!(req.url ~ "(wp-login|wp-admin|cart|my-account/*|wc-api*|checkout|addons|logout|lost-password|product/*)")) { unset req.http.cookie; } # 允许访问 WooCommerce 动态页面 if (req.url ~ "^/(cart|my-account/*|checkout|wc-api/*|addons|logout|lost-password|product/*)") { return (pass); } # 允许访问 WooCommerce 的“加入购物车”功能 if (req.url ~ "\?add-to-cart=") { return (pass); } # 允许访问 WooCommerce API if (req.url ~ "\?wc-api=") { return (pass); } # 通过网站阻止访问 php 管理页面 if (req.url ~ "^/phpmyadmin/.*$" || req.url ~ "^/phppgadmin/.*$" || req.url ~ "^/server-status.*$") { error 403 "出于安全原因,此 URL 只能通过主机名为 localhost (127.0.0.1) 的方式访问"; } 在 vcl_fetch 中添加以下内容: # 移除除了 WordPress 管理和 WooCommerce 页面之外的所有 Cookie if ( (!(req.url ~ "(wp-(login|admin)|login|cart|my-account/*|wc-api*|checkout|addons|logout|lost-password|product/*)")) || (req.request == "GET") ) { unset beresp.http.set-cookie; } 为什么我的密码重置功能陷入循环? 这是因为“我的账户”页面被缓存了。 一些具有服务器端缓存的主机可能不会阻止 my-account.php 被缓存。 如果您无法重置密码,并且始终返回到登录页面,请联系您的主机,以确保该页面已从其缓存中排除。 WooCommerce 扩展的性能最佳实践 优化 WooCommerce 扩展的性能对于确保在线商店的流畅运行、提供卓越的用户体验以及在搜索引擎结果中获得良好的排名至关重要。 本指南专为希望提高 WooCommerce 扩展的速度和效率的开发者而设计,重点在于理解性能影响、基准测试、测试以及实施改进策略。 性能优化 对于 WooCommerce 扩展,性能优化意味着确保您的代码能够为快速、响应的用户体验做出贡献,同时避免增加不必要的加载时间和资源消耗。 为什么性能至关重要 用户体验: 性能良好的扩展有助于提供无缝的购物体验,鼓励客户完成购买。 商店性能: 扩展会显著影响 WooCommerce 商店的整体速度; 优化的扩展有助于保持最佳的网站性能。 SEO 和转化率: 速度是 SEO 排名和转化率的关键因素。 高效的扩展有助于提高商店的排名和更高的转化率。 性能基准测试 为 WooCommerce 扩展的开发和持续改进设定明确的性能基准至关重要。 推荐的性能标准是在一个简单的 Woo 网站上,使用诸如 Chrome Lighthouse 之类的工具,实现 Chrome Core Web Vitals "Performance" 分数 90 或以上。 使用易于访问的工具进行基准测试 Chrome Lighthouse 提供了一个全面的框架来评估网页的性能,包括受您的 WooCommerce 扩展影响的网页。 通过将 Lighthouse 测试集成到您的开发流程中,您可以尽早识别和解决性能问题。 我们建议利用这些工具来评估您的扩展对 WooCommerce 商店性能的影响,并找出需要改进的领域。 性能提升策略 优化 WooCommerce 扩展的性能涉及以下几个关键策略: 优化资源加载: 确保脚本和样式仅在需要时才加载,采用条件加载的方式。 高效的数据库查询: 优化数据库交互,以最大限度地减少查询时间和资源消耗。 适当使用索引,并避免不必要的 Data 检索。 延迟加载: 为您的扩展加载的 Images 和内容实现延迟加载,以减少初始 Page 加载时间。 压缩和合并: 压缩 CSS 和 JavaScript 文件,并在可能的情况下将它们合并,以减少 HTTP Requests 的数量。 在启用和禁用扩展时进行测试: 定期测试启用和禁用您的扩展的 WooCommerce Store,以便清楚地了解其对性能的影响。 缓存支持: 确保您的扩展与流行的缓存解决方案兼容,并避免可能不必要地绕过或 Clear Cache 的 Actions。 通过遵循这些最佳实践,并定期对您的扩展进行基准测试和测试,您可以确保它能够提升,而不是降低,WooCommerce Store 的性能。 实施这些策略将带来更高效、加载速度更快的扩展,这将受到 Store 所有者及其 Customers 的赞赏。 如何优化 WooCommerce 商店的性能 简介 本指南涵盖了优化 WooCommerce 商店性能的最佳实践和技术,包括缓存、图像优化、数据库维护、代码压缩以及使用内容分发网络 (CDN)。 通过遵循这些建议,开发者可以构建高性能的 WooCommerce 商店,从而提供更好的用户体验并提高转化率。 目标读者 本指南面向熟悉 WordPress 和 WooCommerce 且希望提高其在线商店性能的开发者。 前置条件 要遵循本指南,您应该具备: 对 WordPress 和 WooCommerce 的基本了解。 访问已安装并启用的 WooCommerce 的 WordPress 网站。 第一步 - 实施缓存 缓存在加速您的 WooCommerce 商店方面起着至关重要的作用,它通过向访问者提供页面的静态版本来减少服务器的负载。 有几种方法可以为您的 WooCommerce 商店实施缓存: 服务器端缓存 通过您的托管服务提供商或使用服务器级别的缓存解决方案(如 Varnish、NGINX FastCGI Cache 或 Redis)启用服务器端缓存。 WordPress 缓存插件 安装并配置一个 WordPress 缓存插件,例如 WP Rocket、W3 Total Cache 或 WP Super Cache。 这些插件可以帮助您设置 WooCommerce 商店的页面缓存、浏览器缓存和对象缓存。 WooCommerce 专用缓存 确保您的缓存解决方案已正确配置,以便允许动态内容(例如购物车和结账页面)不被缓存。 一些缓存插件,例如 WP Rocket,内置了对 WooCommerce 缓存的支持。 第二步 - 优化图像 优化图像可以通过减少图像文件的大小(而不影响质量)来显着提高商店的性能。 要优化 WooCommerce 商店中的图像: 使用正确的图像格式:为您的图像选择合适的格式,例如 JPEG 用于照片,PNG 用于具有透明度的图形。 压缩图像:使用图像压缩工具(如 TinyPNG 或 ShortPixel)在将它们上传到商店之前减小文件大小。 启用延迟加载:延迟加载会在需要时才加载图像,从而提高初始页面加载时间。 许多缓存插件和性能优化插件提供内置的延迟加载选项。 使用响应式图像:确保您的主题和插件为不同的设备和屏幕分辨率提供适当大小的图像。 第三步 - 压缩和优化代码 压缩和优化商店的 HTML、CSS 和 JavaScript 文件可以帮助减小文件大小并提高网页加载速度。要为您的 WooCommerce 商店压缩和优化代码: 使用插件:安装一个性能优化插件,例如 Autoptimize、WP Rocket 或 W3 Total Cache,以压缩和优化商店的 HTML、CSS 和 JavaScript 文件。 组合并内联关键 CSS:尽可能地组合并内联关键 CSS,以减少请求数量并提高网页加载速度。 延迟加载非关键 JavaScript:延迟加载非关键 JavaScript 文件,以提高 perceived 网页加载速度。 第四步 - 使用内容分发网络 (CDN) 内容分发网络 (CDN) 可以通过从分布在全球各地的服务器网络中提供静态资源,例如图像、CSS 和 JavaScript 文件,来提高您的 WooCommerce 商店的性能。要为您的 WooCommerce 商店使用 CDN: 选择 CDN 提供商:选择一个适合您的需求和预算的 CDN 提供商,例如 Cloudflare、Fastly 或 Amazon CloudFront。 设置您的 CDN:按照您选择的 CDN 提供商的说明,设置和配置 CDN 以用于您的 WooCommerce 商店。 第五步 - 优化数据库 定期优化您的 WordPress 数据库可以帮助提高 WooCommerce 商店的性能,方法是删除不必要的数据并优化数据库表。要优化您的数据库: 使用插件:安装一个数据库优化插件,例如 WP-Optimize、WP-Sweep 或 Advanced Database Cleaner,以清理和优化您的 WordPress 数据库。 删除不必要的数据:定期删除垃圾评论、文章修订和过期的瞬态数据,以减少数据库的冗余。 优化数据库表:使用数据库优化插件来优化您的数据库表,提高其效率并减少查询时间。 第六步 - 选择高性能的主题和插件 您为 WooCommerce 商店选择的主题和插件会对性能产生重大影响。为了确保您的商店运行高效: 选择一个轻量级、性能优化的主题:选择一个专门为 WooCommerce 设计的主题,该主题优先考虑性能并遵循最佳编码实践。 评估插件性能:使用工具,例如 Query Monitor 或 WP Hive,来分析您安装的插件对性能的影响,并移除或替换那些对商店性能产生负面影响的插件。 第七步 - 启用 GZIP 压缩 GZIP 压缩可以帮助减小商店的 HTML、CSS 和 JavaScript 文件的尺寸,从而提高网页加载速度。要启用 GZIP 压缩: 使用插件:安装一个性能优化插件,例如 WP Rocket、W3 Total Cache 或 WP Super Cache,该插件包含 GZIP 压缩选项。 配置您的服务器:或者,通过修改您的 .htaccess 文件(适用于 Apache 服务器)或 nginx.conf 文件(适用于 NGINX 服务器),直接在您的服务器上启用 GZIP 压缩。 第 8 步 - 监控和分析性能 持续监控和分析您的 WooCommerce 商店的性能,以识别潜在的瓶颈和需要改进的方面。为了监控和分析性能: 使用性能测试工具:定期使用诸如 Google PageSpeed Insights、GTmetrix 或 WebPageTest 之类的工具测试您的商店的性能。 实施性能监控:安装一个性能监控插件,例如 New Relic,或者使用一个监控服务,例如 Uptime Robot,以跟踪您的商店的性能。 结论 通过遵循这些最佳实践和性能优化技术,您可以构建一个高性能的 WooCommerce 商店,它能提供更好的用户体验,并有助于提高转化率。持续监控和分析您的商店的性能,以确保它在您的商店成长和发展时保持优化。 如何请求 WooCommerce 插件评论 请求评论的方法 后台通知 后台通知是请求评论的常用方法,但过度使用后台通知会降低效果。 我们建议在通知的设计上保持克制,并且每次只显示一个通知。 过多的或过于 intrusive 的通知很容易让商家感到厌烦。 建议 插件评论的后台通知最好显示在 Plugins 页面以及插件的 设置 页面。 在通知中包含一个或多个“稍后提醒”选项,并明确告知用户下次通知出现的时间。 后台通知必须始终可以被完全关闭。 仅提供“稍后提醒”选项是不够的。 通知中呈现的选项必须措辞谨慎,避免使用具有操纵性的语言。 使用一致的设计风格,使评论请求成为插件的一部分,并与 WooCommerce 的设计保持一致。 客户直接联系 建议 请求评论的最佳方式是,在客户对产品最满意时直接联系他们,这样成功的几率最高。 这可以通过里程碑或时间来触发,遵循以下时间指导原则。 最佳方法是发送电子邮件或其他直接沟通(支持聊天、电话等)。 这种方式的转化率最高,尤其是在时间恰当的情况下,即在客户最满意的时候。 当您可以从特定类型的商家那里收集反馈时,这种方法也非常有效,例如,那些通过您的平台处理了特定金额的商家,或者使用您的物流插件完成了前 100 个订单的商家。 直接沟通最有可能成功,如果您有方法可以针对特定用户发送评论请求(例如,商家账户/使用信息),并且有收集评论的渠道,例如销售或市场团队可以通过电子邮件/电话/聊天与商家沟通。 请求评论的文案 我们推荐的一种请求反馈的方法是使用 NPS 风格的评论征集方式。 这种方式可以增加正面评论的数量,同时也能为那些遇到困难的商家提供帮助。 NPS 风格的评论首先询问用户对产品的评分(满分 5 星),然后根据用户的回复进行不同的处理: 如果用户点击 4 或 5 星,则提示他们留下评论。 如果用户点击 1、2 或 3 星,则告知他们我们在这里提供帮助,并请他们提交支持工单。 在与支持人员进行积极的互动后,商家更有可能留下评论。 类似“感谢我的最佳方式是留下一个带有我的名字的 5 星评论”的说法通常效果很好——人们更愿意帮助一个人,而不是一个产品或公司。 各种建议和指导 与搜索词直接匹配的贡献者姓名将在 WordPress.org 插件库中获得极高的排名,这意味着如果您的 WordPress.org 用户名以您的业务命名(如果该名称是您插件的搜索词),可能会对竞争插件产生不利影响。 持续的提示和在管理员仪表盘上显示不必要的警报会降低用户体验。 您可以请求移除那些实际上不是反馈的评论。例如,如果评论只是一个简单的支持请求,并且明显放在了错误的位置,则可以考虑移除。即使是带有负面情绪的 1 星评论通常也不会被移除。 回复评论!感谢提供反馈的人,如果需要,承认问题,要求提供更具体的反馈,或者在问题得到解决时提供更新!您的评论是了解您的扩展程序用户的真实想法的重要途径。 让与扩展程序开发密切相关的人员(例如开发者和项目经理)定期查看评论,是确保客户的声音被听到的好方法。1 星评论通常最有价值,只要问题能够被理解和解决(如果需要)。 向用户通报错误修复和功能请求 一个错误或缺失的功能可能会对商家造成重大影响。 堆积的错误或未实现的流行功能可能导致负面评论,以及商家流失并寻找竞争解决方案。 通常,错误会通过支持渠道或 GitHub 报告,或者您可以在测试过程中自行发现。 当发现一个严重错误时,应在几天内解决它(大多数严重错误应在 24 小时内解决),并迅速发布一个新的插件版本。 您的发布流程的一部分应该是通知所有利益相关者(支持团队和受影响的商家)即将发布的版本。 即使一个严重错误给商家带来了很大的压力,但快速的解决能够让商家感到被倾听和被支持。 拥有一个可靠的合作伙伴,尤其是在最困难的情况下愿意提供帮助,有助于建立更牢固的关系。 因此,我们通常会要求商家在交付快速解决方案后给予 5 星的评价。 当您实现一个新的功能请求并发布一个新的插件版本时,您可以遵循与错误修复类似的方法: 通知所有利益相关者。 在“功能请求”看板中更新相关的请求,通过分享公开的更新并将其标记为“已完成”。 对于重大版本发布:与您的市场/公关团队沟通,以便在发布前发布更新/新闻邮件。 如何应对 WooCommerce 插件的负面评价 在商家的使用过程中,可能会遇到一些不愉快的事件,导致他们留下公开的负面评价。这些事件通常包括: 产品问题, 缺少产品功能, 没有提供有用的回复, 收到回复的等待时间过长,或者; 上述问题的组合。 收到负面评价时,您的目标应该是尽可能地将负面评价转化为正面评价,这听起来可能很困难,但实际上非常有价值。 在大多数情况下,留下负面评价的商家首先尝试联系客服寻求帮助。 这是一个非常有用的信息,因为我们可以查看对话历史,了解商家遇到的问题,并在我们回复时与他们分享更多详情,即使是从我们第一次回复开始。 我们发现以下流程效果良好: 创建一个新的回复(通过电子邮件或在公开评价中),主题为:关于您最近对 xxx 的评价。 首先,自我介绍,例如:“您好,我是来自开发 xxx 团队的 Andrew”。 使用富有同情心的语言,并明确表示这个负面评价对您产生了影响。 例如:“我阅读了您最近对 xxx 的评价,听到您遇到了问题,无法像您预想的那样使用此插件,我感到很担心。我很乐意帮助您解决这个问题!”。 将上面的句子与“我很抱歉您在使用 xxx 时遇到了问题”进行比较。“我很抱歉”表明您对某个事件感到难过,但可能并不打算采取任何行动。 相比之下,“我感到很担心”表明您会采取行动。 此外,“您遇到了问题”可能会被理解为问题主要在于商家,而使用“一个问题正在阻止您像您预想的那样使用此插件,我很乐意帮助您解决这个问题!” 这样的语言,则暗示您和商家是同一战壕里的。 分享更多详情、解决方案、想法、建议或解释。 鼓励商家更新评价,强调评价对您的团队和其他商家有多重要。 可以使用以下语句:“如果您能花几分钟时间更新您的评价,并描述您与我们的产品和支持的体验,我们将不胜感激。 诚实的评价对其他正在决定某个插件是否适合他们的商家来说非常有帮助。 谢谢您的贡献!”。 包含一个直接链接到评价部分,以便商家可以轻松地访问并更改他们的评价。 在后续沟通中,如果商家已经更新了评价,可以考虑说:“我将此事分享给了团队的其他成员,这让每个人都感到非常高兴”。 如果上述情况属实,与商家分享您的一些流程(强调您的团队如何重视和依赖反馈)有助于确保商家感到您是他们团队的一员,并与他们建立牢固的关系。 技术文档翻译 即使是那些没有对评价进行更改的商家,也可以通过了解对方的设置并提供一些建议,来进行互利的讨论。 这些对话有助于提高商家的信任度。 Setup Suggestions Discussion About Help View Row All Set Off More Sat By Or on at Example: This is an example of how to use the print() function in Python. print("Hello, world!") Explanation: The print() function takes a string as an argument and prints it to the console. Further Reading: Python Documentation Note: This document is a work in progress and may contain errors. Please report any errors to the author. Author: %s Date: %s Version: %d Contact: {name} URL: https://example.com 利用 WooCommerce 扩展的特性请求功能 重要的是要跟踪所有特性请求,并建立一种记录系统,以便任何人都可以了解产品在一段时间内收到的反馈类型。 我们建议每天或每隔一天进行检查,您应该: 评估新的特性请求, 庆祝积极的评论,以及; 采取行动处理负面评论。 仔细维护特性请求看板(或类似的系统)至关重要,因为平均而言,看板包含大量重复/垃圾内容、关于已实现功能的请求以及关于不太可能实现的请求。维护不当的看板会让商家感到被忽视。 这会导致更多负面评论,因为产品团队似乎没有阅读/倾听他们的反馈。 我们已经看到以下流程取得了良好的效果: 从受影响最大的产品开始,逐一查看所有未决请求,回复大部分或全部请求,并将它们分类为: "Open"(打开):表示我们仍然希望收到更多反馈的请求, "Planned"(计划中):表示我们计划实现的请求, "Completed"(已完成):表示已经实现的请求,以及; "Closed"(已关闭):表示我们不计划实现的请求,因为它们不适合产品,或者是因为是重复/垃圾请求,或者是因为实际上是支持问题。 回复所有“Open”请求是目标,但如果当前无法实现,请务必回复 100% 的已关闭请求。 对于作为特性请求而收到的新“Open”请求,请进行讨论/评估,并立即回复,并分配一个状态,以避免看板变得“未托管”,并确保商家感到(并且确实)被倾听。 除了一个整洁的看板对商家的积极影响外,它还可以帮助产品团队更好地了解哪些请求是最受欢迎和最具影响力的,然后据此进行工作规划。 如何利用您的支持团队来响应反馈 您的支持团队通常是商家与您联系的主要入口。门票(Tickets)和聊天是与商家沟通的最佳工具,可以帮助我们了解他们对软件的使用情况,倾听他们的反馈,并分析他们的功能请求。 总体而言,支持团队对产品以及用户的使用方式有着深刻的理解。 这些信息对于传递给产品和工程团队至关重要。 我们建议您采取以下步骤,以最佳方式利用您的支持团队: 创建严格的内部服务级别协议 (SLA),确保支持团队的请求由产品或工程团队来解答。 确保您的支持团队能够有效地向产品和工程团队报告 bug。 在回复您的支持团队时,避免使用过于简短的回答,并尝试用简单明了的语言解释答案。 这样可以让支持人员将您的答案复制/粘贴给商家。 避免直接回复“不可能”或“该功能不会实现”之类的语句,而应提供有关技术或产品限制的更多上下文信息。 定期抽出额外的时间来实施简短的自定义代码,或提供关于如何实施自定义项目的详细技术信息,以便商家如果决定聘请专门的 WooCommerce 开发者,可以更快地找到解决方案。 即使是 небольшое усилие может оказать большое влияние на удовлетворенность клиентов и создать возможности для请求 5 星评价。 当支持团队报告 bug 或请求新功能时,请让他们了解情况。 当我们发布新产品版本时,我们始终会考虑它对支持的影响。 与您的支持团队密切合作。 例如,可以考虑每月举行一次反馈会议,讨论产品反馈和计划的改进。 通过采取这些措施,支持团队更愿意与我们分享反馈、问题、疑虑和问题。 这有助于我们与商家建立更紧密的联系,并在问题成为他们流失的原因之前,尽早发现并解决问题。 何时请求 WooCommerce 扩展的评论 提高我们的五星级评论的最佳方法是,识别出商家旅程中的关键时刻,即他们更有可能留下评论,并主动请求他们留下评论。 对于大多数用例,最明显的时刻是: 当商家感到无助、迷茫或沮丧,而我们能够提供帮助时; 当商家在我们的代码中发现错误,而我们能够迅速修复时; 当商家需要某个功能,而我们通知他们该功能已发布时; 当商家感到孤立,而我们让他们感受到被倾听; 当商家提出问题,而我们竭尽全力为他们提供一流的支持,即使这意味着稍微超出官方支持政策的范围。 请考虑谁会看到评论请求,以及他们在当时正在做什么。向正在尝试发货订单的订单处理人员显示评论请求,可能效果并不好。 在达到某个里程碑后进行推广效果非常好。我们之前使用过的一些措辞是:“恭喜您完成了第 xx 个销售!我们很高兴 WooPayments 促成了这一里程碑。您是否愿意分享您的体验,并鼓励其他人通过评论我们的扩展?”。 另一种优化评论请求时间的方法是设置一个与使用模式相符的提示。例如,如果您知道大多数商家每天都使用您的扩展,那么您可能比那些商家很少使用的扩展更早地发送评论请求。 SaaS/Connector 扩展需要特别注意正确地请求评分,因为如果没有任何问题,它们最容易被忽略,这会导致评分偏差,无法真实反映扩展的实际情况。 请考虑在每次支持互动结束后收集反馈,尤其是在 WordPress.org 支持论坛上。最大的障碍之一是用户需要登录到 WooCommerce.com (或 WordPress.org),而 WordPress.org 支持论坛提供了一个很好的机会来收集这些评论。通过在公共支持论坛上积极响应并解决问题,用户已经登录并能够立即留下评论(在被请求之后!)。 各种建议和指导 与搜索词直接匹配的贡献者姓名将在 WordPress.org 插件库中获得极高的排名,这意味着如果您的 WordPress.org 用户名以您的业务命名(如果该名称是您插件的搜索词),可能会对竞争插件产生不利影响。 持续的提示和在管理员仪表盘上显示不必要的警报会降低用户体验。 您可以请求移除那些实际上不是反馈的评论。例如,如果评论只是一个简单的支持请求,并且明显放在了错误的位置,则可以考虑移除。即使是带有负面情绪的 1 星评论通常也不会被移除。 回复评论!感谢提供反馈的人,如果需要,承认问题,要求提供更具体的反馈,或者在问题得到解决时提供更新!您的评论是了解您的扩展程序用户的真实想法的重要途径。 让与扩展程序开发密切相关的人员(例如开发者和项目经理)定期查看评论,是确保客户的声音被听到的好方法。1 星评论通常最有价值,只要问题能够被理解和解决(如果需要)。 向用户通报错误修复和功能请求 一个错误或缺失的功能可能会对商家造成重大影响。 堆积的错误或未实现的流行功能可能导致负面评论,以及商家流失并寻找竞争解决方案。 通常,错误会通过支持渠道或 GitHub 报告,或者您可以在测试过程中自行发现。 当发现一个严重错误时,应在几天内解决它(大多数严重错误应在 24 小时内解决),并迅速发布一个新的插件版本。 您的发布流程的一部分应该是通知所有利益相关者(支持团队和受影响的商家)即将发布的版本。 即使一个严重错误给商家带来了很大的压力,但快速的解决能够让商家感到被倾听和被支持。 拥有一个可靠的合作伙伴,尤其是在最困难的情况下愿意提供帮助,有助于建立更牢固的关系。 因此,我们通常会要求商家在交付快速解决方案后给予 5 星的评价。 当您实现一个新的功能请求并发布一个新的插件版本时,您可以遵循与错误修复类似的方法: 通知所有利益相关者。 在“功能请求”看板中更新相关的请求,通过分享公开的更新并将其标记为“已完成”。 对于重大版本发布:与您的市场/公关团队沟通,以便在发布前发布更新/新闻邮件。 如何回应 WooCommerce 扩展的负面评价 商家在旅程中遇到不愉快的事件时,可能会留下公开的负面评价。这些事件通常包括: 产品存在问题 产品功能缺失 回复没有帮助 等待回复时间过长 或以上情况的组合 收到负面评价时,您的目标始终应该是扭转这一评价——这听起来很困难,但确实非常有价值。 在大多数情况下,留下负面评价的商家首先会尝试联系支持团队寻求帮助。这是一个有用的信息,因为我们可以阅读对话历史,了解商家遇到的问题,并在联系他们时分享更多详情,即使是在我们的首次回复中。 我们观察到的有效流程是: 创建新的回复(通过邮件或在公开评价中),主题:关于您最近对 xxx 的评价。 首先自我介绍,例如:"您好,我是来自开发 xxx 团队的 Andrew"。 使用共情的语言,并明确表示这次负面评价对您产生了影响。例如:"我阅读了您最近对 xxx 的评价,听到问题阻碍了您按预期使用此插件,我感到很担忧。我很乐意帮助您解决这个问题!"。 将上述句子与以下句子进行比较:"很遗憾听说您在 xxx 上遇到了问题"。"很遗憾"表示您对某事件感到难过,但不一定计划为此采取行动。相比之下,在"我很担心听到"中,"担心"暗示了行动。此外,"您在 xxx 上遇到了问题"可能被解读为问题主要是商家的过错,而像"某个问题阻碍了您按预期使用此插件。我很乐意帮助您解决这个问题!"这样的措辞则暗示您和商家站在同一阵线。 分享更多详情、解决方案、想法、建议或解释。 通过强调评论对我们的团队和其他商家的重要性,敦促商家更新评论。示例措辞为:"如果您能花几分钟时间更新您的评论,描述您对我们产品和支持的体验,我们将不胜感激。诚实的评论对其他尝试决定插件是否适合他们的商家非常有帮助。谢谢您的贡献!"。 包含指向评论部分的直接链接,以便商家轻松导航至该处并更改其评论。 在后续沟通中,如果商家已更改评论,可以考虑这样说:"我与团队其他成员分享了此事,这让每个人都感到非常高兴"。 如果上述情况属实,与商家分享您的部分流程(强调您的团队如何重视反馈并从中获益)有助于确保商家感觉您是他们的团队一员,并与他们建立牢固的关系。 即使商家没有更改评价,通过更多地了解他们的设置并提供一些建议,也能促成一次互利的讨论。这些对话有助于增进商家对您的信任。 如何利用您的支持团队来响应反馈 您的支持团队通常是商家与您联系的主要入口。门票(Tickets)和聊天是与商家沟通的最佳工具,可以帮助我们了解他们对软件的使用情况,倾听他们的反馈,并分析他们的功能请求。 总体而言,支持团队对产品以及用户的使用方式有着深刻的理解。 这些信息对于传递给产品和工程团队至关重要。 我们建议您采取以下步骤,以最佳方式利用您的支持团队: 创建严格的内部服务级别协议 (SLA),确保支持团队的请求由产品或工程团队来解答。 确保您的支持团队能够有效地向产品和工程团队报告 bug。 在回复您的支持团队时,避免使用过于简短的回答,并尝试用简单明了的语言解释答案。 这样可以让支持人员将您的答案复制/粘贴给商家。 避免直接回复“不可能”或“该功能不会实现”之类的语句,而应提供有关技术或产品限制的更多上下文信息。 定期抽出额外的时间来实施简短的自定义代码,或提供关于如何实施自定义项目的详细技术信息,以便商家如果决定聘请专门的 WooCommerce 开发者,可以更快地找到解决方案。 即使是 небольшое усилие может оказать большое влияние на удовлетворенность клиентов и создать возможности для请求 5 星评价。 当支持团队报告 bug 或请求新功能时,请让他们了解情况。 当我们发布新产品版本时,我们始终会考虑它对支持的影响。 与您的支持团队密切合作。 例如,可以考虑每月举行一次反馈会议,讨论产品反馈和计划的改进。 通过采取这些措施,支持团队更愿意与我们分享反馈、问题、疑虑和问题。 这有助于我们与商家建立更紧密的联系,并在问题成为他们流失的原因之前,尽早发现并解决问题。 何时请求 WooCommerce 扩展的评论 提高我们的五星级评论的最佳方法是,识别出商家旅程中的关键时刻,即他们更有可能留下评论,并主动请求他们留下评论。 对于大多数用例,最明显的时刻是: 当商家感到无助、迷茫或沮丧,而我们能够提供帮助时; 当商家在我们的代码中发现错误,而我们能够迅速修复时; 当商家需要某个功能,而我们通知他们该功能已发布时; 当商家感到孤立,而我们让他们感受到被倾听; 当商家提出问题,而我们竭尽全力为他们提供一流的支持,即使这意味着稍微超出官方支持政策的范围。 请考虑谁会看到评论请求,以及他们在当时正在做什么。向正在尝试发货订单的订单处理人员显示评论请求,可能效果并不好。 在达到某个里程碑后进行推广效果非常好。我们之前使用过的一些措辞是:“恭喜您完成了第 xx 个销售!我们很高兴 WooPayments 促成了这一里程碑。您是否愿意分享您的体验,并鼓励其他人通过评论我们的扩展?”。 另一种优化评论请求时间的方法是设置一个与使用模式相符的提示。例如,如果您知道大多数商家每天都使用您的扩展,那么您可能比那些商家很少使用的扩展更早地发送评论请求。 SaaS/Connector 扩展需要特别注意正确地请求评分,因为如果没有任何问题,它们最容易被忽略,这会导致评分偏差,无法真实反映扩展的实际情况。 请考虑在每次支持互动结束后收集反馈,尤其是在 WordPress.org 支持论坛上。最大的障碍之一是用户需要登录到 WooCommerce.com (或 WordPress.org),而 WordPress.org 支持论坛提供了一个很好的机会来收集这些评论。通过在公共支持论坛上积极响应并解决问题,用户已经登录并能够立即留下评论(在被请求之后!)。 如何防止 WooCommerce 网站的数据泄露 数据泄露可能会暴露敏感信息,并危及 WooCommerce 网站的安全性。 数据泄露的一个常见来源是直接访问 PHP 文件。 本教程将向您展示如何防止此类数据泄露。 在您 WooCommerce 扩展的每个 PHP 文件中,您应该检查是否定义了一个名为 'ABSPATH' 的常量。 此常量由 WordPress 本身定义,如果文件被直接访问,则不会定义该常量。 以下是如何操作: if ( ! defined( 'ABSPATH' ) ) { exit; // 如果被直接访问,则退出 } 通过这段代码,如果有人尝试直接访问 PHP 文件,'ABSPATH' 常量将未定义,并且脚本将在任何敏感数据泄露之前退出。 请记住,安全性是任何 WooCommerce 网站的一个至关重要的方面。 始终采取措施防止数据泄露并保护您网站的信息。 WooCommerce 安全最佳实践 安全实践简介 安全性对于在线商店至关重要。安全漏洞可能导致严重的财务损失、声誉损害以及客户信任的丧失。实施强大的安全措施至关重要。本指南涵盖了保护 WooCommerce 商店的最佳实践,包括加固 WordPress 系统、保持插件和主题的更新、实施安全的编码实践以及保护用户数据。通过遵循这些建议,开发者可以构建安全且具有弹性的 WooCommerce 商店,从而保护他们的业务和客户。 目标读者 本指南面向熟悉 WordPress 和 WooCommerce 并且希望提高其在线商店安全性的开发者。 前置条件 要遵循本指南,您应该具备以下条件: 对 WordPress 和 WooCommerce 有基本的了解。 拥有已安装并启用的 WooCommerce 的 WordPress 网站的访问权限。 安全标准 我们建议您维护以下标准: PHPCS: PHP 代码检查工具可以帮助确保您的代码符合特定的编码标准,从而可以防止常见的安全问题。扩展程序不应在 PHPCS 检查中出现任何失败的结果。 SemGrep: 专注于识别可能表明安全漏洞的模式,从而允许开发者编写更安全的代码。扩展程序不应在 SemGrep 检查中出现任何失败的结果。 理解和实施这些标准可以显著降低扩展程序和主题中安全漏洞的风险。 常见的安全陷阱以及如何避免 以下是一些常见的安全陷阱,可以通过谨慎和最佳实践轻松避免: SQL 注入: 确保所有数据库查询都经过适当的清理。 跨站脚本攻击: 清理所有用户输入,以防止恶意代码被执行。 文件包含: 限制文件包含,以防止未经授权的访问文件系统。 了解和预防这些常见问题是保护您的 WooCommerce 商店的关键步骤。 欲了解更多信息,我们建议您阅读 WordPress 安全文档。 手动测试指南 即使没有访问像 Woo Quality Insights Toolkit (QIT) 这样的自动化工具,手动测试仍然是确保您的 WooCommerce 商店安全的重要组成部分。以下是一些关于开发者如何手动测试其扩展程序以查找安全漏洞的指南: 代码审查: 定期审查您的代码是否存在安全漏洞,重点关注容易发生漏洞的区域,例如用户输入字段和数据库查询。代码审查应参考上述 WordPress 安全标准。 使用安全插件: 像 Wordfence、Sucuri 或 iThemes Security 这样的插件提供了一个界面,用于进行手动安全检查,包括文件完整性监控和恶意软件扫描。此外,可以使用诸如 OWASP Zap 或 GitHub Security Scanning 这样的工具。 测试环境: 使用测试环境来测试新功能或更新的安全性,然后再将其部署到生产环境。 其他安全最佳实践 保持 WordPress、WooCommerce 和插件的更新 定期更新 WordPress、WooCommerce 和所有已安装的插件对于维护安全的在线商店至关重要。更新通常包含安全补丁,可以解决漏洞并帮助保护您的商店免受攻击。要保持您的 WordPress 和 WooCommerce 安装的最新状态: 启用 WordPress 核心的自动更新。 定期检查并安装 WooCommerce 和所有插件的更新。 选择安全的插件和主题 您使用的插件和主题会对您的 WooCommerce 商店的安全性产生重大影响。为了确保您的商店安全: 从信誉良好的来源安装插件和主题,例如 WordPress 插件目录和主题目录。 定期审查和更新您使用的插件和主题,删除任何不再维护或已知存在安全漏洞的插件和主题。 避免使用盗版或破解的插件和主题,因为它们可能包含恶意代码。 实施安全的编码实践 安全的编码实践对于构建安全的 WooCommerce 商店至关重要。为了实施安全的编码实践: 在开发自定义主题或插件时,请遵循 WordPress 编码标准。 使用预处理语句和参数化查询来防止 SQL 注入攻击。 验证和清理用户输入,以防止跨站脚本攻击 (XSS) 和其他漏洞。 定期审查和更新您的自定义代码,以解决潜在的安全漏洞。 加强 WordPress 安全性 加强您的 WordPress 安装可以帮助保护您的 WooCommerce 商店免受攻击。 要加强 WordPress 的安全性: 为所有用户帐户使用强密码。 限制登录尝试,并启用双因素身份验证 (2FA),以防止暴力破解攻击。 更改 WordPress 数据库中默认的 wp_ 表前缀。 在不需要时禁用 XML-RPC 和 REST API 访问。 保持文件权限安全,并限制对敏感文件和目录的访问。 保护用户数据 保护客户的数据是确保 WooCommerce 商店安全的关键方面。 要保护用户数据: 使用 SSL 证书来加密您商店和客户之间传输的数据。 安全地存储客户数据,并限制对敏感信息的访问。 遵守数据保护法规,例如 GDPR,以确保您负责地处理客户数据。 实施安全插件 使用安全插件可以帮助您监控和保护您的 WooCommerce 商店免受潜在威胁。 要实施安全插件: 选择一个信誉良好的安全插件,例如 Wordfence、Sucuri 或 iThemes Security。 配置插件的设置,以启用诸如恶意软件扫描、防火墙保护和登录安全等功能。 定期监控和审计您的商店安全 持续监控和审计您的 WooCommerce 商店的安全,以识别潜在的漏洞,并在它们被利用之前解决它们。 要监控和审计您的商店安全: 使用安全插件定期扫描恶意软件和其他安全威胁。 监控您站点的活动日志,以识别可疑活动和潜在的安全问题。 定期进行安全审计,以评估您商店的整体安全性,并确定需要改进的方面。 创建定期备份 备份您的 WooCommerce 商店对于快速恢复安全事件至关重要,例如数据丢失或网站被入侵。 要创建定期备份: 选择一个可靠的备份插件,例如 UpdraftPlus、BackupBuddy 或 Duplicator。 配置插件以自动定期备份您的整个站点,包括数据库、文件和媒体。 将您的备份安全地存储在异地,以确保在发生紧急情况时可以访问它们。 结论 通过遵循这些安全最佳实践,您可以构建一个安全且具有弹性的 WooCommerce 商店,该商店可以保护您的业务和您的客户。 定期监控、审计和更新您商店的安全措施,将有助于确保它在出现新的威胁和漏洞时仍然受到保护。 如何防止 WooCommerce 网站的数据泄露 数据泄露可能会暴露敏感信息,并危及 WooCommerce 网站的安全性。 数据泄露的一个常见来源是直接访问 PHP 文件。 本教程将向您展示如何防止此类数据泄露。 在您 WooCommerce 扩展的每个 PHP 文件中,您应该检查是否定义了一个名为 'ABSPATH' 的常量。 此常量由 WordPress 本身定义,如果文件被直接访问,则不会定义该常量。 以下是如何操作: if ( ! defined( 'ABSPATH' ) ) { exit; // 如果被直接访问,则退出 } 通过这段代码,如果有人尝试直接访问 PHP 文件,'ABSPATH' 常量将未定义,并且脚本将在任何敏感数据泄露之前退出。 请记住,安全性是任何 WooCommerce 网站的一个至关重要的方面。 始终采取措施防止数据泄露并保护您网站的信息。 可分享的结账链接 自定义结账链接会自动将特定产品添加到购物车,并将客户直接重定向到带有唯一会话 ID 的结账页面。 自定义结账链接的路径是 /checkout-link/,且不可自定义。 支持的参数 产品 products=123:2,456:1 产品 ID 和数量的逗号分隔列表。例如: 123:2,456:1。此功能支持没有额外选项的简单产品。也可以通过使用正确的变体 ID 将单个变体添加到购物车。 优惠券 coupon=SPRING10 应用于购物车的优惠券代码。例如: SPRING10。 示例 https://yourstore.com/checkout-link/?products=123:2,456:1&coupon=SPRING10 在这个链接中: 产品 ID 123 将以数量 2 添加到购物车 产品 ID 456 将以数量 1 添加到购物车 将应用优惠券代码 SPRING10 客户将被直接带到结账页面 会话 当用户被重定向到结账页面时,购物车将被填充产品和优惠券代码。最终的 URL 包含一个 session 参数,用于存储会话 ID。对结账的后续更改将保存在会话中,从而实现持久且可共享的购物车。 自定义 WooCommerce 端点 URL 在开始之前,请查看 WooCommerce 端点。 自定义端点 URL 每个端点的 URL 可以在 WooCommerce > 设置 > 高级 的“页面设置”部分进行自定义。 请确保它们是唯一的,以避免冲突。 如果遇到 404 错误,请转到 设置 > 固定链接 并保存以刷新重写规则。 在菜单中使用端点 如果您想在菜单中包含一个端点,则需要使用“链接”部分: 输入端点的完整 URL,然后将其插入到您的菜单中。 请记住,某些端点,例如 view-order,需要一个订单 ID 才能正常工作。 通常,我们不建议将这些端点添加到您的菜单中。 这些页面可以通过“我的账户”页面访问。 在支付网关插件中使用端点 WooCommerce 在订单类中提供了辅助函数,用于获取这些 URL。 它们是: $order->get_checkout_payment_url( $on_checkout = false ); 以及: $order->get_checkout_order_received_url(); 网关需要使用这些方法以获得完整的 2.1+ 兼容性。 故障排除 端点显示 404 错误 如果您看到 404 错误,请转到 WordPress 后台 > 设置 > 固定链接 并保存。 这可确保端点的重写规则存在并且已准备就绪。 如果使用诸如 view-order 之类的端点,请确保它指定了订单号。 /view-order/ 无效。 /view-order/10/ 有效。 此类端点不应出现在您的导航菜单中。 端点无法正常工作 在 Windows 服务器上,web.config 文件可能未正确设置,无法使端点正常工作。 在这种情况下,单击端点链接(例如 /edit-account/ 或 /customer-logout/)可能似乎什么也没做,只是刷新了页面。 为了解决此问题,请尝试简化 Windows 服务器上的 web.config 文件。 以下是一个示例文件配置: <<>?xml version="1.0" encoding="UTF-8"?> 网页跳转到错误的位置 当点击某个端点 URL 时,如果跳转到错误的网页,通常是由于设置不正确造成的。例如,如果在您的账户页面点击“编辑地址”,但跳转到了商店页面,而不是编辑地址的表单,这意味着您在设置中选择了错误的网页。请确认您的网页配置是否正确,并且每个部分都使用了不同的网页。 如何从“我的账户”中移除“下载” 有时,“我的账户”页面上的“下载”端点不需要显示。可以通过访问 WooCommerce > 设置 > 高级 > 账户端点,然后清除“下载”端点字段来移除它。 理解在 WooCommerce 中移除 URL 基础部分的风险 总结 移除 /product/、 /product-category/ 或 /shop/ 这些基础部分,通常是不建议的,因为这会影响 WordPress 解析 URL 的方式。 WordPress 使用 URL 的 product-category (或者任何其他文本) 基础部分来检测该 URL 是否指向一个产品分类。 某些 SEO 插件允许您移除这些基础部分,但这可能会导致性能问题和重复 URL。 尽量避免 移除这些基础部分会使 WordPress 更难检测您尝试访问的页面。 此外,请理解 WordPress 中标准的 "网页" 始终在 URL 中不包含任何基础文本。 例如: http://yoursite.com/about-page/ (这是标准网页的 URL) http://yoursite.com/product-category/category-x/ (这是指向产品分类的 URL) 如果我们移除 "product-category" 部分会发生什么? http://yoursite.com/about-page/ http://yoursite.com/category-x/ 在这种情况下,WordPress 需要付出更多努力才能检测您正在寻找的页面。 这就是为什么我们不建议使用任何 SEO 插件来实现此目的。 在 WooCommerce 中使用 Webhook 什么是 Webhook? 一个 Webhook 是一种事件通知,发送到您选择的 URL。 用户可以配置它们,以便在一个站点的事件触发另一个站点的行为。 Webhook 对于与第三方服务和其他支持它们的外部 API 集成非常有用。 WooCommerce 中的 Webhook Webhook 在 WooCommerce 2.2 中引入,可以在您添加、编辑或删除订单、产品、优惠券或客户时触发事件。 您还可以使用 Webhook 与 WooCommerce 的操作结合使用,例如,创建一个 Webhook,以便在每次将产品添加到购物车时触发,使用操作 woocommerce_add_to_cart。 Webhook 还可以使第三方应用程序更容易与 WooCommerce 集成。 创建 Webhook 要创建新的 Webhook: 1/ 转到: WooCommerce > 设置 > 高级 > Webhook。 注意: 在 WooCommerce 3.4 之前,Webhook 位于 WooCommerce > 设置 > API 下。 2/ 选择 创建新的 Webhook (首次创建) 或 添加 Webhook。 Webhook 数据 框将出现。 3/ 输入: 名称: 名称 会自动生成为 "Webhook created on [创建日期和时间]",作为标准,以方便创建。 将名称更改为其他名称。 状态: 设置为 活动 (发送数据),暂停 (不发送数据),或 禁用 (由于发送失败而不会发送数据)。 主题: 指示何时触发 Webhook - 订单创建,产品删除,或 客户更新。 还有 操作 和 自定义 选项。 操作事件: 当主题是 WooCommerce 操作 时,此选项可用,例如 woocommerce_add_to_cart,表示当客户将产品添加到购物车时。 自定义主题: 此选项仅适用于 高级用户。 您可以使用 woocommerce_webhook_topic_hooks 过滤器引入新的、自定义的主题。 传递 URL: Webhook 数据传递到的 URL。 密钥: 密钥生成传递的 Webhook 的哈希值,并在请求头中提供。 如果未输入任何内容,则默认为当前 API 用户的消费者密钥。 4/ 保存 Webhook。 注意: 首次以“已激活”状态保存 Webhook 时,它会将一个 ping 发送到传递 URL。 如果传递 URL 返回不成功的状态,例如 404 或 5xx,Webhook 默认情况下会尝试 5 次后被禁用。 成功的响应是 2xx、 301 或 302。 要增加重试次数,可以使用 woocommerce_max_webhook_delivery_failures 过滤器函数。 编辑和删除 Webhook Webhook 的显示方式与帖子或产品相同。 查找 您想要修改的 Webhook。 将鼠标悬停在名称上,会显示 编辑 和 永久删除 选项。 删除,或进行 编辑 并 保存 修改。 还可以通过下拉菜单进行批量删除。 Webhook 日志 WooCommerce 会保存所有触发 Webhook 的事件的日志。 Webhook 日志位于:WooCommerce > 状态 > 日志。 可以查看日志以了解服务器的响应和状态,这有助于简化集成和 调试。 理解 WooCommerce 端点 端点是在网站 URL 中的附加部分,当存在时,会被识别出来以显示不同的内容。 例如:您可能在 URL yoursite.com/my-account 上显示一个“我的账户”网页。当将端点 'edit-account' 添加到此 URL,使其变为 'yoursite.com/my-account/edit-account' 时,则会显示 编辑账户页面,而不是 我的账户页面。 这允许我们在无需多个网页和短代码的情况下显示不同的内容,并减少需要安装的内容量。 端点位于 WooCommerce > 设置 > 高级。 结账端点 以下端点用于与结账相关的功能,并附加到 /checkout 页面的 URL: 支付页面 - /order-pay/{ORDER_ID} 订单已收到(感谢)- /order-received/ 添加付款方式 - /add-payment-method/ 删除付款方式 - /delete-payment-method/ 设置默认付款方式 - /set-default-payment-method/ 账户端点 以下端点用于与账户相关的功能,并附加到 /my-account 页面的 URL: 订单 - /orders/ 查看订单 - /view-order/{ORDER_ID} 下载 - /downloads/ 编辑账户(和更改密码)- /edit-account/ 地址 - /edit-address/ 付款方式 - /payment-methods/ 忘记密码 - /lost-password/ 退出 - /customer-logout/ 了解更多 自定义端点 URL 理解在 WooCommerce 中移除 URL 基础部分的风险 总结 移除 /product/、 /product-category/ 或 /shop/ 这些基础部分,通常是不建议的,因为这会影响 WordPress 解析 URL 的方式。 WordPress 使用 URL 的 product-category (或者任何其他文本) 基础部分来检测该 URL 是否指向一个产品分类。 某些 SEO 插件允许您移除这些基础部分,但这可能会导致性能问题和重复 URL。 尽量避免 移除这些基础部分会使 WordPress 更难检测您尝试访问的页面。 此外,请理解 WordPress 中标准的 "网页" 始终在 URL 中不包含任何基础文本。 例如: http://yoursite.com/about-page/ (这是标准网页的 URL) http://yoursite.com/product-category/category-x/ (这是指向产品分类的 URL) 如果我们移除 "product-category" 部分会发生什么? http://yoursite.com/about-page/ http://yoursite.com/category-x/ 在这种情况下,WordPress 需要付出更多努力才能检测您正在寻找的页面。 这就是为什么我们不建议使用任何 SEO 插件来实现此目的。 附加结账字段 对于开发者和商家来说,一个常见的用例是向结账表单添加新的字段,以收集有关客户或其订单的更多信息。 本文档将概述扩展程序应采取的步骤,以注册一些附加的结账字段。 可用的字段位置 附加的结账字段可以在三个不同的位置进行注册: 标题 标识符 联系信息 contact 地址(配送 和 账单) address 订单信息 order 一个字段只能显示在一个位置,在同一个注册中,无法在多个位置渲染相同的字段。 联系信息 联系信息部分当前位于表单的顶部。它包含 email 字段以及任何其他附加字段。 在此处渲染的字段将保存到购物者的帐户中。它们将在购物者的“帐户详情”部分可见和可编辑。 地址 “地址”部分当前包含一个用于配送地址和账单地址的表单。可以注册附加的结账字段,使其出现在这些表单中。 在此处注册的字段将同时保存到客户 和 订单中,因此回头客无需再次填写这些值。 如果在 address 位置注册了一个字段,它将同时出现在配送地址和账单地址中。 不可能将该字段仅显示在其中一个地址中。 您最终将为该字段收集两个值,一个用于配送,一个用于账单。 订单信息 作为“额外结账字段”功能的一部分,结账阻止块现在包含一个名为“订单信息阻止块”的新内部阻止块。 此阻止块用于渲染不属于联系信息或地址信息的部分,例如,它可能是一个“您是通过什么途径了解我们的”字段或一个“礼品留言”字段。 在此处渲染的字段将保存到订单中。它们不会成为客户保存的地址或帐户信息的一部分。新订单不会预先填充任何之前使用过的值。 默认情况下,此阻止块将作为结账表单的最后一步显示,但您可以使用古腾堡阻止控件在编辑器中移动它。 访问值 附加字段会分别保存到客户元数据和订单元数据中的独立元键中。您可以使用辅助方法访问它们,也可以直接使用元键。我们建议使用辅助方法,因为它们不太可能发生变化,可以处理未来的迁移,并且将支持未来的增强功能(例如,从不同的位置读取)。 对于地址字段,会保存两个值:一个用于配送,一个用于账单。如果客户选择了“使用相同的地址用于账单”,则这些值将相同,但仍然独立保存。 对于联系信息和订单字段,每个字段只保存一个值。 辅助方法 CheckoutFields 提供了一个函数用于访问客户和订单中的值,该函数是 get_field_from_object。 要访问客户的账单和/或配送信息: use Automattic\WooCommerce\Blocks\Package; use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields; $field_id = 'my-plugin-namespace/my-field'; $customer = wc()->customer; // 或者 new WC_Customer( $id ) $checkout_fields = Package::container()->get( CheckoutFields::class ); $my_customer_billing_field = $checkout_fields->get_field_from_object( $field_id, $customer, 'billing' ); $my_customer_shipping_field = $checkout_fields->get_field_from_object( $field_id, $customer, 'shipping' ); 要访问订单字段: use Automattic\WooCommerce\Blocks\Package; use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields; $field_id = 'my-plugin-namespace/my-field'; $order = wc_get_order( 1234 ); $checkout_fields = Package::container()->get( CheckoutFields::class ); $my_order_billing_field = $checkout_fields->get_field_from_object( $field_id, $order, 'billing' ); $my_order_shipping_field = $checkout_fields->get_field_from_object( $field_id, $order, 'shipping' ); 在订单提交后,保存到客户的数据和保存到订单的数据将是相同的。 客户可以更改_未来_订单的值,或者在他们的“我的账户”网页中进行更改。 如果您在特定时间点查看客户数据(例如,在订单提交时),请从订单对象中访问它;如果您需要获取最新的数据,请从客户对象中访问它。 访客客户 当访客客户提交包含附加字段的订单时,这些字段将保存到其会话中,因此只要客户仍然有有效的会话,这些值始终可用。 已登录的客户 对于已登录的客户,值只有在他们提交订单后才会持久保存。 在订单提交生命周期中访问已登录的客户对象将返回 null 或过时的数据。 如果在订单提交钩子中执行以下操作,将返回以前的数据(而不是当前插入的数据): $customer = new WC_Customer( $order->customer_id ); // 或者 new WC_Customer( 1234 ) $my_customer_billing_field = $checkout_fields->get_field_from_object( $field_id, $customer, 'billing' ); 相反,如果您想执行一些额外的验证/数据移动,请始终访问最新的数据: $customer = wc()->customer // 这将返回具有其会话的当前客户。 $my_customer_billing_field = $checkout_fields->get_field_from_object( $field_id, $customer, 'billing' ); 访问所有字段 您可以使用 get_all_fields_from_object 函数来访问保存到订单或客户对象上的所有附加字段。 use Automattic\WooCommerce\Blocks\Package; use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields; $order = wc_get_order( 1234 ); $checkout_fields = Package::container()->get( CheckoutFields::class ); $order_additional_billing_fields = $checkout_fields->get_all_fields_from_object( $order, 'billing' ); $order_additional_shipping_fields = $checkout_fields->get_all_fields_from_object( $order, 'shipping' ); $order_other_additional_fields = $checkout_fields->get_all_fields_from_object( $order, 'other' ); // 联络信息和订单信息都保存在附加组中的同一位置。 这将返回一个包含所有值的数组。 默认情况下,它只包含当前注册的字段。 如果您想包含不再注册的字段,可以传递一个第三个 true 参数。 $order = wc_get_order( 1234 ); $checkout_fields = Package::container()->get( CheckoutFields::class ); $order_additional_billing_fields = $checkout_fields->get_all_fields_from_object( $order, 'billing' ); // array( 'my-plugin-namespace/my-field' => 'my-value' ); $order_additional_billing_fields = $checkout_fields->get_all_fields_from_object( $order, 'billing', true ); // array( 'my-plugin-namespace/my-field' => 'my-value', 'old-namespace/old-key' => 'old-value' ); 直接访问值 虽然不推荐,但您可以使用直接的元键来访问某些值。 这对于外部引擎或仅提供对元值访问的页面/电子邮件构建器非常有用。 值保存在预定义的%prefix%下,这是为了能够查询字段,而无需知道该字段在哪个 ID 下注册。 对于键为 'my-plugin-namespace/my-field' 的字段,如果它是%address%,其元键将是以下内容: _wc_billing/my-plugin-namespace/my-field _wc_shipping/my-plugin-namespace/my-field 或者,如果它是%contact%/订单字段,则为以下内容: _wc_other/my-plugin-namespace/my-field。 这些%prefix%是 %CheckoutFields% 类的一部分,可以使用以下常量访问: echo ( CheckoutFields::BILLING_FIELDS_PREFIX ); // _wc_billing/ echo ( CheckoutFields::SHIPPING_FIELDS_PREFIX ); // _wc_shipping/ echo ( CheckoutFields::OTHER_FIELDS_PREFIX ); // _wc_other/ %CheckoutFields% 提供了一些辅助函数,用于根据组名或键来获取组名或键: CheckoutFields::get_group_name( "_wc_billing" ); // "billing" CheckoutFields::get_group_name( "_wc_billing/" ); // "billing" CheckoutFields::get_group_key( "shipping" ); // "_wc_shipping/" 用例是构建键名以直接访问元数据: $key = CheckoutFields::get_group_key( "other" ) . 'my-plugin/is-opt-in'; $opted_in = get_user_meta( 123, $key, true ) === "1" ? true : false; 复选框的值 当直接访问复选框的值时,它将返回 "1" 表示真, "0" 表示假,或者如果值不存在则返回 ""。 只有提供的函数才能将其转换为布尔值。 支持的字段类型 以下字段类型受支持: select text checkbox 计划扩展此列表,但目前这些是可用的类型。 使用 API 要注册额外的结账字段,您必须使用 woocommerce_register_additional_checkout_field 函数。 建议在 woocommerce_init 动作之后运行此函数。 注册函数接受一个选项数组,用于描述您的字段。 某些字段类型需要额外的选项。 选项 常规设置 这些选项适用于所有字段类型(除非在少数情况下,具体情况会在“选项”中注明)。 字段配置 本节描述了如何配置字段。 选项名称 描述 是否必填 示例 默认值 id 字段的 ID。这应该为您的字段提供唯一的标识符。它由命名空间和字段名称组成,中间用 / 分隔。 是 plugin-namespace/how-did-you-hear 无默认值 - 必须提供。 label 在您的字段上显示的标签。这将也是占位符。 是 How did you hear about us? 无默认值 - 必须提供。 optionalLabel 如果字段是可选的,则在您的字段上显示的标签。这将也是占位符。 否 How did you hear about us? (Optional) 默认值将是 label 的值,并在其后附加 (optional)。 location 字段的渲染位置。 是 contact, address, 或 order 无默认值 - 必须提供。 type 您要渲染的字段类型。默认为 text,并且必须与受支持的字段类型之一匹配。 否 text, select, 或 checkbox text attributes 要在字段的输入元素上渲染的附加属性的数组。这_不支持_ select 字段。 否 [ 'data-custom-data' => 'my-custom-data' ] [] required 可以是布尔值或 JSON 结构化数据 数组。如果为布尔值且为 true,则购物者 必须 在结账过程中为该字段提供值。对于复选框字段,购物者必须选中复选框才能完成订单。如果为 JSON 结构化数据 数组,则该字段是否必填取决于结构化数据的条件。请参阅 通过 JSON 结构化数据 实现条件可见性和验证。 否 true 或 ["type" => "object", "properties" => [...]] false hidden 可以是布尔值或 JSON 结构化数据 数组。如果用作布尔值,则必须为 false。如果为 JSON 结构化数据 数组,则该字段是否隐藏取决于结构化数据的条件。请参阅 通过 JSON 结构化数据 实现条件可见性和验证。 否 false 或 ["type" => "object", "properties" => [...]] false validation 定义字段验证规则的 JSON 结构化数据 对象的数组。请参阅 通过 JSON 结构化数据 实现条件可见性和验证。 否 [{"type": "object", "properties": {...}}] [] sanitize_callback 在发布时,用于清理客户提供的值的函数。 否 参见下面的示例 默认情况下,字段的值会不作更改地返回。 validate_callback 在发布时,用于验证客户提供的值的函数。这在清理之后运行。 否 参见下面的示例 默认验证函数将在字段为必填但没有值时,向响应添加一个错误。 请参阅默认验证函数。 ##### `sanitize_callback` 函数示例。此函数将从值中删除空格。 ```php 'sanitize_callback' => function( $field_value ) { return str_replace( ' ', '', $field_value ); }, validate_callback 函数示例。此函数将检查值是否为电子邮件地址。 'validate_callback' => function( $field_value ) { if ( ! is_email( $field_value ) ) { return new WP_Error( 'invalid_alt_email', '请确保您的备用电子邮件地址符合正确的格式。' ); } }, text 字段的选项 text 字段除了上面列出的常规设置之外,没有其他额外的选项。 select 字段的选项 除了上面列出的选项之外, select 字段还必须使用 options 选项进行注册。这用于指定用户可以从中选择的选项。 select 字段默认情况下不会选择任何值;如果该字段是必填的,则用户必须选择一个值。 您可以通过在注册字段时传递 placeholder 值,来设置在 select 字段中显示的占位符。这将是 select 中的第一个选项,并且如果该字段是必填的,则用户无法选择此选项。 选项名称 描述 必需? 示例 默认值 options 用于在 select 输入框中显示的选项数组。每个选项必须是一个包含 label 和 value 属性的数组。每个条目必须具有唯一的 value。任何重复的选项将被删除。 value 是在结账过程中提交到服务器的值,而 label 只是此值的用户友好表示,它不会以任何方式传输到服务器。 是 参见下文 无默认值 - 必须提供。 placeholder 如果设置了此值,则用户将在 select 中看到此选项。如果 select 是必填的,则用户无法选择此选项。 否 选择一个角色 Select a $label options 值的示例 [ [ 'value' => 'store_1', 'label' => '我们的伦敦店' ], [ 'value' => 'store_2', 'label' => '我们的巴黎店' ], [ 'value' => 'store_3', 'label' => '我们的纽约店' ] ] checkbox 字段的选项 除了上面列出的选项之外, checkbox 字段还支持在必填时,如果未选中,则显示错误信息。 选项名称 描述 必需? 示例 默认值 error_message 如果复选框未选中,则显示的自定义消息。 否 您必须确认您已满 18 岁才能下单。 如果希望继续,请选中此框。 ### 属性 支持为复选框和文本字段添加额外的属性。但是,**目前无法**将属性添加到选择字段。 这些属性与 `input` 元素的 HTML 属性一一对应(`pattern` 属性除外,复选框不支持)。 支持的属性包括: - `data-*` 属性 - `aria-*` 属性 - `autocomplete` - `autocapitalize` - `pattern` (复选框字段不支持) - `title` - `maxLength` (等同于 HTML 属性 `maxlength`) - `readOnly` (等同于 HTML 属性 `readonly`) `maxLength` 和 `readOnly` 使用驼峰命名法,因为这些属性会渲染到 React 元素上,必须以这种格式接收。 某些属性有意不传递给字段,这些是 `autofocus` 和 `disabled`。我们欢迎接收反馈,并在提供有效的用例时调整此行为。 ## 使用示例 ### 渲染文本字段 此示例演示如何在地址部分渲染文本字段: ```php add_action( 'woocommerce_init', function() { woocommerce_register_additional_checkout_field( array( 'id' => 'namespace/gov-id', 'label' => 'Government ID', 'optionalLabel' => 'Government ID (optional)', 'location' => 'address', 'required' => true, 'attributes' => array( 'autocomplete' => 'government-id', 'aria-describedby' => 'some-element', 'aria-label' => 'custom aria label', 'pattern' => '[A-Z0-9]{5}', // 5 个大写字母和数字组成的字符串。 'title' => 'Title to show on hover', 'data-custom' => 'custom data', ), ), ); } ); 这将在地址表单中生成以下内容(账单表单与此相同): 生成的 HTML 标记如下: 渲染复选框字段 这个示例演示了如何在联系信息部分渲染一个复选框字段: add_action( 'woocommerce_init', function() { woocommerce_register_additional_checkout_field( array( 'id' => 'namespace/marketing-opt-in', 'label' => '您是否想订阅我们的新闻通讯?', 'location' => 'contact', 'type' => 'checkbox', ) ); } ); 这将在联系信息部分显示以下内容: 请注意,由于没有提供 optionalLabel,因此字符串 (optional) 会附加到标签中。要删除该字符串,应提供 optionalLabel 属性以覆盖此行为。 渲染选择字段 这个示例演示了如何在订单信息部分渲染一个选择字段: add_action( 'woocommerce_init', function() { woocommerce_register_additional_checkout_field( array( 'id' => 'namespace/how-did-you-hear-about-us', 'label' => '您是通过什么途径了解我们的?', 'placeholder' => '选择一个来源', 'location' => 'order', 'type' => 'select', 'options' => [ [ 'value' => 'google', 'label' => 'Google' ], [ 'value' => 'facebook', 'label' => 'Facebook' ], [ 'value' => 'friend', 'label' => '朋友推荐' ], [ 'value' => 'other', 'label' => '其他' ], ] ) ); } ); 这将在订单信息部分以如下方式进行渲染: 获得焦点之前的选择输入框 获得焦点时的选择输入框 如果不想强制用户选择一个值,可以通过将 required 选项设置为 false,将选择框标记为可选。 验证和清理 可以使用 WordPress 动作钩子,为附加的结账字段添加自定义的验证和清理功能。 这些操作发生在两个地方: 在结账过程中更新和提交表单,以及 在“我的账户”区域更新地址/联系信息。 清理 清理用于确保字段的值具有特定的格式。例如,在获取政府身份证件时,您可能希望将其格式化为所有字母大写且没有空格。此时,不应检查该值的 有效性。这将在稍后进行。此步骤仅用于为验证做好准备。 使用 woocommerce_sanitize_additional_field 过滤器 为了运行自定义的字段清理函数,您可以在注册时使用 sanitize_callback 函数,或者使用 woocommerce_sanitize_additional_field 过滤器。 参数 类型 描述 $field_value boolean|string 字段的值。 $field_key string 字段的 ID。 这与字段注册时使用的 ID 相同。 清理示例 此示例展示了如何移除空格并将所有字母转换为大写,以清理我们在上面添加的“政府 ID”示例字段。 add_action( 'woocommerce_sanitize_additional_field', function ( $field_value, $field_key ) { if ( 'namespace/gov-id' === $field_key ) { $field_value = str_replace( ' ', '', $field_value ); $field_value = strtoupper( $field_value ); } return $field_value; }, 10, 2 ); 验证 在附加的结账字段系统中,有两个验证阶段。 第一个阶段是根据字段的键和值验证单个字段。 单个字段验证 使用 woocommerce_validate_additional_field 动作 当 woocommerce_validate_additional_field 动作被触发时,回调函数会接收到字段的键、字段的值以及一个 WP_Error 对象。 要将验证错误添加到响应中,请使用 WP_Error::add 方法。 | 参数 | 类型 | 描述 WP_Error 对象 当您向 WP_Error 对象添加错误时,该错误应该具有唯一的错误代码。 您可能希望在错误代码前添加插件命名空间,以减少冲突的可能性。 使用其他插件中已使用的代码可能会导致错误信息被覆盖或显示在不同的位置。 单个字段验证示例 以下示例展示了如何将自定义验证应用于上述 namespace/gov-id 文本字段。 此处的代码确保该字段由 5 个字符组成,可以是大写字母或数字。 上述示例中的 sanitization 函数确保删除所有空格并将所有字母大写,因此此检查是额外的安全措施,以确保输入与模式匹配。 add_action( 'woocommerce_validate_additional_field', function ( WP_Error $errors, $field_key, $field_value ) { if ( 'namespace/gov-id' === $field_key ) { $match = preg_match( '/[A-Z0-9]{5}/', $field_value ); if ( 0 === $match || false === $match ) { $errors->add( 'invalid_gov_id', '请确保您的政府 ID 符合正确的格式。' ); } } }, 10, 3 ); 重要的是要注意,此操作必须向它接收到的 WP_Error 对象 添加 错误。 返回一个新的 WP_Error 对象或任何其他值会导致错误不显示。 如果没有遇到任何验证错误,该函数可以直接返回 void。 多个字段验证 在某些情况下,一个字段的有效性取决于另一个字段的值,例如,根据购物者所在的国家/地区来验证政府 ID 的格式。 在这种情况下,仅验证单个字段(如上所示)是不够的,因为在 woocommerce_validate_additional_field 操作期间,国家/地区可能未知。 为了解决这个问题,可以在字段呈现的上下文环境中验证该字段。 位于该位置的其他字段将传递给此操作。 使用 woocommerce_blocks_validate_location_{location}_fields 动作 此动作将为每个可以渲染附加字段的位置( address、 contact 和 order)触发一次。对于 address,它会触发两次,一次是用于账单地址,另一次是用于配送地址。 回调函数接收到相同位置的其他附加字段的键和值。 需要注意的是,在其他位置渲染的任何字段都不会传递给此动作,但是可以通过访问客户或订单对象来获取这些值,但这不受支持,并且未来版本不保证兼容性。 参数 类型 描述 $errors WP_Error 一个错误对象,包含在处理请求时已经遇到的错误。如果尚未添加任何错误,它仍然是一个 WP_Error 对象,但为空。 $fields array 在此位置渲染的字段。 $group 'billing'|'shipping'|'other' 如果该动作是针对地址位置,则此处会设置地址类型。如果是针对联系方式或订单,则此值为 'other'。 这些钩子在以下几个地方会被触发。 在使用结账块或 Store API 进行结账时: woocommerce_blocks_validate_location_address_fields (x2) woocommerce_blocks_validate_location_contact_fields woocommerce_blocks_validate_location_other_fields 在“我的账户”区域更新地址时: woocommerce_blocks_validate_location_address_fields (x1 - 仅针对正在编辑的地址) 在“我的账户”区域更新“账户详情”部分时: woocommerce_blocks_validate_location_contact_fields 地址验证示例 在这个示例中,假设除了 namespace/gov-id 之外,还注册了一个名为 namespace/confirm-gov-id 的字段。这个字段将用于确认政府 ID 字段。 下面的示例说明了如何验证确认字段的值是否与主字段的值匹配。 add_action( 'woocommerce_blocks_validate_location_address_fields', function ( \WP_Error $errors, $fields, $group ) { if ( $fields['namespace/gov-id'] !== $fields['namespace/confirm-gov-id'] ) { $errors->add( 'gov_id_mismatch', '请确保您的政府 ID 与确认信息一致。' ); } }, 10, 3 ); 如果这些字段显示在 "联系方式" 位置,则代码相同,只是使用的钩子不同: woocommerce_blocks_validate_location_contact_fields。 通过 JSON Schema 实现条件可见性和验证 required、 hidden 和 validation 属性接受一个 JSON Schema 数组,用于为字段创建条件逻辑。 这允许您根据其他字段的值动态控制字段的可见性、必填状态和验证规则。 Schema 在前端实时评估,并在后端进行任何更新时进行评估。 这确保了快速响应的 UI,以及客户端和服务器之间的一致结果。 JSON Schema 结构 数组中的每个 Schema 应该是一个有效的 JSON Schema 对象,该对象定义了何时应应用该属性的条件。 Schema 会针对当前购物车和结账状态进行评估,其中包括所有字段值以及各种选项(支付、配送、客户)。 JSON Schema 对象的基本结构如下: { "type": "object", "properties": { "fieldId": { "enum": ["value1", "value2"] } }, "required": ["fieldId"] } 如果您不熟悉 JSON Schema,您可以从 官方网站 了解其基本知识,或者参考一些使用的库,例如 AJV 或 OPIS.。 Checkout 构建了一个基于这两个库的抽象层。 Document 对象 当您撰写规则时,您实际上是在撰写一个 document 对象的局部 结构化数据,本质上是描述您希望字段处于何种理想状态,例如是否需要或隐藏。 重要: document 对象中的所有 属性 都使用 snake_case 命名约定(例如, total_price、 shipping_rates、 customer_note),而不是 camelCase。 document 对象的一个示例如下: Document 对象 { "cart": { "coupons": [ "my_coupon" ], "shipping_rates": [ "free_shipping:1" ], "items": [ 27, 27, 68 ], "items_type": [ "simple", "变体" ], "items_count": 3, "items_weight": 0, "needs_shipping": true, "prefers_collection": false, "totals": { "total_price": 6600, "total_tax": 600 }, "extensions": {} }, "checkout": { "create_account": false, "customer_note": "", "additional_fields": { "namespace/myorder-field": "myvalue" }, "payment_method": "bacs" }, "customer": { "id": 1, "billing_address": { "first_name": "名", "last_name": "姓氏", "company": "公司", "address_1": "地址 1", "address_2": "地址 2", "city": "城市", "state": "州", "postcode": "08000", "country": "US", "email": "email@example.com", "phone": "1234567890", "namespace/myfield": "myvalue" }, "shipping_address": { "first_name": "名", "last_name": "姓氏", "company": "公司", "address_1": "地址 1", "address_2": "地址 2", "city": "城市", "state": "州", "postcode": "08000", "country": "US", "phone": "1234567890", "namespace/myfield": "myvalue" }, "additional_fields": { "namespace/mycontact-field": "myvalue" }, "address": { "first_name": "名", "last_name": "姓氏", "company": "公司", "address_1": "地址 1", "address_2": "地址 2", "city": "城市", "state": "州", "postcode": "08000", "country": "US", "phone": "1234567890", "namespace/myfield": "myvalue" } } } 它完整的结构是这样的: 文档结构 { "$schema": "http://json-schema.org/draft-07/schema#", "title": "购物车和结账文档对象结构", "description": "购物车、结账和客户信息的文档对象结构,用于条件可见性、字段要求和验证。", "type": "object", "properties": { "cart": { "type": "object", "description": "关于购物车的的信息", "properties": { "coupons": { "type": "array", "description": "应用于购物车的优惠券代码列表", "items": { "type": "string" } }, "shipping_rates": { "type": "array", "description": "当前选择的运输费率列表", "items": { "type": "string", "description": "使用完整运输费率 ID 的运输费率标识符,例如:method_id:instance_id,例如:flat_rate:1" } }, "items": { "type": "array", "description": "购物车中产品 ID 的列表,ID 将根据产品在购物车中的数量进行重复,如果购物车中有 2 个产品 ID 为 1 的产品,则数组将包含 2 个产品 ID 1 的条目。仅支持整数数量,不支持浮点数(四舍五入到最接近的整数)。", "items": { "type": "integer" } }, "items_type": { "type": "array", "description": "购物车中商品类型,例如:simple、variation、subscription 等。", "items": { "type": "string" } }, "items_count": { "type": "integer", "description": "购物车中商品的总数量", "minimum": 0 }, "items_weight": { "type": "number", "description": "购物车中商品的总重量", "minimum": 0 }, "needs_shipping": { "type": "boolean", "description": "购物车中的商品是否需要运输" }, "prefers_collection": { "type": "boolean", "description": "客户是否更喜欢使用本地自提" }, "totals": { "type": "object", "description": "购物车总价信息", "properties": { "total_price": { "type": "integer", "description": "购物车总价,以最小货币单位表示(例如:分),在应用所有折扣、运费和税费后" }, "total_tax": { "type": "integer", "description": "总税额,以最小货币单位表示(例如:分),在应用所有折扣、运费和税费后" } }, "additionalProperties": false }, "extensions": { "type": "object", "description": "其他购物车扩展数据,这类似于 Store API 的 extensions 参数中传递的数据" } }, "additionalProperties": false }, "checkout": { "type": "object", "description": "结账偏好和设置", "properties": { "create_account": { "type": "boolean", "description": "客户是否选中了创建帐户复选框,如果客户已登录、无法创建帐户或被强制创建帐户,则此值为 false。" }, "customer_note": { "type": "string", "description": "客户的订单备注或特殊说明,如果客户未添加备注,则此字段为空。" }, "additional_fields": { "type": "object", "description": "具有 'order' 位置的附加结账字段。这些字段在订单信息部分中显示。", "additionalProperties": { "type": "string" }, "patternProperties": { "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$": { "type": "string", "description": "具有命名空间标识符的自定义字段" } } }, "payment_method": { "type": "string", "description": "所选的支付方式标识符,无论客户是选择已保存的支付方式还是新的支付方式,此字段都将是支付方式 ID" } }, "additionalProperties": false }, "customer": { "type": "object", "description": "客户信息", "properties": { "id": { "type": "integer", "description": "客户 ID,如果客户未登录,则此值为 0" }, "billing_address": { "$ref": "#/definitions/address", "description": "客户的账单地址" }, "shipping_address": { "$ref": "#/definitions/address", "description": "客户的收货地址" }, "additional_fields": { "type": "object", "description": "具有 'contact' 位置的附加结账字段。这些字段在联系信息部分中显示。", "additionalProperties": { "type": "string" }, "patternProperties": { "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$": { "type": "string", "description": "具有命名空间标识符的自定义字段" } } }, "address": { "$ref": "#/definitions/address", "description": "这是一个动态字段,根据字段评估的上下文,它将是账单地址或收货地址。" } }, "additionalProperties": false } }, "additionalProperties": false, "definitions": { "address": { "type": "object", "description": "客户地址信息", "properties": { "first_name": { "type": "string", "description": "收件人的名" }, "last_name": { "type": "string", "description": "收件人的姓" }, "company": { "type": "string", "description": "公司名称" }, "address_1": { "type": "string", "description": "主要地址行" }, "address_2": { "type": "string", "description": "辅助地址行" }, "city": { "type": "string", "description": "城市名称" }, "state": { "type": "string", "description": "州或省,如果是预定义的列表,则此字段为州代码,例如:CA、TX、NY 等;如果是自由格式的州,则此字段为字段值,例如:London。" }, "postcode": { "type": "string", "description": "邮政编码" }, "country": { "type": "string", "description": "国家代码(例如:US、UK)" }, "email": { "type": "string", "format": "email", "description": "Email 地址" }, "phone": { "type": "string", "description": "电话号码" } }, "additionalProperties": { "type": "string", "description": "具有 'address' 位置的附加字段将在此处以地址对象属性的形式出现" }, "patternProperties": { "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+$": { "type": "string", "description": "使用命名空间标识符(例如:'namespace/field-name')的具有 'address' 位置的附加字段" } } } } } # 关于 %s 的技术文档 本文档提供了关于 %s 的详细信息。 ## 安装 1. 下载 %s 的最新版本。 2. 解压下载的文件。 3. 按照安装说明进行操作。 ## 配置 %s 的配置可以通过修改配置文件进行。 配置文件位于 `%s/config/config.ini`。 以下是一些常用的配置选项: * `server_address`: 服务器地址。 * `server_port`: 服务器端口。 * `database_host`: 数据库主机。 * `database_name`: 数据库名称。 ## 使用 要使用 %s,请按照以下步骤操作: 1. 启动 %s 服务器。 2. 使用客户端连接到服务器。 3. 执行所需的命令。 ## 示例 以下是一个使用 %s 的示例: %s --server-address %s --server-port %d ## 故障排除 如果在使用 %s 时遇到问题,请参考以下故障排除步骤: * 检查配置文件是否正确。 * 检查服务器是否正在运行。 * 检查客户端是否已正确配置。 ## 详情 有关 %s 的更多信息,请访问 [https://www.example.com/%s](https://www.example.com/%s)。 ## 启用高级功能 要启用高级功能,请修改配置文件并设置 `enable_advanced_features` 为 `true`。 ## 日志 %s 将日志信息写入文件 `%s/logs/application.log`。 ## 许可证 %s 采用 Apache 2.0 许可证。 ## 联系方式 如有任何问题,请通过电子邮件发送至 `support@example.com`。 ## 更新日志 * **2023-03-08**: 修复了 %s 的一个 bug。 * **2023-02-15**: 增加了对 %s 的新功能支持。 * **2023-01-01**: 发布了 %s 的第一个版本。 ## 常见问题解答 * **问:%s 是什么?** * 答:%s 是一个用于 %s 的工具。 * **问:如何安装 %s?** * 答:请参考 "安装" 部分的说明。 * **问:如何配置 %s?** * 答:请参考 "配置" 部分的说明。 * **问:如何使用 %s?** * 答:请参考 "使用" 部分的说明。 * **问:%s 的许可证是什么?** * 答:%s 采用 Apache 2.0 许可证。 ## 贡献 欢迎您为 %s 做出贡献。 请访问我们的 GitHub 仓库:[https://github.com/example/%s](https://github.com/example/%s)。 ## 感谢 感谢所有为 %s 做出贡献的人。 ## 术语表 * **Details**: 详情 * **Enable**: 启用 * **Mar**: 三月 * **In**: 在 * **Down**: 向下 示例 必填且可见的字段 在这个示例中,我们使字段成为必填项,并且仅当选择“本地自提”时才可见。 'required' => [ "type" => "object", "properties" => [ "cart" => [ "properties" => [ "prefers_collection" => [ "const" => true ] ] ] ] ], 'hidden' => [ "type" => "object", "properties" => [ "cart" => [ "properties" => [ "prefers_collection" => [ "const" => false ] ] ] ] ] 请注意,对于隐藏的字段,我们反转了该字段的显示状态,这意味着该字段应该仅在 prefers_collection 为 false 时才被隐藏,而 false 几乎适用于所有情况,除非选择了“本地自提”。 在上面的示例中,我们使用了 关键字 const。 验证结构化数据示例 验证与条件可见性和必填性略有不同。 在验证中,您将传入结构化数据的子集(仅适用于您的字段),其作用是验证该字段,并在出现错误时显示错误信息。 在这个示例中,我们确保 VAT 由国家代码和 8-12 个数字组成。 'validation' => [ "type" => "string", "pattern" => "^[A-Z]{2}[0-9]{8,12}$", "errorMessage" => "请填写有效的 VAT 代码,该代码应包含 2 个字母作为国家代码,以及 8-12 个数字。" ] 验证还可以针对其他字段,例如,一个备用电子邮件字段,该字段不应与当前的电子邮件匹配: 'validation' => [ "type" => "string", "format" => "email", "not" => [ "const" => [ '$data' => "/customer/billing_address/email" ] ], "errorMessage" => "请填写有效的备用电子邮件。" ] 在上面的示例中,我们使用了 格式关键字 和 $data 来引用当前字段的字段值,方法是通过 JSON 指针。 我们还使用了 errorMessage 属性来提供自定义的错误消息。 $data 关键字和 JSON 指针 $data 关键字是在 JSON 结构化数据中引用另一个字段值的机制。在上面的示例中,我们使用它来引用账单电子邮件,通过 JSON 指针。 在使用 JSON 指针时,需要注意以下几点: 正斜杠 / 用于在 JSON 对象中导航,因此,对于其他字段,名为 my-plugin-namespace/my-field 的字段需要引用为 my-plugin-namespace~1my-field。 JSON 指针的导航可以从当前字段向后,也可以从根节点开始。如果您有一个地址字段,并且想要验证电话字段,这意味着您将验证两个值,一个用于配送,一个用于账单,因此您可以以两种方式引用电话字段: 0/customer/address/phone,它使用根导航(通过 0/ 前缀),并使用动态的 address 组,该组会根据正在验证的配送或账单值而变化。 1/phone,它使用相对指针向后移动,在这种情况下,它将访问其兄弟字段,即 phone 字段。增加数字可以向后移动更远,例如, 2/id 将访问客户 ID。 不在规范中的关键字和值 我们支持 JSON 结构化数据 Draft-07,它比较简单,不支持所有最新的规范中的关键字和值,但我们认为它涵盖了大多数用例。此外,我们引入了一些非标准的关键字和值,这些值不在规范中,它们的实现可能在 Opis 和 AJV (或任何未来的实现) 之间有所不同。以下是此类关键字和值的列表: errorMessage: 用于验证的自定义错误信息。在 AJV 中,它是 errorMessage,在 Opis 中,它是 $error。我们仅支持 errorMessage,并在内部将其映射到 Opis。目前,我们不支持在 errorMessage 中使用模板。 $data: 通过 JSON 指针 引用当前字段值。Opis 和 AJV 使用相同的实现。 评估逻辑 对于 required: 如果数组中的任何一个结构化数据与当前的结账状态匹配,则该字段将是必填项。 对于 hidden: 如果数组中的任何一个结构化数据与当前的结账状态匹配,则该字段将被隐藏。 对于 validation: 字段的值将根据提供的部分结构化数据进行评估,如果值不匹配,则会显示错误。 性能考虑 复杂的 JSON 结构化数据条件可能会影响结账性能。请尽可能简化您的结构化数据,并限制条件的数量,仅限于您的用例所需的数量。 向后兼容性 由于技术原因,目前还无法为字段指定元键,因为我们希望它们具有前缀并由系统进行管理。 使用短代码在结账页面上存在的字段的插件可以保持兼容性,并通过钩子来响应字段的读取和保存操作。 假设有两个字段,分别命名为 my-plugin-namespace/address-field (位于地址步骤) 和 my-plugin-namespace/my-other-field (位于订单步骤),您可以: 响应字段保存事件 您可以通过钩入 woocommerce_set_additional_field_value 动作来响应这些字段的保存事件。 add_action( 'woocommerce_set_additional_field_value', function ( $key, $value, $group, $wc_object ) { if ( 'my-plugin-namespace/address-field' !== $key ) { return; } if ( 'billing' === $group ) { $my_plugin_address_key = 'existing_billing_address_field_key'; } else { $my_plugin_address_key = 'existing_shipping_address_field_key'; } $wc_object->update_meta_data( $my_plugin_address_key, $value, true ); }, 10, 4 ); add_action( 'woocommerce_set_additional_field_value', function ( $key, $value, $group, $wc_object ) { if ( 'my-plugin-namespace/my-other-field' !== $key ) { return; } $my_plugin_key = 'existing_order_field_key'; $wc_object->update_meta_data( $my_plugin_key, $value, true ); }, 10, 4 ); 这样,您可以确保现有的系统能够继续工作,并且您的集成也能继续工作。 但是,理想情况下,您应该迁移现有的数据和系统,以便使用新的元字段。 响应字段读取事件 您可以使用 woocommerce_get_default_value_for_{$key} 过滤器来提供不同的默认值(例如,来自另一个元字段的值): add_filter( "woocommerce_get_default_value_for_my-plugin-namespace/address-field", function ( $value, $group, $wc_object ) { if ( 'billing' === $group ) { $my_plugin_key = 'existing_billing_address_field_key'; } else { $my_plugin_key = 'existing_shipping_address_field_key'; } return $wc_object->get_meta( $my_plugin_key ); }, 10, 3 ); add_filter( "woocommerce_get_default_value_for_my-plugin-namespace/my-other-field", function ( $value, $group, $wc_object ) { $my_plugin_key = 'existing_order_field_key'; return $wc_object->get_meta( $my_plugin_key ); }, 10, 3 ); 一个完整的示例 在这个完整的示例中,我们将注册“政府身份证”文本字段,并验证它是否符合特定的格式。 这个示例只是前面共享的示例的组合版本。 add_action( 'woocommerce_init', function() { woocommerce_register_additional_checkout_field( array( 'id' => 'namespace/gov-id', 'label' => 'Government ID', 'location' => 'address', 'required' => true, 'attributes' => array( 'autocomplete' => 'government-id', 'pattern' => '[A-Z0-9]{5}', // 由大写字母和数字组成的 5 个字符的字符串。 'title' => 'Your 5-digit Government ID', ), ), ); woocommerce_register_additional_checkout_field( array( 'id' => 'namespace/confirm-gov-id', 'label' => 'Confirm government ID', 'location' => 'address', 'required' => true, 'attributes' => array( 'autocomplete' => 'government-id', 'pattern' => '[A-Z0-9]{5}', // 由大写字母和数字组成的 5 个字符的字符串。 'title' => 'Confirm your 5-digit Government ID', ), ), ); add_action( 'woocommerce_sanitize_additional_field', function ( $field_value, $field_key ) { if ( 'namespace/gov-id' === $field_key || 'namespace/confirm-gov-id' === $field_key ) { $field_value = str_replace( ' ', '', $field_value ); $field_value = strtoupper( $field_value ); } return $field_value; }, 10, 2 ); add_action( 'woocommerce_validate_additional_field', function ( WP_Error $errors, $field_key, $field_value ) { if ( 'namespace/gov-id' === $field_key ) { $match = preg_match( '/[A-Z0-9]{5}/', $field_value ); if ( 0 === $match || false === $match ) { $errors->add( 'invalid_gov_id', '请确保您的政府身份证符合正确的格式。' ); } } return $errors; }, 10, 3 ); } ); add_action( 'woocommerce_blocks_validate_location_address_fields', function ( \WP_Error $errors, $fields, $group ) { if ( $fields['namespace/gov-id'] !== $fields['namespace/confirm-gov-id'] ) { $errors->add( 'gov_id_mismatch', '请确保您的政府身份证与确认信息一致。' ); } }, 10, 3 ); 可用的插槽 本文档列出了可用的插槽,您可以使用它们来添加自定义内容(填充)。 如果您想添加一个新的 SlotFill 组件,请查看 结账 - 插槽填充 文档。 要了解更多关于插槽和填充的信息,请查看 插槽和填充 文档。 关于命名说明: 以 Experimental 开头的插槽是实验性的,可能会发生更改或被移除。 当它们从实验阶段毕业后,命名会发生变化,并且会删除 Experimental 前缀。 请查看 特性控制 文档,以获取更多信息。 ExperimentalOrderMeta 此插槽在购物车中的“继续结账”按钮上方,以及结账流程中的摘要部分下方进行渲染。 const { __ } = window.wp.i18n; const { registerPlugin } = window.wp.plugins; const { ExperimentalOrderMeta } = window.wc.blocksCheckout; const render = () => { return (
{ __( 'Yearly recurring total ...', 'YOUR-TEXTDOMAIN' ) }
); }; registerPlugin( 'slot-and-fill-examples', { render, scope: 'woocommerce-checkout', } ); 购物车: 结账: 传递的参数 cart: wc/store/cart 数据,但使用 camelCase 格式,而不是 snake_case 格式。 对象分解 extensions: 由第三方开发者使用 ExtendSchema 注册的外部数据。 如果您在 wc/store/cart 上使用了 ExtendSchema,您可以在此处找到您的数据,位于您的命名空间下。 context: 等于渲染填充的块的名称,可以是 woocommerce/cart 或 woocommerce/checkout。 ExperimentalOrderShippingPackages 此组件在“结账”流程的“配送”步骤以及“购物车”中的“配送选项”中渲染。 const { __ } = window.wp.i18n; const { registerPlugin } = window.wp.plugins; const { ExperimentalOrderShippingPackages } = window.wc.blocksCheckout; const render = () => { return (
{ __( 'Express Shipping', 'YOUR-TEXTDOMAIN' ) }
); }; registerPlugin( 'slot-and-fill-examples', { render, scope: 'woocommerce-checkout', } ); 购物车: 结账: 传递的参数 collapsible: Boolean|undefined 如果配送选项面板应该是可折叠的,如果是,则在“结账”中为 false,在“购物车”中为 undefined。 collapse: Boolean 如果面板应该默认折叠,如果是可折叠的,则为 true。 showItems: Boolean|undefined 是否显示每个选项的内容,在“购物车”和“结账”中为 undefined,由实际的选项逻辑决定。 noResultsMessage: 一个 React 元素,当没有配送选项时,您可以将其渲染。 renderOption: 一个渲染函数,它接受一个速率对象并返回一个渲染选项。 cart: wc/store/cart 数据,但使用 camelCase 格式,而不是 snake_case。 对象分解。 extensions: 由第三方开发者使用 ExtendSchema 注册的外部数据,如果您在 wc/store/cart 上使用了 ExtendSchema,您可以在此处找到您的数据,位于您的命名空间下。 components: 一个包含您可以用来渲染您自己的配送费率的组件的对象,它包含 ShippingRatesControlPackage。 context: 等于渲染填充的块的名称,可以是 woocommerce/cart 或 woocommerce/checkout。 ExperimentalOrderLocalPickupPackages 此组件在结账页面的“结账”块中的“取货选项”区域内渲染。 它不会在购物车块中渲染。 const { __ } = window.wp.i18n; const { registerPlugin } = window.wp.plugins; const { ExperimentalOrderLocalPickupPackages } = window.wc.blocksCheckout; const render = () => { return (
{ __( '通过使用我们便捷的本地自提选项,您可以来我们的商店取您的订单。 当您的订单准备好取货时,我们会通过电子邮件通知您。', 'YOUR-TEXTDOMAIN' ) }
); }; registerPlugin( 'slot-and-fill-examples', { render, scope: 'woocommerce-checkout', } ); 结账: 已传递的参数 renderPickupLocation: 一个渲染函数,用于渲染本地自提选项的地址详情。 cart: wc/store/cart 的数据,但使用 camelCase 格式,而不是 snake_case。 对象分解。 extensions: 由第三方开发者使用 ExtendSchema 注册的外部数据。 如果您在 wc/store/cart 上使用了 ExtendSchema,您可以在此处找到您的数据,位于您的命名空间下。 components: 一个包含组件的对象,您可以使用这些组件来渲染您自己的取货费用。 它包含 ShippingRatesControlPackage 和 RadioControl。 ExperimentalDiscountsMeta 此组件在 CouponCode 输入框下方渲染。 const { __ } = window.wp.i18n; const { registerPlugin } = window.wp.plugins; const { ExperimentalDiscountsMeta } = window.wc.blocksCheckout; const render = () => { return (
{ __( '您有 98683 积分可用于消费...', 'YOUR-TEXTDOMAIN' ) }
); }; registerPlugin( 'slot-and-fill-examples', { render, scope: 'woocommerce-checkout', } ); 购物车: 结账: 传递的参数 cart: wc/store/cart 数据,但使用了 camelCase 格式,而不是 snake_case 格式。 对象分解 extensions: 由第三方开发者使用 ExtendSchema 注册的外部数据。 如果您在 wc/store/cart 上使用了 ExtendSchema,您可以在此处找到您的数据,它位于您的命名空间下。 context: 等于渲染填充的 阻止 的名称: woocommerce/cart 或 woocommerce/checkout。 结账工具 提供用于结账功能的实用函数和 React 钩子,这些功能来自 @woocommerce/blocks-checkout。 useValidateCheckout 一个钩子,用于验证结账表单,并在发现任何错误时自动滚动到第一个验证错误。 此钩子主要由 PlaceOrderButton 组件内部使用,以向自定义的下单按钮组件提供 validate 属性。 但是,如果需要,也可以直接使用它。 使用方法 // 别名导入 import { useValidateCheckout } from '@woocommerce/blocks-checkout'; // 全局导入 // const { useValidateCheckout } = wc.blocksCheckout; const MyComponent = () => { const validateCheckout = useValidateCheckout(); const handleClick = async () => { const { hasError } = await validateCheckout(); if ( hasError ) { // 验证失败 - 错误会自动显示, // 并且页面会滚动到第一个错误元素 return; } // 验证通过 - 继续执行您的逻辑 }; return ; }; 返回值 该钩子返回一个函数,当调用该函数时: 触发 CHECKOUT_VALIDATION 事件以运行所有已注册的验证回调。 检查验证存储以查找任何字段级别的验证错误。 如果发现错误: 显示所有验证错误。 滚动到并聚焦第一个错误元素。 返回一个 promise,其结果为 { hasError: boolean }。 属性 类型 描述 hasError boolean 如果验证失败则为 true,如果验证通过则为 false。 DOM 事件 某些块需要响应某些事件,以便显示最新的数据或以特定方式运行。 例如,购物车块必须监听“加入购物车”事件,以便更新购物车的内容;或者迷你购物车块,每当一个产品被添加到购物车时,它就会打开。 WooCommerce 核心事件在 WooCommerce 块中的应用 WooCommerce 核心使用 jQuery 事件来触发和监听某些事件,例如当产品被添加到或从购物车中移除时。 在 WooCommerce 块中,我们已经不再使用 jQuery,但我们仍然需要监听这些事件。 为了实现这一点,我们有一个名为 translatejQueryEventToNative() 的实用程序,它监听这些 jQuery 事件,并且每当一个事件被触发时,它会触发一个相关的 DOM 原生事件(带有 wc-blocks_ 前缀)。 WooCommerce 块事件 wc-blocks_adding_to_cart 这个事件相当于 WooCommerce 核心触发的 jQuery 事件 adding_to_cart。 它表示将产品添加到购物车的过程已发送到服务器,但尚未有任何指示表明该产品是否已成功添加。 在 WC 块中的示例用法: 迷你购物车块监听此事件以附加其依赖项。 wc-blocks_added_to_cart 这个事件相当于 WooCommerce 核心触发的 jQuery 事件 added_to_cart。 它表示将产品添加到购物车的过程已成功完成。 在 WC 块中的示例用法: 购物车和迷你购物车块(通过 useStoreCart() 钩子)监听此事件,以了解它们是否需要更新其内容。 detail 参数 参数 类型 默认值 描述 preserveCartData boolean false 是否保留商店中的购物车数据。 默认情况下,其值为 false,因此任何 wc-blocks_added_to_cart 事件都会使购物车数据失效,并且监听该事件的块会再次获取购物车数据。 但是,如果触发事件的代码已经更新了商店(例如:所有产品块),则可以设置 preserveCartData: true 以避免其他块再次获取数据。 wc-blocks_removed_from_cart 此事件等同于 WooCommerce 核心触发的 jQuery 事件 removed_from_cart。 它表示一个产品已从购物车中移除。 在 WC Blocks 中的用法示例: 购物车和迷你购物车块(通过 useStoreCart 钩子)会监听此事件,以了解它们是否需要更新其内容。 结账模块如何处理订单 本文将深入探讨结账流程的内部机制。更具体地说,当用户点击“提交订单”按钮后会发生什么。 结构 以下区域与处理用户的结账过程相关。 支付注册表 (文件) 支付注册表存储每个支付方法的所有配置信息。 我们可以使用 registerPaymentMethod 和 registerExpressPaymentMethod 函数在此处注册新的支付方法,这些函数也供其他插件使用。 数据存储 数据存储用于跟踪可能在用户会话期间发生变化的数据,例如,当前使用的支付方法、结账是否存在错误等。 我们根据关注的领域对这些数据存储进行分割,因此我们有两个与结账相关的数据存储: wc/store/checkout (文件) 和 wc/store/payment (文件)。 数据存储位于 assets/js/data 文件夹中。 上下文 (Contexts) 上下文用于将数据提供给结账模块。 每个上下文都通过钩子提供与特定领域相关的数据和函数。 例如,如果我们要使用 PaymentEventsContext 上下文中的 onPaymentSetup 句柄,可以这样操作: const { onPaymentSetup } = usePaymentEventsContext(); 上下文的另一个作用是为我们的结账模块运行副作用。 通常, CheckoutEvents 和 PaymentEvents 会监听结账和支付数据存储的变化,并根据某些逻辑,基于这些变化分发操作到这些存储中。 例如,在 CheckoutEvents 上下文中,当结账状态为 before_processing 时,我们会分发 emitValidateEvent 操作。 还有很多类似的逻辑,它们会响应来自这两个存储的状态和数据的变化。 结账上下文包括: 上下文 描述 CheckoutEvents 提供与结账相关的事件句柄 PaymentEvents 提供与支付相关的事件句柄 CustomerData 提供与当前客户相关的数据 ShippingData 提供与配送相关的错误数据和操作 结账处理器 (checkout-processor.js) 结账处理器组件会订阅结账或支付数据存储的变化,将部分数据打包起来,并在满足条件时调用 Store API 的 /checkout 接口。 结账提供者 结账提供者 将上述所有上下文封装在 CheckoutProcessor 组件中。 结账用户流程 以下是完整的结账流程: 1. 点击“提交订单”按钮 结账流程从用户点击按钮开始。 2. 结账状态设置为 before_processing 文件 当用户点击“提交订单”按钮后,我们将结账状态更改为 "before_processing"。 在这里,我们处理结账信息的验证。 3. 触发 checkout_validation_before_processing 事件 文件 在这里,WooCommerce Blocks 插件和其他插件可以注册事件监听器来处理验证。 此事件的监听器将运行,如果存在错误,我们将结账状态设置为 idle 并向用户显示错误。 如果没有错误,我们将进入下面的第 4 步。 4. 结账状态设置为 processing 文件 processing 状态由下面的第 5 步用于更改付款状态。 5. 付款状态设置为 processing 文件 在完成所有结账处理并且没有错误后,付款处理开始。 6. 触发 payment_processing 事件 文件 触发 payment_processing 事件。 其他插件可以注册此事件的监听器并运行自己的代码。 例如,Stripe 插件在这里检查地址和付款详情,并使用 Stripe API 在 Stripe 中创建客户和付款参考。 重要提示:实际的付款操作不是在这里进行的。它像一个预付款钩子,用于在尝试实际付款之前运行任何付款插件的代码。 7. 执行 payment_processing 事件监听器,并根据情况设置付款和结账状态 (file) 如果注册的事件监听器返回错误,我们将向用户显示该错误。 如果事件监听器被认为是成功的,我们将同步结账的地址与付款地址,将 paymentMethodData 存储在付款存储中,并设置付款状态属性 { isProcessing: true }。 8. POST 请求发送到 /wc/store/v1/checkout (file) 如果不存在付款错误,则会调用 /checkout StoreApi 端点。该端点会获取最终的客户地址和选择的付款方式,以及任何其他付款数据,然后尝试付款并返回结果。 重要:付款尝试是通过 StoreApi 进行的,而不是通过从客户端发送的 payment_processing 事件。 9. 触发 processCheckoutResponse 操作,该操作作用于结账存储 (file) 一旦对 StoreApi /checkout 端点的请求返回响应,我们将该响应传递给 checkout 数据存储中的 processCheckoutResponse 操作。 它将执行以下操作: 它设置重定向 URL,用于在订单完成后重定向到该 URL。 它将付款结果存储在 checkout 数据存储中。 它将结账状态更改为 after_processing(步骤 10)。 10. 将结账状态设置为 after_processing (file) after_processing 状态表示我们已完成主要的结账处理步骤。在此步骤中,我们执行清理操作,并显示在上一步骤中触发的任何错误。 11. 发出 checkout_after_processing_with_success 事件 (file) 如果没有错误,则会触发 checkout_after_processing_with_success 事件。这是其他插件可以在结账过程成功后运行代码的地方。 在 checkout_after_processing_with_success 事件上注册的任何事件监听器都将被执行。如果事件监听器没有返回错误,则会调用 checkout 数据存储中的 setComplete 操作,以将状态设置为 complete(步骤 13)。事件监听器也可能在此处返回错误,该错误将显示给用户。 12. 发出 checkout_after_processing_with_error 事件 (文件) 如果从第 5 步出现错误,则会发出 checkout_after_processing_with_error 事件。 其他插件可以注册事件监听器,以便在此处向用户显示错误。 事件监听器会被处理,并将任何错误显示给用户。 13. 将结账状态设置为 complete (文件) 如果没有错误,则在结账数据存储中的 status 属性会更改为 complete。 这表示结账流程已完成。 14. 重定向 (文件) 一旦结账状态设置为 complete,如果存在 redirectUrl 在结账数据存储中,则会将用户重定向到该网址。 其他值得注意的事项 检查付款方式 一个付款方式会与一个 配置对象 关联。它必须包含一个名为 canMakePayment 的函数。如果该付款方式可以用于支付当前的购物车,则该函数应返回 true。当前的购物车(商品、地址、配送方式等)会传递给此函数,并且每个付款方式负责报告它是否可用。 checkPaymentMethodsCanPay() 函数 会遍历所有已注册的付款方式,检查它们是否可用,如果可用,则将它们添加到支付数据存储器上的 availablePaymentMethods 属性。 必须在几个地方调用 checkPaymentMethodsCanPay() 函数,以便在将付款方式显示给用户作为可选项之前进行验证。 当购物车加载时,我们希望能够显示快捷付款方式,因此我们需要先验证它们。 当购物车发生变化时,我们可能希望启用/禁用某些付款方式。 当结账页面加载时,我们希望验证所有已注册的付款方式。 移除结账字段 如果您正在尝试扩展新的结账 Block,您可能会注意到之前的 checkout_fields 不起作用。这是有意为之,因为我们希望提供更多经过精心设计的扩展方式。 尽管如此,我们最常收到的一项请求是,如何为某些订单类型禁用结账字段。 我们不鼓励这样做,但由于这项请求非常普遍,我们在这里分享相关 Details。 为什么我们不鼓励移除字段 原因很简单:结账功能非常复杂,许多插件需要不同的数据。例如, Payment methods 需要您的地址信息来进行欺诈检测或验证您的卡,税费(包括核心税费)需要您的完整地址才能正确计算税费。 我们仍在考虑如何在结账功能中找到一个通用的解决方案。 在我们找到该解决方案之前,以下 document 将帮助您移除结账字段。 禁用单个国家/地区的字段 结账字段仍然遵循国家/地区设置,这意味着您可以通过 PHP 修改某个国家/地区的字段,并且这会正常工作。 以下的账单表单有 10 个字段,其中 7 个是必填项: 假设在阿尔及利亚,我们确信邮政编码和城市是冗余的,因此我们可以移除它们: add_filter('woocommerce_get_country_locale', function( $locale ) { $locale['DZ']['postcode']['required'] = false; $locale['DZ']['postcode']['hidden'] = true; $locale['DZ']['city']['required'] = false; $locale['DZ']['city']['hidden'] = true; return $locale; }); 通过上面的代码,这两个字段都已从阿尔及利亚移除,但未从其他国家/地区移除,这是一个安全且良好的更新。 请记住,这会同时移除 Shipping 和 Billing 的字段。 我们强烈认为 Billing 的 Shape 应该与 Shipping 的 Shape 匹配。 移除所有字段,仅保留国家和姓名 我们可以采取以下步骤,移除除了国家之外的所有其他字段。移除国家字段会导致您的订单失败,因为我们需要国家信息来确定要移除哪些字段: add_filter('woocommerce_get_country_locale', function( $locale ) { $locale['DZ']['address_1'] = [ 'required' => false, 'hidden' => true, ]; $locale['DZ']['postcode'] = [ 'required' => false, 'hidden' => true, ]; $locale['DZ']['city'] = [ 'required' => false, 'hidden' => true, ]; $locale['DZ']['company'] = [ 'required' => false, 'hidden' => true, ]; $locale['DZ']['state'] = [ 'required' => false, 'hidden' => true, ]; $locale['DZ']['phone'] = [ 'required' => false, 'hidden' => true, ]; return $locale; }); 结果如下: 您会注意到,地址行 2 不可见。这是因为如果地址行 1 被隐藏,地址行 2 也会被自动隐藏。 移除公司和电话 如果可以访问网站,一种简单的方法是从编辑器中切换关闭这些字段: 结果如下: 通过代码移除公司和电话 与其他的字段不同,电话、公司和地址 2 的信息是通过一个选项持久化到数据库中的: woocommerce_checkout_phone_field woocommerce_checkout_company_field woocommerce_checkout_address_2_field 这些选项的值可以是: required(必填)、 optional(可选)或 hidden(隐藏)。它们管理字段的默认状态。您可以编辑这些选项,但同时也允许商家根据自己的需要进行设置。您还可以根据地区/国家进行编辑。 要编辑默认值: add_filter( 'default_option_woocommerce_checkout_phone_field', function ( $default_value ) { return "required"; }, 10, 1 ); 如果您想根据地区(覆盖该国家/地区的商户设置)来更改值,可以使用上面的示例。 到目前为止,所有更改都仅应用于阿尔及利亚。其他国家的客户将看到适合其所在国家的正确字段: 将更改应用于您销售的所有国家/地区 与上述类似,我们不建议这样做,除非您只面向非常有限的国家/地区,并且已经针对每个国家/地区进行了测试。 某些 支付网关 仅在 生产模式 下启用欺诈检测,而不在 测试模式 下启用,并且在 测试模式 下通过的 字段 可能在 生产模式 下失败。 但无论如何,以下是代码: add_filter('woocommerce_get_country_locale', function( $locale ) { foreach ( $locale as $key => $value ) { $locale[ $key ]['address_1'] = [ 'required' => false, 'hidden' => true, ]; $locale[ $key ]['postcode'] = [ 'required' => false, 'hidden' => true, ]; $locale[ $key ]['city'] = [ 'required' => false, 'hidden' => true, ]; $locale[ $key ]['state'] = [ 'required' => false, 'hidden' => true, ]; } return $locale; }); 上述代码会循环遍历您销售的所有国家/地区,并禁用这些 字段。 限制更改仅适用于虚拟购物车 我们可以选择仅从 虚拟购物车 (仅需要账单信息,不需要 配送 信息) 中移除 字段,这可以通过一些额外的检查来实现: add_filter('woocommerce_get_country_locale', function( $locale ) { $cart = wc()->cart; // 仅当正在处理购物车时才移除 `字段`。 if ( ! $cart ) { return $locale; } // 仅当处理的是虚拟购物车时才移除 `字段`。 if ( $cart->needs_shipping() ) { return $locale; } // 执行以下逻辑... 编辑地址卡文本 在以后的访问中, 结账 页面会显示已保存 地址 的地址卡,目前该功能在账单方面可能无法始终正常工作,但一旦正常工作,它会显示如下: 我们可以使用 PHP 编辑该文本,因为该值来自 get_address_formats 函数,该函数通过 woocommerce_localisation_address_formats 过滤器。 我们可以使用以下代码: add_filter( 'woocommerce_localisation_address_formats', function( $formats ) { foreach ( $formats as $key => $format ) { $formats[ $key ] = "{first_name} {last_name}\n{country}"; // 您也可以使用 `{name}` 代替 `名` 和 `姓氏`。 } return $formats; } ); 请注意,您需要将 字符串 放在双引号中才能使其生效;否则,换行符将无法被识别。 结账流程和事件 本文档概述了 WooCommerce 结账模块中的结账流程,并提供了一些通用的架构概览。 结账模块的架构源于以下原则: 在结账流程中,数据拥有单一的权威来源。 为扩展集成提供一致的界面(例如,付款方式)。此界面保护结账过程的完整性,并将扩展逻辑与结账逻辑隔离。结账模块负责处理所有与服务器的通信,用于处理订单。扩展可以通过提供的界面与结账模块交互并进行通信。 结账流程的状态由结账状态跟踪。 扩展可以通过订阅发出的事件来与结账流程进行交互。 以下是流程的高层概览: 通用概念 通过状态跟踪流程 在结账生命周期的任何阶段,组件都应能够准确检测结账流程的状态。这包括以下内容: 是否正在加载内容?正在加载什么内容? 是否存在错误?是什么错误? 结账是否正在计算总额? 在某些情况下,使用简单的布尔值可能就足够了,但在其他情况下,它可能会导致复杂的条件判断和容易出错的代码(尤其是在处理对各种流程状态做出反应的逻辑行为时)。 为了显示流程状态,该模块使用状态,这些状态在各种上下文中进行跟踪。尽可能地,这些状态是内部设置的,以响应各种操作,因此子组件不需要实现(组件只需要_消费_状态,而不需要设置状态)。 以下是在 Checkout 中存在的状态。 结账数据存储状态 通过选择器,结账数据存储会暴露各种状态。所有选择器的详细信息如下,并在 结账 API 文档 中进行说明。 您可以在组件中使用它们,例如: const { useSelect } = window.wp.data; const { checkoutStore } = window.wc.wcBlocksData; const MyComponent = ( props ) => { const isComplete = useSelect( ( select ) => select( checkoutStore ).isComplete() ); // 对 isComplete 进行操作 }; 以下是与状态相关的可用布尔标志: isIdle: 当结账状态为 IDLE 时,此标志为真。在块加载后,任何对结账状态的更改都会使结账处于此状态。当在处理过程中出现错误后,如果可以重试购买,结账也会处于此状态。 isBeforeProcessing: 当结账状态为 BEFORE_PROCESSING 时,此标志为真。当用户提交结账以进行处理时,结账将处于此状态。 isProcessing: 当结账状态为 PROCESSING 时,此标志为真。当所有在 BEFORE_PROCESSING 状态下触发的事件观察器完成且没有错误时,结账将处于此状态。在此状态下,块会向服务器发送请求,访问结账端点以处理订单。注意: 在此状态下,还会发生一些付款状态的更改(请参阅 PaymentProvider 暴露的状态部分)。 isAfterProcessing: 当结账状态为 AFTER_PROCESSING 时,此标志为真。当块从服务器端处理请求接收到响应后,结账将处于此状态。 isComplete: 当结账状态为 COMPLETE 时,此标志为真。当所有在 AFTER_PROCESSING 状态下触发的事件观察器成功完成后,结账将处于此状态。当结账处于此状态时,购物者的浏览器将被重定向到 redirectUrl 的值(通常是 order-received 路由)。 特殊状态 以下布尔值通过结账提供程序暴露。 它们彼此独立,并且与结账状态不同,但可以组合使用,以响应结账过程中的各种状态。 isCalculating isCalculating 在以下两种情况下为真:当订单的总价正在重新计算时,或者当一个插件使用 disableCheckoutFor 动作(将在下一节中介绍)有意地禁用结账流程时。 有很多因素可能触发总价的重新计算,例如添加或删除优惠券、更新运费、选择运费等。与其检查每个单独的状态,您可以可靠地检查这个布尔值是否为真(计算中)或假(未计算中)。 isCalculating 影响: 禁用结账区块中的“提交订单”按钮。 禁用购物车区块中的“继续结账”按钮。 在计算过程中,显示快速支付方式的加载状态。 使用 disableCheckoutFor 控制 isCalculating 您可以使用 disableCheckoutFor 函数来编程地控制 isCalculating: const { dispatch } = window.wp.data; const { checkoutStore } = window.wc.wcBlocksData; // 示例:在执行异步操作时禁用结账 dispatch( checkoutStore ).disableCheckoutFor( async () => { // 在此处执行您的异步操作,例如使用 API 验证数据 await myAsyncOperation(); // 无需返回任何值 - 我们只关心 Promise 是否已解析 } ); 该函数控制内部状态,确保客户端在提供的 Promise 解析之前无法尝试完成流程,无论成功与否。 hasError hasError 在结账流程的任何部分出现错误状态时为真。这可能包括验证错误、请求错误、优惠券应用错误、支付处理错误等。 ShippingProvider 暴露的 Status shipping 上下文提供者暴露了与 shipping 相关的全部信息。这包括一组错误 status,用于指示 shipping 上下文所处的错误状态。该错误状态受服务器对地址更改、费率检索和选择的 requests 影响。 当前,错误 status 可能为 NONE、 INVALID_ADDRESS 或 UNKNOWN(请注意,此值可能会在未来更改)。 status 通过 useShippingDataContext Hook 提供的 currentErrorStatus 对象暴露。该对象具有以下 property: isPristine 和 isValid:这两个布尔值都与相同的错误 status 相关联。当 status 为 NONE 时,这两个布尔值的取值为 true。它基本上意味着没有 shipping 错误。 hasInvalidAddress:当提供的 shipping 地址无效时,此值为 true。 hasError:当 shipping 的错误 status 为 UNKNOWN 或 hasInvalidAddress 时,此值为 true。 付款方式数据存储状态 付款的状态存储在付款数据存储中。您可以使用以下选择器查询状态: const { select } = window.wp.data; const { paymentStore } = window.wc.wcBlocksData; const MyComponent = ( props ) => { const isPaymentIdle = select( paymentStore ).isPaymentIdle(); const isExpressPaymentStarted = select( paymentStore ).isExpressPaymentStarted(); const isPaymentProcessing = select( paymentStore ).isPaymentProcessing(); const isPaymentReady = select( paymentStore ).isPaymentReady(); const hasPaymentError = select( paymentStore ).hasPaymentError(); // 对布尔值进行操作 }; 这里的状态将有助于了解_客户端_处理的当前****状态,并且会在结账处理周期的不同阶段通过商店操作进行更新。_客户端_是指在注册的、活动的付款方式中,当结账表单通过这些注册的客户端组件提交时,处理任何付款的状态。 尽管如此,付款方式在处理订单时可能仍然存在额外的服务器端处理,但这不会反映在这些状态中(更多信息请参见付款方式集成文档)。 可能设置的_内部_状态包括: IDLE: 这是在初始化结账且存在未执行任何操作的付款方式时的状态。 每当结账状态更改为 IDLE时,也会设置此状态。 EXPRESS_STARTED: 仅限快速 付款方式 - 当用户点击其按钮触发快速付款方式时,将使用此状态。 此流程发生在处理之前,通常在一个模态窗口中。 PROCESSING: 当结账状态为 PROCESSING,结账 hasError为false,结账未进行计算,并且当前****付款状态不是 FINISHED时,将设置此状态。 当设置此状态时,将触发付款处理事件发射器。 READY: 在所有已连接到付款处理事件的观察者成功完成后,将设置此状态。 CheckoutProcessor组件使用此状态以及结账 PROCESSING状态来表示准备好将订单数据发送到服务器进行处理,并进行付款。 ERROR: 当连接到付款处理事件的观察者返回错误响应后,将设置此状态。 这将导致结账 hasError标志设置为true。 发送事件 另一个影响可扩展性的关键点是,提供既具有指导性又灵活的界面,以便扩展程序可以响应和处理流程中的特定事件。 为了保证系统的稳定性,核心结账流程应_控制_所有与服务器的通信,这些通信与结账/订单处理相关,并将扩展程序特定的需求留给扩展程序自行处理。 这样可以使扩展程序能够根据需要,以可预测的方式与结账数据和流程进行交互,而不会影响其他与之挂钩的扩展程序。 实现这种类型可扩展性的最可靠方法是使用事件系统。 因此,各种上下文提供器: 提供订阅 API,允许扩展程序订阅对特定事件做出反应的_观察者_。 在结账流程的特定点触发事件,这些事件会将数据传递给已注册的观察者,并在某些情况下,根据观察者的回复做出相应的反应。 当在任何事件发射器中注册观察者时,有一个_非常重要_的规则,那就是它们_不能_更新上下文状态。 仅对特定组件的局部状态进行更新是可以的,但不能修改任何上下文或全局状态。 原因是观察者回调函数是按顺序在特定点执行的,因此,注册到同一事件的后续观察者将无法响应早期执行的观察者中全局/上下文状态的任何更改。 const unsubscribe = emitter(myCallback); 您可以将您正在注册的任何发射器替换为 emitter 函数。 例如,如果您正在注册 onCheckoutValidation 事件发射器,则代码如下: const unsubscribe = onCheckoutValidation(myCallback); 您还可以指定希望您的观察者以何种优先级执行。 较低的优先级在较高的优先级之前运行,因此您可以控制您的观察者在已注册到发射器的观察者堆栈中何时运行。 您可以通过在第二个参数中指定一个数值来指示优先级: const unsubscribe = onCheckoutValidation(myCallback, 10); 在示例中, myCallback 是您的订阅函数。 订阅函数可以从事件发射器接收数据(如在“发射器详情”中描述的),并且可能需要以特定的格式返回一个回复(也在“特定发射器详情”中描述)。 订阅函数可以是 Promise,并且当事件发射器循环遍历已注册的观察者时,它将等待任何已注册的 Promise 完成。 最后,调用发射器函数的返回值是一个取消订阅函数,该函数可用于取消注册您的观察者。 这在 React 组件上下文中特别有用,您需要在组件卸载时确保取消注册观察者。 例如,可以在 useEffect 钩子中使用: Event Emitter Utilities 这里有一些与事件相关的实用方法。这些方法位于 assets/js/base/context/event-emit/utils.ts 文件中,可以按以下方式导入: import { noticeContexts, responseTypes, shouldRetry, } from '@woocommerce/base-context'; import { isSuccessResponse, isErrorResponse, isFailResponse, } from '@woocommerce/types'; 以下是辅助函数的描述: isSuccessResponse, isErrorResponse 和 isFailResponse: 这些是辅助函数,它们接收一个值,并通过布尔值报告该对象是否为预期的响应类型。对于接收来自注册观察者的响应的事件发射器,返回对象的 type 属性指示响应的类型,事件发射器会根据该类型做出反应。例如,如果观察者返回 { type: 'success' },则发射器可以将该值传递给 isSuccessResponse,该函数将返回 true。您可以在 支付处理事件发射器 的实现中看到一个示例。 noticeContexts: 这是一个对象,包含引用可以在结账过程中定位通知的区域的属性。该对象具有以下属性: PAYMENTS: 这是对支付方式步骤中通知区域的引用。 EXPRESS_PAYMENTS: 这是对快速支付方式步骤中通知区域的引用。 responseTypes: 这是一个对象,包含引用某些事件发射器可以返回的各种响应类型的属性。 这使得自动完成类型更容易,并避免了由于人为错误导致的拼写错误。 类型为 SUCCESS、 FAIL 和 ERROR。 这些类型的对应值与 结账端点响应 中的 付款状态类型。 shouldRetry: 这是一个函数,包含在结账流程中是否允许用户在之前的付款失败后重试付款的逻辑。 它接收 response 对象,并且默认情况下检查 retry 属性是否为 true、 undefined 或 false。 有关更多详细信息,请参阅 onCheckoutSuccess 文档。 技术文档 注意: noticeContexts 和 responseTypes 通过传递给其组件的 emitResponse 属性,暴露给 付款方式。 const MyPaymentMethodComponent = ( { emitResponse } ) => { const { noticeContexts, responseTypes } = emitResponse; // 其他 `付款方式` 的逻辑... }; 以下 活动 允许 扩展 注册观察者: onCheckoutValidation 注册到此事件发射器的观察者将不会接收任何参数。 此外,所有观察者将在结账处理来自发射器的回复之前执行。 注册到此发射器的观察者可以返回 true,表示它们没有需要返回给结账的信息;返回 false,表示希望结账返回到 IDLE 状态;或者返回一个包含以下属性的对象: errorMessage: 这将作为错误通知添加到结账上下文。 validationErrors: 这将设置为结账字段中的内联验证错误。 如果您的观察者希望触发验证错误,可以使用以下结构: 这是一个对象,其中键是验证错误的属性名称(对应于结账字段,例如 country 或 coupon),值是描述验证问题的错误消息。 当结账状态为 BEFORE_PROCESSING 时(这发生在验证时,在用户触发结账表单提交或使用 Express 付款方式之后),会触发此事件。 如果所有观察者都为该事件返回 true,则结账状态将更改为 PROCESSING。 可以通过使用 useCheckoutContext 钩子从结账上下文或作为属性在已注册的组件中,获取此事件发射器的订阅者: 用于内部开发: import { useCheckoutContext } from '@woocommerce/base-contexts'; import { useEffect } from '@wordpress/element'; const Component = () => { const { onCheckoutValidation } = useCheckoutContext(); useEffect( () => { const unsubscribe = onCheckoutValidation( () => true ); return unsubscribe; }, [ onCheckoutValidation ] ); return null; }; 用于已注册的付款方式组件: const { useEffect } = window.wp.element; const PaymentMethodComponent = ( { eventRegistration } ) => { const { onCheckoutValidation } = eventRegistration; useEffect( () => { const unsubscribe = onCheckoutValidation( () => true ); return unsubscribe; }, [ onCheckoutValidation ] ); }; 用于其他情况: const { onCheckoutValidation } = wc.blocksCheckoutEvents; useEffect( () => { const unsubscribe = onCheckoutValidation( () => true ); return unsubscribe; }, [ onCheckoutValidation ] ); onPaymentProcessing 此功能已过时,并已替换为 onPaymentSetup 事件发射器。 onPaymentSetup 当支付方式上下文的 Status 为 PROCESSING 时,此事件触发器会被激活。 Status 的设置条件是:结账的 Status 为 PROCESSING,结账没有 Error,结账没有正在计算,并且当前的支付 Status 不是 FINISHED。 此事件触发器会依次执行所有已注册的观察者(不传递任何参数)。当某个观察者返回非真值时,事件触发器会停止执行后续的已注册观察者。 当支付方式返回非真值时,如果返回的是有效的响应类型,事件触发器会根据响应更新各种内部 Status。以下是事件触发器可能处理的响应类型: 成功 当用户的输入数据正确且支付验证成功时,应返回成功的响应。一个响应被认为是成功的,至少应是具有以下结构的 Object: const successResponse = { type: 'success' }; 当返回成功的响应时,支付方式上下文的 Status 会更改为 SUCCESS。此外,包含以下任何额外的 Property 会触发额外的 Actions: paymentMethodData: 此对象的 Contents 将作为 payment_data 的值,当结账向服务器发送请求以处理订单时,该值会被包含在请求中。如果支付方式需要进行额外的服务器端处理,则此功能非常有用。 billingAddress: 允许支付方式更新结账中的任何账单信息(通常由 Express 支付方式使用),以便将其包含在发送给服务器的结账处理请求中。此数据应符合 此处 描述的结构。 shippingAddress: 允许支付方式更新订单的任何配送信息(通常由 Express 支付方式使用),以便将其包含在发送给服务器的结账处理请求中。此数据应符合 此处 描述的结构。 如果响应对象中没有 billingAddress 或 shippingAddress Property,则相关数据的 Status 将保持不变。 失败 当支付处理出现错误时,应返回失败的回复。一个回复被认为是失败回复,当它是一个具有以下结构的 JSON 对象时: const failResponse = { type: 'failure' }; 当观察者返回一个失败回复时,支付方法上下文的状态将被更改为 FAIL。此外,包含以下任何属性会导致额外的操作: message: 这里提供的字符串将被设置为结账中的错误提示。 messageContext: 如果提供,这将指定错误提示的目标区域(这与前面提到的 noticeContexts 相关)。否则,提示将添加到 noticeContexts.PAYMENTS 区域。 paymentMethodData: (与成功回复相同)。 billingAddress: (与成功回复相同)。 错误 当用户在结账表单中输入存在错误时,应返回错误响应。 响应被认为是错误响应,当它是一个具有以下结构的 对象时: const errorResponse = { type: 'error' }; 当观察者返回错误响应时,支付方法上下文状态将更改为 ERROR。 此外,包含以下任何属性将导致额外的操作: message: 在此处提供的字符串将被设置为错误提示。 messageContext: 如果提供,这将针对指定的区域显示错误提示(这与前面提到的 noticeContexts 相关)。 否则,提示将添加到 noticeContexts.PAYMENTS 区域。 validationErrors: 这将设置为结账字段中的内联验证错误。 如果观察者希望触发验证错误,可以使用以下结构来定义错误: 这是一个对象,其中键是验证错误的属性名称(对应于结账字段,例如 country 或 coupon),值是描述验证问题的错误消息。 如果响应对象不符合上述任何条件,则默认情况下将支付状态设置为 SUCCESS。 当支付状态设置为 SUCCESS 并且结账状态为 PROCESSING 时, CheckoutProcessor 组件将触发向服务器发送请求以处理订单。 可以通过使用 usePaymentEventsContext 钩子获取结账上下文,或者作为已注册组件的属性,将此事件发射器订阅者提供给支付方法扩展: 用于内部开发: import { usePaymentEventsContext } from '@woocommerce/base-contexts'; import { useEffect } from '@wordpress/element'; const Component = () => { const { onPaymentSetup } = usePaymentEventsContext(); useEffect( () => { const unsubscribe = onPaymentSetup( () => true ); return unsubscribe; }, [ onPaymentSetup ] ); return null; }; 用于已注册的支付方法组件: const { useEffect } = window.wp.element; const PaymentMethodComponent = ( { eventRegistration } ) => { const { onPaymentSetup } = eventRegistration; useEffect( () => { const unsubscribe = onPaymentSetup( () => true ); return unsubscribe; }, [ onPaymentSetup ] ); }; onCheckoutSuccess 当结账状态为 AFTER_PROCESSING 且结账的 hasError 状态为 false 时,会触发此事件发射器。 AFTER_PROCESSING 状态由 CheckoutProcessor 组件在接收到服务器对结账处理请求的响应后设置。 注册到此事件发射器的观察者将接收以下对象作为参数: const onCheckoutProcessingData = { redirectUrl, orderId, customerId, orderNotes, paymentResult, }; 属性如下: redirectUrl: 这是一个字符串,表示结账将重定向到的 URL,由服务器上的处理过程返回。 orderId: 是当前正在处理的订单的 ID。 customerId: 是进行购买的客户的 ID(该 ID 与订单相关联)。 orderNotes: 这是客户在订单上留下的任何自定义备注。 paymentResult: 这是来自 /checkout StoreApi 响应的 payment_result 的值 (https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/RestApi/StoreApi/Schemas/CheckoutSchema.php#L103-L138)。 此对象中暴露的数据(通过对象的属性): paymentStatus: 支付在服务器端处理后的状态。可能的值为 success、 failure、 pending 或 error。 paymentDetails: 这将是一个任意对象,包含付款方式处理服务器端在结账处理响应中返回给客户端的任何数据。付款方式可以通过钩子在服务器端进行处理,并设置此数据。 此事件发射器将依次调用所有已注册的观察者,直到任何一个观察者的响应不等于 true。 此时,任何未调用的观察者将被跳过,并且触发中止的观察者的响应将被处理。 此发射器将处理 success 类型的响应 ( { type: success }),并将结账状态设置为 COMPLETE。 此外,如果响应包含 redirectUrl,则结账将重定向到指定的地址。 此发射器还将处理 failure 类型的响应或 error 类型的响应,如果检测到无效的类型,则将其视为 error 类型的响应。 在所有情况下,如果响应中包含以下属性,则会执行额外的操作: 结账状态处理 以下描述了如何处理结账状态。 message: 此字符串将被添加为错误通知。 messageContext: 如果存在,则该通知将被配置为显示在指定的通知区域(否则,它将只是结账块的通用通知)。 retry: 如果此值为 true 或未定义,则结账状态将被设置为 IDLE。 这基本上意味着该错误是可以恢复的(例如,尝试不同的支付方式),因此结账将被重置为 IDLE 以供购物者再次尝试。 如果此值为 false,则结账状态将被设置为 COMPLETE,并且结账将重定向到当前设置为 redirectUrl 的 URL。 redirectUrl: 如果此参数存在,则当状态为 COMPLETE 时,结账将重定向到此 URL。 如果所有观察者都返回 true,则结账状态将仅设置为 COMPLETE。 此事件发射器订阅者可以通过使用 useCheckoutContext 钩子获取结账上下文,或者作为已注册组件的属性提供给支付方式扩展。 用于内部开发: import { useCheckoutContext } from '@woocommerce/base-contexts'; import { useEffect } from '@wordpress/element'; const Component = () => { const { onCheckoutSuccess } = useCheckoutContext(); useEffect( () => { const unsubscribe = onCheckoutSuccess( () => true ); return unsubscribe; }, [ onCheckoutSuccess ] ); return null; }; 用于已注册的支付方式组件: const { useEffect } = window.wp.element; const PaymentMethodComponent = ( { eventRegistration } ) => { const { onCheckoutSuccess } = eventRegistration; useEffect( () => { const unsubscribe = onCheckoutSuccess( () => true ); return unsubscribe; }, [ onCheckoutSuccess ] ); }; 用于其他情况: const { onCheckoutSuccess } = wc.blocksCheckoutEvents; useEffect( () => { const unsubscribe = onCheckoutSuccess( () => true ); return unsubscribe; }, [ onCheckoutSuccess ] ); onCheckoutFail 当结账状态为 AFTER_PROCESSING 且结账的 hasError 状态为 true 时,会触发此事件发射器。 AFTER_PROCESSING 状态由 CheckoutProcessor 组件在接收到服务器对结账处理请求的响应后设置。 注册到此发射器的观察者将接收到与注册到 onCheckoutSuccess 相同的的数据包。 来自第一个观察者的响应,如果返回的值不 === true,则处理方式与 onCheckoutSuccess 类似,但仅处理类型为 error 或 failure 的情况。 如果所有观察者都返回 true,则结账状态将直接设置为 IDLE,并在结账上下文中显示默认错误提示。 可以通过结账上下文使用 useCheckoutContext 钩子,或作为属性传递给已注册的支付方式组件来获取此事件发射器的订阅者: 用于内部开发: import { useCheckoutContext } from '@woocommerce/base-contexts'; import { useEffect } from '@wordpress/element'; const Component = () => { const { onCheckoutFail } = useCheckoutContext(); useEffect( () => { const unsubscribe = onCheckoutFail( () => true ); return unsubscribe; }, [ onCheckoutFail ] ); return null; }; 用于已注册的支付方式组件: const { useEffect } = window.wp.element; const PaymentMethodComponent = ( { eventRegistration } ) => { const { onCheckoutFail } = eventRegistration; useEffect( () => { const unsubscribe = onCheckoutFail( () => true ); return unsubscribe; }, [ onCheckoutFail ] ); }; 用于其他情况: const { onCheckoutFail } = wc.blocksCheckoutEvents; useEffect( () => { const unsubscribe = onCheckoutFail( () => true ); return unsubscribe; }, [ onCheckoutFail ] ); onShippingRateSuccess 当运费信息未加载,且运费数据上下文的错误状态为 NONE,并且存在可用的运费信息时,会触发此事件发射器。 此事件发射器不关心任何已注册的观察者的响应,而是简单地执行所有已注册的观察者,并将从服务器检索到的当前运费信息传递给它们。 onShippingRateFail 当运费信息未加载,且运费数据上下文的错误状态为 UNKNOWN 或 INVALID_ADDRESS 时,会触发此事件发射器。 此事件发射器不关心任何已注册的观察者的响应,而是简单地执行所有已注册的观察者,并将当前的错误状态传递给它们。 onShippingRateSelectSuccess 当运费选择未持久化到服务器,并且存在已选择的运费信息,且当前上下文中的错误状态为 NONE 时,会触发此事件发射器。 此事件发射器不关心任何已注册的观察者的响应,而是简单地执行所有已注册的观察者,并将当前的已选择运费信息传递给它们。 onShippingRateSelectFail 当配送费率选择未能保存到服务器,并且配送数据上下文的错误状态为 UNKNOWN 或 INVALID_ADDRESS 时,会触发此事件发射器。 此事件发射器不关心任何已注册的观察者的响应,它将简单地执行所有已注册的观察者,并将当前的错误状态传递给它们。 在结账块中过滤付款方式 问题 您是一名扩展开发者,您的扩展有条件地隐藏结账步骤中的支付网关。您需要使用前端可扩展性点来隐藏结账块中的支付网关。 解决方案 WooCommerce Blocks 提供了名为 registerPaymentMethodExtensionCallbacks 的函数,允许扩展注册回调函数,用于特定付款方式,以确定是否可以进行支付。 导入 别名导入 import { registerPaymentMethodExtensionCallbacks } from '@woocommerce/blocks-registry'; wc global const { registerPaymentMethodExtensionCallbacks } = window.wc.wcBlocksRegistry; 签名 参数 描述 类型 namespace 用于标识您的扩展的唯一字符串。选择一个能够避免与其他扩展发生命名冲突的名称。 string callbacks 包含为不同付款方式注册的回调函数的对象 Record< string, CanMakePaymentExtensionCallback > 请参阅以下关于 为付款方式注册的回调函数 的更多信息。 扩展命名空间冲突 当尝试在已使用 registerPaymentMethodExtensionCallbacks 的扩展命名空间下注册回调函数时,注册将被中止,并且您将收到通知,表明您没有使用唯一的命名空间。 这将在 JavaScript 控制台中显示。 使用示例 registerPaymentMethodExtensionCallbacks( 'my-hypothetical-extension', { cod: ( arg ) => { return arg.shippingAddress.city === 'Berlin'; }, cheque: ( arg ) => { return false; }, } ); 为付款方式注册的回调函数 扩展程序只能为每种付款方式注册一个回调函数: payment_method_name: (arg) => {...} payment_method_name 是在向 WooCommerce Blocks 注册付款方式时使用的 name 属性 的值。 注册的回调函数用于确定相应的付款方式是否应作为购物者的可用选项。 该函数将传递一个包含有关当前订单的数据的对象。 type CanMakePaymentExtensionCallback = ( cartData: CanMakePaymentArgument ) => boolean; 每个回调函数都可以访问以下信息: interface CanMakePaymentArgument { cart: Cart; cartTotals: CartTotals; cartNeedsShipping: boolean; billingAddress: CartResponseBillingAddress; shippingAddress: CartResponseShippingAddress; selectedShippingMethods: Record< string, unknown >; paymentRequirements: Array< string >; } 如果需要回调函数接收的参数中没有的数据,您可以考虑 在 Store API 中公开您的数据。 使用要求过滤付款方式 问题 您的扩展程序以一种方式向您的商店添加了功能,即只有特定的支付网关才能处理包含某些产品的订单。 例如,如果购物者将 Bookable 产品添加到购物车,例如酒店住宿,并且您(作为商家)希望在付款之前确认所有预订,您仍然需要捕获客户的结账详细信息,但此时不需要他们的付款方式。 解决方案 为了允许购物者在不输入付款详细信息的情况下结账,但仍然要求他们填写其他结账详细信息,您可以创建一个新的付款方式,该付款方式将处理包含 Bookable 项目的购物车。 通过使用付款方式的 supports 配置,可以防止其他付款方式(例如信用卡、PayPal 等)被用于结账,并且仅允许您的扩展程序添加的付款方式出现在结账块中。 有关如何向 WooCommerce Blocks 注册付款方式的更多信息,请参阅 付款方式集成 文档。 基本用法 请参考上方链接的文档,注册您的付款方式,并为其指定一个唯一的 supports 特性,例如 booking_availability。这将用于隔离该付款方式,防止其他付款方式显示。 首先,您需要创建一个函数,该函数将检查购物车的内容,以确定购物车所需的特定付款要求。以下是一个针对我们的 Bookable 产品执行此操作的示例。 然后,您需要在 ExtendSchema 类中使用 register_payment_requirements,以告知结账模块执行一个回调函数来检查这些要求。 整合所有内容 此代码示例假设存在一个名为 Pseudo_Booking_Class 的类,该类具有 cart_contains_bookable_product 方法。 此方法的实现在此处不相关。 /** * 检查购物车的内容,并添加所需的付款方式。 * * * @return array 购物车中项目所需的特性列表。 */ function inject_payment_feature_requirements_for_cart_api() { // 如果购物车包含可预订的产品,则返回一个包含我们要求的 `booking_availability` 的数组。 if ( Pseudo_Booking_Class::cart_contains_bookable_product() ) { return array( 'booking_availability' ); } // 购物车中没有可预订的产品,无需添加任何内容。 return array(); } 总结上述内容:如果购物车中包含可预订的产品,则此函数将返回一个包含 booking_availability 的数组,否则,它将返回一个空数组。 下一步是告诉 ExtendSchema 类,在检查要显示的付款方式时,执行此回调函数。 为此,您可以使用以下代码: add_action('woocommerce_blocks_loaded', function() { woocommerce_store_api_register_payment_requirements( array( 'data_callback' => 'inject_payment_feature_requirements_for_cart_api', ) ); }); 重要的是要注意此代码块中的注释:您必须不要实例化 ExtendSchema 的自定义版本。 如果您已正确添加您的付款方式,并为其指定了正确的 supports 值,那么当您在购物车中包含 Bookable 项目时访问结账页面时,任何不支持 booking_availability 要求的付款方式都应该不显示,而您的付款方式,即_支持_此要求的付款方式_将_显示。 付款方式集成 客户端集成 客户端集成包括一个 API,用于注册 常规 和 快速 付款方式。 在两种情况下,客户端集成都是通过 blocks-registry API 提供的注册方法来完成的。您可以通过 WooCommerce 环境中的 wc 全局对象 ( wc.wcBlocksRegistry) 访问它。 注意:在您的构建过程中,您可以执行类似于 blocks 仓库中执行的操作,该操作将此 API 作为外部 API 别名为 @woocommerce/blocks-registry (https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e089ae17043fa525e8397d605f0f470959f2ae95/bin/webpack-helpers.js#L16-L35)。 快速付款方式 快速付款方式是指由购物者发起的、包含一键支付流程的付款方式,例如 Stripe、ApplePay 或 GooglePay。 注册 要注册一种快速付款方式,您可以使用来自 blocks 注册表的 registerExpressPaymentMethod 函数。 const { registerExpressPaymentMethod } = window.wc.wcBlocksRegistry; 如果您使用 @woocommerce/blocks-registry 的别名导入,您可以这样导入该函数: import { registerExpressPaymentMethod } from '@woocommerce/blocks-registry'; 注册函数期望一个包含特定于付款方式的选项的 JavaScript 对象: registerExpressPaymentMethod( options ); 您传递给配置实例的选项应该是一个具有以下结构的 对象(请参阅 ExpressPaymentMethodConfiguration 类型定义): const options = { name: 'my_payment_method', title: 'My Mayment Method', description: '一两句话描述您的付款方式', gatewayId: 'gateway-id', label: , content: , edit: , canMakePayment: () => true, paymentMethodId: 'my_payment_method', supports: { features: [], style: [], }, }; ExpressPaymentMethodConfiguration 选项 类型 描述 必需 name 字符串 网关客户端的唯一标识符。 是 title 字符串 您的支付方式的人性化名称。在编辑器中向商家显示。 否 description 字符串 描述您的支付网关的简短文字(一到两句话)。在编辑器中向商家显示。 否 gatewayId 字符串 注册服务器端的支付网关的 ID。用于将商家引导到编辑器中的正确设置页面。如果未提供此 ID,商家将被重定向到 WooCommerce 的常规支付设置页面。 否 content ReactNode 当在前端渲染块时,在快速支付方式区域输出的 React 节点。从结账支付方式界面接收 props。 是 edit ReactNode 当在编辑器中渲染块时,在快速支付方式区域输出的 React 节点。从支付方式界面接收 props,用于预览数据。 是 canMakePayment 函数 回调函数,用于确定该支付方式是否应为用户可用。 是 paymentMethodId 字符串 伴随发送到服务器的结账处理请求的标识符。用于标识用于处理支付的支付方式网关类。 否 supports:features 数组 网关支持的支付功能的数组。用于检查该支付方式是否可用于购物车中的商品。如果未提供任何值,则默认为 ['products']。 否 supports:style 数组 这是一个快速支付方式支持的样式变化数组。这些样式应用于所有活动的快速支付方式按钮,并且可以在编辑器中的快速支付方式块中进行控制。支持的值之一是 ['height', 'borderRadius']。 否 canMakePayment 选项 canMakePayment 是一个回调函数,用于确定付款方式是否应该作为购物者的可用选项。该函数将传递一个包含有关当前订单的数据的对象。 canMakePayment( { cart: Cart, cartTotals: CartTotals, cartNeedsShipping: boolean, shippingAddress: CartShippingAddress, billingAddress: CartBillingAddress, selectedShippingMethods: Record, paymentRequirements: string[], } ) canMakePayment 返回一个布尔值。如果您的支付网关需要执行异步初始化以确定可用性,您可以返回一个 Promise(解析为布尔值)。这允许根据购物车隐藏某些付款方式,例如,如果购物车包含实物/可运送的商品(例如: 货到付款);或者,用于控制付款方式的可用性,具体取决于其他条件。 canMakePayment 仅在商店的前端运行。在编辑器上下文中,而不是使用 canMakePayment,编辑器会假定付款方式可用(true),以便向商家显示定义的 edit 组件。 请注意,此函数可能在结账的生命周期中被多次调用,因此,在提供的此属性的回调函数中,任何耗时的逻辑都应该进行缓存。 快速支付方式的按钮属性 此 API 提供了一种同步快速支付方式按钮外观的方法,以提供一致的购物体验。快速支付方式应优先使用 buttonAttributes 中提供的值,并在按钮渲染在购物车或结账阻止之外的地方时,使用其自身的配置设置作为备份。 例如,在您的按钮组件中,您可能会执行以下操作: // 获取您的扩展特定的设置,如果未提供则设置默认值 let { borderRadius = '4', height = '48', } = getButtonSettingsFromConfig(); // 在购物车和结账块上下文中,我们接收 `buttonAttributes` 作为属性,这些属性会覆盖扩展特定的设置 if ( typeof buttonAttributes !== 'undefined' ) { height = buttonAttributes.height; borderRadius = buttonAttributes.borderRadius; } ... return ); } return ( ); }; **注册自定义付款方式** 本指南介绍了如何注册自定义付款方式。 **内容:** * **产品:** 自定义付款方式 * **选择:** 注册自定义付款方式 * **按钮:** 注册按钮 * **方法:** `registerPaymentMethod` * **标签:** 付款方式标签 * **订单:** 订单 * **编辑:** 编辑按钮 * **保存:** 保存按钮 * **显示:** 显示区域 * **列表:** 付款方式列表 * **端口:** 无 * **使用:** 使用指南 * **在:** 在页面中 * **否:** 否 * **付款方式:** 付款方式 * **描述:** 描述信息 * **下单:** 下单按钮 * **已选中:** 已选择状态 ```javascript registerPaymentMethod( { name: 'my-custom-payment', label:
我的自定义付款方式
, content:
付款方式描述
, edit:
付款方式描述
, placeOrderButton: CustomButton, canMakePayment: () => true, supports: { features: [ 'products' ], }, } ); 注意: 自定义按钮仅在从列表中选择付款方式时才会显示。 当选择已保存的付款凭证时,将使用默认的“下单”按钮。 传递给付款方式节点的属性 付款方式集成的一个重要部分是,当提供的节点被克隆并在区块挂载时渲染时,会通过属性向付款方式暴露的界面。虽然所有属性都列在下面,但您可以在 此文件中描述的类型定义 中找到有关这些属性引用的对象、它们的类型等的更多详情。 属性说明 Property Type Description activePaymentMethod String 当前结账流程中活动的付款方式的别名。 billing 包含 billingAddress, cartTotal, currency, cartTotalItems, displayPricesIncludingTax, appliedCoupons, customerId 属性的对象 包含所有与账单相关的信息。 cartData 包含 cartItems, cartFees, extensions 属性的对象 暴露的购物车数据,包括商品、费用以及任何已注册的扩展数据。 请注意,这些数据应被视为不可变的(不应修改),否则会导致应用程序出现错误。 checkoutStatus 包含 isCalculating, isComplete, isIdle, isProcessing 属性的对象 以各种布尔状态暴露的当前结账状态。 components 包含 ValidationInputError, PaymentMethodLabel, PaymentMethodIcons, LoadingMask 属性的对象 暴露 React 组件,这些组件可以由您的付款方式用于各种常见的付款方式界面元素。 emitResponse 包含 noticeContexts 和 responseTypes 属性的对象 包含一些常量,在事件发射器中使用时可能很有用。 请阅读 事件发射 部分以获取更多详细信息。 eventRegistration 包含 onCheckoutValidation, onCheckoutSuccess, onCheckoutFail, onPaymentSetup, onShippingRateSuccess, onShippingRateFail, onShippingRateSelectSuccess, onShippingRateSelectFail 属性的对象 包含所有结账事件发射器注册函数。 这些是付款方式可以注册观察者以与结账流程的各个阶段进行交互的函数(请参阅 此文档 以获取更多信息)。 onClick Function 提供给表达付款方式,当付款方式按钮被点击时触发(这将向结账发出信号,表明付款方式已接管付款处理)。 onClose Function 提供给表达付款方式,当快速付款方式模态框关闭并控制权返回到结账时触发。 onSubmit Function 提交结账并开始处理。 validate Function 异步函数,用于在不提交的情况下验证结账表单。 返回一个解析为 { hasError: boolean } 的 Promise。 当您需要在显示付款方式之前进行验证时,此功能很有用。 buttonAttributes 包含 height, borderRadius 属性的对象 由商家设置的样式,所有快速付款方式按钮都应遵守这些样式。 paymentStatus Object 各种付款状态辅助函数。 请注意,您的付款方式不必在客户端设置此状态。 结账将通过您的付款方式从注册到 结账事件发射器 的回复来处理此操作。 paymentStatus.isPristine Boolean 当当前付款状态为 PRISTINE 时,此值为 true。 paymentStatus.isStarted Boolean 当当前付款状态为 EXPRESS_STARTED 时,此值为 true。 paymentStatus.isProcessing Boolean 当当前付款状态为 PROCESSING 时,此值为 true。 paymentStatus.isFinished Boolean 当当前付款状态为 ERROR, FAILED 或 SUCCESS 中的任何一个时,此值为 true。 paymentStatus.hasError Boolean 当当前付款状态为 ERROR 时,此值为 true。 paymentStatus.hasFailed Boolean 当当前付款状态为 FAILED 时,此值为 true。 paymentStatus.isSuccessful Boolean 当当前付款状态为 SUCCESS 时,此值为 true。 setExpressPaymentError Function 接收一个字符串,允许快速付款方式在需要时为快速付款区域设置错误通知。 这可能是必要的,因为某些快速付款方式的处理可能发生在结账事件之外。 shippingData 包含 shippingRates, shippingRatesLoading, selectedRates, setSelectedRates, isSelectingRate, shippingAddress, setShippingAddress, needsShipping 属性的对象 包含所有与运输相关的数据(不包括运输状态)。 shippingStatus 包含 shippingErrorStatus, shippingErrorTypes 属性的对象 各种运输状态辅助函数。 shouldSavePayment Boolean 指示购物者是否选择保存其付款方式详细信息(适用于支持保存付款方式的付款方式)。 如果已选择,则为 true;否则为 false。 默认为 false。 任何已注册的 savedTokenComponent 节点也会接收一个 token 属性,该属性包含所选择的已保存令牌的 ID,以备您的支付方法需要将其用于某些内部逻辑。但是,请记住,这只是代表该令牌在数据库中的 ID(以及购物者选中的单选框的值),而不是实际的客户支付令牌(因为通常在服务器上进行处理以确保安全)。 服务器端集成 对于服务器端集成,您需要创建一个类,该类需要继承 Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType 类。 这个类是您付款方式的服务器端表示。它用于在正确的时间,将您的付款方式资源注册到商店 API 和结账模块。它与您需要单独实现的 支付网关 API 不同,后者用于处理支付。 示例支付方式集成类 settings = get_option( 'woocommerce_my_payment_method_settings', [] ); } /** * 此函数应返回支付方式是否处于活动状态。 * * 如果为 false,则不会加载脚本。 * * @return boolean */ public function is_active() { return filter_var( $this->get_setting( 'enabled', false ), FILTER_VALIDATE_BOOLEAN ); } /** * 返回一个要注册的脚本/句柄的数组,用于此支付方式。 * * 在此函数中,您应该注册您的支付方式脚本(使用 `wp_register_script`),然后返回您注册的脚本句柄。 这将用于将您的支付方式作为结账脚本的依赖项,从而确保正确加载它。 * * 请注意,您仍然应该确保您的脚本具有的其他任何资源依赖项都已在此处正确注册。 如果您使用 Webpack 构建资源,您可能希望使用 WooCommerce Webpack 依赖项提取插件 * (https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin) 来使此过程更容易。 * * @return array */ public function get_payment_method_script_handles() { wp_register_script( 'my-payment-method', 'path/to/your/script/my-payment-method.js', [], '1.0.0', true ); return [ 'my-payment-method' ]; } /** * 返回一个要为管理后台排队的脚本句柄的数组。 * * 如果您的支付方式有一个脚本,您_只想_在结账块的编辑器上下文加载,则包含此脚本。 * 将 `get_payment_method_script_handles` 中的任何脚本也包含在此处,如果它们也需要在管理后台加载。 */ public function get_payment_method_script_handles_for_admin() { return $this->get_payment_method_script_handles(); } /** * 返回一个键值对数组,这些数据可供付款方式脚本客户端使用。 * * 这些数据可以通过 `wc.wcSettings.getSetting` 在客户端访问。例如,如果您将 `stripe` 赋值为该类的 `name` 属性,则可以在客户端通过以下方式访问任何数据: * `wc.wcSettings.getSetting( 'stripe_data' )`。这将返回一个对象,其形状与您从此函数返回的关联数组匹配。 * * @return array */ public function get_payment_method_data() { return [ 'title' => $this->get_setting( 'title' ), 'description' => $this->get_setting( 'description' ), 'supports' => $this->get_supported_features(), ]; } } 文档 这是一个示例文档,其中包含一些常用的术语。 设置 Settings → 设置 Payment methods → 付款方式 Available → 可用 Property → 属性 Method → 方法 Access → 访问 Title → 标题 Value → 价值 Shape → 形状 Class → 类 Data → 数据 Port → 端口 Via → 通过 Key → 关键字 For → 为 Tan → 褐色 Cc → 抄送 In → 在 Description → 描述 Assigned → 已分配 示例 这是一个示例段落,演示如何使用上述术语。 例如,您可以在 设置 中配置 付款方式。每个 付款方式 都有自己的 属性 和 方法。您可以通过 访问 相应的 端口 来获取 数据。 列表 以下是一个列表,其中包含一些常用的命令: command1 command2 command3 代码示例 以下是一个代码示例,演示如何使用 get_payment_method_data 函数: /** * Returns an array of key=>value pairs of data made available to the payment methods script client side. * * This data will be available client side via `wc.wcSettings.getSetting`. So for instance if you assigned `stripe` as the * value of the `name` property for this class, client side you can access any data via: * `wc.wcSettings.getSetting( 'stripe_data' )`. That would return an object matching the shape of the associative array * you returned from this function. * * @return array */ public function get_payment_method_data() { return [ 'title' => $this->get_setting( 'title' ), 'description' => $this->get_setting( 'description' ), 'supports' => $this->get_supported_features(), ]; } } 占位符和 HTML 标签 以下是一个包含占位符和 HTML 标签的示例: This is a string with a placeholder: %s.

This is a paragraph.

URL 链接 以下是一个 URL 链接: example.com 函数名、变量名、命令名 函数名、变量名和命令名应保持英文原文。例如: MyFunction, myVariable, myCommand. ### 注册付款方式集成 在创建了一个继承自 `Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType` 的类之后,您需要将其注册到服务器端的付款方式处理模块。 您可以通过使用 `PaymentMethodRegistry` 类的 `register` 方法来实现。 ```php use MyPlugin\MyPaymentMethod\MyPaymentMethodType; use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry; add_action( 'woocommerce_blocks_payment_method_type_registration', function( PaymentMethodRegistry $payment_method_registry ) { $payment_method_registry->register( new MyPaymentMethodType() ); } ); 处理付款(旧版本支持) 付款仍然通过 支付网关 API 进行处理。 这与上面用于付款方式集成的 API 是不同的。 结账模块将客户端脚本提供的 payment_data 转换为 $_POST,并调用支付网关的 process_payment 方法。 如果您已经集成了 WooCommerce 付款方式扩展,并且使用了短代码结账流程,那么旧版本的处理方式将负责在服务器端处理您的付款。 通过商店 API 处理支付 在某些更高级的场景下,之前提到的旧版支付处理方式可能无法满足您现有的支付方式集成需求。对于这些情况,还提供了一个动作钩子,您可以使用它来处理服务器端的订单处理,它提供了更多的上下文信息,并且专用于商店 API。 这个钩子是集成支付处理的首选位置: do_action_ref_array( 'woocommerce_rest_checkout_process_payment_with_context', [ $context, &$result ] ); 注意:在您之前创建的支付方式类型类的 initialize 方法中注册您的回调函数是一个不错的选择。 在该钩子上注册的回调函数将接收到: 一个 PaymentContext 对象,其中包含所选的 payment_method(这与在注册支付方式时定义的 paymentMethodId 值相同),正在创建的 order,以及由支付方式客户端提供的任何额外的 payment_data。 一个 PaymentResult 对象,您可以使用它来通过商店 API 将状态、重定向 URL 以及任何其他支付详情返回给客户端。 如果您在提供的 PaymentResult 对象上设置了状态,则您的支付方式将不再使用旧版支付处理方式。如果发生错误,您的回调函数可以抛出异常,该异常将由商店 API 处理。 以下是一个示例回调函数: add_action( 'woocommerce_rest_checkout_process_payment_with_context', function( $context, $result ) { if ( $context->payment_method === 'my_payment_method' ) { // 订单处理逻辑将在此处执行! // $context->order 包含订单对象,如果需要 // ... // 如果上述逻辑成功,我们可以将状态设置为成功。 $result->set_status( 'success' ); $result->set_payment_details( array_merge( $result->payment_details, [ 'custom-data' => '12345', ] ) ); $result->set_redirect_url( 'some/url/to/redirect/to' ); } }, 10, 2 ); 从客户端传递值到服务器端支付处理 在这个例子中,我们将从 BACS 支付方法传递一些数据到服务器。BACS 的注册过程大致如下: // 获取在注册支付方法时提供的设置 const settings = window.wc.wcSettings.getSetting( 'bacs_data' ); // 这是一个组件,当选择 BACS 支付方法时,它将在结账块中渲染 const Content = () => { return decodeEntities( settings?.description || '' ); }; // 这是一个支付方法的标签 const Label = ( props ) => { const { PaymentMethodLabel } = props.components; return ; }; // 注册支付方法 const bankTransferPaymentMethod = { name: 'BACS', label: