PluginProbe
Elementor Website Builder – more than just a page builder / 4.0.0-dev5
Elementor Website Builder – more than just a page builder v4.0.0-dev5
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / migrations / README.md

README.md in Elementor Website Builder – more than just a page builder 4.0.0-dev5, at migrations/README.md

440 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 # Prop Type Migrations
2
3 ## System Overview
4 This is a **prop type migration system**, not a general data migration system.
5
6 **Trigger**: Migrations run when it finds a mismatch between data prop type, and actual schema (code) (e.g., `string``string-v2`). Without a type change, there's no trigger and no migration.
7
8 **Scope**: Having mismatch of type (e.g., `string``string-v2`) will find all instances of mismatch, and send the object to run migration script on.
9
10 See [](#migration-scopeMigration Scope](#migration-scope](#migration-scope) for details.
11
12 ## Appendix
13 - [](#structureStructure](#structure](#structure)
14 - [](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+InvestigationLanguage Design](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation)
15 - [](#pathsPaths](#paths](#paths)
16 - [](#conditionsConditions](#conditions](#conditions)
17 - [](#functionsFunctions](#functions](#functions)
18 - [](#examplesExamples](#examples](#examples)
19
20 ## Structure
21 ### Manifest
22 Manifest describes the different migrations, it can contain widget key migrations and prop-type migrations
23 ```json
24 {
25 "widgetKeys": {
26 "e-logo": [
27 { "from": "svg", "to": "icon" }
28 ]
29 },
30 "propTypes": {
31 "string-to-html": {
32 "fromType": "string",
33 "toType": "html",
34 "url": "string-to-html.json"
35 }
36 }
37 }
38 ```
39 ### Prop Type Migrations
40 Prop type migrations are a set of operations, **up** for upgrade and reverse **down** for downgrade.
41 Prop type migrations support wildcard paths and conditions (see below)
42 ```json
43 {
44 "up": [
45 {
46 "op": {
47 "fn": "set",
48 "path": "$$type",
49 "value": "html"
50 }
51 }
52 ],
53 "down": [
54 {
55 "op": {
56 "fn": "set",
57 "path": "$$type",
58 "value": "string"
59 }
60 }
61 ]
62 }
63 ```
64
65 ## Paths
66 Path parameter works with wildcard, starting from the **root of the prop object**.
67
68 **Important**: For **prop type migrations** (the primary use case), paths always start at the prop root—not the widget or document root. For example:
69 - `$$type` refers to the type field at the prop root
70 - `value.nested` refers to `propObject.value.nested`
71 - Wildcards like `value.*` or `value.items[*]` match children within the prop
72
73 **Widget key migrations** (rare) start at the widget/element root instead. See [](#migration-scopeMigration Scope](#migration-scope](#migration-scope) for details.
74
75 ## Conditions
76 Conditions check whether to run the migration or not, with many helper functions such as `exists`, conditions can be compounded by `AND` and `OR`.
77 Full list can be found [](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#Available-Conditionshere](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#Available-Conditions](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#Available-Conditions)
78
79 ## Important Notes
80
81 ### Data Transformations
82 **Migrations do NOT support value transformations.** Migrations are purely structural - they create or update, but can't activate any functions on the data.
83
84 Handle transformations in transformer code
85 - Migrations change structure: `{ "color": "#fff" }``{ "color": { "$$type": "color", "value": "#fff" } }`
86 - Transformers can take current values, and transform them `{ "oldColor": "#fff", "newColor": {} }` -> `{ "oldColor": "#fff", "newColor": { "gradient": "something", "value": "#fff" }}`
87
88 ### Migration Scope
89 - **Prop Type Migrations**: Operate on a single prop instance, paths start at prop root
90 - **Widget Key Migrations**: Operate on entire widget element, paths start at element root
91 - Migrations run **before** validation and transformation in the data processing pipeline
92
93 **Example widget:**
94
95 ```json
96 {
97 "id": "heading-1",
98 "elType": "widget",
99 "widgetType": "e-heading",
100 "settings": {
101 "title": {
102 "$$type": "string",
103 "value": "Hello"
104 },
105 "tag": {
106 "$$type": "string",
107 "value": "h2"
108 }
109 }
110 }
111 ```
112
113 **Prop Type Migration** (e.g., `title` migrating from `string``string-v2`):
114 - Operates on **just the prop object**:
115 ```json
116 {
117 "$$type": "string",
118 "value": "Hello"
119 }
120 ```
121 - Paths are relative to prop root: `$$type`, `value`
122
123 **Widget Key Migration** (e.g., renaming `tag``htmlTag`):
124 - Operates on **the entire widget/element**
125 - Paths are relative to widget **settings** root: `tag`, `title.value`
126
127 ### Performance Considerations
128 - Migration state is cached per document with version + manifest hash
129 - Cache clears on Elementor version change, manifest change, or feature flag toggle
130
131 ## Functions
132 ### Set
133 `set` creates or updates data, it can update key / value or both. Full Documentation [](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#sethere](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#set](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#set)
134 Params:
135 - key (optional)
136 - value (optional)
137 - merge **default** true - attempts to deep merge objects instead of replace
138
139 #### Usage
140 Replaces nested key and value
141 ```json
142 { "op": { "fn": "set", "path": "value.*.nested", "value": ["a"], "key": "nested2" } }
143 ```
144 Appends to array
145 ```json
146 { "op": { "fn": "set", "path": "value.*.nested.[]", "value": "a" } }
147 ```
148 Creates empty object at path
149 ```json
150 { "op": { "fn": "set", "path": "value.*.nested.[*]" } }
151 ```
152
153 ### Delete
154 `delete` removes keys/values at specified path. Full Documentation [](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#deletehere](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#delete](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#delete)
155 Params:
156 - clean **default** true - deletes empty parent paths until reaching an object that has siblings
157
158 #### Usage
159 Delete specific nested key
160 ```json
161 { "op": { "fn": "delete", "path": "value.deprecated" } }
162 ```
163 Delete all matching wildcard paths
164 ```json
165 { "op": { "fn": "delete", "path": "value.items[*].legacy" } }
166 ```
167 Delete without cleaning empty parents
168 ```json
169 { "op": { "fn": "delete", "path": "value.old", "clean": false } }
170 ```
171
172 ### Move
173 `move` relocates values from one path to another. Full Documentation [](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#movehere](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#move](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#move)
174 Params:
175 - src - Source path
176 - dest - Destination path
177 - clean **default** true - deletes source path after move (will delete empty paths until reaching an object that has siblings)
178
179 #### Usage
180 Move simple value to new location
181 ```json
182 { "op": { "fn": "move", "src": "value.oldField", "dest": "value.nested.newField" } }
183 ```
184 Move without cleaning source
185 ```json
186 { "op": { "fn": "move", "src": "value.data", "dest": "value.backup", "clean": false } }
187 ```
188 Move nested object structure
189 ```json
190 { "op": { "fn": "move", "src": "value.settings", "dest": "value.config.settings" } }
191 ```
192
193 ## Examples
194
195 ### Widget Key Migration: Rename Settings Key
196
197 **Context**: Rename a widget settings key from `tag``htmlTag`. Paths start at **widget settings root**.
198
199 ```json
200 {
201 "up": [
202 { "op": { "fn": "set", "path": "tag", "key": "htmlTag" } }
203 ],
204 "down": [
205 { "op": { "fn": "set", "path": "htmlTag", "key": "tag" } }
206 ]
207 }
208 ```
209
210 **Before**:
211 ```json
212 {
213 "id": "heading-1",
214 "elType": "widget",
215 "widgetType": "e-heading",
216 "settings": {
217 "tag": {
218 "$$type": "string",
219 "value": "h2"
220 },
221 "title": {
222 "$$type": "string",
223 "value": "Hello"
224 }
225 }
226 }
227 ```
228
229 **After**:
230 ```json
231 {
232 "id": "heading-1",
233 "elType": "widget",
234 "widgetType": "e-heading",
235 "settings": {
236 "htmlTag": {
237 "$$type": "string",
238 "value": "h2"
239 },
240 "title": {
241 "$$type": "string",
242 "value": "Hello"
243 }
244 }
245 }
246 ```
247
248 ### Prop Type Migration: Change Type
249
250 **Context**: Migrate `string``html` type. Paths start at **prop root**.
251
252 ```json
253 {
254 "up": [
255 { "op": { "fn": "set", "path": "$$type", "value": "html" } }
256 ],
257 "down": [
258 { "op": { "fn": "set", "path": "$$type", "value": "string" } }
259 ]
260 }
261 ```
262
263 **Before**: `{ "$$type": "string", "value": "Hello" }`
264 **After**: `{ "$$type": "html", "value": "Hello" }`
265
266 ### Prop Type Migration: Rename Keys (Simple and Wildcard)
267
268 **Context**: Rename keys using `key` parameter, with and without wildcards. Paths start at **prop root**.
269
270 **Simple key rename:**
271 ```json
272 {
273 "up": [
274 { "op": { "fn": "set", "path": "value.oldName", "key": "newName" } }
275 ],
276 "down": [
277 { "op": { "fn": "set", "path": "value.newName", "key": "oldName" } }
278 ]
279 }
280 ```
281
282 **Wildcard key rename across multiple objects:**
283 ```json
284 {
285 "up": [
286 {
287 "op": { "fn": "set", "path": "value.*.oldName", "key": "newName" },
288 "condition": { "fn": "exists", "path": "value.*.oldName" }
289 }
290 ],
291 "down": [
292 {
293 "op": { "fn": "set", "path": "value.*.newName", "key": "oldName" },
294 "condition": { "fn": "exists", "path": "value.*.newName" }
295 }
296 ]
297 }
298 ```
299
300 **Before** (wildcard example):
301 ```json
302 {
303 "$$type": "responsive",
304 "value": {
305 "desktop": { "oldName": "value1" },
306 "tablet": { "oldName": "value2" },
307 "mobile": { "oldName": "value3" }
308 }
309 }
310 ```
311
312 **After**:
313 ```json
314 {
315 "$$type": "responsive",
316 "value": {
317 "desktop": { "newName": "value1" },
318 "tablet": { "newName": "value2" },
319 "mobile": { "newName": "value3" }
320 }
321 }
322 ```
323
324 ### Prop Type Migration: Wildcards with Array Items
325
326 **Context**: Update all color types in a gradient using array wildcards `[*]`. Paths start at **prop root**.
327
328 ```json
329 {
330 "up": [
331 {
332 "op": { "fn": "set", "path": "value.stops[*].color.$$type", "value": "color" },
333 "condition": { "fn": "equals", "path": "value.stops[*].color.$$type", "value": "string" }
334 }
335 ],
336 "down": [
337 {
338 "op": { "fn": "set", "path": "value.stops[*].color.$$type", "value": "string" },
339 "condition": { "fn": "equals", "path": "value.stops[*].color.$$type", "value": "color" }
340 }
341 ]
342 }
343 ```
344
345 **Before**:
346 ```json
347 {
348 "$$type": "gradient",
349 "value": {
350 "stops": [
351 { "position": 0, "color": { "$$type": "string", "value": "#ff0000" } },
352 { "position": 50, "color": { "$$type": "string", "value": "#00ff00" } },
353 { "position": 100, "color": { "$$type": "string", "value": "#0000ff" } }
354 ]
355 }
356 }
357 ```
358
359 **After**:
360 ```json
361 {
362 "$$type": "gradient",
363 "value": {
364 "stops": [
365 { "position": 0, "color": { "$$type": "color", "value": "#ff0000" } },
366 { "position": 50, "color": { "$$type": "color", "value": "#00ff00" } },
367 { "position": 100, "color": { "$$type": "color", "value": "#0000ff" } }
368 ]
369 }
370 }
371 ```
372
373 ### Prop Type Migration: Compound Conditions (AND/OR)
374
375 **Context**: Use `and`/`or` conditions to selectively migrate items. Paths start at **prop root**.
376
377 ```json
378 {
379 "up": [
380 {
381 "op": { "fn": "set", "path": "value.items[*].type", "value": "enhanced" },
382 "condition": {
383 "fn": "and",
384 "conditions": [
385 { "fn": "equals", "path": "value.items[*].type", "value": "legacy" },
386 { "fn": "exists", "path": "value.items[*].data" }
387 ]
388 }
389 },
390 {
391 "op": { "fn": "set", "path": "value.items[*].migrated", "value": true },
392 "condition": {
393 "fn": "or",
394 "conditions": [
395 { "fn": "equals", "path": "value.items[*].type", "value": "enhanced" },
396 { "fn": "not_exists", "path": "value.items[*].migrated" }
397 ]
398 }
399 }
400 ],
401 "down": [
402 {
403 "op": { "fn": "set", "path": "value.items[*].type", "value": "legacy" },
404 "condition": { "fn": "equals", "path": "value.items[*].type", "value": "enhanced" }
405 },
406 {
407 "op": { "fn": "delete", "path": "value.items[*].migrated" }
408 }
409 ]
410 }
411 ```
412
413 **Before**:
414 ```json
415 {
416 "$$type": "list",
417 "value": {
418 "items": [
419 { "type": "legacy", "data": { "content": "Item 1" } },
420 { "type": "legacy", "data": { "content": "Item 2" } },
421 { "type": "new", "data": { "content": "Item 3" } }
422 ]
423 }
424 }
425 ```
426
427 **After**:
428 ```json
429 {
430 "$$type": "list",
431 "value": {
432 "items": [
433 { "type": "enhanced", "data": { "content": "Item 1" } },
434 { "type": "enhanced", "data": { "content": "Item 2" } },
435 { "type": "new", "data": { "content": "Item 3" } }
436 ]
437 }
438 }
439 ```
440