函数文档

wp_ajax_inline_save()

💡 云策文档标注

概述

wp_ajax_inline_save() 是一个 WordPress AJAX 处理函数,用于从列表表格中快速编辑并保存文章。它执行权限检查、数据验证和文章更新操作。

关键要点

  • 处理 AJAX 请求,实现文章列表中的快速编辑保存功能。
  • 进行安全检查,包括 check_ajax_referer() 验证和 current_user_can() 权限检查。
  • 检查文章锁定状态,防止并发编辑冲突。
  • 处理文章数据,如状态、评论状态、ping 状态和分类术语。
  • 使用 edit_post() 更新文章,并调用 WP_List_Table::display_rows() 刷新列表显示。
  • 包含 apply_filters('quick_edit_show_taxonomy', ...) 钩子,用于控制分类在快速编辑面板中的显示。

代码示例

Source function wp_ajax_inline_save() {
global $mode;

check_ajax_referer( 'inlineeditnonce', '_inline_edit' );

if ( ! isset( $_POST['post_ID'] ) || ! (int) $_POST['post_ID'] ) {
    wp_die();
}

$post_id = (int) $_POST['post_ID'];

if ( 'page' === $_POST['post_type'] ) {
    if ( ! current_user_can( 'edit_page', $post_id ) ) {
        wp_die( __( 'Sorry, you are not allowed to edit this page.' ) );
    }
} else {
    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
    }
}

$last = wp_check_post_lock( $post_id );
if ( $last ) {
    $last_user      = get_userdata( $last );
    $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );

    /* translators: %s: User's display name. */
    $msg_template = __( 'Saving is disabled: %s is currently editing this post.' );

    if ( 'page' === $_POST['post_type'] ) {
        /* translators: %s: User's display name. */
        $msg_template = __( 'Saving is disabled: %s is currently editing this page.' );
    }

    printf( $msg_template, esc_html( $last_user_name ) );
    wp_die();
}

$data = &$_POST;

$post = get_post( $post_id, ARRAY_A );

// Since it's coming from the database.
$post = wp_slash( $post );

$data['content'] = $post['post_content'];
$data['excerpt'] = $post['post_excerpt'];

// Rename.
$data['user_ID'] = get_current_user_id();

if ( isset( $data['post_parent'] ) ) {
    $data['parent_id'] = $data['post_parent'];
}

// Status.
if ( isset( $data['keep_private'] ) && 'private' === $data['keep_private'] ) {
    $data['visibility']  = 'private';
    $data['post_status'] = 'private';
} elseif ( isset( $data['_status'] ) ) {
    $data['post_status'] = $data['_status'];
}

if ( empty( $data['comment_status'] ) ) {
    $data['comment_status'] = 'closed';
}

if ( empty( $data['ping_status'] ) ) {
    $data['ping_status'] = 'closed';
}

// Exclude terms from taxonomies that are not supposed to appear in Quick Edit.
if ( ! empty( $data['tax_input'] ) ) {
    foreach ( $data['tax_input'] as $taxonomy => $terms ) {
        $tax_object = get_taxonomy( $taxonomy );
        /** This filter is documented in wp-admin/includes/class-wp-posts-list-table.php */
        if ( ! apply_filters( 'quick_edit_show_taxonomy', $tax_object->show_in_quick_edit, $taxonomy, $post['post_type'] ) ) {
            unset( $data['tax_input'][ $taxonomy ] );
        }
    }
}

// Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ), true ) ) {
    $post['post_status'] = 'publish';
    $data['post_name']   = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
}

// Update the post.
edit_post();

$wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );

$mode = 'excerpt' === $_POST['post_view'] ? 'excerpt' : 'list';

$level = 0;
if ( is_post_type_hierarchical( $wp_list_table->screen->post_type ) ) {
    $request_post = array( get_post( $_POST['post_ID'] ) );
    $parent       = $request_post[0]->post_parent;

    while ( $parent > 0 ) {
        $parent_post = get_post( $parent );
        $parent      = $parent_post->post_parent;
        ++$level;
    }
}

$wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );

wp_die();
}

注意事项

  • 函数依赖于 $_POST 数据,需确保 AJAX 请求正确传递参数如 post_ID、post_type 等。
  • 使用 wp_check_post_lock() 防止多用户同时编辑,若锁定则返回错误信息。
  • 通过 apply_filters('quick_edit_show_taxonomy', ...) 可自定义分类在快速编辑中的可见性。
  • 对于草稿或待定状态的文章,会临时将状态设为发布以计算唯一 slug。
  • 函数结束时调用 wp_die() 终止执行,确保无额外输出。

📄 原文内容

Handles Quick Edit saving a post from a list table via AJAX.

Source

function wp_ajax_inline_save() {
	global $mode;

	check_ajax_referer( 'inlineeditnonce', '_inline_edit' );

	if ( ! isset( $_POST['post_ID'] ) || ! (int) $_POST['post_ID'] ) {
		wp_die();
	}

	$post_id = (int) $_POST['post_ID'];

	if ( 'page' === $_POST['post_type'] ) {
		if ( ! current_user_can( 'edit_page', $post_id ) ) {
			wp_die( __( 'Sorry, you are not allowed to edit this page.' ) );
		}
	} else {
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			wp_die( __( 'Sorry, you are not allowed to edit this post.' ) );
		}
	}

	$last = wp_check_post_lock( $post_id );
	if ( $last ) {
		$last_user      = get_userdata( $last );
		$last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );

		/* translators: %s: User's display name. */
		$msg_template = __( 'Saving is disabled: %s is currently editing this post.' );

		if ( 'page' === $_POST['post_type'] ) {
			/* translators: %s: User's display name. */
			$msg_template = __( 'Saving is disabled: %s is currently editing this page.' );
		}

		printf( $msg_template, esc_html( $last_user_name ) );
		wp_die();
	}

	$data = &$_POST;

	$post = get_post( $post_id, ARRAY_A );

	// Since it's coming from the database.
	$post = wp_slash( $post );

	$data['content'] = $post['post_content'];
	$data['excerpt'] = $post['post_excerpt'];

	// Rename.
	$data['user_ID'] = get_current_user_id();

	if ( isset( $data['post_parent'] ) ) {
		$data['parent_id'] = $data['post_parent'];
	}

	// Status.
	if ( isset( $data['keep_private'] ) && 'private' === $data['keep_private'] ) {
		$data['visibility']  = 'private';
		$data['post_status'] = 'private';
	} elseif ( isset( $data['_status'] ) ) {
		$data['post_status'] = $data['_status'];
	}

	if ( empty( $data['comment_status'] ) ) {
		$data['comment_status'] = 'closed';
	}

	if ( empty( $data['ping_status'] ) ) {
		$data['ping_status'] = 'closed';
	}

	// Exclude terms from taxonomies that are not supposed to appear in Quick Edit.
	if ( ! empty( $data['tax_input'] ) ) {
		foreach ( $data['tax_input'] as $taxonomy => $terms ) {
			$tax_object = get_taxonomy( $taxonomy );
			/** This filter is documented in wp-admin/includes/class-wp-posts-list-table.php */
			if ( ! apply_filters( 'quick_edit_show_taxonomy', $tax_object->show_in_quick_edit, $taxonomy, $post['post_type'] ) ) {
				unset( $data['tax_input'][ $taxonomy ] );
			}
		}
	}

	// Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
	if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ), true ) ) {
		$post['post_status'] = 'publish';
		$data['post_name']   = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
	}

	// Update the post.
	edit_post();

	$wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );

	$mode = 'excerpt' === $_POST['post_view'] ? 'excerpt' : 'list';

	$level = 0;
	if ( is_post_type_hierarchical( $wp_list_table->screen->post_type ) ) {
		$request_post = array( get_post( $_POST['post_ID'] ) );
		$parent       = $request_post[0]->post_parent;

		while ( $parent > 0 ) {
			$parent_post = get_post( $parent );
			$parent      = $parent_post->post_parent;
			++$level;
		}
	}

	$wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );

	wp_die();
}

Hooks

apply_filters( ‘quick_edit_show_taxonomy’, bool $show_in_quick_edit, string $taxonomy_name, string $post_type )

Filters whether the current taxonomy should be shown in the Quick Edit panel.

Changelog

Version Description
3.1.0 Introduced.