Elementor is a very popular page builder plugin integrated with WPML. Using its API functions, developers can create additional Elementor widgets. This page explains how to make these custom widgets translatable using WPML.

To make it easier to follow this page, we took one of Elementor’s widgets and extended it to include WPML support. You can find it on this GitHub page.

Adding WPML translation support

Widget plugins should add the wpml_elementor_widgets_to_translate filter during their “init” action. WPML calls this filter to get further information about the different widget texts that need to be translated.

WPML filter for Elementor widgets
add_filter( 'wpml_elementor_widgets_to_translate', [ $this, 'wpml_widgets_to_translate_filter' ] );

This filter passes the array that lists all the widget types that need to be translated. This array includes default Elementor parts and information about what needs translating.

Any new widget types should be added to this structure, as in the following example.

Adding Elementor widgets
public function wpml_widgets_to_translate_filter( $widgets ) {
  $widgets[ $this->get_name() ] = [
     'conditions' => [ 'widgetType' => $this->get_name() ],
     'fields'     => [
        [
           'field'       => 'title',
           'type'        => __( 'Hello World Title', 'hello-world' ),
           'editor_type' => 'LINE'
        ],
     ],
  ];

  return $widgets;
}

Translation support for simple fields

The code example above shows how translation support is added for simple fields. As you can see, there are some guidelines you should follow:

  • Use the widget name as the key to the new structure that is added to the nodes array.
  • The new structure needs two further items:
    • condition – an array of conditions to meet. Usually, it is ‘widgetType’ => widget name.
    • fields – an array of fields that have text that needs translation.

Each of these fields requires the following elements:

  1. field – The id of the field. This is the same as the id used when adding a control via the Control_stack::add_control function.
  2. type – The type of field. This is the text displayed in the WPML Translation Editor to help the translator know what field is to be translated.
  3. editor_type – This is the type of text field used in the WPML translation editor. Valid values are LINE, AREA, and VISUAL.

Translation of more complicated widgets

Some widgets have more complicated structures. To add translation support to these widgets, you can create a custom class for handling the translations and implement the IWPML_Page_Builders_Module interface.

You can find more examples for this in the core WPML plugin’s folder (wp-content\plugins\sitepress-multilingual-cms\vendor\wpml\page-builders-elementor\src\modules).

First, use the integration-class field to specify the class name that will be used.

Specifying a custom class that features more complicated widgets
public function wpml_widgets_to_translate_filter( $widgets ) {
  $widgets[ $this->get_name() ] = [
     'conditions' => [ 'widgetType' => $this->get_name() ],
     'fields'     => [],
      'integration-class' => 'My_Custom_Widget_WPML_Support’,
     ],
  ];

  return $widgets;
}

The integration class needs to implement the get and update functions. The get function returns the list of strings that need translation and the update function updates the Elementor data when a translation is received.

The following code provides an example of such a custom class.

Example of a custom class that features more complicated widgets
/**
* Class IWPML_Page_Builders_Module
*/
interface IWPML_Page_Builders_Module {
  /**
   * @param string|int $node_id
   * @param mixed $element
   * @param WPML_PB_String[] $strings
   *
   * @return WPML_PB_String[]
   */
  public function get( $node_id, $element, $strings );

  /**
   * @param string|int $node_id
   * @param mixed $element
   * @param WPML_PB_String $string
   *
   * @return array
   */
  public function update( $node_id, $element, WPML_PB_String $string );
}

Widgets with lists of other elements

Some widgets can feature lists of other elements, for example, the Elementor Slides widget. Custom widgets like these can extend the WPML_Elementor_Module_With_Items class.

The following WPML_Elementor_Slides class example shows how to do this.

Example of a custom class that features a list of other elements
/**
* Class WPML_Elementor_Slides
*/
class WPML_Elementor_Slides extends WPML_Elementor_Module_With_Items {

  /**
   * @return string
   */
  public function get_items_field() {
     return 'slides';
  }

  /**
   * @return array
   */
  public function get_fields() {
     return array( 'heading', 'description', 'button_text' );
  }

  /**
   * @param string $field
   *
   * @return string
   */
  protected function get_title( $field ) {
     switch( $field ) {
        case 'heading':
           return esc_html__( 'Slides: heading', 'wpml-string-translation' );

        case 'description':
           return esc_html__( 'Slides: description', 'wpml-string-translation' );

        case 'button_text':
           return esc_html__( 'Slides: button text', 'wpml-string-translation' );

        default:
           return '';
     }
  }

  /**
   * @param string $field
   *
   * @return string
   */
  protected function get_editor_type( $field ) {
     switch( $field ) {
        case 'heading':
        case 'button_text':
           return 'LINE';

        case 'description':
           return 'VISUAL';

        default:
           return '';
     }
  }

}

You can find more examples in the core WPML plugin’s folder (wp-content\plugins\sitepress-multilingual-cms\vendor\wpml\page-builders-elementor\src\modules).