Product text import from agency XLSX workbooks
VITEC Import module: Products tab is now a searchable/sortable product overview. "Edit Product" opens an XLSX upload with per-field source mapping (component + cell), old/new preview and checkbox apply via DataHandler; the mapping and manual matches are persisted and preselect the next workbook. Category workbooks are detected and rejected. - new: ProductXlsxReader (PhpSpreadsheet), ProductTextImportController, Products/ProductTexts templates, 4 module routes - related products: per-pair card text in new side table tx_vitec_product_related_text (survives MM rewrites), emitted as `cardtext` in the product JSON; missing MM relations added add-only - card copy read from Body Copy (D) with fallback to CTA/Card Copy (E) - the workbooks fill either depending on row type - product detail page <title> now uses seotitle with title fallback (provider made singleton and fed from the JSON renderer) - per-user recent-search badges; last loaded workbook stored per product (tx_vitec_product_workbook), Edit Product reopens on it - composer: add phpoffice/phpspreadsheet ^5.9 - diagnostics: migrations/check_workbook.php
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
| 1.7 | 2026‑08‑06 | **Robustness:** the import normalizes legacy filenames on fetch so every imported file matches the version convention (`__NN_A` → `__NN-A`, `___NN` → `__NN`, `__NNA` → `__NN-A`, bare `__NN` → `__NN-A` as initial revision), and the three download renderers gained a `filepath` fallback in `getDownloadFile()` (FAL → convention → filepath) as a safety net for anything that still escapes it. Extends the B‑4 duplication (three copies of the fallback) — consolidation target remains a shared file‑resolver service (10.2). |
|
||||
| 1.8 | 2026‑08‑13 | **Defect fix and interface change (additive).** Content Blocks never carried the Core *Appearance* tab: `layout`, `frame_class` — including the VITEC frame classes — `space_before_class`, `space_after_class`, `sectionIndex` and `linkToTop` were unreachable for editors on all nine blocks. Added centrally for every `vitec_*` type (7.7); the `appearance` envelope is unchanged, its values were merely always default. Side effect: those six columns now also appear raw inside `data` on top‑level blocks (B‑13), and `appearance.layout` is represented differently on the two envelope paths (B‑14). `intro-paragraph` gained `background_color` (7.7). `vitec_eventlist` gained the layout `regions`, emitting a `regions` array built from the region categories below parent 104; the event payload is specified for the first time (7.14). B‑11 and B‑12 recorded as resolved. |
|
||||
| 1.9 | 2026‑08‑15 | **Interface change, partly breaking.** The four list plugins were unified: every one of them now emits an object carrying `layout`, the new `showToolbar` flag and its payload array. `vitec_usecaselist` and `vitec_productlist` previously emitted a **bare array** — front ends reading them have to move one level down (7.3, 7.14, 8). New plugin **`vitec_solutionlist`** (`SolutionListJsonRenderer`, key `solutions`), the counterpart 7.13.2 had been asking for since v1.2. `tx_vitec_domain_model_usecase` gained `detail_page`, emitted as the resolved `detailUrl` in the story card shape and therefore also in the `vitec_modelcard` story branch, which had carried no link at all until now. Noted: `vitec_productlist` had a configurable `layout` that was never serialised, and its vocabulary (`0`–`3`) differs from the other lists. |
|
||||
| 1.10 | 2026‑08‑18 | **Interface change (additive).** `tx_vitec_domain_model_product` gained five fields: `heroimage` (multiple FAL images, detail payload only), the richtext fields `description2`, `capabilities` and `textrelatedproducts`, and `portfolio` (TCA `link`) — emitted as a **resolved URL** through the new `LinkResolver::typolinkUrl()`. The product payloads are specified for the first time (7.15). Links in `contentelement` / `contentelementcta` that point at a **container** now resolve its children (`items`, page‑level shape) and `background` (7.4). Two record link handlers (`download`, `product`) added to the link browser, resolved server‑side per the new Clause 9.12; new middleware `vitec/download-file` streams `/download/file/<uid>` as a forced download (5.3), file lookup consolidated into `DownloadFileResolver` — first step towards the B‑4 target (10.2). Backend‑only: `relatedprodukt` moved from the Misc tab to General. Editorial: the document footer had been stuck at v1.7 since v1.8. |
|
||||
|
||||
This document is drafted in the style of, and adopts the terminology conventions of,
|
||||
ISO/IEC/IEEE 42010 (architecture description), ISO/IEC/IEEE 26514 (information for
|
||||
@@ -180,7 +181,7 @@ enhancers for products (`tx_vitec_domain_model_product.slug`) and news detail
|
||||
(`path_segment`).
|
||||
|
||||
### 5.3 Frontend middlewares
|
||||
Two middlewares are registered in `Configuration/RequestMiddlewares.php`, both after
|
||||
Three middlewares are registered in `Configuration/RequestMiddlewares.php`, all after
|
||||
`typo3/cms-core/normalized-params-attribute` and before `typo3/cms-frontend/site` —
|
||||
that is, **before page resolution**:
|
||||
|
||||
@@ -188,6 +189,7 @@ that is, **before page resolution**:
|
||||
|---|---|
|
||||
| `vitec/form-submission` | Answers `POST /api/vitec/form/<formKey>` (Clause 7.8.2). Every other request passes through untouched. |
|
||||
| `vitec/success-story-path-rewrite` | Rewrites `/success-stories/<slug>` internally to `/success-stories/story/<slug>` when `<slug>` matches a visible Success Story. The page router would otherwise always resolve the public SEO URL to the list page (longest page‑slug prefix), so the detail subpage could never answer it. The browser URL is unchanged; a non‑matching slug leaves the request untouched; any exception leaves the request untouched. |
|
||||
| `vitec/download-file` | Answers `GET /download/file/<uid>`: resolves the download record's file (`DownloadFileResolver`: FAL → Collateral naming convention → `filepath`) and streams it with `Content-Disposition: attachment` (Clause 9.12). Unknown uid, hidden record or missing file fall through to normal page resolution. |
|
||||
|
||||
### 5.4 Architectural principles (rationale)
|
||||
- **P1 — One envelope.** Every content element, regardless of source, is exposed with
|
||||
@@ -444,6 +446,13 @@ The `colPos` value of each column is fixed by `COLPOS_TO_COLUMN` in
|
||||
(25/25/25/25), 241/242 (66/33), 251/252 (33/66) — and **shall** be kept in sync with
|
||||
the container TCA (Annex B‑5).
|
||||
|
||||
**Linked containers (since v1.10).** When a link resolved through
|
||||
`ContentElementResolver` (e.g. `contentelement` / `contentelementcta`, 7.15) points at
|
||||
a container, the resolver attaches the container's children under `items` in exactly
|
||||
the column shape above, plus the resolved `background`. Nested containers recurse
|
||||
(depth‑capped at 5, cycle‑safe); children are stripped of container‑level fields as in
|
||||
the page‑level rendering; nested plugins resolve per 9.7.
|
||||
|
||||
### 7.5 Success Story (use case) detail payload
|
||||
Produced by `UsecaseSerializer::serializeDetail()` — the reference implementation of
|
||||
the centralised pattern (Clause 9.2):
|
||||
@@ -856,6 +865,36 @@ Normative behaviour:
|
||||
An event carrying no category belongs to no region and is invisible to this layout while
|
||||
remaining present in `events`.
|
||||
|
||||
### 7.15 Product payloads
|
||||
|
||||
#### 7.15.1 Detail payload (`vitec_productshow`, key `product`)
|
||||
|
||||
Produced by `ProductShowJsonRenderer::serializeProduct()`. Members:
|
||||
|
||||
| Member | Type | Notes |
|
||||
|---|---|---|
|
||||
| `uid` | int | |
|
||||
| `title`, `slug`, `urltitle`, `seotitle`, `seometa`, `keywords`, `structureddata`, `teaser`, `subtitle`, `video`, `shortcutpid` | string | raw column values; `video` is a YouTube clip id |
|
||||
| `applications`, `capabilities`, `description`, `description2`, `highlights`, `textrelatedproducts` | string | richtext, resolved per 9.11 |
|
||||
| `hideonapp`, `hideonwebsite`, `hideondatasheets`, `hideonproducts`, `shortcut`, `legacy`, `supportproduct`, `subproduct`, `showdatapath` | bool | |
|
||||
| `link` | string | `/product/<slug>` |
|
||||
| `portfolio` | string \| null | resolved URL of the portfolio link (9.12); null = no link |
|
||||
| `contentelement`, `contentelementcta` | object \| null | linked tt_content element in the envelope shape of 7.2; a linked container carries `items` and `background` (7.4) |
|
||||
| `categories` | array | `{uid, title, description}` |
|
||||
| `images` | array | product images with `url`, `srcset` and properties (9.9) |
|
||||
| `heroimage` | array | hero images, same shape as `images` — **detail payload only** |
|
||||
| `downloads` | array | download records incl. the resolved `file` |
|
||||
| `ogimage`, `videofile` | object \| null | FAL singletons |
|
||||
| `relatedprodukt` | array | card shape `{uid, title, slug, subtitle, teaser, description, link, images}`, backend order |
|
||||
| `jsonLd` | string | ready‑to‑emit schema.org `@graph` (6.6), detail only |
|
||||
|
||||
#### 7.15.2 List payload (`vitec_productlist`, key `products`)
|
||||
|
||||
List envelope per 7.3 (`layout`, `showToolbar`, `products[]`) — since v1.9. Each item
|
||||
carries the member set of 7.15.1 **except** `heroimage` and `jsonLd`. `heroimage` is
|
||||
deliberately detail‑only: one further FAL query per product would buy data a list
|
||||
rarely shows. The `layout` vocabulary remains `0`–`3` (see the v1.9 note).
|
||||
|
||||
---
|
||||
|
||||
## 8 Content‑type catalogue
|
||||
@@ -1016,6 +1055,23 @@ Fields that merely *look* like richtext are out of scope: FAL metadata
|
||||
(`sys_file_reference.description`), `sys_category.description` and `sys_file` metadata
|
||||
are plain text and **shall not** be passed through the resolver.
|
||||
|
||||
### 9.12 Link resolution and record links
|
||||
|
||||
JSON output **shall never** carry an unresolved TYPO3 link (`t3://…`). Every link
|
||||
field is resolved server‑side — `LinkResolver::pageUrl()` for page uids,
|
||||
`LinkResolver::typolinkUrl()` for full typolink parameters — under the shared
|
||||
contract **null means "no link"**: a hidden or deleted target resolves to null,
|
||||
never to a broken URL.
|
||||
|
||||
The link browser offers two record link handlers (`TCEMAIN.linkHandler`,
|
||||
`Configuration/page.tsconfig`), stored as `t3://record?identifier=<key>&uid=<n>`
|
||||
and resolved by `config.recordLinks` in `setup.typoscript`:
|
||||
|
||||
| Identifier | Resolves to | Notes |
|
||||
|---|---|---|
|
||||
| `product` | `/product/<slug>` | same convention as the `link` member (7.15); assumes the product detail page (uid 10) answers `/product` |
|
||||
| `download` | `/download/file/<uid>` | forced‑download endpoint (5.3), file lookup via `DownloadFileResolver` |
|
||||
|
||||
---
|
||||
|
||||
## 10 Maintainability and upgrade‑safety (ISO 25010)
|
||||
@@ -1208,4 +1264,4 @@ remediation.
|
||||
- Header convention — the uniform header section across CEs, plugins and containers.
|
||||
- `Configuration/Sets/Vitecset/setup.typoscript` — the single TypoScript entry point.
|
||||
|
||||
*End of document EVO‑VITEC‑HL‑001 v1.7.*
|
||||
*End of document EVO‑VITEC‑HL‑001 v1.10.*
|
||||
|
||||
Reference in New Issue
Block a user