WooCommerce REST API - 产品、订单、客户、Webhooks
WooCommerce 开发技能
使用:base.md + (typescript.md 或 python.md)
用于通过REST API集成WooCommerce商店 - 产品、订单、客户、Webhooks和自定义扩展。
来源: WooCommerce REST API | 开发者文档
先决条件
商店要求
# WooCommerce商店必须有:
# 1. 安装了WooCommerce插件的WordPress
# 2. 启用HTTPS(API认证必需)
# 3. 设置固定链接不要使用“Plain”
# WordPress管理 → 设置 → 固定链接 → 文章名称(推荐)
生成API密钥
- 转到 WooCommerce → 设置 → 高级 → REST API
- 点击 添加密钥
- 设置描述、用户(管理员)和权限(读写)
- 点击 生成API密钥
- 复制 消费者密钥 和 消费者密文(仅显示一次)
API基础
基础URL
https://你的商店.com/wp-json/wc/v3/
认证
// Node.js - 基础认证(推荐)
const WooCommerceRestApi = require("@woocommerce/woocommerce-rest-api").default;
const api = new WooCommerceRestApi({
url: "https://你的商店.com",
consumerKey: process.env.WC_CONSUMER_KEY,
consumerSecret: process.env.WC_CONSUMER_SECRET,
version: "wc/v3"
});
# Python
from woocommerce import API
wcapi = API(
url="https://你的商店.com",
consumer_key=os.environ["WC_CONSUMER_KEY"],
consumer_secret=os.environ["WC_CONSUMER_SECRET"],
version="wc/v3"
)
查询字符串认证(备用)
# 如果基础认证失败(某些托管配置)仅使用
curl https://你的商店.com/wp-json/wc/v3/products \
?consumer_key=ck_xxx&consumer_secret=cs_xxx
安装
Node.js
npm install @woocommerce/woocommerce-rest-api
// lib/woocommerce.ts
import WooCommerceRestApi from "@woocommerce/woocommerce-rest-api";
const api = new WooCommerceRestApi({
url: process.env.WC_STORE_URL!,
consumerKey: process.env.WC_CONSUMER_KEY!,
consumerSecret: process.env.WC_CONSUMER_SECRET!,
version: "wc/v3",
queryStringAuth: false, // 设置为true用于HTTP(仅限开发)
});
export default api;
Python
pip install woocommerce
# lib/woocommerce.py
import os
from woocommerce import API
wcapi = API(
url=os.environ["WC_STORE_URL"],
consumer_key=os.environ["WC_CONSUMER_KEY"],
consumer_secret=os.environ["WC_CONSUMER_SECRET"],
version="wc/v3",
timeout=30
)
产品
列出产品
// Node.js
async function getProducts(page = 1, perPage = 20) {
const response = await api.get("products", {
page,
per_page: perPage,
status: "publish",
});
return response.data;
}
// 带过滤器
async function searchProducts(search: string, category?: number) {
const response = await api.get("products", {
search,
category: category || undefined,
orderby: "popularity",
order: "desc",
});
return response.data;
}
# Python
def get_products(page=1, per_page=20):
response = wcapi.get("products", params={
"page": page,
"per_page": per_page,
"status": "publish"
})
return response.json()
获取单个产品
async function getProduct(productId: number) {
const response = await api.get(`products/${productId}`);
return response.data;
}
创建产品
async function createProduct(data: ProductInput) {
const response = await api.post("products", {
name: data.name,
type: "simple", // simple, variable, grouped, external
regular_price: data.price.toString(),
description: data.description,
short_description: data.shortDescription,
categories: data.categoryIds.map(id => ({ id })),
images: data.images.map(url => ({ src: url })),
manage_stock: true,
stock_quantity: data.stockQuantity,
status: "publish",
});
return response.data;
}
更新产品
async function updateProduct(productId: number, data: Partial<ProductInput>) {
const response = await api.put(`products/${productId}`, data);
return response.data;
}
// 仅更新库存
async function updateStock(productId: number, quantity: number) {
const response = await api.put(`products/${productId}`, {
stock_quantity: quantity,
});
return response.data;
}
删除产品
async function deleteProduct(productId: number, force = false) {
// force: true = 永久删除,false = 移动到回收站
const response = await api.delete(`products/${productId}`, {
force,
});
return response.data;
}
可变产品
// 创建可变产品
async function createVariableProduct(data: VariableProductInput) {
// 1. 创建类型为"variable"的产品
const product = await api.post("products", {
name: data.name,
type: "variable",
attributes: [
{
name: "Size",
visible: true,
variation: true,
options: ["Small", "Medium", "Large"],
},
{
name: "Color",
visible: true,
variation: true,
options: ["Red", "Blue"],
},
],
});
// 2. 创建变体
for (const variant of data.variants) {
await api.post(`products/${product.data.id}/variations`, {
regular_price: variant.price.toString(),
stock_quantity: variant.stock,
attributes: [
{ name: "Size", option: variant.size },
{ name: "Color", option: variant.color },
],
});
}
return product.data;
}
// 获取变体
async function getVariations(productId: number) {
const response = await api.get(`products/${productId}/variations`);
return response.data;
}
订单
列出订单
async function getOrders(params: OrderQueryParams = {}) {
const response = await api.get("orders", {
page: params.page || 1,
per_page: params.perPage || 20,
status: params.status || "any", // pending, processing, completed, etc.
after: params.after, // ISO日期字符串
before: params.before,
});
return response.data;
}
// 获取最近订单
async function getRecentOrders(days = 7) {
const after = new Date();
after.setDate(after.getDate() - days);
const response = await api.get("orders", {
after: after.toISOString(),
orderby: "date",
order: "desc",
});
return response.data;
}
获取单个订单
async function getOrder(orderId: number) {
const response = await api.get(`orders/${orderId}`);
return response.data;
}
创建订单
async function createOrder(data: OrderInput) {
const response = await api.post("orders", {
payment_method: "stripe",
payment_method_title: "Credit Card",
set_paid: false,
billing: {
first_name: data.customer.firstName,
last_name: data.customer.lastName,
email: data.customer.email,
phone: data.customer.phone,
address_1: data.billing.address1,
city: data.billing.city,
state: data.billing.state,
postcode: data.billing.postcode,
country: data.billing.country,
},
shipping: {
first_name: data.customer.firstName,
last_name: data.customer.lastName,
address_1: data.shipping.address1,
city: data.shipping.city,
state: data.shipping.state,
postcode: data.shipping.postcode,
country: data.shipping.country,
},
line_items: data.items.map(item => ({
product_id: item.productId,
variation_id: item.variationId,
quantity: item.quantity,
})),
shipping_lines: [
{
method_id: "flat_rate",
method_title: "Flat Rate",
total: data.shippingCost.toString(),
},
],
});
return response.data;
}
更新订单状态
async function updateOrderStatus(orderId: number, status: OrderStatus) {
const response = await api.put(`orders/${orderId}`, {
status, // pending, processing, on-hold, completed, cancelled, refunded, failed
});
return response.data;
}
// 添加订单备注
async function addOrderNote(orderId: number, note: string, customerNote = false) {
const response = await api.post(`orders/${orderId}/notes`, {
note,
customer_note: customerNote, // true = 客户可见
});
return response.data;
}
订单状态
| 状态 | 描述 |
|---|---|
pending |
等待支付 |
processing |
已收到支付,等待履行 |
on-hold |
等待操作(库存、支付确认) |
completed |
订单已履行 |
cancelled |
由管理员或客户取消 |
refunded |
已退款 |
failed |
支付失败 |
客户
列出客户
async function getCustomers(params: CustomerQueryParams = {}) {
const response = await api.get("customers", {
page: params.page || 1,
per_page: params.perPage || 20,
role: "customer",
orderby: "registered_date",
order: "desc",
});
return response.data;
}
// 搜索客户
async function searchCustomers(email: string) {
const response = await api.get("customers", {
email,
});
return response.data;
}
创建客户
async function createCustomer(data: CustomerInput) {
const response = await api.post("customers", {
email: data.email,
first_name: data.firstName,
last_name: data.lastName,
username: data.email.split("@")[0],
billing: {
first_name: data.firstName,
last_name: data.lastName,
email: data.email,
phone: data.phone,
address_1: data.address1,
city: data.city,
state: data.state,
postcode: data.postcode,
country: data.country,
},
shipping: {
// 与账单地址相同或不同
},
});
return response.data;
}
更新客户
async function updateCustomer(customerId: number, data: Partial<CustomerInput>) {
const response = await api.put(`customers/${customerId}`, data);
return response.data;
}
Webhooks
创建Webhook
async function createWebhook(topic: string, deliveryUrl: string) {
const response = await api.post("webhooks", {
name: `Webhook for ${topic}`,
topic, // order.created, order.updated, product.created, etc.
delivery_url: deliveryUrl,
status: "active",
secret: process.env.WC_WEBHOOK_SECRET,
});
return response.data;
}
Webhook主题
| 主题 | 触发器 |
|---|---|
order.created |
新订单放置 |
order.updated |
订单状态/详情更改 |
order.deleted |
订单删除 |
product.created |
新产品创建 |
product.updated |
产品更新 |
product.deleted |
产品删除 |
customer.created |
新客户注册 |
customer.updated |
客户更新 |
coupon.created |
新优惠券创建 |
验证Webhook签名
// Express.js webhook处理器
import crypto from "crypto";
function verifyWooCommerceWebhook(req: Request): boolean {
const signature = req.headers["x-wc-webhook-signature"] as string;
const payload = JSON.stringify(req.body);
const expectedSignature = crypto
.createHmac("sha256", process.env.WC_WEBHOOK_SECRET!)
.update(payload)
.digest("base64");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// 路由处理器
app.post("/webhooks/woocommerce", (req, res) => {
if (!verifyWooCommerceWebhook(req)) {
return res.status(401).json({ error: "Invalid signature" });
}
const topic = req.headers["x-wc-webhook-topic"];
const payload = req.body;
switch (topic) {
case "order.created":
handleNewOrder(payload);
break;
case "order.updated":
handleOrderUpdate(payload);
break;
// ...其他主题
}
res.status(200).json({ received: true });
});
# Python/Flask webhook处理器
import hmac
import hashlib
import base64
@app.route("/webhooks/woocommerce", methods=["POST"])
def woocommerce_webhook():
signature = request.headers.get("X-WC-Webhook-Signature")
payload = request.get_data()
expected = base64.b64encode(
hmac.new(
os.environ["WC_WEBHOOK_SECRET"].encode(),
payload,
hashlib.sha256
).digest()
).decode()
if not hmac.compare_digest(signature, expected):
return {"error": "Invalid signature"}, 401
topic = request.headers.get("X-WC-Webhook-Topic")
data = request.json
if topic == "order.created":
handle_new_order(data)
elif topic == "order.updated":
handle_order_update(data)
return {"received": True}, 200
类别和标签
列出类别
async function getCategories() {
const response = await api.get("products/categories", {
per_page: 100,
orderby: "name",
});
return response.data;
}
// 创建类别
async function createCategory(name: string, parentId?: number) {
const response = await api.post("products/categories", {
name,
parent: parentId || 0,
});
return response.data;
}
列出标签
async function getTags() {
const response = await api.get("products/tags", {
per_page: 100,
});
return response.data;
}
优惠券
创建优惠券
async function createCoupon(data: CouponInput) {
const response = await api.post("coupons", {
code: data.code,
discount_type: data.type, // percent, fixed_cart, fixed_product
amount: data.amount.toString(),
individual_use: true,
exclude_sale_items: false,
minimum_amount: data.minimumAmount?.toString(),
maximum_amount: data.maximumAmount?.toString(),
usage_limit: data.usageLimit,
usage_limit_per_user: 1,
date_expires: data.expiresAt, // ISO日期字符串
});
return response.data;
}
报告
销售报告
async function getSalesReport(period = "month") {
const response = await api.get("reports/sales", {
period, // day, week, month, year
});
return response.data;
}
// 畅销产品
async function getTopSellers(period = "month") {
const response = await api.get("reports/top_sellers", {
period,
});
return response.data;
}
分页
处理大数据集
async function getAllProducts() {
const allProducts = [];
let page = 1;
const perPage = 100;
while (true) {
const response = await api.get("products", {
page,
per_page: perPage,
});
allProducts.push(...response.data);
// 检查头信息总页数
const totalPages = parseInt(response.headers["x-wp-totalpages"]);
if (page >= totalPages) break;
page++;
}
return allProducts;
}
分页头信息
| 头信息 | 描述 |
|---|---|
X-WP-Total |
总项目数 |
X-WP-TotalPages |
总页数 |
错误处理
import WooCommerceRestApi from "@woocommerce/woocommerce-rest-api";
async function safeApiCall<T>(
operation: () => Promise<{ data: T }>
): Promise<T> {
try {
const response = await operation();
return response.data;
} catch (error: any) {
if (error.response) {
// API返回错误
const { status, data } = error.response;
switch (status) {
case 400:
throw new Error(`错误请求:${data.message}`);
case 401:
throw new Error("无效的API凭证");
case 404:
throw new Error("资源未找到");
case 429:
// 限流 - 等待并重试
await new Promise(r => setTimeout(r, 5000));
return safeApiCall(operation);
default:
throw new Error(`API错误:${data.message}`);
}
}
throw error;
}
}
// 使用
const products = await safeApiCall(() => api.get("products"));
环境变量
# .env
WC_STORE_URL=https://你的商店.com
WC_CONSUMER_KEY=ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
WC_CONSUMER_SECRET=cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
WC_WEBHOOK_SECRET=你的webhook密文
添加到credentials.md:
'WC_CONSUMER_KEY': r'ck_[a-f0-9]{40}',
'WC_CONSUMER_SECRET': r'cs_[a-f0-9]{40}',
清单
集成前
- [ ] 安装并激活WooCommerce插件
- [ ] 商店启用HTTPS
- [ ] 设置固定链接为非Plain设置
- [ ] 生成具有适当权限的API密钥
- [ ] 配置Webhook密文
安全
- [ ] API密钥存储在环境变量中
- [ ] 验证Webhook签名
- [ ] 所有API调用使用HTTPS
- [ ] 处理限流
测试
- [ ] 测试API连接
- [ ] 测试产品CRUD操作
- [ ] 测试订单创建/更新
- [ ] 测试Webhook交付
- [ ] 测试大数据集的分页
反模式
- Plain固定链接 - 没有漂亮的固定链接API将无法工作
- 生产中使用HTTP - 总是使用HTTPS
- 忽略限流 - WooCommerce可能会限制请求
- 大型单一请求 - 使用分页进行批量操作
- 在代码中存储密钥 - 使用环境变量
- 跳过Webhook验证 - 总是验证签名