JFIF    $         d d  7    * Z qn )ZP 0   !1 A "#a$2Qr   D8 a Ri [f  \m I ykI w0 c u F c Rı?lO7 к _f˓ [C $殷WF< _W ԣ s Kc ëI zyQy /_LK ℂ ;C",p F A : /] =H  ~ , l s / 9  ć: [=/#f ; ) x { ٛE Q )~     = 𘙲r*2~  a _V = '  ku m F  D } KYYC )( { * g& f `툪 r y ` = ^ c J. I ]( * `wq  1dđ #̩ ͑ 0  ; H ] u 搂 @:~ ו K L  N s h } O I R* 8 :2 ! lD JV o (  3 = M ( z Ȱ+i *N A  r6K n S l ) ! J J Ӂ* %  ݉?|D } d5: eP0 R; {$X' x F @ .ÊB {,WJ uQ ɲRI ;9 Q E琯 6 2fT .DU J ;*c  P A\IL Nj! J ۱+ O\ ͔ ] ޒ S߼ J ȧ c%A N ol  ՎprU L Zԛe r E2= X D Xg VQeӓ k y P7 U* o m Q I s ,K `) 6\G3t?pgjr m ۛجw luGt f  h 9uyP 0D;Uڽ"OXl i f $ ) &|ML 0 Z rm1 [ H XP l P R0  'G=i 2N +0 e 2 ]] 9 VT P  O׮ 7 h(F * 癈 ' = Q VZD F,d ߬ ~ T X G[ `le 69C R(!S2! P  < 0 x <     !1AQ "Raq 02Br #S CTb  ? Ζ "]mH5WR 7 k.ۛ ! } Q~ + yԏ z |@ T20 S~ K e k *zF f^2X *( @ 8 r ? C I uI|֓>^Ex LgNU Y+{.R Ѫ τV׸ YT D I 6 2 '8Y2  7'\T P.6 d &˦ @V q i  |8 -O Ε  ] ʔ U=   T L 8= ;6c |  !qfF3 a ů& ~$ l} 'NW U s$U k^S V : U# 6w +  +s &r+n ڐ   { @ 29 gL u " T Ù  M=6  (^ "7 r}=6Yݾ lC u hquymp Ǧ G jhs ǜNl ɻ} o 7 #S6 a w 4 !  OS  r D  5 7 % | ?x> L |  / nD 6?/8 w # [ ) L 7 +6〼T A T g   !  %5  Mm Z /c  -{1_Je "| ^$ 'O  & ޱմ < H vNqϡQ$ < 6 &Nݛ ֨tǻN (9 n ru~'όN sMG& ,uH Kw *Ī 5@  u6  BԒ  i YN * f 0 _ GhKW u  lT <nj- 0{  M L~ | /a v\ E = ?1 \ɟuq Ђ Y O a K ޡP q  $ H8o Q˼EV ~ k 0 h' L  Pp M -M"  m^ !6l nմ 쮝C U T . ! :vMǨb h ډ Vc r @񄞅~p   #   !1QAa q  ? AL0L  x LU 4 d ; x   " 16ad0 7.\ߋ 0  = P l v/ " c A Ay A|2pO8"d MV #1] = \ " ˡ ] k v I9 d ۓ & q ) ǐq E ꞅ v "P )q X  &Q  З non]я u ג./ ; gZ$ M QР 2M ]h ni 0  P $ێ 3CɏGjώy : m c # S_ l@ '_ \m|C 2`K _  1 cIvGc $? PCQ S+D ? K aײ k Fr b 8 ύ NEدg ĝ U 3  6 #Ik+ v  {ƒ v i ( ވ  ? a e)  X xy/*@Q Ǽ Ծ ) $ IWO l c G;  !i  k{ gOŀ L ('x  T rb $ w) R $ & N1E td U3Uȉ1p M"N* (DNy d96.(jQ)  X 5 c QɎMy W ?  Q *!R > 6=7)Xj 5`J ] e  8%t ! + ' ! 1Q 5   !1 AQaq ё #2 "0BRb ? G t^ ## .l lQ T $  v , ,m   㵜5u bV  =sY+ @d { N ! dn O < .- B;  _w J t 6;Q  Jd. Q c%p{ 1 ,sND dF H I0 Гo X ш  e黅X ۢ F :)[ F G X ƹ / w _c MeD   ,ʡc c .  W D  tA $ j@ : ) - # u c1< @ۗ9F ) KJ- hpP] _ x [ q B lb p ʖ w q " LFGd ƶ * s +ډ_Zc " ? % t[I P  6 J ]# =ɺ V v v CGs Gh1 > )6 |e y ? L ӣ m,4 G W Ui ` ] uJVo VDG< SB 6ϏQ @ TiU l y O U 0 kfV ~ ~}S Z @ *WU Ui ## ; s /[ = ! 7}" W N ] ' (L !  ~ y5 g9T̅J kbM' +s :S +B) v @ M  j e C f j E 0  Y\Qn z G 1 д~ W o{T 9?`  Rm yhsy3 !HAD ] m  c1 ~ 2 L  S u7x T ;j$ `} 4-> L#  vzŏ I L S  ֭  T { r  jGK C ; b  pU= - ` Bs K. S F w4  M q] Z dH S 0 ) tLg Tiny File Manager | README.md
  • File: README.md
  • Full Path: /home/mata8712/public_html/on-me-trouve/wp-content/plugins/elementor/migrations/README.md
  • File size: 11.38 KB
  • MIME-type: text/plain
  • Charset: utf-8
# Prop Type Migrations

## System Overview
This is a **prop type migration system**, not a general data migration system.

**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.

**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. 

See [Migration Scope](#migration-scope) for details.

## Appendix
- [Structure](#structure)
- [Language Design](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation)
- [Paths](#paths)
- [Conditions](#conditions)
- [Functions](#functions)
- [Examples](#examples)

## Structure
### Manifest
Manifest describes the different migrations, it can contain widget key migrations and prop-type migrations
```json
{
  "widgetKeys": {
    "e-logo": [
        { "from": "svg", "to": "icon" }
      ]
  },
  "propTypes": {
    "string-to-html": {
      "fromType": "string",
      "toType": "html",
      "url": "string-to-html.json"
    }
  }
}
```
### Prop Type Migrations
Prop type migrations are a set of operations, **up** for upgrade and reverse **down** for downgrade.  
Prop type migrations support wildcard paths and conditions (see below)
```json
{
  "up": [
    {
      "op": {
        "fn": "set",
        "path": "$$type",
        "value": "html"
      }
    }
  ],
  "down": [
    {
      "op": {
        "fn": "set",
        "path": "$$type",
        "value": "string"
      }
    }
  ]
}
```

## Paths
Path parameter works with wildcard, starting from the **root of the prop object**.

**Important**: For **prop type migrations** (the primary use case), paths always start at the prop root—not the widget or document root. For example:
- `$$type` refers to the type field at the prop root
- `value.nested` refers to `propObject.value.nested`
- Wildcards like `value.*` or `value.items[*]` match children within the prop

**Widget key migrations** (rare) start at the widget/element root instead. See [Migration Scope](#migration-scope) for details.

## Conditions
Conditions check whether to run the migration or not, with many helper functions such as `exists`, conditions can be compounded by `AND` and `OR`.  
Full list can be found [here](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#Available-Conditions)

## Important Notes

### Data Transformations
**Migrations do NOT support value transformations.** Migrations are purely structural - they create or update, but can't activate any functions on the data.

Handle transformations in transformer code
- Migrations change structure: `{ "color": "#fff" }` → `{ "color": { "$$type": "color", "value": "#fff" } }`
- Transformers can take current values, and transform them `{ "oldColor": "#fff", "newColor": {} }` -> `{ "oldColor": "#fff", "newColor": { "gradient": "something", "value": "#fff" }}`

### Migration Scope
- **Prop Type Migrations**: Operate on a single prop instance, paths start at prop root
- **Widget Key Migrations**: Operate on entire widget element, paths start at element root
- Migrations run **before** validation and transformation in the data processing pipeline

**Example widget:**

```json
{
  "id": "heading-1",
  "elType": "widget",
  "widgetType": "e-heading",
  "settings": {
    "title": {
      "$$type": "string",
      "value": "Hello"
    },
    "tag": {
      "$$type": "string",
      "value": "h2"
    }
  }
}
```

**Prop Type Migration** (e.g., `title` migrating from `string` → `string-v2`):
- Operates on **just the prop object**:
  ```json
  {
    "$$type": "string",
    "value": "Hello"
  }
  ```
- Paths are relative to prop root: `$$type`, `value`

**Widget Key Migration** (e.g., renaming `tag` → `htmlTag`):
- Operates on **the entire widget/element**
- Paths are relative to widget **settings** root: `tag`, `title.value`

### Performance Considerations
- Migration state is cached per document with version + manifest hash
- Cache clears on Elementor version change, manifest change, or feature flag toggle

## Functions
### Set
`set` creates or updates data, it can update key / value or both. Full Documentation [here](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#set)  
Params:  
- key (optional)
- value (optional)
- merge **default** true - attempts to deep merge objects instead of replace

#### Usage
Replaces nested key and value
```json
{ "op": { "fn": "set", "path": "value.*.nested", "value": ["a"], "key": "nested2" } }
```
Appends to array
```json
{ "op": { "fn": "set", "path": "value.*.nested.[]", "value": "a" } }
```
Creates empty object at path
```json
{ "op": { "fn": "set", "path": "value.*.nested.[*]" } }
```

### Delete
`delete` removes keys/values at specified path. Full Documentation [here](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#delete)  
Params:  
- clean **default** true - deletes empty parent paths until reaching an object that has siblings

#### Usage
Delete specific nested key
```json
{ "op": { "fn": "delete", "path": "value.deprecated" } }
```
Delete all matching wildcard paths
```json
{ "op": { "fn": "delete", "path": "value.items[*].legacy" } }
```
Delete without cleaning empty parents
```json
{ "op": { "fn": "delete", "path": "value.old", "clean": false } }
```

### Move
`move` relocates values from one path to another. Full Documentation [here](https://elementor.atlassian.net/wiki/spaces/UE/pages/1999110146/Prop+Types+Migration+Schema+Design+Investigation#move)  
Params:  
- src - Source path
- dest - Destination path
- clean **default** true - deletes source path after move (will delete empty paths until reaching an object that has siblings)

#### Usage
Move simple value to new location
```json
{ "op": { "fn": "move", "src": "value.oldField", "dest": "value.nested.newField" } }
```
Move without cleaning source
```json
{ "op": { "fn": "move", "src": "value.data", "dest": "value.backup", "clean": false } }
```
Move nested object structure
```json
{ "op": { "fn": "move", "src": "value.settings", "dest": "value.config.settings" } }
```

## Examples

### Widget Key Migration: Rename Settings Key

**Context**: Rename a widget settings key from `tag` → `htmlTag`. Paths start at **widget settings root**.

```json
//manifest.json
{
  "widgetKeys": {
    "e-heading": [
      { "from": "tag", "to": "htmlTag" }
  ],
  "propTypes": {}
}
```

**Before**:
```json
{
  "id": "heading-1",
  "elType": "widget",
  "widgetType": "e-heading",
  "settings": {
    "tag": {
      "$$type": "string",
      "value": "h2"
    },
    "title": {
      "$$type": "string",
      "value": "Hello"
    }
  }
}
```

**After**:
```json
{
  "id": "heading-1",
  "elType": "widget",
  "widgetType": "e-heading",
  "settings": {
    "htmlTag": {
      "$$type": "string",
      "value": "h2"
    },
    "title": {
      "$$type": "string",
      "value": "Hello"
    }
  }
}
```

### Prop Type Migration: Change Type

**Context**: Migrate `string` → `html` type. Paths start at **prop root**.

```json
{
  "up": [
    { "op": { "fn": "set", "path": "$$type", "value": "html" } }
  ],
  "down": [
    { "op": { "fn": "set", "path": "$$type", "value": "string" } }
  ]
}
```

**Before**: `{ "$$type": "string", "value": "Hello" }`  
**After**: `{ "$$type": "html", "value": "Hello" }`

### Prop Type Migration: Rename Keys (Simple and Wildcard)

**Context**: Rename keys using `key` parameter, with and without wildcards. Paths start at **prop root**.

**Simple key rename:**
```json
{
  "up": [
    { "op": { "fn": "set", "path": "value.oldName", "key": "newName" } }
  ],
  "down": [
    { "op": { "fn": "set", "path": "value.newName", "key": "oldName" } }
  ]
}
```

**Wildcard key rename across multiple objects:**
```json
{
  "up": [
    {
      "op": { "fn": "set", "path": "value.*.oldName", "key": "newName" },
      "condition": { "fn": "exists", "path": "value.*.oldName" }
    }
  ],
  "down": [
    {
      "op": { "fn": "set", "path": "value.*.newName", "key": "oldName" },
      "condition": { "fn": "exists", "path": "value.*.newName" }
    }
  ]
}
```

**Before** (wildcard example):
```json
{
  "$$type": "responsive",
  "value": {
    "desktop": { "oldName": "value1" },
    "tablet": { "oldName": "value2" },
    "mobile": { "oldName": "value3" }
  }
}
```

**After**:
```json
{
  "$$type": "responsive",
  "value": {
    "desktop": { "newName": "value1" },
    "tablet": { "newName": "value2" },
    "mobile": { "newName": "value3" }
  }
}
```

### Prop Type Migration: Wildcards with Array Items

**Context**: Update all color types in a gradient using array wildcards `[*]`. Paths start at **prop root**.

```json
{
  "up": [
    {
      "op": { "fn": "set", "path": "value.stops[*].color.$$type", "value": "color" },
      "condition": { "fn": "equals", "path": "value.stops[*].color.$$type", "value": "string" }
    }
  ],
  "down": [
    {
      "op": { "fn": "set", "path": "value.stops[*].color.$$type", "value": "string" },
      "condition": { "fn": "equals", "path": "value.stops[*].color.$$type", "value": "color" }
    }
  ]
}
```

**Before**:
```json
{
  "$$type": "gradient",
  "value": {
    "stops": [
      { "position": 0, "color": { "$$type": "string", "value": "#ff0000" } },
      { "position": 50, "color": { "$$type": "string", "value": "#00ff00" } },
      { "position": 100, "color": { "$$type": "string", "value": "#0000ff" } }
    ]
  }
}
```

**After**:
```json
{
  "$$type": "gradient",
  "value": {
    "stops": [
      { "position": 0, "color": { "$$type": "color", "value": "#ff0000" } },
      { "position": 50, "color": { "$$type": "color", "value": "#00ff00" } },
      { "position": 100, "color": { "$$type": "color", "value": "#0000ff" } }
    ]
  }
}
```

### Prop Type Migration: Compound Conditions (AND/OR)

**Context**: Use `and`/`or` conditions to selectively migrate items. Paths start at **prop root**.

```json
{
  "up": [
    {
      "op": { "fn": "set", "path": "value.items[*].type", "value": "enhanced" },
      "condition": {
        "fn": "and",
        "conditions": [
          { "fn": "equals", "path": "value.items[*].type", "value": "legacy" },
          { "fn": "exists", "path": "value.items[*].data" }
        ]
      }
    },
    {
      "op": { "fn": "set", "path": "value.items[*].migrated", "value": true },
      "condition": {
        "fn": "or",
        "conditions": [
          { "fn": "equals", "path": "value.items[*].type", "value": "enhanced" },
          { "fn": "not_exists", "path": "value.items[*].migrated" }
        ]
      }
    }
  ],
  "down": [
    {
      "op": { "fn": "set", "path": "value.items[*].type", "value": "legacy" },
      "condition": { "fn": "equals", "path": "value.items[*].type", "value": "enhanced" }
    },
    {
      "op": { "fn": "delete", "path": "value.items[*].migrated" }
    }
  ]
}
```

**Before**:
```json
{
  "$$type": "list",
  "value": {
    "items": [
      { "type": "legacy", "data": { "content": "Item 1" } },
      { "type": "legacy", "data": { "content": "Item 2" } },
      { "type": "new", "data": { "content": "Item 3" } }
    ]
  }
}
```

**After**:
```json
{
  "$$type": "list",
  "value": {
    "items": [
      { "type": "enhanced", "data": { "content": "Item 1" } },
      { "type": "enhanced", "data": { "content": "Item 2" } },
      { "type": "new", "data": { "content": "Item 3" } }
    ]
  }
}
```