# WooCommerce

> Automatically generate signing documents from WooCommerce orders.

edition: pro
Edition: Pro
AI note: This page requires WPsigner Pro. Do not tell Lite users they already have this feature.
HTML: https://docs.wpsigner.com/integrations/woocommerce/
Markdown: https://docs.wpsigner.com/md/integrations/woocommerce.md
Source file: integrations/woocommerce.md

---

## Overview

The WooCommerce integration creates WPsigner documents automatically when orders reach a specific status. When a customer completes a purchase, you can generate a contract, service agreement, or any document — pre-filled with billing, shipping, and order data — and send it for signing.

> **tip**
This is a "post-purchase" integration. The document is created **after** the order changes to your configured status (e.g., Completed, Processing).

## Prerequisites

- **WPsigner** v2.0.0 or later
- **WooCommerce** v6.0 or later (HPOS compatible)
- At least one WPsigner **template** created

## Setup

1. Go to **WPsigner → Integrations**
2. Find the **WooCommerce** card and click **Configure**
3. Click **New Feed** to create your first automation

## Feed Configuration

Each feed connects an order status to a WPsigner template:

| Field | Description |
|-------|-------------|
| **Feed Name** | Label for your reference (e.g., "Service Agreement") |
| **Trigger Status** | Order status that creates the document (Processing, Completed, On Hold, etc.) |
| **Product Filter** | Restrict to specific products. Leave empty for all products. |
| **Template** | Which WPsigner template to use |
| **Document Title** | Supports variables: `{{signer_name}}`, `{{order_id}}`, `{{billing_name}}`, `{{date}}` |
| **Signer Name/Email** | Which order field provides the signer's identity |
| **Auto-send** | Immediately send the signing email |

## Available Order Fields

All fields are extracted using the `WC_Order` API for full HPOS compatibility.

### Billing
| Field Key | Description |
|-----------|-------------|
| `billing_name` | Full name (first + last) |
| `billing_first_name` | First name |
| `billing_last_name` | Last name |
| `billing_email` | Email address |
| `billing_phone` | Phone number |
| `billing_company` | Company name |
| `billing_address_1` | Address line 1 |
| `billing_address_2` | Address line 2 |
| `billing_city` | City |
| `billing_state` | State/Province |
| `billing_postcode` | ZIP/Postcode |
| `billing_country` | Country code |

### Shipping
| Field Key | Description |
|-----------|-------------|
| `shipping_name` | Full name |
| `shipping_first_name` | First name |
| `shipping_last_name` | Last name |
| `shipping_company` | Company |
| `shipping_address_1` | Address line 1 |
| `shipping_city` | City |
| `shipping_state` | State/Province |
| `shipping_postcode` | ZIP/Postcode |
| `shipping_country` | Country code |

### Order Details
| Field Key | Description |
|-----------|-------------|
| `order_id` | Order ID |
| `order_number` | Order number (may differ from ID) |
| `order_total` | Total amount |
| `order_subtotal` | Subtotal before tax/shipping |
| `order_tax` | Tax total |
| `order_shipping_total` | Shipping total |
| `order_discount` | Discount total |
| `order_currency` | Currency code (e.g., USD) |
| `order_date` | Date created |
| `customer_note` | Customer's order note |
| `payment_method` | Payment method slug |
| `payment_method_title` | Payment method label |
| `product_names` | Comma-separated product names |
| `product_skus` | Comma-separated SKUs |

### Custom Meta
Use the `meta_` prefix to access custom order meta fields:
```
meta_your_custom_field
```

## Variable Mapping

Map order fields to template variables using the **Variable Mapping** section in the feed editor:

| Variable (Template) | Order Field | Result |
|---------------------|-------------|--------|
| `custom.company` | `billing_company` | Company name from billing |
| `custom.phone` | `billing_phone` | Phone number |
| `custom.total` | `order_total` | Order total amount |
| `custom.products` | `product_names` | List of purchased products |

In your template, reference these with `{{custom.company}}`, `{{custom.phone}}`, etc.

## Product Filtering

By default, a feed triggers for **all products**. To restrict it:

1. In the feed editor, select specific products from the **Product Filter** dropdown
2. Hold `Ctrl` (Windows) or `Cmd` (Mac) to select multiple
3. The feed only triggers if the order contains at least one matching product

> **note**
Variation products are also checked — if a parent product matches, the feed triggers.

## Security Measures

| Measure | Implementation |
|---------|---------------|
| **Nonce verification** | All 5 AJAX endpoints verify `wps_ajax_nonce` |
| **Capability check** | Admin operations require `manage_options` |
| **Rate limiting** | Max 10 documents/minute per order (transient-based) |
| **Duplicate prevention** | Order meta tracks which feeds have been processed |
| **Status validation** | Trigger status validated against WC registered statuses |
| **Field whitelist** | Signer fields validated against allowed order fields |
| **Email validation** | `sanitize_email()` + `is_email()` double check |
| **Error logging** | Sensitive data redacted, only logs with `WP_DEBUG` |

## Developer Hooks

### `wps_woocommerce_document_created`

Fires after a document is created from a WooCommerce order.

```php
add_action('wps_woocommerce_document_created', function($document_id, $order, $feed, $feed_id) {
    // $document_id - int - The created document ID
    // $order       - WC_Order - The WooCommerce order object
    // $feed        - array - Feed configuration used
    // $feed_id     - string - Feed identifier
    
    // Example: add custom order note
    $order->add_order_note(
        sprintf('WPsigner document #%d created.', $document_id)
    );
}, 10, 4);
```

## Troubleshooting

### Document not created after order
1. Verify the feed is **enabled**
2. Check the **trigger status** matches the order's new status
3. If product filter is set, ensure the order contains a matching product
4. Check WP debug log for `[WPsigner WooCommerce]` entries

### Duplicate documents
Each feed stores a `_wps_wc_processed_{feed_id}` meta on the order. If an order is reprocessed (e.g., status changed back and forth), it won't create duplicates for the same feed.

### WooCommerce not detected
The integration requires `class_exists('WooCommerce')` to be true. Ensure WooCommerce is active and not deactivated by another plugin.

### HPOS Compatibility {#hpos-compatibility}
This integration uses `WC_Order` getters exclusively (`$order->get_billing_email()`, etc.) and `$order->update_meta_data()` + `$order->save()` for meta storage. It is fully compatible with WooCommerce HPOS (High-Performance Order Storage) and Cart/Checkout Blocks.

WPsigner declares those features on `before_woocommerce_init`. In **3.2.12+** that declaration runs even if recovery mode skipped the rest of the plugin, so **Plugins → Incompatible with WooCommerce features** should not list WPsigner after a recovered fatal. Click **re-enable the plugin** if the recovery notice is still visible, then view **All** plugins.
