mcpField
W
woocommerce-rest-api

woocommerce-rest-api

github.com/finsilabs開発60106 回インストール5 日前に更新
リポジトリ

woocommerce-rest-api について

WooCommerce の REST API を使った連携開発向けのスキルガイドです。Node.js クライアントによる認証、商品や注文の操作、在庫更新、同期の実践方法を扱います。

主な機能

  1. 01商品、注文、顧客、設定へのアクセス
  2. 02Node.js クライアントでの認証
  3. 03商品検索の絞り込みとページ分割
  4. 04注文作成と在庫更新
  5. 05一括・差分同期の指針

活用シーン

  1. 01ヘッドレスストアやモバイルアプリの構築
  2. 02WooCommerce と ERP、CRM、フルフィルメントシステムの連携
  3. 03倉庫や POS の在庫同期
  4. 04商品一括登録や価格更新

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill woocommerce-rest-api

インストール後、Claude Code で/woocommerce-rest-apiを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

tile.json
evals/bulk-product-sync-with-concurrency-contr/
criteria.json
task.md
evals/order-creation-and-status-management-wit/
criteria.json
task.md
evals/paginated-product-catalog-with-increment/
criteria.json
task.md

詳細

WooCommerce REST API

概要

WooCommerce には、商品、注文、顧客、クーポン、ストア設定を HTTPS 経由で公開する、バージョン管理された REST API(/wp-json/wc/v3/)が用意されています。HTTPS 環境以外では OAuth 1.0a を使用し、HTTPS 経由では Basic Auth(コンシューマーキー/シークレット)を使用します。公式の @woocommerce/woocommerce-rest-api Node.js クライアントは認証を自動的に処理し、CRUD のすべての操作に対応しています。

このスキルを使用する場面

  • WooCommerce から商品やカテゴリーを読み取るヘッドレスストアフロントを構築するとき
  • WooCommerce を ERP、CRM、またはフルフィルメントシステムと連携するとき
  • WordPress Admin の外部で注文管理ダッシュボードを作成するとき
  • WooCommerce と倉庫または POS システム間で在庫を同期するとき
  • 外部カタログからの商品一括インポートや価格更新を自動化するとき
  • WooCommerce ストアのデータにアクセスする必要があるモバイルアプリを構築するとき

主な手順

  1. API 認証情報を生成する

    WordPress Admin → WooCommerce → Settings → Advanced → REST API → Add Key の順に移動します。

    • Description:My Integration
    • User:(管理者ユーザー)
    • Permissions:Read/Write

    コンシューマーキー(ck_xxx)とコンシューマーシークレット(cs_xxx)が生成されます。これらは環境変数に保存し、ソースコードには決して記載しないでください。

    WOOCOMMERCE_URL=https://mystore.com
    WOOCOMMERCE_CONSUMER_KEY=ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    WOOCOMMERCE_CONSUMER_SECRET=cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    
  2. Node.js クライアントをセットアップする

    npm install @woocommerce/woocommerce-rest-api
    
    // lib/woocommerce.ts
    import WooCommerceRestApi from "@woocommerce/woocommerce-rest-api";
    
    export const woo = new WooCommerceRestApi({
      url: process.env.WOOCOMMERCE_URL!,
      consumerKey: process.env.WOOCOMMERCE_CONSUMER_KEY!,
      consumerSecret: process.env.WOOCOMMERCE_CONSUMER_SECRET!,
      version: "wc/v3",
      axiosConfig: {
        timeout: 15000,
      },
    });
    
  3. フィルタリングとページネーションを使用して商品をクエリする

    // lib/products.ts
    interface ProductQuery {
      page?: number;
      perPage?: number;
      category?: number;
      status?: "publish" | "draft" | "private";
      stockStatus?: "instock" | "outofstock" | "onbackorder";
      orderby?: "date" | "popularity" | "price" | "title";
    }
    
    export async function getProducts(params: ProductQuery = {}) {
      const response = await woo.get("products", {
        page: params.page ?? 1,
        per_page: params.perPage ?? 20,
        status: params.status ?? "publish",
        stock_status: params.stockStatus,
        orderby: params.orderby ?? "date",
        category: params.category,
      });
    
      return {
        products: response.data,
        totalPages: parseInt(response.headers["x-wp-totalpages"]),
        totalProducts: parseInt(response.headers["x-wp-total"]),
      };
    }
    
    export async function getProductById(id: number) {
      const response = await woo.get(`products/${id}`);
      return response.data;
    }
    
    // Get product variations
    export async function getProductVariations(productId: number) {
      const response = await woo.get(`products/${productId}/variations`, {
        per_page: 100,
      });
      return response.data;
    }
    
  4. 注文を作成、管理する

    // lib/orders.ts
    interface OrderLineItem {
      product_id: number;
      variation_id?: number;
      quantity: number;
    }
    
    interface CreateOrderParams {
      billing: {
        first_name: string;
        last_name: string;
        email: string;
        address_1: string;
        city: string;
        postcode: string;
        country: string;
      };
      line_items: OrderLineItem[];
      payment_method?: string;
    }
    
    export async function createOrder(params: CreateOrderParams) {
      const response = await woo.post("orders", {
        ...params,
        status: "pending",
        payment_method: params.payment_method ?? "stripe",
        payment_method_title: "Credit Card",
        set_paid: false,
      });
      return response.data;
    }
    
    export async function updateOrderStatus(
      orderId: number,
      status: "pending" | "processing" | "on-hold" | "completed" | "cancelled" | "refunded",
      note?: string
    ) {
      const updateData: any = { status };
      if (note) {
        // Add an order note
        await woo.post(`orders/${orderId}/notes`, { note });
      }
      const response = await woo.put(`orders/${orderId}`, updateData);
      return response.data;
    }
    
    export async function getOrders(params: {
      status?: string;
      after?: string; // ISO 8601 date
      page?: number;
    } = {}) {
      const response = await woo.get("orders", {
        status: params.status ?? "processing",
        after: params.after,
        per_page: 50,
        page: params.page ?? 1,
      });
      return {
        orders: response.data,
        totalPages: parseInt(response.headers["x-wp-totalpages"]),
      };
    }
    
  5. 在庫と商品情報を管理する

    // Update stock quantity for a product or variation
    export async function updateStock(productId: number, quantity: number, variationId?: number) {
      const endpoint = variationId
        ? `products/${productId}/variations/${variationId}`
        : `products/${productId}`;
    
      const response = await woo.put(endpoint, {
        stock_quantity: quantity,
        manage_stock: true,
      });
      return response.data;
    }
    
    // Batch update products (up to 100 per request)
    export async function batchUpdateProducts(
      updates: Array<{ id: number; regular_price?: string; stock_quantity?: number; status?: string }>
    ) {
      const response = await woo.post("products/batch", { update: updates });
      return response.data;
    }
    

使用例

外部カタログから商品をすべて同期する
import pLimit from "p-limit";

export async function syncProductsFromCatalog(
  externalProducts: Array<{ sku: string; price: number; stock: number }>
) {
  const limit = pLimit(5); // Max 5 concurrent API calls

  const results = await Promise.allSettled(
    externalProducts.map((ext) =>
      limit(async () => {
        // Look up WooCommerce product by SKU
        const searchResponse = await woo.get("products", { sku: ext.sku });
        const existing = searchResponse.data[0];

        if (existing) {
          // Update existing product
          return woo.put(`products/${existing.id}`, {
            regular_price: ext.price.toFixed(2),
            stock_quantity: ext.stock,
            manage_stock: true,
          });
        } else {
          console.warn(`SKU not found in WooCommerce: ${ext.sku}`);
          return null;
        }
      })
    )
  );

  const failed = results.filter((r) => r.status === "rejected");
  if (failed.length > 0) {
    console.error(`${failed.length} products failed to sync`);
  }

  return results;
}
顧客管理
// Create or update customer
export async function upsertCustomer(email: string, data: Record<string, any>) {
  const searchResponse = await woo.get("customers", { email });
  const existing = searchResponse.data[0];

  if (existing) {
    const response = await woo.put(`customers/${existing.id}`, data);
    return response.data;
  } else {
    const response = await woo.post("customers", { email, ...data });
    return response.data;
  }
}

// Get customer order history
export async function getCustomerOrders(customerId: number) {
  const response = await woo.get("orders", {
    customer: customerId,
    per_page: 50,
    orderby: "date",
    order: "desc",
  });
  return response.data;
}

ベストプラクティス

  • 常に HTTPS を使用する — OAuth 1.0a は HTTP 経由でも動作しますが、リクエストごとに認証情報が送信されます。サーバー間通信には、HTTPS と Basic Auth の組み合わせがよりシンプルで安全です
  • レート制限を考慮する — WordPress はデフォルトでは API のレート制限を適用しませんが、リクエスト量が多いと PHP-FPM や MySQL が枯渇する可能性があります。一括処理には p-limit またはキューを使用してください
  • 一括更新にはバッチエンドポイントを使用する — /products/batch は、個別に 100 件リクエストする代わりに、1 回のリクエストで最大 100 件の作成/更新/削除操作を受け付けます
  • _fields パラメーターでフィールドを絞り込む — ?_fields=id,name,price,stock_quantity を指定すると、大量の商品リストのレスポンスサイズを大幅に削減できます
  • WooCommerce 固有のエラーコードを処理する — API はエラーボディに rest_invalid_param、woocommerce_rest_cannot_create などを返します。特定のエラーを処理するには、response.data.code を解析してください
  • 差分同期には after と before の日付フィルターを使用する — 最後の同期以降に更新された注文や商品を ISO 8601 タイムスタンプで絞り込むことで、カタログ全体の再スキャンを避けられます
  • 末尾のスラッシュを付けずに API URL を保存する — WooCommerce クライアントが URL の構築を処理します。ベース URL の末尾にスラッシュがあると、エンドポイントにスラッシュが重複します

よくある問題

問題解決策
キーが正しいのに 401 Unauthorized が発生するサイトで HTTPS が使用されていることを確認してください。HTTP 経由ではクライアントは Basic Auth ではなく OAuth 1.0a を使用する必要があります。クライアント設定で isHttps: false を指定してください
商品エンドポイントが空の配列を返すAPI キーに割り当てられたユーザーに適切な権限があることを確認してください。デフォルトでは woocommerce_manage_products 権限が必要です
商品 ID エラーで注文の作成に失敗するバリエーション商品では line_items に variation_id が必要です。バリエーション商品に product_id だけを渡すと、invalid_variation エラーが発生します
ページネーションヘッダーがないx-wp-total と x-wp-totalpages ヘッダーはリストエンドポイントにのみ含まれ、単一リソースのエンドポイントには含まれません
バッチ操作の一部が失敗するバッチレスポンスには各項目のエラーが含まれます。response.data.update 配列を反復処理し、各項目に error プロパティがあるか確認してください
商品リストのレスポンスが遅い?_fields=id,name,price を追加してレスポンスサイズを削減してください。また、WordPress サーバーで永続オブジェクトキャッシュ(Redis)を有効にすることも検討してください

Related Skills

  • @woocommerce-plugin-development
  • @woocommerce-subscriptions
  • @woocommerce-performance
  • @headless-commerce-architecture
  • @rest-api-design

コメント