Extend Solr search: content coverage, 14.0.2, news recency, result images
- Index the text columns of the market/solution Content Blocks and the vitec_items/vitec_faq_items collection children; story documents now include their body (inline tt_content children via tx_vitec_usecase_content, same per-element extraction as pages) - stories were indexed with subtitle and teaser only until now - Upgrade EXT:solr 14.0.0-RC1 -> 14.0.2 final (the Solr image moved to a fresh volume because the configset changed; synonyms restored via REST) - News decay with age by publication date: crdate is the import date, so news map datetime to created; boost function gated to news only - Results carry `image`: processed 640px tile image per type, root-relative, null for pages and downloads - Spec v1.21: 7.16 states the /_json prefix and lists `solution` in the type vocabulary; footer had been stuck at v1.19 - suggest-demo.html fetches through /_json after the URL swap
This commit is contained in:
1 parent
8e67f5db23
commit
9b1ad202a9
7 files changed
+242
-23
No files matched your search
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
"sort-packages": true
|
"sort-packages": true
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"apache-solr-for-typo3/solr": "^14.0@RC",
|
"apache-solr-for-typo3/solr": "^14.0.2",
|
||||||
"b13/container": "^3.1",
|
"b13/container": "^3.1",
|
||||||
"b13/typo3-updater": "^1.1",
|
"b13/typo3-updater": "^1.1",
|
||||||
"evomedien/evo-megamenu-json": "^1.0.0",
|
"evomedien/evo-megamenu-json": "^1.0.0",
|
||||||
|
|||||||
Generated
+6
-7
@@ -4,20 +4,20 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "0f38c50d2ecb8b6e4b0ec88fc7985249",
|
"content-hash": "f9a73e5875dc0072a5a3853989adda94",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "apache-solr-for-typo3/solr",
|
"name": "apache-solr-for-typo3/solr",
|
||||||
"version": "14.0.1",
|
"version": "14.0.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/TYPO3-Solr/ext-solr.git",
|
"url": "https://github.com/TYPO3-Solr/ext-solr.git",
|
||||||
"reference": "25fad97ffe192b1c4afc9400b98f4b4c4d3a6ea3"
|
"reference": "d430194b11c0581bd70e96a0483ec813b8345529"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/TYPO3-Solr/ext-solr/zipball/25fad97ffe192b1c4afc9400b98f4b4c4d3a6ea3",
|
"url": "https://api.github.com/repos/TYPO3-Solr/ext-solr/zipball/d430194b11c0581bd70e96a0483ec813b8345529",
|
||||||
"reference": "25fad97ffe192b1c4afc9400b98f4b4c4d3a6ea3",
|
"reference": "d430194b11c0581bd70e96a0483ec813b8345529",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
"type": "custom"
|
"type": "custom"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2026-09-03T14:19:19+00:00"
|
"time": "2026-09-16T13:50:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "b13/container",
|
"name": "b13/container",
|
||||||
@@ -10325,7 +10325,6 @@
|
|||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": {
|
"stability-flags": {
|
||||||
"apache-solr-for-typo3/solr": 5,
|
|
||||||
"friendsoftypo3/headless": 5
|
"friendsoftypo3/headless": 5
|
||||||
},
|
},
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
|||||||
* or the FlexForm override on the plugin),
|
* or the FlexForm override on the plugin),
|
||||||
* "numFound": total hits,
|
* "numFound": total hits,
|
||||||
* "totalPages": ceil(numFound / resultsPerPage),
|
* "totalPages": ceil(numFound / resultsPerPage),
|
||||||
* "results": [ { "title", "url", "type", "teaser" } ],
|
* "results": [ { "title", "url", "type", "teaser", "image" } ],
|
||||||
* "filter": the active type filter or null,
|
* "filter": the active type filter or null,
|
||||||
* "facets": { "type": [ { "value", "count", "active" } ] } -
|
* "facets": { "type": [ { "value", "count", "active" } ] } -
|
||||||
* counts stay complete while a filter is active,
|
* counts stay complete while a filter is active,
|
||||||
@@ -217,11 +217,20 @@ class SearchJsonRenderer
|
|||||||
} else {
|
} else {
|
||||||
$teaser = mb_substr(trim((string)$document->getContent()), 0, self::TEASER_FALLBACK_LENGTH);
|
$teaser = mb_substr(trim((string)$document->getContent()), 0, self::TEASER_FALLBACK_LENGTH);
|
||||||
}
|
}
|
||||||
|
$image = (string)($document['image'] ?? '');
|
||||||
|
// IMG_RESOURCE yields fileadmin/... without a leading slash -
|
||||||
|
// made root-relative like every other URL in the payload
|
||||||
|
if ($image !== '' && !str_starts_with($image, '/') && !preg_match('#^https?://#', $image)) {
|
||||||
|
$image = '/' . $image;
|
||||||
|
}
|
||||||
$results[] = [
|
$results[] = [
|
||||||
'title' => (string)$document->getTitle(),
|
'title' => (string)$document->getTitle(),
|
||||||
'url' => (string)$document->getUrl(),
|
'url' => (string)$document->getUrl(),
|
||||||
'type' => self::TYPE_LABELS[$document->getType()] ?? (string)$document->getType(),
|
'type' => self::TYPE_LABELS[$document->getType()] ?? (string)$document->getType(),
|
||||||
'teaser' => $teaser,
|
'teaser' => $teaser,
|
||||||
|
// processed tile image (640px wide) from the index; null when the
|
||||||
|
// document type has none (pages, downloads) or no image is set
|
||||||
|
'image' => $image !== '' ? $image : null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -394,6 +394,67 @@ plugin.tx_solr.index.queue.pages.fields {
|
|||||||
40 = TEXT
|
40 = TEXT
|
||||||
40.field = vitec_quote
|
40.field = vitec_quote
|
||||||
40.noTrimWrap = || |
|
40.noTrimWrap = || |
|
||||||
|
# Content Blocks with their own text columns (market/solution
|
||||||
|
# templates, flip cards) - the workbook imports fill these
|
||||||
|
50 = TEXT
|
||||||
|
50.field = vitec_subline
|
||||||
|
50.noTrimWrap = || |
|
||||||
|
60 = TEXT
|
||||||
|
60.field = vitec_intro_headline
|
||||||
|
60.noTrimWrap = || |
|
||||||
|
70 = TEXT
|
||||||
|
70.field = vitec_intro_text
|
||||||
|
70.noTrimWrap = || |
|
||||||
|
80 = TEXT
|
||||||
|
80.field = vitec_text1
|
||||||
|
80.noTrimWrap = || |
|
||||||
|
90 = TEXT
|
||||||
|
90.field = vitec_text2
|
||||||
|
90.noTrimWrap = || |
|
||||||
|
100 = TEXT
|
||||||
|
100.field = vitec_back_text
|
||||||
|
100.noTrimWrap = || |
|
||||||
|
110 = TEXT
|
||||||
|
110.field = vitec_quote_position
|
||||||
|
110.noTrimWrap = || |
|
||||||
|
# Content Blocks collection children (cards, icon lists,
|
||||||
|
# FAQ) live in their own tables, keyed on the parent uid
|
||||||
|
120 = CONTENT
|
||||||
|
120 {
|
||||||
|
table = vitec_items
|
||||||
|
select {
|
||||||
|
pidInList.field = pid
|
||||||
|
where.dataWrap = {#foreign_table_parent_uid} = {field:uid}
|
||||||
|
orderBy = sorting
|
||||||
|
}
|
||||||
|
renderObj = COA
|
||||||
|
renderObj {
|
||||||
|
10 = TEXT
|
||||||
|
10.field = headline
|
||||||
|
10.noTrimWrap = || |
|
||||||
|
20 = TEXT
|
||||||
|
20.field = text
|
||||||
|
20.noTrimWrap = || |
|
||||||
|
}
|
||||||
|
}
|
||||||
|
130 = CONTENT
|
||||||
|
130 {
|
||||||
|
table = vitec_faq_items
|
||||||
|
select {
|
||||||
|
pidInList.field = pid
|
||||||
|
where.dataWrap = {#foreign_table_parent_uid} = {field:uid}
|
||||||
|
orderBy = sorting
|
||||||
|
}
|
||||||
|
renderObj = COA
|
||||||
|
renderObj {
|
||||||
|
10 = TEXT
|
||||||
|
10.field = question
|
||||||
|
10.noTrimWrap = || |
|
||||||
|
20 = TEXT
|
||||||
|
20.field = answer
|
||||||
|
20.noTrimWrap = || |
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -419,6 +480,37 @@ plugin.tx_solr.index.queue {
|
|||||||
|
|
||||||
products = 1
|
products = 1
|
||||||
products {
|
products {
|
||||||
|
# result tile image: first reference, processed to 640px width
|
||||||
|
fields.image = FILES
|
||||||
|
fields.image {
|
||||||
|
references {
|
||||||
|
table = tx_vitec_domain_model_product
|
||||||
|
uid.data = field:uid
|
||||||
|
fieldName = image
|
||||||
|
}
|
||||||
|
maxItems = 1
|
||||||
|
renderObj = IMG_RESOURCE
|
||||||
|
renderObj {
|
||||||
|
file.import.data = file:current:uid
|
||||||
|
file.treatIdAsReference = 1
|
||||||
|
file.width = 640
|
||||||
|
}
|
||||||
|
stdWrap.ifEmpty.cObject = FILES
|
||||||
|
stdWrap.ifEmpty.cObject {
|
||||||
|
references {
|
||||||
|
table = tx_vitec_domain_model_product
|
||||||
|
uid.data = field:uid
|
||||||
|
fieldName = productimage
|
||||||
|
}
|
||||||
|
maxItems = 1
|
||||||
|
renderObj = IMG_RESOURCE
|
||||||
|
renderObj {
|
||||||
|
file.import.data = file:current:uid
|
||||||
|
file.treatIdAsReference = 1
|
||||||
|
file.width = 640
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
# sys_category titles - feeds the category facet
|
# sys_category titles - feeds the category facet
|
||||||
fields.category_stringM = SOLR_RELATION
|
fields.category_stringM = SOLR_RELATION
|
||||||
fields.category_stringM {
|
fields.category_stringM {
|
||||||
@@ -470,6 +562,22 @@ plugin.tx_solr.index.queue {
|
|||||||
|
|
||||||
markets = 1
|
markets = 1
|
||||||
markets {
|
markets {
|
||||||
|
# result tile image: first reference, processed to 640px width
|
||||||
|
fields.image = FILES
|
||||||
|
fields.image {
|
||||||
|
references {
|
||||||
|
table = tx_vitec_domain_model_market
|
||||||
|
uid.data = field:uid
|
||||||
|
fieldName = image
|
||||||
|
}
|
||||||
|
maxItems = 1
|
||||||
|
renderObj = IMG_RESOURCE
|
||||||
|
renderObj {
|
||||||
|
file.import.data = file:current:uid
|
||||||
|
file.treatIdAsReference = 1
|
||||||
|
file.width = 640
|
||||||
|
}
|
||||||
|
}
|
||||||
type = tx_vitec_domain_model_market
|
type = tx_vitec_domain_model_market
|
||||||
# only markets with an editorially assigned detail page are linkable;
|
# only markets with an editorially assigned detail page are linkable;
|
||||||
# grows automatically as editors fill the field (4 of 34 right now)
|
# grows automatically as editors fill the field (4 of 34 right now)
|
||||||
@@ -503,6 +611,37 @@ plugin.tx_solr.index.queue {
|
|||||||
|
|
||||||
usecases = 1
|
usecases = 1
|
||||||
usecases {
|
usecases {
|
||||||
|
# result tile image: first reference, processed to 640px width
|
||||||
|
fields.image = FILES
|
||||||
|
fields.image {
|
||||||
|
references {
|
||||||
|
table = tx_vitec_domain_model_usecase
|
||||||
|
uid.data = field:uid
|
||||||
|
fieldName = card_image
|
||||||
|
}
|
||||||
|
maxItems = 1
|
||||||
|
renderObj = IMG_RESOURCE
|
||||||
|
renderObj {
|
||||||
|
file.import.data = file:current:uid
|
||||||
|
file.treatIdAsReference = 1
|
||||||
|
file.width = 640
|
||||||
|
}
|
||||||
|
stdWrap.ifEmpty.cObject = FILES
|
||||||
|
stdWrap.ifEmpty.cObject {
|
||||||
|
references {
|
||||||
|
table = tx_vitec_domain_model_usecase
|
||||||
|
uid.data = field:uid
|
||||||
|
fieldName = hero_bgimage
|
||||||
|
}
|
||||||
|
maxItems = 1
|
||||||
|
renderObj = IMG_RESOURCE
|
||||||
|
renderObj {
|
||||||
|
file.import.data = file:current:uid
|
||||||
|
file.treatIdAsReference = 1
|
||||||
|
file.width = 640
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
# market titles from the MM relation - feeds the market facet
|
# market titles from the MM relation - feeds the market facet
|
||||||
fields.market_stringM = SOLR_RELATION
|
fields.market_stringM = SOLR_RELATION
|
||||||
fields.market_stringM {
|
fields.market_stringM {
|
||||||
@@ -524,6 +663,18 @@ plugin.tx_solr.index.queue {
|
|||||||
20 = TEXT
|
20 = TEXT
|
||||||
20.field = teaser
|
20.field = teaser
|
||||||
20.noTrimWrap = || |
|
20.noTrimWrap = || |
|
||||||
|
# the story body: inline tt_content children (text, columns,
|
||||||
|
# quotations) - same per-element extraction as page content
|
||||||
|
30 = CONTENT
|
||||||
|
30 {
|
||||||
|
table = tt_content
|
||||||
|
select {
|
||||||
|
pidInList.field = pid
|
||||||
|
where.dataWrap = {#tx_vitec_usecase_content} = {field:uid}
|
||||||
|
orderBy = sorting
|
||||||
|
}
|
||||||
|
renderObj < plugin.tx_solr.index.queue.pages.fields.content.cObject.10.renderObj
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
url = TEXT
|
url = TEXT
|
||||||
@@ -544,6 +695,22 @@ plugin.tx_solr.index.queue {
|
|||||||
# 39 records a detail_page (and slug). Same pattern as markets.
|
# 39 records a detail_page (and slug). Same pattern as markets.
|
||||||
solutions = 1
|
solutions = 1
|
||||||
solutions {
|
solutions {
|
||||||
|
# result tile image: first reference, processed to 640px width
|
||||||
|
fields.image = FILES
|
||||||
|
fields.image {
|
||||||
|
references {
|
||||||
|
table = tx_vitec_domain_model_solution
|
||||||
|
uid.data = field:uid
|
||||||
|
fieldName = image
|
||||||
|
}
|
||||||
|
maxItems = 1
|
||||||
|
renderObj = IMG_RESOURCE
|
||||||
|
renderObj {
|
||||||
|
file.import.data = file:current:uid
|
||||||
|
file.treatIdAsReference = 1
|
||||||
|
file.width = 640
|
||||||
|
}
|
||||||
|
}
|
||||||
type = tx_vitec_domain_model_solution
|
type = tx_vitec_domain_model_solution
|
||||||
additionalWhereClause = detail_page > 0
|
additionalWhereClause = detail_page > 0
|
||||||
fields {
|
fields {
|
||||||
@@ -575,6 +742,25 @@ plugin.tx_solr.index.queue {
|
|||||||
|
|
||||||
news = 1
|
news = 1
|
||||||
news {
|
news {
|
||||||
|
# crdate is the IMPORT date (Jul/Aug 2026) - the publication date
|
||||||
|
# lives in datetime. `created` feeds the news recency boost.
|
||||||
|
fields.created = datetime
|
||||||
|
# result tile image: first reference, processed to 640px width
|
||||||
|
fields.image = FILES
|
||||||
|
fields.image {
|
||||||
|
references {
|
||||||
|
table = tx_news_domain_model_news
|
||||||
|
uid.data = field:uid
|
||||||
|
fieldName = fal_media
|
||||||
|
}
|
||||||
|
maxItems = 1
|
||||||
|
renderObj = IMG_RESOURCE
|
||||||
|
renderObj {
|
||||||
|
file.import.data = file:current:uid
|
||||||
|
file.treatIdAsReference = 1
|
||||||
|
file.width = 640
|
||||||
|
}
|
||||||
|
}
|
||||||
type = tx_news_domain_model_news
|
type = tx_news_domain_model_news
|
||||||
# type 1 ("page as news") points at pages that are already indexed as
|
# type 1 ("page as news") points at pages that are already indexed as
|
||||||
# pages - indexing them again would duplicate every one of them
|
# pages - indexing them again would duplicate every one of them
|
||||||
@@ -707,3 +893,9 @@ plugin.tx_solr.suggest {
|
|||||||
# type and the full indexed content - too fat and off-contract for type-ahead
|
# type and the full indexed content - too fat and off-contract for type-ahead
|
||||||
showTopResults = 0
|
showTopResults = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# News recency: old news decays against everything else. Additive edismax
|
||||||
|
# boost (bf): non-news documents get the constant 10, news get
|
||||||
|
# recip(age) = 10 when new, ~5 after one year, ~0.7 after 13 years.
|
||||||
|
# The gate keeps products/pages/stories out of the decay entirely.
|
||||||
|
plugin.tx_solr.search.query.boostFunction = if(termfreq(type,'tx_news_domain_model_news'),recip(ms(NOW,created),3.16e-11,10,1),10)
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
| | |
|
| | |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Document identifier** | EVO‑VITEC‑HL‑001 |
|
| **Document identifier** | EVO‑VITEC‑HL‑001 |
|
||||||
| **Version** | 1.20 |
|
| **Version** | 1.21 |
|
||||||
| **Status** | Released |
|
| **Status** | Released |
|
||||||
| **Date** | 2026‑10‑01 |
|
| **Date** | 2026‑10‑07 |
|
||||||
| **Applies to** | `evomedien/vitec` on TYPO3 v14.3 (headless) |
|
| **Applies to** | `evomedien/vitec` on TYPO3 v14.3 (headless) |
|
||||||
| **Owner** | evomedien — VITEC relaunch |
|
| **Owner** | evomedien — VITEC relaunch |
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
| 1.18 | 2026‑09‑24 | **Interface change (additive).** Products gained `solutions` — an MM relation to solutions, emitted as solution cards in both product payloads — and a **Resources tab**: child table `tx_vitec_product_resource` with documentation / support cards (editable title, text and icon around one link, resolved per 9.12; cards without a resolvable link are not emitted) plus a `datasheets` MM selection of download records rendered into the same envelope as `type: datasheet` cards, delivered detail‑only as the `resources` list envelope whose `layout` switches to `carousel` above three cards in total (7.15). The `solutions` relation accepts group‑level records: the eight groups exist as `is_group = 1` solutions (created by `vitec:create-solution-groups`, excluded from lists and from `vitec:align-solutions`) because the agency workbooks reference the group level. Editorial: the footer had been stuck at v1.15 since 1.16/1.17 (2026‑09‑11). |
|
| 1.18 | 2026‑09‑24 | **Interface change (additive).** Products gained `solutions` — an MM relation to solutions, emitted as solution cards in both product payloads — and a **Resources tab**: child table `tx_vitec_product_resource` with documentation / support cards (editable title, text and icon around one link, resolved per 9.12; cards without a resolvable link are not emitted) plus a `datasheets` MM selection of download records rendered into the same envelope as `type: datasheet` cards, delivered detail‑only as the `resources` list envelope whose `layout` switches to `carousel` above three cards in total (7.15). The `solutions` relation accepts group‑level records: the eight groups exist as `is_group = 1` solutions (created by `vitec:create-solution-groups`, excluded from lists and from `vitec:align-solutions`) because the agency workbooks reference the group level. Editorial: the footer had been stuck at v1.15 since 1.16/1.17 (2026‑09‑11). |
|
||||||
| 1.19 | 2026‑09‑25 | **Interface change (additive).** The `vitec_card` Content Block gained the `layout_variant` value `flipcard` and a *Card Back* palette: `back_headline` (string, max 100) and `back_text` (richtext → HTML). The two fields are `displayCond`‑gated on the flipcard layout in the backend but serialised unconditionally (7.7) — the front end **shall** key the back face on `layout_variant`, never on field presence, because stored back values persist when an editor switches the layout away. Backend repair: `vitec_layout_variant` / `vitec_background_variant` are shared with `vitec_ctabanner`, and the index‑wise Content‑Blocks merge had dropped four card‑only select values (“Missing label”) — per‑type item lists now come from `columnsOverrides` (7.7); the Card‑Back palette lives in the Layout tab below the variant select. Editorial: the head‑matter version had been stuck at v1.17 since 1.18. |
|
| 1.19 | 2026‑09‑25 | **Interface change (additive).** The `vitec_card` Content Block gained the `layout_variant` value `flipcard` and a *Card Back* palette: `back_headline` (string, max 100) and `back_text` (richtext → HTML). The two fields are `displayCond`‑gated on the flipcard layout in the backend but serialised unconditionally (7.7) — the front end **shall** key the back face on `layout_variant`, never on field presence, because stored back values persist when an editor switches the layout away. Backend repair: `vitec_layout_variant` / `vitec_background_variant` are shared with `vitec_ctabanner`, and the index‑wise Content‑Blocks merge had dropped four card‑only select values (“Missing label”) — per‑type item lists now come from `columnsOverrides` (7.7); the Card‑Back palette lives in the Layout tab below the variant select. Editorial: the head‑matter version had been stuck at v1.17 since 1.18. |
|
||||||
| 1.20 | 2026‑10‑01 | **Interface change (additive).** Sub-market page template: frontend layout 21 with one colPos group per design section (`colPos110`..`colPos160`, clause 7.17); new Content Blocks `vitec_markethero`, `vitec_marketintro`, `vitec_marketinsights`; new plugin `vitec_productfeature` (key `productfeature`, one product in the 7.15.2 item shape); story cards gained `quote`/`quotePerson`/`quoteRole`; `vitec_usecaselist` gained the layout value `testimonials`; `vitec_productlist` gained hand-picked product selection (editor order, category filter ignored). Field semantics: Template_Sub-Market_Spezifikation_2026-10-01.md. |
|
| 1.20 | 2026‑10‑01 | **Interface change (additive).** Sub-market page template: frontend layout 21 with one colPos group per design section (`colPos110`..`colPos160`, clause 7.17); new Content Blocks `vitec_markethero`, `vitec_marketintro`, `vitec_marketinsights`; new plugin `vitec_productfeature` (key `productfeature`, one product in the 7.15.2 item shape); story cards gained `quote`/`quotePerson`/`quoteRole`; `vitec_usecaselist` gained the layout value `testimonials`; `vitec_productlist` gained hand-picked product selection (editor order, category filter ignored). Field semantics: Template_Sub-Market_Spezifikation_2026-10-01.md. |
|
||||||
|
| 1.21 | 2026‑10‑07 | **Interface change (additive) and corpus change.** Search results carry `image` (processed 640 px tile image, root-relative, `null` for types without one). Corpus: story documents now include their body (the inline `tt_content` children), page and story content include the text columns of the market/solution Content Blocks and the `vitec_items`/`vitec_faq_items` collection children; solutions are indexed. News rank by publication date (`datetime`; `crdate` is the import date) with an age-decay boost. EXT:solr upgraded from 14.0.0-RC1 to 14.0.2 final (TYPO3 and the Solr image). Editorial: 7.16 now states the `/_json` prefix the URL swap introduced, the `type` vocabulary lists `solution` (delivered since 1.14), and the footer had been stuck at v1.19. |
|
||||||
|
|
||||||
This document is drafted in the style of, and adopts the terminology conventions of,
|
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
|
ISO/IEC/IEEE 42010 (architecture description), ISO/IEC/IEEE 26514 (information for
|
||||||
@@ -1033,6 +1034,10 @@ headless by `SearchJsonRenderer` under the payload key `search`. The renderer ru
|
|||||||
EXT:solr’s own query pipeline (`SearchRequestBuilder` → `SearchResultSetService`) -
|
EXT:solr’s own query pipeline (`SearchRequestBuilder` → `SearchResultSetService`) -
|
||||||
only the rendering differs from the stock Fluid plugin.
|
only the rendering differs from the stock Fluid plugin.
|
||||||
|
|
||||||
|
Since the URL swap of 2026‑09‑28 every JSON URL carries the prefix `/_json`:
|
||||||
|
the search answers at `/_json/search?q=…`, while the bare `/search` serves the
|
||||||
|
single-page app. Paths in this clause are given without the prefix.
|
||||||
|
|
||||||
**Request.** GET parameters on the search page:
|
**Request.** GET parameters on the search page:
|
||||||
|
|
||||||
| Parameter | Meaning |
|
| Parameter | Meaning |
|
||||||
@@ -1071,13 +1076,15 @@ identifier).
|
|||||||
},
|
},
|
||||||
"results": [
|
"results": [
|
||||||
{ "title": "MGW Diamond-H", "url": "/product/mgw-diamond-h-hdmi-encoder",
|
{ "title": "MGW Diamond-H", "url": "/product/mgw-diamond-h-hdmi-encoder",
|
||||||
"type": "product", "teaser": "… 4K HDMI <mark>Encoder</mark> …" }
|
"type": "product", "teaser": "… 4K HDMI <mark>Encoder</mark> …",
|
||||||
|
"image": "/fileadmin/_processed_/…/csm_mgw-diamond-h_….jpg" }
|
||||||
],
|
],
|
||||||
"suggestions": []
|
"suggestions": []
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- `type` **shall** be one of `page | product | market | story | news | download`
|
- `type` **shall** be one of `page | product | market | solution | story | news |
|
||||||
|
download`
|
||||||
(mapping table in the renderer; unknown index types pass through verbatim).
|
(mapping table in the renderer; unknown index types pass through verbatim).
|
||||||
- `teaser` carries the highlighted fragment (`<mark>…</mark>`, fragments joined
|
- `teaser` carries the highlighted fragment (`<mark>…</mark>`, fragments joined
|
||||||
with " ... ") when highlighting applies, otherwise a plain 250-character excerpt
|
with " ... ") when highlighting applies, otherwise a plain 250-character excerpt
|
||||||
@@ -1085,6 +1092,10 @@ identifier).
|
|||||||
- `url` follows the shared link contract: root-relative, resolved server-side.
|
- `url` follows the shared link contract: root-relative, resolved server-side.
|
||||||
`download` results point at the forced-download endpoint `/download/<slug>`
|
`download` results point at the forced-download endpoint `/download/<slug>`
|
||||||
(5.3) - front ends should present them as file downloads.
|
(5.3) - front ends should present them as file downloads.
|
||||||
|
- `image` is a processed tile image (640 px wide, root-relative) or `null`.
|
||||||
|
Sources: products `image` (fallback `productimage`), stories `card_image`
|
||||||
|
(fallback `hero_bgimage`), markets/solutions `image`, news `fal_media`;
|
||||||
|
pages and downloads carry none.
|
||||||
- `facets.type` carries the per-type counts for filter tabs, ordered by count.
|
- `facets.type` carries the per-type counts for filter tabs, ordered by count.
|
||||||
While a `filter` is active the counts remain those of the unfiltered query, so
|
While a `filter` is active the counts remain those of the unfiltered query, so
|
||||||
tabs do not collapse - except when the filtered result is empty, where only
|
tabs do not collapse - except when the filtered result is empty, where only
|
||||||
@@ -1102,11 +1113,16 @@ resolvable public URL - products, markets (only those with `detail_page`),
|
|||||||
use cases, news (`type = 0`; "page as news" records are excluded because their
|
use cases, news (`type = 0`; "page as news" records are excluded because their
|
||||||
target pages are already indexed) and downloads (`private_download = 0 AND
|
target pages are already indexed) and downloads (`private_download = 0 AND
|
||||||
hideonwebsite = 0`; their `content` additionally carries the file text extracted
|
hideonwebsite = 0`; their `content` additionally carries the file text extracted
|
||||||
through Apache Tika, so datasheet specifications are searchable). Solutions are not indexed until they carry slugs or detail
|
through Apache Tika, so datasheet specifications are searchable). Solutions are indexed like markets (`detail_page > 0`). Stories include their
|
||||||
pages. Ranking boosts products (^10) and stories (^2). Every executed search is
|
body - the inline `tt_content` children - and both page and story content
|
||||||
|
include the text columns of the market/solution Content Blocks and the
|
||||||
|
collection children (`vitec_items`, `vitec_faq_items`). Ranking boosts products
|
||||||
|
(^10) and stories (^2); news decay with age by their publication date
|
||||||
|
(`datetime` mapped to `created` - `crdate` is the import date), all other
|
||||||
|
types are exempt. Every executed search is
|
||||||
logged to `tx_solr_statistics` with the last two IP octets masked.
|
logged to `tx_solr_statistics` with the last two IP octets masked.
|
||||||
|
|
||||||
**Autocomplete.** `GET /search?type=7384&tx_solr[queryString]=<input>` answers as
|
**Autocomplete.** `GET /_json/search?type=7384&tx_solr[queryString]=<input>` answers as
|
||||||
a lean JSON page type without the page envelope:
|
a lean JSON page type without the page envelope:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -1120,14 +1136,17 @@ wired as **USER_INT** - the example shipped with EXT:solr predates TYPO3 v14
|
|||||||
(`config.no_cache` no longer exists), and a cached USER would pin the first
|
(`config.no_cache` no longer exists), and a cached USER would pin the first
|
||||||
query’s suggestions for every later request. Front ends should debounce
|
query’s suggestions for every later request. Front ends should debounce
|
||||||
(~200 ms), start at 2-3 characters, and turn a picked suggestion into a
|
(~200 ms), start at 2-3 characters, and turn a picked suggestion into a
|
||||||
regular `/search?q=` request. Top-result documents are deliberately disabled
|
regular `/_json/search?q=` request. Top-result documents are deliberately disabled
|
||||||
(`showTopResults = 0`): their shape is hardcoded upstream and carries the raw
|
(`showTopResults = 0`): their shape is hardcoded upstream and carries the raw
|
||||||
document type and the full indexed content.
|
document type and the full indexed content.
|
||||||
|
|
||||||
**Operations.** Indexing runs automatically: record and page saves enter the
|
**Operations.** Indexing runs automatically: record and page saves enter the
|
||||||
index queue, a scheduler task (Index Queue Worker, every 5 minutes) pushes them
|
index queue, a scheduler task (Index Queue Worker, every 5 minutes) pushes them
|
||||||
to Solr; the CLI command `vitec:solr-index` (with `--initialize` and `--debug`)
|
to Solr; the CLI command `vitec:solr-index` (with `--initialize` and `--debug`)
|
||||||
covers manual runs - EXT:solr 14 ships no console commands of its own. Page
|
covers manual runs - EXT:solr 14 ships no console commands of its own. Versions:
|
||||||
|
EXT:solr 14.0.2 and the matching image `typo3solr/ext-solr:14.0.2` (Solr 10);
|
||||||
|
an image upgrade needs a fresh volume, because an existing volume keeps its
|
||||||
|
old configset - managed synonyms are restored through the REST API. Page
|
||||||
content is extracted from the page’s `tt_content` rows via
|
content is extracted from the page’s `tt_content` rows via
|
||||||
`index.queue.pages.fields.content` because the headless JSON output carries no
|
`index.queue.pages.fields.content` because the headless JSON output carries no
|
||||||
`TYPO3SEARCH` markers.
|
`TYPO3SEARCH` markers.
|
||||||
@@ -1538,4 +1557,4 @@ remediation.
|
|||||||
- Header convention — the uniform header section across CEs, plugins and containers.
|
- Header convention — the uniform header section across CEs, plugins and containers.
|
||||||
- `Configuration/Sets/Vitecset/setup.typoscript` — the single TypoScript entry point.
|
- `Configuration/Sets/Vitecset/setup.typoscript` — the single TypoScript entry point.
|
||||||
|
|
||||||
*End of document EVO‑VITEC‑HL‑001 v1.19.*
|
*End of document EVO‑VITEC‑HL‑001 v1.21.*
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
<meta name="twitter:description" content="Enterprise IPTV, video streaming, and digital signage solutions." />
|
<meta name="twitter:description" content="Enterprise IPTV, video streaming, and digital signage solutions." />
|
||||||
<link rel="icon" type="image/svg+xml" href="/fileadmin/icons/favicon.ico" />
|
<link rel="icon" type="image/svg+xml" href="/fileadmin/icons/favicon.ico" />
|
||||||
<title>VITEC</title>
|
<title>VITEC</title>
|
||||||
<script type="module" crossorigin src="/_frontend/assets/index-BpTqLcih.js"></script>
|
<script type="module" crossorigin src="/_frontend/assets/index-CEaqwHyi.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/_frontend/assets/index-CAiVTATb.css">
|
<link rel="stylesheet" crossorigin href="/_frontend/assets/index-CgBOr71d.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="page"></div>␍
|
<div id="page"></div>␍
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
const val = input.value.trim();
|
const val = input.value.trim();
|
||||||
if (val.length < 2) { dd.classList.remove('open'); return; }
|
if (val.length < 2) { dd.classList.remove('open'); return; }
|
||||||
debounceTimer = setTimeout(async () => {
|
debounceTimer = setTimeout(async () => {
|
||||||
const url = '/search?type=7384&tx_solr[queryString]=' + encodeURIComponent(val);
|
const url = '/_json/search?type=7384&tx_solr[queryString]=' + encodeURIComponent(val);
|
||||||
const j = await (await fetch(url)).json();
|
const j = await (await fetch(url)).json();
|
||||||
const terms = Object.entries(j.suggestions || {});
|
const terms = Object.entries(j.suggestions || {});
|
||||||
dd.innerHTML = terms.map(([t, c]) =>
|
dd.innerHTML = terms.map(([t, c]) =>
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
// ---- Suche: GET /search?q=...&filter=...&page=... ----
|
// ---- Suche: GET /search?q=...&filter=...&page=... ----
|
||||||
async function runSearch(q, filter, page) {
|
async function runSearch(q, filter, page) {
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
const url = '/search?q=' + encodeURIComponent(q)
|
const url = '/_json/search?q=' + encodeURIComponent(q)
|
||||||
+ (filter ? '&filter=' + filter : '') + (page > 1 ? '&page=' + page : '');
|
+ (filter ? '&filter=' + filter : '') + (page > 1 ? '&page=' + page : '');
|
||||||
const json = await (await fetch(url)).json();
|
const json = await (await fetch(url)).json();
|
||||||
const s = json.content.colPos0[0].content.search;
|
const s = json.content.colPos0[0].content.search;
|
||||||
|
|||||||
Reference in new issue
Block a user