HikaShop can be driven from a command line, so that a shop can be managed from a terminal, a cron
entry, a deployment script or a Makefile, without opening a browser. It works on both platforms,
using the command line each of them already provides: the Joomla console for a Joomla site, and
WP-CLI for a WordPress one.
Nothing is sent over the network. The commands run inside your own site, on the machine the site
is installed on, so there is no key to create and nothing to open to the outside.
Getting started
On Joomla the commands come from the "Console - HikaShop" plugin, installed and enabled with
HikaShop. On WordPress they come with the HikaShop plugin itself and need
WP-CLI. Ask for the list:
php cli/joomla.php list # Joomla
wp hikashop # WordPress
Each platform spells the same command its own way, Joomla with colons and WordPress with
spaces. Everything else is identical: the same arguments, the same options, the same output and the
same exit codes.
php cli/joomla.php hikashop:product:list --limit=5
wp hikashop product list --limit=5
Options every command understands
| Option | What it does |
| --format | table to read, json to pipe into something else, and also pretty, csv, ids and count. Listings show a table by default, single records show indented JSON. |
| --user | Which account the command acts as, given by id, user name or email address. It decides what the command may do, through the access levels of your site and of the HikaShop configuration. On WordPress this is WP-CLI's own --user, which behaves the same and can be set once in wp-cli.yml. |
| --yes | Required by the commands that remove data or act on many records at once. Without it they refuse and change nothing. |
| --live-site | Joomla only. The address of your site, needed when your configuration does not set one, so that the links the shop generates are correct. |
With no --user a command runs as nobody in particular. On a shop that has not
restricted anything this is enough; on a shop that has restricted a kind of record to a group of
users, the command is refused and says to name a user. Choosing an account also means your change
log records who made the change.
What the shell gets back
Only the data is printed to the standard output, so --format=json can always be piped
into another program. Warnings and error messages go to the error output and never mix into it.
Answers carry the same envelope the Connector API uses: data is what you asked for,
meta holds the paging of a listing, and error is null unless
something went wrong. The tables below describe what is inside data.
The exit code says what happened, which is what a script should test:
| Code | Meaning |
| 0 | It worked |
| 1 | Something went wrong |
| 2 | The command was asked for wrongly, for example a missing option |
| 3 | The record does not exist |
| 4 | This account is not allowed to do that |
The commands for your products, orders, customers, categories, coupons and mass actions come
through the HikaShop Connector plugin, which ships with the Business edition. The commands for the
shop itself, its configuration, its caches and its database, are available in every edition. Running
the cron this way needs the Essential or the Business edition, as the cron itself does.
All commands
Products
product:list
List products.
The catalogue as the backend sees it, unpublished products included, which is what makes this
different from the front end.
Variants are not listed on their own. A parent carries has_variants, and
GET /products/{id} returns the variants themselves.
php cli/joomla.php hikashop:product:list [--search=<search>] [--limit=<limit>] [--start=<start>] [--category=<category>] [--ids=<ids>]
wp hikashop product list [--search=<search>] [--limit=<limit>] [--start=<start>] [--category=<category>] [--ids=<ids>]
| Option | Type | Description |
| --search | string | Filter on a search term |
| --limit | int | How many to return |
| --start | int | Skip this many first |
| --category | int | Only this category |
| --ids | string | Only these product ids, comma separated |
| Returns | Type | Description |
| id | | |
| name | | |
| code | | The SKU. Unique within the shop. |
| quantity | | -1 when the product does not track stock, which is not the same as 0. |
| published | | |
| has_variants | | Ask GET /products/{id} for the variants themselves. |
| image | string|null | Absolute URL of the main image, or null. |
| price | | null when the product has no price row at all. |
| currency_id | | A row in the shop's currency table, not an ISO code. |
| custom_fields | object | The listing values of this product, keyed by field namekey. |
In meta | Type | Description |
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
| total | integer | Rows matching the filter, before paging. This is how you know there is another page. |
| fields | object[] | The custom fields shown on listings, so a client can label the values it just received. |
product:get
Show one product.
Everything the product editor needs in one call: the record, its prices, its images and files, its
categories, its characteristics and variants, and the definitions of the custom fields that apply
to it.
Ask for a variant's id and you get the variant, with parent_id set. A parent's variants are
listed in full, so you rarely need to.
php cli/joomla.php hikashop:product:get <id>
wp hikashop product get <id>
| Argument | Description |
| <id> required | Product id |
| Returns | Type | Description |
| id | | |
| name | | |
| code | | The SKU. Unique within the shop. |
| description | | The long description, as HTML. |
| description_type | | Which editor the description was written with. |
| published | | |
| quantity | | -1 when this product does not track stock, which is not the same as 0. |
| msrp | | The manufacturer's suggested price, shown struck through when the shop is configured to. |
| gtin | | The barcode: EAN, UPC or ISBN. This is what GET /products/lookup matches on. |
| condition | | New, used, refurbished. Used by the feeds rather than by the shop itself. |
| weight | | Shipping weight, in weight_unit. |
| weight_unit | | kg, g, lb or oz. |
| width | | In dimension_unit. |
| height | | In dimension_unit. |
| length | | In dimension_unit. |
| dimension_unit | | m, cm, mm, ft or in. |
| min_per_order | | The smallest quantity a customer may order, 0 for no minimum. |
| max_per_order | | The largest, 0 for no maximum. |
| sale_start | integer|null | Unix timestamp before which the product is not on sale. |
| sale_end | integer|null | Unix timestamp after which it is no longer sold. |
| page_title | | SEO title, empty to use the name. |
| meta_description | | SEO description. |
| keywords | | SEO keywords. |
| canonical | | A canonical URL, when this page should point at another. |
| url | | The address of the product page on the shop. |
| alias | | The slug used in that address. |
| access | object | Who may see the product: mode (all, none or groups) and groups, which are user **group** ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| access.mode | string | all, none, or groups when it is restricted to some. |
| access.groups | integer[] | User group ids, meaningful only when the mode is groups. |
| contact | | Whether this product is enquired about rather than bought. |
| warehouse_id | | The warehouse holding the stock, 0 when the shop has none. |
| type | | main for a product, variant for one of its variants. |
| parent_id | | The parent product when this is a variant, 0 otherwise. |
| value_ids | integer[] | For a variant, the characteristic values it stands for. |
| manufacturer_id | | The brand, 0 when unset. |
| manufacturer_name | string | Its name, saving a second call. |
| tax_id | | The tax category, 0 when the product is untaxed. |
| tax_name | string | Its name. |
| tax_rate | number | The rate as a fraction, so 0.2 is twenty percent. |
| prices | object[] | Every price row, including the restricted ones. A product with none is not sellable. |
| prices.id | | |
| prices.value | | Tax excluded, as stored. |
| prices.currency_id | | |
| prices.min_quantity | | From how many items this row applies, which is how quantity breaks are expressed. |
| prices.access | object | Who this price is for, in the same shape as the product access. |
| prices.access.mode | string | As above. |
| prices.access.groups | integer[] | As above. |
| prices.users | integer[] | Named customers, empty for everyone. |
| prices.zone_ids | integer[] | Zones this price applies in, empty for everywhere. |
| prices.start_date | integer|null | Unix timestamp. |
| prices.end_date | integer|null | Unix timestamp. |
| images | object[] | In the order the editor shows them; the first is the main image. |
| images.id | | |
| images.name | | |
| images.path | | Relative to the upload folder. |
| images.url | | Absolute, ready to display. |
| images.ordering | | |
| images.description | | The alt text. |
| images.access | object | Who may see it. |
| images.access.mode | string | As above. |
| images.access.groups | integer[] | As above. |
| images.free_download | | Files only; meaningless on an image. |
| files | object[] | Downloadable files, in the same shape as the images. |
| files.id | | |
| files.name | | |
| files.path | | Relative to the upload folder. |
| files.url | | Absolute. |
| files.ordering | | |
| files.description | | |
| files.access | object | Who may download it. |
| files.free_download | | Whether it can be downloaded without buying the product. |
| categories | object[] | The categories the product is in. |
| categories.id | | |
| categories.name | | |
| bundle | object[] | The products this one is made of, when it is a bundle. |
| bundle.id | | |
| bundle.name | | |
| bundle.code | | |
| bundle.quantity | | How many of it the bundle contains. |
| options | object[] | Products offered as options alongside this one. |
| options.id | | |
| options.name | | |
| options.code | | |
| options.quantity | | |
| related | object[] | Products shown as related. |
| related.id | | |
| related.name | | |
| related.code | | |
| related.quantity | | |
| tags | integer[] | CMS tag ids. |
| characteristics | object[] | The characteristics this product varies on. Empty when it has no variants. |
| characteristics.id | integer | The characteristic, such as Size. |
| characteristics.name | string | Its name. |
| characteristics.values | object[] | The values of it this product uses, such as S, M and L. |
| characteristics.values.id | integer | The value id, which is what a variant refers to. |
| characteristics.values.value | string | Its name, such as M. |
| variants | object[] | Every variant, with its own code, stock, price and images. Empty for a product that does not vary. |
| variants.id | integer | The variant is a product in its own right, and this is its id. |
| variants.code | string | Its own SKU. |
| variants.quantity | integer | Its own stock. This is the figure to change, not the parent's. |
| variants.published | boolean | |
| variants.price | number|null | null when the variant has no price of its own and the parent's applies. |
| variants.values | object[] | Which characteristic values this variant stands for, one per characteristic. |
| variants.values.option_id | integer | The characteristic. |
| variants.values.option_name | string | Its name, so the variant can be labelled without a second call. |
| variants.values.value_id | integer | The value. |
| variants.values.value | string | Its name. |
| variants.images | object[] | The variant's own images, in the same shape as the product's. |
| variants.images.id | integer | |
| variants.images.name | string | |
| variants.images.path | string | Relative to the upload folder. |
| variants.images.url | string | Absolute. |
| variants.images.ordering | integer | |
| fields | object[] | The definitions of the custom fields that apply to this product, so a client can build a form for them. |
| fields.namekey | string | The key used in custom_fields. |
| fields.label | string | Translated into the operator's language. |
| fields.type | string | text, radio, singledropdown, file, and the rest of HikaShop's field types. |
| fields.required | boolean | Whether the shop refuses to save the product without it. |
| fields.translatable | boolean | Whether its value can be translated, which is what the translation routes offer. |
| fields.upload_dir | string | For a file field, where its uploads are kept. |
| fields.raw_type | string | HikaShop's own name for the type, before it is mapped to something a client can render. |
| fields.default | string | The value used when none is given. |
| fields.options | object[] | The choices, for a field that has them. Empty for a free text one. |
| fields.multiple | boolean | Whether more than one choice may be selected. |
| fields.allowed_extensions | string | For a file field, the extensions it accepts, comma separated. Empty means the shop default. |
| fields.date_format | string | For a date field, the format it is stored in. |
| custom_fields | object | Their values, keyed by namekey. |
| custom_field_files | object | For custom fields holding a file, the file behind each value. |
product:create
Create a product.
Creates a product and answers with its id. Only the name is required; everything else can be set
now or later with PUT /products/{id}.
Prices, images and categories are separate calls, so a new product is not sellable until it has at
least one price.
php cli/joomla.php hikashop:product:create --name=<name> [--code=<code>] [--quantity=<quantity>] [--published] [--description=<description>] [--categories=<categories>]
wp hikashop product create --name=<name> [--code=<code>] [--quantity=<quantity>] [--published] [--description=<description>] [--categories=<categories>]
| Option | Type | Description |
| --name required | string | Product name |
| --code | string | Product code, derived from the name when left out |
| --quantity | int | Stock, -1 for unlimited |
| --published | flag | Publish it |
| --description | string | Description |
| --categories | ids, comma separated | Category ids, comma separated |
| Returns | Type | Description |
| id | | |
| name | | |
| code | | The SKU. Unique within the shop. |
| description | | The long description, as HTML. |
| description_type | | Which editor the description was written with. |
| published | | |
| quantity | | -1 when this product does not track stock, which is not the same as 0. |
| msrp | | The manufacturer's suggested price, shown struck through when the shop is configured to. |
| gtin | | The barcode: EAN, UPC or ISBN. This is what GET /products/lookup matches on. |
| condition | | New, used, refurbished. Used by the feeds rather than by the shop itself. |
| weight | | Shipping weight, in weight_unit. |
| weight_unit | | kg, g, lb or oz. |
| width | | In dimension_unit. |
| height | | In dimension_unit. |
| length | | In dimension_unit. |
| dimension_unit | | m, cm, mm, ft or in. |
| min_per_order | | The smallest quantity a customer may order, 0 for no minimum. |
| max_per_order | | The largest, 0 for no maximum. |
| sale_start | integer|null | Unix timestamp before which the product is not on sale. |
| sale_end | integer|null | Unix timestamp after which it is no longer sold. |
| page_title | | SEO title, empty to use the name. |
| meta_description | | SEO description. |
| keywords | | SEO keywords. |
| canonical | | A canonical URL, when this page should point at another. |
| url | | The address of the product page on the shop. |
| alias | | The slug used in that address. |
| access | object | Who may see the product: mode (all, none or groups) and groups, which are user **group** ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| access.mode | string | all, none, or groups when it is restricted to some. |
| access.groups | integer[] | User group ids, meaningful only when the mode is groups. |
| contact | | Whether this product is enquired about rather than bought. |
| warehouse_id | | The warehouse holding the stock, 0 when the shop has none. |
| type | | main for a product, variant for one of its variants. |
| parent_id | | The parent product when this is a variant, 0 otherwise. |
| value_ids | integer[] | For a variant, the characteristic values it stands for. |
| manufacturer_id | | The brand, 0 when unset. |
| manufacturer_name | string | Its name, saving a second call. |
| tax_id | | The tax category, 0 when the product is untaxed. |
| tax_name | string | Its name. |
| tax_rate | number | The rate as a fraction, so 0.2 is twenty percent. |
| prices | object[] | Every price row, including the restricted ones. A product with none is not sellable. |
| prices.id | | |
| prices.value | | Tax excluded, as stored. |
| prices.currency_id | | |
| prices.min_quantity | | From how many items this row applies, which is how quantity breaks are expressed. |
| prices.access | object | Who this price is for, in the same shape as the product access. |
| prices.access.mode | string | As above. |
| prices.access.groups | integer[] | As above. |
| prices.users | integer[] | Named customers, empty for everyone. |
| prices.zone_ids | integer[] | Zones this price applies in, empty for everywhere. |
| prices.start_date | integer|null | Unix timestamp. |
| prices.end_date | integer|null | Unix timestamp. |
| images | object[] | In the order the editor shows them; the first is the main image. |
| images.id | | |
| images.name | | |
| images.path | | Relative to the upload folder. |
| images.url | | Absolute, ready to display. |
| images.ordering | | |
| images.description | | The alt text. |
| images.access | object | Who may see it. |
| images.access.mode | string | As above. |
| images.access.groups | integer[] | As above. |
| images.free_download | | Files only; meaningless on an image. |
| files | object[] | Downloadable files, in the same shape as the images. |
| files.id | | |
| files.name | | |
| files.path | | Relative to the upload folder. |
| files.url | | Absolute. |
| files.ordering | | |
| files.description | | |
| files.access | object | Who may download it. |
| files.free_download | | Whether it can be downloaded without buying the product. |
| categories | object[] | The categories the product is in. |
| categories.id | | |
| categories.name | | |
| bundle | object[] | The products this one is made of, when it is a bundle. |
| bundle.id | | |
| bundle.name | | |
| bundle.code | | |
| bundle.quantity | | How many of it the bundle contains. |
| options | object[] | Products offered as options alongside this one. |
| options.id | | |
| options.name | | |
| options.code | | |
| options.quantity | | |
| related | object[] | Products shown as related. |
| related.id | | |
| related.name | | |
| related.code | | |
| related.quantity | | |
| tags | integer[] | CMS tag ids. |
| characteristics | object[] | The characteristics this product varies on. Empty when it has no variants. |
| characteristics.id | integer | The characteristic, such as Size. |
| characteristics.name | string | Its name. |
| characteristics.values | object[] | The values of it this product uses, such as S, M and L. |
| characteristics.values.id | integer | The value id, which is what a variant refers to. |
| characteristics.values.value | string | Its name, such as M. |
| variants | object[] | Every variant, with its own code, stock, price and images. Empty for a product that does not vary. |
| variants.id | integer | The variant is a product in its own right, and this is its id. |
| variants.code | string | Its own SKU. |
| variants.quantity | integer | Its own stock. This is the figure to change, not the parent's. |
| variants.published | boolean | |
| variants.price | number|null | null when the variant has no price of its own and the parent's applies. |
| variants.values | object[] | Which characteristic values this variant stands for, one per characteristic. |
| variants.values.option_id | integer | The characteristic. |
| variants.values.option_name | string | Its name, so the variant can be labelled without a second call. |
| variants.values.value_id | integer | The value. |
| variants.values.value | string | Its name. |
| variants.images | object[] | The variant's own images, in the same shape as the product's. |
| variants.images.id | integer | |
| variants.images.name | string | |
| variants.images.path | string | Relative to the upload folder. |
| variants.images.url | string | Absolute. |
| variants.images.ordering | integer | |
| fields | object[] | The definitions of the custom fields that apply to this product, so a client can build a form for them. |
| fields.namekey | string | The key used in custom_fields. |
| fields.label | string | Translated into the operator's language. |
| fields.type | string | text, radio, singledropdown, file, and the rest of HikaShop's field types. |
| fields.required | boolean | Whether the shop refuses to save the product without it. |
| fields.translatable | boolean | Whether its value can be translated, which is what the translation routes offer. |
| fields.upload_dir | string | For a file field, where its uploads are kept. |
| fields.raw_type | string | HikaShop's own name for the type, before it is mapped to something a client can render. |
| fields.default | string | The value used when none is given. |
| fields.options | object[] | The choices, for a field that has them. Empty for a free text one. |
| fields.multiple | boolean | Whether more than one choice may be selected. |
| fields.allowed_extensions | string | For a file field, the extensions it accepts, comma separated. Empty means the shop default. |
| fields.date_format | string | For a date field, the format it is stored in. |
| custom_fields | object | Their values, keyed by namekey. |
| custom_field_files | object | For custom fields holding a file, the file behind each value. |
| Can also fail with | Meaning |
| invalid_fields | One of your own fields was rejected by its own rules. |
| save_failed | The shop refused to save the product. |
product:update
Change a product.
Changes the fields you send and leaves the rest alone, which is the opposite of the price and
category calls: this one merges.
Sending nothing to change is refused rather than treated as a success, so a client cannot believe
it saved something it did not.
php cli/joomla.php hikashop:product:update <id> [--name=<name>] [--code=<code>] [--description=<description>] [--published] [--msrp=<msrp>] [--gtin=<gtin>] [--weight=<weight>] [--tax-id=<tax-id>]
wp hikashop product update <id> [--name=<name>] [--code=<code>] [--description=<description>] [--published] [--msrp=<msrp>] [--gtin=<gtin>] [--weight=<weight>] [--tax-id=<tax-id>]
| Argument | Description |
| <id> required | Product id |
| Option | Type | Description |
| --name | string | Product name |
| --code | string | Product code |
| --description | string | Description |
| --published | flag | Publish it |
| --msrp | float | Recommended retail price |
| --gtin | string | GTIN / barcode |
| --weight | float | Weight |
| --tax-id | int | Tax category id |
| Returns | Type | Description |
| id | | |
| name | | |
| code | | The SKU. Unique within the shop. |
| description | | The long description, as HTML. |
| description_type | | Which editor the description was written with. |
| published | | |
| quantity | | -1 when this product does not track stock, which is not the same as 0. |
| msrp | | The manufacturer's suggested price, shown struck through when the shop is configured to. |
| gtin | | The barcode: EAN, UPC or ISBN. This is what GET /products/lookup matches on. |
| condition | | New, used, refurbished. Used by the feeds rather than by the shop itself. |
| weight | | Shipping weight, in weight_unit. |
| weight_unit | | kg, g, lb or oz. |
| width | | In dimension_unit. |
| height | | In dimension_unit. |
| length | | In dimension_unit. |
| dimension_unit | | m, cm, mm, ft or in. |
| min_per_order | | The smallest quantity a customer may order, 0 for no minimum. |
| max_per_order | | The largest, 0 for no maximum. |
| sale_start | integer|null | Unix timestamp before which the product is not on sale. |
| sale_end | integer|null | Unix timestamp after which it is no longer sold. |
| page_title | | SEO title, empty to use the name. |
| meta_description | | SEO description. |
| keywords | | SEO keywords. |
| canonical | | A canonical URL, when this page should point at another. |
| url | | The address of the product page on the shop. |
| alias | | The slug used in that address. |
| access | object | Who may see the product: mode (all, none or groups) and groups, which are user **group** ids and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| access.mode | string | all, none, or groups when it is restricted to some. |
| access.groups | integer[] | User group ids, meaningful only when the mode is groups. |
| contact | | Whether this product is enquired about rather than bought. |
| warehouse_id | | The warehouse holding the stock, 0 when the shop has none. |
| type | | main for a product, variant for one of its variants. |
| parent_id | | The parent product when this is a variant, 0 otherwise. |
| value_ids | integer[] | For a variant, the characteristic values it stands for. |
| manufacturer_id | | The brand, 0 when unset. |
| manufacturer_name | string | Its name, saving a second call. |
| tax_id | | The tax category, 0 when the product is untaxed. |
| tax_name | string | Its name. |
| tax_rate | number | The rate as a fraction, so 0.2 is twenty percent. |
| prices | object[] | Every price row, including the restricted ones. A product with none is not sellable. |
| prices.id | | |
| prices.value | | Tax excluded, as stored. |
| prices.currency_id | | |
| prices.min_quantity | | From how many items this row applies, which is how quantity breaks are expressed. |
| prices.access | object | Who this price is for, in the same shape as the product access. |
| prices.access.mode | string | As above. |
| prices.access.groups | integer[] | As above. |
| prices.users | integer[] | Named customers, empty for everyone. |
| prices.zone_ids | integer[] | Zones this price applies in, empty for everywhere. |
| prices.start_date | integer|null | Unix timestamp. |
| prices.end_date | integer|null | Unix timestamp. |
| images | object[] | In the order the editor shows them; the first is the main image. |
| images.id | | |
| images.name | | |
| images.path | | Relative to the upload folder. |
| images.url | | Absolute, ready to display. |
| images.ordering | | |
| images.description | | The alt text. |
| images.access | object | Who may see it. |
| images.access.mode | string | As above. |
| images.access.groups | integer[] | As above. |
| images.free_download | | Files only; meaningless on an image. |
| files | object[] | Downloadable files, in the same shape as the images. |
| files.id | | |
| files.name | | |
| files.path | | Relative to the upload folder. |
| files.url | | Absolute. |
| files.ordering | | |
| files.description | | |
| files.access | object | Who may download it. |
| files.free_download | | Whether it can be downloaded without buying the product. |
| categories | object[] | The categories the product is in. |
| categories.id | | |
| categories.name | | |
| bundle | object[] | The products this one is made of, when it is a bundle. |
| bundle.id | | |
| bundle.name | | |
| bundle.code | | |
| bundle.quantity | | How many of it the bundle contains. |
| options | object[] | Products offered as options alongside this one. |
| options.id | | |
| options.name | | |
| options.code | | |
| options.quantity | | |
| related | object[] | Products shown as related. |
| related.id | | |
| related.name | | |
| related.code | | |
| related.quantity | | |
| tags | integer[] | CMS tag ids. |
| characteristics | object[] | The characteristics this product varies on. Empty when it has no variants. |
| characteristics.id | integer | The characteristic, such as Size. |
| characteristics.name | string | Its name. |
| characteristics.values | object[] | The values of it this product uses, such as S, M and L. |
| characteristics.values.id | integer | The value id, which is what a variant refers to. |
| characteristics.values.value | string | Its name, such as M. |
| variants | object[] | Every variant, with its own code, stock, price and images. Empty for a product that does not vary. |
| variants.id | integer | The variant is a product in its own right, and this is its id. |
| variants.code | string | Its own SKU. |
| variants.quantity | integer | Its own stock. This is the figure to change, not the parent's. |
| variants.published | boolean | |
| variants.price | number|null | null when the variant has no price of its own and the parent's applies. |
| variants.values | object[] | Which characteristic values this variant stands for, one per characteristic. |
| variants.values.option_id | integer | The characteristic. |
| variants.values.option_name | string | Its name, so the variant can be labelled without a second call. |
| variants.values.value_id | integer | The value. |
| variants.values.value | string | Its name. |
| variants.images | object[] | The variant's own images, in the same shape as the product's. |
| variants.images.id | integer | |
| variants.images.name | string | |
| variants.images.path | string | Relative to the upload folder. |
| variants.images.url | string | Absolute. |
| variants.images.ordering | integer | |
| fields | object[] | The definitions of the custom fields that apply to this product, so a client can build a form for them. |
| fields.namekey | string | The key used in custom_fields. |
| fields.label | string | Translated into the operator's language. |
| fields.type | string | text, radio, singledropdown, file, and the rest of HikaShop's field types. |
| fields.required | boolean | Whether the shop refuses to save the product without it. |
| fields.translatable | boolean | Whether its value can be translated, which is what the translation routes offer. |
| fields.upload_dir | string | For a file field, where its uploads are kept. |
| fields.raw_type | string | HikaShop's own name for the type, before it is mapped to something a client can render. |
| fields.default | string | The value used when none is given. |
| fields.options | object[] | The choices, for a field that has them. Empty for a free text one. |
| fields.multiple | boolean | Whether more than one choice may be selected. |
| fields.allowed_extensions | string | For a file field, the extensions it accepts, comma separated. Empty means the shop default. |
| fields.date_format | string | For a date field, the format it is stored in. |
| custom_fields | object | Their values, keyed by namekey. |
| custom_field_files | object | For custom fields holding a file, the file behind each value. |
| Can also fail with | Meaning |
| not_found | No such product, or the operator may not change it. |
| invalid_fields | One of your own fields was rejected by its own rules. |
| nothing | The body held no field this shop knows, so nothing would have been written. |
product:delete
Delete a product and its variants.
Deletes a product and its variants.
Orders that already contain it are untouched: an order line records what was sold at the time, and
it does not stop meaning something because the catalogue changed.
php cli/joomla.php hikashop:product:delete <id> --yes
wp hikashop product delete <id> --yes
| Argument | Description |
| <id> required | Product id |
| Returns | Type | Description |
| id | integer | The product that was deleted. |
| deleted | boolean | True when the row is gone. |
| Can also fail with | Meaning |
| not_found | No such product, or the operator may not delete it. |
| delete_failed | The shop refused to delete it. |
product:stock
Set a product's stock.
Sets the tracked quantity to an absolute figure, which is what a stock take does. It is not an
adjustment: send what the shelf holds, not the difference.
A product with variants keeps no stock of its own, so set it on the variant instead. Asking to set
it on the parent is refused rather than silently ignored.
php cli/joomla.php hikashop:product:stock <id> --quantity=<quantity>
wp hikashop product stock <id> --quantity=<quantity>
| Argument | Description |
| <id> required | Product id |
| Option | Type | Description |
| --quantity required | int | New quantity, -1 for unlimited |
| Returns | Type | Description |
| id | integer | |
| quantity | integer | As stored, so you can confirm what was written. |
| Can also fail with | Meaning |
| not_found | No such product, or the operator may not change it. |
| has_variants | It is a parent: set the stock on one of its variants. |
product:price
Replace a product's price set.
Replaces the whole price set, it does not merge into it. Send every price the product should have,
including the ones you are not changing; anything you leave out is deleted.
That is deliberate, because a price set is a set: quantity breaks and audience restrictions only
make sense against each other.
php cli/joomla.php hikashop:product:price <id> --value=<value> [--currency=<currency>] [--min-quantity=<min-quantity>]
wp hikashop product price <id> --value=<value> [--currency=<currency>] [--min-quantity=<min-quantity>]
| Argument | Description |
| <id> required | Product id |
| Option | Type | Description |
| --value required | float | The price |
| --currency | int | Currency id, the shop's own when left out |
| --min-quantity | int | Quantity this price starts at |
| Returns | Type | Description |
| id | integer | |
| value | number | Tax excluded, as stored. |
| currency_id | integer | |
| min_quantity | integer | From how many items this row applies, which is how a quantity break is expressed. |
| access | object | Which user groups the price is for. |
| access.mode | string | all, none or groups. |
| access.groups | integer[] | User group ids, not view levels. |
| users | integer[] | Named customers, empty for everyone. |
| zone_ids | integer[] | Zones it applies in, empty for everywhere. |
| start_date | integer|null | Unix timestamp. |
| end_date | integer|null | Unix timestamp. |
| Can also fail with | Meaning |
| invalid_request | No prices array was sent. |
| invalid_price | A price in the set cannot be stored, and the message says which one and why. Nothing is saved: a set is replaced whole or not at all. |
| not_found | No such product, or the operator may not change it. |
product:lowstock
List sellable products at or below a stock threshold.
Sellable items at or below a stock threshold, cheapest first to reorder. Variants are listed in
their own right, since that is where the stock actually sits.
Products that do not track stock are left out: they are not running out of anything.
php cli/joomla.php hikashop:product:lowstock [--threshold=<threshold>] [--limit=<limit>]
wp hikashop product lowstock [--threshold=<threshold>] [--limit=<limit>]
| Option | Type | Description |
| --threshold | int | Stock level to report at or below |
| --limit | int | How many to return |
| Returns | Type | Description |
| id | | The parent product. |
| variant_id | | The variant that is low, 0 when the parent itself is. |
| name | | |
| code | | The SKU of whichever record is low. |
| quantity | | What is left. |
Orders
order:list
List orders.
The orders the operator may see, newest first. It is the listing the app's order screen is built
on, so it carries just enough to draw a row and no more; ask for one order when you need the rest.
php cli/joomla.php hikashop:order:list [--search=<search>] [--limit=<limit>] [--start=<start>] [--status=<status>]
wp hikashop order list [--search=<search>] [--limit=<limit>] [--start=<start>] [--status=<status>]
| Option | Type | Description |
| --search | string | Filter on a search term |
| --limit | int | How many to return |
| --start | int | Skip this many first |
| --status | string | Only this order status |
| Returns | Type | Description |
| id | | The order id, which is what every other order route takes. |
| number | | The order number the customer sees, which is not the id. |
| status | | A namekey, not a label. GET /statuses translates it. |
| created | | Unix timestamp. |
| total | | What the customer owes, tax included, in the order currency. |
| currency_id | | The order keeps the currency it was placed in, which need not be the shop default. |
| customer | object | Enough to name the buyer in a list. |
| customer.name | | |
| customer.email | | |
| custom_fields | object | The listing values of your own order fields, keyed by namekey. |
In meta | Type | Description |
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
| total | integer | Orders matching the filter, before paging. |
| fields | object[] | The definitions behind custom_fields. |
order:get
Show one order.
The whole order: its lines, its totals, its addresses, its history and your own fields.
Money is in the currency the order was placed in, which is not necessarily the shop's. Do not
convert it: an order is a record of what was agreed at the time.
php cli/joomla.php hikashop:order:get <id>
wp hikashop order get <id>
| Argument | Description |
| <id> required | Order id |
| Returns | Type | Description |
| fees | object | The discount, shipping and payment amounts, which is what PUT /orders/{id}/fees writes. |
| fees.discount | object | Its amount, its tax, the tax_namekeys behind that tax, and the coupon code when one was used. |
| fees.discount.amount | number | A positive figure, already subtracted from the total. |
| fees.discount.tax | number | The tax on it. |
| fees.discount.tax_namekeys | string[] | Which tax rates that came from. |
| fees.discount.code | string | The coupon code, empty for a discount applied by hand. |
| fees.shipping | object | The shipping charge and what carried it. |
| fees.shipping.amount | number | Tax excluded. |
| fees.shipping.tax | number | The tax on it. |
| fees.shipping.tax_namekeys | string[] | Which tax rates that came from. |
| fees.shipping.method | string | The plugin that handled it. |
| fees.shipping.method_name | string | As the merchant named it. |
| fees.payment | object | The payment fee and what took it. |
| fees.payment.amount | number | Tax excluded. |
| fees.payment.tax | number | The tax on it. |
| fees.payment.tax_namekeys | string[] | Which tax rates that came from. |
| fees.payment.method | string | The plugin that took it. |
| fees.payment.method_name | string | As the merchant named it. |
| totals | object | The figures. See the shape below. |
| totals.total | number | What the customer owes, tax included. |
| totals.discount | number | The discount applied, as a positive figure already subtracted. |
| totals.shipping | number | The shipping charged. |
| totals.payment | number | The payment fee charged. |
| totals.tax | number | The tax within the total, not on top of it. |
| id | | |
| number | | The number the customer sees. |
| status | | A namekey. |
| created | | Unix timestamp. |
| modified | | Unix timestamp of the last change. |
| currency_id | | The currency the order was placed in. |
| customer | object | Who placed it. |
| customer.name | | |
| customer.email | | |
| payment_method | string | How it was paid, as the shop names it. |
| shipping_method | string | How it ships. |
| invoice_number | string | Empty until an invoice has been issued. |
| invoice_created | integer|null | Unix timestamp of the invoice. |
| items | object[] | The lines: id, name, code, quantity, price, tax and whether the line can still be edited. |
| items.id | integer | The line id, which is what PUT /orders/{id}/products/{lineId} takes. It is not the product id. |
| items.name | string | The product as it was named when ordered, which may since have changed. |
| items.code | string | Its SKU at the time. |
| items.quantity | integer | |
| items.price | number | Unit price, tax excluded, as agreed at the time. |
| items.tax | number | Tax on the line. |
| items.editable | boolean | False once the line can no longer be changed, for instance on a shipped order. |
| billing_address | object|null | The address as it was at the time, null when there is none. It is a copy, not a pointer at the customer's current address. |
| shipping_address | object|null | The same, for delivery. |
| shipping_address_override | boolean | Whether the delivery address was set apart from the billing one. |
| history | object[] | What has happened to the order, oldest first. |
| history.status | | The namekey it moved to. |
| history.created | | Unix timestamp. |
| history.type | | What caused it: a payment notification, an operator, the shop itself. |
| history.reason | | The note recorded with the change, when there was one. |
| history.notified | boolean | Whether the customer was emailed about it. |
| fields | object[] | The definitions of your own order fields. |
| custom_fields | object | Their values, keyed by namekey. |
| custom_field_files | object | For a field holding a file, the file behind the value. |
| tax_rates | object[] | The rates that made up the tax, each with its namekey and rate, so a total can be explained rather than only shown. |
| tax_rates.namekey | string | The tax rate as the shop names it. |
| tax_rates.rate | number | As a fraction, so 0.1 is ten percent. |
order:status
Change an order's status.
Moves the order and, when asked, sends the customer the same notification the backend would have
sent.
This calls the same code the backend does, so stock, invoices and every plugin listening on a
status change behave exactly as they do there. It is not a database update.
php cli/joomla.php hikashop:order:status <id> <status> [--notify] [--reason=<reason>]
wp hikashop order status <id> <status> [--notify] [--reason=<reason>]
| Argument | Description |
| <id> required | Order id |
| <status> required | Status namekey, e.g. confirmed or shipped |
| Option | Type | Description |
| --notify | flag | Email the customer about the change |
| --reason | string | Note stored with the change |
| Returns | Type | Description |
| id | integer | The order id. |
| status | | The namekey the order now has. |
| changed | | False when the order already had that status. |
| notified | boolean | Whether the customer was actually emailed, which can be false even when you asked, if the status has no notification configured. |
| Can also fail with | Meaning |
| invalid_status | No such status namekey on this shop. |
| not_found | No such order, or the operator may not see it. |
| save_failed | The order could not be saved. |
order:create
Create an empty order for a customer.
Creates an empty order for a customer, to be filled in with lines, fees and an address.
Give it either an existing user_id or a guest with at least an email address, which is how an
order gets taken over the telephone from somebody who has never bought before.
php cli/joomla.php hikashop:order:create [--customer=<customer>] [--guest]
wp hikashop order create [--customer=<customer>] [--guest]
| Option | Type | Description |
| --customer | int | HikaShop customer id |
| --guest | flag | Create it for a guest instead |
| Returns | Type | Description |
| id | integer | The order that was created, to add lines to. |
| Can also fail with | Meaning |
| no_customer | Neither a user_id nor a usable guest was given. |
| save_failed | The order could not be created. |
order:addproduct
Add a product line to an order.
Adds a product to an existing order and re-totals it.
Send a price only to override what the shop would charge; leave it out and the order's own
pricing applies, which is what GET /orders/{id}/products/precompute shows you beforehand.
php cli/joomla.php hikashop:order:addproduct <id> --product=<product> [--quantity=<quantity>] [--price=<price>]
wp hikashop order addproduct <id> --product=<product> [--quantity=<quantity>] [--price=<price>]
| Argument | Description |
| <id> required | Order id |
| Option | Type | Description |
| --product required | int | Product id |
| --quantity | int | How many |
| --price | float | Unit price, the product's own when left out |
| Returns | Type | Description |
| totals | object | The order totalled, so a client need not compute it and disagree with the shop. |
| totals.total | number | What the customer owes, tax included. |
| totals.discount | number | The discount applied, as a positive figure already subtracted. |
| totals.shipping | number | The shipping charged. |
| totals.payment | number | The payment fee charged. |
| totals.tax | number | The tax within the total, not on top of it. |
| items.id | integer | The line id, which is what the line routes take. It is not the product id. |
| items.name | string | The product as it was named when ordered. |
| items.code | string | Its SKU at the time. |
| items.quantity | integer | |
| items.price | number | Unit price, tax excluded, as agreed at the time. |
| items.tax | number | Tax on the line. |
| items.editable | boolean | False once the line can no longer be changed. |
| id | integer | The order. |
| items | object[] | The lines as they now stand, in the same shape as on the order. |
| Can also fail with | Meaning |
| not_found | No such order or product, or the operator may not change the order. |
| save_failed | The order could not be saved. |
Customers
customer:list
List customers.
The customers the operator may see, with enough to recognise one and to know whether they have
bought anything.
Guests are included. A shop that lets people order without an account still has a row for each of
them, and type is how you tell the two apart.
php cli/joomla.php hikashop:customer:list [--search=<search>] [--limit=<limit>] [--start=<start>]
wp hikashop customer list [--search=<search>] [--limit=<limit>] [--start=<start>]
| Option | Type | Description |
| --search | string | Filter on a search term |
| --limit | int | How many to return |
| --start | int | Skip this many first |
| Returns | Type | Description |
| id | | The HikaShop customer id, which is not the CMS user id. |
| name | | The account name, or for a guest the name on their default address, since a guest has no account to take one from. |
| email | | |
| type | | registered for an account, guest for someone who ordered without one. |
| created | | Unix timestamp of the first time the shop saw them. |
| order_count | | How many orders they have placed, so a list can be sorted by worth without a second call. |
In meta | Type | Description |
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
| total | integer | Customers matching the filter, before paging. |
customer:get
Show one customer.
A customer with their addresses, their orders, which groups they are in and your own customer
fields.
can_edit_account and groups_editable are worth reading before drawing a form: they say whether
this operator may change this particular account at all, so a client can leave the controls out
rather than offer something that will be refused. A customer can have many addresses and one
default of each kind.
php cli/joomla.php hikashop:customer:get <id>
wp hikashop customer get <id>
| Argument | Description |
| <id> required | Customer id |
| Returns | Type | Description |
| id | integer | The HikaShop customer id, which is what every customer route takes. |
| cms_id | integer | The Joomla or WordPress user id, 0 for a guest with no account. |
| name | string | |
| email | string | |
| username | string | The login, empty for a guest. |
| type | string | registered or guest. |
| blocked | boolean | Whether the CMS account is disabled. |
| can_edit_account | boolean | Whether this operator may change the login and password of this particular account. False for an account above their own level, which is how a super user is protected from staff. |
| groups_editable | boolean | Whether this operator may change which groups the customer is in. |
| groups | object[] | The groups they are in. |
| groups.id | integer | |
| groups.title | string | |
| available_groups | object[] | Every group, with whether this operator may put the customer into it, so a picker can grey out the rest rather than offering a refusal. |
| available_groups.id | integer | |
| available_groups.title | string | |
| available_groups.assignable | boolean | False for a group this operator may not grant. |
| created | integer | Unix timestamp of the first time the shop saw them. |
| addresses | object[] | Their addresses, defaults first. |
| addresses.id | integer | |
| addresses.types | string[] | Which of billing and shipping it is used for. |
| addresses.name | string | |
| addresses.company | string | |
| addresses.street | string | |
| addresses.city | string | |
| addresses.post_code | string | |
| addresses.telephone | string | |
| addresses.default | boolean | Whether it is the default for one of its types. |
| addresses.formatted | object | The address laid out the way this shop lays addresses out, which depends on its address format setting. |
| addresses.formatted.text | string | Several lines, for an invoice or a label. |
| addresses.formatted.one_line | string | One line, for a list. |
| orders | object[] | Their orders, newest first, enough to list them. |
| orders.id | integer | |
| orders.number | string | The number the customer sees. |
| orders.status | string | A namekey. |
| orders.created | integer | Unix timestamp. |
| orders.total | number | Tax included, in the order currency. |
| orders.currency_id | integer | That currency. |
| fields | object[] | The definitions of your own customer fields. |
| custom_fields | object | Their values, keyed by namekey. |
| custom_field_files | object | For a field holding a file, the file behind the value. |
| Can also fail with | Meaning |
| not_found | No such customer, or the operator may not see them. |
customer:create
Create a customer.
Creates a customer from an email address and a name, as a guest: no account, no password, nothing
for them to log in with.
POST /customers/{id}/account turns one into a registered customer afterwards.
php cli/joomla.php hikashop:customer:create --email=<email> [--name=<name>]
wp hikashop customer create --email=<email> [--name=<name>]
| Option | Type | Description |
| --email required | string | Email address |
| --name | string | Full name |
| Returns | Type | Description |
| id | integer | The customer that was created. |
| Can also fail with | Meaning |
| email_taken | Another customer already has that address. |
| save_failed | The shop refused to save it. |
customer:delete
Delete a customer.
Removes a customer and their addresses.
A customer with orders is refused, which is what the backend does too: delete their orders first,
and then the customer.
php cli/joomla.php hikashop:customer:delete <id> --yes
wp hikashop customer delete <id> --yes
| Argument | Description |
| <id> required | Customer id |
| Returns | Type | Description |
| deleted | boolean | True when the row is gone. |
| Can also fail with | Meaning |
| not_found | No such customer, or the operator may not delete them. |
| has_orders | They have orders. Delete those first. |
| delete_failed | The shop refused to delete the row. |
Categories
category:list
List product categories.
One level of the category tree at a time, unpublished categories included, which is what makes this
a management view rather than a shop one.
Pass a parent_id to walk down. has_children tells you whether there is anything below without
asking, so a tree can be drawn lazily.
HikaShop keeps its manufacturers and its tax categories in the same table as the product
categories, told apart by their root. Ask for the tree you want.
php cli/joomla.php hikashop:category:list
wp hikashop category list
| Returns | Type | Description |
| id | | |
| name | | |
| parent_id | | Its parent, so a flat answer can be rebuilt into a tree. |
| published | | |
| has_children | | Whether anything sits below it. |
| image | string|null | Absolute URL of its image, null when it has none. |
In meta | Type | Description |
| total | integer | Categories matching, before paging. |
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
category:create
Create a product category.
Creates a category under another, or at the top of the product tree when no parent is given.
php cli/joomla.php hikashop:category:create --name=<name>
wp hikashop category create --name=<name>
| Option | Type | Description |
| --name required | string | Category name |
| Returns | Type | Description |
| id | integer | The category that was created. |
| name | string | |
| parent_id | integer | Where it sits. |
| published | boolean | |
| Can also fail with | Meaning |
| invalid_fields | One of your own fields was rejected by its own rules. |
| save_failed | The shop refused to save it. |
category:delete
Delete a product category.
Deletes a category. The products in it are not deleted; they simply stop being in it, and a product
left in no category at all disappears from the shop's listings.
php cli/joomla.php hikashop:category:delete <id> --yes
wp hikashop category delete <id> --yes
| Argument | Description |
| <id> required | Category id |
| Returns | Type | Description |
| id | integer | The category that was deleted. |
| deleted | boolean | True when the row is gone. |
| Can also fail with | Meaning |
| not_found | No such category, or the operator may not delete it. |
Coupons and discounts
discount:list
List coupons and discounts.
Both kinds of reduction live in one table and are told apart by type: a **discount** applies by
itself when its conditions are met, a **coupon** waits for its code to be entered.
The restriction fields are the interesting part, and they are all lists of ids: which products,
which categories, which zones, which customers, and the same again for exclusions. An empty list
means no restriction of that kind rather than none allowed.
php cli/joomla.php hikashop:discount:list [--limit=<limit>] [--start=<start>]
wp hikashop discount list [--limit=<limit>] [--start=<start>]
| Option | Type | Description |
| --limit | int | How many to return |
| --start | int | Skip this many first |
| Returns | Type | Description |
| id | integer | |
| type | string | discount applies by itself, coupon waits for its code. |
| code | string | What the customer types. Empty on a discount. |
| kind | string | Whether the value is a percentage or a fixed amount. |
| value | number | The reduction, read according to kind. |
| currency_id | integer | The currency a fixed amount is in. |
| published | boolean | |
| start | integer|null | Unix timestamp before which it does not apply. |
| end | integer|null | Unix timestamp after which it expires. |
| minimum_order | number | Order total below which it does not apply, 0 for none. |
| maximum_order | number | Order total above which it stops applying, 0 for none. |
| quota | integer | How many times it may be used in total, 0 for no limit. |
| quota_per_user | integer | How many times one customer may use it, 0 for no limit. |
| used_times | integer | How many times it already has been. |
| tax_included | boolean | Whether the value is understood as tax included. |
| tax_id | integer | The tax category of the reduction itself. |
| shipping_percent | number | A reduction on the shipping rather than on the goods. |
| minimum_products | integer | Fewest items in the cart for it to apply. |
| maximum_products | integer | Most items for it to still apply. |
| product_ids | integer[] | Restricted to these products. Empty means all of them. |
| exclude_product_ids | integer[] | Never applies to these. |
| category_ids | integer[] | Restricted to these categories. |
| category_childs | boolean | Whether those categories include their sub-categories. |
| exclude_category_ids | integer[] | Never applies in these categories. |
| exclude_category_childs | boolean | Whether those exclusions include sub-categories. |
| zone_ids | integer[] | Restricted to these zones. |
| user_ids | integer[] | Restricted to these customers. |
| access | object | Who this is for. |
| exclude_access | object | Who this is for. |
| auto_load | boolean | For a coupon, whether the shop applies it without the customer typing it. |
| product_only | boolean | Whether it reduces only the goods and leaves the fees alone. |
| discounted_products | integer | How many products in the cart it applied to, on a discount that has been used. |
| access.mode | string | all, none, or groups when it is restricted to some. |
| access.groups | integer[] | User **group** ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| exclude_access.mode | string | all, none, or groups when it is restricted to some. |
| exclude_access.groups | integer[] | User **group** ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
In meta | Type | Description |
| start | integer | Echoes the offset used. |
| limit | integer | Echoes the page size used. |
| total | integer | Rows matching the filter, before paging. |
discount:create
Create a coupon or a discount.
Creates a reduction and answers with it as the shop stored it.
type decides which kind it is: a coupon needs a code, a discount applies by itself. Either
way value is required, read according to kind.
php cli/joomla.php hikashop:discount:create [--code=<code>] --value=<value> [--kind=<kind>] [--type=<type>] [--published]
wp hikashop discount create [--code=<code>] --value=<value> [--kind=<kind>] [--type=<type>] [--published]
| Option | Type | Description |
| --code | string | Coupon code |
| --value required | float | Amount or percentage |
| --kind | string | percent or flat |
| --type | string | coupon or discount |
| --published | flag | Publish it |
| Returns | Type | Description |
| id | integer | |
| type | string | discount applies by itself, coupon waits for its code. |
| code | string | What the customer types. Empty on a discount. |
| kind | string | Whether the value is a percentage or a fixed amount. |
| value | number | The reduction, read according to kind. |
| currency_id | integer | The currency a fixed amount is in. |
| published | boolean | |
| start | integer|null | Unix timestamp before which it does not apply. |
| end | integer|null | Unix timestamp after which it expires. |
| minimum_order | number | Order total below which it does not apply, 0 for none. |
| maximum_order | number | Order total above which it stops applying, 0 for none. |
| quota | integer | How many times it may be used in total, 0 for no limit. |
| quota_per_user | integer | How many times one customer may use it, 0 for no limit. |
| used_times | integer | How many times it already has been. |
| tax_included | boolean | Whether the value is understood as tax included. |
| tax_id | integer | The tax category of the reduction itself. |
| shipping_percent | number | A reduction on the shipping rather than on the goods. |
| minimum_products | integer | Fewest items in the cart for it to apply. |
| maximum_products | integer | Most items for it to still apply. |
| product_ids | integer[] | Restricted to these products. Empty means all of them. |
| exclude_product_ids | integer[] | Never applies to these. |
| category_ids | integer[] | Restricted to these categories. |
| category_childs | boolean | Whether those categories include their sub-categories. |
| exclude_category_ids | integer[] | Never applies in these categories. |
| exclude_category_childs | boolean | Whether those exclusions include sub-categories. |
| zone_ids | integer[] | Restricted to these zones. |
| user_ids | integer[] | Restricted to these customers. |
| access | object | Who this is for. |
| exclude_access | object | Who this is for. |
| auto_load | boolean | For a coupon, whether the shop applies it without the customer typing it. |
| product_only | boolean | Whether it reduces only the goods and leaves the fees alone. |
| discounted_products | integer | How many products in the cart it applied to, on a discount that has been used. |
| access.mode | string | all, none, or groups when it is restricted to some. |
| access.groups | integer[] | User **group** ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| exclude_access.mode | string | all, none, or groups when it is restricted to some. |
| exclude_access.groups | integer[] | User **group** ids, and not Joomla view levels. The two id spaces overlap and disagree, so a value that looks plausible can grant the wrong audience. |
| Can also fail with | Meaning |
| code_required | A coupon needs a code. |
| code_taken | Another coupon already uses that code. |
| value_required | A reduction needs a value. |
| not_found | Not reachable when creating: the same handler serves the update, where it means no such discount. |
| save_failed | The shop refused to save it. |
discount:delete
Delete a coupon or discount.
Deletes a reduction. Orders that already used it keep the amount they were given: the discount on
an order is a figure, not a pointer at this row.
php cli/joomla.php hikashop:discount:delete <id> --yes
wp hikashop discount delete <id> --yes
| Argument | Description |
| <id> required | Discount id |
| Returns | Type | Description |
| deleted | boolean | True when the row is gone. |
| Can also fail with | Meaning |
| not_found | No such discount, or the operator may not delete it. |
Mass actions
massaction:list
List the shop's own bulk operations.
The mass actions the merchant has configured for a listing, so a client can offer the merchant's own
bulk operations rather than a fixed set of its own.
Whatever they built in the backend appears here, and running one is POST /massactions/{id}.
php cli/joomla.php hikashop:massaction:list [--table=<table>]
wp hikashop massaction list [--table=<table>]
| Option | Type | Description |
| --table | string | Which listing, e.g. product or order |
| Returns | Type | Description |
| id | | What to run. |
| name | | As the merchant named it. |
| description | | Their own note about what it does, when they wrote one. |
| table | | The listing it belongs to. |
| restricted | boolean | Whether it may only run on a selection rather than on everything matching a filter. |
| Can also fail with | Meaning |
| invalid_request | The table is not one the shop has mass actions for. |
| forbidden | The operator may not view that kind of record. |
massaction:run
Run a bulk operation over a selection.
Runs one of the merchant's own bulk operations over a selection.
It runs the same code the backend runs, so whatever the action does there it does here, including
whatever a third-party plugin added to it. Give it the ids to work on.
php cli/joomla.php hikashop:massaction:run <id> --ids=<ids> --yes
wp hikashop massaction run <id> --ids=<ids> --yes
| Argument | Description |
| <id> required | Mass action id |
| Option | Type | Description |
| --ids required | ids, comma separated | Record ids to act on, comma separated |
| Returns | Type | Description |
| ok | boolean | Whether the action reported success. |
| count | integer | How many records it worked on. |
| report | string | Whatever the action had to say, ready to show. Its wording is the action's own. |
| Can also fail with | Meaning |
| invalid_request | No ids were sent, or the action is not one this shop has. |
| forbidden | The operator may not work on that kind of record. |
The shop itself
dbcheck
Bring the database schema up to date, what you want after restoring a dump. Runs inside the site itself and needs no plugin beyond HikaShop.
php cli/joomla.php hikashop:dbcheck
wp hikashop dbcheck
| Returns | Type | Description |
| checked | boolean | Always true once the check has run. |
| report | string[] | What it changed, one line per change. Empty when the schema was already correct. |
shop:statuses
List the shop's order statuses.
Every published order status, in the order the backend shows them. A shop invents its own, so this
list is not a fixed set and should never be hard coded.
The namekey is the identifier to send to POST /orders/{id}/status; the name is for a person
to read.
php cli/joomla.php hikashop:shop:statuses
wp hikashop shop statuses
| Returns | Type | Description |
| namekey | | The identifier. This is what you send when changing an order. |
| name | | Translated into the operator's language, ready to display. |
| label_key | | The translation key behind that name, if you would rather translate it yourself. |
| color | | The colour the backend uses for this status, empty when none is set. |
shop:stats
Show the dashboard totals.
Revenue, orders, average basket and new customers over a period, the same figures again for the
period before it so a change can be shown, the series behind them, and the best sellers.
Only orders the shop counts as sold are included, so a cancelled order does not inflate a total.
Amounts are in the shop's own currency.
php cli/joomla.php hikashop:shop:stats [--range=<range>]
wp hikashop shop stats [--range=<range>]
| Option | Type | Description |
| --range | string | day, week, month or year |
| Returns | Type | Description |
| range | string | The period the figures cover. |
| currency_id | integer | The shop's currency, which every amount here is in. |
| totals | object | The four headline figures. |
| totals.revenue | number | Taken in the period. |
| totals.orders | integer | How many were placed. |
| totals.average_order | number | Revenue divided by orders. |
| totals.customers | integer | New customers in the period. |
| previous | object | The same four figures for the preceding period of the same length, for a comparison. |
| previous.revenue | number | Taken in the preceding period. |
| previous.orders | integer | Placed in it. |
| previous.average_order | number | Its average basket. |
| previous.customers | integer | New customers in it. |
| series_granularity | string | Whether the series is by day, week, month or year, which follows from the range. |
| revenue_series | object[] | One point per interval, for a chart. |
| revenue_series.date | string | The interval, as a date. |
| revenue_series.revenue | number | Taken in it. |
| top_products | object[] | The best sellers of the period. |
| top_products.name | string | |
| top_products.quantity | integer | How many were sold. |
Configuration
config:get
Read one configuration value. Runs inside the site itself and needs no plugin beyond HikaShop.
php cli/joomla.php hikashop:config:get <key>
wp hikashop config get <key>
| Argument | Description |
| <key> required | Configuration key, e.g. main_currency |
| Returns | Type | Description |
| key | string | The key that was read. |
| value | mixed | Its value, as the shop stores it. |
| Can also fail with | Meaning |
| not_found | No configuration key of that name. |
config:set
Change one configuration value. Runs inside the site itself and needs no plugin beyond HikaShop.
php cli/joomla.php hikashop:config:set <key> <value>
wp hikashop config set <key> <value>
| Argument | Description |
| <key> required | Configuration key |
| <value> required | New value |
| Returns | Type | Description |
| key | string | The key that was changed. |
| was | mixed | The value before the change, so a script can put it back. |
| now | mixed | The value after it. |
| Can also fail with | Meaning |
| not_found | No configuration key of that name. This changes existing keys, it does not invent them. |
| save_failed | The configuration could not be written. |
Caches
cache:clean
Empty the shop's caches. Runs inside the site itself and needs no plugin beyond HikaShop.
php cli/joomla.php hikashop:cache:clean
wp hikashop cache clean
| Returns | Type | Description |
| cleaned | string[] | Which caches were emptied: the shop's own plugin cache, and the platform's. |
Cron
cron:run
Run the scheduled tasks the shop would run on a page hit. Runs inside the site itself and needs no plugin beyond HikaShop.
php cli/joomla.php hikashop:cron:run
wp hikashop cron run
| Returns | Type | Description |
| launched | boolean | False when the cron was not due to run yet. |
| messages | string[] | The summary the cron would otherwise have emailed. |
| details | string[] | The detail lines behind that summary. |
| Can also fail with | Meaning |
| cron_disabled | The cron is turned off in the shop configuration. |
Anything the named commands do not cover
Everything the HikaShop Connector API can do is reachable from the command line as well, with the
same paths and the same content the
Connector API
page documents, through a single command:
php cli/joomla.php hikashop:api GET products --query="limit=5&search=shirt"
php cli/joomla.php hikashop:api PUT products/12 --data='{"name":"New name"}'
wp hikashop api POST orders/44/status --data='{"status":"shipped"}'
The body can also be read from a file, or from the output of another program, with
--data-file=<file> or --data-file=- for the standard input.
Examples
# The products lowest on stock
php cli/joomla.php hikashop:product:lowstock --threshold=3
# Every order id waiting to be confirmed, one per line, for a script to loop over
wp hikashop order list --status=created --format=ids
# Create a product and give it a price
php cli/joomla.php hikashop:product:create --name="Blue mug" --code=MUG-BLUE --quantity=40 --published
php cli/joomla.php hikashop:product:price 812 --value=12.50
# Mark an order shipped and tell the customer
wp hikashop order status 44 shipped --notify
# After restoring a backup
php cli/joomla.php hikashop:dbcheck
Running it from a cron
The scheduled tasks of your shop can be run from your server's own scheduler, which is more
reliable than waiting for a visitor to open a page:
0 * * * * cd /path/to/your/site && php cli/joomla.php hikashop:cron:run --live-site=https://www.example.com
0 * * * * wp --path=/path/to/your/site hikashop cron run
The older cli/hikashop_cron.php script still works and does the same thing, so a cron
entry that already uses it does not need changing.