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:
orasche committed 2026-10-07 16:22:50 +02:00
1 parent 8e67f5db23
commit 9b1ad202a9
7 files changed
+242 -23

No files matched your search

+1 -1
View File
@@ -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
View File
@@ -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.*
+2 -2
View File
@@ -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>␍
+2 -2
View File
@@ -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;