commit 2080fa3878105c4808fb0e916d268cfcf1fc8f91
Author: unknown <2551654928@qq.com>
Date: Wed Oct 22 01:33:45 2025 +0800
first commit
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..53c040d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,58 @@
+## 扩展资源
+
+本手册应被视为区块开发相关领域的权威资源,但以下其他资源也能为您提供帮助:
+
+- **[WordPress 开发者博客](https://developer.wordpress.org/news/):** 持续更新的技术文章库,涵盖区块开发专题及各类应用场景。该博客也是[跟进WordPress最新动态](https://developer.wordpress.org/news/tag/roundup/)的理想渠道。
+- **[Learn WordPress](https://learn.wordpress.org/):** WordPress官方学习中心,提供[《区块开发入门:创建你的第一个自定义区块》](https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/)、[《将简码转换为区块》](https://learn.wordpress.org/course/converting-a-shortcode-to-a-block/)、[《使用WordPress数据层》](https://learn.wordpress.org/course/using-the-wordpress-data-layer/)等系列课程。
+- **[WordPress.tv](https://wordpress.tv/):** 由WordPress社区维护的视频资源库,收录WordCamp演讲实录及在线研讨会录像。您一定能在此找到关于[区块开发](https://wordpress.tv/?s=block%20development&sort=newest)或[区块编辑器](https://wordpress.tv/?s=block%20editor&sort=relevance)的学习资料。
+- **[Gutenberg代码库](https://github.com/WordPress/gutenberg/):** 区块编辑器的开发在GitHub上进行。该仓库包含[`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src)(核心区块)与[`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components)(通用UI组件)等重要代码包。*[block-development-examples](https://github.com/WordPress/block-development-examples)代码库也是极佳的参考资源。*
+- **[终端用户文档](https://wordpress.org/documentation/):** 该文档站点面向终端用户(非开发者),同样收录了[区块编辑器](https://wordpress.org/documentation/category/block-editor/)与[区块操作指南](https://wordpress.org/documentation/article/work-with-blocks/)相关内容。
+
+## 确认您的需求场景
+
+《区块编辑器手册》专为基于区块编辑器进行创作和开发的用户设计。请注意,[开发者资源中心](https://developer.wordpress.org/)还提供了多本可能对您有益的手册:
+
+- [主题开发手册](https://developer.wordpress.org/themes)
+- [插件开发手册](https://developer.wordpress.org/plugins)
+- [通用API手册](https://developer.wordpress.org/apis)
+- [高级管理手册](https://developer.wordpress.org/advanced-administration)
+- [REST API手册](https://developer.wordpress.org/rest-api/)
+- [编码标准手册](https://developer.wordpress.org/coding-standards)
+
+# 区块编辑器手册
+
+欢迎使用区块编辑器手册。
+
+[**区块编辑器**](https://wordpress.org/gutenberg/) 是用于构建和发布 WordPress 网站的现代范式。它采用模块化的**区块**系统来创作和格式化内容,旨在为网站和数字产品创建丰富灵活的布局。
+
+区块编辑器包含以下几个主要元素,如下图所示:
+
+
+
+图中高亮显示的元素包括:
+
+1. **插入器:** 用于将区块插入内容画布的面板
+2. **内容画布:** 内容编辑器,承载使用区块创建的内容
+3. **设置面板:** 配置选定区块设置或文章设置的面板
+
+通过区块编辑器,您可以使用区块以模块化方式创建内容。WordPress 默认提供多种[区块](https://developer.wordpress.org/block-editor/reference-guides/core-blocks/),您也可以[创建自己的区块](https://developer.wordpress.org/block-editor/getting-started/create-block/)。
+
+[区块](https://developer.wordpress.org/block-editor/explanations/architecture/key-concepts/#blocks)是一个独立元素,例如段落、标题、媒体或嵌入内容。每个区块都被视为具有独立编辑和格式控件的单独元素。当所有这些组件组合在一起时,就构成了页面或文章的内容,随后这些内容将[存储到 WordPress 数据库](https://developer.wordpress.org/block-editor/explanations/architecture/data-flow/#serialization-and-parsing)中。
+
+区块编辑器是 [**Gutenberg 项目**](https://developer.wordpress.org/block-editor/getting-started/faq/#what-is-gutenberg)的工作成果,该项目旨在彻底改变 WordPress 的编辑体验。
+
+除了通过可视化内容创建工具提供[增强的编辑体验](https://wordpress.org/gutenberg/)外,区块编辑器还是一个强大的开发平台,拥有[丰富的 API 功能集](https://developer.wordpress.org/block-editor/reference-guides/),可通过无数种方式进行操作和扩展。
+
+## 手册使用指南
+
+本手册主要关注区块开发,分为五个主要部分:
+
+- **[入门指南](https://developer.wordpress.org/block-editor/getting-started/):** 适合刚接触区块开发的用户,您可以在此设置[开发环境](https://developer.wordpress.org/block-editor/getting-started/devenv/)并学习[区块开发基础知识](https://developer.wordpress.org/block-editor/getting-started/fundamentals/)。其中的[快速入门指南](https://developer.wordpress.org/block-editor/getting-started/quick-start-guide/)和[教程:构建您的第一个区块](https://developer.wordpress.org/block-editor/getting-started/tutorial/)是开始学习区块开发的理想起点。
+
+- **[操作指南](https://developer.wordpress.org/block-editor/how-to-guides/):** 在此部分,您可以基于入门指南所学知识,进一步学习如何解决特定问题。您还可以找到教程和示例代码,以便在自己的项目中重复使用,例如[处理 WordPress 数据](https://developer.wordpress.org/block-editor/how-to-guides/data-basics/)或[优化编辑器体验](https://developer.wordpress.org/block-editor/how-to-guides/curating-the-editor-experience/)。
+
+- **[参考指南](https://developer.wordpress.org/block-editor/reference-guides/):** 这是手册的核心部分,您可以在此深入了解细节,查找正在使用或需要了解的特定 API 的详细信息。[区块 API 参考](https://developer.wordpress.org/block-editor/reference-guides/block-api/)涵盖了您可能需要对区块执行的大部分操作,每个[组件](https://developer.wordpress.org/block-editor/reference-guides/components/)和[包](https://developer.wordpress.org/block-editor/reference-guides/packages/)也在此处记录。_组件还通过 [Storybook](https://wordpress.github.io/gutenberg/?path=/story/docs-introduction--page) 进行文档记录。_
+
+- **[原理解释](https://developer.wordpress.org/block-editor/explanations/):** 此部分让您能够更深入地学习,通过对区块编辑器[架构](https://developer.wordpress.org/block-editor/explanations/architecture/)的理论理解来巩固您的实践知识。
+
+- **[贡献者指南](https://developer.wordpress.org/block-editor/contributors/):** Gutenberg 是开源软件,欢迎所有人为此项目做出贡献。此部分详细说明了如何贡献,无论是通过[代码](https://developer.wordpress.org/block-editor/contributors/code/)、[设计](https://developer.wordpress.org/block-editor/contributors/design/)、[文档](https://developer.wordpress.org/block-editor/contributors/documentation/)还是其他方式。
\ No newline at end of file
diff --git a/assets/Locking comparison visual.png b/assets/Locking comparison visual.png
new file mode 100644
index 0000000..c223d68
Binary files /dev/null and b/assets/Locking comparison visual.png differ
diff --git a/assets/Locking interface.png b/assets/Locking interface.png
new file mode 100644
index 0000000..8ada25b
Binary files /dev/null and b/assets/Locking interface.png differ
diff --git a/assets/fancy-quote-in-inspector.png b/assets/fancy-quote-in-inspector.png
new file mode 100644
index 0000000..6bd8c06
Binary files /dev/null and b/assets/fancy-quote-in-inspector.png differ
diff --git a/assets/fancy-quote-with-style.png b/assets/fancy-quote-with-style.png
new file mode 100644
index 0000000..31f3806
Binary files /dev/null and b/assets/fancy-quote-with-style.png differ
diff --git a/assets/inspector.png b/assets/inspector.png
new file mode 100644
index 0000000..bd1a5ee
Binary files /dev/null and b/assets/inspector.png differ
diff --git a/assets/js-tutorial-console-log-error.png b/assets/js-tutorial-console-log-error.png
new file mode 100644
index 0000000..836a663
Binary files /dev/null and b/assets/js-tutorial-console-log-error.png differ
diff --git a/assets/js-tutorial-console-log-success.png b/assets/js-tutorial-console-log-success.png
new file mode 100644
index 0000000..7b42853
Binary files /dev/null and b/assets/js-tutorial-console-log-success.png differ
diff --git a/assets/js-tutorial-error-blocks-undefined.png b/assets/js-tutorial-error-blocks-undefined.png
new file mode 100644
index 0000000..1f27c36
Binary files /dev/null and b/assets/js-tutorial-error-blocks-undefined.png differ
diff --git a/assets/meta-block.png b/assets/meta-block.png
new file mode 100644
index 0000000..4fe3ebf
Binary files /dev/null and b/assets/meta-block.png differ
diff --git a/assets/overview-block-editor-2023.png b/assets/overview-block-editor-2023.png
new file mode 100644
index 0000000..ad3a6e1
Binary files /dev/null and b/assets/overview-block-editor-2023.png differ
diff --git a/assets/plugin-block-settings-menu-item-screenshot.png b/assets/plugin-block-settings-menu-item-screenshot.png
new file mode 100644
index 0000000..bc33b4f
Binary files /dev/null and b/assets/plugin-block-settings-menu-item-screenshot.png differ
diff --git a/assets/plugin-more-menu-item.png b/assets/plugin-more-menu-item.png
new file mode 100644
index 0000000..23fa73d
Binary files /dev/null and b/assets/plugin-more-menu-item.png differ
diff --git a/assets/plugin-post-publish-panel.png b/assets/plugin-post-publish-panel.png
new file mode 100644
index 0000000..b4cd931
Binary files /dev/null and b/assets/plugin-post-publish-panel.png differ
diff --git a/assets/plugin-post-status-info-location.png b/assets/plugin-post-status-info-location.png
new file mode 100644
index 0000000..fa35405
Binary files /dev/null and b/assets/plugin-post-status-info-location.png differ
diff --git a/assets/plugin-pre-publish-panel.png b/assets/plugin-pre-publish-panel.png
new file mode 100644
index 0000000..ea765f4
Binary files /dev/null and b/assets/plugin-pre-publish-panel.png differ
diff --git a/assets/plugin-sidebar-more-menu-item.gif b/assets/plugin-sidebar-more-menu-item.gif
new file mode 100644
index 0000000..8518984
Binary files /dev/null and b/assets/plugin-sidebar-more-menu-item.gif differ
diff --git a/assets/plugin-sidebar-open-state.png b/assets/plugin-sidebar-open-state.png
new file mode 100644
index 0000000..a114f71
Binary files /dev/null and b/assets/plugin-sidebar-open-state.png differ
diff --git a/assets/plugin-sidebar-text-control-custom-field.png b/assets/plugin-sidebar-text-control-custom-field.png
new file mode 100644
index 0000000..0a0d6d2
Binary files /dev/null and b/assets/plugin-sidebar-text-control-custom-field.png differ
diff --git a/assets/quick-view-of-the-block-editor.png b/assets/quick-view-of-the-block-editor.png
new file mode 100644
index 0000000..1bab7e8
Binary files /dev/null and b/assets/quick-view-of-the-block-editor.png differ
diff --git a/assets/sidebar-style-and-controls.png b/assets/sidebar-style-and-controls.png
new file mode 100644
index 0000000..725ddfd
Binary files /dev/null and b/assets/sidebar-style-and-controls.png differ
diff --git a/assets/sidebar-up-and-running.png b/assets/sidebar-up-and-running.png
new file mode 100644
index 0000000..12bc294
Binary files /dev/null and b/assets/sidebar-up-and-running.png differ
diff --git a/assets/text-decoration-component.png b/assets/text-decoration-component.png
new file mode 100644
index 0000000..4626f95
Binary files /dev/null and b/assets/text-decoration-component.png differ
diff --git a/assets/text-transform-component.png b/assets/text-transform-component.png
new file mode 100644
index 0000000..2155fbd
Binary files /dev/null and b/assets/text-transform-component.png differ
diff --git a/assets/toolbar-text.png b/assets/toolbar-text.png
new file mode 100644
index 0000000..b71a342
Binary files /dev/null and b/assets/toolbar-text.png differ
diff --git a/assets/toolbar-with-custom-button.png b/assets/toolbar-with-custom-button.png
new file mode 100644
index 0000000..3b22afa
Binary files /dev/null and b/assets/toolbar-with-custom-button.png differ
diff --git a/assets/xcode-accessibility-inspector-screenshot.png b/assets/xcode-accessibility-inspector-screenshot.png
new file mode 100644
index 0000000..648db05
Binary files /dev/null and b/assets/xcode-accessibility-inspector-screenshot.png differ
diff --git a/contributors/README.md b/contributors/README.md
new file mode 100644
index 0000000..5e6b607
--- /dev/null
+++ b/contributors/README.md
@@ -0,0 +1,27 @@
+# 贡献者指南
+
+欢迎来到古腾堡项目贡献者指南。本指南旨在帮助您完成环境配置并开始为项目贡献力量。如有任何疑问,您可以在WordPress核心Slack的#core-editor频道中找到我们,[欢迎免费加入](https://make.wordpress.org/chat/)。
+
+古腾堡是WordPress核心的子项目。更多信息请参阅[核心贡献者手册](https://make.wordpress.org/core/handbook/)。
+
+## 章节导航
+
+请根据您的贡献方向选择对应章节:
+
+- **代码开发?** 请参阅[开发者章节](/docs/contributors/code/README.md)
+- **设计相关?** 请参阅[设计章节](/docs/contributors/design/README.md)
+- **文档编写?** 请参阅[文档章节](/docs/contributors/documentation/README.md)
+- **问题分类?** 请参阅[问题分类章节](/docs/contributors/triage.md)
+- **国际化?** 请参阅[本地化与翻译章节](/docs/contributors/localizing.md)
+
+### 代码库管理
+
+古腾堡项目使用GitHub进行代码管理和问题追踪。请参阅以下章节了解基于GitHub的项目管理方法:
+
+- [问题管理](/docs/contributors/repository-management.md#issues)
+- [拉取请求](/docs/contributors/repository-management.md#pull-requests)
+- [团队与项目](/docs/contributors/repository-management.md#teams)
+
+## 指导原则
+
+请查阅[贡献准则](https://github.com/WordPress/gutenberg/blob/HEAD/CONTRIBUTING.md)了解相关规范,其中包含行为准则与许可协议信息。
\ No newline at end of file
diff --git a/contributors/accessibility-testing.md b/contributors/accessibility-testing.md
new file mode 100644
index 0000000..17c8788
--- /dev/null
+++ b/contributors/accessibility-testing.md
@@ -0,0 +1,65 @@
+# 无障碍功能测试
+
+本文是关于如何在Gutenberg平台上进行无障碍功能测试的指南。这是一份动态文档,将随着新方法和新技术的出现不断完善。
+
+## 快速开始
+
+请确保已按照[快速开始](/docs/contributors/code/getting-started-with-code-contribution.md)指南完成本地环境配置。
+
+## 键盘操作测试
+
+除鼠标操作外,请确保界面完全支持纯键盘用户操作。尝试仅使用键盘进行交互测试:
+
+- 确保交互元素可通过Tab、Shift+Tab或方向键获取焦点
+- 按钮应支持Enter和空格键激活
+- 单选按钮和复选框应支持空格键选中(不适用Enter键)
+
+若元素可通过方向键聚焦但无法使用Tab或Shift+Tab操作,建议采用[WAI-ARIA复合子类角色](https://www.w3.org/TR/wai-aria-1.1/#composite)进行分组,例如[`toolbar`](https://www.w3.org/TR/wai-aria-1.1/#toolbar)、[`menu`](https://www.w3.org/TR/wai-aria-1.1/#menu)和[`listbox`](https://www.w3.org/TR/wai-aria-1.1/#listbox)。
+
+若交互逻辑对您而言复杂难懂,请意识到这同样会影响纯键盘用户的使用体验。
+
+## 屏幕阅读器测试
+
+根据[WebAIM第八次屏幕阅读器用户调查](https://webaim.org/projects/screenreadersurvey8/#usage),以下是最常见的屏幕阅读器与浏览器组合:
+
+| 屏幕阅读器与浏览器组合 | 受访人数 | 占比 |
+| ----------------------------- | -------- | ------ |
+| JAWS + Chrome | 259 | 21.4% |
+| NVDA + Firefox | 237 | 19.6% |
+| NVDA + Chrome | 218 | 18.0% |
+| JAWS + Internet Explorer | 139 | 11.5% |
+| VoiceOver + Safari | 110 | 9.1% |
+| JAWS + Firefox | 71 | 5.9% |
+| VoiceOver + Chrome | 36 | 3.0% |
+| NVDA + Internet Explorer | 14 | 1.2% |
+| 其他组合 | 126 | 10.4% |
+
+进行屏幕阅读器测试时,建议优先使用上表中的主流组合。例如测试VoiceOver时,推荐使用Safari浏览器。
+
+### NVDA + Firefox 组合
+
+[NVDA](https://www.nvaccess.org/about-nvda/)是Windows平台免费的屏幕阅读器,也是[目前最流行的解决方案](https://webaim.org/projects/screenreadersurvey8/#primary)。
+
+安装完成后,您可像启动常规程序一样激活NVDA。系统托盘将出现功能图标,提供更多选项设置。建议启用"语音查看器"对话框,便于在截屏时直观展示NVDA的语音提示内容。
+
+
+
+在Gutenberg编辑器中激活NVDA后,可按Insert+F7打开元素列表。该功能将页面元素按类型分类展示,包括链接、标题、表单字段、按钮和地标区域。
+
+
+
+请确保元素具有规范标签,建议优先通过地标导航,再结合Tab键与方向键在地标区域内移动焦点。
+
+### VoiceOver + Safari 组合
+
+[VoiceOver](https://support.apple.com/guide/voiceover-guide/welcome/web)是macOS原生屏幕阅读器。可通过系统偏好设置>辅助功能>VoiceOver>启用VoiceOver激活,或在按住Command键的同时快速连按三次Touch ID启用。
+
+
+
+在Gutenberg编辑器中激活VoiceOver后,可按Control+Option+U启动转子功能,快速定位页面中的不同区域与元素。这也是检验元素标签是否规范的有效方式,若转子列表中的名称表述不清,则需要优化改进。
+
+
+
+建议在转子中优先选择区域或较大范围开始测试,而非直接选择独立元素,以便更完整地验证区域内的导航逻辑。
+
+定位目标区域后,可使用Control+Option配合左右方向键在页面元素间移动。请遵循VoiceOver的语音提示进行操作指引。
\ No newline at end of file
diff --git a/contributors/assets/gutenberg-logo-black.svg b/contributors/assets/gutenberg-logo-black.svg
new file mode 100644
index 0000000..467a13b
--- /dev/null
+++ b/contributors/assets/gutenberg-logo-black.svg
@@ -0,0 +1,256 @@
+
+
+
diff --git a/contributors/code/README.md b/contributors/code/README.md
new file mode 100644
index 0000000..2cf62f1
--- /dev/null
+++ b/contributors/code/README.md
@@ -0,0 +1,27 @@
+# 代码贡献指南
+
+关于如何开始为古腾堡项目贡献代码的指南。
+
+## 讨论交流
+
+[Make WordPress Core 博客](https://make.wordpress.org/core/)是获取WordPress开发最新信息的主要平台,包括公告、产品目标、会议记录、会议议程等。
+
+开发讨论将在[Make WordPress Slack](https://make.wordpress.org/chat)(需要注册)的`#core-editor`和`#core-js`频道实时进行。
+
+## 开发中心
+
+古腾堡项目使用GitHub管理代码并跟踪问题。主代码库位于:[https://github.com/WordPress/gutenberg](https://github.com/WordPress/gutenberg)。
+
+浏览[问题列表](https://github.com/wordpress/gutenberg/issues)寻找可参与解决的问题。[初试身手](https://github.com/wordpress/gutenberg/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+First+Issue%22)和[初次审阅](https://github.com/WordPress/gutenberg/pulls?q=is%3Aopen+is%3Apr+label%3A%22Good+First+Review%22)标签是不错的入门起点。
+
+## 贡献者资源
+
+- [入门指南](/docs/contributors/code/getting-started-with-code-contribution.md):记录开发环境搭建流程,包括测试站点和开发者工具建议
+- [Git工作流](/docs/contributors/code/git-workflow.md):说明使用拉取请求部署更改的git流程
+- [编码规范](/docs/contributors/code/coding-guidelines.md):概述古腾堡项目中使用的额外模式与约定
+- [测试概览](/docs/contributors/code/testing-overview.md):针对古腾堡中PHP和JavaScript开发的测试指南
+- [无障碍测试](/docs/contributors/accessibility-testing.md):记录古腾堡无障碍功能测试流程
+- [包管理](/docs/contributors/code/managing-packages.md):说明npm包的管理流程
+- [古腾堡发布流程](/docs/contributors/code/release.md):古腾堡项目不同类型发布的检查清单
+- [React Native移动编辑器](/docs/contributors/code/react-native/README.md):参与React Native移动编辑器开发的指南
+- [React Native集成测试指南](/docs/contributors/code/react-native/integration-test-guide.md):创建移动编辑器集成测试的指南
\ No newline at end of file
diff --git a/contributors/code/auto-cherry-picking.md b/contributors/code/auto-cherry-picking.md
new file mode 100644
index 0000000..8de2446
--- /dev/null
+++ b/contributors/code/auto-cherry-picking.md
@@ -0,0 +1,91 @@
+# 自动化精选合并
+
+`npm run other:cherry-pick` 可自动将带有特定标签的拉取请求精选合并至**当前分支**。
+
+该功能在WordPress主要版本发布时尤为实用,因为脚本默认会查找带有`Backport to WP Beta/RC`标签的已合并拉取请求。
+
+您也可以通过传递自定义标签作为第一个参数,在不同场景中使用此功能。具体示例可参阅本文档末尾的Gutenberg插件发布案例。
+
+运行`npm run other:cherry-pick`会出现以下提示:
+
+```
+当前位于 "wp/6.2" 分支
+本脚本将执行以下操作:
+• 将标记为"Backport to WP Beta/RC"的已合并PR精选合并至此分支
+• 询问是否推送该分支
+• 在每个PR中添加注释
+• 移除每个PR的标签
+
+后两项操作将使用您关联至GitHub CLI(gh命令)的账户执行
+
+是否继续?(Y/n)
+```
+
+同意后将会执行以下流程:
+
+```
+开始逐个执行精选合并..
+
+$ git pull origin wp/6.2 --rebase...
+$ git fetch origin trunk...
+
+发现以下待精选合并的PR:
+ #41198 – 站点编辑器:设置样式预览最小宽度
+
+正在获取提交ID... 完成!
+ #41198 – 860a39665c318d33027d – 站点编辑器:设置样式预览...
+
+开始逐个执行精选合并...
+
+第一轮精选合并:
+ 精选提交:afe9b757b4 对应PR:#41198 – 站点编辑器:设置样式预览...
+精选合并完成!
+
+执行结果:
+ 成功精选合并 1 个PR
+ 合并失败 0 个PR
+
+即将推送至 origin/wp/6.2
+是否继续?(Y/n)
+```
+
+本次运行成功!此时您可以确认是否精选合并了正确的PR。
+
+如果精选合并出现冲突怎么办?脚本会继续处理其他PR并自动重试。
+若部分PR仍合并失败,脚本将跳过这些PR并告知需要手动解决冲突的节点。
+
+无论哪种情况,当您通过精选合并阶段后:
+
+```
+正在推送至 origin/wp/6.2
+添加注释并移除标签...
+ 41198: 已将此PR精选合并至wp/6.2分支以便纳入下一版本:afe9b757b4
+完成!
+```
+
+注释功能为可选操作,仅当您安装[`gh`命令行工具](https://cli.github.com/)时可用。
+
+### 能否使用`Backport to WP Beta/RC`之外的标签?
+
+可以!只需将其作为第一个参数传递:
+
+```
+npm run other:cherry-pick "其他标签"
+```
+
+### 如何用于Gutenberg插件发布?
+
+```
+# 切换到发布分支
+git checkout release/X.Y
+
+# 精选合并所有带有相关回溯标签的已合并PR
+npm run other:cherry-pick "Backport to Gutenberg RC"
+```
+
+### 未来改进方向
+
+未来有望实现根据当前所选分支自动匹配对应标签:
+
+* release/X.Y - 插件发布分支 → "Backport to Gutenberg RC"
+* wp/X.Y - WordPress发布分支 → "Backport to WP Beta/RC"
\ No newline at end of file
diff --git a/contributors/code/back-merging-to-wp-core.md b/contributors/code/back-merging-to-wp-core.md
new file mode 100644
index 0000000..1d2d1dd
--- /dev/null
+++ b/contributors/code/back-merging-to-wp-core.md
@@ -0,0 +1,38 @@
+# 将代码反向合并至WordPress核心
+
+在WordPress软件的主要版本发布时,需要将Gutenberg的功能合并到WordPress核心代码中。通常这涉及提取Gutenberg代码库中`.php`文件的变更,并在WP核心代码库中进行相应更新。
+
+## 合并标准
+
+### 文件/目录范围
+
+以下文件/目录内的变更通常需要反向合并至WP核心:
+
+- `lib/` 目录
+- `phpunit/` 目录
+
+### 排除目录/文件
+
+以下目录/文件_无需_反向合并至WP核心:
+
+- `lib/load.php` - 插件专用代码
+- `lib/experiments-page.php` - 实验性功能为插件专用
+- `packages/block-library` - 将在程序包同步过程中自动处理
+- `packages/e2e-tests/plugins` - 仅限端到端测试相关的PHP文件(主要为测试数据生成器)
+- `phpunit/blocks` - 该代码由Gutenberg维护,测试文件也应保留在此
+
+请注意此列表并未涵盖所有情况。
+
+### 拉取请求标准
+
+通常来说,自[上一稳定版WP核心](https://developer.wordpress.org/block-editor/contributors/versions-in-wordpress/)所包含的最终版Gutenberg发布之日起,所有提交至Gutenberg代码库的PHP代码都应考虑反向合并至WP核心。
+
+但存在以下例外情况,符合这些标准的PR_无需_反向合并至WP核心:
+
+- 未包含PHP代码变更
+- 具有`Backport from WordPress Core`标签 - 该代码已存在于WP核心,正在同步回Gutenberg
+- 具有`Backported to WordPress Core`标签 - 该代码已完成向WP核心的同步
+
+## 扩展阅读
+
+另请参阅关于[Gutenberg PHP代码](/lib/README.md)的补充文档。
\ No newline at end of file
diff --git a/contributors/code/backward-compatibility.md b/contributors/code/backward-compatibility.md
new file mode 100644
index 0000000..52fd656
--- /dev/null
+++ b/contributors/code/backward-compatibility.md
@@ -0,0 +1,79 @@
+# 向后兼容性
+
+历史上,WordPress 以其跨版本保持向后兼容性而闻名。Gutenberg 在其生产环境的公共 API 中尽可能遵循这一原则。在极少数情况下,破坏向后兼容性不可避免,此时需确保:
+
+- 破坏范围应尽可能限制在 API 的小部分区域内。
+- 应通过开发者说明文档向第三方开发者尽可能清晰地记录破坏性变更。
+
+## 生产环境公共 API 的界定标准
+
+Gutenberg 代码库由两种不同类型的包组成:
+
+- **生产环境包**:这些包作为 WordPress 脚本发布(例如:wp-components、wp-editor...)。
+- **开发环境包**:这些包由开发者工具组成,可供第三方开发者用于检查、测试、格式化和构建其主题和插件(例如:@wordpress/scrips、@wordpress/env...)。通常,这些包在第三方项目中作为 npm 依赖项使用。
+
+向后兼容性保证仅适用于生产环境包,因为更新是通过 WordPress 升级进行的。
+
+生产环境包使用 `wp` 全局变量向第三方开发者提供 API。这些 API 可以是 JavaScript 函数、变量和 React 组件。
+
+### 如何保持 JavaScript 函数的向后兼容性
+
+- 函数名称不应更改。
+- 函数的参数顺序不应更改。
+- 函数的返回值类型不应更改。
+- 如果保证所有之前的调用仍然有效,可以对参数进行更改(新增参数、修改语义)。
+
+### 如何保持 React 组件的向后兼容性
+
+- 组件名称不应更改。
+- 组件的属性不应被移除。
+- 应继续支持现有的属性值。如果组件接受函数作为属性,可以更新组件以接受同一属性的新类型,但不应破坏现有用法。
+- 允许添加新属性。
+- 只有在确保之前的上下文契约不被破坏的情况下,才能添加或移除 React Context 依赖。
+
+### 如何保持区块的向后兼容性
+
+- 当编辑器加载时,区块的现有用法不应被破坏或标记为无效。
+- 应保证现有区块的样式。
+- 标记更改应尽可能限制在最小范围内,但如果区块需要更改其保存的标记,导致先前版本无效,则应添加该区块的[**废弃版本**](/docs/reference-guides/block-api/block-deprecation.md)。
+
+## 类名和 DOM 更新
+
+React 组件树内部使用的类名和 DOM 节点不被视为公共 API 的一部分,可以进行修改。
+
+对这些内容的更改应谨慎进行,因为它们可能影响第三方代码的样式和行为(即使它们本不应依赖这些内容)。如果可能,保留旧的类名和 DOM 节点。如果无法保留,请记录更改并撰写开发者说明。
+
+## 废弃
+
+随着项目的发展,现有 API 的缺陷会被发现,或者需要更新以支持新功能。在这种情况下,我们尽量保证现有 API 不被破坏,并构建新的替代 API。
+
+为了鼓励第三方开发者采用新的 API,我们可以使用[**废弃**](/packages/deprecated/README.md)辅助工具来显示一条消息,说明废弃情况并在使用旧 API 时提供替代方案。
+
+明确说明功能何时被废弃。使用辅助方法的 `since` 和 `plugin` 选项。
+
+示例:
+
+```js
+deprecated( 'wp.components.ClipboardButton', {
+ since: '10.3',
+ plugin: 'Gutenberg',
+ alternative: 'wp.compose.useCopyToClipboard',
+} );
+```
+
+## 开发者说明
+
+开发者说明是在 WordPress 发布之前[发布在 make/core 网站上的文章](https://make.wordpress.org/core/tag/dev-notes/),用于向第三方开发者通报开发者 API 的重要变更,这些变更可能包括:
+
+- 新的 API。
+- 可能影响现有插件和主题的现有 API 变更(例如:类名更改等)。
+- 不可避免的向后兼容性破坏,附带理由和迁移流程。
+- 重要的废弃(即使没有破坏性变更),附带理由和迁移流程。
+
+### 开发者说明工作流程
+
+- 在处理拉取请求时,如果发现需要开发者说明,请为 PR 添加 **Needs Dev Note** 标签。
+- 如果可能,在 PR 中添加评论,说明为什么需要开发者说明。
+- 当即将发布的 WordPress 版本的第一个测试版发布时,检查发布中包含的已合并 PR 列表,这些 PR 标记有 **Needs Dev Note** 标签。
+- 对于每一个这样的 PR,撰写开发者说明,并与 WordPress 发布负责人协调发布开发者说明。
+- 一旦 PR 的开发者说明发布,从 PR 中移除 **Needs Dev Note** 标签。
\ No newline at end of file
diff --git a/contributors/code/coding-guidelines.md b/contributors/code/coding-guidelines.md
new file mode 100644
index 0000000..bef0346
--- /dev/null
+++ b/contributors/code/coding-guidelines.md
@@ -0,0 +1,766 @@
+### 记录 React 组件文档
+
+在可能的情况下,所有组件都应实现为[函数式组件](https://react.dev/learn/your-first-component),并使用[钩子](https://react.dev/reference/react/hooks)来管理组件的生命周期和状态。
+
+记录函数式组件的方式应与记录其他函数相同。在记录组件时需要注意的主要问题是,该函数通常只接受一个参数(即“props”),该参数可能包含多个属性成员。使用[参数属性的点语法](https://jsdoc.app/tags-param.html#parameters-with-properties)来记录各个属性的类型。
+
+````js
+/**
+ * 将区块配置的标题渲染为字符串,如果无法确定标题则返回空值。
+ *
+ * @example
+ *
+ * ```jsx
+ *
\`\`\` 代码块标记来界定代码段的起始与结束。示例可跨越多行。
+
+````js
+/**
+ * 根据已注册存储的名称,返回该存储选择器对象。选择器函数已预绑定,可自动传递当前状态。
+ * 作为使用者,仅需传递选择器所需参数(若适用)。
+ *
+ * @param {string} name 存储名称。
+ *
+ * @example
+ * ```js
+ * select( 'my-shop' ).getPrice( 'hammer' );
+ * ```
+ *
+ * @return {Recorde2e-test-utils-playwright 包并非旨在完全替代 Jest + Puppeteer 的 e2e-test-utils 包。部分工具函数仅为简化迁移过程而创建,并非必需。
+段落
+` ); +``` + +我们可以将这种模式视为快照测试的变体,在编写时应遵循相同的规则。通常最好使用`editor.getBlocks`或其他方法重写它们,以进行明确断言: + +```js +await expect.poll( editor.getBlocks ).toMatchObject( [ { + name: 'core/paragraph', + attributes: { content: '段落' }, +} ] ); +``` + +## 测试覆盖率怎么办? + +将明确断言与快照测试比较,我们确实在这个测试中损失了一些测试覆盖率。当我们需要断言块的完整序列化内容时,快照测试仍然有用。但幸运的是,集成测试中的一些测试已经对每个核心块的[完整内容](https://github.com/WordPress/gutenberg/blob/trunk/test/integration/fixtures/blocks/README.md)进行了断言。这些测试在Node.js中运行,比在Playwright中重复相同测试要快得多。在我的机器上运行273个测试用例仅需约5.7秒。这类测试在单元或集成级别效果很好,我们可以在不损失测试覆盖率的情况下更快地运行它们。 + +## 最佳实践 + +在端到端测试中很少需要快照测试,通常有更好的替代方案可以利用明确断言。在确实没有其他合适替代方案时,我们应遵循使用快照测试的最佳实践。 + +### 避免巨大的快照 + +巨大的快照难以阅读和审查。而且,当所有内容都重要时,实际上没有任何内容是重要的。巨大的快照会阻碍我们关注快照的重要部分。 + +### 避免重复的快照 + +如果你发现在同一个测试中创建了多个相似内容的快照,这可能表明你应该进行更原子化的断言。重新思考你想要测试什么,如果第一个快照只是第二个的参考,那么你真正需要的是快照之间的**差异**。将第一个结果存储在变量中,然后断言结果之间的差异。 + +## 延伸阅读 + +- [有效的快照测试 - Kent C. Dodds](https://kentcdodds.com/blog/effective-snapshot-testing) +- [常见测试错误 - Kent C. Dodds](https://kentcdodds.com/blog/common-testing-mistakes) \ No newline at end of file diff --git a/contributors/code/getting-started-with-code-contribution.md b/contributors/code/getting-started-with-code-contribution.md new file mode 100644 index 0000000..32f1c3a --- /dev/null +++ b/contributors/code/getting-started-with-code-contribution.md @@ -0,0 +1,254 @@ +# 代码贡献入门指南 + +以下指南将帮助您设置本地环境,以便为 Gutenberg 项目做出贡献。用于贡献代码的环境与用于扩展 WordPress 区块编辑器的环境存在显著重叠。您可以查阅[开发环境教程](/docs/getting-started/devenv/README.md)获取更多设置信息。 + +## 环境要求 + +- Node.js + Gutenberg 是一个 JavaScript 项目,需要安装 [Node.js](https://nodejs.org/)。项目目前基于 Node.js v20 和 npm v10 构建。虽然我们尽力使用 Node.js 的 Active LTS 版本,但并非总能实现。更多详细信息请参考 [Node.js 发布计划](https://github.com/nodejs/Release#release-schedule)。 + +我们推荐使用 [Node Version Manager](https://github.com/nvm-sh/nvm) (nvm),这是在 macOS、Linux 和 Windows 10(使用 WSL2)上安装和管理 Node.js 的最简单方式。如需更多安装说明,请参阅[我们的开发工具指南](/docs/getting-started/devenv/README.md#development-tools)或 Node.js 官网。 + +- Git + Gutenberg 使用 git 进行版本控制。请确保您的计算机上安装了最新版本的 git,并拥有 GitHub 账户。您可以阅读 [Git 工作流程](/docs/contributors/code/git-workflow.md)了解如何在 Gutenberg 中使用 git 和 GitHub。 + +- [推荐] Docker Desktop + 我们推荐使用 [wp-env 包](/packages/env/README.md)在本地设置 WordPress 环境。使用 `wp-env` 需要安装 Docker。更多详细信息请参阅[开发环境教程](/docs/getting-started/devenv/README.md)。 + > 注意:若要在 Windows 10 家庭版上安装 Docker,请按照 [Docker for Windows with WSL2 的安装说明](https://docs.docker.com/docker-for-windows/wsl/)操作。 + +作为 Docker 设置的替代方案,您可以使用 [Local](https://localwp.com/)、[WampServer](https://wampserver.aviatechno.net/) 或 [MAMP](https://www.mamp.info/),甚至可以使用远程服务器。 + +- GitHub CLI + 虽然不是必需,但 [GitHub CLI](https://cli.github.com/) 能极大帮助您在本地检出拉取请求,包括来自 Gutenberg 主仓库和分叉仓库的请求。这在代码审查和测试拉取请求时能显著节省时间。 + +## 获取 Gutenberg 代码 + +请先 Fork Gutenberg 仓库,然后克隆到您的计算机,并将 WordPress 仓库添加为上游源。 + +```bash +$ git clone https://github.com/您的GitHub用户名/gutenberg.git +$ cd gutenberg +$ git remote add upstream https://github.com/WordPress/gutenberg.git +``` + +## 将 Gutenberg 构建为插件 + +安装 Gutenberg 依赖项并以开发模式构建代码: + +```bash +npm install +npm run dev +``` + +> 注意:安装脚本要求系统已安装 [Python](https://www.python.org/) 并配置在环境变量中。根据操作系统的不同,Python 可能已默认安装或需要手动下载安装。 + +有两种构建代码的方式。在开发过程中,您可能希望使用 `npm run dev` 在源文件更改时自动持续构建。开发构建还包含额外的警告和错误信息,便于开发过程中进行故障排除。完成更改后,可以运行 `npm run build` 创建优化的生产构建。 + +构建完成后,Gutenberg 即可作为 WordPress 插件使用! + +## 本地 WordPress 环境 + +要测试 WordPress 插件,您需要先安装 WordPress 本体。如果您已设置好 WordPress 本地环境,只需将 gutenberg 目录放入 wp-content/plugins/ 目录即可将构建好的 Gutenberg 作为标准 WordPress 插件使用。 + +如果尚未设置本地 WordPress 环境,请按照本节剩余步骤创建环境。 + +## 开发者工具 + +我们建议将编辑器配置为自动检查语法和代码规范错误。这能帮助您在开发过程中自动修复细微的格式问题,从而节省时间。以下是为 Visual Studio Code(许多核心开发者常用的编辑器)的设置指南,这些工具也适用于其他编辑器。 + +### EditorConfig + +[EditorConfig](https://editorconfig.org/) 定义了编辑器的标准配置,例如使用制表符代替空格。您应安装 [VS Code 的 EditorConfig 扩展](https://marketplace.visualstudio.com/items?itemName=editorconfig.editorconfig),它将自动配置您的编辑器以符合 [.editorconfig](https://github.com/WordPress/gutenberg/blob/HEAD/.editorconfig) 中定义的规则。 + +### ESLint + +[ESLint](https://eslint.org/) 通过静态分析代码来发现问题。代码规范检查规则已集成到持续集成流程中,必须通过检查才能提交代码。您应为 Visual Studio Code 安装 [ESLint 扩展](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint),其他编辑器的集成方案请参阅 [eslint 文档](https://eslint.org/docs/user-guide/integrations)。 + +安装扩展后,ESLint 将使用 Gutenberg 代码库根目录中的 [.eslintrc.js](https://github.com/WordPress/gutenberg/blob/HEAD/.eslintrc.js) 文件作为格式规则。它会在开发时高亮显示问题,您还可以通过以下设置实现在保存时自动修复规范问题: + +```json + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, +``` + +### Prettier + +[Prettier](https://prettier.io/) 是一款能够定义规范化格式并自动修复代码以匹配该格式的工具。Prettier 与 ESLint 功能相似,但 Prettier 更侧重于格式和样式,而 ESLint 主要用于检测编码错误。 + +若要在 Visual Studio Code 中使用 Prettier,请安装 [Prettier 代码格式化扩展](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)。随后可通过在设置中添加以下配置,将其设为默认格式化工具并实现保存时自动修复问题: +**_注意_:根据文档查看环境的不同,方括号可能显示为双括号,实际正确格式应为单层方括号。** + +```json +"[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true +}, +"[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true +}, +``` + +此配置将使用 Gutenberg 代码库根目录中的 `.prettierrc.js` 文件,该配置继承自 [@wordpress/prettier-config](/packages/prettier-config/README.md) 包。 + +如果仅希望在 Gutenberg 项目中使用此配置,请在项目根目录创建 `.vscode` 文件夹,并将设置存入其中的 `settings.json` 文件。Visual Studio Code 将其称为工作区设置,且仅适用于当前项目。 + +其他编辑器的配置请参阅 [Prettier 编辑器集成文档](https://prettier.io/docs/en/editors.html)。 + +### TypeScript + +**TypeScript** 是 JavaScript 语言的类型化超集。Gutenberg 项目通过 JSDoc 使用 TypeScript 来实现 [JavaScript 文件的类型检查](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html)。如果您使用 Visual Studio Code,其已内置 TypeScript 支持,其他编辑器的集成方案请参阅 [TypeScript 编辑器支持](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support)。 + +### 使用 Docker 与 wp-env + +[wp-env 工具包](/packages/env/README.md)最初为古腾堡项目开发,旨在通过 Docker 快速创建标准 WordPress 环境。该工具已作为 `@wordpress/env` npm 包发布。 + +默认情况下,在插件目录中运行 `wp-env` 即可创建并启动 WordPress 环境,同时自动挂载并激活对应插件。您还可以配置 `wp-env` 以使用现有安装、多插件或主题。完整文档请参阅 [wp-env 工具包](/packages/env/README.md#wp-envjson)。 + +确保 Docker 处于运行状态,在古腾堡目录中执行以下命令启动 `wp-env`: + +```bash +npm run wp-env start +``` + +该脚本将在后台创建基于最新 WordPress Docker 镜像的实例,并将本地古腾堡插件代码通过 Docker 卷映射到环境中。这样您在本地对代码的任何修改都会即时同步到 WordPress 实例中。 + +> 注意:`npm run` 将使用古腾堡项目内指定的 `wp-env` / `WordPress`?? 版本,确保您运行的是最新的 wp-env 版本。 + +停止运行环境: + +```bash +npm run wp-env stop +``` + +若一切正常,终端将显示如下信息: + +```bash +WordPress 开发站点已启动:http://localhost:8888/ +WordPress 测试站点已启动:http://localhost:8889/ +MySQL 正在监听端口 51220 + + ✔ 完成!(耗时 261 秒 898 毫秒) +``` + +通过右键点击菜单栏(Mac)或系统托盘(Linux/Windows)中的 Docker 图标并选择「控制台」,您将看到脚本已下载若干 Docker 镜像,并正在运行包含完整 WordPress 环境的容器: + + + +彻底删除安装环境: + +```bash +npm run wp-env destroy +``` + +更多命令请查阅[工具包文档](/packages/env/README.md)。 + +#### 访问本地 WordPress 安装 + +WordPress 安装现已可通过 `http://localhost:8888` 访问 + +管理后台地址:`http://localhost:8888/wp-admin/`,登录凭据为:**用户名**:`admin`,**密码**:`password`。您会注意到古腾堡插件已安装并激活,这正是您的本地构建版本。 + +#### 访问 MySQL 数据库 + +古腾堡项目默认集成 phpMyAdmin。您可通过以下地址访问 MySQL 数据库:`http://localhost:9000/`。 + +若需通过其他工具访问数据库,请先获取连接信息: + +1. 在终端中进入本地古腾堡代码库目录 +2. 运行 `npm run wp-env start` - 终端将输出 `wp-env` 环境的相关信息 +3. 在输出信息中查找 _MySQL_ 端口号: + 例如: + +> MySQL 正在监听端口 {MYSQL端口号} + +4. 复制/记录该端口号(注意此端口号会在每次 `wp-env` 重启时变更) +5. 使用以下信息连接 MySQL 实例(请将 `{MYSQL端口号}` 替换为第三步获取的端口号): + +``` +主机:127.0.0.1 +用户名:root +密码:password +数据库:wordpress +端口:{MYSQL端口号} +``` + +**请注意**:MySQL 端口号会在每次 `wp-env` 重启时变更。若发现无法访问数据库,请重复上述步骤获取新端口号以恢复连接。 + +**技巧**:[Sequel Ace](https://sequel-ace.com/) 是访问 MySQL 数据库的实用图形化工具。其他工具及其使用方式可参阅 [WordPress 数据库访问指南](https://developer.wordpress.org/advanced-administration/before-install/creating-database/)。 + +#### 故障排除 + +若遇到问题,请查阅 [`wp-env` 文档中的故障排除章节](/packages/env/README.md#troubleshooting-common-problems)。 + +### 使用 Local 或 MAMP + +作为 Docker 和 `wp-env` 的替代方案,您也可以使用 [Local](https://localwp.com/)、[WampServer](https://wampserver.aviatechno.net/) 或 [MAMP](https://www.mamp.info/) 来运行本地 WordPress 环境。为此,请通过创建符号链接或将目录复制到相应的 `wp-content/plugins` 目录中,将 Gutenberg 作为常规插件克隆并安装到您的环境中。 + +您还需要进行一些额外配置才能运行端到端测试。 + +将当前目录切换到插件文件夹,并为所有端到端测试插件创建符号链接: + +```bash +ln -s gutenberg/packages/e2e-tests/plugins/* . +``` + +如果添加了新插件,您需要再次运行此命令。运行端到端测试的命令如下: + +```bash +WP_BASE_URL=http://localhost:8888/gutenberg/ npm run test:e2e +``` + +#### PHP 文件缓存 + +您需要禁用 OPCache 才能正确编辑 PHP 文件。修复方法如下: + +- 转到 **MAMP > 首选项 > PHP** +- 在 **缓存** 下选择 **关闭** +- 点击 **确定** 确认 + +#### 传入连接 + +默认情况下,MAMP 启动的 Web 服务器(Apache)会监听所有传入连接,而不仅仅是本地连接。这意味着同一本地网络上的任何人(在某些情况下,甚至是互联网上的任何人)都可以访问您的 Web 服务器。这可能是故意的,对于在其他设备上测试站点很有用,但大多数情况下这可能会引发隐私或安全问题。请记住这一点,不要在此服务器上存储敏感信息。 + +虽然可以修复此问题,但您需要自行承担风险,因为它会破坏 MAMP 解析 Web 服务器配置的能力,从而导致 MAMP 认为 Apache 正在监听错误的端口。建议考虑改用其他工具替代 MAMP。否则,您可以按照以下步骤操作: + +- 编辑 `/Applications/MAMP/conf/apache/httpd.conf` +- 将 `Listen 8888` 改为 `Listen 127.0.0.1:8888` + +#### 链接到其他目录 + +您可能希望在 `plugins` 和 `themes` 目录中创建指向其他文件夹的链接,例如: + +- wp-content/plugins/gutenberg -> ~/projects/gutenberg +- wp-content/themes/twentytwenty -> ~/projects/twentytwenty + +如果是这样,您需要配置 Apache 以允许跟随此类链接: + +- 打开或新建文件 `/Applications/MAMP/htdocs/.htaccess` +- 添加以下行:`Options +SymLinksIfOwnerMatch` + +#### 使用 WP-CLI + +像 MAMP 这样的工具倾向于将 MySQL 配置为使用非默认端口 3306,通常偏好使用 8889。这可能会影响 WP-CLI,使其在尝试连接数据库后失败。要解决此问题,请编辑 `wp-config.php` 并将 `DB_HOST` 常量从 `define( 'DB_HOST', 'localhost' )` 改为 `define( 'DB_HOST', '127.0.0.1:8889' )`。 + +### 在远程服务器上 + +您可以通过在本地构建然后将构建的文件作为插件上传到远程服务器,在开发中使用远程服务器。 + +构建步骤:打开终端(如果在 Windows 上,则打开命令提示符)并导航到您克隆的代码库。输入 `npm ci` 以设置所有依赖项。完成后,输入 `npm run build`。 + +构建完成后,克隆的 Gutenberg 目录包含完整的插件,您可以将整个代码库上传到 `wp-content/plugins` 目录,并在 WordPress 管理后台激活插件。 + +另一种构建后上传的方法是运行 `npm run build:plugin-zip` 来创建插件压缩文件——这需要 `bash` 和 `php` 环境。该脚本会创建 `gutenberg.zip`,您可以通过 WordPress 管理后台安装 Gutenberg。 + +## Storybook + +> Storybook 是一个开源工具,用于独立开发 React、React Native 等的 UI 组件。它使构建出色的 UI 变得有条理且高效。 + +Gutenberg 代码库还集成了 [Storybook](https://storybook.js.org/),允许在与 WordPress 无关的环境中进行测试和开发。这对于开发可复用组件和尝试通用 JavaScript 模块非常有帮助,无需任何后端依赖。 + +您可以通过本地运行 `npm run storybook:dev` 启动 Storybook。它会自动在浏览器中打开。 + +您还可以在 GitHub Pages 上测试当前 `trunk` 分支的 Storybook:[https://wordpress.github.io/gutenberg/](https://wordpress.github.io/gutenberg/) \ No newline at end of file diff --git a/contributors/code/git-workflow.md b/contributors/code/git-workflow.md new file mode 100644 index 0000000..a93b3e7 --- /dev/null +++ b/contributors/code/git-workflow.md @@ -0,0 +1,155 @@ +## 分支命名规范 + +命名分支时应使用前缀+简短描述的形式,例如:`[类型]/[变更内容]` + +推荐使用的前缀: + +- `add/` = 新增功能 +- `try/` = 实验性功能(暂定添加) +- `update/` = 更新现有功能 +- `remove/` = 移除现有功能 +- `fix/` = 修复现存问题 + +例如:`add/gallery-block` 表示您正在开发新增画廊区块功能 + +## 保持分支同步 + +当多人同时参与项目开发时,拉取请求很容易过时。"过时"的拉取请求是指与主干开发进度脱节的分支,在合并前需要重新同步。 + +同步方式有两种:合并与变基。在Gutenberg项目中推荐使用变基操作。变基会将您的修改重写为基于开发主线的增量提交,从而确保提交历史的整洁与线性。在处理拉取请求期间,您可以随时执行变基操作。**请尽早开启拉取请求**并持续保持提交历史的变基状态。 + +开发主线即 `trunk` 分支。当拉取请求分支因冲突无法合并至主干时(长期存续的拉取请求常出现此情况),您需要在变基过程中手动解决本地副本的冲突。具体操作请参阅《如何对拉取请求执行变基》中的[「执行变基」章节](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request#perform-a-rebase)。 + +本地解决冲突后,可通过 `git push --force-with-lease` 更新拉取请求。使用 `--force-with-lease` 参数至关重要,它能有效避免意外覆盖他人代码。 + +同步流程可总结为:获取仓库更新 → 基于trunk执行变基 → 推送至远程仓库。具体命令如下: + +```sh +git fetch +git rebase trunk +git push --force-with-lease origin 您的分支名称 +``` + +## 维护派生仓库同步 + +参与拉取请求需先派生Gutenberg仓库作为独立工作副本。随着新代码不断并入主仓库,您的派生仓库容易失去同步。这里您的工作仓库称为 `fork`,主Gutenberg仓库称为 `upstream`。在创建新分支 (`git checkout -b my-new-branch`) 进行功能开发前,请务必先更新派生仓库。 + +需配置 upstream 远程仓库以保持同步: + +```sh +git remote add upstream https://github.com/WordPress/gutenberg.git +git remote -v +origin git@github.com:您的账户/gutenberg.git (fetch) +origin git@github.com:您的账户/gutenberg.git (push) +upstream https://github.com/WordPress/gutenberg.git (fetch) +upstream https://github.com/WordPress/gutenberg.git (push) +``` + +同步派生仓库需先获取上游更新并合并至本地: + +```sh +git fetch upstream +git checkout trunk +git merge upstream/trunk +``` + +本地更新完成后,推送至GitHub完成派生仓库更新: + +```sh +git push +``` + +上述命令将更新您的 `trunk` 分支与上游同步。如需更新其他分支,将 `trunk` 替换为对应分支名即可。 + +## 扩展应用 + +### 提交追溯 + +当需要定位引入特定修改的提交时,忽略仅含样式或格式修改的提交会提升效率。 + +新版 `git` 支持在历史记录中跳过指定提交: + +```sh +git blame --ignore-rev f63053cace3c02e284f00918e1854284c85b9132 -L 66,73 packages/api-fetch/src/middlewares/media-upload.js +``` + +Gutenberg仓库通过 `.git-blame-ignore-revs` 文件记录所有样式与格式修订。使用该文件可一次性忽略所有相关提交: + +```sh +git blame --ignore-revs-file .git-blame-ignore-revs -L 66,73 packages/api-fetch/src/middlewares/media-upload.js +``` + +# Git 工作流程 + +本文档旨在帮助您开始使用 Git 与 Gutenberg 进行协作。Git 是一款强大的源代码管理工具;若要深入学习 Git,请查阅基于 CC BY-NC-SA 3.0 许可证免费在线提供的 [Pro Git 书籍](https://git-scm.com/book/zh/v2)。 + +如果您不熟悉 Git 的使用,值得探索和实践。请尝试 [Git 教程](https://git-scm.com/docs/gittutorial) 以及 [Git 用户手册](https://git-scm.com/docs/user-manual) 来帮助入门。 + +Gutenberg 项目遵循标准的拉取请求流程进行贡献。有关拉取请求的更多详细信息,请参阅 GitHub 的[相关文档](https://docs.github.com/zh/github/collaborating-with-issues-and-pull-requests)。 + +## 概述 + +贡献者的流程概述如下: + +- 复刻(Fork)Gutenberg 代码库。 +- 克隆复刻后的代码库。 +- 创建新分支。 +- 进行代码更改。 +- 确认测试通过。 +- 在新创建的分支中提交代码更改。 +- 将分支推送到复刻的代码库。 +- 向 Gutenberg 代码库提交拉取请求。 + +有关 Gutenberg 项目如何使用 GitHub 的更多信息,请参阅[代码库管理文档](/docs/contributors/repository-management.md)。 + +## Git 工作流程详解 + +代码和文档的工作流程是相同的,因为两者都在 GitHub 中进行管理。您可以观看[贡献文档的视频详解](https://wordpress.tv/2020/09/02/marcus-kazmierczak-contribute-developer-documentation-to-gutenberg/)以及相应的[贡献给 Gutenberg 的教程](https://mkaz.blog/wordpress/contribute-developer-documentation-to-gutenberg/)。 + +以下是 Git 工作流程的视觉概览: + + + +**步骤 1**:前往 GitHub 上的 Gutenberg 代码库,点击 Fork。这将在您的账户下创建主 Gutenberg 代码库的副本。 + + + +**步骤 2**:在本地克隆您复刻的代码库。其地址为:`https://github.com/您的用户名/gutenberg`。克隆操作会将所有文件复制到您的计算机上。打开终端并运行: + +```bash +git clone https://github.com/您的用户名/gutenberg +``` + +这将创建一个名为 `gutenberg` 的目录,其中包含项目的所有文件。由于需要下载 Gutenberg 项目的完整历史记录,此过程可能需要几分钟。 + +**步骤 3**:为您的更改创建一个分支(分支命名规则见下文)。在此示例中,分支名称为完整字符串:`update/my-branch` + +```bash +git switch -c update/my-branch +``` + +**步骤 4**:进行代码更改。全面构建、确认并测试您的更改。请参阅[编码指南](/docs/contributors/code/coding-guidelines.md)和[测试概述](/docs/contributors/code/testing-overview.md)以获取指导。 + +**步骤 5**:使用[良好的提交信息](https://make.wordpress.org/core/handbook/best-practices/commit-messages/)提交您的更改。这会将您的更改提交到本地的代码库副本中。 + +```bash +git commit -m "您的良好提交信息" 路径/到/文件 +``` + +**步骤 6**:将您的更改推送到 GitHub。更改将被推送到您在 GitHub 上复刻的代码库中。 + +```bash +git push -u origin update/my-branch +``` + +**步骤 7**:前往您在 GitHub 上复刻的代码库——它将自动检测到更改,并为您提供创建拉取请求的链接。 + + + +**步骤 8**:创建拉取请求。这将在 WordPress Gutenberg 代码库上创建请求,以集成来自您复刻代码库的更改。 + +**步骤 9**:关注拉取请求上的新动态。如果要求进行任何额外的更改或更新,请在本地进行更改并按照步骤 4-6 推送它们。 + +请勿为更新创建新的拉取请求;通过将更改推送到您的代码库,它将更新同一个 PR。从这个意义上说,PR 是 WordPress Gutenberg 代码库指向您副本的指针。因此,当您更新副本时,PR 也会相应更新。 + +就是这样!一旦获得批准并合并,您的更改将被纳入主代码库。🎉 \ No newline at end of file diff --git a/contributors/code/how-to-get-your-pull-request-reviewed.md b/contributors/code/how-to-get-your-pull-request-reviewed.md new file mode 100644 index 0000000..f9c36ae --- /dev/null +++ b/contributors/code/how-to-get-your-pull-request-reviewed.md @@ -0,0 +1,83 @@ +# 如何让你的拉取请求获得审阅? + +有时我们发布了拉取请求,却无人[审阅](/docs/contributors/repository-management.md#code-review)我们的工作。该怎么办? + +吸引审阅主要不在于代码本身——而在于让审阅过程变得轻松。 + +如果你发布的拉取请求未获得任何评论或审阅,可以尝试核心贡献者们使用的策略: + +## 创建最合理的精简PR + +审批一个2000行的PR需要数月时间且令人望而生畏。 + +审批一个50行的PR仅需数日或数小时且轻松自如。 + +大规模提交会拖慢进度。将工作拆分成小模块进行提交,才能更快合并代码、加速学习进程。 + +## 提供相关背景信息: + +请阐明: +* 你要解决什么问题? +* 你的PR如何解决该问题? +* 你需要什么反馈? +* 哪些内容不在讨论范围? +* 哪些设计不符合直觉? +* 如何进行测试? + +总结所有相关议题和PR。 + +这比让他人自行摸索要简单得多。 + +## 让你的PR引人注目 + +所有贡献都在争夺注意力。让你的作品脱颖而出。 + +最简单的方法?说明其重要性: + +❌ 一个获取数据的新React钩子 +✅ `useEntityRecord`:用减少90%模板代码的方式获取数据 + +然后用代码示例、可视化效果和屏幕录像证明其价值。 + +## 展示你的工作 + +在相关议题和PR中发布你的PR链接。 + +提醒相关议题的评论者、先前提交者和技术负责人关注。 + +在WordPress.org Slack的#core-editor频道中提出。获取反馈最便捷的方式是在每周[核心编辑器会议](/docs/getting-started/README.md)的[自由发言环节](https://make.wordpress.org/core/tag/core-editor-agenda/)主动发声。 + +分配相关标签、里程碑和项目(或请他人协助分配)。 + +## 审阅他人的工作 + +这是进入他人视野的最简单途径。 + +查阅相关议题评论者、先前提交者和技术负责人的PR,然后进行审阅。 + +对他们的工作不熟悉?可以: + +* 花时间理解内容 +* 提议结对编程环节 +* 跳过此项,审阅下一个PR + +## 通过清晰表述降低风险 + +风险会增加阻力——当前的批准可能在日后产生反效果。 + +清晰的阐述如同润滑剂。请明确记录: + +* 涉及哪些风险?为何要承担这些风险? +* 为何此PR是最佳解决方案? +* 如何将风险最小化? +* 已尝试过哪些其他方案? + +## 关注热点领域 + +某些PR天然比其他PR更容易获得关注。 + +请重点投入这些领域。 + +部分议题比其他议题更具时效性(例如列入下一版发布目标的议题),因此能获得更多关注。专注于这些议题将更容易吸引审阅者。 + +如何快速切入?参与WordPress路线图中的活跃项目提供协助 \ No newline at end of file diff --git a/contributors/code/managing-packages.md b/contributors/code/managing-packages.md new file mode 100644 index 0000000..911d409 --- /dev/null +++ b/contributors/code/managing-packages.md @@ -0,0 +1,7 @@ +# 包管理 + +本代码库采用 [npm 工作区](https://docs.npmjs.com/cli/v10/using-npm/workspaces)来管理 WordPress 软件包,并使用 [lerna](https://lerna.js.org/) 将这些软件包发布至 [npm](https://www.npmjs.com/)。这一机制在工作流程中设定了特定步骤,具体说明详见[软件包](https://github.com/WordPress/gutenberg/blob/HEAD/packages/README.md)文档。 + +维护数十个 npm 软件包颇具挑战——追踪变更内容尤为困难。因此我们为每个软件包配置 `CHANGELOG.md` 文件来简化发布流程。作为贡献者,当您提交涉及生产环境的代码时,请按照[维护更新日志](https://github.com/WordPress/gutenberg/blob/HEAD/packages/README.md#maintaining-changelogs)章节的说明,在前述文件中添加对应条目。 + +通过与双周发布的 Gutenberg 插件 RC1 版本保持同步,实现了 WordPress 软件包发布至 npm 的自动化流程。您可以在[Gutenberg 发布流程文档](/docs/contributors/code/release.md#packages-releases-to-npm-and-wordpress-core-updates)中了解此过程及其他发布 npm 软件包新版本的方式。 \ No newline at end of file diff --git a/contributors/code/react-native/README.md b/contributors/code/react-native/README.md new file mode 100644 index 0000000..d4c3033 --- /dev/null +++ b/contributors/code/react-native/README.md @@ -0,0 +1,35 @@ +# React Native 移动编辑器 + +Gutenberg 代码库包含了基于 [React Native](https://reactnative.dev/) 的移动端编辑器源码。 + +## 移动端注意事项 + +贡献者需确保在代码重构期间更新所有受影响的本地移动文件,因为我们目前还无法依赖自动化工具完成这一工作。例如,重命名函数或属性时也需在原生模块中同步修改,否则移动客户端将出现故障。我们已在 PR 中设置了移动端专项 CI 测试作为防护机制,但仍有诸多待完善之处。感谢您的理解与支持。❤️🙇 + +## 移动端专属文件 + +与移动端共享的代码大多位于相同的 JavaScript 模块和 SASS 样式文件中。当代码路径需要区分时,会创建 `.native.js` 或 `.native.scss` 格式的文件变体。某些情况下还可找到针对 Android (`.android.js`) 或 iOS (`.ios.js`) 的平台专属文件。 + +## 在 Android 和 iOS 上运行 Gutenberg Mobile + +如需了解如何在 Android 或 iOS 上运行 **Gutenberg Mobile 演示应用**,请参阅 [React Native 移动版 Gutenberg 入门指南](/docs/contributors/code/react-native/getting-started-react-native.md) + +此外,移动客户端通过[官方 WordPress 应用](https://wordpress.org/mobile/)进行打包和发布。虽然构建流程与移动演示应用略有不同,且目前存放在独立代码库中([此处为移动端原生代码库](https://github.com/wordpress-mobile/gutenberg-mobile)),但其源代码直接取自本代码库及“网页”端代码路径。 + +## 持续集成中的移动端端到端测试 + +若在拉取请求中遇到 Android/iOS 测试失败,建议采取以下步骤: + +1. 重新运行失败的 GitHub Action 任务([重新运行指南](https://docs.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#viewing-your-workflow-history))—— 多数情况下可解决测试失败问题 +2. 按照[端到端测试文档](/packages/react-native-editor/__device-tests__/README.md)中的步骤在本地运行测试,验证是否会出现相同故障 +3. 除了查看端到端测试日志外,还可从 GitHub 任务的 Artifacts 区域下载视频记录以获取更多有效信息 +4. 检查 PR 中的变更是否需要对 `.native.js` 格式的文件进行相应修改 +5. 若最终仍无法解决移动测试失败问题,欢迎通过 Slack 在 #mobile 或 #core-editor 频道联系贡献者([免费加入](https://make.wordpress.org/chat/)) + +## 调试移动端单元测试 + +需要时可按照[移动端原生测试指南](/docs/contributors/code/react-native/integration-test-guide.md)中的说明在本地调试移动端单元测试。 + +## 国际化 (i18n) + +关于此主题的更多信息请参阅 [React Native 国际化指南](/docs/contributors/code/react-native/internationalization-guide.md)。 \ No newline at end of file diff --git a/contributors/code/react-native/getting-started-react-native.md b/contributors/code/react-native/getting-started-react-native.md new file mode 100644 index 0000000..bfaa6e0 --- /dev/null +++ b/contributors/code/react-native/getting-started-react-native.md @@ -0,0 +1,148 @@ +# React Native 版移动端 Gutenberg 入门指南 + +欢迎阅读!本文档是针对 Android 和 iOS 设备的区块编辑器原生移动端移植版的入门指南。总体而言,这是一个可在全新项目或现有项目中使用的 React Native 库。请继续阅读了解如何构建、测试和运行。 + +## 环境准备 + +为了获得与项目维护者相近的开发体验,请确保安装以下工具: + +- git +- [nvm](https://github.com/nvm-sh/nvm) +- Node.js 和 npm(使用 nvm 安装) +- [Android Studio](https://developer.android.com/studio/)(用于编译 Android 版应用) +- [Xcode](https://developer.apple.com/xcode/)(用于编译 iOS 应用) +- CocoaPods(通过 `sudo gem install cocoapods` 安装)用于获取 React 及第三方依赖 + +请注意,维护者使用的操作系统平台是 macOS,但相关工具和设置也应适用于其他平台。 + +## 克隆项目 + +```sh +git clone https://github.com/WordPress/gutenberg.git +``` + +## 环境设置 + +请注意,此处描述的命令应在克隆项目的顶层目录中运行。在运行演示应用之前,需要下载并安装项目依赖。通过以下命令完成: + +```sh +nvm install +npm ci +npm run native preios +``` + +## 运行项目 + +```sh +npm run native start:reset +``` + +该命令将在开发模式下运行打包程序(Metro)。打包程序会持续运行,向请求的客户端提供应用包。 + +在打包程序运行的同时,打开另一个终端窗口,使用以下命令编译并运行 Android 应用: + +```sh +npm run native android +``` + +此时应用应在连接的设备或运行的模拟器中打开,并从正在运行的打包程序获取 JavaScript 代码。 + +要使用默认模拟器设备编译并运行 iOS 版本的应用,请使用: + +```sh +npm run native ios +``` + +如果您使用的是 Mac 并已安装相关环境,该命令将尝试在 iOS 模拟器中打开您的应用。 + +### 在其他 iOS 设备模拟器上运行 + +要使用其他设备模拟器编译并运行应用,请使用以下命令。注意使用双 `--` 将模拟器选项传递给 `react-native` CLI: + +```sh +npm run native ios -- -- --simulator="设备名称" +``` + +例如,如果要在 iPhone Xs Max 上运行,请尝试: + +```sh +npm run native ios -- -- --simulator="iPhone Xs Max" +``` + +要查看所有可用 iOS 设备列表,请使用 `xcrun simctl list devices`。 + +### 自定义演示编辑器 + +默认情况下,演示编辑器会渲染大多数受支持的核心区块。这有助于展示编辑器的功能,但在专注于特定区块或功能时可能会分散注意力。可以通过在 `packages/react-native-editor/src/setup-local.js` 文件中使用 `native.block_editor_props` 钩子来自定义编辑器的初始状态。 + +
+
+## 常见陷阱与注意事项
+
+### 省略 `waitFor` 前的 `await` 会导致误判
+
+在 `waitFor` 前省略 `await` 可能导致测试通过但未验证预期行为的情况。例如,若使用 `toBeDefined` 来断言 `waitFor` 的调用结果,由于 `waitFor` 始终会返回值,断言将通过——即使该值并非我们想要检查的 `ReactTestInstance`。因此建议使用自定义匹配器 `toBeVisible`,可有效防范此类误判情况。
+
+### 使用 `find` 类查询
+
+组件渲染或事件触发后,可能因状态更新产生副作用,导致目标元素尚未渲染。此时需要等待元素可用,为此可使用查询函数的 `find*` 版本,这些函数内部采用 `waitFor` 机制周期性检测元素是否出现。
+
+示例如下:
+
+```js
+const mediaLibraryButton = await findByText( 'WordPress媒体库' );
+```
+
+```js
+const missingBlock = await findByLabelText( /不支持的块\. 第1行/ );
+```
+
+```js
+const radiusSlider = await findByTestId( '滑块圆角半径' );
+```
+
+多数情况下我们会使用 `find*` 函数,但需注意应仅限于真正需要等待元素出现的查询场景。
+
+### `within` 查询
+
+通过 `within` 函数可查询其他元素内部包含的元素,示例如下:
+
+```js
+const missingBlock = await findByLabelText( /不支持的块\. 第1行/ );
+const translatedTableTitle = within( missingBlock ).getByText( '表格' );
+```
+
+## 触发事件
+
+除了查询元素,触发事件模拟用户交互同样重要。为此可使用 `fireEvent` 函数([文档](https://callstack.github.io/react-native-testing-library/docs/api#fireevent))。
+
+点击事件示例:
+
+**点击事件:**
+
+```js
+fireEvent.press( settingsButton );
+```
+
+我们也可以触发任意类型事件(包括自定义事件)。以下示例展示如何触发滑块组件的 `onValueChange` 事件([代码参考](https://github.com/WordPress/gutenberg/blob/520cbd9d2af4bbc275d388edf92a6cadb685de56/packages/components/src/mobile/bottom-sheet/range-cell.native.js#L227)):
+
+**自定义事件 – onValueChange:**
+
+```js
+fireEvent( heightSlider, 'valueChange', '50' );
+```
+
+## 验证元素行为
+
+完成元素查询和事件触发后,需验证逻辑是否符合预期。可使用与单元测试相同的 Jest `expect` 函数,推荐使用自定义匹配器 `toBeVisible` 来确保元素已定义、属于有效React元素且可见。
+
+示例如下:
+
+```js
+const translatedTableTitle = within( missingBlock ).getByText( '表格' );
+expect( translatedTableTitle ).toBeVisible();
+```
+
+当渲染完整编辑器时,还可验证HTML输出是否符合预期:
+
+```js
+expect( getEditorHtml() ).toBe(
+ '\n\n'
+);
+```
+
+## 清理操作
+
+最后需要清理可能影响后续测试的修改。以下是注册区块后的典型清理示例(需取消注册所有区块):
+
+```js
+afterAll( () => {
+ // 清理已注册区块
+ getBlockTypes().forEach( ( block ) => {
+ unregisterBlockType( block.name );
+ } );
+} );
+```
+
+## 辅助工具
+
+为简化原生版本集成测试的编写,可在[此README文件](https://github.com/WordPress/gutenberg/blob/HEAD/test/native/integration-test-helpers/README.md)中查看辅助函数列表。
+
+## 常见流程
+
+### 查询区块
+
+通过无障碍访问标签查询区块是常见方式,示例如下:
+
+```js
+const spacerBlock = await waitFor( () =>
+ getByLabelText( /间距区块\. 第1行/ )
+);
+```
+
+关于区块无障碍访问标签的更多信息,可查阅 [`getAccessibleBlockLabel` 函数](https://github.com/WordPress/gutenberg/blob/520cbd9d2af4bbc275d388edf92a6cadb685de56/packages/blocks/src/api/utils.js#L167-L234)的代码实现。
+
+### 添加区块
+
+以下是插入段落区块的示例:
+
+```js
+// 打开插入器菜单
+fireEvent.press( await findByLabelText( '添加区块' ) );
+
+const blockList = getByTestId( 'InserterUI-区块列表' );
+// 通过onScroll事件强制FlatList渲染所有项
+fireEvent.scroll( blockList, {
+ nativeEvent: {
+ contentOffset: { y: 0, x: 0 },
+ contentSize: { width: 100, height: 100 },
+ layoutMeasurement: { width: 100, height: 100 },
+ },
+} );
+
+// 插入段落区块
+fireEvent.press( await findByText( `段落` ) );
+```
+
+# React Native 集成测试指南
+
+## 什么是集成测试?
+
+集成测试被定义为将不同部分作为整体进行测试的一种测试类型。在我们的场景中,需要测试的部件是指为特定区块或编辑器逻辑所需渲染的不同组件。最终它们与单元测试非常相似,因为它们都是使用 Jest 库通过相同命令运行的。主要区别在于,对于集成测试,我们将使用特定库 [`react-native-testing-library`](https://testing-library.com/docs/react-native-testing-library/intro/) 来测试编辑器如何渲染不同组件。
+
+## 集成测试的结构
+
+测试可以包含以下部分:
+
+- [设置](#设置)
+- [渲染](#渲染)
+- [查询元素](#查询元素)
+- [触发事件](#触发事件)
+- [验证元素行为](#验证元素行为)
+- [清理](#清理)
+
+我们还在后续章节中提供了常见任务示例和技巧:
+
+- [辅助工具](#辅助工具)
+- [常见流程](#常见流程)
+- [工具](#工具)
+- [常见陷阱与注意事项](#常见陷阱与注意事项)
+
+## 设置
+
+这部分通常通过使用 Jest 回调函数 `beforeAll` 和 `beforeEach` 来完成,目的是准备测试可能需要的所有内容,比如注册区块或模拟部分逻辑。
+
+以下是一个预期所有核心区块可用时的常见模式示例:
+
+```js
+beforeAll( () => {
+ // 注册所有核心区块
+ registerCoreBlocks();
+} );
+```
+
+## 渲染
+
+在引入测试逻辑之前,我们需要先渲染要测试的组件。根据是否使用作用域组件方法或完整编辑器方法,这部分会有所不同。
+
+### 使用作用域组件方法
+
+以下是渲染封面区块的示例(摘自[此代码](https://github.com/WordPress/gutenberg/blob/86cd187873984f80ddeeec3e82454b486dd1860f/packages/block-library/src/cover/test/edit.native.js#L82-L91)):
+
+```js
+// 此导入指向区块的索引文件
+import { metadata, settings, name } from '../index';
+
+...
+
+const setAttributes = jest.fn();
+const attributes = {
+ backgroundType: IMAGE_BACKGROUND_TYPE,
+ focalPoint: { x: '0.25', y: '0.75' },
+ hasParallax: false,
+ overlayColor: { color: '#000000' },
+ url: 'mock-url',
+};
+
+...
+
+// 在插槽内渲染封面编辑器的简化树结构
+const CoverEdit = ( props ) => (
+
+
+## 单元测试
+
+```sh
+npm run test:native
+```
+
+## 集成测试
+
+[Appium](https://appium.io/) 自带诊断工具。通过以下命令运行:
+
+```sh
+npx appium-doctor
+```
+
+
+
+请解决所有必需的依赖项。
+
+### iOS 集成测试
+
+若能确保 iOS 本地环境正常运行,iOS 端到端测试将十分简单。首先停止所有正在运行的 Metro 进程(之前通过 `npm run native start:reset` 启动)。
+
+然后在终端中输入:
+
+```sh
+npm run native test:e2e:ios:local
+```
+
+通过指定文件名可运行部分测试用例:
+
+```sh
+npm run native test:e2e:ios:local gutenberg-editor-paragraph.test.js
+```
+
+若一切顺利,将呈现如下效果:
+
+
+
+### Android 集成测试
+
+**创建新的虚拟设备**,需与 [packages/react-native-editor/**device-tests**/helpers/caps.js](https://github.com/WordPress/gutenberg/blob/trunk/packages/react-native-editor/__device-tests__/helpers/caps.js#L30) 中指定的设备参数匹配。截至本文撰写时,需使用 Pixel 3 XL 镜像配合 Android 9(API 28)系统。
+
+首先启动虚拟设备:点击手机图标进入 AVD 管理器,然后点击绿色启动按钮。
+
+
+
+确保没有 Metro 进程正在运行(之前通过 `npm run native start:reset` 启动)。
+
+然后在终端中运行:
+
+```sh
+npm run native test:e2e:android:local
+```
+
+通过指定文件名可运行部分测试用例:
+
+```
+npm run native test:e2e:android:local gutenberg-editor-paragraph.test.js
+```
+
+稍等片刻后应显示:
+
+
+
+# React Native 开发环境配置指南(macOS 版)
+
+是否对移动端原生编辑器开发感兴趣?本指南将手把手带您完成开发环境配置!
+
+请注意,本文说明主要针对 macOS 环境。若需配置其他环境,请参考 [React Native 快速入门文档](https://reactnative.dev/docs/environment-setup) 获取相关指引和步骤。
+
+## 克隆 Gutenberg 项目
+
+```sh
+git clone git@github.com:WordPress/gutenberg.git
+```
+
+### 安装 node 与 npm
+
+若您同时参与多个 JS 项目,建议使用 node 版本管理器。管理器可让您自由切换不同的 node 和 npm 版本。
+
+我们推荐使用 [nvm](https://github.com/nvm-sh/nvm)。
+
+安装 nvm 后,在克隆项目的根目录下执行:
+
+```sh
+nvm install 'lts/*'
+nvm alias default 'lts/*' # 设置为新终端打开时的默认版本
+nvm use # 切换至项目配置版本
+```
+
+随后安装依赖:
+
+```
+npm ci
+```
+
+### 已有旧版 Gutenberg 代码?
+
+若您已持有 Gutenberg 代码,请务必彻底清理 `node_modules` 并重新安装依赖。
+这将有助于避免后续出现错误。
+
+```sh
+npm run distclean
+npm ci
+```
+
+## iOS 环境配置
+
+### CocoaPods 依赖管理
+
+需要安装 [CocoaPods](https://guides.cocoapods.org/using/getting-started.html) 来获取 React 及第三方依赖。安装步骤因 Ruby 管理方式而异。
+
+#### 系统自带 Ruby
+
+若使用 MacOS 默认 Ruby,需通过 `sudo` 命令安装 Cocoapods:
+
+```
+sudo gem install cocoapods
+```
+
+注意:Mac M1 芯片与 Cocoapods 存在兼容性问题。若遇安装问题,可尝试执行以下命令安装 ffi 包(确保以正确架构安装 pods):
+
+```
+sudo arch -x86_64 gem install ffi
+arch -x86_64 pod install
+```
+
+#### Ruby 版本管理器
+
+若使用 Ruby 版本管理器,可能无需手动安装 Cocoapods 或 `ffi` 包。请参照所选管理器的文档进行操作。
+
+若需在 [WordPress iOS 应用](https://github.com/wordpress-mobile/WordPress-iOS) 中运行 Gutenberg(而非仅演示应用),推荐使用 [`rbenv`](https://github.com/rbenv/rbenv) 管理器。
+
+### 配置 Xcode
+
+通过 App Store 安装 [Xcode](https://developer.apple.com/xcode/) 后启动:
+
+- 接受许可协议
+- 确认 `Xcode > 偏好设置 > 位置 > 命令行工具` 指向当前 Xcode 版本
+
+
+
+### 环境诊断工具
+
+可通过 [react-native doctor](https://reactnative.dev/blog/2019/11/18/react-native-doctor) 检测开发环境缺失项。在 Gutenberg 项目根目录或 `/packages/react-native-editor` 文件夹内运行:
+
+```sh
+npx @react-native-community/cli doctor
+```
+
+
+
+尝试让 `doctor` 工具修复所有“通用”和“iOS”问题(此时“Android”项显示❌无需担心,后续会处理!)
+
+### 运行演示应用
+
+当所有通用和 iOS 问题解决后,尝试运行:
+
+```
+npm run native start:reset # 启动 metro 打包器
+```
+
+另开终端窗口执行:
+
+```
+npm run native ios
+```
+
+等待构建完成后,演示应用将在 iOS 模拟器中运行:
+
+
+
+## Android 环境配置
+
+### Java开发工具包(JDK)
+
+[React Native文档](https://reactnative.dev/docs/environment-setup)推荐的JDK名为Azul Zulu。可通过[Homebrew](https://brew.sh/)安装。安装Homebrew后,在终端执行以下命令:
+
+```
+brew tap homebrew/cask-versions
+brew install --cask zulu11
+```
+
+若系统已安装JDK,需确保版本为JDK 11或更高。
+
+### 配置Android Studio
+
+编译Android应用需先[下载Android Studio](https://developer.android.com/studio)。
+
+打开现有项目,选择已克隆的Gutenberg文件夹。
+
+点击下图高亮的立方体图标进入SDK管理器,也可通过`工具 > SDK管理器`进入:
+
+
+
+在此界面可下载SDK平台、软件包及其他工具。需勾选“显示包详细信息”查看特定版本,因为构建过程对E2E测试和开发环境有特定版本要求:
+
+
+
+根据[build.gradle](https://github.com/WordPress/gutenberg/blob/trunk/packages/react-native-editor/android/build.gradle)勾选所有相关软件包,点击“应用”开始下载。node_modules中的build.gradle文件可能包含其他依赖项。
+
+若不想逐行查阅文件,系统会在堆栈跟踪中提示缺失包,但此方法需多次尝试。
+
+
+
+
+
+
+
+### 更新路径配置
+
+导出以下环境变量并更新$PATH。若终端使用zsh可添加到`~/.zshrc`文件,若使用bash则添加到`~/.bash_profile`:
+
+```sh
+### Android Studio自带的Java:
+export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jre/Contents/Home
+### Android Home可在Android Studio中配置:偏好设置 > 系统设置 > Android SDK
+export ANDROID_HOME=$HOME/Library/Android/sdk
+export PATH=$PATH:$ANDROID_HOME/emulator
+export PATH=$PATH:$ANDROID_HOME/tools
+export PATH=$PATH:$ANDROID_HOME/tools/bin
+export PATH=$PATH:$ANDROID_HOME/platform-tools
+```
+
+保存后执行source命令或重启终端使配置生效:
+
+```sh
+source ~/.zshrc
+```
+
+或
+
+```sh
+source ~/.bash_profile
+```
+
+若找不到SDK路径,可通过Android Studio > 偏好设置 > 系统设置 > Android SDK验证位置:
+
+
+
+### 创建设备镜像
+
+点击右下角带Android标识的手机图标创建虚拟设备镜像:
+
+
+
+进入“Android虚拟设备管理器(AVD)”,点击“创建虚拟设备”,选择手机类型:
+
+
+
+选择目标SDK版本(对应[build.gradle](https://github.com/WordPress/gutenberg/blob/trunk/packages/react-native-editor/android/build.gradle)中的targetSdkVersion设置):
+
+
+
+可根据需要调整高级设置(可选),最后点击完成。
\ No newline at end of file
diff --git a/contributors/code/release/README.md b/contributors/code/release/README.md
new file mode 100644
index 0000000..2d5eef3
--- /dev/null
+++ b/contributors/code/release/README.md
@@ -0,0 +1,23 @@
+# Gutenberg 发布流程
+
+GitHub 上的 [Gutenberg 代码库](https://github.com/WordPress/gutenberg) 用于执行多种类型的发布。本页概述了不同的发布流程,并为您提供每种类型对应的文档指引。
+
+## 前置条件
+
+在开始任何发布流程之前,需满足以下要求才能成功发布稳定版的 Gutenberg 插件:
+
+- 成为 [Gutenberg 开发团队](https://developer.wordpress.org/block-editor/contributors/repository-management/#teams) 的成员。这将使您具备启动与发布流程相关的 GitHub 操作以及将拉取请求(PR)回溯到发布分支的权限。
+- 拥有 [Make WordPress Core](https://make.wordpress.org/core) 博客的写权限。这将允许您起草发布文稿。
+- 获得 Gutenberg 核心团队成员的批准,以便将新版本的 Gutenberg 上传至 WordPress.org 插件目录。
+
+## 插件发布
+
+插件发布涉及创建新版本的 Gutenberg 插件并将其发布到 WordPress.org 插件目录。此流程包括创建候选版本、测试以及最终发布。
+
+有关如何执行插件发布的详细说明,请参阅 [Gutenberg 插件发布](https://developer.wordpress.org/block-editor/contributors/code/release/plugin-release/)。
+
+## 软件包发布
+
+软件包发布涉及将更新后的 WordPress 软件包版本发布到 npm。此流程包括与插件发布、WordPress 核心更新以及独立的错误修复发布同步。
+
+有关软件包发布和 WordPress 核心更新的完整说明,请参阅 [发布软件包至 NPM 及 WordPress 核心更新](https://developer.wordpress.org/block-editor/contributors/code/release/package-release-and-core-updates/)。
\ No newline at end of file
diff --git a/contributors/code/release/package-release-and-core-updates.md b/contributors/code/release/package-release-and-core-updates.md
new file mode 100644
index 0000000..afe34fb
--- /dev/null
+++ b/contributors/code/release/package-release-and-core-updates.md
@@ -0,0 +1,156 @@
+- 系统会多次要求您输入一次性密码(OTP),即您使用的双因素认证应用生成的验证码。根据待发布软件包的数量,您可能需要输入多个OTTP,因为这些代码往往在所有软件包发布前就会失效。
+- 若发布流程意外中断(可能因超时或输错OTP导致),可通过执行 [`npx lerna publish from-package`](https://lerna.js.org/docs/features/version-and-publish#from-package) 命令恢复操作。
+
+6. 最后,当 npm 软件包发布完成后,请将 Lerna 生成的提交记录("发布"和更新日志更新)遴选合并到 Gutenberg 的 `trunk` 分支。
+
+## 开发版发布
+
+如[同步 Gutenberg 插件](#synchronizing-the-gutenberg-plugin)章节所述,软件包每两周会从 `wp/latest` 分支发布一次。此外,开发者可随时通过开发版来测试 `trunk` 分支即将推出的变更。我们利用[软件包分发标签](https://docs.npmjs.com/cli/v7/commands/npm-dist-tag)功能,使得根据 npm 指南使用未来版本代码成为可能:
+
+> 默认情况下,npm 使用 `latest` 标签标识软件包当前版本,执行 `npm install release/12.5分支精选了提交,但12.6.0-rc.1已发布,则需将相同提交精选至release/12.6分支,否则这些提交不会包含在后续12.6版本中!通常建议与下个版本的发布协调员协同处理此流程。
+[Type] 为前缀的标签。Backport to Gutenberg RC标签。git checkout release/X.Ynpm run other:cherry-pick "Backport to Gutenberg RC"16:9宽高比,并以最高分辨率拍摄。
+
欢迎来到区块世界。
+ +``` + +区块分为静态与动态两类。静态区块包含渲染内容和属性对象,可根据变更重新渲染。动态区块在生成文章内容时需要服务器端数据和渲染过程。 + +每个区块包含属性或配置设置,这些数据可从内容中的原始HTML、元数据或其他自定义来源获取。 + +详细了解[数据格式与数据流](/docs/explanations/architecture/data-flow.md)。 + +### 区块转换 + +区块具备转换为其他区块类型的能力。既可实现基础操作(如将段落转为标题),也能完成复杂转换(如多张图片转为相册)。区块转换适用于单个区块及多选区块组合,内部区块变体也可作为转换目标。 + +### 区块变体 + +区块变体是特定区块类型的预定义初始属性集合。该API支持创建基础区块,并衍生出多种配置方案。变体提供不同的交互界面,既可在库中显示为全新区块,也可作为插入新区块时的预设模板。详见[API文档](/docs/reference-guides/block-api/block-registration.md#variations-optional)。 + +**区块进阶指南** +- **[区块API](/docs/reference-guides/block-api/README.md)** +- **[教程:构建自定义区块](/docs/getting-started/devenv/get-started-with-create-block.md)** + +## 可复用区块 + +可复用区块是区块(或多个区块组合)的**实例**,可在多处插入和编辑,并保持全局同步。当在某处编辑可复用区块时,所有使用该区块的文章和页面都会同步更新。典型应用场景包括:具有特定内容和自定义颜色的标题区块(用于多个页面),以及侧边栏小组件(用于所有页面)。 + +对可复用区块的任何编辑都会自动同步到所有使用位置,避免在不同文章中重复修改。 + +技术上,可复用区块以隐藏文章类型(`wp_block`)存储,属于动态区块,通过"引用"方式关联`post_id`并返回对应区块的`post_content`。 + +## 区块模式 + +[区块模式](/docs/reference-guides/block-api/block-patterns.md)是由多个区块组合形成的设计范式。这些设计模式为快速构建高级页面和布局提供起点,无需逐个插入区块。区块模式小至单个区块,大至整页内容。与可复用区块不同,模式插入后不会与原始内容保持同步,其包含的区块需用户自行编辑定制。本质上,模式就是常规区块的组合。主题可通过注册模式,为用户提供符合其设计语言的快速入门方案。 + +## 模板 + +文章编辑器专注于内容创作,而[模板](/docs/reference-guides/block-api/block-templates.md)编辑器支持用区块声明和编辑整个站点(从页眉到页脚)。模板系统分为完整页面模板和模板部件(描述模板内的可复用区域,包括页眉、侧边栏、页脚等语义区域)。 + +这些模板和模板部件可由主题组合注册。用户也可通过区块编辑器完全自定义它们。在编辑模板时,与站点属性(如站点标题、描述、徽标、导航等)交互的区块集合尤为实用。自定义模板保存在`wp_template`文章类型中,包括静态页面和动态页面(如归档页、单篇文章页、首页、404页等)。 + +注意:自定义文章类型也可通过初始`post_content`模板初始化,请勿与上述主题模板系统混淆。 + +深入了解[全站编辑模板](/docs/explanations/architecture/full-site-editing-templates.md)。 + +## 样式 + +样式系统(代码中仍沿用旧称“全局样式”)既是用户通过编辑器访问的界面,也是通过[`theme.json`文件](/docs/how-to-guides/themes/global-settings-and-styles.md)实现的配置系统。该文件整合了通常分散在多个`add_theme_support`调用中的配置项,简化与编辑器的通信。其目标是改进以下功能的声明方式:应启用的设置、主题提供的特定工具(如自定义调色板)、可用的设计工具,以及协调WordPress、活跃主题和用户样式的基础架构。 + +了解更多关于[全局样式](/docs/explanations/architecture/styles.md#global-styles)的信息。 \ No newline at end of file diff --git a/explanations/architecture/modularity.md b/explanations/architecture/modularity.md new file mode 100644 index 0000000..8c7a643 --- /dev/null +++ b/explanations/architecture/modularity.md @@ -0,0 +1,103 @@ +## 进阶阅读 + +- [软件包参考](/docs/reference-guides/packages.md) + +# 模块化设计 + +WordPress 区块编辑器的核心理念在于通过组合独立区块来撰写文章或构建页面。区块之间能够相互调用与交互,这种设计赋予了系统高度的模块化特性与灵活性。 + +但区块编辑器的模块化不仅体现在功能与输出层面。古腾堡项目仓库本身也是由多个可复用独立模块(即程序包)构建而成,这些模块共同构成了我们熟悉的应用程序与交互界面。这些模块被称为 [WordPress 程序包](https://www.npmjs.com/org/wordpress),会定期发布并更新至 npm 包仓库。 + +这些程序包不仅为区块编辑器提供核心支持,也可用于增强 WordPress 管理后台或外部环境的任何页面。 + +## 设计理念 + +采用模块化架构为所有参与者带来多重优势: + +- 每个程序包都是独立单元,拥有明确定义的公共 API 用于与其他程序包及第三方代码交互。这使得**核心贡献者**能更清晰地理解代码库,可专注于单个程序包的开发维护,并在明确知晓变更影响范围的前提下进行更新 +- 模块化架构对**终端用户**同样有益。通过在不同管理页面选择性加载脚本,有效控制资源包体积。例如当使用组件包构建插件设置页面时,就无需额外加载区块编辑器包 +- 这种架构允许**第三方开发者**通过 npm 或 WordPress 脚本依赖的方式,在 WordPress 内外环境中复用这些程序包 + +## 程序包分类 + +古腾堡仓库中的几乎所有功能都被构建为程序包。这些程序包可分为两大类型: + +### 生产环境包 + +这类程序包以 JavaScript 脚本形式随 WordPress 核心发布,构成在浏览器中运行的实际生产代码。例如: +- `components` 程序包提供可复用的 React 组件集合,用于快速原型设计与界面构建 +- `api-fetch` 程序包可用于调用 WordPress REST API + +第三方开发者可通过两种方式使用这些生产环境包: + +- 若在 WordPress 环境外构建 JavaScript 应用、网站或页面,可像使用常规 npm 包那样调用: + +``` +npm install @wordpress/components +``` + +```js +import { Button } from '@wordpress/components'; + +function MyApp() { + return ; +} +``` + +- 若开发 WordPress 插件,建议直接调用 WordPress 内置程序包。这样可实现多插件共享同一程序包,避免代码重复。在 WordPress 中,这些程序包以后缀为 `wp-包名称`(如 `wp-components`)的脚本句柄形式提供。只需将脚本添加到插件依赖中,即可通过全局变量 `wp` 调用: + +```php +// myplugin.php +// 注册依赖 "components" 和 "element" 程序包的示例 +wp_register_script( 'myscript', 'pathtomyscript.js', array ('wp-components', "react" ) ); +``` + +```js +// 在脚本中使用程序包 +const { Button } = wp.components; + +function MyApp() { + return ; +} +``` + +手动定义脚本依赖对开发者而言可能繁琐易错。若需了解如何自动化此流程,请参阅 [@wordpress/scripts](https://developer.wordpress.org/block-editor/packages/packages-scripts/#build) 与 [@wordpress/dependency-extraction-webpack-plugin](https://developer.wordpress.org/block-editor/packages/packages-dependency-extraction-webpack-plugin/) 文档。 + +#### 包含样式文件的功能包 + +部分生产环境功能包需依赖样式文件才能正常运行。 + +- 若通过 npm 依赖形式使用功能包,样式文件将存放于功能包的 `build-style` 目录。请确保在应用中加载该样式文件。 +- 若在 WordPress 环境中使用,需通过 wp_enqueue_style 函数加载样式文件,或将其添加至现有样式依赖中。样式文件句柄命名规则与脚本句柄保持一致。 + +在现有 WordPress 页面环境中,若未正确定义脚本或样式依赖,当这些资源已被 WordPress 或其他插件加载时,您的插件仍可能正常运行。但为规避未来版本可能出现的兼容性问题,强烈建议完整定义所有依赖项。 + +#### 包含数据存储的功能包 + +部分 WordPress 生产环境功能包通过数据存储机制管理状态。这些存储空间也可被第三方插件和主题调用,用于数据获取与操作。数据存储命名遵循 `core/功能包名称` 的标准化格式(例如 `@wordpress/block-editor` 功能包定义并使用 `core/block-editor` 数据存储)。 + +若在插件中通过此类存储空间访问或操作 WordPress 数据,请务必将对应的 WordPress 脚本添加至插件脚本依赖中以确保正常运行(例如:若从 `core/block-editor` 存储获取数据,应按前文示例将 `wp-block-editor` 包添加至脚本依赖)。 + +### 开发环境功能包 + +此类功能包用于开发模式,协助开发者完成 JavaScript 应用、WordPress 插件及主题的开发、构建和发布等日常任务。包含代码规范检查、项目构建、测试验证等开发工具。 + +## 编辑器功能包 + + + +### 不同编辑器功能包有何区别?各自承担什么职责? + +新贡献者往往会对文章编辑器由三个独立功能包(`@wordpress/edit-post`、`@wordpress/editor` 和 `@wordpress/block-editor`)分层构建的架构感到惊讶。 + +前文[设计初衷](#why)章节已说明单个功能包如何满足特定需求的设计理念,这同样适用于以下功能包: + +- `@wordpress/block-editor` 提供用于实现区块编辑器的组件,其操作对象为区块对象数组的基础数据。该包不预设数据保存方式,且无需感知(或依赖)WordPress 环境。 +- `@wordpress/editor` 是 WordPress 文章专用的增强版区块编辑器。它在 `@wordpress/block-editor` 组件基础上构建,具备 WordPress 文章概念感知能力,将表征区块的数据加载保存机制与文章及其内容相关联。同时提供在编辑器环境中处理文章对象的相关组件(如文章标题输入组件)。该功能包支持编辑任何文章类型的文章,且不限定渲染环境必须位于特定 WordPress 界面或布局中。 +- `@wordpress/edit-post` 是 WordPress 后台“新建文章”(“编辑文章”)界面的具体实现。它负责对 `@wordpress/editor` 和 `@wordpress/block-editor` 提供的各类组件进行布局编排,完全掌控其在 WordPress 管理后台特定界面中的呈现方式。 + +通过这样的结构设计,这些功能包可在“新建文章”界面之外实现多样化组合应用: + +- `@wordpress/edit-site` 或 `@wordpress/edit-widgets` 功能包可分别实现“站点编辑器”或“小工具编辑器”,其实现方式与 `@wordpress/edit-post` 高度相似。 +- `@wordpress/editor` 可应用于“可重用区块”功能的实现,因其本质上是与 `wp_block` 文章类型关联的嵌套区块编辑器。 +- `@wordpress/block-editor` 可独立于 WordPress 环境使用,或采用完全不同的保存机制。例如:可用于构建网站文章的评论区编辑器。 \ No newline at end of file diff --git a/explanations/architecture/performance.md b/explanations/architecture/performance.md new file mode 100644 index 0000000..5851192 --- /dev/null +++ b/explanations/architecture/performance.md @@ -0,0 +1,97 @@ +# 性能表现 + +性能是编辑器应用的关键特性,块编辑器也不例外。 + +## 指标衡量 + +为确保块编辑器在版本迭代和开发过程中始终保持高性能,我们通过[性能基准测试任务](#性能基准测试任务)监控以下核心指标: + +部分关键指标包括: + +- **加载时间:** 编辑器页面加载所需时长。涵盖服务器响应时间、首次绘制时间、首次内容绘制时间、DOM内容加载完成时间、页面完全加载时间以及首区块渲染时间(文章与站点编辑场景均包含)。 +- **输入响应时间:** 在编辑器中输入时浏览器作出响应所需时长。 +- **区块选择时间:** 用户选择区块后浏览器作出响应所需时长(插入区块等效于选择区块,监控选择操作即可同步覆盖这两项指标)。 + +## 关键性能决策与解决方案 + +**数据模块异步模式** + +WordPress组件库与块编辑器的数据模块基于Redux构建。这意味着状态全局存储,当状态发生变化时,依赖该状态的组件(UI)会相应更新。 + +随着渲染组件数量增加(例如长文编辑时),由于全局状态会向所有组件分发事件,性能将受到影响。这是Redux应用的常见问题,Gutenberg通过数据模块异步模式解决了这一难题。 + +异步模式的核心在于:开发者可自主决定以同步或异步方式刷新/重渲染React组件树的特定部分。 + +在此语境下,异步渲染意味着当全局状态触发变更时,订阅者(组件)不会立即被同步调用,而是等待浏览器进入空闲状态后再执行React树更新。 + +基于**编辑特定区块时,该区块的更新极少影响内容其他部分**这一理念,块编辑器画布仅以同步模式渲染当前选中区块,其余所有区块均采用异步渲染。这确保了随着文章内容增长,编辑器仍能保持流畅响应。 + +## 性能基准测试任务 + +我们提供了跨分支/标签/提交进行性能对比的工具。可通过以下方式本地运行:`./bin/plugin/cli.js perf [分支名]`,例如: + +``` +./bin/plugin/cli.js perf trunk v8.1.0 v8.0.0 +``` + +为获得最精确结果,运行测试时必须确保测试版本与环境(主题等)完全一致,各分支间唯一差异应为Gutenberg插件版本(或用于构建插件的分支)。 + +为实现该目标,指令会先创建以下目录结构: + + │ + ├── tests/packages/e2e-tests/specs/performance/* + │ 待运行的实际性能测试 + │ + ├── tests/test/emptytheme + │ 测试环境所用主题(站点编辑器) + │ + │── envs/branch1/.wp-env.json + │ branch1的wp-env配置文件(除插件目录外与其他分支配置相同) + │── envs/branch1/plugin + │ branch1的Gutenberg插件构建副本(通过git checkout branch1获取) + │ + └── envs/branchX + 所有其他分支均复制perf-envs/branch1的目录结构 + +完成目录准备后,性能测试指令将循环执行各性能测试套件(文章编辑器与站点编辑器),并执行以下操作: + +1. 启动`branch1`对应环境 +2. 运行当前套件的性能测试 +3. 停止`branch1`对应环境 +4. 对其余所有分支重复前三步操作 +5. 计算当前套件所有性能指标的中位数值 + +所有测试套件执行完毕后,将生成汇总报告。 + +## 通过CodeVitals追踪性能 + +每次提交的性能结果将推送至codevitals,可在[Gutenberg数据看板](https://www.codevitals.run/project/gutenberg)查看。通过趋势图可追踪特定指标随时间的变化情况。 + +因此确保所计算指标的稳定性至关重要。这意味着在代码与环境相同的情况下,重复运行测试应获得相近结果。 + +由于性能任务运行于GitHub CI环境,我们不能完全相信两次相似任务运行获得的数值一致性。例如GitHub CI可能随时间推移分配不同的CPU与内存资源。为缓解此问题,每次在trunk分支运行性能任务时,我们会将当前提交的性能与固定的参考提交哈希进行对比,这样无论环境如何变化,都能持续追踪当前提交与参考提交间的相对差异。 + +### 更新参考提交 + +Gutenberg仅支持两个WP版本,这对性能任务产生两方面影响: + + - 当Gutenberg支持的最低版本变更时,用于运行性能任务的基础WP版本需同步更新。为此,我们依赖插件`readme.txt`文件中的`Tested up to`标识。每次该标识变更时,性能任务所用版本也会相应调整。 + + - 更新性能任务使用的WP版本意味着,用于保证性能测试稳定性的参考提交很可能与当前WP版本不兼容。因此每次`readme.txt`中的`Tested up to`标识更新时,必须同步更新`.github/workflows/performance.yml`中使用的参考提交。 + +新选的参考提交哈希需满足以下要求: + + - 与`Tested up to`标识使用的新WP版本兼容 + - 已在codevitals.run平台追踪所有现有指标 + +当发布涉及最低WordPress版本要求变更的插件更新时,需更新Core SVN中失去支持分支的端到端测试GitHub Action工作流,否则该分支在发布后的首次工作流运行将会失败。 + +可通过在测试矩阵中添加`gutenberg-version`输入来固定工作流中使用的插件版本。[Core-59221](https://core.trac.wordpress.org/changeset/59221)展示了6.4分支的此类变更示例。 + +**注意:** 请始终使用包含错误修复的最终发行版(例如`x.y.2`或`x.y.3`)。若最终发行版尚未确定,请创建[Trac工单](https://core.trac.wordpress.org/ticket/62488)以免遗忘。 + +**选择提交的简易方法是选取trunk分支上最近一次通过性能测试的提交。** + +## 拓展阅读 + +- [高性能编辑器的演进之路](https://riad.blog/2020/02/14/a-journey-towards-a-performant-web-editor/) \ No newline at end of file diff --git a/explanations/architecture/styles.md b/explanations/architecture/styles.md new file mode 100644 index 0000000..c73dbe6 --- /dev/null +++ b/explanations/architecture/styles.md @@ -0,0 +1,549 @@ +#### 语义化类名 + +当前正在扩展布局区块支持输出的稳定语义化类名,相关讨论可在[此议题](https://github.com/WordPress/gutenberg/issues/38719)中查看。 + +目前通过布局区块支持可输出的语义化类名包括: + +- `is-layout-flow`:采用默认/流式布局类型的区块 +- `is-layout-constrained`:采用约束布局类型的区块 +- `is-layout-flex`:采用弹性布局类型的区块 +- `is-layout-grid`:采用网格布局类型的区块 +- `wp-container-$id`:其中`$id`为半随机数。该容器类仅当区块包含非默认布局值时存在,请勿直接将其用于CSS选择器,因其可能动态变化 +- `is-horizontal`:当区块显式设置`orientation`为`horizontal`时 +- `is-vertical`:当区块显式设置`orientation`为`vertical`时 +- `is-content-justification-left`:当区块显式设置`justifyContent`为`left`时 +- `is-content-justification-center`:当区块显式设置`justifyContent`为`center`时 +- `is-content-justification-right`:当区块显式设置`justifyContent`为`right`时 +- `is-content-justification-space-between`:当区块显式设置`justifyContent`为`space-between`时 +- `is-nowrap`:当区块显式设置`flexWrap`为`nowrap`时 + +### 禁用自动生成的布局样式 + +由于核心结构区块需要依赖布局样式,系统默认开启布局样式输出。但主题可通过使用`disable-layout-styles`区块支持来禁用自动生成的区块布局样式,同时保留语义化类名输出。选择此方案的主题需自行提供完整的布局样式支持,具体请参阅[主题支持文档](https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-support/#disabling-base-layout-styles)中的相关说明。 + +### 基础布局样式 + +基础布局样式是指那些选择特定布局类型的所有区块共通的样式。常见的基础布局样式示例包括:为采用弹性布局类型的区块(例如按钮区块和社交图标区块)设置 `display: flex`,以及为受限布局提供默认的最大宽度。 + +基础布局样式通过[处理全局样式的主要 PHP 类](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/class-wp-theme-json.php)输出,并构成全局样式表的一部分。为了在经典主题中支持核心区块,无论主题是否提供自身的 `theme.json` 文件,这些样式始终会被输出。 + +通用布局定义存储在[核心布局区块支持文件](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/block-supports/layout.php)中。 + +### 独立布局样式 + +当选择支持布局的区块被渲染时,会通过 [`layout.php`](https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/block-supports/layout.php) 处理并将以下两项内容添加到输出中: + +- 语义类名会被添加到区块标记中,以指示正在使用的布局设置。例如,`is-layout-flow` 用于使用默认/流式布局的区块(如群组区块),而 `is-content-justification-right` 会在用户将区块设置为右对齐时添加。 +- 为正在渲染的单个区块上设置的非默认布局值生成独立样式。这些样式通过容器类名附加到区块上,类名格式为 `wp-container-$id`,其中 `$id` 是一个[唯一编号](https://developer.wordpress.org/reference/functions/wp_unique_id/)。 + +### 可用的布局类型 + +目前有四种布局类型在使用: + +- 默认/流式布局:项目垂直堆叠。父容器区块的显示值未指定,因此可以使用该 HTML 元素的默认值。对于大多数元素,这通常是 `block`。子元素之间的间距通过垂直边距处理。 +- 受限布局:项目垂直堆叠,使用与流式布局相同的间距逻辑。具有子内容宽度的限制,为标准内容尺寸和宽尺寸输出宽度。默认使用 `theme.json` 中 `settings.layout` 设置的全局 `contentSize` 和 `wideSize` 值。 +- 弹性布局:项目使用弹性盒子布局显示。默认为水平方向。子元素之间的间距通过 `gap` CSS 属性处理。 +- 网格布局:项目使用网格布局显示。默认为 `auto-fill` 方式生成列,但也可以设置为固定列数。子元素之间的间距通过 `gap` CSS 属性处理。 + +关于控制区块之间的间距以及启用区块间距控制,请参阅:[什么是 blockGap,我该如何使用它?](https://developer.wordpress.org/block-editor/how-to-guides/themes/global-settings-and-styles/#what-is-blockgap-and-how-can-i-use-it) + +### 从主题中定位布局或容器区块 + +布局区块支持旨在通过区块和站点编辑器实现对布局功能的控制。在可能的情况下,尽量使用区块的功能来确定特定的布局需求,而不是依赖额外的样式表。 + +对于希望定位容器区块以添加或调整特定样式的主题,区块的类名通常是最佳选择。例如 `wp-block-group` 或 `wp-block-columns` 这样的类名通常是定位特定区块的可靠类名。除了区块和布局类名外,还有一个由区块和布局组合而成的类名:例如,对于具有受限布局的群组区块,类名将是 `wp-block-group-is-layout-constrained`。 + +对于使用特定布局类型的区块进行定位,请避免定位 `wp-container-`,因为容器类可能不会始终出现在渲染的标记中。 + +### 从界面控件到HTML标记 + +若您遵循[区块教程](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/),可深入了解[区块API](https://developer.wordpress.org/block-editor/reference-guides/block-api/)的各个组成部分,并构建专属区块。本文将介绍区块如何让用户编辑其状态的核心概念。 + +要构建上述交互体验,区块开发者需具备以下要素: + +1. **界面控件**:向用户提供选项交互,例如调整区块字体大小。该控件负责读取区块数据(当前是否已设定字体大小?)及其他必要信息(本区块允许使用哪些字号?)。可查阅现有[组件库](https://developer.wordpress.org/block-editor/reference-guides/components/)。 +2. **区块属性**:区块需存储数据以记录修改状态,例如是否已设定字号。了解区块如何定义[属性](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/)。 +3. **样式数据接入**:控件可能需要获取区块可用样式的外部信息,如色彩列表或字号列表。这类预设样式通常由主题定义(WordPress也提供默认配置)。查看主题可向编辑器提供的[数据列表](https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/theme-json-living/#settings),以及开发者如何通过[useSetting](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#usesetting)获取这些数据。 +4. **将用户样式序列化为HTML标记**:用户操作后,需相应更新区块HTML标记(添加对应类或行内样式)。此序列化过程由[编辑/保存](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/)函数与[render_callback](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/)函数实现,它们将区块数据转换为HTML代码。 + +本质上,这些是区块开发者实现用户样式定制需关注的核心机制。虽然完全手动可实现,但针对通用样式需求,可通过自动化API——区块支持功能来简化流程。 + +### 区块支持API + +[区块支持](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/)API允许区块声明其支持的功能。通过在[block.json文件](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/)中添加配置信息,区块可向系统声明允许用户执行的操作类型。 + +例如: + +```json +{ + "name": "core/paragraph", + "...": "...", + "supports": { + "typography": { + "fontSize": true + } + } +} +``` + +段落区块在其`block.json`中声明支持字号调整。这意味着区块将显示字号调节控件(除非被主题禁用,详见[主题配置参考](https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/))。系统会自动配置控件数据(当前字号、可用字号列表),并在用户操作时将区块数据序列化为HTML标记(自动附加类与行内样式)。 + +通过`block.json`使用区块支持机制,开发者仅需数行代码即可实现完整交互体验。查看[区块支持API文档](/docs/reference-guides/block-api/block-supports.md)了解如何为静态或动态区块添加支持功能。 + +除简化开发流程外,该机制还有以下优势: + +- 区块样式信息可被原生移动应用和服务端调用 +- 区块对同类样式使用统一控件,确保用户体验一致性 +- 所用界面控件将随系统升级自动优化,无需开发者干预 + +# 编辑器中的样式 + +本文档将介绍影响区块编辑器用户内容的相关样式核心概念,同时提供对应的参考指南和教程链接,方便读者深入探究每个主题。本文主要面向区块创作者和参与区块编辑器项目的开发人员。 + +## HTML 与 CSS + +用户在区块编辑器中创建内容时,实际上在生成一系列产物:一个 HTML 文档和若干 CSS 样式表(可内嵌于文档或作为外部文件)。 + +最终生成的 HTML 文档由以下要素共同构成: + +- 主题提供的 [WordPress 模板](https://developer.wordpress.org/themes/basics/template-files/)(通过 PHP 实现的经典主题或通过 HTML 模板实现的区块主题)([详细了解](https://developer.wordpress.org/themes/block-themes/#differences-and-similarities-between-classic-themes-and-block-themes)二者差异) +- 具有预定义结构(HTML 标记)的[区块](https://developer.wordpress.org/block-editor/reference-guides/core-blocks/)与版式 +- 用户对内容的修改:添加内容、转换现有内容(如将段落转换为标题)或调整内容(为区块添加类或内联样式) + +前端加载的样式表包含: + +- **区块样式**:区块自带的样式表。在前端,您可能会看到 WordPress 定义的所有区块样式合并为单一样式表(`wp-block-library-*`),也可能是每个使用中的区块拥有独立样式表(如 `wp-block-group-*`、`wp-block-columns-*` 等)。完整说明请参阅[此说明文档](https://make.wordpress.org/core/2021/07/01/block-styles-loading-enhancements-in-wordpress-5-8/)。 +- **全局样式**:这些样式通过 theme.json 文件的数据动态生成(参见[说明文档](https://make.wordpress.org/core/2021/06/25/introducing-theme-json-in-wordpress-5-8/)、[参考指南](https://developer.wordpress.org/block-editor/reference-guides/theme-json-reference/)和[操作指南](https://developer.wordpress.org/block-editor/how-to-guides/themes/global-settings-and-styles/))。具体而言,它会整合来自 WordPress 的 theme.json、主题自带的 theme.json(如有)以及用户通过站点编辑器的全局样式侧边栏提供的数据,最终生成一个 ID 为 `global-styles-inline-css` 的内嵌样式表。 +- **主题样式**:传统上主题会自行注册样式表,其 ID 基于主题名称(如 `twentytwentytwo-style-css`)。如今除了自有样式表外,主题还可声明包含样式的 theme.json 文件,这些样式将成为全局样式生成样式表的一部分。 +- **用户样式**:用户在编辑器中的某些操作会生成样式内容,例如双色调、布局或链接颜色等功能。 +- **其他样式**:WordPress 核心和插件也可注册样式表。 + +## 区块样式 + +自 WordPress 5.0 引入区块编辑器以来,一直提供为用户“添加样式”到特定区块的工具。通过这些工具,用户可为区块附加新类或内联样式,从而改变其视觉呈现。 + +默认情况下,区块具有预设的 HTML 标记。以段落区块为例: + +```html + +``` + +在最简形式下,任何针对 `p` 选择器的样式规则都会作用于该区块,无论这些规则来自区块、主题或其他来源。 + +用户可通过应用不同样式来改变区块状态:文本对齐方式、颜色、字体大小、行高等。这些状态通过 HTML 属性(主要是 `class` 或 `style` 属性,也可以是区块作者认为合适的任何其他属性)反映在区块的 HTML 标记中。 + +经过用户修改后,初始标记可能变为: + +```html + +``` + +这就是我们所说的“用户提供的区块样式”,也称为“本地样式”或“序列化样式”。本质上,每个工具(字体大小、颜色等)最终都会向区块标记添加若干类和/或内联样式。这些类对应的 CSS 样式属于区块、全局或主题样式表的一部分。 + +修改区块状态的能力,加上区块可嵌套于其他区块的特性(例如段落区块位于编组区块内),创造了海量的潜在状态和样式组合可能。 + +#### 设置项到CSS规则的转换 + +从 `settings` 部分中,所有预设值都将转换为遵循此命名结构的CSS自定义属性:`--wp--preset--<类别>-<别名>`。选择器遵循上述样式部分描述的相同规则。 + +例如,以下 theme.json 配置: + +```json +{ + "settings": { + "color": { + "palette": { + "default": [ + { + "slug": "vivid-red", + "value": "#cf2e2e", + "name": "Vivid Red" + } + ], + "theme": [ + { + "slug": "foreground", + "value": "#000", + "name": "Foreground" + } + ] + } + }, + "blocks": { + "core/site-title": { + "color": { + "palette": { + "theme": [ + { + "slug": "foreground", + "value": "#1a4548", + "name": "Foreground" + } + ] + } + } + } + } + } +} +``` + +将被转换为以下CSS样式规则: + +```CSS +body { + --wp--preset--color--vivid-red: #cf2e2e; + --wp--preset--color--foreground: #000; +} + +.wp-block-site-title { + --wp--preset--color--foreground: #1a4548; +} +``` + +除了CSS自定义属性外,除双色调外的所有预设都会为每个值生成CSS类。上例还会生成以下CSS类: + +```CSS +/* vivid-red */ +.has-vivid-red-color { color: var(--wp--preset--color--vivid-red) !important; } +.has-vivid-red-background-color { background-color: var(--wp--preset--color--vivid-red) !important; } +.has-vivid-red-border-color { border-color: var(--wp--preset--color--vivid-red) !important; } + +/* foreground */ +.has-foreground-color { color: var(--wp--preset--color--foreground) !important; } +.has-foreground-background-color { background-color: var(--wp--preset--color--foreground) !important; } +.has-foreground-border-color { border-color: var(--wp--preset--color--foreground) !important; } + +/* 站点标题内的foreground */ +.wp-block-site-title .has-foreground-color { color: var(--wp--preset--color--foreground) !important; } +.wp-block-site-title .has-foreground-background-color { background-color: var(--wp--preset--color--foreground) !important; } +.wp-block-site-title .has-foreground-border-color { border-color: var(--wp--preset--color--foreground) !important; } +``` + +### 全局样式API的当前限制 + +#### 1. **为区块设置不同CSS选择器需服务端注册** + +默认情况下,分配给区块的选择器是 `.wp-block-<区块名称>`。但区块可以根据需要更改此设置,可以通过其 `block.json` 中的 `__experimentalSelector` 属性提供CSS选择器。 + +如果区块这样做,需要在服务端使用 `block.json` 进行注册,否则全局样式代码无法访问该信息,将使用区块的默认CSS选择器。 + +#### 2. **无法为不同样式定位不同HTML节点** + +每个样式块只能使用单个选择器。 + +当区块使用 `__experimentalSkipSerialization` 将不同样式属性序列化到包装器以外的不同节点时,这一点尤为重要。详见"区块支持的当前限制"。 + +#### 3. **每个区块仅支持单一属性** + +与区块支持类似,区块只能使用任何样式的单个实例。例如,区块只能拥有单一字体大小。详见相关"区块支持的当前限制"。 + +#### 4. **仅使用区块支持的区块会显示在全局样式UI中** + +站点编辑器中的全局样式UI设有按区块样式的界面。区块列表是使用来自区块 `block.json` 的区块支持动态生成的。如果区块希望被列出,需要使用区块支持机制。 + +## 布局样式 + +除了单个区块级别和全局样式中的样式外,还存在为基于区块的主题和经典主题输出的布局样式概念。 + +布局区块支持输出用于创建布局的区块之间共享的通用布局样式。布局样式对于为作为其他区块容器的任何区块提供通用样式非常有用。依赖这些布局样式的区块示例包括群组、行、列、按钮和社交图标。核心区块通过其 `block.json` 文件中 `supports` 下的 `layout` 设置启用此功能。 + +布局样式主要输出在两个位置: + +### 区块支持API的当前限制 + +尽管区块支持API具有实用价值,但区块开发者仍需注意其存在的一些限制。为了更好地理解这些限制,我们以表格区块为例进行说明: + +```html +| 标题 | +
|---|
| 第一行 | +
| 第二行 | +
| 页脚 | +
| 标题 | +
| { decodeEntities( page.title.rendered ) } | +
| 标题 | +
|---|
| { decodeEntities( page.title.rendered ) } | +
| 标题 | +操作 | +
| { decodeEntities( page.title.rendered ) } | +
+ |
+
| 标题 | +操作 | +
| { decodeEntities( page.title.rendered ) } | +
+
+
+ |
+
| 标题 | +操作 | +
| { page.title.rendered } | +
+
+
+ |
+
{ __( '你好世界', 'myguten' ) }
; + }, + + save: () => { + const blockProps = useBlockProps.save( { style: { color: 'red' } } ); + + return{ __( '你好世界', 'myguten' ) }
; + }, +} ); +``` + +在上述示例中,该函数将使用第一个参数作为要翻译的字符串。第二个参数是文本域,必须与插件指定的文本域标识符匹配。 + +常用函数(这些函数与它们的 PHP 版本相对应)包括: + +- `__( '你好世界', 'my-text-domain' )` - 翻译特定字符串。 +- `_n( '%s 条评论', '%s 条评论', numberOfComments, 'my-text-domain' )` - 根据给定数字翻译并返回单数或复数形式。 +- `_x( '默认', '区块样式', 'my-text-domain' )` - 在特定上下文中翻译字符串。 + +本实验旨在探索在WordPress后台创建独立区块编辑器实例的难易程度。
+ +``` + +### 检索历史区块数据 + +实现持久化固然重要,但只有当这些数据在每次完整页面重载时被检索并在编辑器中恢复,才能真正发挥作用。 + +访问数据会产生副作用,因此必须使用`useEffect`钩子来处理: + +```jsx +// 文件:src/components/block-editor/index.js + +useEffect( () => { + const storedBlocks = window.localStorage.getItem( 'getdavesbeBlocks' ); + + if ( storedBlocks && storedBlocks.length ) { + updateBlocks( () => parse( storedBlocks ) ); + createInfoNotice( '区块已加载', { + type: 'snackbar', + isDismissible: true, + } ); + } +}, [] ); +``` + +该处理程序: + +- 从本地存储中获取序列化的区块数据 +- 使用`parse()`工具将序列化区块转换回JavaScript对象 +- 调用状态设置器`updateBlocks`,使状态中的`blocks`值更新为从LocalStorage检索到的区块 + +这些操作的结果是,受控的`<BlockInspector>
+本身实际上渲染了一个用于 <InspectorControls> 的 Slot。这使你可以在区块的 edit() 定义中渲染一个 <InspectorControls>> 组件,并在编辑器的侧边栏中显示它。建议进一步探索该组件的更多细节。
+URL是{ attributes.url },标题是{ attributes.title },尺寸是{ attributes.size }。
+ ) +} +``` + +区块需负责使用`save`函数确保所有带`source`字段的属性按照属性定义保存。此过程非自动执行。 + +没有`source`的属性将自动保存在区块[注释分隔符](/docs/explanations/architecture/key-concepts.md#data-attributes)中。 + +例如,使用上述属性定义时,您需要确保`save`函数包含与`url`属性对应的img标签。`title`和`size`属性将保存在注释分隔符中。 + +*示例*:包含`url`属性的`save`函数示例 + +```js +function YourBlockSave( { attributes } ) { + return ( +
+
+```
+
+若属性随时间变化,可通过[区块弃用](/docs/reference-guides/block-api/block-deprecation.md)来迁移旧属性或完全移除。
+
+## 类型验证
+
+`type`指明属性存储的数据类型。它不表示数据存储位置(由`source`字段定义)。
+
+除非提供`enum`,否则`type`是必需的。`type`可与`enum`同时使用。
+
+`type`字段必须是以下之一:
+
+- `null`
+- `boolean`
+- `object`
+- `array`
+- `string`
+- `integer`
+- `number`(与`integer`相同)
+
+注意:`object`的有效性由您的`source`决定。示例可参阅下文的`query`详情。
+
+## 枚举验证
+
+属性可定义为固定值集合中的一个值。通过包含允许值数组的`enum`来指定:
+
+*示例*:`enum`示例。
+
+```js
+{
+ size: {
+ enum: [ 'large', 'small', 'tiny' ]
+ }
+}
+```
+
+## 值来源
+
+属性来源用于定义如何从已保存的文章内容中提取属性值。它们提供了一种从已保存标记到区块JavaScript表示的映射机制。
+
+可用的`source`值包括:
+- `(无值)`- 未指定`source`时,数据存储在区块的[注释分隔符](/docs/explanations/architecture/key-concepts.md#data-attributes)中
+- `attribute`- 数据存储在HTML元素属性中
+- `text`- 数据存储在HTML文本中
+- `html`- 数据以HTML形式存储(通常由`RichText`使用)
+- `query`- 数据以对象数组形式存储
+- `meta`- 数据存储在文章元数据中(已弃用)
+
+`source`字段通常与`selector`字段结合使用。若未指定选择器参数,源定义将针对区块根节点运行。若指定选择器参数,则将针对区块内的匹配元素运行。
+
+`selector`可以是HTML标签,或任何可通过[querySelector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)查询的内容,例如类或id属性。下方提供了示例。
+
+例如,`img`选择器将匹配`img`元素,而`img.class`将匹配具有`class`类的`img`元素。
+
+在底层实现中,属性来源是[hpq](https://github.com/aduth/hpq)库功能的超集,该小型库用于将HTML标记解析和查询为对象形态。
+
+总结而言,`source`决定数据在内容中的存储位置,而`type`决定数据的类型。为减少存储数据量,通常建议尽可能将数据存储在HTML中而非注释分隔符内的属性中。
+
+### 元数据源(已弃用)
+
+
+
+
+
+ .my-content 类的内部文本
+
+
+ The record ID: { props.attributes.recordId }
; +} +``` + +5. 创建一篇新文章并添加 `record` 区块。如果您在文本框中输入一个数字,您会看到其下方的 `record-title` 区块中显示相同的数字。 + + \ No newline at end of file diff --git a/reference-guides/block-api/block-deprecation.md b/reference-guides/block-api/block-deprecation.md new file mode 100644 index 0000000..d18bb7d --- /dev/null +++ b/reference-guides/block-api/block-deprecation.md @@ -0,0 +1,203 @@ +## 修改属性集 + +有时需要更新属性集,以重命名或修改旧属性。 + +**示例** + +```js +const { registerBlockType } = wp.blocks; + +registerBlockType( 'gutenberg/block-with-deprecated-version', { + // ... 其他区块属性 + + attributes: { + content: { + type: 'string', + default: '随机值', + }, + }, + + save( props ) { + return{ props.attributes.text }
; + }, + }, + ], +} ); +``` + +在上方示例中,我们将区块的标记从 `p` 更新为 `div`,并将 `text` 属性重命名为 `content`。 + +## 修改内部区块 + +某些情况下,在迁移区块时可能需要添加或移除内部区块。 +例如:某个区块需要将标题属性迁移至段落内部区块。 + +**示例** + +```js +const { registerBlockType } = wp.blocks; + +registerBlockType( 'gutenberg/block-with-deprecated-version', { + // ... 区块属性 + + save( props ) { + return{ props.attributes.title }
; + }, + + deprecated: [ + { + attributes: { + title: { + type: 'string', + source: 'html', + selector: 'p', + }, + }, + + migrate( attributes, innerBlocks ) { + const { title, ...restAttributes } = attributes; + + return [ + restAttributes, + [ + createBlock( 'core/paragraph', { + content: attributes.title, + fontSize: 'large', + } ), + ...innerBlocks, + ], + ]; + }, + + save( props ) { + return{ props.attributes.title }
; + }, + }, + ], +} ); +``` + +在上方示例中,我们将区块更新为使用带标题的内部段落区块,而非标题属性。 + +_以上是区块弃用的示例案例。如需查看真实场景的示例,请参阅[核心区块库](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-library/src)中的弃用实现。核心区块在版本迭代中持续更新,包含简单与复杂的弃用方案。_ + +# 弃用说明 + +> 本页面提供了关于弃用API原理与使用的完整指南。入门教程请参阅[开发者博客](https://developer.wordpress.org/news/)上的[区块弃用基础教程](https://developer.wordpress.org/news/2023/03/block-deprecation-a-tutorial/)。 + +当更新静态区块标记与属性时,区块开发者需要考虑使用旧版区块的现有文章。为提供平滑的升级路径,您可选择以下策略之一: + +- 不弃用原区块,创建新区块(使用不同名称) +- 提供区块的"弃用"版本,允许用户在区块编辑器中打开旧版内容时使用更新后的区块进行编辑。 + +一个区块可包含多个弃用版本。当解析后的区块当前状态无效,或弃用版本定义了返回true的`isEligible`函数时,将尝试执行弃用流程。 + +弃用机制并非像数据库迁移等软件数据更新那样以链式更新方式运作。初看容易认为每个弃用版本会对数据执行必要修改,然后将新形态的区块传递给下一个弃用版本继续处理。但实际流程是: + +1. 若当前`save`方法无法生成有效区块,弃用数组中的第一个弃用版本将接收原始保存内容 +2. 若该版本的`save`方法能生成有效内容,则使用此弃用版本来解析区块属性。若其包含`migrate`方法,系统将使用弃用版本解析的属性运行该方法 +3. 若首个弃用版本的`save`方法无法生成有效区块,则依次尝试数组中后续弃用版本,直到找到能生成有效区块的版本 +4. 首个生成有效区块的弃用版本对应的属性及innerBlocks,将被传回当前`save`方法以生成新的有效区块内容 +5. 此时当前区块应处于有效状态,弃用工作流程随即终止 + +需特别注意:若弃用版本的`save`方法无法生成有效区块,则其`migrate`方法也会被完全跳过——即使`isEligible`函数对给定属性返回true。这意味着若区块存在多个弃用版本且需执行新迁移(如将内容移至`InnerBlocks`),可能需要更新多个弃用版本中的`migrate`方法,以确保所有历史版本都能应用必要更改。 + +另需注意:若弃用版本的`save`方法从其他文件导入额外函数,对这些文件的修改可能意外改变弃用行为。建议将这些函数的快照副本添加到弃用文件中,而非直接导入,以避免意外破坏弃用功能。 + +对于含多个弃用版本的区块,建议将每个弃用版本保存为对应区块版本的常量,再将其添加到区块的`deprecated`数组。数组中的弃用版本应按时间倒序排列,这样区块编辑器会优先尝试应用最新且最可能的弃用版本,避免不必要的性能损耗。 + +**示例** + +```js +const v1 = {}; +const v2 = {}; +const v3 = {}; +const deprecated = [ v3, v2, v1 ]; +``` + +同时建议维护包含不同版本区块内容的[测试固件](https://github.com/WordPress/gutenberg/blob/HEAD/test/integration/fixtures/blocks/README.md),以便轻松验证新弃用版本和迁移功能在所有历史版本中的运行情况。 + +弃用定义位于区块类型的`deprecated`属性中,这是一个弃用对象数组,每个对象包含以下形式: + +- `attributes` (对象):区块弃用版本的[属性定义](/docs/reference-guides/block-api/block-attributes.md) +- `supports` (对象):区块弃用版本的[支持定义](/docs/reference-guides/block-api/block-registration.md) +- `save` (函数):区块弃用版本的[save实现](/docs/reference-guides/block-api/block-edit-save.md) +- `migrate`:(函数,可选)。接收旧属性与内部区块后,应返回新属性或与区块兼容的属性元组数组。如前所述,若弃用版本的`save`函数未返回有效区块,其`migrate`将不会运行,因此需确保迁移功能在所有相关弃用版本中均可用。 + - _参数_ + - `attributes`: 区块旧属性 + - `innerBlocks`: 区块旧内部区块 + - _返回值_ + - `Object | Array`: 更新后的区块属性或元组数组`[attributes, innerBlocks]` +- `isEligible`:(函数,可选)。当函数返回`true`时,即使区块有效仍可由该弃用版本处理迁移。这在区块技术上有效但仍需更新属性或内部区块时特别有用。**注意**:当所有先前弃用版本的save函数结果均无效时,此函数不会被调用。 + - _参数_ + - `attributes`: 从序列化HTML解析得到的原始区块属性(在应用区块类型代码之前) + - `innerBlocks`: 区块当前内部区块 + - `data`: 包含代表区块节点及其结果区块对象属性的对象 + - `data.blockNode`: 解析序列化HTML后得到的区块原始形态 + - `data.block`: 对`blockNode`应用区块类型后得到的区块对象 + - _返回值_ + - `boolean`: 指示此有效区块是否符合该弃用版本的迁移条件 + +attributes、supports和save会影响区块的解析与序列化,它们不会自动从当前版本继承,必须在弃用对象中明确定义才能在迁移过程中被处理。
+{ props.attributes.text }
; + }, + }, + ], +} ); +``` + +以上示例中,我们将区块标记从`p`标签更新为`div`标签。 \ No newline at end of file diff --git a/reference-guides/block-api/block-edit-save.md b/reference-guides/block-api/block-edit-save.md new file mode 100644 index 0000000..d0bd72d --- /dev/null +++ b/reference-guides/block-api/block-edit-save.md @@ -0,0 +1,328 @@ +### 验证常见问题解答 + +**区块如何变为无效状态?** + +导致区块失效最常见的两种原因是: + +1. 区块代码存在缺陷,导致内容被意外修改。插件开发者可参阅下文了解如何调试区块失效问题。 +2. 您或外部编辑器对区块的HTML标记进行了更改,导致其不再符合规范。 + +**作为插件开发者,应如何调试区块被标记为无效的问题?** + +开始调试前,请务必先了解上文所述的验证步骤,该步骤记录了检测区块是否无效的流程。当区块重新生成的标记与文章内容中保存的标记不匹配时,该区块即被视为无效,这通常是由于区块属性未能从已保存内容中正确解析所致。 + +若您正在使用[属性源](/docs/reference-guides/block-api/block-attributes.md),请确保从标记中提取的属性完全符合预期,且类型正确(通常应为`'字符串'`或`'数字'`类型)。 + +当检测到区块无效时,浏览器开发者工具控制台会记录警告信息。该警告会包含标记差异具体位置的详细信息。请仔细比对预期标记与实际标记的差异,定位问题根源。 + +**更改区块的`save`行为后,旧内容中出现无效区块应如何修复?** + +请参阅[过时区块处理指南](/docs/reference-guides/block-api/block-deprecation.md),了解如何在主动调整标记时兼容历史内容。 + +## 示例 + +以下是结合使用属性、编辑和保存功能的几个示例。 + +### 将属性保存至子元素 + +```jsx +attributes: { + content: { + type: 'string', + source: 'html', + selector: 'div' + } +}, + +edit: ( { attributes, setAttributes } ) => { + const blockProps = useBlockProps(); + const updateFieldValue = ( val ) => { + setAttributes( { content: val } ); + } + return ( +