Elementor Global Classes 数据模型解析:CPT 持久化、Kit Meta 与仓库 API 实战指南
2026/9/17 22:05:56 网站建设 项目流程

Elementor Global Classes 数据模型解析:CPT 持久化、Kit Meta 与仓库 API 实战指南

【免费下载链接】elementorThe most advanced frontend drag & drop page builder. Create high-end, pixel perfect websites at record speeds. Any theme, any page, any design.项目地址: https://gitcode.com/GitHub_Trending/el/elementor

导读

Global Classes(全局类)是 Elementor 4.0 原子构建体系中用于承载"可复用视觉样式"的 Kit 级数据模型:每个全局类以一条 WordPress 自定义文章类型(CPT)记录持久化,其顺序、标签映射与 ID 索引则存放在 Site Kit 的文章元数据(post meta)中。本文以 docs/atomic-builder/global-classes/data-model.md 为核心主线,逐层拆解其存储布局(CPT + kit meta)、{ items, order }内存形态、label与内部g-*ID 的区别、数据不变量(含 1000 条上限与顺序规范化)、sync_to_v3同步机制、Repository/Parser 公开 API,并结合modules/global-classes/下的源码实现,帮助你理解 Kit 导入导出(global-classes.json)、调试 RESTPUT载荷与 MCPmanage-classes、追踪预览态与发布态差异,以及理清每个 Kit 的隔离边界。

数据模型总览:两层存储 + 一个内存形态

Global Classes 的数据并非单一存储,而是"CPT 帖子 + Kit meta + 内存值对象"三层配合:

层次载体职责
CPT 帖子e_global_class(每类一条)保存标签(label)、内部 ID、发布态/草稿态 variants
Kit post meta活跃 Site Kit 上的 meta顺序、标签映射、id → 帖子ID查找表、v3 同步标记
内存值对象Global_Classes统一对外暴露{ items, order }形态

内存中的完整形态如下(来自>{ "items": { "g-abc123": { "id": "g-abc123", "label": "wc26-gold", "type": "class", "variants": [ { "meta": { "breakpoint": "desktop", "state": null }, "props": { "color": { "$$type": "color", "value": "#D4AF37" } } } ] } }, "order": ["g-abc123", "g-def456"] }

items以内部 ID 为键,order是 ID 的有序数组。两条关键约定需要牢记:

  • 面向作者(author-facing)的上下文一律用 label 引用类,例如 HTML 的class属性、MCP 的classes映射;
  • 内部 ID(g-*)是稳定存储键,出现在元素 JSON 的settings.classes.value、REST 更新/删除以及 Kit meta 中,不应对作者暴露。

从实现上看,Global_Classes_Repository::all()会先读 Kit 的 order meta,再按 ID 批量拉取 CPT,最后组装成Global_Classes::make( $items, $order )值对象,并在组装时调用Global_Classes_Parser::sanitize_order()兜底修复顺序(见 global-classes-repository.php 与 global-classes-parser.php)。

何时需要理解这份数据模型

  • 理解 Kit 导出结构:导入/导出产生的global-classes.json正是{ items, order }的序列化形态,模块内的 import-export/export-runner.php 与 import-export/import-runner.php 直接操作该结构;
  • 调试 RESTPUT载荷或 MCPmanage-classesPUT elementor/v1/global-classes的参数(itemsorderchanges)与本数据模型一一对应,理解校验逻辑才能定位 400 报错;
  • 追踪预览态与发布态:草稿与发布分别使用独立的 meta 键,阅读数据模型可解释"编辑器里改了没生效/发布了才生效"的现象;
  • 推理每个 Kit 的隔离:所有类帖子与 meta 都归属活跃 Kit,不同 Kit 之间互不可见。

CPT 持久化:e_global_class

每个全局类对应一条e_global_class类型的帖子。该 CPT 在 global-class-post-type.php 中注册:public => false(不对外公开、无前端 URL),仅supports => ['title'],即只用标题字段。

字段与存储位置的映射如下(原文档表格):

字段存储位置
Label(标签)post_title
Internal id(内部 ID)_elementor_global_class_id
Published variants(发布态变体)_elementor_global_class_data
Draft variants(草稿态变体)_elementor_global_class_data_preview

这些 meta 键在 global-class-post.php 中以常量定义:

const META_KEY_VERSION = '_elementor_version'; const META_KEY_ID = '_elementor_global_class_id'; const META_KEY_DATA = '_elementor_global_class_data'; const META_KEY_DATA_PREVIEW = '_elementor_global_class_data_preview'; const META_KEY_EDITED = '_elementor_global_class_edited';

Global_Class_Post还额外维护两个辅助 meta:

  • _elementor_version:记录数据写入时的 Elementor 版本,供迁移编排器判断是否需要跑 prop-type 迁移;
  • _elementor_global_class_edited:最近编辑时间戳(发布态写入时刷新),用于判断"类是否被编辑过"(was_edited()比较该时间与创建时间)。

Global_Class_Post::to_array()负责把帖子归一化为StyleDefinition形态:先读取上下文对应的 variants 数据,合并label,再经Global_Class_Data_Normalizer::normalize_style()输出{ id, label, type, variants }(见 utils/global-class-data-normalizer.php)。一个值得注意的实现细节:草稿态数据为空时,读取会回退到发布态数据get_data()empty( $data ) && is_preview()分支),因此一个从未被编辑过的类,在预览上下文下也能读到发布内容。

写入侧,Global_Class_Post::create()wp_insert_post创建帖子,写入META_KEY_IDMETA_KEY_DATAMETA_KEY_VERSION,并在 Kit 的Global_Classes_Post_IDs映射中登记class_id → post_idupdate_data()按当前上下文写入 variants meta;非预览写入时还会同步清除草稿 metadelete_post_meta( ..., META_KEY_DATA_PREVIEW )),保证发布态总是权威的。

Kit meta:顺序、标签映射与 ID 索引

每个类的内容存在 CPT 上,但"类如何组织成 Kit"的信息——顺序、标签映射、ID 索引——全部存放在活跃 Site Kit 的 meta 中。完整清单如下(原文档表格):

Meta 键用途
_elementor_global_classes_order发布态类 ID 顺序
_elementor_global_classes_order_preview草稿态顺序
_elementor_global_classes_labels发布态id → label映射
_elementor_global_classes_labels_preview草稿态标签映射
_elementor_global_classes_post_ids内部 ID → CPT 帖子 ID
_elementor_global_classes_sync_to_v3已同步到 v3 全局字体的类 ID

对应源码常量分别位于 global-classes-order.php(_elementor_global_classes_order/_elementor_global_classes_order_preview)、global-classes-labels.php(_elementor_global_classes_labels/_elementor_global_classes_labels_preview)与 global-classes-post-ids.php(_elementor_global_classes_post_ids)。

各存储组件都实现相同的"上下文切换"模式,通过Has_Preview_Contexttrait 在frontend(发布)与preview(草稿)之间切换,并具备以下行为:

  • 顺序Global_Classes_Order把 ID 数组以['order' => [...]]载荷写入 Kit meta;预览态读不到内容时自动回退到发布态(read_kit_meta_payload()中的回退逻辑);
  • 标签Global_Classes_Labels维护扁平映射,get_ordered_labels()会按 order 输出有序的id → label,预览态缺失的标签从发布态映射补齐;
  • ID 索引Global_Classes_Post_IDs保存class_id → post_id映射,读取时会校验帖子仍存在,若已被删除则自动从映射中移除(get_post_id()的清理逻辑);同时它挂在deleted_post钩子上,任何e_global_class帖子被删除后都会在所有 Kit 中清除对应条目。

仓库上下文(Context)

Repository 通过两个常量区分读写上下文:

const CONTEXT_FRONTEND = 'frontend'; const CONTEXT_PREVIEW = 'preview';

REST 端点、MCP 调用以及 JSapiClient.all( context )都接受这两个取值。set_preview()切换上下文时会清空内存缓存(on_preview_change()$cache置空),避免脏读。

Label 与内部 ID:两个概念,一个对应关系

这是全局类数据模型中最容易混淆的一对概念:

概念出现位置说明
LabelHTMLclass属性、MCPclasses映射公开的 CSS 类名,例如wc26-gold
内部 ID(g-*元素settings.classes.value、REST 更新/删除稳定存储键,随导入导出保持不变

元素侧通过Classes_Prop_Type(modules/atomic-widgets/prop-types/classes-prop-type.php)保存有序的内部 ID 引用数组;渲染时由样式系统把 ID 解析为 label 输出为最终 CSS 类名。

重复 label 的自动改名是数据完整性的一道防线,实现在Global_Classes_Labels::generate_unique_label()

  • 冲突标签会被加上DUP_前缀并追加递增数字(如DUP_wc26-gold1);
  • 最终长度上限50 字符$max_length = 50),超长时先截断原始部分再拼接计数器;
  • 已有DUP_前缀的标签再次冲突时,会在前缀基础上继续递增计数器,保证始终唯一。

在 REST 层,Global_Classes_REST_API::put()会先调用Global_Classes_Parser::check_for_duplicate_labels()检查新增项是否与存量标签冲突;若冲突,服务端自动改名并返回{ "code": "DUPLICATED_LABEL", "modifiedLabels": { "<item_id>": { "original": "...", "modified": "DUP_..." } } },客户端可根据modifiedLabels回显修正后的名称(见 global-classes-rest-api.php)。

数据不变量(Invariants)

模型层保证以下约束不被破坏:

  1. order是级联与 UI 的权威排序:层叠(cascade)优先级与界面展示都依据该数组,后出现的条目在样式冲突时胜出;
  2. items的键必须与order匹配:解析器通过sanitize_order()兜底——过滤非字符串项、去重、只保留 items 中真实存在的 ID,并把缺失的 ID 按字符串排序追加到末尾;parse_order()则严格校验order与最终 item ID 集合完全一致,缺失项报missing、多余项报excess
  3. 每个 Kit 最多 1000 个类:上限常量定义在Global_Classes_REST_API::MAX_ITEMS = 1000PUT写入时计算当前总数 - 删除数 + 新增数,超限返回 400,错误码global_classes_limit_exceeded,并在 meta 中携带current_countmax_allowed
  4. 新 Kit 会克隆上一个 Kit 的类帖子Global_Class_Post::clone_to_kit()/clone_to_other_kit()会复制源帖子的_elementor_global_class_id、发布态与草稿态数据、版本与编辑时间戳,并在目标 Kit 的Global_Classes_Post_IDs中重新登记,实现跨 Kit 的样式继承。

解析器的完整校验链路

Global_Classes_Parser(global-classes-parser.php)是载荷校验的核心,完整流程如下:

  • parse( $data ):要求$data同时包含itemsorder两个键,否则返回missing错误;随后依次执行parse_itemsparse_order,两者都通过才返回{ items, order }的规范化结果;
  • parse_items( $items ):对每个 item 调用Style_Parser(基于Style_Schema校验 variants 与 props,见 docs/atomic-builder/fundamentals/style-schema.md);同时强制item 的键必须与 item 内id字段一致,不一致时报mismatching_value并拒绝该条;
  • parse_order( $order, $final_item_ids ):去重、仅保留字符串后,对比期望 ID 集合,报告missing/excess

RESTPUT的参数约束(changes对象)也在这里体现:

{ "changes": { "added": ["g-abc123"], "deleted": [], "modified": ["g-def456"], "order": true }, "items": { "g-abc123": { "id": "g-abc123", "label": "wc26-gold", "type": "class", "variants": [] } }, "order": ["g-abc123", "g-def456"] }

其中changes的四个字段(added/deleted/modified为字符串数组,order为布尔值,表示顺序是否发生变化)在Global_Classes_Repository::apply_changes()中决定批处理动作。

sync_to_v3:可选的传统全局字体同步

sync_to_v3是类 item 上的一个可选布尔字段,表示该类的排版(typography)是否镜像同步到传统 v3 全局字体(Global Fonts):

  • 值为true时,类中的字体相关 props 会通过 modules/design-system-sync/ 模块同步到 v3 体系,保证旧特性与新原子样式库不脱节;
  • 该字段仅在编辑器 UI 中提供开关,MCP 不暴露此字段;
  • 数据归一化时,Global_Class_Data_Normalizer::normalize_style_fields()会把sync_to_v3强制转换为布尔值((bool) $item['sync_to_v3']);
  • apply_changes()/put()的非预览分支中,变更会交给Global_Classes_Sync_Map::apply_changes( $touched_items, $to_delete )驱动实际同步。

Public API:Repository 与 Parser

数据模型对外暴露的 PHP API 集中在 Repository 与 Parser 两个类(原文档表格,签名以源码为准):

方法签名用途
Global_Classes_Repositorypublic function all( bool $force = false ): Global_Classes读取全部类,返回{ items, order }值对象;带内存缓存,$force = true强制穿透
Global_Classes_Repositorypublic function get( string $class_id ): ?array按内部 ID 读取单个类(无则返回null
Global_Classes_Repositorypublic function get_by_ids( array $class_ids ): array按 ID 批量读取
Global_Classes_Repositorypublic function get_order(): array返回有序 ID 列表
Global_Classes_Repositorypublic function apply_changes( array $touched_items, array $changes, array $order ): void批量写入增量变更(增/删/改 + 顺序)
Global_Classes_Repositorypublic function put( array $items, array $order )全量替换(导入场景),内部自动 diff 出 added/deleted/modified
Global_Classes_Parserpublic function parse( $data ): Parse_Result校验完整{ items, order }载荷
Global_Classes_Parserpublic function parse_items( array $items )仅校验 items
Global_Classes_Parserpublic function parse_order( array $order, array $final_item_ids )校验/规范化顺序

源码位置:global-classes-repository.php、global-classes-parser.php。

all()的实现值得留意(含源码注释提醒):该方法可能较重,会阻塞直到拉取全部全局类,调用方应注意批处理与缓存。读取侧按READ_BATCH_SIZE = 100分批执行get_posts()(以meta_queryIN匹配_elementor_global_class_id),配合clean_post_cache()wp_cache_flush_runtime()控制内存占用;写入侧同样按PERSIST_BATCH_SIZE = 100分批执行创建/更新/删除。

扩展方式:固定数据模型,只走 REST 与 MCP

Global Classes 采用固定数据模型,不提供公开注册钩子(no public registration hook)。扩展与集成必须通过以下两个受支持入口:

  1. REST APIPUT elementor/v1/global-classes(含context参数区分预览/发布),详见 docs/atomic-builder/global-classes/api.md;
  2. MCPelementor/manage-classes工具。

不要直接写 CPT 或 meta——绕过 Repository 的写入会破坏顺序、标签映射、ID 索引与 usage 关系的一致性。若要在自定义 Widget 上暴露classes属性,正确做法是在define_props_schema()中调用Classes_Prop_Type::make()

REST 端点全景(源码常量API_NAMESPACE = 'elementor/v1'API_BASE = 'global-classes'):

端点方法权限说明
/elementor/v1/global-classesGET已登录用户返回有序[{ id, label }]索引
/elementor/v1/global-classesPUTAdd_Capabilities::UPDATE_CLASS增量更新(changes + items + order)
/elementor/v1/global-classes/post?post_id=GET已登录用户单个文档实际使用的类
/elementor/v1/global-classes/styles?ids=GET已登录用户按逗号分隔 ID 批量取类
/elementor/v1/global-classes/usageGETmanage_options类的使用统计

所有端点都接受context参数(frontend/preview,默认frontend)。

内部机制:读、写与关系索引

读路径

all() → 读 Kit order meta → 按 ID 分批批量取 CPT → Global_Classes_Parser::sanitize_order() → Global_Classes 值对象

all_from_posts()先取 order;order 为空直接返回空值对象,否则按iterate_class_posts_for_ids()分批遍历帖子,逐条to_array()组装 items,最后sanitize_order()修复顺序。读取时若数据带版本信息,会经Migrations_Orchestrator自动执行 prop-type 数据迁移并写回(见 docs/atomic-builder/migration/prop-type-migrations.md 与Global_Class_Post::migrate_data())。

写路径

apply_changes() → 按 added/deleted/modified 分批做 CPT CRUD → 更新 order/labels meta → (非预览)同步 v3 + 清除草稿 meta → 触发 elementor/global_classes/update 动作 → (有删除且非预览)触发 elementor/global_classes/cleanup

apply_changes()(global-classes-repository.php)的核心步骤:

  1. 依据$changes['deleted'|'added'|'modified']计算受影响文档 ID(用于后续清理);
  2. persist_class_batch_mutations()分批执行删除(预览态清空数据、发布态删帖并清除关系)、创建(Global_Class_Post::create()并登记post_ids_map)、更新(写入数据与 label);
  3. 重建orderlabels映射;
  4. 非预览分支:Global_Classes_Sync_Map同步 v3、把同一 order 写入预览态、批量清除预览 meta 与预览标签(保证发布后草稿不留残留);
  5. 触发elementor/global_classes/update动作(载荷含added/deleted/modified/order/affected_post_ids);存在删除且非预览时再触发elementor/global_classes/cleanup

put()是导入专用路径:先与当前状态 diff 出增删改,收集受影响文档后再put_to_posts()全量落库,同样触发 update/cleanup 动作。源码注释特别说明了"预先收集受影响文档"的原因:更新机制在批处理迭代时会顺带处理Global_Classes_Relations,进入清理阶段时关系已不存在;提前收集还能避免同一文档被 N 个被删类重复遍历 N 次。

关系索引(Relations)

Global_Classes_Relations(global-classes-relations.php)在文档保存时(钩子elementor/document/after_save)重建"文档 ↔ 类"的双向索引:

  • 正向:文档 meta_elementor_used_global_class(预览态_elementor_used_global_class_preview)记录该文档用到的类 ID;
  • 反向:类 CPT 的 meta_elementor_global_class_using_documents记录哪些文档使用该类,供删除时快速定位受影响文档;
  • 索引标记:_elementor_global_class_usage_indexed(预览态后缀_preview)避免重复全量扫描。

正是这套索引支撑了 REST 的/global-classes/post/global-classes/styles端点,以及删除类时的affected_post_ids清理通知。删除类的清理动作(elementor/global_classes/cleanup)由模块监听后移除文档中的类引用,详见 global-classes-cleanup.php。

数据模型相关的其他文档

  • docs/atomic-builder/global-classes/overview.md:模块全景、实验开关e_classes与两种"classes"概念辨析;
  • docs/atomic-builder/global-classes/api.md:REST 与 MCP 完整接口;
  • docs/atomic-builder/global-classes/applying-classes.md:类如何挂接到元素并解析为 CSS;
  • docs/atomic-builder/fundamentals/style-schema.md:variants 与 props 的校验 Schema;
  • docs/atomic-builder/migration/prop-type-migrations.md:读取期的 prop-type 数据迁移机制。

【免费下载链接】elementorThe most advanced frontend drag & drop page builder. Create high-end, pixel perfect websites at record speeds. Any theme, any page, any design.项目地址: https://gitcode.com/GitHub_Trending/el/elementor

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询