Skip to content

[5.x]: disclosuremenu.twig crashes on non-iterable menu items #18340

@mraap

Description

@mraap

What happened?

Bug Report: disclosuremenu.twig crashes on non-iterable menu items

Note: I've asked Copilot to create this bug report based on our findings. Sadly it's very hard to reproduce the issue as it seems to only occur in a situation very specific to the website we're currently upgrading from 4 to 5, and we haven't been able to pinpoint what exactly sets this site apart from all the other ones that we've upgraded in the past. I can confirm that the fix proposed by Copilot resolves the issue.

Summary

The disclosuremenu.twig template in Craft CMS 5.9.x throws an error when menu items contain non-iterable values (such as Color enum objects or strings). This prevents users from opening entries in the Control Panel.

Error Message

yii\base\ErrorException: Undefined property: craft\enums\Color::$selected
in /vendor/yiisoft/yii2/helpers/BaseArrayHelper.php:221

Environment

  • Craft CMS Version: 5.9.3
  • PHP Version: 8.2
  • Craft Commerce: 5.5.2
  • Upgraded from: Craft 4

Steps to Reproduce

  1. Upgrade a Craft 4 site to Craft 5.9.3
  2. Have multiple sections/entry types configured
  3. Open any entry in the Control Panel
  4. Error occurs when rendering the CP layout

Note: This bug is difficult to reproduce on fresh installations. It appears to be triggered by specific data configurations that may occur during migration or with sites that have many sections.

Root Cause Analysis

The bug is located in vendor/craftcms/cms/src/templates/_includes/disclosuremenu.twig, line 7:

{% set hasSelected = items|map(i => (i.items ?? [i]))|flatten(1)|contains('selected') %}

Problem

The |contains('selected') filter calls ArrayHelper::contains(), which iterates through all flattened items and attempts to access a selected property on each one. When non-iterable values are present in the flattened array (such as Color enum objects or strings like "link"), the property access fails.

How non-iterable values end up in the array

  1. Color enum objects: Entry types can have a color property set. When this is passed through to disclosure menus via the iconColor property, the Color enum object ends up in the items array.

    From vendor/craftcms/cms/src/elements/Entry.php (around line 2562):

    'iconColor' => $et->color,  // This is a Color enum when set
  2. String values: Menu item properties like type: 'link' can leak into the flattened array under certain data configurations.

Stack Trace

#0 vendor/craftcms/cms/src/web/ErrorHandler.php(115)
#1 vendor/yiisoft/yii2/helpers/BaseArrayHelper.php(221): accessing ->selected on Color enum
#2 vendor/craftcms/cms/src/helpers/ArrayHelper.php(494): getValue(Color, 'selected', NULL)
#3 vendor/craftcms/cms/src/helpers/ArrayHelper.php(277): contains(Array, 'selected')
#4 storage/runtime/compiled_templates/.../disclosuremenu.twig(57)
...

The error also manifests in breadcrumb menus (crumbs.twig:54) where string values like "link" appear in the flattened items.

Proposed Fix

Add a filter to exclude non-iterable values before calling |contains():

Before (buggy):

{% set hasSelected = items|map(i => (i.items ?? [i]))|flatten(1)|contains('selected') %}

After (fixed):

{% set hasSelected = items|map(i => (i.items ?? [i]))|flatten(1)|filter(i => i is iterable)|contains('selected') %}

This ensures only array/object items that can have a selected property are checked.

Workaround

Until an official fix is released, users can create a module that patches the vendor file on load:

<?php
namespace modules\craft5compat;

use Craft;
use yii\base\Module;

class Craft5Compat extends Module
{
    public function init(): void
    {
        parent::init();
        $this->applyDisclosureMenuPatch();
    }

    private function applyDisclosureMenuPatch(): void
    {
        $vendorTemplatePath = Craft::getAlias('@vendor/craftcms/cms/src/templates/_includes/disclosuremenu.twig');
        
        if (!file_exists($vendorTemplatePath)) {
            return;
        }

        $content = file_get_contents($vendorTemplatePath);
        
        $buggyLine = "{% set hasSelected = items|map(i => (i.items ?? [i]))|flatten(1)|contains('selected') %}";
        $fixedLine = "{% set hasSelected = items|map(i => (i.items ?? [i]))|flatten(1)|filter(i => i is iterable)|contains('selected') %}";
        
        if (strpos($content, $buggyLine) !== false) {
            $patchedContent = str_replace($buggyLine, $fixedLine, $content);
            file_put_contents($vendorTemplatePath, $patchedContent);
        }
    }
}

Additional Context

  • The issue was confirmed on a site upgraded from Craft 4 with 31+ sections
  • All plugins were disabled during testing - the issue persists with only core Craft
  • Fresh Craft 5 installations with similar configurations do not exhibit this issue
  • The bug may be related to how data structures are transformed during Craft 4 → 5 migration

Related Files

  • vendor/craftcms/cms/src/templates/_includes/disclosuremenu.twig (line 7)
  • vendor/craftcms/cms/src/templates/_layouts/components/crumbs.twig (line 54)
  • vendor/craftcms/cms/src/helpers/ArrayHelper.php (contains method)
  • vendor/craftcms/cms/src/elements/Entry.php (iconColor property)

Craft CMS version

Craft Pro 5.9.3 (also occurs in earlier versions)

PHP version

8.2.29

Operating system and version

Linux 6.6.87.2-microsoft-standard-WSL2

Database type and version

MariaDB 10.8.8

Image driver and version

Imagick 3.8.0 (ImageMagick 6.9.11-60)

Installed plugins and versions

All plugins were disabled during testing, including Craft Commerce, but the problem persisted. Here's a list of installed plugins, all except for site-copy-x were enabled initially:

panlatent/craft-aliyun 1.1.2
craftcms/aws-s3 2.2.4
born05/craft-assetusage 4.1.3
craftcms/ckeditor 4.11.0
craftcms/commerce 5.5.2
vaersaagod/geomate 3.1.0
verbb/hyper 2.3.0
nystudio107/craft-minify 5.0.0
spicyweb/craft-neo 5.5.4
ttempleton/craft-nocache 3.0.4
craftcms/postmark 3.1.0
ostark/craft-relax 2.1.0
nystudio107/craft-retour 5.0.13
nystudio107/craft-seomatic 5.1.20
nst/craft-sitecopy 2.1.1
craftcms/store-hours 4.2.0
verbb/super-table 4.0.5
verbb/wishlist 3.0.12

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions