Wordpress/wp-admin/includes/nav-menu.php
Mark Jaquith c2945a394f Improve the UX of the Nav Menus screen. Kill the tabs, and change to a
dropdown, unless you have zero or one menus (which is the most common),
in which case you jump right into editing your sole menu.

Do assignment to location using checkboxes in the main menu editing
section instead of the backwards menu => location assignment in a
random meta box.

More to come, but this gets us started.

props lessbloat, DrewAPicture, jkudish. see #23119

git-svn-id: https://develop.svn.wordpress.org/trunk@23441 602fd350-edb4-49c9-b593-d223f7449a82
2013-02-16 04:53:59 +00:00

1298 lines
50 KiB
PHP

<?php
/**
* Create HTML list of nav menu input items.
*
* @package WordPress
* @since 3.0.0
* @uses Walker_Nav_Menu
*/
class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
/**
* @see Walker_Nav_Menu::start_lvl()
* @since 3.0.0
*
* @param string $output Passed by reference.
*/
function start_lvl(&$output) {}
/**
* @see Walker_Nav_Menu::end_lvl()
* @since 3.0.0
*
* @param string $output Passed by reference.
*/
function end_lvl(&$output) {
}
/**
* @see Walker::start_el()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
* @param object $args
*/
function start_el(&$output, $item, $depth, $args) {
global $_wp_nav_menu_max_depth;
$_wp_nav_menu_max_depth = $depth > $_wp_nav_menu_max_depth ? $depth : $_wp_nav_menu_max_depth;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
ob_start();
$item_id = esc_attr( $item->ID );
$removed_args = array(
'action',
'customlink-tab',
'edit-menu-item',
'menu-item',
'page-tab',
'_wpnonce',
);
$original_title = '';
if ( 'taxonomy' == $item->type ) {
$original_title = get_term_field( 'name', $item->object_id, $item->object, 'raw' );
if ( is_wp_error( $original_title ) )
$original_title = false;
} elseif ( 'post_type' == $item->type ) {
$original_object = get_post( $item->object_id );
$original_title = $original_object->post_title;
}
$classes = array(
'menu-item menu-item-depth-' . $depth,
'menu-item-' . esc_attr( $item->object ),
'menu-item-edit-' . ( ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? 'active' : 'inactive'),
);
$title = $item->title;
if ( ! empty( $item->_invalid ) ) {
$classes[] = 'menu-item-invalid';
/* translators: %s: title of menu item which is invalid */
$title = sprintf( __( '%s (Invalid)' ), $item->title );
} elseif ( isset( $item->post_status ) && 'draft' == $item->post_status ) {
$classes[] = 'pending';
/* translators: %s: title of menu item in draft status */
$title = sprintf( __('%s (Pending)'), $item->title );
}
$title = empty( $item->label ) ? $title : $item->label;
$submenu_text = '';
if ( 0 == $depth )
$submenu_text = 'style="display: none;"';
?>
<li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes ); ?>">
<dl class="menu-item-bar">
<dt class="menu-item-handle">
<span class="item-title"><?php echo esc_html( $title ); ?> <span class="is-submenu" <?php echo $submenu_text; ?>><?php _e( 'sub item' ); ?></span></span>
<span class="item-controls">
<span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
<span class="item-order hide-if-js">
<a href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'move-up-menu-item',
'menu-item' => $item_id,
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'move-menu_item'
);
?>" class="item-move-up"><abbr title="<?php esc_attr_e('Move up'); ?>">&#8593;</abbr></a>
|
<a href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'move-down-menu-item',
'menu-item' => $item_id,
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'move-menu_item'
);
?>" class="item-move-down"><abbr title="<?php esc_attr_e('Move down'); ?>">&#8595;</abbr></a>
</span>
<a class="item-edit" id="edit-<?php echo $item_id; ?>" title="<?php esc_attr_e('Edit Menu Item'); ?>" href="<?php
echo ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? admin_url( 'nav-menus.php' ) : add_query_arg( 'edit-menu-item', $item_id, remove_query_arg( $removed_args, admin_url( 'nav-menus.php#menu-item-settings-' . $item_id ) ) );
?>"><?php _e( 'Edit Menu Item' ); ?></a>
</span>
</dt>
</dl>
<div class="menu-item-settings" id="menu-item-settings-<?php echo $item_id; ?>">
<?php if( 'custom' == $item->type ) : ?>
<p class="field-url description description-wide">
<label for="edit-menu-item-url-<?php echo $item_id; ?>">
<?php _e( 'URL' ); ?><br />
<input type="text" id="edit-menu-item-url-<?php echo $item_id; ?>" class="widefat code edit-menu-item-url" name="menu-item-url[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->url ); ?>" />
</label>
</p>
<?php endif; ?>
<p class="description description-thin">
<label for="edit-menu-item-title-<?php echo $item_id; ?>">
<?php _e( 'Navigation Label' ); ?><br />
<input type="text" id="edit-menu-item-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-title" name="menu-item-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->title ); ?>" />
</label>
</p>
<p class="description description-thin">
<label for="edit-menu-item-attr-title-<?php echo $item_id; ?>">
<?php _e( 'Title Attribute' ); ?><br />
<input type="text" id="edit-menu-item-attr-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-attr-title" name="menu-item-attr-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->post_excerpt ); ?>" />
</label>
</p>
<p class="field-link-target description">
<label for="edit-menu-item-target-<?php echo $item_id; ?>">
<input type="checkbox" id="edit-menu-item-target-<?php echo $item_id; ?>" value="_blank" name="menu-item-target[<?php echo $item_id; ?>]"<?php checked( $item->target, '_blank' ); ?> />
<?php _e( 'Open link in a new window/tab' ); ?>
</label>
</p>
<p class="field-css-classes description description-thin">
<label for="edit-menu-item-classes-<?php echo $item_id; ?>">
<?php _e( 'CSS Classes (optional)' ); ?><br />
<input type="text" id="edit-menu-item-classes-<?php echo $item_id; ?>" class="widefat code edit-menu-item-classes" name="menu-item-classes[<?php echo $item_id; ?>]" value="<?php echo esc_attr( implode(' ', $item->classes ) ); ?>" />
</label>
</p>
<p class="field-xfn description description-thin">
<label for="edit-menu-item-xfn-<?php echo $item_id; ?>">
<?php _e( 'Link Relationship (XFN)' ); ?><br />
<input type="text" id="edit-menu-item-xfn-<?php echo $item_id; ?>" class="widefat code edit-menu-item-xfn" name="menu-item-xfn[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->xfn ); ?>" />
</label>
</p>
<p class="field-description description description-wide">
<label for="edit-menu-item-description-<?php echo $item_id; ?>">
<?php _e( 'Description' ); ?><br />
<textarea id="edit-menu-item-description-<?php echo $item_id; ?>" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html( $item->description ); // textarea_escaped ?></textarea>
<span class="description"><?php _e('The description will be displayed in the menu if the current theme supports it.'); ?></span>
</label>
</p>
<div class="menu-item-actions description-wide submitbox">
<?php if( 'custom' != $item->type && $original_title !== false ) : ?>
<p class="link-to-original">
<?php printf( __('Original: %s'), '<a href="' . esc_attr( $item->url ) . '">' . esc_html( $original_title ) . '</a>' ); ?>
</p>
<?php endif; ?>
<a class="item-delete submitdelete deletion" id="delete-<?php echo $item_id; ?>" href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'delete-menu-item',
'menu-item' => $item_id,
),
admin_url( 'nav-menus.php' )
),
'delete-menu_item_' . $item_id
); ?>"><?php _e( 'Remove' ); ?></a> <span class="meta-sep hide-if-no-js"> | </span> <a class="item-cancel submitcancel hide-if-no-js" id="cancel-<?php echo $item_id; ?>" href="<?php echo esc_url( add_query_arg( array( 'edit-menu-item' => $item_id, 'cancel' => time() ), admin_url( 'nav-menus.php' ) ) );
?>#menu-item-settings-<?php echo $item_id; ?>"><?php _e('Cancel'); ?></a>
</div>
<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->menu_item_parent ); ?>" />
<input class="menu-item-data-position" type="hidden" 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-->
<ul class="menu-item-transport"></ul>
<?php
$output .= ob_get_clean();
}
}
/**
* Create HTML list of nav menu input items.
*
* @package WordPress
* @since 3.0.0
* @uses Walker_Nav_Menu
*/
class Walker_Nav_Menu_Checklist extends Walker_Nav_Menu {
function __construct( $fields = false ) {
if ( $fields ) {
$this->db_fields = $fields;
}
}
function start_lvl( &$output, $depth ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent<ul class='children'>\n";
}
function end_lvl( &$output, $depth ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent</ul>";
}
/**
* @see Walker::start_el()
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
* @param object $args
*/
function start_el(&$output, $item, $depth, $args) {
global $_nav_menu_placeholder;
$_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;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$output .= $indent . '<li>';
$output .= '<label class="menu-item-title">';
$output .= '<input type="checkbox" class="menu-item-checkbox';
if ( property_exists( $item, 'front_or_home' ) && $item->front_or_home ) {
$title = sprintf( _x( 'Home: %s', 'nav menu front page title' ), $item->post_title );
$output .= ' add-to-top';
}
$output .= '" name="menu-item[' . $possible_object_id . '][menu-item-object-id]" value="'. esc_attr( $item->object_id ) .'" /> ';
$output .= isset( $title ) ? esc_html( $title ) : esc_html( $item->title );
$output .= '</label>';
// 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="'. 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-title" name="menu-item[' . $possible_object_id . '][menu-item-title]" value="'. esc_attr( $item->title ) .'" />';
$output .= '<input type="hidden" class="menu-item-url" name="menu-item[' . $possible_object_id . '][menu-item-url]" value="'. esc_attr( $item->url ) .'" />';
$output .= '<input type="hidden" class="menu-item-target" name="menu-item[' . $possible_object_id . '][menu-item-target]" value="'. esc_attr( $item->target ) .'" />';
$output .= '<input type="hidden" class="menu-item-attr_title" name="menu-item[' . $possible_object_id . '][menu-item-attr_title]" value="'. esc_attr( $item->attr_title ) .'" />';
$output .= '<input type="hidden" class="menu-item-classes" name="menu-item[' . $possible_object_id . '][menu-item-classes]" value="'. esc_attr( implode( ' ', $item->classes ) ) .'" />';
$output .= '<input type="hidden" class="menu-item-xfn" name="menu-item[' . $possible_object_id . '][menu-item-xfn]" value="'. esc_attr( $item->xfn ) .'" />';
}
}
/**
* Prints the appropriate response to a menu quick search.
*
* @since 3.0.0
*
* @param array $request The unsanitized request values.
*/
function _wp_ajax_menu_quick_search( $request = array() ) {
$args = array();
$type = isset( $request['type'] ) ? $request['type'] : '';
$object_type = isset( $request['object_type'] ) ? $request['object_type'] : '';
$query = isset( $request['q'] ) ? $request['q'] : '';
$response_format = isset( $request['response-format'] ) && in_array( $request['response-format'], array( 'json', 'markup' ) ) ? $request['response-format'] : 'json';
if ( 'markup' == $response_format ) {
$args['walker'] = new Walker_Nav_Menu_Checklist;
}
if ( 'get-post-item' == $type ) {
if ( post_type_exists( $object_type ) ) {
if ( isset( $request['ID'] ) ) {
$object_id = (int) $request['ID'];
if ( 'markup' == $response_format ) {
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_post( $object_id ) ) ), 0, (object) $args );
} elseif ( 'json' == $response_format ) {
$post_obj = get_post( $object_id );
echo json_encode(
array(
'ID' => $object_id,
'post_title' => get_the_title( $object_id ),
'post_type' => get_post_type( $object_id ),
)
);
echo "\n";
}
}
} elseif ( taxonomy_exists( $object_type ) ) {
if ( isset( $request['ID'] ) ) {
$object_id = (int) $request['ID'];
if ( 'markup' == $response_format ) {
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_term( $object_id, $object_type ) ) ), 0, (object) $args );
} elseif ( 'json' == $response_format ) {
$post_obj = get_term( $object_id, $object_type );
echo json_encode(
array(
'ID' => $object_id,
'post_title' => $post_obj->name,
'post_type' => $object_type,
)
);
echo "\n";
}
}
}
} elseif ( preg_match('/quick-search-(posttype|taxonomy)-([a-zA-Z_-]*\b)/', $type, $matches) ) {
if ( 'posttype' == $matches[1] && get_post_type_object( $matches[2] ) ) {
query_posts(array(
'posts_per_page' => 10,
'post_type' => $matches[2],
's' => $query,
));
if ( ! have_posts() )
return;
while ( have_posts() ) {
the_post();
if ( 'markup' == $response_format ) {
$var_by_ref = get_the_ID();
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_post( $var_by_ref ) ) ), 0, (object) $args );
} elseif ( 'json' == $response_format ) {
echo json_encode(
array(
'ID' => get_the_ID(),
'post_title' => get_the_title(),
'post_type' => get_post_type(),
)
);
echo "\n";
}
}
} elseif ( 'taxonomy' == $matches[1] ) {
$terms = get_terms( $matches[2], array(
'name__like' => $query,
'number' => 10,
));
if ( empty( $terms ) || is_wp_error( $terms ) )
return;
foreach( (array) $terms as $term ) {
if ( 'markup' == $response_format ) {
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( $term ) ), 0, (object) $args );
} elseif ( 'json' == $response_format ) {
echo json_encode(
array(
'ID' => $term->term_id,
'post_title' => $term->name,
'post_type' => $matches[2],
)
);
echo "\n";
}
}
}
}
}
/**
* Register nav menu metaboxes and advanced menu items
*
* @since 3.0.0
**/
function wp_nav_menu_setup() {
// Register meta boxes
wp_nav_menu_post_type_meta_boxes();
add_meta_box( 'add-custom-links', __( 'Add Links' ), 'wp_nav_menu_item_link_meta_box', 'nav-menus', 'side', 'default' );
wp_nav_menu_taxonomy_meta_boxes();
// Register advanced menu items (columns)
add_filter( 'manage_nav-menus_columns', 'wp_nav_menu_manage_columns');
// If first time editing, disable advanced items by default.
if( false === get_user_option( 'managenav-menuscolumnshidden' ) ) {
$user = wp_get_current_user();
update_user_option($user->ID, 'managenav-menuscolumnshidden',
array( 0 => 'link-target', 1 => 'css-classes', 2 => 'xfn', 3 => 'description', ),
true);
}
}
/**
* Limit the amount of meta boxes to just links, pages and cats for first time users.
*
* @since 3.0.0
**/
function wp_initial_nav_menu_meta_boxes() {
global $wp_meta_boxes;
if ( get_user_option( 'metaboxhidden_nav-menus' ) !== false || ! is_array($wp_meta_boxes) )
return;
$initial_meta_boxes = array( 'nav-menu-theme-locations', 'add-page', 'add-custom-links', 'add-category' );
$hidden_meta_boxes = array();
foreach ( array_keys($wp_meta_boxes['nav-menus']) as $context ) {
foreach ( array_keys($wp_meta_boxes['nav-menus'][$context]) as $priority ) {
foreach ( $wp_meta_boxes['nav-menus'][$context][$priority] as $box ) {
if ( in_array( $box['id'], $initial_meta_boxes ) ) {
unset( $box['id'] );
} else {
$hidden_meta_boxes[] = $box['id'];
}
}
}
}
$user = wp_get_current_user();
update_user_option( $user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true );
}
/**
* Creates metaboxes for any post type menu item.
*
* @since 3.0.0
*/
function wp_nav_menu_post_type_meta_boxes() {
$post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
if ( ! $post_types )
return;
foreach ( $post_types as $post_type ) {
$post_type = apply_filters( 'nav_menu_meta_box_object', $post_type );
if ( $post_type ) {
$id = $post_type->name;
add_meta_box( "add-{$id}", $post_type->labels->name, 'wp_nav_menu_item_post_type_meta_box', 'nav-menus', 'side', 'default', $post_type );
}
}
}
/**
* Creates metaboxes for any taxonomy menu item.
*
* @since 3.0.0
*/
function wp_nav_menu_taxonomy_meta_boxes() {
$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'object' );
if ( !$taxonomies )
return;
foreach ( $taxonomies as $tax ) {
$tax = apply_filters( 'nav_menu_meta_box_object', $tax );
if ( $tax ) {
$id = $tax->name;
add_meta_box( "add-{$id}", $tax->labels->name, 'wp_nav_menu_item_taxonomy_meta_box', 'nav-menus', 'side', 'default', $tax );
}
}
}
/**
* Displays a metabox for the nav menu theme locations.
*
* @since 3.0.0
*/
function wp_nav_menu_locations_meta_box() {
global $nav_menu_selected_id;
if ( ! current_theme_supports( 'menus' ) ) {
// We must only support widgets. Leave a message and bail.
echo '<p class="howto">' . __('The current theme does not natively support menus, but you can use the &#8220;Custom Menu&#8221; widget to add any menus you create here to the theme&#8217;s sidebar.') . '</p>';
return;
}
$locations = get_registered_nav_menus();
$menus = wp_get_nav_menus();
$menu_locations = get_nav_menu_locations();
$num_locations = count( array_keys($locations) );
echo '<p class="howto">' . _n( 'Select a menu to use within your theme.', 'Select the menus you will use in your theme.', $num_locations ) . '</p>';
foreach ( $locations as $location => $description ) {
?>
<p>
<label class="howto" for="locations-<?php echo $location; ?>">
<span><?php echo $description; ?></span>
<select name="menu-locations[<?php echo $location; ?>]" id="locations-<?php echo $location; ?>">
<option value="0"></option>
<?php foreach ( $menus as $menu ) : ?>
<option<?php selected( isset( $menu_locations[ $location ] ) && $menu_locations[ $location ] == $menu->term_id ); ?>
value="<?php echo $menu->term_id; ?>"><?php
$truncated_name = wp_html_excerpt( $menu->name, 40 );
echo $truncated_name == $menu->name ? $menu->name : trim( $truncated_name ) . '&hellip;';
?></option>
<?php endforeach; ?>
</select>
</label>
</p>
<?php
}
?>
<p class="button-controls">
<?php submit_button( __( 'Save' ), 'primary right', 'nav-menu-locations', false, wp_nav_menu_disabled_check( $nav_menu_selected_id ) ); ?>
<span class="spinner"></span>
</p>
<?php
}
/**
* Check whether to disable the Menu Locations meta box submit button
*
* @since 3.6.0
*
* @uses global $one_theme_location_no_menus to determine if no menus exist
* @uses disabled() to output the disabled attribute in $other_attributes param in submit_button()
*
* @param int|string $nav_menu_selected_id (id, name or slug) of the currently-selected menu
* @return string Disabled attribute if at least one menu exists, false if not
*/
function wp_nav_menu_disabled_check( $nav_menu_selected_id ) {
global $one_theme_location_no_menus;
if ( $one_theme_location_no_menus )
return false;
return disabled( $nav_menu_selected_id, 0 );
}
/**
* Displays a metabox for the custom links menu item.
*
* @since 3.0.0
*/
function wp_nav_menu_item_link_meta_box() {
global $_nav_menu_placeholder, $nav_menu_selected_id;
$_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1;
$current_tab = 'create';
if ( isset( $_REQUEST['customlink-tab'] ) && in_array( $_REQUEST['customlink-tab'], array('create', 'all') ) ) {
$current_tab = $_REQUEST['customlink-tab'];
}
$removed_args = array(
'action',
'customlink-tab',
'edit-menu-item',
'menu-item',
'page-tab',
'_wpnonce',
);
?>
<div class="customlinkdiv" id="customlinkdiv">
<input type="hidden" value="custom" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" />
<p id="menu-item-url-wrap">
<label class="howto" for="custom-menu-item-url">
<span><?php _e('URL'); ?></span>
<input id="custom-menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" type="text" class="code menu-item-textbox" value="http://" />
</label>
</p>
<p id="menu-item-name-wrap">
<label class="howto" for="custom-menu-item-name">
<span><?php _e( 'Link Text' ); ?></span>
<input id="custom-menu-item-name" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-title]" type="text" class="regular-text menu-item-textbox input-with-default-title" title="<?php esc_attr_e('Menu Item'); ?>" />
</label>
</p>
<p class="button-controls">
<span class="add-to-menu">
<input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e('Add to Menu'); ?>" name="add-custom-menu-item" id="submit-customlinkdiv" />
<span class="spinner"></span>
</span>
</p>
</div><!-- /.customlinkdiv -->
<?php
}
/**
* Displays a metabox for a post type menu item.
*
* @since 3.0.0
*
* @param string $object Not used.
* @param string $post_type The post type object.
*/
function wp_nav_menu_item_post_type_meta_box( $object, $post_type ) {
global $_nav_menu_placeholder, $nav_menu_selected_id;
$post_type_name = $post_type['args']->name;
// paginate browsing for large numbers of post objects
$per_page = 50;
$pagenum = isset( $_REQUEST[$post_type_name . '-tab'] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
$offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
$args = array(
'offset' => $offset,
'order' => 'ASC',
'orderby' => 'title',
'posts_per_page' => $per_page,
'post_type' => $post_type_name,
'suppress_filters' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false
);
if ( isset( $post_type['args']->_default_query ) )
$args = array_merge($args, (array) $post_type['args']->_default_query );
// @todo transient caching of these results with proper invalidation on updating of a post of this type
$get_posts = new WP_Query;
$posts = $get_posts->query( $args );
if ( ! $get_posts->post_count ) {
echo '<p>' . __( 'No items.' ) . '</p>';
return;
}
$post_type_object = get_post_type_object($post_type_name);
$num_pages = $get_posts->max_num_pages;
$page_links = paginate_links( array(
'base' => add_query_arg(
array(
$post_type_name . '-tab' => 'all',
'paged' => '%#%',
'item-type' => 'post_type',
'item-object' => $post_type_name,
)
),
'format' => '',
'prev_text' => __('&laquo;'),
'next_text' => __('&raquo;'),
'total' => $num_pages,
'current' => $pagenum
));
if ( !$posts )
$error = '<li id="error">'. $post_type['args']->labels->not_found .'</li>';
$db_fields = false;
if ( is_post_type_hierarchical( $post_type_name ) ) {
$db_fields = array( 'parent' => 'post_parent', 'id' => 'ID' );
}
$walker = new Walker_Nav_Menu_Checklist( $db_fields );
$current_tab = 'most-recent';
if ( isset( $_REQUEST[$post_type_name . '-tab'] ) && in_array( $_REQUEST[$post_type_name . '-tab'], array('all', 'search') ) ) {
$current_tab = $_REQUEST[$post_type_name . '-tab'];
}
if ( ! empty( $_REQUEST['quick-search-posttype-' . $post_type_name] ) ) {
$current_tab = 'search';
}
$removed_args = array(
'action',
'customlink-tab',
'edit-menu-item',
'menu-item',
'page-tab',
'_wpnonce',
);
?>
<div id="posttype-<?php echo $post_type_name; ?>" class="posttypediv">
<ul id="posttype-<?php echo $post_type_name; ?>-tabs" class="posttype-tabs add-menu-item-tabs">
<li <?php echo ( 'most-recent' == $current_tab ? ' class="tabs"' : '' ); ?>><a class="nav-tab-link" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($post_type_name . '-tab', 'most-recent', remove_query_arg($removed_args))); ?>#tabs-panel-posttype-<?php echo $post_type_name; ?>-most-recent"><?php _e('Most Recent'); ?></a></li>
<li <?php echo ( 'all' == $current_tab ? ' class="tabs"' : '' ); ?>><a class="nav-tab-link" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($post_type_name . '-tab', 'all', remove_query_arg($removed_args))); ?>#<?php echo $post_type_name; ?>-all"><?php _e('View All'); ?></a></li>
<li <?php echo ( 'search' == $current_tab ? ' class="tabs"' : '' ); ?>><a class="nav-tab-link" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($post_type_name . '-tab', 'search', remove_query_arg($removed_args))); ?>#tabs-panel-posttype-<?php echo $post_type_name; ?>-search"><?php _e('Search'); ?></a></li>
</ul>
<div id="tabs-panel-posttype-<?php echo $post_type_name; ?>-most-recent" class="tabs-panel <?php
echo ( 'most-recent' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
?>">
<ul id="<?php echo $post_type_name; ?>checklist-most-recent" class="categorychecklist form-no-clear">
<?php
$recent_args = array_merge( $args, array( 'orderby' => 'post_date', 'order' => 'DESC', 'posts_per_page' => 15 ) );
$most_recent = $get_posts->query( $recent_args );
$args['walker'] = $walker;
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $most_recent), 0, (object) $args );
?>
</ul>
</div><!-- /.tabs-panel -->
<div class="tabs-panel <?php
echo ( 'search' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
?>" id="tabs-panel-posttype-<?php echo $post_type_name; ?>-search">
<?php
if ( isset( $_REQUEST['quick-search-posttype-' . $post_type_name] ) ) {
$searched = esc_attr( $_REQUEST['quick-search-posttype-' . $post_type_name] );
$search_results = get_posts( array( 's' => $searched, 'post_type' => $post_type_name, 'fields' => 'all', 'order' => 'DESC', ) );
} else {
$searched = '';
$search_results = array();
}
?>
<p class="quick-search-wrap">
<input type="search" class="quick-search input-with-default-title" title="<?php esc_attr_e('Search'); ?>" value="<?php echo $searched; ?>" name="quick-search-posttype-<?php echo $post_type_name; ?>" />
<span class="spinner"></span>
<?php submit_button( __( 'Search' ), 'button-small quick-search-submit button-secondary hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-posttype-' . $post_type_name ) ); ?>
</p>
<ul id="<?php echo $post_type_name; ?>-search-checklist" data-wp-lists="list:<?php echo $post_type_name?>" class="categorychecklist form-no-clear">
<?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
<?php
$args['walker'] = $walker;
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $search_results), 0, (object) $args );
?>
<?php elseif ( is_wp_error( $search_results ) ) : ?>
<li><?php echo $search_results->get_error_message(); ?></li>
<?php elseif ( ! empty( $searched ) ) : ?>
<li><?php _e('No results found.'); ?></li>
<?php endif; ?>
</ul>
</div><!-- /.tabs-panel -->
<div id="<?php echo $post_type_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php
echo ( 'all' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
?>">
<?php if ( ! empty( $page_links ) ) : ?>
<div class="add-menu-item-pagelinks">
<?php echo $page_links; ?>
</div>
<?php endif; ?>
<ul id="<?php echo $post_type_name; ?>checklist" data-wp-lists="list:<?php echo $post_type_name?>" class="categorychecklist form-no-clear">
<?php
$args['walker'] = $walker;
// if we're dealing with pages, let's put a checkbox for the front page at the top of the list
if ( 'page' == $post_type_name ) {
$front_page = 'page' == get_option('show_on_front') ? (int) get_option( 'page_on_front' ) : 0;
if ( ! empty( $front_page ) ) {
$front_page_obj = get_post( $front_page );
$front_page_obj->front_or_home = true;
array_unshift( $posts, $front_page_obj );
} else {
$_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
array_unshift( $posts, (object) array(
'front_or_home' => true,
'ID' => 0,
'object_id' => $_nav_menu_placeholder,
'post_content' => '',
'post_excerpt' => '',
'post_parent' => '',
'post_title' => _x('Home', 'nav menu home label'),
'post_type' => 'nav_menu_item',
'type' => 'custom',
'url' => home_url('/'),
) );
}
}
$posts = apply_filters( 'nav_menu_items_'.$post_type_name, $posts, $args, $post_type );
$checkbox_items = walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $posts), 0, (object) $args );
if ( 'all' == $current_tab && ! empty( $_REQUEST['selectall'] ) ) {
$checkbox_items = preg_replace('/(type=(.)checkbox(\2))/', '$1 checked=$2checked$2', $checkbox_items);
}
echo $checkbox_items;
?>
</ul>
<?php if ( ! empty( $page_links ) ) : ?>
<div class="add-menu-item-pagelinks">
<?php echo $page_links; ?>
</div>
<?php endif; ?>
</div><!-- /.tabs-panel -->
<p class="button-controls">
<span class="list-controls">
<a href="<?php
echo esc_url( add_query_arg(
array(
$post_type_name . '-tab' => 'all',
'selectall' => 1,
),
remove_query_arg( $removed_args )
));
?>#posttype-<?php echo $post_type_name; ?>" class="select-all"><?php _e('Select All'); ?></a>
</span>
<span class="add-to-menu">
<input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( __( 'Add to Menu' ) ); ?>" name="add-post-type-menu-item" id="<?php esc_attr_e( 'submit-posttype-' . $post_type_name ); ?>" />
<span class="spinner"></span>
</span>
</p>
</div><!-- /.posttypediv -->
<?php
}
/**
* Displays a metabox for a taxonomy menu item.
*
* @since 3.0.0
*
* @param string $object Not used.
* @param string $taxonomy The taxonomy object.
*/
function wp_nav_menu_item_taxonomy_meta_box( $object, $taxonomy ) {
global $nav_menu_selected_id;
$taxonomy_name = $taxonomy['args']->name;
// paginate browsing for large numbers of objects
$per_page = 50;
$pagenum = isset( $_REQUEST[$taxonomy_name . '-tab'] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
$offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
$args = array(
'child_of' => 0,
'exclude' => '',
'hide_empty' => false,
'hierarchical' => 1,
'include' => '',
'number' => $per_page,
'offset' => $offset,
'order' => 'ASC',
'orderby' => 'name',
'pad_counts' => false,
);
$terms = get_terms( $taxonomy_name, $args );
if ( ! $terms || is_wp_error($terms) ) {
echo '<p>' . __( 'No items.' ) . '</p>';
return;
}
$num_pages = ceil( wp_count_terms( $taxonomy_name , array_merge( $args, array('number' => '', 'offset' => '') ) ) / $per_page );
$page_links = paginate_links( array(
'base' => add_query_arg(
array(
$taxonomy_name . '-tab' => 'all',
'paged' => '%#%',
'item-type' => 'taxonomy',
'item-object' => $taxonomy_name,
)
),
'format' => '',
'prev_text' => __('&laquo;'),
'next_text' => __('&raquo;'),
'total' => $num_pages,
'current' => $pagenum
));
$db_fields = false;
if ( is_taxonomy_hierarchical( $taxonomy_name ) ) {
$db_fields = array( 'parent' => 'parent', 'id' => 'term_id' );
}
$walker = new Walker_Nav_Menu_Checklist( $db_fields );
$current_tab = 'most-used';
if ( isset( $_REQUEST[$taxonomy_name . '-tab'] ) && in_array( $_REQUEST[$taxonomy_name . '-tab'], array('all', 'most-used', 'search') ) ) {
$current_tab = $_REQUEST[$taxonomy_name . '-tab'];
}
if ( ! empty( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] ) ) {
$current_tab = 'search';
}
$removed_args = array(
'action',
'customlink-tab',
'edit-menu-item',
'menu-item',
'page-tab',
'_wpnonce',
);
?>
<div id="taxonomy-<?php echo $taxonomy_name; ?>" class="taxonomydiv">
<ul id="taxonomy-<?php echo $taxonomy_name; ?>-tabs" class="taxonomy-tabs add-menu-item-tabs">
<li <?php echo ( 'most-used' == $current_tab ? ' class="tabs"' : '' ); ?>><a class="nav-tab-link" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'most-used', remove_query_arg($removed_args))); ?>#tabs-panel-<?php echo $taxonomy_name; ?>-pop"><?php _e('Most Used'); ?></a></li>
<li <?php echo ( 'all' == $current_tab ? ' class="tabs"' : '' ); ?>><a class="nav-tab-link" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'all', remove_query_arg($removed_args))); ?>#tabs-panel-<?php echo $taxonomy_name; ?>-all"><?php _e('View All'); ?></a></li>
<li <?php echo ( 'search' == $current_tab ? ' class="tabs"' : '' ); ?>><a class="nav-tab-link" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'search', remove_query_arg($removed_args))); ?>#tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>"><?php _e('Search'); ?></a></li>
</ul>
<div id="tabs-panel-<?php echo $taxonomy_name; ?>-pop" class="tabs-panel <?php
echo ( 'most-used' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
?>">
<ul id="<?php echo $taxonomy_name; ?>checklist-pop" class="categorychecklist form-no-clear" >
<?php
$popular_terms = get_terms( $taxonomy_name, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
$args['walker'] = $walker;
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $popular_terms), 0, (object) $args );
?>
</ul>
</div><!-- /.tabs-panel -->
<div id="tabs-panel-<?php echo $taxonomy_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php
echo ( 'all' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
?>">
<?php if ( ! empty( $page_links ) ) : ?>
<div class="add-menu-item-pagelinks">
<?php echo $page_links; ?>
</div>
<?php endif; ?>
<ul id="<?php echo $taxonomy_name; ?>checklist" data-wp-lists="list:<?php echo $taxonomy_name?>" class="categorychecklist form-no-clear">
<?php
$args['walker'] = $walker;
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $terms), 0, (object) $args );
?>
</ul>
<?php if ( ! empty( $page_links ) ) : ?>
<div class="add-menu-item-pagelinks">
<?php echo $page_links; ?>
</div>
<?php endif; ?>
</div><!-- /.tabs-panel -->
<div class="tabs-panel <?php
echo ( 'search' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
?>" id="tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>">
<?php
if ( isset( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] ) ) {
$searched = esc_attr( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] );
$search_results = get_terms( $taxonomy_name, array( 'name__like' => $searched, 'fields' => 'all', 'orderby' => 'count', 'order' => 'DESC', 'hierarchical' => false ) );
} else {
$searched = '';
$search_results = array();
}
?>
<p class="quick-search-wrap">
<input type="search" class="quick-search input-with-default-title" title="<?php esc_attr_e('Search'); ?>" value="<?php echo $searched; ?>" name="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" />
<span class="spinner"></span>
<?php submit_button( __( 'Search' ), 'button-small quick-search-submit button-secondary hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-taxonomy-' . $taxonomy_name ) ); ?>
</p>
<ul id="<?php echo $taxonomy_name; ?>-search-checklist" data-wp-lists="list:<?php echo $taxonomy_name?>" class="categorychecklist form-no-clear">
<?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
<?php
$args['walker'] = $walker;
echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $search_results), 0, (object) $args );
?>
<?php elseif ( is_wp_error( $search_results ) ) : ?>
<li><?php echo $search_results->get_error_message(); ?></li>
<?php elseif ( ! empty( $searched ) ) : ?>
<li><?php _e('No results found.'); ?></li>
<?php endif; ?>
</ul>
</div><!-- /.tabs-panel -->
<p class="button-controls">
<span class="list-controls">
<a href="<?php
echo esc_url(add_query_arg(
array(
$taxonomy_name . '-tab' => 'all',
'selectall' => 1,
),
remove_query_arg($removed_args)
));
?>#taxonomy-<?php echo $taxonomy_name; ?>" class="select-all"><?php _e('Select All'); ?></a>
</span>
<span class="add-to-menu">
<input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( __( 'Add to Menu' ) ); ?>" name="add-taxonomy-menu-item" id="<?php esc_attr_e( 'submit-taxonomy-' . $taxonomy_name ); ?>" />
<span class="spinner"></span>
</span>
</p>
</div><!-- /.taxonomydiv -->
<?php
}
/**
* Save posted nav menu item data.
*
* @since 3.0.0
*
* @param int $menu_id The menu ID for which to save this item. $menu_id of 0 makes a draft, orphaned menu item.
* @param array $menu_data The unsanitized posted menu item data.
* @return array The database IDs of the items saved
*/
function wp_save_nav_menu_items( $menu_id = 0, $menu_data = array() ) {
$menu_id = (int) $menu_id;
$items_saved = array();
if ( 0 == $menu_id || is_nav_menu( $menu_id ) ) {
// Loop through all the menu items' POST values
foreach( (array) $menu_data as $_possible_db_id => $_item_object_data ) {
if (
empty( $_item_object_data['menu-item-object-id'] ) && // checkbox is not checked
(
! isset( $_item_object_data['menu-item-type'] ) || // and item type either isn't set
in_array( $_item_object_data['menu-item-url'], array( 'http://', '' ) ) || // or URL is the default
! ( 'custom' == $_item_object_data['menu-item-type'] && ! isset( $_item_object_data['menu-item-db-id'] ) ) || // or it's not a custom menu item (but not the custom home page)
! empty( $_item_object_data['menu-item-db-id'] ) // or it *is* a custom menu item that already exists
)
) {
continue; // then this potential menu item is not getting added to this menu
}
// if this possible menu item doesn't actually have a menu database ID yet
if (
empty( $_item_object_data['menu-item-db-id'] ) ||
( 0 > $_possible_db_id ) ||
$_possible_db_id != $_item_object_data['menu-item-db-id']
) {
$_actual_db_id = 0;
} else {
$_actual_db_id = (int) $_item_object_data['menu-item-db-id'];
}
$args = array(
'menu-item-db-id' => ( isset( $_item_object_data['menu-item-db-id'] ) ? $_item_object_data['menu-item-db-id'] : '' ),
'menu-item-object-id' => ( isset( $_item_object_data['menu-item-object-id'] ) ? $_item_object_data['menu-item-object-id'] : '' ),
'menu-item-object' => ( isset( $_item_object_data['menu-item-object'] ) ? $_item_object_data['menu-item-object'] : '' ),
'menu-item-parent-id' => ( isset( $_item_object_data['menu-item-parent-id'] ) ? $_item_object_data['menu-item-parent-id'] : '' ),
'menu-item-position' => ( isset( $_item_object_data['menu-item-position'] ) ? $_item_object_data['menu-item-position'] : '' ),
'menu-item-type' => ( isset( $_item_object_data['menu-item-type'] ) ? $_item_object_data['menu-item-type'] : '' ),
'menu-item-title' => ( isset( $_item_object_data['menu-item-title'] ) ? $_item_object_data['menu-item-title'] : '' ),
'menu-item-url' => ( isset( $_item_object_data['menu-item-url'] ) ? $_item_object_data['menu-item-url'] : '' ),
'menu-item-description' => ( isset( $_item_object_data['menu-item-description'] ) ? $_item_object_data['menu-item-description'] : '' ),
'menu-item-attr-title' => ( isset( $_item_object_data['menu-item-attr-title'] ) ? $_item_object_data['menu-item-attr-title'] : '' ),
'menu-item-target' => ( isset( $_item_object_data['menu-item-target'] ) ? $_item_object_data['menu-item-target'] : '' ),
'menu-item-classes' => ( isset( $_item_object_data['menu-item-classes'] ) ? $_item_object_data['menu-item-classes'] : '' ),
'menu-item-xfn' => ( isset( $_item_object_data['menu-item-xfn'] ) ? $_item_object_data['menu-item-xfn'] : '' ),
);
$items_saved[] = wp_update_nav_menu_item( $menu_id, $_actual_db_id, $args );
}
}
return $items_saved;
}
/**
* Adds custom arguments to some of the meta box object types.
*
* @since 3.0.0
*
* @access private
*
* @param object $object The post type or taxonomy meta-object.
* @return object The post type of taxonomy object.
*/
function _wp_nav_menu_meta_box_object( $object = null ) {
if ( isset( $object->name ) ) {
if ( 'page' == $object->name ) {
$object->_default_query = array(
'orderby' => 'menu_order title',
'post_status' => 'publish',
);
// posts should show only published items
} elseif ( 'post' == $object->name ) {
$object->_default_query = array(
'post_status' => 'publish',
);
// cats should be in reverse chronological order
} elseif ( 'category' == $object->name ) {
$object->_default_query = array(
'orderby' => 'id',
'order' => 'DESC',
);
// custom post types should show only published items
} else {
$object->_default_query = array(
'post_status' => 'publish',
);
}
}
return $object;
}
/**
* Returns the menu formatted to edit.
*
* @since 3.0.0
*
* @param string $menu_id The ID of the menu to format.
* @return string|WP_Error $output The menu formatted to edit or error object on failure.
*/
function wp_get_nav_menu_to_edit( $menu_id = 0 ) {
$menu = wp_get_nav_menu_object( $menu_id );
// If the menu exists, get its items.
if ( is_nav_menu( $menu ) ) {
$menu_items = wp_get_nav_menu_items( $menu->term_id, array('post_status' => 'any') );
$result = '<div id="menu-instructions" class="post-body-plain';
$result .= ( ! empty($menu_items) ) ? ' menu-instructions-inactive">' : '">';
$result .= '<p>' . __( 'Next, add menu items (i.e. pages, links, categories) from the column on the left.' ) . '</p>';
$result .= '</div>';
if( empty($menu_items) )
return $result . ' <ul class="menu" id="menu-to-edit"> </ul>';
$walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $menu_id );
if ( class_exists( $walker_class_name ) )
$walker = new $walker_class_name;
else
return new WP_Error( 'menu_walker_not_exist', sprintf( __('The Walker class named <strong>%s</strong> does not exist.'), $walker_class_name ) );
$some_pending_menu_items = $some_invalid_menu_items = false;
foreach( (array) $menu_items as $menu_item ) {
if ( isset( $menu_item->post_status ) && 'draft' == $menu_item->post_status )
$some_pending_menu_items = true;
if ( ! empty( $menu_item->_invalid ) )
$some_invalid_menu_items = true;
}
if ( $some_pending_menu_items )
$result .= '<div class="updated inline"><p>' . __('Click Save Menu to make pending menu items public.') . '</p></div>';
if ( $some_invalid_menu_items )
$result .= '<div class="error inline"><p>' . __('There are some invalid menu items. Please check or delete them.') . '</p></div>';
$result .= '<ul class="menu" id="menu-to-edit"> ';
$result .= walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $menu_items), 0, (object) array('walker' => $walker ) );
$result .= ' </ul> ';
return $result;
} elseif ( is_wp_error( $menu ) ) {
return $menu;
}
}
/**
* Returns the columns for the nav menus page.
*
* @since 3.0.0
*
* @return string|WP_Error $output The menu formatted to edit or error object on failure.
*/
function wp_nav_menu_manage_columns() {
return array(
'_title' => __('Show advanced menu properties'),
'cb' => '<input type="checkbox" />',
'link-target' => __('Link Target'),
'css-classes' => __('CSS Classes'),
'xfn' => __('Link Relationship (XFN)'),
'description' => __('Description'),
);
}
/**
* Deletes orphaned draft menu items
*
* @access private
* @since 3.0.0
*
*/
function _wp_delete_orphaned_draft_menu_items() {
global $wpdb;
$delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
// delete orphaned draft menu items
$menu_items_to_delete = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts AS p LEFT JOIN $wpdb->postmeta AS m ON p.ID = m.post_id WHERE post_type = 'nav_menu_item' AND post_status = 'draft' AND meta_key = '_menu_item_orphaned' AND meta_value < '%d'", $delete_timestamp ) );
foreach( (array) $menu_items_to_delete as $menu_item_id )
wp_delete_post( $menu_item_id, true );
}
add_action('admin_head-nav-menus.php', '_wp_delete_orphaned_draft_menu_items');
/**
* Delete nav menus from the nav menu management screen
*
* @since 3.6.0
* @access private
*
* @param int|string $nav_menu_id The menu to delete (id, slug, or name)
* @return false if Error, otherwise true
*/
function _wp_delete_nav_menu( $nav_menu_id ) {
if ( ! is_nav_menu( $nav_menu_id ) )
return;
$deleted_nav_menu = wp_get_nav_menu_object( $nav_menu_id );
$delete_nav_menu = wp_delete_nav_menu( $nav_menu_id );
if ( is_wp_error( $delete_nav_menu ) )
return $delete_nav_menu;
// Remove this menu from any locations.
$locations = get_theme_mod( 'nav_menu_locations' );
foreach ( (array) $locations as $location => $menu_id ) {
if ( $menu_id == $nav_menu_id )
$locations[ $location ] = 0;
}
set_theme_mod( 'nav_menu_locations', $locations );
return true;
}
/**
* Saves nav menu items
*
* @since 3.6.0
*
* @uses wp_get_nav_menu_items() to retrieve the nav menu's menu items
* @uses wp_defer_term_counter() to enable then disable term counting
*
* @param int|string $nav_menu_selected_id (id, slug, or name ) of the currently-selected menu
* @param string $nav_menu_selected_title Title of the currently-selected menu
* @return array $messages The menu updated message
*/
function wp_nav_menu_update_menu_items ( $nav_menu_selected_id, $nav_menu_selected_title ) {
$unsorted_menu_items = wp_get_nav_menu_items( $nav_menu_selected_id, array( 'orderby' => 'ID', 'output' => ARRAY_A, 'output_key' => 'ID', 'post_status' => 'draft,publish' ) );
$menu_items = array();
// Index menu items by db ID
foreach ( $unsorted_menu_items as $_item )
$menu_items[$_item->db_id] = $_item;
$post_fields = array(
'menu-item-db-id', 'menu-item-object-id', 'menu-item-object',
'menu-item-parent-id', 'menu-item-position', 'menu-item-type',
'menu-item-title', 'menu-item-url', 'menu-item-description',
'menu-item-attr-title', 'menu-item-target', 'menu-item-classes', 'menu-item-xfn'
);
wp_defer_term_counting( true );
// Loop through all the menu items' POST variables
if ( ! empty( $_POST['menu-item-db-id'] ) ) {
foreach( (array) $_POST['menu-item-db-id'] as $_key => $k ) {
// Menu item title can't be blank
if ( empty( $_POST['menu-item-title'][$_key] ) )
continue;
$args = array();
foreach ( $post_fields as $field )
$args[$field] = isset( $_POST[$field][$_key] ) ? $_POST[$field][$_key] : '';
$menu_item_db_id = wp_update_nav_menu_item( $nav_menu_selected_id, ( $_POST['menu-item-db-id'][$_key] != $_key ? 0 : $_key ), $args );
if ( is_wp_error( $menu_item_db_id ) )
$messages[] = '<div id="message" class="error"><p>' . $menu_item_db_id->get_error_message() . '</p></div>';
elseif ( isset( $menu_items[$menu_item_db_id] ) )
unset( $menu_items[$menu_item_db_id] );
}
}
// Remove menu items from the menu that weren't in $_POST
if ( ! empty( $menu_items ) ) {
foreach ( array_keys( $menu_items ) as $menu_item_id ) {
if ( is_nav_menu_item( $menu_item_id ) ) {
wp_delete_post( $menu_item_id );
}
}
}
// Store 'auto-add' pages.
$auto_add = ! empty( $_POST['auto-add-pages'] );
$nav_menu_option = (array) get_option( 'nav_menu_options' );
if ( ! isset( $nav_menu_option['auto_add'] ) )
$nav_menu_option['auto_add'] = array();
if ( $auto_add ) {
if ( ! in_array( $nav_menu_selected_id, $nav_menu_option['auto_add'] ) )
$nav_menu_option['auto_add'][] = $nav_menu_selected_id;
} else {
if ( false !== ( $key = array_search( $nav_menu_selected_id, $nav_menu_option['auto_add'] ) ) )
unset( $nav_menu_option['auto_add'][$key] );
}
// Remove nonexistent/deleted menus
$nav_menu_option['auto_add'] = array_intersect( $nav_menu_option['auto_add'], wp_get_nav_menus( array( 'fields' => 'ids' ) ) );
update_option( 'nav_menu_options', $nav_menu_option );
wp_defer_term_counting( false );
do_action( 'wp_update_nav_menu', $nav_menu_selected_id );
$messages[] = '<div id="message" class="updated"><p>' . sprintf( __( '<strong>%1$s</strong> has been updated.' ), $nav_menu_selected_title ) . '</p></div>';
unset( $menu_items, $unsorted_menu_items );
return $messages;
}