# WooCommerce

Install and configure the punchout.dev plugin for WordPress and WooCommerce, with the block cart, auto-login and why administrator accounts are never signed in.

URL: https://punchout.dev/docs/plugins/woocommerce/

The punchout.dev plugin for WooCommerce prints the script tag, marks the block cart and the classic cart for punchout.dev and signs punchout buyers in to their WordPress account.

## Requirements

| Requirement | Value |
| --- | --- |
| PHP | 8.1 or later, with `sodium` |
| WordPress | 6.5 or later |
| WooCommerce | 8.0 or later |
| Plugin | `punchout-dev`, version 2.0.0, no Composer dependencies |
| Download | `punchout-dev-<version>.zip` from the shop's **Embed** tab in the portal (Shop platform: WooCommerce) |

## Install

1. Download the plugin from the portal's **Embed** tab.
2. In the WordPress admin, open **Plugins**, add a new plugin with **Upload Plugin**, choose the zip, then install and activate it.

Alternatively, unzip it into `wp-content/plugins`, which creates `wp-content/plugins/punchout-dev`, and activate it in the plugin list.

Activation creates one table for single-use login tokens and two options, `punchout_dev_settings` and `punchout_dev_db_version`. Deactivating the plugin keeps them; deleting it removes all three.

## Configure

Open **WooCommerce → punchout.dev**. The page needs the `manage_options` capability.

| Setting | Value |
| --- | --- |
| Embed the snippet | On (default). Off prints no script tag. |
| Snippet URL | `https://js.punchout.dev/pob.js`, from the portal's Embed tab. Empty prints nothing. |
| API base URL (optional) | Leave empty. |
| Enable auto-login | On (default). |
| Shop ID | The **Shop ID** from the portal's Embed tab. Also printed as `data-shop-id` on the script tag. |
| Public key lines | Every line from the portal's Auto-login tab, section **Public keys**, one per line. Lines starting with `#` and blank lines are ignored. |

The page's **Auto-login** section shows three status lines:

- **Login path (enter it on the portal's Auto-login tab)**: the exact REST path of this install, sub-directory included.
- **Configured key ids**: the keys the plugin could read from **Public key lines**, or "none" when every login would fall back to a guest punchout.
- **Single-use token table**: present, or MISSING. If it is missing, deactivate and activate the plugin once.

The script tag goes into the footer of every storefront page (`wp_footer`).

## What the plugin marks

| Cart | How it is marked |
| --- | --- |
| Block cart (`woocommerce/cart`) | The whole block is wrapped in `<div data-punchout-cart>` |
| Classic cart (`[woocommerce_cart]` shortcode) | The cart table is wrapped: line items and their column header. The cart totals and the checkout button stay outside. |

The mini cart, the checkout and the order-received page are never marked.

### The block cart renders in the browser

The block cart arrives as an empty shell, and WooCommerce fills in the line items with JavaScript after the page has loaded. The script tag waits until the cart has finished loading before it reads it, both in a punchout and in setup mode. An empty cart is a normal state.

## Auto-login

The plugin registers the REST route `GET /wp-json/punchout-dev/v1/login?token=…`. An install in a sub-directory prefixes its own path, for example `/shop/wp-json/punchout-dev/v1/login`. The settings page prints the exact path.

Set up the portal side on the shop's **Auto-login** tab:

| Portal field | Value |
| --- | --- |
| Adapter | WooCommerce |
| Login path | The path from the plugin's settings page |
| Customer reference | See the table below |

WooCommerce has no customer number of its own. The three kinds map like this:

| Customer reference | Matched against |
| --- | --- |
| Email address (recommended) | The WordPress user's email address |
| Customer number | The WordPress **login name** |
| Customer ID | The numeric WordPress user ID |

Then give each buyer credential its **Shop customer reference** on the **Buyers** tab.

:::caution
An administrator is never signed in this way. A WordPress user with the `manage_options` capability is refused (reason `administrator_refused`) and gets a guest punchout. If your buyer's account is an administrator, create an ordinary customer account for the punchout.
:::

On success the plugin sets the WordPress login and fires `wp_login`, which is how WooCommerce merges the guest cart into the customer's saved cart. Every failure redirects to the landing page as a guest, never to an error page and never to `wp-login.php`.

The plugin redirects to the landing path as it is, without adding the sub-directory. Set the **Landing path** on the General tab to the full cart path, for example `/cart/`, or `/shop/cart/` in a sub-directory install.

The full flow is on the [Auto-login](https://punchout.dev/docs/plugins/auto-login/) page.

## Setup self-test

1. On the shop's **Setup** tab in the portal, create a setup link (valid 60 minutes by default).
2. Put 2 or 3 different products in the cart.
3. Open the cart page with the setup link and click **Detect cart**.

With the plugin in place, the result names the source **Shop plugin**. Confirm with **Yes, that's it**. This proves that the marker and the Shop ID are right, and it completes the **Cart detected** step in the portal.

## Update

Download the new zip from the Embed tab, upload it as you did for the install and let WordPress replace the installed version. If you unzip it over the old folder instead, WordPress skips the activation step. In that case the plugin checks its stored table version on the next request and creates the table itself if the version has changed. The settings page shows whether the table is there.

### Coming from punchout-ninja 1.x

WordPress installs 2.0.0 as a new plugin: deactivate and delete the old `punchout-ninja` plugin first, and never run both. Enter the settings again from the portal and change the **Login path** on the portal's Auto-login tab to `/wp-json/punchout-dev/v1/login`, with the sub-directory prefix if there is one.

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| The setup panel reports **Preset** instead of **Shop plugin** | The cart page uses neither the Cart block nor the `[woocommerce_cart]` shortcode, or a page cache serves an older copy | Use the Cart block or the shortcode, and clear the page cache |
| Auto-login does nothing and the buyer shops as a guest | **Enable auto-login** is off, or the Shop ID or the Public key lines are wrong | Compare **Configured key ids** with the portal's Public keys and the Shop ID with the Embed tab |
| The buyer lands on an error page instead of the shop | The portal's **Login path** does not match the route, for example the sub-directory is missing | Copy the login path from the settings page to the portal's Auto-login tab |
| **Single-use token table** shows MISSING | The activation step did not run | Deactivate and activate the plugin once |
| The buyer is a guest although the mapping is right | The mapped user is an administrator | Map the credential to an ordinary customer account |

The plugin writes one line per refused login token to the PHP error log, with a reason word, and only when `WP_DEBUG` is on. It never logs the token or the customer. The reason words are listed on the [Auto-login](https://punchout.dev/docs/plugins/auto-login/) page.

For more, see [Troubleshooting](https://punchout.dev/docs/troubleshooting/).

## Full README

The plugin's README covers the token checks, the security notes and the development self-test: [WooCommerce plugin README](https://punchout.dev/docs/plugins/woocommerce/readme/).
