i'm trying to create a menubar with typoscript when im assigning an integer like 116 everything is working as expected but the thing is i dont know the page id and im getting from the session like this TSFE:fe_user|sesData|usergroup|menuProtectedRoot in this case the menu fails to appear
MENU_PROTECTED_ROOT = HMENU
MENU_PROTECTED_ROOT {
special = directory
special.value = TSFE:fe_user|sesData|usergroup|menuProtectedRoot
...
but this will
MENU_PROTECTED_ROOT = HMENU
MENU_PROTECTED_ROOT {
special = directory
special.value = 116
...
im absolutely sure the variable is there i can even output in another subpart
SPAN = COA
SPAN {
10 = TEXT
10.data = TSFE:fe_user|sesData|usergroup|menuProtectedRoot
10.wrap = |
}
i have tried setting it as a constant in my template > same result
i make sure it's a integer using (int) when setting the variable in my controller
MENU_PROTECTED_ROOT = HMENU
MENU_PROTECTED_ROOT {
special = directory
special.value = TSFE:fe_user|sesData|usergroup|menuProtectedRoot
special.value.insertData = 1
no effect
MENU_PROTECTED_ROOT = HMENU
MENU_PROTECTED_ROOT {
special = directory
special.data = TSFE:fe_user|sesData|usergroup|menuProtectedRoot
no effect
Try this approach:
MENU_PROTECTED_ROOT = HMENU
MENU_PROTECTED_ROOT {
special = directory
special.value.stdWrap.data = TSFE:fe_user|sesData|usergroup|menuProtectedRoot
Definition of special.value in HMENU[1] says that it can be stdWrap type which includes data parameter.
[1] http://wiki.typo3.org/TSref/HMENU
special.value does not support getText[1] (so it won't resolve any values from TSFE, GP, etc.) unless you set insertData = 1. Try this:
MENU_PROTECTED_ROOT = HMENU
MENU_PROTECTED_ROOT {
special = directory
special.value = {TSFE:fe_user|sesData|usergroup|menuProtectedRoot}
special.value.insertData = 1
[1] http://wiki.typo3.org/TSref/getText
Related
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
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.
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
}
In TYPO3 6.2 (just upgraded from 4.5) I have a TMENU with Images, using a cObject in NO to build the menu as desired.
It works in the main language, but in the second language's frontend, the images are not rendered - unless they are filled in in the second language's media field.
How do you force FILES to refer to the media field of the original language?
In my case, always. In other cases, a fallback solution may be desired.
temp.menu = COA
temp.menu {
wrap = <div class="teasermenu">|</div>
15 = HMENU
15 {
special = list
//special.value.cObject < temp.displayedpages
// recieves a list, such as:
special.value = 1,3,9
1 = TMENU
1 {
noBlur = 1
maxItems = 16
wrap = <ul>|</ul>
NO {
wrapItemAndSub = <li>|</li>
ATagBeforeWrap = 1
ATagParams = || || || || class="red" |*| |*|
stdWrap.cObject=COA
stdWrap.cObject{
10 = TEXT
10.field = nav_title // title
10.wrap = <strong class="teasermenu_header">|</span></strong>
20=FILES
20{
if{
isInList.field = uid
//value.cObject < temp.displayedpages_wimage
// receives another list, like:
// value = 3,9
}
references {
table=pages
fieldName=media
}
renderObj=IMAGE
renderObj{
file{
height=80
maxH=80
import.data=file:current:publicUrl
}
altText.field=title
titleText.field=title
}
}
}
}
}
}
}
PS there are many media field / FAL fallback related bugs on forge, e.g. this one. But I have a feeling this might be a simpler issue.
mergeIfNotBlank is gone now, the current solution (TYPO3 8.7) seems to be to set
$GLOBALS['TCA']['pages']['columns']['media']['config']['behaviour']['allowLanguageSynchronization'] = 1;
But based on https://forum.typo3.org/index.php/t/217033/-typo3-ug-freiburg-media-feld-in-den-seiteneigenschaften (thanks) there's this snippet. It also works with cropVariants:
temp.bgimg_wide = CONTENT
temp.bgimg_wide{
table = sys_file_reference
select{
pidInList = {$pids.pidHome}
where = tablenames='pages' AND fieldname='media'
orderBy = sorting_foreign
languageField = 0
selectFields = uid_local
max = 1
begin = 0
}
renderObj = FILES
renderObj{
files.stdWrap.field = uid
renderObj = IMG_RESOURCE
renderObj {
file {
import.data = file:current:uid
treatIdAsReference = 1
width = 1600
cropVariant = bgimg_wide
}
}
}
}
}
This works!
With TYPO3 CMS 7.6 you need to exclude field media of table pages from [FE][pageOverlayFields] as set in ~/typo3_src-7.6.10/typo3/sysext/core/Configuration/DefaultConfiguration.php, until it is solved - see forge issue https://forge.typo3.org/issues/65863
Write in your AdditionalConfiguration
$GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields'] = 'uid,doktype,title,subtitle,nav_title,keywords,description,abstract,author,author_email,url,urltype,shortcut,shortcut_mode';
or in your Extension ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields'] = str_replace(',media', '', $GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields']);
Based on Urs' answer, here comes a slight variation.
lib.getCurrentPageMedia = CONTENT
lib.getCurrentPageMedia {
table = sys_file_reference
select{
pinInList = root, this
where = tablenames='pages' AND fieldname='media' AND uid_foreign=###pid###
orderBy = sorting_foreign
languageField = 0
selectFields = uid_local
max = 1
begin = 0
markers {
pid.data = TSFE:id
}
}
renderObj = TEXT
renderObj.stdWrap.field = uid
}
Fluid:
<f:image src="{f:cObject(typoscriptObjectPath:'lib.getCurrentPageMedia')}" alt="" width="400c" height="400c" treatIdAsReference="1" class="img-responsive" />
Advantage: you can define cropping, alt-text, etc. in your template.
You might want to try to set the TCA of the media field to l10n_mode => mergeIfNotBlank .
http://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Index.html#columns-properties-l10n-mode
Put this into the typo3conf/AdditionalConfiguration.php:
$TCA['pages']['columns']['media']['l10n_mode'] = 'mergeIfNotBlank';
Since this issue is from Februari, you've probably found a solution by now. I just ran into this issue and solved it by including:
$GLOBALS['TCA']['pages_language_overlay']['columns']['media']['l10n_mode'] = 'mergeIfNotBlank';
in my ext_tables.php
I'm building a site with Fluid Template. I have created two different front-end layouts and two different back-end layout but I always get this error #1288085266: No template has been specified. Use either setTemplateSource() or setTemplatePathAndFilename(). Accordingly to Typo3 Wiki this should be a solution Exception/CMS/1288085266
but not in my case. This is my code:
config.doctype = html5
page = PAGE
page {
includeCSSLibs.bootstrap = https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css
includeCSS.style = fileadmin/templates/rka2015/css/style.css
includeJSlibs.jquery = https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
includeJSlibs.bootstrap = https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js
includeJS.custom = fileadmin/templates/rka2015/js/custom.js
}
page.10 = FLUIDTEMPLATE
page.10 {
file = fileadmin/templates/rka2015/layouts/main_layout.html
layoutRootPath = fileadmin/templates/rka2015/layouts/
patialRootPath = fileadmin/templates/rka2015/partials/
variables {
siteName = TEXT
siteName.value = rka2015
contentMain < styles.content.get
contentMain.select.where = colPos = 0
content_column_1 < styles.content.get
content_column_1.select.where = colPos = 1
content_column_2 < styles.content.get
content_column_2.select.where = colPos = 2
}
}
page.10.file.stdWrap.cObject = CASE
page.10.file.stdWrap.cObject
{
key.data = levelfield:-1, backend_layout_next_level, slide
key.override.field = backend_layout
default = TEXT
default.value = fileadmin/templates/rka2015/main_1_column.html
1 = TEXT
1.value = fileadmin/templates/rka2015/main_1_column.html
2 = TEXT
2.value = fileadmin/templates/rka2015/main_2_column.html
}
I have already checked all; section name is OK, ID for back-end layouts are ok, template is defined, everything seem to be as it should be. I really don't have a clue where else to search.
UPDATE!!!
Seems like there is a problem with a file path. I am running my site on a subdomain and it looks like that ts doesn't find the file paths if they are defined only as fileadmin/... Any thoughts? Thanks
SOLUTION!
page {
includeCSSLibs.bootstrap = https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css
includeCSS.style = fileadmin/templates/rka2015/css/style.css
includeJSlibs.jquery = https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
includeJSlibs.jquery.external = 1
includeJSlibs.bootstrap = https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js
includeJS.custom = fileadmin/templates/rka2015/js/custom.js
}
page.10 = FLUIDTEMPLATE
page.10 {
template = CASE
template {
key.data = levelfield:-1,backend_layout_next_level,slide
key.override.field = backend_layout
1 = FILE
1.file = fileadmin/templates/rka2015/main_1_column.html
2 = FILE
2.file = fileadmin/templates/rka2015/main_2_column.html
}
partialRootPath = fileadmin/templates/rka2015/partials/
layoutRootPath = fileadmin/templates/rka2015/layouts/
variables {
siteName = TEXT
siteName.value = rka2015
contentMain < styles.content.get
contentMain.select.where = colPos = 0
content_column_1 < styles.content.get
content_column_1.select.where = colPos = 1
content_column_2 < styles.content.get
content_column_2.select.where = colPos = 2
}
}
First, check out if TYPO3 can read the file by overwriting the page object by appending this to the end of your template:
page.10 >
page.10 = FILE
page.10.file = fileadmin/templates/rka2015/layouts/main_layout.html
If that doesn't generate a page with the raw, uninterpreted output of your template file, then theres something wrong with either the file path or file permissions.
Secondly, in Fluid, Templates and Layouts are different things with different uses and should propably not be put into the same directory.
Most importantly, theres something wrong with the backend layout switch you're trying to build with the CASE in page.10.file.stdWrap.cObject . You see, the stdWrap object actually wraps around the text you've already set. If stdWrap cant find a pipe to figure out how to wrap, it just appends instead. Remove the line where you set the file in the top part and only leave the stdWrap case and you should be good to go.
at the first look it looks right... but check your file paths, maybe they are wrong as "Jost" commented.
i'm not sure but i think the problem is that the template path (file = ...) is the same as layout root path...
by the way... if you include external styles and javascripts you need to set something like the follows i think...
includeJSlibs.jquery = https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
includeJSlibs.jquery.external = 1