Working with
Working withElementor

Elementor

We can edit the Elementor data from a post and update it as needed, by querying, iterating, transforming and storing the Elementor JSON meta for that post.

Query Elementor data

There are 2 fields to query the Elementor data:

  • elementorData returns the JSON of all the elements in the Elementor post
  • elementorFlattenedDataItems also returns the JSON, but flattened into an array of a single level

To transform and update Elementor data, we will use elementorFlattenedDataItems, as it makes it easier to iterate the elements.

Query field elementorFlattenedDataItems, which returns the flattened JSON of all the elements in the Elementor post.

query GetElementorData($customPostId: ID!) {
  customPost(by: { id: $customPostId }, status: any) {
    ...on ElementorMaybeEnabledForCustomPostType {
      elementorFlattenedDataItems
    }
  }
}

The response will look like this:

{
  "data": {
    "post": {
      "elementorFlattenedDataItems": [
        {
          "id": "164e55c4",
          "elType": "container",
          "settings": {
            "layout": "full_width",
            "flex_gap": {
              "size": 0,
              "unit": "px",
              "column": "0",
              "row": "0",
              "isLinked": true
            },
            "min_height": {
              "unit": "vh",
              "size": 100,
              "sizes": []
            },
            "flex_align_items": "stretch",
            "content_position": "middle",
            "structure": "20",
            "margin": {
              "unit": "%",
              "top": "",
              "right": 0,
              "bottom": "",
              "left": 0,
              "isLinked": true
            },
            "padding": {
              "unit": "%",
              "top": "0",
              "right": "6",
              "bottom": "0",
              "left": "6",
              "isLinked": false
            },
            "margin_tablet": {
              "unit": "%",
              "top": "12",
              "right": 0,
              "bottom": "0",
              "left": 0,
              "isLinked": false
            },
            "margin_mobile": {
              "unit": "%",
              "top": "20",
              "right": 0,
              "bottom": "0",
              "left": 0,
              "isLinked": false
            },
            "padding_tablet": {
              "unit": "%",
              "top": "",
              "right": "",
              "bottom": "",
              "left": "",
              "isLinked": true
            },
            "z_index": 1,
            "_title": "Hero",
            "flex_direction": "row",
            "content_width": "full",
            "flex_direction_tablet": "column"
          },
          "isInner": false,
          "innerElementIds": [
            "600c1786",
            "5b451d4"
          ],
          "parentElementId": null
        },
        {
          "id": "600c1786",
          "elType": "container",
          "settings": {
            "_column_size": 50,
            "width": {
              "size": 50,
              "unit": "%"
            },
            "padding": {
              "unit": "%",
              "top": "0",
              "right": "12",
              "bottom": "0",
              "left": "0",
              "isLinked": false
            },
            "width_tablet": {
              "size": 100,
              "unit": "%"
            },
            "align_tablet": "center",
            "flex_gap": {
              "size": 20,
              "unit": "px",
              "column": "20",
              "row": "20",
              "isLinked": true
            },
            "padding_tablet": {
              "unit": "%",
              "top": "0",
              "right": "15",
              "bottom": "0",
              "left": "15",
              "isLinked": false
            },
            "padding_mobile": {
              "unit": "px",
              "top": "0",
              "right": "0",
              "bottom": "0",
              "left": "0",
              "isLinked": false
            },
            "content_width": "full",
            "flex_direction": "column",
            "flex_justify_content": "center",
            "flex_align_items": "flex-start",
            "flex_align_items_tablet": "center"
          },
          "isInner": true,
          "parentElementId": "164e55c4",
          "innerElementIds": [
            "db84e33",
            "7fe7b508",
            "314da60",
            "7b7e33ce",
            "7ff4508"
          ]
        },
        {
          "id": "db84e33",
          "elType": "widget",
          "settings": {
            "title": "Your health, <br><b>on your time<\/b>",
            "header_size": "h1",
            "title_color": "#0D3276",
            "typography_typography": "custom",
            "typography_font_family": "Poppins",
            "typography_font_size": {
              "unit": "px",
              "size": 76,
              "sizes": []
            },
            "typography_font_weight": "400",
            "typography_text_transform": "capitalize",
            "typography_font_style": "normal",
            "typography_text_decoration": "none",
            "typography_line_height": {
              "unit": "em",
              "size": 1,
              "sizes": []
            },
            "typography_letter_spacing": {
              "unit": "px",
              "size": 0,
              "sizes": []
            },
            "_z_index": 1,
            "align_tablet": "center",
            "typography_font_size_tablet": {
              "unit": "px",
              "size": 55,
              "sizes": []
            },
            "typography_font_size_mobile": {
              "unit": "px",
              "size": 40,
              "sizes": []
            }
          },
          "widgetType": "heading",
          "parentElementId": "600c1786",
          "innerElementIds": []
        }
      ]
    }
  }
}

We can also filter elements by name via param filterBy (which accepts include and exclude).

Running this query:

query GetElementorData($customPostId: ID!) {
  customPost(by: { id: $customPostId }, status: any) {
    ...on ElementorMaybeEnabledForCustomPostType {
      elementorFlattenedDataItems(filterBy: { include: ["heading"] })
    }
  }
}

...will produce this response:

{
  "data": {
    "post": {
      "elementorFlattenedDataItems": [
        {
          "id": "db84e33",
          "elType": "widget",
          "settings": {
            "title": "Your health, <br><b>on your time<\/b>",
            "header_size": "h1",
            "title_color": "#0D3276",
            "typography_typography": "custom",
            "typography_font_family": "Poppins",
            "typography_font_size": {
              "unit": "px",
              "size": 76,
              "sizes": []
            },
            "typography_font_weight": "400",
            "typography_text_transform": "capitalize",
            "typography_font_style": "normal",
            "typography_text_decoration": "none",
            "typography_line_height": {
              "unit": "em",
              "size": 1,
              "sizes": []
            },
            "typography_letter_spacing": {
              "unit": "px",
              "size": 0,
              "sizes": []
            },
            "_z_index": 1,
            "align_tablet": "center",
            "typography_font_size_tablet": {
              "unit": "px",
              "size": 55,
              "sizes": []
            },
            "typography_font_size_mobile": {
              "unit": "px",
              "size": 40,
              "sizes": []
            }
          },
          "widgetType": "heading",
          "parentElementId": "600c1786",
          "innerElementIds": []
        }
      ]
    }
  }
}

Modify and Store Elementor data

Iterate the elements in the JSON produced by elementorFlattenedDataItems, modify them as needed, and store the modified JSON back into post meta, via the elementorMergeCustomPostElementDataItem mutation.

In this query, we filter the elements by name, and export the modified headings (under dynamic variable $modifiedElementorHeadings) and also their IDs (under dynamic variable $modifiedElementorHeadingIDs):

query GetAndModifyElementorData($customPostId: ID!) {
  customPost(by: { id: $customPostId }, status: any) {
    ...on ElementorMaybeEnabledForCustomPostType {
      elementorFlattenedDataItems(filterBy: {include: ["heading"]})
        @underEachArrayItem(affectDirectivesUnderPos: [1, 3])
          @underJSONObjectProperty(by: { key: "id" })
            @export(as: "modifiedElementorHeadingIDs")
          @underJSONObjectProperty(
            by: { path: "settings.title" }
            failIfNonExistingKeyOrPath: false
            affectDirectivesUnderPos: [1, 2]
          )
            @strUpperCase
            @export(as: "modifiedElementorHeadings")
    }
  }
}

Then, use the elementorMergeCustomPostElementDataItem mutation to merge those entries into the post meta JSON.

To do that, you must first generate the input to inject into the mutation, as an array with the ID and settings of each modified element:

query GenerateElementorMergeDataItemInputs
  @depends(on: "GetAndModifyElementorData")
{
  elementorMergeDataItemInputs: _echo(value: $modifiedElementorHeadingIDs)
    @underEachArrayItem(
      passIndexOnwardsAs: "index",
      passValueOnwardsAs: "id"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_arrayItem",
        arguments: {
          array: $modifiedElementorHeadings,
          position: $index
        },
        passOnwardsAs: "heading"
      )
      @applyField(
        name: "_echo",
        arguments: {
          value: {
            id: $id,
            settings: {
              title: $heading
            }
          }
        }
        setResultInResponse: true
      )
    @export(as: "elementorMergeDataItemInputs")
}
 
mutation StoreElementorData($customPostId: ID!)
  @depends(on: "GenerateElementorMergeDataItemInputs")
{
  elementorMergeCustomPostElementDataItem(input: {
    customPostID: $customPostId
    elements: $elementorMergeDataItemInputs
  }) {
    status
    errors {
      __typename
      ...on ErrorPayload {
        message
      }
    }
    customPost {
      __typename
      ...on CustomPost {
        id
        elementorFlattenedDataItems
      }
    }
  }
}