函数文档

wp_ajax_add_menu_item()

💡 云策文档标注

概述

wp_ajax_add_menu_item() 是一个 WordPress AJAX 处理函数,用于通过 AJAX 请求添加导航菜单项。它验证用户权限、处理菜单项数据,并输出菜单项的 HTML 结构。

关键要点

  • 函数通过 check_ajax_referer() 验证 AJAX 请求安全性,并使用 current_user_can('edit_theme_options') 检查用户权限。
  • 处理非自定义菜单项(如 post_type、post_type_archive、taxonomy)时,通过 get_post()、get_post_type_object()、get_term() 获取对象数据,并使用 wp_setup_nav_menu_item() 恢复缺失属性。
  • 使用 wp_save_nav_menu_items() 保存菜单项数据,并处理可能的 WP_Error。
  • 通过 apply_filters('wp_edit_nav_menu_walker') 应用自定义 Walker 类,并使用 walk_nav_menu_tree() 生成菜单项的 HTML 输出。
  • 函数在 WordPress 3.1.0 版本中引入。

代码示例

// 示例:处理 AJAX 添加菜单项的核心逻辑片段
foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
    if ( ! empty( $menu_item_data['menu-item-type'] ) && 'custom' !== $menu_item_data['menu-item-type'] ) {
        // 根据类型获取对象并设置菜单项
        $_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
        $_menu_item = reset( $_menu_items );
        $menu_item_data['menu-item-description'] = $_menu_item->description;
    }
    $menu_items_data[] = $menu_item_data;
}

注意事项

  • 函数依赖于 wp-admin/includes/nav-menu.php 中的相关函数,如 wp_save_nav_menu_items() 和 wp_setup_nav_menu_item()。
  • 使用 wp_die() 处理错误或权限不足情况,确保 AJAX 响应正确终止。
  • 通过过滤器 wp_edit_nav_menu_walker 允许自定义菜单项的 Walker 类,增强扩展性。

📄 原文内容

Handles adding a menu item via AJAX.

Source

function wp_ajax_add_menu_item() {
	check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );

	if ( ! current_user_can( 'edit_theme_options' ) ) {
		wp_die( -1 );
	}

	require_once ABSPATH . 'wp-admin/includes/nav-menu.php';

	/*
	 * For performance reasons, we omit some object properties from the checklist.
	 * The following is a hacky way to restore them when adding non-custom items.
	 */
	$menu_items_data = array();

	foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
		if (
			! empty( $menu_item_data['menu-item-type'] ) &&
			'custom' !== $menu_item_data['menu-item-type'] &&
			! empty( $menu_item_data['menu-item-object-id'] )
		) {
			switch ( $menu_item_data['menu-item-type'] ) {
				case 'post_type':
					$_object = get_post( $menu_item_data['menu-item-object-id'] );
					break;

				case 'post_type_archive':
					$_object = get_post_type_object( $menu_item_data['menu-item-object'] );
					break;

				case 'taxonomy':
					$_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
					break;
			}

			$_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
			$_menu_item  = reset( $_menu_items );

			// Restore the missing menu item properties.
			$menu_item_data['menu-item-description'] = $_menu_item->description;
		}

		$menu_items_data[] = $menu_item_data;
	}

	$item_ids = wp_save_nav_menu_items( 0, $menu_items_data );
	if ( is_wp_error( $item_ids ) ) {
		wp_die( 0 );
	}

	$menu_items = array();

	foreach ( (array) $item_ids as $menu_item_id ) {
		$menu_obj = get_post( $menu_item_id );

		if ( ! empty( $menu_obj->ID ) ) {
			$menu_obj        = wp_setup_nav_menu_item( $menu_obj );
			$menu_obj->title = empty( $menu_obj->title ) ? __( 'Menu Item' ) : $menu_obj->title;
			$menu_obj->label = $menu_obj->title; // Don't show "(pending)" in ajax-added items.
			$menu_items[]    = $menu_obj;
		}
	}

	/** This filter is documented in wp-admin/includes/nav-menu.php */
	$walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] );

	if ( ! class_exists( $walker_class_name ) ) {
		wp_die( 0 );
	}

	if ( ! empty( $menu_items ) ) {
		$args = array(
			'after'       => '',
			'before'      => '',
			'link_after'  => '',
			'link_before' => '',
			'walker'      => new $walker_class_name(),
		);

		echo walk_nav_menu_tree( $menu_items, 0, (object) $args );
	}

	wp_die();
}

Hooks

apply_filters( ‘wp_edit_nav_menu_walker’, string $class, int $menu_id )

Filters the Walker class used when adding nav menu items.

Changelog

Version Description
3.1.0 Introduced.