TYPO3: how to display content elements from different pages - typo3

Hopefully, someone knows how I can simplify the following TypoScript so I can pass a list of page ids from the template constant to the template script. say, I have defined a TEASER_IDS = 6,7,9,12,4, and the TypeScript walks thru that list and uses it for the select.pidInList one after the other instead of having to manually create a CONTENT object in the TypoScript for each ID.
lib.teaser = COA
lib.teaser {
10 = CONTENT
10 {
stdWrap.wrap = <div class="part">|</div>
table = tt_content
select.orderBy = sorting
select.pidInList = 6
select.where = colPos=1
select.languageField = sys_language_uid
}
20 = CONTENT
20 {
stdWrap.wrap = <div class="part">|</div>
table = tt_content
select.orderBy = sorting
select.pidInList = 7
select.where = colPos=1
select.languageField = sys_language_uid
}
}
page.50.30 < lib.teaser
It is TYPO3 version 10.4.8
EDIT: new version but I'd like to have the elements be wrapped each, so it results in
//this is what it should look like
<div class="header">CONTENT ID 6 colPos 1</div>
<div class="text">CONTENT ID 6 colPos 2</div>
<div class="header">CONTENT ID 7 colPos 1</div>
<div class="text">CONTENT ID 7 colPos 2</div>
<div class="header">CONTENT ID 4 colPos 1</div>
<div class="text">CONTENT ID 4 colPos 2</div>
TypoScript now:
lib.teaser = COA
lib.teaser {
10 = CONTENT
10 {
stdWrap.wrap = <div class="header">|</div>
table = tt_content
select.orderBy = sorting
select.pidInList = 6,7,4
select.where = colPos=1
select.languageField = sys_language_uid
}
20 = CONTENT
20 {
stdWrap.wrap = <div class="text">|</div>
table = tt_content
select.orderBy = sorting
select.pidInList = 6,7,4
select.where = colPos=2
select.languageField = sys_language_uid
}
}
page.50.30 < lib.teaser
The code gives me, which makes sense, but I have no idea how to change the code so it gives me the preferred output like mentioned above the new code
//this is not what i want
<div class="header">
CONTENT ID 6 colPos 1
CONTENT ID 7 colPos 1
CONTENT ID 4 colPos 1
</div>
<div class="text">
CONTENT ID 6 colPos 2
CONTENT ID 7 colPos 2
CONTENT ID 4 colPos 2
</div>

Do not use two CONTENT objects as they both iterate over all matching CEs. Instead, use the option to overwrite the wrap if the colPos has a corresponding value.
stdWrap {
wrap = <div class="text">|</div>
override = <div class="header">|</div>
override.if {
value.field = colPos
equals = 1
}
}
( https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/Functions/If.html#if )

If you want a loop over the pages where you collect content from different columns you need to build this structure in typoscript.
As you have noticed now you get all content for column 1 from all pages and then all content from column2.
How could you build a loop over the page IDs? we have no for loop in typoscript as it is a configuration language and no programming language.
That might be possible with a split on the comma separated list of the ids.
lib.teaser = TEXT
lib.teaser {
# list of page ids:
value = 6,7,9,12,4
split.token = ,
# only one kind of rendering (otherwise use optionsplit to define cases)
cObjNum = 1
# example: 1 = first, 4 = last, between: 2,3 alternating
# cObjNum = 1 |*| 2 || 3 |*| 4
# cases of rendering:
1 = COA
1 {
10 = CONTENT
10 {
stdWrap.wrap = <div class="part">|</div>
table = tt_content
select.orderBy = sorting
# use current value of split:
select.pidInList.current = 1
select.where = colPos=1
select.languageField = sys_language_uid
}
20 = CONTENT
20 {
stdWrap.wrap = <div class="part">|</div>
table = tt_content
select.orderBy = sorting
select.pidInList.current = 1
select.where = colPos=1
select.languageField = sys_language_uid
}
}
}

Related

How to create a select clause with AND query that matches tx_news items with two or more assotiated categories

I try to create a query to get all news items, that are flagged with at least two different categories and they have to match the AND clause.
I need this query to make a decision, if the following code should be rendered, or not. E.g. If there is no news item with category A and category B, do nothing. Else show tx_news LIST view.
lib.field_dmnewsplugin.5 = CONTENT
lib.field_dmnewsplugin.5 {
table = tx_news_domain_model_news
select {
pidInList = 124
max = 9
orderBy = uid DESC
leftjoin = sys_category_record_mm ON (sys_category_record_mm.uid_foreign = tx_news_domain_model_news.uid)
#andWhere = sys_category_record_mm.uid_local IN (14,16)
#where = sys_category_record_mm.uid_local = 14
andWhere = sys_category_record_mm.uid_local = 14 AND sys_category_record_mm.uid_local = 16
}
renderObj = COA
renderObj {
1 = TEXT
1.value = Aktuelles
1.wrap = <h2>|</h2>
2 = TEXT
2.field = title
2.crop = 50|...|1
2.wrap = <h3>|</h3>
3 = TEXT
3.field = teaser
3.crop = 500|...|1
3.wrap = <p>|</p>
}
}
My code is the result of some testings. With the "andWhere" clause, the result is empty. without any where clause, I get double entries for all news items, because all of them have at least two different categories.
My goal is to get unique results for each news item, that is flagged with category A and category B (and maybe as an universal solution additional categories).
What do I have to do?
Thank you in advance,
Ralf
Try to put the WHERE clause into the ON part of the JOIN and use a groupBy to get a counter.
select {
selectFields = count(*) AS counter
leftjoin = sys_category_record_mm ON (sys_category_record_mm.uid_foreign = tx_news_domain_model_news.uid) AND sys_category_record_mm.uid_local IN (14,16)
pidInList = 124
max = 9
groupBy = uid
orderBy = uid DESC
where = counter > 1
}
After I had to realize, that Jo's solution does not work for me, I had another idea:
lib.field_dmnewsplugin = COA
lib.field_dmnewsplugin {
10 = CONTENT
10 {
table = tx_news_domain_model_news
select {
selectFields = title, teaser, count(uid) AS counter
leftjoin = sys_category_record_mm ON (sys_category_record_mm.uid_foreign = tx_news_domain_model_news.uid) AND sys_category_record_mm.uid_local IN ({14,###maincat###)
pidInList = 124
max = 1
groupBy = uid
orderBy = counter DESC, crdate DESC
#where = counter > 1
markers {
maincat.value = 16
}
}
renderObj = COA
renderObj {
10 = COA
10 {
stdWrap {
if {
value = 1
isGreaterThan.data = field:counter
#equals.data = field:counter
}
required = 1
wrap = <h2>Some Headline</h2>
}
10 = USER
10 {
userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run
extensionName = News
pluginName = Pi1
vendorName = GeorgRinger
switchableControllerActions {
News {
1 = list
}
}
settings < plugin.tx_news.settings
settings {
cropMaxCharacters = 164 | [...] | 1
categoryConjunction = and
categories = 14,16
excludeAlreadyDisplayedNews = 1
archiveRestriction = active
[...]
The problem is, that we cannot use the alias "counter" in the where clause and I have no idea, how I can solve the problem with typoscript. With native SQL there might be a better way.
But I'm able to get the value of "counter" to create an "if" rule. And additionally, I can sort the query by "counter". So, if the query returns at least one hit with "counter" greater than 1, I can decide to render a COA-Object like a news list view with headline.
I'm satisfied with this solution. But maybe, somebody has a special trick for me?
Thank's for your help,
Ralf

Show category names of current page in TYPO3 8

I am trying to display the category name(s) of the current page on a TYPO3 8 installation. In TYPO3 7 it used to work like this (see below), however now I only receive a random error code and no Text output. Any Ideas?
lib.catclass = CONTENT
lib.catclass {
wrap = <div class="categories">|</div>
table = sys_category
select {
pidInList = 35 // UiD of your category_page
join = sys_category_record_mm ON(sys_category_record_mm.uid_local=sys_category.uid)
where = sys_category_record_mm.tablenames='pages'
andWhere.dataWrap = sys_category_record_mm.uid_foreign = {TSFE:id}
}
renderObj = TEXT
renderObj.field = title
renderObj.wrap = <li class="category {field:title}">|</li>
renderObj.insertData = 1
}
The corresponding error output is as follows:
An exception occurred while executing 'SELECT * FROM `sys_category` INNER JOIN `sys_category_record_mm`
`ON(sys_category_record_mm`.`uid_local=sys_category`.`uid)` ON WHERE
(`sys_category`.`pid` IN (35)) AND
(sys_category_record_mm.tablenames='pages') AND (`sys_category`.`sys_language_uid` IN (0, -1)) AND
((`sys_category`.`deleted` = 0) AND (`sys_category`.`t3ver_state` <= 0) AND (`sys_category`.`pid` <> -1) AND (`sys_category`.`hidden` = 0) AND (`sys_category`.`starttime` <= 1546204860) AND
((`sys_category`.`endtime` = 0) OR (`sys_category`.`endtime` > 1546204860)))': You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near '.`uid_local=sys_category`.`uid)` ON WHERE (`sys_category`.`pid` IN (35)) AND (s' at line 1
Try adding a space after ON, so:
join = sys_category_record_mm ON (sys_category_record_mm.uid_local=sys_category.uid)
Also, andWhere has been deprecated since TYPO3 7.1 and has been removed in 8. You need to add that to where and use markers to add the page uid. From the top of my head, that would make it:
lib.catclass = CONTENT
lib.catclass {
wrap = <div class="categories">|</div>
table = sys_category
select {
pidInList = 35 // UiD of your category_page
join = sys_category_record_mm ON (sys_category_record_mm.uid_local=sys_category.uid)
where = sys_category_record_mm.tablenames='pages' AND sys_category_record_mm.uid_foreign = ###pageuid###
markers {
pageuid.data = TSFE:id
}
}
renderObj = TEXT
renderObj.field = title
renderObj.wrap = <li class="category {field:title}">|</li>
renderObj.insertData = 1
}
See https://docs.typo3.org/typo3cms/TyposcriptReference/8.7/Functions/Select/#markers for more on markers

Sort order slider // "For each" in TypoScript

I have a problem with my self made carousel slider. Unfortunately the order is random!
The pid for the slider elements are defined in TS constants:
slider_site_ids = 1359,1348,1076,1067,1078,1117,1346,1349,1376
But this order is not the one displayed on the page.
The slider itself is build like that:
lib.contentSlider = COA
lib.contentSlider {
10 = CONTENT
10 {
table = tt_content
select.where = colPos = 1
select.languageField = sys_language_uid
select.orderBy = sorting
select.pidInList = {$slider_site_ids}
}
10.wrap = <div class="slider-img-cnt">|</div>
20 = CONTENT
20 {
table = tt_content
select.where = colPos = 10
select.languageField = sys_language_uid
select.pidInList = {$slider_site_ids}
}
20.wrap = <div class="content-left fl-left">|</div>
30 = CONTENT
30 {
table = tt_content
select.where = colPos = 20
select.languageField = sys_language_uid
select.pidInList = {$slider_site_ids}
}
30.wrap = <div class="content-right fl-right">|</div>
40 = CONTENT
40 {
table = tt_content
select.where = colPos = 30
select.languageField = sys_language_uid
select.pidInList = {$slider_site_ids}
}
40.wrap = <div class="slogan-box"><div class="first-line">|</div>
50 = CONTENT
50 {
table = tt_content
select.where = colPos = 40
select.languageField = sys_language_uid
select.pidInList = {$slider_site_ids}
}
50.wrap = <div class="second-line">|</div>
60 = CONTENT
60 {
table = tt_content
select.where = colPos = 50
select.languageField = sys_language_uid
select.pidInList = {$slider_site_ids}
}
60.wrap = <div class="third-line">|</div></div>
}
lib.contentSlider.wrap = <article>|</article>
Is there a way to define the sort order? Maybe a for each loop will do the trick? Any ideas?
You can try to use the split function of typoscript.
EDIT: Example
20 = TEXT
20 {
value = {$slider_site_ids}
split {
token = ,
cObjNum = 1
1.10 = CONTENT
1.10 {
table = tt_content
select.where = colPos = 10
select.languageField = sys_language_uid
select.pidInList.current = 1
}
}
}

Typoscript | How to write this like an IF ELSE condition?

I'm new to Typo3, and building a site with TemplaVoila.
I got the following TS (within TV XML) which outputs 2 sets of content
10= RECORDS
10.source.current=1
10.tables = tt_content
10.wrap.required = 1
10.wrap = <!--TYPO3SEARCH_begin--> | <!--TYPO3SEARCH_end-->]]>
20 = CONTENT
20.table = tt_content
20.select {
pidInList = 36
}
The first set (10) is the current page content, and the second (20) fetches content from page ID 36.
Currently both are printed, but I want 20 to print only if 10 is empty.
How can I achieve this?
10.stdWrap.ifEmpty.cObject = CONTENT
10.stdWrap.ifEmpty.cObject {
table = tt_content
select.pidInList = 36
}
did not test, but should work. stdWrap is executed after wrap. So in this case, you will not have the Search-Markers are set.

Select other PID if select result is empty

I got this TS:
markers.input_readonly_b_price = CONTENT
markers.input_readonly_b_price {
table = tx_pricelist_prices_full
select {
pidInList = 27
orderBy = uid
selectFields = uid, group_b_1_3
# possible conditions
where = ( hidden='0' AND deleted='0')
}
renderObj = COA
renderObj {
#value
1 = TEXT
1.insertData = 1
1.data = field:group_b_1_3
2 = TEXT
2.value = *
3 = TEXT
3.insertData = 1
3.data = TSFE:fe_user|sesData|finish_day
stdWrap.prioriCalc = 1
}
}
I need to change that TypoScript with that condition:
If on page with id 27 - pid=27 record inside will have status deleted/hidden then read data from pid=20 else (there is one record visible) read data from pid=27
On pid=20 there will be a record (always). On 'pid=27` will be one record but sometime hidden, sometime visible.
Does anyone have an idea how to set this condition?