WordPress 编辑器(无论是文章编辑器还是站点编辑器)操作我们所称的实体记录。这些对象表示一篇文章、一个页面、一个用户、一个分类项、一个模板等。它们是存储在数据库中并由编辑器操作的数据。每个编辑器都可以同时获取、编辑和保存多个实体记录。

例如,在站点编辑器中打开一个页面时:

  • 你可以编辑页面本身的属性(标题、内容等)
  • 你可以编辑页面模板的属性(模板内容、设计等)
  • 你可以编辑与模板一起使用的模板部分(页眉、页脚)的属性。

编辑器会跟踪所有这些修改,并协调保存所有这些已修改的记录。这一切都是在 @wordpress/core-data 包中进行的。

编辑实体

要能够编辑一个实体,你需要先获取它并将其加载到 core-data store 中。例如,以下代码将 ID 为 1 的文章加载到 store 中。(实体是 post,post 1 是实体记录。)

wp.data.select( 'core' ).getEntityRecord( 'postType', 'post', 1 );

实体加载完成后,你就可以编辑它了。例如,以下代码将文章的标题设置为“Hello World”。对于每个已获取的实体记录,core-data store 会跟踪以下内容:

  • “已持久化”记录:从后端获取时该记录的最后状态。
  • “编辑”列表:针对记录的一个或多个属性所做的未保存的本地修改。

该包还提供了一组用于操作已获取实体记录的 action。

要编辑实体记录,你可以调用 editEntityRecord,它接受实体类型、实体 ID 以及新的实体记录作为参数。以下示例将 ID 为 1 的文章的标题设置为“Hello World”。

wp.data.dispatch( 'core' ).editEntityRecord( 'postType', 'post', 1, { title: 'Hello World' } );

编辑实体记录后,你就可以保存它了。以下代码保存 ID 为 1 的文章。

wp.data.dispatch( 'core' ).saveEditedEntityRecord( 'postType', 'post', 1 );

撤销/重做

由于 WordPress 编辑器允许同时编辑多个实体记录,core-data 包会在一个公共的撤销/重做栈中跟踪所有已获取并已编辑的实体记录。撤销/重做栈中的每个步骤都包含一个“编辑”列表,在调用 undo 或 redo action 时,这些编辑会被同时撤销或重做。

为了能够正确执行撤销和重做操作,编辑列表中的每个修改都包含以下信息:

  • 实体种类和名称:core-data 中的每个实体都由 (kind, name) 对标识。这对应于被修改实体的标识符。
  • 实体记录 ID:被修改记录的 ID。
  • 属性:被修改属性的名称。
  • From:属性之前的值(执行撤销操作时需要)。
  • To:属性的新值(执行重做操作时需要)。

例如,假设用户编辑了一篇文章的标题,接着修改了文章的别名(slug),然后又修改了与该文章一起使用的可重用区块的标题。以下信息会被存储在撤销/重做栈中:

  • [ { kind: 'postType', name: 'post', id: 1, property: 'title', from: '', to: 'Hello World' } ]
  • [ { kind: 'postType', name: 'post', id: 1, property: 'slug', from: 'Previous slug', to: 'This is the slug of the hello world post' } ]
  • [ { kind: 'postType', name: 'wp_block', id: 2, property: 'title', from: 'Reusable Block', to: 'Awesome Reusable Block' } ]

store 还会跟踪一个指向当前“撤销/重做”步骤的“指针”。默认情况下,该指针总是指向栈中的最后一项。当用户执行撤销或重做操作时,该指针会被更新。

缓存的更改

撤销/重做的核心行为还支持我们所说的“缓存修改”。这些修改不会立即存储到撤销/重做栈中。例如,当用户开始在文本字段中输入时,该字段的值会在 store 中被修改,但直到用户移到下一个单词之后或经过几毫秒之后,此修改才会被存储到撤销/重做栈中。这样做是为了避免为用户输入的每个字符都创建一个新的撤销/重做步骤。

缓存的更改保存在撤销/重做栈之外,即所谓的修改“缓存”中,只有当我们显式调用 __unstableCreateUndoLevel 或下一个修改不是缓存修改时,这些修改才会被存储到撤销/重做栈中。

默认情况下,所有对 editEntityRecord 的调用都被视为“非缓存”的,除非将 isCached 选项传递为 true。示例:

wp.data.dispatch( 'core' ).editEntityRecord( 'postType', 'post', 1, { title: 'Hello World' }, { isCached: true } );