Make WordPress Core

Opened 3 years ago

Closed 7 months ago

Last modified 7 months ago

#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:


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] ) )

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]]))

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) {
        // Add the dirty flag and set it to dirty immediately
        // Reassign the mousedown/up events

  // 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 + '" />';
        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

    // Dirty Flag handler if a click happens
    $menu_items.mousedown(function() {

    // if the parent changes on release the mouse handle, change all items with the new parent to dirty
    $menu_items.mouseup(function() {

  // 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)

  // 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();
      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
    return true;

  // Assign mouse events on first load
  // Add all dirty flags (not dirty by default of course)

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.

Change History (4)

#1 @SergeyBiryukov
3 years ago

Related: #14134

Version 0, edited 3 years ago by SergeyBiryukov (next)

#2 @chriscct7
7 months ago

  • Keywords dev-feedback removed
  • Resolution set to worksforme
  • Status changed from new to closed
  • Version changed from 3.4.2 to 3.4

Menus can no longer be saved without a title due to some JS validation added between when this ticket was reported and 4.2. As such, closing as worksforme

#3 @SergeyBiryukov
7 months ago

  • Resolution changed from worksforme to duplicate

Duplicate of #24146 and #14134.

#4 @SergeyBiryukov
7 months ago

  • Milestone Awaiting Review deleted
Note: See TracTickets for help on using tickets.