I have the following config
page = PAGE
page {
typeNum = 0
10 = FLUIDTEMPLATE
10 {
templateRootPath = EXT:folder/Resources/Private/Website/Templates/
partialRootPath = EXT:folder/Resources/Private/Website/Partials/
layoutRootPath = EXT:folder/Resources/Private/Website/Layout/
file.stdWrap.cObject = CASE
file.stdWrap.cObject {
key.data = levelfield:-1, backend_layout_next_level, slide
key.override.field = backend_layout
default = TEXT
default.value = whatever.html
1 < .default
2 = TEXT
2.value = whatever-else.html
}
}
Somehow the 'backend_layout_next_level' is not working; it is not sliding down the tree. As a result I have to set a backend_layout for each page which is not what one should expect.
Is there a way of knowing/debugging/finding out what's causing this? I thought it might be something related to a curly brace being in the wrong place (too early, too late or just plain wrong) inside my typoscript. Therefor I looked inside the Typoscript Template Analyzer and found some errors which I've fixed, but the problem still persists.
Thanks already!
Best regards
You use have to give the full path to the file as a value in the .file property or you should use .templateName instead and only provide the name (case sensitive!!!) of the template file without suffix.
#see https://docs.typo3.org/typo3cms/TyposcriptReference/ContentObjects/Fluidtemplate/Index.html
Note that in your current setting, the uid of the template record must be 1 or 2.
And you can try to use levelfield: -2 instead of levelfield: -1.
TBH I never understood this #^$#% CASE syntax... Therefore definitely prefer common condition which works perfect, you must to add custom condition like I showed in other post, so you can use it like:
page {
typeNum = 0
10 = FLUIDTEMPLATE
10 {
templateRootPath = EXT:folder/Resources/Private/Website/Templates/
partialRootPath = EXT:folder/Resources/Private/Website/Partials/
layoutRootPath = EXT:folder/Resources/Private/Website/Layout/
file = whatever.html
}
}
[userFunc = user_beLayout(2)]
page.10.file = whatever-else.html
[userFunc = user_beLayout(3)]
page.10.file = yet-other.html
[userFunc = user_beLayout(4)]
page.10.file = etc.html
[end]
Edit - to satisfy some comments
Note: When I say that I don't understand CASE syntax, that doesn't mean that I don't know it... especially that I studied it in details not once, here's the conclusion...
About performance:
Custom conditions solution is faster than using CASE and slide combination as it doesn't involve additional DB queries (slide does), it iterates $GLOBALS['TSFE']->page array, which is already collected, and stops further checks ASAP, so it's cheaper than slide which makes additional queries if it finds slide in TS (doesn't matter if it's required or not) - (examine the code for slide mechanics), so actually conditions are performance-saver not killer :)
Yet more
Using conditions blocks you can change behavior of multiple elements at once (instead writing separate CASE for each) i.e.:
[userFunc = user_beLayout(2)]
page.10.file = whatever-else.html
lib.genericMenu >
config.absRefPrefix = /layout-specific-abs/
// etc...
[end]
Using CASE syntax you'll need to repeat all these checks for each element... (where's DRY?)
Finally
Both solutions are ... usable especially when using with cached pages, (difference between them will be about teens or maybe in drastic situation hundred milliseconds -conditions will be faster), for uncached pages most probably it will be good idea to set be_layout directly for each pages record in both cases.
It is quite some time ago, you probably resolved your issue but here is a working approach:
page = PAGE
page {
10 = FLUIDTEMPLATE
10 {
# select different html files for layouts - ref: backend_layout
file.stdWrap.cObject = TEXT
file.stdWrap.cObject {
data = levelfield:-2,backend_layout_next_level,slide
override.field = backend_layout
split {
token = pagets__
1.current = 1
1.wrap = |
}
wrap = EXT:folder/Resources/Private/Templates/|.html
}
layoutRootPath = EXT:folder/Resources/Private/Layouts/
partialRootPath = EXT:folder/Resources/Private/Partials/
}
}
or you can pass it as a variable:
page = PAGE
page {
10 = FLUIDTEMPLATE
10 {
file = EXT:folder/Resources/Private/Templates/Main.html
layoutRootPath = EXT:folder/Resources/Private/Layouts/
partialRootPath = EXT:folder/Resources/Private/Partials/
variables {
# BE_Layout
BE_Layout = COA
BE_Layout {
stdWrap.cObject = TEXT
stdWrap.cObject {
data = levelfield:-2,backend_layout_next_level,slide
override.field = backend_layout
split {
token = pagets__
1.current = 1
1.wrap = |
}
wrap = |.html
}
}
}
}
Related
I tried this, in my extension's setup.typoscript. but is not work for me.
plugin.tx_blog {
view {
layoutRootPaths = EXT:solution/Resources/Private/Extensions/Blog/Layouts/
partialRootPaths = EXT:solution/Resources/Private/Extensions/Blog/Partials/
templateRootPaths = EXT:solution/Resources/Private/Extensions/Blog/Templates/
}
}
all the "RootPaths" are arrays so change it to somting like this
plugin.tx_blog {
view {
layoutRootPaths.200 = EXT:solution/Resources/Private/Extensions/Blog/Layouts/
partialRootPaths.200 = EXT:solution/Resources/Private/Extensions/Blog/Partials/
templateRootPaths.200 = EXT:solution/Resources/Private/Extensions/Blog/Templates/
}
the "200" in the examle is the position if Fluid is looking for a Resource (like a template) it will check every provided path in numerical order.
use the Typoscript Object Browser (in the Template Module) to check the configured RootPaths
The standard setup of that extension is a bit uncommon.
The easiest was to override the paths for fluid files is to use the constant editor. There you have fields where you can enter your own paths.
If you want to do it in the setup, you can look in the TypoScript setup of the extension that looks like shown below.
page = PAGE
page {
typeNum = 0
10 = FLUIDTEMPLATE
10 {
templateName = BlogList
templateRootPaths {
0 = EXT:blog/Resources/Private/Templates/Page/
1 = {$page.fluidtemplate.templateRootPath}
}
partialRootPaths {
0 = EXT:blog/Resources/Private/Partials/Page/
1 = {$page.fluidtemplate.partialRootPath}
}
layoutRootPaths {
0 = EXT:blog/Resources/Private/Layouts/Page/
1 = {$page.fluidtemplate.layoutRootPath}
}
...
So in a short block the the paths would look like this:
page.10.templateRootPaths {
0 = EXT:blog/Resources/Private/Templates/Page/
1 = {$page.fluidtemplate.templateRootPath}
}
page.10.partialRootPaths {
0 = EXT:blog/Resources/Private/Partials/Page/
1 = {$page.fluidtemplate.partialRootPath}
}
page.10.layoutRootPaths {
0 = EXT:blog/Resources/Private/Layouts/Page/
1 = {$page.fluidtemplate.layoutRootPath}
}
In the lines starting with 1 you can enter your own path if you never want to use the constants. For this you never have to enter it in the original TypoScript template, but just copy the block above in your own TypoScript and adjust the paths. If your TypoScript is loaded after that of the blog, it's overwriting the original values.
Take care that there exist different setups, one in each folder inside https://github.com/TYPO3GmbH/blog/tree/master/Configuration/TypoScript. So depending on the template you chose the setup must be different. But I hope you're able to adapt the way to go now.
I'm trying to wrap an image with additional HTML elements and parameters, using Typoscript in a Setup Template.
So far, I've managed to wrap elements with HTML, but I'd like to add some parameters as well. The problem occurs, when I try to escape variables in variables - I can't pass UID from one of the parameters.
Below is the sample:
lib.parseFunc_RTE {
tags.img = TEXT
tags.img {
current = 1
preUserFunc = Netresearch\RteCKEditorImage\Controller\ImageRenderingController->renderImageAttributes
dataWrap = |
}
}
The problematic part is here: title="file:{parameters:data-htmlarea-file-uid}:title"
I've tried using {file:{parameters:data-htmlarea-file-uid}:title}, but it still doesn't work and shows error within rendered element:
The only working example is when I hardcode the UID ({file:120:title}), but it should be added dynamically, as there are many images.
How can I escape this "double variables"? Or maybe there is another solution to make it work?
==================================================
Here's the full solution of my problem, thanks to #Jo Hasenau
lib.parseFunc_RTE {
tags.img = COA
tags.img {
10 = TEXT
10 {
dataWrap = file:{parameters:data-htmlarea-file-uid}:title
wrap3 = <a href="{parameters:src}" class="lightbox" title="{|}"
insertData = 1
}
20 = TEXT
20 {
dataWrap = file:{parameters:data-htmlarea-file-uid}:description
wrap3 = data-lightbox-caption="{|}" data-lightbox-width="{parameters:width}" data-lightbox-height="{parameters:height}" rel="lightbox-group">
insertData = 1
}
30 = TEXT
30 {
current = 1
preUserFunc = Netresearch\RteCKEditorImage\Controller\ImageRenderingController->renderImageAttributes
wrap = |</a>
}
}
}
You can use dataWrap and/or insertData multiple times either by using the official order of stdWrap functions or by squeezing in another "level" of stdWrap functions with stdWrap.functionName
In this case it's the order of functions combined with a COA to separate the original wrap into smaller chunks and some additional braces provided by another wrap.
lib.parseFunc_RTE {
tags.img = COA
tags.img {
10 = TEXT
10 {
preUserFunc = Netresearch\RteCKEditorImage\Controller\ImageRenderingController->renderImageAttributes
dataWrap = file:{parameters:data-htmlarea-file-uid}:title
wrap3 = <a href="{parameters:src}" class="lightbox" title="{|}" data-lightbox-caption="{file:120:title}" data-lightbox-width="{parameters:width}" data-lightbox-height="{parameters:height}" rel="lightbox-group">
insertData=1
}
20 = TEXT
20.current = 1
20.wrap = |</a>
}
}
preUserFunc will be executed first, then the first dataWrap will create the actual variable name, followed by wrap3 to get the necessary curly braces, finalized by insertData to fill in all the other variables together with the generated variable.
The order in this code is just for better readability, but the actual order of function calls within stdWrap is predefined in the PHP code and follows exactly the order of function descriptions in the official docs: https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/Functions/Stdwrap.html
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
I'm trying to build from scratch a website with typo3 9.5 and setting up different template files for different pages. How do I achieve this?
I'm following the tutorial from https://docs.typo3.org/m/typo3/tutorial-sitepackage/master/en-us/TypoScriptConfiguration/Index.html and also tried the solution with no success provided at Typo3 Fluid Templates How to add multiple templates
Now all pages load the Default template and if I set the default cObject to Alternative, it loads the Alternative.html to all pages, even when the TCA at Typo3 is set correctly for each page:
All Pages Back-end Layout to [Default]
Contact set to [Alternative].
_
page = PAGE
page {
typeNum = 0
// Part 1: Fluid template section
10 = FLUIDTEMPLATE
10 {
templateName = TEXT
templateName.stdWrap.cObject = CASE
templateName.stdWrap.cObject {
key.data = pagelayout
pagets__default = TEXT
pagets__default.value = Default
default = TEXT
default.value = Default
pagets__alternative = TEXT
pagets__alternative.value = Alternative
alternative = TEXT
alternative.value = Alternative
}
templateRootPaths {
0 = EXT:photo/Resources/Private/Templates/Page/
1 = {$page.fluidtemplate.templateRootPath}
}
partialRootPaths {
0 = EXT:photo/Resources/Private/Partials/Page/
1 = {$page.fluidtemplate.partialRootPath}
}
layoutRootPaths {
0 = EXT:photo/Resources/Private/Layouts/Page/
1 = {$page.fluidtemplate.layoutRootPath}
}
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor
10 {
levels = 1
includeSpacer = 1
as = mainnavigation
}
}
}
I want to use for instance a default.html template for all pages except contact page, which will have it's own template ( site_template/Resources/Private/Templates/Page/Alternative.html ).
First:
you should use higher numbers for the paths to your templates.
The higher the number the higher the priority for overriding files with the same name.
second:
there is no field pagelayout. either use layout or better backend_layout and backend_layout_next_level (example configuration with the full usage of configuration for subpages).
Your key values (pagets__default and pagets__alternative) already hint to the usage of backend_layout (pagets__* is the usual key for backend layouts defined in page TSconfig).
Probably the example in the documentation needs some correction. (Pull-request commited)
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