Extending
ExtendingTranslating additional Gutenberg blocks

Translating additional Gutenberg blocks

Gato AI Translations for Polylang can translate block-based posts.

The plugin ships with support for WordPress core blocks, and provides the ability for users to support additional blocks.

Supporting additional blocks

You can translate custom blocks from your application, or block from 3rd-party plugins.

Please read guide Extending Page Builder elements to translate first.

The documentation below is a continuation of that process, applied to Gutenberg blocks.

For instance, let's say we are using the Kadence's testimonials block:

Editing a post with a testimonials block
Editing a post with a testimonials block

When executing the translation, that block will remain in its original language:

Editing the translated post with a testimonials block
Editing the translated post with a testimonials block

By the end of this guide, all properties in the block will be translated:

The testimonail block is now translated
The testimonail block is now translated

To add support for translating a block, follow the steps below.

Identify the block properties to translate

The plugin translates blocks by extracting all the properties inside a block, translating those, and then injecting the translated properties back into the block.

In order to extract the properties from a block, the plugin needs to know:

  • Which properties are translatable
  • How to retrieve them from within the block
  • How to replace the property with its translation

Execute the Translate custom posts GraphQL query, and browse all the blocks and their properties in the GraphQL response, under key blockFlattenedDataItems.

Explore that entry to identify the block properties that must be translated.

In our case, we find the "kadence/testimonial" block, containing properties title, content and occupation (all under attributes) that need to be translated.

Identifying the block properties to translate
Identifying the block properties to translate

We must also identify how those strings are stored in the block HTML, printed under the first rawContent entry:

Identifying the block properties to translate
Identifying the block properties to translate

In our case, the block HTML is:

<!-- wp:kadence/testimonial {\"uniqueID\":\"1021_4fe748-f5\",\"url\":\"https://gatomultilingual.local/wp-content/uploads/2025/01/Luciano_Pavarotti_2004.jpg\",\"id\":184,\"subtype\":\"jpeg\",\"title\":\"Here is my secret\",\"content\":\"My voice needs to be strong and clear. That's why I drink green tea every morning. Stay away from fried food!\",\"name\":\"Luciano Pavarotti\",\"occupation\":\"Opera singer\",\"sizes\":{\"thumbnail\":{\"height\":150,\"width\":150,\"url\":\"https://gatomultilingual.local/wp-content/uploads/2025/01/Luciano_Pavarotti_2004-150x150.jpg\",\"orientation\":\"landscape\"},\"medium\":{\"height\":300,\"width\":210,\"url\":\"https://gatomultilingual.local/wp-content/uploads/2025/01/Luciano_Pavarotti_2004-210x300.jpg\",\"orientation\":\"portrait\"},\"full\":{\"url\":\"https://gatomultilingual.local/wp-content/uploads/2025/01/Luciano_Pavarotti_2004.jpg\",\"height\":629,\"width\":440,\"orientation\":\"portrait\"}}} /-->

The query will execute a regular expression (regex) search and replace on that HTML, to replace a string with its translation.

Later on, from this HTML, we will identify how to reach each property that needs to be translated (title, content and occupation) and create the corresponding regex.

Adapt the Gato GraphQL query

We can conveniently check which of the already-supported core blocks has a similar structure, and copy/paste/adapt that code for our block.

In our case, "kadence/testimonial" has a similar structure to "core/paragraph" (which contains the content property to translate), then we can copy and adapt its code.

The logic to translate a block is spread across 7 sections in the GraphQL query. They are marked with a GraphQL comment Insert code for custom blocks (g-{1-7}), like this one:

###############################################
##### Insert code for custom blocks (g-1)
###############################################

Search for them, copy the logic from the already-supported block ("core/paragraph") in that section, and adapt it accordingly for your block ("kadence/testimonial") by renaming variables, adapting the name of the property, and identifying the regex to replace the value of property in the block HTML.

The 7 sections for "core/paragraph" are:

Section 1 (defines a set of dynamic variables):

      @export(
        as: "originCoreParagraphContentItems"
        type: DICTIONARY
      )
      @export(
        as: "originCoreParagraphContentReplacementsFrom"
        type: DICTIONARY
      )
      @export(
        as: "originCoreParagraphContentReplacementsTo"
        type: DICTIONARY
      )

Section 2 (extracts a property from within the block, and exports it under a dynamic variable):

      originCoreParagraph: blockFlattenedDataItems(
        filterBy: { include: "core/paragraph" }
      )
        @underEachArrayItem
          @underJSONObjectProperty(
            by: { path: "attributes.content" }
            failIfNonExistingKeyOrPath: false
          )
            @export(
              as: "originCoreParagraphContentItems"
              type: DICTIONARY
            )

Section 3 (defines another set of dynamic variables):

        @export(
          as: "coreParagraphContentItems"
          type: DICTIONARY
        )
        @export(
          as: "coreParagraphContentReplacementsFrom"
          type: DICTIONARY
        )
        @export(
          as: "coreParagraphContentReplacementsTo"
          type: DICTIONARY
        )

Section 4 (extracts the strings to translate for a property and assigns them to a dynamic variable, and prepares storing the translations in another dynamic variable):

      originCoreParagraphContentItems: _objectProperty(
        object: $originCoreParagraphContentItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      coreParagraphContentItems: _echo(value: $__originCoreParagraphContentItems)
        @export(
          as: "coreParagraphContentItems"
          type: DICTIONARY
        )
        @remove
        
      originCoreParagraphContentReplacementsFrom: _objectProperty(
        object: $originCoreParagraphContentReplacementsFrom
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      coreParagraphContentReplacementsFrom: _echo(value: $__originCoreParagraphContentReplacementsFrom)
        @export(
          as: "coreParagraphContentReplacementsFrom"
          type: DICTIONARY
        )
        @remove
        
      originCoreParagraphContentReplacementsTo: _objectProperty(
        object: $originCoreParagraphContentReplacementsTo
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      coreParagraphContentReplacementsTo: _echo(value: $__originCoreParagraphContentReplacementsTo)
        @export(
          as: "coreParagraphContentReplacementsTo"
          type: DICTIONARY
        )
        @remove

Section 5 (defines a set of replacements to perform):

    coreParagraphContent: {
      from: $coreParagraphContentItems,
      to: $coreParagraphContentItems,
    },

Section 6 (defines the regex that will match the property value within the block's HTML):

    @underJSONObjectProperty(
      by: { key: "coreParagraphContent" }
      affectDirectivesUnderPos: [1, 6]
    )
      @underJSONObjectProperty(
        by: { key: "from" }
        affectDirectivesUnderPos: [1, 4],
      )
        @underEachJSONObjectProperty
          @underEachArrayItem(
            passValueOnwardsAs: "value"
          )
            @applyField(
              name: "_sprintf",
              arguments: {
                string: "#(<!-- wp:paragraph .*?-->\\n?<p ?.*?>)%s(</p>\\n?<!-- /wp:paragraph -->)#",
                values: [$value]
              },
              setResultInResponse: true
            )
        @export(
          as: "coreParagraphContentReplacementsFrom",
        )
      @underJSONObjectProperty(
        by: { key: "to" }
      )
        @export(
          as: "coreParagraphContentReplacementsTo",
        )

Section 7 (performs the regex search and replace, replacing the property value inside the block's HTML with its translation):

    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_propertyExistsInJSONObject"
        arguments: {
          object: $coreParagraphContentReplacementsFrom
          by: { key: $customPostID }
        }
        passOnwardsAs: "hasPostID"
      )
      @if(
        condition: $hasPostID
        affectDirectivesUnderPos: [1, 2, 3]
      )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $coreParagraphContentReplacementsFrom,
            by: {
              key: $customPostID
            }
          },
          passOnwardsAs: "postCoreParagraphContentReplacementsFrom"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $coreParagraphContentReplacementsTo,
            by: {
              key: $customPostID
            }
          },
          passOnwardsAs: "postCoreParagraphContentReplacementsTo"
        )
        @strRegexReplaceMultiple(
          limit: 1,
          searchRegex: $postCoreParagraphContentReplacementsFrom,
          replaceWith: $postCoreParagraphContentReplacementsTo
        )

Let's adapt them for "kadence/testimonial". Notice that, with the exception of Section 6 (more details below), all sections are pretty much a copy/paste and adapt:

Section 1:

      @export(
        as: "originKadenceTestimonialTitleItems"
        type: DICTIONARY
      )
      @export(
        as: "originKadenceTestimonialTitleReplacementsFrom"
        type: DICTIONARY
      )
      @export(
        as: "originKadenceTestimonialTitleReplacementsTo"
        type: DICTIONARY
      )
 
      @export(
        as: "originKadenceTestimonialContentItems"
        type: DICTIONARY
      )
      @export(
        as: "originKadenceTestimonialContentReplacementsFrom"
        type: DICTIONARY
      )
      @export(
        as: "originKadenceTestimonialContentReplacementsTo"
        type: DICTIONARY
      )
 
      @export(
        as: "originKadenceTestimonialOccupationItems"
        type: DICTIONARY
      )
      @export(
        as: "originKadenceTestimonialOccupationReplacementsFrom"
        type: DICTIONARY
      )
      @export(
        as: "originKadenceTestimonialOccupationReplacementsTo"
        type: DICTIONARY
      )

Section 2:

      originKadenceTestimonial: blockFlattenedDataItems(
        filterBy: { include: "kadence/testimonial" }
      )
        @underEachArrayItem
          @underJSONObjectProperty(
            by: { path: "attributes.title" }
            failIfNonExistingKeyOrPath: false
          )
            @export(
              as: "originKadenceTestimonialTitleItems"
              type: DICTIONARY
            )
        @underEachArrayItem
          @underJSONObjectProperty(
            by: { path: "attributes.content" }
            failIfNonExistingKeyOrPath: false
          )
            @export(
              as: "originKadenceTestimonialContentItems"
              type: DICTIONARY
            )
        @underEachArrayItem
          @underJSONObjectProperty(
            by: { path: "attributes.occupation" }
            failIfNonExistingKeyOrPath: false
          )
            @export(
              as: "originKadenceTestimonialOccupationItems"
              type: DICTIONARY
            )

Section 3:

        @export(
          as: "kadenceTestimonialTitleItems"
          type: DICTIONARY
        )
        @export(
          as: "kadenceTestimonialTitleReplacementsFrom"
          type: DICTIONARY
        )
        @export(
          as: "kadenceTestimonialTitleReplacementsTo"
          type: DICTIONARY
        )
 
        @export(
          as: "kadenceTestimonialContentItems"
          type: DICTIONARY
        )
        @export(
          as: "kadenceTestimonialContentReplacementsFrom"
          type: DICTIONARY
        )
        @export(
          as: "kadenceTestimonialContentReplacementsTo"
          type: DICTIONARY
        )
 
        @export(
          as: "kadenceTestimonialOccupationItems"
          type: DICTIONARY
        )
        @export(
          as: "kadenceTestimonialOccupationReplacementsFrom"
          type: DICTIONARY
        )
        @export(
          as: "kadenceTestimonialOccupationReplacementsTo"
          type: DICTIONARY
        )

Section 4:

      originKadenceTestimonialTitleItems: _objectProperty(
        object: $originKadenceTestimonialTitleItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialTitleItems: _echo(value: $__originKadenceTestimonialTitleItems)
        @export(
          as: "kadenceTestimonialTitleItems"
          type: DICTIONARY
        )
        @remove
        
      originKadenceTestimonialTitleReplacementsFrom: _objectProperty(
        object: $originKadenceTestimonialTitleReplacementsFrom
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialTitleReplacementsFrom: _echo(value: $__originKadenceTestimonialTitleReplacementsFrom)
        @export(
          as: "kadenceTestimonialTitleReplacementsFrom"
          type: DICTIONARY
        )
        @remove
        
      originKadenceTestimonialTitleReplacementsTo: _objectProperty(
        object: $originKadenceTestimonialTitleReplacementsTo
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialTitleReplacementsTo: _echo(value: $__originKadenceTestimonialTitleReplacementsTo)
        @export(
          as: "kadenceTestimonialTitleReplacementsTo"
          type: DICTIONARY
        )
        @remove
        
 
      originKadenceTestimonialContentItems: _objectProperty(
        object: $originKadenceTestimonialContentItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialContentItems: _echo(value: $__originKadenceTestimonialContentItems)
        @export(
          as: "kadenceTestimonialContentItems"
          type: DICTIONARY
        )
        @remove
        
      originKadenceTestimonialContentReplacementsFrom: _objectProperty(
        object: $originKadenceTestimonialContentReplacementsFrom
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialContentReplacementsFrom: _echo(value: $__originKadenceTestimonialContentReplacementsFrom)
        @export(
          as: "kadenceTestimonialContentReplacementsFrom"
          type: DICTIONARY
        )
        @remove
        
      originKadenceTestimonialContentReplacementsTo: _objectProperty(
        object: $originKadenceTestimonialContentReplacementsTo
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialContentReplacementsTo: _echo(value: $__originKadenceTestimonialContentReplacementsTo)
        @export(
          as: "kadenceTestimonialContentReplacementsTo"
          type: DICTIONARY
        )
        @remove
 
 
      originKadenceTestimonialOccupationItems: _objectProperty(
        object: $originKadenceTestimonialOccupationItems
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialOccupationItems: _echo(value: $__originKadenceTestimonialOccupationItems)
        @export(
          as: "kadenceTestimonialOccupationItems"
          type: DICTIONARY
        )
        @remove
        
      originKadenceTestimonialOccupationReplacementsFrom: _objectProperty(
        object: $originKadenceTestimonialOccupationReplacementsFrom
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialOccupationReplacementsFrom: _echo(value: $__originKadenceTestimonialOccupationReplacementsFrom)
        @export(
          as: "kadenceTestimonialOccupationReplacementsFrom"
          type: DICTIONARY
        )
        @remove
        
      originKadenceTestimonialOccupationReplacementsTo: _objectProperty(
        object: $originKadenceTestimonialOccupationReplacementsTo
        by: { key: $__originCustomPostId }
        failIfNonExistingKeyOrPath: false
        valueWhenNonExistingKeyOrPath: []
      )
      kadenceTestimonialOccupationReplacementsTo: _echo(value: $__originKadenceTestimonialOccupationReplacementsTo)
        @export(
          as: "kadenceTestimonialOccupationReplacementsTo"
          type: DICTIONARY
        )
        @remove

Section 5:

    kadenceTestimonialTitle: {
      from: $kadenceTestimonialTitleItems,
      to: $kadenceTestimonialTitleItems,
    },
    kadenceTestimonialContent: {
      from: $kadenceTestimonialContentItems,
      to: $kadenceTestimonialContentItems,
    },
    kadenceTestimonialOccupation: {
      from: $kadenceTestimonialOccupationItems,
      to: $kadenceTestimonialOccupationItems,
    },

Section 6:

Analyzing the HTML for the "kadence/testimonial" block, we must identify how to reach each property that needs to be translated (title, content and occupation):

<!-- wp:kadence/testimonial {[...],\"title\":\"Here is my secret\",\"content\":\"My voice needs to be strong and clear. That's why I drink green tea every morning. Stay away from fried food!\",[...],\"occupation\":\"Opera singer\",[...]} /-->

Then we create the corresponding regex for each property. The regex must match everything that comes before and after the string to translate, like this:

#(match everything before)%s(match everything after)#

In our case, we obtain:

  • title: #(<!-- wp:kadence/testimonial .*?\"title\":\")%s(\".*? /-->)#
  • content: #(<!-- wp:kadence/testimonial .*?\"content\":\")%s(\".*? /-->)#
  • occupation: #(<!-- wp:kadence/testimonial .*?\"occupation\":\")%s(\".*? /-->)#

Finally, we inject the regex on the code below:

    @underJSONObjectProperty(
      by: { key: "kadenceTestimonialTitle" }
      affectDirectivesUnderPos: [1, 6]
    )
      @underJSONObjectProperty(
        by: { key: "from" }
        affectDirectivesUnderPos: [1, 4],
      )
        @underEachJSONObjectProperty
          @underEachArrayItem(
            passValueOnwardsAs: "value"
          )
            @applyField(
              name: "_sprintf",
              arguments: {
                string: "#(<!-- wp:kadence/testimonial .*?\"title\":\")%s(\".*? /-->)#",
                values: [$value]
              },
              setResultInResponse: true
            )
        @export(
          as: "kadenceTestimonialTitleReplacementsFrom",
        )
      @underJSONObjectProperty(
        by: { key: "to" }
      )
        @export(
          as: "kadenceTestimonialTitleReplacementsTo",
        )
 
    @underJSONObjectProperty(
      by: { key: "kadenceTestimonialContent" }
      affectDirectivesUnderPos: [1, 6]
    )
      @underJSONObjectProperty(
        by: { key: "from" }
        affectDirectivesUnderPos: [1, 4],
      )
        @underEachJSONObjectProperty
          @underEachArrayItem(
            passValueOnwardsAs: "value"
          )
            @applyField(
              name: "_sprintf",
              arguments: {
                string: "#(<!-- wp:kadence/testimonial .*?\"content\":\")%s(\".*? /-->)#",
                values: [$value]
              },
              setResultInResponse: true
            )
        @export(
          as: "kadenceTestimonialContentReplacementsFrom",
        )
      @underJSONObjectProperty(
        by: { key: "to" }
      )
        @export(
          as: "kadenceTestimonialContentReplacementsTo",
        )
 
    @underJSONObjectProperty(
      by: { key: "kadenceTestimonialOccupation" }
      affectDirectivesUnderPos: [1, 6]
    )
      @underJSONObjectProperty(
        by: { key: "from" }
        affectDirectivesUnderPos: [1, 4],
      )
        @underEachJSONObjectProperty
          @underEachArrayItem(
            passValueOnwardsAs: "value"
          )
            @applyField(
              name: "_sprintf",
              arguments: {
                string: "#(<!-- wp:kadence/testimonial .*?\"occupation\":\")%s(\".*? /-->)#",
                values: [$value]
              },
              setResultInResponse: true
            )
        @export(
          as: "kadenceTestimonialOccupationReplacementsFrom",
        )
      @underJSONObjectProperty(
        by: { key: "to" }
      )
        @export(
          as: "kadenceTestimonialOccupationReplacementsTo",
        )

Section 7:

    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_propertyExistsInJSONObject"
        arguments: {
          object: $kadenceTestimonialTitleReplacementsFrom
          by: { key: $customPostID }
        }
        passOnwardsAs: "hasPostID"
      )
      @if(
        condition: $hasPostID
        affectDirectivesUnderPos: [1, 2, 3]
      )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $kadenceTestimonialTitleReplacementsFrom,
            by: {
              key: $customPostID
            }
          },
          passOnwardsAs: "postKadenceTestimonialTitleReplacementsFrom"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $kadenceTestimonialTitleReplacementsTo,
            by: {
              key: $customPostID
            }
          },
          passOnwardsAs: "postKadenceTestimonialTitleReplacementsTo"
        )
        @strRegexReplaceMultiple(
          limit: 1,
          searchRegex: $postKadenceTestimonialTitleReplacementsFrom,
          replaceWith: $postKadenceTestimonialTitleReplacementsTo
        )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_propertyExistsInJSONObject"
        arguments: {
          object: $kadenceTestimonialContentReplacementsFrom
          by: { key: $customPostID }
        }
        passOnwardsAs: "hasPostID"
      )
      @if(
        condition: $hasPostID
        affectDirectivesUnderPos: [1, 2, 3]
      )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $kadenceTestimonialContentReplacementsFrom,
            by: {
              key: $customPostID
            }
          },
          passOnwardsAs: "postKadenceTestimonialContentReplacementsFrom"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $kadenceTestimonialContentReplacementsTo,
            by: {
              key: $customPostID
            }
          },
          passOnwardsAs: "postKadenceTestimonialContentReplacementsTo"
        )
        @strRegexReplaceMultiple(
          limit: 1,
          searchRegex: $postKadenceTestimonialContentReplacementsFrom,
          replaceWith: $postKadenceTestimonialContentReplacementsTo
        )
 
    @underEachJSONObjectProperty(
      passKeyOnwardsAs: "customPostID"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_propertyExistsInJSONObject"
        arguments: {
          object: $kadenceTestimonialOccupationReplacementsFrom
          by: { key: $customPostID }
        }
        passOnwardsAs: "hasPostID"
      )
      @if(
        condition: $hasPostID
        affectDirectivesUnderPos: [1, 2, 3]
      )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $kadenceTestimonialOccupationReplacementsFrom,
            by: {
              key: $customPostID
            }
          },
          passOnwardsAs: "postKadenceTestimonialOccupationReplacementsFrom"
        )
        @applyField(
          name: "_objectProperty",
          arguments: {
            object: $kadenceTestimonialOccupationReplacementsTo,
            by: {
              key: $customPostID
            }
          },
          passOnwardsAs: "postKadenceTestimonialOccupationReplacementsTo"
        )
        @strRegexReplaceMultiple(
          limit: 1,
          searchRegex: $postKadenceTestimonialOccupationReplacementsFrom,
          replaceWith: $postKadenceTestimonialOccupationReplacementsTo
        )

Working on some code editor, copy the GraphQL query into a new file (you can format it as GraphQL to have syntax highlighting), add the 7 sections for the new block, and copy the adapted query back into the GraphiQL client.

Then execute the query, and check if the translated post has the block properties translated (by editing the translated post in the WordPress editor and refreshing the page).

Repeat until it all works, and then persist the query via a hook in PHP code.

Persist the GraphQL query via hooks in PHP code

When using the gatompl:persisted_query hook, the placeholders in the GraphQL query to inject the custom logic are:

  • ##### Insert code for custom blocks (g-1)
  • ##### Insert code for custom blocks (g-2)
  • ...
  • ##### Insert code for custom blocks (g-7)

Example - Persisting the query for the testimonial block

For the "kadence/testimonial" block, using the gatompl:persisted_query hook, 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 custom blocks (g-1)',
          '##### Insert code for custom blocks (g-2)',
          '##### Insert code for custom blocks (g-3)',
          '##### Insert code for custom blocks (g-4)',
          '##### Insert code for custom blocks (g-5)',
          '##### Insert code for custom blocks (g-6)',
          '##### Insert code for custom blocks (g-7)',
        ],
        [
          <<<GRAPHQL
          ##### Insert code for custom blocks (g-1)
                @export(
                  as: "originKadenceTestimonialTitleItems"
                  type: DICTIONARY
                )
                @export(
                  as: "originKadenceTestimonialTitleReplacementsFrom"
                  type: DICTIONARY
                )
                @export(
                  as: "originKadenceTestimonialTitleReplacementsTo"
                  type: DICTIONARY
                )
 
                @export(
                  as: "originKadenceTestimonialContentItems"
                  type: DICTIONARY
                )
                @export(
                  as: "originKadenceTestimonialContentReplacementsFrom"
                  type: DICTIONARY
                )
                @export(
                  as: "originKadenceTestimonialContentReplacementsTo"
                  type: DICTIONARY
                )
 
                @export(
                  as: "originKadenceTestimonialOccupationItems"
                  type: DICTIONARY
                )
                @export(
                  as: "originKadenceTestimonialOccupationReplacementsFrom"
                  type: DICTIONARY
                )
                @export(
                  as: "originKadenceTestimonialOccupationReplacementsTo"
                  type: DICTIONARY
                )
          GRAPHQL,
 
          <<<GRAPHQL
          ##### Insert code for custom blocks (g-2)
                originKadenceTestimonial: blockFlattenedDataItems(
                  filterBy: { include: "kadence/testimonial" }
                )
                  @underEachArrayItem
                    @underJSONObjectProperty(
                      by: { path: "attributes.title" }
                      failIfNonExistingKeyOrPath: false
                    )
                      @export(
                        as: "originKadenceTestimonialTitleItems"
                        type: DICTIONARY
                      )
                  @underEachArrayItem
                    @underJSONObjectProperty(
                      by: { path: "attributes.content" }
                      failIfNonExistingKeyOrPath: false
                    )
                      @export(
                        as: "originKadenceTestimonialContentItems"
                        type: DICTIONARY
                      )
                  @underEachArrayItem
                    @underJSONObjectProperty(
                      by: { path: "attributes.occupation" }
                      failIfNonExistingKeyOrPath: false
                    )
                      @export(
                        as: "originKadenceTestimonialOccupationItems"
                        type: DICTIONARY
                      )
          GRAPHQL,
 
          <<<GRAPHQL
          ##### Insert code for custom blocks (g-3)
                @export(
                  as: "kadenceTestimonialTitleItems"
                  type: DICTIONARY
                )
                @export(
                  as: "kadenceTestimonialTitleReplacementsFrom"
                  type: DICTIONARY
                )
                @export(
                  as: "kadenceTestimonialTitleReplacementsTo"
                  type: DICTIONARY
                )
 
                @export(
                  as: "kadenceTestimonialContentItems"
                  type: DICTIONARY
                )
                @export(
                  as: "kadenceTestimonialContentReplacementsFrom"
                  type: DICTIONARY
                )
                @export(
                  as: "kadenceTestimonialContentReplacementsTo"
                  type: DICTIONARY
                )
 
                @export(
                  as: "kadenceTestimonialOccupationItems"
                  type: DICTIONARY
                )
                @export(
                  as: "kadenceTestimonialOccupationReplacementsFrom"
                  type: DICTIONARY
                )
                @export(
                  as: "kadenceTestimonialOccupationReplacementsTo"
                  type: DICTIONARY
                )
          GRAPHQL,
 
          <<<GRAPHQL
          ##### Insert code for custom blocks (g-4)
                originKadenceTestimonialTitleItems: _objectProperty(
                  object: \$originKadenceTestimonialTitleItems
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialTitleItems: _echo(value: \$__originKadenceTestimonialTitleItems)
                  @export(
                    as: "kadenceTestimonialTitleItems"
                    type: DICTIONARY
                  )
                  @remove
                  
                originKadenceTestimonialTitleReplacementsFrom: _objectProperty(
                  object: \$originKadenceTestimonialTitleReplacementsFrom
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialTitleReplacementsFrom: _echo(value: \$__originKadenceTestimonialTitleReplacementsFrom)
                  @export(
                    as: "kadenceTestimonialTitleReplacementsFrom"
                    type: DICTIONARY
                  )
                  @remove
                  
                originKadenceTestimonialTitleReplacementsTo: _objectProperty(
                  object: \$originKadenceTestimonialTitleReplacementsTo
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialTitleReplacementsTo: _echo(value: \$__originKadenceTestimonialTitleReplacementsTo)
                  @export(
                    as: "kadenceTestimonialTitleReplacementsTo"
                    type: DICTIONARY
                  )
                  @remove
                  
 
                originKadenceTestimonialContentItems: _objectProperty(
                  object: \$originKadenceTestimonialContentItems
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialContentItems: _echo(value: \$__originKadenceTestimonialContentItems)
                  @export(
                    as: "kadenceTestimonialContentItems"
                    type: DICTIONARY
                  )
                  @remove
                  
                originKadenceTestimonialContentReplacementsFrom: _objectProperty(
                  object: \$originKadenceTestimonialContentReplacementsFrom
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialContentReplacementsFrom: _echo(value: \$__originKadenceTestimonialContentReplacementsFrom)
                  @export(
                    as: "kadenceTestimonialContentReplacementsFrom"
                    type: DICTIONARY
                  )
                  @remove
                  
                originKadenceTestimonialContentReplacementsTo: _objectProperty(
                  object: \$originKadenceTestimonialContentReplacementsTo
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialContentReplacementsTo: _echo(value: \$__originKadenceTestimonialContentReplacementsTo)
                  @export(
                    as: "kadenceTestimonialContentReplacementsTo"
                    type: DICTIONARY
                  )
                  @remove
 
 
                originKadenceTestimonialOccupationItems: _objectProperty(
                  object: \$originKadenceTestimonialOccupationItems
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialOccupationItems: _echo(value: \$__originKadenceTestimonialOccupationItems)
                  @export(
                    as: "kadenceTestimonialOccupationItems"
                    type: DICTIONARY
                  )
                  @remove
                  
                originKadenceTestimonialOccupationReplacementsFrom: _objectProperty(
                  object: \$originKadenceTestimonialOccupationReplacementsFrom
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialOccupationReplacementsFrom: _echo(value: \$__originKadenceTestimonialOccupationReplacementsFrom)
                  @export(
                    as: "kadenceTestimonialOccupationReplacementsFrom"
                    type: DICTIONARY
                  )
                  @remove
                  
                originKadenceTestimonialOccupationReplacementsTo: _objectProperty(
                  object: \$originKadenceTestimonialOccupationReplacementsTo
                  by: { key: \$__originCustomPostId }
                  failIfNonExistingKeyOrPath: false
                  valueWhenNonExistingKeyOrPath: []
                )
                kadenceTestimonialOccupationReplacementsTo: _echo(value: \$__originKadenceTestimonialOccupationReplacementsTo)
                  @export(
                    as: "kadenceTestimonialOccupationReplacementsTo"
                    type: DICTIONARY
                  )
                  @remove
          GRAPHQL,
 
          <<<GRAPHQL
          ##### Insert code for custom blocks (g-5)
              kadenceTestimonialTitle: {
                from: \$kadenceTestimonialTitleItems,
                to: \$kadenceTestimonialTitleItems,
              },
              kadenceTestimonialContent: {
                from: \$kadenceTestimonialContentItems,
                to: \$kadenceTestimonialContentItems,
              },
              kadenceTestimonialOccupation: {
                from: \$kadenceTestimonialOccupationItems,
                to: \$kadenceTestimonialOccupationItems,
              },
          GRAPHQL,
 
          <<<GRAPHQL
          ##### Insert code for custom blocks (g-6)
                @underJSONObjectProperty(
                  by: { key: "kadenceTestimonialTitle" }
                  affectDirectivesUnderPos: [1, 6]
                )
                  @underJSONObjectProperty(
                    by: { key: "from" }
                    affectDirectivesUnderPos: [1, 4],
                  )
                    @underEachJSONObjectProperty
                      @underEachArrayItem(
                        passValueOnwardsAs: "value"
                      )
                        @applyField(
                          name: "_sprintf",
                          arguments: {
                            string: "#(<!-- wp:kadence/testimonial .*?\"title\":\")%s(\".*? /-->)#",
                            values: [\$value]
                          },
                          setResultInResponse: true
                        )
                    @export(
                      as: "kadenceTestimonialTitleReplacementsFrom",
                    )
                  @underJSONObjectProperty(
                    by: { key: "to" }
                  )
                    @export(
                      as: "kadenceTestimonialTitleReplacementsTo",
                    )
 
                @underJSONObjectProperty(
                  by: { key: "kadenceTestimonialContent" }
                  affectDirectivesUnderPos: [1, 6]
                )
                  @underJSONObjectProperty(
                    by: { key: "from" }
                    affectDirectivesUnderPos: [1, 4],
                  )
                    @underEachJSONObjectProperty
                      @underEachArrayItem(
                        passValueOnwardsAs: "value"
                      )
                        @applyField(
                          name: "_sprintf",
                          arguments: {
                            string: "#(<!-- wp:kadence/testimonial .*?\"content\":\")%s(\".*? /-->)#",
                            values: [\$value]
                          },
                          setResultInResponse: true
                        )
                    @export(
                      as: "kadenceTestimonialContentReplacementsFrom",
                    )
                  @underJSONObjectProperty(
                    by: { key: "to" }
                  )
                    @export(
                      as: "kadenceTestimonialContentReplacementsTo",
                    )
 
                @underJSONObjectProperty(
                  by: { key: "kadenceTestimonialOccupation" }
                  affectDirectivesUnderPos: [1, 6]
                )
                  @underJSONObjectProperty(
                    by: { key: "from" }
                    affectDirectivesUnderPos: [1, 4],
                  )
                    @underEachJSONObjectProperty
                      @underEachArrayItem(
                        passValueOnwardsAs: "value"
                      )
                        @applyField(
                          name: "_sprintf",
                          arguments: {
                            string: "#(<!-- wp:kadence/testimonial .*?\"occupation\":\")%s(\".*? /-->)#",
                            values: [\$value]
                          },
                          setResultInResponse: true
                        )
                    @export(
                      as: "kadenceTestimonialOccupationReplacementsFrom",
                    )
                  @underJSONObjectProperty(
                    by: { key: "to" }
                  )
                    @export(
                      as: "kadenceTestimonialOccupationReplacementsTo",
                    )
          GRAPHQL,
 
          <<<GRAPHQL
          ##### Insert code for custom blocks (g-7)
                @underEachJSONObjectProperty(
                  passKeyOnwardsAs: "customPostID"
                  affectDirectivesUnderPos: [1, 2]
                )
                  @applyField(
                    name: "_propertyExistsInJSONObject"
                    arguments: {
                      object: \$kadenceTestimonialTitleReplacementsFrom
                      by: { key: \$customPostID }
                    }
                    passOnwardsAs: "hasPostID"
                  )
                  @if(
                    condition: \$hasPostID
                    affectDirectivesUnderPos: [1, 2, 3]
                  )
                    @applyField(
                      name: "_objectProperty",
                      arguments: {
                        object: \$kadenceTestimonialTitleReplacementsFrom,
                        by: {
                          key: \$customPostID
                        }
                      },
                      passOnwardsAs: "postKadenceTestimonialTitleReplacementsFrom"
                    )
                    @applyField(
                      name: "_objectProperty",
                      arguments: {
                        object: \$kadenceTestimonialTitleReplacementsTo,
                        by: {
                          key: \$customPostID
                        }
                      },
                      passOnwardsAs: "postKadenceTestimonialTitleReplacementsTo"
                    )
                    @strRegexReplaceMultiple(
                      limit: 1,
                      searchRegex: \$postKadenceTestimonialTitleReplacementsFrom,
                      replaceWith: \$postKadenceTestimonialTitleReplacementsTo
                    )
 
                @underEachJSONObjectProperty(
                  passKeyOnwardsAs: "customPostID"
                  affectDirectivesUnderPos: [1, 2]
                )
                  @applyField(
                    name: "_propertyExistsInJSONObject"
                    arguments: {
                      object: \$kadenceTestimonialContentReplacementsFrom
                      by: { key: \$customPostID }
                    }
                    passOnwardsAs: "hasPostID"
                  )
                  @if(
                    condition: \$hasPostID
                    affectDirectivesUnderPos: [1, 2, 3]
                  )
                    @applyField(
                      name: "_objectProperty",
                      arguments: {
                        object: \$kadenceTestimonialContentReplacementsFrom,
                        by: {
                          key: \$customPostID
                        }
                      },
                      passOnwardsAs: "postKadenceTestimonialContentReplacementsFrom"
                    )
                    @applyField(
                      name: "_objectProperty",
                      arguments: {
                        object: \$kadenceTestimonialContentReplacementsTo,
                        by: {
                          key: \$customPostID
                        }
                      },
                      passOnwardsAs: "postKadenceTestimonialContentReplacementsTo"
                    )
                    @strRegexReplaceMultiple(
                      limit: 1,
                      searchRegex: \$postKadenceTestimonialContentReplacementsFrom,
                      replaceWith: \$postKadenceTestimonialContentReplacementsTo
                    )
 
                @underEachJSONObjectProperty(
                  passKeyOnwardsAs: "customPostID"
                  affectDirectivesUnderPos: [1, 2]
                )
                  @applyField(
                    name: "_propertyExistsInJSONObject"
                    arguments: {
                      object: \$kadenceTestimonialOccupationReplacementsFrom
                      by: { key: \$customPostID }
                    }
                    passOnwardsAs: "hasPostID"
                  )
                  @if(
                    condition: \$hasPostID
                    affectDirectivesUnderPos: [1, 2, 3]
                  )
                    @applyField(
                      name: "_objectProperty",
                      arguments: {
                        object: \$kadenceTestimonialOccupationReplacementsFrom,
                        by: {
                          key: \$customPostID
                        }
                      },
                      passOnwardsAs: "postKadenceTestimonialOccupationReplacementsFrom"
                    )
                    @applyField(
                      name: "_objectProperty",
                      arguments: {
                        object: \$kadenceTestimonialOccupationReplacementsTo,
                        by: {
                          key: \$customPostID
                        }
                      },
                      passOnwardsAs: "postKadenceTestimonialOccupationReplacementsTo"
                    )
                    @strRegexReplaceMultiple(
                      limit: 1,
                      searchRegex: \$postKadenceTestimonialOccupationReplacementsFrom,
                      replaceWith: \$postKadenceTestimonialOccupationReplacementsTo
                    )
          GRAPHQL,
        ],
        $persistedQuery
      );
    }
    return $persistedQuery;
  },
  10,
  2
);