#22070 closed defect (bug) (duplicate)
Deleting menus with no title / slow menu saving
Reported by: | msebel | Owned by: | |
---|---|---|---|
Milestone: | Priority: | normal | |
Severity: | normal | Version: | 3.4 |
Component: | Menus | Keywords: | |
Focuses: | Cc: |
Description
Hello there
I saw that when saving nav menus in wp-admin/nav-menus.php WordPress executes the following lines, if a menu item is saved (no matter if newly added or existing) that doesn't have a title:
if ( empty( $_POST['menu-item-title'][$_key] ) ) continue;
I changed this to the following to make it work. Problem is, it needs to be removed from $menu_items, because it's handled like a deleted menu else.
if ( empty( $_POST['menu-item-title'][$_key] ) ) { if (isset($menu_items[$_POST['menu-item-db-id'][$_key]])) unset($menu_items[$_POST['menu-item-db-id'][$_key]]); continue; } }
Sidenote:
With that fixed, I was able to solve a major saving bug. Many of our customers have a lot of menu items in out nav_menu (like 100 - 600), which without a timeout would take 10 minutes and more to save.
So I created some hotfix jQuery script that does "dirty-handling". Basically it marks everything that's touched (like changed data, adding a menu item or moving things around) as "dirty". On submit it doesn't nothing more than change every "undirty" menu items title to an empty string so it doesn't get saved.
I think WordPress core developers could integrate something like this with far less code since I wasn't able to use events - I didn't really had a lot of time to fix this. So if it helps anyone, this is the jQuery code I used to create the fix:
jQuery(function($) { // the currently displayed menu form var $form = $('#update-nav-menu'); // Listen to new menus, since we have no possibility to hook // we have to interval it, because we can't capture an event here $('.submit-add-to-menu').click(function() { var $item_count = $form.find('.menu-item-handle').length; var $interval_id = setInterval(function() { var $current_item_count = $form.find('.menu-item-handle').length; if ($item_count < $current_item_count) { clearInterval($interval_id); // Add the dirty flag and set it to dirty immediately add_dirty_flags(1); // Reassign the mousedown/up events assign_mouse_events(); } },200); }); // add a hidden field, telling if the menu is dirty (by default, it's not) function add_dirty_flags($flag) { $form.find('.menu-item-handle').each(function() { if ($(this).find('.dirty-handle').length == 0) { var $html = '<input type="hidden" class="dirty-handle" value="' + $flag + '" />'; $(this).append($html); console.log('flag added'); } }); } // (re)assigns mouse events to menu items function assign_mouse_events() { var $menu_items = $('.menu-item-bar'); // Unbind previously assigned events $menu_items.unbind('mouseup').unbind('mousedown'); // Dirty Flag handler if a click happens $menu_items.mousedown(function() { $(this).find('.dirty-handle').val('1'); }); // if the parent changes on release the mouse handle, change all items with the new parent to dirty $menu_items.mouseup(function() { menu_save_mouseup($(this)); }); } // The call back for mouseup on menu bars function menu_save_mouseup($this) { var $temp_object = $this.parent(); // Mark everything with the same parent dirty setTimeout(function() { var $parent_id = $temp_object.find('.menu-item-data-parent-id').val(); // Go through all fields, dirtying everything that has the same parent $('.menu-item-data-parent-id').each(function() { if ($(this).val() == $parent_id) $(this).parent().prev().find('.dirty-handle').val('1'); }); },200); } // On submit make every undirty menu an empty title, so it won't get saved // We're using a hoax in nav-menus.php, line 335 here.. $form.submit(function() { // Now traverse all handles and make only dirties saveable $form.find('.menu-item-handle').each(function() { // Find the dirty flag var $is_dirty = $(this).find('.dirty-handle').val(); $(this).find('.dirty-handle').remove(); if ($is_dirty == 0) { // The div containing the menu informations var $forms = $(this).parent().next(); // Remove the title value so it doesn't get saved $forms.find('.edit-menu-item-title').val(''); } }); return true; }); // Assign mouse events on first load assign_mouse_events(); // Add all dirty flags (not dirty by default of course) add_dirty_flags(0); });
Since WordPress now only saves the menu's that changed it doesn't matter how many menu items a customer has, but only how many he want's to save at one time.
Related: #14134, #17031