3.3 KiB
Design: Per-Integration Product Content
Date: 2026-02-27 Status: Approved
Summary
Products need separate name, short_description, and description for each integration. Global values in product_translations remain the fallback. Integration-specific overrides are stored in a new table.
Model
Global + override per integration:
product_translationsstays as the global/base content (unchanged)- New table
product_integration_translationsstores per-integration overrides - NULL field = use global value
- When exporting to a specific integration, prefer integration-specific content, fall back to global
Database
New migration file: 20260227_000014_create_product_integration_translations.sql
CREATE TABLE product_integration_translations (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_id INT UNSIGNED NOT NULL,
integration_id INT UNSIGNED NOT NULL,
name VARCHAR(255) NULL,
short_description TEXT NULL,
description LONGTEXT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY pit_product_integration_unique (product_id, integration_id),
CONSTRAINT pit_product_fk FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,
CONSTRAINT pit_integration_fk FOREIGN KEY (integration_id) REFERENCES integrations(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Data migration: For all products currently linked to the "marianek.pl" integration via product_channel_map, copy name, short_description, description from product_translations to product_integration_translations.
Import Flow
In SettingsController::importExternalProductById:
- Save to
product_translationsas now (global, unchanged) - Additionally upsert
name,short_description,descriptiontoproduct_integration_translationsfor the currentintegration_id
Repository
New methods in ProductRepository:
findIntegrationTranslations(int $productId): array— returns all per-integration translation rows for a productupsertIntegrationTranslation(int $productId, int $integrationId, string|null $name, string|null $shortDescription, string|null $description): void
Edit UI
In products/edit.php, the Name/Short description/Description section gets tabs at the top:
[ Globalna ] [ marianek.pl ] [ inny sklep... ]
- Each tab shows: Nazwa, Krótki opis, Opis (WYSIWYG with Quill)
- "Globalna" tab = existing global fields (
name,short_description,description) - Integration tabs = per-integration overrides (
integration_content[{id}][name], etc.) - Rest of the form (prices, SKU, images, meta) is global — no tabs
Controller Changes
ProductsController:
editaction: load active integrations +findIntegrationTranslations($id), pass to viewupdateaction: processintegration_content[{id}]array, callupsertIntegrationTranslationfor each
Existing Products Migration
One-off SQL script assigns existing product content to "marianek.pl" integration. All products in product_channel_map linked to the marianek.pl integration get their current product_translations content copied to product_integration_translations.