Product Import — How It Works

Overview

Products in the Laravel shop are not managed directly. They are imported from the CakePHP image processing tool (tool.rugartisan.com), which is the source of truth for the product catalog. The import is triggered manually via an Artisan command and pulls data through an HTTP API.


Systems Involved

System Role Port
tool.rugartisan.com Source of truth — designs, products, pricing, images api.rugartisan.com (API), tool.rugartisan.com (media)
rugartisan.com Storefront — receives and stores imported products 8001

The two systems have separate databases. Laravel stores a copy of the product data after import, along with ra_product_id as a foreign key back to the CakePHP product.


Running the Import

php artisan import:run {design_category} {local_category_name}

Arguments

Argument Description Example
design_category Category slug on the CakePHP side — filters which products the API returns geometric
local_category_name Category name in Laravel's DB — the category imported products are assigned to "Geometric"

Example

php artisan import:run geometric "Geometric"

This fetches all products tagged geometric from the CakePHP API and assigns them to the "Geometric" collection category in Laravel.

If no arguments are passed, design_category is empty (returns all products from CakePHP) and products will have no category assigned.

Note: There is no UI button for this. It must be run manually from the terminal over SSH.


What the Command Does (Step by Step)

Step 1 — Sync Colors

Calls POST /api/getColors and upserts results into Laravel's attribute_options table for the color attribute. New colors are added; existing ones (matched by seo_name/slug) are updated.

Step 2 — Sync Tags

Calls POST /api/getTags and upserts results into attribute_options for the producttags attribute. Same upsert logic as colors.

Step 3 — Fetch Products from CakePHP

POST https://api.rugartisan.com/api/export?category={design_category}

Returns a flat array of product records. Each record contains SKU, name, weaving type, material, shape, pricing per currency, image URLs, tags, available customization options, and more.

Authentication uses authkey and token headers (configured via API_ENDPOINT_AUTH_KEY and API_ENDPOINT_VENDOR_KEY in .env).

Step 4 — Upsert Each Product into Laravel

For each product returned by the API:

  1. Find or create a row in products by SKU.
  2. Build the product data array mapping CakePHP fields to Laravel fields (see mapping table below).
  3. Resolve attribute option IDsweavingtype, material, and shape values are looked up in attribute_options by their seo_name to get Laravel's internal IDs.
  4. Call productRepository->update() — Bagisto's repository writes to products, product_flat, product_attribute_values, and product_images.
  5. Fix attribute text values — Bagisto stores attribute selections as option IDs in product_attribute_values. This step overwrites those back to human-readable names (e.g. Handknotted, Rectangle) so they display correctly.
  6. Sync product_flat across locales — the custom rug fields (available_shapes, available_materials, available_weaving_types, and their labels) are copied from the default locale row to all other locale rows.

Step 5 — Import Images

Image URLs from CakePHP's product_media array are stored in Laravel's product_images table. The CakePHP product ID in the URL is replaced with the SKU. Images are not downloaded — the URLs point to the CakePHP media server at https://tool.rugartisan.com/media/.


Field Mapping — CakePHP → Laravel

Laravel Field CakePHP Source Field Notes
sku sku Used as the unique key for upsert
name name
ra_product_id id Foreign key back to CakePHP
price price_usd_ft / price_gbp_ft / etc. Selected based on active channel currency
cost price_usd_cm / price_gbp_cm / etc. Per-cm price, used for custom size calculation
weavingtype weaving_type Resolved to attribute_option.id
material material Resolved to attribute_option.id
shape shape Resolved to attribute_option.id
design_color color_weight_new[0] Primary color data for the design
pile_height pile_height
available_shapes avalable_shapes JSON list of shapes the rug can be ordered in
available_weaving_types available_weaving_types JSON list of weaving options
available_materials available_materials JSON list of material options
delivery_time shipment_time
meta_keywords keywords
is_default is_default
producttags product_tags Resolved to attribute_option slugs
product_media product_media[].image_url Image URLs with ID replaced by SKU
thumbnail product_media where image_type = thumbnail
url_key Constructed from name + weaving_type + shape + material e.g. custom-rug/custom-floral-handknotted-rectangle-wool-rug.html

Tables Written To

Table What is written
products One row per SKU; ra_product_id links back to CakePHP
product_flat Denormalized product data per channel + locale combination
product_attribute_values EAV values for all product attributes
product_images Image URL paths pointing to CakePHP media server
attribute_options Color and tag options synced from CakePHP

Re-running the Import

The command is safe to re-run. Products are matched by SKU:


Related Commands

Command Purpose
import:run Full product import from CakePHP API
updateprice:run Re-fetches and updates pricing only, in paginated batches

Environment Variables

API_ENDPOINT=https://api.rugartisan.com/api
API_ENDPOINT_AUTH_KEY=...
API_ENDPOINT_VENDOR_KEY=...
DESIGN_TOOL_BASE_URL=https://tool.rugartisan.com/
TOOL_BASE_IMAGE_URL=https://tool.rugartisan.com/media/