0
votes

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:

enter image description here

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 …

  1. special = rootline does not support special.value.
  2. 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.

3

3 Answers

1
votes

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.


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
1
votes

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
0
votes

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