The Atria Connector - your shop floor and your website, in sync.
A two-way bridge between a store's in-store Atria POS and its WooCommerce website. Products flow out to the web, online orders and customers flow back to the counter, fulfilment status syncs automatically, and a full loyalty program ties in-store and online shopping together with one barcode.
×
· built by eux.


One connector. Two systems. Data moving both ways.
The plugin lives inside WordPress and brokers every exchange between Atria and WooCommerce - so staff work in one system and customers shop in another, without anyone re-keying data.
Atria ↔ WooCommerce
Two-way sync

x-api-client
x-api-key
· ODATA QUERY SYNTAX
Four jobs, one plugin.
Product Sync
The in-store catalogue - prices, descriptions, stock, images and weights - becomes the online shop automatically.
View detailsOrder & Customer Sync
Every online order and customer is pushed into Atria. Mark it “Filled” in-store and the website order completes itself.
View detailsLoyalty Program
1 point per $1 - online or in-store. One barcode by email & SMS, a live balance and ledger, and redemption at checkout.
View detailsAdmin Control Centre
Sandbox/production credentials, a Test Connection button, one-click bulk import with live progress, and a searchable sync log.
View detailsWhere your team sets it up: the E-commerce tab.
Everything online starts in Atria Manager. Product Editing has an E-commerce tab - tick “Send to E-commerce”, choose how the item should appear, and it syncs to the website. These are real screens from the Atria Manager guide.
g or kg; appends to the description and price.Status - control availability without deleting
The Status field decides how (or whether) the product shows online. Change the status in Atria rather than unticking “Send to E-commerce”.
Active
Ready to sell online and available to customers.
Active / No Stock
Shows online but marked “Sold out / Out of stock”.
Archived
No longer sold - removed from the store and unavailable.
Draft
Not ready to sell - hidden and unavailable to customers.
Setup requirements
| Wedderburn side | Needs |
|---|---|
| Atria Manager | Version 9.6 or higher |
| WSAIMSHOP | Atria E-Commerce AIM integration module licence |
| WSMYACCESS | Atria Manager My Access |
| WSMYSHOPIFY | E-Commerce monthly link |
| .NET Desktop Runtime | 8.0.23 x64 |
| EUX side | Needs |
|---|---|
| EUX e-commerce website | The WooCommerce store running the Atria Connector |
| EUX subscription | Active subscription |
From an Atria item to a finished shop page.
Only items flagged IsEcommerce eq true are pulled in. Each field maps to its place on the WooCommerce product - hover or tap a field on the left to see where it lands.
Whatever you sell in store shows up on your website on its own. The name, price and photo are pulled straight from your Atria POS and kept up to date - so you manage everything in one place, and the website just follows along. Here's the live result:

_uom = ea
🔍 Click to enlarge
‘KAIZEN’ MINCE (LIVER/HEART/TESTICLE) 500g
FAITHFUL RECREATION OF THE LIVE PAGE · boococks.com.au/shop/beef/kaizen-mince-liver-heart-testicle-500g · SKU 206 · $10.99 ea · in stock
[ingredients], [storage] and [country_of_origin] shortcodes. Edit a product in Atria Manager and the change syncs straight through - no editing on the website itself.Product-type decision tree
How the connector decides whether to build a simple, variable or variation product.
→ Variation
The item becomes a product variation under its parent, matched by SKU. A weight term like 500 g is created and linked to the parent, then the parent is re-synced.
→ Variable product
A query for items?$filter=ParentPLUCode eq {sku} finds children, so a variable parent is built with a global pa_weight attribute.
→ Simple product Kaizen
A straightforward simple product with one price and unit. Kaizen (PLU 206) is this kind - $10.99 ea. Stock management stays off; everything saves as “in stock”.
How each product type looks to shoppers
Two of the three become shopping pages. A simple product has one fixed price; a variable product lets the customer choose a weight, and the price updates to match. Try the weight selector on the right.

ParentPLUCode and no children - sold as a fixed pack.
pa_weight variations - each weight is its own child item in Atria (ParentPLUCode 188), priced at $37.00/kg.Complete product field map
Every Atria item field and where it lands on the WooCommerce product. Mandatory fields are flagged - an item with no PLUCode is skipped entirely.
| Atria field | WooCommerce destination | Notes |
|---|---|---|
| PLUCode | SKU | Mandatory. Product creation is skipped without it. |
| ParentPLUCode | Product type | If present, the item becomes a variation of that parent (matched by SKU). |
| EcommerceDescription | Product name | Falls back to ItemTexts type 1031 if empty. |
| EcommerceRrpPrice | _regular_price | The RRP. |
| EcommerceUnitPrice | _sale_price & _price | When present, becomes the displayed (active) price. Kaizen has none, so only the regular price shows. |
| EcommerceGroup | Product category & tag | Category is created if it does not exist. Kaizen → BEEF. |
| Inventories[].OnHand | Stock qty (calculated) | Summed, but stock management is off - all products save as “in stock”. |
| IsWeighed | _uom | true → kg, false → ea (each). Kaizen is ea. |
| EcommerceUnitWeight + Uom | _unit_weight_in_kg | If Uom === 6 already kg, else grams ÷ 1000. Defaults to 1 for non-weighed items. |
| ParentConversions[0] | Variation pa_weight term | SubUom 6 = kg else grams. Builds option strings like “500 g” / “1.2 kg”. |
| ItemLabelImages[] · ImageBoxNo 7 | Featured image | Downloaded & sideloaded with the filename prefix atria-sync- (e.g. atria-sync-plu206-7.jpg). |
ItemTexts & the content shortcodes
Atria items carry an ItemTexts array of typed content blocks. These map to product meta, surfaced on the page by three shortcodes.
| Type code | Maps to |
|---|---|
| 1031 | Product name (fallback) |
| 8 | _country_of_origin |
| 1033 | _ingredients |
| 1034 | _storage |
| 10 | Long & short description |
| other | Appended to long description |
| Shortcode | Renders |
|---|---|
| [country_of_origin] | _country_of_origin |
| [ingredients] | _ingredients |
| [storage] | _storage |
view="list" attribute (currently the only view), letting a page builder drop “Country of Origin / Ingredients / Storage” blocks onto the product template with data straight from the POS. The Kaizen page leaves these empty, so only the Reviews and Shipping & Delivery tabs render.One product, a few options - built from a parent & its children.
A drop-down like 2 kg / 4 kg online is three items in Atria: a parent and a child per option. Variant items must be set up as inventory Stock items.

🔍 Click to enlarge
PORK HAND CORNED BONELESS
INTERACTIVE · hover an Atria field on the left to see where it lands · change the weight to watch the price & SKU update
INTERACTIVE · change the weight to watch the price update - one product, a few options
Create the parent item
e.g. PORK HAND CORNED BONELESS. On the Inventory tab set Inventory type = Stock and the unit of measure (kg or each), then Save.
Create a child per option
e.g. …2 kg and …4 kg, each as a Stock item with the right unit of measure.
Point each child at the parent
On each child’s Inventory tab set Parent product = 100 and Parent quantity = its weight (2, then 4). Save - the online drop-down builds itself.
Weighed vs non-weighed items
Weighed items are sold by the kilo in store but as fixed “each” units online, using the nominal unit weight to auto-calculate the price (which you can override). Non-weighed items are sold as each in both places - unit weight doesn’t apply and is disabled in Atria.
One order, from “Place order” to packed and paid.
Staff never re-type a web order. It lands in Atria with the rest of the day's sales - and when it's packed and marked “Filled”, the website finishes the job. Tap a step.
The customer checks out online
On the order-confirmation page, the woocommerce_thankyou hook fires. The connector reads the cart, the customer's details and any pickup/delivery slot, ready to push everything to Atria.
For store staff: picking an online order
Your EUX store takes the order and the payment. To fulfil it, your team works from the EUX admin - no re-keying.
Log on to EUX & open orders
View or print your online orders.
Pick the goods
For items sold by weight, weigh and label them on your store’s weigh-labelling scales so customers can identify bagged products.
Add the picking slip
Include a copy of the EUX picking slip or invoice with the goods.
Store for pickup or delivery
Set the order aside, ready for the customer.
How a customer is matched in Atria
On woocommerce_thankyou, the connector queries GET customers?$filter=Email eq '{billing email}'. An order already carrying atria_synced = yes is skipped.
update. The current AllocationPoints balance is read.create. New ID = highest existing Atria ID + 1.Customer payload → POST/PUT customers
| Atria field | Source |
|---|---|
| id | Matched or newly assigned ID |
| CustomerGroupId | Constant 1 - the “online customer” group |
| Name / LastName | First / last name |
| Billing email | |
| Phone | Shipping phone (delivery) or billing phone |
| Company | Shipping / billing company |
| Address | Object - Street1, Street2, City, State, Postcode |
| Barcode | Loyalty barcode (only if consented) - 983000{id} |
| AllocationPoints | On update: net points change for this order (earned − redeemed); Atria accumulates |
Pickup vs delivery
Order meta written by the EUX Pickup & Delivery plugin is read into the Atria order. Delivery orders use the shipping address & phone; pickup orders use billing details.
| Order meta | Meaning |
|---|---|
| _wpd_type | delivery or pickup → sets Delivered true / false |
| _wpd_delivery_address | street, suburb, state, postcode (delivery) |
| _wpd_date | Date (Y-m-d) of the slot |
| _wpd_time_slot | Slot; pickup start time parsed (e.g. “08:00 - 09:00” → 08:00) → PickupTime |
| _wpd_delivery_instructions | Prepended to the order notes |
Order payload → POST customers/{id}/orders
| Order field | Source |
|---|---|
| CustomerOrderReference | WooCommerce order ID - the key Atria returns to fulfil |
| CreatedBy | Literal "api" |
| Status | 0 (new) |
| Delivered | true / false |
| PickupTime | Slot datetime |
| Notes | Delivery instructions + customer note |
| OrderItems | Array - see right |
| OrderItem field | Source |
|---|---|
| LineNo | Sequential from 1 |
| PluCode | Product SKU |
| AmountUom | 1 if _uom = kg, 2 if ea |
| Amount | _unit_weight_in_kg × qty |
| Comment | Variation summary (e.g. “Weight: 500 g”) |
PluCode: 900001, AmountUom: 2 and Amount = the total discount, which Atria maps to a discount line. Result writes atria_synced = yes/no and a log row (type=order, sync_type=create).Earn in store, earn online - one barcode, one balance.
Customers earn 1 point per dollar wherever they shop, get a personal barcode by email and SMS, watch their balance in My Account, and redeem points as a discount at checkout - 40 points is a dollar off.
Sign up while you shop
A single tick on the checkout page - no separate form.
Apply loyalty credit
What a regular shopper earns
$1 SPENT = 1 POINT · 400 POINTS = $10 REWARD · POINTS NEVER EXPIRE
The rules (constants)
| Constant | Value | Meaning |
|---|---|---|
| AMOUNT_SPENT_TO_LOYALTY_POINTS | 1 | $1 spent = 1 point earned - floor(subtotal / 1) |
| LOYALTY_POINTS_PER_DOLLAR | 40 | 40 points = $1 of redemption (400 = $10 off) |
| BARCODE_PREFIX | 983000 | Barcode = 983000 + Atria customer ID |
| ATRIA_ONLINE_CUSTOMER_GROUP_ID | 1 | Customer group used in Atria |
| ATRIA_LOYALTY_DEPOSIT_FLEX_KEY_ID | 70 | Deposit flex key for redemption (currently unused) |
Two ways to join
Checkout consent checkbox
A “Sign up to our loyalty program” checkbox sits before the Place Order button - default-checked for guests & new users, hidden if already consented. Consent saves to order & user meta (and the WC session via an AJAX handler). On the first consenting order, points are earned, a barcode assigned, and the welcome email + SMS sent (de-duped by loyalty_welcome_sent across user, order & past orders).
From the loyalty page · /my-account/loyalty/
Customers can join any time from their account's Loyalty page - no separate form plugin. On signup, consent is set immediately, then a background job creates a WooCommerce account if needed (emails credentials), creates/updates the Atria customer with a barcode, sends the “🎉 Your Boococks Butchery Loyalty Barcode” email (Code 128 via barcodeapi.org), adds the contact to a TopSMS list and sends a welcome SMS.
The My Account “Loyalty” page - three states
A loyalty endpoint adds a “Loyalty” tab just before Logout. If a customer has no local barcode but exists in Atria (e.g. signed up in store), the page imports their barcode, consent & balance on the spot.
Not a member
Signup pitch, the built-in “Join” form, and the “how it works” footer ($1 = 1 pt, 400 = $10).
Barcode pending
“You’re all signed up!” - the barcode is being generated by the background job and appears shortly.
Member dashboard
Balance, “worth $X”, lifetime/redeemed/this-month stats, the member-card barcode, and the full ledger (All / Earned / Redeemed).
Redeeming at checkout
Shown only to logged-in users whose balance is worth ≥ $1. The “You have $X in loyalty credit (N pts) - apply it?” checkbox triggers a checkout refresh and applies a non-taxable negative fee: “Loyalty credit redeemed −$X”. Redemption is all-or-nothing up to min(balance worth, floor(total)). Order meta records loyalty_redeemed, loyalty_redeemed_points, loyalty_redeemed_dollars.
Earning
Online - floor(subtotal / 1), 1 point per whole dollar, only when consent = yes. In-store - pushed by Atria via the webhook. After checkout, net points (earned − redeemed) sync to Atria in one customer update, the user’s atria_loyalty_points meta is set, and two ledger rows are written - an earn row “Order #N” and, if applicable, a redeem row timestamped +1 second so it sorts after.
The same 983000… barcode at the counter and online.
Everything the store owner touches lives on one screen.
Switch between sandbox and production credentials, test the connection in a click, and run a full catalogue import with a live progress bar. Try the import below.
IsEcommerce item.Settings fields
A top-level Atria Connector admin menu (two submenus - Settings & Logs - both require manage_options). The environment radio toggles which credential block shows.
| Field | Option name | Type | Notes |
|---|---|---|---|
| Environment | atria_environment | radio | sandbox / production · default sandbox |
| Sandbox API URL | atria_sandbox_url | text | Base URL, e.g. https://…/api/ |
| Sandbox Client Id | atria_sandbox_client_id | text | Sent as x-api-client |
| Sandbox Client Key | atria_sandbox_client_key | password | Sent as x-api-key |
| Production API URL | atria_production_url | text | Production base URL |
| Production Client Id | atria_production_client_id | text | - |
| Production Client Key | atria_production_client_key | password | - |
Test Connection
One button per environment. AJAX atria_test_connection performs GET {base}customers - success = HTTP 200. Each attempt is logged to atria_connection_logs (last 10) with timestamp, environment, status (attempting / success / error) and message, rendered in a Connection Logs table.
“Sync now” - full re-import
atria_sync_products first deletes all WooCommerce products with an SKU (force delete), all categories (except Uncategorized), and all previously synced images (atria-sync-). It is a full reset, not an incremental sync.A lock transient atria_sync_in_progress (2-hour expiry) prevents simultaneous runs. Items are fetched via GET items?$filter=IsEcommerce eq true and processed in batches of 100 with a 0.05s delay between items. Live progress is tracked in atria_sync_progress.
The Logs page
A WP_List_Table over wp_atria_sync_logs - searchable, with status views and type / sync-type / date filters. Columns: Type, Reference Key, Sync Type, Status, Date Added, Sync Details (sortable; per-page saved as a screen option, default 10).
| Value | Means |
|---|---|
| Type | product · order · customer |
| Sync Type | create · update · bulk_sync |
| Status | success · failed |
| Reference Key | SKU (products) · order ID (orders) · email (customers) |
Atria can push, too - one endpoint, three jobs.
When something changes in store, Atria POSTs to a single endpoint. The connector looks at which key is in the body and routes it - exactly one key per request. Pick a key to see the request and what happens.
{
"PLUCode": "206",
"EcommerceDescription": "‘KAIZEN’ MINCE…",
"EcommerceRrpPrice": 10.99
}
product_id.none or two and the endpoint returns 400 “one data at a time”.What each key does
| Key in body | Triggers | Behaviour |
|---|---|---|
| PLUCode | Product create / update | Found by SKU → updates name & prices only (200, or 403 if not valid for update). Not found → full create (201 with product_id, or 400). |
| CustomerOrderReference | Order fulfilment | Requires Status = "Filled". Already completed → 200 no-op. Else completes the order - capturing the authorised card via EUX WCPay Auth if active. Not found → 404. |
| In-store loyalty | At least one of Earn/Redeem non-zero. Unregistered email → 200 skipped. Else balance += Earn − Redeem and one ledger row per activity. |
_regular_price (from EcommerceRrpPrice), _sale_price (from EcommerceUnitPrice), _price and the name. For variable products the connector walks the children to find the variation matching the SKU. Inventory updating exists but is commented out - stock stays unmanaged.Integrations & dependencies.
WooCommerce Required
The storefront, orders, customers and checkout the connector reads and writes.
Atria API Required
The POS / ERP backend. Client-id/key headers and OData-style queries.
TopSMS Optional
Welcome SMS and the marketing list when a customer joins the program.
barcodeapi.org
Renders the Code 128 barcode images shown in emails and My Account.
EUX Pickup & Delivery Optional
Supplies the pickup/delivery slot, address and instructions on each order.
EUX Tyro Payments Optional
Take the payment via Tyro at checkout and capture it only when Atria marks the order “Filled”.
Technical reference.
The Atria Connector follows the WordPress Plugin Boilerplate pattern (loader, i18n, admin, public classes). The essentials, at a glance.
x-api-client- client IDx-api-key- client keyContent-Type: application/json- OData query syntax -
$filter $orderby $top $select
- GET items?$filter=IsEcommerce eq true
- GET customers?$filter=Email eq '…'
- POST customers/{id}/orders
- POST /wp-json/atriasync/v1/sync
- 1 pt per $1 spent
- 40 pts = $1 redemption
- 400 pts = $10 reward
- Barcode
983000+ customer ID
Two tables, created on activation.
Complete reference of stored keys
| WordPress option | Purpose |
|---|---|
| atria_environment | sandbox / production |
| atria_sandbox_* / atria_production_* | URL, client id, client key per env |
| atria_connection_logs | Last 10 connection tests |
| atria_sync_progress | Live bulk-sync progress object |
| topsms_access_token / topsms_sender | Read for TopSMS |
| User meta | Purpose |
|---|---|
| customer_loyalty_consent | yes / no |
| loyalty_welcome_sent | yes / no |
| loyalty_barcode | e.g. 98300042 |
| atria_loyalty_points | Current balance |
| Order meta | Purpose |
|---|---|
| atria_synced | yes / no - pushed to Atria |
| customer_loyalty_consent | Consent captured at checkout |
| loyalty_redeemed(_points/_dollars) | Redemption details |
| _wpd_* | Pickup / delivery slot & address |
| Product meta | Purpose |
|---|---|
| _uom | kg or ea |
| _unit_weight_in_kg | Unit weight for order amounts |
| _country_of_origin / _ingredients / _storage | Text, surfaced by shortcodes |
| woodmart_price_unit_of_measure | Display unit of measure (/kg, /ea) |
Hooks registered
| Hook | What it does |
|---|---|
| admin_menu / admin_init | Menu, pages & settings |
| wp_ajax_atria_test_connection | Test the API |
| wp_ajax_atria_sync_products | Bulk import |
| rest_api_init | Registers the atriasync/v1/sync webhook |
| woocommerce_thankyou | Push order / customer / loyalty to Atria |
| woocommerce_checkout_update_order_meta | Save loyalty consent & redemption at checkout |
| loyalty_signup (background job) | Account creation, Atria sync, welcome email/SMS |
| woocommerce_review_order_before_submit | Loyalty consent checkbox |
| woocommerce_review_order_before_payment | Redemption checkbox |
| woocommerce_cart_calculate_fees | Applies the negative redemption fee |
| woocommerce_account_loyalty_endpoint | My Account loyalty tab, endpoint & content |
| add_shortcode ×3 | country_of_origin · ingredients · storage |