From cc30654d892bdc2ba1f31b456de86502a4c7f81a Mon Sep 17 00:00:00 2001 From: Stephen Callender Date: Wed, 13 May 2026 12:54:33 -0400 Subject: [PATCH] Rewrite docs, final --- CHANGELOG.md | 1 + README.md | 60 +++++++- docs/README.md | 25 ---- docs/dev-guide/custom-queue.md | 74 ++++++++++ docs/dev-guide/template-tags.md | 69 +++++++++ docs/dev-guide/twig-queries.md | 103 +++++++++++++ docs/element-queries/variant-queries.md | 76 ---------- docs/getting-started.md | 119 +++++++++++++++ docs/getting-started/configuration.md | 111 -------------- docs/getting-started/field.md | 31 ---- docs/getting-started/permissions.md | 26 ---- docs/getting-started/setup.md | 39 ----- docs/index.md | 23 +++ docs/installation.md | 96 ++++++++++++ docs/recipes/add-to-cart.md | 64 ++++---- docs/recipes/variant-filter.md | 84 +++++------ docs/reference/configuration.md | 186 ++++++++++++++++++++++++ docs/reference/console-commands.md | 23 +++ docs/reference/field-type.md | 63 ++++++++ docs/reference/permissions.md | 14 ++ docs/templates/function-reference.md | 86 ----------- docs/usage/exporting.md | 15 -- docs/usage/importing.md | 60 -------- docs/usage/overview.md | 76 ---------- docs/usage/queues.md | 54 ------- docs/user-guide/activity-log.md | 60 ++++++++ docs/user-guide/bulk-import.md | 72 +++++++++ docs/user-guide/csv-format.md | 153 +++++++++++++++++++ docs/user-guide/exporting.md | 81 +++++++++++ docs/user-guide/importing.md | 111 ++++++++++++++ docs/user-guide/permissions.md | 26 ++++ docs/user-guide/troubleshooting.md | 136 +++++++++++++++++ 32 files changed, 1536 insertions(+), 681 deletions(-) delete mode 100644 docs/README.md create mode 100644 docs/dev-guide/custom-queue.md create mode 100644 docs/dev-guide/template-tags.md create mode 100644 docs/dev-guide/twig-queries.md delete mode 100644 docs/element-queries/variant-queries.md create mode 100644 docs/getting-started.md delete mode 100644 docs/getting-started/configuration.md delete mode 100644 docs/getting-started/field.md delete mode 100644 docs/getting-started/permissions.md delete mode 100644 docs/getting-started/setup.md create mode 100644 docs/index.md create mode 100644 docs/installation.md create mode 100644 docs/reference/configuration.md create mode 100644 docs/reference/console-commands.md create mode 100644 docs/reference/field-type.md create mode 100644 docs/reference/permissions.md delete mode 100644 docs/templates/function-reference.md delete mode 100644 docs/usage/exporting.md delete mode 100644 docs/usage/importing.md delete mode 100644 docs/usage/overview.md delete mode 100644 docs/usage/queues.md create mode 100644 docs/user-guide/activity-log.md create mode 100644 docs/user-guide/bulk-import.md create mode 100644 docs/user-guide/csv-format.md create mode 100644 docs/user-guide/exporting.md create mode 100644 docs/user-guide/importing.md create mode 100644 docs/user-guide/permissions.md create mode 100644 docs/user-guide/troubleshooting.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 96774cf..67799d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Add optional `status` column for product imports and exports. - Refactor the Export Product sidebar button. - Set `promotable` to true by default +- Rewrote docs ## 2.0.5 - 2026-02-19 diff --git a/README.md b/README.md index d5d89cb..6e82c14 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,60 @@ -![Screenshot](resources/img/header.png) +![Variant Manager](resources/img/header.png) + # Variant Manager -A plugin for managing products and their variants in Craft Commerce. +A Craft CMS plugin that imports and exports Craft Commerce product **variants** from CSV files. + +## What it does + +- Imports a CSV to create or update a Craft Commerce product and its variants. +- Bulk-imports many products at once from a zip of CSVs, each file becoming its own product. +- Exports a product to CSV from the product edit page, or many products at once from the Variants element index. +- Adds a **Variant Attributes** field that stores option name and value pairs (Color, Size, Material) on each variant for filtering on the storefront. +- Logs each import and export, with configurable retention, in a dashboard activity feed. + +## Requirements + +- Craft CMS `^5.0` +- Craft Commerce `^5.0` +- PHP `^8.2` + +## Install + +```sh +composer require fostercommerce/variant-manager +./craft plugin/install variant-manager +``` + +See [`docs/installation.md`](./docs/installation.md) for the full installation and configuration guide. + +## Importing + +Upload a CSV (or a zip of CSVs) from **Variant Manager -> Dashboard**. The CSV's filename determines the product: a new filename creates a new product, an existing product title updates that product. Each row becomes one variant. Columns map to product fields, variant fields, per-site Commerce fields, inventory levels, and variant attributes. + +See [`docs/user-guide/importing.md`](./docs/user-guide/importing.md) and [`docs/user-guide/csv-format.md`](./docs/user-guide/csv-format.md). + +## Exporting + +Two ways to export: from a single product's edit page (sidebar **Export Product** button), or from the **Variants** element index using the **Export Variant Data** action on a multi-select. A single product downloads as one CSV; multiple products download as a zip. Exported CSVs are shaped so they can be reimported without edits to the column headers. + +See [`docs/user-guide/exporting.md`](./docs/user-guide/exporting.md). + +## Variant Attributes field + +The plugin ships a **Variant Attributes** field type that you add to each product type's variant field layout. The field stores the option-name and option-value pairs from your CSV (Color: Red, Size: Small) as JSON on the variant, and exposes them to Twig for variant selectors and faceted filtering. + +See [`docs/reference/field-type.md`](./docs/reference/field-type.md) for storage and Twig usage. + +## Permissions + +In addition to `accessPlugin-variant-manager`: + +- `variant-manager:import`, upload CSVs and create or update products and variants. +- `variant-manager:export`, export products from the product edit page or the variants index. +- `variant-manager:manage`, clear the activity log and manage plugin data. + +See [`docs/reference/permissions.md`](./docs/reference/permissions.md). -## Setup and Usage +## License -[See docs](/docs) +Proprietary. diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 94ddace..0000000 --- a/docs/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Variant Manager Docs - -## Getting started - -1. [Setup](getting-started/setup.md) -2. [Configuration](getting-started/configuration.md) -3. [Field Type](getting-started/field.md) -4. [Permissions](getting-started/permissions.md) - -## Usage - -1. [Overview](usage/overview.md) -2. [Importing Product Variants](usage/importing.md) -3. [Exporting Product Variants](usage/exporting.md) -4. [Queues](usage/queues.md) - -## Templating - -1. [Template Tags](templates/function-reference.md) -2. [Querying Variants](element-queries/variant-queries.md) - -## Template Recipes - -1. [Select a variant and add to cart](recipes/add-to-cart.md) -1. [Filter variants based on a selection examples](recipes/variant-filter.md) diff --git a/docs/dev-guide/custom-queue.md b/docs/dev-guide/custom-queue.md new file mode 100644 index 0000000..2bfcb58 --- /dev/null +++ b/docs/dev-guide/custom-queue.md @@ -0,0 +1,74 @@ +# Custom queue + +How to keep Variant Manager's import jobs from delaying other Craft queue work. Audience: developers running production sites with high queue volume. + +Bulk imports can generate thousands of import jobs. By default they go on Craft's main queue, which means other Craft work (search index rebuilds, image transforms, emails) can sit behind a long import batch. + +Two ways to address this: lower the priority of Variant Manager jobs, or send them to a custom queue. + +## Lower job priority + +In a site module, listen for `Queue::EVENT_BEFORE_PUSH` and bump the priority of `ImportJob` instances. Higher priority numbers run later. + +```php +use fostercommerce\variantmanager\jobs\Import as ImportJob; +use yii\base\Event; +use yii\queue\PushEvent; +use yii\queue\Queue; + +Event::on( + Queue::class, + Queue::EVENT_BEFORE_PUSH, + static function (PushEvent $event): void { + if ($event->job instanceof ImportJob) { + // UpdateSearchIndex jobs have a priority of 2048; pushing above that means imports run after search updates. + $event->priority = 2049; + } + } +); +``` + +Wire this into your module's `init()` method. + +## Run imports on a dedicated queue + +Configure Variant Manager to push its jobs to a separate Yii queue, so they run on a different worker (or run alongside the main queue without blocking it). + +In `config/app.php`: + +```php +return [ + 'bootstrap' => ['priorityQueue'], + 'components' => [ + 'plugins' => [ + 'pluginConfigs' => [ + 'variant-manager' => [ + 'queue' => 'priorityQueue', + ], + ], + ], + 'priorityQueue' => [ + 'class' => \craft\queue\Queue::class, + 'channel' => 'priority', + ], + ], +]; +``` + +The string `priorityQueue` is the component handle Variant Manager will resolve at runtime; it can be anything as long as the component is registered. + +Then run the worker for the custom queue separately: + +```sh +./craft queue/run --queue=priorityQueue +``` + +See Craft's [custom queues guide](https://craftcms.com/docs/5.x/system/queue.html#custom-queues) for more on how Yii's queue components are wired up. + +## Verifying it works + +1. Upload a small CSV from **Variant Manager -> Dashboard**. The upload modal returns "File ... has been queued for processing" as usual. +2. With the main queue worker stopped, check the dashboard activity log; the new row stays in its pending state because the main queue does not own the job. +3. Start the custom queue worker: `./craft queue/run --queue=priorityQueue`. +4. Refresh the dashboard. The activity log row flips to the green-dot success state once the worker drains the import. +5. For the priority approach, push two jobs back to back (an import and a search index rebuild) and confirm the search rebuild runs first. diff --git a/docs/dev-guide/template-tags.md b/docs/dev-guide/template-tags.md new file mode 100644 index 0000000..2d716f3 --- /dev/null +++ b/docs/dev-guide/template-tags.md @@ -0,0 +1,69 @@ +# Template tags + +Twig helpers Variant Manager exposes on the `craft` variable for use in storefront templates. + +## `craft.variantManager.getAttributeOptions(product, only?)` + +Returns the distinct attribute names and the unique values used across a product's variants. Useful for building variant pickers and faceted filters. + +Parameters: + +- `product`: a `Product` element or a product ID. +- `only` (optional): a string or array of attribute names to limit the result to. + +Returns an array of associative arrays, each with: + +- `name`: the attribute name. +- `values`: a deduplicated array of every value used by any variant for that attribute. + +### Example output + +```twig +{% set attributeOptions = craft.variantManager.getAttributeOptions(product.id) %} +{{ attributeOptions | json_encode }} +``` + +Renders something like: + +```json +[ + { "name": "Color", "values": ["Red", "Blue"] }, + { "name": "Size", "values": ["Small", "Medium", "Large"] } +] +``` + +### Example: build a radio picker for every attribute + +```twig +{% set product = craft.products().id(30).one() %} + +{% for attribute in craft.variantManager.getAttributeOptions(product) %} +
+ {{ attribute.name }} + {% for value in attribute.values %} + + {% endfor %} +
+{% endfor %} +``` + +### Example: limit to specific attributes + +```twig +{% set colorsAndSizes = craft.variantManager.getAttributeOptions(product, ['Color', 'Size']) %} +``` + +Pass a single string for one attribute: + +```twig +{% set colors = craft.variantManager.getAttributeOptions(product, 'Color') %} +``` + +## Related + +- [Querying variants](./twig-queries.md), filtering `craft.variants()` by attribute values. +- [Add to cart recipe](../recipes/add-to-cart.md), a full variant picker that adds to cart. +- [Variant filter recipe](../recipes/variant-filter.md), client-side filtering examples. diff --git a/docs/dev-guide/twig-queries.md b/docs/dev-guide/twig-queries.md new file mode 100644 index 0000000..66b53fb --- /dev/null +++ b/docs/dev-guide/twig-queries.md @@ -0,0 +1,103 @@ +# Querying variants + +How to filter Commerce variants by their Variant Attributes field. Audience: developers building storefront templates or PHP code that queries variants. + +Substitute the handle you gave your Variant Attributes field (`variantAttributes`, `myVariantAttributes`, anything you chose) for `variantAttributes` in the examples below. + +## Three filter shapes + +The Variant Attributes field accepts: + +1. A string. Returns variants that have **any** attribute with that value. +2. An associative array. Returns variants that match **every** name/value pair. +3. A list of strings and/or associative arrays. Returns variants that match **any** of the entries. + +## Filter by an option value + +Find variants whose Variant Attributes contains the value `Red` under any attribute name. + +PHP: + +```php +\craft\commerce\elements\Variant::find() + ->variantAttributes('Red') + ->all(); +``` + +Twig: + +```twig +{% set variants = craft.variants().variantAttributes('Red').all() %} +``` + +## Filter by all attribute and option pairs (AND) + +Find variants that have `Color = Red` AND `Size = Small`. + +PHP: + +```php +\craft\commerce\elements\Variant::find() + ->variantAttributes([ + 'Color' => 'Red', + 'Size' => 'Small', + ]) + ->all(); +``` + +Twig: + +```twig +{% set filter = { + 'Color': 'Red', + 'Size': 'Small' +} %} +{% set variants = craft.variants().variantAttributes(filter).all() %} +``` + +## Filter by any attribute and option pair (OR) + +Find variants that match any of the entries in a list. Each entry can be a value-only string or a `Name => Value` pair. + +PHP: + +```php +\craft\commerce\elements\Variant::find() + ->variantAttributes([ + ['Color' => 'Red'], + 'Cotton', + ['Size' => 'Small'], + ]) + ->all(); +``` + +Twig: + +```twig +{% set filter = [ + { 'Color': 'Red' }, + 'Cotton', + { 'Size': 'Small' } +] %} +{% set variants = craft.variants().variantAttributes(filter).all() %} +``` + +## How it works + +The field stores attributes as JSON. The query builder generates database conditions tailored to your database: + +- MySQL: `json_search()` against the field's JSON path, with one condition per name/value pair. +- PostgreSQL: `@>` containment against the JSON column. + +You do not need to do anything special to enable this; both paths are picked automatically. + +## Errors + +- `$value items must be associative arrays or strings`: a list entry was neither. Check that every element of the array is a string or an `{ name: value }` map. +- `$value must be either an array or a string`: a non-string, non-array value was passed (a number, a Date, an Element). Convert to a string before passing. + +## Related + +- [Template tags](./template-tags.md), the `getAttributeOptions` helper. +- [Add to cart recipe](../recipes/add-to-cart.md). +- [Variant filter recipe](../recipes/variant-filter.md). diff --git a/docs/element-queries/variant-queries.md b/docs/element-queries/variant-queries.md deleted file mode 100644 index a326494..0000000 --- a/docs/element-queries/variant-queries.md +++ /dev/null @@ -1,76 +0,0 @@ -# Querying Variants - -If a `VariantAttributesField` is attached to a product types variants, then it is possible to use that field to filter -variants by the attributes and options stored in that field. - -The Variant Attributes field accepts 3 formats of filters: - -- Filter by an option value, regardless of attribute; -- Filter _all_ provided attribute/option pairs; -- And, filter by any of the provided attribute/option pairs. - -## Filter by an option value - -The following will return all variants which have the option `'Value'`: - -#### PHP - -```php -\craft\commerce\elements\Variant::find()->myVariantAttributes('Value')->all(); -``` - -#### Twig - -```twig -{% craft.variants().myVariantAttributes("Value").all() %} -``` - -## Filter by all attribute/option pairs - -The following will return all variants which have an attribute of `Attribute A` with a value of `Value A1`, _and_ an -attribute of `Attribute B` with a value of `Value B1`. - -#### PHP - -```php -\craft\commerce\elements\Variant::find()->myVariantAttributes([ - 'Attribute A' => 'Value A1', - 'Attribute B' => 'Value B1', -])->all(); -``` - -#### Twig - -```twig -{% set filter = { - 'Attribute A': 'Value A1', - 'Attribute B': 'Value B1', -} %} -{% set variants = craft.variants().myVariantAttributes(filter).all() %} -``` - -## Filter by any attribute/option pairs - -The following will return all variants which have an attribute of `Attribute A` with a value of `Value A1`, _or_ any -option value of `Value`, _or_ an attribute of `Attribute B` with a value of `Value B1`. - -#### PHP - -```php -\craft\commerce\elements\Variant::find()->myVariantAttributes([ - ['Attribute A' => 'Value A1'], - 'Value', - ['Attribute B' => 'Value B1'], -])->all(); -``` - -#### Twig - -```twig -{% set filter = { - {'Attribute A': 'Value A1'}, - 'Value', - {'Attribute B': 'Value B1'}, -} %} -{% set variants = craft.variants().myVariantAttributes(filter).all() %} -``` diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..80978bd --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,119 @@ +# Getting started + +This walks you from `composer require` to your first successful CSV import. By the end you will have a Commerce product whose variants came in from a spreadsheet, and you will know the round-trip flow for editing it. + +## 1. Install + +```sh +composer require fostercommerce/variant-manager +./craft plugin/install variant-manager +``` + +In the CP you should see a **Variant Manager** nav item with two subnav entries: **Dashboard** and **Variants**. + +## 2. Configure + +Create `config/variant-manager.php`: + +```php + '', + 'attributePrefix' => 'Attribute: ', + 'inventoryPrefix' => 'Inventory', + 'activityLogRetention' => '30 days', + 'productFieldMap' => [ + '*' => [ + 'title' => 'title', + 'slug' => 'slug', + 'status' => 'status', + ], + ], + 'variantFieldMap' => [ + '*' => [ + 'title' => 'title', + 'sku' => 'sku', + 'inventoryTracked' => 'inventoryTracked', + 'price' => 'basePrice', + 'height' => 'height', + 'width' => 'width', + 'length' => 'length', + 'weight' => 'weight', + ], + ], +]; +``` + +All keys have defaults; you can skip the file entirely and revisit it once you know which fields you want to import. + +## 3. Add the Variant Attributes field + +The plugin needs a place to store option name and value pairs (Color: Red, Size: Small) on each variant. + +1. **Settings -> Fields -> New field**. +2. **Field Type**: **Variant Attributes**. Name it **Variant Attributes**, handle `variantAttributes`. No further settings needed. +3. **Commerce -> Settings -> Product Types -> {your product type} -> Variant Fields**. Drag the new field onto the layout. Save. + +You only need one Variant Attributes field per product type's variant layout. Extras are ignored. + +## 4. Build your first CSV + +Create a file called `Demo Shirt.csv` with this content: + +```csv +title,sku,basePrice[default],inventoryTracked[default],Attribute: Color,Attribute: Size +Demo Shirt,,,,, +,DEMO-RED-S,19.99,1,Red,Small +,DEMO-RED-M,19.99,1,Red,Medium +,DEMO-BLUE-S,19.99,1,Blue,Small +,DEMO-BLUE-M,19.99,1,Blue,Medium +``` + +The filename matters: `Demo Shirt.csv` tells Variant Manager you want to create a new product titled `Demo Shirt`. Row 2's first cell repeats the title; rows 3-6 are the four variants. + +`basePrice[default]` is per-site; replace `default` with your site's handle if it is different. See [CSV format](./user-guide/csv-format.md) for the rest of the columns. + +## 5. Upload + +**Variant Manager -> Dashboard -> Upload Product**. Pick `Demo Shirt.csv`. + +The modal opens with "Are you sure you want to create a new product?" and a **Product Type** dropdown. Pick the product type you added the Variant Attributes field to. Click **Create Product**. + +You will see "File Demo Shirt.csv has been queued for processing" and the page refreshes. Once the queue runs the import job, the dashboard's activity log shows a green-dot row: "Imported new product Demo Shirt into {your product type}." + +If your queue is not running automatically, run `./craft queue/run`. + +## 6. Verify in Commerce + +Click the product link in the activity log row. The product opens at **Commerce -> Products -> Demo Shirt**. + +Check the variants tab: + +- Four variants: DEMO-RED-S, DEMO-RED-M, DEMO-BLUE-S, DEMO-BLUE-M. +- Each has its price set to 19.99 and inventory tracking on. +- Open one variant. Scroll to the Variant Attributes field; you should see Color and Size with the value for that variant. + +## 7. Round-trip: export, edit, reimport + +This is the workflow you will use to bulk-edit existing products. + +1. On the product edit page, click **Export Product** in the sidebar. A file called `{id}__demo-shirt.csv` downloads. +2. Open it in your spreadsheet app. You will see the row layout the import produced, with every Commerce column the plugin can write to. +3. Change something. Bump the price on DEMO-RED-S to 21.99. +4. Save the file. **Do not rename it.** +5. Back to **Variant Manager -> Dashboard -> Upload Product** and pick the same file. +6. The modal recognises the existing product and asks "Are you sure you want to edit an existing product named \"Demo Shirt\"?" with a **Refresh variants** radio group. Leave it on **Update and remove extra variants** (the default) and click **Edit Product**. +7. Activity log shows another green-dot row. Reopen the product; DEMO-RED-S is now 21.99. + +## 8. Where to go next + +For deeper reading: + +- [CSV format](./user-guide/csv-format.md), every column the import recognises, with formatting rules. +- [Importing](./user-guide/importing.md), the upload flow in detail, including the choice between updating and replacing variants. +- [Exporting](./user-guide/exporting.md), single-product and bulk export. +- [Bulk import](./user-guide/bulk-import.md), uploading a zip of CSVs. +- [Troubleshooting](./user-guide/troubleshooting.md), when imports fail. +- [Variant Attributes field](./reference/field-type.md), how the attribute data is stored and read. +- [Template tags](./dev-guide/template-tags.md) and [recipes](./recipes/add-to-cart.md), using the attributes on the storefront. diff --git a/docs/getting-started/configuration.md b/docs/getting-started/configuration.md deleted file mode 100644 index a731552..0000000 --- a/docs/getting-started/configuration.md +++ /dev/null @@ -1,111 +0,0 @@ -# Configuration - -Create a `variant-manager.php` file in your `config` directory. The following shows the defaults applied by Variant Manager: - -```php - '', - 'attributePrefix' => 'Attribute: ', - 'inventoryPrefix' => 'Inventory: ', - 'activityLogRetention' => '30 days', - 'productFieldMap' => [ - '*' => [ - 'title' => 'title', - 'slug' => 'slug', - 'status' => 'status', - ], - ], - 'variantFieldMap' => [ - '*' => [ - 'title' => 'title', - 'sku' => 'sku', - 'inventoryTracked' => 'inventoryTracked', - 'price' => 'basePrice', - 'height' => 'height', - 'width' => 'width', - 'length' => 'length', - 'weight' => 'weight', - ], - ], -]; -``` - -## Configuration options - -### Variant Attributes - -When a variant has a `VariantAttributesField` field, the following config options will be used. - -**Note** that variant fields may only have a single VariantAttributes field. Any additional fields will be ignored by the plugin. - -#### `emptyAttributeValue` - -The value to use when a variant's attribute value is empty. - -#### `attributePrefix` - -The prefix to use to determine which columns correspond to variant attributes when importing/exporting product variants. - -#### `inventoryPrefix` - -The prefix to use to determine which columns correspond to variant inventory counts when importing/exporting product variants. - -#### `activityLogRetention` - -The duration for which activity logs should be retained. Accepts values like '1 week', '30 days', etc. Set to `null` or `false` to retain logs indefinitely. - -When enabled, activity logs outside the retention period are automatically removed during GC. - -Activity logs can also be removed using the `variant-manager/activities/clear` command. Pass `all` to the command to remove all activity logs. - -### `productFieldMap` - -The map of column names to product properties. - -Supported field types and formatting: - -- title -- slug -- status -- entries - -#### `status` column - -Optional. Exports write `enabled` or `disabled`. Imports accept `disabled` (case-insensitive, whitespace trimmed) as disabled; any other value or empty cell imports as enabled. Remove the `'status' => 'status'` entry from `productFieldMap` to skip. - -### `variantFieldMap` - -The map of column names to variant properties. - -This map does _not_ need to include the handle for the VariantAttributes field. - -This config option accepts a `'*'` key which would apply the mapping to any product type which isn't included in the map. For example, if you had a product type with an extra field you can include that field with the following config: - -```php - 'sku', - 'stock' => 'stock', - 'price' => 'price', - 'height' => 'height', - 'width' => 'width', - 'length' => 'length', - 'weight' => 'weight', -]; - -return [ - 'emptyAttributeValue' => 'None', - 'attributePrefix' => 'Option : ', - 'activityLogRetention' => '30 days', - 'variantFieldMap' => [ - "*" => $defaultFieldMap, - 'general' => array_merge( - $defaultFieldMap, - ['notes' => 'notes'] - ), - ], -]; -``` diff --git a/docs/getting-started/field.md b/docs/getting-started/field.md deleted file mode 100644 index 513692e..0000000 --- a/docs/getting-started/field.md +++ /dev/null @@ -1,31 +0,0 @@ -# The Variant Attributes Field - -Variant Manager provides a "Variant Attributes" custom field type you need to add to your Craft Commerce variant field -layouts. This field is used by Variant Manager to save the variant attribute name and value pairs when imports occur, -and can be used in your Twig templates to allow users to [select a variant and add to cart](recipes/add-to-cart.md) or -[filter variants based on a selection](../recipes/variant-filter.md). - -Content for this field can only be added via Variant Manager's import utility. Once added, a row's value field can be -manually edited, however, the name cannot. This is intentional to reduce human error. - -![Screenshot](../../resources/img/field-display.png) - -## Add the Variant Attributes field to your product types variants - -In order for Variant Manager to import your variant data from your spreadsheets, and to use Twig tags in your templates -to filter and select variants, you will first need to add the "Variant Attributes" custom field included in Variant -Manager to your product type's variant field layouts. - -### 1. Create a "Variant Attributes" field in Craft - -Create a new custom field in Craft and select the "Variant Attributes" field type. The field type has no settings so you -just need to give it a unique name and field handle (ex. "Variant Attributes" and "variantAttributes" respectively). - -![Screenshot](../../resources/img/field-new.png) - -### 2. Assign it to your product types variant fields - -Now add the custom field you created to your product types variant field layouts for all of your product types that you -want to be able to import and export, and use twig tags for in your templates to filter and select variants. - -![Screenshot](../../resources/img/field-add.png) diff --git a/docs/getting-started/permissions.md b/docs/getting-started/permissions.md deleted file mode 100644 index d3de5df..0000000 --- a/docs/getting-started/permissions.md +++ /dev/null @@ -1,26 +0,0 @@ -# Permissions - -Variant Manager includes two permissions; One for importing products and variants and one for exporting. - -![Screenshot](../../resources/img/permissions.png) - -These can be set on user groups in the Settings → Users section in Craft, or also on specific users in their Permissions -tab. The two permission settings are : - -## Import products and variants - -Allows users to import products through the Variant Manager dashboard. - -#### `variant-manager:import` - -## Export products and variants - -Allows users to export products from Craft Commerce's product list or from individual products. - -#### `variant-manager:export` - -## Manage - -Allows users to manage plugin data, such as clearing activity logs. - -#### `variant-manager:manage` diff --git a/docs/getting-started/setup.md b/docs/getting-started/setup.md deleted file mode 100644 index a1f1245..0000000 --- a/docs/getting-started/setup.md +++ /dev/null @@ -1,39 +0,0 @@ - -# Setup - -## Requirements - -- Craft CMS 5.0 or later -- Craft Commerce 5.0 or later -- PHP 8.2 or greater - -## Installation - -You can install this plugin from the Plugin Store or with Composer. - -#### From the Plugin Store - -Go to the Plugin Store in your project’s Control Panel and search for “Variant Manager”. Then press “Install”. - -#### With Composer - -Open your terminal and run the following commands: - -```bash -# go to the project directory -cd /path/to/my-project.test - -# tell Composer to load the plugin -composer require fostercommerce/variant-manager - -# tell Craft to install the plugin -./craft plugin/install variant-manager -``` - -#### With DDEV - -Run the following command from DDEV: - -```bash -ddev composer require fostercommerce/variant-manager -w && ddev exec php craft plugin/install variant-manager -``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..3a5e11b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,23 @@ +# Variant Manager documentation + +Import and export Craft Commerce product variants from CSV files. + +## Where to go + +**First time here?** Start with [Getting started](./getting-started.md), a walkthrough from install to your first successful CSV import. + +**Building or editing CSVs for a Craft Commerce store?** See the [user guide](./user-guide/): + +- [CSV format](./user-guide/csv-format.md), every column the import recognises, with a working example. +- [Importing](./user-guide/importing.md), uploading single CSVs and zip batches. +- [Exporting](./user-guide/exporting.md), getting CSVs out of Commerce to edit. +- [Troubleshooting](./user-guide/troubleshooting.md), when an import does not behave the way you expected. + +**Building on top of the plugin?** See the [developer guide](./dev-guide/), [recipes](./recipes/), and [reference](./reference/): + +- [Template tags and queries](./dev-guide/template-tags.md), reading and filtering Variant Attributes in Twig. +- [Recipes](./recipes/add-to-cart.md), full storefront examples for variant pickers and faceted filtering. +- [Custom queue](./dev-guide/custom-queue.md), running imports on a dedicated queue. +- [Configuration reference](./reference/configuration.md), every config key with defaults. + +**Setup details:** [Installation](./installation.md). diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..25111ae --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,96 @@ +# Installation + +A Craft CMS plugin that manages Craft Commerce product variants from CSV files. + +## Requirements + +- Craft CMS `^5.0` +- Craft Commerce `^5.0` +- PHP `^8.2` + +## Install + +From the Plugin Store, search for **Variant Manager** in **Settings -> Plugins** and press **Install**. + +With Composer: + +```sh +composer require fostercommerce/variant-manager +./craft plugin/install variant-manager +``` + +With DDEV: + +```sh +ddev composer require fostercommerce/variant-manager -w && ddev exec php craft plugin/install variant-manager +``` + +After install you will see a **Variant Manager** item in the CP navigation with two subnav entries: **Dashboard** and **Variants**. + +## Configure + +Settings live in a config file, not the Control Panel. Create `config/variant-manager.php`: + +```php + '', + 'attributePrefix' => 'Attribute: ', + 'inventoryPrefix' => 'Inventory', + 'activityLogRetention' => '30 days', + 'productFieldMap' => [ + '*' => [ + 'title' => 'title', + 'slug' => 'slug', + 'status' => 'status', + ], + ], + 'variantFieldMap' => [ + '*' => [ + 'title' => 'title', + 'sku' => 'sku', + 'inventoryTracked' => 'inventoryTracked', + 'price' => 'basePrice', + 'height' => 'height', + 'width' => 'width', + 'length' => 'length', + 'weight' => 'weight', + ], + ], +]; +``` + +Every key has a default; the plugin runs without the file. See [configuration reference](./reference/configuration.md) for what each key controls. + +## Add the Variant Attributes field + +The plugin ships a **Variant Attributes** field type. Add it to every Commerce product type whose variants you want to import or export by attribute. + +1. **Settings -> Fields -> New field**. +2. Set the **Field Type** to **Variant Attributes**. Give it a name and handle, for example `variantAttributes`. The field has no settings of its own. +3. **Commerce -> Settings -> Product Types -> {product type} -> Variant Fields** and drag the field into the variant field layout. + +Only one Variant Attributes field per variant field layout is read by the plugin. Additional copies are ignored. + +See [Variant Attributes field reference](./reference/field-type.md) for how the field stores data. + +## Permissions + +Grant the plugin's permissions on user groups in **Users -> {group} -> Permissions** or on individual users: + +- `variant-manager:import`, upload CSVs and create or update products and variants. +- `variant-manager:export`, export products from the product edit page or the variants index. +- `variant-manager:manage`, clear the activity log and manage plugin data. + +`accessPlugin-variant-manager` is required to see the plugin's CP section at all. + +See [permissions reference](./reference/permissions.md). + +## Console commands + +```sh +./craft variant-manager/activities/clear +``` + +Deletes activity log entries older than `activityLogRetention`. Pass `--all` to wipe every entry regardless of age. Craft's garbage collection runs the same expiry pass automatically. See [console commands](./reference/console-commands.md). diff --git a/docs/recipes/add-to-cart.md b/docs/recipes/add-to-cart.md index 29f11d3..1d123cc 100644 --- a/docs/recipes/add-to-cart.md +++ b/docs/recipes/add-to-cart.md @@ -1,14 +1,16 @@ -# Variant switcher +# Recipe: select a variant and add to cart -Select a variant based on a it's attributes and add it to the cart. +A full storefront example: a product page with a select element for every attribute (Color, Size, Material), where changing a selection picks the matching variant and the form adds that variant to the cart on submit. + +Replace `variantAttributes` with the handle of your Variant Attributes field. ## Twig ```twig {% set attributeOptions = craft.variantManager.getAttributeOptions(product.id) %} -{% set selection={} %} +{% set selection = {} %} {% for attribute in attributeOptions %} - {# Find the selected option for the attribute using the kebab case of the attribute name #} + {# Find the selected option for the attribute using a kebab-case query param #} {% set selected = craft.app.request.getParam(attribute.name|kebab|ascii) ?? attribute.values|first %} {% set selection = selection|merge({(attribute.name): selected}) %} {% endfor %} @@ -20,22 +22,20 @@ Select a variant based on a it's attributes and add it to the cart. {{ hiddenInput('purchasableId', variant.id) }}
-

{{ product.title }}

-
-
{{ variant.onPromotion ? variant.salePriceAsCurrency : variant.priceAsCurrency }} - {% if variant.onPromotion %} - - (was {{ variant.priceAsCurrency }}) - - {% endif %} -
-
+

{{ product.title }}

+
+ {{ variant.onPromotion ? variant.salePriceAsCurrency : variant.priceAsCurrency }} + {% if variant.onPromotion %} + + (was {{ variant.priceAsCurrency }}) + + {% endif %} +
- {# Show variant selections #} {% for attribute in attributeOptions %}