/** * Merge a custom menu with the current default WordPress menu. Adds/replaces defaults, * inserts new items and removes missing items. * * @uses self::$item_templates * * @param array $tree A menu in plugin's internal form * @return array Updated menu tree */ function menu_merge($tree) { //Iterate over all menus and submenus and look up default values //Also flag used and missing items. $orphans = array(); //Build an index of menu positions so that we can quickly pick the right position for new/unused items. $positions_by_template = array(); $following_separator_position = array(); $previous_default_top_menu = null; foreach ($tree as &$topmenu) { if (!empty($topmenu['separator']) && isset($previous_default_top_menu)) { $following_separator_position[$previous_default_top_menu] = ameMenuItem::get($topmenu, 'position', 0); } $previous_default_top_menu = null; if (!ameMenuItem::get($topmenu, 'custom')) { $template_id = ameMenuItem::template_id($topmenu); //Is this menu present in the default WP menu? if (isset($this->item_templates[$template_id])) { //Yes, load defaults from that item $topmenu['defaults'] = $this->item_templates[$template_id]['defaults']; //Note that the original item was used $this->item_templates[$template_id]['used'] = true; //Add valid, non-custom items to the position index. $positions_by_template[$template_id] = ameMenuItem::get($topmenu, 'position', 0); $previous_default_top_menu = $template_id; } else { //Record the menu as missing, unless it's a menu separator if (empty($topmenu['separator'])) { $topmenu['missing'] = true; $temp = ameMenuItem::apply_defaults($topmenu); $temp = $this->set_final_menu_capability($temp); $this->add_access_lookup($temp, 'menu', true); } //Don't add missing menus to the index because they won't show up anyway. } } if (is_array($topmenu['items'])) { //Iterate over submenu items foreach ($topmenu['items'] as &$item) { if (!ameMenuItem::get($item, 'custom')) { $template_id = ameMenuItem::template_id($item); //Is this item present in the default WP menu? if (isset($this->item_templates[$template_id])) { //Yes, load defaults from that item $item['defaults'] = $this->item_templates[$template_id]['defaults']; $this->item_templates[$template_id]['used'] = true; //Add valid, non-custom items to the position index. $positions_by_template[$template_id] = ameMenuItem::get($item, 'position', 0); //We must move orphaned items elsewhere. Use the default location if possible. if (isset($topmenu['missing']) && $topmenu['missing']) { $orphans[] = $item; } } else { if (empty($item['separator'])) { //Record as missing, unless it's a menu separator $item['missing'] = true; $temp = ameMenuItem::apply_defaults($item); $temp = $this->set_final_menu_capability($temp); $this->add_access_lookup($temp, 'submenu', true); } } } else { //What if the parent of this custom item is missing? //Right now the custom item will just disappear. } } } } //If we don't unset these they will f**k up the next two loops where the same names are used. unset($topmenu); unset($item); //Now we have some items marked as missing, and some items in lookup arrays //that are not marked as used. Lets remove the missing items from the tree. $tree = ameMenu::remove_missing_items($tree); //Lets merge in the unused items. $max_menu_position = !empty($positions_by_template) ? max($positions_by_template) : 100; foreach ($this->item_templates as $template_id => $template) { //Skip used menus and separators if (!empty($template['used']) || !empty($template['defaults']['separator'])) { continue; } //Found an unused item. Build the tree entry. $entry = ameMenuItem::blank_menu(); $entry['template_id'] = $template_id; $entry['defaults'] = $template['defaults']; $entry['unused'] = true; //Note that this item is unused if ($this->options['unused_item_position'] === 'relative') { //Attempt to maintain relative menu order. $previous_item = $was_separated = null; if (isset($this->relative_template_order[$template_id])) { $previous_item = $this->relative_template_order[$template_id]['previous_item']; $was_separated = $this->relative_template_order[$template_id]['was_previous_item_separated']; } if (isset($previous_item, $positions_by_template[$previous_item])) { if ($was_separated && isset($following_separator_position[$previous_item])) { //Desired order: previous item -> separator -> this item. $entry['position'] = $following_separator_position[$previous_item]; } else { //Desired order: previous item -> this item. $entry['position'] = $positions_by_template[$previous_item]; if (isset($following_separator_position[$previous_item])) { //Now the separator is after this item, not the previous one. $following_separator_position[$template_id] = $following_separator_position[$previous_item]; unset($following_separator_position[$previous_item]); } } $entry['position'] = $entry['position'] + 0.01; } else { if ($previous_item === '') { //Empty string = this was originally the first item. $entry['position'] = -1; } else { //Previous item is unknown or doesn't exist. Leave this item in its current, incorrect position. } } } else { //Move unused entries to the bottom. $max_menu_position = $max_menu_position + 1; $entry['position'] = $max_menu_position; } $positions_by_template[$template_id] = ameMenuItem::get($entry, 'position', 0); //Add the new entry to the menu tree if (isset($template['defaults']['parent'])) { if (isset($tree[$template['defaults']['parent']])) { //Okay, insert the item. $tree[$template['defaults']['parent']]['items'][] = $entry; } else { //This can happen if the original parent menu has been moved to a submenu. $tree[$template['defaults']['file']] = $entry; } } else { $tree[$template['defaults']['file']] = $entry; } } //Move orphaned items back to their original parents. foreach ($orphans as $item) { $defaultParent = $item['defaults']['parent']; if (isset($defaultParent) && isset($tree[$defaultParent])) { $tree[$defaultParent]['items'][] = $item; } else { //This can happen if the parent has been moved to a submenu. //Just put the orphan at the bottom of the menu. $tree[$item['defaults']['file']] = $item; } } //Resort the tree to ensure the found items are in the right spots $tree = ameMenu::sort_menu_tree($tree); //Order data is no longer necessary. $this->relative_template_order = null; return $tree; }
/** * Merge a custom menu with the current default WordPress menu. Adds/replaces defaults, * inserts new items and removes missing items. * * @uses self::$item_templates * * @param array $tree A menu in plugin's internal form * @return array Updated menu tree */ function menu_merge($tree) { //Iterate over all menus and submenus and look up default values //Also flag used and missing items. $orphans = array(); foreach ($tree as &$topmenu) { if (!ameMenuItem::get($topmenu, 'custom')) { $template_id = ameMenuItem::template_id($topmenu); //Is this menu present in the default WP menu? if (isset($this->item_templates[$template_id])) { //Yes, load defaults from that item $topmenu['defaults'] = $this->item_templates[$template_id]['defaults']; //Note that the original item was used $this->item_templates[$template_id]['used'] = true; } else { //Record the menu as missing, unless it's a menu separator if (empty($topmenu['separator'])) { $topmenu['missing'] = true; $temp = ameMenuItem::apply_defaults($topmenu); $temp = $this->set_final_menu_capability($temp); $this->add_access_lookup($temp, 'menu', true); } } } if (is_array($topmenu['items'])) { //Iterate over submenu items foreach ($topmenu['items'] as &$item) { if (!ameMenuItem::get($item, 'custom')) { $template_id = ameMenuItem::template_id($item); //Is this item present in the default WP menu? if (isset($this->item_templates[$template_id])) { //Yes, load defaults from that item $item['defaults'] = $this->item_templates[$template_id]['defaults']; $this->item_templates[$template_id]['used'] = true; //We must move orphaned items elsewhere. Use the default location if possible. if (isset($topmenu['missing']) && $topmenu['missing']) { $orphans[] = $item; } } else { if (empty($item['separator'])) { //Record as missing, unless it's a menu separator $item['missing'] = true; $temp = ameMenuItem::apply_defaults($item); $temp = $this->set_final_menu_capability($temp); $this->add_access_lookup($temp, 'submenu', true); } } } else { //What if the parent of this custom item is missing? //Right now the custom item will just disappear. } } } } //If we don't unset these they will f**k up the next two loops where the same names are used. unset($topmenu); unset($item); //Now we have some items marked as missing, and some items in lookup arrays //that are not marked as used. Lets remove the missing items from the tree. $tree = ameMenu::remove_missing_items($tree); //Lets merge in the unused items. foreach ($this->item_templates as $template_id => $template) { //Skip used menus and separators if (!empty($template['used']) || !empty($template['defaults']['separator'])) { continue; } //Found an unused item. Build the tree entry. $entry = ameMenuItem::blank_menu(); $entry['template_id'] = $template_id; $entry['defaults'] = $template['defaults']; $entry['unused'] = true; //Note that this item is unused //Add the new entry to the menu tree if (!empty($template['defaults']['parent'])) { if (isset($tree[$template['defaults']['parent']])) { //Okay, insert the item. $tree[$template['defaults']['parent']]['items'][] = $entry; } else { //This can happen if the original parent menu has been moved to a submenu. $tree[$template['defaults']['file']] = $entry; } } else { $tree[$template['defaults']['file']] = $entry; } } //Move orphaned items back to their original parents. foreach ($orphans as $item) { $defaultParent = !empty($item['defaults']['parent']) ? $item['defaults']['parent'] : null; if (isset($defaultParent) && isset($tree[$defaultParent])) { $tree[$defaultParent]['items'][] = $item; } else { //This can happen if the parent has been moved to a submenu. //Just put the orphan at the bottom of the menu. $tree[$item['defaults']['file']] = $item; } } //Resort the tree to ensure the found items are in the right spots $tree = ameMenu::sort_menu_tree($tree); return $tree; }
/** * Merge a custom menu with the current default WordPress menu. Adds/replaces defaults, * inserts new items and removes missing items. * * @uses self::$item_templates * * @param array $tree A menu in plugin's internal form * @return array Updated menu tree */ function menu_merge($tree) { //Iterate over all menus and submenus and look up default values foreach ($tree as &$topmenu) { if (!ameMenuItem::get($topmenu, 'custom')) { $template_id = ameMenuItem::template_id($topmenu); //Is this menu present in the default WP menu? if (isset($this->item_templates[$template_id])) { //Yes, load defaults from that item $topmenu['defaults'] = $this->item_templates[$template_id]['defaults']; //Note that the original item was used $this->item_templates[$template_id]['used'] = true; } else { //Record the menu as missing, unless it's a menu separator if (empty($topmenu['separator'])) { $topmenu['missing'] = true; $temp = ameMenuItem::apply_defaults($topmenu); $temp['access_level'] = $this->get_menu_capability($temp); $this->add_access_lookup($temp, 'menu', true); } } } if (is_array($topmenu['items'])) { //Iterate over submenu items foreach ($topmenu['items'] as &$item) { if (!ameMenuItem::get($item, 'custom')) { $template_id = ameMenuItem::template_id($item); //Is this item present in the default WP menu? if (isset($this->item_templates[$template_id])) { //Yes, load defaults from that item $item['defaults'] = $this->item_templates[$template_id]['defaults']; $this->item_templates[$template_id]['used'] = true; } else { if (empty($item['separator'])) { //Record as missing, unless it's a menu separator $item['missing'] = true; $temp = ameMenuItem::apply_defaults($item); $temp['access_level'] = $this->get_menu_capability($temp); $this->add_access_lookup($temp, 'submenu', true); } } } } } } //If we don't unset these they will f**k up the next two loops where the same names are used. unset($topmenu); unset($item); //Now we have some items marked as missing, and some items in lookup arrays //that are not marked as used. Lets remove the missing items from the tree. $filteredTree = array(); foreach ($tree as $file => $topmenu) { if ($topmenu['missing']) { continue; } $filteredSubmenu = array(); if (is_array($topmenu['items'])) { foreach ($topmenu['items'] as $index => $item) { if (!$item['missing']) { $filteredSubmenu[$index] = $item; } } } $topmenu['items'] = $filteredSubmenu; $filteredTree[$file] = $topmenu; } $tree = $filteredTree; //Lets merge in the unused items. foreach ($this->item_templates as $template_id => $template) { //Skip used menus and separators if (!empty($template['used']) || !empty($template['defaults']['separator'])) { continue; } //Found an unused item. Build the tree entry. $entry = ameMenuItem::blank_menu(); $entry['template_id'] = $template_id; $entry['defaults'] = $template['defaults']; $entry['unused'] = true; //Note that this item is unused //Add the new entry to the menu tree if (!empty($template['defaults']['parent'])) { if (isset($tree[$template['defaults']['parent']])) { //Okay, insert the item. $tree[$template['defaults']['parent']]['items'][] = $entry; } else { //This can happen if the original parent menu has been moved to a submenu. //Todo: Handle this unusual situation. } } else { $tree[$template['defaults']['file']] = $entry; } } //Resort the tree to ensure the found items are in the right spots $tree = ameMenu::sort_menu_tree($tree); return $tree; }