Typoscript HMENU: get level 1 title in level 2 navigation - typo3

I need to create a menu where, for mobile purposes, before all entries of level 2 there is the title of level 1. Example: my structure looks like this:
team
Max
Sepp
projects
project 1
project 2
now I want my navigation to look like this:
<ul>
<li>
<a>Team</a>
<div class="dropdown-menu">
<ul>
<li>Team</li>
<li><a>Max</a></li>
<li><a>Sepp</a></li>
</ul>
</div>
</li>
<li>
<a>Projects</a>
<div class="dropdown-menu">
<ul>
<li>Projects</li>
<li><a>Project 1</a></li>
<li><a>Project 2</a></li>
</ul>
</div>
</li>
</ul>
So I need in level 2 the title of level 1. how to I access field: nav_title for the parent element?
My typoscript looks like this:
temp.nav = HMENU
temp.nav {
1 = TMENU
1 {
expAll = 1
wrap = |
noBlur = 1
stdWrap.innerWrap.cObject = LOAD_REGISTER
stdWrap.innerWrap.cObject {
level1Title.field = nav_title//title
}
NO = 1
NO {
...
}
}
2 = TMENU
2 {
expAll = 1
stdWrap.dataWrap = <ul><li> {register:level1Title}</li>|</ul><a>Jetzt Mitglied werden</a></div>
noBlur = 1
NO = 1
NO {
...
}
}
}
I tried it with LOAD_REGISTER but that doesnt work. Any suggestions?

what you want is the default behaviour of TYPO3 menus. You just need to set the correct wrapping. Do the wrapping where it belongs:
temp.menu = HMENU
temp.menu {
1 = TMENU
1 {
expAll = 1
wrap = <ul>|</ul>
NO = 1
NO {
wrapItemAndSub = <li>|</li>
}
}
// as you have no specific wrapping all levels can be generated the same:
2 < .1
3 < .2
}
if you want specific wraps on each level you can adapt it after copying (in this example you can see where a wrapping is coming from)
temp.menu = HMENU
temp.menu {
1 = TMENU
1 {
wrap = <ul class="level1">|</ul>
NO = 1
NO {
wrapItemAndSub = <li class="lev1">|</li>
}
}
2 < .1
2 {
wrap = <ul class="level2">|</ul>
NO.wrapItemAndSub = <li class="lev2">|</li>
}
3 < .2
3 {
wrap = <ul class="level3">|</ul>
NO.wrapItemAndSub = <li class="lev3">|</li>
}
}
.
EDIT: after clarification of problem:
working with LOADREGISTER in menus would result in a mess as the menu items are not generated inline recursive.
If you want to repeat the menuitem you should generate it in place.
Therefore you need to split the clean wrappings and use soem enhanced menu magic.
temp.menu = HMENU
temp.menu {
1 = TMENU
1 {
wrap = <ul class="level1">|</ul>
NO = 1
NO.wrapItemAndSub = <li>|</li>
// only for menuitems which contains further pages:
IFSUB < .NO
IFSUB {
// beginning the part of the submenu
after.cObject = TEXT
after.cObject {
field = nav_title // title
wrap = <div class="dropdown-menu"><ul><li>|</li>
}
}
}
2 < .1
2 {
// no beginning in wrap needed as it is done at level 1
wrap = |</ul></div>
}
}
further levels need additional handling. e.g.: 2.IFSUB > and 3.wrap = <ul>|</ul>
Note: If you want a clean html with indentions you need to use .noTrimWrap and multi line values in typoscript.

Related

TYPO3CMS: Different Menu Language than Content

Our customer wants, why the hell not, a Spanish Homepage, but the menu should refer to the English pages.
Unfortunately English isn't the default language in the system.
Is this somehow possible to achieve within TYPO3?
The menu is generated via Typoscript:
lib.nav = HMENU
lib.nav {
wrap = <ul class="noListStyle">|</ul>
entryLevel = 0
1 = TMENU
1 {
noBlur = 1
expAll = 1
NO = 1
NO {
wrapItemAndSub = <li>|</li>
ATagParams = data-id="{field:uid}"
allStdWrap.insertData = 1
}
CUR < lib.nav.1.NO
CUR {
wrapItemAndSub = <li class="active">|</li>
}
ACT < lib.nav.1.NO
ACT {
wrapItemAndSub = <li class="active">|</li>
}
IFSUB < lib.nav.1.NO
IFSUB {
wrapItemAndSub = <li class="hasChildren">|</li>
# doNotLinkIt = 1
}
CURIFSUB = 1
CURIFSUB {
wrapItemAndSub = <li class="hasChildren active">|</li>
}
ACTIFSUB = 1
ACTIFSUB {
wrapItemAndSub = <li class="hasChildren active">|</li>
}
SPC = 1
SPC {
doNotLinkIt = 1
doNotShowLink = 1
allWrap = <li class="spacer">|</li>
}
}
2 < lib.nav.1
2 {
wrap = <ul class="navSub">|</ul>
}
}
The solution to fallback to another language than the default one is using config.sys_language_mode = content_fallback. As you can read in the Docs, with this mode you can specify some language UIDs to which language you want to fallback: https://docs.typo3.org/typo3cms/TyposcriptReference/Setup/Config/Index.html#sys-language-mode
However, the content on the page can still fall back to another
language, defined by the value of this keyword, e.g.
content_fallback;1,3,0, to fall back to the content of
sys_language_uid 1, after that to the content of sys_language_uid 3
and if that is not present either, to default (0).
In your case you still have to find a way, how to hide the spanish pages from the menue but having a fallback to english. Maybe there is something in the page language overlay configuration?
In the worst case you have get the page titles in the TMENU object "manually" by requesting the DB.
EDIT: And how about just naming the spanish pages titles with english titles by hand?

TypoScript Menu with manual columns

I have a typical grid-based dropdown menu with predefined columns, as you find them in foundation, bootstrap etc.
Now I'd like to manually let the editor control which items go in which column – without having to hardwire too many pids or creating additional pagetree nodes (Pages like "Group for column 1") in the BE.
How do I do that with TypoScript?
The page type "Spacer" or "Separator" (doktype 199) is perfect for this:
It can be rendered as html content, using the SPC state. Editors can place it in their pagetree where they want to split up columns.
lib.main_nav_1 = HMENU
lib.main_nav_1 {
special = directory
special.value = {$pidEntryPoint}
wrap = <div class="columns small-12 medium-3"><ul>|</ul></div>
1 = TMENU
1 {
expAll = 1
NO {
text = nav_title // title
wrapItemAndSub=<li>|</li>
}
ACT < .NO
ACT {
wrapItemAndSub = <li class="active">|</li>
}
ACT = 1
CUR < .NO
CUR {
wrapItemAndSub = <li class="current">|</li>
}
CUR = 1
SPC = 1
SPC {
doNotLinkIt = 1
doNotShowLink = 1
allWrap = </ul></div><div class="columns small-12 medium-3">|<ul>
}
}
2 < .1
2 {
wrap = <ul>|</ul>
SPC = 0
}
}
}

Id counting in TYPO3 menu using register:count_MENUOBJ

I made the menu in TYPO3 for bootstrap framework. Everything working just fine, but I have problem with counting the id element using register:count_MENUOBJ. The whole menu is constructed from two parts - main menu and sub menu:
page = PAGE
page.10 = HMENU
page.10.special = directory
page.10.entryLevel = 0
page.10.maxItems = 6
page.10 {
1 = TMENU
1 {
wrap = <div class="row"><ul class="nav nav-tabs pull-right" id="myTab" role="tablist">|</ul></div>
noBlur = 1
expAll = 1
NO {
ATagTitle.field = title
wrapItemAndSub = <li class="dropdown">|</li>
stdWrap.htmlSpecialChars = 1
accessKey = 1
}
IFSUB < .NO
IFSUB = 1
IFSUB {
wrapItemAndSub = <li class="dropdown">|</li>
linkWrap= |
ATagParams = role="button" data-toggle="collapse" data-target="#item-{register:count_MENUOBJ}"
ATagParams.insertData = 1
ATagBeforeWrap = 1
stdWrap.htmlSpecialChars = 1
}
ACTIFSUB < .IFSUB
ACTIFSUB {
wrapItemAndSub = <li class="active dropdown">|</li>
}
ACT < .NO
ACT = 1
ACT {
wrapItemAndSub = <li class="active">|</li>
}
CURIFSUB < .IFSUB
CURIFSUB = 1
CURIFSUB {
wrapItemAndSub = <li class="active dropdown">|</li>
}
}
}
page.20 = HMENU
page.20.special = directory
page.20.entryLevel = 0
page.20.maxItems = 6
page.20 {
1 = TMENU
1 {
wrap = <div class="row"><div class="tab-content">|</div></div>
noBlur = 1
expAll = 1
NO.doNotShowLink = 1
}
# second level
2.maxItems = 5
2 = TMENU
2.stdWrap.wrap = <div class="tab-pane fade in active pull-right" id="item-{register:count_MENUOBJ}"><nav class="navbar navbar-default pull-right submenu" role="navigation"><ul class="nav navbar-nav in">|</ul></nav></div>
2.stdWrap.wrap.insertData = 1
2{
expAll = 1
NO{
ATagTitle.field = title
wrapItemAndSub = <li>|</li>
}
IFSUB = 1
IFSUB{
ATagTitle.field = title
wrapItemAndSub = <li>|</li>
}
}
}
In the first menu block links has the correct value: data-target="#item-1", data-target="#item-2" etc..
In the second block the all links are generated in this form: id="item-5" staring and ending on item-5
Any suggestions?
register:count_MENUOBJ is counting the menu-items in the context where it's used.
In the first menu it's used in the context of the main-items and therefore counting in the natural order of the menu-items like an index. This might be the reason that the function of register:count_MENUOBJ is still confusing, even usable in that context.
In the second menu register:count_MENUOBJ is used in the context of the sub-menu items and counting the sub-items on level 2. So if on level two are 3 sub-items the register is 3. If 5 sub-items it's 5. In this context register:count_MENUOBJ is not usable as index as the amount of sub-items never reflects the expected value according to the question.
Therefore to get unique id's it's common practice to use p{field:uid} for pages or for content-elements c{field:uid}.
Example:
...
NO.wrapItemAndSub = <li id="nav-main-p{field:uid}">|</li>
NO.wrapItemAndSub.insertData = 1
...
Another alternative is to use register:count_MENUOBJ in the second menu also on the first level. Question if the menu in the question would have the required properties then.
Use the MenuProcessor instead of HMENU. I always had problems with the custom rendering of HMENU and than i turned to MenuProcessor because the html markup may be created directly in fluid.
Typoscript:
page = PAGE
page.10 = FLUIDTEMPLATE
page.10 {
...
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor
10 {
as = navigationMain
}
}
}
FLUID:
<f:for each="{navigationMain}" as="menuItem">
<!-- There you have access to menu items -->
</f:for>
Documentation: https://docs.typo3.org/typo3cms/SitePackageTutorial/MainMenuCreation/Index.html
In general #David already gave all relevant information.
For clarification and as hint for an easier implementation:
In your example you used the count register in page.20.2.stdWrap.wrap. this Wrap is executed in context of second level menu, but after the menu is allready generated, so it contains the number of elements in this menu level.
You need to use the count register in first level, and so it is a wrap to the second level you can use it in .1.IFSUB.wrapItemAndSub, as you have no content in first level it will be a wrap only for the second level menu.
And also mentioned from #David:
You also could use the uids from the pages itself.
Use it in page.10, and in page.20.2 you could use the field pid from any page on that level.
As you want to use it out of the context of a menuItem you might get the problem: there is no real field pid. Either you do the wrap on the first page/ menuItem (hint: optionsplit) or do it in the first level again.
(I doubt that for .1.stdWrap you are in the context of the first level page, so you could use field uid.)
you probably have to insert the following (not tested):
page.15 = RESTORE_REGISTER
just before page.20 = HMENU ... normally used in combination with LOAD_REGISTER but it looks as if your second HMENU has the count_MENUOBJ stuck at the last value of the first ...

HMENU only pages with a specific value in custom field

I have a custom field (lets say its named myfield) in the table pages with the values 0, 1 or 2. I now want to create a HMENU for all pages that have a specific value (for example all pages with myfield=1) in this field.
How could I get this?
As far as I know I can not add a where-clause to the HMENU. So will I need a USER_INT for it?
Will it work somehow like this:
includeLibs.something = mypath/user_myclass.php
lib.servicenav = HMENU
lib.servicenav {
special = list
special.value = USER
special.value.userFunc = user_myclass->myFunction
special.value.myfieldvalue = 1 # 0, 1, or 3
}
user_myclass.php->myFunction:
function myFunction($a, $myfieldvalue) {
// - search all pages with $myfieldvalue
// - add all pids of this page to the returnvalue (as string)
$returnvalue = "5, 19, 200";
return $returnvalue;
}
Will this solution work? Are there better solutions?
Edit: cascavals solution:
It works in a small testproject with this:
lib.menu = HMENU
lib.menu{
special = list
special.value.cObject = CONTENT
special.value.cObject {
table = pages
select {
where = myfield=0
}
renderObj = TEXT
renderObj {
field = uid
wrap = |,
}
}
entrylevel = 1
1 = TMENU
1.NO = 1
1.NO.linkWrap =
<div class="menu">|</div>
überschreibt
2 < .1
2.NO.linkWrap =
<div class="menu-ebene2">|</div>
But it does not work in a bigger project with this (I get no output):
Also when I copy the Menu from above it does not work in this project..
lib.navigation = HMENU
lib.navigation {
special = list
special.value.cObject = CONTENT
special.value.cObject {
table = pages
select {
where = myfield=0
}
renderObj = TEXT
renderObj {
field = uid
wrap = |,
}
}
1 = TMENU
1 {
noBlur = 1
expAll = 0
wrap = <ul class="nav1">|</ul>
NO = 1
NO {
wrapItemAndSub = <li class="first">|</li> |*| <li>|</li> |*| <li class="last">|</li>
altText = subtitle // title
title = subtitle // title
}
CUR < .NO
CUR.ATagParams = class="active"
CUR.wrapItemAndSub = <li class="current first">|</li> |*| <li class="current">|</li> |*| <li class="current last">|</li>
ACT < .CUR
ACT = 1
ACT.ATagParams = class="active"
}
2 = TMENU
2 < .1
2 {
expAll = 0
wrap = <ul class="nav2">|</ul>
}
}
As special.value has stdWrap, you can still select page UIDs dynamically and create a comma-separated list that is expected:
lib.servicenav = HMENU
lib.servicenav {
special = list
special.value.cObject = CONTENT
special.value.cObject {
table = pages
select {
pidInList = [UID of the root page of your website]
recursive = 99
where = myfield=1
}
renderObj = TEXT
renderObj {
field = uid
wrap = |,
}
}
}

Load register inside TMENU

In a TYPO3 HMENU, the second level TMENU should reproduce the abstract of the first level page.
I do manage to fill the register with a value and use it in the second level TMENU - but I am unable to load the field's content into the register.
So
field = abstract
as well as
value = {field:abstract}
value.insertData = 1
don't produce any output.
How can that register be filled with the parent page's abstract?
Here's the full code.
temp.main_nav = HMENU
temp.main_nav {
wrap = <nav id="cbp-hrmenu" class="clearfix cbp-hrmenu span12">|</nav>
entryLevel = 0
1 = TMENU
1 {
noBlur = 1
expAll = 1
wrap = <ul class="level1">|</ul>
NO {
wrapItemAndSub=<li>|</li>
before.cObject=LOAD_REGISTER
before.cObject{
parentAbstract.stdWrap.cObject=TEXT
parentAbstract.stdWrap.cObject{
field = abstract
#value = {field:abstract}
#value.insertData = 1
}
}
}
}
2 < .1
2.stdWrap.dataWrap = <div class="cbp-hrsub"><div class="cbp-hrsub-inner"><div>{register:parentAbstract}</div><div><ul class="level2">|</ul></div></div><!-- /cbp-hrsub-inner --></div><!-- /cbp-hrsub -->
}
PS: {levelfield} seems to be problematic inside a TMENU, that's why I switched to LOAD_REGISTER
Solved it.
The problem was in
2 < .1
The second TMENU inherited the load_register from the first one and kept filling it. That's why there was a wrong abstract (e.g. an empty one) in it.
Here's the working code:
temp.main_nav = HMENU
temp.main_nav {
wrap = <nav id="cbp-hrmenu" class="clearfix cbp-hrmenu span12">|</nav>
entryLevel = 0
1 = TMENU
1 {
noBlur = 1
expAll = 1
wrap = <ul class="level1">|</ul>
NO {
wrapItemAndSub=<li>|</li>
before.cObject=LOAD_REGISTER
before.cObject{
parentAbstract.cObject=TEXT
parentAbstract.cObject{
field = abstract
}
}
}
// EDIT: if you have additional states, don't forget to add the abstract too
ACT < .NO
ACT = 1
ACT {
wrapItemAndSub=<li class="dropdown active">|</li>
}
}
2 = TMENU
2 {
noBlur = 1
expAll = 1
stdWrap.dataWrap = <div class="cbp-hrsub"><div class="cbp-hrsub-inner"><div>{register:parentAbstract}</div><div><ul class="level2">|</ul></div></div><!-- /cbp-hrsub-inner --></div><!-- /cbp-hrsub -->
NO {
wrapItemAndSub=<li>|</li>
}
}
}