Skip to content

Import & export (CSV) ​

Ambikly moves products and orders in and out as CSV. Exports stream row by row, so a catalog with tens of thousands of products does not exhaust memory on a shared host. Imports read one row at a time and report the outcome of each.

Finding the Tools screen ​

Careful: Tools is not in the sidebar. Open it with the wrench icon in the top header of any Ambikly admin screen, next to the theme toggle.

Ambikly → Tools holds four cards:

CardWhat it does
Export productsDownloads a product CSV, optionally filtered.
Export ordersDownloads an order CSV for a date range.
Import productsUploads a product CSV and reports per-row results.
System statusDiagnostic JSON you can copy into a support ticket. See System status.

All four import and export routes require full WordPress administrator access (manage_options). A Store Manager cannot reach them. See Roles & permissions.

Exporting products ​

  1. Open Ambikly → Tools with the wrench icon.
  2. On the Export products card, pick a Status and a Type, or leave both at All.
  3. Click Download products CSV.

The file is named ambikly-products-YYYY-MM-DD.csv, starts with a UTF-8 byte-order mark so Excel reads it correctly, and is streamed in batches of 500 rows ordered by ID.

FilterValuesMatches on
StatusAll, Published, DraftThe status column
TypeAny, Physical, Digital, Variable, External, Bundle, SubscriptionThe type column — except Variable, which matches sub_type = variable

Variable is handled separately because variable is not a value of the type column: a product with variants is stored as type = physical, sub_type = variable.

External, Bundle and Subscription match the type column directly. Those rows only exist if they were created by import or through the API — see Products.

Exporting a selection ​

The Products screen exports too. Set your filters there and click Export to export what matches, or tick specific rows and click Export Selected to export exactly those IDs. Both open the same endpoint with an ids parameter.

Exporting orders ​

  1. On the Export orders card, set From and To, or leave them blank for everything.
  2. Click Download orders CSV.

The file is ambikly-orders-YYYY-MM-DD.csv, streamed in batches of 200. The From date is sent as 00:00:00 and the To date as 23:59:59, so both ends are inclusive.

The order export carries 30 columns:

order_number, created_at, status, payment_status, customer_email, customer_phone, subtotal, discount_total, shipping_total, tax_total, total, currency, payment_method, then the billing block (billing_first_name, billing_last_name, billing_company, billing_address_1, billing_address_2, billing_city, billing_state, billing_postcode, billing_country), a shorter shipping block (shipping_first_name, shipping_last_name, shipping_address_1, shipping_city, shipping_state, shipping_postcode, shipping_country) and items.

items is a flattened summary, one entry per line item joined with |:

2x Blue Hoodie @ 49.00 | 1x Sticker Pack @ 6.00

Every field that traces back to a public checkout form — names, company, addresses, email, phone and item names — is protected against CSV formula injection: a value starting with =, +, -, @, a tab or a carriage return is prefixed with a single quote so a spreadsheet treats it as text. Server-generated fields such as totals and order numbers are written as-is.

There is no order import.

Importing products ​

  1. On the Import products card, click Download template to get a header-only CSV with every supported column in the right order.
  2. Fill it in, or start from an export of your existing catalog.
  3. Choose the file and click Import.
  4. Read the result line: rows processed, created, updated, and errors.

The file must be UTF-8 CSV. The first row is the header. Upload happens as multipart form data with the field name file.

The update rule ​

For each row, Ambikly decides between create and update like this:

  1. If the row's sku cell is not empty, look for an existing product with that exact SKU. A match is an update.
  2. Otherwise, look for an existing product whose slug matches the row's slug — or, when slug is empty, the slugified name. A match is an update.
  3. No match is a create. The slug is made unique by appending -1, -2, and created_at / updated_at are stamped.
Careful: an update writes every one of the 32 mapped columns, not just the ones you changed. An empty cell is written as empty or null, so a hand-built CSV with a few columns filled in will clear the rest. Always start from an export or the downloaded template, and keep every column.
Careful: the importer reads several columns without first checking that they exist in your header row. A CSV that leaves out category_id, weight, length, width, height, download_limit, download_expiry_days, button_text or billing_cycle can write 0 into those columns rather than leaving them alone. Use the full template.

Unlike the REST API, the importer does not auto-generate a SKU for a new product with a blank sku cell, and it does not reject a negative price or a sale price that is not lower than the regular price. Validate your spreadsheet before uploading.

The product CSV columns ​

These are the 32 columns of productHeaders(), in the exact order the export and the template emit them.

#ColumnExpectsNotes
1skuTextThe match key for updates. Must be unique across products. Blank on a new row stays blank.
2nameTextRequired. A row with an empty name is skipped with an error.
3slugTextFalls back to a slugified name. Made unique on create only.
4typeOne of physical, digital, external, grouped, bundle, subscriptionAnything else silently becomes physical.
5sub_typeTextEmpty becomes simple. In practice simple or variable. Not validated.
6statusOne of published, draft, trashAnything else silently becomes published.
7category_idIntegerThe numeric ID of an existing category. Not validated — a wrong ID is stored as-is.
8priceDecimalEmpty becomes 0. Negative values are not rejected here.
9sale_priceDecimalEmpty becomes null. Not validated against price.
10stock_quantityIntegerEmpty becomes 0.
11stock_statusinstock, outofstock or onbackorderEmpty becomes instock. Not validated.
12manage_stock1 / 0Empty becomes 1. Any truthy value becomes 1.
13weightDecimalEmpty becomes null. Units are whatever you decide — see Products.
14lengthDecimalEmpty becomes null.
15widthDecimalEmpty becomes null.
16heightDecimalEmpty becomes null.
17short_descriptionPlain textSanitized as a textarea — HTML is stripped.
18descriptionHTMLSanitized with wp_kses_post, so post-safe HTML survives.
19imageURLThe main product image. Run through esc_url_raw.
20galleryJSON array of URLs, or a comma-separated listEach entry is URL-sanitized; anything that is not a URL is dropped. Stored as a JSON array.
21featured1 / 0Empty becomes 0.
22is_downloadable1 / 0Empty becomes 0 — note this differs from the API, which defaults digital products to 1.
23download_limitIntegerEmpty becomes null, meaning unlimited.
24download_expiry_daysIntegerEmpty becomes null, meaning no expiry.
25tax_classTextEmpty becomes standard.
26tax_statustaxable or noneEmpty becomes taxable.
27external_urlURLOnly meaningful for type = external.
28button_textTextThe buy-button label on an external product. Sanitized.
29billing_perioddaily, weekly, monthly, yearlyLegacy product-level subscription field. Empty becomes null.
30billing_cycleIntegerEmpty becomes 1.
31meta_titleTextUsed as the product page <title>.
32meta_descriptionTextPrinted as the page meta description.

Note what is not in that list: meta_keywords, license_enabled, license_activation_limit, trial_period and subscription_length are all real columns but are neither exported nor imported.

What does not import ​

The product CSV covers the ambikly_products row and nothing else. None of the following are created, updated or removed by an import:

  • Variations and attributes, and their values.
  • Digital pricing plans and downloadable files.
  • Product meta, including the per-product low-stock threshold.
  • Tag and brand assignments. Only category_id on the product row is set.
  • Images beyond storing the URL strings you supply — nothing is side-loaded into the media library.
  • Reviews.
Careful: orders, customers and active subscriptions do not import at all — not from a CSV and not from another plugin. Products import by CSV only. Plan a migration around that: move the catalog, then take orders forward from the switchover date.

Error reporting ​

The result object is { processed, created, updated, errors }. The Tools card prints, for example:

12 rows processed — 9 created, 2 updated, 1 error

with a Show errors disclosure listing each failure as Row {n}: {message}. Row numbers count the header as row 1, so the first data row is row 2.

MessageCause
Empty file. (row 0)No header row could be read.
Column count mismatch.The row has a different number of cells than the header. Usually an unescaped comma or a stray line break inside a cell.
Missing name.The name cell is empty.
A raw database errorThe write failed — a value too long for its column under strict SQL mode, a lock-wait timeout, or a duplicate SKU hitting the unique key.
Any other messageAn exception thrown while processing that row.

A row that fails is counted in processed but not in created or updated. The import continues to the next row; it is not transactional and does not roll back.

The routes ​

MethodRoutePermission
GET/ambikly/v1/export/productsmanage_options
GET/ambikly/v1/export/ordersmanage_options
POST/ambikly/v1/import/productsmanage_options
GET/ambikly/v1/import/products/templatemanage_options

export/products accepts status, type and ids (a comma-separated list). export/orders accepts status, date_from and date_to. import/products takes a multipart upload with the field name file.

Both export routes stream directly to the response with Content-Type: text/csv and a Content-Disposition attachment header, then exit — they do not return the usual JSON envelope.

WP-CLI ​

Exports are also available on the command line, which is the better option for very large catalogs and for scheduled backups.

bash
wp ambikly export products --status=published > products.csv
wp ambikly export orders --file=orders.csv
CommandOptions
wp ambikly export products--status=, --type=, --file=
wp ambikly export orders--status=, --from=, --to=, --file=
wp ambikly upgrade-db—
wp ambikly recompute customer-totals--id=

Without --file, output goes to stdout so you can redirect or pipe it.

Careful: --from and --to on wp ambikly export orders have no effect. They are passed through under those names, but the export service reads date_from and date_to, so the date range is silently ignored and the whole order table is exported. Use the Tools screen when you need a date range; --status works normally.

There is no wp ambikly import command. Imports go through the Tools screen or POST /import/products.

Full reference: WP-CLI.

A safe round-trip for bulk edits ​

  1. Take a database backup. An import cannot be undone.
  2. Export the products you want to change, using the Status and Type filters or an explicit selection.
  3. Open the file in a spreadsheet. Keep every column and keep the header row exactly as exported.
  4. Edit only the cells you mean to change. Leave sku untouched — it is the match key.
  5. Save as UTF-8 CSV.
  6. Import, then read the created / updated / errors counts before assuming it worked.
  7. Spot-check a few products in Ambikly → Products.
Tip: run bulk stock imports when the store is quiet. An import writes stock_quantity directly and does not go through the oversell-safe adjust path, so an import landing at the same moment as a checkout can overwrite that order's decrement. See Inventory & stock.

Troubleshooting ​

SymptomCause
The Tools screen is nowhere in the sidebarIt is only reachable from the wrench icon in the top header.
"Export products" with Type = Variable produced a header-only fileYou have no products with sub_type = variable.
Type = Bundle or Subscription returned nothingThose type values can only be created by import or the API.
Every row came back Column count mismatch.A cell contains an unescaped comma, quote or line break. Re-export from a spreadsheet that quotes fields properly.
Products imported but fields you did not touch went blankAn update writes all 32 mapped columns. Import a full-width file, not a partial one.
A variable product imported but has no variantsVariations do not import. Re-create them in the product editor or through the API.
Prices imported as negative numbersThe importer does not validate prices. Only the REST API does.
Excel shows mangled accented charactersOpen the file as UTF-8. Ambikly writes a BOM, which most spreadsheet apps honor.
The CLI order export ignored --fromKnown limitation — the flag is not read. Use the Tools screen.

Next ​

  • Reviews — moderation and the public review form.
  • Products — what each column on a product actually does.
  • WP-CLI — the full command reference.