Giter VIP home page Giter VIP logo

menus's Introduction

CI

Menus - A TYPO3 Extension for creating fast menus - in a fast way

Introduction

TYPO3 CMS is known for handling large websites with lots of content. TYPO3 Core provides several ways to build navigation / menus in a very flexible way. However, generating menus has been a tedious issue in most of our large-scale projects. With TYPO3 v9, the performance of generating menus improved when it comes to URL generation, but a few conceptual issues within linking and menu generation still exist:

  1. All logic relies on HMENU

    Every menu is generated using HMENU, even the MenuDataProcessor for Fluid is using this. Yes, it's powerful, but also offers a lot of options we do not need in most circumstances.

  2. HMENU saves states for each page

    HMENU offers the possibility to define A LOT of states ("active", "current", "has children"). This information is different for each page - obviously - which is then cached in a separate cache entry in cache_hash - making the cache entries fairly large even though we do not use states.

    We use expAll (expand all subpages for all other pages as well) which makes the requests to the pages enormously large.

  3. HMENU has a cryptic syntax for "special" menus

    Nowadays, it is fairly common to build menus for footer navigation, mega-menus, sitemap-like menus for an additional sidebar. Using "special." for language menus, for "directories" or just a simple list of pages, seems rather complex.

This extension tries to overcome these pitfalls by

  • building menus once, then caches the results and afterwards applying active states (reduce amount of cached data). This is especially important for Tree-based menus,
  • introducing new cObjects and DataProcessors for the specific use cases making them more understandable for non-TYPO3-Gurus.

Installation & Requirements

Use composer req b13/menus or install it via TYPO3's Extension Manager from the TYPO3 Extension Repository using the extension key menus.

You need TYPO3 v9 with Site Handling for this extension to work. If your project supports mount points, this is not implemented. In addition, pages to access restricted pages (even though no access exists) are not yet considered.

Features

The extension ships TypoScript cObjects and TypoScript DataProcessors for Fluid-based page templates.

Common Options for all menus

  • excludePages - a list of page IDs (and their subpages if Tree Menu or Breadcrumbs is used) to exclude from the page
  • excludeDoktypes - a list of doktypes that are not rendered. BE_USER_SECTIONs are excluded by default. SYS_FOLDERs are queried (for subpages etc) but never rendered.
  • includeNotInMenu - include pages with nav_hide set to 1, instead of ignoring them

Common options for items

In TypoScript this is available as field:isSpacer, in Fluid, this is accessible in {page.isSpacer}

- {page.isCurrentPage} (bool)
- {page.isInRootLine} (bool)
- {page.isSpacer} (bool)
- {page.hasSubpages} (bool) - TreeMenu only
- {page.subpages} (array) - TreeMenu only

Tree Menu

Use this for mega menus, or separate menus for mobile devices, like sitemaps.

Pure TypoScript-based solution:

page.10 = TREEMENU
# a list of page IDs, rootpageID is used if none given
page.10.entryPoints = 23,13
# the number of levels to fetch from the database (1 if empty)
page.10.depth = 3
page.10.excludePages = 4,51
# 0: default, 1 to include nav_hide = 1 pages
page.10.includeNotInMenu = 0
page.10.renderObj.level0 = TEXT
page.10.renderObj.level0.typolink.parameter.data = field:uid
page.10.renderObj.level0.typolink.ATagParams = class="active"
page.10.renderObj.level0.typolink.ATagParams.if.isTrue.field = isInRootLine
page.10.renderObj.level0.dataWrap = <li class="firstLevel">|<ul>{field:subpageContent}</ul></li>

Fluid-based solution:

page.10 = FLUIDTEMPLATE
page.10.dataProcessing.10 = B13\Menus\DataProcessing\TreeMenu
page.10.dataProcessing.10.entryPoints = 23,13
page.10.dataProcessing.10.depth = 3
page.10.dataProcessing.10.excludePages = 4,51
# 0: default, 1 to include nav_hide = 1 pages
page.10.dataProcessing.10.includeNotInMenu = 0
page.10.dataProcessing.10.as = mobilemenu

Usage in Fluid:

<nav>
    <f:for each="{mobilemenu}" as="page">
        <f:link.page pageUid="{page.uid}">{page.nav_title}</f:link.page>
        <f:if condition="{page.hasSubpages} && {page.isInRootLine}">
            <ul>
                <f:for each="{page.subpages}" as="subpage">
                    <li><f:link.page pageUid="{subpage.uid}">{subpage.nav_title}</f:link.page>
                </f:for>
            </ul>
        </f:if>
    </f:for>
</nav>

Note: nav_title is title if Database-Record nav_title is empty.

Language Menu

Building a language switcher can be achieved by a few lines of code:

Pure TypoScript solution:

page.10 = LANGUAGEMENU
page.10.excludeLanguages = de,en
# 0: default, 1 to include nav_hide = 1 pages
page.10.includeNotInMenu = 0
# add all siteLanguages to menu even if page is not available in language (default 0)
page.10.addAllSiteLanguages = 1
page.10.wrap = <ul> | </ul>
page.10.renderObj.typolink.parameter.data = field:uid
page.10.renderObj.typolink.additionalParams.data = field:language|languageId
page.10.renderObj.typolink.additionalParams.intval = 1
page.10.renderObj.typolink.additionalParams.wrap = &L=|
page.10.renderObj.data = field:language|title // field:language|twoLetterIsoCode
page.10.renderObj.wrap = <li class="language-item"> | </li>

The stdWrap data is the information of the current page plus the information merged from the selected SiteLanguage.

Fluid-based solution:

page.10 = FLUIDTEMPLATE
page.10.dataProcessing.10 = B13\Menus\DataProcessing\LanguageMenu
page.10.dataProcessing.10.excludeLanguages = de,en
# 0: default, 1 to include nav_hide = 1 pages
page.10.dataProcessing.10.includeNotInMenu = 0
# add all siteLanguages to menu even if page is not available in language (default 0)
page.10.dataProcessing.10.addAllSiteLanguages = 1
page.10.dataProcessing.10.as = languageswitcher

Usage in Fluid:

<nav>
    <f:for each="{languageswitcher}" as="item">
        <f:link.page pageUid="{item.uid}" language="{item.language.languageId}">{item.language.title}</f:link.page>
    </f:for>
</nav>

Note: the languageMenu hold the siteLanguage on each item in the language property as an array

List Menu

If you just want a list of all items within a folder, or for a link list in the footer, use the List Menu.

Pure TypoScript-based solution:

page.10 = LISTMENU
# a page ID, rootpageID is used if none given, stdWrap possible
page.10.pages = 13,14,15
# 0: default, 1 to include nav_hide = 1 pages
page.10.includeNotInMenu = 0
page.10.wrap = <ul> | </ul>
page.10.renderObj = TEXT
page.10.renderObj.typolink.parameter.data = field:uid
page.10.renderObj.wrap = <li> | </li>

Fluid-based solution:

page.10 = FLUIDTEMPLATE
page.10.dataProcessing.10 = B13\Menus\DataProcessing\ListMenu
page.10.dataProcessing.10.pages = 13,14,15
page.10.dataProcessing.10.as = footerlinks
# 0: default, 1 to include nav_hide = 1 pages
page.10.dataProcessing.10.includeNotInMenu = 0

Usage in Fluid:

<nav>
    <f:for each="{footerlinks}" as="page">
        <f:link.page pageUid="{page.uid}">{page.nav_title}</f:link.page>
    </f:for>
</nav>

Breadcrumb Menu (a.k.a. Rootline Menu)

page.10 = BREADCRUMBS
page.10.excludePages = 4,51
# 0: default, 1 to include nav_hide = 1 pages
page.10.includeNotInMenu = 0
page.10.wrap = <ul> | </ul>
page.10.renderObj = TEXT
page.10.renderObj.typolink.parameter.data = field:uid
page.10.renderObj.wrap = <li> | </li>

Fluid-based solution:

page.10 = FLUIDTEMPLATE
page.10.dataProcessing.10 = B13\Menus\DataProcessing\BreadcrumbsMenu
page.10.dataProcessing.10.excludePages = 4,51
# 0: default, 1 to include nav_hide = 1 pages
page.10.dataProcessing.10.includeNotInMenu = 0
page.10.dataProcessing.10.as = breadcrumbs

Usage in Fluid:

<nav>
    <f:for each="{breadcrumbs}" as="page">
        <f:link.page pageUid="{page.uid}">{page.nav_title}</f:link.page>
        <f:if condition="{page.isCurrentPage} == false"> &nbsp; </f:if>
    </f:for>
</nav>

Dynamic configuration values for the menu (stdWrap)

If you want to get a menu of the direct siblings of a page, no matter what page you have selected, you can use the stdWrap functions built into each property:

9999 = B13\Menus\DataProcessing\TreeMenu
9999 {
	entryPoints.data = page:pid
	as = listOfJobPages
}

By using the .data property of the entryPoints attribute we can access each property of the currently build page. And so we can render the siblings of the page.

Technical Details

Caching

Fetching the records is cached in a cache entry (with proper cache tags) within "cache_hash", and the rendering is also cached in a separated cache entry within "cache_pages" for each page (regular), where active state is applied.

FAQ

This extension refrains from handling options addQueryParams, or ADD_GET_PARAM, or the target property in order to deal with the pages as "native" as possible, like any other link.

License

The extension is licensed under GPL v2+, same as the TYPO3 Core. For details see the LICENSE file in this repository.

Open Issues

If you find an issue, feel free to create an issue on GitHub or a pull request.

ToDos

  • add includeSpacer option
  • extract stdWrap functionality out of caching parameters

Credits

This extension was created by Benni Mack in 2019 for b13 GmbH.

Find more TYPO3 extensions we have developed that help us deliver value in client projects. As part of the way we work, we focus on testing and best practices to ensure long-term performance, reliability, and results in all our code.

menus's People

Contributors

achimfritz avatar b13-michaelsemle avatar bmack avatar chesio avatar davidsteeb avatar georgringer avatar infabo avatar jdreesen avatar josefglatz avatar jschlier avatar julianhofmann avatar kaystrobach avatar linawolf avatar lochmueller avatar magichatoftypo3 avatar rtpast avatar sbuerk avatar simonschaufi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

menus's Issues

Pre-resolve menu item urls

Currently menu items does not contain the their url.

When i use the f:link.page or f:link.typolink ViewHelper a lot of code is executed to resolve an url for a menu item by {item.uid} which also means extra SQL queries for every menu item. So my idea is to resolve the urls before they go to cache.

What do you think?

With that one can simple write <a href={item.url}>{item.nav_title}</a>

State "isCurrentPage" & "isInRootline" missing in 3rd depth level and below

Having a menu with depth=7 I have the problem that isCurrentPage and isInRootline are not given for pages with depth level 3 and below (so 4th, 5th, ...).

Here is a screenshot of the debug list.
As you can see the first and second level do have both attributes but the third does not:

grafik

The TypoScript setup is the following:

 50 = B13\Menus\DataProcessing\TreeMenu
  50 {
    entryPoints = {$plugin.tx_extensionname.settings.mainMenuPid}
    depth = 6
    excludePages = {$plugin.tx_extensionname.settings.pageToExcludePid}
    as = mainnavigation
  }

Is this a bug or is there something that I could have made wrong?

System:
TYPO3 9.5.21
EXT:b13/menus v0.2.0

[BUG] B13\Menus\Domain\Repository\MenuRepository->getBreadcrumbsMenu() won't respect excludedDoktypes

I'm using B13\Menus\DataProcessing\BreadcrumbsMenu which uses B13\Menus\Domain\Repository\MenuRepository->getBreadcrumbsMenu() internally. But MenuRepository->getBreadcrumbsMenu() won't respect MenuRepository::$excludedDoktypes (I know it's not a static variable 😉) and won't remove the "Hauptmenü" folder from the rootLine.

Steps to reproduce

Have a folder inside the rootLine like this:
image

$GLOBALS['TSFE']->rootLine:

array (size=3)
  2 =>
    array (size=26)
      'pid' => int 118
      'uid' => int 7
      'title' => string 'News' (length=4)
      'nav_title' => string '' (length=0)
      'doktype' => int 1
  1 =>
    array (size=26)
      'pid' => int 1
      'uid' => int 118
      'title' => string 'Hauptmenü' (length=10)
      'nav_title' => string '' (length=0)
      'doktype' => int 254
  0 =>
    array (size=26)
      'pid' => int 0
      'uid' => int 1
      'title' => string 'root-page' (length=9)
      'nav_title' => string 'Startseite' (length=10)
      'doktype' => int 1

Actual result:

MenuRepository->getBreadcrumbsMenu():

array (size=3)
  0 => array
      'uid' => int 1
      'pid' => int 0
      'title' => string 'root-page' (length=9)
      'doktype' => int 1
      'nav_title' => string 'Startseite' (length=10)
      'hasSubpages' => boolean false
  2 => array
      'nav_title' => string 'Hauptmenü' (length=10)
      'hasSubpages' => boolean false
  1 => array
      'uid' => int 7
      'pid' => int 118
      'title' => string 'News' (length=4)
      'doktype' => int 1
      'nav_title' => string 'News' (length=4)
      'hasSubpages' => boolean false

Expected result:

MenuRepository->getBreadcrumbsMenu():

array (size=2)
  0 => array
      'uid' => int 1
      'pid' => int 0
      'title' => string 'root-page' (length=9)
      'doktype' => int 1
      'nav_title' => string 'Startseite' (length=10)
      'hasSubpages' => boolean false
  1 => array
      'uid' => int 7
      'pid' => int 118
      'title' => string 'News' (length=4)
      'doktype' => int 1
      'nav_title' => string 'News' (length=4)
      'hasSubpages' => boolean false

P.S. I think MenuRepository->getBreadcrumbsMenu() shouldn't add the hasSubpages value, because it will always be false.

ListMenu Processor results in error when one of the given pages is deleted.

we are using the B13\Menus\DataProcessing\ListMenu DataProcessor and populate it with data an editor may change:

10 = B13\Menus\DataProcessing\ListMenu
10 {
        if.isTrue.field = some_pages
        pages.field = some_pages
        as = someMenu
        titleField = nav_title // title
}

If the editor adds some pages to the field some_pages and then afterwards deletes one of them, the MenuProcessor results in an error in the frontend.

I will try to provide a patch for this issue later.

LanguageMenu does not create links for plugins

Problem
The TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor creates links on pages with plugins (means: which have query parameters).
The B13\Menus\DataProcessing\LanguageMenu does not create links for these pages.

Or am I missing something?

Cache invalidation works not as expected

Caching of Menus do not work as expected, e.g. edit Page-Title in BE do not show changed Page-Title in FE in Menus

That's because the page cache itself cache the (rendered) menu also, and is not flushed.

Unit tests are broken

Unit tests are broken, and throwing 1 error and 2 failures:

Creating network "local_default" with the default driver
PHP 7.2.34-18+ubuntu18.04.1+deb.sury.org+1 (cli) (built: Feb 23 2021 15:08:03) ( NTS )
PHPUnit 8.5.17 by Sebastian Bergmann and contributors.

.FFE..                                                              6 / 6 (100%)

Time: 89 ms, Memory: 28.01 MB

There was 1 error:

1) B13\Menus\Tests\Unit\Domain\Repository\MenuRepositoryTest::getBreadcrumbsMenuRespectConfiguredExcludeDoktypes
Undefined index: nav_hide

/var/www/work/typo3-play/packages/menus/Classes/Domain/Repository/MenuRepository.php:165
/var/www/work/typo3-play/packages/menus/Classes/Domain/Repository/MenuRepository.php:59
/var/www/work/typo3-play/packages/menus/Tests/Unit/Domain/Repository/MenuRepositoryTest.php:90
/var/www/work/typo3-play/packages/menus/.Build/vendor/phpunit/phpunit/phpunit:76

--

There were 2 failures:

1) B13\Menus\Tests\Unit\Domain\Repository\MenuRepositoryTest::getSubPagesOfPageRestrictQueryToExcludeDoktypes
Some predictions failed:
Double\TYPO3\CMS\Core\Domain\Repository\PageRepository\P6:
  No calls have been made that match:
      Double\TYPO3\CMS\Core\Domain\Repository\PageRepository\P6->getMenu(exact(1), exact("*"), exact("sorting"), exact("AND doktype NOT IN (6,255,254) AND nav_hide=0 "), exact(false))
    but expected at least one.
    Recorded `getMenu(...)` calls:
      - getMenu(1, "*", "sorting", "AND doktype NOT IN (6,255,254) ", false) @ /var/www/work/typo3-play/packages/menus/Classes/Domain/Repository/MenuRepository.php:146

/var/www/work/typo3-play/packages/menus/.Build/vendor/phpunit/phpunit/phpunit:76

2) B13\Menus\Tests\Unit\Domain\Repository\MenuRepositoryTest::getSubPagesOfPageMergeExcludeDoktypesFromConfiguration
Some predictions failed:
Double\TYPO3\CMS\Core\Domain\Repository\PageRepository\P6:
  No calls have been made that match:
      Double\TYPO3\CMS\Core\Domain\Repository\PageRepository\P6->getMenu(exact(1), exact("*"), exact("sorting"), exact("AND doktype NOT IN (6,255,254,99) AND nav_hide=0 "), exact(false))
    but expected at least one.
    Recorded `getMenu(...)` calls:
      - getMenu(1, "*", "sorting", "AND doktype NOT IN (6,255,254,99) ", false) @ /var/www/work/typo3-play/packages/menus/Classes/Domain/Repository/MenuRepository.php:146

/var/www/work/typo3-play/packages/menus/.Build/vendor/phpunit/phpunit/phpunit:76

ERRORS!
Tests: 6, Assertions: 29, Errors: 1, Failures: 2.
Removing local_unit_run_a24fb92c288c ... done
Removing network local_default

The error could be solved by providing nav_hide values in the rootline data. But what be should be thinked about is, to fix this really.

The two failiures are, that the assumed query is not that one which is really build in the menuRepository.

PullRequests to get unit tests green will come.

Possibility of "entryLevel" for a subMenu?

Hi there,

I like to switch our menus to use your extension. We have a mainMenu and a subMenu with entryLevel = 1.
Is there a way with the menus extension to achieve "entryLevel = 1" (like HMENU)?
https://docs.typo3.org/m/typo3/reference-typoscript/master/en-us/ContentObjects/Hmenu/#hmenu-entrylevel

I guess it would work to set the "entryPoints" to the current active page from mainMenu. But I can not think of a solution to get this value in typoscript...

lib.menuMain = FLUIDTEMPLATE
lib.menuMain {
  dataProcessing {
    10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor
    10 {
      levels = 2
      as = menuMain
    }
  }
}

lib.menuSub = FLUIDTEMPLATE
lib.menuSub {
  dataProcessing {
    10 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor
    10 {
      levels = 3
      entryLevel = 1
      as = menuSub
    }
  }
}

excludeDoktypes cannot overwrite some default values

In the function getExcludeDoktypes(array $configuration) in the class MenuRepository.php the following doctypes are always suppressed and I have no possibility to activate e.g. the BE User Section via excludeDoktypes.

https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/ContentObjects/Hmenu/Index.html#excludedoktypes

    protected $excludedDoktypes = [
        PageRepository::DOKTYPE_BE_USER_SECTION,
        PageRepository::DOKTYPE_RECYCLER,
        PageRepository::DOKTYPE_SYSFOLDER,
    ];
protected function getExcludeDoktypes(array $configuration): array
    {
        if (!empty($configuration['excludeDoktypes'])) {
            $excludedDoktypes = array_unique(array_merge($this->excludedDoktypes, GeneralUtility::intExplode(',', (string)$configuration['excludeDoktypes'])));
        } else {
            $excludedDoktypes = $this->excludedDoktypes;
        }
        return $excludedDoktypes;
    }

Optimize clear frontend/page cache behaviour

After editing a page, the complete frontend (page?) cache is deleted, so navigation changes will be directly visible to the visitors. That's very good, that editors don't have to press "clear frontend cache" after every change manually.

Problem on large sites is, that the whole page cache is deleted. Even if you have more site configurations and the change only affects one site. Would it be possible, to restrict the cache clearing to the current site configuration?

And not all changes of the page properties are directly relevant to clear the whole page cache. Mostly (in my known projects) it's the title and slug - changes on these fields should clear the cache for a correct navigation. But many other fields are only relevant for the current page, and so it's enough, to only clear the cache of that specific site. Maybe it's possible, to configure the fields in the future, which trigger a cache-clearing for the whole site.

I think with optimizations in that area, the "clear cache"-button could be deactivated most of the time.

cacheHelper must respect preview visibility

The visibility aspect must be taken into account to prevent (A) delivering hidden pages from cache or (B) enable admPanel preview of hidden pages (showHiddenPages).

Until then, b13/menus is (at least) broken/incompatible with Admin Panel's "showHiddenPages" feature:
If visiting a site with showHiddenPages=1, either
(A) b13/menus may deliver hidden pages without backend login (if b13/menus' data not yet cached) or
(B) "showHiddenPages" isn't respected (if b13/menus' data already cached)

Possible solutions:

  • own cache entries depending on visibility aspect (may be done in AbstractMenuCompiler::generateCacheIdentifierForMenu)
  • not caching b13/menus at all if (pseudo-code) TYPO3\CMS\Core\Context\Context::getAspect('visibility')->get('includeHiddenPages') returns true.

Possibility to create anchor menus

It would be a nice addition to be able to create anchor menus as well. Like having one level and then the second level is build by the content element anchors on the first level pages.

PageStateMarker:markStatesRecursively covers only two levels

Hi all,

PageStateMarker:markStatesRecursively is only covering the first two levels and therefore is not recursive.

Please find attached a little patch which solves the issue:

@@ -20,20 +20,26 @@ class PageStateMarker
         $page['level'] = $level;
         if (!empty($page['subpages'])) {
             foreach ($page['subpages'] as &$subPage) {
-                self::markStates($subPage, $level+1);
+                $subPage = self::markStates($subPage, $level+1);
             }
         }
         $page['isInRootLine'] = self::isPageInCurrentRootLine((int)$page['uid']);
         $page['isCurrentPage'] = self::isCurrentPage((int)$page['uid']);
     }
 
-    public static function markStates(array &$page, int $level = null): void
+    public static function markStates(array $page, int $level = null): array
     {
         if ($level !== null) {
             $page['level'] = $level;
         }
+        if (!empty($page['subpages'])) {
+            foreach ($page['subpages'] as &$subPage) {
+                $subPage = self::markStates($subPage, $level+1);
+            }
+        }
         $page['isInRootLine'] = self::isPageInCurrentRootLine((int)$page['uid']);
         $page['isCurrentPage'] = self::isCurrentPage((int)$page['uid']);
+        return $page;
     }

best regards and many thanks for this very helpful extension!
Arne

Clear Cache when pages are being updated

We're using menus to render a tree menu from standard and custom pagetypes. Everything works fine, besides cache invalidation.

Entries in cache_pages and cache_hash are correctly created, however invalidation seems to be not working properly. To the issue seems to be in conjunction with cache_pages and cache_pagesection.

Example: I have three levels:

  • Home
    -- Page 2
    --- Page 3A
    --- Page 3B

I warm up the cache for all pages. Then I disable Page 3A through the backend. Now when I open page 3B, page 3A still appears in the menu - but without the link being rendered. The same happens on page 2.

So it seems that when cache_pages / cache_pagesection entries are invalidated by TYPO3, the link disappears in some cases.

The expected behavior is that entry and link are always consistent.

TYPO3 9.5.16

clearCache_pageGrandParent = 0
clearCache_pageSiblingChildren = 0

usergroup of current frontend user is not being respected

I've noticed that the call here https://github.com/b13/menus/blob/master/Classes/Domain/Repository/MenuRepository.php#L156-L162 to get the generated menu as array is not generating a proper SQL expression for the current logged-in frontend user.

I'd have to implement this:

$usergroup = $GLOBALS['TSFE']->fe_user->user['usergroup'];

$this->pageRepository->where_groupAccess = <<<SQL
    AND ((`pages`.`fe_group` IN ({$usergroup}))
    OR (`pages`.`fe_group` = '')
    OR (`pages`.`fe_group` IS NULL)
    OR (`pages`.`fe_group` = '0'))
SQL;

since the current $this->pageRepository->where_groupAccess returns me the same SQL expression just as my custom one with the only difference that AND ((pages.fe_group IN ({$usergroup})) is NOT presence.

I'm not aware about TYPO3's core where it's actually defining the where_groupAccess to the $GLOBALS (or using UserAspect or whatsoever) but in my (rare, I assume) use-case I'd need such implementation since my frontend login is underlying an AJAX call via middleware. OTOH the MenuRepository is being called post the whole middleware stack has been iterated through.

In the current state I'd need to fork the whole extension and adjust this or perform a composer-patch but I guess it's either fundamentally missing something in the core or my own configuration is wrong...

Would appreciate any information about this! :)

option to omit current language from languageMenu

A setup for a two-language site does not need to configure excludeLanguages with TS conditions per language or check for isActiveLanguage in a Fluid-loop, if this option is avaliable.

Either excludeCurrentLanguage = 1 or excludeLanguages = _current,foo,bar

no language menu is generated

I am following the documentation for language menus in TYPO3 11.5.26 with adaption to my marker based site template. However the language menu remains empty. Config.yaml is filled in as required by TYPO3.

<div class="languagemenu"><ul></ul></div>

temp.language = LANGUAGEMENU

temp.language.includeNotInMenu = 1
# add all siteLanguages to menu even if page is not available in language (default 0)
temp.language.addAllSiteLanguages = 1
temp.language.wrap = <ul> | </ul>
temp.language.renderObj.typolink.parameter.data = field:uid
temp.language.renderObj.typolink.additionalParams.data = field:language|languageId
temp.language.renderObj.typolink.additionalParams.intval = 1
temp.language.renderObj.typolink.additionalParams.wrap = &L=|
temp.language.renderObj.data = field:language|title // field:language|twoLetterIsoCode
temp.language.renderObj.wrap = <li class="language-item"> | </li>
temp.language.dataProcessing {
  40 = TYPO3\CMS\Frontend\DataProcessing\LanguageMenuProcessor
  40 {
    languages = <insert language-id> or "auto"
    as = languagenavigation
  }
}

page.10.marks {
  	LANGMENU < temp.language
}

Undefined index nav_title executing tests

Cloning the master branch and executing the tests shows an error:

There was 1 error:

1) B13\Menus\Tests\Unit\Domain\Repository\MenuRepositoryTest::getBreadcrumbsMenuRespectConfiguredExcludeDoktypes
Undefined index: nav_title

/var/www/work/typo3extensions/blub/menus/Classes/Domain/Repository/MenuRepository.php:151
/var/www/work/typo3extensions/blub/menus/Classes/Domain/Repository/MenuRepository.php:60
/var/www/work/typo3extensions/blub/menus/Tests/Unit/Domain/Repository/MenuRepositoryTest.php:91
/var/www/work/typo3extensions/blub/menus/.Build/vendor/phpunit/phpunit/phpunit:61

Make Package available

Can it be that the package b13/menus is not yet available, neither on packagist nor in TER?

composer req b13/menus

[InvalidArgumentException]                                                                                                                                      
 Could not find a matching version of package b13/menus. Check the package spelling, your version constraint and that the package is available in a stability which matches your minimum-stability (stable).  

Adding stability constraint @dev does not help.

Migration path for "menuItem.link"

menuItem.link -> is dropped, use Page-Link-VH with menuItem.uid

This description may need further description.
page doktype=4 can't be handled 1:1 with f:link.page. same for doktype=3. Should at least be mentioned in the documention.

Bug: LanguageMenu excludes "nav_hide" pages

LanguageMenu should not exclude "nav_hide" pages as this is against the use-case. It makes so sense to adhere this page-attribute in a language-menu context.

see

$page = $this->menuRepository->getPageInLanguage($targetPage, $context);

and escpecially

if ((int)$page['nav_hide'] === 1 || !$pageRepository->isPageSuitableForLanguage($page, $context->getAspect('language'))) {

cache mismatch for list and language menus

both store their results with the cache identifier

$cacheIdentifier = $this->generateCacheIdentifierForMenu('list', $configuration);

for the LanguageMenuCompiler class the first parameter should be 'language' I guess?

Sorry I can't provide a PR right now, would be rather easy.

Bug: TreeMenu and translated hidden pages

When you translate a page and hide the translation, you still get the default-page-variant in the output.

Scenario with DE and EN site language and 2 pages:

  • Seite A
  • Seite B

Translate pages:

  • Seite A -> Page A
  • Seite B -> Page B

Now:

  • disable/hide Page B

Expected treemenu when visiting EN website:

  • Page A

Actual result:

  • Page A
  • Seite B

ERROR: first submenu point gives an error

If the first submenu item is called, the following error message is displayed:

Tue, 23 Aug 2022 13:00:40 +0000 [CRITICAL] request="2349ed0797b81" component="TYPO3.CMS.Core.Error.DebugExceptionHandler": Core: Exception handler (WEB: FE): TYPO3\CMS\Core\Error\Exception, code #1476107295, file /var/www/html/public/typo3/sysext/core/Classes/Error/ErrorHandler.php, line 137: PHP Warning: Undefined array key "prev" in /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php line 1063- Exception: PHP Warning: Undefined array key "prev" in /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php line 1063, in file /var/www/html/public/typo3/sysext/core/Classes/Error/ErrorHandler.php:137 - {"mode":"WEB","application_mode":"FE","exception_class":"TYPO3\CMS\Core\Error\Exception","exception_code":1476107295,"file":"/var/www/html/public/typo3/sysext/core/Classes/Error/ErrorHandler.php","line":137,"message":"PHP Warning: Undefined array key "prev" in /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php line 1063","request_url":"https://tus-fresh.ddev.site/sparten/basketball.html","exception":"TYPO3\\CMS\\Core\\Error\\Exception: PHP Warning: Undefined array key "prev" in /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php line 1063 in /var/www/html/public/typo3/sysext/core/Classes/Error/ErrorHandler.php:137\nStack trace:\n#0 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php(1063): TYPO3\CMS\Core\Error\ErrorHandler->handleError(2, 'Undefined array...', '/var/www/html/p...', 1063)\n#1 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php(544): TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject->prepareMenuItemsForBrowseMenu(515, 'sorting', ' AND pages.dokt...')\n#2 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/Menu/AbstractMenuContentObject.php(383): TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject->prepareMenuItems()\n#3 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/HierarchicalMenuContentObject.php(56): TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject->makeMenu()\n#4 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(800): TYPO3\CMS\Frontend\ContentObject\HierarchicalMenuContentObject->render(Array)\n#5 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(736): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->render(Object(TYPO3\CMS\Frontend\ContentObject\HierarchicalMenuContentObject), Array)\n#6 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(1545): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGetSingle('HMENU', Array, '/stdWrap/.cObje...')\n#7 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(1347): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->stdWrap_cObject('', Array)\n#8 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(1326): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->stdWrap('', Array)\n#9 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/HierarchicalMenuContentObject.php(65): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->stdWrap('', Array)\n#10 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(800): TYPO3\CMS\Frontend\ContentObject\HierarchicalMenuContentObject->render(Array)\n#11 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(736): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->render(Object(TYPO3\CMS\Frontend\ContentObject\HierarchicalMenuContentObject), Array)\n#12 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(698): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGetSingle('HMENU', Array, '10')\n#13 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectArrayContentObject.php(43): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGet(Array)\n#14 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(800): TYPO3\CMS\Frontend\ContentObject\ContentObjectArrayContentObject->render(Array)\n#15 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(736): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->render(Object(TYPO3\CMS\Frontend\ContentObject\ContentObjectArrayContentObject), Array)\n#16 /var/www/html/public/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php(197): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGetSingle('COA', Array, 'lib.backbutton')\n#17 /var/www/html/public/typo3/sysext/fluid/Classes/ViewHelpers/CObjectViewHelper.php(174): TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper::renderContentObject(Object(TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer), Array, 'lib.backbutton', 'backbutton')\n#18 /var/www/html/var/cache/code/fluid_template/Standard_action_index_e6f867e69e1273801bb48a5ad14b5a05b04b0e65.php(186): TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper::renderStatic(Array, Object(Closure), Object(TYPO3\CMS\Fluid\Core\Rendering\RenderingContext))\n#19 /var/www/html/vendor/typo3fluid/fluid/src/View/AbstractTemplateView.php(258): Standard_action_index_e6f867e69e1273801bb48a5ad14b5a05b04b0e65->section_186817d730a4234a5cb5db37d7099a3440fc5dea(Object(TYPO3\CMS\Fluid\Core\Rendering\RenderingContext))\n#20 /var/www/html/vendor/typo3fluid/fluid/src/ViewHelpers/RenderViewHelper.php(171): TYPO3Fluid\Fluid\View\AbstractTemplateView->renderSection('MainContent', Array, false)\n#21 /var/www/html/var/cache/code/fluid_template/layout_Default_html_f3a95b5ac0cd9e6ea25e910fd5a3c3bac0cea718.php(132): TYPO3Fluid\Fluid\ViewHelpers\RenderViewHelper::renderStatic(Array, Object(Closure), Object(TYPO3\CMS\Fluid\Core\Rendering\RenderingContext))\n#22 /var/www/html/vendor/typo3fluid/fluid/src/ViewHelpers/SpacelessViewHelper.php(61): layout_Default_html_f3a95b5ac0cd9e6ea25e910fd5a3c3bac0cea718->{closure}()\n#23 /var/www/html/var/cache/code/fluid_template/layout_Default_html_f3a95b5ac0cd9e6ea25e910fd5a3c3bac0cea718.php(267): TYPO3Fluid\Fluid\ViewHelpers\SpacelessViewHelper::renderStatic(Array, Object(Closure), Object(TYPO3\CMS\Fluid\Core\Rendering\RenderingContext))\n#24 /var/www/html/vendor/typo3fluid/fluid/src/View/AbstractTemplateView.php(200): layout_Default_html_f3a95b5ac0cd9e6ea25e910fd5a3c3bac0cea718->render(Object(TYPO3\CMS\Fluid\Core\Rendering\RenderingContext))\n#25 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/FluidTemplateContentObject.php(340): TYPO3Fluid\Fluid\View\AbstractTemplateView->render()\n#26 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/FluidTemplateContentObject.php(106): TYPO3\CMS\Frontend\ContentObject\FluidTemplateContentObject->renderFluidView()\n#27 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(800): TYPO3\CMS\Frontend\ContentObject\FluidTemplateContentObject->render(Array)\n#28 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(736): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->render(Object(TYPO3\CMS\Frontend\ContentObject\FluidTemplateContentObject), Array)\n#29 /var/www/html/public/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php(698): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGetSingle('FLUIDTEMPLATE', Array, '10')\n#30 /var/www/html/public/typo3/sysext/frontend/Classes/Http/RequestHandler.php(223): TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGet(Array)\n#31 /var/www/html/public/typo3/sysext/frontend/Classes/Http/RequestHandler.php(189): TYPO3\CMS\Frontend\Http\RequestHandler->generatePageBodyContent(Object(TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController))\n#32 /var/www/html/public/typo3/sysext/frontend/Classes/Http/RequestHandler.php(141): TYPO3\CMS\Frontend\Http\RequestHandler->generatePageContent(Object(TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController), Object(TYPO3\CMS\Core\Http\ServerRequest))\n#33 /var/www/html/public/typo3/sysext/core/Classes/Middleware/ResponsePropagation.php(34): TYPO3\CMS\Frontend\Http\RequestHandler->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#34 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Core\Middleware\ResponsePropagation->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(TYPO3\CMS\Frontend\Http\RequestHandler))\n#35 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/OutputCompression.php(48): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#36 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\OutputCompression->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#37 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/ContentLengthResponseHeader.php(46): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#38 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\ContentLengthResponseHeader->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#39 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/ShortcutAndMountPointRedirect.php(79): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#40 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\ShortcutAndMountPointRedirect->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#41 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/PrepareTypoScriptFrontendRendering.php(78): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#42 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\PrepareTypoScriptFrontendRendering->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#43 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/TypoScriptFrontendInitialization.php(104): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#44 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\TypoScriptFrontendInitialization->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#45 /var/www/html/public/typo3conf/ext/yoast_seo/Classes/Middleware/PageRequestMiddleware.php(32): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#46 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): YoastSeoForTypo3\YoastSeo\Middleware\PageRequestMiddleware->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#47 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/PageArgumentValidator.php(132): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#48 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\PageArgumentValidator->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#49 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/PreviewSimulator.php(66): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#50 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\PreviewSimulator->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#51 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/PageResolver.php(106): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#52 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\PageResolver->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#53 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/StaticRouteResolver.php(80): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#54 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\StaticRouteResolver->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#55 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/SiteBaseRedirectResolver.php(94): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#56 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\SiteBaseRedirectResolver->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#57 /var/www/html/public/typo3/sysext/redirects/Classes/Http/Middleware/RedirectHandler.php(84): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#58 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Redirects\Http\Middleware\RedirectHandler->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#59 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/FrontendUserAuthenticator.php(91): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#60 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\FrontendUserAuthenticator->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#61 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php(78): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#62 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\BackendUserAuthenticator->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#63 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/MaintenanceMode.php(55): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#64 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\MaintenanceMode->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#65 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/SiteResolver.php(65): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#66 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\SiteResolver->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#67 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/EidHandler.php(64): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#68 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\EidHandler->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#69 /var/www/html/public/typo3/sysext/core/Classes/Middleware/NormalizedParamsAttribute.php(45): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#70 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Core\Middleware\NormalizedParamsAttribute->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#71 /var/www/html/public/typo3/sysext/core/Classes/Middleware/VerifyHostHeader.php(55): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#72 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Core\Middleware\VerifyHostHeader->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#73 /var/www/html/public/typo3/sysext/frontend/Classes/Middleware/TimeTrackerInitialization.php(58): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#74 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(172): TYPO3\CMS\Frontend\Middleware\TimeTrackerInitialization->process(Object(TYPO3\CMS\Core\Http\ServerRequest), Object(Psr\Http\Server\RequestHandlerInterface@anonymous))\n#75 /var/www/html/public/typo3/sysext/core/Classes/Http/MiddlewareDispatcher.php(78): Psr\Http\Server\RequestHandlerInterface@anonymous->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#76 /var/www/html/public/typo3/sysext/core/Classes/Http/AbstractApplication.php(86): TYPO3\CMS\Core\Http\MiddlewareDispatcher->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#77 /var/www/html/public/typo3/sysext/frontend/Classes/Http/Application.php(69): TYPO3\CMS\Core\Http\AbstractApplication->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#78 /var/www/html/public/typo3/sysext/core/Classes/Http/AbstractApplication.php(100): TYPO3\CMS\Frontend\Http\Application->handle(Object(TYPO3\CMS\Core\Http\ServerRequest))\n#79 /var/www/html/public/index.php(20): TYPO3\CMS\Core\Http\AbstractApplication->run()\n#80 /var/www/html/public/index.php(21): {closure}()\n#81 {main}"}

I'm using TYPO3 v11.5.14 and PHP 8.0 in an DDEV Project.

TreeMenu does not list pages created in a workspace

Yeah, basically as the topic already says: TreeMenu does not list pages which where created in an active workspace.

Although TreeMenu lists Workspace-Versions for changed-in-workspace pages, it simply ignores new pages.

includeNotInMenu for breadcrumbs

We used includeNotInMenu=1 to include pages with nav_hide=1 in our old HMENU breadcrumb menus:

10 = HMENU
10 {
	special = rootline
	includeNotInMenu = 1
	...

This doesn't seem to be possible with the menus extension (which otherwise works great, btw!). Or am I just missing something?

page.10.dataProcessing.110 = B13\Menus\DataProcessing\BreadcrumbsMenu
page.10.dataProcessing.110.as = breadcrumbNavigation
page.10.dataProcessing.110.includeNotInMenu = 1

Invalide Cache Identifier for many fe_groups

Screenshot 2023-06-09 at 10 22 31

may be we should use md5() hash for usergroups:
$identifier = $prefix . '-root-' . $root . '-language-' . $language . '-groups-' . md5(implode('_', $groupIds)) . '-' . $visibility . '-' . substr(md5(json_encode($configuration)), 0, 10);
instead of
$identifier = $prefix . '-root-' . $root . '-language-' . $language . '-groups-' .implode('_', $groupIds) . '-' . $visibility . '-' . substr(md5(json_encode($configuration)), 0, 10);

excludeLanguages with IDs fails due to strict typing

good morning,
I am using the LanguageMenuProcessor and exclude some languages via their uid (Field Two Letter ISO Code[iso-639-1] can't be used because it is not unique).

In LanguageMenuCompiler line 42 the in_array condition is strict typed, but due to stdWrap handling the uids are given as strings, which makes the comparison fail.

Removing the strict parameter already solves the issue.

Would you please fix the issue (I can also provide a PR if wanted, just let me know) and release a new version? Thank you so much for all the work.

TreeMenu: "isCurrentPage" and "isInRootLine" are undeclared from level 2 on downwards

I have a page tree with up to 4 levels which I all want to display in a mega menu (tree menu). Using treeMenu, everything works as expected down to level 1 (subpage), but as soon as I iterate down on level 2 (subpages of subpages = subsubpages), the state variables are not present anymore.

What am I missing?

Example Fluid Template:

<f:for each="{mainmenu}" as="page">
    <f:debug title="page {page.uid}.isCurrentPage">{page.isCurrentPage}</f:debug>
    <f:debug title="page {page.uid}.isInRootLine">{page.isInRootLine}</f:debug>
    <f:for each="{page.subpages}" as="subpage">
        <f:debug title="subpage {subpage.uid}.isCurrentPage">{subpage.isCurrentPage}</f:debug>
        <f:debug title="subpage {subpage.uid}.isInRootLine">{subpage.isInRootLine}</f:debug>
        <f:for each="{subpage.subpages}" as="subsubpage">
            <f:debug title="subsubpage {subsubpage.uid}.isCurrentPage">{subsubpage.isCurrentPage}</f:debug>
            <!-- this always returns NULL even if I'm on the current page -->
            <f:debug title="subsubpage {subsubpage.uid}.isInRootLine">{subsubpage.isInRootLine}</f:debug>
            <!-- this always returns NULL even if the current page is in rootline -->
        </f:for>
    </f:for>
</f:for>

TypoScript:

lib.mainmenu = FLUIDTEMPLATE
lib.mainmenu {
    dataProcessing.10 = B13\Menus\DataProcessing\TreeMenu
    dataProcessing.10.entryPoints = 1
    dataProcessing.10.depth = 3
    dataProcessing.10.as = mainmenu
    templateName = Mainmenu
    templateRootPaths {
        10 = EXT:my_provider/Resources/Private/Templates/Fluidtemplate
    }
}

[FEATURE] BreadcrumbsMenu: excludePages

We are evaluating to change our menues with this extensions. For the Breadcrumbs we need the ability to configure pages to be excluded from the rendering / rootline.

ROOTLINE: PAGE1 -> PAGE2 -> PAGE3 -> PAGE4
EXCLUDE.: 2
EXPECTED: PAGE1 -> PAGE3 -> PAGE4

The TreeMenu has a excludePages configuration, the BreadcrumbsMenu itself is missing that (for us).

Documentation in README.md misleading

I found out about this extension dealing with a very large menu. 5 levels down. Our old approach using HMENU generated way to many SQL queries (according to the admin panel). And using b13/menus is a game changer.

When I read through the documentation regarding the "Tree Menu" part stating "Usage in Fluid:...". The Fluid template code uses

<f:link.page pageUid="{page.uid}">{page.nav_title}</f:link.page>

In my opinion this is a overload, as the Link Page Viewhelper again produces queries, which are in this context absolutely not necessary. The "mobilemenu" from the DataProcessor already contains all necessary information (especially the "slug").

That's the reason why this is so great, you do not need any other database query, respectively ViewHelpers building your menu. I chose to use this instead

<a href="{page.slug}">{page.nav_title}</a>

The important part here is, that the "slug" is already included in the result form the DataProcessor TreeMenu. No need to use the Fluid Page Viewhelper.

In my case it works, or am I missing something?

Thanks

Languagemenu error after TYPO3 upgrade to 12.4.5

Since upgrading from TYPO3 12.4.4 to 12.4.5 the following error occurs when using the LANGUAGEMENU in typoscript.
Typed property TYPO3\CMS\Frontend\ContentObject\AbstractContentObject::$request must not be accessed before initialization.

I think this block $this->setContentObjectRenderer($this->cObj); inside of B13\Menus\ContentObject\LanguageMenuContentObject must be moved outside of the constructor or the $request property of TYPO3\CMS\Frontend\ContentObject\AbstractContentObject needs to have a default value. I am not certain if this would have any side effects, otherwise I would have created an pull request.

v10 compatibility missing in composer.json of 0.2.0

It's not possible to install a tagget version of this extension on TYPO3 v10 via composer because in the composer.json of the latest version the compatibility is limited to v.9.5:

  "require": {
    "php": "^7.2",
    "typo3/cms-core": "^9.5",
    "typo3/cms-frontend": "^9.5"
  },

I saw that v10 compatibility was added in master branch 10months ago. Would be nice to have v10 compatibilty in a tagged version. Or are there any unsolved problems with v10?

TYPO3 v13 compatibility

In preparation for TYPO3 version 13, this repository / extension would also have to be adapted to the requirements. It has already happened in the b13/container extension.

Please make this extension compatible with TYPO3 v13.

BreadcrumbsMenu: excludeDoktypes ignored

Hi all,

for the Breadcrumbs Menu the excludeDoktypes config is ignored.
Could be something like this in BreadcrumbsMenu:porcess:

` if (!empty($processorConfiguration['excludeDoktypes'])) {
$excludedDoktypes = GeneralUtility::intExplode(',', $processorConfiguration['excludeDoktypes']);
foreach ($GLOBALS['TSFE']->rootLine as $page) {
if (array_search($page['doktype'], $excludedDoktypes) === false ) {
$rootline[] = $page;
}
}
} else {
$rootline = $GLOBALS['TSFE']->rootLine;
}

    $pages = $this->menuRepository->getBreadcrumbsMenu($rootline);

`
best regards
Arne

BreadcrumbsMenu: Missing Reference Syntax

Hi all,

Class BreadcrumbsMenu is wrongly using an unreferenced variable in function process, which may cause problems under certain curcumstances.

          $rootLevelCount = count($pages);
-         foreach ($pages as $page) {
+         foreach ($pages as &$page) {
                PageStateMarker::markStates($page, $rootLevelCount--);
        }

best regards
Arne

Flush alle caches by tags

Hey @bmack

Thanks for the fix in #47 Do you saw my info related to the cache invalidation? Why you only drop two caches: https://github.com/b13/menus/blob/master/Classes/Hooks/DataHandlerHook.php#L64 (hash and pages) It is impossible for EXT:staticfilecache to get the "clear cache" in its own cache. The StaticFileCache entry is also tagged with menuId_XXX. Why don't you use flushCachesByTags() to support all caches that are tagged with the menuId_XXX tags?
https://api.typo3.org/master/class_t_y_p_o3_1_1_c_m_s_1_1_core_1_1_cache_1_1_cache_manager.html#ae8af86d7af4c26e4d6aae11ab07585fd
Nice side effect: The implementation would be smaller :)

Thank you for your feedback.
If I have a mistake in my thoughts, just close the ticket.

Regards,
Tim

Increase usage of the internal menu cache

Hey @bmack

we have a very large site incl. a "Mega Navigation" (multiple layer and also images etc.). In the backend I also use this workaround #51 , but we need more speed in the generation process. The current tree compile calculate the tree and cache this, but the fluid template still use 30-40% of the rendering time in frontend on every page (many page link, image viewhelper, reselction etc.).

So the idea was born, that we enrich the "populateAdditionalKeysForPage" function and precalculate more information for a page. The compiler use also the rendered language in the cache identifier, so it is possible to calculate images, links etc. in this function. The template is only the "output helper" and there is no <f:page.link> or <f:image> anymore. This speed up the generation of next request because all menu information are already part of the cache.

What are your thoughts? Perhaps a PSR Event in populateAdditionalKeysForPage is useful in the future?

Regards,
Tim

Hidden pages without link in cache

We have the problem that our customer uses in TYPO3 11.5 the preview feature to get a preview of his hidden pages. The TreeMenu generates for the preview the menu with hidden pages and everything looks fine.

[Page 1] [Page 2] [Page 3] [Page 4 (hidden)]

But at the same time it also generates the cache for the regular user and adds the hidden pages to the menu too but without links.

[Page 1] [Page 2] [Page 3] Page 4 (hidden)

(The missing brackets should represent the missing link) ;o)

This is easily reproducible with the admin panel -> show hidden pages.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.