Skip to content

Supported fields

Every field Import/export can write, per kind of record.

This list is the floor, not the ceiling. Import/export reads the columns your own tables actually have, so a column another extension added is mappable too — it simply cannot be named here, because it is not in OpenCart's schema. The mapping screen labels those as coming from an extension so you can tell them apart from OpenCart's own.

The type of each column — how long a text field may be, how many decimal places a price keeps, which columns are a yes or a no — is read from your store's own schema rather than fixed here, and a value that does not fit is reported in the plan instead of being written.

A record is not only its own row. The fields of the tables it spans are written in one cell as text: rows separated by |, and the columns of a row by :. A row may stop early and the rest of its columns take their blank. Anything naming another record is given by that record's name, or by #12 to name it by identifier instead.

On a store with more than one language, every field of a table kept per language is offered once per language as name:de-de, with the default language keeping the plain name.

Products

A product is matched on its model, its SKU, or one of its trade identifiers: UPC, EAN, JAN, ISBN or MPN. Two products sharing a model or a SKU resolve to the one with the lowest identifier; a trade identifier more than one product carries is refused as a row error instead, because OpenCart 4.1 copies a product's identifiers into every variant made from it. A mirroring job never sweeps a product whose match value is blank. model is the one field a new product cannot be created without.

Columns of the product record

Field Required to create Can identify a record
product_id — —
master_id — —
model Yes Yes
sku — Yes
upc — Yes
ean — Yes
jan — Yes
isbn — Yes
mpn — Yes
location — —
variant — —
override — —
quantity — —
stock_status_id — —
image — —
manufacturer_id — —
shipping — —
price — —
points — —
tax_class_id — —
date_available — —
weight — —
weight_class_id — —
length — —
width — —
height — —
length_class_id — —
subtract — —
minimum — —
rating — —
sort_order — —
status — —
date_added — —
date_modified — —

The tables a product spans

Kept per language: product_description, product_attribute, seo_url.

Field Table Rows Written as Required to create Can identify a record
name product_description One name — —
description product_description One description — —
tag product_description One tag — —
meta_title product_description One meta_title — —
meta_description product_description One meta_description — —
meta_keyword product_description One meta_keyword — —
seo_keyword seo_url One keyword — —
manufacturer product One manufacturer_id — —
categories product_to_category Many category_id — —
images product_image Many image:sort_order — —
stores product_to_store Many store_id — —
downloads product_to_download Many download_id — —
related product_related Many related_id — —
layouts product_to_layout Many store_id:layout_id — —
attributes product_attribute Many attribute_id:text — —
options product_option Many option_id:required:option_value_id:quantity:subtract:price:price_prefix:points:points_prefix:weight:weight_prefix — —
discounts product_discount Many customer_group_id:quantity:priority:price:date_start:date_end — —
specials product_discount (product_special before 4.1) Many customer_group_id:priority:price:date_start:date_end — —
rewards product_reward Many customer_group_id:points — —
subscriptions product_subscription Many subscription_plan_id:customer_group_id:trial_price:price — —

Categories

A category is identified by where it sits rather than by what it is called, so the field that matches it is path — Home > Widgets > Blue. Levels the store does not have yet are created as the import runs, which is how a flat file builds a tree. parent_id is therefore not a field of its own: the path already says where the category goes, and a feed whose paths carry no parent gets one from the under transformation. A category's name in the store's default language is the last level of its path unless the mapping binds name itself.

Columns of the category record

Field Required to create Can identify a record
category_id — —
image — —
sort_order — —
status — —

The tables a category spans

Kept per language: category_description, seo_url.

Field Table Rows Written as Required to create Can identify a record
path category One parent_id Yes Yes
name category_description One name — —
description category_description One description — —
meta_title category_description One meta_title — —
meta_description category_description One meta_description — —
meta_keyword category_description One meta_keyword — —
seo_keyword seo_url One keyword — —
stores category_to_store Many store_id — —
layouts category_to_layout Many store_id:layout_id — —
products product_to_category Many product_id — —
filters category_filter Many filter_id — —

Manufacturers

A manufacturer is matched on its name, which is a column of its own row rather than a translated description — manufacturers are not translated in OpenCart.

Columns of the manufacturer record

Field Required to create Can identify a record
manufacturer_id — —
name Yes Yes
image — —
sort_order — —

The tables a manufacturer spans

Kept per language: seo_url.

Field Table Rows Written as Required to create Can identify a record
seo_keyword seo_url One keyword — —
stores manufacturer_to_store Many store_id — —
layouts manufacturer_to_layout Many store_id:layout_id — —

Attribute groups

An attribute group is the heading a product's attributes are printed under, and its own table holds nothing but a sort order — so it is matched on its name, which lives in the description table and is therefore per language. The name in the store's default language is what a match is made against; the others are fields like any other. A group is not deleted with the attributes filed under it, and OpenCart's own form will not delete one that still has any.

Columns of the attribute group record

Field Required to create Can identify a record
attribute_group_id — —
sort_order — —

The tables an attribute group spans

Kept per language: attribute_group_description.

Field Table Rows Written as Required to create Can identify a record
name attribute_group_description One name Yes Yes

Attributes

An attribute is a name and the group it is printed under: Weight under Technical. The value — 2.4kg — belongs to the product rather than to the attribute, and is written through a product's own attributes field. attribute_group_id is therefore not a field of its own: group stands in for it and is written as the group's name, so a file that says Technical imports into a store that numbers its groups differently. A group this store does not have is reported in the plan rather than created, because an attribute filed under a group nobody named is invisible on every product form that uses it. An attribute is matched on its name in the store's default language, and where two groups each hold one of the same name Import/export plans against the first of them.

Columns of the attribute record

Field Required to create Can identify a record
attribute_id — —
sort_order — —

The tables an attribute spans

Kept per language: attribute_description.

Field Table Rows Written as Required to create Can identify a record
group attribute One attribute_group_id Yes —
name attribute_description One name Yes Yes

Options

An option is the question a product asks a shopper — Size, Colour, Engraving — and its type is how the storefront asks it: a dropdown, a set of radio buttons, a text box. That is why type is a field a new option cannot be created without; OpenCart's own form refuses to save without one, and an option with an empty type draws nothing on the product page. An option is matched on its name in the store's default language. The answers it offers are records of their own — see option values below — and Import/export does not delete them with the option, because they have their own history and no journal of the option's job could put them back.

Columns of the option record

Field Required to create Can identify a record
option_id — —
type Yes —
validation — —
sort_order — —

The tables an option spans

Kept per language: option_description.

Field Table Rows Written as Required to create Can identify a record
name option_description One name Yes Yes

Option values

An option value is one of the answers an option offers: Large under Size. What a product charges for it — the price, the weight, the stock it subtracts — belongs to the product and is written through the product's own options field. option_id is therefore not a field of its own: option stands in for it and is written as the option's name, so a file that says Size imports into a store that numbers its options differently. An option this store does not have is reported in the plan rather than created, because a value belonging to no option appears on no product form at all. A value is matched on its name in the store's default language, and where two options each hold one of the same name — Red under both Colour and Ribbon — Import/export plans against the first of them; a feed that cannot live with that binds option_value_id and matches on that instead, and the identifier it supplies is written as given. Matching an existing value rather than replacing it is what leaves product_option_value pointing where it pointed, which OpenCart's own option form does not do.

Columns of the option value record

Field Required to create Can identify a record
option_value_id — Yes
image — —
sort_order — —

The tables an option value spans

Kept per language: option_value_description.

Field Table Rows Written as Required to create Can identify a record
option option_value One option_id Yes —
name option_value_description One name Yes Yes

Filter groups

A filter group is one facet of the storefront's filter module — Colour, Material — and its own table holds nothing but a sort order, so it is matched on its name, which lives in the description table and is therefore per language. The name in the store's default language is what a match is made against; the others are fields like any other. A group is not deleted with the filters listed under it.

Columns of the filter group record

Field Required to create Can identify a record
filter_group_id — —
sort_order — —

The tables a filter group spans

Kept per language: filter_group_description.

Field Table Rows Written as Required to create Can identify a record
name filter_group_description One name Yes Yes

Filters

A filter is a name and the group it is listed under: Red under Colour. Which categories offer it belongs to the category and is written through the category's own filters field. filter_group_id is therefore not a field of its own: group stands in for it and is written as the group's name, so a file that says Colour imports into a store that numbers its groups differently. A group this store does not have is reported in the plan rather than created, because a filter listed under no group appears in no facet at all. A filter is matched on its name in the store's default language, and where two groups each hold one of the same name Import/export plans against the first of them; a feed that cannot live with that binds filter_id and matches on that instead, and the identifier it supplies is written as given. A category names a filter the third way — qualified by its group, Colour > Red — which is the spelling an export writes and the one that is never ambiguous.

Columns of the filter record

Field Required to create Can identify a record
filter_id — Yes
sort_order — —

The tables a filter spans

Kept per language: filter_description.

Field Table Rows Written as Required to create Can identify a record
group filter One filter_group_id Yes —
name filter_description One name Yes Yes

Coupons

A coupon is matched on the code a shopper types, which is the one thing about it that has to be unique. Coupons are not translated, so the name is a column of the row. The products and categories a coupon is restricted to are fields like any other; leaving both empty is what OpenCart reads as "everything".

Columns of the coupon record

Field Required to create Can identify a record
coupon_id — —
name Yes —
code Yes Yes
type — —
discount — —
logged — —
shipping — —
total — —
date_start — —
date_end — —
uses_total — —
uses_customer — —
status — —
date_added — —

The tables a coupon spans

None of them is kept per language.

Field Table Rows Written as Required to create Can identify a record
products coupon_product Many product_id — —
categories coupon_category Many category_id — —

Reviews

A review is matched on review_id, its own identifier, and is the only kind of record that is. It has no natural key — two shoppers can leave the same rating on the same product on the same day — so a matcher keyed on the product and the author would quietly fold one review into another. A feed migrating reviews carries the identifiers they had wherever they came from, and the mapping binds review_id like any other field. The product is bound by its model, and a model this store does not have is reported in the plan rather than written as product 0.

Columns of the review record

Field Required to create Can identify a record
review_id — Yes
product_id — —
customer_id — —
author Yes —
text Yes —
rating — —
status — —
date_added — —
date_modified — —

The tables a review spans

None of them is kept per language.

Field Table Rows Written as Required to create Can identify a record
product review One product_id — —

Downloads

A download is matched on filename — where the file sits under the store's download directory, which is unique per upload. mask is the name the shopper's browser is given and name is what the admin list calls it, per language. Import/export writes the record, never the file: importing a download into a store where that file is not already present produces the same broken download OpenCart's own form would.

Columns of the download record

Field Required to create Can identify a record
download_id — —
filename Yes Yes
mask Yes —
date_added — —

The tables a download spans

Kept per language: download_description.

Field Table Rows Written as Required to create Can identify a record
name download_description One name — —

Stores

A store is matched on its name, or on its URL if you would rather. OpenCart's default store is store 0 and has no row in this table — its name and address are settings — so it is neither exported nor matchable, and every other entity still refers to it as Default. A store this creates is a row rather than a configured shop: its settings are filled in on OpenCart's own store form.

Columns of the store record

Field Required to create Can identify a record
store_id — —
name Yes Yes
url Yes Yes

A store is its own row and nothing else: there are no other tables to map into.

Orders

An order import is historical migration and not order creation. OpenCart has no admin-side API for writing an order, and the side effects a shop must never repeat — stock coming off the shelf, reward points, a coupon counted as redeemed, a confirmation email — live in its order history path rather than in the row. Import/export writes the rows and never calls that path, so nothing is decremented, nothing is awarded and nothing is sent. An order is matched on order_id, its own identifier: two customers ordering the same thing on the same day is ordinary, so there is no other key, and a feed carries the order numbers the invoices already show. Totals are taken from the source and never recalculated, which is why total is a field a create cannot do without. The status, and the country and zone of each address, are given as the names your store uses and resolved to its own identifiers — a name it does not have is reported in the plan rather than written as 0 — and a zone is resolved within the country of the same address, because two countries can each have a Limburg. A line item is one row of items, and the options chosen on it are written in its last position as Size=Large=select, separated from each other by ; — OpenCart keys those options to the line rather than to the order, so the line is where they belong. The line names its product by model, and a model your catalogue no longer has keeps the model and the name and points at product 0, exactly as OpenCart holds an order whose product has been deleted.

Columns of the order record

Field Required to create Can identify a record
order_id — Yes
subscription_id — —
invoice_no — —
invoice_prefix — —
transaction_id — —
store_id — —
store_name — —
store_url — —
customer_id — —
customer_group_id — —
firstname Yes —
lastname Yes —
email Yes —
telephone — —
custom_field — —
payment_address_id — —
payment_firstname — —
payment_lastname — —
payment_company — —
payment_address_1 — —
payment_address_2 — —
payment_city — —
payment_postcode — —
payment_country — —
payment_zone — —
payment_address_format — —
payment_custom_field — —
payment_method — —
shipping_address_id — —
shipping_firstname — —
shipping_lastname — —
shipping_company — —
shipping_address_1 — —
shipping_address_2 — —
shipping_city — —
shipping_postcode — —
shipping_country — —
shipping_zone — —
shipping_address_format — —
shipping_custom_field — —
shipping_method — —
comment — —
total Yes —
affiliate_id — —
commission — —
marketing_id — —
tracking — —
language_id — —
language_code — —
currency_id — —
currency_code — —
currency_value — —
ip — —
forwarded_ip — —
user_agent — —
accept_language — —
date_added — —
date_modified — —

The tables an order spans

None of them is kept per language.

Field Table Rows Written as Required to create Can identify a record
order_status order One order_status_id Yes —
payment_country order One payment_country_id, payment_country — —
payment_zone order One payment_zone_id, payment_zone — —
shipping_country order One shipping_country_id, shipping_country — —
shipping_zone order One shipping_zone_id, shipping_zone — —
items order_product Many model:name:quantity:price:total:tax:reward:order_option — —
totals order_total Many code:title:value:sort_order:extension — —
history order_history Many order_status_id:notify:comment:date_added — —

Customers

A customer is matched on email, which is what a shopper signs in with and the one thing about an account that has to be unique; a migration carrying the identifiers the accounts had elsewhere can match on customer_id instead. Passwords are never imported. There is no field for one, plain or hashed: a plain-text password would put your whole customer base in a spreadsheet, an upload directory and a saved plan, and a hash from another platform is one OpenCart cannot verify against. So a customer this creates has no usable password and cannot sign in until they use your storefront's Forgotten Password link, which is the migration story — the account, its addresses and its history arrive, and the credential is re-established by the person who owns it. token and code are withheld for the same reason. The customer group is given as the name your store uses and is required, as it is on OpenCart's own customer form; a group your store does not have is reported in the plan rather than created, because a group decides what an account is charged. Every address a customer has is one row of addresses, with its country and zone given by name — a zone is resolved within the country of the same address, because two countries can each have a Limburg — and its custom fields in the last position, where OpenCart's own serialised shape survives the round trip. Approval is not a column in OpenCart 4.1: an account awaiting approval has a row in customer_approval, so an approved account carries nothing in approvals. Deleting a customer takes exactly what OpenCart's own customer form takes, which leaves their orders, reviews and returns where they are.

Columns of the customer record

Field Required to create Can identify a record
customer_id — Yes
store_id — —
language_id — —
firstname Yes —
lastname Yes —
email Yes Yes
telephone — —
custom_field — —
newsletter — —
ip — —
status — —
safe — —
commenter — —
date_added — —

The tables a customer spans

None of them is kept per language.

Field Table Rows Written as Required to create Can identify a record
customer_group customer One customer_group_id Yes —
addresses address Many firstname:lastname:company:address_1:address_2:city:postcode:country_id:zone_id:default:custom_field — —
approvals customer_approval Many type:date_added — —