PluginProbe
Themify Builder / trunk
Themify Builder vtrunk
7.8.1 7.8.0 7.7.9 7.7.8 7.7.7 7.7.6 7.7.5 7.7.4 7.7.3 7.7.2 trunk 7.6.0 7.6.1 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.8 7.6.9 7.7.0 7.7.1
themify-builder / includes / components / module.php

module.php in Themify Builder trunk, at includes/components/module.php

2,196 lines 79.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file contain abstraction class to create module object.
5 *
6 * Themify_Builder_Component_Module class should be used as main class and
7 * create any child extend class for module.
8 *
9 *
10 * @package Themify_Builder
11 * @subpackage Themify_Builder/classes
12 */
13 defined('ABSPATH') || exit;
14
15 /**
16 * The abstract class for Module.
17 *
18 * Abstraction class to initialize module object, don't initialize
19 * this class directly but please create child class of it.
20 *
21 *
22 * @package Themify_Builder
23 * @subpackage Themify_Builder/classes
24 * @author Themify
25 */
26 class Themify_Builder_Component_Module {
27
28 /**
29 * Module Name.
30 *
31 * @access public
32 * @var string $name
33 */
34 public $name = ''; //deprecated
35
36 /**
37 * Module Slug.
38 *
39 * @access public
40 * @var string $slug
41 */
42 public $slug = ''; //deprecated
43
44 /**
45 * Module Category.
46 *
47 * @access public
48 * @var string $category
49 */
50 public $category = null; //deprecated
51
52 private static $assets = array();
53 public static $isFirstModule = false;
54 public static $disable_inline_edit = false;
55
56 public static function get_module_class(string $slug):string{
57 $name=\explode('-',$slug);
58 $items=['TB'];
59 foreach($name as $v){
60 $items[]= \ucfirst($v);
61 }
62 $items[]='Module';
63 $className= \implode('_',$items);
64 if(!class_exists('\\'.$className,false)){//bakward
65 if($slug==='pro-image'){
66 $className= 'TB_Image_Pro_Module';
67 }
68 elseif($slug==='typewriter'){
69 $className= 'TB_Typewriter';
70 }
71 elseif($slug==='stats'){
72 $className= 'TB_Statistics_Module';
73 }
74 elseif($slug==='readtime'){
75 $className= 'TB_Read_Time_Module';
76 }
77 elseif($slug==='ab-image'){
78 $className= 'TB_AB_Image_Module';
79 }
80 }
81 return '\\'.$className;
82 }
83
84 public static function get_js_css():array {
85 return array();
86 }
87
88 public static function get_module_icon():string {
89 return '';
90 }
91
92 public static function get_module_name():string {
93 return '';
94 }
95
96 public static function is_available():bool{
97 return true;
98 }
99
100 public static function get_json_file():array {
101 return array();
102 }
103
104 public static function get_styles_json():array {
105 $keys=array();
106 $loadFiles=apply_filters('tb_json_files', []);
107 $res=[THEMIFY_BUILDER_URI.'/json/style.json?ver='.THEMIFY_VERSION];
108 foreach($loadFiles as $file){
109 $res[]=$file['f'].'?ver='.$file['v'];
110 }
111 unset($loadFiles);
112 $modules=self::load_modules();
113 foreach ($modules as $id=>$module) {
114 $file=$module::get_json_file();
115 if(!empty($file)){
116 $files[]=$file;
117 $keys[]=$id.$file['v'];
118 }
119 }
120 if(!empty($files)){
121 if ( ! themify_is_dev_mode() && count( $files ) > 2 ) {
122 sort($keys);
123 $jsonDir='/json/';
124 $jsonName=$jsonDir.crc32(implode('',$keys)).'.json';
125 $jsonF=THEMIFY_BUILDER_DIR. $jsonName;
126 unset($keys);
127 $hasError=false;
128 if (!is_file($jsonF)) {
129 $jsonData=$fallback=[];
130 foreach($files as $file){
131 $content=$hasError===false?Themify_Filesystem::get_file_content($file['f']):null;
132 if(!empty($content)){
133 $content=json_decode($content,true);
134 if(!empty($content)){
135 $jsonData=array_merge($jsonData, $content);
136 }
137 }
138 if($hasError===false && empty($content)){
139 $hasError=true;
140 $jsonData=null;
141 }
142 $fallback[]=$file['f'].'?ver='.$file['v'];
143 }
144 if($hasError===false){
145 $tmpF=THEMIFY_BUILDER_DIR.$jsonDir. uniqid('tmp_');
146 $jsonData=json_encode($jsonData);
147 if(empty($jsonData) || !file_put_contents($tmpF, $jsonData) || !rename($tmpF,$jsonF)){
148 $hasError=true;
149 if(is_file($tmpF)){
150 unlink($tmpF);
151 }
152 }
153 $jsonData=null;
154 }
155 if($hasError===true){
156 $res=array_merge($res,$fallback);
157 }
158 unset($fallback);
159 }
160 if($hasError===false){
161 $res[]=THEMIFY_BUILDER_URI.$jsonName.'?ver='.THEMIFY_VERSION;
162 }
163 }
164 else{
165 foreach($files as $file){
166 $res[]=$file['f'].'?ver='.$file['v'];
167 }
168 }
169 }
170 return $res;
171 }
172
173 //will be need later
174 public static function add_inline_edit_icon() {
175
176 }
177
178 /**
179 * Get checkbox data
180 * @param $setting
181 * @return string
182 */
183 public static function get_checkbox_data(string $setting):string {
184 return \implode(' ', \explode('|', $setting));
185 }
186
187 /**
188 * Return only value setting
189 * @param $string
190 * @return string
191 */
192 public static function get_param_value(string $string):string {
193 return \explode('|', $string)[0];
194 }
195
196
197 /**
198 * Retrieve builder templates
199 * @param $template_name
200 * @param array $args
201 * @param string $template_path
202 * @param string $default_path
203 * @param bool $echo
204 * @return string|VOID
205 */
206 public static function retrieve_template(string $template_name,$args = array(),string $template_path = '', string $default_path = '', bool $echo = true) {
207 if ($echo === false) {
208 ob_start();
209 }
210 self::get_template($template_name, $args, $template_path, $default_path);
211 if ($echo === false) {
212 return ob_get_clean();
213 }
214 }
215
216 /**
217 * Get template builder
218 * @param $template_name
219 * @param array $args
220 * @param string $template_path
221 * @param string $default_path
222 */
223 protected static function get_template(string $template_name, &$args = array(),string $template_path = '',string $default_path = '') {
224 static $paths = array();
225 $key = $template_path . $template_name;
226 if (!isset($paths[$key])) {
227 $paths[$key] = self::locate_template($template_name, $template_path, $default_path);
228 }
229 if (isset($paths[$key]) && $paths[$key] !== '') {
230 global $ThemifyBuilder;//deprecated
231 include($paths[$key]);
232 }
233 }
234
235 /**
236 * Locate a template and return the path for inclusion.
237 *
238 * This is the load order:
239 *
240 * yourtheme / $template_path / $template_name
241 * $default_path / $template_name
242 */
243 public static function locate_template(string $template_name,string $template_path = '',string $default_path = ''):string {
244 static $theme_dir = null;
245 static $child_dir = null;
246 $template = '';
247
248 $DS = DIRECTORY_SEPARATOR;
249 if ($theme_dir === null) {
250 $builderDir = $DS . 'themify-builder' . $DS;
251 $theme_dir = get_template_directory() . $builderDir;
252 if (!\is_dir($theme_dir)) {
253 $theme_dir = false;
254 }
255 if (is_child_theme()) {
256 $child_dir = get_stylesheet_directory() . $builderDir;
257 if (!\is_dir($child_dir)) {
258 $child_dir = false;
259 }
260 }
261 $builderDir = null;
262 }
263 if ($theme_dir !== false || $child_dir !== null || $child_dir !== false) {
264 $templates = array();
265 if ($child_dir !== null && $child_dir !== false) {
266 $templates[] = $child_dir;
267 }
268 if ($theme_dir !== false) {
269 $templates[] = $theme_dir;
270 }
271 foreach ($templates as $dir) {//is theme file
272 if (\is_file($dir . $template_name)) {
273 $template = $dir . $template_name;
274 break;
275 }
276 }
277 unset($templates);
278 }
279 if ($template === '') {
280 if ($template_path === '') {
281 $modulesPath = \Themify_Builder_Model::get_directory_path();
282 if (\strpos($template_name, 'template-') === 0) {
283 $module = str_replace(array('template-', '.php'), '', $template_name);
284 if (isset($modulesPath[$module])) {
285 $template = pathinfo($modulesPath[$module], PATHINFO_DIRNAME) . $DS . 'templates' . $DS . $template_name;
286 }
287 }
288 if ($template === '') {
289 $dir = rtrim(THEMIFY_BUILDER_TEMPLATES_DIR, $DS) . $DS;
290 if (\is_file($dir . $template_name)) {
291 $template = $dir . $template_name;
292 }
293 // Get default template
294 if ($template === '') {
295 foreach ($modulesPath as $m) {//backward
296 $dir = pathinfo($m, PATHINFO_DIRNAME) . $DS . 'templates' . $DS . $template_name;
297 if (\is_file($dir)) {
298 $template = $dir;
299 break;
300 }
301 }
302 if ($template === '') {
303 $template = $default_path . $template_name;
304 if (\is_file($template)) {
305 $template = '';
306 }
307 }
308 }
309 }
310 } else {
311 $template = \rtrim($template_path, $DS) . $DS . $template_name;
312 }
313 }
314 // Return what we found
315 return apply_filters('themify_builder_locate_template', $template, $template_name, $template_path);
316 }
317
318
319 /**
320 * Sticky Element props attributes, also handles Motion Effects
321 * @param array $props
322 * @param array $fields_args
323 * @param string $mod_name
324 * @param string $module_ID
325 * @return array
326 */
327 public static function sticky_element_props( array &$props,array $fields_args, string $motion_option_prefix = '' ) {
328 // Prefixed calls (e.g. cover_) target child overlays — skip row/module sticky + ID.
329 if ( $motion_option_prefix === '' && ( !empty($fields_args['stick_at_check']) || !empty($fields_args['stick_at_check_t']) || !empty($fields_args['stick_at_check_tl']) || !empty($fields_args['stick_at_check_m']) ) ) {
330 static $is_sticky = null;
331 if ($is_sticky === null) {
332 $is_sticky = \Themify_Builder_Model::is_sticky_scroll_active();
333 }
334 if ($is_sticky !== false) {
335 $_arr = array('d', 'tl', 't', 'm');
336 $settings = array();
337 foreach ($_arr as $v) {
338 $key = $v === 'd' ? '' : '_' . $v;
339 if (($key === '' && !empty($fields_args['stick_at_check'])) || ($key !== '' && isset($fields_args['stick_at_check' . $key]) && $fields_args['stick_at_check' . $key] !== '')) {
340 $settings[$v] = array();
341 if ($key !== '' && $fields_args['stick_at_check' . $key] !== '1') {
342 $settings[$v] = 0;
343 } else {
344 if (isset($fields_args['stick_at_position' . $key]) && $fields_args['stick_at_position' . $key] === 'bottom') {
345 $settings[$v]['stick'] = array();
346 $settings[$v]['stick']['p'] = $fields_args['stick_at_position' . $key];
347 }
348 if (!empty($fields_args['stick_at_pos_val' . $key])) {
349 if (!isset($settings[$v]['stick'])) {
350 $settings[$v] = array('stick' => array());
351 }
352 $settings[$v]['stick']['v'] = $fields_args['stick_at_pos_val' . $key];
353 if (isset($fields_args['stick_at_pos_val_unit' . $key]) && $fields_args['stick_at_pos_val_unit' . $key] !== 'px') {
354 $settings[$v]['stick']['u'] = $fields_args['stick_at_pos_val_unit' . $key];
355 }
356 }
357
358 if (!empty($fields_args['unstick_when_check' . $key])) {
359 $unstick = array();
360 if (isset($fields_args['unstick_when_element' . $key]) && $fields_args['unstick_when_element' . $key] !== 'builder_end') {
361 if (isset($fields_args['unstick_when_condition' . $key]) && $fields_args['unstick_when_condition' . $key] !== 'hits') {
362 $unstick['r'] = $fields_args['unstick_when_condition' . $key];
363 }
364 $unstick['type'] = $fields_args['unstick_when_element' . $key];
365 if ($unstick['type'] === 'row' && isset($fields_args['unstick_when_el_row_id' . $key]) && $fields_args['unstick_when_el_row_id' . $key] !== 'row') {
366 $unstick['el'] = $fields_args['unstick_when_el_row_id' . $key];
367 } elseif ($unstick['type'] === 'module' && !empty($fields_args['unstick_when_el_mod_id' . $key])) {
368 $unstick['el'] = $fields_args['unstick_when_el_mod_id' . $key];
369 } else {
370 continue;
371 }
372
373 if (isset($fields_args['unstick_when_pos' . $key]) && $fields_args['unstick_when_pos' . $key] !== 'this') {
374 $unstick['cur'] = $fields_args['unstick_when_pos' . $key];
375 if (!empty($fields_args['unstick_when_pos_val' . $key])) {
376 $unstick['v'] = $fields_args['unstick_when_pos_val' . $key];
377 if (isset($fields_args['unstick_when_pos_val_unit' . $key]) && $fields_args['unstick_when_pos_val_unit' . $key] !== 'px') {
378 $unstick['u'] = $fields_args['unstick_when_pos_val_unit' . $key];
379 }
380 }
381 }
382 } else {
383 $unstick['type'] = 'builder';
384 }
385 if (!empty($unstick)) {
386 $settings[$v]['unstick'] = $unstick;
387 }
388 }
389 }
390 }
391 }
392 if (!empty($settings)) {
393 unset($_arr);
394 $props['data-sticky-active'] = \json_encode($settings);
395 if ($is_sticky !== 'done') {
396 $is_sticky = 'done';
397 \Themify_Enqueue_Assets::addPrefetchJs(THEMIFY_BUILDER_JS_MODULES . 'sticky.js', THEMIFY_VERSION);
398 }
399 }
400 }
401 }//Add custom attributes html5 data to module container div to show parallax options.
402 elseif (Themify_Builder::$frontedit_active === false && (!empty($fields_args[ $motion_option_prefix . 'motion_effects' ] ) || !empty($fields_args['custom_parallax_scroll_speed']) )) {
403 static $is_lax = null;
404 if ($is_lax === null) {
405 $is_lax = \Themify_Builder_Model::is_scroll_effect_active();
406 }
407 if ($is_lax !== false) {
408 $has_lax = false; /* validate Lax settings */
409 // Check settings from Floating tab to apply them to Lax library
410 if (!empty($fields_args['custom_parallax_scroll_speed'])) {
411 $has_lax = true;
412 $props['data-parallax-element-speed'] = $fields_args['custom_parallax_scroll_speed'];
413
414 $speed = self::map_animation_speed($fields_args['custom_parallax_scroll_speed']);
415
416 if (!isset($fields_args['custom_parallax_scroll_reverse']) || $fields_args['custom_parallax_scroll_reverse'] === '|') {
417 $speed = '-' . $speed;
418 }
419 $props['data-lax-translate-y'] = 'vh 1,0 ' . $speed;
420 if (!empty($fields_args['custom_parallax_scroll_fade']) && $fields_args['custom_parallax_scroll_fade'] !== '|') {
421 $props['data-lax-opacity'] = 'vh 1,0 0';
422 }
423 }
424 // Add motion effects from Motion tab
425 $effects = isset($fields_args[ $motion_option_prefix . 'motion_effects' ] ) ? $fields_args[ $motion_option_prefix . 'motion_effects' ] : array();
426 if (!isset($effects['t'])) {
427 $props['data-lax-optimize'] = 'true';
428 }
429 // Vertical
430 if (!empty($effects['v']['val']['v_dir'])) {
431 $has_lax = true;
432 $v_speed = isset($effects['v']['val']['v_speed']) ? $effects['v']['val']['v_speed'] : 1;
433 $v_speed = self::map_animation_speed($v_speed);
434 $viewport = isset($effects['v']['val']['v_vp']) ? explode(',', $effects['v']['val']['v_vp']) : array(0, 100);
435 $bottom = 1 - ( (int) $viewport[0] / 100 );
436 $top = 1 - ( (int) $viewport[1] / 100 );
437 $props['data-lax-translate-y'] = $effects['v']['val']['v_dir'] === 'up' ? '(vh*' . $bottom . ') 0,(vh*' . $top . ') -' . $v_speed : '(vh*' . $bottom . ') 0,(vh*' . $top . ') ' . $v_speed;
438 }
439 // Horizontal
440 if (!empty($effects['h']['val']['h_dir'])) {
441 $has_lax = true;
442 $h_speed = isset($effects['h']['val']['h_speed']) ? $effects['h']['val']['h_speed'] : 9;
443 $h_speed=self::map_animation_speed($h_speed);
444 $viewport = isset($effects['h']['val']['h_vp']) ? explode(',', $effects['h']['val']['h_vp']) : array(0, 100);
445 $bottom = 1 - ( (int) $viewport[0] / 100 );
446 $top = 1 - ( (int) $viewport[1] / 100 );
447 $props['data-lax-translate-x'] = $effects['h']['val']['h_dir'] === 'toleft' ? '(vh*' . $bottom . ') 0,(vh*' . $top . ') -' . $h_speed : '(vh*' . $bottom . ') 0,(vh*' . $top . ') ' . $h_speed;
448 }
449 // Opacity
450 if (!empty($effects['t']['val']['t_dir'])) {
451 $has_lax = true;
452 $viewport = isset($effects['t']['val']['t_vp']) ? explode(',', $effects['t']['val']['t_vp']) : array(0, 100);
453 $bottom = 1 - ( (int) $viewport[0] / 100 );
454 $top = 1 - ( (int) $viewport[1] / 100 );
455 $center = ( $bottom - ( ( $bottom - $top ) / 2 ) );
456 if ($effects['t']['val']['t_dir'] === 'fadein') {
457 $props['data-lax-opacity'] = '(vh*' . $bottom . ') 0,(vh*' . $top . ') 1';
458 } elseif ($effects['t']['val']['t_dir'] === 'fadeout') {
459 $props['data-lax-opacity'] = '(vh*' . $bottom . ') 1,(vh*' . $top . ') 0';
460 } elseif ($effects['t']['val']['t_dir'] === 'fadeoutin') {
461 $props['data-lax-opacity'] = '(vh*' . $bottom . ') 1,(vh*' . $center . ') 0,(vh*' . $top . ') 1';
462 } elseif ($effects['t']['val']['t_dir'] === 'fadeinout') {
463 $props['data-lax-opacity'] = '(vh*' . $bottom . ') 0,(vh*' . $center . ') 1,(vh*' . $top . ') 0';
464 }
465 } elseif (!isset($fields_args['animation_effect_delay'])) {
466 unset($props['data-lax-opacity'], $props['data-lax-optimize']);
467 }
468 // Blur
469 if (!empty($effects['b']['val']['b_dir'])) {
470 $has_lax = true;
471 $b_level = isset($effects['b']['val']['b_level']) ? $effects['b']['val']['b_level']: 5;
472 $b_level=self::map_animation_speed($b_level, 'blur');
473 $viewport = isset($effects['b']['val']['b_vp']) ? explode(',', $effects['b']['val']['b_vp']) : array(0, 100);
474 $bottom = 1 - ( (int) $viewport[0] / 100 );
475 $top = 1 - ( (int) $viewport[1] / 100 );
476 $props['data-lax-blur'] = $effects['b']['val']['b_dir'] === 'fadein' ? '(vh*' . $bottom . ') ' . $b_level . ',(vh*' . $top . ') 0' : '(vh*' . $bottom . ') 0,(vh*' . $top . ') ' . $b_level;
477 }
478 // Rotate
479 if (!empty($effects['r']['val']['r_dir'])) {
480 $has_lax = true;
481 $viewport = isset($effects['r']['val']['r_vp']) ? explode(',', $effects['r']['val']['r_vp']) : array(0, 100);
482 $rotates = isset($effects['r']['val']['r_num']) ? (float) $effects['r']['val']['r_num'] * 360 : 360;
483 $bottom = 1 - ( (int) $viewport[0] / 100 );
484 $top = 1 - ( (int) $viewport[1] / 100 );
485 $props['data-lax-rotate'] = $effects['r']['val']['r_dir'] === 'toleft' ? '(vh*' . $bottom . ') 0,(vh*' . $top . ') -' . $rotates : '(vh*' . $bottom . ') 0,(vh*' . $top . ') ' . $rotates;
486 if (isset($effects['r']['val']['r_origin'])) {
487 $props['data-box-position'] = self::map_transform_origin($effects['r']['val']['r_origin']);
488 }
489 }
490 // Scale
491 if (!empty($effects['s']['val']['s_dir'])) {
492 $has_lax = true;
493 $viewport = isset($effects['s']['val']['s_vp']) ? explode(',', $effects['s']['val']['s_vp']) : array(0, 100);
494 $ratio = isset($effects['s']['val']['s_ratio']) ? (float) $effects['s']['val']['s_ratio'] : 3;
495 $bottom = 1 - ( (int) $viewport[0] / 100 );
496 $top = 1 - ( (int) $viewport[1] / 100 );
497 $props['data-lax-scale'] = $effects['s']['val']['s_dir'] === 'up' ? '(vh*' . $bottom . ') 1,(vh*' . $top . ') ' . $ratio : '(vh*' . $bottom . ') 1,(vh*' . $top . ') ' . number_format(1 / $ratio, 3);
498 if (isset($effects['s']['val']['s_origin'])) {
499 $props['data-box-position'] = self::map_transform_origin($effects['s']['val']['s_origin']);
500 }
501 }
502 if ($has_lax === true) {
503 $props['data-lax'] = 'true';
504 }
505 if ($is_lax !== 'done') {
506 $is_lax = 'done';
507 \Themify_Enqueue_Assets::addPrefetchJs(THEMIFY_URI . '/js/modules/lax.js', THEMIFY_VERSION);
508 }
509 }
510 }
511 if ( $motion_option_prefix === '' && isset($fields_args['custom_css_id'])) {
512 $props['id'] = $fields_args['custom_css_id'];
513 }
514 return $props;
515 }
516
517 /**
518 * Map animation speed parameter and returns new speed
519 *
520 * @param string $val Initial speed value
521 * @param string $attr attribute name
522 *
523 * @return float|int Returns speed of element based on initial value
524 */
525 private static function map_animation_speed(float $val,string $attr = ''):float {
526 if($val<0 || $val>10){
527 $val=5;
528 }
529 if($attr === 'blur'){
530 $speed = 2*$val;
531 }
532 else{
533 $speed = $val===3?200:($val<3?(70*$val):(670-(10-$val)*70));
534 }
535 return $speed;
536 }
537
538 /**
539 * Map initial origin value and returns transform origin property
540 *
541 * @param string $props Initial origin value
542 *
543 * @return string Returns transform origin value of element based on initial value
544 */
545 private static function map_transform_origin(string $props):string {
546 switch ($props) {
547 case '0,0':
548 $output = 'top left';
549 break;
550
551 case '50,0':
552 $output = 'top center';
553 break;
554
555 case '100,0':
556 $output = 'top right';
557 break;
558
559 case '0,50':
560 $output = 'left center';
561 break;
562
563 case '50,50':
564 $output = 'center center';
565 break;
566
567 case '100,50':
568 $output = 'right center';
569 break;
570
571 case '0,100':
572 $output = 'bottom left';
573 break;
574
575 case '50,100':
576 $output = 'bottom center';
577 break;
578
579 case '100,100':
580 $output = 'bottom right';
581 break;
582
583 default:
584 $perc = \explode(',', $props);
585 $output = $perc[0] . '% ' . $perc[1] . '%';
586 }
587
588 return $output;
589 }
590
591 /**
592 * Return the correct animation css class name
593 * @param string $effect
594 * @return string
595 */
596 public static function parse_animation_effect($settings, array $attr = array(), array $option_names = [] ) {
597 /* backward compatibility for addons */
598 if (!is_array($settings)) {
599 return '';
600 }
601 static $has = null;
602 if ($has === null) {
603 $has = \Themify_Builder_Model::is_animation_active();
604 }
605 if ($has !== false) {
606
607 $option_names = wp_parse_args( $option_names, [
608 'effect' => 'animation_effect',
609 'delay' => 'animation_effect_delay',
610 'repeat' => 'animation_effect_repeat',
611 'effect_hover' => 'hover_animation_effect'
612 ] );
613
614 if (!empty($settings[ $option_names['effect_hover'] ])) {
615 $attr['data-tf-animation_hover'] = $settings[ $option_names['effect_hover'] ];
616 if (isset($attr['class'])) {
617 $attr['class'] .= ' hover-wow';
618 } else {
619 $attr['class'] = 'hover-wow';
620 }
621 if ($has !== 'done') {
622 $has = 'load';
623 }
624 }
625 if (!empty($settings[ $option_names['effect'] ])) {
626 $attr['data-tf-animation'] = $settings[ $option_names['effect'] ];
627 if (!in_array($settings[ $option_names['effect'] ], array('fade-in', 'fly-in', 'slide-up'), true)) {
628 if (isset($attr['class'])) {
629 $attr['class'] .= ' wow';
630 } else {
631 $attr['class'] = 'wow';
632 }
633 }
634 if (!empty($settings[ $option_names['delay'] ])) {
635 $attr['data-tf-animation_delay'] = $settings[ $option_names['delay'] ];
636 }
637 if (!empty($settings[ $option_names['repeat'] ])) {
638 $attr['data-tf-animation_repeat'] = $settings[ $option_names['repeat'] ];
639 }
640 if ($has !== 'done') {
641 $has = 'load';
642 }
643 }
644 if ($has === 'load') {
645 $has = 'done';
646 \Themify_Enqueue_Assets::preFetchAnimtion();
647 }
648 }
649 return $attr;
650 }
651
652 /**
653 * Load builder modules
654 */
655 public static function load_modules(string $mod_name = 'active', bool $ignore = false) {
656 // load modules
657
658 if ($mod_name !== 'active' && $mod_name !== 'all') {
659 if(isset(Themify_Builder_Model::$modules[$mod_name])){//backward will be removed in the future
660 return Themify_Builder_Model::$modules[$mod_name];
661 }
662 $className=self::get_module_class($mod_name);
663 if(class_exists($className,false)){
664 return $className::is_available()?$className:'';
665 }
666 $dir = \Themify_Builder_Model::get_modules($mod_name,$ignore);
667
668 if($dir!==''){
669 if($dir === true ){
670 $dir=THEMIFY_BUILDER_MODULES_DIR;
671 }
672 require $dir . '/module-' . $mod_name . '.php';
673 $className=self::get_module_class($mod_name);//the second call need for backward
674 return isset(Themify_Builder_Model::$modules[$mod_name])?Themify_Builder_Model::$modules[$mod_name]:($className::is_available()?$className:'');
675 }
676 return '';
677 }
678 $modules=[];
679 $items = \Themify_Builder_Model::get_modules($mod_name);
680 foreach ($items as $m => $dir) {
681 if ($dir === true) {
682 $dir = THEMIFY_BUILDER_MODULES_DIR;
683 }
684 require_once $dir . '/module-' . $m . '.php';
685 if(isset(Themify_Builder_Model::$modules[$m])){
686 $item=Themify_Builder_Model::$modules[$m];
687 }else{
688 $className=self::get_module_class($m);
689 if(!$className::is_available()){
690 continue;
691 }
692 $item=$className;
693 }
694 $modules[$m]=$item;
695 }
696 return $modules;
697 }
698
699 public static function get_modules_assets():array {
700 return self::$assets;
701 }
702
703 public static function add_modules_assets($k, $item):void {
704 self::$assets[$k] = $item;
705 }
706
707 public static function render(string $slug, string $mod_id, $builder_id, array &$settings = array(), bool $echo = false) {
708 $template = $slug === 'highlight' || $slug === 'testimonial' || $slug === 'post' || $slug === 'portfolio' ? 'blog' : $slug;
709
710 $vars = array(
711 'module_ID' => $mod_id,
712 'mod_name' => $slug,
713 'builder_id' => $builder_id,
714 'mod_settings' => $settings
715 );
716 $vars = apply_filters('themify_builder_module_render_vars', $vars, $slug);
717
718 return self::retrieve_template('template-' . $template . '.php', $vars, '', '', $echo);
719 }
720
721 /**
722 * If there's not an options tab in Themify Custom Panel meta box already defined for this post type, like "Portfolio Options", add one.
723 *
724 * @since 2.3.8
725 *
726 * @param array $meta_boxes
727 *
728 * @return array
729 */
730 public static function cpt_meta_boxes(array $meta_boxes = array()):array {
731 Themify_Builder_Model::load_general_metabox(); // setup common fields
732
733 $meta_box_id = static::SLUG . '-options';
734 if (!in_array($meta_box_id, wp_list_pluck($meta_boxes, 'id'), true)) {
735 $options = static::get_metabox();
736 if (!empty($options)) {
737 $meta_boxes = array_merge($meta_boxes, array(
738 array(
739 'name' => sprintf(__('%s Options', 'themify'), self::get_module_name()),
740 'id' => $meta_box_id,
741 'options' => $options,
742 'pages' => static::SLUG
743 )
744 ));
745 }
746 }
747
748 return $meta_boxes;
749 }
750
751 public static function get_module_title(array $fields_args,string $key = 'mod_title'):string {
752 if (isset($fields_args[$key]) && $fields_args[$key] !== '') {
753 $titleTag=apply_filters('themify_builder_module_title_tag', 'h3');
754 $startTag='<'.$titleTag.' class="module-title"';
755 if($key!=='' && (Themify_Builder::$frontedit_active === true || Themify_Builder_Model::is_front_builder_activate())){
756 $startTag.=' data-name="'.$key.'" contenteditable="false"';
757 }
758 return $startTag .'>'. $fields_args[$key] . '</'.$titleTag.'>';
759 }
760 return '';
761 }
762
763
764
765 /**
766 * Get query page
767 */
768 public static function get_paged_query():int {
769 global $wp;
770 if (isset($_GET['tf-page']) && is_numeric($_GET['tf-page'])) {
771 $page = (int) $_GET['tf-page'];
772 }
773 else {
774 $qpaged = get_query_var('paged');
775 if (!empty($qpaged)) {
776 $page = (int)$qpaged;
777 }
778 else {
779 $qpaged = wp_parse_args($wp->matched_query);
780 $page = isset($qpaged['paged']) && $qpaged['paged'] > 0?(int)$qpaged['paged']:1;
781 }
782 }
783 return $page;
784 }
785
786 public static function query(array $args):WP_Query {
787 $isPaged = isset($args['paged']) && $args['paged'] > 1;
788 $hasSticky = isset($args['ignore_sticky_posts']) && $args['ignore_sticky_posts'] === false;
789 $maxPage = (int) $args['posts_per_page'];
790 if ($hasSticky === true) {
791 $sticky_posts = get_option('sticky_posts');
792 if (empty($sticky_posts)) {
793 $hasSticky = false;
794 } else {
795 $sticky_posts = array_slice($sticky_posts, 0, $maxPage);
796 }
797 }
798 if ($hasSticky === true && $isPaged === false) {
799 $params = array(
800 'post_status' => 'publish',
801 'post_type' => $args['post_type'],
802 'post__in' => $sticky_posts,
803 'orderby' => 'post__in',
804 'posts_per_page' => $maxPage,
805 'ignore_sticky_posts' => true
806 );
807 if (isset($args['tax_query'])) {
808 $params['tax_query'] = $args['tax_query'];
809 }
810 if (isset($args['meta_key'])) {
811 $params['meta_key'] = $args['meta_key'];
812 }
813 if (isset($args['post__not_in'])) {
814 $params['post__not_in'] = $args['post__not_in'];
815 }
816 $the_query = new WP_Query($params);
817 if ($the_query->post_count < $maxPage) {
818 if (isset($args['post__not_in'])) {
819 $args['post__not_in'] = array_merge($args['post__not_in'],$sticky_posts);;
820 } else {
821 $args['post__not_in'] = $sticky_posts;
822 }
823 $args['ignore_sticky_posts'] = true;
824 $args['posts_per_page'] = $maxPage - $the_query->post_count;
825 $q = new WP_Query($args);
826 $the_query->found_posts = $q->found_posts;
827 $the_query->posts = array_merge($the_query->posts, $q->posts);
828 $the_query->post_count = count($the_query->posts);
829 $the_query->max_num_pages = ceil($the_query->found_posts / $maxPage);
830 unset($q, $args);
831 }
832 } else {
833 if ($isPaged === true && $hasSticky === true) {
834 if (isset($args['post__not_in'])) {
835 $args['post__not_in']= array_merge($args['post__not_in'],$sticky_posts);
836 } else {
837 $args['post__not_in'] = $sticky_posts;
838 }
839 }
840 $the_query = new WP_Query($args);
841 }
842
843 return $the_query;
844 }
845
846 /**
847 * Returns Pagination
848 * @param string Markup to show before pagination links
849 * @param string Markup to show after pagination links
850 * @param object WordPress query object to use
851 * @param original_offset number of posts configured to skip over
852 * @return string
853 */
854 public static function get_pagination($before = '', $after = '', $query = false, $original_offset = 0, $max_page = 0, $paged = 0):string {
855 if (false == $query) {
856 global $wp_query;
857 $query = $wp_query;
858 }
859 if ($paged === 0) {
860 $paged = (int) self::get_paged_query();
861 }
862 if ($max_page === 0) {
863 $numposts = $query->found_posts;
864 $original_offset = (int) $original_offset;
865 // $query->found_posts does not take offset into account, we need to manually adjust that
866 if ($original_offset > 0) {
867 $numposts -= $original_offset;
868 }
869 $max_page = ceil($numposts / $query->query_vars['posts_per_page']);
870 }
871 if ($max_page > 1) {
872 Themify_Builder_Model::loadCssModules('pagenav', THEMIFY_BUILDER_CSS_MODULES . 'pagenav.css', THEMIFY_VERSION);
873 if (!is_string($query) && is_single()) {
874 $query = 'tf-page';
875 }
876 }
877 return themify_get_pagenav($before, $after, $query, $max_page, $paged);
878 }
879
880
881
882
883 /**
884 * Get template for module
885 * @param $mod
886 * @param int $builder_id
887 * @param bool $echo
888 * @return string
889 */
890 public static function template(array &$mod, $builder_id = 0,bool $echo = true) {
891 if (Themify_Builder::$frontedit_active === false) {
892 /* allow addons to control the display of the modules */
893 $display = apply_filters('themify_builder_module_display', true, $mod, $builder_id);
894 if (false === $display || ( isset($mod['mod_settings']['visibility_all']) && $mod['mod_settings']['visibility_all'] === 'hide_all' )) {
895 return '';
896 }
897 }
898 if (!isset($mod['mod_name'])) {
899 return '';
900 }
901 $output = '';
902 $slug = $mod['mod_name'];
903 static $isLoaded = array();
904 self::$isFirstModule = false;
905 if (!isset($isLoaded[$slug])) {//load only the modules in the page
906 $module = self::load_modules($slug);
907 if($module===''){// check whether module active or not
908 return '';
909 }
910 $isLoaded[$slug] = true;
911 if (Themify_Builder::$frontedit_active === false && empty($mod['mod_settings']['_render_plain_content'])) {
912 $assets = \is_string($module) ? $module::get_js_css() : $module->get_assets();
913 static $count = 0; //only need to load the modules styles in concate for the first 2 modules to show LCP asap,even if they should load as async
914 if (!empty($assets)) {
915 $ver = isset($assets['ver']) ? $assets['ver'] : THEMIFY_VERSION;
916 self::$isFirstModule = $count < 2;
917 if (isset($assets['css']) && ($count < 2 || !isset($assets['async']))) {
918 if ($echo === true) {
919 $assets['css'] = (array) $assets['css'];
920 $content_url=content_url();
921 foreach ($assets['css'] as $k => $s) {
922 $key = is_int($k) ? $slug : $k;
923 if ($s === 1) {
924 $s = THEMIFY_BUILDER_CSS_MODULES . $slug . '.css';
925 } else {
926 if (\strpos($s, 'http') === false && \strpos($s,$content_url)===false) {
927 $s = THEMIFY_BUILDER_CSS_MODULES . $s;
928 }
929 if (\strpos($s, '.css') === false) {
930 $s .= '.css';
931 }
932 }
933 \Themify_Builder_Model::loadCssModules($key, $s, $ver);
934 }
935 }
936 unset($assets['css']);
937 }
938 if (isset($assets['js']) || isset($assets['css'])) {
939 if (self::$isFirstModule === true && isset($assets['js'])) {
940 $u = $assets['js'];
941 if ($u === 1) {
942 $u = THEMIFY_BUILDER_JS_MODULES . $slug . '.js';
943 } else {
944 if (\strpos($u, 'http') === false && \strpos($s, content_url())===false) {
945 $u = THEMIFY_BUILDER_JS_MODULES . $u;
946 }
947 if (\strpos($u, '.js') === false) {
948 $u .= '.js';
949 }
950 }
951 \Themify_Enqueue_Assets::addPrefetchJs($u, $ver);
952 }
953 unset($assets['async']);
954 self::$assets[$slug] = $assets;
955 }
956 if ($slug === 'feature' || $slug === 'menu' || $slug === 'tab' || $slug === 'accordion' || $slug === 'table') {
957 \Themify_Enqueue_Assets::addPrefetchJs(THEMIFY_BUILDER_JS_MODULES . $slug . '.js', $ver);
958 }
959 unset($assets, $ver);
960 }
961 ++$count;
962 }
963 }
964 $mod['mod_settings'] = isset($mod['mod_settings']) ? $mod['mod_settings'] : array();
965 if ($echo !== true) {
966 $output .= PHP_EOL; // add line break
967 ob_start();
968 }
969 do_action('themify_builder_background_styling', $builder_id, array('styling' => $mod['mod_settings'], 'mod_name' => $slug, 'element_id' => $mod['element_id']), 'module', '');
970 if ($echo !== true) {
971 $output .= ob_get_clean() . PHP_EOL;
972 }
973 elseif ($slug === 'slider' && Themify_Builder::$frontedit_active === false) {
974 $isEcho = true;
975 $echo = false;
976 }
977 // render the module
978 $res = self::render($slug, 'tb_' . $mod['element_id'], $builder_id, $mod['mod_settings'], $echo);
979 if (!empty($res)) {
980 $output .= $res;
981 }
982 if ($echo === true) {
983 echo $output;
984 }
985 else {
986 if ($slug === 'slider' && Themify_Builder::$frontedit_active === false) {
987 $output = \themify_make_lazy($output, false);
988 if (isset($isEcho) && $isEcho === true) {
989 echo $output;
990 return;
991 }
992 }
993 return $output . PHP_EOL;
994 }
995 }
996
997
998 /**
999 * Retrieve saved settings for a module
1000 *
1001 * @return array
1002 */
1003 public static function get_element_settings( $post_id, $element_id ):array {
1004 $data = Themify_Builder::get_builder_modules_list( $post_id );
1005 if ( ! empty( $data ) ) {
1006 foreach ( $data as $module ) {
1007 if ( isset( $module['element_id'], $module['mod_settings'] ) && $module['element_id'] === $element_id ) {
1008 return $module['mod_settings'];
1009 }
1010 }
1011 }
1012
1013 return [];
1014 }
1015
1016 /**
1017 * Get plain content of the module output.
1018 *
1019 * @param array $module
1020 * @return string
1021 */
1022 public static function get_static_content(array $module):string {
1023 if (isset($module['mod_settings'])) {
1024 $module['mod_settings']['_render_plain_content'] = true;
1025 // Remove format text filter including do_shortcode
1026 if (!Themify_Builder_Model::is_front_builder_activate()) {
1027 remove_filter('themify_builder_module_content', array('Themify_Builder_Model', 'format_text'));
1028 }
1029 } else {
1030 $module['mod_settings'] = array('_render_plain_content' => true);
1031 }
1032 return self::template($module, 0, false);
1033 }
1034
1035
1036 /**
1037 * Add z-index option to styling tab
1038 *
1039 * @return array
1040 */
1041 private static function add_zindex_filed(array &$styling) {//@deprecated has been moved to js
1042 $field = self::get_expand('zi',
1043 array(
1044 self::get_zindex('', 'custom_parallax_scroll_zindex')
1045 )
1046 );
1047 if (isset($styling['type']) && 'tabs' === $styling['type']) {
1048 $k = key($styling['options']);
1049 if (isset($styling['options'][$k]['options'])) {
1050 $styling['options'][$k]['options'][] = $field;
1051 } else {
1052 $styling['options'][$k][] = $field;
1053 }
1054 } else {
1055 $styling[] = $field;
1056 }
1057 return $styling;
1058 }
1059
1060 /**
1061 * Add Transform options to styling tab
1062 *
1063 * @return array
1064 */
1065 private static function add_transform_filed(array &$styling) {//@deprecated has been moved to js
1066 $field = self::get_expand('tr', array(
1067 self::get_tab(array(
1068 'n' => array(self::get_transform()),
1069 'h' => array(self::get_transform('', 'tr', 'h'))
1070 ))
1071 ));
1072 if (isset($styling['type']) && 'tabs' === $styling['type']) {
1073 $k = key($styling['options']);
1074 if (isset($styling['options'][$k]['options'])) {
1075 $styling['options'][$k]['options'][] = $field;
1076 } else {
1077 $styling['options'][$k][] = $field;
1078 }
1079 } else {
1080 $styling[] = $field;
1081 }
1082 return $styling;
1083 }
1084
1085 public function __construct($slug) {//@deprecated
1086 if (is_string($slug)) {
1087 $this->slug = $slug;
1088 $this->name = $this->get_name();
1089 } else {
1090 $this->name = $slug['name'];
1091 $this->slug = $slug['slug'];
1092 if (isset($slug['category'])) {
1093 $this->category = $slug['category'];
1094 }
1095 }
1096 Themify_Builder_Model::$modules[$this->slug] = $this;
1097 }
1098
1099 public function get_form_settings($tab = '') {//@deprecated has been moved to js
1100 $styles = $this->get_styling();
1101 if (empty($styles)) {
1102 return array();
1103 }
1104 // Add Z-index to all modules
1105 self::add_zindex_filed($styles);
1106 self::add_transform_filed($styles);
1107 return $styles;
1108 }
1109
1110 /**
1111 * Get Module Title.
1112 *
1113 * @access public
1114 * @param object $module
1115 */
1116 public function get_title($module) {//@deprecated
1117 return '';
1118 }
1119
1120 public function get_assets() {//@deprecated use get_js_css
1121 }
1122
1123 /**
1124 * Get module styling options.
1125 *
1126 * @access public
1127 */
1128 public function get_styling() {//@deprecated has been moved to js
1129 return array();
1130 }
1131
1132 public function get_icon() {//@deprecated use get_module_icon
1133 return '';
1134 }
1135
1136 public function get_name() {//@deprecated use get_module_name
1137 return '';
1138 }
1139
1140 /**
1141 * Get module options.
1142 *
1143 * @access public
1144 */
1145 public function get_options() {//@deprecated has been moved to js.
1146 return array();
1147 }
1148
1149 protected function _visual_template() {//@deprecated has been moved to js.
1150 }
1151
1152 public function get_default_settings() {//@deprecated
1153 return false;
1154 }
1155
1156 public function get_default_args() {//@deprecated
1157 return array();
1158 }
1159
1160 public function get_live_default() {//@deprecated has been moved to js.
1161 return false;
1162 }
1163
1164 public function get_visual_type() {//@deprecated has been moved to js.
1165 return 'live';
1166 }
1167
1168 public function get_group() {//@deprecated has been moved to js.
1169 return false;
1170 }
1171
1172 public function print_template($echo = false, $ignoreLocal = false) {//@deprecated has been moved to js
1173 }
1174
1175
1176 public static function get_element_attributes(array $props) {//@deprecated use themify_get_element_attributes
1177 return themify_get_element_attributes($props);
1178 }
1179
1180 //add inline editing fields
1181 public static function add_inline_edit_fields( $name, $condition = true, $hasEditor = false, $repeat = false, $index = -1, $echo = true) {//@deprecated
1182 return '';
1183 }
1184
1185
1186
1187 public static function get_module_args($key = '') {//@deprecated
1188 return apply_filters('themify_builder_module_args', array('before_title' => '<h3 class="module-title">', 'after_title' => '</h3>'));
1189 }
1190
1191 /**
1192 * Render a module, as a plain text
1193 *
1194 * @return string
1195 */
1196 public function get_plain_text($module) {//@deprecated
1197 $options = $this->get_options();
1198 if (empty($options)) {
1199 return '';
1200 }
1201 $out = array();
1202
1203 foreach ($options as $field) {
1204 // sanitization, check for existence of needed keys
1205 if (!isset($field['type'], $field['id'], $module[$field['id']])) {
1206 continue;
1207 }
1208 // text, textarea, and wp_editor field types
1209 if (in_array($field['type'], array('text', 'textarea', 'wp_editor'), true)) {
1210 $out[] = $module[$field['id']];
1211 }
1212 // builder field type
1213 elseif ($field['type'] === 'builder' && is_array($module[$field['id']])) {
1214 // gather text field types included in the "builder" field type
1215 $text_fields = array();
1216 foreach ($field['options'] as $row_field) {
1217 if (isset($row_field['type']) && in_array($row_field['type'], array('text', 'textarea', 'wp_editor'), true)) {
1218 $text_fields[] = $row_field['id'];
1219 }
1220 }
1221 foreach ($module[$field['id']] as $row) {
1222 // separate fields from the row that have text fields
1223 $texts = array_intersect_key($row, array_flip($text_fields));
1224 // add them to the output
1225 $out = array_merge(array_values($texts), $out);
1226 }
1227 }
1228 }
1229
1230 return implode(' ', $out);
1231 }
1232
1233
1234 public static function get_pagenav($before = '', $after = '', $query = false, $original_offset = 0) {//backward compatibility for addons,deprecated use get_pagination
1235 return self::get_pagination($before, $after, $query, $original_offset);
1236 }
1237
1238 public function get_plain_content($module) {//@deprecated use get_static_content
1239 return self::get_static_content($module);
1240 }
1241
1242 public static function get_tab(array $options, $fullwidth = false, $cl = '') {//@deprecated has been moved to js
1243 $opt = array(
1244 'type' => 'tabs',
1245 'options' => $options
1246 );
1247 if ($fullwidth === true) {
1248 if ($cl !== '') {
1249 $cl .= ' tb_tabs_fullwidth';
1250 } else {
1251 $cl = 'tb_tabs_fullwidth';
1252 }
1253 }
1254 if ($cl !== '') {
1255 $opt['class'] = $cl;
1256 }
1257 return $opt;
1258 }
1259
1260 public static function get_seperator($label = false) {//@deprecated has been moved to js
1261 $opt = array(
1262 'type' => 'separator'
1263 );
1264 if ($label !== false) {
1265 $opt['label'] = $label;
1266 }
1267 return $opt;
1268 }
1269
1270 public static function get_expand($label, array $options) {//@deprecated has been moved to js
1271 return array(
1272 'type' => 'expand',
1273 'label' => $label,
1274 'options' => $options
1275 );
1276 }
1277
1278 protected static function get_font_family($selector = '', $id = 'font_family', $state = '') {//@deprecated has been moved to js
1279 if ($state !== '') {
1280 $id .= '_' . $state;
1281 }
1282 $res = array(
1283 'id' => $id,
1284 'type' => 'font_select',
1285 'prop' => 'font-family',
1286 'selector' => $selector
1287 );
1288 if ($state === 'h' || $state === 'hover') {
1289 $res['ishover'] = true;
1290 }
1291 return $res;
1292 }
1293
1294 protected static function get_element_font_weight($selector = '', $id = 'element_font_weight', $state = '') {//backward compatibility
1295 }
1296
1297 protected static function get_font_size($selector = '', $id = 'font_size', $label = '', $state = '') {//@deprecated has been moved to js
1298 if ($state !== '') {
1299 $id .= '_' . $state;
1300 }
1301 $res = array(
1302 'id' => $id,
1303 'type' => 'fontSize',
1304 'selector' => $selector,
1305 'prop' => 'font-size'
1306 );
1307 if ($label !== '') {
1308 $res['label'] = $label;
1309 }
1310 if ($state === 'h' || $state === 'hover') {
1311 $res['ishover'] = true;
1312 }
1313 return $res;
1314 }
1315
1316 protected static function get_line_height($selector = '', $id = 'line_height', $state = '') {//@deprecated has been moved to js
1317 if ($state !== '') {
1318 $id .= '_' . $state;
1319 }
1320 $res = array(
1321 'id' => $id,
1322 'type' => 'lineHeight',
1323 'selector' => $selector,
1324 'prop' => 'line-height'
1325 );
1326 if ($state === 'h' || $state === 'hover') {
1327 $res['ishover'] = true;
1328 }
1329 return $res;
1330 }
1331
1332 protected static function get_letter_spacing($selector = '', $id = 'letter_spacing', $state = '') {//@deprecated has been moved to js
1333 if ($state !== '') {
1334 $id .= '_' . $state;
1335 }
1336 $res = array(
1337 'id' => $id,
1338 'type' => 'letterSpace',
1339 'selector' => $selector,
1340 'prop' => 'letter-spacing'
1341 );
1342 if ($state === 'h' || $state === 'hover') {
1343 $res['ishover'] = true;
1344 }
1345 return $res;
1346 }
1347
1348 protected static function get_flex_align($selector = '', $id = 'align', $state = '') {//@deprecated has been moved to js
1349 if ($state !== '') {
1350 $id .= '_' . $state;
1351 }
1352 $res = array(
1353 'id' => $id,
1354 'label' => 't_a',
1355 'type' => 'icon_radio',
1356 'falign' => true,
1357 'prop' => 'align-content',
1358 'selector' => $selector
1359 );
1360 if ($state === 'h' || $state === 'hover') {
1361 $res['ishover'] = true;
1362 }
1363 return $res;
1364 }
1365
1366 protected static function get_flex_align_items($selector = '', $id = 'align', $state = '') {//@deprecated has been moved to js
1367 if ($state !== '') {
1368 $id .= '_' . $state;
1369 }
1370 $res = array(
1371 'id' => $id,
1372 'label' => 't_a',
1373 'type' => 'icon_radio',
1374 'falign' => true,
1375 'prop' => 'align-items',
1376 'selector' => $selector
1377 );
1378 if ($state === 'h' || $state === 'hover') {
1379 $res['ishover'] = true;
1380 }
1381 return $res;
1382 }
1383
1384 protected static function get_flex_align_content($selector = '', $id = 'align', $state = '') {//@deprecated has been moved to js
1385 if ($state !== '') {
1386 $id .= '_' . $state;
1387 }
1388 $res = array(
1389 'id' => $id,
1390 'label' => 't_a',
1391 'type' => 'icon_radio',
1392 'falign' => true,
1393 'prop' => 'align-content',
1394 'selector' => $selector
1395 );
1396 if ($state === 'h' || $state === 'hover') {
1397 $res['ishover'] = true;
1398 }
1399 return $res;
1400 }
1401
1402 protected static function get_text_align($selector = '', $id = 'text_align', $state = '') {//@deprecated has been moved to js
1403 if ($state !== '') {
1404 $id .= '_' . $state;
1405 }
1406 $res = array(
1407 'id' => $id,
1408 'label' => 't_a',
1409 'type' => 'icon_radio',
1410 'aligment' => true,
1411 'prop' => 'text-align',
1412 'selector' => $selector
1413 );
1414 if ($state === 'h' || $state === 'hover') {
1415 $res['ishover'] = true;
1416 }
1417 return $res;
1418 }
1419
1420 protected static function get_text_transform($selector = '', $id = 'text_transform', $state = '') {//@deprecated has been moved to js
1421 if ($state !== '') {
1422 $id .= '_' . $state;
1423 }
1424 $res = array(
1425 'id' => $id,
1426 'label' => 't_t',
1427 'type' => 'icon_radio',
1428 'text_transform' => true,
1429 'prop' => 'text-transform',
1430 'selector' => $selector
1431 );
1432 if ($state === 'h' || $state === 'hover') {
1433 $res['ishover'] = true;
1434 }
1435 return $res;
1436 }
1437
1438 protected static function get_text_decoration($selector = '', $id = 'text_decoration', $state = '') {//@deprecated has been moved to js
1439 if ($state !== '') {
1440 $id .= '_' . $state;
1441 }
1442 $res = array(
1443 'id' => $id,
1444 'type' => 'icon_radio',
1445 'label' => 't_d',
1446 'text_decoration' => true,
1447 'prop' => 'text-decoration',
1448 'selector' => $selector
1449 );
1450 if ($state === 'h' || $state === 'hover') {
1451 $res['ishover'] = true;
1452 }
1453 return $res;
1454 }
1455
1456 protected static function get_font_style($selector = '', $id = 'font_style', $id2 = 'font_weight', $state = '') {//@deprecated has been moved to js
1457 if ($state !== '') {
1458 $id .= '_' . $state;
1459 $id2 .= '_' . $state;
1460 }
1461 $res = array(
1462 'id' => $id,
1463 'id2' => $id2,
1464 'type' => 'fontStyle',
1465 'prop' => 'font-style',
1466 'selector' => $selector
1467 );
1468 if ($state === 'h' || $state === 'hover') {
1469 $res['ishover'] = true;
1470 }
1471
1472 return $res;
1473 }
1474
1475 protected static function get_color($selector = '', $id = '', $label = null, $prop = 'color', $state = '') {//@deprecated has been moved to js
1476 if ($state !== '') {
1477 $id .= '_' . $state;
1478 }
1479 if ($prop === null) {
1480 $prop = 'color';
1481 }
1482 $color = array(
1483 'id' => $id,
1484 'type' => 'color',
1485 'prop' => $prop,
1486 'selector' => $selector
1487 );
1488 if ($label !== null) {
1489 $color['label'] = $label;
1490 }
1491 if ($state === 'h' || $state === 'hover') {
1492 $color['ishover'] = true;
1493 }
1494 return $color;
1495 }
1496
1497 protected static function get_image($selector = '', $id = 'background_image', $colorId = 'background_color', $repeatId = 'background_repeat', $posId = 'background_position', $state = '') {//@deprecated has been moved to js
1498 if ($state !== '') {
1499 $id .= '_' . $state;
1500 if ($colorId !== '') {
1501 $colorId .= '_' . $state;
1502 }
1503 if ($repeatId !== '') {
1504 $repeatId .= '_' . $state;
1505 }
1506 if ($posId !== '') {
1507 $posId .= '_' . $state;
1508 }
1509 }
1510 $res = array(
1511 'id' => $id,
1512 'type' => 'imageGradient',
1513 'prop' => 'background-image',
1514 'selector' => $selector,
1515 'origId' => $id,
1516 'colorId' => $colorId,
1517 'repeatId' => $repeatId,
1518 'posId' => $posId
1519 );
1520 if ($state === 'h' || $state === 'hover') {
1521 $res['ishover'] = true;
1522 }
1523 return $res;
1524 }
1525
1526 // CSS Filters
1527 protected static function get_blend($selector = '', $id = 'bl_m', $state = '', $filters_id = 'css_f') {//@deprecated has been moved to js
1528 if ($state !== '') {
1529 $id .= '_' . $state;
1530 $filters_id .= '_' . $state;
1531 }
1532 $res = array(
1533 'id' => $filters_id,
1534 'mid' => $id,
1535 'type' => 'filters',
1536 'prop' => 'filter',
1537 'selector' => $selector
1538 );
1539 if ($state === 'h' || $state === 'hover') {
1540 $res['ishover'] = true;
1541 }
1542 return $res;
1543 }
1544
1545 protected static function get_repeat($selector = '', $id = 'background_repeat', $state = '') {//@deprecated has been moved to js
1546 if ($state !== '') {
1547 $id .= '_' . $state;
1548 }
1549 $res = array(
1550 'id' => $id,
1551 'type' => 'select',
1552 'repeat' => true,
1553 'prop' => 'background-mode',
1554 'selector' => $selector,
1555 'wrap_class' => 'tb_group_element_image tb_image_options'
1556 );
1557 if ($state === 'h' || $state === 'hover') {
1558 $res['ishover'] = true;
1559 }
1560 return $res;
1561 }
1562
1563 protected static function get_position($selector = '', $id = 'background_position', $state = '') {//@deprecated has been moved to js
1564 if ($state !== '') {
1565 $id .= '_' . $state;
1566 }
1567 $res = array(
1568 'id' => $id,
1569 'type' => 'position_box',
1570 'prop' => 'background-position',
1571 'selector' => $selector
1572 );
1573 if ($state === 'h' || $state === 'hover') {
1574 $res['ishover'] = true;
1575 }
1576 return $res;
1577 }
1578
1579 protected static function get_padding($selector = '', $id = 'padding', $state = '') {//@deprecated has been moved to js
1580 if ($id === '') {
1581 $id = 'padding';
1582 }
1583 if ($state !== '') {
1584 $id .= '_' . $state;
1585 }
1586 $res = array(
1587 'id' => $id,
1588 'type' => 'padding',
1589 'prop' => 'padding',
1590 'selector' => $selector
1591 );
1592 if ($state === 'h' || $state === 'hover') {
1593 $res['ishover'] = true;
1594 }
1595 return $res;
1596 }
1597
1598 protected static function get_margin($selector = '', $id = 'margin', $state = '') {//@deprecated has been moved to js
1599 if ($id === '') {
1600 $id = 'margin';
1601 }
1602 if ($state !== '') {
1603 $id .= '_' . $state;
1604 }
1605 $res = array(
1606 'id' => $id,
1607 'type' => 'margin',
1608 'prop' => 'margin',
1609 'selector' => $selector
1610 );
1611 if ($state === 'h' || $state === 'hover') {
1612 $res['ishover'] = true;
1613 }
1614 return $res;
1615 }
1616
1617 protected static function get_gap($selector = '', $id = 'gap', $prop = 'gap', $state = '', $percent = false, $label = '') {//@deprecated has been moved to js
1618 if ($id === '') {
1619 $id = 'gap';
1620 }
1621 if ($state !== '') {
1622 $id .= '_' . $state;
1623 }
1624 $units = array(
1625 'px' => array(
1626 'max' => 1000
1627 ),
1628 'em' => array(
1629 'max' => 50
1630 )
1631 );
1632 if ($percent !== false && $percent !== '') {
1633 $units['%'] = $percent === true ? '' : $percent;
1634 }
1635 $res = array(
1636 'id' => $id,
1637 'type' => 'range',
1638 'label' => $label === '' ? ($prop === 'column-gap' ? 'ng' : ($prop === 'row-gap' ? 'rg' : 'gap')) : $label,
1639 'prop' => $prop,
1640 'selector' => $selector,
1641 'grid_gap' => 1,
1642 'units' => $units
1643 );
1644 if ($state === 'h' || $state === 'hover') {
1645 $res['ishover'] = true;
1646 }
1647 return $res;
1648 }
1649
1650 protected static function get_column_gap($selector = '', $id = 'cgap', $state = '', $percent = false, $label = '') {//@deprecated has been moved to js
1651 if ($id === '') {
1652 $id = 'cgap';
1653 }
1654 return self::get_gap($selector, $id, 'column-gap', $state, $percent, $label);
1655 }
1656
1657 protected static function get_row_gap($selector = '', $id = 'rgap', $state = '', $percent = false, $label = '') {//@deprecated has been moved to js
1658 if ($id === '') {
1659 $id = 'rgap';
1660 }
1661 return self::get_gap($selector, $id, 'row-gap', $state, $percent, $label);
1662 }
1663
1664 protected static function get_margin_top_bottom_opposity($selector = '', $topId = 'margin-top', $bottomId = 'margin-bottom', $state = '') {//@deprecated has been moved to js
1665 if ($state !== '') {
1666 $topId .= '_' . $state;
1667 $bottomId .= '_' . $state;
1668 }
1669 $res = array(
1670 'topId' => $topId,
1671 'bottomId' => $bottomId,
1672 'type' => 'margin_opposity',
1673 'prop' => '',
1674 'selector' => $selector
1675 );
1676 if ($state === 'h' || $state === 'hover') {
1677 $res['ishover'] = true;
1678 }
1679 return $res;
1680 }
1681
1682 protected static function get_border($selector = '', $id = 'border', $state = '') {//@deprecated has been moved to js
1683 if ($state !== '') {
1684 $id .= '_' . $state;
1685 }
1686 $res = array(
1687 'id' => $id,
1688 'type' => 'border',
1689 'prop' => 'border',
1690 'selector' => $selector
1691 );
1692 if ($state === 'h' || $state === 'hover') {
1693 $res['ishover'] = true;
1694 }
1695 return $res;
1696 }
1697
1698 protected static function get_outline($selector = '', $id = 'o', $state = '') {//@deprecated has been moved to js
1699 if ($state !== '') {
1700 $id .= '_' . $state;
1701 }
1702 $res = array(
1703 'id' => $id,
1704 'type' => 'outline',
1705 'prop' => 'outline',
1706 'selector' => $selector
1707 );
1708 if ($state === 'h' || $state === 'hover') {
1709 $res['ishover'] = true;
1710 }
1711 return $res;
1712 }
1713
1714 protected static function get_aspect_ratio($selector = '', $id = 'asp', $state = '') {//@deprecated has been moved to js
1715 if ($state !== '') {
1716 $id .= '_' . $state;
1717 }
1718
1719 $res = array(
1720 'id' => $id,
1721 'type' => 'aspectRatio',
1722 'prop' => 'aspect-ratio',
1723 'selector' => $selector,
1724 );
1725 if ($state === 'h' || $state === 'hover') {
1726 $res['ishover'] = true;
1727 }
1728 return $res;
1729 }
1730
1731 protected static function get_multi_columns_count($selector = '', $id = 'column', $state = '') {//@deprecated has been moved to js
1732 if ($state !== '') {
1733 $id .= '_' . $state;
1734 }
1735 $res = array(
1736 'id' => $id . '_count',
1737 'type' => 'multiColumns',
1738 'prop' => 'column-count',
1739 'selector' => $selector
1740 );
1741 if ($state === 'h' || $state === 'hover') {
1742 $res['ishover'] = true;
1743 }
1744 return $res;
1745 }
1746
1747 protected static function get_color_type($selector = '', $state = '', $id = '', $solid_id = '', $gradient_id = '') {//@deprecated has been moved to js
1748 if ($state !== '') {
1749 if ($id === '') {
1750 $id = 'f_c_t';
1751 }
1752 if ($solid_id === '') {
1753 $solid_id = 'f_c';
1754 }
1755 if ($gradient_id === '') {
1756 $gradient_id = 'f_g_c';
1757 }
1758 $id .= '_' . $state;
1759 $solid_id .= '_' . $state;
1760 $gradient_id .= '_' . $state;
1761 } else {
1762 if ($id === '') {
1763 $id = 'font_color_type';
1764 }
1765 if ($solid_id === '') {
1766 $solid_id = 'font_color';
1767 }
1768 if ($gradient_id === '') {
1769 $gradient_id = 'font_gradient_color';
1770 }
1771 }
1772
1773 $res = array(
1774 'id' => $id,
1775 'type' => 'fontColor',
1776 'selector' => $selector,
1777 'prop' => 'radio',
1778 's' => $solid_id,
1779 'g' => $gradient_id
1780 );
1781 if ($state === 'h' || $state === 'hover') {
1782 $res['ishover'] = true;
1783 }
1784 return $res;
1785 }
1786
1787 // Get Rounded Corners
1788 protected static function get_border_radius($selector = '', $id = 'b_ra', $state = '') {//@deprecated has been moved to js
1789 if ($state !== '') {
1790 $id .= '_' . $state;
1791 }
1792 $res = array(
1793 'id' => $id,
1794 'type' => 'border_radius',
1795 'prop' => 'border-radius',
1796 'selector' => $selector
1797 );
1798 if ($state === 'h' || $state === 'hover') {
1799 $res['ishover'] = true;
1800 }
1801 return $res;
1802 }
1803
1804 // Get Box Shadow
1805 protected static function get_box_shadow($selector = '', $id = 'b_sh', $state = '') {//@deprecated has been moved to js
1806 if ($state !== '') {
1807 $id .= '_' . $state;
1808 }
1809 $res = array(
1810 'id' => $id,
1811 'type' => 'box_shadow',
1812 'prop' => 'box-shadow',
1813 'selector' => $selector
1814 );
1815 if ($state === 'h' || $state === 'hover') {
1816 $res['ishover'] = true;
1817 }
1818 return $res;
1819 }
1820
1821 // Get Text Shadow
1822 protected static function get_text_shadow($selector = '', $id = 'text-shadow', $state = '') {//@deprecated has been moved to js
1823 if ($state !== '') {
1824 $id .= '_' . $state;
1825 }
1826 $res = array(
1827 'id' => $id,
1828 'type' => 'text_shadow',
1829 'prop' => 'text-shadow',
1830 'selector' => $selector
1831 );
1832 if ($state === 'h' || $state === 'hover') {
1833 $res['ishover'] = true;
1834 }
1835 return $res;
1836 }
1837
1838 // Get z-index
1839 protected static function get_zindex($selector = '', $id = 'zi') {//@deprecated has been moved to js
1840 return array(
1841 'id' => $id,
1842 'selector' => $selector,
1843 'prop' => 'z-index',
1844 'type' => 'zIndex'
1845 );
1846 }
1847
1848 protected static function get_width($selector = '', $id = 'width', $state = '') {//@deprecated has been moved to js
1849 if ($state !== '') {
1850 $id .= '_' . $state;
1851 }
1852
1853 $res = array(
1854 'id' => $id,
1855 'type' => 'width',
1856 'prop' => 'width',
1857 'selector' => $selector,
1858 );
1859 if ($state === 'h' || $state === 'hover') {
1860 $res['ishover'] = true;
1861 }
1862 return $res;
1863 }
1864
1865 // Get Height Options plus Auto Height
1866 protected static function get_height($selector = '', $id = 'ht', $state = '', $minH = '', $maxH = '') {//@deprecated has been moved to js
1867 if ($state !== '') {
1868 $id .= '_' . $state;
1869 }
1870
1871 $res = array(
1872 'id' => $id,
1873 'type' => 'height',
1874 'prop' => 'height',
1875 'selector' => $selector
1876 );
1877 if ($minH !== '') {
1878 $res['minid'] = $minH;
1879 }
1880 if ($maxH !== '') {
1881 $res['maxid'] = $maxH;
1882 }
1883 if ($state === 'h' || $state === 'hover') {
1884 $res['ishover'] = true;
1885 }
1886 return $res;
1887 }
1888
1889 // Get CSS Position
1890 protected static function get_css_position($selector = '', $id = 'po', $state = '') {//@deprecated has been moved to js
1891 if ($state !== '') {
1892 $id .= '_' . $state;
1893 }
1894 $res = array(
1895 'id' => $id,
1896 'type' => 'position',
1897 'prop' => 'position',
1898 'selector' => $selector
1899 );
1900 if ($state === 'h' || $state === 'hover') {
1901 $res['ishover'] = true;
1902 }
1903 return $res;
1904 }
1905
1906 // CSS Display
1907 protected static function get_display($selector = '', $id = 'disp') {//@deprecated has been moved to js
1908 $va_id = $id . '_va';
1909 $res = array();
1910 $res[] = array(
1911 'id' => $id,
1912 'label' => 'disp',
1913 'type' => 'select',
1914 'prop' => 'display',
1915 'selector' => $selector,
1916 'binding' => array(
1917 'empty' => array('hide' => $va_id),
1918 'block' => array('hide' => $va_id),
1919 'none' => array('hide' => $va_id),
1920 'inline-block' => array('show' => $va_id)
1921 ),
1922 'display' => true
1923 );
1924 $res[] = array(
1925 'id' => $va_id,
1926 'label' => 'valign',
1927 'type' => 'select',
1928 'prop' => 'vertical-align',
1929 'selector' => $selector,
1930 'origID' => $id,
1931 'va_display' => true
1932 );
1933 return $res;
1934 }
1935
1936 // Get transform
1937 protected static function get_transform($selector = '', $id = 'tr', $state = '') {//@deprecated has been moved to js
1938 if ($state !== '') {
1939 $id .= '-' . $state;
1940 }
1941 $res = array(
1942 'id' => $id,
1943 'type' => 'transform',
1944 'prop' => 'transform',
1945 'selector' => $selector
1946 );
1947 if ($state === 'h' || $state === 'hover') {
1948 $res['ishover'] = true;
1949 }
1950 return $res;
1951 }
1952
1953
1954 protected static function get_min_width($selector = '', $id = 'mi_w') {//deprecated, included in width field
1955 return array();
1956 }
1957
1958 // Get Min Height Option
1959 protected static function get_min_height($selector = '', $id = 'mi_h') {//deprecated, included in height field
1960 return array();
1961 }
1962
1963 // Get Max Height Option
1964 protected static function get_max_height($selector = '', $id = 'mx_h') {//deprecated, included in height field
1965 return array();
1966 }
1967
1968
1969 protected static function get_margin_top($selector = '', $id = 'margin-top', $state = '') {//deprecated
1970 return array();
1971 }
1972
1973 protected static function get_margin_bottom($selector = '', $id = 'margin-bottom', $state = '') {//deprecated
1974 return array();
1975 }
1976
1977 protected static function get_multi_columns_gap($selector = '', $id = 'column', $state = '') {//backward compatibility
1978 }
1979
1980 protected static function get_multi_columns_divider($selector = '', $id = 'column', $state = '') {//backward compatibility
1981 }
1982
1983 protected static function get_heading_margin_multi_field($selector = '', $h_level = 'h1', $margin_side = 'top', $state = '', $id = '') {//deprecated use get_margin_top_bottom_opposity
1984 $id = $id === '' ? $h_level : $id;
1985 if ($h_level === '') {
1986 $h_level .= ' ';
1987 }
1988 $id = $id . '_margin_' . $margin_side;
1989 if ($state !== '') {
1990 $id .= '_' . $state;
1991 }
1992 if ($selector !== '' && is_array($selector)) {
1993 foreach ($selector as $key => $val) {
1994 $selector[$key] = $val . ' ' . $h_level;
1995 }
1996 } else {
1997 $selector .= ' ' . $h_level;
1998 }
1999 $res = array(
2000 'label' => ('top' === $margin_side ? 'm' : ''),
2001 'id' => $id,
2002 'type' => 'range',
2003 'prop' => 'margin-' . $margin_side,
2004 'selector' => $selector,
2005 'description' => '<span class="tb_range_after">' . sprintf(__('%s', 'themify'), $margin_side) . '</span>',
2006 'units' => array(
2007 'px' => array(
2008 'min' => -1000,
2009 'max' => 1000
2010 ),
2011 'em' => array(
2012 'min' => -50,
2013 'max' => 50
2014 ),
2015 '%' => ''
2016 )
2017 );
2018 if ($state === 'h' || $state === 'hover') {
2019 $res['ishover'] = true;
2020 }
2021 return $res;
2022 }
2023
2024 protected function module_title_custom_style() {//@deprecated has been moved to js
2025 return array(
2026 // Background
2027 self::get_expand('bg', array(
2028 self::get_tab(array(
2029 'n' => array(
2030 self::get_color('.module .module-title', 'background_color_module_title', 'bg_c', 'background-color')
2031 ),
2032 'h' => array(
2033 self::get_color('.module .module-title', 'bg_c_m_t', 'bg_c', 'background-color', 'h')
2034 )
2035 ))
2036 )),
2037 // Font
2038 self::get_expand('f', array(
2039 self::get_tab(array(
2040 'n' => array(
2041 self::get_font_family('.module .module-title', 'font_family_module_title'),
2042 self::get_color('.module .module-title', 'font_color_module_title'),
2043 self::get_font_size('.module .module-title', 'font_size_module_title'),
2044 self::get_line_height('.module .module-title', 'line_height_module_title'),
2045 self::get_text_align('.module .module-title', 'text_align_module_title'),
2046 self::get_text_shadow('.module .module-title', 't_sh_m_t'),
2047 ),
2048 'h' => array(
2049 self::get_font_family('.module .module-title', 'f_f_m_t', 'h'),
2050 self::get_color('.module .module-title', 'f_c_m_t', null, null, 'h'),
2051 self::get_font_size('.module .module-title', 'f_s_m_t', '', 'h'),
2052 self::get_text_shadow('.module .module-title', 't_sh_m_t', 'h'),
2053 )
2054 ))
2055 ))
2056 );
2057 }
2058
2059 /**
2060 * Returns a list of image/imageGradient fields in module's Styling
2061 */
2062 public static function get_styling_image_fields() : array {
2063 return [];
2064 }
2065
2066 /**
2067 * Return a list of module fields that need translating in WPML
2068 *
2069 * Format:
2070 * [
2071 * 'value' => String,
2072 * 'title' => Optional title displayed in WPML translation screeen
2073 * 'id' => field ID,
2074 * 'type' => 'TEXTAREA', 'VISUAL', 'LINK', or default: 'LINE'
2075 * ]
2076 *
2077 * @note: "link" field is being registered as LINE instead, so they show up in translation editor
2078 */
2079 public static function get_translatable_fields( $module, $classname ) : array {
2080 $fields = [];
2081 foreach ( array_merge( $classname::get_translatable_text_fields( $module ), $classname::get_translatable_link_fields( $module ) ) as $field_id ) {
2082 if ( isset( $module['mod_settings'][ $field_id ] ) ) {
2083 $fields[] = [
2084 'value' => $module['mod_settings'][ $field_id ],
2085 'id' => $field_id
2086 ];
2087 }
2088 }
2089 foreach ( $classname::get_translatable_textarea_fields( $module ) as $field_id ) {
2090 if ( isset( $module['mod_settings'][ $field_id ] ) ) {
2091 $fields[] = [
2092 'value' => $module['mod_settings'][ $field_id ],
2093 'id' => $field_id,
2094 'type' => 'TEXTAREA'
2095 ];
2096 }
2097 }
2098
2099 foreach ( $classname::get_translatable_repeatable_fields( $module ) as $repeater_field_id => $repeater_field_childs ) {
2100 if ( ! empty( $module['mod_settings'][ $repeater_field_id ] ) ) {
2101 foreach ( $module['mod_settings'][ $repeater_field_id ] as $repeater_row_index => &$repeater_row_value ) {
2102 foreach ( $repeater_field_childs as $item_id => $item_type ) {
2103 if ( isset( $repeater_row_value[ $item_id ] ) ) {
2104 $fields[] = [
2105 'value' => $repeater_row_value[ $item_id ],
2106 'id' => $repeater_field_id . '::' . $repeater_row_index . '::' . $item_id,
2107 'type' => $item_type === 'LINK' ? 'LINE' : $item_type
2108 ];
2109 }
2110 }
2111 }
2112 }
2113 }
2114
2115 return $fields;
2116 }
2117
2118 /**
2119 * Translate module data
2120 */
2121 public static function translate_module( $module, $translations ) {
2122 /* convert $translation array for repeatable fields */
2123 $m = Themify_Builder_WPML_Integration::get_module( $module['mod_name'] );
2124 if ( $m ) {
2125 $repeter_fields = $m::get_translatable_repeatable_fields( $module );
2126 if ( ! empty( $repeter_fields ) ) {
2127 foreach ( $repeter_fields as $repeater_field_id => $repeater_field_childs ) {
2128 foreach ( $translations as $translation_key => $translation_value ) {
2129 if ( str_contains( $translation_key, $repeater_field_id . '::' ) ) { // this value is for a repeatable field, need to unpack
2130 list( $_repeater_id, $row_id, $item_id ) = explode( '::', $translation_key );
2131 if ( isset( $module['mod_settings'][ $repeater_field_id ][ $row_id ][ $item_id ] ) ) {
2132 $module['mod_settings'][ $repeater_field_id ][ $row_id ][ $item_id ] = $translation_value;
2133 unset( $translations[ $translation_key ] );
2134 }
2135 }
2136 }
2137 }
2138 }
2139 }
2140
2141 $module['mod_settings'] = array_merge( $module['mod_settings'], $translations );
2142 return $module;
2143 }
2144
2145 public static function get_translatable_text_fields( $module ) {
2146 return [];
2147 }
2148
2149 public static function get_translatable_textarea_fields( $module ) {
2150 return [];
2151 }
2152
2153 public static function get_translatable_link_fields( $module ) {
2154 return [];
2155 }
2156
2157 public static function get_translatable_repeatable_fields( $module ) {
2158 return [];
2159 }
2160 }
2161
2162 if (!function_exists('themify_builder_testimonial_author_name')) :
2163
2164 function themify_builder_testimonial_author_name($post, $show_author) {
2165 $out = '';
2166 if ('yes' === $show_author) {
2167 if ($author = get_post_meta($post->ID, '_testimonial_name', true))
2168 $out = '<span class="dash"></span><cite class="testimonial-name">' . $author . '</cite> <br/>';
2169
2170 if ($position = get_post_meta($post->ID, '_testimonial_position', true))
2171 $out .= '<em class="testimonial-title">' . $position;
2172
2173 if ($link = get_post_meta($post->ID, '_testimonial_link', true)) {
2174 if ($position) {
2175 $out .= ', ';
2176 } else {
2177 $out .= '<em class="testimonial-title">';
2178 }
2179 $out .= '<a href="' . esc_url($link) . '">';
2180 }
2181
2182 if ($company = get_post_meta($post->ID, '_testimonial_company', true))
2183 $out .= $company;
2184 else
2185 $out .= $link;
2186
2187 if ($link)
2188 $out .= '</a>';
2189
2190 $out .= '</em>';
2191 }
2192 return $out;
2193 }
2194
2195 endif;
2196