first commit
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\BeaverBuilder\Config;
|
||||
|
||||
class Factory extends \WPML\PB\Config\Factory {
|
||||
|
||||
const DATA = [
|
||||
'configRoot' => 'beaver-builder-widgets',
|
||||
'defaultConditionKey' => 'type',
|
||||
'pbKey' => 'beaver-builder',
|
||||
'translatableWidgetsHook' => 'wpml_beaver_builder_modules_to_translate',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getPbData( $key ) {
|
||||
return self::DATA[ $key ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\BeaverBuilder\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class Editor implements \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'wpml_pb_is_editing_translation_with_native_editor', 10, 2 )
|
||||
->then( spreadArgs( function( $isTranslationWithNativeEditor, $translatedPostId ) {
|
||||
return $isTranslationWithNativeEditor
|
||||
|| (
|
||||
Obj::path( [ 'fl_builder_data', 'action' ], $_POST ) === 'save_layout'
|
||||
&& (int) Obj::path( [ 'fl_builder_data', 'post_id' ], $_POST ) === $translatedPostId
|
||||
);
|
||||
|
||||
} ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\BeaverBuilder\TranslationJob;
|
||||
|
||||
use WPML_Beaver_Builder_Data_Settings;
|
||||
|
||||
class Hooks implements \IWPML_Backend_Action, \IWPML_Frontend_Action, \IWPML_DIC_Action {
|
||||
|
||||
/** @var WPML_Beaver_Builder_Data_Settings $dataSettings */
|
||||
private $dataSettings;
|
||||
|
||||
public function __construct( WPML_Beaver_Builder_Data_Settings $dataSettings ) {
|
||||
$this->dataSettings = $dataSettings;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_tm_translation_job_data', [ $this, 'filterFieldsByPageBuilderKind' ], PHP_INT_MAX, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translationPackage
|
||||
* @param \stdClass|\WP_Post $post
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filterFieldsByPageBuilderKind( array $translationPackage, $post ) {
|
||||
if ( ! $this->isPostPackage( $translationPackage, $post ) ) {
|
||||
return $translationPackage;
|
||||
}
|
||||
|
||||
if ( $this->dataSettings->is_handling_post( $post->ID ) ) {
|
||||
return $this->removeFieldsFromKind( $translationPackage, $post->ID, 'gutenberg' );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
return $this->removeFieldsFromKind( $translationPackage, $post->ID, 'beaver-builder' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translationPackage
|
||||
* @param \stdClass|\WP_Post $post
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isPostPackage( array $translationPackage, $post ) {
|
||||
return 'external' !== $translationPackage['type'] && isset( $post->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translationPackage
|
||||
* @param int $postId
|
||||
* @param string $kindSlug
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function removeFieldsFromKind( array $translationPackage, $postId, $kindSlug ) {
|
||||
$packageIdToRemove = wpml_collect( apply_filters( 'wpml_st_get_post_string_packages', [], $postId ) )
|
||||
->pluck( 'ID', 'kind_slug' )
|
||||
->get( $kindSlug );
|
||||
|
||||
if ( $packageIdToRemove ) {
|
||||
$isFieldFromPackageToRemove = function( $value, $key ) use ( $packageIdToRemove ) {
|
||||
return preg_match( '/^package-string-' . $packageIdToRemove . '-/', $key );
|
||||
};
|
||||
|
||||
$translationPackage['contents'] = wpml_collect( $translationPackage['contents'] )
|
||||
->reject( $isFieldFromPackageToRemove )
|
||||
->toArray();
|
||||
}
|
||||
|
||||
return $translationPackage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Data_Settings_For_Media extends WPML_Beaver_Builder_Data_Settings {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields_to_copy() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Data_Settings implements IWPML_Page_Builders_Data_Settings {
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_meta_field() {
|
||||
return '_fl_builder_data';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_node_id_field() {
|
||||
return 'node';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields_to_copy() {
|
||||
return array( '_fl_builder_draft_settings', '_fl_builder_data_settings', '_fl_builder_enabled' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function convert_data_to_array( $data ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function prepare_data_for_saving( array $data ) {
|
||||
return $this->slash( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_pb_name(){
|
||||
return 'Beaver builder';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields_to_save() {
|
||||
return array( '_fl_builder_data', '_fl_builder_draft' );
|
||||
}
|
||||
|
||||
public function add_hooks(){}
|
||||
|
||||
/**
|
||||
* Adds slashes to data going into the database as WordPress
|
||||
* removes them when we save using update_metadata. This is done
|
||||
* to ensure slashes in user input aren't removed.
|
||||
*
|
||||
* Inspired by `\FLBuilderModel::slash_settings`
|
||||
*
|
||||
* @param mixed $data The data to slash.
|
||||
*
|
||||
* @return mixed The slashed data.
|
||||
*/
|
||||
private function slash( $data ) {
|
||||
if ( is_array( $data ) ) {
|
||||
foreach ( $data as $key => $val ) {
|
||||
$data[ $key ] = $this->slash( $val );
|
||||
}
|
||||
} elseif ( is_object( $data ) ) {
|
||||
foreach ( $data as $key => $val ) {
|
||||
$data->$key = $this->slash( $val );
|
||||
}
|
||||
} elseif ( is_string( $data ) ) {
|
||||
$data = wp_slash( $data );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_handling_post( $postId ) {
|
||||
return (bool) get_post_meta( $postId, '_fl_builder_enabled', true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
class WPML_PB_Beaver_Builder_Handle_Custom_Fields_Factory implements IWPML_Backend_Action_Loader, IWPML_AJAX_Action_Loader, IWPML_Frontend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_PB_Handle_Custom_Fields( new WPML_Beaver_Builder_Data_Settings() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Integration_Factory {
|
||||
|
||||
const SLUG = 'beaver-builder';
|
||||
|
||||
public function create() {
|
||||
$action_filter_loader = new WPML_Action_Filter_Loader();
|
||||
$action_filter_loader->load(
|
||||
array(
|
||||
'WPML_PB_Beaver_Builder_Handle_Custom_Fields_Factory',
|
||||
'WPML_Beaver_Builder_Media_Hooks_Factory',
|
||||
\WPML\PB\BeaverBuilder\TranslationJob\Hooks::class,
|
||||
\WPML\PB\BeaverBuilder\Config\Factory::class,
|
||||
\WPML\PB\BeaverBuilder\Hooks\Editor::class,
|
||||
)
|
||||
);
|
||||
|
||||
$nodes = new WPML_Beaver_Builder_Translatable_Nodes();
|
||||
$data_settings = new WPML_Beaver_Builder_Data_Settings();
|
||||
|
||||
$string_registration_factory = new WPML_String_Registration_Factory( $data_settings->get_pb_name() );
|
||||
$string_registration = $string_registration_factory->create();
|
||||
|
||||
$register_strings = new WPML_Beaver_Builder_Register_Strings( $nodes, $data_settings, $string_registration );
|
||||
$update_translation = new WPML_Beaver_Builder_Update_Translation( $nodes, $data_settings );
|
||||
|
||||
return new WPML_Page_Builders_Integration( $register_strings, $update_translation, $data_settings );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Beaver_Builder_Register_Strings
|
||||
*/
|
||||
class WPML_Beaver_Builder_Register_Strings extends WPML_Page_Builders_Register_Strings {
|
||||
|
||||
/**
|
||||
* @param array $data_array
|
||||
* @param array $package
|
||||
*/
|
||||
protected function register_strings_for_modules( array $data_array, array $package ) {
|
||||
foreach ( $data_array as $data ) {
|
||||
if ( is_array( $data ) ) {
|
||||
$data = $this->sort_modules_before_string_registration( $data );
|
||||
$this->register_strings_for_modules( $data, $package );
|
||||
} elseif ( is_object( $data ) ) {
|
||||
if ( isset( $data->type, $data->node, $data->settings ) && 'module' === $data->type && ! $this->is_embedded_global_module( $data ) ) {
|
||||
$this->register_strings_for_node( $data->node, $data->settings, $package );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The modules are not in the order they appear on the page,
|
||||
* so we need to sort it before to register the strings.
|
||||
*
|
||||
* @param array $modules
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function sort_modules_before_string_registration( array $modules ) {
|
||||
if ( count( $modules ) > 1 ) {
|
||||
uasort( $modules, array( $this, 'sort_modules_by_position_only' ) );
|
||||
return $this->sort_modules_by_parent_and_child( $modules );
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* We receive all modules as a flat tree and we need to reorder from:
|
||||
* - child A
|
||||
* - child A
|
||||
* - parent A
|
||||
* - child B
|
||||
* - parent B
|
||||
* - child B
|
||||
* - child C
|
||||
*
|
||||
* To:
|
||||
* - parent A
|
||||
* - child A
|
||||
* - child B
|
||||
* - parent B
|
||||
* - child A
|
||||
* - child B
|
||||
* - child C
|
||||
*
|
||||
* The relative positions are already sorted by `sort_modules_by_position_only`
|
||||
*
|
||||
* @param array $all_modules
|
||||
* @param string|null $parent_hash
|
||||
* @param array $sorted_modules
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function sort_modules_by_parent_and_child( array $all_modules, $parent_hash = null, array $sorted_modules = array() ){
|
||||
foreach ( $all_modules as $hash => $module ) {
|
||||
|
||||
if ( $module->parent === $parent_hash ) {
|
||||
$sorted_modules[ $hash ] = $module;
|
||||
unset( $all_modules[ $hash ] );
|
||||
$sorted_modules = $this->sort_modules_by_parent_and_child( $all_modules, $module->node, $sorted_modules );
|
||||
}
|
||||
}
|
||||
|
||||
return $sorted_modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass $a
|
||||
* @param stdClass $b
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function sort_modules_by_position_only( stdClass $a, stdClass $b ) {
|
||||
return ( (int) $a->position < (int) $b->position ) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_embedded_global_module( $data ) {
|
||||
return ! empty( $data->template_node_id ) && isset( $data->node ) && $data->template_node_id !== $data->node;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
<?php
|
||||
/**
|
||||
* WPML_Beaver_Builder_Translatable_Nodes class file.
|
||||
*
|
||||
* @package wpml-page-builders-beaver-builder
|
||||
*/
|
||||
|
||||
use WPML\PB\BeaverBuilder\Modules\ModuleWithItemsFromConfig;
|
||||
|
||||
/**
|
||||
* Class WPML_Beaver_Builder_Translatable_Nodes
|
||||
*/
|
||||
class WPML_Beaver_Builder_Translatable_Nodes implements IWPML_Page_Builders_Translatable_Nodes {
|
||||
|
||||
/**
|
||||
* Nodes to translate.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $nodes_to_translate;
|
||||
|
||||
/**
|
||||
* Get translatable node.
|
||||
*
|
||||
* @param string|int $node_id Node id.
|
||||
* @param stdClass $settings Node settings.
|
||||
*
|
||||
* @return WPML_PB_String[]
|
||||
*/
|
||||
public function get( $node_id, $settings ) {
|
||||
if ( ! $this->nodes_to_translate ) {
|
||||
$this->initialize_nodes_to_translate();
|
||||
}
|
||||
|
||||
$strings = array();
|
||||
|
||||
foreach ( $this->nodes_to_translate as $node_type => $node_data ) {
|
||||
if ( $this->conditions_ok( $node_data, $settings ) ) {
|
||||
foreach ( $node_data['fields'] as $field ) {
|
||||
$field_key = $field['field'];
|
||||
if ( isset( $settings->$field_key ) && trim( $settings->$field_key ) ) {
|
||||
|
||||
$string = new WPML_PB_String(
|
||||
$settings->$field_key,
|
||||
$this->get_string_name( $node_id, $field, $settings ),
|
||||
$field['type'],
|
||||
$field['editor_type'],
|
||||
$this->get_wrap_tag( $settings )
|
||||
);
|
||||
|
||||
$strings[] = $string;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $this->get_integration_instances( $node_data ) as $node ) {
|
||||
try {
|
||||
$strings = $node->get( $node_id, $settings, $strings );
|
||||
// phpcs:disable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
} catch ( Exception $e ) {}
|
||||
// phpcs:enable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update translatable node.
|
||||
*
|
||||
* @param string $node_id Node id.
|
||||
* @param stdClass $settings Node settings.
|
||||
* @param WPML_PB_String $string String object.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function update( $node_id, $settings, WPML_PB_String $string ) {
|
||||
if ( ! $this->nodes_to_translate ) {
|
||||
$this->initialize_nodes_to_translate();
|
||||
}
|
||||
|
||||
foreach ( $this->nodes_to_translate as $node_type => $node_data ) {
|
||||
if ( $this->conditions_ok( $node_data, $settings ) ) {
|
||||
foreach ( $node_data['fields'] as $field ) {
|
||||
$field_key = $field['field'];
|
||||
if ( $this->get_string_name( $node_id, $field, $settings ) === $string->get_name() ) {
|
||||
$settings->$field_key = $string->get_value();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $this->get_integration_instances( $node_data ) as $node ) {
|
||||
try {
|
||||
$node->update( $node_id, $settings, $string );
|
||||
// phpcs:disable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
} catch ( Exception $e ) {}
|
||||
// phpcs:enable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $node_data
|
||||
*
|
||||
* @return WPML_Beaver_Builder_Module_With_Items[]
|
||||
*/
|
||||
private function get_integration_instances( array $node_data ) {
|
||||
$instances = [];
|
||||
|
||||
if ( isset( $node_data['integration-class'] ) ) {
|
||||
try {
|
||||
$instances[] = new $node_data['integration-class']();
|
||||
// phpcs:disable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
} catch ( Exception $e ) {}
|
||||
// phpcs:enable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
}
|
||||
|
||||
if ( isset( $node_data['fields_in_item'] ) ) {
|
||||
foreach ( $node_data['fields_in_item'] as $item_of => $config ) {
|
||||
$instances[] = new ModuleWithItemsFromConfig( $item_of, $config );
|
||||
}
|
||||
}
|
||||
|
||||
return array_filter( $instances );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string name.
|
||||
*
|
||||
* @param string $node_id Node id.
|
||||
* @param array $field Page builder field.
|
||||
* @param stdClass $settings Node settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_string_name( $node_id, $field, $settings ) {
|
||||
return $field['field'] . '-' . $settings->type . '-' . $node_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get wrap tag for string.
|
||||
* Used for SEO, can contain (h1...h6, etc.)
|
||||
*
|
||||
* @param stdClass $settings Field settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_wrap_tag( $settings ) {
|
||||
if ( isset( $settings->type ) && 'heading' === $settings->type && isset( $settings->tag ) ) {
|
||||
return $settings->tag;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if node condition is ok.
|
||||
*
|
||||
* @param array $node_data Node data.
|
||||
* @param stdClass $settings Node settings.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function conditions_ok( $node_data, $settings ) {
|
||||
$conditions_meet = true;
|
||||
foreach ( $node_data['conditions'] as $field_key => $field_value ) {
|
||||
if ( ! isset( $settings->$field_key ) || $settings->$field_key !== $field_value ) {
|
||||
$conditions_meet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $conditions_meet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_nodes_to_translate() {
|
||||
return array(
|
||||
'button' => array(
|
||||
'conditions' => array( 'type' => 'button' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'text',
|
||||
'type' => __( 'Button: Text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'link',
|
||||
'type' => __( 'Button: Link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
),
|
||||
),
|
||||
),
|
||||
'heading' => array(
|
||||
'conditions' => array( 'type' => 'heading' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'heading',
|
||||
'type' => __( 'Heading', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'link',
|
||||
'type' => __( 'Heading: Link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
),
|
||||
),
|
||||
),
|
||||
'html' => array(
|
||||
'conditions' => array( 'type' => 'html' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'html',
|
||||
'type' => __( 'HTML', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
),
|
||||
),
|
||||
'photo' => array(
|
||||
'conditions' => array( 'type' => 'photo' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'link_url',
|
||||
'type' => __( 'Photo: Link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
),
|
||||
),
|
||||
),
|
||||
'rich-text' => array(
|
||||
'conditions' => array( 'type' => 'rich-text' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'text',
|
||||
'type' => __( 'Text Editor', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
),
|
||||
),
|
||||
'accordion' => array(
|
||||
'conditions' => array( 'type' => 'accordion' ),
|
||||
'fields' => array(),
|
||||
'integration-class' => 'WPML_Beaver_Builder_Accordion',
|
||||
),
|
||||
'pricing-table' => array(
|
||||
'conditions' => array( 'type' => 'pricing-table' ),
|
||||
'fields' => array(),
|
||||
'integration-class' => 'WPML_Beaver_Builder_Pricing_Table',
|
||||
),
|
||||
'tabs' => array(
|
||||
'conditions' => array( 'type' => 'tabs' ),
|
||||
'fields' => array(),
|
||||
'integration-class' => 'WPML_Beaver_Builder_Tab',
|
||||
),
|
||||
'callout' => array(
|
||||
'conditions' => array( 'type' => 'callout' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'title',
|
||||
'type' => __( 'Callout: Heading', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'text',
|
||||
'type' => __( 'Callout: Text', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
array(
|
||||
'field' => 'cta_text',
|
||||
'type' => __( 'Callout: Call to action text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'link',
|
||||
'type' => __( 'Callout: Link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
),
|
||||
),
|
||||
),
|
||||
'contact-form' => array(
|
||||
'conditions' => array( 'type' => 'contact-form' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'name_placeholder',
|
||||
'type' => __( 'Contact Form: Name Field Placeholder', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'subject_placeholder',
|
||||
'type' => __( 'Contact Form: Subject Field Placeholder', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'email_placeholder',
|
||||
'type' => __( 'Contact Form: Email Field Placeholder', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'phone_placeholder',
|
||||
'type' => __( 'Contact Form: Phone Field Placeholder', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'message_placeholder',
|
||||
'type' => __( 'Contact Form: Your Message Placeholder', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'terms_checkbox_text',
|
||||
'type' => __( 'Contact Form: Checkbox Text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'terms_text',
|
||||
'type' => __( 'Contact Form: Terms and Conditions', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
array(
|
||||
'field' => 'success_message',
|
||||
'type' => __( 'Contact Form: Success Message', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
array(
|
||||
'field' => 'btn_text',
|
||||
'type' => __( 'Contact Form: Button Text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'success_url',
|
||||
'type' => __( 'Contact Form: Redirect Link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
),
|
||||
),
|
||||
),
|
||||
'call-to-action' => array(
|
||||
'conditions' => array( 'type' => 'cta' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'title',
|
||||
'type' => __( 'Call to Action: Heading', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'text',
|
||||
'type' => __( 'Call to Action: Text', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
array(
|
||||
'field' => 'btn_text',
|
||||
'type' => __( 'Call to Action: Button text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'btn_link',
|
||||
'type' => __( 'Call to Action: Button link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
),
|
||||
|
||||
),
|
||||
),
|
||||
'subscribe-form' => array(
|
||||
'conditions' => array( 'type' => 'subscribe-form' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'terms_checkbox_text',
|
||||
'type' => __( 'Subscribe form: Checkbox Text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'terms_text',
|
||||
'type' => __( 'Subscribe form: Terms and Conditions', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
array(
|
||||
'field' => 'custom_subject',
|
||||
'type' => __( 'Subscribe form: Notification Subject', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'success_message',
|
||||
'type' => __( 'Subscribe form: Success Message', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
array(
|
||||
'field' => 'btn_text',
|
||||
'type' => __( 'Subscribe form: Button Text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'success_url',
|
||||
'type' => __( 'Subscribe form: Redirect Link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
),
|
||||
),
|
||||
),
|
||||
'content-slider' => array(
|
||||
'conditions' => array( 'type' => 'content-slider' ),
|
||||
'fields' => array(),
|
||||
'integration-class' => 'WPML_Beaver_Builder_Content_Slider',
|
||||
),
|
||||
'icon' => array(
|
||||
'conditions' => array( 'type' => 'icon' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'text',
|
||||
'type' => __( 'Icon: Text', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
array(
|
||||
'field' => 'link',
|
||||
'type' => __( 'Icon: Link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
),
|
||||
),
|
||||
),
|
||||
'icon-group' => array(
|
||||
'conditions' => array( 'type' => 'icon-group' ),
|
||||
'fields' => array(),
|
||||
'integration-class' => 'WPML_Beaver_Builder_Icon_Group',
|
||||
),
|
||||
'map' => array(
|
||||
'conditions' => array( 'type' => 'map' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'address',
|
||||
'type' => __( 'Map: Address', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
),
|
||||
),
|
||||
'testimonials' => array(
|
||||
'conditions' => array( 'type' => 'testimonials' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'heading',
|
||||
'type' => __( 'Testimonial: Heading', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
|
||||
),
|
||||
'integration-class' => 'WPML_Beaver_Builder_Testimonials',
|
||||
),
|
||||
'numbers' => array(
|
||||
'conditions' => array( 'type' => 'numbers' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'before_number_text',
|
||||
'type' => __( 'Number Counter: Text before number', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'after_number_text',
|
||||
'type' => __( 'Number Counter: Text after number', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'number_prefix',
|
||||
'type' => __( 'Number Counter: Number Prefix', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'number_suffix',
|
||||
'type' => __( 'Number Counter: Number Suffix', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
),
|
||||
),
|
||||
'post-grid' => array(
|
||||
'conditions' => array( 'type' => 'post-grid' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'no_results_message',
|
||||
'type' => __( 'Posts: No Results Message', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
),
|
||||
array(
|
||||
'field' => 'more_btn_text',
|
||||
'type' => __( 'Posts: Button Text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'terms_list_label',
|
||||
'type' => __( 'Posts: Terms Label', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
array(
|
||||
'field' => 'more_link_text',
|
||||
'type' => __( 'Posts: More Link Text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
),
|
||||
),
|
||||
'post-slider' => array(
|
||||
'conditions' => array( 'type' => 'post-slider' ),
|
||||
'fields' => array(
|
||||
array(
|
||||
'field' => 'more_link_text',
|
||||
'type' => __( 'Posts Slider: More Link Text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize translatable nodes.
|
||||
*/
|
||||
public function initialize_nodes_to_translate() {
|
||||
$this->nodes_to_translate = apply_filters( 'wpml_beaver_builder_modules_to_translate', self::get_nodes_to_translate() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Beaver_Builder_Update_Translation
|
||||
*/
|
||||
class WPML_Beaver_Builder_Update_Translation extends WPML_Page_Builders_Update_Translation {
|
||||
|
||||
/** @param array $data_array */
|
||||
public function update_strings_in_modules( array &$data_array ) {
|
||||
foreach ( $data_array as &$data ) {
|
||||
if ( is_array( $data ) ) {
|
||||
$this->update_strings_in_modules( $data );
|
||||
} elseif ( is_object( $data ) ) {
|
||||
if ( isset( $data->type, $data->node, $data->settings ) && 'module' === $data->type ) {
|
||||
$data->settings = $this->update_strings_in_node( $data->node, $data->settings );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $node_id
|
||||
* @param array $settings
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function update_strings_in_node( $node_id, $settings ) {
|
||||
$strings = $this->translatable_nodes->get( $node_id, $settings );
|
||||
foreach ( $strings as $string ) {
|
||||
$translation = $this->get_translation( $string );
|
||||
$settings = $this->translatable_nodes->update( $node_id, $settings, $translation );
|
||||
}
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Media_Hooks_Factory implements IWPML_Backend_Action_Loader, IWPML_Frontend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_Page_Builders_Media_Hooks(
|
||||
new WPML_Beaver_Builder_Update_Media_Factory(),
|
||||
WPML_Beaver_Builder_Integration_Factory::SLUG
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Media_Node_Provider {
|
||||
|
||||
/** @var WPML_Page_Builders_Media_Translate $media_translate */
|
||||
private $media_translate;
|
||||
|
||||
/** @var WPML_Beaver_Builder_Media_Node[] */
|
||||
private $nodes = array();
|
||||
|
||||
public function __construct( WPML_Page_Builders_Media_Translate $media_translate ) {
|
||||
$this->media_translate = $media_translate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return WPML_Beaver_Builder_Media_Node|null
|
||||
*/
|
||||
public function get( $type ) {
|
||||
if ( ! array_key_exists( $type, $this->nodes ) ) {
|
||||
switch ( $type ) {
|
||||
case 'photo':
|
||||
$node = new WPML_Beaver_Builder_Media_Node_Photo( $this->media_translate );
|
||||
break;
|
||||
|
||||
case 'gallery':
|
||||
$node = new WPML_Beaver_Builder_Media_Node_Gallery( $this->media_translate );
|
||||
break;
|
||||
|
||||
case 'content-slider':
|
||||
$node = new WPML_Beaver_Builder_Media_Node_Content_Slider( $this->media_translate );
|
||||
break;
|
||||
|
||||
case 'slideshow':
|
||||
$node = new WPML_Beaver_Builder_Media_Node_Slideshow( $this->media_translate );
|
||||
break;
|
||||
|
||||
default:
|
||||
$node = null;
|
||||
}
|
||||
|
||||
$this->nodes[ $type ] = $node;
|
||||
}
|
||||
|
||||
return $this->nodes[ $type ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Media_Nodes_Iterator implements IWPML_PB_Media_Nodes_Iterator {
|
||||
|
||||
/** @var WPML_Beaver_Builder_Media_Node_Provider $node_provider */
|
||||
private $node_provider;
|
||||
|
||||
public function __construct( WPML_Beaver_Builder_Media_Node_Provider $node_provider ) {
|
||||
$this->node_provider = $node_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data_array
|
||||
* @param string $lang
|
||||
* @param string $source_lang
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function translate( $data_array, $lang, $source_lang ) {
|
||||
foreach ( $data_array as &$data ) {
|
||||
if ( is_array( $data ) ) {
|
||||
$data = $this->translate( $data, $lang, $source_lang );
|
||||
} elseif ( is_object( $data )
|
||||
&& isset( $data->type ) && 'module' === $data->type
|
||||
&& isset( $data->settings ) && isset( $data->settings->type )
|
||||
) {
|
||||
$data->settings = $this->translate_node( $data->settings, $lang, $source_lang );
|
||||
}
|
||||
}
|
||||
|
||||
return $data_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass $settings
|
||||
* @param string $lang
|
||||
* @param string $source_lang
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function translate_node( $settings, $lang, $source_lang ) {
|
||||
$node = $this->node_provider->get( $settings->type );
|
||||
|
||||
if ( $node ) {
|
||||
$settings = $node->translate( $settings, $lang, $source_lang );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Update_Media_Factory implements IWPML_PB_Media_Update_Factory {
|
||||
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
|
||||
$media_translate = new WPML_Page_Builders_Media_Translate(
|
||||
new WPML_Translation_Element_Factory( $sitepress ),
|
||||
new WPML_Media_Image_Translate( $sitepress, new WPML_Media_Attachment_By_URL_Factory() )
|
||||
);
|
||||
|
||||
return new WPML_Page_Builders_Update_Media(
|
||||
new WPML_Page_Builders_Update( new WPML_Beaver_Builder_Data_Settings_For_Media() ),
|
||||
new WPML_Translation_Element_Factory( $sitepress ),
|
||||
new WPML_Beaver_Builder_Media_Nodes_Iterator(
|
||||
new WPML_Beaver_Builder_Media_Node_Provider( $media_translate )
|
||||
),
|
||||
new WPML_Page_Builders_Media_Usage( $media_translate, new WPML_Media_Usage_Factory() )
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Media_Node_Content_Slider extends WPML_Beaver_Builder_Media_Node {
|
||||
|
||||
private $property_prefixes = array(
|
||||
'bg_', // i.e. `bg_photo` for an ID or `bg_photo_src` for a URL
|
||||
'fg_',
|
||||
'r_',
|
||||
);
|
||||
|
||||
public function translate( $node_data, $target_lang, $source_lang ) {
|
||||
if ( ! isset( $node_data->slides ) || ! is_array( $node_data->slides ) ) {
|
||||
return $node_data;
|
||||
}
|
||||
|
||||
foreach ( $node_data->slides as &$slide ) {
|
||||
|
||||
foreach ( $this->property_prefixes as $prefix ) {
|
||||
$id_prop = $prefix . 'photo';
|
||||
$src_prop = $prefix . 'photo_src';
|
||||
|
||||
if ( isset( $slide->{$id_prop} ) && $slide->{$id_prop} ) {
|
||||
$slide->{$id_prop} = $this->media_translate->translate_id( $slide->{$id_prop}, $target_lang );
|
||||
}
|
||||
|
||||
if ( isset( $slide->{$src_prop} ) && $slide->{$src_prop} ) {
|
||||
$slide->{$src_prop} = $this->media_translate->translate_image_url( $slide->{$src_prop}, $target_lang, $source_lang );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $node_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Media_Node_Gallery extends WPML_Beaver_Builder_Media_Node {
|
||||
|
||||
public function translate( $node_data, $target_lang, $source_lang ) {
|
||||
foreach ( $node_data->photos as &$photo ) {
|
||||
$photo = $this->media_translate->translate_id( $photo, $target_lang );
|
||||
}
|
||||
|
||||
foreach ( $node_data->photo_data as &$photo_data ) {
|
||||
$translated_id = $this->media_translate->translate_id( $photo_data->id, $target_lang );
|
||||
|
||||
if ( $translated_id !== $photo_data->id ) {
|
||||
$translation_data = wp_prepare_attachment_for_js( $translated_id );
|
||||
$photo_data->id = $translated_id;
|
||||
$photo_data->alt = $translation_data['alt'];
|
||||
$photo_data->caption = $translation_data['caption'];
|
||||
$photo_data->description = $translation_data['description'];
|
||||
$photo_data->title = $translation_data['title'];
|
||||
$photo_data->src = $translation_data['url'];
|
||||
$photo_data->link = $translation_data['url'];
|
||||
}
|
||||
}
|
||||
|
||||
return $node_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Media_Node_Photo extends WPML_Beaver_Builder_Media_Node {
|
||||
|
||||
public function translate( $node_data, $target_lang, $source_lang ) {
|
||||
$translated_id = $this->media_translate->translate_id( $node_data->photo, $target_lang );
|
||||
|
||||
if ( $translated_id !== $node_data->photo ) {
|
||||
$node_data->photo = $translated_id;
|
||||
$node_data->photo_src = $this->media_translate->translate_image_url( $node_data->photo_src, $target_lang, $source_lang );
|
||||
$node_data->data = wp_prepare_attachment_for_js( $translated_id );
|
||||
}
|
||||
|
||||
return $node_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @group media
|
||||
*/
|
||||
class WPML_Beaver_Builder_Media_Node_Slideshow extends WPML_Beaver_Builder_Media_Node {
|
||||
|
||||
private $url_properties = array(
|
||||
'largeURL',
|
||||
'x3largeURL',
|
||||
'thumbURL',
|
||||
);
|
||||
|
||||
public function translate( $node_data, $target_lang, $source_lang ) {
|
||||
if ( ! isset( $node_data->photos, $node_data->photo_data ) || ! is_array( $node_data->photos ) ) {
|
||||
return $node_data;
|
||||
}
|
||||
|
||||
foreach ( $node_data->photos as &$photo ) {
|
||||
$photo = $this->media_translate->translate_id( $photo, $target_lang );
|
||||
}
|
||||
|
||||
foreach ( $node_data->photo_data as $photo_id => $photo_data ) {
|
||||
$translated_id = $this->media_translate->translate_id( $photo_id, $target_lang );
|
||||
|
||||
if ( $translated_id !== $photo_id ) {
|
||||
$translation_data = wp_prepare_attachment_for_js( $translated_id );
|
||||
$photo_data->caption = $translation_data['caption'];
|
||||
|
||||
foreach ( $this->url_properties as $property ) {
|
||||
|
||||
if ( isset( $photo_data->{$property} ) && $photo_data->{$property} ) {
|
||||
$photo_data->{$property} = $this->media_translate->translate_image_url( $photo_data->{$property}, $target_lang, $source_lang );
|
||||
}
|
||||
}
|
||||
|
||||
$node_data->photo_data[ $translated_id ] = $photo_data;
|
||||
unset( $node_data->photo_data[ $photo_id ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $node_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
abstract class WPML_Beaver_Builder_Media_Node {
|
||||
|
||||
/** @var WPML_Page_Builders_Media_Translate $media_translate */
|
||||
protected $media_translate;
|
||||
|
||||
public function __construct( WPML_Page_Builders_Media_Translate $media_translate ) {
|
||||
$this->media_translate = $media_translate;
|
||||
}
|
||||
|
||||
abstract function translate( $node_data, $target_lang, $source_lang );
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\BeaverBuilder\Modules;
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Obj;
|
||||
|
||||
class ModuleWithItemsFromConfig extends \WPML_Beaver_Builder_Module_With_Items {
|
||||
|
||||
/** @var array $fieldDefinitions */
|
||||
private $fieldDefinitions = [];
|
||||
|
||||
/** @var string $itemsField */
|
||||
private $itemsField;
|
||||
|
||||
/**
|
||||
* @param string $itemsField
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct( $itemsField, array $config ) {
|
||||
$this->itemsField = $itemsField;
|
||||
$this->init( $config );
|
||||
}
|
||||
|
||||
private function init( array $config ) {
|
||||
$keyByField = Fns::converge( Lst::zipObj(), [ Lst::pluck( 'field' ), Fns::identity() ] );
|
||||
$this->fieldDefinitions = $keyByField( $config );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_title( $field ) {
|
||||
return Obj::path( [ $field, 'type' ], $this->fieldDefinitions );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_fields() {
|
||||
return array_keys( $this->fieldDefinitions );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_editor_type( $field ) {
|
||||
return Obj::path( [ $field, 'editor_type' ], $this->fieldDefinitions );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function &get_items( $settings ) {
|
||||
return $settings->{$this->itemsField};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Accordion extends WPML_Beaver_Builder_Module_With_Items {
|
||||
|
||||
protected function get_title( $field ) {
|
||||
switch( $field ) {
|
||||
case 'label':
|
||||
return esc_html__( 'Accordion Item Label', 'sitepress' );
|
||||
|
||||
case 'content':
|
||||
return esc_html__( 'Accordion Item Content', 'sitepress' );
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Content_Slider extends WPML_Beaver_Builder_Module_With_Items {
|
||||
|
||||
public function &get_items( $settings ) {
|
||||
return $settings->slides;
|
||||
}
|
||||
|
||||
public function get_fields() {
|
||||
return array( 'title', 'text', 'cta_text', 'link' );
|
||||
}
|
||||
|
||||
protected function get_title( $field ) {
|
||||
switch( $field ) {
|
||||
case 'title':
|
||||
return esc_html__( 'Content Slider: Slide heading', 'sitepress' );
|
||||
|
||||
case 'text':
|
||||
return esc_html__( 'Content Slider: Slide content', 'sitepress' );
|
||||
|
||||
case 'cta_text':
|
||||
return esc_html__( 'Content Slider: Slide call to action text', 'sitepress' );
|
||||
|
||||
case 'link':
|
||||
return esc_html__( 'Content Slider: Slide call to action link', 'sitepress' );
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_editor_type( $field ) {
|
||||
switch( $field ) {
|
||||
case 'title':
|
||||
case 'cta_text':
|
||||
return 'LINE';
|
||||
|
||||
case 'link':
|
||||
return 'LINK';
|
||||
|
||||
case 'text':
|
||||
return 'VISUAL';
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Icon_Group extends WPML_Beaver_Builder_Module_With_Items {
|
||||
|
||||
public function &get_items( $settings ) {
|
||||
return $settings->icons;
|
||||
}
|
||||
|
||||
public function get_fields() {
|
||||
return array( 'link' );
|
||||
}
|
||||
|
||||
protected function get_title( $field ) {
|
||||
switch ( $field ) {
|
||||
case 'link':
|
||||
return esc_html__( 'Icon link', 'sitepress' );
|
||||
|
||||
default:
|
||||
return '';
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_editor_type( $field ) {
|
||||
switch ( $field ) {
|
||||
case 'link':
|
||||
return 'LINK';
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Beaver_Builder_Module_With_Items
|
||||
*/
|
||||
abstract class WPML_Beaver_Builder_Module_With_Items implements IWPML_Page_Builders_Module {
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_title( $field );
|
||||
|
||||
/** @return array */
|
||||
protected function get_fields() {
|
||||
return array( 'label', 'content' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_editor_type( $field ) {
|
||||
switch( $field ) {
|
||||
case 'label':
|
||||
return 'LINE';
|
||||
|
||||
case 'content':
|
||||
return 'VISUAL';
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function &get_items( $settings ) {
|
||||
return $settings->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $node_id
|
||||
* @param object $settings
|
||||
* @param WPML_PB_String[] $strings
|
||||
*
|
||||
* @return WPML_PB_String[]
|
||||
*/
|
||||
public function get( $node_id, $settings, $strings ) {
|
||||
foreach ( $this->get_items( $settings ) as $item ) {
|
||||
foreach( $this->get_fields() as $field ) {
|
||||
if ( is_array( $item->$field ) ) {
|
||||
foreach ( $item->$field as $key => $value ) {
|
||||
$strings[] = new WPML_PB_String(
|
||||
$value,
|
||||
$this->get_string_name( $node_id, $value, $field, $key ),
|
||||
$this->get_title( $field ),
|
||||
$this->get_editor_type( $field )
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$strings[] = new WPML_PB_String(
|
||||
$item->$field,
|
||||
$this->get_string_name( $node_id, $item->$field, $field ),
|
||||
$this->get_title( $field ),
|
||||
$this->get_editor_type( $field )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $node_id
|
||||
* @param object $settings
|
||||
* @param WPML_PB_String $string
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function update( $node_id, $settings, WPML_PB_String $string ) {
|
||||
foreach ( $this->get_items( $settings ) as &$item ) {
|
||||
foreach( $this->get_fields() as $field ) {
|
||||
if ( is_array( $item->$field ) ) {
|
||||
foreach ( $item->$field as $key => &$value ) {
|
||||
if ( $this->get_string_name( $node_id, $value, $field, $key ) == $string->get_name() ) {
|
||||
$value = $string->get_value();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( $this->get_string_name( $node_id, $item->$field, $field ) == $string->get_name() ) {
|
||||
$item->$field = $string->get_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function get_string_name( $node_id, $value, $type, $key = '' ) {
|
||||
return md5( $value ) . '-' . $type . $key . '-' . $node_id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Pricing_Table extends WPML_Beaver_Builder_Module_With_Items {
|
||||
|
||||
public function &get_items( $settings ) {
|
||||
return $settings->pricing_columns;
|
||||
}
|
||||
|
||||
public function get_fields() {
|
||||
return array( 'title', 'button_text', 'button_url', 'features', 'price', 'duration' );
|
||||
}
|
||||
|
||||
protected function get_title( $field ) {
|
||||
switch ( $field ) {
|
||||
case 'title':
|
||||
return esc_html__( 'Pricing table: Title', 'sitepress' );
|
||||
|
||||
case 'button_text':
|
||||
return esc_html__( 'Pricing table: Button text', 'sitepress' );
|
||||
|
||||
case 'button_url':
|
||||
return esc_html__( 'Pricing table: Button link', 'sitepress' );
|
||||
|
||||
case 'features':
|
||||
return esc_html__( 'Pricing table: Feature', 'sitepress' );
|
||||
|
||||
case 'price':
|
||||
return esc_html__( 'Pricing table: Price', 'sitepress' );
|
||||
|
||||
case 'duration':
|
||||
return esc_html__( 'Pricing table: Duration', 'sitepress' );
|
||||
|
||||
default:
|
||||
return '';
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_editor_type( $field ) {
|
||||
switch ( $field ) {
|
||||
case 'title':
|
||||
case 'button_text':
|
||||
case 'price':
|
||||
case 'duration':
|
||||
return 'LINE';
|
||||
|
||||
case 'button_url':
|
||||
return 'LINK';
|
||||
|
||||
case 'features':
|
||||
return 'VISUAL';
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Tab extends WPML_Beaver_Builder_Module_With_Items {
|
||||
|
||||
protected function get_title( $field ) {
|
||||
switch( $field ) {
|
||||
case 'label':
|
||||
return esc_html__( 'Tab Item Label', 'sitepress' );
|
||||
|
||||
case 'content':
|
||||
return esc_html__( 'Tab Item Content', 'sitepress' );
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
class WPML_Beaver_Builder_Testimonials extends WPML_Beaver_Builder_Module_With_Items {
|
||||
|
||||
public function &get_items( $settings ) {
|
||||
return $settings->testimonials;
|
||||
}
|
||||
|
||||
public function get_fields() {
|
||||
return array( 'testimonial' );
|
||||
}
|
||||
|
||||
protected function get_title( $field ) {
|
||||
switch( $field ) {
|
||||
case 'testimonial':
|
||||
return esc_html__( 'Testimonial content', 'sitepress' );
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_editor_type( $field ) {
|
||||
switch( $field ) {
|
||||
case 'testimonial':
|
||||
return 'VISUAL';
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Cornerstone\Config;
|
||||
|
||||
class Factory extends \WPML\PB\Config\Factory {
|
||||
|
||||
const DATA = [
|
||||
'configRoot' => 'cornerstone-widgets',
|
||||
'defaultConditionKey' => '_type',
|
||||
'pbKey' => 'cornerstone',
|
||||
'translatableWidgetsHook' => 'wpml_cornerstone_modules_to_translate',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getPbData( $key ) {
|
||||
return self::DATA[ $key ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Cornerstone\Hooks;
|
||||
|
||||
use WPML\FP\Cast;
|
||||
use WPML\FP\Maybe;
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Str;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class Editor implements \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'wpml_pb_is_editing_translation_with_native_editor', 10, 2 )
|
||||
->then( spreadArgs( function( $isTranslationWithNativeEditor, $translatedPostId ) {
|
||||
return $isTranslationWithNativeEditor
|
||||
|| (
|
||||
Str::includes( 'themeco/data/save', Obj::prop( 'REQUEST_URI', $_SERVER ) )
|
||||
&& self::getEditedId() === $translatedPostId
|
||||
);
|
||||
} ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
private static function getEditedId() {
|
||||
/**
|
||||
* @see \Cornerstone_Routing::process_params
|
||||
* $decodeCornerstoneData :: string -> array
|
||||
*/
|
||||
$decodeCornerstoneData = function( $data ) {
|
||||
$request = Obj::prop( 'request', $data );
|
||||
|
||||
if ( Obj::prop( 'gzip', $data ) ) {
|
||||
return (array) json_decode( gzdecode( base64_decode( $request, true ) ), true );
|
||||
}
|
||||
|
||||
return (array) $request;
|
||||
};
|
||||
|
||||
return Maybe::fromNullable( \WP_REST_Server::get_raw_data() )
|
||||
->map( 'json_decode' )
|
||||
->map( $decodeCornerstoneData )
|
||||
->map( Obj::path( [ 'requests', 'builder', 'id' ] ) )
|
||||
->map( Cast::toInt() )
|
||||
->getOrElse( null );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Cornerstone\Styles;
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Logic;
|
||||
use WPML\FP\Maybe;
|
||||
use WPML\LIB\WP\Post;
|
||||
|
||||
class Hooks implements \IWPML_Backend_Action, \IWPML_Frontend_Action, \IWPML_DIC_Action {
|
||||
|
||||
const META_KEY_OLD = '_cs_generated_styles';
|
||||
const META_KEY_V6 = '_cs_generated_tss';
|
||||
|
||||
/** @var callable $shouldInvalidateStyle */
|
||||
private $shouldInvalidateStyles;
|
||||
|
||||
/**
|
||||
* Hooks constructor.
|
||||
*
|
||||
* @param \WPML_PB_Last_Translation_Edit_Mode $lastEditMode
|
||||
* @param \WPML_Cornerstone_Data_Settings $dataSettings
|
||||
*/
|
||||
public function __construct(
|
||||
\WPML_PB_Last_Translation_Edit_Mode $lastEditMode,
|
||||
\WPML_Cornerstone_Data_Settings $dataSettings
|
||||
) {
|
||||
$this->shouldInvalidateStyles = Logic::both( [ $dataSettings, 'is_handling_post' ], [ $lastEditMode, 'is_translation_editor' ] );
|
||||
}
|
||||
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'save_post', [ $this, 'invalidateStylesInTranslation' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
*/
|
||||
public function invalidateStylesInTranslation( $postId ) {
|
||||
Maybe::of( $postId )
|
||||
->filter( $this->shouldInvalidateStyles )
|
||||
->map( Fns::tap( Post::deleteMeta( Fns::__, self::META_KEY_V6 ) ) )
|
||||
->map( Fns::tap( Post::deleteMeta( Fns::__, self::META_KEY_OLD ) ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Data_Settings implements IWPML_Page_Builders_Data_Settings {
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_meta_field() {
|
||||
return '_cornerstone_data';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_node_id_field() {
|
||||
return '_type';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields_to_copy() {
|
||||
return array( '_cornerstone_settings', '_cornerstone_version', 'post_content' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function convert_data_to_array( $data ) {
|
||||
$converted_data = $data;
|
||||
if ( is_array( $data ) ) {
|
||||
$converted_data = $data[0];
|
||||
}
|
||||
|
||||
return json_decode( $converted_data, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function prepare_data_for_saving( array $data ) {
|
||||
return wp_slash( wp_json_encode( $data ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_pb_name() {
|
||||
return 'Cornerstone';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields_to_save() {
|
||||
return array( '_cornerstone_data' );
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_handling_post( $postId ) {
|
||||
return get_post_meta( $postId, $this->get_meta_field(), true )
|
||||
&& ! get_post_meta( $postId, '_cornerstone_override', true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
class WPML_PB_Cornerstone_Handle_Custom_Fields_Factory implements IWPML_Backend_Action_Loader, IWPML_AJAX_Action_Loader, IWPML_Frontend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_PB_Handle_Custom_Fields( new WPML_Cornerstone_Data_Settings() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use function WPML\Container\make;
|
||||
|
||||
class WPML_Cornerstone_Integration_Factory {
|
||||
|
||||
const SLUG = 'cornerstone';
|
||||
|
||||
public function create() {
|
||||
$action_filter_loader = new WPML_Action_Filter_Loader();
|
||||
$action_filter_loader->load(
|
||||
[
|
||||
'WPML_PB_Cornerstone_Handle_Custom_Fields_Factory',
|
||||
'WPML_Cornerstone_Media_Hooks_Factory',
|
||||
\WPML\PB\Cornerstone\Config\Factory::class,
|
||||
\WPML\PB\Cornerstone\Styles\Hooks::class,
|
||||
\WPML\PB\Cornerstone\Hooks\Editor::class,
|
||||
]
|
||||
);
|
||||
|
||||
$nodes = new WPML_Cornerstone_Translatable_Nodes();
|
||||
$data_settings = new WPML_Cornerstone_Data_Settings();
|
||||
|
||||
$string_registration_factory = new WPML_String_Registration_Factory( $data_settings->get_pb_name() );
|
||||
$string_registration = $string_registration_factory->create();
|
||||
|
||||
$factory = make( WPML_PB_Factory::class );
|
||||
$strategy = make( WPML_PB_API_Hooks_Strategy::class, [ ':name' => $data_settings->get_pb_name() ] );
|
||||
$strategy->set_factory( $factory );
|
||||
|
||||
$reuse_translation = make( WPML_PB_Reuse_Translations_By_Strategy::class, [ ':strategy' => $strategy ] );
|
||||
|
||||
$register_strings = new WPML_Cornerstone_Register_Strings( $nodes, $data_settings, $string_registration, $reuse_translation );
|
||||
$update_translation = new WPML_Cornerstone_Update_Translation( $nodes, $data_settings );
|
||||
|
||||
return new WPML_Page_Builders_Integration( $register_strings, $update_translation, $data_settings );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
use WPML\PB\Cornerstone\Utils;
|
||||
|
||||
class WPML_Cornerstone_Register_Strings extends WPML_Page_Builders_Register_Strings {
|
||||
|
||||
/**
|
||||
* @param array $data_array
|
||||
* @param array $package
|
||||
*/
|
||||
protected function register_strings_for_modules( array $data_array, array $package ) {
|
||||
foreach ( $data_array as $data ) {
|
||||
if ( isset( $data['_type'] ) && ! Utils::typeIsLayout( $data['_type'] ) ) {
|
||||
$this->register_strings_for_node( Utils::getNodeId( $data ), $data, $package );
|
||||
} elseif ( is_array( $data ) ) {
|
||||
$this->register_strings_for_modules( $data, $package );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
<?php
|
||||
/**
|
||||
* WPML_Cornerstone_Translatable_Nodes class file.
|
||||
*
|
||||
* @package wpml-page-builders-cornerstone
|
||||
*/
|
||||
|
||||
use WPML\PB\Cornerstone\Modules\ModuleWithItemsFromConfig;
|
||||
use WPML\FP\Obj;
|
||||
|
||||
/**
|
||||
* Class WPML_Cornerstone_Translatable_Nodes
|
||||
*/
|
||||
class WPML_Cornerstone_Translatable_Nodes implements IWPML_Page_Builders_Translatable_Nodes {
|
||||
|
||||
const SETTINGS_FIELD = '_modules';
|
||||
|
||||
/**
|
||||
* Nodes to translate.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $nodes_to_translate;
|
||||
|
||||
/**
|
||||
* Get translatable node.
|
||||
*
|
||||
* @param string|int $node_id Node id.
|
||||
* @param array $settings Node settings.
|
||||
*
|
||||
* @return WPML_PB_String[]
|
||||
*/
|
||||
public function get( $node_id, $settings ) {
|
||||
|
||||
if ( ! $this->nodes_to_translate ) {
|
||||
$this->initialize_nodes_to_translate();
|
||||
}
|
||||
|
||||
$strings = array();
|
||||
|
||||
foreach ( $this->nodes_to_translate as $node_type => $node_data ) {
|
||||
if ( $this->conditions_ok( $node_data, $settings ) ) {
|
||||
foreach ( $node_data['fields'] as $field ) {
|
||||
$field_key = $field['field'];
|
||||
if ( isset( $settings[ $field_key ] ) && trim( $settings[ $field_key ] ) ) {
|
||||
|
||||
$string = new WPML_PB_String(
|
||||
$settings[ $field_key ],
|
||||
$this->get_string_name( $node_id, $field, $settings ),
|
||||
$field['type'],
|
||||
$field['editor_type'],
|
||||
$this->get_wrap_tag( $settings )
|
||||
);
|
||||
|
||||
$strings[] = $string;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $this->get_integration_instances( $node_data ) as $node ) {
|
||||
$strings = $node->get( $node_id, $settings, $strings );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update translatable node.
|
||||
*
|
||||
* @param string $node_id Node id.
|
||||
* @param array $settings Node settings.
|
||||
* @param WPML_PB_String $string String object.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function update( $node_id, $settings, WPML_PB_String $string ) {
|
||||
|
||||
if ( ! $this->nodes_to_translate ) {
|
||||
$this->initialize_nodes_to_translate();
|
||||
}
|
||||
|
||||
foreach ( $this->nodes_to_translate as $node_type => $node_data ) {
|
||||
if ( $this->conditions_ok( $node_data, $settings ) ) {
|
||||
foreach ( $node_data['fields'] as $field ) {
|
||||
$field_key = $field['field'];
|
||||
if ( $this->get_string_name( $node_id, $field, $settings ) === $string->get_name() ) {
|
||||
$settings[ $field_key ] = $string->get_value();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $this->get_integration_instances( $node_data ) as $node ) {
|
||||
$settings = $node->update( $node_id, $settings, $string );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $node_data
|
||||
*
|
||||
* @return WPML_Cornerstone_Module_With_Items[]
|
||||
*/
|
||||
private function get_integration_instances( $node_data ) {
|
||||
$instances = [];
|
||||
|
||||
if ( isset( $node_data['integration-class'] ) ) {
|
||||
try {
|
||||
$instances[] = new $node_data['integration-class']();
|
||||
// phpcs:disable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
} catch ( Exception $e ) {}
|
||||
// phpcs:enable Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
}
|
||||
|
||||
if ( isset( $node_data['fields_in_item'] ) ) {
|
||||
foreach ( $node_data['fields_in_item'] as $config ) {
|
||||
$instances[] = new ModuleWithItemsFromConfig( $config );
|
||||
}
|
||||
}
|
||||
|
||||
return $instances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string name.
|
||||
*
|
||||
* @param string $node_id Node id.
|
||||
* @param array $field Page builder field.
|
||||
* @param array $settings Node settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_string_name( $node_id, $field, $settings ) {
|
||||
return $field['field'] . '-' . $settings['_type'] . '-' . $node_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get wrap tag for string.
|
||||
* Used for SEO, can contain (h1...h6, etc.)
|
||||
*
|
||||
* @param array $settings Field settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_wrap_tag( $settings ) {
|
||||
if ( isset( $settings['_type'] ) && 'headline' === $settings['_type'] ) {
|
||||
return Obj::propOr( 'h1', 'text_tag', $settings );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if node condition is ok.
|
||||
*
|
||||
* @param array $node_data Node data.
|
||||
* @param array $settings Node settings.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function conditions_ok( $node_data, $settings ) {
|
||||
$conditions_meet = true;
|
||||
foreach ( $node_data['conditions'] as $field_key => $field_value ) {
|
||||
if ( ! isset( $settings[ $field_key ] ) || $settings[ $field_key ] !== $field_value ) {
|
||||
$conditions_meet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $conditions_meet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
public static function get_nodes_to_translate() {
|
||||
return [
|
||||
'card' => [
|
||||
'conditions' => [ '_type' => 'card' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'card_front_text_content',
|
||||
'type' => __( 'Card: front text content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
[
|
||||
'field' => 'card_back_text_content',
|
||||
'type' => __( 'Card: back text content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
[
|
||||
'field' => 'anchor_text_primary_content',
|
||||
'type' => __( 'Card: anchor text primary content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
[
|
||||
'field' => 'anchor_text_secondary_content',
|
||||
'type' => __( 'Card: anchor text secondary content', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
[
|
||||
'field' => 'anchor_href',
|
||||
'type' => __( 'Card: anchor link', 'sitepress' ),
|
||||
'editor_type' => 'LINK',
|
||||
],
|
||||
],
|
||||
],
|
||||
'alert' => [
|
||||
'conditions' => [ '_type' => 'alert' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'alert_content',
|
||||
'type' => __( 'Alert Content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
],
|
||||
],
|
||||
'text' => [
|
||||
'conditions' => [ '_type' => 'text' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'text_content',
|
||||
'type' => __( 'Text content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
],
|
||||
],
|
||||
'quote' => [
|
||||
'conditions' => [ '_type' => 'quote' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'quote_content',
|
||||
'type' => __( 'Quote content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
[
|
||||
'field' => 'quote_cite_content',
|
||||
'type' => __( 'Quote: cite content', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
],
|
||||
],
|
||||
'counter' => [
|
||||
'conditions' => [ '_type' => 'counter' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'counter_number_prefix_content',
|
||||
'type' => __( 'Counter: number prefix', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
[
|
||||
'field' => 'counter_number_suffix_content',
|
||||
'type' => __( 'Counter: number suffix', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
],
|
||||
],
|
||||
'content-area' => [
|
||||
'conditions' => [ '_type' => 'content-area' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'content',
|
||||
'type' => __( 'Content Area: content', 'sitepress' ),
|
||||
'editor_type' => 'AREA',
|
||||
],
|
||||
],
|
||||
],
|
||||
'breadcrumbs' => [
|
||||
'conditions' => [ '_type' => 'breadcrumbs' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'breadcrumbs_home_label_text',
|
||||
'type' => __( 'Breadcrumbs: home label text', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
],
|
||||
],
|
||||
'audio' => [
|
||||
'conditions' => [ '_type' => 'audio' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'audio_embed_code',
|
||||
'type' => __( 'Audio: embed code', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
],
|
||||
],
|
||||
'headline' => [
|
||||
'conditions' => [ '_type' => 'headline' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'text_content',
|
||||
'type' => __( 'Headline text content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
],
|
||||
],
|
||||
'content-area-off-canvas' => [
|
||||
'conditions' => [ '_type' => 'content-area-off-canvas' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'off_canvas_content',
|
||||
'type' => __( 'Canvas content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
],
|
||||
],
|
||||
'content-area-modal' => [
|
||||
'conditions' => [ '_type' => 'content-area-modal' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'modal_content',
|
||||
'type' => __( 'Modal content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
],
|
||||
],
|
||||
'content-area-dropdown' => [
|
||||
'conditions' => [ '_type' => 'content-area-dropdown' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'dropdown_content',
|
||||
'type' => __( 'Dropdown content', 'sitepress' ),
|
||||
'editor_type' => 'VISUAL',
|
||||
],
|
||||
],
|
||||
],
|
||||
'button' => [
|
||||
'conditions' => [ '_type' => 'button' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'anchor_text_primary_content',
|
||||
'type' => __( 'Anchor text: primary content', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
[
|
||||
'field' => 'anchor_text_secondary_content',
|
||||
'type' => __( 'Anchor text: secondary content', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
],
|
||||
],
|
||||
'video' => [
|
||||
'conditions' => [ '_type' => 'video' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'video_embed_code',
|
||||
'type' => __( 'Video: embed code', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
],
|
||||
],
|
||||
'search-inline' => [
|
||||
'conditions' => [ '_type' => 'search-inline' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'search_placeholder',
|
||||
'type' => __( 'Search Inline: placeholder', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
],
|
||||
],
|
||||
'search-modal' => [
|
||||
'conditions' => [ '_type' => 'search-modal' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'search_placeholder',
|
||||
'type' => __( 'Search Modal: placeholder', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
],
|
||||
],
|
||||
'search-dropdown' => [
|
||||
'conditions' => [ '_type' => 'search-dropdown' ],
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'search_placeholder',
|
||||
'type' => __( 'Search Dropdown: placeholder', 'sitepress' ),
|
||||
'editor_type' => 'LINE',
|
||||
],
|
||||
],
|
||||
],
|
||||
'accordion' => [
|
||||
'conditions' => [ '_type' => 'accordion' ],
|
||||
'fields' => [],
|
||||
'integration-class' => 'WPML_Cornerstone_Accordion',
|
||||
],
|
||||
'tabs' => [
|
||||
'conditions' => [ '_type' => 'tabs' ],
|
||||
'fields' => [],
|
||||
'integration-class' => 'WPML_Cornerstone_Tabs',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize translatable nodes.
|
||||
*/
|
||||
public function initialize_nodes_to_translate() {
|
||||
$this->nodes_to_translate = apply_filters( 'wpml_cornerstone_modules_to_translate', self::get_nodes_to_translate() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use WPML\PB\Cornerstone\Utils;
|
||||
|
||||
class WPML_Cornerstone_Update_Translation extends WPML_Page_Builders_Update_Translation {
|
||||
|
||||
/** @param array $data_array */
|
||||
public function update_strings_in_modules( array &$data_array ) {
|
||||
foreach ( $data_array as $key => &$data ) {
|
||||
if ( isset( $data['_type'] ) && ! Utils::typeIsLayout( $data['_type'] ) ) {
|
||||
$data = $this->update_strings_in_node( Utils::getNodeId( $data ), $data );
|
||||
} elseif ( is_array( $data ) ) {
|
||||
$this->update_strings_in_modules( $data );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $node_id
|
||||
* @param array $settings
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function update_strings_in_node( $node_id, $settings ) {
|
||||
$strings = $this->translatable_nodes->get( $node_id, $settings );
|
||||
foreach ( $strings as $string ) {
|
||||
$translation = $this->get_translation( $string );
|
||||
$settings = $this->translatable_nodes->update( $node_id, $settings, $translation );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Cornerstone;
|
||||
|
||||
class Utils {
|
||||
|
||||
const MODULE_TYPE_PREFIX = 'classic:';
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public static function getNodeId( $data ) {
|
||||
return md5( serialize( $data ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the type is a layout type.
|
||||
*
|
||||
* @param string $type The type to check.
|
||||
* @return bool
|
||||
*/
|
||||
public static function typeIsLayout( $type ) {
|
||||
// Remove the classic prefix before checking.
|
||||
$type = preg_replace( '/^' . self::MODULE_TYPE_PREFIX . '/', '', $type );
|
||||
|
||||
return in_array(
|
||||
$type,
|
||||
[ 'bar', 'container', 'section', 'row', 'column', 'layout-row', 'layout-column', 'layout-grid', 'layout-cell' ],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Hooks_Factory implements IWPML_Backend_Action_Loader, IWPML_Frontend_Action_Loader {
|
||||
public function create() {
|
||||
return new WPML_Page_Builders_Media_Hooks(
|
||||
new WPML_Cornerstone_Update_Media_Factory(),
|
||||
WPML_Cornerstone_Integration_Factory::SLUG
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Node_Provider {
|
||||
|
||||
private $media_translate;
|
||||
|
||||
private $nodes = array();
|
||||
|
||||
public function __construct( WPML_Page_Builders_Media_Translate $media_translate ) {
|
||||
$this->media_translate = $media_translate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return WPML_Cornerstone_Media_Node|null
|
||||
*/
|
||||
public function get( $type ) {
|
||||
if ( ! array_key_exists( $type, $this->nodes ) ) {
|
||||
$this->add( $type );
|
||||
}
|
||||
|
||||
return $this->nodes[ $type ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*/
|
||||
private function add( $type ) {
|
||||
switch ( $type ) {
|
||||
case 'image':
|
||||
$node = new WPML_Cornerstone_Media_Node_Image( $this->media_translate );
|
||||
break;
|
||||
|
||||
case 'classic:creative-cta':
|
||||
$node = new WPML_Cornerstone_Media_Node_Classic_Creative_CTA( $this->media_translate );
|
||||
break;
|
||||
|
||||
case 'classic:feature-box':
|
||||
$node = new WPML_Cornerstone_Media_Node_Classic_Feature_Box( $this->media_translate );
|
||||
break;
|
||||
|
||||
case 'classic:card':
|
||||
$node = new WPML_Cornerstone_Media_Node_Classic_Card( $this->media_translate );
|
||||
break;
|
||||
|
||||
case 'classic:image':
|
||||
$node = new WPML_Cornerstone_Media_Node_Classic_Image( $this->media_translate );
|
||||
break;
|
||||
|
||||
case 'classic:promo':
|
||||
$node = new WPML_Cornerstone_Media_Node_Classic_Promo( $this->media_translate );
|
||||
break;
|
||||
|
||||
default:
|
||||
$node = null;
|
||||
}
|
||||
|
||||
$this->nodes[ $type ] = $node;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Nodes_Iterator implements IWPML_PB_Media_Nodes_Iterator {
|
||||
|
||||
const ITEMS_FIELD = WPML_Cornerstone_Module_With_Items::ITEMS_FIELD;
|
||||
|
||||
/** @var WPML_Cornerstone_Media_Node_Provider $node_provider */
|
||||
private $node_provider;
|
||||
public function __construct( WPML_Cornerstone_Media_Node_Provider $node_provider ) {
|
||||
$this->node_provider = $node_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data_array
|
||||
* @param string $lang
|
||||
* @param string $source_lang
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function translate( $data_array, $lang, $source_lang ) {
|
||||
foreach ( $data_array as $key => &$data ) {
|
||||
if ( isset( $data[ self::ITEMS_FIELD ] ) && $data[ self::ITEMS_FIELD ] ) {
|
||||
$data[ self::ITEMS_FIELD ] = $this->translate( $data[ self::ITEMS_FIELD ], $lang, $source_lang );
|
||||
} elseif ( is_numeric( $key ) && isset( $data['_type'] ) ) {
|
||||
$data = $this->translate_node( $data, $lang, $source_lang );
|
||||
}
|
||||
}
|
||||
|
||||
return $data_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass $settings
|
||||
* @param string $lang
|
||||
* @param string $source_lang
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function translate_node( $settings, $lang, $source_lang ) {
|
||||
$node = $this->node_provider->get( $settings['_type'] );
|
||||
|
||||
if ( $node ) {
|
||||
$settings = $node->translate( $settings, $lang, $source_lang );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Update_Media_Factory implements IWPML_PB_Media_Update_Factory {
|
||||
|
||||
/** @var WPML_Page_Builders_Media_Translate|null $media_translate */
|
||||
private $media_translate;
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
return new WPML_Page_Builders_Update_Media(
|
||||
new WPML_Page_Builders_Update( new WPML_Cornerstone_Data_Settings() ),
|
||||
new WPML_Translation_Element_Factory( $sitepress ),
|
||||
new WPML_Cornerstone_Media_Nodes_Iterator(
|
||||
new WPML_Cornerstone_Media_Node_Provider( $this->get_media_translate() )
|
||||
),
|
||||
new WPML_Page_Builders_Media_Usage( $this->get_media_translate(), new WPML_Media_Usage_Factory() )
|
||||
);
|
||||
}
|
||||
|
||||
/** @return WPML_Page_Builders_Media_Translate */
|
||||
private function get_media_translate() {
|
||||
global $sitepress;
|
||||
|
||||
if ( ! $this->media_translate ) {
|
||||
$this->media_translate = new WPML_Page_Builders_Media_Translate(
|
||||
new WPML_Translation_Element_Factory( $sitepress ),
|
||||
new WPML_Media_Image_Translate( $sitepress, new WPML_Media_Attachment_By_URL_Factory() )
|
||||
);
|
||||
}
|
||||
|
||||
return $this->media_translate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
abstract class WPML_Cornerstone_Media_Node_With_URLs extends WPML_Cornerstone_Media_Node {
|
||||
|
||||
/** @return array */
|
||||
abstract protected function get_keys();
|
||||
|
||||
/**
|
||||
* @param array $node_data
|
||||
* @param string $target_lang
|
||||
* @param string $source_lang
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function translate( $node_data, $target_lang, $source_lang ) {
|
||||
foreach ( $this->get_keys() as $key ) {
|
||||
if ( ! empty( $node_data[ $key ] ) ) {
|
||||
list( $attachment_id, $type ) = explode( ':', $node_data[ $key ], 2 );
|
||||
if ( is_numeric( $attachment_id ) ) {
|
||||
$attachment_id = apply_filters( 'wpml_object_id', $attachment_id, 'attachment', true, $target_lang );
|
||||
$node_data[ $key ] = $attachment_id . ':' . $type;
|
||||
} else {
|
||||
$node_data[ $key ] = $this->media_translate->translate_image_url( $node_data[ $key ], $target_lang, $source_lang );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $node_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
abstract class WPML_Cornerstone_Media_Node {
|
||||
|
||||
/** @var WPML_Page_Builders_Media_Translate $media_translate */
|
||||
protected $media_translate;
|
||||
|
||||
public function __construct( WPML_Page_Builders_Media_Translate $media_translate ) {
|
||||
$this->media_translate = $media_translate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $node_data
|
||||
* @param string $target_lang
|
||||
* @param string $source_lang
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract function translate( $node_data, $target_lang, $source_lang );
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Node_Classic_Card extends WPML_Cornerstone_Media_Node_With_URLs {
|
||||
|
||||
protected function get_keys() {
|
||||
return array(
|
||||
'front_image',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Node_Classic_Creative_CTA extends WPML_Cornerstone_Media_Node_With_URLs {
|
||||
|
||||
protected function get_keys() {
|
||||
return array(
|
||||
'image',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Node_Classic_Feature_Box extends WPML_Cornerstone_Media_Node_With_URLs {
|
||||
|
||||
protected function get_keys() {
|
||||
return array(
|
||||
'graphic_image',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Node_Classic_Image extends WPML_Cornerstone_Media_Node_With_URLs {
|
||||
|
||||
protected function get_keys() {
|
||||
return array(
|
||||
'src',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Node_Classic_Promo extends WPML_Cornerstone_Media_Node_With_URLs {
|
||||
|
||||
protected function get_keys() {
|
||||
return array(
|
||||
'image',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Media_Node_Image extends WPML_Cornerstone_Media_Node_With_URLs {
|
||||
|
||||
protected function get_keys() {
|
||||
return array(
|
||||
'image_src',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Cornerstone\Modules;
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Obj;
|
||||
|
||||
class ModuleWithItemsFromConfig extends \WPML_Cornerstone_Module_With_Items {
|
||||
|
||||
/** @var array $fieldDefinitions */
|
||||
private $fieldDefinitions;
|
||||
|
||||
public function __construct( array $config ) {
|
||||
$keyByField = Fns::converge( Lst::zipObj(), [ Lst::pluck( 'field' ), Fns::identity() ] );
|
||||
$this->fieldDefinitions = $keyByField( $config );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_title( $field ) {
|
||||
return Obj::path( [ $field, 'type' ], $this->fieldDefinitions );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_fields() {
|
||||
return array_keys( $this->fieldDefinitions );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get_editor_type( $field ) {
|
||||
return Obj::path( [ $field, 'editor_type' ], $this->fieldDefinitions );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Accordion extends WPML_Cornerstone_Module_With_Items {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields() {
|
||||
return array( 'accordion_item_header_content', 'accordion_item_content' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_title( $field ) {
|
||||
if ( 'accordion_item_header_content' === $field ) {
|
||||
return esc_html__( 'Accordion: header content', 'sitepress' );
|
||||
}
|
||||
|
||||
if ( 'accordion_item_content' === $field ) {
|
||||
return esc_html__( 'Accordion: content', 'sitepress' );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_editor_type( $field ) {
|
||||
if ( 'accordion_item_header_content' === $field ) {
|
||||
return 'LINE';
|
||||
} else {
|
||||
return 'VISUAL';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Cornerstone_Module_With_Items
|
||||
*/
|
||||
abstract class WPML_Cornerstone_Module_With_Items implements IWPML_Page_Builders_Module {
|
||||
|
||||
const ITEMS_FIELD = WPML_Cornerstone_Translatable_Nodes::SETTINGS_FIELD;
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_title( $field );
|
||||
|
||||
/** @return array */
|
||||
abstract protected function get_fields();
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_editor_type( $field );
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_items( $settings ) {
|
||||
return $settings[ self::ITEMS_FIELD ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $node_id
|
||||
* @param array $settings
|
||||
* @param WPML_PB_String[] $strings
|
||||
*
|
||||
* @return WPML_PB_String[]
|
||||
*/
|
||||
public function get( $node_id, $settings, $strings ) {
|
||||
foreach ( $this->get_items( $settings ) as $item ) {
|
||||
foreach ( $this->get_fields() as $field ) {
|
||||
if ( is_array( $item[ $field ] ) ) {
|
||||
foreach ( $item[ $field ] as $key => $value ) {
|
||||
$strings[] = new WPML_PB_String(
|
||||
$value,
|
||||
$this->get_string_name( $node_id, $value, $field, $key ),
|
||||
$this->get_title( $field ),
|
||||
$this->get_editor_type( $field )
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$strings[] = new WPML_PB_String(
|
||||
$item[ $field ],
|
||||
$this->get_string_name( $node_id, $item[ $field ], $field ),
|
||||
$this->get_title( $field ),
|
||||
$this->get_editor_type( $field )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $node_id
|
||||
* @param array $settings
|
||||
* @param WPML_PB_String $string
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function update( $node_id, $settings, WPML_PB_String $string ) {
|
||||
foreach ( $this->get_items( $settings ) as $key => $item ) {
|
||||
foreach ( $this->get_fields() as $field ) {
|
||||
if ( $this->get_string_name( $node_id, $item[ $field ], $field ) === $string->get_name() ) {
|
||||
$settings[ self::ITEMS_FIELD ][ $key ][ $field ] = $string->get_value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
private function get_string_name( $node_id, $value, $type, $key = '' ) {
|
||||
return md5( $value ) . '-' . $type . $key . '-' . $node_id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cornerstone_Tabs extends WPML_Cornerstone_Module_With_Items {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields() {
|
||||
return array( 'tab_label_content', 'tab_content' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_title( $field ) {
|
||||
if ( 'tab_label_content' === $field ) {
|
||||
return esc_html__( 'Tabs: label', 'sitepress' );
|
||||
}
|
||||
|
||||
if ( 'tab_content' === $field ) {
|
||||
return esc_html__( 'Tabs: content', 'sitepress' );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_editor_type( $field ) {
|
||||
if ( 'tab_label_content' === $field ) {
|
||||
return 'LINE';
|
||||
} else {
|
||||
return 'VISUAL';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
use WPML\FP\Obj;
|
||||
|
||||
class DisplayConditions implements \IWPML_Frontend_Action {
|
||||
|
||||
const BASE64_EMPTY_ARRAY = 'W10=';
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'et_pb_module_shortcode_attributes' )
|
||||
->then( spreadArgs( [ $this, 'translateAttributes' ] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $atts
|
||||
* @return array
|
||||
*/
|
||||
public function translateAttributes( $atts ) {
|
||||
$displayConditions = Obj::prop( 'display_conditions', $atts );
|
||||
|
||||
if ( $displayConditions && self::BASE64_EMPTY_ARRAY !== $displayConditions ) {
|
||||
/* phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode */
|
||||
$conditions = json_decode( base64_decode( $atts['display_conditions'] ), true );
|
||||
|
||||
foreach ( $conditions as &$condition ) {
|
||||
if ( 'categoryPage' === $condition['condition'] ) {
|
||||
foreach ( $condition['conditionSettings']['categories'] as &$category ) {
|
||||
$category['value'] = (string) apply_filters( 'wpml_object_id', $category['value'], $category['groupSlug'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode */
|
||||
$atts['display_conditions'] = base64_encode( wp_json_encode( $conditions ) );
|
||||
}
|
||||
|
||||
return $atts;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
/**
|
||||
* Divi replaces double quotes with %22 when saving shortcode attributes.
|
||||
* ATE needs valid HTML so we temporarily decode the double quotes.
|
||||
* When we receive the translation we undo the change.
|
||||
*
|
||||
* @package WPML\Compatibility\Divi
|
||||
*/
|
||||
class DoubleQuotes implements \IWPML_Backend_Action, \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_pb_shortcode_decode', [ $this, 'decode' ], -PHP_INT_MAX, 2 );
|
||||
add_filter( 'wpml_pb_shortcode_encode', [ $this, 'encode' ], PHP_INT_MAX, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @param string $encoding
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function decode( $string, $encoding ) {
|
||||
if ( self::canHaveDoubleQuotes( $string, $encoding ) ) {
|
||||
$string = str_replace( '%22', '"', $string );
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @param string $encoding
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode( $string, $encoding ) {
|
||||
if ( self::canHaveDoubleQuotes( $string, $encoding ) ) {
|
||||
$string = str_replace( '"', '%22', $string );
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @param string $encoding
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function canHaveDoubleQuotes( $string, $encoding ) {
|
||||
return is_string( $string ) && 'allow_html_tags' === $encoding;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
use WPML\PB\Helper\LanguageNegotiation;
|
||||
|
||||
class DomainsBackendEditor implements \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
if ( LanguageNegotiation::isUsingDomains()
|
||||
&& self::isPostEditor()
|
||||
&& self::getDomainByCurrentPostLanguage() !== $_SERVER['HTTP_HOST']
|
||||
) {
|
||||
Hooks::onAction( 'admin_notices' )
|
||||
->then( spreadArgs( [ $this, 'displayNotice' ] ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function displayNotice() {
|
||||
$url = ( is_ssl() ? 'https://' : 'http://' ) . self::getDomainByCurrentPostLanguage() . $_SERVER['REQUEST_URI'];
|
||||
?>
|
||||
<div class="notice notice-warning is-dismissible">
|
||||
<p>
|
||||
<?php
|
||||
echo sprintf(
|
||||
// translators: placeholders are opening and closing <a> tag.
|
||||
esc_html__( "It is not possible to use Divi's backend builder to edit a post in a different language than your domain. Please use Divi's frontend builder to edit this post or %1\$s switch to the correct domain %2\$s to use the backend builder.", 'sitepress' ),
|
||||
sprintf( '<a href="%s">', esc_url( $url ) ),
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<button type="button" class="notice-dismiss">
|
||||
<span class="screen-reader-text">Dismiss this notice.</span>
|
||||
</button>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private static function isPostEditor() {
|
||||
global $pagenow;
|
||||
|
||||
return 'post.php' === $pagenow
|
||||
&& self::getPostId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
private static function getPostId() {
|
||||
/* phpcs:ignore WordPress.CSRF.NonceVerification.NoNonceVerification */
|
||||
return (int) Obj::prop( 'post', $_GET );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
private static function getDomainByCurrentPostLanguage() {
|
||||
$postDetails = apply_filters( 'wpml_post_language_details', null, self::getPostId() );
|
||||
$language = Obj::prop( 'language_code', $postDetails );
|
||||
|
||||
return LanguageNegotiation::getDomainByLanguage( $language );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class Editor implements \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'wpml_pb_is_editing_translation_with_native_editor', 10, 2 )
|
||||
->then( spreadArgs( function( $isTranslationWithNativeEditor, $translatedPostId ) {
|
||||
return $isTranslationWithNativeEditor
|
||||
|| (
|
||||
Relation::propEq( 'action', 'et_fb_ajax_save', $_POST )
|
||||
&& (int) Obj::prop( 'post_id', $_POST ) === $translatedPostId
|
||||
);
|
||||
} ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi\Hooks;
|
||||
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class GutenbergUpdate implements \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'wpml_pb_is_post_built_with_shortcodes', 10, 2 )
|
||||
->then( spreadArgs( [ $this, 'isPostBuiltWithShortcodes' ] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $builtWithShortcodes
|
||||
* @param \WP_Post $post
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isPostBuiltWithShortcodes( $builtWithShortcodes, $post ) {
|
||||
return self::isDiviPost( $post->ID ) || $builtWithShortcodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function isDiviPost( $postId ) {
|
||||
return 'on' === get_post_meta( $postId, '_et_pb_use_builder', true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
|
||||
class TinyMCE implements \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
if ( defined( 'WPML_TM_FOLDER' ) ) {
|
||||
add_filter( 'tiny_mce_before_init', [ $this, 'filterEditorAutoTags' ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filterEditorAutoTags( $config ) {
|
||||
if ( did_action( 'admin_init' ) ) {
|
||||
$screen = get_current_screen();
|
||||
$cteUrl = 'wpml_page_' . constant( 'WPML_TM_FOLDER' ) . '/menu/translations-queue';
|
||||
|
||||
if ( Obj::prop( 'id', $screen ) === $cteUrl ) {
|
||||
$config['wpautop'] = false;
|
||||
$config['indent'] = true;
|
||||
$config['tadv_noautop'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
use WPML\FP\Obj;
|
||||
|
||||
class WooShortcodes implements \IWPML_Frontend_Action {
|
||||
|
||||
const WOO_SHORTCODES = [
|
||||
'et_pb_wc_description',
|
||||
'et_pb_wc_title',
|
||||
];
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'et_pb_module_shortcode_attributes', 10, 3 )
|
||||
->then( spreadArgs( [ $this, 'translateAttributes' ] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $shortcodeAttrs
|
||||
* @param array $attrs
|
||||
* @param string $slug
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function translateAttributes( $shortcodeAttrs, $attrs, $slug ) {
|
||||
if ( in_array( $slug, self::WOO_SHORTCODES, true ) && (int) Obj::prop( 'product', $shortcodeAttrs ) ) {
|
||||
$shortcodeAttrs['product'] = apply_filters( 'wpml_object_id', $shortcodeAttrs['product'], 'product', true );
|
||||
}
|
||||
return $shortcodeAttrs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
class Builder implements \IWPML_Frontend_Action, \IWPML_Backend_Action, \IWPML_AJAX_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'theme_locale', [ $this, 'switch_to_user_language' ] );
|
||||
}
|
||||
|
||||
public function switch_to_user_language( $locale ) {
|
||||
if ( isset( $_POST['action'] ) && ( 'et_fb_update_builder_assets' === $_POST['action'] ) ) { // phpcs:ignore WordPress.CSRF.NonceVerification
|
||||
return get_user_locale();
|
||||
}
|
||||
|
||||
return $locale;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
|
||||
class WPML_Compatibility_Divi implements \IWPML_DIC_Action, \IWPML_Backend_Action, \IWPML_Frontend_Action {
|
||||
|
||||
const REGEX_REMOVE_OPENING_PARAGRAPH = '/(<p>[\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 <p> 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]
|
||||
*
|
||||
* </p>
|
||||
* <p>Global text 1 EN5</p>
|
||||
* <p>
|
||||
*
|
||||
* [/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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
class WPML_Compatibility_Divi_Notice extends WPML_Notice {
|
||||
|
||||
const ID = 'wpml-compatibility-divi-editor-warning';
|
||||
const GROUP = 'wpml-compatibility-divi';
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct( self::ID, $this->get_message(), self::GROUP );
|
||||
$this->set_dismissible( true );
|
||||
$this->set_css_class_types( 'warning' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function get_message() {
|
||||
$msg = esc_html_x(
|
||||
'You are using DIVI theme, and you have chosen to use the standard editor for translating content.',
|
||||
'Use Translation Editor notice 1/3',
|
||||
'sitepress'
|
||||
);
|
||||
|
||||
$msg .= ' ' . esc_html_x(
|
||||
'Some functionalities may not work properly. We encourage you to switch to use the Translation Editor.',
|
||||
'Use Translation Editor notice 2/3',
|
||||
'sitepress'
|
||||
);
|
||||
|
||||
$msg .= ' ' . sprintf(
|
||||
/* translators: %s will be replaced with a URL. */
|
||||
esc_html_x(
|
||||
'You can find more information here: %s',
|
||||
'Use Translation Editor notice 2/3',
|
||||
'sitepress'
|
||||
),
|
||||
'<a href="https://wpml.org/errata/some-internal-taxonomies-will-be-missing-when-you-translate-divi-layouts/?utm_source=plugin&utm_medium=gui&utm_campaign=wpmlcore">Some internal taxonomies will be missing when you translate Divi layouts</a>'
|
||||
);
|
||||
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
class DiviOptionsEncoding implements \IWPML_Backend_Action, \IWPML_Frontend_Action {
|
||||
|
||||
const CHARS_ENCODED = [ '%22', '%91', '%93' ];
|
||||
const CHARS_DECODED = [ '"', '[', ']' ];
|
||||
const DELIMITER = '_';
|
||||
const TRANSLATABLE_KEYS = [ 'value', 'link_url', 'link_text' ];
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_pb_shortcode_decode', [ $this, 'decode_divi_options' ], 10, 2 );
|
||||
add_filter( 'wpml_pb_shortcode_encode', [ $this, 'encode_divi_options' ], 10, 2 );
|
||||
}
|
||||
|
||||
public function decode_divi_options( $string, $encoding ) {
|
||||
if ( 'divi_options' === $encoding ) {
|
||||
$options = str_replace( self::CHARS_ENCODED, self::CHARS_DECODED, $string );
|
||||
$options = json_decode( $options, true );
|
||||
$string = [];
|
||||
foreach ( $options as $index => $option ) {
|
||||
foreach ( $option as $key => $value ) {
|
||||
$string[ $key . self::DELIMITER . $index ] = [
|
||||
'value' => $value,
|
||||
'translate' => in_array( $key, self::TRANSLATABLE_KEYS, true ),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
public function encode_divi_options( $string, $encoding ) {
|
||||
if ( 'divi_options' === $encoding ) {
|
||||
$output = [];
|
||||
foreach ( $string as $combined_key => $value ) {
|
||||
$parts = explode( self::DELIMITER, $combined_key );
|
||||
$index = array_pop( $parts );
|
||||
$key = implode( self::DELIMITER, $parts );
|
||||
$output[ $index ][ $key ] = $value;
|
||||
}
|
||||
$output = wp_json_encode( $output, JSON_UNESCAPED_UNICODE );
|
||||
$string = str_replace( self::CHARS_DECODED, self::CHARS_ENCODED, $output );
|
||||
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
use WPML\Compatibility\BaseDynamicContent;
|
||||
|
||||
class DynamicContent extends BaseDynamicContent {
|
||||
|
||||
const ENCODED_CONTENT_START = '@ET-DC@';
|
||||
const ENCODED_CONTENT_END = '@';
|
||||
|
||||
/** @var array */
|
||||
protected $positions = [ 'before', 'after' ];
|
||||
|
||||
/**
|
||||
* Sets $positions dynamic content to be translatable.
|
||||
*
|
||||
* @param string $string The decoded string so far.
|
||||
* @param string $encoding The encoding used.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function decode_dynamic_content( $string, $encoding ) {
|
||||
if ( $this->is_dynamic_content( $string ) ) {
|
||||
$field = $this->decode_field( $string );
|
||||
|
||||
$decodedContent = [
|
||||
'et-dynamic-content' => [
|
||||
'value' => $string,
|
||||
'translate' => false,
|
||||
],
|
||||
];
|
||||
|
||||
foreach ( $this->positions as $position ) {
|
||||
if ( ! empty( $field['settings'][ $position ] ) ) {
|
||||
$decodedContent[ $position ] = [
|
||||
'value' => $field['settings'][ $position ],
|
||||
'translate' => true,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $decodedContent;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds dynamic content with translated strings.
|
||||
*
|
||||
* @param string|array $string The field array or string.
|
||||
* @param string $encoding The encoding used.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encode_dynamic_content( $string, $encoding ) {
|
||||
if ( is_array( $string ) && isset( $string['et-dynamic-content'] ) ) {
|
||||
$field = $this->decode_field( $string['et-dynamic-content'] );
|
||||
|
||||
foreach ( $this->positions as $position ) {
|
||||
if ( isset( $string[ $position ] ) ) {
|
||||
$field['settings'][ $position ] = $string[ $position ];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->encode_field( $field );
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a dynamic-content field.
|
||||
*
|
||||
* @param string $string The string to decode.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_dynamic_content( $string ) {
|
||||
return substr( $string, 0, strlen( self::ENCODED_CONTENT_START ) ) === self::ENCODED_CONTENT_START;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a dynamic-content field.
|
||||
*
|
||||
* @param string $string The string to decode.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function decode_field( $string ) {
|
||||
$start = strlen( self::ENCODED_CONTENT_START );
|
||||
$end = strlen( self::ENCODED_CONTENT_END );
|
||||
|
||||
// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
return json_decode( base64_decode( substr( $string, $start, -$end ) ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a dynamic-content field.
|
||||
*
|
||||
* @param array $field The field to encode.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encode_field( $field ) {
|
||||
// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
||||
return self::ENCODED_CONTENT_START
|
||||
. base64_encode( wp_json_encode( $field ) )
|
||||
. self::ENCODED_CONTENT_END;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
class Search implements \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'et_search_form_fields', [ $this, 'add_language_form_field' ] );
|
||||
}
|
||||
|
||||
public function add_language_form_field() {
|
||||
do_action( 'wpml_add_language_form_field' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
class ThemeBuilderFactory implements \IWPML_Deferred_Action_Loader, \IWPML_Backend_Action_Loader, \IWPML_Frontend_Action_Loader {
|
||||
|
||||
public function get_load_action() {
|
||||
return 'init';
|
||||
}
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
|
||||
return new ThemeBuilder( $sitepress );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Compatibility\Divi;
|
||||
|
||||
use SitePress;
|
||||
|
||||
class ThemeBuilder implements \IWPML_Action {
|
||||
|
||||
/** @var SitePress */
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
public function __construct( SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add filters and actions.
|
||||
*/
|
||||
public function add_hooks() {
|
||||
if ( ! defined( 'ET_THEME_BUILDER_DIR' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->sitepress->is_setup_complete() ) {
|
||||
if ( is_admin() ) {
|
||||
add_action( 'init', [ $this, 'make_layouts_editable' ], 1000 ); // Before WPML_Sticky_Links::init.
|
||||
add_filter( 'wpml_document_view_item_link', [ $this, 'document_view_layout_link' ], 10, 5 );
|
||||
} else {
|
||||
add_filter( 'get_post_metadata', [ $this, 'translate_layout_ids' ], 10, 4 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all post types that are layouts.
|
||||
*/
|
||||
private static function get_types() {
|
||||
return [
|
||||
ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE,
|
||||
ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE,
|
||||
ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the global post types array to tweak the settings for layouts
|
||||
*/
|
||||
public function make_layouts_editable() {
|
||||
global $wp_post_types;
|
||||
|
||||
foreach ( $this->get_types() as $type ) {
|
||||
$wp_post_types[ $type ]->show_ui = true;
|
||||
$wp_post_types[ $type ]->show_in_menu = false;
|
||||
$wp_post_types[ $type ]->_edit_link = 'post.php?post=%d';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate theme builder layout ids in the frontend.
|
||||
*
|
||||
* @param string $value The layout id.
|
||||
* @param int $post_id The post it belongs to.
|
||||
* @param string $key The meta key we are handling.
|
||||
* @param bool $single Fetch a single row or an array.
|
||||
* @return string
|
||||
*/
|
||||
public function translate_layout_ids( $value, $post_id, $key, $single ) {
|
||||
|
||||
if ( in_array( $key, [ '_et_header_layout_id', '_et_body_layout_id', '_et_footer_layout_id' ], true ) ) {
|
||||
/**
|
||||
* The `get_post_metadata` filter provides `null` as the initial `$value`.
|
||||
* When we return a different $value it is used directly, to avoid a second query.
|
||||
* This means that we have to get the original value first, removing ourselves so
|
||||
* we don't fall into an infinite loop.
|
||||
*/
|
||||
remove_filter( 'get_post_metadata', [ $this, 'translate_layout_ids' ], 10 );
|
||||
$original_id = get_post_meta( $post_id, $key, true );
|
||||
add_filter( 'get_post_metadata', [ $this, 'translate_layout_ids' ], 10, 4 );
|
||||
|
||||
$type = substr( $key, 1, -3 );
|
||||
$value = $this->sitepress->get_object_id( $original_id, $type, true );
|
||||
|
||||
if ( ! $single ) {
|
||||
$value = [ $value ];
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the 'View' link because you can't view layouts alone.
|
||||
*
|
||||
* @param string $link The complete link.
|
||||
* @param string $text The text to link.
|
||||
* @param object $job The corresponding translation job.
|
||||
* @param string $prefix The prefix of the element type.
|
||||
* @param string $type The element type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function document_view_layout_link( $link, $text, $job, $prefix, $type ) {
|
||||
if ( 'post' === $prefix && $this->is_theme_layout( $type ) ) {
|
||||
$link = '';
|
||||
}
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain Type is a theme builder layout.
|
||||
*
|
||||
* @param string $type The type to check.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_theme_layout( $type ) {
|
||||
return in_array( $type, $this->get_types(), true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Config\DynamicElements\EssentialAddons;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use function WPML\FP\compose;
|
||||
|
||||
/**
|
||||
* @see https://essential-addons.com/elementor/docs/creative-elements/content-timeline/
|
||||
*/
|
||||
class ContentTimeline {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get() {
|
||||
// $isEAContentTimeline :: array -> bool
|
||||
$isEAContentTimeline = Relation::propEq( 'widgetType', 'eael-content-timeline' );
|
||||
|
||||
// $contentTimelineLinksLens :: callable -> callable -> mixed
|
||||
$contentTimelineLinksLens = compose(
|
||||
Obj::lensProp( 'settings' ),
|
||||
Obj::lensMappedProp( 'eael_coustom_content_posts' ),
|
||||
Obj::lensPath( [ '__dynamic__', 'eael_read_more_text_link' ] )
|
||||
);
|
||||
|
||||
return [ $isEAContentTimeline, $contentTimelineLinksLens, 'popup', 'popup' ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Config\DynamicElements;
|
||||
|
||||
use WPML\FP\Logic;
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
|
||||
class FormPopup {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get() {
|
||||
$popupIdPath = [ 'settings', 'popup_action_popup_id' ];
|
||||
|
||||
$isFormWithPopup = Logic::allPass( [
|
||||
Relation::propEq( 'widgetType', 'form' ),
|
||||
Obj::path( $popupIdPath ),
|
||||
] );
|
||||
|
||||
$popupIdLens = Obj::lensPath( $popupIdPath );
|
||||
|
||||
return [ $isFormWithPopup, $popupIdLens ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Config\DynamicElements;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use function WPML\FP\compose;
|
||||
|
||||
class Hotspot{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get() {
|
||||
$isHotspot = Relation::propEq( 'widgetType', 'hotspot' );
|
||||
|
||||
// $hotspotLinksLens :: callable -> callable -> mixed
|
||||
$hotspotLinksLens = compose(
|
||||
Obj::lensProp( 'settings' ),
|
||||
Obj::lensMappedProp( 'hotspot' ),
|
||||
Obj::lensPath( [ '__dynamic__', 'hotspot_link' ] )
|
||||
);
|
||||
|
||||
return [ $isHotspot, $hotspotLinksLens, 'popup', 'popup' ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Config\DynamicElements;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\FP\Logic;
|
||||
|
||||
|
||||
class Popup {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get() {
|
||||
$popupPath = [ 'settings', '__dynamic__', 'link' ];
|
||||
|
||||
// $isDynamicLink :: array -> bool
|
||||
$isDynamicLink = Logic::allPass( [
|
||||
Relation::propEq( 'elType', 'widget' ),
|
||||
Obj::path( $popupPath ),
|
||||
] );
|
||||
|
||||
$lens = Obj::lensPath( $popupPath );
|
||||
|
||||
return [ $isDynamicLink, $lens, 'popup', 'popup' ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Config\DynamicElements;
|
||||
|
||||
class Provider {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get() {
|
||||
return [
|
||||
EssentialAddons\ContentTimeline::get(),
|
||||
Hotspot::get(),
|
||||
Popup::get(),
|
||||
FormPopup::get(),
|
||||
WooProduct::get( 'title' ),
|
||||
WooProduct::get( 'short-description' ),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Config\DynamicElements;
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\FP\Logic;
|
||||
|
||||
|
||||
class WooProduct {
|
||||
|
||||
/**
|
||||
* @param string $widgetName
|
||||
*
|
||||
* @return callable(string): string
|
||||
*/
|
||||
private static function getConfig( $widgetName ) {
|
||||
$widgetConfig = wpml_collect( [
|
||||
'title' => [
|
||||
'dynamicKey' => 'title',
|
||||
'widgetType' => 'heading',
|
||||
'shortcodeName' => 'woocommerce-product-title-tag',
|
||||
],
|
||||
'short-description' => [
|
||||
'dynamicKey' => 'editor',
|
||||
'widgetType' => 'text-editor',
|
||||
'shortcodeName' => 'woocommerce-product-short-description-tag',
|
||||
],
|
||||
] )->get( $widgetName );
|
||||
|
||||
return Obj::prop( Fns::__, $widgetConfig );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $widget
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get( $widget ) {
|
||||
$get = self::getConfig( $widget );
|
||||
|
||||
$widgetPath = [ 'settings', '__dynamic__', $get( 'dynamicKey' ) ];
|
||||
|
||||
// $isWooWidget :: array -> bool
|
||||
$isWooWidget = Logic::allPass( [
|
||||
Relation::propEq( 'widgetType', $get( 'widgetType' ) ),
|
||||
Obj::path( $widgetPath ),
|
||||
] );
|
||||
|
||||
// $widgetLens :: callable -> callable -> mixed
|
||||
$widgetLens = Obj::lensPath( $widgetPath );
|
||||
|
||||
return [ $isWooWidget, $widgetLens, $get( 'shortcodeName' ), 'product_id' ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Config;
|
||||
|
||||
class Factory extends \WPML\PB\Config\Factory {
|
||||
|
||||
const DATA = [
|
||||
'configRoot' => 'elementor-widgets',
|
||||
'defaultConditionKey' => 'widgetType',
|
||||
'pbKey' => 'elementor',
|
||||
'translatableWidgetsHook' => 'wpml_elementor_widgets_to_translate',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function getPbData( $key ) {
|
||||
return self::DATA[ $key ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor;
|
||||
|
||||
class DataConvert {
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function serialize( array $data ) {
|
||||
return wp_slash( wp_json_encode( $data ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function unserialize( $data ) {
|
||||
return json_decode( is_array( $data ) ? $data[0] : $data, true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\DynamicContent;
|
||||
|
||||
use WPML_PB_String;
|
||||
|
||||
class Field {
|
||||
|
||||
/**
|
||||
* e.g. '[elementor-tag id="cc0b6c6" name="post-title" settings="ENCODED_STRING"]'
|
||||
*
|
||||
* @var string $tagValue
|
||||
*/
|
||||
public $tagValue;
|
||||
|
||||
/**
|
||||
* e.g. 'title'
|
||||
*
|
||||
* @var string $tagKey
|
||||
*/
|
||||
public $tagKey;
|
||||
|
||||
/**
|
||||
* The node ID.
|
||||
*
|
||||
* @var string $nodeId
|
||||
*/
|
||||
public $nodeId;
|
||||
|
||||
/**
|
||||
* The item ID inside the node with items.
|
||||
*
|
||||
* @var string $itemId
|
||||
*/
|
||||
public $itemId;
|
||||
|
||||
/**
|
||||
* @param string $tagValue
|
||||
* @param string $tagKey
|
||||
* @param string $nodeId
|
||||
* @param string $itemId
|
||||
*/
|
||||
public function __construct( $tagValue, $tagKey, $nodeId, $itemId = '' ) {
|
||||
$this->tagValue = $tagValue;
|
||||
$this->tagKey = $tagKey;
|
||||
$this->nodeId = $nodeId;
|
||||
$this->itemId = $itemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \WPML_Elementor_Translatable_Nodes::get_string_name()
|
||||
* @see \WPML_Elementor_Module_With_Items::get_string_name()
|
||||
*
|
||||
* @param WPML_PB_String $string
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isMatchingStaticString( WPML_PB_String $string ) {
|
||||
$pattern = '/^' . $this->tagKey . '-.*-' . $this->nodeId . '$/';
|
||||
|
||||
if ( $this->itemId ) {
|
||||
$pattern = '/^' . $this->tagKey . '-.*-' . $this->nodeId . '-' . $this->itemId . '$/';
|
||||
}
|
||||
|
||||
return (bool) preg_match( $pattern, $string->get_name() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\DynamicContent;
|
||||
|
||||
use WPML\Collect\Support\Collection;
|
||||
use WPML_Elementor_Translatable_Nodes;
|
||||
use WPML_PB_String;
|
||||
|
||||
class Strings {
|
||||
|
||||
const KEY_SETTINGS = WPML_Elementor_Translatable_Nodes::SETTINGS_FIELD;
|
||||
const KEY_DYNAMIC = '__dynamic__';
|
||||
const KEY_NODE_ID = 'id';
|
||||
const KEY_ITEM_ID = '_id';
|
||||
|
||||
const SETTINGS_REGEX = '/settings="(.*?(?="]))/';
|
||||
const NAME_PREFIX = 'dynamic';
|
||||
const DELIMITER = '-';
|
||||
const TRANSLATABLE_SETTINGS = [
|
||||
'before',
|
||||
'after',
|
||||
'fallback',
|
||||
];
|
||||
|
||||
/**
|
||||
* Remove the strings overwritten with dynamic content
|
||||
* and add the extra strings "before", "after" and "fallback".
|
||||
*
|
||||
* @param WPML_PB_String[] $strings
|
||||
* @param string $nodeId
|
||||
* @param array $element
|
||||
*
|
||||
* @return WPML_PB_String[]
|
||||
*/
|
||||
public static function filter( array $strings, $nodeId, array $element ) {
|
||||
|
||||
$dynamicFields = self::getDynamicFields( $element );
|
||||
|
||||
$updateFromDynamicFields = function( WPML_PB_String $string ) use ( &$dynamicFields ) {
|
||||
$matchingField = $dynamicFields->first(
|
||||
function( Field $field ) use ( $string ) {
|
||||
return $field->isMatchingStaticString( $string );
|
||||
}
|
||||
);
|
||||
|
||||
if ( $matchingField ) {
|
||||
return self::addBeforeAfterAndFallback( wpml_collect( [ $dynamicFields->pull( $dynamicFields->search( $matchingField ) ) ] ) );
|
||||
}
|
||||
|
||||
return $string;
|
||||
};
|
||||
|
||||
return wpml_collect( $strings )
|
||||
->map( $updateFromDynamicFields )
|
||||
->merge( self::addBeforeAfterAndFallback( $dynamicFields ) )
|
||||
->flatten()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private static function getDynamicFields( array $element ) {
|
||||
if ( self::isModuleWithItems( $element ) ) {
|
||||
return self::getDynamicFieldsForModuleWithItems( $element );
|
||||
} elseif ( isset( $element[ self::KEY_SETTINGS ][ self::KEY_DYNAMIC ] ) ) {
|
||||
return self::getFields(
|
||||
$element[ self::KEY_SETTINGS ][ self::KEY_DYNAMIC ],
|
||||
$element[ self::KEY_NODE_ID ]
|
||||
);
|
||||
}
|
||||
|
||||
return wpml_collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private static function getDynamicFieldsForModuleWithItems( array $element ) {
|
||||
$isDynamic = function( $item ) {
|
||||
return isset( $item[ self::KEY_DYNAMIC ] );
|
||||
};
|
||||
$getFields = function( array $item ) use ( $element ) {
|
||||
return self::getFields(
|
||||
$item[ self::KEY_DYNAMIC ],
|
||||
$element[ self::KEY_NODE_ID ],
|
||||
$item[ self::KEY_ITEM_ID ]
|
||||
);
|
||||
};
|
||||
|
||||
return wpml_collect( reset( $element[ self::KEY_SETTINGS ] ) )
|
||||
->filter( $isDynamic )
|
||||
->map( $getFields )
|
||||
->flatten();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $nodeId
|
||||
* @param string $itemId
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private static function getFields( array $data, $nodeId, $itemId = '' ) {
|
||||
$buildField = function( $tagValue, $tagKey ) use ( $nodeId, $itemId ) {
|
||||
return new Field( $tagValue, $tagKey, $nodeId, $itemId );
|
||||
};
|
||||
|
||||
return wpml_collect( $data )->map( $buildField );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function isModuleWithItems( array $element ) {
|
||||
if ( isset( $element[ self::KEY_SETTINGS ] ) ) {
|
||||
$firstSettingElement = reset( $element[ self::KEY_SETTINGS ] );
|
||||
return is_array( $firstSettingElement ) && 0 === key( $firstSettingElement );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $dynamicFields
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
private static function addBeforeAfterAndFallback( Collection $dynamicFields ) {
|
||||
$dynamicFieldToSettingStrings = function( Field $field ) {
|
||||
preg_match( self::SETTINGS_REGEX, $field->tagValue, $matches );
|
||||
|
||||
$isTranslatableSetting = function( $value, $settingField ) {
|
||||
return $value && is_string( $value ) && in_array( $settingField, self::TRANSLATABLE_SETTINGS, true );
|
||||
};
|
||||
|
||||
$buildStringFromSetting = function( $value, $settingField ) use ( $field ) {
|
||||
return new WPML_PB_String(
|
||||
$value,
|
||||
self::getStringName( $field->nodeId, $field->itemId, $field->tagKey, $settingField ),
|
||||
sprintf( __( 'Dynamic content string: %s', 'sitepress' ), $field->tagKey ),
|
||||
'LINE'
|
||||
);
|
||||
};
|
||||
|
||||
return wpml_collect( isset( $matches[1] ) ? self::decodeSettings( $matches[1] ) : [] )
|
||||
->filter( $isTranslatableSetting )
|
||||
->map( $buildStringFromSetting );
|
||||
};
|
||||
|
||||
return $dynamicFields->map( $dynamicFieldToSettingStrings );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
* @param WPML_PB_String $string
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function updateNode( array $element, WPML_PB_String $string ) {
|
||||
$stringNameParts = explode( self::DELIMITER, $string->get_name() );
|
||||
|
||||
if ( count( $stringNameParts ) !== 5 || self::NAME_PREFIX !== $stringNameParts[0] ) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
list( , , $itemId, $dynamicField, $settingField ) = $stringNameParts;
|
||||
|
||||
if ( $itemId && self::isModuleWithItems( $element ) ) {
|
||||
$element = self::updateNodeWithItems( $element, $string, $stringNameParts );
|
||||
} elseif ( isset( $element[ self::KEY_SETTINGS ][ self::KEY_DYNAMIC ][ $dynamicField ] ) ) {
|
||||
$element[ self::KEY_SETTINGS ][ self::KEY_DYNAMIC ][ $dynamicField ] = self::replaceSettingString(
|
||||
$element[ self::KEY_SETTINGS ][ self::KEY_DYNAMIC ][ $dynamicField ],
|
||||
$string,
|
||||
$settingField
|
||||
);
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encodedSettings
|
||||
* @param WPML_PB_String $string
|
||||
* @param string $settingField
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private static function replaceSettingString( $encodedSettings, WPML_PB_String $string, $settingField ) {
|
||||
$replace = function( array $matches ) use ( $string, $settingField ) {
|
||||
$settings = self::decodeSettings( $matches[1] );
|
||||
$settings[ $settingField ] = $string->get_value();
|
||||
$replace = urlencode( json_encode( $settings ) );
|
||||
|
||||
return str_replace( $matches[1], $replace, $matches[0] );
|
||||
};
|
||||
|
||||
return preg_replace_callback( self::SETTINGS_REGEX, $replace, $encodedSettings );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
* @param WPML_PB_String $string
|
||||
* @param array $stringNameParts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function updateNodeWithItems( array $element, WPML_PB_String $string, array $stringNameParts ) {
|
||||
list( , , $itemId, $dynamicField, $settingField ) = $stringNameParts;
|
||||
|
||||
$items = wpml_collect( reset( $element[ self::KEY_SETTINGS ] ) );
|
||||
$mainKey = key( $element[ self::KEY_SETTINGS ] );
|
||||
|
||||
$replaceStringInItem = function( array $item ) use ( $itemId, $string, $dynamicField, $settingField ) {
|
||||
if (
|
||||
isset( $item[ self::KEY_DYNAMIC ][ $dynamicField ], $item[ self::KEY_ITEM_ID ] )
|
||||
&& $item[ self::KEY_ITEM_ID ] === $itemId
|
||||
) {
|
||||
$item[ self::KEY_DYNAMIC ][ $dynamicField ] = self::replaceSettingString( $item[ self::KEY_DYNAMIC ][ $dynamicField ], $string, $settingField );
|
||||
}
|
||||
|
||||
return $item;
|
||||
};
|
||||
|
||||
$element[ self::KEY_SETTINGS ][ $mainKey ] = $items->map( $replaceStringInItem )->toArray();
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $settingsString
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function decodeSettings( $settingsString ) {
|
||||
return json_decode( urldecode( $settingsString ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $nodeId
|
||||
* @param string $itemId
|
||||
* @param string $tagKey
|
||||
* @param string $settingField
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getStringName( $nodeId, $itemId, $tagKey, $settingField ) {
|
||||
return self::NAME_PREFIX . self::DELIMITER
|
||||
. $nodeId . self::DELIMITER
|
||||
. $itemId . self::DELIMITER
|
||||
. $tagKey . self::DELIMITER
|
||||
. $settingField;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Helper;
|
||||
|
||||
class Node {
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTranslatable( $element ) {
|
||||
return isset( $element['elType'] ) && in_array( $element['elType'], [ 'widget', 'container' ], true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $element
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasChildren( $element ) {
|
||||
return isset( $element['elements'] ) && count( $element['elements'] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Helper;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Str;
|
||||
|
||||
class StringFormat {
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param \WPML_PB_String $string
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function useWpAutoP( $settings, $string ) {
|
||||
return 'VISUAL' === $string->get_editor_type() && self::isOneLine( self::getOriginalString( $settings, $string ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $content
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function isOneLine( $content ) {
|
||||
return ! Str::includes( PHP_EOL, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param \WPML_PB_String $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function getOriginalString( $settings, $string ) {
|
||||
if ( 'text-editor' === $settings['widgetType'] ) {
|
||||
return Obj::path( [ 'settings', 'editor' ], $settings );
|
||||
} elseif ( 'hotspot' === $settings['widgetType'] ) {
|
||||
$items = Obj::path( [ 'settings', 'hotspot' ], $settings );
|
||||
$found = wpml_collect( $items )->first( function( $item ) use ( $string ) {
|
||||
return Str::endsWith( $item['_id'], $string->get_name() );
|
||||
});
|
||||
return Obj::prop( 'hotspot_tooltip_content', $found );
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
use WPML\PB\Helper\LanguageNegotiation;
|
||||
|
||||
class DomainsWithMultisite implements \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
if ( is_multisite() && LanguageNegotiation::isUsingDomains() ) {
|
||||
Hooks::onAction( 'elementor/editor/init' )
|
||||
->then( spreadArgs( [ $this, 'onElementorEditor' ] ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function onElementorEditor() {
|
||||
$isCurrentLangDifferentThanDefault = apply_filters( 'wpml_current_language', null ) !== apply_filters( 'wpml_default_language', null );
|
||||
|
||||
if ( $isCurrentLangDifferentThanDefault ) {
|
||||
Hooks::onFilter( 'admin_url' )
|
||||
->then( spreadArgs( [ $this, 'filterUrl' ] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url The admin area URL.
|
||||
*/
|
||||
public function filterUrl( $url ) {
|
||||
$parsedUrl = wpml_parse_url( $url );
|
||||
|
||||
if ( is_array( $parsedUrl ) && ! empty( $parsedUrl['host'] ) ) {
|
||||
return http_build_url( Obj::assoc( 'host', $_SERVER['HTTP_HOST'], $parsedUrl ) );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
private static function isUsingDomains() {
|
||||
return apply_filters( 'wpml_setting', [], 'language_domains' )
|
||||
&& constant( 'WPML_LANGUAGE_NEGOTIATION_TYPE_DOMAIN' ) === (int) apply_filters( 'wpml_setting', 1, 'language_negotiation_type' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\PB\Elementor\Config\DynamicElements\Provider;
|
||||
use function WPML\FP\curryN;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class DynamicElements implements \IWPML_Frontend_Action, \IWPML_DIC_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'elementor/frontend/builder_content_data', [ $this, 'convert' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function convert( array $data ) {
|
||||
// $convertTag :: (curried) string -> string -> string -> string
|
||||
$convertTag = curryN( 3, [ __CLASS__, 'convertTag' ] );
|
||||
|
||||
// $assignConvertCallable :: (callable, callable, string|null, string|null) -> array
|
||||
$assignConvertCallable = function( $shouldConvert, $lens, $allowedTag = null, $idKey = null ) use ( $convertTag ) {
|
||||
if ( $allowedTag && $idKey ) {
|
||||
$convert = $convertTag( $allowedTag, $idKey );
|
||||
} else {
|
||||
$convert = [ __CLASS__, 'convertId' ];
|
||||
}
|
||||
|
||||
return [ $shouldConvert, Obj::over( $lens, $convert ) ];
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter widget dynamic id conversion configuration.
|
||||
*
|
||||
* Gather conversion configuration for Elementor widget dynamic ids.
|
||||
* The id can be stored in a widget key, or in a shortcode string.
|
||||
*
|
||||
* @since 2.0.4
|
||||
*
|
||||
* @param array $args {
|
||||
* @type array $configuration {
|
||||
* Conversion configuration.
|
||||
*
|
||||
* @type callable $shouldConvert Check if the widget should be converted.
|
||||
* @type callable $keyLens Lens to the key that holds the dynamic id.
|
||||
* @type string $tagName Optional. Shortcode name attribute.
|
||||
* @type string $idKey Optional. Id key in the shortcode's settings attribute.
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
$converters = apply_filters( 'wpml_pb_elementor_widget_dynamic_id_converters', Provider::get() );
|
||||
|
||||
$converters = wpml_collect( $converters )
|
||||
->map( spreadArgs( $assignConvertCallable ) )
|
||||
->toArray();
|
||||
|
||||
return $this->applyConverters( $data, $converters );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $converters
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function applyConverters( $data, $converters ) {
|
||||
foreach ( $data as &$item ) {
|
||||
foreach ( $converters as $converter ) {
|
||||
list( $shouldConvert, $convert ) = $converter;
|
||||
|
||||
if ( $shouldConvert( $item ) ) {
|
||||
$item = $convert( $item );
|
||||
}
|
||||
}
|
||||
|
||||
$item['elements'] = $this->applyConverters( $item['elements'], $converters );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $allowedTag
|
||||
* @param string $idKey
|
||||
* @param string $tagString
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function convertTag( $allowedTag, $idKey, $tagString ) {
|
||||
preg_match( '/name="(.*?(?="))"/', $tagString, $tagNameMatch );
|
||||
|
||||
if ( ! $tagNameMatch || $tagNameMatch[1] !== $allowedTag ) {
|
||||
return $tagString;
|
||||
}
|
||||
|
||||
return preg_replace_callback( '/settings="(.*?(?="]))/', function( array $matches ) use ( $idKey ) {
|
||||
$settings = json_decode( urldecode( $matches[1] ), true );
|
||||
|
||||
if ( ! isset( $settings[ $idKey ] ) ) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$settings[ $idKey ] = self::convertId( $settings[ $idKey ] );
|
||||
$replace = urlencode( json_encode( $settings ) );
|
||||
|
||||
return str_replace( $matches[1], $replace, $matches[0] );
|
||||
|
||||
}, $tagString );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $elementId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function convertId( $elementId ) {
|
||||
return apply_filters( 'wpml_object_id', $elementId, get_post_type( $elementId ), true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class Editor implements \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'wpml_pb_is_editing_translation_with_native_editor', 10, 2 )
|
||||
->then( spreadArgs( function( $isTranslationWithNativeEditor, $translatedPostId ) {
|
||||
return $isTranslationWithNativeEditor
|
||||
|| (
|
||||
(int) Obj::prop( 'editor_post_id', $_POST ) === $translatedPostId
|
||||
&& Relation::propEq( 'action', 'elementor_ajax', $_POST )
|
||||
);
|
||||
} ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class FormPopup implements \IWPML_Frontend_Action, \IWPML_AJAX_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
$isElementorFormAjaxSubmit = Relation::propEq( 'action', 'elementor_pro_forms_send_form' );
|
||||
if ( $isElementorFormAjaxSubmit( $_POST ) ) {
|
||||
Hooks::onAction( 'elementor_pro/forms/new_record', 10, 2 )
|
||||
->then( spreadArgs( [ $this, 'convertFormPopupIdAjax' ] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ElementorPro\Modules\Forms\Classes\Form_Record $record An instance of the form record.
|
||||
* @param \ElementorPro\Modules\Forms\Classes\Ajax_Handler $ajaxHandler An instance of the ajax handler.
|
||||
*/
|
||||
public function convertFormPopupIdAjax ( $record, $ajaxHandler ) {
|
||||
if ( Obj::path( [ 'data', 'popup', 'id' ], $ajaxHandler ) ) {
|
||||
$popup = Obj::path( [ 'data', 'popup'], $ajaxHandler );
|
||||
$getCurrentLanguageFromPost = function () {
|
||||
return Obj::prop( 'language_code', apply_filters( 'wpml_post_language_details', null, sanitize_text_field( wp_unslash( $_POST['post_id'] ) ) ) );
|
||||
};
|
||||
|
||||
$popup['id'] = apply_filters( 'wpml_object_id', $popup['id'], get_post_type( $popup['id'] ), false, $getCurrentLanguageFromPost() );
|
||||
|
||||
$ajaxHandler->add_response_data( 'popup', $popup );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
class Frontend implements \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'elementor_pro/search_form/after_input', [ $this, 'addLanguageFormField' ] );
|
||||
}
|
||||
|
||||
public function addLanguageFormField() {
|
||||
do_action( 'wpml_add_language_form_field' );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Logic;
|
||||
use WPML\FP\Maybe;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\PB\Elementor\DataConvert;
|
||||
use WPML\PB\GutenbergCleanup\Package;
|
||||
use WPML_Elementor_Data_Settings;
|
||||
use function WPML\FP\curryN;
|
||||
use function WPML\FP\pipe;
|
||||
|
||||
class GutenbergCleanup implements \IWPML_Backend_Action, \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter(
|
||||
'update_post_metadata',
|
||||
Fns::withoutRecursion( Fns::identity(), [ $this, 'removeGutenbergFootprint' ] ),
|
||||
10,
|
||||
4
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If we detect Gutenberg footprint in the Elementor data,
|
||||
* we'll remove it and delete the Gutenberg string package.
|
||||
*
|
||||
* @param null|bool $check
|
||||
* @param int $postId
|
||||
* @param string $metaKey
|
||||
* @param string $metaValue
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function removeGutenbergFootprint( $check, $postId, $metaKey, $metaValue ) {
|
||||
if (
|
||||
WPML_Elementor_Data_Settings::META_KEY_DATA === $metaKey
|
||||
&& WPML_Elementor_Data_Settings::is_edited_with_elementor( $postId )
|
||||
) {
|
||||
// $ifValueHasChanged :: string -> bool
|
||||
$ifValueHasChanged = pipe( Relation::equals( $metaValue ), Logic::not() );
|
||||
|
||||
// $update :: int -> string -> bool
|
||||
$update = curryN( 2, function( $postId, $meta ) {
|
||||
// Do not use update_post_meta, we need update meta for revisions too.
|
||||
update_metadata( 'post', $postId, WPML_Elementor_Data_Settings::META_KEY_DATA, $meta );
|
||||
Package::delete( Package::get( $postId ) );
|
||||
return true;
|
||||
} );
|
||||
|
||||
return Maybe::of( $metaValue )
|
||||
->map( [ DataConvert::class, 'unserialize' ] )
|
||||
->map( [ $this, 'removeBlockMetaInEditorWidget' ] )
|
||||
->map( [ DataConvert::class, 'serialize' ] )
|
||||
->filter( $ifValueHasChanged )
|
||||
->map( $update( $postId ) )
|
||||
->getOrElse( $check );
|
||||
}
|
||||
|
||||
return $check;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function removeBlockMetaInEditorWidget( array $data ) {
|
||||
foreach ( $data as &$element ) {
|
||||
if ( $element['elements'] ) {
|
||||
$element['elements'] = $this->removeBlockMetaInEditorWidget( $element['elements'] );
|
||||
} elseif ( 'widget' === $element['elType'] && isset( $element['settings']['editor'] ) ) {
|
||||
$element['settings']['editor'] = preg_replace( '(<!--[^<]*-->)', '', $element['settings']['editor'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
use function WPML\FP\pipe;
|
||||
|
||||
class LandingPages implements \IWPML_Frontend_Action, \IWPML_Backend_Action, \IWPML_DIC_Action {
|
||||
|
||||
const POST_TYPE = 'e-landing-page';
|
||||
const BACKUP_HOOK_PRIORITY = 11;
|
||||
|
||||
/** @var \SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
public function __construct( \SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
if ( get_option( 'permalink_structure' ) ) {
|
||||
add_filter( 'post_type_link', [ $this, 'adjustLink' ], PHP_INT_MAX, 2 );
|
||||
Hooks::onFilter( 'pre_handle_404', self::BACKUP_HOOK_PRIORITY, 2 )
|
||||
->then( spreadArgs( [ $this, 'backupQuery' ] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Elementor\Modules\LandingPages\Module::remove_post_type_slug
|
||||
*
|
||||
* @param string $postUrl
|
||||
* @param \WP_Post $post
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function adjustLink( $postUrl, $post ) {
|
||||
if ( self::POST_TYPE !== $post->post_type || 'publish' !== $post->post_status ) {
|
||||
return $postUrl;
|
||||
}
|
||||
|
||||
$homeUrl = get_home_url();
|
||||
$urlParts = wp_parse_url( $homeUrl );
|
||||
$urlParts['path'] = trailingslashit( Obj::prop( 'path', $urlParts ) ) . $post->post_name . '/';
|
||||
$newPostUrl = http_build_url( null, $urlParts );
|
||||
$postLangCode = $this->sitepress->get_language_for_element( $post->ID, 'post_' . self::POST_TYPE );
|
||||
|
||||
return $this->sitepress->convert_url( $newPostUrl, $postLangCode );
|
||||
}
|
||||
|
||||
/**
|
||||
* Backup and restore the global $wp_query that was overwritten by Elementor.
|
||||
*
|
||||
* In order for Elementor to treat landing pages(post_type: e-landing-page) as pages, it overwrites the global
|
||||
* $wp_query when using the /%category%/%postname%/ permalink structure.
|
||||
* WPML then resets the global $wp_query in SitePress::get_ls_languages() and this causes 404 errors on landing pages
|
||||
* and prevents editing them in the Elementor editor.
|
||||
*
|
||||
* In this case, we backup the global $wp_query when Elementor overwrites it on 'pre_handle_404' hook, and we restore
|
||||
* it after WPML resets it on 'wp_head' hook.
|
||||
*
|
||||
* @see \WPML_SEO_HeadLangs::head_langs()
|
||||
* @see \SitePress::get_ls_languages()
|
||||
* @see \Elementor\Modules\LandingPages\Module::handle_404
|
||||
*
|
||||
* @param bool $value
|
||||
* @param \WP_Query $query
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function backupQuery( $value, $query ) {
|
||||
global $wp_query;
|
||||
|
||||
if ( $value ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// $wasModifiedByElementor :: \WP_Query -> bool
|
||||
$wasModifiedByElementor = pipe(
|
||||
Obj::prop( 'query' ),
|
||||
Relation::propEq( 'post_type', self::POST_TYPE )
|
||||
);
|
||||
|
||||
// $hasPosts :: \WP_Query -> array
|
||||
$hasPosts = Obj::prop( 'posts' );
|
||||
|
||||
if (
|
||||
$query->is_main_query()
|
||||
&& empty( $query->posts )
|
||||
&& ! empty( $query->query['category_name'] )
|
||||
&& empty( $query->tax_query->table_aliases )
|
||||
&& $wasModifiedByElementor( $wp_query )
|
||||
&& $hasPosts( $wp_query )
|
||||
) {
|
||||
if ( apply_filters( 'wpml_sub_setting', 1, 'seo', 'head_langs' ) ) {
|
||||
$wpQueryBackup = clone $wp_query;
|
||||
$priority = (int) apply_filters( 'wpml_sub_setting', 1, 'seo', 'head_langs_priority' );
|
||||
Hooks::onAction( 'wp_head', $priority + 1 )
|
||||
->then( function() use ( $wpQueryBackup ) {
|
||||
global $wp_query;
|
||||
|
||||
$wp_query = $wpQueryBackup; //phpcs:ignore WordPress.Variables.GlobalVariables.OverrideProhibited
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class Templates implements \IWPML_Frontend_Action, \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'elementor/theme/conditions/cache/regenerate/query_args' )
|
||||
->then( spreadArgs( Obj::assoc( 'suppress_filters', true ) ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\LIB\WP\Hooks;
|
||||
use function WPML\FP\spreadArgs;
|
||||
|
||||
class WooCommerce implements \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onFilter( 'option_elementor_woocommerce_purchase_summary_page_id' )
|
||||
->then( spreadArgs( Fns::memorize( function( $pageId ) {
|
||||
return apply_filters( 'wpml_object_id', $pageId, 'page', true );
|
||||
} ) ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\Hooks;
|
||||
|
||||
use WPML\LIB\WP\Hooks;
|
||||
|
||||
class WordPressWidgets implements \IWPML_Backend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
Hooks::onAction( 'wp_ajax_elementor_ajax' )
|
||||
->then( function() {
|
||||
add_filter( 'wpml_widget_language_selector_disable', '__return_true' );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\LanguageSwitcher;
|
||||
|
||||
use Elementor\Plugin;
|
||||
|
||||
class LanguageSwitcher implements \IWPML_Backend_Action, \IWPML_Frontend_Action {
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'elementor/widgets/widgets_registered', [ $this, 'registerWidgets' ] );
|
||||
add_filter( 'wpml_custom_language_switcher_is_enabled', '__return_true' );
|
||||
}
|
||||
|
||||
public function registerWidgets() {
|
||||
// @phpstan-ignore-next-line
|
||||
Plugin::instance()->widgets_manager->register_widget_type( new Widget() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace WPML\PB\Elementor\LanguageSwitcher;
|
||||
|
||||
use Elementor\Widget_Base;
|
||||
|
||||
class Widget extends Widget_Base {
|
||||
|
||||
/** @var WidgetAdaptor $adaptor */
|
||||
private $adaptor;
|
||||
|
||||
public function __construct( $data = [], $args = null, WidgetAdaptor $adaptor = null ) {
|
||||
$this->adaptor = $adaptor ?: new WidgetAdaptor();
|
||||
$this->adaptor->setTarget( $this );
|
||||
parent::__construct( $data, $args );
|
||||
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function get_name() {
|
||||
return $this->adaptor->getName();
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function get_title() {
|
||||
return $this->adaptor->getTitle();
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function get_icon() {
|
||||
return $this->adaptor->getIcon();
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public function get_categories() {
|
||||
return $this->adaptor->getCategories();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register controls.
|
||||
*
|
||||
* Used to add new controls to any element type. For example, external
|
||||
* developers use this method to register controls in a widget.
|
||||
*
|
||||
* Should be inherited and register new controls using `add_control()`,
|
||||
* `add_responsive_control()` and `add_group_control()`, inside control
|
||||
* wrappers like `start_controls_section()`, `start_controls_tabs()` and
|
||||
* `start_controls_tab()`.
|
||||
*/
|
||||
protected function register_controls() {
|
||||
$this->adaptor->registerControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render element.
|
||||
*
|
||||
* Generates the final HTML on the frontend.
|
||||
*/
|
||||
protected function render() {
|
||||
$this->adaptor->render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\PB\Elementor\LanguageSwitcher;
|
||||
|
||||
use Elementor\Controls_Manager;
|
||||
use Elementor\Group_Control_Typography;
|
||||
use Elementor\Core\Schemes\Color as SchemeColor;
|
||||
|
||||
class WidgetAdaptor {
|
||||
|
||||
/** @var Widget $widget */
|
||||
private $widget;
|
||||
|
||||
public function setTarget( Widget $widget ) {
|
||||
$this->widget = $widget;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getName() {
|
||||
return 'wpml-language-switcher';
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getTitle() {
|
||||
return __( 'WPML Language Switcher', 'sitepress' );
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getIcon() {
|
||||
return 'fa fa-globe';
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public function getCategories() {
|
||||
return [ 'general' ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register controls.
|
||||
*
|
||||
* Used to add new controls to any element type. For example, external
|
||||
* developers use this method to register controls in a widget.
|
||||
*
|
||||
* Should be inherited and register new controls using `add_control()`,
|
||||
* `add_responsive_control()` and `add_group_control()`, inside control
|
||||
* wrappers like `start_controls_section()`, `start_controls_tabs()` and
|
||||
* `start_controls_tab()`.
|
||||
*/
|
||||
public function registerControls() {
|
||||
//Content Tab
|
||||
$this->widget->start_controls_section(
|
||||
'section_content',
|
||||
[
|
||||
'label' => __( 'Content', 'sitepress' ),
|
||||
'type' => Controls_Manager::SECTION,
|
||||
'tab' => Controls_Manager::TAB_CONTENT,
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'style',
|
||||
[
|
||||
'label' => __('Language switcher type', 'sitepress'),
|
||||
'type' => Controls_Manager::SELECT,
|
||||
'default' => 'custom',
|
||||
'options' => [
|
||||
'custom' => __( 'Custom', 'sitepress' ),
|
||||
'footer' => __( 'Footer', 'sitepress' ),
|
||||
'post_translations' => __( 'Post Translations', 'sitepress' ),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'display_flag',
|
||||
[
|
||||
'label' => __( 'Display Flag', 'sitepress' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'return_value' => 1,
|
||||
'default' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'link_current',
|
||||
[
|
||||
'label' => __( 'Show Active Language - has to be ON with Dropdown', 'sitepress' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'return_value' => 1,
|
||||
'default' => 1,
|
||||
'conditions' => [
|
||||
'relation' => 'and',
|
||||
'terms' => [
|
||||
[
|
||||
'name' => 'style',
|
||||
'operator' => '!=',
|
||||
'value' => 'custom',
|
||||
]
|
||||
]
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'native_language_name',
|
||||
[
|
||||
'label' => __( 'Native language name', 'sitepress' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'return_value' => 1,
|
||||
'default' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'language_name_current_language',
|
||||
[
|
||||
'label' => __( 'Language name in current language', 'sitepress' ),
|
||||
'type' => Controls_Manager::SWITCHER,
|
||||
'return_value' => 1,
|
||||
'default' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->end_controls_section();
|
||||
|
||||
$this->widget->start_controls_section(
|
||||
'style_section',
|
||||
[
|
||||
'label' => __( 'Style', 'sitepress' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
]
|
||||
);
|
||||
$this->widget->start_controls_tabs( 'style_tabs' );
|
||||
|
||||
$this->widget->start_controls_tab(
|
||||
'style_normal_tab',
|
||||
[
|
||||
'label' => __( 'Normal', 'sitepress' ),
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'switcher_typography',
|
||||
'selector' => '{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item',
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'switcher_text_color',
|
||||
[
|
||||
'label' => __( 'Text Color', 'sitepress' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'scheme' => [
|
||||
'type' => SchemeColor::get_type(),
|
||||
'value' => SchemeColor::COLOR_3,
|
||||
],
|
||||
'default' => '',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item .wpml-ls-link,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-legacy-dropdown a' => 'color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'switcher_bg_color',
|
||||
[
|
||||
'label' => __( 'Background Color', 'sitepress' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'default' => '',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item .wpml-ls-link,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-legacy-dropdown a' => 'background-color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->end_controls_tab();
|
||||
|
||||
$this->widget->start_controls_tab(
|
||||
'style_hover_tab',
|
||||
[
|
||||
'label' => __( 'Hover', 'sitepress' ),
|
||||
]
|
||||
);
|
||||
$this->widget->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'switcher_hover_typography',
|
||||
'selector' => '{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item:hover,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item.wpml-ls-item__active,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item.highlighted,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item:focus',
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'switcher_hover_color',
|
||||
[
|
||||
'label' => __( 'Text Color', 'sitepress' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'scheme' => [
|
||||
'type' => SchemeColor::get_type(),
|
||||
'value' => SchemeColor::COLOR_4,
|
||||
],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .wpml-elementor-ls .wpml-ls-legacy-dropdown a:hover,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-legacy-dropdown a:focus,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-legacy-dropdown .wpml-ls-current-language:hover>a,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item .wpml-ls-link:hover,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item .wpml-ls-link.wpml-ls-link__active,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item .wpml-ls-link.highlighted,
|
||||
{{WRAPPER}} .wpml-elementor-ls .wpml-ls-item .wpml-ls-link:focus' => 'color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->end_controls_tab();
|
||||
|
||||
$this->widget->end_controls_tabs();
|
||||
|
||||
$this->widget->end_controls_section();
|
||||
|
||||
$this->widget->start_controls_section(
|
||||
'language_flag',
|
||||
[
|
||||
'label' => __( 'Language Flag', 'sitepress' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
'condition' => [
|
||||
'display_flag' => [ 1 ],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'flag_margin',
|
||||
[
|
||||
'label' => __( 'Margin', 'sitepress' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .wpml-elementor-ls .wpml-ls-flag' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->end_controls_section();
|
||||
|
||||
$this->widget->start_controls_section(
|
||||
'post_translation_text',
|
||||
[
|
||||
'label' => __( 'Post Translation Text', 'sitepress' ),
|
||||
'tab' => Controls_Manager::TAB_STYLE,
|
||||
'condition' => [
|
||||
'style' => [ 'post_translations' ],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_group_control(
|
||||
Group_Control_Typography::get_type(),
|
||||
[
|
||||
'name' => 'post_translation_typography',
|
||||
'selector' => '{{WRAPPER}} .wpml-elementor-ls .wpml-ls-statics-post_translations',
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'post_translation_color',
|
||||
[
|
||||
'label' => __( 'Text Color', 'sitepress' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'scheme' => [
|
||||
'type' => SchemeColor::get_type(),
|
||||
'value' => SchemeColor::COLOR_3,
|
||||
],
|
||||
'default' => '',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .wpml-elementor-ls .wpml-ls-statics-post_translations' => 'color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'post_translation_bg_color',
|
||||
[
|
||||
'label' => __( 'Background Color', 'sitepress' ),
|
||||
'type' => Controls_Manager::COLOR,
|
||||
'default' => '',
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .wpml-elementor-ls .wpml-ls-statics-post_translations' => 'background-color: {{VALUE}}',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'post_translation_padding',
|
||||
[
|
||||
'label' => __( 'Padding', 'sitepress' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .wpml-elementor-ls .wpml-ls-statics-post_translations' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->add_control(
|
||||
'post_translation_margin',
|
||||
[
|
||||
'label' => __( 'Margin', 'sitepress' ),
|
||||
'type' => Controls_Manager::DIMENSIONS,
|
||||
'size_units' => [ 'px', '%', 'em' ],
|
||||
'selectors' => [
|
||||
'{{WRAPPER}} .wpml-elementor-ls .wpml-ls-statics-post_translations' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->widget->end_controls_section();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Render element.
|
||||
*
|
||||
* Generates the final HTML on the frontend.
|
||||
*/
|
||||
public function render() {
|
||||
$settings = $this->widget->get_settings_for_display();
|
||||
|
||||
$this->widget->add_render_attribute('wpml-elementor-ls', 'class', [
|
||||
'wpml-elementor-ls',
|
||||
]);
|
||||
|
||||
$args = array(
|
||||
'display_link_for_current_lang' => $settings['link_current'],
|
||||
'flags' => $settings['display_flag'],
|
||||
'native' => $settings['native_language_name'],
|
||||
'translated' => $settings['language_name_current_language'],
|
||||
'type' => $settings['style'],
|
||||
);
|
||||
|
||||
if ( 'custom' === $settings['style'] ) {
|
||||
//forcing in dropdown case
|
||||
$args['display_link_for_current_lang'] = 1;
|
||||
}
|
||||
|
||||
echo "<div " . $this->widget->get_render_attribute_string('wpml-elementor-ls') . ">";
|
||||
do_action('wpml_language_switcher', $args);
|
||||
echo "</div>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
class WPML_Elementor_Adjust_Global_Widget_ID_Factory implements IWPML_Backend_Action_Loader, IWPML_Frontend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
global $sitepress;
|
||||
|
||||
$elementor_db_factory = new WPML_Elementor_DB_Factory();
|
||||
$data_settings = new WPML_Elementor_Data_Settings( $elementor_db_factory->create() );
|
||||
|
||||
return new WPML_Elementor_Adjust_Global_Widget_ID(
|
||||
$data_settings,
|
||||
new WPML_Translation_Element_Factory( $sitepress ),
|
||||
$sitepress
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
class WPML_Elementor_Adjust_Global_Widget_ID {
|
||||
|
||||
/** @var IWPML_Page_Builders_Data_Settings */
|
||||
private $elementor_settings;
|
||||
|
||||
/** @var WPML_Translation_Element_Factory */
|
||||
private $translation_element_factory;
|
||||
|
||||
/** @var SitePress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var string */
|
||||
private $current_language;
|
||||
|
||||
public function __construct(
|
||||
IWPML_Page_Builders_Data_Settings $elementor_settings,
|
||||
WPML_Translation_Element_Factory $translation_element_factory,
|
||||
SitePress $sitepress
|
||||
) {
|
||||
$this->elementor_settings = $elementor_settings;
|
||||
$this->translation_element_factory = $translation_element_factory;
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'elementor/editor/before_enqueue_scripts', array( $this, 'adjust_ids' ) );
|
||||
add_action( 'elementor/editor/after_enqueue_scripts', array( $this, 'restore_current_language' ) );
|
||||
add_action( 'elementor/frontend/the_content', array( $this, 'duplicate_css_class_with_original_id' ) );
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_filter(
|
||||
'wpml_should_use_display_as_translated_snippet',
|
||||
array( $this, 'should_use_display_as_translated_snippet' ),
|
||||
PHP_INT_MAX,
|
||||
2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function adjust_ids() {
|
||||
$this->current_language = $this->sitepress->get_current_language();
|
||||
|
||||
$post_id = absint( $_REQUEST['post'] ); // WPCS: sanitization ok.
|
||||
|
||||
$post = $this->translation_element_factory->create_post( $post_id );
|
||||
$language = $post->get_language_code();
|
||||
$this->sitepress->switch_lang( $language );
|
||||
|
||||
$custom_field_data = get_post_meta(
|
||||
$post_id,
|
||||
$this->elementor_settings->get_meta_field()
|
||||
);
|
||||
|
||||
if ( ! $custom_field_data ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$custom_field_data = $this->elementor_settings->convert_data_to_array( $custom_field_data );
|
||||
|
||||
$custom_field_data_adjusted = $this->set_global_widget_id_for_language( $custom_field_data, $language );
|
||||
|
||||
if ( $custom_field_data_adjusted !== $custom_field_data ) {
|
||||
update_post_meta(
|
||||
$post_id,
|
||||
$this->elementor_settings->get_meta_field(),
|
||||
$this->elementor_settings->prepare_data_for_saving( $custom_field_data_adjusted )
|
||||
);
|
||||
|
||||
// Update post date so Elementor doesn't use auto saved post
|
||||
$post_data = get_post( $post_id, ARRAY_A );
|
||||
$post_data['post_date'] = current_time( 'mysql' );
|
||||
$post_data['post_date_gmt'] = '';
|
||||
|
||||
wp_update_post( $post_data );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function set_global_widget_id_for_language( $data_array, $language ) {
|
||||
foreach ( $data_array as &$data ) {
|
||||
if ( isset( $data['elType'] ) && 'widget' === $data['elType'] && 'global' === $data['widgetType'] ) {
|
||||
try {
|
||||
$widget_post = $this->translation_element_factory->create_post( $data['templateID'] );
|
||||
if ( $widget_post->get_language_code() !== $language ) {
|
||||
$translation = $widget_post->get_translation( $language );
|
||||
if ( $translation ) {
|
||||
$data['templateID'] = $translation->get_element_id();
|
||||
}
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// Not much we can do if the elementor templateID is a non existing post
|
||||
}
|
||||
}
|
||||
$data['elements'] = $this->set_global_widget_id_for_language( $data['elements'], $language );
|
||||
}
|
||||
|
||||
return $data_array;
|
||||
}
|
||||
|
||||
public function restore_current_language() {
|
||||
$this->sitepress->switch_lang( $this->current_language );
|
||||
}
|
||||
|
||||
/**
|
||||
* The snippet is a WHERE condition which is added to a DB query.
|
||||
* This will include the source element in the query results in case the element
|
||||
* does not exist in the current language.
|
||||
*
|
||||
* @see WPML_Query_Filter::display_as_translated_snippet
|
||||
*
|
||||
* @param bool $display_as_translated
|
||||
* @param array $post_types
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function should_use_display_as_translated_snippet( $display_as_translated, $post_types ) {
|
||||
if ( isset( $_GET['action'] ) && 'elementor' === $_GET['action']
|
||||
&& in_array( 'elementor_library', array_keys( $post_types ), true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $display_as_translated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function duplicate_css_class_with_original_id( $content ) {
|
||||
$classPrefixes = wpml_collect( [
|
||||
'elementor-',
|
||||
'elementor-global-',
|
||||
] )->implode( '|' );
|
||||
|
||||
return preg_replace_callback( '/(class=".*(' . $classPrefixes . '))(\d+)/', array( $this, 'convert_id_to_original' ), $content );
|
||||
}
|
||||
|
||||
private function convert_id_to_original( array $matches ) {
|
||||
$class_prefix = $matches[2];
|
||||
$id = (int)$matches[3];
|
||||
$element = $this->translation_element_factory->create_post( $id );
|
||||
$source = $element->get_source_element();
|
||||
|
||||
if ( $source ) {
|
||||
$new_class = $class_prefix . $source->get_id();
|
||||
$search = $matches[0];
|
||||
$replace = $search . ' ' . $new_class;
|
||||
$matches[0] = str_replace( $search, $replace, $matches[0] );
|
||||
}
|
||||
|
||||
return $matches[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
use WPML\PB\AutoUpdate\Settings as AutoUpdateSettings;
|
||||
use WPML\PB\Elementor\DataConvert;
|
||||
|
||||
class WPML_Elementor_Data_Settings implements IWPML_Page_Builders_Data_Settings {
|
||||
|
||||
const META_KEY_DATA = '_elementor_data';
|
||||
const META_KEY_MODE = '_elementor_edit_mode';
|
||||
|
||||
/**
|
||||
* @var WPML_Elementor_DB|null
|
||||
*/
|
||||
private $elementor_db;
|
||||
|
||||
public function __construct( WPML_Elementor_DB $elementor_db = null ) {
|
||||
$this->elementor_db = $elementor_db;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_custom_field_values_for_post_signature', array( $this, 'add_data_custom_field_to_md5' ), 10, 2 );
|
||||
add_filter( 'wpml_pb_copy_meta_field', array( $this, 'mark_css_field_as_empty' ), 10, 4 );
|
||||
|
||||
if ( $this->elementor_db ) {
|
||||
add_action(
|
||||
'wpml_page_builder_string_translated',
|
||||
array( $this, 'save_post_body_as_plain_text' ),
|
||||
11,
|
||||
5
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @param int $translated_post_id
|
||||
* @param int $original_post_id
|
||||
* @param string $meta_key
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function mark_css_field_as_empty( $value, $translated_post_id, $original_post_id, $meta_key ) {
|
||||
if ( '_elementor_css' === $meta_key && is_array( $value ) ) {
|
||||
if ( ! isset( $value['status'] ) ) {
|
||||
$value = current( $value );
|
||||
$value['status'] = '';
|
||||
$value = array( $value );
|
||||
} else {
|
||||
$value['status'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function save_post_body_as_plain_text( $type, $post_id, $original_post, $string_translations, $lang ) {
|
||||
if ( $this->is_handling_post( $post_id ) ) {
|
||||
$this->elementor_db->save_plain_text( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_meta_field() {
|
||||
return self::META_KEY_DATA;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_node_id_field() {
|
||||
return 'id';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields_to_copy() {
|
||||
return array(
|
||||
'_elementor_version',
|
||||
self::META_KEY_MODE,
|
||||
'_elementor_css',
|
||||
'_elementor_template_type',
|
||||
'_elementor_template_widget_type',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function convert_data_to_array( $data ) {
|
||||
return DataConvert::unserialize( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function prepare_data_for_saving( array $data ) {
|
||||
return DataConvert::serialize( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_pb_name(){
|
||||
return 'Elementor';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_fields_to_save() {
|
||||
return array( '_elementor_data' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $custom_fields_values
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_data_custom_field_to_md5( array $custom_fields_values, $post_id ) {
|
||||
if ( AutoUpdateSettings::isEnabled() ) {
|
||||
unset( $custom_fields_values[ $this->get_meta_field() ] );
|
||||
} else {
|
||||
$custom_fields_values[ $this->get_meta_field() ] = get_post_meta( $post_id, $this->get_meta_field(), true );
|
||||
}
|
||||
|
||||
return $custom_fields_values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_handling_post( $postId ) {
|
||||
return (bool) get_post_meta( $postId, $this->get_meta_field(), true )
|
||||
&& self::is_edited_with_elementor( $postId );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_edited_with_elementor( $postId ) {
|
||||
return 'builder' === get_post_meta( $postId, self::META_KEY_MODE, true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
class WPML_Elementor_DB_Factory {
|
||||
|
||||
/**
|
||||
* @return null|WPML_Elementor_DB
|
||||
*/
|
||||
public function create() {
|
||||
$wpml_elementor_db = null;
|
||||
|
||||
if ( version_compare( phpversion(), '5.3.0', '>=' ) && class_exists( '\Elementor\DB' ) ) {
|
||||
// @codingStandardsIgnoreLine
|
||||
$elementor_db = new \Elementor\DB();
|
||||
|
||||
if ( method_exists( $elementor_db, 'save_plain_text' ) ) {
|
||||
$wpml_elementor_db = new WPML_Elementor_DB( $elementor_db );
|
||||
}
|
||||
}
|
||||
|
||||
return $wpml_elementor_db;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
class WPML_Elementor_DB {
|
||||
|
||||
/**
|
||||
* @var \Elementor\DB
|
||||
*/
|
||||
private $elementor_db;
|
||||
|
||||
// @codingStandardsIgnoreLine
|
||||
public function __construct( \Elementor\DB $elementor_db ) {
|
||||
$this->elementor_db = $elementor_db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function save_plain_text( $post_id ) {
|
||||
$this->elementor_db->save_plain_text( $post_id );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Elementor_Integration_Factory
|
||||
*/
|
||||
class WPML_Elementor_Integration_Factory {
|
||||
|
||||
const SLUG = 'elementor';
|
||||
|
||||
/**
|
||||
* @return WPML_Page_Builders_Integration
|
||||
*/
|
||||
public function create() {
|
||||
|
||||
$action_filter_loader = new WPML_Action_Filter_Loader();
|
||||
$action_filter_loader->load(
|
||||
array(
|
||||
'WPML_Elementor_Translate_IDs_Factory',
|
||||
'WPML_Elementor_URLs_Factory',
|
||||
'WPML_Elementor_Adjust_Global_Widget_ID_Factory',
|
||||
'WPML_PB_Elementor_Handle_Custom_Fields_Factory',
|
||||
'WPML_Elementor_Media_Hooks_Factory',
|
||||
'WPML_Elementor_WooCommerce_Hooks_Factory',
|
||||
\WPML\PB\Elementor\Hooks\WooCommerce::class,
|
||||
\WPML\PB\Elementor\LanguageSwitcher\LanguageSwitcher::class,
|
||||
\WPML\PB\Elementor\Hooks\DynamicElements::class,
|
||||
\WPML\PB\Elementor\Hooks\FormPopup::class,
|
||||
\WPML\PB\Elementor\Hooks\GutenbergCleanup::class,
|
||||
\WPML\PB\Elementor\Hooks\Frontend::class,
|
||||
\WPML\PB\Elementor\Hooks\DomainsWithMultisite::class,
|
||||
\WPML\PB\Elementor\Config\Factory::class,
|
||||
\WPML\PB\Elementor\Hooks\LandingPages::class,
|
||||
\WPML\PB\Elementor\Hooks\Editor::class,
|
||||
\WPML\PB\Elementor\Hooks\WordPressWidgets::class,
|
||||
\WPML\PB\Elementor\Hooks\Templates::class,
|
||||
\WPML_PB_Fix_Maintenance_Query::class,
|
||||
)
|
||||
);
|
||||
|
||||
$nodes = new WPML_Elementor_Translatable_Nodes();
|
||||
$elementor_db_factory = new WPML_Elementor_DB_Factory();
|
||||
$data_settings = new WPML_Elementor_Data_Settings( $elementor_db_factory->create() );
|
||||
|
||||
$string_registration_factory = new WPML_String_Registration_Factory( $data_settings->get_pb_name() );
|
||||
$string_registration = $string_registration_factory->create();
|
||||
|
||||
$register_strings = new WPML_Elementor_Register_Strings( $nodes, $data_settings, $string_registration );
|
||||
$update_translation = new WPML_Elementor_Update_Translation( $nodes, $data_settings );
|
||||
|
||||
return new WPML_Page_Builders_Integration( $register_strings, $update_translation, $data_settings );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
class WPML_PB_Elementor_Handle_Custom_Fields_Factory implements IWPML_Backend_Action_Loader, IWPML_AJAX_Action_Loader, IWPML_Frontend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
$elementor_db_factory = new WPML_Elementor_DB_Factory();
|
||||
$data_settings = new WPML_Elementor_Data_Settings( $elementor_db_factory->create() );
|
||||
|
||||
return new WPML_PB_Handle_Custom_Fields( $data_settings );
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user