Assign register value to TYPO3 CASE key - typo3

Am making some complex menus and would like to use CASE (or similar) to determine the number of submenus in a given branch in order to determine the style of menu to use.
Code:
5 = HMENU
5 {
entryLevel = -1
1 = TMENU
1 {
expAll = 1
NO = 1
NO {
...
}
IFSUB = 1
IFSUB {
10 = CASE
10 {
key.data = {register:count_menuItems}
1 = COA
1 {
data = {field:title}
data.insertData = 1
}
2 = COA
2 {
data = {field:title}
data.insertData = 1
}
default = COA
default {
data = {field:title}
data.insertData = 1
}
}
wrapItemAndSub = |
}
}
2 = TMENU
2 {
maxItems = 2
expAll = 1
...
}
}
How can I get CASE to work? I've tried it with and without the braces.

you should get more information how to access fields, register and other data in typoscript.
if you have a property you mostly can modify the way to get other information than a constant text.
In your example it is the key property where constants are not meaningful.
if you want to access a field of the 'current' record/data you just use key.field = fieldname
if it is other data you modify it to key.data = register:registername
accessing a field can be done with key.data = field:fieldname
If you want these data connected to other information you could use a wrap:
key.data = register:registername
key.wrap = prefix- | -suffix
Notice: the parts of the wrap are trimmed before they are connected
another way would be an inline notation where you even can use multiple values:
key = {register:registername}-with-{field:fieldname}
key.insertData = 1
here you have two replacements. each has to be wrapped in braces {} and you need to tell TYPO3 that there are replacements to do: insertData = 1
special case TEXTobject:
10 = TEXT
10.value = constant Text
20 = TEXT
20.field = fieldname
30 = TEXT
30.data = register:registername
40 = TEXT
40.value = register is '{register:registername}' and field is '{field:fieldname}'
40.insertData = 1
ADDED:
see the manual of the typoscript data type getText where you can find what else can be used instead of register:
then the manual entry for data which is a property of the function .stdWrap and of type getText.
This entry is followed by the property field stating, it is a shortcut for data = field:
(This explaines why your COA with .data results in anything, as doing a .stdWrap.data on any object will replace the object's content.)
be aware that field (either as property or as key of getText) will select
a field of the current record, which might vary dependent on context:
for page rendering it is the record of the current page (table pages),
for rendering a content element it is the element (table tt_content),
inside a filesProcessor it is a file (table sys_file_reference`),
in the renderObj of CONTENT, RECORDS, or split it is the selction you define.

Found the answer. As far as I can tell, CASE works on stdwrap.cObjects and so the code
10 = CASE
10 {
key.data = {register:count_menuItems}
...
}
should be
stdWrap.cObject = CASE
stdWrap.cObject {
key.data = register:count_menuItems
if.isTrue.data = register:count_menuItems
...
}
This way it works.

Related

How to get "leveltitle" for HMENU items via TypoScript?

I have a menu (HMENU with special = updated) that gives me the latest sub and sub-sub pages from 3 categories.
The page structure looks like this in the backend:
In addition to the title, I would like to output the name of the respective category (the parent level-1 page).
This is my TypoScript attempt:
lib.myMenu = HMENU
lib.myMenu {
special = updated
special{
value.field = 10,11,12
beginAtLevel = 1
limit = 99
}
1 = TMENU
1{
NO{
doNotLinkIt = 1
stdWrap.cObject = COA
stdWrap.cObject {
10 = TEXT
10{
wrap = <h3>|</h3>
field = seo_title // title
typolink.parameter.field = uid
}
20 = HMENU
20{
wrap = <div class="category attempt-1">|</div>
special = rootline
special.range = 1|1
special.value.field = uid # does not work
1 = TMENU
1.NO.allWrap = |
}
30 = TEXT
30{
wrap = <div class="category attempt-2">|</div>
data = leveltitle : 1 # does not work as expected
}
}
}
}
}
Unfortunately it does not work, because …
special = rootline does not support special.value.
data = leveltitle : 1 uses the ID of the current page, instead of the TMENU item ID.
Does anyone have another approach how I can get the title of the respective category using TypoScript?
Edit: Background information / what this is needed for
With this menu I intend to replace the news module ext:news of an existing project. Instead of news records, pages are now used and this menu creates the list view. Of course a TypoScript page browser will be added.
I would not rebuild the complete menu item generation (NO.doNotLinkIt = 1).
Just use NO.after.cObject = COA.
leveltitle : 1 is correct if you want to have the title for the current page.
The same if you show a rootline menu: it is generated for the current page.
If you want the levelfield for another page you need to build it by yourself.
In typoscript you might use a userfunction. (there is a core function for getting the rootline for a given page id)
If you generate your menu with FLUID you might use a viewhelper. (You might get inspired from this option of viewhelper menu.directory or this option of VH page.breadCrumb in ext:vhs.)
Edit:
you might store the needed information directly in the pagesrecord.
add a new field to the record (or use any unused).
then make sure that each category page contains some page TS_config:
TCADefaults.pages.<yourfield> = CategoryName
With this configuration each new page below will get this value set automatically.
Of course you need to set these values for all existing pages by hand or by some manual queries.
And if the editors are to be prevented from changing this value you need to remove the field from the edit form with this TSConfig on the top-page:
TCEForm.pages.<yourfield>.hide= 1
I have found a pure TypoScript solution that may not be very elegant, but it works:
lib.myMenu = HMENU
lib.myMenu {
special = updated
special{
value.field = 10,11,12
beginAtLevel = 1
limit = 99
}
1 = TMENU
1{
NO{
doNotLinkIt = 1
stdWrap.cObject = COA
stdWrap.cObject {
10 = TEXT
10{
wrap = <h3>|</h3>
field = seo_title // title
typolink.parameter.field = uid
}
20 = HMENU
20{
wrap = <div class="category">|</div>
special = list
special.value.field = pid
1 = TMENU
1{
NO{
doNotLinkIt = 1
stdWrap.override{
# Overwrite it if we are not yet at the category level
if{
# The ID of the page parent to the categories ("Website") is 1618
equals = 1618
value.field = pid
negate = 1
}
cObject = HMENU
cObject{
special = list
special.value.field = pid
1 = TMENU
1.NO.doNotLinkIt = 1
}
}
}
}
}
}
}
}
}
If the menu is to go over further levels, the override must of course be nested even deeper.
Edit – Improvements:
RECORDS instead of HMENU: Bernd Wilke suggested in the comments to use CONTENT instead of HMENU to generate the category title. This caused problems in my tests when sysfolders (as subpages of the categories) were used to structure the items. This could be related to the bug/feature #20933 (Enable working with SysFolders in CONTENT). But RECORDS might be comparable. I tried it and was able to improve the render times a little bit (see table below).
lib.myMenu.1.NO.stdWrap.cObject.20 = RECORDS
lib.myMenu.1.NO.stdWrap.cObject.20{
stdWrap.wrap = <div class="category">|</div>
source.field = pid
tables = pages
conf.pages = TEXT
conf.pages {
field = seo_title // title
stdWrap.override{
# Overwrite it if we are not yet at the category level
if{
# The ID of the page parent to the categories ("Website") is 1618
equals = 1618
value.field = pid
negate = 1
}
cObject = RECORDS
cObject{
source.field = pid
tables = pages
conf.pages = TEXT
conf.pages.field = seo_title // title
}
}
}
}
CONTENT instead of HMENU: if no sysfolders are needed (as of TYPO3 10.4 sysfolders should also work)
lib.myMenu.1.NO.stdWrap.cObject.20 = CONTENT
lib.myMenu.1.NO.stdWrap.cObject.20{
stdWrap.wrap = <div class="category">|</div>
table = pages
select {
uidInList.field = pid
pidInList = 0
selectFields = uid, pid, seo_title, title
}
renderObj = TEXT
renderObj {
field = seo_title // title
stdWrap.override{
# Overwrite it if we are not yet at the category level
if{
# The ID of the page parent to the categories ("Website") is 1618
equals = 1618
value.field = pid
negate = 1
}
cObject = CONTENT
cObject{
table = pages
select {
uidInList.field = pid
pidInList = 0
selectFields = uid, pid, seo_title, title
}
renderObj = TEXT
renderObj.field = seo_title // title
}
}
}
}
userFunc instead of HMENU: Bernd Wilke suggested in his answer to use a userfunction. Even if this is not a pure TypoScript solution, I would have liked to test it to be able to compare the performance. The method getRootLine() has unfortunately been marked as deprecated. Since I'm not an extension developer, it's not clear to me yet how to read the category via a userFunc and if this is actually more effective. If I still come across a solution regarding this, it will be added here.
Rendertime: I have test-implemented the menu in the live site (in the existing template) and compared the website render times with and without the output of the categories to see how much the nested menu affects the performance. The values are average values from 10 measurements. I also limited the output to 20 items, which should be a more realistic value per page later on:
mode
20 items
100 items
without category
99 ms
218 ms
categories via HMENU
133 ms
353 ms
categories via RECORDS
132 ms
331 ms
categories via CONTENT
121 ms
255 ms
categories via userFunc
TBD
TBD
You should neither use a separate HMENU nor a userFunc but a simple LOAD_REGISTER within the menu items of the parent level. This generates register entries, that can be added, changed or restored while looping through the different levels of the HMENU structure.
So you don't need the custom code of a PHP function and you won't get the performance penalty of a nested HMENU.
Basically it's shown in the official documentation, but with a CSS class instead of a title. But of course you could hand over other information from the parent to its children the same way.
Here is the example:
10 = COA
10 {
### left menu table column
10 = LOAD_REGISTER
10 {
ulClass = col-left
}
### right menu table column
20 = LOAD_REGISTER
20 {
ulClass = col-right
}
30 = HMENU
30 {
special = list
special.value = 1
1 = TMENU
# ...
3 = TMENU
3 {
stdWrap {
preCObject = COA
preCObject {
10 = RESTORE_REGISTER
}
dataWrap = <ul class="{register:ulClass}">|</ul>
}
wrap =
SPC = 1
SPC {
allStdWrap {
replacement {
10 {
search = ---
replace =
}
}
dataWrap = </ul>|<ul class="{register:ulClass}">
}
}
}
}
}
And here the link to the full documentation page:
https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/UsingSetting/Register.html

TYPO3 - simpler way, rendering content from colPos into Fluidtemplate?

The official TYPO3 Documentation explains how to create (or copy) and use a lib.dynamicContent to render columns into a Fluidtemplate.
I do not understand exactly whats going on in this example.
The TypoScript there is:
lib.dynamicContent = COA
lib.dynamicContent {
10 = LOAD_REGISTER
10.colPos.cObject = TEXT
10.colPos.cObject {
field = colPos
ifEmpty.cObject = TEXT
ifEmpty.cObject {
value.current = 1
ifEmpty = 0
}
}
20 = CONTENT
20 {
table = tt_content
select {
orderBy = sorting
where = colPos={register:colPos}
where.insertData = 1
}
}
90 = RESTORE_REGISTER
}
I use this snippet in a ton of TYPO3 projects and often had asked myself whats going on there.
I have changed this by experimenting a bit and ended with:
lib {
dynamicContent = COA
dynamicContent {
10 = CONTENT
10 {
table = tt_content
select {
orderBy = sorting
where {
data = field:colPos
wrap = colPos=|
}
}
}
}
}
That seems to do "exactly the same" thing - it outputs my content when called via cObject ViewHelper.
Can somebody explain if or why this is the worse way to render Content?
Here's the link to the lib.dynamicContent-doc: https://docs.typo3.org/c/typo3/cms-fluid-styled-content/master/en-us/Installation/InsertingContentPageTemplate/Index.html#based-on-the-fluidtemplate-content-object-cobj
Here you go!
you can try this,
# Clear out any constants in this reserved room!
styles.content >
# get content
styles.content.get = CONTENT
styles.content.get {
table = tt_content
select.orderBy = sorting
select.where = colPos=0
}
# Left Column
styles.content.getLeft < styles.content.get
styles.content.getLeft.select.where = colPos=1
# Right content
styles.content.getRight < styles.content.get
styles.content.getRight.select.where = colPos=2
Also, you can use variable in the fluid page object, check this out:
lib.pageTemplate = FLUIDTEMPLATE
lib.pageTemplate {
variables {
content = CONTENT
content {
table = tt_content
select.orderBy = sorting
select.where = colPos=0
}
contentRight = CONTENT
contentRight {
table = tt_content
slide = -1
select.orderBy = sorting
select.where = colPos=2
}
}
}
You can find out more here:
Adding the page content to a fluid template
Typo3 7.6 typoscript problems with markers
Hope this make sense, Cheer...!
You should look at this snippet together with some information about the Fluid view helper <f:cObject> which can be found here: https://docs.typo3.org/other/typo3/view-helper-reference/9.5/en-us/typo3/fluid/latest/CObject.html
As you can see there are the parameters data, currentValueKey and table that will be handed over to the typoscriptObjectPath, which is why the snippet makes perfect sense. The reason is, that it's a bit hard to put the different options into the where clause of the CONTENT object. So it increases readability and those registers can be easily extended.
So the register in this example is used to put in either the value of the data field colPos or if that is empty it will take the current value from the currentValueKey and if that is empty too it will fall back to a value of 0 to make sure the query won't produce an exception.
lib.dynamicContent = COA
lib.dynamicContent {
10 = LOAD_REGISTER
10.colPos.cObject = TEXT
10.colPos.cObject {
field = colPos
ifEmpty.cObject = TEXT
ifEmpty.cObject {
value.current = 1
ifEmpty = 0
}
}
20 = CONTENT
20 {
table = tt_content
select {
orderBy = sorting
where = colPos={register:colPos}
where.insertData = 1
}
}
90 = RESTORE_REGISTER
}
We used a modified version of that snippet to sneak in some more parameter values for the CONTENT object.
So we can hand over a data field pageUid, if that is not set we will use the uid of the current page. This will be overriden if the current or the target page is configured to show content from another page and finally we can trigger a slide with another data field.
lib.dynamicContent = COA
lib.dynamicContent {
5 = LOAD_REGISTER
5 {
colPos.cObject = TEXT
colPos.cObject {
field = colPos
ifEmpty.cObject = TEXT
ifEmpty.cObject {
value.current = 1
ifEmpty = 0
}
}
pageUid.cObject = TEXT
pageUid.cObject {
field = pageUid
ifEmpty.data = TSFE:id
}
contentFromPid.cObject = TEXT
contentFromPid.cObject {
data = DB:pages:{register:pageUid}:content_from_pid
data.insertData = 1
}
}
20 = CONTENT
20 {
table = tt_content
slide = -1
slide.if.isTrue.field = slide
select {
includeRecordsWithoutDefaultTranslation = 1
orderBy = sorting
where = {#colPos}={register:colPos}
where.insertData = 1
pidInList.data = register:pageUid
pidInList.override.data = register:contentFromPid
}
}
90 = RESTORE_REGISTER
}
This enables us to make use of the <f:cObject> view helper while triggering additional parameters just by handing over some more values within the data array.

Typoscript operators - Value of filelink referencing to another one

I've set up the Typoscript below, but the last line doesn't work.
I want 20.filelink to have the same content as 10.filelink (the real code is more complex and that bit is redundant).
lib.test = COA
lib.test {
10 = TEXT
10.value = A value
10.filelink {
path = fileadmin/path/
target = blank
stdWrap.wrap = <li>|</li>
}
20 = TEXT
20.if.isFalse.data = subheader
20.value = Another value
20.filelink =< lib.test.10.filelink
}
Copying (with the < operator) works, but not =< as stated.
I've also tried without the lib.test. or with just = but without any success.
Is what I want to do possible?
What did I not understand about operators?
you should put it out of the curly brackets :
lib.test = COA
lib.test {
10 = TEXT
10.value = A value
10.filelink {
path = fileadmin/path/
target = blank
stdWrap.wrap = <li>|</li>
}
20 = TEXT
20.if.isFalse.data = subheader
20.value = Another value
}
lib.test.10.filelink =< lib.test.20.filelink
I figured out what I did not understand. Apparently, you can only copy or reference Content Objects.
The answer then is to reference the entire object, and to modify and add what needs changing. In this case it would be:
lib.test = COA
lib.test {
10 = TEXT
10.value = A value
10.filelink {
path = fileadmin/path/
target = blank
stdWrap.wrap = <li>|</li>
}
20 = < lib.test.10
20.if.isFalse.data = subheader
20.value = Another value
}

Insert comma separated list created with HMENU in TEXT.value

I want to insert my comma separated list created with HMENU at the value of the TEXT item. If I fill the list manually, all working fine, but I can't fill my value from the created hmenu:
temp.pageIds = HMENU
temp.pageIds.entryLevel = 2
temp.pageIds.1 = TMENU
temp.pageIds.1 {
NO.stdWrap.field = uid
NO.allWrap = |,
NO.doNotLinkIt = 1
}
#output temp.pageIds for example 13,53,12,34,
temp.orderedContent = TEXT
temp.orderedContent {
value < temp.pageIds # <------ not working (value = 23,25,57,... working)
split {
token = ,
cObjNum = 1
1 = COA
1 {
10 = CONTENT
10 {
table = tt_content
select {
pidInList.current = 1
where = colPos = 0
}
}
}
}
}
Any ideas?
The value property of a TEXT object will not be interpreted. If you just copy the temp.pageIds-object, it will be just be the literal string HMENU (and have some subproperties), which is not a list of page IDs.
To get it evaluated, notice in the docs that the type of value is of type string/stdWrap, so the value will be filtered through the stdWrap-function. stdWrap has the property cObject, which can be used to interpret content objects.
So this should work:
value.cObject < temp.pageIds

how to insert the language id in a typolink in typoscript

i want to add the language id in a typolink
so far
LOGO = COA
LOGO {
10 = TEXT
10 {
value = logo
typolink {
parameter = 116
additionalParams = &L={$config.sys_language_uid}
}
}
}
if L=4 it's working
but if i use L={$config.sys_language_uid} it gets ignored altogether
same with L=GP:L
and L=GPvar:L
what would be the proper syntax here
working if i do something like
additionalParams = COA
additionalParams {
10 = TEXT
10.data = GP : L
10.intval = 1
10.wrap = &L=|
}
You do not need to do that on your own. With the following global TypoScript configuration the parameter L will added to every link:
config.linkVars = L(int)
So, if you use HMENU.special = language this will be managed on the switch automatically, too:)
http://docs.typo3.org/typo3cms/TyposcriptReference/Setup/Config/Index.html
I do not know about {$config.sys_language_uid}, but your code will output it as plain text. In order to use variables like {GP:L}, you got to dataWrap it or insert "insertData" after the value.
10 = TEXT
10 {
value = logo
typolink {
parameter = 116
additionalParams.dataWrap = &L={GP:L}
}
}
OR (the best way I'd say):
10 = TEXT
10 {
value = logo
typolink {
parameter = 116
additionalParams.cObject = TEXT
additionalParams.cObject {
wrap = &L=|
data = GP:L
}
}
}
Using {TSFE:sys_language_uid} might be a better option if you are querying the database.
There is no need to make a cObject or COA
additionalParams = type=0&L={GP:L}
additionalParams.insertData = 1
You can do this kind of URL using addQueryString = 1. https://docs.typo3.org/typo3cms/TyposcriptReference/Functions/Typolink/Index.html#addquerystring