home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-admin / includes / nav-menu.php < prev    next >
Encoding:
PHP Script  |  2017-10-24  |  41.5 KB  |  1,138 lines

  1. <?php
  2. /**
  3.  * Core Navigation Menu API
  4.  *
  5.  * @package WordPress
  6.  * @subpackage Nav_Menus
  7.  * @since 3.0.0
  8.  */
  9.  
  10. /** Walker_Nav_Menu_Edit class */
  11. require_once( ABSPATH . 'wp-admin/includes/class-walker-nav-menu-edit.php' );
  12.  
  13. /** Walker_Nav_Menu_Checklist class */
  14. require_once( ABSPATH . 'wp-admin/includes/class-walker-nav-menu-checklist.php' );
  15.  
  16. /**
  17.  * Prints the appropriate response to a menu quick search.
  18.  *
  19.  * @since 3.0.0
  20.  *
  21.  * @param array $request The unsanitized request values.
  22.  */
  23. function _wp_ajax_menu_quick_search( $request = array() ) {
  24.     $args = array();
  25.     $type = isset( $request['type'] ) ? $request['type'] : '';
  26.     $object_type = isset( $request['object_type'] ) ? $request['object_type'] : '';
  27.     $query = isset( $request['q'] ) ? $request['q'] : '';
  28.     $response_format = isset( $request['response-format'] ) && in_array( $request['response-format'], array( 'json', 'markup' ) ) ? $request['response-format'] : 'json';
  29.  
  30.     if ( 'markup' == $response_format ) {
  31.         $args['walker'] = new Walker_Nav_Menu_Checklist;
  32.     }
  33.  
  34.     if ( 'get-post-item' == $type ) {
  35.         if ( post_type_exists( $object_type ) ) {
  36.             if ( isset( $request['ID'] ) ) {
  37.                 $object_id = (int) $request['ID'];
  38.                 if ( 'markup' == $response_format ) {
  39.                     echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_post( $object_id ) ) ), 0, (object) $args );
  40.                 } elseif ( 'json' == $response_format ) {
  41.                     echo wp_json_encode(
  42.                         array(
  43.                             'ID' => $object_id,
  44.                             'post_title' => get_the_title( $object_id ),
  45.                             'post_type' => get_post_type( $object_id ),
  46.                         )
  47.                     );
  48.                     echo "\n";
  49.                 }
  50.             }
  51.         } elseif ( taxonomy_exists( $object_type ) ) {
  52.             if ( isset( $request['ID'] ) ) {
  53.                 $object_id = (int) $request['ID'];
  54.                 if ( 'markup' == $response_format ) {
  55.                     echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_term( $object_id, $object_type ) ) ), 0, (object) $args );
  56.                 } elseif ( 'json' == $response_format ) {
  57.                     $post_obj = get_term( $object_id, $object_type );
  58.                     echo wp_json_encode(
  59.                         array(
  60.                             'ID' => $object_id,
  61.                             'post_title' => $post_obj->name,
  62.                             'post_type' => $object_type,
  63.                         )
  64.                     );
  65.                     echo "\n";
  66.                 }
  67.             }
  68.  
  69.         }
  70.  
  71.     } elseif ( preg_match('/quick-search-(posttype|taxonomy)-([a-zA-Z_-]*\b)/', $type, $matches) ) {
  72.         if ( 'posttype' == $matches[1] && get_post_type_object( $matches[2] ) ) {
  73.             $post_type_obj = _wp_nav_menu_meta_box_object( get_post_type_object( $matches[2] ) );
  74.             $args = array_merge(
  75.                 $args,
  76.                 array(
  77.                     'no_found_rows'          => true,
  78.                     'update_post_meta_cache' => false,
  79.                     'update_post_term_cache' => false,
  80.                     'posts_per_page'         => 10,
  81.                     'post_type'              => $matches[2],
  82.                     's'                      => $query,
  83.                 )
  84.             );
  85.             if ( isset( $post_type_obj->_default_query ) ) {
  86.                 $args = array_merge( $args, (array) $post_type_obj->_default_query );
  87.             }
  88.             $search_results_query = new WP_Query( $args );
  89.             if ( ! $search_results_query->have_posts() ) {
  90.                 return;
  91.             }
  92.             while ( $search_results_query->have_posts() ) {
  93.                 $post = $search_results_query->next_post();
  94.                 if ( 'markup' == $response_format ) {
  95.                     $var_by_ref = $post->ID;
  96.                     echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_post( $var_by_ref ) ) ), 0, (object) $args );
  97.                 } elseif ( 'json' == $response_format ) {
  98.                     echo wp_json_encode(
  99.                         array(
  100.                             'ID' => $post->ID,
  101.                             'post_title' => get_the_title( $post->ID ),
  102.                             'post_type' => $matches[2],
  103.                         )
  104.                     );
  105.                     echo "\n";
  106.                 }
  107.             }
  108.         } elseif ( 'taxonomy' == $matches[1] ) {
  109.             $terms = get_terms( $matches[2], array(
  110.                 'name__like' => $query,
  111.                 'number' => 10,
  112.             ));
  113.             if ( empty( $terms ) || is_wp_error( $terms ) )
  114.                 return;
  115.             foreach ( (array) $terms as $term ) {
  116.                 if ( 'markup' == $response_format ) {
  117.                     echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( $term ) ), 0, (object) $args );
  118.                 } elseif ( 'json' == $response_format ) {
  119.                     echo wp_json_encode(
  120.                         array(
  121.                             'ID' => $term->term_id,
  122.                             'post_title' => $term->name,
  123.                             'post_type' => $matches[2],
  124.                         )
  125.                     );
  126.                     echo "\n";
  127.                 }
  128.             }
  129.         }
  130.     }
  131. }
  132.  
  133. /**
  134.  * Register nav menu meta boxes and advanced menu items.
  135.  *
  136.  * @since 3.0.0
  137.  **/
  138. function wp_nav_menu_setup() {
  139.     // Register meta boxes
  140.     wp_nav_menu_post_type_meta_boxes();
  141.     add_meta_box( 'add-custom-links', __( 'Custom Links' ), 'wp_nav_menu_item_link_meta_box', 'nav-menus', 'side', 'default' );
  142.     wp_nav_menu_taxonomy_meta_boxes();
  143.  
  144.     // Register advanced menu items (columns)
  145.     add_filter( 'manage_nav-menus_columns', 'wp_nav_menu_manage_columns' );
  146.  
  147.     // If first time editing, disable advanced items by default.
  148.     if ( false === get_user_option( 'managenav-menuscolumnshidden' ) ) {
  149.         $user = wp_get_current_user();
  150.         update_user_option($user->ID, 'managenav-menuscolumnshidden',
  151.             array( 0 => 'link-target', 1 => 'css-classes', 2 => 'xfn', 3 => 'description', 4 => 'title-attribute', ),
  152.             true);
  153.     }
  154. }
  155.  
  156. /**
  157.  * Limit the amount of meta boxes to pages, posts, links, and categories for first time users.
  158.  *
  159.  * @since 3.0.0
  160.  *
  161.  * @global array $wp_meta_boxes
  162.  **/
  163. function wp_initial_nav_menu_meta_boxes() {
  164.     global $wp_meta_boxes;
  165.  
  166.     if ( get_user_option( 'metaboxhidden_nav-menus' ) !== false || ! is_array($wp_meta_boxes) )
  167.         return;
  168.  
  169.     $initial_meta_boxes = array( 'add-post-type-page', 'add-post-type-post', 'add-custom-links', 'add-category' );
  170.     $hidden_meta_boxes = array();
  171.  
  172.     foreach ( array_keys($wp_meta_boxes['nav-menus']) as $context ) {
  173.         foreach ( array_keys($wp_meta_boxes['nav-menus'][$context]) as $priority ) {
  174.             foreach ( $wp_meta_boxes['nav-menus'][$context][$priority] as $box ) {
  175.                 if ( in_array( $box['id'], $initial_meta_boxes ) ) {
  176.                     unset( $box['id'] );
  177.                 } else {
  178.                     $hidden_meta_boxes[] = $box['id'];
  179.                 }
  180.             }
  181.         }
  182.     }
  183.  
  184.     $user = wp_get_current_user();
  185.     update_user_option( $user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true );
  186. }
  187.  
  188. /**
  189.  * Creates meta boxes for any post type menu item..
  190.  *
  191.  * @since 3.0.0
  192.  */
  193. function wp_nav_menu_post_type_meta_boxes() {
  194.     $post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
  195.  
  196.     if ( ! $post_types )
  197.         return;
  198.  
  199.     foreach ( $post_types as $post_type ) {
  200.         /**
  201.          * Filters whether a menu items meta box will be added for the current
  202.          * object type.
  203.          *
  204.          * If a falsey value is returned instead of an object, the menu items
  205.          * meta box for the current meta box object will not be added.
  206.          *
  207.          * @since 3.0.0
  208.          *
  209.          * @param object $meta_box_object The current object to add a menu items
  210.          *                                meta box for.
  211.          */
  212.         $post_type = apply_filters( 'nav_menu_meta_box_object', $post_type );
  213.         if ( $post_type ) {
  214.             $id = $post_type->name;
  215.             // Give pages a higher priority.
  216.             $priority = ( 'page' == $post_type->name ? 'core' : 'default' );
  217.             add_meta_box( "add-post-type-{$id}", $post_type->labels->name, 'wp_nav_menu_item_post_type_meta_box', 'nav-menus', 'side', $priority, $post_type );
  218.         }
  219.     }
  220. }
  221.  
  222. /**
  223.  * Creates meta boxes for any taxonomy menu item.
  224.  *
  225.  * @since 3.0.0
  226.  */
  227. function wp_nav_menu_taxonomy_meta_boxes() {
  228.     $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'object' );
  229.  
  230.     if ( !$taxonomies )
  231.         return;
  232.  
  233.     foreach ( $taxonomies as $tax ) {
  234.         /** This filter is documented in wp-admin/includes/nav-menu.php */
  235.         $tax = apply_filters( 'nav_menu_meta_box_object', $tax );
  236.         if ( $tax ) {
  237.             $id = $tax->name;
  238.             add_meta_box( "add-{$id}", $tax->labels->name, 'wp_nav_menu_item_taxonomy_meta_box', 'nav-menus', 'side', 'default', $tax );
  239.         }
  240.     }
  241. }
  242.  
  243. /**
  244.  * Check whether to disable the Menu Locations meta box submit button
  245.  *
  246.  * @since 3.6.0
  247.  *
  248.  * @global bool $one_theme_location_no_menus to determine if no menus exist
  249.  *
  250.  * @param int|string $nav_menu_selected_id (id, name or slug) of the currently-selected menu
  251.  * @return string Disabled attribute if at least one menu exists, false if not
  252.  */
  253. function wp_nav_menu_disabled_check( $nav_menu_selected_id ) {
  254.     global $one_theme_location_no_menus;
  255.  
  256.     if ( $one_theme_location_no_menus )
  257.         return false;
  258.  
  259.     return disabled( $nav_menu_selected_id, 0 );
  260. }
  261.  
  262. /**
  263.  * Displays a meta box for the custom links menu item.
  264.  *
  265.  * @since 3.0.0
  266.  *
  267.  * @global int        $_nav_menu_placeholder
  268.  * @global int|string $nav_menu_selected_id
  269.  */
  270. function wp_nav_menu_item_link_meta_box() {
  271.     global $_nav_menu_placeholder, $nav_menu_selected_id;
  272.  
  273.     $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1;
  274.  
  275.     ?>
  276.     <div class="customlinkdiv" id="customlinkdiv">
  277.         <input type="hidden" value="custom" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" />
  278.         <p id="menu-item-url-wrap" class="wp-clearfix">
  279.             <label class="howto" for="custom-menu-item-url"><?php _e( 'URL' ); ?></label>
  280.             <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://" />
  281.         </p>
  282.  
  283.         <p id="menu-item-name-wrap" class="wp-clearfix">
  284.             <label class="howto" for="custom-menu-item-name"><?php _e( 'Link Text' ); ?></label>
  285.             <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" />
  286.         </p>
  287.  
  288.         <p class="button-controls wp-clearfix">
  289.             <span class="add-to-menu">
  290.                 <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e('Add to Menu'); ?>" name="add-custom-menu-item" id="submit-customlinkdiv" />
  291.                 <span class="spinner"></span>
  292.             </span>
  293.         </p>
  294.  
  295.     </div><!-- /.customlinkdiv -->
  296.     <?php
  297. }
  298.  
  299. /**
  300.  * Displays a meta box for a post type menu item.
  301.  *
  302.  * @since 3.0.0
  303.  *
  304.  * @global int        $_nav_menu_placeholder
  305.  * @global int|string $nav_menu_selected_id
  306.  *
  307.  * @param string $object Not used.
  308.  * @param array  $box {
  309.  *     Post type menu item meta box arguments.
  310.  *
  311.  *     @type string       $id       Meta box 'id' attribute.
  312.  *     @type string       $title    Meta box title.
  313.  *     @type string       $callback Meta box display callback.
  314.  *     @type WP_Post_Type $args     Extra meta box arguments (the post type object for this meta box).
  315.  * }
  316.  */
  317. function wp_nav_menu_item_post_type_meta_box( $object, $box ) {
  318.     global $_nav_menu_placeholder, $nav_menu_selected_id;
  319.  
  320.     $post_type_name = $box['args']->name;
  321.  
  322.     // Paginate browsing for large numbers of post objects.
  323.     $per_page = 50;
  324.     $pagenum = isset( $_REQUEST[$post_type_name . '-tab'] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
  325.     $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
  326.  
  327.     $args = array(
  328.         'offset' => $offset,
  329.         'order' => 'ASC',
  330.         'orderby' => 'title',
  331.         'posts_per_page' => $per_page,
  332.         'post_type' => $post_type_name,
  333.         'suppress_filters' => true,
  334.         'update_post_term_cache' => false,
  335.         'update_post_meta_cache' => false
  336.     );
  337.  
  338.     if ( isset( $box['args']->_default_query ) )
  339.         $args = array_merge($args, (array) $box['args']->_default_query );
  340.  
  341.     // @todo transient caching of these results with proper invalidation on updating of a post of this type
  342.     $get_posts = new WP_Query;
  343.     $posts = $get_posts->query( $args );
  344.     if ( ! $get_posts->post_count ) {
  345.         echo '<p>' . __( 'No items.' ) . '</p>';
  346.         return;
  347.     }
  348.  
  349.     $num_pages = $get_posts->max_num_pages;
  350.  
  351.     $page_links = paginate_links( array(
  352.         'base' => add_query_arg(
  353.             array(
  354.                 $post_type_name . '-tab' => 'all',
  355.                 'paged' => '%#%',
  356.                 'item-type' => 'post_type',
  357.                 'item-object' => $post_type_name,
  358.             )
  359.         ),
  360.         'format' => '',
  361.         'prev_text'          => '<span aria-label="' . esc_attr__( 'Previous page' ) . '">' . __( '«' ) . '</span>',
  362.         'next_text'          => '<span aria-label="' . esc_attr__( 'Next page' ) . '">' . __( '»' ) . '</span>',
  363.         'before_page_number' => '<span class="screen-reader-text">' . __( 'Page' ) . '</span> ',
  364.         'total'   => $num_pages,
  365.         'current' => $pagenum
  366.     ));
  367.  
  368.     $db_fields = false;
  369.     if ( is_post_type_hierarchical( $post_type_name ) ) {
  370.         $db_fields = array( 'parent' => 'post_parent', 'id' => 'ID' );
  371.     }
  372.  
  373.     $walker = new Walker_Nav_Menu_Checklist( $db_fields );
  374.  
  375.     $current_tab = 'most-recent';
  376.     if ( isset( $_REQUEST[$post_type_name . '-tab'] ) && in_array( $_REQUEST[$post_type_name . '-tab'], array('all', 'search') ) ) {
  377.         $current_tab = $_REQUEST[$post_type_name . '-tab'];
  378.     }
  379.  
  380.     if ( ! empty( $_REQUEST['quick-search-posttype-' . $post_type_name] ) ) {
  381.         $current_tab = 'search';
  382.     }
  383.  
  384.     $removed_args = array(
  385.         'action',
  386.         'customlink-tab',
  387.         'edit-menu-item',
  388.         'menu-item',
  389.         'page-tab',
  390.         '_wpnonce',
  391.     );
  392.  
  393.     ?>
  394.     <div id="posttype-<?php echo $post_type_name; ?>" class="posttypediv">
  395.         <ul id="posttype-<?php echo $post_type_name; ?>-tabs" class="posttype-tabs add-menu-item-tabs">
  396.             <li <?php echo ( 'most-recent' == $current_tab ? ' class="tabs"' : '' ); ?>>
  397.                 <a class="nav-tab-link" data-type="tabs-panel-posttype-<?php echo esc_attr( $post_type_name ); ?>-most-recent" 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">
  398.                     <?php _e( 'Most Recent' ); ?>
  399.                 </a>
  400.             </li>
  401.             <li <?php echo ( 'all' == $current_tab ? ' class="tabs"' : '' ); ?>>
  402.                 <a class="nav-tab-link" data-type="<?php echo esc_attr( $post_type_name ); ?>-all" 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">
  403.                     <?php _e( 'View All' ); ?>
  404.                 </a>
  405.             </li>
  406.             <li <?php echo ( 'search' == $current_tab ? ' class="tabs"' : '' ); ?>>
  407.                 <a class="nav-tab-link" data-type="tabs-panel-posttype-<?php echo esc_attr( $post_type_name ); ?>-search" 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">
  408.                     <?php _e( 'Search'); ?>
  409.                 </a>
  410.             </li>
  411.         </ul><!-- .posttype-tabs -->
  412.  
  413.         <div id="tabs-panel-posttype-<?php echo $post_type_name; ?>-most-recent" class="tabs-panel <?php
  414.             echo ( 'most-recent' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
  415.         ?>">
  416.             <ul id="<?php echo $post_type_name; ?>checklist-most-recent" class="categorychecklist form-no-clear">
  417.                 <?php
  418.                 $recent_args = array_merge( $args, array( 'orderby' => 'post_date', 'order' => 'DESC', 'posts_per_page' => 15 ) );
  419.                 $most_recent = $get_posts->query( $recent_args );
  420.                 $args['walker'] = $walker;
  421.  
  422.                 /**
  423.                  * Filters the posts displayed in the 'Most Recent' tab of the current
  424.                  * post type's menu items meta box.
  425.                  *
  426.                  * The dynamic portion of the hook name, `$post_type_name`, refers to the post type name.
  427.                  *
  428.                  * @since 4.3.0
  429.                  * @since 4.9.0 Added the `$recent_args` parameter.
  430.                  *
  431.                  * @param array $most_recent An array of post objects being listed.
  432.                  * @param array $args        An array of WP_Query arguments for the meta box.
  433.                  * @param array $box         Arguments passed to wp_nav_menu_item_post_type_meta_box().
  434.                  * @param array $recent_args An array of WP_Query arguments for 'Most Recent' tab.
  435.                  */
  436.                 $most_recent = apply_filters( "nav_menu_items_{$post_type_name}_recent", $most_recent, $args, $box, $recent_args );
  437.  
  438.                 echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $most_recent ), 0, (object) $args );
  439.                 ?>
  440.             </ul>
  441.         </div><!-- /.tabs-panel -->
  442.  
  443.         <div class="tabs-panel <?php
  444.             echo ( 'search' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
  445.         ?>" id="tabs-panel-posttype-<?php echo $post_type_name; ?>-search">
  446.             <?php
  447.             if ( isset( $_REQUEST['quick-search-posttype-' . $post_type_name] ) ) {
  448.                 $searched = esc_attr( $_REQUEST['quick-search-posttype-' . $post_type_name] );
  449.                 $search_results = get_posts( array( 's' => $searched, 'post_type' => $post_type_name, 'fields' => 'all', 'order' => 'DESC', ) );
  450.             } else {
  451.                 $searched = '';
  452.                 $search_results = array();
  453.             }
  454.             ?>
  455.             <p class="quick-search-wrap">
  456.                 <label for="quick-search-posttype-<?php echo $post_type_name; ?>" class="screen-reader-text"><?php _e( 'Search' ); ?></label>
  457.                 <input type="search" class="quick-search" value="<?php echo $searched; ?>" name="quick-search-posttype-<?php echo $post_type_name; ?>" id="quick-search-posttype-<?php echo $post_type_name; ?>" />
  458.                 <span class="spinner"></span>
  459.                 <?php submit_button( __( 'Search' ), 'small quick-search-submit hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-posttype-' . $post_type_name ) ); ?>
  460.             </p>
  461.  
  462.             <ul id="<?php echo $post_type_name; ?>-search-checklist" data-wp-lists="list:<?php echo $post_type_name?>" class="categorychecklist form-no-clear">
  463.             <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
  464.                 <?php
  465.                 $args['walker'] = $walker;
  466.                 echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $search_results), 0, (object) $args );
  467.                 ?>
  468.             <?php elseif ( is_wp_error( $search_results ) ) : ?>
  469.                 <li><?php echo $search_results->get_error_message(); ?></li>
  470.             <?php elseif ( ! empty( $searched ) ) : ?>
  471.                 <li><?php _e('No results found.'); ?></li>
  472.             <?php endif; ?>
  473.             </ul>
  474.         </div><!-- /.tabs-panel -->
  475.  
  476.         <div id="<?php echo $post_type_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php
  477.             echo ( 'all' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
  478.         ?>">
  479.             <?php if ( ! empty( $page_links ) ) : ?>
  480.                 <div class="add-menu-item-pagelinks">
  481.                     <?php echo $page_links; ?>
  482.                 </div>
  483.             <?php endif; ?>
  484.             <ul id="<?php echo $post_type_name; ?>checklist" data-wp-lists="list:<?php echo $post_type_name?>" class="categorychecklist form-no-clear">
  485.                 <?php
  486.                 $args['walker'] = $walker;
  487.  
  488.                 /*
  489.                  * If we're dealing with pages, let's put a checkbox for the front
  490.                  * page at the top of the list.
  491.                  */
  492.                 if ( 'page' == $post_type_name ) {
  493.                     $front_page = 'page' == get_option('show_on_front') ? (int) get_option( 'page_on_front' ) : 0;
  494.                     if ( ! empty( $front_page ) ) {
  495.                         $front_page_obj = get_post( $front_page );
  496.                         $front_page_obj->front_or_home = true;
  497.                         array_unshift( $posts, $front_page_obj );
  498.                     } else {
  499.                         $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
  500.                         array_unshift( $posts, (object) array(
  501.                             'front_or_home' => true,
  502.                             'ID' => 0,
  503.                             'object_id' => $_nav_menu_placeholder,
  504.                             'post_content' => '',
  505.                             'post_excerpt' => '',
  506.                             'post_parent' => '',
  507.                             'post_title' => _x('Home', 'nav menu home label'),
  508.                             'post_type' => 'nav_menu_item',
  509.                             'type' => 'custom',
  510.                             'url' => home_url('/'),
  511.                         ) );
  512.                     }
  513.                 }
  514.  
  515.                 $post_type = get_post_type_object( $post_type_name );
  516.  
  517.                 if ( $post_type->has_archive ) {
  518.                     $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
  519.                     array_unshift( $posts, (object) array(
  520.                         'ID' => 0,
  521.                         'object_id' => $_nav_menu_placeholder,
  522.                         'object'     => $post_type_name,
  523.                         'post_content' => '',
  524.                         'post_excerpt' => '',
  525.                         'post_title' => $post_type->labels->archives,
  526.                         'post_type' => 'nav_menu_item',
  527.                         'type' => 'post_type_archive',
  528.                         'url' => get_post_type_archive_link( $post_type_name ),
  529.                     ) );
  530.                 }
  531.  
  532.                 /**
  533.                  * Filters the posts displayed in the 'View All' tab of the current
  534.                  * post type's menu items meta box.
  535.                  *
  536.                  * The dynamic portion of the hook name, `$post_type_name`, refers
  537.                  * to the slug of the current post type.
  538.                  *
  539.                  * @since 3.2.0
  540.                  * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object.
  541.                  *
  542.                  * @see WP_Query::query()
  543.                  *
  544.                  * @param array        $posts     The posts for the current post type.
  545.                  * @param array        $args      An array of WP_Query arguments.
  546.                  * @param WP_Post_Type $post_type The current post type object for this menu item meta box.
  547.                  */
  548.                 $posts = apply_filters( "nav_menu_items_{$post_type_name}", $posts, $args, $post_type );
  549.  
  550.                 $checkbox_items = walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $posts), 0, (object) $args );
  551.  
  552.                 if ( 'all' == $current_tab && ! empty( $_REQUEST['selectall'] ) ) {
  553.                     $checkbox_items = preg_replace('/(type=(.)checkbox(\2))/', '$1 checked=$2checked$2', $checkbox_items);
  554.  
  555.                 }
  556.  
  557.                 echo $checkbox_items;
  558.                 ?>
  559.             </ul>
  560.             <?php if ( ! empty( $page_links ) ) : ?>
  561.                 <div class="add-menu-item-pagelinks">
  562.                     <?php echo $page_links; ?>
  563.                 </div>
  564.             <?php endif; ?>
  565.         </div><!-- /.tabs-panel -->
  566.  
  567.         <p class="button-controls wp-clearfix">
  568.             <span class="list-controls">
  569.                 <a href="<?php
  570.                     echo esc_url( add_query_arg(
  571.                         array(
  572.                             $post_type_name . '-tab' => 'all',
  573.                             'selectall' => 1,
  574.                         ),
  575.                         remove_query_arg( $removed_args )
  576.                     ));
  577.                 ?>#posttype-<?php echo $post_type_name; ?>" class="select-all aria-button-if-js"><?php _e( 'Select All' ); ?></a>
  578.             </span>
  579.  
  580.             <span class="add-to-menu">
  581.                 <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-post-type-menu-item" id="<?php echo esc_attr( 'submit-posttype-' . $post_type_name ); ?>" />
  582.                 <span class="spinner"></span>
  583.             </span>
  584.         </p>
  585.  
  586.     </div><!-- /.posttypediv -->
  587.     <?php
  588. }
  589.  
  590. /**
  591.  * Displays a meta box for a taxonomy menu item.
  592.  *
  593.  * @since 3.0.0
  594.  *
  595.  * @global int|string $nav_menu_selected_id
  596.  *
  597.  * @param string $object Not used.
  598.  * @param array  $box {
  599.  *     Taxonomy menu item meta box arguments.
  600.  *
  601.  *     @type string $id       Meta box 'id' attribute.
  602.  *     @type string $title    Meta box title.
  603.  *     @type string $callback Meta box display callback.
  604.  *     @type object $args     Extra meta box arguments (the taxonomy object for this meta box).
  605.  * }
  606.  */
  607. function wp_nav_menu_item_taxonomy_meta_box( $object, $box ) {
  608.     global $nav_menu_selected_id;
  609.     $taxonomy_name = $box['args']->name;
  610.     $taxonomy = get_taxonomy( $taxonomy_name );
  611.  
  612.     // Paginate browsing for large numbers of objects.
  613.     $per_page = 50;
  614.     $pagenum = isset( $_REQUEST[$taxonomy_name . '-tab'] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
  615.     $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
  616.  
  617.     $args = array(
  618.         'child_of' => 0,
  619.         'exclude' => '',
  620.         'hide_empty' => false,
  621.         'hierarchical' => 1,
  622.         'include' => '',
  623.         'number' => $per_page,
  624.         'offset' => $offset,
  625.         'order' => 'ASC',
  626.         'orderby' => 'name',
  627.         'pad_counts' => false,
  628.     );
  629.  
  630.     $terms = get_terms( $taxonomy_name, $args );
  631.  
  632.     if ( ! $terms || is_wp_error($terms) ) {
  633.         echo '<p>' . __( 'No items.' ) . '</p>';
  634.         return;
  635.     }
  636.  
  637.     $num_pages = ceil( wp_count_terms( $taxonomy_name , array_merge( $args, array('number' => '', 'offset' => '') ) ) / $per_page );
  638.  
  639.     $page_links = paginate_links( array(
  640.         'base' => add_query_arg(
  641.             array(
  642.                 $taxonomy_name . '-tab' => 'all',
  643.                 'paged' => '%#%',
  644.                 'item-type' => 'taxonomy',
  645.                 'item-object' => $taxonomy_name,
  646.             )
  647.         ),
  648.         'format' => '',
  649.         'prev_text'          => '<span aria-label="' . esc_attr__( 'Previous page' ) . '">' . __( '«' ) . '</span>',
  650.         'next_text'          => '<span aria-label="' . esc_attr__( 'Next page' ) . '">' . __( '»' ) . '</span>',
  651.         'before_page_number' => '<span class="screen-reader-text">' . __( 'Page' ) . '</span> ',
  652.         'total'   => $num_pages,
  653.         'current' => $pagenum
  654.     ));
  655.  
  656.     $db_fields = false;
  657.     if ( is_taxonomy_hierarchical( $taxonomy_name ) ) {
  658.         $db_fields = array( 'parent' => 'parent', 'id' => 'term_id' );
  659.     }
  660.  
  661.     $walker = new Walker_Nav_Menu_Checklist( $db_fields );
  662.  
  663.     $current_tab = 'most-used';
  664.     if ( isset( $_REQUEST[$taxonomy_name . '-tab'] ) && in_array( $_REQUEST[$taxonomy_name . '-tab'], array('all', 'most-used', 'search') ) ) {
  665.         $current_tab = $_REQUEST[$taxonomy_name . '-tab'];
  666.     }
  667.  
  668.     if ( ! empty( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] ) ) {
  669.         $current_tab = 'search';
  670.     }
  671.  
  672.     $removed_args = array(
  673.         'action',
  674.         'customlink-tab',
  675.         'edit-menu-item',
  676.         'menu-item',
  677.         'page-tab',
  678.         '_wpnonce',
  679.     );
  680.  
  681.     ?>
  682.     <div id="taxonomy-<?php echo $taxonomy_name; ?>" class="taxonomydiv">
  683.         <ul id="taxonomy-<?php echo $taxonomy_name; ?>-tabs" class="taxonomy-tabs add-menu-item-tabs">
  684.             <li <?php echo ( 'most-used' == $current_tab ? ' class="tabs"' : '' ); ?>>
  685.                 <a class="nav-tab-link" data-type="tabs-panel-<?php echo esc_attr( $taxonomy_name ); ?>-pop" 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">
  686.                     <?php echo esc_html( $taxonomy->labels->most_used ); ?>
  687.                 </a>
  688.             </li>
  689.             <li <?php echo ( 'all' == $current_tab ? ' class="tabs"' : '' ); ?>>
  690.                 <a class="nav-tab-link" data-type="tabs-panel-<?php echo esc_attr( $taxonomy_name ); ?>-all" 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">
  691.                     <?php _e( 'View All' ); ?>
  692.                 </a>
  693.             </li>
  694.             <li <?php echo ( 'search' == $current_tab ? ' class="tabs"' : '' ); ?>>
  695.                 <a class="nav-tab-link" data-type="tabs-panel-search-taxonomy-<?php echo esc_attr( $taxonomy_name ); ?>" 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; ?>">
  696.                     <?php _e( 'Search' ); ?>
  697.                 </a>
  698.             </li>
  699.         </ul><!-- .taxonomy-tabs -->
  700.  
  701.         <div id="tabs-panel-<?php echo $taxonomy_name; ?>-pop" class="tabs-panel <?php
  702.             echo ( 'most-used' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
  703.         ?>">
  704.             <ul id="<?php echo $taxonomy_name; ?>checklist-pop" class="categorychecklist form-no-clear" >
  705.                 <?php
  706.                 $popular_terms = get_terms( $taxonomy_name, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
  707.                 $args['walker'] = $walker;
  708.                 echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $popular_terms), 0, (object) $args );
  709.                 ?>
  710.             </ul>
  711.         </div><!-- /.tabs-panel -->
  712.  
  713.         <div id="tabs-panel-<?php echo $taxonomy_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php
  714.             echo ( 'all' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
  715.         ?>">
  716.             <?php if ( ! empty( $page_links ) ) : ?>
  717.                 <div class="add-menu-item-pagelinks">
  718.                     <?php echo $page_links; ?>
  719.                 </div>
  720.             <?php endif; ?>
  721.             <ul id="<?php echo $taxonomy_name; ?>checklist" data-wp-lists="list:<?php echo $taxonomy_name?>" class="categorychecklist form-no-clear">
  722.                 <?php
  723.                 $args['walker'] = $walker;
  724.                 echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $terms), 0, (object) $args );
  725.                 ?>
  726.             </ul>
  727.             <?php if ( ! empty( $page_links ) ) : ?>
  728.                 <div class="add-menu-item-pagelinks">
  729.                     <?php echo $page_links; ?>
  730.                 </div>
  731.             <?php endif; ?>
  732.         </div><!-- /.tabs-panel -->
  733.  
  734.         <div class="tabs-panel <?php
  735.             echo ( 'search' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
  736.         ?>" id="tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>">
  737.             <?php
  738.             if ( isset( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] ) ) {
  739.                 $searched = esc_attr( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] );
  740.                 $search_results = get_terms( $taxonomy_name, array( 'name__like' => $searched, 'fields' => 'all', 'orderby' => 'count', 'order' => 'DESC', 'hierarchical' => false ) );
  741.             } else {
  742.                 $searched = '';
  743.                 $search_results = array();
  744.             }
  745.             ?>
  746.             <p class="quick-search-wrap">
  747.                 <label for="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" class="screen-reader-text"><?php _e( 'Search' ); ?></label>
  748.                 <input type="search" class="quick-search" value="<?php echo $searched; ?>" name="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" id="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" />
  749.                 <span class="spinner"></span>
  750.                 <?php submit_button( __( 'Search' ), 'small quick-search-submit hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-taxonomy-' . $taxonomy_name ) ); ?>
  751.             </p>
  752.  
  753.             <ul id="<?php echo $taxonomy_name; ?>-search-checklist" data-wp-lists="list:<?php echo $taxonomy_name?>" class="categorychecklist form-no-clear">
  754.             <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
  755.                 <?php
  756.                 $args['walker'] = $walker;
  757.                 echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $search_results), 0, (object) $args );
  758.                 ?>
  759.             <?php elseif ( is_wp_error( $search_results ) ) : ?>
  760.                 <li><?php echo $search_results->get_error_message(); ?></li>
  761.             <?php elseif ( ! empty( $searched ) ) : ?>
  762.                 <li><?php _e('No results found.'); ?></li>
  763.             <?php endif; ?>
  764.             </ul>
  765.         </div><!-- /.tabs-panel -->
  766.  
  767.         <p class="button-controls wp-clearfix">
  768.             <span class="list-controls">
  769.                 <a href="<?php
  770.                     echo esc_url(add_query_arg(
  771.                         array(
  772.                             $taxonomy_name . '-tab' => 'all',
  773.                             'selectall' => 1,
  774.                         ),
  775.                         remove_query_arg($removed_args)
  776.                     ));
  777.                 ?>#taxonomy-<?php echo $taxonomy_name; ?>" class="select-all aria-button-if-js"><?php _e( 'Select All' ); ?></a>
  778.             </span>
  779.  
  780.             <span class="add-to-menu">
  781.                 <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-taxonomy-menu-item" id="<?php echo esc_attr( 'submit-taxonomy-' . $taxonomy_name ); ?>" />
  782.                 <span class="spinner"></span>
  783.             </span>
  784.         </p>
  785.  
  786.     </div><!-- /.taxonomydiv -->
  787.     <?php
  788. }
  789.  
  790. /**
  791.  * Save posted nav menu item data.
  792.  *
  793.  * @since 3.0.0
  794.  *
  795.  * @param int $menu_id The menu ID for which to save this item. $menu_id of 0 makes a draft, orphaned menu item.
  796.  * @param array $menu_data The unsanitized posted menu item data.
  797.  * @return array The database IDs of the items saved
  798.  */
  799. function wp_save_nav_menu_items( $menu_id = 0, $menu_data = array() ) {
  800.     $menu_id = (int) $menu_id;
  801.     $items_saved = array();
  802.  
  803.     if ( 0 == $menu_id || is_nav_menu( $menu_id ) ) {
  804.  
  805.         // Loop through all the menu items' POST values.
  806.         foreach ( (array) $menu_data as $_possible_db_id => $_item_object_data ) {
  807.             if (
  808.                 // Checkbox is not checked.
  809.                 empty( $_item_object_data['menu-item-object-id'] ) &&
  810.                 (
  811.                     // And item type either isn't set.
  812.                     ! isset( $_item_object_data['menu-item-type'] ) ||
  813.                     // Or URL is the default.
  814.                     in_array( $_item_object_data['menu-item-url'], array( 'http://', '' ) ) ||
  815.                     ! ( '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)
  816.                     // Or it *is* a custom menu item that already exists.
  817.                     ! empty( $_item_object_data['menu-item-db-id'] )
  818.                 )
  819.             ) {
  820.                 // Then this potential menu item is not getting added to this menu.
  821.                 continue;
  822.             }
  823.  
  824.             // If this possible menu item doesn't actually have a menu database ID yet.
  825.             if (
  826.                 empty( $_item_object_data['menu-item-db-id'] ) ||
  827.                 ( 0 > $_possible_db_id ) ||
  828.                 $_possible_db_id != $_item_object_data['menu-item-db-id']
  829.             ) {
  830.                 $_actual_db_id = 0;
  831.             } else {
  832.                 $_actual_db_id = (int) $_item_object_data['menu-item-db-id'];
  833.             }
  834.  
  835.             $args = array(
  836.                 'menu-item-db-id' => ( isset( $_item_object_data['menu-item-db-id'] ) ? $_item_object_data['menu-item-db-id'] : '' ),
  837.                 'menu-item-object-id' => ( isset( $_item_object_data['menu-item-object-id'] ) ? $_item_object_data['menu-item-object-id'] : '' ),
  838.                 'menu-item-object' => ( isset( $_item_object_data['menu-item-object'] ) ? $_item_object_data['menu-item-object'] : '' ),
  839.                 'menu-item-parent-id' => ( isset( $_item_object_data['menu-item-parent-id'] ) ? $_item_object_data['menu-item-parent-id'] : '' ),
  840.                 'menu-item-position' => ( isset( $_item_object_data['menu-item-position'] ) ? $_item_object_data['menu-item-position'] : '' ),
  841.                 'menu-item-type' => ( isset( $_item_object_data['menu-item-type'] ) ? $_item_object_data['menu-item-type'] : '' ),
  842.                 'menu-item-title' => ( isset( $_item_object_data['menu-item-title'] ) ? $_item_object_data['menu-item-title'] : '' ),
  843.                 'menu-item-url' => ( isset( $_item_object_data['menu-item-url'] ) ? $_item_object_data['menu-item-url'] : '' ),
  844.                 'menu-item-description' => ( isset( $_item_object_data['menu-item-description'] ) ? $_item_object_data['menu-item-description'] : '' ),
  845.                 'menu-item-attr-title' => ( isset( $_item_object_data['menu-item-attr-title'] ) ? $_item_object_data['menu-item-attr-title'] : '' ),
  846.                 'menu-item-target' => ( isset( $_item_object_data['menu-item-target'] ) ? $_item_object_data['menu-item-target'] : '' ),
  847.                 'menu-item-classes' => ( isset( $_item_object_data['menu-item-classes'] ) ? $_item_object_data['menu-item-classes'] : '' ),
  848.                 'menu-item-xfn' => ( isset( $_item_object_data['menu-item-xfn'] ) ? $_item_object_data['menu-item-xfn'] : '' ),
  849.             );
  850.  
  851.             $items_saved[] = wp_update_nav_menu_item( $menu_id, $_actual_db_id, $args );
  852.  
  853.         }
  854.     }
  855.     return $items_saved;
  856. }
  857.  
  858. /**
  859.  * Adds custom arguments to some of the meta box object types.
  860.  *
  861.  * @since 3.0.0
  862.  *
  863.  * @access private
  864.  *
  865.  * @param object $object The post type or taxonomy meta-object.
  866.  * @return object The post type of taxonomy object.
  867.  */
  868. function _wp_nav_menu_meta_box_object( $object = null ) {
  869.     if ( isset( $object->name ) ) {
  870.  
  871.         if ( 'page' == $object->name ) {
  872.             $object->_default_query = array(
  873.                 'orderby' => 'menu_order title',
  874.                 'post_status' => 'publish',
  875.             );
  876.  
  877.         // Posts should show only published items.
  878.         } elseif ( 'post' == $object->name ) {
  879.             $object->_default_query = array(
  880.                 'post_status' => 'publish',
  881.             );
  882.  
  883.         // Categories should be in reverse chronological order.
  884.         } elseif ( 'category' == $object->name ) {
  885.             $object->_default_query = array(
  886.                 'orderby' => 'id',
  887.                 'order' => 'DESC',
  888.             );
  889.  
  890.         // Custom post types should show only published items.
  891.         } else {
  892.             $object->_default_query = array(
  893.                 'post_status' => 'publish',
  894.             );
  895.         }
  896.     }
  897.  
  898.     return $object;
  899. }
  900.  
  901. /**
  902.  * Returns the menu formatted to edit.
  903.  *
  904.  * @since 3.0.0
  905.  *
  906.  * @param int $menu_id Optional. The ID of the menu to format. Default 0.
  907.  * @return string|WP_Error $output The menu formatted to edit or error object on failure.
  908.  */
  909. function wp_get_nav_menu_to_edit( $menu_id = 0 ) {
  910.     $menu = wp_get_nav_menu_object( $menu_id );
  911.  
  912.     // If the menu exists, get its items.
  913.     if ( is_nav_menu( $menu ) ) {
  914.         $menu_items = wp_get_nav_menu_items( $menu->term_id, array('post_status' => 'any') );
  915.         $result = '<div id="menu-instructions" class="post-body-plain';
  916.         $result .= ( ! empty($menu_items) ) ? ' menu-instructions-inactive">' : '">';
  917.         $result .= '<p>' . __( 'Add menu items from the column on the left.' ) . '</p>';
  918.         $result .= '</div>';
  919.  
  920.         if ( empty($menu_items) )
  921.             return $result . ' <ul class="menu" id="menu-to-edit"> </ul>';
  922.  
  923.         /**
  924.          * Filters the Walker class used when adding nav menu items.
  925.          *
  926.          * @since 3.0.0
  927.          *
  928.          * @param string $class   The walker class to use. Default 'Walker_Nav_Menu_Edit'.
  929.          * @param int    $menu_id ID of the menu being rendered.
  930.          */
  931.         $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $menu_id );
  932.  
  933.         if ( class_exists( $walker_class_name ) ) {
  934.             $walker = new $walker_class_name;
  935.         } else {
  936.             return new WP_Error( 'menu_walker_not_exist',
  937.                 /* translators: %s: walker class name */
  938.                 sprintf( __( 'The Walker class named %s does not exist.' ),
  939.                     '<strong>' . $walker_class_name . '</strong>'
  940.                 )
  941.             );
  942.         }
  943.  
  944.         $some_pending_menu_items = $some_invalid_menu_items = false;
  945.         foreach ( (array) $menu_items as $menu_item ) {
  946.             if ( isset( $menu_item->post_status ) && 'draft' == $menu_item->post_status )
  947.                 $some_pending_menu_items = true;
  948.             if ( ! empty( $menu_item->_invalid ) )
  949.                 $some_invalid_menu_items = true;
  950.         }
  951.  
  952.         if ( $some_pending_menu_items ) {
  953.             $result .= '<div class="notice notice-info notice-alt inline"><p>' . __( 'Click Save Menu to make pending menu items public.' ) . '</p></div>';
  954.         }
  955.  
  956.         if ( $some_invalid_menu_items ) {
  957.             $result .= '<div class="notice notice-error notice-alt inline"><p>' . __( 'There are some invalid menu items. Please check or delete them.' ) . '</p></div>';
  958.         }
  959.  
  960.         $result .= '<ul class="menu" id="menu-to-edit"> ';
  961.         $result .= walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $menu_items), 0, (object) array('walker' => $walker ) );
  962.         $result .= ' </ul> ';
  963.         return $result;
  964.     } elseif ( is_wp_error( $menu ) ) {
  965.         return $menu;
  966.     }
  967.  
  968. }
  969.  
  970. /**
  971.  * Returns the columns for the nav menus page.
  972.  *
  973.  * @since 3.0.0
  974.  *
  975.  * @return array Columns.
  976.  */
  977. function wp_nav_menu_manage_columns() {
  978.     return array(
  979.         '_title'          => __( 'Show advanced menu properties' ),
  980.         'cb'              => '<input type="checkbox" />',
  981.         'link-target'     => __( 'Link Target' ),
  982.         'title-attribute' => __( 'Title Attribute' ),
  983.         'css-classes'     => __( 'CSS Classes' ),
  984.         'xfn'             => __( 'Link Relationship (XFN)' ),
  985.         'description'     => __( 'Description' ),
  986.     );
  987. }
  988.  
  989. /**
  990.  * Deletes orphaned draft menu items
  991.  *
  992.  * @access private
  993.  * @since 3.0.0
  994.  *
  995.  * @global wpdb $wpdb WordPress database abstraction object.
  996.  */
  997. function _wp_delete_orphaned_draft_menu_items() {
  998.     global $wpdb;
  999.     $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
  1000.  
  1001.     // Delete orphaned draft menu items.
  1002.     $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 ) );
  1003.  
  1004.     foreach ( (array) $menu_items_to_delete as $menu_item_id )
  1005.         wp_delete_post( $menu_item_id, true );
  1006. }
  1007.  
  1008. /**
  1009.  * Saves nav menu items
  1010.  *
  1011.  * @since 3.6.0
  1012.  *
  1013.  * @param int|string $nav_menu_selected_id (id, slug, or name ) of the currently-selected menu
  1014.  * @param string $nav_menu_selected_title Title of the currently-selected menu
  1015.  * @return array $messages The menu updated message
  1016.  */
  1017. function wp_nav_menu_update_menu_items ( $nav_menu_selected_id, $nav_menu_selected_title ) {
  1018.     $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' ) );
  1019.     $messages = array();
  1020.     $menu_items = array();
  1021.     // Index menu items by db ID
  1022.     foreach ( $unsorted_menu_items as $_item )
  1023.         $menu_items[$_item->db_id] = $_item;
  1024.  
  1025.     $post_fields = array(
  1026.         'menu-item-db-id', 'menu-item-object-id', 'menu-item-object',
  1027.         'menu-item-parent-id', 'menu-item-position', 'menu-item-type',
  1028.         'menu-item-title', 'menu-item-url', 'menu-item-description',
  1029.         'menu-item-attr-title', 'menu-item-target', 'menu-item-classes', 'menu-item-xfn'
  1030.     );
  1031.  
  1032.     wp_defer_term_counting( true );
  1033.     // Loop through all the menu items' POST variables
  1034.     if ( ! empty( $_POST['menu-item-db-id'] ) ) {
  1035.         foreach ( (array) $_POST['menu-item-db-id'] as $_key => $k ) {
  1036.  
  1037.             // Menu item title can't be blank
  1038.             if ( ! isset( $_POST['menu-item-title'][ $_key ] ) || '' == $_POST['menu-item-title'][ $_key ] )
  1039.                 continue;
  1040.  
  1041.             $args = array();
  1042.             foreach ( $post_fields as $field )
  1043.                 $args[$field] = isset( $_POST[$field][$_key] ) ? $_POST[$field][$_key] : '';
  1044.  
  1045.             $menu_item_db_id = wp_update_nav_menu_item( $nav_menu_selected_id, ( $_POST['menu-item-db-id'][$_key] != $_key ? 0 : $_key ), $args );
  1046.  
  1047.             if ( is_wp_error( $menu_item_db_id ) ) {
  1048.                 $messages[] = '<div id="message" class="error"><p>' . $menu_item_db_id->get_error_message() . '</p></div>';
  1049.             } else {
  1050.                 unset( $menu_items[ $menu_item_db_id ] );
  1051.             }
  1052.         }
  1053.     }
  1054.  
  1055.     // Remove menu items from the menu that weren't in $_POST
  1056.     if ( ! empty( $menu_items ) ) {
  1057.         foreach ( array_keys( $menu_items ) as $menu_item_id ) {
  1058.             if ( is_nav_menu_item( $menu_item_id ) ) {
  1059.                 wp_delete_post( $menu_item_id );
  1060.             }
  1061.         }
  1062.     }
  1063.  
  1064.     // Store 'auto-add' pages.
  1065.     $auto_add = ! empty( $_POST['auto-add-pages'] );
  1066.     $nav_menu_option = (array) get_option( 'nav_menu_options' );
  1067.     if ( ! isset( $nav_menu_option['auto_add'] ) )
  1068.         $nav_menu_option['auto_add'] = array();
  1069.     if ( $auto_add ) {
  1070.         if ( ! in_array( $nav_menu_selected_id, $nav_menu_option['auto_add'] ) )
  1071.             $nav_menu_option['auto_add'][] = $nav_menu_selected_id;
  1072.     } else {
  1073.         if ( false !== ( $key = array_search( $nav_menu_selected_id, $nav_menu_option['auto_add'] ) ) )
  1074.             unset( $nav_menu_option['auto_add'][$key] );
  1075.     }
  1076.     // Remove nonexistent/deleted menus
  1077.     $nav_menu_option['auto_add'] = array_intersect( $nav_menu_option['auto_add'], wp_get_nav_menus( array( 'fields' => 'ids' ) ) );
  1078.     update_option( 'nav_menu_options', $nav_menu_option );
  1079.  
  1080.     wp_defer_term_counting( false );
  1081.  
  1082.     /** This action is documented in wp-includes/nav-menu.php */
  1083.     do_action( 'wp_update_nav_menu', $nav_menu_selected_id );
  1084.  
  1085.     $messages[] = '<div id="message" class="updated notice is-dismissible"><p>' .
  1086.         /* translators: %s: nav menu title */
  1087.         sprintf( __( '%s has been updated.' ),
  1088.             '<strong>' . $nav_menu_selected_title . '</strong>'
  1089.         ) . '</p></div>';
  1090.  
  1091.     unset( $menu_items, $unsorted_menu_items );
  1092.  
  1093.     return $messages;
  1094. }
  1095.  
  1096. /**
  1097.  * If a JSON blob of navigation menu data is in POST data, expand it and inject
  1098.  * it into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134.
  1099.  *
  1100.  * @ignore
  1101.  * @since 4.5.3
  1102.  * @access private
  1103.  */
  1104. function _wp_expand_nav_menu_post_data() {
  1105.     if ( ! isset( $_POST['nav-menu-data'] ) ) {
  1106.         return;
  1107.     }
  1108.  
  1109.     $data = json_decode( stripslashes( $_POST['nav-menu-data'] ) );
  1110.  
  1111.     if ( ! is_null( $data ) && $data ) {
  1112.         foreach ( $data as $post_input_data ) {
  1113.             // For input names that are arrays (e.g. `menu-item-db-id[3][4][5]`),
  1114.             // derive the array path┬ákeys via regex and set the value in $_POST.
  1115.             preg_match( '#([^\[]*)(\[(.+)\])?#', $post_input_data->name, $matches );
  1116.  
  1117.             $array_bits = array( $matches[1] );
  1118.  
  1119.             if ( isset( $matches[3] ) ) {
  1120.                 $array_bits = array_merge( $array_bits, explode( '][', $matches[3] ) );
  1121.             }
  1122.  
  1123.             $new_post_data = array();
  1124.  
  1125.             // Build the new array value from leaf to trunk.
  1126.             for ( $i = count( $array_bits ) - 1; $i >= 0; $i -- ) {
  1127.                 if ( $i == count( $array_bits ) - 1 ) {
  1128.                     $new_post_data[ $array_bits[ $i ] ] = wp_slash( $post_input_data->value );
  1129.                 } else {
  1130.                     $new_post_data = array( $array_bits[ $i ] => $new_post_data );
  1131.                 }
  1132.             }
  1133.  
  1134.             $_POST = array_replace_recursive( $_POST, $new_post_data );
  1135.         }
  1136.     }
  1137. }
  1138.