The actual problem: WPML + Themify Builder is not maintainable
We run a multilingual website with WPML and dozens of pages in multiple languages. Two bugs make this setup unmaintainable in practice:
- Hook Content Conditions set for the original page never apply to translated pages – each condition would have to be manually duplicated for each translation
- Builder styles do not automatically synchronize to translated pages – editors must manually open each translated page in the Builder after every layout change to apply the styles
Both problems have the same cause: Themify Builder does not fully utilize the integration APIs provided by WPML.
Background: How WPML manages pages
WPML links pages across languages via translation relationships, which are accessible through a dedicated API:
// Übersetzung einer Seite in einer anderen Sprache ermitteln
$translated_id = apply_filters('wpml_object_id', $post_id, 'page', false, $lang);
// Aktuelle / Standard-Sprache abfragen
$current_lang = apply_filters('wpml_current_language', null);
$default_lang = apply_filters('wpml_default_language', null);These APIs exist precisely so that plugins can work WPML-compatible without duplicating logic per language.
Bug 1: Hook Content Conditions do not apply to translated pages
In themify/class-hook-contents.php, check_visibility() builds the page path via child_post_name():
// class-hook-contents.php ~Zeile 179
in_array( '/' . self::child_post_name( $query_object ) . '/', $posts )child_post_name() recursively runs over post_parent and concatenates the post_name values. On a translated page, this returns the English slug, e.g.:
/services/production-and-delivery-of-green-hydrogen/However, the saved Visibility Condition contains the German slug (default language):
/leistungen/produktion-und-lieferung-von-gruenem-wasserstoff/The in_array() comparison always fails → Hook Content is never output on translated pages.
Expected Fix – resolve to the original language version before comparison:
$original_id = apply_filters('wpml_object_id', $query_object->ID, 'page', false, $default_lang);
$original_post = get_post($original_id);
$original_path = '/' . self::child_post_name($original_p