Skip to content

Fatal TypeError in breadcrumb when menu_order is non-sequential or post appears twice in menu #2806

@curtismchale

Description

@curtismchale

Builds

Bug

Two related fatal errors can occur in ProudBreadcrumb::build_breadcrumb() inside wp-proud-core/modules/proud-menu/proud-menu.php.

Error 1 — TypeError on line 324 (reported via Zendesk)

Fatal error: Uncaught TypeError: Cannot access offset of type string on string
in wp-proud-core/modules/proud-menu/proud-menu.php:324

Root cause: get_active_trail() returns an array of [menu_item_id => ''] placeholders. The fill loop in build_breadcrumb() used end($active_trail) to detect when the deepest (leaf) item was filled and then break'd. wp_get_nav_menu_items() returns items sorted by menu_order, which is not guaranteed to be root→leaf. If the active page's menu item has a lower menu_order than an ancestor, the leaf slot is filled first, the break fires, and ancestor slots remain as empty strings ''. reset($active_trail) then returns '', and ''['post_id'] throws the TypeError.

Error 2 — Duplicate post in menu creates a forked active trail

If the same post appears more than once in a nav menu, get_nested_menu() marks both menu items as active, inserting two separate trail entries. This produces an ambiguous/forked breadcrumb that could cause unexpected rendering or a second TypeError when $firstItem is resolved from the wrong branch.

Fix (applied in wp-proud-core)

  1. get_nested_menu — added a $found_active flag so only the first occurrence of the active post in the tree traversal is marked active. Duplicates are ignored.
  2. build_breadcrumb fill loop — removed the end()-based early break. The loop now iterates all menu items and fills any matching trail slot; no early exit.
  3. After the looparray_filter($active_trail, 'is_array') drops any slots that were never matched (handles edge cases like items removed from the menu). The last (deepest) item is then marked active explicitly via array_key_last().
  4. $firstItem guard — added is_array($firstItem) check before accessing ['post_id'] so an empty trail after filtering doesn't produce a second TypeError.

References

Zendesk ticket: https://proudcity.zendesk.com/agent/tickets/7856

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions