Extending
ExtendingTranslating additional Elementor widgets

Translating additional Elementor widgets

Gato AI Translations for Polylang can translate widget-based Elementor pages.

It does this by extracting all the widget properties from within the _elementor_data JSON, translating those, injecting the translated properties back into the JSON, and then saving the JSON back to the post as _elementor_data meta.

In order to extract the properties from a widget, the plugin needs to know which properties are translatable.

The plugin ships with support for all Elementor and Elementor PRO widgets, and provides the ability for users to support additional widgets.

Supporting additional Elementor widgets

The process is similar to translating additional Gutenberg blocks.

Please read that guide first. The documentation below is a continuation of that process, applied to Elementor widgets.

The placeholders in the GraphQL queries to inject Elementor widgets are:

  • ##### Insert code for Elementor widgets (e-1)
  • ##### Insert code for Elementor widgets (e-2)
  • ...
  • ##### Insert code for Elementor widgets (e-12)

You must replicate the up-to-12 pieces of logic for the widget you want to translate, and inject the corresponding code via PHP hooks, as explained in the previous guide.

The widget data is contained in the _elementor_data JSON, which you can visualize after executing the query. The response will contain the data for all widgets under key elementorFlattenedDataItems.

Explore that entry to identify your widget, which properties that must be translated.

There are 3 common patterns for storing widget data in the _elementor_data JSON:

  1. Properties only
  2. Arrays of elements only
  3. Properties + arrays of elements

Based on the widget's pattern, replicate the corresponding GraphQL query logic from the examples below.

1. Properties only: Animated Headline

The animated-headline widget stores properties only (before_text, highlighted_text, rotating_text, and after_text) in its JSON structure:

{
  "id": "6dac79c",
  "elType": "widget",
  "settings": {
    "before_text": "This page is",
    "highlighted_text": "Amazing",
    "rotating_text": "Better\nBigger\nFaster",
    "after_text": "And super brilliant"
  },
  "elements": [],
  "widgetType": "animated-headline"
}

This is the GraphQL query implementation:

query InitializeVariablesForElementor(
  $customPostIds: [ID!]!
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "CheckPageBuilderToUserForCustomPostType")
  @include(if: $hasCustomPosts)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  initCustomPostsForElementor: customPosts(filter: { ids: $customPostIds, customPostTypes: [$customPostType], status: any }, pagination: { limit: -1 }) {
    emptyArray: _echo(value: [])
 
      @export(
        as: "originElementorAnimatedHeadlineIDs"
        type: DICTIONARY
      )
      @export(
        as: "originElementorAnimatedHeadlineBeforeTextItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorAnimatedHeadlineHighlightedTextItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorAnimatedHeadlineRotatingTextItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorAnimatedHeadlineAfterTextItems"
        type: DICTIONARY
      )
####################################################
##### Insert code for Elementor widgets (e-1)
####################################################
  }
}
 
# ...
 
query ExportOriginCustomPostDataForElementor(
  $customPostIds: [ID!]!
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "ExportOriginCustomPostData")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  originCustomPostsForElementor: customPosts(filter: { ids: $customPostIds, customPostTypes: [$customPostType], status: any }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
 
      elementorFlattenedDataItems
      
        @underEachArrayItem(
          passValueOnwardsAs: "elementJSON"
          affectDirectivesUnderPos: [1, 2, 3]
        )
          @applyField(
            name: "_objectProperty",
            arguments: {
              object: $elementJSON,
              by: { key: "widgetType" }
              failIfNonExistingKeyOrPath: false,
            },
            passOnwardsAs: "widgetType"
          )
          @applyField(
            name: "_equals",
            arguments: {
              value1: $widgetType,
              value2: "animated-headline"
            },
            passOnwardsAs: "isMatch"
          )
          @if(
            condition: $isMatch
            affectDirectivesUnderPos: [1, 3, 5, 7, 9]
          )
            @underJSONObjectProperty(
              by: { key: "id" }
            )
              @export(
                as: "originElementorAnimatedHeadlineIDs"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.before_text" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorAnimatedHeadlineBeforeTextItems"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.highlighted_text" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorAnimatedHeadlineHighlightedTextItems"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.rotating_text" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorAnimatedHeadlineRotatingTextItems"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.after_text" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorAnimatedHeadlineAfterTextItems"
                type: DICTIONARY
              )
 
####################################################
##### Insert code for Elementor widgets (e-3)
####################################################
 
    }
  }
}
 
# ...
 
query InitializeTranslationVariablesForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft,
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "FixExportOriginCustomPostDataForElementor")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useGutenbergEditor)
{
  emptyTranslationCustomPostVarsForElementor: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
      id
      emptyArray: _echo(value: [])
 
        @export(
          as: "destinationElementorAnimatedHeadlineIDs"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorAnimatedHeadlineBeforeTextItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorAnimatedHeadlineHighlightedTextItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorAnimatedHeadlineRotatingTextItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorAnimatedHeadlineAfterTextItems"
          type: DICTIONARY
        )
 
####################################################
##### Insert code for Elementor widgets (e-5)
####################################################
 
        @remove
 
    }
  }
}
 
# ...
 
query FetchDataForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "FetchData")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  translationCustomPostsForElementor: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
 
      originElementorAnimatedHeadlineIDs: _objectProperty(
        object: $originElementorAnimatedHeadlineIDs
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorAnimatedHeadlineIDs"
          type: DICTIONARY
        )
        @remove
 
      originElementorAnimatedHeadlineBeforeTextItems: _objectProperty(
        object: $originElementorAnimatedHeadlineBeforeTextItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorAnimatedHeadlineBeforeTextItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorAnimatedHeadlineHighlightedTextItems: _objectProperty(
        object: $originElementorAnimatedHeadlineHighlightedTextItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorAnimatedHeadlineHighlightedTextItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorAnimatedHeadlineRotatingTextItems: _objectProperty(
        object: $originElementorAnimatedHeadlineRotatingTextItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorAnimatedHeadlineRotatingTextItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorAnimatedHeadlineAfterTextItems: _objectProperty(
        object: $originElementorAnimatedHeadlineAfterTextItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorAnimatedHeadlineAfterTextItems"
          type: DICTIONARY
        )
        @remove
 
####################################################
##### Insert code for Elementor widgets (e-6)
####################################################
 
    }
  }
}
 
# ...
 
query ExportTransformationDataSourceForElementor
  @depends(on: "ExportTransformationDataSourceForClassicEditor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{
  allTransformationSourcesElementor: _objectMerge(
    objects: [
      $transformationSources,
      {
        elementorWidgets: {
 
          animatedHeadlineBeforeText: {
            to: $destinationElementorAnimatedHeadlineBeforeTextItems,
          },
          animatedHeadlineHighlightedText: {
            to: $destinationElementorAnimatedHeadlineHighlightedTextItems,
          },
          animatedHeadlineRotatingText: {
            to: $destinationElementorAnimatedHeadlineRotatingTextItems,
          },
          animatedHeadlineAfterText: {
            to: $destinationElementorAnimatedHeadlineAfterTextItems,
          },
 
####################################################
##### Insert code for Elementor widgets (e-7)
####################################################
        },
      }
    ]
  )
    @export(as: "transformationSources")
 
}
 
# ...
 
query PrepareReplacementsForElementor
  @depends(on: "PrepareReplacementsForClassicEditor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{
  transformedElementorAnimatedHeadline: _echo(value: $destinationElementorAnimatedHeadlineIDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.animatedHeadlineBeforeText.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorAnimatedHeadlineBeforeTextItems"
    )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.animatedHeadlineHighlightedText.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorAnimatedHeadlineHighlightedTextItems"
    )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.animatedHeadlineRotatingText.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorAnimatedHeadlineRotatingTextItems"
    )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.animatedHeadlineAfterText.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorAnimatedHeadlineAfterTextItems"
    )
 
####################################################
##### Insert code for Elementor widgets (e-8)
####################################################
 
}
 
# ...
 
query PrepareTranslationInputsForElementor
  @depends(on: "TranslateCustomPosts")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{    
  transformedElementorAnimatedHeadlineEntries: _echo(value: $destinationElementorAnimatedHeadlineIDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
    )
      @underEachArrayItem(
        passIndexOnwardsAs: "key"
        passValueOnwardsAs: "elementID"
        affectDirectivesUnderPos: [1, 2, 3, 4, 5, 6]
      )
        @applyField(
          name: "_sprintf",
          arguments: {
            string: "%s.%s",
            values: [$customPostID, $key]
          }
          passOnwardsAs: "path"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorAnimatedHeadlineBeforeTextItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "before_text"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorAnimatedHeadlineHighlightedTextItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "highlighted_text"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorAnimatedHeadlineRotatingTextItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "rotating_text"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorAnimatedHeadlineAfterTextItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "after_text"
        )
        @applyField(
          name: "_echo",
          arguments: {
            value: {
              id: $elementID,
              settings: {
                before_text: $before_text,
                highlighted_text: $highlighted_text,
                rotating_text: $rotating_text,
                after_text: $after_text,
              }
            }
          },
          setResultInResponse: true
        )
    @export(as: "transformedElementorAnimatedHeadlineEntries")
 
####################################################
##### Insert code for Elementor widgets (e-10)
####################################################
 
}
 
query GenerateTranslationInputsForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft
  $customPostType: CustomPostEnumString!
)
  @depends(on: "PrepareTranslationInputsForElementor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{   
  elementorGenerateMutationInputs: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
 
      transformedElementorAnimatedHeadlineEntries: _objectProperty(
        object: $transformedElementorAnimatedHeadlineEntries,
        by: {
          key: $__id
        }
      )
 
####################################################
##### Insert code for Elementor widgets (e-11)
####################################################
 
      elements: _arrayMerge(arrays: [
        $__transformedElementorAnimatedHeadlineEntries,
####################################################
##### Insert code for Elementor widgets (e-12)
####################################################  
      ])
    }
  }
 
}

2. Arrays of elements only: Price List

The price-list widget stores arrays of elements only (properties title and item_description under entry price_list) in its JSON structure:

{
  "id": "1fc4fc6",
  "elType": "widget",
  "settings": {
    "price_list": [
      {
        "title": "First item on the list",
        "item_description": "Enter the description for the first item on the list",
        "price": "$20",
        "link": {
          "url": "#"
        },
        "_id": "764b2a8"
      },
      {
        "title": "Second item on the list",
        "item_description": "Enter the description for the second item on the list",
        "price": "$9",
        "link": {
          "url": "#"
        },
        "_id": "80ec42a"
      },
      {
        "title": "Third item on the list",
        "item_description": "Enter the description for the third item on the list",
        "price": "$32",
        "link": {
          "url": "#"
        },
        "_id": "d10acc9"
      }
    ]
  },
  "elements": [],
  "widgetType": "price-list"
}

This is the GraphQL query implementation:

query InitializeVariablesForElementor(
  $customPostIds: [ID!]!
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "CheckPageBuilderToUserForCustomPostType")
  @include(if: $hasCustomPosts)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  initCustomPostsForElementor: customPosts(filter: { ids: $customPostIds, customPostTypes: [$customPostType], status: any }, pagination: { limit: -1 }) {
    emptyArray: _echo(value: [])
 
      @export(
        as: "originElementorPriceListIDs"
        type: DICTIONARY
      )
      @export(
        as: "originElementorPriceListListTitleItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorPriceListListDescriptionItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorPriceListListIDs"
        type: DICTIONARY
      )
####################################################
##### Insert code for Elementor widgets (e-1)
####################################################
 
    emptyObject: _echo(value: {})
      @export(
        as: "originElementorPriceListListElementProps"
        type: DICTIONARY
      )
####################################################
##### Insert code for Elementor widgets (e-2)
####################################################
 
  }
}
 
# ...
 
query ExportOriginCustomPostDataForElementor(
  $customPostIds: [ID!]!
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "ExportOriginCustomPostData")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  originCustomPostsForElementor: customPosts(filter: { ids: $customPostIds, customPostTypes: [$customPostType], status: any }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
 
      elementorFlattenedDataItems
 
        @underEachArrayItem(
          passValueOnwardsAs: "elementJSON"
          affectDirectivesUnderPos: [1, 2, 3]
        )
          @applyField(
            name: "_objectProperty",
            arguments: {
              object: $elementJSON,
              by: { key: "widgetType" }
              failIfNonExistingKeyOrPath: false,
            },
            passOnwardsAs: "widgetType"
          )
          @applyField(
            name: "_equals",
            arguments: {
              value1: $widgetType,
              value2: "price-list"
            },
            passOnwardsAs: "isMatch"
          )
          @if(
            condition: $isMatch
            affectDirectivesUnderPos: [1, 3]
          )
            @underJSONObjectProperty(
              by: { key: "id" }
            )
              @export(
                as: "originElementorPriceListIDs"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.price_list" }
              failIfNonExistingKeyOrPath: false
              affectDirectivesUnderPos: [1, 2, 3, 10, 11, 12, 13]
            )
              @passOnwards(as: "list")
              @applyField(
                name: "_objectProperty",
                arguments: {
                  object: $elementJSON,
                  by: { key: "id" }
                }
                passOnwardsAs: "elementID"
              )
              @underEachArrayItem(
                affectDirectivesUnderPos: [1, 3, 5, 6]
              )
                @underJSONObjectProperty(
                  by: { key: "title" }
                  failIfNonExistingKeyOrPath: false
                )
                  @export(
                    as: "originElementorPriceListListTitleItems"
                    type: DICTIONARY
                  )
                @underJSONObjectProperty(
                  by: { key: "item_description" }
                  failIfNonExistingKeyOrPath: false
                )
                  @export(
                    as: "originElementorPriceListListDescriptionItems"
                    type: DICTIONARY
                  )
                @applyField(
                  name: "_echo",
                  arguments: {
                    value: $elementID
                  }
                  setResultInResponse: true
                )
                @export(
                  as: "originElementorPriceListListIDs"
                  type: DICTIONARY
                )
              @applyField(
                name: "_arrayLength",
                arguments: {
                  array: $list,
                }
                passOnwardsAs: "arrayLength"
              )
              @applyField(
                name: "_objectProperty",
                arguments: {
                  object: $originElementorPriceListListElementProps,
                  by: { key: $customPostID }
                }
                passOnwardsAs: "props"
              )
              @applyField(
                name: "_objectAddEntry",
                arguments: {
                  object: $props,
                  key: $elementID,
                  value: {
                    length: $arrayLength,
                  }
                }
                setResultInResponse: true
              )
              @export(
                as: "originElementorPriceListListElementProps"
                type: DICTIONARY
              )
 
####################################################
##### Insert code for Elementor widgets (e-3)
####################################################
 
    }
  }
}
 
query FixExportOriginCustomPostDataForElementor
  @depends(on: "ExportOriginCustomPostDataForElementor")
  @include(if: $hasCustomPosts)
  @include(if: $useElementorPageBuilder)
  @include(if: $executeTranslation)
{
  originElementorPriceListListElementProps: _echo(value: $originElementorPriceListListElementProps)
    @underEachJSONObjectProperty(
      passValueOnwardsAs: "list"
    )
      @applyField(
        name: "_objectMerge",
        arguments: {
          objects: $list,
        },
        setResultInResponse: true
      )
    @export(
      as: "originElementorPriceListListElementProps"
    )
 
####################################################
##### Insert code for Elementor widgets (e-4)
#################################################### 
 
}
 
# ...
 
query InitializeTranslationVariablesForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft,
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "FixExportOriginCustomPostDataForElementor")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useGutenbergEditor)
{
  emptyTranslationCustomPostVarsForElementor: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
      id
      emptyArray: _echo(value: [])
 
        @export(
          as: "destinationElementorPriceListIDs"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorPriceListListTitleItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorPriceListListDescriptionItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorPriceListListElementProps"
          type: DICTIONARY
        )
 
####################################################
##### Insert code for Elementor widgets (e-5)
####################################################
 
        @remove
 
    }
  }
}  
 
# ...
 
query FetchDataForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "FetchData")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  translationCustomPostsForElementor: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
 
 
      originElementorPriceListIDs: _objectProperty(
        object: $originElementorPriceListIDs
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorPriceListIDs"
          type: DICTIONARY
        )
        @remove
 
      originElementorPriceListListIDs: _objectProperty(
        object: $originElementorPriceListListIDs
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorPriceListListIDs"
          type: DICTIONARY
        )
        @remove
 
      originElementorPriceListListTitleItems: _objectProperty(
        object: $originElementorPriceListListTitleItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorPriceListListTitleItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorPriceListListDescriptionItems: _objectProperty(
        object: $originElementorPriceListListDescriptionItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorPriceListListDescriptionItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorPriceListListElementProps: _objectProperty(
        object: $originElementorPriceListListElementProps
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorPriceListListElementProps"
          type: DICTIONARY
        )
        @remove
 
####################################################
##### Insert code for Elementor widgets (e-6)
####################################################
 
    }
  }
}
 
# ...
 
query ExportTransformationDataSourceForElementor
  @depends(on: "ExportTransformationDataSourceForClassicEditor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{
  allTransformationSourcesElementor: _objectMerge(
    objects: [
      $transformationSources,
      {
        elementorWidgets: {
 
          priceListListTitle: {
            to: $destinationElementorPriceListListTitleItems,
          },
          priceListListDescription: {
            to: $destinationElementorPriceListListDescriptionItems,
          },
 
####################################################
##### Insert code for Elementor widgets (e-7)
####################################################
        },
      }
    ]
  )
    @export(as: "transformationSources")
 
}
 
# ...
 
query PrepareReplacementsForElementor
  @depends(on: "PrepareReplacementsForClassicEditor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{
  transformedElementorPriceList: _echo(value: $destinationElementorPriceListIDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.priceListListTitle.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorPriceListListTitleItems"
    )
 
####################################################
##### Insert code for Elementor widgets (e-8)
####################################################
 
}
 
query AdaptReplacementsForElementor
  @depends(on: "PrepareReplacementsForElementor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{
  adaptedElementorPriceListListItems: _echo(value: $destinationElementorPriceListListIDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
    )
      @underEachArrayItem(
        passIndexOnwardsAs: "key"
        affectDirectivesUnderPos: [1, 2, 3, 4]
      )
        @applyField(
          name: "_sprintf",
          arguments: {
            string: "%s.%s",
            values: [$customPostID, $key]
          }
          passOnwardsAs: "path"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorPriceListListTitleItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "title"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorPriceListListDescriptionItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "item_description"
        )
        @applyField(
          name: "_echo",
          arguments: {
            value: {
              title: $title,
              item_description: $item_description,
            }
          }
          setResultInResponse: true
        )
    @export(
      as: "transformedElementorPriceListListItems"
    )
 
####################################################
##### Insert code for Elementor widgets (e-9)
####################################################
 
}
 
# ...
 
query PrepareTranslationInputsForElementor
  @depends(on: "TranslateCustomPosts")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{    
  transformedElementorPriceListEntries: _echo(value: $destinationElementorPriceListIDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
    )
      @underEachArrayItem(
        passIndexOnwardsAs: "key"
        passValueOnwardsAs: "elementID"
        affectDirectivesUnderPos: [1, 2, 3, 4, 5, 6, 7, 8, 9]
      )
        @applyField(
          name: "_sprintf",
          arguments: {
            string: "%s.%s",
            values: [$customPostID, $key]
          }
          passOnwardsAs: "path"
        )
        @applyField(
          name: "_sprintf",
          arguments: {
            string: "%s.%s",
            values: [$customPostID, $elementID]
          }
          passOnwardsAs: "idPath"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $destinationElementorPriceListListIDs
            by: { key: $customPostID }
          }
          passOnwardsAs: "priceListIDs"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorPriceListListItems
            by: { key: $customPostID }
          }
          passOnwardsAs: "priceListItems"
        )
        @applyField(
          name: "_arraySearch",
          arguments: {
            array: $priceListIDs
            element: $elementID
          }
          passOnwardsAs: "offset"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $destinationElementorPriceListListElementProps
            by: { path: $idPath }
          }
          passOnwardsAs: "priceListItemProps"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $priceListItemProps
            by: { key: "length" }
          }
          passOnwardsAs: "length"
        )
        @applyField(
          name: "_arraySlice",
          arguments: {
            array: $priceListItems
            length: $length,
            offset: $offset
          }
          passOnwardsAs: "price_list"
        )
        @applyField(
          name: "_echo",
          arguments: {
            value: {
              id: $elementID,
              settings: {
                price_list: $price_list,
              }
            }
          },
          setResultInResponse: true
        )
    @export(as: "transformedElementorPriceListEntries")
 
####################################################
##### Insert code for Elementor widgets (e-10)
####################################################
 
}
 
query GenerateTranslationInputsForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft
  $customPostType: CustomPostEnumString!
)
  @depends(on: "PrepareTranslationInputsForElementor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{   
  elementorGenerateMutationInputs: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
      id
 
      originCustomPostId: _objectProperty(
        object: $translationCustomPostIdOringCustomPostIDs
        by: { key: $__id }
      )
      
 
      transformedElementorPriceListEntries: _objectProperty(
        object: $transformedElementorPriceListEntries,
        by: {
          key: $__id
        }
      )
 
####################################################
##### Insert code for Elementor widgets (e-11)
####################################################
 
      elements: _arrayMerge(arrays: [
        $__transformedElementorPriceListEntries,
####################################################
##### Insert code for Elementor widgets (e-12)
####################################################  
      ])
    }
  }
 
}

The link-in-bio widget (and also its variations link-in-bio-var-2 til link-in-bio-var-5) stores both properties (bio_heading, bio_title, and bio_description) and arrays of elements (property cta_link_text under cta_link) in its JSON structure:

{
  "id": "fe5104f",
  "elType": "widget",
  "settings": {
    "bio_heading": "Sara Parker",
    "bio_title": "Kitchen Chronicles",
    "bio_description": "Join me on my journey to a healthier lifestyle",
    "icon": [
      {
        "_id": "3ef8485"
      },
      {
        "icon_platform": "Instagram",
        "_id": "c1ad656"
      },
      {
        "icon_platform": "TikTok",
        "_id": "563c5b0"
      }
    ],
    "cta_link": [
      {
        "cta_link_text": "Get Healthy",
        "_id": "d84226c"
      },
      {
        "cta_link_text": "Top 10 Recipes",
        "_id": "8c7f165"
      },
      {
        "cta_link_text": "Meal Prep",
        "_id": "17a129f"
      },
      {
        "cta_link_text": "Healthy Living Resources",
        "_id": "9c1b615"
      }
    ]
  },
  "elements": [],
  "widgetType": "link-in-bio"
}

This is the GraphQL query implementation:

query InitializeVariablesForElementor(
  $customPostIds: [ID!]!
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "CheckPageBuilderToUserForCustomPostType")
  @include(if: $hasCustomPosts)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  initCustomPostsForElementor: customPosts(filter: { ids: $customPostIds, customPostTypes: [$customPostType], status: any }, pagination: { limit: -1 }) {
    emptyArray: _echo(value: [])
 
      @export(
        as: "originElementorLinkInBio1To5IDs"
        type: DICTIONARY
      )
      @export(
        as: "originElementorLinkInBio1To5HeadingItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorLinkInBio1To5TitleItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorLinkInBio1To5DescriptionItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorLinkInBio1To5CtaLinkListItemTexts"
        type: DICTIONARY
      )
      @export(
        as: "originElementorLinkInBio1To5CtaLinkListIDs"
        type: DICTIONARY
      )
####################################################
##### Insert code for Elementor widgets (e-1)
####################################################
 
    emptyObject: _echo(value: {})
      @export(
        as: "originElementorLinkInBio1To5CtaLinkListElementProps"
        type: DICTIONARY
      )
 
####################################################
##### Insert code for Elementor widgets (e-2)
####################################################
  }
}
 
# ...
 
query ExportOriginCustomPostDataForElementor(
  $customPostIds: [ID!]!
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "ExportOriginCustomPostData")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  originCustomPostsForElementor: customPosts(filter: { ids: $customPostIds, customPostTypes: [$customPostType], status: any }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
 
      elementorFlattenedDataItems
 
        @underEachArrayItem(
          passValueOnwardsAs: "elementJSON"
          affectDirectivesUnderPos: [1, 2, 3]
        )
          @applyField(
            name: "_objectProperty",
            arguments: {
              object: $elementJSON,
              by: { key: "widgetType" }
              failIfNonExistingKeyOrPath: false,
            },
            passOnwardsAs: "widgetType"
          )
          @applyField(
            name: "_inArray",
            arguments: {
              value: $widgetType,
              array: [
                "link-in-bio",
                "link-in-bio-var-2",
                "link-in-bio-var-3",
                "link-in-bio-var-4",
                "link-in-bio-var-5",
              ]
            },
            passOnwardsAs: "isMatch"
          )
          @if(
            condition: $isMatch
            affectDirectivesUnderPos: [1, 3, 5, 7, 9]
          )
            @underJSONObjectProperty(
              by: { key: "id" }
            )
              @export(
                as: "originElementorLinkInBio1To5IDs"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.bio_heading" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorLinkInBio1To5HeadingItems"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.bio_title" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorLinkInBio1To5TitleItems"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.bio_description" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorLinkInBio1To5DescriptionItems"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.cta_link" }
              failIfNonExistingKeyOrPath: false
              affectDirectivesUnderPos: [1, 2, 3, 8, 9, 10, 11]
            )
              @passOnwards(as: "list")
              @applyField(
                name: "_objectProperty",
                arguments: {
                  object: $elementJSON,
                  by: { key: "id" }
                }
                passOnwardsAs: "elementID"
              )
              @underEachArrayItem(
                affectDirectivesUnderPos: [1, 3, 4]
              )
                @underJSONObjectProperty(
                  by: { key: "cta_link_text" }
                  failIfNonExistingKeyOrPath: false
                )
                  @export(
                    as: "originElementorLinkInBio1To5CtaLinkListItemTexts"
                    type: DICTIONARY
                  )
                @applyField(
                  name: "_echo",
                  arguments: {
                    value: $elementID
                  }
                  setResultInResponse: true
                )
                @export(
                  as: "originElementorLinkInBio1To5CtaLinkListIDs"
                  type: DICTIONARY
                )
              @applyField(
                name: "_arrayLength",
                arguments: {
                  array: $list,
                }
                passOnwardsAs: "arrayLength"
              )
              @applyField(
                name: "_objectProperty",
                arguments: {
                  object: $originElementorLinkInBio1To5CtaLinkListElementProps,
                  by: { key: $customPostID }
                }
                passOnwardsAs: "props"
              )
              @applyField(
                name: "_objectAddEntry",
                arguments: {
                  object: $props,
                  key: $elementID,
                  value: {
                    length: $arrayLength,
                  }
                }
                setResultInResponse: true
              )
              @export(
                as: "originElementorLinkInBio1To5CtaLinkListElementProps"
                type: DICTIONARY
              )
 
####################################################
##### Insert code for Elementor widgets (e-3)
####################################################
 
    }
  }
}
 
query FixExportOriginCustomPostDataForElementor
  @depends(on: "ExportOriginCustomPostDataForElementor")
  @include(if: $hasCustomPosts)
  @include(if: $useElementorPageBuilder)
  @include(if: $executeTranslation)
{
  originElementorLinkInBio1To5CtaLinkListElementProps: _echo(value: $originElementorLinkInBio1To5CtaLinkListElementProps)
    @underEachJSONObjectProperty(
      passValueOnwardsAs: "list"
    )
      @applyField(
        name: "_objectMerge",
        arguments: {
          objects: $list,
        },
        setResultInResponse: true
      )
    @export(
      as: "originElementorLinkInBio1To5CtaLinkListElementProps"
    )
 
####################################################
##### Insert code for Elementor widgets (e-4)
#################################################### 
 
}
 
# ...
 
query InitializeTranslationVariablesForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft,
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "FixExportOriginCustomPostDataForElementor")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useGutenbergEditor)
{
  emptyTranslationCustomPostVarsForElementor: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
      id
      emptyArray: _echo(value: [])
 
        @export(
          as: "destinationElementorLinkInBio1To5IDs"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorLinkInBio1To5HeadingItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorLinkInBio1To5TitleItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorLinkInBio1To5DescriptionItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorLinkInBio1To5CtaLinkListItemTexts"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorLinkInBio1To5CtaLinkListElementProps"
          type: DICTIONARY
        )
 
####################################################
##### Insert code for Elementor widgets (e-5)
####################################################
 
        @remove
 
    }
  }
}
 
# ...
 
query FetchDataForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft
  $customPostType: CustomPostEnumString!
  $translateContent: Boolean! = true
)
  @depends(on: "FetchData")
  @include(if: $executeTranslation)
  @include(if: $translateContent)
  @include(if: $useElementorPageBuilder)
{
  translationCustomPostsForElementor: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
 
 
      originElementorLinkInBio1To5IDs: _objectProperty(
        object: $originElementorLinkInBio1To5IDs
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorLinkInBio1To5IDs"
          type: DICTIONARY
        )
        @remove
 
      originElementorLinkInBio1To5HeadingItems: _objectProperty(
        object: $originElementorLinkInBio1To5HeadingItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorLinkInBio1To5HeadingItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorLinkInBio1To5TitleItems: _objectProperty(
        object: $originElementorLinkInBio1To5TitleItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorLinkInBio1To5TitleItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorLinkInBio1To5DescriptionItems: _objectProperty(
        object: $originElementorLinkInBio1To5DescriptionItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorLinkInBio1To5DescriptionItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorLinkInBio1To5CtaLinkListIDs: _objectProperty(
        object: $originElementorLinkInBio1To5CtaLinkListIDs
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorLinkInBio1To5CtaLinkListIDs"
          type: DICTIONARY
        )
        @remove
 
      originElementorLinkInBio1To5CtaLinkListItemTexts: _objectProperty(
        object: $originElementorLinkInBio1To5CtaLinkListItemTexts
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorLinkInBio1To5CtaLinkListItemTexts"
          type: DICTIONARY
        )
        @remove
 
      originElementorLinkInBio1To5CtaLinkListElementProps: _objectProperty(
        object: $originElementorLinkInBio1To5CtaLinkListElementProps
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorLinkInBio1To5CtaLinkListElementProps"
          type: DICTIONARY
        )
        @remove
 
####################################################
##### Insert code for Elementor widgets (e-6)
####################################################
 
    }
  }
}
 
# ...
 
query ExportTransformationDataSourceForElementor
  @depends(on: "ExportTransformationDataSourceForClassicEditor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{
  allTransformationSourcesElementor: _objectMerge(
    objects: [
      $transformationSources,
      {
        elementorWidgets: {
 
          linkInBio1To5Heading: {
            to: $destinationElementorLinkInBio1To5HeadingItems,
          },
          linkInBio1To5Title: {
            to: $destinationElementorLinkInBio1To5TitleItems,
          },
          linkInBio1To5Description: {
            to: $destinationElementorLinkInBio1To5DescriptionItems,
          },
          linkInBio1To5CtaLinkList: {
            to: $destinationElementorLinkInBio1To5CtaLinkListItemTexts,
          },
 
####################################################
##### Insert code for Elementor widgets (e-7)
####################################################
        },
      }
    ]
  )
    @export(as: "transformationSources")
 
}
 
# ...
 
query PrepareReplacementsForElementor
  @depends(on: "PrepareReplacementsForClassicEditor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{
  transformedElementorLinkInBio1To5: _echo(value: $destinationElementorLinkInBio1To5IDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.linkInBio1To5Heading.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorLinkInBio1To5HeadingItems"
    )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.linkInBio1To5Title.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorLinkInBio1To5TitleItems"
    )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.linkInBio1To5Description.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorLinkInBio1To5DescriptionItems"
    )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.linkInBio1To5CtaLinkList.to.%s",
          values: [$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: $transformations
          by: { path: $path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorLinkInBio1To5CtaLinkListItemTexts"
    )
 
####################################################
##### Insert code for Elementor widgets (e-8)
####################################################
 
}
 
query AdaptReplacementsForElementor
  @depends(on: "PrepareReplacementsForElementor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{
  adaptedElementorLinkInBio1To5CtaLinkListItemTexts: _echo(value: $transformedElementorLinkInBio1To5CtaLinkListItemTexts)
    @underEachJSONObjectProperty
      @underEachArrayItem(
        passValueOnwardsAs: "value"
      )
        @applyField(
          name: "_echo",
          arguments: {
            value: {
              cta_link_text: $value,
            }
          }
          setResultInResponse: true
        )
    @export(
      as: "transformedElementorLinkInBio1To5CtaLinkListItemTexts"
    )
 
####################################################
##### Insert code for Elementor widgets (e-9)
####################################################
 
}
 
# ...
 
query PrepareTranslationInputsForElementor
  @depends(on: "TranslateCustomPosts")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{    
  transformedElementorLinkInBio1To5Entries: _echo(value: $destinationElementorLinkInBio1To5IDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
    )
      @underEachArrayItem(
        passIndexOnwardsAs: "key"
        passValueOnwardsAs: "elementID"
        affectDirectivesUnderPos: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
      )
        @applyField(
          name: "_sprintf",
          arguments: {
            string: "%s.%s",
            values: [$customPostID, $key]
          }
          passOnwardsAs: "path"
        )
        @applyField(
          name: "_sprintf",
          arguments: {
            string: "%s.%s",
            values: [$customPostID, $elementID]
          }
          passOnwardsAs: "idPath"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorLinkInBio1To5HeadingItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "bio_heading"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorLinkInBio1To5TitleItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "bio_title"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorLinkInBio1To5DescriptionItems
            by: { path: $path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "bio_description"
        )
 
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $destinationElementorLinkInBio1To5CtaLinkListIDs
            by: { key: $customPostID }
          }
          passOnwardsAs: "ctaLinkListIDs"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $transformedElementorLinkInBio1To5CtaLinkListItemTexts
            by: { key: $customPostID }
          }
          passOnwardsAs: "ctaLinkListItems"
        )
        @applyField(
          name: "_arraySearch",
          arguments: {
            array: $ctaLinkListIDs
            element: $elementID
          }
          passOnwardsAs: "offset"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $destinationElementorLinkInBio1To5CtaLinkListElementProps
            by: { path: $idPath }
          }
          passOnwardsAs: "ctaLinkListItemProps"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $ctaLinkListItemProps
            by: { key: "length" }
          }
          passOnwardsAs: "length"
        )
        @applyField(
          name: "_arraySlice",
          arguments: {
            array: $ctaLinkListItems
            length: $length,
            offset: $offset
          }
          passOnwardsAs: "cta_link"
        )
        @applyField(
          name: "_echo",
          arguments: {
            value: {
              id: $elementID,
              settings: {
                bio_heading: $bio_heading,
                bio_title: $bio_title,
                bio_description: $bio_description,
                cta_link: $cta_link,
              }
            }
          },
          setResultInResponse: true
        )
    @export(as: "transformedElementorLinkInBio1To5Entries")
 
####################################################
##### Insert code for Elementor widgets (e-10)
####################################################
 
}
 
query GenerateTranslationInputsForElementor(
  $statusToUpdate: CustomPostStatusEnum! = draft
  $customPostType: CustomPostEnumString!
)
  @depends(on: "PrepareTranslationInputsForElementor")
  @include(if: $executeTranslation)
  @include(if: $useElementorPageBuilder)
{   
  elementorGenerateMutationInputs: customPosts(filter: { ids: $translationCustomPostIds, customPostTypes: [$customPostType], status: $statusToUpdate }, pagination: { limit: -1 }) {
    __typename
    ...on CustomPost {
 
      transformedElementorLinkInBio1To5Entries: _objectProperty(
        object: $transformedElementorLinkInBio1To5Entries,
        by: {
          key: $__id
        }
      )
####################################################
##### Insert code for Elementor widgets (e-11)
####################################################
 
      elements: _arrayMerge(arrays: [
        $__transformedElementorLinkInBio1To5Entries,
####################################################
##### Insert code for Elementor widgets (e-12)
####################################################  
      ])
    }
  }
 
}

Example implementation

Let's say that we have a widget "Call to Action", with the following data:

{
  "id": "206a911",
  "elType": "widget",
  "settings": {
    "title": "This is the heading",
    "description": "Your Call to Action content comes here",
    "button": "Click Here"
  },
  "elements": [],
  "widgetType": "call-to-action"
}

As this widget stores properties only, we can replicate the pattern from the "Animated Headline" widget.

Using the gatompl:persisted_query hook to inject the logic into the GraphQL query, the PHP logic is this one (notice that inside <<<GRAPHQL, GraphQL variables must be escaped: \$):

add_filter(
  'gatompl:persisted_query',
  function (string $persistedQuery, string $persistedQueryFile): string {
    if (str_ends_with($persistedQueryFile, '/translate-customposts-for-polylang.gql')) {
      return str_replace(
        [
          '##### Insert code for Elementor widgets (e-1)',
          // '##### Insert code for Elementor widgets (e-2)', <= Not needed for this widget
          '##### Insert code for Elementor widgets (e-3)',
          // '##### Insert code for Elementor widgets (e-4)', <= Not needed for this widget
          '##### Insert code for Elementor widgets (e-5)',
          '##### Insert code for Elementor widgets (e-6)',
          '##### Insert code for Elementor widgets (e-7)',
          '##### Insert code for Elementor widgets (e-8)',
          // '##### Insert code for Elementor widgets (e-9)', <= Not needed for this widget
          '##### Insert code for Elementor widgets (e-10)',
          '##### Insert code for Elementor widgets (e-11)',
          '##### Insert code for Elementor widgets (e-12)',
        ],
        [
<<<GRAPHQL
##### Insert code for Elementor widgets (e-1)
      @export(
        as: "originElementorCallToActionIDs"
        type: DICTIONARY
      )
      @export(
        as: "originElementorCallToActionTitleItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorCallToActionDescriptionItems"
        type: DICTIONARY
      )
      @export(
        as: "originElementorCallToActionButtonItems"
        type: DICTIONARY
      )
GRAPHQL,
 
<<<GRAPHQL
##### Insert code for Elementor widgets (e-3)
        @underEachArrayItem(
          passValueOnwardsAs: "elementJSON"
          affectDirectivesUnderPos: [1, 2, 3]
        )
          @applyField(
            name: "_objectProperty",
            arguments: {
              object: \$elementJSON,
              by: { key: "widgetType" }
              failIfNonExistingKeyOrPath: false,
            },
            passOnwardsAs: "widgetType"
          )
          @applyField(
            name: "_equals",
            arguments: {
              value1: \$widgetType,
              value2: "call-to-action"
            },
            passOnwardsAs: "isMatch"
          )
          @if(
            condition: \$isMatch
            affectDirectivesUnderPos: [1, 3, 5, 7]
          )
            @underJSONObjectProperty(
              by: { key: "id" }
            )
              @export(
                as: "originElementorCallToActionIDs"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.title" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorCallToActionTitleItems"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.description" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorCallToActionDescriptionItems"
                type: DICTIONARY
              )
            @underJSONObjectProperty(
              by: { path: "settings.button" }
              failIfNonExistingKeyOrPath: false
            )
              @export(
                as: "originElementorCallToActionButtonItems"
                type: DICTIONARY
              )
GRAPHQL,
 
<<<GRAPHQL
##### Insert code for Elementor widgets (e-5)
        @export(
          as: "destinationElementorCallToActionIDs"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorCallToActionTitleItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorCallToActionDescriptionItems"
          type: DICTIONARY
        )
        @export(
          as: "destinationElementorCallToActionButtonItems"
          type: DICTIONARY
        )
GRAPHQL,
 
<<<GRAPHQL
##### Insert code for Elementor widgets (e-6)
      originElementorCallToActionIDs: _objectProperty(
        object: \$originElementorCallToActionIDs
        by: { key: \$__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorCallToActionIDs"
          type: DICTIONARY
        )
        @remove
 
      originElementorCallToActionTitleItems: _objectProperty(
        object: \$originElementorCallToActionTitleItems
        by: { key: \$__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorCallToActionTitleItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorCallToActionDescriptionItems: _objectProperty(
        object: \$originElementorCallToActionDescriptionItems
        by: { key: \$__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorCallToActionDescriptionItems"
          type: DICTIONARY
        )
        @remove
 
      originElementorCallToActionButtonItems: _objectProperty(
        object: \$originElementorCallToActionButtonItems
        by: { key: \$__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
        @export(
          as: "destinationElementorCallToActionButtonItems"
          type: DICTIONARY
        )
        @remove
GRAPHQL,
 
<<<GRAPHQL
##### Insert code for Elementor widgets (e-7)
          callToActionTitle: {
            to: \$destinationElementorCallToActionTitleItems,
          },
          callToActionDescription: {
            to: \$destinationElementorCallToActionDescriptionItems,
          },
          callToActionButton: {
            to: \$destinationElementorCallToActionButtonItems,
          },
GRAPHQL,
 
<<<GRAPHQL
##### Insert code for Elementor widgets (e-8)
  transformedElementorCallToAction: _echo(value: \$destinationElementorCallToActionIDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.callToActionTitle.to.%s",
          values: [\$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: \$transformations
          by: { path: \$path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorCallToActionTitleItems"
    )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.callToActionDescription.to.%s",
          values: [\$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: \$transformations
          by: { path: \$path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorCallToActionDescriptionItems"
    )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_sprintf",
        arguments: {
          string: "elementorWidgets.callToActionButton.to.%s",
          values: [\$customPostID]
        }
        passOnwardsAs: "path"
      )
      @applyField(
        name: "_objectProperty",
        arguments: {
          object: \$transformations
          by: { path: \$path }
        }
        setResultInResponse: true
      )
    @export(
      as: "transformedElementorCallToActionButtonItems"
    )
GRAPHQL,
 
<<<GRAPHQL
##### Insert code for Elementor widgets (e-10)
  transformedElementorCallToActionEntries: _echo(value: \$destinationElementorCallToActionIDs)
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
    )
      @underEachArrayItem(
        passIndexOnwardsAs: "key"
        passValueOnwardsAs: "elementID"
        affectDirectivesUnderPos: [1, 2, 3, 4, 5]
      )
        @applyField(
          name: "_sprintf",
          arguments: {
            string: "%s.%s",
            values: [\$customPostID, \$key]
          }
          passOnwardsAs: "path"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: \$transformedElementorCallToActionTitleItems
            by: { path: \$path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "title"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: \$transformedElementorCallToActionDescriptionItems
            by: { path: \$path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "description"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: \$transformedElementorCallToActionButtonItems
            by: { path: \$path }
            failIfNonExistingKeyOrPath: false
          }
          passOnwardsAs: "button"
        )
        @applyField(
          name: "_echo",
          arguments: {
            value: {
              id: \$elementID,
              settings: {
                title: \$title,
                description: \$description,
                button: \$button,
              }
            }
          },
          setResultInResponse: true
        )
    @export(as: "transformedElementorCallToActionEntries")
GRAPHQL,
 
<<<GRAPHQL
##### Insert code for Elementor widgets (e-11)
      transformedElementorCallToActionEntries: _objectProperty(
        object: \$transformedElementorCallToActionEntries,
        by: {
          key: \$__id
        }
      )
GRAPHQL,
 
<<<GRAPHQL
##### Insert code for Elementor widgets (e-12)
        \$__transformedElementorCallToActionEntries,
GRAPHQL,
        ],
        $persistedQuery
      );
    }
    return $persistedQuery;
  },
  10,
  2
);