> This is part 1 of 2 of the full documentation (pages 1–100 of 154).
> The content is paginated: fetch every part to see all of it.
> Next part: https://developers.weglot.com/llms-full.txt/1
> Page index: https://developers.weglot.com/llms.txt

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
This site has an agentic ask interface you may use to query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://developers.weglot.com/index.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

---

# Weglot Developer Documentation

Translate your project with Weglot, and customize the Weglot plugins and libraries.

<button type="button" class="button primary" data-action="ask" data-icon="gitbook-assistant">Ask a question...</button>

<button type="button" class="button secondary" data-action="ask" data-query="How do I translate my React app with Weglot?" data-icon="react">Translate a React app</button><button type="button" class="button secondary" data-action="ask" data-query="How do I translate my JSON localization files with the Translate Action?" data-icon="github">Translate JSON files</button><button type="button" class="button secondary" data-action="ask" data-query="How do I customize the Weglot WordPress plugin?" data-icon="wordpress">Customize WordPress</button>

## Translate your project

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4><i class="fa-react">:react:</i></h4></td><td><strong>React</strong></td><td>Translate your React and Next.js apps, and their CMS content.</td><td><a href="https://developers.weglot.com/frameworks-and-ai/react">https://developers.weglot.com/frameworks-and-ai/react</a></td></tr><tr><td><h4><i class="fa-github">:github:</i></h4></td><td><strong>Translate Action</strong></td><td>Translate your JSON localization files from GitHub Actions.</td><td><a href="https://developers.weglot.com/frameworks-and-ai/translate-action">https://developers.weglot.com/frameworks-and-ai/translate-action</a></td></tr><tr><td><h4><i class="fa-terminal">:terminal:</i></h4></td><td><strong>API</strong></td><td>Call the Weglot API directly over HTTP.</td><td><a href="https://developers.weglot.com/api-reference">https://developers.weglot.com/api-reference</a></td></tr></tbody></table>

## Translate a React app in minutes

{% columns %}
{% column width="50%" %}
Install the Weglot package on your Next.js or Vite app. Text written in your code is translated when your app is built, and languages and translations are managed in your Weglot 2.0 project.

{% hint style="warning" icon="life-ring" %}
**Need some help?**

<details>

<summary>Some text in my components is not translated</summary>

Point `sourceRoot` to the folder that contains all your pages and components. If the text is in a prop of your own component, declare it with `translatableAttributes`.

</details>

<details>

<summary>Dynamic content stays in the source language</summary>

The first request for a text returns the source text while it is translated. Check that the field goes through `tDynamic`, `tDynamicAll` or `tDynamicHtml`.

</details>

<details>

<summary>The build fails while waiting for translations</summary>

Run the build again without the `.next` cache: the translations already received are kept. To wait longer, raise `translationTimeout`.

</details>
{% endhint %}

<a href="https://developers.weglot.com/frameworks-and-ai/react/getting-started" class="button primary" data-icon="rocket-launch">Get started</a> <a href="https://developers.weglot.com/frameworks-and-ai/react/troubleshooting" class="button secondary" data-icon="life-ring">Troubleshooting</a>
{% endcolumn %}

{% column width="50%" %}
{% stepper %}
{% step %}

#### Create your project

Sign in to Weglot 2.0, create a project with its source and target languages, then copy its API key, from your project settings.

<a href="https://auth.weglot.com/" class="button primary">Sign in to Weglot 2.0</a>
{% endstep %}

{% step %}

#### Install the package

{% code overflow="wrap" %}

```bash
npm install @weglot/translate-react
echo "WEGLOT_API_KEY=pk_your_weglot_api_key" >> .env
```

{% endcode %}
{% endstep %}

{% step %}

#### Add the plugin

{% tabs %}
{% tab title="Next.js" %}
{% code overflow="wrap" %}

```ts
// next.config.ts
import { withWeglot } from "@weglot/translate-react/next";

export default async function () {
  return await withWeglot({}, { sourceRoot: "./app" });
}
```

{% endcode %}
{% endtab %}

{% tab title="Vite" %}
{% code overflow="wrap" %}

```ts
// vite.config.ts
import { defineConfig } from "vite";
import { weglotPlugin } from "@weglot/translate-react/vite";

export default defineConfig({
  plugins: [weglotPlugin({ sourceRoot: "src" })],
});
```

{% endcode %}
{% endtab %}
{% endtabs %}

Then wrap your app with `WeglotProvider`. [See the full setup](https://developers.weglot.com/frameworks-and-ai/react/getting-started).
{% endstep %}
{% endstepper %}
{% endcolumn %}
{% endcolumns %}

## Customize your integration

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4><i class="fa-wordpress">:wordpress:</i></h4></td><td><strong>WordPress</strong></td><td>Hooks, filters and helper functions to customize the plugin.</td><td><a href="https://developers.weglot.com/cms/wordpress/getting-started">https://developers.weglot.com/cms/wordpress/getting-started</a></td></tr><tr><td><h4><i class="fa-feather">:feather:</i></h4></td><td><strong>Craft CMS</strong></td><td>Settings, events and use cases to customize the plugin.</td><td><a href="https://developers.weglot.com/cms/craft-cms/overview">https://developers.weglot.com/cms/craft-cms/overview</a></td></tr><tr><td><h4><i class="fa-js">:js:</i></h4></td><td><strong>JavaScript snippet</strong></td><td>Options, functions and link hooks of the JavaScript library.</td><td><a href="https://developers.weglot.com/cms/javascript/javascript">https://developers.weglot.com/cms/javascript/javascript</a></td></tr><tr><td><h4><i class="fa-shopify">:shopify:</i></h4></td><td><strong>Shopify</strong></td><td>Customize the Weglot JavaScript integration on your Shopify theme.</td><td><a href="https://developers.weglot.com/cms/integrations/shopify">https://developers.weglot.com/cms/integrations/shopify</a></td></tr><tr><td><h4><i class="fa-server">:server:</i></h4></td><td><strong>Proxy</strong></td><td>Headers Weglot sends to your original website.</td><td><a href="https://developers.weglot.com/cms/proxy/headers">https://developers.weglot.com/cms/proxy/headers</a></td></tr></tbody></table>

{% hint style="info" icon="sparkle" %}
**Coming soon**: the Weglot MCP server, to add Weglot to your project and manage your translations from your LLM, and the reference for the new Weglot API 2.0.
{% endhint %}

<h2 align="center">Join the Weglot developer community</h2>

<p align="center">Ask questions, share feedback and follow what we build.</p>

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4><i class="fa-slack">:slack:</i></h4></td><td><strong>Slack community</strong></td><td>Join our Slack to ask questions, share feedback and get tips from the Weglot team and other developers.</td><td><a href="https://inviter.co/weglot" class="button secondary">Join Slack</a></td><td><a href="https://inviter.co/weglot">https://inviter.co/weglot</a></td></tr><tr><td><h4><i class="fa-github">:github:</i></h4></td><td><strong>GitHub</strong></td><td>Browse the source of our plugins and libraries, report issues and contribute.</td><td><a href="https://github.com/weglot" class="button secondary">Go to GitHub</a></td><td><a href="https://github.com/weglot">https://github.com/weglot</a></td></tr></tbody></table>


# CMS & integrations

Weglot plugins and integrations for CMS and websites.

Guides and references for the Weglot plugins and integrations:

* [**WordPress**](/cms/wordpress/getting-started): plugin settings, helper functions, hooks and filters, use cases.
* [**Craft CMS**](/cms/craft-cms/overview): plugin installation, settings, use cases and troubleshooting.
* [**JavaScript**](/cms/javascript/javascript): options, functions and link hooks of the JavaScript library.
* [**Shopify**](/cms/integrations/shopify): Shopify uses the JavaScript integration.
* [**Proxy**](/cms/proxy/headers): headers sent by Weglot to your original website.

To call Weglot over HTTP, see the [API Reference](https://developers.weglot.com/api-reference/1.0).

## Community

Join the [**Weglot Community**](https://inviter.co/weglot) Slack to share feedback and get tips.


# Requirements

## Requirements

Before installing Weglot, make sure your environment meets the minimum requirements. They depend on the plugin version you're running.

### Weglot 6.1 and later

| Requirement              | Minimum | Tested up to |
| ------------------------ | ------- | ------------ |
| WordPress                | 5.9     | 7.0          |
| PHP                      | 7.4     | —            |
| WooCommerce *(optional)* | 4.0     | 9.5          |

### Weglot before 6.1

| Requirement              | Minimum | Tested up to |
| ------------------------ | ------- | ------------ |
| WordPress                | 4.5     | 6.9          |
| PHP                      | 7.4     | —            |
| WooCommerce *(optional)* | 4.0     | 9.5          |

{% hint style="info" %}
WooCommerce is only required if you translate a WooCommerce store.
{% endhint %}

{% hint style="success" %}
**Next step:** once your environment is ready, follow the [Getting Started](/cms/wordpress/getting-started) guide to install and configure the plugin.
{% endhint %}


# Getting Started

Starting with the Weglot WordPress plugin

## Getting Started

### Introduction

Weglot has built a powerful WordPress plugin that integrates in your WordPress website and make it multilingual in a few minutes.

What does Weglot plugin do exactly ?

1. It creates URL for each languages, like `/fr/about/` or `/es/about/` for instance (but doesn't create actual pages in WordPress backend)
2. On these URL, it returns the translated content
3. It adds a language button on the page and the `hreflang` tags in the `<head>` section of your page for SEO.

### Getting started

To start, install [Weglot Translate](https://wordpress.org/plugins/weglot/) plugin directly from the directory.

In the settings page, configure the 3 mandatory settings :

* **API Key** : You get an API key in your account. If you don't have one, you can [create your account](https://dashboard.weglot.com/register-wordpress).
* **Original Language** : The original language of your WordPress website.
* **Destination Languages** : The languages you want your website to be translated into.

Save the settings and you are done. You will see the language button appear on your website.

{% hint style="success" %}
**Next step:** head over to [Plugin settings](/cms/wordpress/plugin-settings) to control what gets translated (emails, search, specific URLs or blocks) and customize the language switcher.
{% endhint %}


# Plugin settings

## Plugin settings

Once the plugin is set up, a few built-in options let you fine-tune **what** gets translated and **how** the language switcher looks. You'll find them in the plugin's **Advanced** and **Appearance** tabs.

### Translate emails

When enabled, Weglot translates the emails sent by WordPress (through the `wp_mail` function) — both the **subject** and the **body** — into the language of the visitor who triggered them. Typical examples are a WooCommerce order confirmation or a contact-form notification sent to your customer.

The visitor's language is detected from the current request, or from the page they were on when the email was sent.

{% hint style="info" %}
Emails sent to your **site admin address are not translated** by default — they stay in your original language, which is usually what you want for internal notifications.
{% endhint %}

### Translate search

When enabled, your visitors can search your site in their own language. Weglot translates their search term back into your original language, runs the WordPress search on your original content, and returns the results translated.

This means you don't need to store translated content in your database for search to work.

### Exclude URLs

By default, every page of your site is translated. Use **Exclude URLs** to leave some pages untranslated. Rules are managed from your Weglot dashboard and support several matching modes:

* **Contains** — the path contains a given text (default)
* **Is exactly** — the path matches exactly
* **Starts with** / **Ends with**
* **Matches regex** — for advanced patterns

For example, to translate **only your homepage** (exclude every path except `/`), use a "Matches regex" rule with: `[^/]`

{% hint style="info" %}
Rules are matched against the URL **path** only — the query string (everything after `?`) is ignored.
{% endhint %}

### Exclude blocks

Sometimes you want to keep part of a page untranslated — a customer-review area, a code snippet, a brand name. With **Exclude blocks** you provide a CSS selector, and Weglot adds a `data-wg-notranslate` attribute to the matching element. Everything inside it is left as-is.

For example, excluding `.product-description` produces:

```markup
<h1 class="product-title">Mon super article</h1> <!-- translated -->
<p class="product-description" data-wg-notranslate>My awesome article</p> <!-- not translated -->
```

### Language switcher

Weglot adds a language button to your site. From the **Appearance** tab you can customize how it looks:

* **Dropdown or inline** — show the languages in a dropdown menu or side by side
* **With flags** — show a flag next to each language, and choose its shape: rectangle (mat or shiny), square or circle
* **With name** — show the language name, either its full local name (e.g. *Français*) or its ISO code (e.g. *FR*)
* **Custom CSS** — override the switcher's styling with your own rules

#### Positioning the switcher

You can place the language button wherever you want:

* **Default** — automatically added at the bottom-right of every page
* **In a menu** — add a "Weglot Translate" item from *Appearance → Menus*
* **In a widget area** — from *Appearance → Widgets*
* **Anywhere via shortcode** — drop `[weglot_switcher]` into a page, post or template


# Helpers Functions

All Weglot functions you can call in WordPress to get informations

## Helpers Functions

Weglot plugin is exposing functions that can be called in your code.

To see the source code of all available functions, you can go to the file : **weglot-functions.php.**

{% hint style="warning" %}
Make sure your plugin's version is > 3.0
{% endhint %}

#### weglot\_get\_service

```php
weglot_get_service( string $service )
```

Return a Weglot service.

#### weglot\_get\_options

```php
weglot_get_options()
```

Return all Weglot options.

#### weglot\_get\_option

```php
weglot_get_option( string $key )
```

Return Weglot option by key.

#### weglot\_get\_original\_language

```php
weglot_get_original_language()
```

Return the original language code (2-letter internal code, e.g. `en`).

#### weglot\_get\_current\_language

```php
weglot_get_current_language()
```

Return the current language **internal** code (2-letter code, e.g. `en`). This is the code Weglot uses internally, not the one that may appear in your URLs.

#### weglot\_get\_current\_language\_custom

```php
weglot_get_current_language_custom()
```

Return the current language **external** code — the custom language code configured in your Weglot dashboard (falls back to the standard code when none is set). Use this when you need the code as it appears to your visitors.

{% hint style="info" %}
`weglot_get_current_language_code_from_custom_language()` is an alias that returns the exact same value.
{% endhint %}

#### weglot\_get\_destination\_languages

```php
weglot_get_destination_languages()
```

Return an array of public destination language keys.

#### weglot\_get\_request\_url\_service

```php
weglot_get_request_url_service()
```

Return weglot request URL service.

#### weglot\_get\_languages\_available

```php
weglot_get_languages_available()
```

Return an array of all languages objects available.

#### weglot\_get\_button\_selector\_html

```php
weglot_get_button_selector_html( string $add_class = '' )
```

Return the language's selector button HTML in string format.

#### weglot\_get\_exclude\_urls

```php
weglot_get_exclude_urls()
```

Return an array of all excluded URLs.

#### weglot\_get\_translate\_amp\_translation

```php
weglot_get_translate_amp_translation()
```

Return `true` if amp pages translation is activated.

#### weglot\_get\_current\_full\_url

```php
weglot_get_current_full_url()
```

Return a string of current URL.

#### weglot\_create\_url\_object

```php
weglot_create_url_object( string $url )
```

Return a `Weglot\Util\Url` object for the given URL. Call `->getForLanguage( $language )` on it to get the URL translated into a specific language.

#### weglot\_is\_eligible\_url

```php
weglot_is_eligible_url( string $url )
```

Return `true` if `$url` is an eligible URL.

#### weglot\_get\_api\_key

```php
weglot_get_api_key()
```

Return a string of private API key.

#### weglot\_has\_auto\_redirect

```php
weglot_has_auto_redirect()
```

Return `true` if redirect users based on their browser language option is activated.

#### weglot\_get\_full\_url\_no\_language

```php
weglot_get_full_url_no_language()
```

Return a string of current URL without the language key.

#### weglot\_get\_postid\_from\_url

```php
weglot_get_postid_from_url()
```

Return the WordPress post ID matching the current URL, or `0` if none is found.

#### weglot\_get\_rest\_current\_url\_path

```php
weglot_get_rest_current_url_path()
```

Return a string of rest current URL path.


# Hooks

All filters exposed by Weglot


# Translations Hooks

WordPress Filters relating to detecting & translating words

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\Parser\Definitions\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;
}
```

{% hint style="warning" %}
Add the class to `$dom_checkers` **outside** the `class_exists()` check. The filter can run several times in the same request (emails, PDF invoices, cart fragments): inside the check, the class would only be added the first time.
{% endhint %}

**Removing a checker**

Some attributes Weglot detects by default may not make sense on your site. A common case is a `data-value` holding a slug that your JavaScript compares against: translating it silently breaks the filtering, while the visible label still has to be translated.

The same filter removes checkers — return the array without the classes you do not want.

```php
<?php

add_filter( 'weglot_get_dom_checkers', 'custom_weglot_remove_dom_checker' );
function custom_weglot_remove_dom_checker( $dom_checkers ) {
	return array_diff( $dom_checkers, array( '\WeglotWP\Domcheckers\Button_Data_Value' ) );
}
```

Pass as many classes as you need:

```php
<?php

add_filter( 'weglot_get_dom_checkers', 'custom_weglot_remove_dom_checkers' );
function custom_weglot_remove_dom_checkers( $dom_checkers ) {
	$remove = array(
		'\WeglotWP\Domcheckers\Button_Data_Value',
		'\WeglotWP\Domcheckers\Video_Source',
		'\WeglotWP\Domcheckers\Meta_Twitter',
	);

	return array_diff( $dom_checkers, $remove );
}
```

**Checkers you can remove**

`$dom_checkers` holds the checkers added by the WordPress plugin. These are the ones you can remove:

| Class                                       | Tag                                    | Attribute translated |
| ------------------------------------------- | -------------------------------------- | -------------------- |
| `\WeglotWP\Domcheckers\Button_Data_Value`   | `button`                               | `data-value`         |
| `\WeglotWP\Domcheckers\Button_Value`        | `button`                               | `value`              |
| `\WeglotWP\Domcheckers\Input_Reset`         | `input[type="reset"]`                  | `value`              |
| `\WeglotWP\Domcheckers\Link_Data_Href`      | `a`                                    | `data-href`          |
| `\WeglotWP\Domcheckers\Video_Source`        | `video source`, `video`                | `src`                |
| `\WeglotWP\Domcheckers\Meta_Facebook_Image` | `meta og:image`                        | `content`            |
| `\WeglotWP\Domcheckers\Meta_Twitter_Image`  | `meta twitter:image`                   | `content`            |
| `\WeglotWP\Domcheckers\Meta_Twitter`        | `meta twitter:card`, `site`, `creator` | `content`            |

{% hint style="info" %}
The parser library loads its own checkers (`Text`, `ImageAlt`, `Placeholder`, `LinkHref`, `LinkTitle`, `Button`, …) before this filter runs, so they are **not** part of `$dom_checkers` and cannot be removed this way.

In particular, the inner text of your elements is detected by the library's `Text` checker. Removing a checker only ever stops an **attribute** from being translated — the visible text of the element keeps being translated.
{% endhint %}

{% hint style="warning" %}
A class name that does not match exactly is ignored without any error: `array_diff` finds nothing and the checker stays active. Keep the leading backslash and the exact casing (`Button_Data_Value`, not `Button_DataValue`).

To see the list actually handed to the parser, log it from a filter registered with a later priority:

```php
add_filter( 'weglot_get_dom_checkers', function ( $checkers ) {
	error_log( 'Weglot DOM checkers: ' . implode( ', ', $checkers ) );
	return $checkers;
}, 99 );
```

{% endhint %}

#### 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 inline tags (`strong`, `em`, `abbr`…) the parser keeps inside the surrounding sentence instead of handling them as separate nodes: their text is sent for translation together with the sentence, as one string. 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;
}
```

{% hint style="info" %}
This list is only used when the project runs translation engine 2. Engine 3 (the default) keeps inline tags inside the sentence by itself, and engine 1 (legacy API keys) does not use the list.
{% endhint %}

### 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 (this version replaces the function above, keep only one of them):

```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 is empty by default: "name", "description" and HTML values are always translated
    $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 its key is exactly `redirecturl`, `url` or `link`. Keys are case-sensitive: `redirectURL` is not rewritten. 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/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** (add `redirectURL` there to have it rewritten too).

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_list_json_ld_keys' );
function custom_weglot_list_json_ld_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       |

The lists only take effect once their toggle is on: `weglot_escape_attributes` needs `weglot_escape_attribute_in_html` (HTML pages) or `weglot_escape_attribute_in_json` (JSON responses), and the four `weglot_escape_script_*` lists need `weglot_escape_script_templates`.

```php
<?php

// Never translate the value of placeholder attributes
add_filter( 'weglot_escape_attributes', function( $attributes ) {
    $attributes[] = 'placeholder';
    return $attributes;
} );

// Required: turn the attribute escape on for HTML pages
add_filter( 'weglot_escape_attribute_in_html', '__return_true' );
```

### 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. Excluding blocks from dynamic translation**

`weglot_excluded_blocks_selectors` lists the blocks the JavaScript engine must leave untranslated, using the same `['value' => '…']` shape as the selectors above.

Since Weglot 6.3 it defaults to `[ ['value' => 'address'] ]`. Postal addresses rendered client-side — the WooCommerce block cart and block checkout, for instance — never go through the PHP parser, so the server-side `address` exclusion cannot reach them.

```php
add_filter( 'weglot_excluded_blocks_selectors', function( $blocks ) {
    $blocks[] = [ 'value' => '.customer-reviews' ];
    return $blocks;
} );
```

Return an empty array to translate everything, `<address>` tags included.

{% hint style="info" %}
Unlike the server-side `weglot_exclude_blocks`, which a non-empty `weglot_parser_whitelist` disables entirely, these client-side exclusions still apply **inside** whitelisted and dynamic blocks. That is what makes the `address` default effective on the WooCommerce checkout even though `.wc-block-checkout` is whitelisted.
{% endhint %}

**7. 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, and only below `weglot_length_replace_tags`, which skips longer tags first |
| `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                                                                                                         |


# Dynamic translation loading

Control when and how the Weglot JavaScript library is loaded

When dynamic translation is enabled, Weglot loads `weglot.min.js` from its CDN in `wp_head` and calls `Weglot.initialize()` immediately. These two filters let you change **when** that happens, or skip it altogether, to reduce the impact on page-load metrics.

{% hint style="info" %}
Both filters on this page are available since Weglot 6.3.
{% endhint %}

Both only apply when `weglot_translate_dynamics` returns `true`. See [Translations Hooks](/cms/wordpress/filters/translations-filters) for the selectors and URL configuration that go with it.

{% hint style="warning" %}
Both filters are ignored when `weglot_autoredirect_js` returns `true`. In that mode the JavaScript library performs the browser-language redirect from the original-language page, so it can neither be skipped nor deferred without breaking the redirect.
{% endhint %}

#### weglot\_load\_dynamics\_in\_original\_language

| Argument | Type | Default |
| -------- | ---- | ------- |
| `$load`  | bool | `true`  |

Return `false` to skip loading the library entirely while the visitor is on the original-language page. Translated pages are unaffected.

Use it when your dynamic content only needs translating on translated URLs — the original language does not need the library to display its own content.

```php
<?php

add_filter( 'weglot_load_dynamics_in_original_language', '__return_false' );
```

#### weglot\_defer\_dynamics\_js

| Argument | Type | Default |
| -------- | ---- | ------- |
| `$defer` | bool | `false` |

Return `true` to load `weglot.min.js` with the `defer` attribute and move `Weglot.initialize()` into the script's `load` handler, so it no longer blocks rendering in `wp_head`.

```php
<?php

add_filter( 'weglot_defer_dynamics_js', '__return_true' );
```

This filter is opt-in on purpose. Deferring widens the window during which dynamic content can appear untranslated: the library starts parsing later, so content injected early by other scripts may be visible in the original language for a moment before being translated.

Enable it when you are optimising Core Web Vitals and can accept that trade-off; leave it off if a brief flash of untranslated dynamic content is not acceptable.

#### Using both

The two filters combine: skip the library in the original language, and defer it everywhere else.

```php
<?php

add_filter( 'weglot_translate_dynamics', '__return_true' );
add_filter( 'weglot_load_dynamics_in_original_language', '__return_false' );
add_filter( 'weglot_defer_dynamics_js', '__return_true' );
```


# Host & URL Hooks

WordPress Filters relating to the host Weglot uses to build URLs, hreflang tags and the language switcher

Weglot needs to know the **public host** of the current request to build the language switcher links, the `hreflang` tags, and to decide whether a link is internal and should be rewritten with the language prefix.

By default it reads the `Host` header sent by the browser, which is correct on the vast majority of sites. You do not need any of the filters on this page unless your site sits behind a **reverse proxy**.

#### When you need these filters

Behind a reverse proxy (a CDN, a load balancer, or a hosting setup that fronts your origin with an internal domain), the origin server does not receive the public domain in the `Host` header — it receives its own internal hostname. The public domain is carried by the `X-Forwarded-Host` header instead.

When that happens, WordPress keeps working normally, because `home`, `siteurl` and the canonical URLs are stored in the database. But Weglot resolves the host from the request, so you see:

* language switcher links pointing to the internal domain,
* `hreflang` tags pointing to the internal domain,
* internal absolute links not getting the language prefix.

A typical symptom is a page whose canonical URL is right while the switcher and `hreflang` are wrong.

{% hint style="warning" %}
On a WordPress multisite, do not try to fix this by editing the `domain` column of the `wp_blogs` table. WordPress uses that value to resolve which site the incoming request belongs to, so changing it breaks site resolution and causes a redirect loop.
{% endhint %}

#### weglot\_use\_forwarded\_host

Tells Weglot to read the public host from the `X-Forwarded-Host` header instead of `Host`.

{% hint style="info" %}
Available since Weglot 6.3.
{% endhint %}

| Argument              | Type | Description                                  |
| --------------------- | ---- | -------------------------------------------- |
| $use\_forwarded\_host | bool | `false` by default. Return `true` to opt in. |

**Use case**

Your site is served on `example.com`, but the origin receives an internal hostname and the public domain arrives in `X-Forwarded-Host`.

```php
<?php

add_filter( 'weglot_use_forwarded_host', '__return_true' );
```

If the header is absent on a given request, Weglot falls back to the `Host` header, so the filter is safe to leave enabled.

When several proxies are chained, `X-Forwarded-Host` can contain a comma-separated list such as `example.com, internal.host`. Weglot keeps the first entry, which is the host the visitor actually requested.

{% hint style="danger" %}
`X-Forwarded-Host` is a header sent by the client. Only enable this filter if your proxy **overwrites** it on every incoming request. If the proxy forwards a client-supplied value untouched, a visitor can inject any domain — and if your site uses a page cache, the poisoned links can then be served to everyone else.
{% endhint %}

#### weglot\_server\_host

Forces the host directly, whatever the request headers contain. Use it when no header carries the public domain, or when you prefer not to trust `X-Forwarded-Host`.

{% hint style="info" %}
Available since Weglot 6.3.
{% endhint %}

| Argument | Type   | Description                                |
| -------- | ------ | ------------------------------------------ |
| $host    | string | The host resolved from the request headers |

**Use case**

```php
<?php

add_filter( 'weglot_server_host', function ( $host ) {
    return 'example.com';
} );
```

Return the host name only — no scheme, no trailing slash, no path.

This filter is applied last, so it overrides `weglot_use_forwarded_host`. It is the most reliable option when your public domain is a fixed, known value.

#### weglot\_check\_link\_server\_host

Overrides the host used for one specific decision: whether an absolute link found in the page is internal (and must be rewritten with the language prefix) or external (and must be left alone).

This filter is not new — it has existed for several versions and was simply undocumented until now.

| Argument      | Type   | Description                               |
| ------------- | ------ | ----------------------------------------- |
| $server\_host | string | The host resolved for the current request |

In most cases `weglot_server_host` is what you want, since it covers link rewriting along with the switcher and the `hreflang` tags. Reach for `weglot_check_link_server_host` only when you need link rewriting to use a different host from the rest of the page.

```php
<?php

add_filter( 'weglot_check_link_server_host', function ( $server_host ) {
    return 'example.com';
} );
```


# Language Switcher Hooks

WordPress Filters relating to the language switcher scripts served by the Weglot CDN

When your project uses a switcher template, Weglot loads the corresponding script from `cdn.weglot.com`:

```html
<script id="weglot-switcher-underline_edge-js" src="https://cdn.weglot.com/switchers/underline_edge.812411f0d5ee3549e026c42e4ccb6166888df6a4.min.js"></script>
```

{% hint style="info" %}
Subresource Integrity on the switcher scripts, and the filter that disables it, are available since Weglot 6.3. Earlier versions render the script tag without an `integrity` attribute.
{% endhint %}

#### Integrity of the scripts served by the CDN

The long hexadecimal string in the filename is a **cache-busting** identifier. It tells the CDN which build to serve, and it lets that file be cached forever — the CDN answers with `cache-control: public, max-age=31536000`, and a new build always gets a new filename. It does **not** let the browser verify the bytes it received.

That verification is what [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) (SRI) provides, and Weglot enables it for you. Alongside each template hash, `https://cdn.weglot.com/switchers/versions.json` publishes a SHA-384 digest:

```json
{
  "name": "underline_edge",
  "hash": "812411f0d5ee3549e026c42e4ccb6166888df6a4",
  "integrity": "sha384-CZNjAG4i1RQE7vG/pwnVcrKXI07L/LiE1Yh74wEJ7apQRJDDTLqMguiMHo+rSxTf"
}
```

The plugin reads that digest and renders it on the tag, together with the `crossorigin` attribute SRI requires:

```html
<script integrity="sha384-CZNjAG4i1RQE7vG/pwnVcrKXI07L/LiE1Yh74wEJ7apQRJDDTLqMguiMHo+rSxTf" crossorigin="anonymous" id="weglot-switcher-underline_edge-js" src="https://cdn.weglot.com/switchers/underline_edge.812411f0d5ee3549e026c42e4ccb6166888df6a4.min.js"></script>
```

The browser then hashes the file it downloaded and refuses to execute it if the digest does not match. You do not have to configure anything — this is on by default.

{% hint style="info" %}
The digest is only attached when the build your project points to is the one currently published in `versions.json`. A project pinned to an older template build gets no `integrity` attribute, because the digest would belong to a different file and the browser would reject a perfectly legitimate script.
{% endhint %}

#### weglot\_switcher\_sri\_enabled

Disables the `integrity` and `crossorigin` attributes on the switcher scripts.

| Argument | Type   | Description                                       |
| -------- | ------ | ------------------------------------------------- |
| $enabled | bool   | `true` by default. Return `false` to disable SRI. |
| $handle  | string | Handle of the script being rendered               |

SRI fails closed: when the digest does not match the bytes received, the browser drops the script entirely and falls back to nothing — the language switcher simply does not appear, and the only trace is a message in the browser console.

In practice this happens when something between Weglot and the browser rewrites the script after the tag has been generated. Front-end optimization plugins that proxy or re-serve external scripts from their own domain are the usual cause.

**Use case**

Turn it off everywhere:

```php
<?php

add_filter( 'weglot_switcher_sri_enabled', '__return_false' );
```

Or only for a given template, keeping the protection on the others:

```php
<?php

add_filter( 'weglot_switcher_sri_enabled', function ( $enabled, $handle ) {
    return 'weglot-switcher-default' !== $handle;
}, 10, 2 );
```

{% hint style="warning" %}
Only reach for this filter if you have confirmed in the browser console that a switcher script is being blocked for an integrity mismatch. Disabling SRI removes the guarantee that the script executed by your visitors is the one Weglot published.
{% endhint %}


# Page builders

Keep Weglot out of page builder editors and previews

Page builders edit and preview content in the original language, from the front end. Weglot must stay out of those requests: the builder would otherwise display translated markup, and could save it back as source content.

Weglot recognises them from the query string. When one of the parameters below is present in the URL with a non-empty value, Weglot does not register its front-end hooks at all — the page is served untranslated and no language switcher is injected.

These parameters are excluded by default, so those builders need no configuration:

| Parameter                | Page builder | Excluded since   |
| ------------------------ | ------------ | ---------------- |
| `elementor-preview`      | Elementor    | earlier versions |
| `_breakdance_doing_ajax` | Breakdance   | earlier versions |
| `in-front-editor`        | Brizy        | 6.3              |
| `is-editor-iframe`       | Brizy        | 6.3              |
| `brizy_media`            | Brizy        | 6.3              |

Values PHP treats as falsy — an empty string, or `0` — do not trigger the exclusion.

#### weglot\_page\_builder\_query\_params

Use this filter to support a builder that is not listed, or to drop an entry that conflicts with another plugin.

{% hint style="info" %}
Available since Weglot 6.3. On earlier versions the list is hard-coded and cannot be extended.
{% endhint %}

| Argument        | Type  | Description                                            |
| --------------- | ----- | ------------------------------------------------------ |
| `$query_params` | array | Query parameter names that disable Weglot when present |

**Add a page builder**

Append the query parameter the builder sets while editing:

```php
<?php

add_filter( 'weglot_page_builder_query_params', 'custom_weglot_page_builder_params' );
function custom_weglot_page_builder_params( $query_params ) {
    $query_params[] = 'ct_builder'; // Oxygen.
    return $query_params;
}
```

Several at once:

```php
<?php

add_filter( 'weglot_page_builder_query_params', function( $query_params ) {
    return array_merge( $query_params, array( 'bricks', 'brx_preview' ) );
} );
```

**Remove a parameter**

`in-front-editor` and `is-editor-iframe` are not prefixed by their plugin. If another plugin uses one of those names on public URLs, translation would be skipped there. Remove the entry rather than patching Weglot:

```php
<?php

add_filter( 'weglot_page_builder_query_params', function( $query_params ) {
    return array_values( array_diff( $query_params, array( 'is-editor-iframe' ) ) );
} );
```

**Finding the right parameter**

Open a page in the builder's editor and look at the URL of the editing frame. The parameter the builder adds there — often the one carrying the post ID, or an `ajax`/`preview` flag — is the one to declare. Parameters are matched exactly, and the filter must return an array of strings.

{% hint style="info" %}
To disable Weglot whenever a builder is loaded, and not only inside its editor, see [Deactivate Weglot on Elementor](/cms/wordpress/use-cases/deactivate-weglot-on-elementor).
{% endhint %}


# Use cases


# Lang attribute

Modify the lang attribute on html tag

You can modify your own `lang` attribute (or any other element in the DOM) using the `weglot_render_dom` filter.

```php
add_filter( 'weglot_render_dom', 'prefix_weglot_render_dom' );
function prefix_weglot_render_dom( $dom ) {
	$dom = str_replace( 'lang="en-US"', 'lang="en-US-wg"', $dom );
	return $dom;
}
```


# Translate link

Add method to translate specifix link

By default, Weglot translates links based on a set of built-in patterns. In the example below, we want to translate the URL held in a `data-link2` attribute. We use the `weglot_get_replace_modify_link` filter to register a new pattern, then provide the function that rewrites it.

```php
add_filter( 'weglot_get_replace_modify_link', 'custom_weglot_get_replace_modify_link' );
function custom_weglot_get_replace_modify_link( $data ) {
	$data['datalink2'] = '/<([^\>]+?)?data-link2=(\"|\')([^\s\>]+?)(\"|\')([^\>]+?)?>/';
	return $data;
}

function replace_datalink2( $translated_page, $current_url, $quote1, $quote2, $sometags = null, $sometags2 = null ) {
	$request_url_services = weglot_get_service( 'Request_Url_Service_Weglot' );
	$replace_url_Service = weglot_get_service( 'Replace_Link_Service_Weglot' );
	$current_language = $request_url_services->get_current_language();
	$translated_page  = preg_replace( '/<' . preg_quote( $sometags, '/' ) . 'data-link2=' . preg_quote( $quote1 . $current_url . $quote2, '/' ) . '/', '<' . $sometags . 'data-link2=' . $quote1 . $replace_url_Service->replace_url( $current_url, $current_language ) . $quote2, $translated_page );
	return $translated_page;
}
```

{% hint style="info" %}
**How the pattern maps to a function.** Each key you add to the `$data` array (here `datalink2`) is resolved to a global function named `replace_<key>` (here `replace_datalink2`). Weglot calls it for every match with these arguments, in order: `$translated_page`, `$current_url`, `$quote1`, `$quote2`, `$sometags`, `$sometags2`. Your function must return the (possibly modified) page. You can change the resolved function name with the `weglot_modify_link_replace_function` filter.
{% endhint %}


# How Weglot handles link translation and exclusions

Weglot automatically translates both the **URL** of a link and its **text label**, based on the current language. This page explains the default behavior and how to control each part independently.

### Default behavior

Take this link:

```html
<a id="my-link" href="https://weglot.com" title="Weglot website">this is my link label</a>
```

On the French version of your site, Weglot outputs:

```html
<a id="my-link" href="https://weglot.com/fr/" title="Weglot website">ceci est le label de mon lien</a>
```

* The **label** (`this is my link label`) is translated.
* The **URL** is automatically adapted to include the language code (`/fr/`).

### Excluding a link from translation

If you exclude the link (for example with the `#my-link` selector in your exclusion rules), the **label stays untranslated** — but the **URL is still adapted** to include the language code:

```html
<a id="my-link" href="https://weglot.com/fr/" title="Weglot website">this is my link label</a>
```

This is expected: excluding a block prevents its text from being translated, while link URLs are rewritten by a separate mechanism.

### Keep the URL untranslated but still translate the label

Sometimes you want the opposite: keep the link URL exactly as-is (no language code) while still translating the label. Add the `wg-excluded-link` attribute to the tag:

```html
<a id="my-link" href="https://weglot.com" title="Weglot website" wg-excluded-link>this is my link label</a>
```

Result in French:

```html
<a id="my-link" href="https://weglot.com" title="Weglot website">ceci est le label de mon lien</a>
```

* The URL stays `https://weglot.com` (no `/fr/`).
* The label is still translated.

Use this when a specific URL must stay untouched (an external tracking link, a file, a third-party endpoint…) while still giving your visitors a localized link text.


# Implementing Custom Link Translation

By default, Weglot translates links based on built-in patterns. In some cases you may want to build a translated link yourself. Below is an example that returns the URL of a WooCommerce product in the current language. You can adapt it further — for instance to target a specific language instead of the current one.

```php
function weglot_get_current_full_product_by_id( $product_id ) {
	$post = get_post( $product_id );
	if ( ! $post || $post->post_type !== 'product' ) {
		return '';
	}
	$product_url = get_permalink( $product_id );
	return weglot_create_url_object( $product_url )->getForLanguage( weglot_get_request_url_service()->get_current_language() );
}
echo weglot_get_current_full_product_by_id( 17 );
```


# Wp-rocket Lazyload

Modify attr when Lazyloading is activate on wp-rocket plugins

When lazy-loading is enabled (for example by WP Rocket), image URLs are stored in `data-lazy-src` / `data-lazy-srcset` attributes instead of `src` / `srcset`. You can tell the Weglot parser to detect and translate those attributes with the `weglot_get_dom_checkers` filter.

```php
add_filter( 'weglot_get_dom_checkers', 'weglot_dom_check_data_lazy_src' );
function weglot_dom_check_data_lazy_src( $dom_checkers ) {

	if ( ! class_exists( 'Img_Data_Lazy_Src' ) ) {
		class Img_Data_Lazy_Src extends Weglot\Parser\Check\Dom\AbstractDomChecker {
			const DOM       = 'img';
			const PROPERTY  = 'data-lazy-src';
			const WORD_TYPE = Weglot\Parser\Definitions\Enum\WordType::IMG_SRC;
		}
	}
	$dom_checkers[] = '\Img_Data_Lazy_Src';

	if ( ! class_exists( 'Source_Data_Lazy_SrcSet' ) ) {
		class Source_Data_Lazy_SrcSet extends Weglot\Parser\Check\Dom\AbstractDomChecker {
			const DOM       = 'source';
			const PROPERTY  = 'data-lazy-srcset';
			const WORD_TYPE = Weglot\Parser\Definitions\Enum\WordType::IMG_SRC;
		}
	}
	$dom_checkers[] = '\Source_Data_Lazy_SrcSet';

	return $dom_checkers;
}
```

{% hint style="info" %}
Add each class to `$dom_checkers` **outside** the `class_exists()` check: the filter can run several times in the same request (emails, PDF invoices, cart fragments), and the checker must be added every time.

Since Weglot 6.3 these classes live under `Weglot\Parser\…`. Snippets written with the older `Weglot\Client\Api\Enum\WordType` keep working.
{% endhint %}


# Deactivate Weglot on Elementor

Deactivate Weglot (translate and add swtcher(s)) when you're on elementor webview

Weglot also runs inside Elementor's editor and preview (translating content and injecting switchers), which is not always desirable. To disable Weglot while Elementor is loaded, hook `elementor/init` and turn translation off:

```php
add_action( 'elementor/init', 'weglot_deactivate_elementor' );
function weglot_deactivate_elementor() {
	add_filter( 'weglot_active_translation', '__return_false' );
}
```


# Weglot translate on Elementor

With this code, we force translation of content generate by elementor using the elementor/frontend/the\_content filter

With the code below, we force the translation of content generated by Elementor, using the `elementor/frontend/the_content` filter.

```php
use Weglot\Parser\Parser;
use Weglot\Parser\ConfigProvider\ServerConfigProvider;

function weglot_content_check( $content ) {

	$request_url_services = weglot_get_service( 'Request_Url_Service_Weglot' );
	$parser_services      = weglot_get_service( 'Parser_Service_Weglot' );
	$generate_switcher    = weglot_get_service( 'Generate_Switcher_Service_Weglot' );
	$replace_url_services = weglot_get_service( 'Replace_Url_Service_Weglot' );
	$current_language     = $request_url_services->get_current_language()->getExternalCode();
	$original_language    = weglot_get_original_language();

	$content = $generate_switcher->generate_switcher_from_dom( $content );
	if ( $original_language == $current_language ) {
		return $content;
	}

	$config  = new ServerConfigProvider();
	$client  = $parser_services->get_client();
	$parser  = new Parser( $client, $config, [] );
	$content = $parser->translate( $content, $original_language, $current_language );
	$content = $replace_url_services->replace_link_in_dom( $content );

	return $content;
}
add_action( 'elementor/frontend/the_content', 'weglot_content_check' );
```


# Language Selector Styling

Adding your own CSS code or HTML button

#### Override language selector CSS

You can add your own CSS rules to customize the language button. Weglot automatically adds a button to your page, which is either a dropdown or a list and looks like this:

{% tabs %}
{% tab title="Dropdown" %}

```markup
<aside data-wg-notranslate class="country-selector weglot-dropdown weglot-default weglot-invert">
    <input id="weglot_choice" type="checkbox" name="menu">
    <label for="weglot_choice" class="wgcurrent wg-li weglot-flags flag-0 en" data-code-language="en">
        <span>EN</span>
    </label>
    <ul>
        <li class="wg-li weglot-flags flag-0 fr" data-code-language="fr">
            <a data-wg-notranslate href="http://example.com/">FR</a>
        </li>
    </ul>
</aside>
```

{% endtab %}

{% tab title="List" %}

```markup
<aside data-wg-notranslate class="country-selector weglot-inline weglot-default weglot-invert">
    <input id="weglot_choice" type="checkbox" name="menu">
    <label for="weglot_choice" class="wgcurrent wg-li weglot-flags en" data-code-language="en">
        <span>English</span>
    </label>
    <ul>
        <li class="wg-li weglot-flags fr" data-code-language="fr">
            <a data-wg-notranslate href="http://example.com/fr/">Français</a>
        </li>
    </ul>
</aside>
```

{% endtab %}
{% endtabs %}

You can use these classes to add your own rules. For example, add this in "Override CSS" to make the language name uppercase:

```css
.country-selector a {
    text-transform: uppercase;
}
```

#### Override CSS on the WordPress back office

You can add your custom CSS rules directly from your WordPress back office. To do that, log in to your WordPress and go to: **Weglot > Language button design (Optional) > Override CSS**

#### Override CSS using a WordPress hook

This filter lets you add custom CSS by default, without going through the settings.

```php
<?php

add_filter( 'weglot_css_custom_inline', 'custom_weglot_css_custom_inline' );
function custom_weglot_css_custom_inline( $css_custom ){     
    $css_custom .= '.country-selector { background-color: red; }'; 
    return $css_custom;
}
```

#### Don't load the Weglot CSS file

By default, the Weglot plugin loads the stylesheet `/wp-content/plugins/weglot/dist/css/front-css.css`. If you would prefer not to load it, you can dequeue it with the `wp_enqueue_scripts` action:

```php
<?php

add_action( 'wp_enqueue_scripts', 'custom_weglot_dequeue_style' );
function custom_weglot_dequeue_style() {
    wp_dequeue_style( 'weglot-css' );
}
```

#### Override the language selector HTML markup

The Weglot plugin exposes a filter that lets you modify the HTML structure of your language-switch button. See the reference: [weglot\_button\_html](/cms/wordpress/helpers-functions-1/weglot_button_html).

**Hook parameters**

* `$button_html`: string containing the switcher's HTML before it is rendered.
* `$add_class`: string containing the classes (space-separated) related to the switcher's layout context and options.

**Example: add code before/after the button**

The example below adds HTML before and/or after the button (you can also run `preg_replace()` on the selector's HTML).

```php
<?php

add_filter( 'weglot_button_html', 'custom_weglot_button_html', 10, 2 );
function custom_weglot_button_html( $button_html, $add_class ) {

	$button_html = '<div style="border: 1px solid red;"><p>Choose your language:</p>' . $button_html . '</div>';

	return $button_html;
}
```

**Example: rebuild the language selector from scratch**

If you'd like to make major changes to the HTML structure of your language button, you can start from the code below.

{% hint style="info" %}
This example mirrors the plugin's built-in button. It is a starting point — keep an eye on it across plugin updates, as the internal markup can evolve.
{% endhint %}

```php
<?php

add_filter( 'weglot_button_html', 'custom_weglot_button_html' );
function custom_weglot_button_html( $html, $add_class = '' ) {

	$current_this        = weglot_get_service( 'Button_Service_Weglot' );
	$option_service      = weglot_get_service( 'Option_Service_Weglot' );
	$request_url_service = weglot_get_service( 'Request_Url_Service_Weglot' );
	$amp_service         = weglot_get_service( 'Amp_Service_Weglot' );
	$language_service    = weglot_get_service( 'Language_Service_Weglot' );

	if ( ! $request_url_service->is_eligible_url() ) {
		return '';
	}

	$original_language = weglot_get_original_language();

	$weglot_url           = $request_url_service->get_weglot_url();
	$amp_regex            = $amp_service->get_regex( true );
	$destination_language = weglot_get_destination_languages();

	$current_language = $request_url_service->get_current_language();

	if ( weglot_get_translate_amp_translation() && preg_match( '#' . $amp_regex . '#', $weglot_url->getUrl() ) === 1 ) {
		$add_class .= ' weglot-invert';
	}

	$flag_class  = $current_this->get_flag_class();
	$class_aside = $current_this->get_class_dropdown();

	$button_html = sprintf( '<!--Weglot %s-->', WEGLOT_VERSION );
	$button_html .= sprintf( "<aside data-wg-notranslate class='country-selector %s'>", $class_aside . $add_class );
	if ( ! empty( $original_language ) && ! empty( $destination_language ) ) {
		$current_language_entry = $language_service->get_language_from_internal( $current_language->getInternalCode() );
		$name                   = $current_this->get_name_with_language_entry( $current_language_entry );
		$uniq_id                = 'wg' . uniqid( strtotime( 'now' ) ) . rand( 1, 1000 );
		$button_html            .= sprintf( '<input id="%s" class="weglot_choice" type="checkbox" name="menu"/><label for="%s" class="wgcurrent wg-li weglot-lang weglot-language %s" data-code-language="%s"><span>%s</span></label>', esc_attr( $uniq_id ), esc_attr( $uniq_id ), esc_attr( $flag_class . $current_language->getInternalCode() ), esc_attr( $current_language->getInternalCode() ), esc_html( $name ) );

		$button_html .= '<ul>';

		array_unshift( $destination_language, $original_language );

		foreach ( $language_service->get_original_and_destination_languages( $request_url_service->is_allowed_private() ) as $language ) {

			if ( $language->getInternalCode() === $current_language->getInternalCode() ) {
				continue;
			}

			$link_button = $request_url_service->get_weglot_url()->getForLanguage( $language );
			if ( ! $link_button ) {
				continue;
			}

			$button_html .= sprintf( '<li class="wg-li weglot-lang weglot-language %s" data-code-language="%s">', $flag_class . $language->getInternalCode(), $language->getInternalCode() );
			$name        = $current_this->get_name_with_language_entry( $language );

			if ( $language === $language_service->get_original_language() &&
			     strpos( $link_button, 'wg-choose-original' ) === false && // If not exist
			     ( is_home() || is_front_page() )
			     && $option_service->get_option( 'auto_redirect' )
			) { // Only for homepage
				if ( strpos( $link_button, '?' ) !== false ) {
					$link_button = str_replace( '?', '?wg-choose-original=true', $link_button );
				} else {
					$link_button .= '?wg-choose-original=true';
				}
			}

			$button_html .= sprintf(
				'<a data-wg-notranslate href="%s">%s</a>',
				esc_url( $link_button ),
				esc_html( $name )
			);

			$button_html .= '</li>';
		}

		$button_html .= '</ul>';
	}

	$button_html .= '</aside>';

	return $button_html;
}
```

#### Change the language selector title

If you use the language selector in a menu with the "dropdown" option enabled, the title of the selector in the menu is "**Choose your language**" in English. To change this text, edit the plugin's translation files, or use the following hook:

```php
<?php

add_filter( 'weglot_menu_parent_menu_item_title', 'custom_weglot_menu_parent_menu_item_title' );
function custom_weglot_menu_parent_menu_item_title( $title ) {

	switch ( weglot_get_current_language() ) {
		case 'en':
			$title = 'Choose your language please';
			break;
		case 'fr':
			$title = 'Choisissez votre langue s\'il vous plaît';
			break;
	}

	return $title;
}
```

#### Add the current-menu-item class to the selector in a menu

If you use the language selector in a menu and want the **`current-menu-item`** class to be present on the current page's link in the selector, use the **`weglot_active_current_menu_item`** filter:

```php
<?php

add_filter( 'weglot_active_current_menu_item', '__return_true' );
```

{% hint style="info" %}
When the auto-redirect option is enabled, the original-language link carries a `wg-choose-original` query parameter so visitors can reach the original language without being redirected again. If you rebuild the button yourself (see above), keep that parameter on the original-language link.
{% endhint %}


# Change flag size

Changing the Weglot flag size with CSS

Because Weglot has grouped all flags within a single file (CSS sprite) for performance, changing the flag size on your website can be a bit tricky.

{% hint style="info" %}
The `flag-N` number depends on your flag type: **shiny** = `flag-1`, **square** = `flag-2`, **circle** = `flag-3`. The default **rectangle (mat)** type has no `flag-N` class — target `.weglot-flags` directly in that case.
{% endhint %}

**1st step:** With your browser's code inspector, find the CSS properties that set the global flag size. It depends on your flag settings. In this example (setting: circle flags), the properties are:

```css
.weglot-flags.flag-3 a::before, 
.weglot-flags.flag-3 span::before {
    background-image: url("../images/circular_flag.png");
    width: 24px !important;
    height: 24px !important;
    -webkit-background-size: auto 24px !important;
    background-size: auto 24px !important;
}
```

Override the `width`, `height` and `background-size` properties with the wanted size.

**2nd step:** For each flag, find its `background-position` property and override it. In this example, the `background-position` properties are:

```css
/* For English flag */
.weglot-flags.flag-3.en > a::before, 
.weglot-flags.flag-3.en > span::before {
    background-position: -2520px 0 !important;
}

/* For Portuguese flag */
.weglot-flags.flag-3.pt > a::before, 
.weglot-flags.flag-3.pt > span::before {
    background-position: -4344px 0 !important;
}
```

To override it, calculate the new value with a cross product using the original size (24px), the wanted size and the default `background-position`.

*New background-position = ( Wanted size / Default size ) \* current background-position*

**Example 1: Smallest flags**

**Type of flags:** Circle\
**Languages:** English and Portuguese\
**Wanted size:** 16px \* 16px

```css
/* Customize English flag */
.weglot-flags.flag-3.en > a::before,
.weglot-flags.flag-3.en > span::before {
    background-position: -1680px 0 !important;
}

/* Customize Portuguese flag */
.weglot-flags.flag-3.pt > a::before,
.weglot-flags.flag-3.pt > span::before {
    background-position: -2896px 0 !important;
}

.weglot-flags.flag-3 a::before,
.weglot-flags.flag-3 span::before {
    width: 16px !important;
    height: 16px !important;
    -webkit-background-size: auto 16px !important;
    background-size: auto 16px !important;
}
```

Calculation for English flag: (16/24)\*-2520 = -1680\
Calculation for Portuguese flag: (16/24)\*-4344 = -2896

**Example 2: Biggest flags**

**Type of flags:** Circle\
**Languages:** English and Portuguese\
**Wanted size:** 48px \* 48px

```css
/* Customize English flag */
.weglot-flags.flag-3.en > a::before,
.weglot-flags.flag-3.en > span::before {
    background-position: -5040px 0 !important;
}

/* Customize Portuguese flag */
.weglot-flags.flag-3.pt > a::before,
.weglot-flags.flag-3.pt > span::before {
    background-position: -8688px 0 !important;
}

.weglot-flags.flag-3 a::before,
.weglot-flags.flag-3 span::before {
    width: 48px !important;
    height: 48px !important;
    -webkit-background-size: auto 48px !important;
    background-size: auto 48px !important;
}
```

Calculation for English flag: (48/24)\*-2520 = -5040\
Calculation for Portuguese flag: (48/24)\*-4344 = -8688


# Exclude a Custom Post Type

To avoid adding URLs to the Weglot exclusion list, you can disable the translation of a given post type directly with our hooks. In the example below we exclude the built-in `page` type — replace `'page'` with your own Custom Post Type slug.

The two filters do different jobs, and you need both:

* `weglot_is_eligible_url` marks the URL as not translatable for the language switcher and the `hreflang` tags. On its own, it does **not** stop the page from being translated.
* `weglot_active_translation_before_process` is what keeps the page in its original language: a visitor who reaches a translated URL of such a page is redirected to the original one.

```php
<?php

add_filter( 'weglot_is_eligible_url', 'not_authorize_translation' );
function not_authorize_translation( $eligible ) {
	if ( get_post_type( weglot_get_postid_from_url() ) === 'page' ) {
		return false;
	}
	return $eligible;
}

add_filter( 'weglot_active_translation_before_process', 'check_page_translation' );
function check_page_translation() {
	if ( get_post_type( weglot_get_postid_from_url() ) === 'page' && weglot_get_current_language() !== weglot_get_original_language() ) {
		wp_redirect( weglot_get_request_url_service()->get_full_url() );
		exit;
	}

	return true;
}
```


# Exclude the search page

If you would like to exclude the search page from being translated, you can use the following code:

```php
<?php

add_action( 'pre_get_posts', 'custom_weglot_translated_search_redirect' );
function custom_weglot_translated_search_redirect() {
	if ( ! function_exists( 'weglot_get_original_language' ) || ! function_exists( 'weglot_get_current_language' ) ) {
		return;
	}
	if ( is_search() && ! is_admin() && weglot_get_original_language() != weglot_get_current_language() ) {
		wp_redirect( weglot_get_full_url_no_language(), 301 );
		exit;
	}
}

add_filter( 'weglot_button_html', 'custom_weglot_translated_search_no_selector' );
function custom_weglot_translated_search_no_selector( $button_html ) {
	if ( is_search() && ! is_admin() ) {
		return '';
	}
	return $button_html;
}
```


# Exclude draft or private status post

If you would like to exclude a page that is in draft or private status, you can add the code below:

```php
<?php

add_action( 'pre_get_posts', 'custom_weglot_exclude_draft_private_redirect' );
function custom_weglot_exclude_draft_private_redirect() {
	global $post;
	if ( $post ) {
		$post_status = get_post_status( $post->ID );
		if ( ! function_exists( 'weglot_get_original_language' ) || ! function_exists( 'weglot_get_current_language' ) ) {
			return;
		}
		if ( ( $post_status == 'draft' || $post_status == 'private' ) && ! is_admin() && weglot_get_original_language() != weglot_get_current_language() ) {
			wp_redirect( weglot_get_full_url_no_language(), 301 );
			exit;
		}
	}
}

add_filter( 'weglot_button_html', 'custom_weglot_exclude_draft_private_no_selector' );
function custom_weglot_exclude_draft_private_no_selector( $button_html ) {
	global $post;
	if ( $post ) {
		$post_status = get_post_status( $post->ID );
		if ( ( $post_status == 'draft' || $post_status == 'private' ) && ! is_admin() ) {
			return '';
		}
	}
	return $button_html;
}
```


# Plugin Woocommerce: Translate all email sent to customers

When a WooCommerce order is placed in a translated language, Weglot records that language in the order's metadata (`weglot_language`). The WooCommerce emails related to that order (order confirmation, invoice, etc.) are then translated into the customer's language.

Two conditions must be met:

* The **Translate emails** option is enabled in the Weglot settings.
* The order is linked to a language — orders placed in your original language are not translated.

This behavior is **enabled by default**. If you need to turn it off, use the `weglot_woocommerce_translate_following_mail` filter:

```php
add_filter( 'weglot_woocommerce_translate_following_mail', '__return_false' );
```


# Plugin WooCommerce: Translate Product URLs

By default, Weglot doesn't allow you to translate product URL, you can do it following this

Weglot lets you translate the URL slug of your WooCommerce products directly from the product edit screen: a **Weglot** metabox appears at the bottom of the product page, where you can set a translated slug for each language.

This metabox is available for every public post type except a few that are excluded by default: `attachment`, `shop_order` and `shop_coupon`. You can change that list with the `weglot_url_translate_metabox_post_type_exclude` filter.

For example, to also hide the translated-slug metabox for products:

```php
add_filter( 'weglot_url_translate_metabox_post_type_exclude', 'custom_weglot_metabox_exclude' );
function custom_weglot_metabox_exclude( $excluded ) {
	$excluded[] = 'product';
	return $excluded;
}
```

Or to re-enable it for a post type that is excluded by default (here `shop_coupon`):

```php
add_filter( 'weglot_url_translate_metabox_post_type_exclude', 'custom_weglot_metabox_include' );
function custom_weglot_metabox_include( $excluded ) {
	$index = array_search( 'shop_coupon', $excluded, true );
	if ( $index !== false ) {
		unset( $excluded[ $index ] );
	}
	return $excluded;
}
```


# Use custom language code (URL, lang and hreflang attribute)

Here we explain how to change the default language code. This is useful when you don't like Weglot's default code in the URL and want to replace it with another one.

#### Example: change "zh-tw" to "zh-HK"

Below we change the language code `zh-tw` (Traditional Chinese) into `zh-HK` (Hong Kong Chinese).

```markup
<!-- HTML output by default (Traditional Chinese) -->
<html lang="zh-tw">
    <head>
        <link rel="alternate" hreflang="en" href="https://mysite.com/"/>
        <link rel="alternate" hreflang="zh-tw" href="https://mysite.com/zh-tw/"/>
    </head>
</html>

<!-- HTML output with custom language code (Hong Kong Chinese) -->
<html lang="zh-HK">
    <head>
        <link rel="alternate" hreflang="en" href="https://mysite.com/"/>
        <link rel="alternate" hreflang="zh-HK" href="https://mysite.com/zh-HK/"/>
    </head>
</html>
```

#### Hook to customize the language code

This hook must be loaded **before your theme**, so it cannot live in your `functions.php`. Use one of the two methods below (Code Snippets plugin or an MU-plugin).

The array key is the Weglot language code (`zh-tw` for Traditional Chinese, as listed in your Weglot dashboard), the value is the code you want to use instead. A key that matches no Weglot language is silently ignored.

```php
// Use zh-HK (Hong Kong Chinese) instead of zh-tw (Traditional Chinese)
add_filter( 'weglot_language_code_replace', 'custom_weglot_language_code_replace' );
function custom_weglot_language_code_replace( $replacements ) {
    $replacements['zh-tw'] = 'zh-HK';
    return $replacements;
}

// Optional: keep zh-tw instead of zh-HK on the hreflang tags
add_filter( 'weglot_href_lang', 'custom_weglot_href_lang' );
function custom_weglot_href_lang( $render ) {
    $render = str_replace( 'hreflang="zh-HK"', 'hreflang="zh-tw"', $render );
    return $render;
}
```

#### With the auto-redirect option

If the auto-redirect option is enabled, also map your custom code in the browser-language list with the `weglot_navigator_language` filter. Weglot compares the browser languages with your language codes in lowercase, so map `zh-tw` to `zh-hk`:

```php
add_filter( 'weglot_navigator_language', 'custom_weglot_navigator_language' );
function custom_weglot_navigator_language( $navigator_languages ) {
    $navigator_languages = array();
    if ( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) { // phpcs:ignore
        $navigator_languages = explode( ',', trim( sanitize_text_field( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) );
        foreach ( $navigator_languages as &$navigator_language ) {
            if ( strpos( $navigator_language, ';' ) !== false ) {
                $navigator_language = substr( $navigator_language, 0, strpos( $navigator_language, ';' ) );
            }
            $navigator_language = strtolower( $navigator_language );
            if ( 'zh-tw' === $navigator_language ) {
                $navigator_language = 'zh-hk';
            }
        }
    }
    return $navigator_languages;
}
```

#### How to load it

**Method 1 — Code Snippets plugin:** install [Code Snippets](https://wordpress.org/plugins/code-snippets/), go to *Snippets → Add new*, paste the code (without the `<?php` tag, the plugin adds it) and save.

**Method 2 — MU-plugin:** create `/wp-content/mu-plugins/weglot-language-code-replace.php` and paste the code (with the `<?php` tag).


# Theme OceanWP: Use language selector in the main menu

How to fix the language selector in mobile menu of OceanWP theme

To build its mobile menu, the OceanWP theme duplicates the main menu with modified attributes, which breaks the Weglot switcher there. Add the JavaScript below (via *Code Snippets* or your theme's `functions.php`) to fix the switcher classes in the OceanWP mobile menu.

OceanWP theme: <https://oceanwp.org/>

```php
add_action( 'wp_footer', 'weglotsupport_wpocean_menu' );
function weglotsupport_wpocean_menu() {
    ?>
    <script type="text/javascript">
        /* WEGLOT FIX WP OCEAN MENU */
        jQuery(document).ready(function ($) {
            var weglotMenuDone = false;
            jQuery(document).on('click', '.oceanwp-theme .mobile-menu', function () {
                if (weglotMenuDone) {
                    return;
                }
                jQuery(".sidr-class-weglot-flags").each(function () {
                    if (typeof jQuery(this).attr("class") !== 'undefined') {
                        var element_class = jQuery(this).attr("class");
                        jQuery(this).addClass(element_class.replace(/sidr-class-/g, ''));
                    }
                });
                weglotMenuDone = true;
            });
        });
    </script>
    <?php
}
```


# Theme Avada: Use language selector in the main menu

How to fix the language selector in mobile menu of Avada theme

To build its mobile menu, the Avada theme duplicates the main menu with modified attributes, which breaks the Weglot switcher there. Add the JavaScript below (via *Code Snippets* or your theme's `functions.php`) to copy the switcher classes onto the Avada mobile menu.

Avada theme: <https://avada.theme-fusion.com/>

```php
add_action( 'wp_footer', 'weglotsupport_fix_avada_menu' );
function weglotsupport_fix_avada_menu() {
    ?>
    <script type="text/javascript">
        /* WEGLOT FIX AVADA MENU */
        jQuery(document).ready(function ($) {
            var weglotMenuDone = false;
            jQuery(document).on('click', '.fusion-mobile-menu-icons', function () {
                if (weglotMenuDone) {
                    return;
                }
                jQuery(".menu-item-weglot.menu-item-object-custom").each(function () {
                    if (typeof jQuery(this).attr("id") !== 'undefined') {
                        var id = jQuery(this).attr("id");
                        var str = "menu-item-";
                        var dataId = id.substring(str.length, id.length);
                        jQuery('[data-item-id="' + dataId + '"]').addClass(jQuery(this).attr("class"));
                    }
                });
                weglotMenuDone = true;
            });
        });
    </script>
    <?php
}
```


# LinkedIn Share Post: Translate oEmbed WP URL

Use filter to translate oEmbed WP URL

The data LinkedIn uses for its share preview is not read from the page title but from the WordPress oEmbed endpoint. The filter below translates that oEmbed URL so LinkedIn picks up the translated page:

```php
add_filter( 'weglot_html_treat_page', 'rb_weglot_localise_oembed_url' );
function rb_weglot_localise_oembed_url( $html ) {
    $search           = '/wp-json/oembed';
    $current_language = weglot_get_current_language();
    $default_language = weglot_get_original_language();
    if ( $current_language !== $default_language ) {
        $html = str_replace( $search, "/$current_language/wp-json/oembed", $html );
    }
    return $html;
}
```

Once done, check the result with the [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/).


# Hide button on excluded page

Since the version 3.5 of Weglot plugin, the button is visible even is the page is excluded. Here is how to hide it on excluded page

Since version 3.5, the language button stays visible even on pages you excluded from translation. For example, if you excluded `/fr/contact`, the button still shows on both `/contact` and `/fr/contact`.

To hide the button on excluded pages:

```php
// Add this using the "Code Snippets" plugin or directly in functions.php
add_filter( 'weglot_button_html', 'weglot_button_hide', 10, 3 );
function weglot_button_hide( $html, $classes ) {
    $show_button = weglot_get_service( 'Request_Url_Service_Weglot' )->is_eligible_url( weglot_get_current_full_url() );
    if ( ! $show_button ) {
        return '';
    }
    return $html;
}
```


# Auto switch only for HomePage

Since the version 3.5 of Weglot plugin, the auto redirection feature works on all pages. Here is how to restrict it to the homepage only

Since version 3.5, the auto-redirect (auto-switch) feature works on every page. For example, with a **French** browser:

* `/` is redirected to `/fr/`
* `/contact` is redirected to `/fr/contact`

To restrict the auto-redirect to the homepage only:

```php
// Add this using the "Code Snippets" plugin or directly in functions.php
add_filter( 'weglot_autoredirect_only_home', '__return_true' );
```


# Proxify Url

Since the version 4.2 of Weglot plugin, you have a filter to proxify an url

Since version 4.2, a filter lets you route ("proxify") a resource URL through Weglot. A proxified URL is rewritten to this form:

`proxy.weglot.com/API_KEY/LANGUAGE_FROM/LANGUAGE_TO/my.ressource.io`

To proxify one or more URLs, use the `weglot_proxify_urls` filter:

```php
// Add this using the "Code Snippets" plugin or directly in functions.php
add_filter( 'weglot_proxify_urls', 'proxify_callback' );
function proxify_callback( $urls_to_proxify ) {
    $urls_to_proxify[] = 'https://my.ressource.io/';
    return $urls_to_proxify;
}
```

You can add several URLs to the array.


# Translate pdf for Woocommerce pdf invoice

Since the version 3.7 of Weglot plugin, you can translate pdf generate by WooCommerce PDF Invoices & Packing Slips plugin

Since version 3.7, Weglot can translate the PDFs generated by the *WooCommerce PDF Invoices & Packing Slips* plugin. This is disabled by default.

To enable it:

```php
// Add this using the "Code Snippets" plugin or directly in functions.php
add_filter( 'weglot_translate_pdf', '__return_true' );
```


# Translate pdf with Gravity pdf

Since the version 3.7 of Weglot plugin, you can translate pdf generate by Gravity PDF.

Below is an example of how to translate a PDF generated by Gravity PDF into the current language, based on the `gfpdf_pdf_html_output` filter documented here: <https://docs.gravitypdf.com/v6/developers/filters/gfpdf_pdf_html_output/>

```php
// Add this using the "Code Snippets" plugin.

// Create a new meta entry to store the weglot_language on Gravity Forms entries.
add_filter( 'gform_entry_meta', 'get_entry_meta', 10, 2 );
function get_entry_meta( $entry_meta, $form_id ) {
	$entry_meta['weglot_language'] = array(
		'label'                      => 'Weglot language',
		'is_numeric'                 => false,
		'is_default_column'          => true,
		'update_entry_meta_callback' => 'update_entry_meta',
	);
	return $entry_meta;
}

function update_entry_meta( $key, $lead, $form ) {
	return ''; // Return the value of the entry meta.
}

// Store the Weglot language on submission.
add_action( 'gform_after_submission', 'after_submission' );
function after_submission( $entry ) {
	$request_url_services = weglot_get_service( 'Request_Url_Service_Weglot' );
	$current_language     = $request_url_services->get_current_language()->getExternalCode();
	gform_update_meta( $entry['id'], 'weglot_language', $current_language );
}

// Translate the PDF using the stored language.
add_filter( 'gfpdf_pdf_html_output', function( $html, $form, $entry, $settings, $Helper_PDF ) {
	$weglot_language = gform_get_meta( $entry['id'], 'weglot_language' );
	if ( $weglot_language === weglot_get_original_language() ) {
		return $html;
	}
	$qp                    = new GFPDF\Helper\Helper_QueryPath();
	$pdf_translate_service = weglot_get_service( 'Pdf_Translate_Service_Weglot' );
	$html                  = $pdf_translate_service->translate_pdf( $html, $weglot_language );
	$wrapper               = $qp->html5( $html['content'] );
	return $wrapper->top( 'html' )->innerHTML5();
}, 10, 5 );
```


# Translate Dublin core meta (or other meta)

Dublin Core is a collection of meta tags to describe your content.These tags are automatically generated. Recognised by states/governments, these are used by directories, Bing, Baidu and Yandex.

Dublin Core is a set of meta tags describing your content (recognised by several search engines and directories). They are not translated by default, but you can register them with the `weglot_get_dom_checkers` filter.

Translate a single meta (e.g. `<meta name="dc.title" content="…" />`):

```php
add_filter( 'weglot_get_dom_checkers', 'dublin_core_weglot_dom_check' );
function dublin_core_weglot_dom_check( $dom_checkers ) {
    if ( ! class_exists( 'Dublin_Core_Meta' ) ) {
        class Dublin_Core_Meta extends Weglot\Parser\Check\Dom\AbstractDomChecker {
            const DOM       = 'meta[name="dc.title"]';
            const PROPERTY  = 'content';
            const WORD_TYPE = Weglot\Parser\Definitions\Enum\WordType::META_CONTENT;
        }
    }
    $dom_checkers[] = '\Dublin_Core_Meta';
    return $dom_checkers;
}
```

To target several meta tags at once, list them in the `DOM` selector (comma-separated):

```php
const DOM = 'meta[name="dc.title"],meta[name="dc.description"]';
```

{% hint style="info" %}
Add the class to `$dom_checkers` **outside** the `class_exists()` check: the filter can run several times in the same request, and the checker must be added every time.

Since Weglot 6.3 these classes live under `Weglot\Parser\…`. Snippets written with the older `Weglot\Client\Api\Enum\WordType` keep working.
{% endhint %}


# How to not translate specific ajax action

Weglot translates the response of admin-ajax actions by default. If a specific AJAX action should not be translated, add it to the list with the `weglot_ajax_no_translate` filter.

#### Example: excluding the `loadmore` ajax action

```php
add_filter( 'weglot_ajax_no_translate', 'custom_ajax_no_translate', 10, 1 );
function custom_ajax_no_translate( $ajax_action ) {
    $ajax_action[] = 'loadmore';
    return $ajax_action;
}
```


# How to get translated url programmatically

Below an example of how to get a translated url programmatically

```php
//get services
$language_services = weglot_get_service( 'Language_Service_Weglot' );
$request_url_services = weglot_get_service( 'Request_Url_Service_Weglot' );

//the url we want to get on other languages
$url = "http://myurl.local/hello-world/";

//create url object
$wg_url = $request_url_services->create_url_object( $url );

// get a language (in my case fr)
$language = $language_services->get_language_from_internal('fr');

//display url for my language
$wg_url->getForLanguage( $language );
```


# How to set WP locale based on Weglot current language

Below is an example of how to set the WordPress locale based on the current Weglot language, using the WordPress `locale` filter:

```php
add_filter( 'locale', 'weglot_set_locale' );
function weglot_set_locale( $lang ) {
    if ( function_exists( 'weglot_get_current_language' ) ) {
        $current_language = weglot_get_current_language();
        switch ( $current_language ) {
            case 'sv':
                return 'sv_SE';
            case 'en':
                return 'en_US';
            case 'no':
                return 'nb_NO';
            default:
                return $lang;
        }
    }
    return $lang;
}
```


# How to translate mail from Photo Reviews for WooCommerce

Works since version 1.2.7 of Photo Reviews for WooCommerce

The following code translates the reminder emails sent by *Photo Reviews for WooCommerce*, using the order's recorded language (stored by Weglot in the `weglot_language` order meta).

```php
use Weglot\Parser\Parser;
use Weglot\Parser\ConfigProvider\ServerConfigProvider;

function wg_viwcpr_email_reminder_get_content( $content, $order_id ) {
	$parser_services   = weglot_get_service( 'Parser_Service_Weglot' );
	$language_services = weglot_get_service( 'Language_Service_Weglot' );
	$original_language = $language_services->get_original_language()->getInternalCode();

	$woocommerce_order_language = get_post_meta( $order_id, 'weglot_language', true ); // phpcs:ignore

	if ( $woocommerce_order_language == weglot_get_original_language() ) {
		return $content;
	}

	$config  = new ServerConfigProvider();
	$client  = $parser_services->get_client();
	$parser  = new Parser( $client, $config, [] );
	$content = $parser->translate( $content, $original_language, $woocommerce_order_language ); // phpcs:ignore

	return $content;
}

function wg_viwcpr_email_reminder_get_subject( $subject, $order_id ) {
	$parser_services   = weglot_get_service( 'Parser_Service_Weglot' );
	$language_services = weglot_get_service( 'Language_Service_Weglot' );
	$original_language = $language_services->get_original_language()->getInternalCode();

	$woocommerce_order_language = get_post_meta( $order_id, 'weglot_language', true ); // phpcs:ignore

	if ( $woocommerce_order_language == weglot_get_original_language() ) {
		return $subject;
	}

	$config  = new ServerConfigProvider();
	$client  = $parser_services->get_client();
	$parser  = new Parser( $client, $config, [] );
	$subject = $parser->translate( $subject, $original_language, $woocommerce_order_language ); // phpcs:ignore

	return $subject;
}

add_filter( 'viwcpr_email_reminder_get_content', 'wg_viwcpr_email_reminder_get_content', 10, 2 );
add_filter( 'viwcpr_email_reminder_get_subject', 'wg_viwcpr_email_reminder_get_subject', 10, 2 );
```


# How to translate schema from schema.org generate by Yoast plugin

On this example we use a filter to translate some entry from our schema based on this doc : https\://developer.yoast.com/features/schema/api/

```php
add_filter( 'wpseo_schema_graph', 'wg_schema', 10, 2 );

function wg_schema( $data, $context ) {
	
	foreach ( $data as $key => $value ) {
        if ( $value['@type'] === 'WebPage' || $value['@type'] === 'WebSite') {
            $data[$key]['@id'] = weglot_get_current_full_url();
			$data[$key]['url'] = weglot_get_current_full_url();
			$data[$key]['inLanguage'] = weglot_get_current_language();
        }
		
		if ( $value['@type'] === 'ImageObject' || $value['@type'] === 'primaryImageOfPage') {
			$data[$key]['inLanguage'] = weglot_get_current_language();
        }
    }
		
    return $data;
}
```


# How to translate email sending by plugin WP Mail SMTP

On this example we use a filter to translate our email message based on this doc : https\://wpmailsmtp.com/docs/setting-a-custom-reply-to-email/

{% hint style="info" %}
Weglot can translate `wp_mail` emails natively — just enable the **Translate emails** option in the Weglot settings. Use the snippet below only if you need custom handling on top of the built-in option (for example with WP Mail SMTP).
{% endhint %}

This example translates the email message body into the current language:

```php
function wp_mail_smtp_weglot( $args ) {
	$original_lang    = weglot_get_original_language();
	$current_language = weglot_get_current_language();
	if ( $original_lang == $current_language ) {
		return $args;
	}

	if ( ! empty( $args['message'] ) ) {
		$translate_service = weglot_get_service( 'Pdf_Translate_Service_Weglot' );
		$translate_message = $translate_service->translate_pdf( $args['message'], $current_language );
		$args['message']   = $translate_message['content'];
	}
	return $args;
}

add_filter( 'wp_mail', 'wp_mail_smtp_weglot', PHP_INT_MAX );
```


# How to hide the Weglot admin button for non administrator roles

In this example, we hide the Weglot button in the top navigation for users without the role of administrator

```php
if(is_user_logged_in()){
	$user = wp_get_current_user();
	if ( !in_array( 'administrator', (array) $user->roles ) ) {
		add_action( 'admin_head', 'hide_wg_button' );
	}
}

function hide_wg_button() {
 echo "<style>#wp-admin-bar-weglot{display:none;}</style>";
}
```


# Exemple of snippet to translate search from JetSearch plugin

In this example, we use custom code to translate the search result provide by the plugin jetSearch

To translate the results of the JetSearch plugin, reverse-translate the search term back into your original language before the query runs, then declare the JSON keys JetSearch returns so Weglot translates them.

```php
add_action( 'jet-search/ajax-search/search-query', 'modify_weglot_search_query', 10, 2 );
function modify_weglot_search_query( $instance, $args ) {
    $parser_services      = weglot_get_service( 'Parser_Service_Weglot' );
    $parser               = $parser_services->get_parser();
    $language_services    = weglot_get_service( 'Language_Service_Weglot' );
    $original_language    = $language_services->get_original_language()->getInternalCode();
    $destination_languages = weglot_get_destination_languages();
    $current_language     = weglot_get_current_language();

    if ( $original_language === $current_language ) {
        return;
    }

    foreach ( $destination_languages as $destination ) {
        if ( $destination['language_to'] === $current_language && ! empty( $destination['custom_code'] ) ) {
            $current_language = substr( $destination['custom_code'], 0, 2 );
        }
    }

    if ( ! empty( $instance->search_query['s'] ) ) {
        $instance->search_query['s'] = $parser->translate( $instance->search_query['s'], $current_language, $original_language );
    }
}

add_filter( 'weglot_add_json_keys', 'custom_weglot_add_json_keys' );
function custom_weglot_add_json_keys( $keys ) {
    $keys[] = 'title';
    $keys[] = 'link';
    $keys[] = 'before_title';
    $keys[] = 'posts';
    return $keys;
}
```


# Example of snippet to translate your checkout element (override/added by the Funnel Builder plugin)

```php
add_filter('woocommerce_update_order_review_fragments', 'wg_update_checkout', 999, 2);
function wg_update_checkout($arr) {
$pdf_translate_service = weglot_get_service( 'Pdf_Translate_Service_Weglot' );
$original_lang = weglot_get_original_language();
$current_language = weglot_get_current_language();
if ( $original_lang == $current_language ) {
	return $arr;
}
$pot = $pdf_translate_service->translate_pdf( $arr['place_order_text'], $current_language );
$arr['place_order_text'] = $pot['content'];
return $arr;
}
```


# LScache

Compatibility issue with LScache

LScache uses so called “Cache Vary”. That means each URL can be cached with different cache copies depending on user related facts like cookie, device and many others. The problem is that Weglot uses PHP and detects language using PHP, but if a page is cached there is no more PHP interpretor, because a cached URL is pure plain text and plain text can’t execute PHP. To make Weglot work with LScache a cookie must be set with different cookie value depending on the selected language. Then this cookie can be used for cache vary so each language gets its own cached copy.

To make it works you can modifiy your Litespeed Vhost with this code :

```php
<IfModule LiteSpeed>
RewriteEngine onCacheLookup on
## Create a separate cache for each language [create a rule for each language you have on your website except the fallback language. In this example we have: FR (original language) + ES (target language) + EN (target but fallback language)] ##
## FR cache ##
RewriteCond %{HTTP:Accept-Language} ^fr [NC]RewriteRule .* - [E=Cache-Control:vary=%{ENV:LSCACHE_VARY_VALUE}+french]
## ES cache ##
RewriteCond %{HTTP:Accept-Language} ^es [NC]RewriteRule .* - [E=Cache-Control:vary=%{ENV:LSCACHE_VARY_VALUE}+spain]
## Create a separate cache if the browser is different from the website - add it imperatively or it will cause issue if the cache is made with the wrong language ##
RewriteCond %{HTTP_COOKIE} ^.*WG_CHOOSE_ORIGINAL.*$RewriteRule .* - [E=Cache-Control:vary=%{ENV:LSCACHE_VARY_VALUE}+wg_choose_original]
</IfModule>
```

Be careful, in some cases, if the Litespeed server is a “fake”, configured with reverse proxies by the host, this code must be added to the Litespeed Vhost. Unfortunately, some hosts do not allow this...


# How to fix live builder issue with Weglot

Compatibility issue with live theme builder

Weglot is not intended to translate backoffice elements. More and more site builders offer the live builder feature. Some of its live builders will come into conflict with Weglot because Weglot will attempt to translate elements that are not wanted at that time. To avoid this we will ask Weglot not to translate when we are in the live builder.

Let’s take the example of Avada theme builder. When we are in the live builder we have the get fb-edit variable in the url so we can use this snippet:

<pre class="language-php"><code class="lang-php">if(isset($_GET['fb-edit']) || isset($_GET['builder'])){
<strong>    add_filter( 'weglot_active_translation', '__return_false', 99999 );
</strong>}
</code></pre>

Here another exemple with elementor : we use a hook instead of url parameters :

```php
function weglot_deactivate_elementor() {
	add_filter( 'weglot_active_translation', '__return_false', 99999 );
}
add_action( 'elementor/init', 'weglot_deactivate_elementor' );
```


# Add translated url to Rankmath sitemap index

First step, add this snippet to be sure to purge the sitemap caching

```php
/**
 * Filter if XML sitemap transient cache is enabled.
 *
 * @param boolean $unsigned Enable cache or not, defaults to true
 */
add_filter( 'rank_math/sitemap/enable_caching', '__return_false');
```

Add this filter. For the moment you need to add the list of url you want to translate into your sitemap

```php
add_filter( 'rank_math/sitemap/index', function( $xml ) {
	// Fetch Weglot services
	$language_services = weglot_get_service( 'Language_Service_Weglot' );
	$request_url_services = weglot_get_service( 'Request_Url_Service_Weglot' );

	// List of URLs to be translated
	$urls = [
		"http://beta-429.local/post-sitemap.xml",
		"http://beta-429.local/page-sitemap.xml",
		"http://beta-429.local/category-sitemap.xml",
	];

	$destination_languages = weglot_get_destination_languages();
	foreach ( $urls as $url ) {
		$wg_url = $request_url_services->create_url_object( $url );

		// Iterate over each destination language
		foreach ( $destination_languages as $language_code ) {
			$language = $language_services->get_language_from_internal( $language_code['language_to'] );

			$translated_url = $wg_url->getForLanguage( $language );

			$xml .= '
                <sitemap>
                    <loc>' . esc_url( $translated_url ) . '</loc>
                    <lastmod>' . esc_html( date( 'c' ) ) . '</lastmod>
                </sitemap>';
		}
	}

	return $xml;
}, 999 );
```


# Advanced Woo Search X Weglot

Advanced Woo Search (aws) is a plugin to make advance search with WooCommerce. You can find the plugin here : https\://wordpress.org/plugins/advanced-woo-search/

To make Advanced Woo Search return results in translated languages, reverse-translate the search terms into your original language before the search runs. The right hook (see the [Advanced Woo Search hooks reference](https://advanced-woo-search.com/guide/hooks-reference/)) is `aws_search_terms`.

```php
use WeglotWP\Helpers\Helper_API;

add_filter( 'aws_search_terms', 'my_aws_search_terms' );
function my_aws_search_terms( $terms ) {
    $original_language = weglot_get_original_language();
    $current_language  = weglot_get_current_language();
    if ( $original_language === $current_language || ! $terms ) {
        return $terms;
    }

    $option_services = weglot_get_service( 'Option_Service_Weglot' );
    $api_key_private = $option_services->get_api_key_private();

    foreach ( $terms as $key => $term ) {
        $request_body = wp_json_encode( array(
            'l_from'      => $current_language,
            'l_to'        => $original_language,
            'request_url' => home_url( '/' ),
            'words'       => array(
                array( 'w' => $term, 't' => 1 ),
            ),
        ) );

        $url      = sprintf( '%s/translate?api_key=%s', Helper_API::get_api_url(), $api_key_private );
        $response = wp_remote_post( $url, array(
            'body'        => $request_body,
            'headers'     => array( 'Content-Type' => 'application/json' ),
            'method'      => 'POST',
            'data_format' => 'body',
        ) );

        if ( is_wp_error( $response ) ) {
            continue; // Keep the original term if the request fails.
        }

        $response_data = json_decode( wp_remote_retrieve_body( $response ), true );
        if ( isset( $response_data['to_words'][0] ) ) {
            $terms[ $key ] = $response_data['to_words'][0];
        }
    }

    return $terms;
}
```


# Conditionally Disabling Weglot Translation for Specific URLs

When using Weglot on your website, you might occasionally encounter issues where its translation processes interfere with certain functionalities, like generating PDFs or handling custom endpoints. In

Suppose you’re facing an issue where generating PDFs is not working correctly due to Weglot's translation being applied to those URLs. In this case, instead of disabling the entire Weglot plugin, you can selectively disable its translation process for specific URLs.

```php
add_action('init', 'conditionally_apply_weglot_translation');
function conditionally_apply_weglot_translation() {
    $current_url = $_SERVER['REQUEST_URI'];
    // Check if the current URL contains 'front-end'
    if (strpos($current_url, 'front-end') !== false) {
        // Disable Weglot translation for this specific request
        add_filter('weglot_active_translation_before_process', function() {
            return false;
        });
    }
}
```

**Why Use This Approach?**

* **Avoid full deactivation**: Instead of disabling the entire Weglot plugin (which affects your whole site), this solution allows you to keep Weglot active while bypassing translation only for specific scenarios.
* **Resolve conflicts efficiently**: For example, if generating PDFs or handling specific routes fails due to translations, disabling Weglot only for those URLs resolves the issue without affecting the rest of your website.


# How to store your API key outside the database

{% hint style="info" %}
Available since Weglot 6.3.
{% endhint %}

By default the plugin keeps your Weglot API key in the WordPress database, in the `wp_options` table. On hosting where secrets are managed outside the codebase and outside the database — WordPress VIP environment variables, Docker secrets, a `.env` file — you can supply it as a PHP constant instead.

When the constant is defined and non-empty, it becomes the only source for the key: the plugin reads it instead of the database, and stops writing it to the database entirely.

### The constant

Only one constant is needed: `WEGLOT_API_KEY_PRIVATE`, set to the API key shown in your Weglot dashboard — the same key you would otherwise paste into the plugin's API key field.

| Constant                 | Value                           | Replaces the option                |
| ------------------------ | ------------------------------- | ---------------------------------- |
| `WEGLOT_API_KEY_PRIVATE` | Your API key from the dashboard | `weglot-translate-api_key_private` |

The constant must be set before WordPress loads plugins, so it belongs in `wp-config.php` — above the `require_once ABSPATH . 'wp-settings.php';` line — or in your host's equivalent configuration file.

### Reading the key from an environment variable

The plugin only checks that the constant exists and is non-empty. Where the value comes from is up to you, so any secret store that PHP can read works.

#### WordPress VIP

Store the key as an environment variable with VIP-CLI. The command prompts for the value rather than taking it as an argument, which keeps it out of your shell history:

```bash
vip @your-app.production config envvar set WEGLOT_API_KEY_PRIVATE
```

Then read it in `/vip-config/vip-config.php`, which is loaded before WordPress core and before any plugin:

```php
// Weglot reads its API key from this constant instead of the database.
if ( function_exists( 'vip_get_env_var' ) ) {
	define( 'WEGLOT_API_KEY_PRIVATE', vip_get_env_var( 'WEGLOT_API_KEY_PRIVATE', '' ) );
}
```

Each VIP environment carries its own variables, so set it on every environment you deploy to. An environment where it is missing falls back to the database.

#### Any other host

```php
define( 'WEGLOT_API_KEY_PRIVATE', getenv( 'WEGLOT_API_KEY_PRIVATE' ) ?: '' );
```

Keep the empty-string fallback. If the variable is missing the constant stays empty, and the plugin reads the database as before instead of breaking.

### What changes in the admin

The API key field in the Weglot settings is filled in from the constant and becomes read-only, with a note saying where the value comes from. Saving the settings still validates the key against the Weglot API — it simply does not store it.

Resetting the Weglot settings no longer disconnects the site either: that action clears the plugin's options, and the key is no longer among them.

To rotate the key, change it in your secret store and deploy. Nothing needs to change in WordPress.

### Migrating a site that is already configured

On a site that ran Weglot before, the key is already in the database and defining the constant does not remove it. Once you have confirmed the front end still translates, delete it explicitly:

```bash
wp option delete weglot-translate-api_key_private
```

Nothing rewrites it afterwards.

You can check the result at any time with:

```bash
wp option get weglot-translate-api_key_private
```

It should report that the option could not be found.

### Limitations

The plugin caches its configuration in a WordPress transient, and that cache contains the key. With a persistent object cache — which WordPress VIP provides — transients are held in memory and never reach the database. Without one, WordPress stores transients in the `wp_options` table, so a copy of the key lands there despite the constant.

The key also remains visible in the admin: the settings field is read-only, not hidden. Anyone who can reach the Weglot settings screen can read it.


# Weglot filters

All Weglot filters you can call to modify translations

Weglot plugin is exposing actions and filters that can be called in your code.


# weglot\_translate\_email

This filter allow you to prevent weglot translate email even if the option is checks on your options.

```php
add_filter( 'weglot_translate_email', '__return_false' );
```


# weglot\_cancel\_init

This filter allow you to prevent weglot to be load.

### weglot\_cancel\_init

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


# weglot\_translate\_email\_languages\_forced

Weglot prevent to translate emails that are fro admins. But you can force it by adding this filter.

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


# weglot\_menu\_parent\_menu\_item\_title

When the language switcher is added through the WordPress menu in dropdown mode, its parent item shows a default title ("Choose your language"). Use this filter to change it.

```php
add_filter( 'weglot_menu_parent_menu_item_title', 'custom_weglot_menu_parent_menu_item_title' );
function custom_weglot_menu_parent_menu_item_title( $title ) {
    return 'Choose your language';
}
```


# weglot\_active\_current\_menu\_item

With this filter you can manage if you want to add the current-item-menu class into your switcher element (menu version).

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


# weglot\_ajax\_no\_translate

This filter help you prevent Weglot to translate some ajax action. Here the list of action we don't translate :

The filter receives the list of AJAX actions Weglot never translates, and must return it. An `admin-ajax.php` request whose `action` parameter (POST or GET) is in the list is left untranslated.

```php
add_filter( 'weglot_ajax_no_translate', 'custom_weglot_ajax_no_translate' );
function custom_weglot_ajax_no_translate( $actions ) {
    $actions[] = 'my_ajax_action';
    return $actions;
}
```

The default list:

```
array(
   'add-menu-item', // WP Core.
   'query-attachments', // WP Core.
   'avia_ajax_switch_menu_walker', // Enfold theme.
   'query-themes', // WP Core.
   'wpestate_ajax_check_booking_valability_internal', // WP Estate theme.
   'wpestate_ajax_add_booking', // WP Estate theme.
   'wpestate_ajax_check_booking_valability', // WP Estate theme.
   'mailster_get_template', // Mailster Pro.
   'mmp_map_settings', // MMP Map.
   'elementor_ajax', // Elementor since 2.5.
   'ct_get_svg_icon_sets', // Oxygen.
   'oxy_render_nav_menu', // Oxygen.
   'hotel_booking_ajax_add_to_cart', // Hotel booking plugin.
   'imagify_get_admin_bar_profile', // Imagify Admin Bar.
   'el_check_user_login', // Event list plugin.
   'wcfm_ajax_controller', // wcfm_ajax_controller.
   'jet_ajax_search', // jet_ajax_search.
   'woofc_update_qty', // jet_ajax_search.
   'et_fb_ajax_save', // Divi builder save.
   'generate_wpo_wcpdf', // WooCommerce PDF Invoices & Packing Slips.
   'wpamelia_api', // Amelia booking plugin.
)
```

With the filter you can update this array by add or unset array index.


# weglot\_active\_translation\_before\_process

This filter allow you to interrupt translation process before Weglot check redirection needed.

```php
add_filter( 'weglot_active_translation_before_process', '__return_false' );
```


# weglot\_active\_translation\_before\_treat\_page

This filter allow you to interrupt translation process after Weglot have check redirection needed.

```php
add_filter( 'weglot_active_translation_before_treat_page', '__return_false' );
```


# weglot\_debug\_file

In the Weglot plugin you can active a debug mode.

To activate the debug mode the steps are:

* In Weglot.php set **`WEGLOT_DEBUG`** to true
* Create a file **`content.html`** on Weglot plugin dir root

```php
add_filter( 'weglot_debug_file', 'path to your file' );
```

With this filter you can access debug mode from another file instead of :

```
WEGLOT_DIR . '/content.html'
```


# weglot\_autoredirect\_only\_home

This filter allow you to restrict autoredirect to the homepage only.

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


# weglot\_autoredirect\_skip

This filter allow you to deactivate the autoswitch feature even if the option is activate.

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


# weglot\_remove\_google\_translate

By default, Weglot prevent google translating page but with this flter you can enable this google feature

On translated pages, Weglot tells Google not to translate the page again (a `<meta name="google" content="notranslate"/>` tag and a `translate="no"` attribute on `<html>`). The filter defaults to `true`; return `false` to let Google offer its own translation.

```php
add_filter( 'weglot_remove_google_translate', '__return_false' );
```


# weglot\_add\_hreflang

This filter allow you to prevent Weglot add hreflangs if you want to add yours

```php
add_filter( 'weglot_add_hreflang', '__return_false' );
```


# weglot\_get\_replace\_modify\_link

This filter allow you to add pattern to define kind of link you want to translate.

here the list of pattern we already treat on Weglot:

```php
array(
   'a'         => '/<a([^\>]+?)?href=(\"|\')([^\s\>]+?)(\"|\')([^\>]+?)?>/',
   'datalink'  => '/<([^\>]+?)?data-link=(\"|\')([^\s\>]+?)(\"|\')([^\>]+?)?>/',
   'dataurl'   => '/<([^\>]+?)?data-url=(\"|\')([^\s\>]+?)(\"|\')([^\>]+?)?>/',
   'datacart'  => '/<([^\>]+?)?data-cart-url=(\"|\')([^\s\>]+?)(\"|\')([^\>]+?)?>/',
   'form'      => '/<form([^\>]+?)?action=(\"|\')([^\s\>]+?)(\"|\')/',
   'canonical' => '/<link rel="canonical"(.*?)?href=(\"|\')([^\s\>]+?)(\"|\')/',
   'amp'       => '/<link rel="amphtml"(.*?)?href=(\"|\')([^\s\>]+?)(\"|\')/',
   'meta'      => '/<meta property="og:url"(.*?)?content=(\"|\')([^\s\>]+?)(\"|\')/',
   'next' => '/<link rel="next"(.*?)?href=(\"|\')([^\s\>]+?)(\"|\')/',
   'prev' => '/<link rel="prev"(.*?)?href=(\"|\')([^\s\>]+?)(\"|\')/',
);
```

The filter receives this array and must return it. Each key you add needs a matching `replace_<key>()` function that does the replacement, as in the two examples below.

Here 2 exemples of how to use this filter :<br>

```html
<div data-link2="http://debug-wp-woo.local/shop/">http://debug-wp-woo.local/shop/</div>
```

To translate the link into the attribute data-link-2 you cn use this code :

```php
add_filter( 'weglot_get_replace_modify_link', 'custom_weglot_get_replace_modify_link' );
function custom_weglot_get_replace_modify_link( $data ) {
	$data['datalink2'] = '/<([^\>]+?)?data-link2=(\"|\')([^\s\>]+?)(\"|\')([^\>]+?)?>/';
    return $data;
}

function replace_datalink2( $translated_page, $current_url, $quote1, $quote2, $sometags = null, $sometags2 = null ) {
	$request_url_services = weglot_get_service( 'Request_Url_Service_Weglot' );
	$replace_url_Service = weglot_get_service( 'Replace_Link_Service_Weglot' );
	$current_language = $request_url_services->get_current_language();
	$translated_page  = preg_replace( '/<' . preg_quote( $sometags, '/' ) . 'data-link2=' . preg_quote( $quote1 . $current_url . $quote2, '/' ) . '/', '<' . $sometags . 'data-link2=' . $quote1 . $replace_url_Service->replace_url( $current_url, $current_language ) . $quote2, $translated_page );
	return $translated_page;
}
```

Now try with a more complexe case :

```html
                <div data-actions="o:click;a:simplelink;target:_self;url:http://debug-wp-woo.local/shop/;">http://debug-wp-woo.local/shop/</div>
```

```php
add_filter( 'weglot_get_replace_modify_link', 'custom_weglot_get_replace_modify_link_2' );
function custom_weglot_get_replace_modify_link_2( $data ) {
	$data['dataactions'] = '/<div[^>]*?data-actions=(["\'].*?url:)([^"\'>]+).*?>(.*?)<\/div>/';
	return $data;
}

function replace_dataactions( $translated_page, $current_url, $quote1, $quote2, $sometags = null, $sometags2 = null ) {
    $request_url_services = weglot_get_service( 'Request_Url_Service_Weglot' );
    $replace_url_Service = weglot_get_service( 'Replace_Link_Service_Weglot' );
    $current_language = $request_url_services->get_current_language();
    $sometags = 'div ';
    $quote1 = '"o:click;a:simplelink;target:_self;url:';
    $quote2 = ';"';
	$translated_page  = preg_replace( '/<' . preg_quote( $sometags, '/' ) . 'data-actions=' . preg_quote( $quote1 . $current_url . $quote2, '/' ) . '/', '<' . $sometags . 'data-actions=' . $quote1 . $replace_url_Service->replace_url( $current_url, $current_language ) . $quote2, $translated_page );
	return $translated_page;
}
```


# get\_replace\_modify\_link\_in\_xml

This filter allow you to add pattern to define kind of link you want to translate in xml.

here the list of pattern we already treat on Weglot:

```php
array('loc' => '/<loc>(.*?)<\/loc>/');
```

The filter receives this array and must return it. Each key you add needs a global function named `replace_<key>( $translated_page, $current_url )`: Weglot calls it for every URL the pattern captures (its first capture group) and uses the page it returns. Without that function the pattern is ignored. Rename the function with the `weglot_modify_link_sitemap_replace_function` filter.

```php
add_filter( 'get_replace_modify_link_in_xml', 'custom_weglot_xml_link_patterns' );
function custom_weglot_xml_link_patterns( $patterns ) {
    $patterns['page_loc'] = '/<page:loc>([^<]+)<\/page:loc>/';
    return $patterns;
}

function replace_page_loc( $translated_page, $current_url ) {
    $replace_link_service = weglot_get_service( 'Replace_Link_Service_Weglot' );
    $current_language     = weglot_get_service( 'Request_Url_Service_Weglot' )->get_current_language();

    return str_replace(
        '<page:loc>' . $current_url . '</page:loc>',
        '<page:loc>' . esc_url( $replace_link_service->replace_url( $current_url, $current_language ) ) . '</page:loc>',
        $translated_page
    );
}
```

{% hint style="warning" %}
Only target tags holding page URLs. File URLs (images, PDF…) are skipped, and the `<xhtml:link rel="alternate">` tags of a sitemap are its hreflang cluster: rewriting them to the current language would break it.
{% endhint %}


# weglot\_get\_flag\_class

This filter allow to add or remove class use to display flag on switcher

```php
add_filter( 'weglot_get_flag_class', 'list of class' );
```


# weglot\_get\_name\_with\_language\_entry

With this filter you can modifiy the name of language we diplay on switcher for each languages

```php
add_filter( 'weglot_get_name_with_language_entry', $name, $language_entry );
```


# weglot\_get\_class\_dropdown

This filter allow you to modify list of class use to display our switcher dropdown.

```php
add_filter( 'weglot_get_class_dropdown', '' );
```


# weglot\_button\_html

this filter allows you yo get the html generate for our switcher and modify it.

You can find an exemple [here](https://developers.weglot.com/wordpress/use-cases/language-selector-styling#example-adding-code-before-after-the-button).

```php
add_filter( 'weglot_button_html', 'custom_weglot_button_html', 10, 2 );
```


# weglot\_get\_dom\_checkers

This filter allow you to add rule to our dom checker. You can add rule to telle Weglot what kind of node need to be translate.

You've an exemple here: <https://developers.weglot.com/wordpress/filters/translations-filters#weglot_get_dom_checkers>


# weglot\_replace\_div\_id

This filter allow you to get the translated content after we have replace the \<div id="weglot\_here">\</div> with the switcher

The filter receives the page HTML (a string) once every `<div id="weglot_here"></div>` has been replaced by the language switcher, and must return it.

```php
add_filter( 'weglot_replace_div_id', 'custom_weglot_replace_div_id' );
function custom_weglot_replace_div_id( $html ) {
    // Edit the HTML here.
    return $html;
}
```


# weglot\_replace\_weglot\_menu

This filter allow to modify the content before we add the switcher(s)

The filter receives the page HTML (a string) before Weglot adds its switcher(s), and must return it.

```php
add_filter( 'weglot_replace_weglot_menu', 'custom_weglot_replace_weglot_menu' );
function custom_weglot_replace_weglot_menu( $html ) {
    // Edit the HTML here.
    return $html;
}
```


# weglot\_render\_default\_button

This filter allows you to modifiy the content after the default switcher is added

The filter receives the page HTML (a string) once the default switcher has been added, and must return it.

```php
add_filter( 'weglot_render_default_button', 'custom_weglot_render_default_button' );
function custom_weglot_render_default_button( $html ) {
    // Edit the HTML here.
    return $html;
}
```


# weglot\_render\_switcher\_editor\_button

This filter allow you to modifiy the translated content after the custom switcher is added.

The filter receives the translated page HTML (a string) once the custom switchers have been added, and must return it.

```php
add_filter( 'weglot_render_switcher_editor_button', 'custom_weglot_render_switcher_editor_button' );
function custom_weglot_render_switcher_editor_button( $html ) {
    // Edit the HTML here.
    return $html;
}
```


# weglot\_href\_lang

With this filter you can modifiy hreflangs generate by Weglot before we add them.

Lets you alter the hreflang block Weglot outputs in the `<head>` (for example to swap a language code).

```php
add_filter( 'weglot_href_lang', 'custom_weglot_href_lang' );
function custom_weglot_href_lang( $render ) {
    $render = str_replace( 'hreflang="zh-HK"', 'hreflang="tw"', $render );
    return $render;
}
```


# weglot\_get\_options\_from\_cdn\_cache

This filter allow you to prevent to load Weglot settings from transient.

```php
add_filter( 'weglot_get_options_from_cdn_cache', '__return_false' );
```


# weglot\_get\_options\_from\_cdn\_cache\_duration

With this filter you can modifiy the duration of cache where we save Weglot settings. By default we fix it to 300 seconds

```php
add_filter( 'weglot_get_options_from_cdn_cache_duration', 300 );
```


# weglot\_get\_slugs\_from\_cache

This filter allow you to get your slug directly from the API instead of getting them from transient. Be carefull using this filter.

```php
add_filter( 'weglot_get_slugs_from_cache', '__return_false' );
```


# weglot\_get\_slugs\_cache\_duration

This filter allow you to change the duration of cache we store the slugs. By default is setting to 0.

Translated URL slugs are cached in a transient. By default the duration is `0` (no explicit expiration set on the transient). Use this filter to set a custom cache duration, in seconds.

```php
add_filter( 'weglot_get_slugs_cache_duration', 'custom_weglot_get_slugs_cache_duration' );
function custom_weglot_get_slugs_cache_duration( $duration ) {
    return HOUR_IN_SECONDS;
}
```


# weglot\_exclude\_blocks

This filter allow you to modifiy the array of exclude blocks.

The filter receives the array of CSS selectors whose content is never translated, and must return it. Weglot adds a `data-wg-notranslate` attribute to every matching element.

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

{% hint style="info" %}
The exclusions are ignored as soon as `weglot_parser_whitelist` returns a non-empty list: the page then only translates the whitelisted blocks.
{% endhint %}


# weglot\_exclude\_urls

This filter allow you to modifiy the list of your excluded url.

The filter receives the list of excluded URLs and must return it. Each entry is an array: a `Weglot\Util\Regex` matched against the URL path, then the excluded languages (`null` for all languages).

```php
add_filter( 'weglot_exclude_urls', 'custom_weglot_exclude_urls' );
function custom_weglot_exclude_urls( $exclude_urls ) {
    $exclude_urls[] = array( new \Weglot\Util\Regex( \Weglot\Util\Regex\RegexEnum::CONTAIN, '/members/' ), null );
    return $exclude_urls;
}
```


# weglot\_get\_parser\_ignored\_nodes

This filter allow you to modify the list of node ignored by Weglot.

the default list is :

```php
$ignoredNodes = [
    'strong', 'b',
    'em', 'i',
    'small', 'big',
    'sub', 'sup',
    'abbr',
    'acronym',
    'bdo',
    'cite',
    'kbd',
    'q',
];
```

```php
add_filter( 'weglot_get_parser_ignored_nodes', $ignored_nodes );
```


# weglot\_navigator\_language

With this filter you can modifiy the browser language(s) detect by Weglot.

Lets you change the list of browser languages Weglot reads from the visitor to decide the redirect language. Useful together with a custom language code.

The filter receives the browser languages as lowercase codes, in the visitor's order of preference (for example `array( 'zh-tw', 'en' )`), and must return the list. Weglot compares them with your language codes in lowercase.

```php
add_filter( 'weglot_navigator_language', 'custom_weglot_navigator_language' );
function custom_weglot_navigator_language( $navigator_languages ) {
    return $navigator_languages;
}
```

For a complete example that maps a browser language to a custom code, see [Use custom language code](/cms/wordpress/use-cases/use-custom-language-code-url-lang-and-hreflang-attribute#with-the-auto-redirect-option).


# weglot\_url\_auto\_redirect

This filter can be use to modify the url where use will be redirect if the autoswitch option is activate.

When the browser-language auto-redirect runs, this filter lets you change the destination URL.

```php
add_filter( 'weglot_url_auto_redirect', 'custom_weglot_url_auto_redirect' );
function custom_weglot_url_auto_redirect( $url ) {
    return $url;
}
```


# weglot\_replace\_url

This filter allow you to modifiy the replaced url when it is translated.

The filter receives three arguments: the translated URL, the original URL and the target language (a `Weglot\Client\Api\LanguageEntry`). It must return the URL to use.

```php
add_filter( 'weglot_replace_url', 'custom_weglot_replace_url', 10, 3 );
function custom_weglot_replace_url( $replaced_url, $url, $language ) {
    // Return another URL for a given language if needed.
    return $replaced_url;
}
```


# weglot\_replace\_link

This filter allow you to modifiy the dom after the link has benne replaced.

This filter lets you modify the DOM while Weglot replaces links. It receives the DOM string being processed and must return it.

```php
add_filter( 'weglot_replace_link', 'custom_weglot_replace_link' );
function custom_weglot_replace_link( $dom ) {
    // Modify $dom here.
    return $dom;
}
```


# weglot\_ajax\_replace\_urls

When Weglot translate json content, we don't translate all entry. With this filter you can modifiy the keys we translate for url.

by default we translate this keys :

```php
[ 'redirecturl', 'url', 'link' ]
```

The filter receives this array and must return it.

```php
add_filter( 'weglot_ajax_replace_urls', 'custom_weglot_ajax_replace_urls' );
function custom_weglot_ajax_replace_urls( $keys ) {
    $keys[] = 'checkout_url';
    return $keys;
}
```


# weglot\_proxify\_urls

This filter allow you to modify the list of url you want to proxify.

The filter receives a list of absolute URLs (empty by default) and must return it. On translated pages, each listed URL is replaced in the HTML by its Weglot proxy URL, so the resource it points to is served translated.

```php
add_filter( 'weglot_proxify_urls', 'custom_weglot_proxify_urls' );
function custom_weglot_proxify_urls( $urls ) {
    $urls[] = 'https://widget.example.com/embed.html';
    return $urls;
}
```


# weglot\_add\_json\_keys

With this filter you can add keys Weglot msut translate into a json content.

The filter receives an array of JSON keys (empty by default: `name`, `description` and HTML values are always translated) and must return it. The values of the keys you add are translated too.

```php
add_filter( 'weglot_add_json_keys', 'custom_weglot_add_json_keys' );
function custom_weglot_add_json_keys( $keys ) {
    $keys[] = 'message';
    return $keys;
}
```


# weglot\_json\_treat\_page

This filter allow you to modifiy the translated content when this one is a json.

The filter receives the translated JSON response (a string) and must return it.

```php
add_filter( 'weglot_json_treat_page', 'custom_weglot_json_treat_page' );
function custom_weglot_json_treat_page( $json ) {
    // Edit the translated JSON here.
    return $json;
}
```


# weglot\_html\_treat\_page

This filter allow you to modifiy the translated content when this one is html.

The filter receives the translated HTML page (a string) and must return it. It also runs on XML responses, before `weglot_xml_treat_page`.

```php
add_filter( 'weglot_html_treat_page', 'custom_weglot_html_treat_page' );
function custom_weglot_html_treat_page( $html ) {
    // Edit the translated HTML here.
    return $html;
}
```


# weglot\_xml\_treat\_page

This filter allow you to modifiy the translated content when this one is xml.

The filter receives the translated XML response (a string, for example a sitemap) and must return it. `weglot_html_treat_page` has already run on it.

```php
add_filter( 'weglot_xml_treat_page', 'custom_weglot_xml_treat_page' );
function custom_weglot_xml_treat_page( $xml ) {
    // Edit the translated XML here.
    return $xml;
}
```


# weglot\_render\_dom

This filter allow to modify the translated content after putting meta and replace link.

The filter receives the translated page HTML (a string) once the meta tags and links have been rewritten, and must return it.

```php
add_filter( 'weglot_render_dom', 'custom_weglot_render_dom' );
function custom_weglot_render_dom( $html ) {
    // Edit the HTML here.
    return $html;
}
```


# weglot\_default\_current\_language\_empty

When we not able to find the current language, we set it to the original language by default. This filter allow you to modifiy.

Runs when Weglot cannot read the current language from the URL, for example during a WP-CLI command. The filter receives the original language (a `Weglot\Client\Api\LanguageEntry`) and must return a `LanguageEntry`.

```php
add_filter( 'weglot_default_current_language_empty', 'custom_weglot_default_current_language' );
function custom_weglot_default_current_language( $language ) {
    // Use French instead of the original language.
    return weglot_get_service( 'Language_Service_Weglot' )->get_language_from_internal( 'fr' );
}
```

{% hint style="warning" %}
Always return a language object. Returning `true`, a string or `null` makes every caller of the current language fail with a fatal error.
{% endhint %}


# weglot\_active\_translation

The master switch for Weglot's page translation. Return `false` to disable translation entirely.

```php
add_filter( 'weglot_active_translation', '__return_false' );
```


# weglot\_active\_slugs

Controls whether Weglot loads and applies translated URL slugs. Return `false` to disable them.

```php
add_filter( 'weglot_active_slugs', '__return_false' );
```


# weglot\_is\_eligible\_url

Lets you force whether a URL counts as translatable for the language switcher, the `hreflang` tags and the `weglot_is_eligible_url()` helper. The filter receives the current decision and the URL object.

```php
add_filter( 'weglot_is_eligible_url', 'custom_weglot_is_eligible_url', 10, 2 );
function custom_weglot_is_eligible_url( $eligible, $weglot_url ) {
    // return true or false to force eligibility
    return $eligible;
}
```

{% hint style="warning" %}
This filter does **not** stop the page from being translated. To keep a page in its original language, use `weglot_active_translation_before_process` (see [Exclude a Custom Post Type](/cms/wordpress/use-cases/exclude-a-custom-post-type)) or the URL exclusions.
{% endhint %}




---

[Next Page](https://developers.weglot.com/llms-full.txt/1)

