baldie81/woocommerce-sdk
Composer 安装命令:
composer require baldie81/woocommerce-sdk
包简介
Framework-independent PHP SDK for the WooCommerce REST API (v3): products, variations, categories, attributes, orders, customers, coupons, tax, shipping, webhooks, settings and the batch API.
README 文档
README
A small, framework-independent PHP client for the WooCommerce REST API (v3). No WordPress/Laravel/Symfony coupling — just PHP 8.1+ and Guzzle. It wraps the endpoints you actually reach for when integrating a store:
- Products — get / create / update / delete, list & paginate, look up by SKU
- Product variations — the variations of a variable product
- Product categories / tags / attributes — full catalog taxonomy, attribute terms
- Orders — get / list, create, partial update, set status, notes & refunds
- Customers — get / list, create / update (with inline addresses), look up by email
- Coupons — get / list, create / update, look up by code
- Tax — tax rates and tax classes
- Shipping — zones, their locations, and their methods
- Webhooks — register topic → delivery-URL hooks
- Store config — payment gateways, system status & tools, settings
- Batch API — create/update/delete up to 100 per call, auto-chunked past that
It also gives you fluent value-object builders (ProductInput, VariationInput,
OrderInput, LineItem, Address, CustomerInput, CouponInput,
CategoryInput, MetaData, BatchPayload) that every write method accepts
interchangeably with plain arrays, a fluent Query builder for list endpoints,
typed enums (ProductStatus, ProductType, CatalogVisibility, StockStatus,
OrderStatus, DiscountType), and a clean exception hierarchy instead of leaking
Guzzle exceptions.
Scope: this targets the standard WooCommerce core REST API (
wc/v3). Endpoints added by extensions (subscriptions, bookings, …) are out of scope, though their custom fields pass straight through viameta_dataand theset()escape hatches.
Install
composer require baldie81/woocommerce-sdk
Quick start
use Baldie81\WooCommerceSDK\Configuration; use Baldie81\WooCommerceSDK\WooCommerceClient; $woo = WooCommerceClient::create(new Configuration( baseUrl: 'https://shop.example.com', consumerKey: 'ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', consumerSecret: 'cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // timeout: 30.0, connectTimeout: 10.0, verifySsl: true, )); $product = $woo->products()->get(123);
Authentication
Create a consumer key / consumer secret pair under WooCommerce → Settings → Advanced → REST API. Over HTTPS the SDK sends them as HTTP Basic auth, which is all WooCommerce needs.
TLS verification is on by default; pass verifySsl: false only for
local/self-signed environments.
For a non-SSL store (local dev), WooCommerce can't use Basic auth, so set
queryStringAuth: true to send the credentials as query parameters instead.
Don't do this over plain HTTP in production — it exposes the credentials in URLs
and logs.
new Configuration( baseUrl: 'http://localhost:8080', consumerKey: 'ck_...', consumerSecret: 'cs_...', verifySsl: false, queryStringAuth: true, );
Value objects (or arrays)
Every write method accepts either a fluent builder or a raw array, so you
can opt into type-safety without giving up the array escape hatch. The builders
all implement Arrayable:
use Baldie81\WooCommerceSDK\Support\ProductInput; use Baldie81\WooCommerceSDK\Enum\ProductStatus; use Baldie81\WooCommerceSDK\Enum\ProductType; // Builder — a simple product with an image and a variation attribute: $woo->products()->create( ProductInput::make() ->name('Example')->type(ProductType::Simple)->sku('SKU-123') ->regularPrice('19.90')->status(ProductStatus::Publish) ->manageStock(true)->stockQuantity(100) ->categories([15, 21]) ->image('https://example.com/front.jpg', 'Front') ->meta('_origin', 'import') ); // …or the exact same call with a raw array — accepted everywhere: $woo->products()->create([ 'name' => 'Example', 'type' => 'simple', 'sku' => 'SKU-123', 'regular_price' => '19.90', 'status' => 'publish', 'manage_stock' => true, 'stock_quantity' => 100, 'categories' => [['id' => 15], ['id' => 21]], ]);
Money is a string in WooCommerce. The builders' price setters accept a string or a number and stringify it for you (
->regularPrice(19.9)→"19.9").
A variable product carries its variations separately:
use Baldie81\WooCommerceSDK\Support\VariationInput; $parent = $woo->products()->create( ProductInput::make() ->name('T-Shirt')->type(ProductType::Variable) ->attribute('Color', ['Red', 'Blue'], variation: true) ->attribute('Size', ['S', 'M', 'L'], variation: true) ); $variations = $woo->products()->variations($parent['id']); $variations->create( VariationInput::make() ->sku('TS-RED-M')->regularPrice('24.90') ->attribute('Color', 'Red')->attribute('Size', 'M') ->manageStock(true)->stockQuantity(10) );
Orders
use Baldie81\WooCommerceSDK\Support\OrderInput; use Baldie81\WooCommerceSDK\Support\Address; use Baldie81\WooCommerceSDK\Support\LineItem; use Baldie81\WooCommerceSDK\Enum\OrderStatus; $order = $woo->orders()->create( OrderInput::make() ->status(OrderStatus::Processing)->setPaid(true) ->paymentMethod('bacs', 'Direct bank transfer') ->billing( Address::make()->name('Jane', 'Doe') ->line1('1 High St')->city('London')->postcode('EC1A 1AA')->country('GB') ->email('jane@example.com') ) ->lineItem(LineItem::make()->product(93)->quantity(2)) ->shippingLine('flat_rate', 'Flat rate', '5.00') ->couponLine('SAVE10') ); $woo->orders()->setStatus($order['id'], OrderStatus::Completed); // Notes and refunds hang off an order id: $woo->orders()->notes($order['id'])->create('Picked & packed', customerNote: false); $woo->orders()->refunds($order['id'])->refundAmount('12.50', 'Damaged item');
Listing & pagination
Build list queries with Query; list() returns one page, all() walks every
page for you.
WooCommerce reports totals in the X-WP-Total / X-WP-TotalPages response
headers (not the body) and caps per_page at 100. all() reads those headers
and paginates until the last page, so you never silently truncate a large result
set:
use Baldie81\WooCommerceSDK\Support\Query; use Baldie81\WooCommerceSDK\Enum\ProductStatus; // One page: $page = $woo->products()->list( Query::create()->search('shirt')->status(ProductStatus::Publish)->perPage(50) ); // Every matching record, across all pages: $everything = $woo->products()->all( Query::create()->after('2026-01-01T00:00:00')->orderBy('date', 'desc') ); // Direct look-ups by natural key: $bySku = $woo->products()->bySku('SKU-123'); // ?array $byEmail = $woo->customers()->byEmail('jane@example.com'); $byCode = $woo->coupons()->byCode('SAVE10');
Batch API
Most collections expose a /batch endpoint that creates, updates and deletes in
one round-trip. BatchPayload builds it; the SDK splits payloads larger than
WooCommerce's 100-operation limit into several requests and merges the results:
use Baldie81\WooCommerceSDK\Support\BatchPayload; use Baldie81\WooCommerceSDK\Support\ProductInput; $result = $woo->products()->batch( BatchPayload::make() ->create(ProductInput::make()->name('A')->sku('A-1')->regularPrice('5')) ->update(ProductInput::make()->id(42)->regularPrice('9.99')) ->delete(43, 44) ); // $result['create'], $result['update'], $result['delete']
Deleting
delete() permanently deletes by default (force: true) — required for
resources that can't be trashed (customers, webhooks) and usually what an
integration wants. Pass force: false to move a product/order to the trash
instead:
$woo->products()->delete(123); // permanent $woo->orders()->delete(456, force: false); // trashed
Errors
Every failure is a WooCommerceException. Two concrete types:
ApiException— WooCommerce returned a 4xx/5xx. Carries the HTTPstatusCode, the machineerrorCode(e.g.woocommerce_rest_product_invalid_id), the parseddata, and therawBody.TransportException— no usable HTTP response (DNS, connection, timeout, TLS).
use Baldie81\WooCommerceSDK\Exception\ApiException; use Baldie81\WooCommerceSDK\Exception\TransportException; try { $woo->products()->get(999999); } catch (ApiException $e) { if ($e->statusCode === 404) { // not found — $e->errorCode is "woocommerce_rest_product_invalid_id" } } catch (TransportException $e) { // network-level failure, safe to retry }
Custom transport
Need retries, logging or your own middleware? Build a Guzzle client yourself and
hand it over — its base_uri must point at the store root and the API prefix is
prepended to every path:
use Baldie81\WooCommerceSDK\WooCommerceClient; $woo = WooCommerceClient::fromGuzzle($myGuzzleClient, 'wp-json/wc/v3/');
Examples
Copy-pasteable usage lives in examples/ — one class per area,
each method demonstrating a single operation against the real API. Build a client
with ExampleClient::create() (edit its dummy placeholder credentials first —
never commit real keys), then call a class, e.g.
(new ProductExamples($woo))->create().
- ProductExamples — create / update / status / delete / get / by-SKU / list / paginate
- VariationExamples — variable parent, add variations, bulk-create the matrix
- CategoryExamples — categories (nesting, tree) and tags
- AttributeExamples — global attributes and their terms (single & batch)
- OrderExamples — create, set status, search, notes, refunds
- CustomerExamples — CRUD, by-email, idempotent upsert
- CouponExamples — percentage & fixed-cart coupons, by-code
- TaxExamples — tax classes and rates
- ShippingExamples — zones, locations, flat-rate & free-shipping methods
- WebhookExamples — register / pause / list / delete webhooks
- BatchExamples — mixed create/update/delete, large auto-chunked imports
- StoreConfigExamples — payment gateways, settings, system status & tools
Testing
composer test
The suite drives the client against a Guzzle MockHandler, so it makes no real
HTTP calls.
License
MIT — see LICENSE.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-30