[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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'] ) ? $request['response-format'] : ''; 29 30 if ( ! $response_format || ! in_array( $response_format, array( 'json', 'markup' ), true ) ) { 31 $response_format = 'json'; 32 } 33 34 if ( 'markup' === $response_format ) { 35 $args['walker'] = new Walker_Nav_Menu_Checklist(); 36 } 37 38 if ( 'get-post-item' === $type ) { 39 if ( post_type_exists( $object_type ) ) { 40 if ( isset( $request['ID'] ) ) { 41 $object_id = (int) $request['ID']; 42 43 if ( 'markup' === $response_format ) { 44 echo walk_nav_menu_tree( 45 array_map( 'wp_setup_nav_menu_item', array( get_post( $object_id ) ) ), 46 0, 47 (object) $args 48 ); 49 } elseif ( 'json' === $response_format ) { 50 echo wp_json_encode( 51 array( 52 'ID' => $object_id, 53 'post_title' => get_the_title( $object_id ), 54 'post_type' => get_post_type( $object_id ), 55 ) 56 ); 57 echo "\n"; 58 } 59 } 60 } elseif ( taxonomy_exists( $object_type ) ) { 61 if ( isset( $request['ID'] ) ) { 62 $object_id = (int) $request['ID']; 63 64 if ( 'markup' === $response_format ) { 65 echo walk_nav_menu_tree( 66 array_map( 'wp_setup_nav_menu_item', array( get_term( $object_id, $object_type ) ) ), 67 0, 68 (object) $args 69 ); 70 } elseif ( 'json' === $response_format ) { 71 $post_obj = get_term( $object_id, $object_type ); 72 echo wp_json_encode( 73 array( 74 'ID' => $object_id, 75 'post_title' => $post_obj->name, 76 'post_type' => $object_type, 77 ) 78 ); 79 echo "\n"; 80 } 81 } 82 } 83 } elseif ( preg_match( '/quick-search-(posttype|taxonomy)-([a-zA-Z_-]*\b)/', $type, $matches ) ) { 84 if ( 'posttype' === $matches[1] && get_post_type_object( $matches[2] ) ) { 85 $post_type_obj = _wp_nav_menu_meta_box_object( get_post_type_object( $matches[2] ) ); 86 $args = array_merge( 87 $args, 88 array( 89 'no_found_rows' => true, 90 'update_post_meta_cache' => false, 91 'update_post_term_cache' => false, 92 'posts_per_page' => 10, 93 'post_type' => $matches[2], 94 's' => $query, 95 ) 96 ); 97 98 if ( isset( $post_type_obj->_default_query ) ) { 99 $args = array_merge( $args, (array) $post_type_obj->_default_query ); 100 } 101 102 $search_results_query = new WP_Query( $args ); 103 if ( ! $search_results_query->have_posts() ) { 104 return; 105 } 106 107 while ( $search_results_query->have_posts() ) { 108 $post = $search_results_query->next_post(); 109 110 if ( 'markup' === $response_format ) { 111 $var_by_ref = $post->ID; 112 echo walk_nav_menu_tree( 113 array_map( 'wp_setup_nav_menu_item', array( get_post( $var_by_ref ) ) ), 114 0, 115 (object) $args 116 ); 117 } elseif ( 'json' === $response_format ) { 118 echo wp_json_encode( 119 array( 120 'ID' => $post->ID, 121 'post_title' => get_the_title( $post->ID ), 122 'post_type' => $matches[2], 123 ) 124 ); 125 echo "\n"; 126 } 127 } 128 } elseif ( 'taxonomy' === $matches[1] ) { 129 $terms = get_terms( 130 array( 131 'taxonomy' => $matches[2], 132 'name__like' => $query, 133 'number' => 10, 134 'hide_empty' => false, 135 ) 136 ); 137 138 if ( empty( $terms ) || is_wp_error( $terms ) ) { 139 return; 140 } 141 142 foreach ( (array) $terms as $term ) { 143 if ( 'markup' === $response_format ) { 144 echo walk_nav_menu_tree( 145 array_map( 'wp_setup_nav_menu_item', array( $term ) ), 146 0, 147 (object) $args 148 ); 149 } elseif ( 'json' === $response_format ) { 150 echo wp_json_encode( 151 array( 152 'ID' => $term->term_id, 153 'post_title' => $term->name, 154 'post_type' => $matches[2], 155 ) 156 ); 157 echo "\n"; 158 } 159 } 160 } 161 } 162 } 163 164 /** 165 * Register nav menu meta boxes and advanced menu items. 166 * 167 * @since 3.0.0 168 */ 169 function wp_nav_menu_setup() { 170 // Register meta boxes. 171 wp_nav_menu_post_type_meta_boxes(); 172 add_meta_box( 173 'add-custom-links', 174 __( 'Custom Links' ), 175 'wp_nav_menu_item_link_meta_box', 176 'nav-menus', 177 'side', 178 'default' 179 ); 180 wp_nav_menu_taxonomy_meta_boxes(); 181 182 // Register advanced menu items (columns). 183 add_filter( 'manage_nav-menus_columns', 'wp_nav_menu_manage_columns' ); 184 185 // If first time editing, disable advanced items by default. 186 if ( false === get_user_option( 'managenav-menuscolumnshidden' ) ) { 187 $user = wp_get_current_user(); 188 update_user_meta( 189 $user->ID, 190 'managenav-menuscolumnshidden', 191 array( 192 0 => 'link-target', 193 1 => 'css-classes', 194 2 => 'xfn', 195 3 => 'description', 196 4 => 'title-attribute', 197 ) 198 ); 199 } 200 } 201 202 /** 203 * Limit the amount of meta boxes to pages, posts, links, and categories for first time users. 204 * 205 * @since 3.0.0 206 * 207 * @global array $wp_meta_boxes Global meta box state. 208 */ 209 function wp_initial_nav_menu_meta_boxes() { 210 global $wp_meta_boxes; 211 212 if ( get_user_option( 'metaboxhidden_nav-menus' ) !== false || ! is_array( $wp_meta_boxes ) ) { 213 return; 214 } 215 216 $initial_meta_boxes = array( 'add-post-type-page', 'add-post-type-post', 'add-custom-links', 'add-category' ); 217 $hidden_meta_boxes = array(); 218 219 foreach ( array_keys( $wp_meta_boxes['nav-menus'] ) as $context ) { 220 foreach ( array_keys( $wp_meta_boxes['nav-menus'][ $context ] ) as $priority ) { 221 foreach ( $wp_meta_boxes['nav-menus'][ $context ][ $priority ] as $box ) { 222 if ( in_array( $box['id'], $initial_meta_boxes, true ) ) { 223 unset( $box['id'] ); 224 } else { 225 $hidden_meta_boxes[] = $box['id']; 226 } 227 } 228 } 229 } 230 231 $user = wp_get_current_user(); 232 update_user_meta( $user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes ); 233 } 234 235 /** 236 * Creates meta boxes for any post type menu item.. 237 * 238 * @since 3.0.0 239 */ 240 function wp_nav_menu_post_type_meta_boxes() { 241 $post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'object' ); 242 243 if ( ! $post_types ) { 244 return; 245 } 246 247 foreach ( $post_types as $post_type ) { 248 /** 249 * Filters whether a menu items meta box will be added for the current 250 * object type. 251 * 252 * If a falsey value is returned instead of an object, the menu items 253 * meta box for the current meta box object will not be added. 254 * 255 * @since 3.0.0 256 * 257 * @param WP_Post_Type|false $post_type The current object to add a menu items 258 * meta box for. 259 */ 260 $post_type = apply_filters( 'nav_menu_meta_box_object', $post_type ); 261 262 if ( $post_type ) { 263 $id = $post_type->name; 264 // Give pages a higher priority. 265 $priority = ( 'page' === $post_type->name ? 'core' : 'default' ); 266 add_meta_box( 267 "add-post-type-{$id}", 268 $post_type->labels->name, 269 'wp_nav_menu_item_post_type_meta_box', 270 'nav-menus', 271 'side', 272 $priority, 273 $post_type 274 ); 275 } 276 } 277 } 278 279 /** 280 * Creates meta boxes for any taxonomy menu item. 281 * 282 * @since 3.0.0 283 */ 284 function wp_nav_menu_taxonomy_meta_boxes() { 285 $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'object' ); 286 287 if ( ! $taxonomies ) { 288 return; 289 } 290 291 foreach ( $taxonomies as $tax ) { 292 /** This filter is documented in wp-admin/includes/nav-menu.php */ 293 $tax = apply_filters( 'nav_menu_meta_box_object', $tax ); 294 295 if ( $tax ) { 296 $id = $tax->name; 297 add_meta_box( 298 "add-{$id}", 299 $tax->labels->name, 300 'wp_nav_menu_item_taxonomy_meta_box', 301 'nav-menus', 302 'side', 303 'default', 304 $tax 305 ); 306 } 307 } 308 } 309 310 /** 311 * Check whether to disable the Menu Locations meta box submit button and inputs. 312 * 313 * @since 3.6.0 314 * @since 5.3.1 The `$display` parameter was added. 315 * 316 * @global bool $one_theme_location_no_menus to determine if no menus exist 317 * 318 * @param int|string $nav_menu_selected_id ID, name, or slug of the currently selected menu. 319 * @param bool $display Whether to display or just return the string. 320 * @return string|false Disabled attribute if at least one menu exists, false if not. 321 */ 322 function wp_nav_menu_disabled_check( $nav_menu_selected_id, $display = true ) { 323 global $one_theme_location_no_menus; 324 325 if ( $one_theme_location_no_menus ) { 326 return false; 327 } 328 329 return disabled( $nav_menu_selected_id, 0, $display ); 330 } 331 332 /** 333 * Displays a meta box for the custom links menu item. 334 * 335 * @since 3.0.0 336 * 337 * @global int $_nav_menu_placeholder 338 * @global int|string $nav_menu_selected_id 339 */ 340 function wp_nav_menu_item_link_meta_box() { 341 global $_nav_menu_placeholder, $nav_menu_selected_id; 342 343 $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1; 344 345 ?> 346 <div class="customlinkdiv" id="customlinkdiv"> 347 <input type="hidden" value="custom" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" /> 348 <p id="menu-item-url-wrap" class="wp-clearfix"> 349 <label class="howto" for="custom-menu-item-url"><?php _e( 'URL' ); ?></label> 350 <input id="custom-menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" 351 type="text"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> 352 class="code menu-item-textbox form-required" placeholder="https://" 353 /> 354 </p> 355 356 <p id="menu-item-name-wrap" class="wp-clearfix"> 357 <label class="howto" for="custom-menu-item-name"><?php _e( 'Link Text' ); ?></label> 358 <input id="custom-menu-item-name" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-title]" 359 type="text"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> 360 class="regular-text menu-item-textbox" 361 /> 362 </p> 363 364 <p class="button-controls wp-clearfix"> 365 <span class="add-to-menu"> 366 <input id="submit-customlinkdiv" name="add-custom-menu-item" 367 type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> 368 class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" 369 /> 370 <span class="spinner"></span> 371 </span> 372 </p> 373 374 </div><!-- /.customlinkdiv --> 375 <?php 376 } 377 378 /** 379 * Displays a meta box for a post type menu item. 380 * 381 * @since 3.0.0 382 * 383 * @global int $_nav_menu_placeholder 384 * @global int|string $nav_menu_selected_id 385 * 386 * @param string $data_object Not used. 387 * @param array $box { 388 * Post type menu item meta box arguments. 389 * 390 * @type string $id Meta box 'id' attribute. 391 * @type string $title Meta box title. 392 * @type callable $callback Meta box display callback. 393 * @type WP_Post_Type $args Extra meta box arguments (the post type object for this meta box). 394 * } 395 */ 396 function wp_nav_menu_item_post_type_meta_box( $data_object, $box ) { 397 global $_nav_menu_placeholder, $nav_menu_selected_id; 398 399 $post_type_name = $box['args']->name; 400 $post_type = get_post_type_object( $post_type_name ); 401 $tab_name = $post_type_name . '-tab'; 402 403 // Paginate browsing for large numbers of post objects. 404 $per_page = 50; 405 $pagenum = isset( $_REQUEST[ $tab_name ] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1; 406 $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0; 407 408 $args = array( 409 'offset' => $offset, 410 'order' => 'ASC', 411 'orderby' => 'title', 412 'posts_per_page' => $per_page, 413 'post_type' => $post_type_name, 414 'suppress_filters' => true, 415 'update_post_term_cache' => false, 416 'update_post_meta_cache' => false, 417 ); 418 419 if ( isset( $box['args']->_default_query ) ) { 420 $args = array_merge( $args, (array) $box['args']->_default_query ); 421 } 422 423 /* 424 * If we're dealing with pages, let's prioritize the Front Page, 425 * Posts Page and Privacy Policy Page at the top of the list. 426 */ 427 $important_pages = array(); 428 if ( 'page' === $post_type_name ) { 429 $suppress_page_ids = array(); 430 431 // Insert Front Page or custom Home link. 432 $front_page = 'page' === get_option( 'show_on_front' ) ? (int) get_option( 'page_on_front' ) : 0; 433 434 $front_page_obj = null; 435 436 if ( ! empty( $front_page ) ) { 437 $front_page_obj = get_post( $front_page ); 438 } 439 440 if ( $front_page_obj ) { 441 $front_page_obj->front_or_home = true; 442 443 $important_pages[] = $front_page_obj; 444 $suppress_page_ids[] = $front_page_obj->ID; 445 } else { 446 $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? (int) $_nav_menu_placeholder - 1 : -1; 447 $front_page_obj = (object) array( 448 'front_or_home' => true, 449 'ID' => 0, 450 'object_id' => $_nav_menu_placeholder, 451 'post_content' => '', 452 'post_excerpt' => '', 453 'post_parent' => '', 454 'post_title' => _x( 'Home', 'nav menu home label' ), 455 'post_type' => 'nav_menu_item', 456 'type' => 'custom', 457 'url' => home_url( '/' ), 458 ); 459 460 $important_pages[] = $front_page_obj; 461 } 462 463 // Insert Posts Page. 464 $posts_page = 'page' === get_option( 'show_on_front' ) ? (int) get_option( 'page_for_posts' ) : 0; 465 466 if ( ! empty( $posts_page ) ) { 467 $posts_page_obj = get_post( $posts_page ); 468 469 if ( $posts_page_obj ) { 470 $front_page_obj->posts_page = true; 471 472 $important_pages[] = $posts_page_obj; 473 $suppress_page_ids[] = $posts_page_obj->ID; 474 } 475 } 476 477 // Insert Privacy Policy Page. 478 $privacy_policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); 479 480 if ( ! empty( $privacy_policy_page_id ) ) { 481 $privacy_policy_page = get_post( $privacy_policy_page_id ); 482 483 if ( $privacy_policy_page instanceof WP_Post && 'publish' === $privacy_policy_page->post_status ) { 484 $privacy_policy_page->privacy_policy_page = true; 485 486 $important_pages[] = $privacy_policy_page; 487 $suppress_page_ids[] = $privacy_policy_page->ID; 488 } 489 } 490 491 // Add suppression array to arguments for WP_Query. 492 if ( ! empty( $suppress_page_ids ) ) { 493 $args['post__not_in'] = $suppress_page_ids; 494 } 495 } 496 497 // @todo Transient caching of these results with proper invalidation on updating of a post of this type. 498 $get_posts = new WP_Query(); 499 $posts = $get_posts->query( $args ); 500 501 // Only suppress and insert when more than just suppression pages available. 502 if ( ! $get_posts->post_count ) { 503 if ( ! empty( $suppress_page_ids ) ) { 504 unset( $args['post__not_in'] ); 505 $get_posts = new WP_Query(); 506 $posts = $get_posts->query( $args ); 507 } else { 508 echo '<p>' . __( 'No items.' ) . '</p>'; 509 return; 510 } 511 } elseif ( ! empty( $important_pages ) ) { 512 $posts = array_merge( $important_pages, $posts ); 513 } 514 515 $num_pages = $get_posts->max_num_pages; 516 517 $page_links = paginate_links( 518 array( 519 'base' => add_query_arg( 520 array( 521 $tab_name => 'all', 522 'paged' => '%#%', 523 'item-type' => 'post_type', 524 'item-object' => $post_type_name, 525 ) 526 ), 527 'format' => '', 528 'prev_text' => '<span aria-label="' . esc_attr__( 'Previous page' ) . '">' . __( '«' ) . '</span>', 529 'next_text' => '<span aria-label="' . esc_attr__( 'Next page' ) . '">' . __( '»' ) . '</span>', 530 /* translators: Hidden accessibility text. */ 531 'before_page_number' => '<span class="screen-reader-text">' . __( 'Page' ) . '</span> ', 532 'total' => $num_pages, 533 'current' => $pagenum, 534 ) 535 ); 536 537 $db_fields = false; 538 if ( is_post_type_hierarchical( $post_type_name ) ) { 539 $db_fields = array( 540 'parent' => 'post_parent', 541 'id' => 'ID', 542 ); 543 } 544 545 $walker = new Walker_Nav_Menu_Checklist( $db_fields ); 546 547 $current_tab = 'most-recent'; 548 549 if ( isset( $_REQUEST[ $tab_name ] ) && in_array( $_REQUEST[ $tab_name ], array( 'all', 'search' ), true ) ) { 550 $current_tab = $_REQUEST[ $tab_name ]; 551 } 552 553 if ( ! empty( $_REQUEST[ "quick-search-posttype-{$post_type_name}" ] ) ) { 554 $current_tab = 'search'; 555 } 556 557 $removed_args = array( 558 'action', 559 'customlink-tab', 560 'edit-menu-item', 561 'menu-item', 562 'page-tab', 563 '_wpnonce', 564 ); 565 566 $most_recent_url = ''; 567 $view_all_url = ''; 568 $search_url = ''; 569 570 if ( $nav_menu_selected_id ) { 571 $most_recent_url = add_query_arg( $tab_name, 'most-recent', remove_query_arg( $removed_args ) ); 572 $view_all_url = add_query_arg( $tab_name, 'all', remove_query_arg( $removed_args ) ); 573 $search_url = add_query_arg( $tab_name, 'search', remove_query_arg( $removed_args ) ); 574 } 575 ?> 576 <div id="<?php echo esc_attr( "posttype-{$post_type_name}" ); ?>" class="posttypediv"> 577 <ul id="<?php echo esc_attr( "posttype-{$post_type_name}-tabs" ); ?>" class="posttype-tabs add-menu-item-tabs"> 578 <li <?php echo ( 'most-recent' === $current_tab ? ' class="tabs"' : '' ); ?>> 579 <a class="nav-tab-link" 580 data-type="<?php echo esc_attr( "tabs-panel-posttype-{$post_type_name}-most-recent" ); ?>" 581 href="<?php echo esc_url( $most_recent_url . "#tabs-panel-posttype-{$post_type_name}-most-recent" ); ?>" 582 > 583 <?php _e( 'Most Recent' ); ?> 584 </a> 585 </li> 586 <li <?php echo ( 'all' === $current_tab ? ' class="tabs"' : '' ); ?>> 587 <a class="nav-tab-link" 588 data-type="<?php echo esc_attr( "{$post_type_name}-all" ); ?>" 589 href="<?php echo esc_url( $view_all_url . "#{$post_type_name}-all" ); ?>" 590 > 591 <?php _e( 'View All' ); ?> 592 </a> 593 </li> 594 <li <?php echo ( 'search' === $current_tab ? ' class="tabs"' : '' ); ?>> 595 <a class="nav-tab-link" 596 data-type="<?php echo esc_attr( "tabs-panel-posttype-{$post_type_name}-search" ); ?>" 597 href="<?php echo esc_url( $search_url . "#tabs-panel-posttype-{$post_type_name}-search" ); ?>" 598 > 599 <?php _e( 'Search' ); ?> 600 </a> 601 </li> 602 </ul><!-- .posttype-tabs --> 603 604 <div id="<?php echo esc_attr( "tabs-panel-posttype-{$post_type_name}-most-recent" ); ?>" 605 class="tabs-panel <?php echo ( 'most-recent' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" 606 role="region" aria-label="<?php esc_attr_e( 'Most Recent' ); ?>" tabindex="0" 607 > 608 <ul id="<?php echo esc_attr( "{$post_type_name}checklist-most-recent" ); ?>" 609 class="categorychecklist form-no-clear" 610 > 611 <?php 612 $recent_args = array_merge( 613 $args, 614 array( 615 'orderby' => 'post_date', 616 'order' => 'DESC', 617 'posts_per_page' => 15, 618 ) 619 ); 620 $most_recent = $get_posts->query( $recent_args ); 621 622 $args['walker'] = $walker; 623 624 /** 625 * Filters the posts displayed in the 'Most Recent' tab of the current 626 * post type's menu items meta box. 627 * 628 * The dynamic portion of the hook name, `$post_type_name`, refers to the post type name. 629 * 630 * Possible hook names include: 631 * 632 * - `nav_menu_items_post_recent` 633 * - `nav_menu_items_page_recent` 634 * 635 * @since 4.3.0 636 * @since 4.9.0 Added the `$recent_args` parameter. 637 * 638 * @param WP_Post[] $most_recent An array of post objects being listed. 639 * @param array $args An array of `WP_Query` arguments for the meta box. 640 * @param array $box Arguments passed to `wp_nav_menu_item_post_type_meta_box()`. 641 * @param array $recent_args An array of `WP_Query` arguments for 'Most Recent' tab. 642 */ 643 $most_recent = apply_filters( 644 "nav_menu_items_{$post_type_name}_recent", 645 $most_recent, 646 $args, 647 $box, 648 $recent_args 649 ); 650 651 echo walk_nav_menu_tree( 652 array_map( 'wp_setup_nav_menu_item', $most_recent ), 653 0, 654 (object) $args 655 ); 656 ?> 657 </ul> 658 </div><!-- /.tabs-panel --> 659 660 <div id="<?php echo esc_attr( "tabs-panel-posttype-{$post_type_name}-search" ); ?>" 661 class="tabs-panel <?php echo ( 'search' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" 662 role="region" aria-label="<?php echo esc_attr( $post_type->labels->search_items ); ?>" tabindex="0" 663 > 664 <?php 665 if ( isset( $_REQUEST[ "quick-search-posttype-{$post_type_name}" ] ) ) { 666 $searched = esc_attr( $_REQUEST[ "quick-search-posttype-{$post_type_name}" ] ); 667 $search_results = get_posts( 668 array( 669 's' => $searched, 670 'post_type' => $post_type_name, 671 'fields' => 'all', 672 'order' => 'DESC', 673 ) 674 ); 675 } else { 676 $searched = ''; 677 $search_results = array(); 678 } 679 ?> 680 <p class="quick-search-wrap"> 681 <label for="<?php echo esc_attr( "quick-search-posttype-{$post_type_name}" ); ?>" class="screen-reader-text"> 682 <?php 683 /* translators: Hidden accessibility text. */ 684 _e( 'Search' ); 685 ?> 686 </label> 687 <input type="search"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> 688 class="quick-search" value="<?php echo $searched; ?>" 689 name="<?php echo esc_attr( "quick-search-posttype-{$post_type_name}" ); ?>" 690 id="<?php echo esc_attr( "quick-search-posttype-{$post_type_name}" ); ?>" 691 /> 692 <span class="spinner"></span> 693 <?php 694 submit_button( 695 __( 'Search' ), 696 'small quick-search-submit hide-if-js', 697 'submit', 698 false, 699 array( 'id' => "submit-quick-search-posttype-{$post_type_name}" ) 700 ); 701 ?> 702 </p> 703 704 <ul id="<?php echo esc_attr( "{$post_type_name}-search-checklist" ); ?>" 705 data-wp-lists="<?php echo esc_attr( "list:{$post_type_name}" ); ?>" 706 class="categorychecklist form-no-clear" 707 > 708 <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?> 709 <?php 710 $args['walker'] = $walker; 711 echo walk_nav_menu_tree( 712 array_map( 'wp_setup_nav_menu_item', $search_results ), 713 0, 714 (object) $args 715 ); 716 ?> 717 <?php elseif ( is_wp_error( $search_results ) ) : ?> 718 <li><?php echo $search_results->get_error_message(); ?></li> 719 <?php elseif ( ! empty( $searched ) ) : ?> 720 <li><?php _e( 'No results found.' ); ?></li> 721 <?php endif; ?> 722 </ul> 723 </div><!-- /.tabs-panel --> 724 725 <div id="<?php echo esc_attr( "{$post_type_name}-all" ); ?>" 726 class="tabs-panel tabs-panel-view-all <?php echo ( 'all' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" 727 role="region" aria-label="<?php echo esc_attr( $post_type->labels->all_items ); ?>" tabindex="0" 728 > 729 <?php if ( ! empty( $page_links ) ) : ?> 730 <div class="add-menu-item-pagelinks"> 731 <?php echo $page_links; ?> 732 </div> 733 <?php endif; ?> 734 735 <ul id="<?php echo esc_attr( "{$post_type_name}checklist" ); ?>" 736 data-wp-lists="<?php echo esc_attr( "list:{$post_type_name}" ); ?>" 737 class="categorychecklist form-no-clear" 738 > 739 <?php 740 $args['walker'] = $walker; 741 742 if ( $post_type->has_archive ) { 743 $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? (int) $_nav_menu_placeholder - 1 : -1; 744 array_unshift( 745 $posts, 746 (object) array( 747 'ID' => 0, 748 'object_id' => $_nav_menu_placeholder, 749 'object' => $post_type_name, 750 'post_content' => '', 751 'post_excerpt' => '', 752 'post_title' => $post_type->labels->archives, 753 'post_type' => 'nav_menu_item', 754 'type' => 'post_type_archive', 755 'url' => get_post_type_archive_link( $post_type_name ), 756 ) 757 ); 758 } 759 760 /** 761 * Filters the posts displayed in the 'View All' tab of the current 762 * post type's menu items meta box. 763 * 764 * The dynamic portion of the hook name, `$post_type_name`, refers 765 * to the slug of the current post type. 766 * 767 * Possible hook names include: 768 * 769 * - `nav_menu_items_post` 770 * - `nav_menu_items_page` 771 * 772 * @since 3.2.0 773 * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object. 774 * 775 * @see WP_Query::query() 776 * 777 * @param object[] $posts The posts for the current post type. Mostly `WP_Post` objects, but 778 * can also contain "fake" post objects to represent other menu items. 779 * @param array $args An array of `WP_Query` arguments. 780 * @param WP_Post_Type $post_type The current post type object for this menu item meta box. 781 */ 782 $posts = apply_filters( 783 "nav_menu_items_{$post_type_name}", 784 $posts, 785 $args, 786 $post_type 787 ); 788 789 $checkbox_items = walk_nav_menu_tree( 790 array_map( 'wp_setup_nav_menu_item', $posts ), 791 0, 792 (object) $args 793 ); 794 795 echo $checkbox_items; 796 ?> 797 </ul> 798 799 <?php if ( ! empty( $page_links ) ) : ?> 800 <div class="add-menu-item-pagelinks"> 801 <?php echo $page_links; ?> 802 </div> 803 <?php endif; ?> 804 </div><!-- /.tabs-panel --> 805 806 <p class="button-controls wp-clearfix" data-items-type="<?php echo esc_attr( "posttype-{$post_type_name}" ); ?>"> 807 <span class="list-controls hide-if-no-js"> 808 <input type="checkbox"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> 809 id="<?php echo esc_attr( $tab_name ); ?>" class="select-all" 810 /> 811 <label for="<?php echo esc_attr( $tab_name ); ?>"><?php _e( 'Select All' ); ?></label> 812 </span> 813 814 <span class="add-to-menu"> 815 <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> 816 class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" 817 name="add-post-type-menu-item" id="<?php echo esc_attr( "submit-posttype-{$post_type_name}" ); ?>" 818 /> 819 <span class="spinner"></span> 820 </span> 821 </p> 822 823 </div><!-- /.posttypediv --> 824 <?php 825 } 826 827 /** 828 * Displays a meta box for a taxonomy menu item. 829 * 830 * @since 3.0.0 831 * 832 * @global int|string $nav_menu_selected_id 833 * 834 * @param string $data_object Not used. 835 * @param array $box { 836 * Taxonomy menu item meta box arguments. 837 * 838 * @type string $id Meta box 'id' attribute. 839 * @type string $title Meta box title. 840 * @type callable $callback Meta box display callback. 841 * @type object $args Extra meta box arguments (the taxonomy object for this meta box). 842 * } 843 */ 844 function wp_nav_menu_item_taxonomy_meta_box( $data_object, $box ) { 845 global $nav_menu_selected_id; 846 847 $taxonomy_name = $box['args']->name; 848 $taxonomy = get_taxonomy( $taxonomy_name ); 849 $tab_name = $taxonomy_name . '-tab'; 850 851 // Paginate browsing for large numbers of objects. 852 $per_page = 50; 853 $pagenum = isset( $_REQUEST[ $tab_name ] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1; 854 $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0; 855 856 $args = array( 857 'taxonomy' => $taxonomy_name, 858 'child_of' => 0, 859 'exclude' => '', 860 'hide_empty' => false, 861 'hierarchical' => 1, 862 'include' => '', 863 'number' => $per_page, 864 'offset' => $offset, 865 'order' => 'ASC', 866 'orderby' => 'name', 867 'pad_counts' => false, 868 ); 869 870 $terms = get_terms( $args ); 871 872 if ( ! $terms || is_wp_error( $terms ) ) { 873 echo '<p>' . __( 'No items.' ) . '</p>'; 874 return; 875 } 876 877 $num_pages = (int) ceil( 878 (int) wp_count_terms( 879 array_merge( 880 $args, 881 array( 882 'number' => '', 883 'offset' => '', 884 ) 885 ) 886 ) / $per_page 887 ); 888 889 $page_links = paginate_links( 890 array( 891 'base' => add_query_arg( 892 array( 893 $tab_name => 'all', 894 'paged' => '%#%', 895 'item-type' => 'taxonomy', 896 'item-object' => $taxonomy_name, 897 ) 898 ), 899 'format' => '', 900 'prev_text' => '<span aria-label="' . esc_attr__( 'Previous page' ) . '">' . __( '«' ) . '</span>', 901 'next_text' => '<span aria-label="' . esc_attr__( 'Next page' ) . '">' . __( '»' ) . '</span>', 902 /* translators: Hidden accessibility text. */ 903 'before_page_number' => '<span class="screen-reader-text">' . __( 'Page' ) . '</span> ', 904 'total' => $num_pages, 905 'current' => $pagenum, 906 ) 907 ); 908 909 $db_fields = false; 910 if ( is_taxonomy_hierarchical( $taxonomy_name ) ) { 911 $db_fields = array( 912 'parent' => 'parent', 913 'id' => 'term_id', 914 ); 915 } 916 917 $walker = new Walker_Nav_Menu_Checklist( $db_fields ); 918 919 $current_tab = 'most-used'; 920 921 if ( isset( $_REQUEST[ $tab_name ] ) && in_array( $_REQUEST[ $tab_name ], array( 'all', 'most-used', 'search' ), true ) ) { 922 $current_tab = $_REQUEST[ $tab_name ]; 923 } 924 925 if ( ! empty( $_REQUEST[ "quick-search-taxonomy-{$taxonomy_name}" ] ) ) { 926 $current_tab = 'search'; 927 } 928 929 $removed_args = array( 930 'action', 931 'customlink-tab', 932 'edit-menu-item', 933 'menu-item', 934 'page-tab', 935 '_wpnonce', 936 ); 937 938 $most_used_url = ''; 939 $view_all_url = ''; 940 $search_url = ''; 941 942 if ( $nav_menu_selected_id ) { 943 $most_used_url = add_query_arg( $tab_name, 'most-used', remove_query_arg( $removed_args ) ); 944 $view_all_url = add_query_arg( $tab_name, 'all', remove_query_arg( $removed_args ) ); 945 $search_url = add_query_arg( $tab_name, 'search', remove_query_arg( $removed_args ) ); 946 } 947 ?> 948 <div id="<?php echo esc_attr( "taxonomy-{$taxonomy_name}" ); ?>" class="taxonomydiv"> 949 <ul id="<?php echo esc_attr( "taxonomy-{$taxonomy_name}-tabs" ); ?>" class="taxonomy-tabs add-menu-item-tabs"> 950 <li <?php echo ( 'most-used' === $current_tab ? ' class="tabs"' : '' ); ?>> 951 <a class="nav-tab-link" 952 data-type="<?php echo esc_attr( "tabs-panel-{$taxonomy_name}-pop" ); ?>" 953 href="<?php echo esc_url( $most_used_url . "#tabs-panel-{$taxonomy_name}-pop" ); ?>" 954 > 955 <?php echo esc_html( $taxonomy->labels->most_used ); ?> 956 </a> 957 </li> 958 <li <?php echo ( 'all' === $current_tab ? ' class="tabs"' : '' ); ?>> 959 <a class="nav-tab-link" 960 data-type="<?php echo esc_attr( "tabs-panel-{$taxonomy_name}-all" ); ?>" 961 href="<?php echo esc_url( $view_all_url . "#tabs-panel-{$taxonomy_name}-all" ); ?>" 962 > 963 <?php _e( 'View All' ); ?> 964 </a> 965 </li> 966 <li <?php echo ( 'search' === $current_tab ? ' class="tabs"' : '' ); ?>> 967 <a class="nav-tab-link" 968 data-type="<?php echo esc_attr( "tabs-panel-search-taxonomy-{$taxonomy_name}" ); ?>" 969 href="<?php echo esc_url( $search_url . "#tabs-panel-search-taxonomy-{$taxonomy_name}" ); ?>" 970 > 971 <?php _e( 'Search' ); ?> 972 </a> 973 </li> 974 </ul><!-- .taxonomy-tabs --> 975 976 <div id="<?php echo esc_attr( "tabs-panel-{$taxonomy_name}-pop" ); ?>" 977 class="tabs-panel <?php echo ( 'most-used' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" 978 role="region" aria-label="<?php echo esc_attr( $taxonomy->labels->most_used ); ?>" tabindex="0" 979 > 980 <ul id="<?php echo esc_attr( "{$taxonomy_name}checklist-pop" ); ?>" 981 class="categorychecklist form-no-clear" 982 > 983 <?php 984 $popular_terms = get_terms( 985 array( 986 'taxonomy' => $taxonomy_name, 987 'orderby' => 'count', 988 'order' => 'DESC', 989 'number' => 10, 990 'hierarchical' => false, 991 ) 992 ); 993 994 $args['walker'] = $walker; 995 echo walk_nav_menu_tree( 996 array_map( 'wp_setup_nav_menu_item', $popular_terms ), 997 0, 998 (object) $args 999 ); 1000 ?> 1001 </ul> 1002 </div><!-- /.tabs-panel --> 1003 1004 <div id="<?php echo esc_attr( "tabs-panel-{$taxonomy_name}-all" ); ?>" 1005 class="tabs-panel tabs-panel-view-all <?php echo ( 'all' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" 1006 role="region" aria-label="<?php echo esc_attr( $taxonomy->labels->all_items ); ?>" tabindex="0" 1007 > 1008 <?php if ( ! empty( $page_links ) ) : ?> 1009 <div class="add-menu-item-pagelinks"> 1010 <?php echo $page_links; ?> 1011 </div> 1012 <?php endif; ?> 1013 1014 <ul id="<?php echo esc_attr( "{$taxonomy_name}checklist" ); ?>" 1015 data-wp-lists="<?php echo esc_attr( "list:{$taxonomy_name}" ); ?>" 1016 class="categorychecklist form-no-clear" 1017 > 1018 <?php 1019 $args['walker'] = $walker; 1020 echo walk_nav_menu_tree( 1021 array_map( 'wp_setup_nav_menu_item', $terms ), 1022 0, 1023 (object) $args 1024 ); 1025 ?> 1026 </ul> 1027 1028 <?php if ( ! empty( $page_links ) ) : ?> 1029 <div class="add-menu-item-pagelinks"> 1030 <?php echo $page_links; ?> 1031 </div> 1032 <?php endif; ?> 1033 </div><!-- /.tabs-panel --> 1034 1035 <div id="<?php echo esc_attr( "tabs-panel-search-taxonomy-{$taxonomy_name}" ); ?>" 1036 class="tabs-panel <?php echo ( 'search' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" 1037 role="region" aria-label="<?php echo esc_attr( $taxonomy->labels->search_items ); ?>" tabindex="0"> 1038 <?php 1039 if ( isset( $_REQUEST[ "quick-search-taxonomy-{$taxonomy_name}" ] ) ) { 1040 $searched = esc_attr( $_REQUEST[ "quick-search-taxonomy-{$taxonomy_name}" ] ); 1041 $search_results = get_terms( 1042 array( 1043 'taxonomy' => $taxonomy_name, 1044 'name__like' => $searched, 1045 'fields' => 'all', 1046 'orderby' => 'count', 1047 'order' => 'DESC', 1048 'hierarchical' => false, 1049 ) 1050 ); 1051 } else { 1052 $searched = ''; 1053 $search_results = array(); 1054 } 1055 ?> 1056 <p class="quick-search-wrap"> 1057 <label for="<?php echo esc_attr( "quick-search-taxonomy-{$taxonomy_name}" ); ?>" class="screen-reader-text"> 1058 <?php 1059 /* translators: Hidden accessibility text. */ 1060 _e( 'Search' ); 1061 ?> 1062 </label> 1063 <input type="search" 1064 class="quick-search" value="<?php echo $searched; ?>" 1065 name="<?php echo esc_attr( "quick-search-taxonomy-{$taxonomy_name}" ); ?>" 1066 id="<?php echo esc_attr( "quick-search-taxonomy-{$taxonomy_name}" ); ?>" 1067 /> 1068 <span class="spinner"></span> 1069 <?php 1070 submit_button( 1071 __( 'Search' ), 1072 'small quick-search-submit hide-if-js', 1073 'submit', 1074 false, 1075 array( 'id' => "submit-quick-search-taxonomy-{$taxonomy_name}" ) 1076 ); 1077 ?> 1078 </p> 1079 1080 <ul id="<?php echo esc_attr( "{$taxonomy_name}-search-checklist" ); ?>" 1081 data-wp-lists="<?php echo esc_attr( "list:{$taxonomy_name}" ); ?>" 1082 class="categorychecklist form-no-clear" 1083 > 1084 <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?> 1085 <?php 1086 $args['walker'] = $walker; 1087 echo walk_nav_menu_tree( 1088 array_map( 'wp_setup_nav_menu_item', $search_results ), 1089 0, 1090 (object) $args 1091 ); 1092 ?> 1093 <?php elseif ( is_wp_error( $search_results ) ) : ?> 1094 <li><?php echo $search_results->get_error_message(); ?></li> 1095 <?php elseif ( ! empty( $searched ) ) : ?> 1096 <li><?php _e( 'No results found.' ); ?></li> 1097 <?php endif; ?> 1098 </ul> 1099 </div><!-- /.tabs-panel --> 1100 1101 <p class="button-controls wp-clearfix" data-items-type="<?php echo esc_attr( "taxonomy-{$taxonomy_name}" ); ?>"> 1102 <span class="list-controls hide-if-no-js"> 1103 <input type="checkbox"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> 1104 id="<?php echo esc_attr( $tab_name ); ?>" class="select-all" 1105 /> 1106 <label for="<?php echo esc_attr( $tab_name ); ?>"><?php _e( 'Select All' ); ?></label> 1107 </span> 1108 1109 <span class="add-to-menu"> 1110 <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> 1111 class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" 1112 name="add-taxonomy-menu-item" id="<?php echo esc_attr( "submit-taxonomy-{$taxonomy_name}" ); ?>" 1113 /> 1114 <span class="spinner"></span> 1115 </span> 1116 </p> 1117 1118 </div><!-- /.taxonomydiv --> 1119 <?php 1120 } 1121 1122 /** 1123 * Save posted nav menu item data. 1124 * 1125 * @since 3.0.0 1126 * 1127 * @param int $menu_id The menu ID for which to save this item. Value of 0 makes a draft, orphaned menu item. Default 0. 1128 * @param array[] $menu_data The unsanitized POSTed menu item data. 1129 * @return int[] The database IDs of the items saved 1130 */ 1131 function wp_save_nav_menu_items( $menu_id = 0, $menu_data = array() ) { 1132 $menu_id = (int) $menu_id; 1133 $items_saved = array(); 1134 1135 if ( 0 === $menu_id || is_nav_menu( $menu_id ) ) { 1136 1137 // Loop through all the menu items' POST values. 1138 foreach ( (array) $menu_data as $_possible_db_id => $_item_object_data ) { 1139 if ( 1140 // Checkbox is not checked. 1141 empty( $_item_object_data['menu-item-object-id'] ) && 1142 ( 1143 // And item type either isn't set. 1144 ! isset( $_item_object_data['menu-item-type'] ) || 1145 // Or URL is the default. 1146 in_array( $_item_object_data['menu-item-url'], array( 'https://', 'http://', '' ), true ) || 1147 // Or it's not a custom menu item (but not the custom home page). 1148 ! ( 'custom' === $_item_object_data['menu-item-type'] && ! isset( $_item_object_data['menu-item-db-id'] ) ) || 1149 // Or it *is* a custom menu item that already exists. 1150 ! empty( $_item_object_data['menu-item-db-id'] ) 1151 ) 1152 ) { 1153 // Then this potential menu item is not getting added to this menu. 1154 continue; 1155 } 1156 1157 // If this possible menu item doesn't actually have a menu database ID yet. 1158 if ( 1159 empty( $_item_object_data['menu-item-db-id'] ) || 1160 ( 0 > $_possible_db_id ) || 1161 $_possible_db_id !== (int) $_item_object_data['menu-item-db-id'] 1162 ) { 1163 $_actual_db_id = 0; 1164 } else { 1165 $_actual_db_id = (int) $_item_object_data['menu-item-db-id']; 1166 } 1167 1168 $args = array( 1169 'menu-item-db-id' => ( isset( $_item_object_data['menu-item-db-id'] ) ? $_item_object_data['menu-item-db-id'] : '' ), 1170 'menu-item-object-id' => ( isset( $_item_object_data['menu-item-object-id'] ) ? $_item_object_data['menu-item-object-id'] : '' ), 1171 'menu-item-object' => ( isset( $_item_object_data['menu-item-object'] ) ? $_item_object_data['menu-item-object'] : '' ), 1172 'menu-item-parent-id' => ( isset( $_item_object_data['menu-item-parent-id'] ) ? $_item_object_data['menu-item-parent-id'] : '' ), 1173 'menu-item-position' => ( isset( $_item_object_data['menu-item-position'] ) ? $_item_object_data['menu-item-position'] : '' ), 1174 'menu-item-type' => ( isset( $_item_object_data['menu-item-type'] ) ? $_item_object_data['menu-item-type'] : '' ), 1175 'menu-item-title' => ( isset( $_item_object_data['menu-item-title'] ) ? $_item_object_data['menu-item-title'] : '' ), 1176 'menu-item-url' => ( isset( $_item_object_data['menu-item-url'] ) ? $_item_object_data['menu-item-url'] : '' ), 1177 'menu-item-description' => ( isset( $_item_object_data['menu-item-description'] ) ? $_item_object_data['menu-item-description'] : '' ), 1178 'menu-item-attr-title' => ( isset( $_item_object_data['menu-item-attr-title'] ) ? $_item_object_data['menu-item-attr-title'] : '' ), 1179 'menu-item-target' => ( isset( $_item_object_data['menu-item-target'] ) ? $_item_object_data['menu-item-target'] : '' ), 1180 'menu-item-classes' => ( isset( $_item_object_data['menu-item-classes'] ) ? $_item_object_data['menu-item-classes'] : '' ), 1181 'menu-item-xfn' => ( isset( $_item_object_data['menu-item-xfn'] ) ? $_item_object_data['menu-item-xfn'] : '' ), 1182 ); 1183 1184 $items_saved[] = wp_update_nav_menu_item( $menu_id, $_actual_db_id, $args ); 1185 1186 } 1187 } 1188 1189 return $items_saved; 1190 } 1191 1192 /** 1193 * Adds custom arguments to some of the meta box object types. 1194 * 1195 * @since 3.0.0 1196 * 1197 * @access private 1198 * 1199 * @param object $data_object The post type or taxonomy meta-object. 1200 * @return object The post type or taxonomy object. 1201 */ 1202 function _wp_nav_menu_meta_box_object( $data_object = null ) { 1203 if ( isset( $data_object->name ) ) { 1204 1205 if ( 'page' === $data_object->name ) { 1206 $data_object->_default_query = array( 1207 'orderby' => 'menu_order title', 1208 'post_status' => 'publish', 1209 ); 1210 1211 // Posts should show only published items. 1212 } elseif ( 'post' === $data_object->name ) { 1213 $data_object->_default_query = array( 1214 'post_status' => 'publish', 1215 ); 1216 1217 // Categories should be in reverse chronological order. 1218 } elseif ( 'category' === $data_object->name ) { 1219 $data_object->_default_query = array( 1220 'orderby' => 'id', 1221 'order' => 'DESC', 1222 ); 1223 1224 // Custom post types should show only published items. 1225 } else { 1226 $data_object->_default_query = array( 1227 'post_status' => 'publish', 1228 ); 1229 } 1230 } 1231 1232 return $data_object; 1233 } 1234 1235 /** 1236 * Returns the menu formatted to edit. 1237 * 1238 * @since 3.0.0 1239 * 1240 * @param int $menu_id Optional. The ID of the menu to format. Default 0. 1241 * @return string|WP_Error The menu formatted to edit or error object on failure. 1242 */ 1243 function wp_get_nav_menu_to_edit( $menu_id = 0 ) { 1244 $menu = wp_get_nav_menu_object( $menu_id ); 1245 1246 // If the menu exists, get its items. 1247 if ( is_nav_menu( $menu ) ) { 1248 $menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'post_status' => 'any' ) ); 1249 $result = '<div id="menu-instructions" class="post-body-plain'; 1250 $result .= ( ! empty( $menu_items ) ) ? ' menu-instructions-inactive">' : '">'; 1251 $result .= '<p>' . __( 'Add menu items from the column on the left.' ) . '</p>'; 1252 $result .= '</div>'; 1253 1254 if ( empty( $menu_items ) ) { 1255 return $result . ' <ul class="menu" id="menu-to-edit"> </ul>'; 1256 } 1257 1258 /** 1259 * Filters the Walker class used when adding nav menu items. 1260 * 1261 * @since 3.0.0 1262 * 1263 * @param string $class The walker class to use. Default 'Walker_Nav_Menu_Edit'. 1264 * @param int $menu_id ID of the menu being rendered. 1265 */ 1266 $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $menu_id ); 1267 1268 if ( class_exists( $walker_class_name ) ) { 1269 $walker = new $walker_class_name(); 1270 } else { 1271 return new WP_Error( 1272 'menu_walker_not_exist', 1273 sprintf( 1274 /* translators: %s: Walker class name. */ 1275 __( 'The Walker class named %s does not exist.' ), 1276 '<strong>' . $walker_class_name . '</strong>' 1277 ) 1278 ); 1279 } 1280 1281 $some_pending_menu_items = false; 1282 $some_invalid_menu_items = false; 1283 1284 foreach ( (array) $menu_items as $menu_item ) { 1285 if ( isset( $menu_item->post_status ) && 'draft' === $menu_item->post_status ) { 1286 $some_pending_menu_items = true; 1287 } 1288 if ( ! empty( $menu_item->_invalid ) ) { 1289 $some_invalid_menu_items = true; 1290 } 1291 } 1292 1293 if ( $some_pending_menu_items ) { 1294 $message = __( 'Click Save Menu to make pending menu items public.' ); 1295 $notice_args = array( 1296 'type' => 'info', 1297 'additional_classes' => array( 'notice-alt', 'inline' ), 1298 ); 1299 $result .= wp_get_admin_notice( $message, $notice_args ); 1300 } 1301 1302 if ( $some_invalid_menu_items ) { 1303 $message = __( 'There are some invalid menu items. Please check or delete them.' ); 1304 $notice_args = array( 1305 'type' => 'error', 1306 'additional_classes' => array( 'notice-alt', 'inline' ), 1307 ); 1308 $result .= wp_get_admin_notice( $message, $notice_args ); 1309 } 1310 1311 $result .= '<ul class="menu" id="menu-to-edit"> '; 1312 $result .= walk_nav_menu_tree( 1313 array_map( 'wp_setup_nav_menu_item', $menu_items ), 1314 0, 1315 (object) array( 'walker' => $walker ) 1316 ); 1317 $result .= ' </ul> '; 1318 1319 return $result; 1320 } elseif ( is_wp_error( $menu ) ) { 1321 return $menu; 1322 } 1323 } 1324 1325 /** 1326 * Returns the columns for the nav menus page. 1327 * 1328 * @since 3.0.0 1329 * 1330 * @return string[] Array of column titles keyed by their column name. 1331 */ 1332 function wp_nav_menu_manage_columns() { 1333 return array( 1334 '_title' => __( 'Show advanced menu properties' ), 1335 'cb' => '<input type="checkbox" />', 1336 'link-target' => __( 'Link Target' ), 1337 'title-attribute' => __( 'Title Attribute' ), 1338 'css-classes' => __( 'CSS Classes' ), 1339 'xfn' => __( 'Link Relationship (XFN)' ), 1340 'description' => __( 'Description' ), 1341 ); 1342 } 1343 1344 /** 1345 * Deletes orphaned draft menu items 1346 * 1347 * @access private 1348 * @since 3.0.0 1349 * 1350 * @global wpdb $wpdb WordPress database abstraction object. 1351 */ 1352 function _wp_delete_orphaned_draft_menu_items() { 1353 global $wpdb; 1354 1355 $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS ); 1356 1357 // Delete orphaned draft menu items. 1358 $menu_items_to_delete = $wpdb->get_col( 1359 $wpdb->prepare( 1360 "SELECT ID FROM $wpdb->posts AS p 1361 LEFT JOIN $wpdb->postmeta AS m ON p.ID = m.post_id 1362 WHERE post_type = 'nav_menu_item' AND post_status = 'draft' 1363 AND meta_key = '_menu_item_orphaned' AND meta_value < %d", 1364 $delete_timestamp 1365 ) 1366 ); 1367 1368 foreach ( (array) $menu_items_to_delete as $menu_item_id ) { 1369 wp_delete_post( $menu_item_id, true ); 1370 } 1371 } 1372 1373 /** 1374 * Saves nav menu items. 1375 * 1376 * @since 3.6.0 1377 * 1378 * @param int|string $nav_menu_selected_id ID, slug, or name of the currently-selected menu. 1379 * @param string $nav_menu_selected_title Title of the currently-selected menu. 1380 * @return string[] The menu updated messages. 1381 */ 1382 function wp_nav_menu_update_menu_items( $nav_menu_selected_id, $nav_menu_selected_title ) { 1383 $unsorted_menu_items = wp_get_nav_menu_items( 1384 $nav_menu_selected_id, 1385 array( 1386 'orderby' => 'ID', 1387 'output' => ARRAY_A, 1388 'output_key' => 'ID', 1389 'post_status' => 'draft,publish', 1390 ) 1391 ); 1392 1393 $messages = array(); 1394 $menu_items = array(); 1395 1396 // Index menu items by DB ID. 1397 foreach ( $unsorted_menu_items as $_item ) { 1398 $menu_items[ $_item->db_id ] = $_item; 1399 } 1400 1401 $post_fields = array( 1402 'menu-item-db-id', 1403 'menu-item-object-id', 1404 'menu-item-object', 1405 'menu-item-parent-id', 1406 'menu-item-position', 1407 'menu-item-type', 1408 'menu-item-title', 1409 'menu-item-url', 1410 'menu-item-description', 1411 'menu-item-attr-title', 1412 'menu-item-target', 1413 'menu-item-classes', 1414 'menu-item-xfn', 1415 ); 1416 1417 wp_defer_term_counting( true ); 1418 1419 // Loop through all the menu items' POST variables. 1420 if ( ! empty( $_POST['menu-item-db-id'] ) ) { 1421 foreach ( (array) $_POST['menu-item-db-id'] as $_key => $k ) { 1422 1423 // Menu item title can't be blank. 1424 if ( ! isset( $_POST['menu-item-title'][ $_key ] ) || '' === $_POST['menu-item-title'][ $_key ] ) { 1425 continue; 1426 } 1427 1428 $args = array(); 1429 foreach ( $post_fields as $field ) { 1430 $args[ $field ] = isset( $_POST[ $field ][ $_key ] ) ? $_POST[ $field ][ $_key ] : ''; 1431 } 1432 1433 $menu_item_db_id = wp_update_nav_menu_item( 1434 $nav_menu_selected_id, 1435 ( (int) $_POST['menu-item-db-id'][ $_key ] !== $_key ? 0 : $_key ), 1436 $args 1437 ); 1438 1439 if ( is_wp_error( $menu_item_db_id ) ) { 1440 $messages[] = wp_get_admin_notice( 1441 $menu_item_db_id->get_error_message(), 1442 array( 1443 'id' => 'message', 1444 'additional_classes' => array( 'error' ), 1445 ) 1446 ); 1447 } else { 1448 unset( $menu_items[ $menu_item_db_id ] ); 1449 } 1450 } 1451 } 1452 1453 // Remove menu items from the menu that weren't in $_POST. 1454 if ( ! empty( $menu_items ) ) { 1455 foreach ( array_keys( $menu_items ) as $menu_item_id ) { 1456 if ( is_nav_menu_item( $menu_item_id ) ) { 1457 wp_delete_post( $menu_item_id ); 1458 } 1459 } 1460 } 1461 1462 // Store 'auto-add' pages. 1463 $auto_add = ! empty( $_POST['auto-add-pages'] ); 1464 $nav_menu_option = (array) get_option( 'nav_menu_options' ); 1465 1466 if ( ! isset( $nav_menu_option['auto_add'] ) ) { 1467 $nav_menu_option['auto_add'] = array(); 1468 } 1469 1470 if ( $auto_add ) { 1471 if ( ! in_array( $nav_menu_selected_id, $nav_menu_option['auto_add'], true ) ) { 1472 $nav_menu_option['auto_add'][] = $nav_menu_selected_id; 1473 } 1474 } else { 1475 $key = array_search( $nav_menu_selected_id, $nav_menu_option['auto_add'], true ); 1476 if ( false !== $key ) { 1477 unset( $nav_menu_option['auto_add'][ $key ] ); 1478 } 1479 } 1480 1481 // Remove non-existent/deleted menus. 1482 $nav_menu_option['auto_add'] = array_intersect( 1483 $nav_menu_option['auto_add'], 1484 wp_get_nav_menus( array( 'fields' => 'ids' ) ) 1485 ); 1486 1487 update_option( 'nav_menu_options', $nav_menu_option, false ); 1488 1489 wp_defer_term_counting( false ); 1490 1491 /** This action is documented in wp-includes/nav-menu.php */ 1492 do_action( 'wp_update_nav_menu', $nav_menu_selected_id ); 1493 1494 /* translators: %s: Nav menu title. */ 1495 $message = sprintf( __( '%s has been updated.' ), '<strong>' . $nav_menu_selected_title . '</strong>' ); 1496 $notice_args = array( 1497 'id' => 'message', 1498 'dismissible' => true, 1499 'additional_classes' => array( 'updated' ), 1500 ); 1501 1502 $messages[] = wp_get_admin_notice( $message, $notice_args ); 1503 1504 unset( $menu_items, $unsorted_menu_items ); 1505 1506 return $messages; 1507 } 1508 1509 /** 1510 * If a JSON blob of navigation menu data is in POST data, expand it and inject 1511 * it into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134. 1512 * 1513 * @ignore 1514 * @since 4.5.3 1515 * @access private 1516 */ 1517 function _wp_expand_nav_menu_post_data() { 1518 if ( ! isset( $_POST['nav-menu-data'] ) ) { 1519 return; 1520 } 1521 1522 $data = json_decode( stripslashes( $_POST['nav-menu-data'] ) ); 1523 1524 if ( ! is_null( $data ) && $data ) { 1525 foreach ( $data as $post_input_data ) { 1526 /* 1527 * For input names that are arrays (e.g. `menu-item-db-id[3][4][5]`), 1528 * derive the array path keys via regex and set the value in $_POST. 1529 */ 1530 preg_match( '#([^\[]*)(\[(.+)\])?#', $post_input_data->name, $matches ); 1531 1532 $array_bits = array( $matches[1] ); 1533 1534 if ( isset( $matches[3] ) ) { 1535 $array_bits = array_merge( $array_bits, explode( '][', $matches[3] ) ); 1536 } 1537 1538 $new_post_data = array(); 1539 1540 // Build the new array value from leaf to trunk. 1541 for ( $i = count( $array_bits ) - 1; $i >= 0; $i-- ) { 1542 if ( count( $array_bits ) - 1 === $i ) { 1543 $new_post_data[ $array_bits[ $i ] ] = wp_slash( $post_input_data->value ); 1544 } else { 1545 $new_post_data = array( $array_bits[ $i ] => $new_post_data ); 1546 } 1547 } 1548 1549 $_POST = array_replace_recursive( $_POST, $new_post_data ); 1550 } 1551 } 1552 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sat Dec 21 08:20:01 2024 | Cross-referenced by PHPXref |