Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pimcore Navigation Laravel Package

gal-digital-gmbh/pimcore-navigation

A navigation bundle for Pimcore that helps developers build and manage site menus and navigation structures. Integrates with Pimcore documents and supports configurable, template-friendly navigation rendering.

View on GitHub
Deep Wiki
Context7

Getting Started

This is not a Laravel package. It's a Pimcore bundle built on Symfony, so the mental model shifts: no Eloquent models (documents are Pimcore\Model\Document instances), no Blade (Pimcore uses Twig), no app() helper for services (use constructor injection or bin/console debug:container).

Minimal steps

  1. composer require gal-digital-gmbh/pimcore-navigation:^3.1.1 — the 3.x line is current, and 3.1.1 is the first 3.x release carrying the menu renderer fix that had previously only shipped on the 2.x branch. Don't start on an older 3.x patch.
  2. Register the bundle in config/bundles.php (Pimcore 11 / Symfony 6 layout):
    GalDigitalGmbh\PimcoreNavigation\PimcoreNavigationBundle::class => ['all' => true],
    
  3. Clear caches: bin/console cache:clear and bin/console pimcore:cache:clear
  4. Confirm the bundle's config surface: bin/console config:dump-reference pimcore_navigation (adjust the alias to whatever src/DependencyInjection/Configuration.php defines) and inspect services with bin/console debug:container --tag=twig.extension.

Where to look first

  • src/ — the navigation service/builder and any Twig extension. This is the real API surface; the README on a small bundle is often thinner than the code.
  • config/services.php (or .yaml) — service IDs and autowiring aliases you'll inject.
  • README.md — install snippet and the one canonical example.
  • CHANGELOG.md / GitHub releases — you need this more than usual here, because fixes occasionally land on one major branch and get ported later (see Gotchas).

First use case

Render a primary menu in your site layout from the children of the home document:

{# templates/layout.html.twig #}
<nav>
    {{ pimcore_navigation(document, { depth: 2 }) }}  {# check the actual function name in the Twig extension #}
</nav>

If no Twig function exists, inject the service into your controller instead — the point is to get one working menu before wiring breadcrumbs and sitemaps.

Implementation Patterns

Pattern 1 — Root-driven menus Bind a menu to a specific branch by passing the root Document, not the current page. This keeps the menu identical across the subtree and avoids accidental "menu of whatever page I'm on" bugs.

Pattern 2 — Active state and trail Active/highlight state needs the current document passed explicitly (document in Twig, or $request->attributes->get('_document')). Expect the bundle to compute an active trail; if not, walk getParent() up from the current page and compare document IDs against the menu items.

Pattern 3 — Respect Pimcore's built-in navigation properties Pimcore documents already carry navigation_name, navigation_title, navigation_target, and navigation_exclude. Verify the bundle reads these; if it doesn't, layer them on in your template:

{% if not item.document.getProperty('navigation_exclude') %}
    <a href="{{ item.uri }}" target="{{ item.document.getProperty('navigation_target') }}">
        {{ item.document.getProperty('navigation_name') ?: item.label }}
    </a>
{% endif %}

Pattern 4 — Filtering by document type Folders, snippets, and links behave differently in menus. Filter on $doc->getType() (page, link, folder, snippet) and on $doc->getPublished() before handing documents to the builder. Links especially: they need getHref(), not getRealFullPath().

Pattern 5 — Caching Navigation is the classic N+1. For anything past trivial sites:

  • Wrap the built tree in Pimcore's cache service keyed by root document ID + site ID.
  • Invalidate on pimcore.document.postUpdate / postDelete events (or a tag-collection per root).
  • Do not cache per-request user-role menus in the same namespace.
  • After any bundle upgrade, flush this cache. A renderer fix (like the one in 3.1.1) won't show up if your cached nav tree was built by the buggy renderer.

Pattern 6 — Recursive Twig macro For depth > 2, a recursive macro is cleaner than nested for loops:

{% macro render(items) %}
    <ul>
    {% for item in items %}
        <li class="{{ item.active ? 'active' }}">
            <a href="{{ item.uri }}">{{ item.label }}</a>
            {% if item.pages %}{{ _self.render(item.pages) }}{% endif %}
        </li>
    {% endfor %}
    </ul>
{% endmacro %}

Integration tips for Laravel devs

  • Symfony's service container ≈ Laravel's, but there's no app() — inject via constructor or use AbstractController::getContainer.
  • Twig's {{ }} auto-escapes, like Blade; use |raw sparingly for pre-rendered HTML from the bundle's renderer.
  • Pimcore "documents" ≈ routed pages; "snippets" are reusable partials; "areas" are the block system. Navigation typically lives in the site layout, not in area bricks.
  • Think of the 2.x/3.x split like Laravel's LTS vs current: same idea, but here patch fixes are not guaranteed to be mirrored across branches on release day.

Gotchas and Tips

Package maturity is still the biggest risk — and the version graph is now the specific trap. It's a small, low-dependency-count package, but it is not a single-release project: there is a maintained 2.x line and a 3.x line, and 3.1.1 exists purely to migrate a menu renderer bugfix that had shipped in 2.1.0 on the older branch. That tells you two things: (a) fixes sometimes land on one branch and are ported to the other later, and (b) if you adopted 3.0.x or 3.1.0 you were running a renderer with a known, already-fixed-elsewhere bug. Pin an exact version, read the changelog on every bump, and vendor-review src/ before adopting. There is no community to catch regressions for you.

Never assume a 2.x fix is in your 3.x install. Before upgrading, or when you hit a rendering oddity (wrong nesting, missing wrapper markup, malformed <ul>), check whether a 2.x patch exists that hasn't been migrated to the branch you're on. 3.1.1 is exactly that scenario resolved — treat it as the floor for 3.x, not as a nice-to-have.

Bugfix-only releases still need a full redeploy cycle. php-cs-fixer noise in the 3.1.1 notes is cosmetic, but the renderer change is behavioural. Run bin/console cache:clear and bin/console pimcore:cache:clear, and invalidate any nav tree you've cached, before concluding the upgrade "did nothing".

Pimcore/Symfony version drift. Check composer.json constraints against your Pimcore major (10 vs 11 imply Symfony 5 vs 6, and different bundle registration styles). Mismatches surface as container compile errors, not runtime ones. Note that branch 2.x vs 3.x may not track the same Pimcore majors — confirm which branch your Pimcore version targets before pinning.

It is not Laravel. Every Laravel instinct — Facades, Artisan, Eloquent relationships, php artisan vendor:publish — has no equivalent. Use bin/console, Pimcore's Element\Service, and Symfony config trees.

Unpublished/hidden documents vanish silently. Menus empty out for no visible reason when a parent folder is unpublished. Debug by dumping $doc->getChildren(true) vs ->getChildren() in a controller before blaming the bundle.

Service and Twig function naming collisions. Pimcore core ships Pimcore\Navigation\Builder and menu renderers. If you have both, debug:twig to see which function wins — aliases are resolved by registration order, and this bites quietly. This matters more now that the bundle's renderer has been patched: if core's renderer is winning, the 3.1.1 fix is simply not in play.

Current-document context is not magically resolved. If active states are all false, nine times out of ten the current document wasn't passed in, or _document isn't set on the request in that context (e.g. inside a snippet rendered from a block).

Debugging checklist

  • bin/console debug:container gal — confirm the service is registered and its alias.
  • bin/console debug:twig — confirm the extension and function names, and that the bundle's renderer (not core's) is the one wired up.
  • bin/console pimcore:documents:list or a dump() in a throwaway controller to inspect the tree.
  • bin/console cache:clear after editing any bundle config or upgrading — Symfony container caching is aggressive.
  • Compare installed version (composer show gal-digital-gmbh/pimcore-navigation) against the changelog before filing a renderer bug.

Extension points. Decorate the bundle's service (services.yaml with decorates:) rather than editing vendor code; override Twig templates by placing same-named files in templates/bundles/PimcoreNavigationBundle/; hook document save events for cache invalidation. If the bundle lacks the flexibility you need, wrapping Pimcore\Navigation\Builder directly is often less work than bending a small package — and it frees you from waiting on cross-branch bugfix ports.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin