1

I create a menu "XXXX" move "Create content" and all of it's children to "XXXX" then remove XXXX menu. now I miss "Create content", how can I restore them?

1
  • 1
    I have updated my answer. The code is now more generic, and it should work in more cases. Keep in mind what I reported in my answer: The code could catch the wrong row, if there are more rows with a link path equal to node/add. It excludes the row added by the Shortcut module, but not similar rows added from other modules.
    – avpaderno
    Commented Dec 11, 2012 at 22:45

1 Answer 1

2

You can execute the following query.

if ($mlid = db_query("SELECT mlid from {menu_links} WHERE link_path = :path AND menu_name NOT LIKE :menu", array(':path' => 'node/add', ':menu' => db_like('shortcut-set-') . '%'))->fetchField()) {
  db_update('menu_links')
    ->fields(array('menu_name' => 'navigation', 'plid' => 0))
    ->condition('mlid', $mlid)
    ->execute();
  db_update('menu_links')
    ->fields(array('menu_name' => 'navigation', 'plid' => $mlid))
    ->condition('link_path', db_like('node/add/') . '%', 'LIKE')
    ->condition('menu_name', db_like('shortcut-set-') . '%', 'NOT LIKE')
    ->execute();
}
else {
  // There isn't any row for node/add.
}

What the code does is the following.

  • It finds the database row where the link path is node/add, and where the menu name doesn't start with shortcut-set-, which is the menu name used from the Shortcut module for its shortcut sets; as the default shortcut set used from that module contains a link that points to node/add, the code exclude that link. If there are other rows that would point to node/add, you need to edit the first query to exclude them.
  • For the row found from the first query, it changes the menu name to navigation, and plid (the parent link ID) to 0.
  • For any row whose link path matches the SQL regular expression node/add/%, it sets plid to the mlid previously found.

In the code I used db_like(), even in this case was not strictly necessary. The purpose of db_like() is escaping any character that for the SQL regular expressions has a specific meaning. Suppose that I would change the code to find any database row whose link path is node/%, where % is the character that is really present in the link path; without db_like(), the query would find any row where the link path starts with node/, which would include more rows than the ones where the link path is node/%.

As the code is using two update queries, it should use transactions. In that way, if the second query would fail, the database would be left in a consistent state, which means that the rows for node/add, and node/add/[content type] will be part of the same menu. If the first query is executed, and the second one fails, you would have node/add that is part of a menu, while any node/add/[content type] link would be part of a different menu (or some of the node/add/[content type] links will be part of a menu, and other node/add/[content type] links will part of another menu).

if ($mlid = db_query("SELECT mlid from {menu_links} WHERE link_path = :path AND menu_name NOT LIKE :menu", array(':path' => 'node/add', ':menu' => db_like('shortcut-set-') . '%'))->fetchField()) {
  $transaction = db_transaction();
  try {
    db_update('menu_links')
      ->fields(array('menu_name' => 'navigation', 'plid' => 0))
      ->condition('mlid', $mlid)
      ->execute();
    db_update('menu_links')
      ->fields(array('menu_name' => 'navigation', 'plid' => $mlid))
      ->condition('link_path', db_like('node/add/') . '%', 'LIKE')
      ->condition('menu_name', db_like('shortcut-set-') . '%', 'NOT LIKE')
      ->execute();
  }
  catch(Exception $e) {
    // One of the queries failed; rollback the database to the previous status.
    $transaction->rollback();
  }
}
else {
  // There isn't any row for node/add.
}

PS: As the only way to find the menu item is too look for its link path, there could be more than one row using that link path. It is important the code excludes those rows that are not the correct one, and that is what my code does when it excludes the rows there the menu name starts with shortcut-set-. Unfortunately, it is not possible to write code that generic enough to work in any condition.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.