> For the complete documentation index, see [llms.txt](https://developers.weglot.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.weglot.com/wordpress/filters/translations-filters.md).

# Translations Hooks

Weglot plugin will detect all the words in your HTML. To do this, it will parse the DOM in PHP and detect the inner text of HTML nodes but also some attributes we have defined, like the "placeholder" attribute in a `<input>` node or the "alt" attribute of an `img` node.

This usually ensure all the text in your page is detected and get translated. However, in some case, your text can be located in other location in your HTML. Like it could be in a JavaScript variable like this

```javascript
<script>
var myAwesomeVar = 'This is a text I would like to translate';
</script>
```

In that case, your text will not be detected and not be translated.

This is where you will use filters to extend the definitions of the Weglot Parser and instruct it to detect other text.

### Extend what gets detected

#### weglot\_get\_dom\_checkers

This filter extend the list of HTML nodes and attribute that are being translated.

| Argument       | Type  | Description                                                                       |
| -------------- | ----- | --------------------------------------------------------------------------------- |
| $dom\_checkers | array | Names of used **DomChecker** (extends Weglot\Parser\Check\Dom\AbstractDomChecker) |

**Use case**

It can happen in your HTML that you use data-attributes that are not translated by default. Example with **data-slide-title**

```markup
<div data-slide-title="Title slide">
    New project !
</div>
```

With the `weglot_get_dom_checkers` filter, you will extend the list of "Dom checkers" by adding a class in the list like on the following example.

```php
<?php

add_filter( 'weglot_get_dom_checkers', 'custom_weglot_dom_check' );
function custom_weglot_dom_check( $dom_checkers ) { //$dom_checkers contains the list of all the class we are checking by default
	if (!class_exists('Div_Slide_Title')) {
		class Div_Slide_Title extends Weglot\Parser\Check\Dom\AbstractDomChecker {
			const DOM       = 'div'; //Type of tag you want to detect // CSS Selector
			const PROPERTY  = 'data-slide-title'; //Name of the attribute in that tag you want to detect
			const WORD_TYPE = Weglot\Client\Api\Enum\WordType::TEXT; //Do not change unless it's not text but a media URL like a .pdf file for example.
		}
		$dom_checkers[] = '\Div_Slide_Title'; //You add your class to the list because you want the parser to also detect it
	}
	return $dom_checkers;
}
```

#### weglot\_get\_regex\_checkers

This filter is a bit more tricky to understand but also very powerful. It allows you to give a Regex to the parser in order for it to detect the text you want in your DOM.

| Argument         | Type  | Description           |
| ---------------- | ----- | --------------------- |
| $regex\_checkers | array | Used **RegexChecker** |

**$regex\_checkers** is an array that contains the **RegexChecker** objects, which determine what elements to treat as well as the type of data it is (TEXT, HTML or JSON).

```php
\Weglot\Parser\Check\Regex\RegexChecker( $regex = '', $type = '', $var_number = 0, $keys = array(), $callback = null, $revert_callback = null );
```

The **RegexChecker** constructor settings are as follows:

* **$regex**: Regex that target the element you want to be parsed
* **$type**: String variable that determines the type of the targeted element ('TEXT', 'HTML' or 'JSON')
* **$var\_number**: Denotes the number of variable targeted by the regex that you want to parse
* **$keys**: If the element being treated is a 'JSON' element, this variable allows you to specify keys to translate
* **$callback**: Function callback applied to intercepted content
* **$revert\_callback**: Function callback applied to returned content

**Use case**

Below are several examples of content that will not be translated by default by Weglot, but that you can translate using this filter

```markup
<script type="text/javascript">
    jQuery(document).ready(function ($) {

        // Untranslate text
        alert("My untranslate text");
        console.log("My untranslate text", "My untranslate text");

        // Untranslate HTML
        $("body").append("<p>My <strong>untranslate</strong> text</p>");

        // Untranslate JSON values
        var myJson = {
            "MyKey1": {
                "MyKey1-1": "My untranslate text",
                "MyKey1-2": "My untranslate text"
            },
            "MyKey2": "My untranslate text",
            "some_array" : [ "Hello" , "Translate this"]
        };

    });
</script>
<script type="text/template">"\r\n\t\t\t<div class=\"sticky-sidebar\">\r\n\t\t\t\t\ ....  \t\t<\/div>\r\n\r\n\t\t\t"</script>
<div data-escapedjson="{&quot;schema&quot;:{&quot;content&quot;:{&quot;desktop&quot;:&quot;&lt;h1&gt;Translate it&lt;\/h1&gt;&quot;}}}"><h1>This, no problem</h1></div>
```

In order for the content in this example to be interpreted, and then translated, we will use the **weglot\_get\_regex\_checkers** filter as followed.

```php
<?php

add_filter( 'weglot_get_regex_checkers', 'custom_weglot_add_regex_checkers' );

function custom_weglot_add_regex_checkers( $regex_checkers ) {

    // Text
    $regex_checkers[] = new \Weglot\Parser\Check\Regex\RegexChecker( '#alert\(\"(.*)\"\);#', 'TEXT', 1 );
    $regex_checkers[] = new \Weglot\Parser\Check\Regex\RegexChecker( '#console\.log\(\"(.*?)\",.*?\"(.*?)\"\);#', 'TEXT', 2 );

    // HTML
    $regex_checkers[] = new \Weglot\Parser\Check\Regex\RegexChecker( '#\$\(\"body\"\)\.append\(\"(.*)\"\);#', 'HTML', 1 );

    // JSON
    $regex_checkers[] = new \Weglot\Parser\Check\Regex\RegexChecker( '#var myJson = ((.|\s)+?);#', 'JSON', 1, array('MyKey1-1', 'MyKey1-2', 'MyKey2' , 'some_array') );

    //More advanced : HTML after a callback
    $regex_checkers[] = new \Weglot\Parser\Check\Regex\RegexChecker( "#<script type=\"text\/template\">(.*)<\/script>#", "HTML", 1, array(),"json_decode" , "json_encode");

    //More advanced : JSON after a callback
    $regex_checkers[] = new \Weglot\Parser\Check\Regex\RegexChecker( '#data-escapedjson="((.|\s)+?)"#', 'JSON', 1, array(), "html_entity_decode" , "htmlentities" );

    //More advanced : JSON after a callback, version with another regex
    $regex_checkers[] = new \Weglot\Parser\Check\Regex\RegexChecker( '#data-escapedjson="(.*)"#', 'JSON', 1, array(), "html_entity_decode" , "htmlentities" );

    return $regex_checkers;
}
```

#### weglot\_words\_translate

Use this filter to target a specific word literally in your source code.

| Argument | Type  | Description     |
| -------- | ----- | --------------- |
| $words   | array | Array of string |

You can add words that are present in your HTML page but not translated. It's useful when a word is not being translated by Weglot because it's inside a JavaScript for example and you can't really use other filters.

**Use case**

```php
<?php

add_filter( 'weglot_words_translate', 'custom_weglot_words_translate' );
function custom_weglot_words_translate( $words ){
    $words[] = "Monday";
    $words[] = "Tuesday";
    $words[] = "Nice to meet you";
    return $words;
}
```

This filter will tell Weglot to look literally for words in your source code, then translate it and literally replace these words in your source code. Be very careful to not enter keywords as "head" "body" for example as it could break your page.

#### weglot\_preserve\_words\_enabled / weglot\_preserve\_words\_list

The mirror image of `weglot_words_translate`: use these two filters to keep specific words **untranslated**, wherever they appear on the page (brand names, product references, etc.).

* `weglot_preserve_words_enabled` — return `true` to turn the feature on (default `false`).
* `weglot_preserve_words_list` — return the array of literal words to preserve (default empty). It also receives the page content as a second argument if you need to build the list dynamically.

```php
<?php

add_filter( 'weglot_preserve_words_enabled', '__return_true' );

add_filter( 'weglot_preserve_words_list', 'custom_weglot_preserve_words' );
function custom_weglot_preserve_words( $words ) {
    $words[] = "Weglot";
    $words[] = "iPhone";
    return $words;
}
```

#### weglot\_get\_parser\_ignored\_nodes

Change the list of DOM node types the parser never descends into (so their content is never detected nor translated). The filter receives the default list of tag names provided by the parser and must return the modified list.

```php
<?php

add_filter( 'weglot_get_parser_ignored_nodes', 'custom_weglot_ignored_nodes' );
function custom_weglot_ignored_nodes( $nodes ) {
    $nodes[] = 'my-custom-tag';
    return $nodes;
}
```

### Whitelist & exclude blocks

By default, everything on a page is translated except the blocks you exclude. These two filters give you both sides of that control from your code.

#### weglot\_parser\_whitelist

This filter flips the page into **opt-in mode**. By default Weglot translates the whole page; when the array returned by this filter is **not empty**, Weglot adds a `wg-mode-whitelist` attribute to the `<body>` tag and translates **only** the blocks matching the listed CSS selectors — everything else is left untranslated.

```php
<?php

add_filter( 'weglot_parser_whitelist', 'custom_whitelist' );
function custom_whitelist( $whitelist ) {
    $whitelist[] = '.product-title';
    return $whitelist;
}
```

You can whitelist more than one block:

```php
<?php

add_filter( 'weglot_parser_whitelist', 'custom_whitelist' );
function custom_whitelist( $whitelist ) {
    $whitelist[] = '.product-title';
    $whitelist[] = '.product-description';
    return $whitelist;
}
```

{% hint style="warning" %}
Do not confuse `weglot_parser_whitelist` (server-side PHP parser, described here) with `weglot_whitelist_selectors` (client-side JavaScript engine, in the [Client-side (dynamic) translation](#client-side-dynamic-translation) section). They share the word "whitelist" but operate in different layers.
{% endhint %}

#### weglot\_exclude\_blocks

The opposite of the whitelist: add CSS selectors whose content must **not** be translated. Weglot marks every matching element with a `data-wg-notranslate` attribute.

```php
<?php

add_filter( 'weglot_exclude_blocks', 'custom_weglot_exclude_blocks' );
function custom_weglot_exclude_blocks( $blocks ) {
    $blocks[] = '.customer-reviews';
    return $blocks;
}
```

{% hint style="info" %}
Weglot always appends a set of built-in selectors to this list (for example `#wpadminbar`, `.material-icons`, and WooCommerce/Query Monitor selectors when those plugins are active). Your custom selectors are added on top of them.
{% endhint %}

### JSON responses

#### weglot\_add\_json\_keys

Weglot also translates JSON response but not all values. Use this filter to target specific values.

| Argument | Type  | Description     |
| -------- | ----- | --------------- |
| $keys    | array | Array of string |

The JSON values translated by default are:

* Value with key: "name"
* Value with key: "description"
* Value in HTML format

**Use case**

You may come across values used in your JSON that are not translated by default. Here's an example using the **message** value:

```javascript
{
    "name":"My name value, already translated", //Will be translated by default because key is "name"
    "description":"My description value, already translated", //Will be translated by default because key is "description"
    "my_custom_key":"<p>HTML content, already translated</p>", //Will be translated by default because we detect this is HTML
    "message":"My message value to translate!" //This will not be translated and you will need to use the filter
}
```

To do this, we use **weglot\_add\_json\_keys** filter.

```php
<?php

add_filter( 'weglot_add_json_keys',  'custom_weglot_add_json_keys' );
function custom_weglot_add_json_keys( $keys ){ //$keys already contains "name" and "description"
    $keys[] = 'message'; //This tells Weglot to also look for key "message" when detecting content to translated
    return $keys;
}
```

Also, note that if a URL is detected in a value of the JSON, it will be replaced by the URL with the language code if and only if it is one of the `redirecturl`, `url`, `link`. For example, if your original JSON is

```javascript
{
    "url" : "https://mysite.com/contact",
    "redirectURL" : "https://mysite.com/contact",
    "niceURL" : "https://mysite.com/contact",
    "name" : "This is my name"
}
```

The translated response would be

```javascript
{
    "url" : "https://mysite.com/fr/contact",
    "redirectURL" : "https://mysite.com/fr/contact",
    "niceURL" : "https://mysite.com/contact",
    "name" : "C'est mon nom"
}
```

Adding keys to check when replacing URL is done with **weglot\_ajax\_replace\_urls**.

If you want to remove some defaults keys you can use the filter **`list_json_ld_keys`**

```php
add_filter( 'list_json_ld_keys',  'custom_weglot_add_json_keys' );
function custom_weglot_add_json_keys( $keys ){
    $key = array_search('name', $keys);
    if ($key !== false) {
        unset($keys[$key]);
    }
    $keys[] = 'message';
    return $keys;
}
```

Through this filter, it is possible to remove existing keys and add new ones. In this example, the `name` key is explicitly removed from the array using `array_search()` and `unset()`. After that, a new key called `message` is added to the list.

This approach allows you to customize the structure of the JSON-LD data by excluding unwanted keys (such as `name`) and including alternative ones depending on your needs.

### Escaping content from translation

These filters "shield" parts of your markup from the parser: their content is tokenized before translation and restored afterwards. Use them when a script, template or attribute must be left exactly as-is.

The following filters take an **array** and return the modified array:

| Filter                          | Default                                                                       | Purpose                                                      |
| ------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `weglot_escape_attributes`      | `[]`                                                                          | HTML attribute names whose values must not be translated     |
| `weglot_escape_script_types`    | `text/template`, `text/html`, `text/x-template`, `text/x-handlebars-template` | `<script type="…">` values whose content is escaped          |
| `weglot_escape_script_ids`      | `tmpl-*`, `nf-*`, `*-js-extra`                                                | `<script>` id patterns to escape (`*` wildcard supported)    |
| `weglot_escape_script_classes`  | `[]`                                                                          | `<script>` class patterns to escape (`*` wildcard supported) |
| `weglot_escape_script_contains` | `[]`                                                                          | Escape scripts whose inner content matches a pattern         |

The following filters are simple **on/off toggles** (return `true` to enable, default `false`):

| Filter                            | Purpose                                              |
| --------------------------------- | ---------------------------------------------------- |
| `weglot_escape_script_templates`  | Escape `<script>` template blocks before translation |
| `weglot_escape_vue_js`            | Escape Vue.js attributes                             |
| `weglot_escape_attribute_in_html` | Escape configured attributes in HTML responses       |
| `weglot_escape_attribute_in_json` | Escape configured attributes in JSON responses       |

```php
<?php

// Never translate the value of a data-config attribute
add_filter( 'weglot_escape_attributes', function( $attributes ) {
    $attributes[] = 'data-config';
    return $attributes;
} );
```

### Modifying the final output

These filters let you edit the fully translated response, right before it is sent to the browser. Use them as a last resort, when no detection filter fits.

#### weglot\_html\_treat\_page

A very powerful filter that allows you to make manual edition on the final translated DOM in PHP.

| Argument | Type   | Description                     |
| -------- | ------ | ------------------------------- |
| $html    | string | HTML content of translated page |

**Use case 1**

The following code replaces all of the "<https://codex.wordpress.org/>" links with "<https://codex.wordpress.org/fr:Accueil>" in the translated versions.

```php
<?php

add_filter( 'weglot_html_treat_page', 'custom_weglot_html_treat_page_1' );
function custom_weglot_html_treat_page_1( $html ) {

    $s = 'https://codex.wordpress.org/';
    $r = 'https://codex.wordpress.org/fr:Accueil';

    $html = str_replace( $s, $r, $html );
    return $html;
}
```

**Use case 2**

In this example, the replacement occurs according to the chosen language.

```php
<?php

add_filter( 'weglot_html_treat_page', 'custom_weglot_html_treat_page_2' );
function custom_weglot_html_treat_page_2( $html ) {

    $search = 'https://codex.wordpress.org/';

    switch ( weglot_get_current_language() ) {
        case 'fr':
            $html = str_replace( $search, 'https://codex.wordpress.org/fr:Accueil', $html );
            break;
        case 'pt':
            $html = str_replace( $search, 'https://codex.wordpress.org/pt:Página_Inicial', $html );
            break;
    }

    return $html;
}
```

#### weglot\_json\_treat\_page / weglot\_xml\_treat\_page

Same idea as `weglot_html_treat_page`, but for the other response types. Each one receives the final translated string and must return the modified string:

* `weglot_json_treat_page` — final translated **JSON** response.
* `weglot_xml_treat_page` — final translated **XML** response (for example a sitemap).

```php
<?php

add_filter( 'weglot_xml_treat_page', function( $xml ) {
    // edit the translated sitemap here
    return $xml;
} );
```

#### weglot\_render\_dom

Same as `weglot_html_treat_page`, except the language button HTML is already included and the links are already translated. Handy when you need to act on the exact markup that will be rendered.

### Client-side (dynamic) translation

{% hint style="info" %}
All the filters in this section only take effect when `weglot_translate_dynamics` returns `true`. They configure Weglot's front-end **JavaScript** library — not the server-side PHP parser — and are used to translate content that changes after the initial page load.
{% endhint %}

**1. Enabling Dynamic Content Translation**

To enable the use of dynamic content translation on your website, add the following filter:

```php
add_filter( 'weglot_translate_dynamics', '__return_true' );
```

This filter allows Weglot to handle the translation of dynamic content, which may change after the initial page load (e.g., content updated via JavaScript).

**2. Defining Custom Selectors**

Next, define the selectors that Weglot should use to identify dynamic content. We achieve this by creating a custom function:

```php
function custom_weglot_dynamics_selectors( $default_dynamics ) {
    return [
        ['value' => '.wp-block-woocommerce-cart'],
        ['value' => '.qodef-m-content'],
        ['value' => '.wp-block-woocommerce-checkout'],
    ];
}
```

* The function `custom_weglot_dynamics_selectors()` returns an array of CSS selectors. These selectors specify which parts of your website's content should be treated as dynamic.
* For example, `.wp-block-woocommerce-cart` and `.wp-block-woocommerce-checkout` target WooCommerce cart and checkout blocks.

**3. Applying Custom Selectors to Weglot Filters**

To use the custom selectors defined above, apply them to both the dynamic and whitelist selector filters:

```php
add_filter( 'weglot_dynamics_selectors', 'custom_weglot_dynamics_selectors' );
add_filter( 'weglot_whitelist_selectors', 'custom_weglot_dynamics_selectors' );
```

* `weglot_dynamics_selectors`: This filter allows Weglot to recognize dynamic content based on the selectors you defined.
* `weglot_whitelist_selectors`: This filter specifies elements that Weglot should always translate, ensuring that the specified content is included in translations.

By using the same function for both filters, you can reuse the list of selectors for both dynamic and whitelisted content.

**4. Specifying URLs for Applying Custom Translations**

Lastly, define where your custom dynamic translations should be applied. By default, this is set to an empty value, but you can configure it to apply to all URLs or a specific list:

```php
add_filter( 'weglot_allowed_urls', function( $urls ) {
    return 'all'; // This will make $allowed_urls === 'all'
});
```

* `weglot_allowed_urls`: This filter determines on which URLs the custom translation rules will be applied.
* Setting the value to `'all'` ensures that your custom selectors will work on every page of your website. You can also pass an array of specific URLs if you only want the rules to apply to certain pages.

**5. Proxifying iframes and URLs**

Two more front-end filters let you route content through Weglot when needed:

* `weglot_proxify_iframes` — list iframe selectors (same `['value' => '…']` shape as above) whose content should be handled by the JS library. Default empty.
* `weglot_proxify_urls` — list resource URLs that should be routed through the Weglot proxy on translated pages. Default empty.

**6. External JavaScript Dependency for Custom Code**

When using the dynamic code, it requires an external JavaScript script to be loaded correctly for it to function as expected.

**Key Considerations:**

1. **Script Loading**: If the external script fails to load or is not included properly on the page, the custom code will not work. Make sure that the script is loaded before the code is executed.
2. **`defer` Attribute Issues**: If the external script is loaded with the `defer` attribute, it may cause unexpected behavior or delays, especially if your custom code depends on the script being fully available before execution.
3. **Solution**: To ensure that your custom code works seamlessly, you may need to **exclude this specific script from being deferred**. This way, the script will load immediately and be available when your code is executed, avoiding potential timing issues.

### Advanced parser tuning

Low-level filters you should only need in edge cases (very large pages, PCRE limits, custom parser configuration). Each returns the same type it receives.

| Filter                          | Type   | Default                | Purpose                                                                                               |
| ------------------------------- | ------ | ---------------------- | ----------------------------------------------------------------------------------------------------- |
| `weglot_parser_config_provider` | object | `ServerConfigProvider` | Swap the parser's ConfigProvider (must implement `ConfigProviderInterface`)                           |
| `weglot_regex_tags_limit`       | int    | `200000`               | Max tag length before `data-link` URL rewriting is skipped (only applied if a callback is registered) |
| `weglot_length_replace_a`       | int    | `1500`                 | Max URL length considered for `<a>` link replacement; longer URLs are skipped to avoid PCRE errors    |
| `weglot_length_replace_tags`    | int    | `2000`                 | Max surrounding-tag length for link replacement; longer tags are skipped                              |
