Hello Bricks Team,
I just create a custom query type to loop a menu item from menus, here is my current code
// Register a custom query type for menu items
add_filter('bricks/setup/control_options', function($control_options) {
$control_options['queryTypes']['menu_items'] = esc_html__('Menu Items', 'bricks-child');
return $control_options;
});
// Add custom control for selecting the menu
add_filter('bricks/elements/container/controls', 'add_menu_controls', 40);
add_filter('bricks/elements/block/controls', 'add_menu_controls', 40);
add_filter('bricks/elements/div/controls', 'add_menu_controls', 40);
function add_menu_controls($controls) {
$menus = get_terms('nav_menu', ['hide_empty' => true]);
$menu_options = [];
if (!empty($menus) && !is_wp_error($menus)) {
foreach ($menus as $menu) {
$menu_options[$menu->slug] = $menu->name;
}
}
$newControls['menuNameOrId'] = [
'tab' => 'content',
'label' => esc_html__('Select Menu', 'bricks-child'),
'type' => 'select',
'options' => $menu_options,
'placeholder' => esc_html__('Select a menu...', 'bricks-child'),
'required' => [
['query.objectType', '=', 'menu_items'],
['hasLoop', '!=', false],
['isSubmenu', '!=', true]
],
];
$newControls['isSubmenu'] = [
'tab' => 'content',
'label' => esc_html__('Is it for submenu?', 'bricks-child'),
'type' => 'checkbox',
'required' => [
['query.objectType', '=', 'menu_items'],
],
'default' => false,
];
$query_key_index = absint(array_search('query', array_keys($controls)));
$new_controls = array_slice($controls, 0, $query_key_index + 1, true) + $newControls + array_slice($controls, $query_key_index + 1, null, true);
return $new_controls;
}
// Execute the custom query to fetch menu items and handle submenus
add_filter('bricks/query/run', function($results, $query_obj) {
if ($query_obj->object_type !== 'menu_items') {
return $results;
}
$settings = $query_obj->settings;
if (!$settings['hasLoop']) {
return [];
}
$menu_name_or_id = $settings['menuNameOrId'] ?? '';
$is_submenu = $settings['isSubmenu'] ?? false;
if (!empty($menu_name_or_id)) {
$menu_items = wp_get_nav_menu_items($menu_name_or_id);
if (!empty($menu_items)) {
if (!$is_submenu) {
foreach ($menu_items as $menu_item) {
if ($menu_item->menu_item_parent == 0) {
$results[] = $menu_item;
}
}
} else {
$parent_menu_item = \Bricks\Query::get_loop_object();
if ($parent_menu_item) {
$parent_id = $parent_menu_item->ID;
foreach ($menu_items as $menu_item) {
if ($menu_item->menu_item_parent == $parent_id) {
$results[] = $menu_item;
}
}
}
}
return $results;
}
}
return [];
}, 10, 2);
// Map the entire menu item object to the loop object
add_filter('bricks/query/loop_object', function($loop_object, $loop_key, $query_obj) {
if ($query_obj->object_type !== 'menu_items') {
return $loop_object;
}
if (isset($query_obj->results[$loop_key])) {
$loop_object = $query_obj->results[$loop_key];
$meta_data = get_post_meta($loop_object->ID);
foreach ($meta_data as $key => $value) {
if (strpos($key, '_') !== 0) {
$acf_value = get_field($key, $loop_object->ID);
if ($acf_value) {
$loop_object->$key = $acf_value;
}
}
if (is_array($value) && count($value) === 1) {
$value = $value[0];
}
if (!isset($loop_object->$key)) {
$loop_object->$key = $value;
}
}
}
return $loop_object;
}, 10, 3);
// Fetch specific data from the current loop object
function get_menu_item_data($key) {
$menu_item = \Bricks\Query::get_loop_object();
if (!$menu_item) {
return '';
}
switch ($key) {
case 'title':
return esc_html($menu_item->title ?? '');
case 'url':
return esc_url($menu_item->url ?? '#');
case 'is_submenu':
return !empty($menu_item->menu_item_parent);
case 'parent_id':
return $menu_item->menu_item_parent ?? 0;
default:
return '';
}
}
// Register the echo function
add_filter('bricks/code/echo_function_names', function() {
return ['get_menu_item_data'];
});
at the moment, it works perfectly render the top level menu, see screenshot below
but, i got an issue when rendering the submenu item (using nested loop)
the sub menu is never rendered, the issue is the code in bricks/query/run filter at the $submenu is true condition is never triggered, i’ve tried add an error_log to see what is happens but it’s never rendered
if (!$is_submenu) {
foreach ($menu_items as $menu_item) {
if ($menu_item->menu_item_parent == 0) {
$results[] = $menu_item;
}
}
} else { //This condition is never triggered
$parent_menu_item = \Bricks\Query::get_loop_object();
if ($parent_menu_item) {
$parent_id = $parent_menu_item->ID;
foreach ($menu_items as $menu_item) {
if ($menu_item->menu_item_parent == $parent_id) {
$results[] = $menu_item;
}
}
}
}
I wonder if I made a mistake at the code, thanks
cc: @itchycode