[\n\r]*)([\n\r]{1}\[\/et_)/m'; const REGEX_REMOVE_CLOSING_PARAGRAPH = '/(\[et_.*\][\n\r]{1})([\n\r]*<\/p>)/m'; /** @var SitePress */ private $sitepress; /** * @param SitePress $sitepress */ public function __construct( SitePress $sitepress ) { $this->sitepress = $sitepress; } public function add_hooks() { if ( $this->sitepress->is_setup_complete() ) { add_action( 'init', [ $this, 'load_resources_if_they_are_required' ], 10, 0 ); add_filter( 'et_builder_load_actions', [ $this, 'load_builder_for_ajax_actions' ] ); add_action( 'admin_init', [ $this, 'display_warning_notice' ], 10, 0 ); add_filter( 'wpml_pb_should_handle_content', [ $this, 'should_handle_shortcode_content' ], 10, 2 ); add_filter( 'wpml_pb_shortcode_content_for_translation', [ $this, 'cleanup_global_layout_content' ], 10, 2 ); add_filter( 'icl_job_elements', [ $this, 'remove_old_content_from_translation' ], 10, 2 ); add_filter( 'wpml_words_count_custom_fields_to_count', [ $this, 'remove_old_content_from_words_count' ], 10, 2 ); } } /** * @return bool */ private function is_standard_editor_used() { $tm_settings = $this->sitepress->get_setting( 'translation-management', [] ); return ! isset( $tm_settings['doc_translation_method'] ) || ICL_TM_TMETHOD_MANUAL === $tm_settings['doc_translation_method']; } public function display_warning_notice() { $notices = wpml_get_admin_notices(); if ( $this->is_standard_editor_used() ) { $notices->add_notice( new WPML_Compatibility_Divi_Notice() ); } elseif ( $notices->get_notice( WPML_Compatibility_Divi_Notice::ID, WPML_Compatibility_Divi_Notice::GROUP ) ) { $notices->remove_notice( WPML_Compatibility_Divi_Notice::GROUP, WPML_Compatibility_Divi_Notice::ID ); } } /** * These actions require the custom widget area to be initialized. * * @param array $actions * @return array */ public function load_builder_for_ajax_actions( $actions ) { $actions[] = 'save-widget'; $actions[] = 'widgets-order'; $actions[] = 'wpml-ls-save-settings'; return $actions; } public function load_resources_if_they_are_required() { if ( ! isset( $_GET['page'] ) || ! is_admin() ) { /* phpcs:ignore */ return; } $pages = [ self::get_duplication_action_page() ]; if ( self::is_tm_active() ) { $pages[] = self::get_translation_dashboard_page(); $pages[] = self::get_translation_editor_page(); } if ( self::is_sl_active() ) { $pages[] = self::get_sl_page(); } if ( in_array( $_GET['page'], $pages, true ) ) { /* phpcs:ignore */ $this->register_layouts(); } } private static function get_translation_dashboard_page() { return constant( 'WPML_TM_FOLDER' ) . '/menu/main.php'; } private static function get_translation_editor_page() { return constant( 'WPML_TM_FOLDER' ) . '/menu/translations-queue.php'; } private static function get_duplication_action_page() { return constant( 'WPML_PLUGIN_FOLDER' ) . '/menu/languages.php'; } private static function get_sl_page() { return 'wpml-sticky-links'; } private static function is_tm_active() { return defined( 'WPML_TM_FOLDER' ); } private static function is_sl_active() { return defined( 'WPML_STICKY_LINKS_VERSION' ); } private function register_layouts() { /** * @phpstan-ignore-next-line */ if ( function_exists( 'et_builder_should_load_framework' ) && ! et_builder_should_load_framework() ) { if ( function_exists( 'et_builder_register_layouts' ) ) { /** * @phpstan-ignore-next-line */ et_builder_register_layouts(); } else { $lib_file = ET_BUILDER_DIR . 'feature/Library.php'; if ( ! class_exists( 'ET_Builder_Library' ) && defined( 'ET_BUILDER_DIR' ) && file_exists( $lib_file ) ) { require_once $lib_file; } if ( class_exists( 'ET_Builder_Library' ) ) { ET_Builder_Library::instance(); } } } } /** * The global layout is not properly extracted from the page * because it adds

tags either not opened or not closed. * * See the global content below as an example: * * [et_pb_section prev_background_color="#000000" next_background_color="#000000"][et_pb_text] * *

*

Global text 1 EN5

*

* * [/et_pb_text][/et_pb_section] * * We also need to remove `prev_background` and `next_background` attributes which are added from the page. * * @param string $content * @param int $post_id */ public function cleanup_global_layout_content( $content, $post_id ) { if ( 'et_pb_layout' === get_post_type( $post_id ) ) { $content = preg_replace( self::REGEX_REMOVE_OPENING_PARAGRAPH, '$2', $content ); $content = preg_replace( self::REGEX_REMOVE_CLOSING_PARAGRAPH, '$1', $content ); $content = preg_replace( '/( prev_background_color="#[0-9a-f]*")/', '', $content ); $content = preg_replace( '/( next_background_color="#[0-9a-f]*")/', '', $content ); } return $content; } public function should_handle_shortcode_content( $handle_content, $shortcode ) { if ( strpos( $shortcode['tag'], 'et_' ) === 0 && strpos( $shortcode['attributes'], 'global_module=' ) !== false ) { // If a translatable attribute has been excluded from sync, we need to handle it. $handle_content = $this->is_excluded_from_sync( $shortcode ); } return $handle_content; } /** * Check if a global module has excluded any translatable text that we need to handle * * @param array $shortcode * { * @type string $tag. * @type string $content. * @type string $attributes. * } * @return bool */ private function is_excluded_from_sync( $shortcode ) { $handle_content = false; preg_match( '/global_module="([0-9]+)"/', $shortcode['attributes'], $matches ); $excluded = json_decode( get_post_meta( $matches[1], '_et_pb_excluded_global_options', true ), true ); if ( is_array( $excluded ) && count( $excluded ) > 0 ) { $attributes = $this->get_translatable_shortcode_attributes( $shortcode['tag'] ); foreach ( $excluded as $field ) { if ( in_array( $field, $attributes, true ) ) { $handle_content = true; break; } } } return $handle_content; } /** * Get a list of translatable attributes for a shortcode tag. * This includes the inner content and any attributes found in XML configuration. * * @param string $tag The shortcode tag. * @return array */ private function get_translatable_shortcode_attributes( $tag ) { $attributes = [ 'et_pb_content_field' ]; $settings = get_option( 'icl_st_settings', [] ); if ( ! isset( $settings['pb_shortcode'] ) ) { return $attributes; } foreach ( $settings['pb_shortcode'] as $setting ) { if ( $tag === $setting['tag']['value'] ) { foreach ( $setting['attributes'] as $attribute ) { if ( empty( $attribute['type'] ) ) { $attributes[] = $attribute['value']; } } break; } } return $attributes; } /** * Remove the `_et_pb_old_content` meta field from translation jobs, except for products. * * @param array $fields Array of fields to translate. * @param object $post_id The ID of the post being translated. * * @return array */ public function remove_old_content_from_translation( $fields, $post_id ) { // Bail out early if its a product. if ( 'product' === get_post_type( $post_id ) ) { return $fields; } // Search for the _et_pb_old_content element and empty it. $field_types = wp_list_pluck( $fields, 'field_type' ); $index = array_search( 'field-_et_pb_old_content-0', $field_types, true ); if ( false !== $index ) { $fields[ $index ]->field_data = ''; $fields[ $index ]->field_data_translated = ''; } return $fields; } /** * Remove the `_et_pb_old_content` meta field from words count, except for products. * * @param array $fields_to_count Array of custom fields to count. * @param object $post_id The ID of the post for which we are counting the words. * * @return array */ public function remove_old_content_from_words_count( $fields_to_count, $post_id ) { if ( 'product' !== get_post_type( $post_id ) ) { $index = array_search( '_et_pb_old_content', $fields_to_count, true ); if ( false !== $index ) { unset( $fields_to_count[ $index ] ); } } return $fields_to_count; } }