Search cards above the results, detail-page fallback for market/solution documents

- New record type tx_vitec_domain_model_searchcard ("best bets"):
  keyword list, priority, optional referenced record (page, product,
  story, solution, market, news) and overridable title/teaser/image/link;
  hidden/start/end time allow timed campaigns
- SearchCardService delivers content.search.cards on page 1: max. 3,
  priority-ordered, deduplicated by URL, independent of filter, facets
  and result count. Keywords match as whole words/phrases, case- and
  punctuation-insensitive, including one level of the Solr managed
  synonyms in both directions (cached for an hour, fail-soft). Record
  cards read the record's indexed Solr document, so a card always
  matches the record's own search result
- Index fallback for markets and solutions: when the record carries no
  image or text, the document takes the intro image (then the hero
  background) and the hero subline, intro headline and intro text from
  the content blocks of its detail page - selected by CType, so it works
  for layout 21 and layout 5 alike; improves results and cards
- Fix: a search request without q returned an empty body instead of the
  documented empty shape (stdClass resolved inside the renderer namespace)
- migrations/check_solution_fields.php: shows live/workspace versions of
  solution records
- Spec v1.22 (clause 7.16: cards)
This commit is contained in:
orasche committed 2026-10-09 12:59:12 +02:00
1 parent 8ead213bdf
commit 91ad5e6596
11 files changed
+626 -7

No files matched your search

@@ -476,6 +476,91 @@ plugin.tx_solr.statistics.anonymizeIP = 2
# downloads/events/locations (no public detail pages), Datapath news (pid 442,
# import awaiting an editorial decision).
# =============================================================================
# Detail-page fallbacks for markets and solutions (2026-10-09). The records
# themselves are mostly empty (no teaser/description/image) - the real copy
# lives in the market/solution Content Blocks on the record's detail_page,
# filled by the workbook importers. Copied into both queues below, so search
# results AND search cards (which mirror the indexed document) get a teaser
# and a tile image without double maintenance. Selected by CType, so it works
# for layout 21 (colPos 110/120) and layout 5 (colPos 1/0) alike.
#
# Image chain: record image -> detail page intro image -> hero background.
lib.vitecIndexDetailImage = CONTENT
lib.vitecIndexDetailImage {
table = tt_content
select {
pidInList.field = detail_page
where = {#CType} = 'vitec_marketintro'
orderBy = sorting
max = 1
}
renderObj = FILES
renderObj {
references {
table = tt_content
uid.data = field:uid
fieldName = vitec_image
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
}
stdWrap.ifEmpty.cObject = CONTENT
stdWrap.ifEmpty.cObject {
table = tt_content
select {
pidInList.field = detail_page
where = {#CType} = 'vitec_markethero'
orderBy = sorting
max = 1
}
renderObj = FILES
renderObj {
references {
table = tt_content
uid.data = field:uid
fieldName = vitec_bgimage
}
maxItems = 1
renderObj = IMG_RESOURCE
renderObj {
file.import.data = file:current:uid
file.treatIdAsReference = 1
file.width = 640
}
}
}
}
# Searchable text of the detail page: hero subline, intro headline, intro
# text - in page order (hero first), appended to the record's own content.
lib.vitecIndexDetailText = CONTENT
lib.vitecIndexDetailText {
table = tt_content
select {
pidInList.field = detail_page
where = {#CType} IN ('vitec_markethero', 'vitec_marketintro')
orderBy = CType ASC
}
renderObj = COA
renderObj {
10 = TEXT
10.field = vitec_subline
10.noTrimWrap = || |
20 = TEXT
20.field = vitec_intro_headline
20.noTrimWrap = || |
30 = TEXT
30.field = vitec_intro_text
30.noTrimWrap = || |
}
}
plugin.tx_solr.index.queue {
products = 1
@@ -577,6 +662,7 @@ plugin.tx_solr.index.queue {
file.treatIdAsReference = 1
file.width = 640
}
stdWrap.ifEmpty.cObject < lib.vitecIndexDetailImage
}
type = tx_vitec_domain_model_market
# only markets with an editorially assigned detail page are linkable;
@@ -597,6 +683,7 @@ plugin.tx_solr.index.queue {
30 = TEXT
30.field = description
30.noTrimWrap = || |
40 < lib.vitecIndexDetailText
}
}
url = TEXT
@@ -710,6 +797,7 @@ plugin.tx_solr.index.queue {
file.treatIdAsReference = 1
file.width = 640
}
stdWrap.ifEmpty.cObject < lib.vitecIndexDetailImage
}
type = tx_vitec_domain_model_solution
additionalWhereClause = detail_page > 0
@@ -728,6 +816,7 @@ plugin.tx_solr.index.queue {
30 = TEXT
30.field = description
30.noTrimWrap = || |
40 < lib.vitecIndexDetailText
}
}
url = TEXT