Non-JS menu ordering fixes, also parent handling fixes. props filosofo, fixes #13135, fixes #13249

git-svn-id: http://svn.automattic.com/wordpress/trunk@14450 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
nacin 2010-05-04 19:40:04 +00:00
parent 37797d1dc9
commit eded683486
4 changed files with 152 additions and 77 deletions

View File

@ -15,7 +15,7 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
* @param string $output Passed by reference.
* @param int $depth Depth of page.
*/
function start_lvl(&$output, $depth) {}
function start_lvl(&$output) {}
/**
* @see Walker_Nav_Menu::end_lvl()
@ -24,7 +24,8 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
* @param string $output Passed by reference.
* @param int $depth Depth of page.
*/
function end_lvl(&$output, $depth) {}
function end_lvl(&$output) {
}
/**
* @see Walker::start_el()
@ -79,7 +80,7 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'move-item'
'move-menu_item'
);
?>" class="item-move-up"><abbr title="<?php esc_attr_e('Move up'); ?>">&#8593;</abbr></a>
|
@ -92,7 +93,7 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'move-item'
'move-menu_item'
);
?>" class="item-move-down"><abbr title="<?php esc_attr_e('Move down'); ?>">&#8595;</abbr></a>
</span>
@ -187,7 +188,7 @@ class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
<input class="menu-item-data-db-id" type="hidden" name="menu-item-db-id[<?php echo $item_id; ?>]" value="<?php echo $item_id; ?>" />
<input class="menu-item-data-object-id" type="hidden" name="menu-item-object-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->object_id ); ?>" />
<input class="menu-item-data-object" type="hidden" name="menu-item-object[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->object ); ?>" />
<input class="menu-item-data-parent-id" type="hidden" name="menu-item-parent-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->post_parent ); ?>" />
<input class="menu-item-data-parent-id" type="hidden" name="menu-item-parent-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->menu_item_parent ); ?>" />
<input class="menu-item-data-position" type="hidden" class="menu-item-position" name="menu-item-position[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->menu_order ); ?>" />
<input class="menu-item-data-type" type="hidden" name="menu-item-type[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->type ); ?>" />
</div><!-- .menu-item-settings-->

View File

@ -61,99 +61,165 @@ switch ( $action ) {
case 'move-down-menu-item' :
// moving down a menu item is the same as moving up the next in order
check_admin_referer( 'move-menu_item' );
$menu_item_id = (int) $_REQUEST['menu-item'];
$next_item_id = 0;
$menu_item_id = isset( $_REQUEST['menu-item'] ) ? (int) $_REQUEST['menu-item'] : 0;
if ( is_nav_menu_item( $menu_item_id ) ) {
$menus = isset( $_REQUEST['menu'] ) ? array( (int) $_REQUEST['menu'] ) : wp_get_object_terms( $menu_item_id, 'nav_menu', array( 'fields' => 'ids' ) );
if ( ! is_wp_error( $menus ) ) {
foreach( (array) $menus as $menu_id ) {
$move_down_ordered_menu_items = (array) wp_get_nav_menu_items( $menu_id );
while ( $next = array_shift( $move_down_ordered_menu_items ) ) {
if ( isset( $next->ID ) && $next->ID == $menu_item_id ) {
break;
if ( ! is_wp_error( $menus ) && ! empty( $menus[0] ) ) {
$menu_id = (int) $menus[0];
$ordered_menu_items = wp_get_nav_menu_items( $menu_id );
$menu_item_data = (array) wp_setup_nav_menu_item( get_post( $menu_item_id ) );
// setup the data we need in one pass through the array of menu items
$dbids_to_orders = array();
$orders_to_dbids = array();
foreach( (array) $ordered_menu_items as $ordered_menu_item_object ) {
if ( isset( $ordered_menu_item_object->ID ) ) {
if ( isset( $ordered_menu_item_object->menu_order ) ) {
$dbids_to_orders[$ordered_menu_item_object->ID] = $ordered_menu_item_object->menu_order;
$orders_to_dbids[$ordered_menu_item_object->menu_order] = $ordered_menu_item_object->ID;
}
}
}
if ( $following = array_shift( $move_down_ordered_menu_items ) ) {
$next_item_id = (int) $following->ID;
// get next in order
if (
isset( $orders_to_dbids[$dbids_to_orders[$menu_item_id] + 1] )
) {
$next_item_id = $orders_to_dbids[$dbids_to_orders[$menu_item_id] + 1];
$next_item_data = (array) wp_setup_nav_menu_item( get_post( $next_item_id ) );
// if not siblings of same parent, bubble menu item up but keep order
if (
! empty( $menu_item_data['menu_item_parent'] ) &&
(
empty( $next_item_data['menu_item_parent'] ) ||
$next_item_data['menu_item_parent'] != $menu_item_data['menu_item_parent']
)
) {
$parent_db_id = in_array( $menu_item_data['menu_item_parent'], $orders_to_dbids ) ? (int) $menu_item_data['menu_item_parent'] : 0;
$parent_object = wp_setup_nav_menu_item( get_post( $parent_db_id ) );
if ( ! is_wp_error( $parent_object ) ) {
$parent_data = (array) $parent_object;
$menu_item_data['menu_item_parent'] = $parent_data['menu_item_parent'];
update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
}
// make menu item a child of its next sibling
} else {
$next_item_data['menu_order'] = $next_item_data['menu_order'] - 1;
$menu_item_data['menu_order'] = $menu_item_data['menu_order'] + 1;
$menu_item_data['menu_item_parent'] = $next_item_data['ID'];
update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
wp_update_post($menu_item_data);
wp_update_post($next_item_data);
}
// the item is last but still has a parent, so bubble up
} elseif (
! empty( $menu_item_data['menu_item_parent'] ) &&
in_array( $menu_item_data['menu_item_parent'], $orders_to_dbids )
) {
$menu_item_data['menu_item_parent'] = (int) get_post_meta( $menu_item_data['menu_item_parent'], '_menu_item_menu_item_parent', true);
update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
}
}
}
// fall through to next case
break;
case 'move-up-menu-item' :
check_admin_referer( 'move-menu_item' );
$menu_item_id = empty( $next_item_id ) ? (int) $_REQUEST['menu-item'] : $next_item_id;
$menu_item_id = isset( $_REQUEST['menu-item'] ) ? (int) $_REQUEST['menu-item'] : 0;
if ( is_nav_menu_item( $menu_item_id ) ) {
$menus = isset( $_REQUEST['menu'] ) ? array( (int) $_REQUEST['menu'] ) : wp_get_object_terms( $menu_item_id, 'nav_menu', array( 'fields' => 'ids' ) );
if ( ! is_wp_error( $menus ) ) {
foreach( (array) $menus as $menu_id ) {
$ordered_menu_items = wp_get_nav_menu_items( $menu_id );
$menu_item_data = get_post( $menu_item_id , ARRAY_A );
if ( ! is_wp_error( $menus ) && ! empty( $menus[0] ) ) {
$menu_id = (int) $menus[0];
$ordered_menu_items = wp_get_nav_menu_items( $menu_id );
$menu_item_data = (array) wp_setup_nav_menu_item( get_post( $menu_item_id ) );
// setup the data we need in one pass through the array of menu items
$dbids_to_orders = array();
$orders_to_dbids = array();
$objectids_to_dbids = array();
$dbids_to_objectids = array();
foreach( (array) $ordered_menu_items as $ordered_menu_item_object ) {
if ( isset( $ordered_menu_item_object->ID ) ) {
if ( isset( $ordered_menu_item_object->menu_order ) ) {
$dbids_to_orders[$ordered_menu_item_object->ID] = $ordered_menu_item_object->menu_order;
$orders_to_dbids[$ordered_menu_item_object->menu_order] = $ordered_menu_item_object->ID;
}
$possible_object_id = (int) get_post_meta( $ordered_menu_item_object->ID, '_menu_item_object_id', true );
if ( ! empty( $possible_object_id ) ) {
$dbids_to_objectids[$ordered_menu_item_object->ID] = $possible_object_id;
$objectids_to_dbids[$possible_object_id] = $ordered_menu_item_object->ID;
}
// setup the data we need in one pass through the array of menu items
$dbids_to_orders = array();
$orders_to_dbids = array();
foreach( (array) $ordered_menu_items as $ordered_menu_item_object ) {
if ( isset( $ordered_menu_item_object->ID ) ) {
if ( isset( $ordered_menu_item_object->menu_order ) ) {
$dbids_to_orders[$ordered_menu_item_object->ID] = $ordered_menu_item_object->menu_order;
$orders_to_dbids[$ordered_menu_item_object->menu_order] = $ordered_menu_item_object->ID;
}
}
}
// if this menu item is not first
if ( ! empty( $dbids_to_orders[$menu_item_id] ) && ! empty( $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] ) ) {
// if this menu item is not first
if ( ! empty( $dbids_to_orders[$menu_item_id] ) && ! empty( $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] ) ) {
// if this menu item is a child of the previous
if (
! empty( $menu_item_data['post_parent'] ) &&
isset( $objectids_to_dbids[$menu_item_data['post_parent']] ) &&
isset( $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] ) &&
( $objectids_to_dbids[$menu_item_data['post_parent']] == $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] )
) {
// if this menu item is a child of the previous
if (
! empty( $menu_item_data['menu_item_parent'] ) &&
in_array( $menu_item_data['menu_item_parent'], array_keys( $dbids_to_orders ) ) &&
isset( $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] ) &&
( $menu_item_data['menu_item_parent'] == $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] )
) {
$parent_db_id = in_array( $menu_item_data['menu_item_parent'], $orders_to_dbids ) ? (int) $menu_item_data['menu_item_parent'] : 0;
$parent_object = wp_setup_nav_menu_item( get_post( $parent_db_id ) );
$parent_db_id = $objectids_to_dbids[$menu_item_data['post_parent']];
$parent_data = get_post( $parent_db_id, ARRAY_A );
if ( ! is_wp_error( $parent_object ) ) {
$parent_data = (array) $parent_object;
if ( ! is_wp_error( $parent_data ) ) {
// if there is something before the parent and parent a child of it, make menu item a child also of it
if (
! empty( $dbids_to_orders[$parent_db_id] ) &&
! empty( $orders_to_dbids[$dbids_to_orders[$parent_db_id] - 1] ) &&
! empty( $parent_data['menu_item_parent'] )
) {
$menu_item_data['menu_item_parent'] = $parent_data['menu_item_parent'];
// if there is something before the parent, make menu item a child of the parent's parent
if ( ! empty( $dbids_to_orders[$parent_db_id] ) && ! empty( $orders_to_dbids[$dbids_to_orders[$parent_db_id] - 1] ) ) {
$menu_item_data['post_parent'] = $parent_data['post_parent'];
// else if there is something before parent and parent not a child of it, make menu item a child of that something's parent
} elseif (
! empty( $dbids_to_orders[$parent_db_id] ) &&
! empty( $orders_to_dbids[$dbids_to_orders[$parent_db_id] - 1] )
) {
$_possible_parent_id = (int) get_post_meta( $orders_to_dbids[$dbids_to_orders[$parent_db_id] - 1], '_menu_item_menu_item_parent', true);
if ( in_array( $_possible_parent_id, array_keys( $dbids_to_orders ) ) )
$menu_item_data['menu_item_parent'] = $_possible_parent_id;
else
$menu_item_data['menu_item_parent'] = 0;
// else there isn't something before the parent
} else {
$menu_item_data['post_parent'] = 0;
}
// set former parent's [menu_order] to that of menu-item's
$parent_data['menu_order'] = $parent_data['menu_order'] + 1;
// set menu-item's [menu_order] to that of former parent
$menu_item_data['menu_order'] = $menu_item_data['menu_order'] - 1;
// save changes
wp_update_post($menu_item_data);
wp_update_post($parent_data);
// else there isn't something before the parent
} else {
$menu_item_data['menu_item_parent'] = 0;
}
// else this menu item is not a child of the previous
} elseif ( isset($dbids_to_objectids[$orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1]] ) ) {
// just make it a child of the previous; keep the order
$menu_item_data['post_parent'] = (int) $dbids_to_objectids[$orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1]];
// set former parent's [menu_order] to that of menu-item's
$parent_data['menu_order'] = $parent_data['menu_order'] + 1;
// set menu-item's [menu_order] to that of former parent
$menu_item_data['menu_order'] = $menu_item_data['menu_order'] - 1;
// save changes
update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
wp_update_post($menu_item_data);
wp_update_post($parent_data);
}
// else this menu item is not a child of the previous
} elseif (
empty( $menu_item_data['menu_order'] ) ||
empty( $menu_item_data['menu_item_parent'] ) ||
! in_array( $menu_item_data['menu_item_parent'], array_keys( $dbids_to_orders ) ) ||
empty( $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] ) ||
$orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] != $menu_item_data['menu_item_parent']
) {
// just make it a child of the previous; keep the order
$menu_item_data['menu_item_parent'] = (int) $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1];
update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
wp_update_post($menu_item_data);
}
}
}

View File

@ -28,7 +28,7 @@ class Walker_Nav_Menu extends Walker {
* @todo Decouple this.
* @var array
*/
var $db_fields = array( 'parent' => 'post_parent', 'id' => 'object_id' );
var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
/**
* @see Walker::start_lvl()
@ -137,7 +137,6 @@ class Walker_Nav_Menu_Checklist extends Walker_Nav_Menu {
$_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
$possible_object_id = isset( $item->post_type ) && 'nav_menu_item' == $item->post_type ? $item->object_id : $_nav_menu_placeholder;
$possible_db_id = ( ! empty( $item->ID ) ) && ( 0 < $possible_object_id ) ? (int) $item->ID : 0;
$possible_parent_id = ( ! empty( $item->ID ) ) && ( 0 < $possible_object_id ) ? (int) $item->post_parent : 0;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
@ -157,7 +156,7 @@ class Walker_Nav_Menu_Checklist extends Walker_Nav_Menu {
// Menu item hidden fields
$output .= '<input type="hidden" class="menu-item-db-id" name="menu-item[' . $possible_object_id . '][menu-item-db-id]" value="' . $possible_db_id . '" />';
$output .= '<input type="hidden" class="menu-item-object" name="menu-item[' . $possible_object_id . '][menu-item-object]" value="'. esc_attr( $item->object ) .'" />';
$output .= '<input type="hidden" class="menu-item-parent-id" name="menu-item[' . $possible_object_id . '][menu-item-parent-id]" value="'. $possible_parent_id .'" />';
$output .= '<input type="hidden" class="menu-item-parent-id" name="menu-item[' . $possible_object_id . '][menu-item-parent-id]" value="'. esc_attr( $item->menu_item_parent ) .'" />';
$output .= '<input type="hidden" class="menu-item-type" name="menu-item[' . $possible_object_id . '][menu-item-type]" value="'. esc_attr( $item->type ) .'" />';
$output .= '<input type="hidden" class="menu-item-append" name="menu-item[' . $possible_object_id . '][menu-item-append]" value="'. esc_attr( $item->append ) .'" />';
$output .= '<input type="hidden" class="menu-item-title" name="menu-item[' . $possible_object_id . '][menu-item-title]" value="'. esc_attr( $item->title ) .'" />';

View File

@ -256,6 +256,8 @@ function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item
}
}
$original_parent = 0 < $menu_item_db_id ? get_post_field( 'post_parent', $menu_item_db_id ) : 0;
if ( 'custom' != $args['menu-item-type'] ) {
/* if non-custom menu item, then:
* use original object's URL
@ -266,10 +268,12 @@ function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item
$original_title = '';
if ( 'taxonomy' == $args['menu-item-type'] ) {
$original_parent = get_term_field( 'parent', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' );
$original_title = get_term_field( 'name', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' );
} elseif ( 'post_type' == $args['menu-item-type'] ) {
$original_object = get_post( $args['menu-item-object-id'] );
$original_parent = (int) $original_object->post_parent;
$original_title = $original_object->post_title;
if ( 'trash' == get_post_status( $args['menu-item-object-id'] ) ) {
@ -297,7 +301,7 @@ function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item
'ping_status' => 0,
'post_content' => $args['menu-item-description'],
'post_excerpt' => $args['menu-item-attr-title'],
'post_parent' => $args['menu-item-parent-id'],
'post_parent' => $original_parent,
'post_title' => $args['menu-item-title'],
'post_type' => 'nav_menu_item',
'tax_input' => array( 'nav_menu' => $menu->name ),
@ -326,6 +330,7 @@ function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item
$menu_item_db_id = (int) $menu_item_db_id;
update_post_meta( $menu_item_db_id, '_menu_item_type', sanitize_key($args['menu-item-type']) );
update_post_meta( $menu_item_db_id, '_menu_item_menu_item_parent', (int) $args['menu-item-parent-id'] );
update_post_meta( $menu_item_db_id, '_menu_item_object_id', (int) $args['menu-item-object-id'] );
update_post_meta( $menu_item_db_id, '_menu_item_object', sanitize_key($args['menu-item-object']) );
update_post_meta( $menu_item_db_id, '_menu_item_target', sanitize_key($args['menu-item-target']) );
@ -439,12 +444,13 @@ function wp_get_nav_menu_items( $menu, $args = array() ) {
* Decorates a menu item object with the shared navigation menu item properties.
*
* Properties:
* - db_id: The DB ID of the this item as a nav_menu_item object, if it exists (0 if it doesn't exist).
* - db_id: The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn't exist).
* - object_id: The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories.
* - type: The family of objects originally represented, such as "post_type" or "taxonomy."
* - object: The type of object originally represented, such as "category," "post", or "attachment."
* - append: The singular label used to describe this type of menu item.
* - parent: The DB ID of the original object's parent object, if any (0 otherwise).
* - post_parent: The DB ID of the original object's parent object, if any (0 otherwise).
* - menu_item_parent: The DB ID of the nav_menu_item that is this item's menu parent, if any. 0 otherwise.
* - url: The URL to which this menu item points.
* - title: The title of this menu item.
* - target: The target attribute of the link element for this menu item.
@ -462,6 +468,7 @@ function wp_setup_nav_menu_item( $menu_item ) {
if ( isset( $menu_item->post_type ) ) {
if ( 'nav_menu_item' == $menu_item->post_type ) {
$menu_item->db_id = (int) $menu_item->ID;
$menu_item->menu_item_parent = get_post_meta( $menu_item->ID, '_menu_item_menu_item_parent', true );
$menu_item->object_id = get_post_meta( $menu_item->ID, '_menu_item_object_id', true );
$menu_item->object = get_post_meta( $menu_item->ID, '_menu_item_object', true );
$menu_item->type = get_post_meta( $menu_item->ID, '_menu_item_type', true );
@ -498,6 +505,7 @@ function wp_setup_nav_menu_item( $menu_item ) {
$menu_item->xfn = get_post_meta( $menu_item->ID, '_menu_item_xfn', true );
} else {
$menu_item->db_id = 0;
$menu_item->menu_item_parent = 0;
$menu_item->object_id = (int) $menu_item->ID;
$menu_item->type = 'post_type';
@ -517,6 +525,7 @@ function wp_setup_nav_menu_item( $menu_item ) {
} elseif ( isset( $menu_item->taxonomy ) ) {
$menu_item->ID = $menu_item->term_id;
$menu_item->db_id = 0;
$menu_item->menu_item_parent = 0;
$menu_item->object_id = (int) $menu_item->term_id;
$menu_item->post_parent = (int) $menu_item->parent;
$menu_item->type = 'taxonomy';