PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / 3.1.9
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits v3.1.9
3.2.2 3.2.3 3.2.1 3.2.0 3.1.9 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.9 trunk 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.3 1.1.4 1.1.5 All 174 releases
master-addons / inc / classes / helper.php

helper.php in Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits 3.1.9, at inc/classes/helper.php

2,839 lines 87.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace MasterAddons\Inc\Classes;
4
5 if (!defined('ABSPATH')) {
6 exit; // Exit if accessed directly
7 }
8
9 use Elementor\Utils;
10 use Elementor\Icons_Manager;
11 use MasterAddons\Inc\Classes\Pro_Upgrade;
12
13 class Helper {
14
15 public static function upgrade_to_pro( $content = '' ){
16 // Adds a direct checkout link in the free version.
17 if (!self::jltma_premium()) {
18 return apply_filters('master_addons/upgrade_pro', sprintf(
19 '%1$s <a href="%2$s" target="_blank">%3$s</a>',
20 ($content) ? $content : '',
21 ma_el_fs()->checkout_url(),
22 __('Upgrade Now', 'master-addons')
23 ));
24 }
25 }
26
27 // Adds a direct checkout link in the free version.
28 public static function unlock_pro_feature( $content = '' ){
29 $default_message = '<span class="pro-feature"> Upgrade to <a href="https://master-addons.com/pricing" target="_blank">Pro Version</a> to unlock this feature.</span>';
30 $message = !empty($content) ? $content : $default_message;
31 return apply_filters('master_addons/upgrade_pro', $message);
32 }
33
34 /**
35 * Remove spaces from Plugin Slug
36 */
37 public static function jltma_slug_cleanup() {
38 if ( self::jltma_premium() && defined( 'JLTMA_PRO_SLUG' ) ) {
39 return str_replace( '-', '_', strtolower( JLTMA_PRO_SLUG ) );
40 }
41 return str_replace( '-', '_', strtolower( JLTMA_SLUG ) );
42 }
43
44 /**
45 * Function current_datetime() compability for wp version < 5.3
46 *
47 * @return DateTimeImmutable
48 */
49 public static function jltma_current_datetime() {
50 if ( function_exists( 'current_datetime' ) ) {
51 return current_datetime();
52 }
53
54 return new \DateTimeImmutable( 'now', self::jltma_wp_timezone() );
55 }
56
57 /**
58 * Add Pro upgrade notice control to any Elementor widget/extension
59 *
60 * @param object $element The Elementor element (widget, section, etc.)
61 * @param string $control_id Optional custom control ID
62 * @param string $message Optional custom message
63 * @return void
64 */
65 public static function jltma_upgrade_to_popup($element, $control_id = 'jltma_editor_upgrade_notice', $message = ''){
66 if (!self::jltma_premium()) {
67 $element->add_control(
68 $control_id,
69 [
70 'label' => '',
71 'type' => \Elementor\Controls_Manager::RAW_HTML,
72 'raw' => !empty($message) ? $message : self::jltma_pro_notice_html(),
73 ]
74 );
75 }
76 }
77
78 /**
79 * Simple pro upgrade message for Elementor editor controls
80 * Light inline notice: "Click Here to see what options are available in the Pro version"
81 *
82 * @param string $url Optional custom URL
83 * @return string HTML markup
84 */
85 public static function jltma_pro_upgrade_message($url = '') {
86 if (empty($url)) {
87 $url = 'https://master-addons.com/pricing/';
88 }
89 return '<div style="background:#f0f5ff; padding:15px; border-radius:4px; text-align:center; line-height:1.6;">'
90 . '<a href="' . esc_url($url) . '" target="_blank" style="color:#2563eb; font-weight:600; text-decoration:none;">'
91 . esc_html__('Click Here', 'master-addons') . '</a> '
92 . esc_html__('to see what options are available in the', 'master-addons') . ' '
93 . '<a href="' . esc_url($url) . '" target="_blank" style="color:#2563eb; font-weight:600; text-decoration:none;">'
94 . esc_html__('Pro version', 'master-addons') . '</a>'
95 . '</div>';
96 }
97
98 /**
99 * Function jltma_wp_timezone() compability for wp version < 5.3
100 *
101 * @return DateTimeZone
102 */
103 public static function jltma_wp_timezone() {
104 if ( function_exists( 'wp_timezone' ) ) {
105 return wp_timezone();
106 }
107
108 return new \DateTimeZone( self::jltma_wp_timezone_string() );
109 }
110 public static function jltma_load_svg( $icon ) {
111
112 if ( ! file_exists( $icon ) ) {
113 return false;
114 }
115
116 ob_start();
117
118 include $icon;
119
120 $svg = ob_get_clean();
121
122 return $svg;
123 }
124
125 public static function get_plugin_name( $full = false ) {
126 return apply_filters( 'jltma_white_label_plugin_name', __( 'Master Addons', 'master-addons' ), $full );
127 }
128
129 /**
130 * API Endpoint
131 *
132 * @return string
133 */
134 public static function api_endpoint() {
135 $api_endpoint_url = 'https://pixarlabs.com';
136 $api_endpoint = apply_filters( 'jltma_endpoint', $api_endpoint_url );
137
138 return trailingslashit( $api_endpoint );
139 }
140
141 /**
142 * CRM Endpoint
143 *
144 * @return string
145 */
146 public static function crm_endpoint() {
147 $crm_endpoint_url = self::api_endpoint() . 'api/plugin/subscribe';
148 $crm_endpoint = apply_filters( 'jltma_crm_crm_endpoint', $crm_endpoint_url );
149
150 return trailingslashit( $crm_endpoint );
151 }
152
153 /**
154 * Function jltma_wp_timezone_string() compability for wp version < 5.3
155 *
156 * @return string
157 */
158 public static function jltma_wp_timezone_string() {
159 $timezone_string = get_option( 'timezone_string' );
160
161 if ( $timezone_string ) {
162 return $timezone_string;
163 }
164
165 $offset = (float) get_option( 'gmt_offset' );
166 $hours = (int) $offset;
167 $minutes = ( $offset - $hours );
168
169 $sign = ( $offset < 0 ) ? '-' : '+';
170 $abs_hour = abs( $hours );
171 $abs_mins = abs( $minutes * 60 );
172 $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
173
174 return $tz_offset;
175 }
176
177 /**
178 * Get Merged Data
179 *
180 * @param [type] $data .
181 * @param string $start_date .
182 * @param string $end_data .
183 *
184 * @author Jewel Theme <[email protected]>
185 */
186 public static function get_merged_data( $data, $start_date = '', $end_data = '' ) {
187 $_data = shortcode_atts(
188 array(
189 'image_url' => JLTMA_IMAGE_DIR . 'ma-fallback.png',
190 'start_date' => $start_date,
191 'end_date' => $end_data,
192 'counter_time' => '',
193 'is_campaign' => 'false',
194 'button_text' => 'Get Premium',
195 'button_url' => 'https://jeweltheme.com',
196 'btn_color' => '#CC22FF',
197 'notice' => '',
198 'notice_timestamp' => '',
199 'show_for_premium' => 'false',
200 ),
201 $data
202 );
203
204 if ( empty( $_data['image_url'] ) ) {
205 $_data['image_url'] = JLTMA_IMAGE_DIR . 'ma-fallback.png';
206 }
207
208 return $_data;
209 }
210
211
212 /**
213 * wp_kses attributes map
214 *
215 * @param array $attrs .
216 *
217 * @author Jewel Theme <[email protected]>
218 */
219 public static function wp_kses_atts_map( array $attrs ) {
220 return array_fill_keys( array_values( $attrs ), true );
221 }
222
223 /**
224 * Custom method
225 *
226 * @param [type] $content .
227 *
228 * @author Jewel Theme <[email protected]>
229 */
230 public static function wp_kses_custom( $content ) {
231 $allowed_tags = wp_kses_allowed_html( 'post' );
232
233 $custom_tags = array(
234 'select' => self::wp_kses_atts_map( array( 'class', 'id', 'style', 'width', 'height', 'title', 'data', 'name', 'autofocus', 'disabled', 'multiple', 'required', 'size' ) ),
235 'input' => self::wp_kses_atts_map( array( 'class', 'id', 'style', 'width', 'height', 'title', 'data', 'name', 'autofocus', 'disabled', 'required', 'size', 'type', 'checked', 'readonly', 'placeholder', 'value', 'maxlength', 'min', 'max', 'multiple', 'pattern', 'step', 'autocomplete' ) ),
236 'textarea' => self::wp_kses_atts_map( array( 'class', 'id', 'style', 'width', 'height', 'title', 'data', 'name', 'autofocus', 'disabled', 'required', 'rows', 'cols', 'wrap', 'maxlength' ) ),
237 'option' => self::wp_kses_atts_map( array( 'class', 'id', 'label', 'disabled', 'label', 'selected', 'value' ) ),
238 'optgroup' => self::wp_kses_atts_map( array( 'disabled', 'label', 'class', 'id' ) ),
239 'form' => self::wp_kses_atts_map( array( 'class', 'id', 'data', 'style', 'width', 'height', 'accept-charset', 'action', 'autocomplete', 'enctype', 'method', 'name', 'novalidate', 'rel', 'target' ) ),
240 'svg' => self::wp_kses_atts_map( array( 'class', 'xmlns', 'viewbox', 'width', 'height', 'fill', 'aria-hidden', 'aria-labelledby', 'role' ) ),
241 'rect' => self::wp_kses_atts_map( array( 'rx', 'width', 'height', 'fill' ) ),
242 'path' => self::wp_kses_atts_map( array( 'd', 'fill' ) ),
243 'g' => self::wp_kses_atts_map( array( 'fill' ) ),
244 'defs' => self::wp_kses_atts_map( array( 'fill' ) ),
245 'linearGradient' => self::wp_kses_atts_map( array( 'id', 'x1', 'x2', 'y1', 'y2', 'gradientUnits' ) ),
246 'stop' => self::wp_kses_atts_map( array( 'stop-color', 'offset', 'stop-opacity' ) ),
247 'style' => self::wp_kses_atts_map( array( 'type' ) ),
248 'div' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
249 'ul' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
250 'li' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
251 'label' => self::wp_kses_atts_map( array( 'class', 'for' ) ),
252 'span' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
253 'h1' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
254 'h2' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
255 'h3' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
256 'h4' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
257 'h5' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
258 'h6' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
259 'a' => self::wp_kses_atts_map( array( 'class', 'href', 'target', 'rel' ) ),
260 'p' => self::wp_kses_atts_map( array( 'class', 'id', 'style', 'data' ) ),
261 'table' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
262 'thead' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
263 'tbody' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
264 'tr' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
265 'th' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
266 'td' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
267 'i' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
268 'button' => self::wp_kses_atts_map( array( 'class', 'id' ) ),
269 'nav' => self::wp_kses_atts_map( array( 'class', 'id', 'style' ) ),
270 'time' => self::wp_kses_atts_map( array( 'datetime' ) ),
271 'br' => array(),
272 'strong' => array(),
273 'style' => array(),
274 'img' => self::wp_kses_atts_map( array( 'class', 'src', 'alt', 'height', 'width', 'srcset', 'id', 'loading' ) ),
275 );
276
277 $allowed_tags = array_merge_recursive( $allowed_tags, $custom_tags );
278
279 return wp_kses( stripslashes_deep( $content ), $allowed_tags );
280 }
281
282 /**
283 * Validate HTML tag name to prevent XSS
284 *
285 * Only allows safe HTML tags from a whitelist.
286 * Returns default tag if provided tag is not in whitelist.
287 *
288 * @since 2.0.7.1
289 * @param string $tag The HTML tag to validate
290 * @param string $default Default tag to return if validation fails (default: 'div')
291 * @return string Safe HTML tag name
292 */
293 public static function jltma_validate_html_tag($tag, $default = 'div') {
294 $allowed_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'span', 'p', 'header', 'footer', 'section', 'article', 'aside', 'nav', 'main'];
295 return in_array($tag, $allowed_tags, true) ? $tag : $default;
296 }
297
298 public static function jltma_elementor() {
299 return \Elementor\Plugin::$instance;
300 }
301
302 /**
303 * Check if Woocommerce is installed and active
304 *
305 * @since 1.5.7
306 */
307 public static function is_woocommerce_active() {
308 return in_array(
309 'woocommerce/woocommerce.php',
310 apply_filters( 'active_plugins', get_option( 'active_plugins' ) )
311 );
312 }
313
314 /**
315 * Get WooCommerce product categories
316 *
317 * @since 2.0.0
318 * @return array Array of category ID => name pairs
319 */
320 public static function jltma_get_woo_categories() {
321 $options = [];
322 if ( ! class_exists( 'WooCommerce' ) ) {
323 return $options;
324 }
325 $terms = get_terms([
326 'taxonomy' => 'product_cat',
327 'hide_empty' => false,
328 ]);
329 if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
330 foreach ( $terms as $term ) {
331 $options[ $term->term_id ] = $term->name;
332 }
333 }
334 return $options;
335 }
336
337 /**
338 * Get WooCommerce product tags
339 *
340 * @since 2.0.0
341 * @return array Array of tag ID => name pairs
342 */
343 public static function jltma_get_woo_tags() {
344 $options = [];
345 if ( ! class_exists( 'WooCommerce' ) ) {
346 return $options;
347 }
348 $terms = get_terms([
349 'taxonomy' => 'product_tag',
350 'hide_empty' => false,
351 ]);
352 if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
353 foreach ( $terms as $term ) {
354 $options[ $term->term_id ] = $term->name;
355 }
356 }
357 return $options;
358 }
359
360 /**
361 * Get WooCommerce products
362 *
363 * @since 2.0.0
364 * @return array Array of product ID => title pairs
365 */
366 public static function jltma_get_woo_products() {
367 $options = [];
368 if ( ! class_exists( 'WooCommerce' ) ) {
369 return $options;
370 }
371 $products = get_posts([
372 'post_type' => 'product',
373 'posts_per_page' => -1,
374 'post_status' => 'publish',
375 ]);
376 if ( ! empty( $products ) ) {
377 foreach ( $products as $product ) {
378 $options[ $product->ID ] = $product->post_title;
379 }
380 }
381 return $options;
382 }
383
384 /**
385 * Get WordPress user roles
386 *
387 * @since 2.0.0
388 * @return array Array of role slug => name pairs
389 */
390 public static function jltma_get_user_roles() {
391 global $wp_roles;
392 $options = [];
393 if ( ! isset( $wp_roles ) ) {
394 $wp_roles = new \WP_Roles();
395 }
396 $roles = $wp_roles->get_names();
397 foreach ( $roles as $role_slug => $role_name ) {
398 $options[ $role_slug ] = $role_name;
399 }
400 return $options;
401 }
402
403 /**
404 * Get data if isset.
405 * Retrieves data with selected key if isset.
406 *
407 * @param array|object $data Data to check.
408 * @param string $key Data key to look for.
409 * @param string $else Default value if key is not found.
410 *
411 * @return mixed Data with selected key, default value otherwise.
412 */
413 public static function get_if_isset( $data, $key, $else = '' ) {
414 if ( 'object' === gettype( $data ) ) {
415 return isset( $data->{$key} ) ? $data->{$key} : $else;
416 }
417
418 return isset( $data[ $key ] ) ? $data[ $key ] : $else;
419 }
420
421 /**
422 * Get data if not empty.
423 * Retrieves data with selected key if not empty.
424 *
425 * @param array $data Array of data.
426 * @param string $key Data key to look for.
427 * @param string $else Default value if key is empty.
428 *
429 * @return mixed Data with selected key, default value otherwise.
430 */
431 public static function get_if_not_empty( $data, $key, $else = '' ) {
432 return ( ! empty( $data[ $key ] ) ) ? $data[ $key ] : $else;
433 }
434
435
436 /**
437 * Check if value in array or equal.
438 *
439 * If `$haystack` is array - checks if `$needle` is in
440 * `$haystack` array, or if they are equal otherwise.
441 *
442 * @param string $needle Test value.
443 * @param mixed $haystack Array or value to check.
444 * @return bool True if `$needle` is in array or equal to
445 * `$haystack`, false otherwise.
446 */
447 public static function in_array_or_equal( $needle, $haystack ) {
448 if ( is_array( $haystack ) ) {
449 return in_array( $needle, $haystack, true );
450 }
451
452 return $needle === $haystack;
453 }
454
455 public static function generate_html_tag( $name, $attributes = array(), $content = false ) {
456 if ( is_array( $attributes ) ) {
457 $attributes_array = array();
458
459 foreach ( $attributes as $key => $value ) {
460 $attributes_array[] = sprintf( "{$key}=\"%s\"", esc_attr( $value ) );
461 }
462
463 $attributes = sprintf( ' %s', implode( ' ', $attributes_array ) );
464 } else {
465 $attributes = " {$attributes}";
466 }
467
468 $tag = "<{$name}{$attributes}>";
469
470 if ( $content ) {
471 $tag .= "{$content}</{$name}>";
472 }
473
474 return $tag;
475 }
476
477 /**
478 * Get class name.
479 * Converts string to valid class name.
480 *
481 * @param string $name The name string.
482 * @return array The class name.
483 */
484 public static function generate_class_name( $name ) {
485 return str_replace( '-', '_', ucwords( $name, '-' ) );
486 }
487
488
489 /**
490 * Unset key by value.
491 * Unset array items by value.
492 *
493 * @param string $needle The searchable value.
494 * @param array $haystack The array to search.
495 *
496 * @return array The filtered array.
497 */
498 public static function unset_items_by_value( $needle, $haystack ) {
499 foreach ( array_keys( $haystack, $needle, true ) as $key ) {
500 unset( $haystack[ $key ] );
501 }
502
503 return $haystack;
504 }
505
506 /**
507 * Check if request is ajax.
508 *
509 * Whether the current request is a WordPress ajax request.
510 *
511 * @since 1.0.0
512 *
513 * @return bool True if it's a WordPress ajax request, false otherwise.
514 */
515 public static function is_ajax() {
516 if ( function_exists( 'wp_doing_ajax' ) ) {
517 return wp_doing_ajax();
518 }
519
520 return defined( 'DOING_AJAX' ) && DOING_AJAX;
521 }
522
523 /**
524 * Get breakpoints.
525 *
526 * Retrieve the responsive breakpoints.
527 *
528 * @return array Responsive breakpoints.
529 */
530 public static function get_breakpoints() {
531 return self::jltma_elementor()->breakpoints->get_breakpoints();
532 }
533
534 /**
535 * Check if request is preview.
536 *
537 * Whether the current request is elementor preview mode or
538 * WordPress preview.
539 *
540 * @param int $post_id Post ID.
541 *
542 * @return bool True if it's a preview request, false otherwise.
543 */
544 public static function is_preview( $post_id = 0 ) {
545 return self::is_preview_mode( $post_id ) || is_preview();
546 }
547
548 /**
549 * Check if request is preview mode.
550 *
551 * Whether the current request is elementor preview mode.
552 *
553 * @return bool True if it's an elementor preview mode, false otherwise.
554 */
555 public static function is_preview_mode( $post_id = 0 ) {
556 return self::jltma_elementor()->preview->is_preview_mode( $post_id );
557 }
558
559 public static function jltma_is_edit_mode( $post_id = 0 ) {
560 if ( self::jltma_elementor()->preview->is_preview_mode() || self::jltma_elementor()->editor->is_edit_mode( $post_id ) ) {
561 return true;
562 }
563 return false;
564 }
565
566
567 /**
568 * Retrive the list of Contact Form 7 Forms [ if plugin activated ]
569 */
570 public static function maad_el_retrive_cf7() {
571 if ( function_exists( 'wpcf7' ) ) {
572 $wpcf7_form_list = get_posts(
573 array(
574 'post_type' => 'wpcf7_contact_form',
575 'showposts' => 999,
576 )
577 );
578 $options = array();
579 $options[0] = esc_html__( 'Select a Form', 'master-addons' );
580 if ( ! empty( $wpcf7_form_list ) && ! is_wp_error( $wpcf7_form_list ) ) {
581 foreach ( $wpcf7_form_list as $post ) {
582 $options[ $post->ID ] = $post->post_title;
583 }
584 } else {
585 $options[0] = esc_html__( 'Create a Form First', 'master-addons' );
586 }
587 return $options;
588 }
589 }
590
591 public static function get_page_template_options( $type = '' ) {
592
593 $page_templates = self::jltma_get_page_templates( $type );
594
595 $options[-1] = __( 'Select', 'master-addons' );
596
597 if ( count( $page_templates ) ) {
598 foreach ( $page_templates as $id => $name ) {
599 $options[ $id ] = $name;
600 }
601 } else {
602 $options['no_template'] = __( 'No saved templates found!', 'master-addons' );
603 }
604
605 return $options;
606 }
607
608
609 public static function jltma_get_page_templates( $type = '' ) {
610 $args = array(
611 'post_type' => 'elementor_library',
612 'posts_per_page' => -1,
613 );
614
615 if ( $type ) {
616 $args['tax_query'] = array(
617 array(
618 'taxonomy' => 'elementor_library_type',
619 'field' => 'slug',
620 'terms' => $type,
621 ),
622 );
623 }
624
625 $page_templates = get_posts( $args );
626
627 $options = array();
628
629 if ( ! empty( $page_templates ) && ! is_wp_error( $page_templates ) ) {
630 foreach ( $page_templates as $post ) {
631 $options[ $post->ID ] = $post->post_title;
632 }
633 }
634 return $options;
635 }
636
637
638 // Get all forms of Ninja Forms plugin
639 public static function jltma_el_get_ninja_forms() {
640 if ( class_exists( 'Ninja_Forms' ) ) {
641 $options = array();
642
643 $contact_forms = Ninja_Forms()->form()->get_forms();
644
645 if ( ! empty( $contact_forms ) && ! is_wp_error( $contact_forms ) ) {
646
647 $i = 0;
648
649 foreach ( $contact_forms as $form ) {
650 if ( $i == 0 ) {
651 $options[0] = esc_html__( 'Select a Contact form', 'master-addons' );
652 }
653 $options[ $form->get_id() ] = $form->get_setting( 'title' );
654 ++$i;
655 }
656 }
657 } else {
658 $options = array();
659 }
660
661 return $options;
662 }
663
664
665 // Get all forms of WPForms plugin
666 public static function jltma_el_get_wpforms_forms() {
667 if ( class_exists( 'WPForms' ) ) {
668 $options = array();
669
670 $args = array(
671 'post_type' => 'wpforms',
672 'posts_per_page' => -1,
673 );
674
675 $contact_forms = get_posts( $args );
676
677 if ( ! empty( $contact_forms ) && ! is_wp_error( $contact_forms ) ) {
678
679 $i = 0;
680
681 foreach ( $contact_forms as $post ) {
682 if ( $i == 0 ) {
683 $options[0] = esc_html__( 'Select a Contact form', 'master-addons' );
684 }
685 $options[ $post->ID ] = $post->post_title;
686 ++$i;
687 }
688 }
689 } else {
690 $options = array();
691 }
692
693 return $options;
694 }
695
696
697 // get weForms
698 public static function jltma_el_get_weforms() {
699 $wpuf_form_list = get_posts(
700 array(
701 'post_type' => 'wpuf_contact_form',
702 'showposts' => 999,
703 )
704 );
705
706 $options = array();
707
708 if ( ! empty( $wpuf_form_list ) && ! is_wp_error( $wpuf_form_list ) ) {
709 $options[0] = esc_html__( 'Select weForm', 'master-addons' );
710 foreach ( $wpuf_form_list as $post ) {
711 $options[ $post->ID ] = $post->post_title;
712 }
713 } else {
714 $options[0] = esc_html__( 'Create a Form First', 'master-addons' );
715 }
716
717 return $options;
718 }
719
720 // Get forms of Caldera plugin
721 public static function jltma_el_get_caldera_forms() {
722 if ( class_exists( 'Caldera_Forms' ) ) {
723 $options = array();
724
725 $contact_forms = \Caldera_Forms_Forms::get_forms( true, true );
726
727 if ( ! empty( $contact_forms ) && ! is_wp_error( $contact_forms ) ) {
728
729 $i = 0;
730
731 foreach ( $contact_forms as $form ) {
732 if ( $i == 0 ) {
733 $options[0] = esc_html__( 'Select a Contact form', 'master-addons' );
734 }
735 $options[ $form['ID'] ] = $form['name'];
736 ++$i;
737 }
738 }
739 } else {
740 $options = array();
741 }
742
743 return $options;
744 }
745
746
747 // Get forms of Gravity Forms plugin
748 public static function jltma_el_get_gravity_forms() {
749 if ( class_exists( 'GFCommon' ) ) {
750 $options = array();
751
752 $contact_forms = \RGFormsModel::get_forms( null, 'title' );
753
754 if ( ! empty( $contact_forms ) && ! is_wp_error( $contact_forms ) ) {
755
756 $i = 0;
757
758 foreach ( $contact_forms as $form ) {
759 if ( $i == 0 ) {
760 $options[0] = esc_html__( 'Select a Contact form', 'master-addons' );
761 }
762 $options[ $form->id ] = $form->title;
763 ++$i;
764 }
765 }
766 } else {
767 $options = array();
768 }
769
770 return $options;
771 }
772
773
774 /**
775 * Check if Elementor Pro active.
776 *
777 * Checks whether the Elementor Pro plugin is currently active.
778 *
779 * @return bool True if Elementor Pro is active, false otherwise.
780 */
781 public static function is_elementor_pro() {
782 return class_exists( 'ElementorPro\Plugin' );
783 }
784
785 // Content Alignments
786 public static function jltma_content_alignment() {
787 $content_alignment = array(
788 'left' => array(
789 'title' => __( 'Left', 'master-addons' ),
790 'icon' => 'eicon-text-align-left',
791 ),
792 'center' => array(
793 'title' => __( 'Center', 'master-addons' ),
794 'icon' => 'eicon-text-align-center',
795 ),
796 'right' => array(
797 'title' => __( 'Right', 'master-addons' ),
798 'icon' => 'eicon-text-align-right',
799 ),
800 );
801 return $content_alignment;
802 }
803
804 // Justify Content Alignments
805 public static function jltma_content_alignments() {
806 $content_alignment = array(
807 'left' => array(
808 'title' => __( 'Left', 'master-addons' ),
809 'icon' => 'eicon-text-align-left',
810 ),
811 'center' => array(
812 'title' => __( 'Center', 'master-addons' ),
813 'icon' => 'eicon-text-align-center',
814 ),
815 'right' => array(
816 'title' => __( 'Right', 'master-addons' ),
817 'icon' => 'eicon-text-align-right',
818 ),
819 'justify' => array(
820 'title' => __( 'Justify', 'master-addons' ),
821 'icon' => 'eicon-text-align-justify',
822 ),
823 );
824 return $content_alignment;
825 }
826
827 // Justify Flex Content Alignments
828 public static function jltma_content_flex_alignments() {
829 $content_alignment = array(
830 'flex-start' => array(
831 'title' => __( 'Left', 'master-addons' ),
832 'icon' => 'eicon-text-align-left',
833 ),
834 'center' => array(
835 'title' => __( 'Center', 'master-addons' ),
836 'icon' => 'eicon-text-align-center',
837 ),
838 'flex-end' => array(
839 'title' => __( 'Right', 'master-addons' ),
840 'icon' => 'eicon-text-align-right',
841 ),
842 'space-between' => array(
843 'title' => __( 'Justify', 'master-addons' ),
844 'icon' => 'eicon-text-align-justify',
845 ),
846 );
847 return $content_alignment;
848 }
849
850 // Heading Tags
851 public static function jltma_heading_tags() {
852 $heading_tags = array(
853 'h1' => array(
854 'title' => __( 'H1', 'master-addons' ),
855 'icon' => 'eicon-editor-h1',
856 ),
857 'h2' => array(
858 'title' => __( 'H2', 'master-addons' ),
859 'icon' => 'eicon-editor-h2',
860 ),
861 'h3' => array(
862 'title' => __( 'H3', 'master-addons' ),
863 'icon' => 'eicon-editor-h3',
864 ),
865 'h4' => array(
866 'title' => __( 'H4', 'master-addons' ),
867 'icon' => 'eicon-editor-h4',
868 ),
869 'h5' => array(
870 'title' => __( 'H5', 'master-addons' ),
871 'icon' => 'eicon-editor-h5',
872 ),
873 'h6' => array(
874 'title' => __( 'H6', 'master-addons' ),
875 'icon' => 'eicon-editor-h6',
876 ),
877 );
878
879 return $heading_tags;
880 }
881
882
883 // Escape Heading Tags
884 public static function jltma_escape_tags( $tag, $default = 'span', $extra = array() ) {
885
886 $supports = array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'span', 'p' );
887
888 $supports = array_merge( $supports, $extra );
889
890 if ( ! in_array( $tag, $supports, true ) ) {
891 return $default;
892 }
893
894 return $tag;
895 }
896
897 // Title Tags
898 public static function jltma_title_tags() {
899 $title_tags = array(
900 'h1' => esc_html__( 'H1', 'master-addons' ),
901 'h2' => esc_html__( 'H2', 'master-addons' ),
902 'h3' => esc_html__( 'H3', 'master-addons' ),
903 'h4' => esc_html__( 'H4', 'master-addons' ),
904 'h5' => esc_html__( 'H5', 'master-addons' ),
905 'h6' => esc_html__( 'H6', 'master-addons' ),
906 'div' => esc_html__( 'div', 'master-addons' ),
907 'span' => esc_html__( 'span', 'master-addons' ),
908 'p' => esc_html__( 'p', 'master-addons' ),
909 'button' => esc_html__( 'button', 'master-addons' ),
910 'a' => esc_html__( 'a', 'master-addons' ),
911 );
912
913 return $title_tags;
914 }
915
916
917 // Master Addons Position
918 public static function jltma_el_content_positions() {
919 $position_options = array(
920 '' => esc_html__( 'Default', 'master-addons' ),
921 'top-left' => esc_html__( 'Top Left', 'master-addons' ),
922 'top-center' => esc_html__( 'Top Center', 'master-addons' ),
923 'top-right' => esc_html__( 'Top Right', 'master-addons' ),
924 'center' => esc_html__( 'Center', 'master-addons' ),
925 'center-left' => esc_html__( 'Center Left', 'master-addons' ),
926 'center-right' => esc_html__( 'Center Right', 'master-addons' ),
927 'bottom-left' => esc_html__( 'Bottom Left', 'master-addons' ),
928 'bottom-center' => esc_html__( 'Bottom Center', 'master-addons' ),
929 'bottom-right' => esc_html__( 'Bottom Right', 'master-addons' ),
930 );
931
932 return $position_options;
933 }
934
935
936
937 // Master Addons Transition
938 public static function jltma_el_transition_options() {
939 $transition_options = array(
940 '' => __( 'None', 'master-addons' ),
941 'fade' => __( 'Fade', 'master-addons' ),
942 'scale-up' => __( 'Scale Up', 'master-addons' ),
943 'scale-down' => __( 'Scale Down', 'master-addons' ),
944 'slide-top' => __( 'Slide Top', 'master-addons' ),
945 'slide-bottom' => __( 'Slide Bottom', 'master-addons' ),
946 'slide-left' => __( 'Slide Left', 'master-addons' ),
947 'slide-right' => __( 'Slide Right', 'master-addons' ),
948 'slide-top-small' => __( 'Slide Top Small', 'master-addons' ),
949 'slide-bottom-small' => __( 'Slide Bottom Small', 'master-addons' ),
950 'slide-left-small' => __( 'Slide Left Small', 'master-addons' ),
951 'slide-right-small' => __( 'Slide Right Small', 'master-addons' ),
952 'slide-top-medium' => __( 'Slide Top Medium', 'master-addons' ),
953 'slide-bottom-medium' => __( 'Slide Bottom Medium', 'master-addons' ),
954 'slide-left-medium' => __( 'Slide Left Medium', 'master-addons' ),
955 'slide-right-medium' => __( 'Slide Right Medium', 'master-addons' ),
956 );
957
958 return $transition_options;
959 }
960
961
962 // Master Addons Animations
963 public static function jltma_animation_options() {
964 $transition_options = array(
965 '' => esc_html__( 'None', 'master-addons' ),
966 'jltma-fade-in' => esc_html__( 'Fade In', 'master-addons' ),
967 'jltma-fade-in-down' => esc_html__( 'Fade In Down', 'master-addons' ),
968 'jltma-fade-in-down-1' => esc_html__( 'Fade In Down 1', 'master-addons' ),
969 'jltma-fade-in-down-2' => esc_html__( 'Fade In Down 2', 'master-addons' ),
970 'jltma-fade-in-up' => esc_html__( 'Fade In Up', 'master-addons' ),
971 'jltma-fade-in-up-1' => esc_html__( 'Fade In Up 1', 'master-addons' ),
972 'jltma-fade-in-up-2' => esc_html__( 'Fade In Up 2', 'master-addons' ),
973 'jltma-fade-in-left' => esc_html__( 'Fade In Left', 'master-addons' ),
974 'jltma-fade-in-left-1' => esc_html__( 'Fade In Left 1', 'master-addons' ),
975 'jltma-fade-in-left-2' => esc_html__( 'Fade In Left 2', 'master-addons' ),
976 'jltma-fade-in-right' => esc_html__( 'Fade In Right', 'master-addons' ),
977 'jltma-fade-in-right-1' => esc_html__( 'Fade In Right 1', 'master-addons' ),
978 'jltma-fade-in-right-2' => esc_html__( 'Fade In Right 2', 'master-addons' ),
979
980 // Slide Animation
981 'jltma-slide-from-right' => esc_html__( 'Slide From Right', 'master-addons' ),
982 'jltma-slide-from-left' => esc_html__( 'Slide From Left', 'master-addons' ),
983 'jltma-slide-from-top' => esc_html__( 'Slide From Top', 'master-addons' ),
984 'jltma-slide-from-bot' => esc_html__( 'Slide From Bottom', 'master-addons' ),
985
986 // Mask Animation
987 'jltma-mask-from-top' => esc_html__( 'Mask From Top', 'master-addons' ),
988 'jltma-mask-from-bot' => esc_html__( 'Mask From Bottom', 'master-addons' ),
989 'jltma-mask-from-left' => esc_html__( 'Mask From Left', 'master-addons' ),
990 'jltma-mask-from-right' => esc_html__( 'Mask From Right', 'master-addons' ),
991
992 'jltma-rotate-in' => esc_html__( 'Rotate In', 'master-addons' ),
993 'jltma-rotate-in-down-left' => esc_html__( 'Rotate In Down Left', 'master-addons' ),
994 'jltma-rotate-in-down-left-1' => esc_html__( 'Rotate In Down Left 1', 'master-addons' ),
995 'jltma-rotate-in-down-left-2' => esc_html__( 'Rotate In Down Left 2', 'master-addons' ),
996 'jltma-rotate-in-down-right' => esc_html__( 'Rotate In Down Right', 'master-addons' ),
997 'jltma-rotate-in-down-right-1' => esc_html__( 'Rotate In Down Right 1', 'master-addons' ),
998 'jltma-rotate-in-down-right-2' => esc_html__( 'Rotate In Down Right 2', 'master-addons' ),
999 'jltma-rotate-in-up-left' => esc_html__( 'Rotate In Up Left', 'master-addons' ),
1000 'jltma-rotate-in-up-left-1' => esc_html__( 'Rotate In Up Left 1', 'master-addons' ),
1001 'jltma-rotate-in-up-left-2' => esc_html__( 'Rotate In Up Left 2', 'master-addons' ),
1002 'jltma-rotate-in-up-right' => esc_html__( 'Rotate In Up Right', 'master-addons' ),
1003 'jltma-rotate-in-up-right-1' => esc_html__( 'Rotate In Up Right 1', 'master-addons' ),
1004 'jltma-rotate-in-up-right-2' => esc_html__( 'Rotate In Up Right 2', 'master-addons' ),
1005
1006 'jltma-zoom-in' => esc_html__( 'Zoom In', 'master-addons' ),
1007 'jltma-zoom-in-1' => esc_html__( 'Zoom In 1', 'master-addons' ),
1008 'jltma-zoom-in-2' => esc_html__( 'Zoom In 2', 'master-addons' ),
1009 'jltma-zoom-in-3' => esc_html__( 'Zoom In 3', 'master-addons' ),
1010
1011 'jltma-scale-up' => esc_html__( 'Scale Up', 'master-addons' ),
1012 'jltma-scale-up-1' => esc_html__( 'Scale Up 1', 'master-addons' ),
1013 'jltma-scale-up-2' => esc_html__( 'Scale Up 2', 'master-addons' ),
1014
1015 'jltma-scale-down' => esc_html__( 'Scale Down', 'master-addons' ),
1016 'jltma-scale-down-1' => esc_html__( 'Scale Down 1', 'master-addons' ),
1017 'jltma-scale-down-2' => esc_html__( 'Scale Down 2', 'master-addons' ),
1018
1019 'jltma-flip-in-down' => esc_html__( 'Flip In Down', 'master-addons' ),
1020 'jltma-flip-in-down-1' => esc_html__( 'Flip In Down 1', 'master-addons' ),
1021 'jltma-flip-in-down-2' => esc_html__( 'Flip In Down 2', 'master-addons' ),
1022 'jltma-flip-in-up' => esc_html__( 'Flip In Up', 'master-addons' ),
1023 'jltma-flip-in-up-1' => esc_html__( 'Flip In Up 1', 'master-addons' ),
1024 'jltma-flip-in-up-2' => esc_html__( 'Flip In Up 2', 'master-addons' ),
1025 'jltma-flip-in-left' => esc_html__( 'Flip In Left', 'master-addons' ),
1026 'jltma-flip-in-left-1' => esc_html__( 'Flip In Left 1', 'master-addons' ),
1027 'jltma-flip-in-left-2' => esc_html__( 'Flip In Left 2', 'master-addons' ),
1028 'jltma-flip-in-left-3' => esc_html__( 'Flip In Left 3', 'master-addons' ),
1029 'jltma-flip-in-right' => esc_html__( 'Flip In Right', 'master-addons' ),
1030 'jltma-flip-in-right-1' => esc_html__( 'Flip In Right 1', 'master-addons' ),
1031 'jltma-flip-in-right-2' => esc_html__( 'Flip In Right 2', 'master-addons' ),
1032 'jltma-flip-in-right-3' => esc_html__( 'Flip In Right 3', 'master-addons' ),
1033
1034 'jltma-pulse' => esc_html__( 'Pulse In 1', 'master-addons' ),
1035 'jltma-pulse1' => esc_html__( 'Pulse In 2', 'master-addons' ),
1036 'jltma-pulse2' => esc_html__( 'Pulse In 3', 'master-addons' ),
1037 'jltma-pulse3' => esc_html__( 'Pulse In 4', 'master-addons' ),
1038 'jltma-pulse4' => esc_html__( 'Pulse In 5', 'master-addons' ),
1039
1040 'jltma-pulse-out-1' => esc_html__( 'Pulse Out 1', 'master-addons' ),
1041 'jltma-pulse-out-2' => esc_html__( 'Pulse Out 2', 'master-addons' ),
1042 'jltma-pulse-out-3' => esc_html__( 'Pulse Out 3', 'master-addons' ),
1043 'jltma-pulse-out-4' => esc_html__( 'Pulse Out 4', 'master-addons' ),
1044
1045 // Specials
1046 'jltma-shake' => esc_html__( 'Shake', 'master-addons' ),
1047 'jltma-bounce-in' => esc_html__( 'Bounce In', 'master-addons' ),
1048 'jltma-jack-in-box' => esc_html__( 'Jack In the Box', 'master-addons' ),
1049 );
1050
1051 return $transition_options;
1052 }
1053
1054
1055 public static function get_installed_theme() {
1056
1057 $theme = wp_get_theme();
1058
1059 if ( $theme->parent() ) {
1060
1061 $theme_name = $theme->parent()->get( 'Name' );
1062 } else {
1063
1064 $theme_name = $theme->get( 'Name' );
1065 }
1066
1067 $theme_name = sanitize_key( $theme_name );
1068
1069 return $theme_name;
1070 }
1071
1072
1073 public static function jltma_el_get_post_types() {
1074 $post_type_args = array(
1075 'public' => true,
1076 'show_in_nav_menus' => true,
1077 );
1078
1079 $post_types = get_post_types( $post_type_args, 'objects' );
1080 $post_lists = array();
1081 foreach ( $post_types as $post_type ) {
1082 $post_lists[ $post_type->name ] = $post_type->labels->singular_name;
1083 }
1084 return $post_lists;
1085 }
1086
1087
1088 public static function jltma_el_blog_post_type_categories() {
1089 // Core categories first so existing selections keep their familiar labels,
1090 // then every other public taxonomy so custom post types can be filtered too.
1091 $taxonomies = get_taxonomies(
1092 array(
1093 'public' => true,
1094 ),
1095 'objects'
1096 );
1097
1098 unset( $taxonomies['category'], $taxonomies['post_tag'] );
1099
1100 $options = array();
1101
1102 $category_terms = get_terms(
1103 array(
1104 'taxonomy' => 'category',
1105 'hide_empty' => true,
1106 )
1107 );
1108
1109 if ( ! empty( $category_terms ) && ! is_wp_error( $category_terms ) ) {
1110 foreach ( $category_terms as $term ) {
1111 $options[ $term->term_id ] = $term->name;
1112 }
1113 }
1114
1115 foreach ( $taxonomies as $taxonomy ) {
1116 $terms = get_terms(
1117 array(
1118 'taxonomy' => $taxonomy->name,
1119 'hide_empty' => true,
1120 )
1121 );
1122
1123 if ( empty( $terms ) || is_wp_error( $terms ) ) {
1124 continue;
1125 }
1126
1127 foreach ( $terms as $term ) {
1128 /* translators: 1: taxonomy label, 2: term name. */
1129 $options[ $term->term_id ] = sprintf( '%1$s: %2$s', $taxonomy->labels->singular_name, $term->name );
1130 }
1131 }
1132
1133 return $options;
1134 }
1135
1136 /**
1137 * Resolves saved control values (term IDs) into term objects of any taxonomy.
1138 */
1139 public static function jltma_el_blog_get_terms_by_ids( $term_ids ) {
1140
1141 $terms = array();
1142
1143 foreach ( (array) $term_ids as $term_id ) {
1144
1145 $term_id = (int) $term_id;
1146
1147 if ( ! $term_id ) {
1148 continue;
1149 }
1150
1151 $term = get_term( $term_id );
1152
1153 if ( ! $term || is_wp_error( $term ) ) {
1154 continue;
1155 }
1156
1157 $terms[] = $term;
1158 }
1159
1160 return $terms;
1161 }
1162
1163 /**
1164 * CSS class used by the isotope filter tabs. Tabs and posts must agree on it.
1165 */
1166 public static function jltma_el_blog_get_term_filter_class( $term ) {
1167
1168 $class = sanitize_html_class( strtolower( str_replace( ' ', '-', $term->name ) ) );
1169
1170 if ( '' === $class ) {
1171 $class = sanitize_html_class( $term->slug, 'term-' . $term->term_id );
1172 }
1173
1174 // Core categories keep their historical class, other taxonomies are prefixed so
1175 // same named terms of different taxonomies do not filter each other in.
1176 if ( 'category' !== $term->taxonomy ) {
1177 $class = sanitize_html_class( $term->taxonomy ) . '-' . $class;
1178 }
1179
1180 return $class;
1181 }
1182
1183 /**
1184 * Builds a tax_query from term IDs, grouped per taxonomy, so custom taxonomies work.
1185 *
1186 * The old 'category' / 'tag__in' arguments only ever matched the core taxonomies.
1187 */
1188 public static function jltma_el_blog_build_tax_query( $term_ids ) {
1189
1190 $terms = self::jltma_el_blog_get_terms_by_ids( $term_ids );
1191
1192 if ( empty( $terms ) ) {
1193 return array();
1194 }
1195
1196 $grouped = array();
1197
1198 foreach ( $terms as $term ) {
1199 $grouped[ $term->taxonomy ][] = $term->term_id;
1200 }
1201
1202 $tax_query = array();
1203
1204 foreach ( $grouped as $taxonomy => $ids ) {
1205 $tax_query[] = array(
1206 'taxonomy' => $taxonomy,
1207 'field' => 'term_id',
1208 'terms' => $ids,
1209 );
1210 }
1211
1212 if ( count( $tax_query ) > 1 ) {
1213 $tax_query['relation'] = 'OR';
1214 }
1215
1216 return $tax_query;
1217 }
1218
1219
1220 public static function jltma_el_blog_post_type_tags() {
1221 $tags = get_tags();
1222
1223 $options = array();
1224
1225 if ( ! empty( $tags ) && ! is_wp_error( $tags ) ) {
1226 foreach ( $tags as $tag ) {
1227 $options[ $tag->term_id ] = $tag->name;
1228 }
1229 }
1230
1231 return $options;
1232 }
1233
1234 public static function jltma_el_blog_post_type_users() {
1235 $users = get_users();
1236
1237 $options = array();
1238
1239 if ( ! empty( $users ) && ! is_wp_error( $users ) ) {
1240 foreach ( $users as $user ) {
1241 if ( $user->display_name !== 'wp_update_service' ) {
1242 $options[ $user->ID ] = $user->display_name;
1243 }
1244 }
1245 }
1246
1247 return $options;
1248 }
1249
1250 public static function jltma_el_blog_posts_list() {
1251 $list = get_posts(
1252 array(
1253 'post_type' => 'post',
1254 'posts_per_page' => -1,
1255 )
1256 );
1257
1258 $options = array();
1259
1260 if ( ! empty( $list ) && ! is_wp_error( $list ) ) {
1261 foreach ( $list as $post ) {
1262 $options[ $post->ID ] = $post->post_title;
1263 }
1264 }
1265
1266 return $options;
1267 }
1268
1269
1270 public static function jltma_el_blog_get_post_settings( $settings ) {
1271
1272 // "Current Query" hands the archive being viewed straight to the widget, so a
1273 // category, tag, date or author archive lists that archive's posts instead of
1274 // the widget's own selection.
1275 if ( 'current' === ( $settings['ma_el_blog_query_source'] ?? 'latest' ) ) {
1276 return self::jltma_el_blog_get_current_query_settings( $settings );
1277 }
1278
1279 $post_args = array();
1280
1281 $authors = $settings['ma_el_blog_users'] ?? [];
1282
1283 if ( ! empty( $authors ) ) {
1284 $post_args['author'] = implode( ',', $authors );
1285 }
1286
1287 $post_args['post_type'] = $settings['ma_el_post_grid_type'] ?? $settings['ma_el_timeline_post_type'] ?? 'post';
1288
1289 // Categories and tags are stored as term IDs of any taxonomy, so they are resolved
1290 // into a tax_query instead of the core-only 'category' and 'tag__in' arguments.
1291 $selected_terms = array_merge(
1292 (array) ( $settings['ma_el_blog_categories'] ?? $settings['ma_el_timeline_categories'] ?? array() ),
1293 (array) ( $settings['ma_el_blog_tags'] ?? $settings['ma_el_timeline_tags'] ?? array() )
1294 );
1295
1296 $tax_query = self::jltma_el_blog_build_tax_query( $selected_terms );
1297
1298 if ( ! empty( $tax_query ) ) {
1299 $post_args['tax_query'] = $tax_query;
1300 }
1301
1302 $post_args['post__not_in'] = $settings['ma_el_blog_posts_exclude'] ?? $settings['ma_el_timeline_posts_exclude'] ?? '';
1303 $post_args['order'] = $settings['ma_el_blog_order'] ?? $settings['ma_el_timeline_order'] ?? 'DESC';
1304 $post_args['orderby'] = $settings['ma_el_blog_order_by'] ?? $settings['ma_el_timeline_order_by'] ?? 'date';
1305 $post_args['posts_per_page'] = $settings['ma_el_blog_posts_per_page'] ?? $settings['ma_el_timeline_posts_per_page'] ?? 10;
1306 $post_args['ignore_sticky_posts'] = $settings['ma_el_post_grid_ignore_sticky'] ?? $settings['ma_el_timeline_ignore_sticky'] ?? 1;
1307
1308 return $post_args;
1309 }
1310
1311 /**
1312 * Query arguments taken from the archive the visitor is looking at.
1313 *
1314 * The widget keeps control of how many posts a page shows; everything that decides
1315 * WHICH posts (taxonomy term, date, author, search) comes from the main query.
1316 *
1317 * @param array $settings Widget settings.
1318 * @return array
1319 */
1320 public static function jltma_el_blog_get_current_query_settings( $settings ) {
1321
1322 global $wp_query;
1323
1324 $query_args = ( $wp_query instanceof \WP_Query ) ? $wp_query->query_vars : array();
1325
1326 // Pagination is re-applied by jltma_el_blog_get_post_data() from the widget's
1327 // own per-page value, and these would fight it or skew the count.
1328 unset(
1329 $query_args['paged'],
1330 $query_args['offset'],
1331 $query_args['nopaging'],
1332 $query_args['fields'],
1333 $query_args['no_found_rows']
1334 );
1335
1336 // get_posts() falls back to 'post' when post_type is empty. That is right for a
1337 // date or author archive, but wrong for a taxonomy attached to a custom post
1338 // type — the term archive would then return nothing.
1339 if ( empty( $query_args['post_type'] ) ) {
1340 $queried = get_queried_object();
1341
1342 if ( $queried instanceof \WP_Term ) {
1343 $taxonomy = get_taxonomy( $queried->taxonomy );
1344
1345 if ( $taxonomy && ! empty( $taxonomy->object_type ) ) {
1346 $query_args['post_type'] = $taxonomy->object_type;
1347 }
1348 }
1349 }
1350
1351 $query_args['posts_per_page'] = $settings['ma_el_blog_posts_per_page'] ?? 10;
1352 $query_args['ignore_sticky_posts'] = $settings['ma_el_post_grid_ignore_sticky'] ?? 1;
1353
1354 return $query_args;
1355 }
1356
1357 public static function jltma_el_blog_get_post_data( $args, $paged, $new_offset ) {
1358 $defaults = array(
1359 'author' => '',
1360 'category' => '',
1361 'orderby' => '',
1362 'posts_per_page' => 1,
1363 'ignore_sticky_posts' => 1,
1364 );
1365
1366 $query_args = wp_parse_args( $args, $defaults );
1367
1368 // WordPress ignores 'paged' whenever 'offset' is set, and mixing the two breaks
1369 // pagination (it can silently skip to older posts). $new_offset already encodes
1370 // the current page, so use exactly one pagination source: offset when there is
1371 // an offset to apply, otherwise paged.
1372 if ( $new_offset > 0 ) {
1373 $query_args['offset'] = $new_offset;
1374 unset( $query_args['paged'] );
1375 } else {
1376 $query_args['paged'] = max( 1, (int) $paged );
1377 unset( $query_args['offset'] );
1378 }
1379
1380 $posts = get_posts( $query_args );
1381 wp_reset_postdata();
1382
1383 return $posts;
1384 }
1385
1386 /**
1387 * Counts every post matching the widget query, ignoring pagination.
1388 *
1389 * get_posts() forces no_found_rows, so the render query cannot report a total.
1390 * This mirrors the same arguments through WP_Query to get a reliable found_posts.
1391 */
1392 public static function jltma_el_blog_get_post_count( $args ) {
1393
1394 $count_args = $args;
1395
1396 unset( $count_args['numberposts'], $count_args['paged'], $count_args['offset'] );
1397
1398 // get_posts() maps 'category' to the 'cat' query var, WP_Query does not.
1399 if ( ! empty( $count_args['category'] ) ) {
1400 $count_args['cat'] = $count_args['category'];
1401 }
1402
1403 unset( $count_args['category'] );
1404
1405 if ( empty( $count_args['post_status'] ) ) {
1406 $count_args['post_status'] = ( 'attachment' === ( $count_args['post_type'] ?? 'post' ) ) ? 'inherit' : 'publish';
1407 }
1408
1409 $count_args['posts_per_page'] = 1;
1410 $count_args['fields'] = 'ids';
1411 $count_args['no_found_rows'] = false;
1412 $count_args['ignore_sticky_posts'] = true;
1413
1414 $count_query = new \WP_Query( $count_args );
1415
1416 return (int) $count_query->found_posts;
1417 }
1418
1419 /**
1420 * Number of pagination pages a blog widget produces for its own query.
1421 */
1422 public static function jltma_el_blog_get_total_pages( $settings ) {
1423
1424 $per_page = (int) ( $settings['ma_el_blog_posts_per_page'] ?? 0 );
1425
1426 if ( $per_page < 1 ) {
1427 return 0;
1428 }
1429
1430 $offset = (int) ( $settings['ma_el_blog_post_offset'] ?? 0 );
1431
1432 $found_posts = self::jltma_el_blog_get_post_count( self::jltma_el_blog_get_post_settings( $settings ) );
1433
1434 $total_posts = ! empty( $settings['ma_el_blog_total_posts_number'] )
1435 ? min( (int) $settings['ma_el_blog_total_posts_number'], $found_posts )
1436 : $found_posts;
1437
1438 return (int) ceil( max( 0, $total_posts - $offset ) / $per_page );
1439 }
1440
1441
1442
1443 public static function jltma_el_get_excerpt_by_id( $post_id, $excerpt_length, $excerpt_type, $exceprt_text, $excerpt_src, $excerpt_icon, $excerpt_icon_align, $read_more_link ) {
1444
1445 $the_post = get_post( $post_id );
1446
1447 $the_excerpt = null;
1448
1449 if ( $the_post ) {
1450 $the_excerpt = ( $excerpt_src ) ? $the_post->post_content : $the_post->post_excerpt;
1451 }
1452
1453 $the_excerpt = wp_strip_all_tags( strip_shortcodes( $the_excerpt ) );
1454
1455 $words = explode( ' ', $the_excerpt, $excerpt_length + 1 );
1456
1457 if ( $excerpt_icon ) {
1458
1459 $migrated = isset( $settings['__fa4_migrated'][ $excerpt_icon ] );
1460 $is_new = empty( $settings['icon'] ) && \Elementor\Icons_Manager::is_migration_allowed();
1461
1462 if ( $is_new || $migrated ) {
1463 $excerpt_icon = \Elementor\Icons_Manager::render_icon(
1464 $settings[ $excerpt_icon ],
1465 array(
1466 'aria-hidden' => 'true',
1467 'class' => 'blog_excerpt_icon',
1468 )
1469 );
1470 } else {
1471 $excerpt_icon = '<i class="' . esc_attr( $settings['icon'] ) . '" aria-hidden="true"></i>';
1472 }
1473 }
1474
1475 if ( count( $words ) > $excerpt_length ) :
1476 array_pop( $words );
1477
1478 if ( 'three_dots' == $excerpt_type ) {
1479 array_push( $words, '…' );
1480 $the_excerpt = '<p>' . implode( ' ', $words ) . '</p>';
1481 } elseif ( 'read_more_link' == $excerpt_type || $read_more_link ) {
1482 // Excerpt text in paragraph
1483 $the_excerpt = '<p>' . implode( ' ', $words ) . '</p>';
1484
1485 // Read More button outside paragraph
1486 if ( $excerpt_icon_align == 'left' ) {
1487 $the_excerpt .= '<a href="' . get_permalink( $post_id ) . '" class="jltma-post-btn"><i class="' . esc_attr( $excerpt_icon ) . '"></i>' . esc_html( $exceprt_text ) . '</a>';
1488 } elseif ( $excerpt_icon_align == 'right' ) {
1489 $the_excerpt .= '<a href="' . get_permalink( $post_id ) . '" class="jltma-post-btn">' . esc_html( $exceprt_text ) . ' <i class="' . esc_attr( $excerpt_icon ) . '"></i></a>';
1490 } else {
1491 $the_excerpt .= '<a href="' . get_permalink( $post_id ) . '" class="jltma-post-btn">' . esc_html( $exceprt_text ) . '</a>';
1492 }
1493 } else {
1494 $the_excerpt = '<p>' . implode( ' ', $words ) . '</p>';
1495 }
1496 endif;
1497
1498 return $the_excerpt;
1499 }
1500
1501
1502 public static function jltma_custom_message( $title, $content ) {
1503 ob_start(); ?>
1504
1505 <div class="elementor-alert elementor-alert-danger" role="alert">
1506 <span class="elementor-alert-title">
1507 <?php /* translators: %s: Title */ printf( esc_html__( '%s !', 'master-addons' ), esc_html( $title ) ); ?>
1508 </span>
1509 <span class="elementor-alert-description">
1510 <?php /* translators: %s: Content */ printf( esc_html__( '%s &nbsp;', 'master-addons' ), esc_html( $content ) ); ?>
1511 </span>
1512 </div>
1513
1514 <?php
1515 $notice = ob_get_clean();
1516 echo wp_kses_post( $notice );
1517 }
1518
1519 public static function jltma_render_alert( $message, $type = 'warning', $admin_only = true ) {
1520 echo self::get_elementor_alert( $message, $type, $admin_only ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- get_elementor_alert returns plugin-constructed safe HTML
1521 }
1522
1523 public static function get_elementor_alert( $message, $type = 'warning', $admin_only = true ) {
1524 if ( $admin_only && ! is_admin() ) {
1525 return;
1526 }
1527
1528 return sprintf( '<div class="elementor-alert elementor-alert-%2$s">%1$s</div>', $message, esc_attr( $type ) );
1529 }
1530
1531 public static function jltma_elementor_plugin_missing_notice( $args ) {
1532
1533 // default params
1534 $defaults = array(
1535 'plugin_name' => '',
1536 'title' => '',
1537 'description' => '',
1538 'echo' => true,
1539 );
1540 $args = wp_parse_args( $args, $defaults );
1541
1542 $title = $args['title'];
1543 if ( empty( $title ) && ! empty( $args['plugin_name'] ) ) {
1544 /* translators: %s: Plugin Name */
1545 $title = sprintf( esc_html__( '"%s" Plugin is Not Activated!', 'master-addons' ), esc_html( $args['plugin_name'] ) );
1546 }
1547
1548 $description = $args['description'];
1549 if ( empty( $description ) ) {
1550 $description = esc_html__( 'In order to use this element, you need to install and activate this plugin.', 'master-addons' );
1551 }
1552
1553 ob_start();
1554 ?>
1555 <div class="elementor-alert elementor-alert-info" role="alert">
1556 <span class="elementor-alert-title">
1557 <?php echo wp_kses_post( $title ); ?>
1558 </span>
1559 <span class="elementor-alert-description">
1560 <?php echo wp_kses_post( $description ); ?>
1561 </span>
1562 </div>
1563
1564 <?php
1565
1566 $notice = ob_get_clean();
1567
1568 if ( wp_validate_boolean( $args['echo'] ) ) {
1569 echo wp_kses_post( $notice );
1570 } else {
1571 return $notice;
1572 }
1573 }
1574
1575
1576
1577 public static function jltma_user_roles() {
1578
1579 global $wp_roles;
1580
1581 $all_roles = $wp_roles->roles;
1582 $user_roles = array();
1583
1584 if ( ! empty( $all_roles ) ) {
1585 foreach ( $all_roles as $key => $value ) {
1586 $user_roles[ $key ] = $all_roles[ $key ]['name'];
1587 }
1588 }
1589
1590 return $user_roles;
1591 }
1592
1593
1594 public static function jltma_warning_messaage( $message, $type = 'warning', $close = true ) { ?>
1595
1596 <div class="ma-el-alert elementor-alert elementor-alert-<?php echo esc_attr( $type ); ?>" role="alert">
1597
1598 <!-- <span class="elementor-alert-title">
1599 <?php //echo __( 'Sorry !!!', 'master-addons' ); ?>
1600 </span> -->
1601
1602 <span class="elementor-alert-description">
1603 <?php echo wp_kses_post( $message ); ?>
1604 </span>
1605
1606 <?php if ( $close ) : ?>
1607 <button type="button" class="elementor-alert-dismiss" data-dismiss="alert" aria-label="Close">X</button>
1608 <?php endif; ?>
1609
1610 </div>
1611
1612 <?php
1613 }
1614
1615 // Check if True/False
1616 public static function jltma_is_true( $var ) {
1617 if ( is_bool( $var ) ) {
1618 return $var;
1619 }
1620
1621 if ( is_string( $var ) ) {
1622 $var = strtolower( $var );
1623 if ( in_array( $var, array( 'yes', 'on', 'true', 'checked' ) ) ) {
1624 return true;
1625 }
1626 }
1627
1628 if ( is_numeric( $var ) ) {
1629 return (bool) $var;
1630 }
1631
1632 return false;
1633 }
1634
1635
1636 // Get all forms of Formidable Forms plugin
1637 public static function jltma_elements_lite_get_formidable_forms() {
1638 if ( class_exists( 'FrmForm' ) ) {
1639 $options = array();
1640
1641 $forms = FrmForm::get_published_forms( array(), 999, 'exclude' );
1642 if ( count( $forms ) ) {
1643 $i = 0;
1644 foreach ( $forms as $form ) {
1645 if ( 0 === $i ) {
1646 $options[0] = esc_html__( 'Select a Contact form', 'master-addons' );
1647 }
1648 $options[ $form->id ] = $form->name;
1649 ++$i;
1650 }
1651 }
1652 } else {
1653 $options = array();
1654 }
1655
1656 return $options;
1657 }
1658
1659
1660 // Get all forms of Fluent Forms plugin
1661 public static function jltma_elements_lite_get_fluent_forms() {
1662 $options = array();
1663
1664 if ( function_exists( 'wpFluentForm' ) ) {
1665
1666 global $wpdb;
1667
1668 $result = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}fluentform_forms" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- direct query required for third-party plugin table; no core API available
1669 if ( $result ) {
1670 $options[0] = esc_html__( 'Select a Contact Form', 'master-addons' );
1671 foreach ( $result as $form ) {
1672 $options[ $form->id ] = $form->title;
1673 }
1674 } else {
1675 $options[0] = esc_html__( 'No forms found!', 'master-addons' );
1676 }
1677 }
1678
1679 return $options;
1680 }
1681
1682
1683 // Tooltip Icon &
1684 public static function jltma_admin_tooltip_info( $info_name, $info_url, $info_icon ) {
1685
1686 if ( ! empty( $info_url ) ) {
1687 ?>
1688 <div class="jltma-tooltip-item tooltip-top">
1689 <i class="<?php echo esc_attr( $info_icon ); ?>"></i>
1690 <div class="jltma-tooltip-text">
1691 <a href="<?php echo esc_url( $info_url ); ?>" class="jltma-tooltip-content" target="_blank">
1692 <?php /* translators: %s: Content */ printf( esc_html__( '%s &nbsp;', 'master-addons' ), esc_html( $info_name ) ); ?>
1693 </a>
1694 </div>
1695 </div>
1696 <?php
1697 }
1698 }
1699
1700 /**
1701 * Get Taxonomies Options
1702 *
1703 * Fetches available taxonomies
1704 *
1705 * @since 1.4.8
1706 */
1707 public static function get_taxonomies_options() {
1708
1709 $options = array();
1710
1711 $taxonomies = get_taxonomies(
1712 array(
1713 'show_in_nav_menus' => true,
1714 ),
1715 'objects'
1716 );
1717
1718 if ( empty( $taxonomies ) ) {
1719 $options[''] = __( 'No taxonomies found', 'master-addons' );
1720 return $options;
1721 }
1722
1723 foreach ( $taxonomies as $taxonomy ) {
1724 $options[ $taxonomy->name ] = $taxonomy->label;
1725 }
1726
1727 return $options;
1728 }
1729
1730
1731 public static function get_page_by_title( $page_title, $post_type = 'page' ) {
1732 $query = new \WP_Query(
1733 array(
1734 'post_type' => $post_type,
1735 'title' => $page_title,
1736 )
1737 );
1738
1739 if ( ! empty( $query->post ) ) {
1740 $page_got_by_title = $query->post;
1741 } else {
1742 $page_got_by_title = null;
1743 }
1744
1745 return $page_got_by_title;
1746 }
1747
1748 public static function jltma_post_types_category_slug() {
1749
1750 $post_types = array(
1751 'category' => esc_html__( 'Post', 'master-addons' ),
1752 );
1753
1754 if ( class_exists( 'WooCommerce' ) ) {
1755 $post_types['product_cat'] = esc_html__( 'Product', 'master-addons' );
1756 }
1757
1758 // other post types taxonomies here
1759
1760 return apply_filters( 'jltma_post_types_category_slug', $post_types );
1761 }
1762
1763
1764 public static function jltma_set_global_authordata() {
1765 global $authordata;
1766 if ( ! isset( $authordata->ID ) ) {
1767 $post = get_post();
1768 $authordata = get_userdata( $post->post_author ); // WPCS: override ok.
1769 }
1770 }
1771
1772
1773 public static function jltma_get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
1774 global $wp_taxonomies;
1775
1776 $field = ( 'names' === $output ) ? 'name' : false;
1777
1778 // Handle 'object_type' separately.
1779 if ( isset( $args['object_type'] ) ) {
1780 $object_type = (array) $args['object_type'];
1781 unset( $args['object_type'] );
1782 }
1783
1784 $taxonomies = wp_filter_object_list( $wp_taxonomies, $args, $operator );
1785
1786 if ( isset( $object_type ) ) {
1787 foreach ( $taxonomies as $tax => $tax_data ) {
1788 if ( ! array_intersect( $object_type, $tax_data->object_type ) ) {
1789 unset( $taxonomies[ $tax ] );
1790 }
1791 }
1792 }
1793
1794 if ( $field ) {
1795 $taxonomies = wp_list_pluck( $taxonomies, $field );
1796 }
1797
1798 return $taxonomies;
1799 }
1800
1801
1802
1803 public static function is_plugin_installed( $plugin_slug, $plugin_file ) {
1804 $installed_plugins = get_plugins();
1805 return isset( $installed_plugins[ $plugin_file ] );
1806 }
1807
1808
1809 // Get Page Title
1810 public static function jltma_get_page_title( $include_context = true ) {
1811 $title = '';
1812
1813 if ( is_singular() ) {
1814 /* translators: %s: Search term. */
1815 $title = get_the_title();
1816
1817 if ( $include_context ) {
1818 $post_type_obj = get_post_type_object( get_post_type() );
1819 $title = sprintf( '%s: %s', $post_type_obj->labels->singular_name, $title );
1820 }
1821 } elseif ( is_search() ) {
1822 /* translators: %s: Search term. */
1823 $title = sprintf( __( 'Search Results for: %s', 'master-addons' ), get_search_query() );
1824
1825 if ( get_query_var( 'paged' ) ) {
1826 /* translators: %s is the page number. */
1827 $title .= sprintf( __( '&nbsp;&ndash; Page %s', 'master-addons' ), get_query_var( 'paged' ) );
1828 }
1829 } elseif ( is_category() ) {
1830 $title = single_cat_title( '', false );
1831
1832 if ( $include_context ) {
1833 /* translators: Category archive title. 1: Category name */
1834 $title = sprintf( __( 'Category: %s', 'master-addons' ), $title );
1835 }
1836 } elseif ( is_tag() ) {
1837 $title = single_tag_title( '', false );
1838 if ( $include_context ) {
1839 /* translators: Tag archive title. 1: Tag name */
1840 $title = sprintf( __( 'Tag: %s', 'master-addons' ), $title );
1841 }
1842 } elseif ( is_author() ) {
1843 $title = '<span class="vcard">' . get_the_author() . '</span>';
1844
1845 if ( $include_context ) {
1846 /* translators: Author archive title. 1: Author name */
1847 $title = sprintf( __( 'Author: %s', 'master-addons' ), $title );
1848 }
1849 } elseif ( is_year() ) {
1850 $title = get_the_date( _x( 'Y', 'yearly archives date format', 'master-addons' ) );
1851
1852 if ( $include_context ) {
1853 /* translators: Yearly archive title. 1: Year */
1854 $title = sprintf( __( 'Year: %s', 'master-addons' ), $title );
1855 }
1856 } elseif ( is_month() ) {
1857 $title = get_the_date( _x( 'F Y', 'monthly archives date format', 'master-addons' ) );
1858
1859 if ( $include_context ) {
1860 /* translators: Monthly archive title. 1: Month name and year */
1861 $title = sprintf( __( 'Month: %s', 'master-addons' ), $title );
1862 }
1863 } elseif ( is_day() ) {
1864 $title = get_the_date( _x( 'F j, Y', 'daily archives date format', 'master-addons' ) );
1865
1866 if ( $include_context ) {
1867 /* translators: Daily archive title. 1: Date */
1868 $title = sprintf( __( 'Day: %s', 'master-addons' ), $title );
1869 }
1870 } elseif ( is_tax( 'post_format' ) ) {
1871 if ( is_tax( 'post_format', 'post-format-aside' ) ) {
1872 $title = _x( 'Asides', 'post format archive title', 'master-addons' );
1873 } elseif ( is_tax( 'post_format', 'post-format-gallery' ) ) {
1874 $title = _x( 'Galleries', 'post format archive title', 'master-addons' );
1875 } elseif ( is_tax( 'post_format', 'post-format-image' ) ) {
1876 $title = _x( 'Images', 'post format archive title', 'master-addons' );
1877 } elseif ( is_tax( 'post_format', 'post-format-video' ) ) {
1878 $title = _x( 'Videos', 'post format archive title', 'master-addons' );
1879 } elseif ( is_tax( 'post_format', 'post-format-quote' ) ) {
1880 $title = _x( 'Quotes', 'post format archive title', 'master-addons' );
1881 } elseif ( is_tax( 'post_format', 'post-format-link' ) ) {
1882 $title = _x( 'Links', 'post format archive title', 'master-addons' );
1883 } elseif ( is_tax( 'post_format', 'post-format-status' ) ) {
1884 $title = _x( 'Statuses', 'post format archive title', 'master-addons' );
1885 } elseif ( is_tax( 'post_format', 'post-format-audio' ) ) {
1886 $title = _x( 'Audio', 'post format archive title', 'master-addons' );
1887 } elseif ( is_tax( 'post_format', 'post-format-chat' ) ) {
1888 $title = _x( 'Chats', 'post format archive title', 'master-addons' );
1889 }
1890 } elseif ( is_post_type_archive() ) {
1891 $title = post_type_archive_title( '', false );
1892
1893 if ( $include_context ) {
1894 /* translators: Post type archive title. 1: Post type name */
1895 $title = sprintf( __( 'Archives: %s', 'master-addons' ), $title );
1896 }
1897 } elseif ( is_tax() ) {
1898 $title = single_term_title( '', false );
1899
1900 if ( $include_context ) {
1901 $tax = get_taxonomy( get_queried_object()->taxonomy );
1902 /* translators: Taxonomy term archive title. 1: Taxonomy singular name, 2: Current taxonomy term */
1903 $title = sprintf( __( '%1$s: %2$s', 'master-addons' ), $tax->labels->singular_name, $title );
1904 }
1905 } elseif ( is_404() ) {
1906 $title = __( 'Page Not Found', 'master-addons' );
1907 } // End if().
1908
1909 $title = apply_filters( 'jltma/core_elements/get_the_archive_title', $title );
1910
1911 return $title;
1912 }
1913
1914
1915
1916 // Archive URL
1917 public static function jltma_get_the_archive_url() {
1918 $url = '';
1919 if ( is_category() || is_tag() || is_tax() ) {
1920 $url = get_term_link( get_queried_object() );
1921 } elseif ( is_author() ) {
1922 $url = get_author_posts_url( get_queried_object_id() );
1923 } elseif ( is_year() ) {
1924 $url = get_year_link( get_query_var( 'year' ) );
1925 } elseif ( is_month() ) {
1926 $url = get_month_link( get_query_var( 'year' ), get_query_var( 'monthnum' ) );
1927 } elseif ( is_day() ) {
1928 $url = get_day_link( get_query_var( 'year' ), get_query_var( 'monthnum' ), get_query_var( 'day' ) );
1929 } elseif ( is_post_type_archive() ) {
1930 $url = get_post_type_archive_link( get_post_type() );
1931 }
1932
1933 return $url;
1934 }
1935
1936 public static function jltma_blend_options() {
1937 $blend_options = array(
1938 'multiply' => esc_html__( 'Multiply', 'master-addons' ),
1939 'screen' => esc_html__( 'Screen', 'master-addons' ),
1940 'overlay' => esc_html__( 'Overlay', 'master-addons' ),
1941 'darken' => esc_html__( 'Darken', 'master-addons' ),
1942 'lighten' => esc_html__( 'Lighten', 'master-addons' ),
1943 'color-dodge' => esc_html__( 'Color-Dodge', 'master-addons' ),
1944 'color-burn' => esc_html__( 'Color-Burn', 'master-addons' ),
1945 'hard-light' => esc_html__( 'Hard-Light', 'master-addons' ),
1946 'soft-light' => esc_html__( 'Soft-Light', 'master-addons' ),
1947 'difference' => esc_html__( 'Difference', 'master-addons' ),
1948 'exclusion' => esc_html__( 'Exclusion', 'master-addons' ),
1949 'hue' => esc_html__( 'Hue', 'master-addons' ),
1950 'saturation' => esc_html__( 'Saturation', 'master-addons' ),
1951 'color' => esc_html__( 'Color', 'master-addons' ),
1952 'luminosity' => esc_html__( 'Luminosity', 'master-addons' ),
1953 );
1954
1955 return $blend_options;
1956 }
1957
1958 public static function jltma_carousel_navigation_position() {
1959 $position_options = array(
1960 'top-left' => esc_html__( 'Top Left', 'master-addons' ),
1961 'top-center' => esc_html__( 'Top Center', 'master-addons' ),
1962 'top-right' => esc_html__( 'Top Right', 'master-addons' ),
1963 'center' => esc_html__( 'Center', 'master-addons' ),
1964 'bottom-left' => esc_html__( 'Bottom Left', 'master-addons' ),
1965 'bottom-center' => esc_html__( 'Bottom Center', 'master-addons' ),
1966 'bottom-right' => esc_html__( 'Bottom Right', 'master-addons' ),
1967 );
1968
1969 return $position_options;
1970 }
1971
1972
1973 public static function jltma_carousel_pagination_position() {
1974 $position_options = array(
1975 'top-left' => esc_html__( 'Top Left', 'master-addons' ),
1976 'top-center' => esc_html__( 'Top Center', 'master-addons' ),
1977 'top-right' => esc_html__( 'Top Right', 'master-addons' ),
1978 'bottom-left' => esc_html__( 'Bottom Left', 'master-addons' ),
1979 'bottom-center' => esc_html__( 'Bottom Center', 'master-addons' ),
1980 'bottom-right' => esc_html__( 'Bottom Right', 'master-addons' ),
1981 );
1982
1983 return $position_options;
1984 }
1985
1986 public static function jltma_get_preloadable_previews() {
1987 $position_options = array(
1988 'no' => esc_html__( 'Blank', 'master-addons' ),
1989 'yes' => esc_html__( 'Blurred placeholder image', 'master-addons' ),
1990 'progress-box' => esc_html__( 'In-progress box animation', 'master-addons' ),
1991 'simple-spinner' => esc_html__( 'Loading spinner (blue)', 'master-addons' ),
1992 'simple-spinner-light' => esc_html__( 'Loading spinner (light)', 'master-addons' ),
1993 'simple-spinner-dark' => esc_html__( 'Loading spinner (dark)', 'master-addons' ),
1994 );
1995 return $position_options;
1996 }
1997
1998 public static function jltma_get_array_value( $array, $key, $default = '' ) {
1999 return isset( $array[ $key ] ) ? $array[ $key ] : $default;
2000 }
2001
2002
2003
2004 public static function render_image( $image_id, $settings, $class = '' ) {
2005 $image_size = $settings;
2006
2007 if ( 'custom' === $image_size ) {
2008 $image_src = \Elementor\Group_Control_Image_Size::get_attachment_image_src( $image_id, $image_size, $settings );
2009 } else {
2010 $image_src = wp_get_attachment_image_src( $image_id, $image_size );
2011 $image_src = $image_src[0];
2012 }
2013
2014 return sprintf( '<img src="%s" class="%s" alt="%s" />', esc_url( $image_src ), esc_attr( $class ), esc_html( get_post_meta( $image_id, '_wp_attachment_image_alt', true ) ) );
2015 }
2016
2017
2018 /**
2019 * Get Elementor Pro Locked Html
2020 *
2021 * Returns the markup to display when a feature requires Elementor Pro
2022 *
2023 * @since 2.1.0
2024 * @return \Elementor\Plugin|$instace
2025 */
2026 public static function jltma_pro_locked_html() {
2027 return '<div class="elementor-nerd-box">
2028 <i class="elementor-nerd-box-icon eicon-hypster"></i>
2029 <div class="elementor-nerd-box-title">' .
2030 __( 'Oups, hang on!', 'master-addons' ) .
2031 '</div>
2032 <div class="elementor-nerd-box-message">' .
2033 __( 'This feature is only available if you have Master Addons Pro.', 'master-addons' ) .
2034 '</div>
2035 <a class="elementor-nerd-box-link elementor-button elementor-button-default elementor-go-pro" href="https://master-addons.com/pricing" target="_blank">' .
2036 __( 'Go Pro', 'master-addons' ) .
2037 '</a>
2038 </div>';
2039 }
2040
2041
2042 public static function jltma_tooltip_options() {
2043 return array(
2044 '' => esc_html__( 'Top (Default)', 'master-addons' ),
2045
2046 'top-start' => esc_html__( 'Top Start', 'master-addons' ),
2047 'top-end' => esc_html__( 'Top End', 'master-addons' ),
2048
2049 'right' => esc_html__( 'Right', 'master-addons' ),
2050 'right-start' => esc_html__( 'Right Start', 'master-addons' ),
2051 'right-end' => esc_html__( 'Right End', 'master-addons' ),
2052
2053 'bottom' => esc_html__( 'Bottom', 'master-addons' ),
2054 'bottom-start' => esc_html__( 'Bottom Start', 'master-addons' ),
2055 'bottom-end' => esc_html__( 'Bottom End', 'master-addons' ),
2056
2057 'left' => esc_html__( 'Left', 'master-addons' ),
2058 'left-start' => esc_html__( 'Left Start', 'master-addons' ),
2059 'left-end' => esc_html__( 'Left End', 'master-addons' ),
2060
2061 'auto' => esc_html__( 'Auto', 'master-addons' ),
2062 'auto-start' => esc_html__( 'Auto Start', 'master-addons' ),
2063 'auto-end' => esc_html__( 'Auto End', 'master-addons' ),
2064 );
2065 }
2066
2067 public static function jltma_tooltip_animations() {
2068 return array(
2069 'none' => esc_html__( 'None', 'master-addons' ),
2070 '' => esc_html__( 'Fade', 'master-addons' ),
2071 'shift-away' => esc_html__( 'Shift-Away', 'master-addons' ),
2072 'shift-toward' => esc_html__( 'Shift-Toward', 'master-addons' ),
2073 'scale' => esc_html__( 'Scale', 'master-addons' ),
2074 'perspective' => esc_html__( 'Perspective', 'master-addons' ),
2075 'fill' => esc_html__( 'Fill Effect', 'master-addons' ),
2076 );
2077 }
2078
2079 public static function jltma_placeholder_images() {
2080 $demo_images =
2081 array(
2082 'id' => 0,
2083 'url' => Utils::get_placeholder_image_src(),
2084 );
2085 return $demo_images;
2086 }
2087
2088 public static function find_widget_elements_by_id( $elements, $id ) {
2089 static $widget = null;
2090
2091 foreach ( $elements as $element ) {
2092 if ( $id === $element['id'] ) {
2093 $widget = $element;
2094
2095 break;
2096 } elseif ( isset( $element['elements'] ) ) {
2097 self::find_widget_elements_by_id( $element['elements'], $id );
2098 }
2099 }
2100
2101 return $widget;
2102 }
2103
2104
2105 public static function get_client_ip_as_key() {
2106 return str_replace( '.', '_', self::get_client_ip() );
2107 }
2108
2109 public static function get_client_ip() {
2110 $ip = self::IP_LOCAL;
2111
2112 $server_ip_keys = array(
2113 'REMOTE_ADDR',
2114 'HTTP_CLIENT_IP',
2115 'HTTP_X_FORWARDED_FOR',
2116 'HTTP_X_FORWARDED',
2117 'HTTP_X_CLUSTER_CLIENT_IP',
2118 'HTTP_FORWARDED_FOR',
2119 'HTTP_FORWARDED',
2120 );
2121
2122 foreach ( $server_ip_keys as $key ) {
2123 if ( isset( $_SERVER[ $key ] ) && filter_var( wp_unslash( $_SERVER[ $key ] ), FILTER_VALIDATE_IP ) ) {
2124 $ip = sanitize_text_field( wp_unslash( $_SERVER[ $key ] ) );
2125
2126 break;
2127 }
2128 }
2129
2130 return apply_filters( 'jltma_elementor/utils/client_ip', $ip );
2131 }
2132
2133
2134 public static function short_number( $number ) {
2135 $abbrevs = array(
2136 12 => 'T',
2137 9 => 'B',
2138 6 => 'M',
2139 3 => 'K',
2140 0 => '',
2141 );
2142
2143 foreach ( $abbrevs as $exponent => $abbrev ) {
2144 if ( abs( $number ) >= pow( 10, $exponent ) ) {
2145 $display = $number / pow( 10, $exponent );
2146 $decimals = ( $exponent >= 3 && round( $display ) < 100 ) ? 1 : 0;
2147 $number = number_format( $display, $decimals ) . $abbrev;
2148 break;
2149 }
2150 }
2151
2152 return $number;
2153 }
2154
2155 public static function array_merge_recursive( $array1, $array2 ) {
2156 $merged = $array1;
2157
2158 foreach ( $array2 as $key => &$value ) {
2159 if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
2160 $merged[ $key ] = self::array_merge_recursive( $merged[ $key ], $value );
2161 } elseif ( is_numeric( $key ) ) {
2162 if ( ! in_array( $value, $merged, true ) ) {
2163 $merged[] = $value;
2164 }
2165 } else {
2166 $merged[ $key ] = $value;
2167 }
2168 }
2169
2170 return $merged;
2171 }
2172
2173 /**
2174 * Get current elementor document id
2175 *
2176 * @return int|false
2177 */
2178 public static function get_document_id() {
2179 $document = self::jltma_elementor()->documents->get_current();
2180
2181 if ( $document ) {
2182 return $document->get_main_id();
2183 }
2184
2185 return $document;
2186 }
2187
2188 public static function get_ob_html( $callback ) {
2189 if ( ! is_callable( $callback ) ) {
2190 return '';
2191 }
2192
2193 ob_start();
2194
2195 call_user_func( $callback );
2196
2197 return ob_get_clean();
2198 }
2199
2200 public static function render_icon( $icon_setting, $attributes = array() ) {
2201 if ( empty( $icon_setting['value'] ) ) {
2202 return;
2203 }
2204
2205 echo '<span class="jltma-wrap-icon">';
2206
2207 Icons_Manager::render_icon( $icon_setting, $attributes );
2208
2209 echo '</span>';
2210 }
2211
2212 /**
2213 * Render Icon
2214 *
2215 * Used to render Icon for \Elementor\Controls_Manager::ICONS
2216 *
2217 * @param array $icon Icon Type, Icon value
2218 * @param array $attributes Icon HTML Attributes
2219 */
2220 public static function get_render_icon( $icon_setting, $attributes = array() ) {
2221 return self::get_ob_html(
2222 function () use ( $icon_setting, $attributes ) {
2223 self::render_icon( $icon_setting, $attributes );
2224 }
2225 );
2226 }
2227
2228
2229 /**
2230 * Prepare css var.
2231 *
2232 * @param string $control_id Control id.
2233 * @param string $value Control selectors value.
2234 *
2235 * @return string Control id that prepared for css vars.
2236 */
2237 public static function prepare_css_var( $control_id, $value = '' ) {
2238 $var_key = '--' . str_replace( '_', '-', $control_id );
2239
2240 if ( empty( $value ) ) {
2241 return $var_key;
2242 }
2243
2244 return $var_key . ': ' . $value . ';';
2245 }
2246
2247 public static function get_available_image_sizes() {
2248 $glob_sizes = wp_get_additional_image_sizes();
2249 $image_sizes = get_intermediate_image_sizes();
2250 $sizes = array();
2251
2252 if ( is_array( $image_sizes ) && $image_sizes ) {
2253 foreach ( $image_sizes as $size ) {
2254 if ( in_array( $size, array( 'thumbnail', 'medium', 'medium_large', 'large' ), true ) ) {
2255 $sizes[ $size ] = array(
2256 'width' => get_option( "{$size}_size_w" ),
2257 'height' => get_option( "{$size}_size_h" ),
2258 'crop' => (bool) get_option( "{$size}_crop" ),
2259 );
2260 } elseif ( isset( $glob_sizes[ $size ] ) ) {
2261 $sizes[ $size ] = array(
2262 'width' => $glob_sizes[ $size ]['width'],
2263 'height' => $glob_sizes[ $size ]['height'],
2264 'crop' => $glob_sizes[ $size ]['crop'],
2265 );
2266 }
2267
2268 if ( 0 === (int) $sizes[ $size ]['width'] || 0 === (int) $sizes[ $size ]['height'] ) {
2269 unset( $sizes[ $size ] );
2270 }
2271 }
2272 }
2273
2274 return $sizes;
2275 }
2276
2277 public static function jltma_animate_class( $addon_animate, $effect, $delay ) {
2278 if ( $addon_animate == 'on' ) :
2279 $animate_class = ' animate-in" data-anim-type="' . $effect . '" data-anim-delay="' . $delay . '"';
2280 else :
2281 $animate_class = '"';
2282 endif;
2283 return $animate_class;
2284 }
2285
2286
2287
2288 public static function jltma_post_type_query( $source, $posts_source, $posts_type, $categories, $categories_post_type, $order, $orderby, $pagination, $pagination_type, $num_posts, $num_posts_page ) {
2289
2290 if ( $orderby == 'views' ) {
2291 $orderby = 'meta_value_num';
2292 $view_order = 'views';
2293 } else {
2294 $view_order = '';
2295 }
2296
2297 if ( $source == 'post_type' ) {
2298 $posts_source = 'all_posts';
2299 }
2300
2301 if ( $posts_source == 'all_posts' ) {
2302
2303 $query = 'post_type=Post&post_status=publish&ignore_sticky_posts=1&orderby=' . $orderby . '&order=' . $order . '';
2304
2305 // CUSTOM POST TYPE
2306 if ( $source == 'post_type' ) {
2307 $query .= '&post_type=' . $posts_type . '';
2308 }
2309
2310 if ( $view_order == 'views' ) {
2311 $query .= '&meta_key=wpb_post_views_count';
2312 }
2313
2314 // CATEGORIES POST TYPE
2315 if ( $categories_post_type != '' && ! empty( $categories_post_type ) && $source == 'post_type' ) {
2316 $taxonomy_names = get_object_taxonomies( $posts_type );
2317 $query .= '&' . $taxonomy_names[0] . '=' . $categories_post_type . '';
2318 }
2319
2320 // CATEGORIES POSTS
2321 if ( $categories != '' && $categories != 'all' && ! empty( $categories ) && $source == 'wp_posts' ) {
2322 $query .= '&category_name=' . $categories . '';
2323 }
2324
2325 if ( $pagination == 'yes' || $pagination == 'load-more' ) {
2326 $query .= '&posts_per_page=' . $num_posts_page . '';
2327 } else {
2328 if ( $num_posts == '' ) {
2329 $num_posts = '-1';
2330 }
2331 $query .= '&posts_per_page=' . $num_posts . '';
2332 }
2333
2334 // PAGINATION
2335 if ( $pagination == 'yes' || $pagination == 'load-more' ) {
2336 if ( get_query_var( 'paged' ) ) {
2337 $paged = get_query_var( 'paged' );
2338 } elseif ( get_query_var( 'page' ) ) {
2339 $paged = get_query_var( 'page' );
2340 } else {
2341 $paged = 1;
2342 }
2343 $query .= '&paged=' . $paged . '';
2344 }
2345 // #PAGINATION
2346
2347 } else { // IF STICKY
2348
2349 if ( $pagination == 'yes' || $pagination == 'load-more' ) {
2350 $num_posts = $num_posts_page;
2351 } else {
2352 if ( $num_posts == '' ) {
2353 $num_posts = '-1';
2354 }
2355 $num_posts = $num_posts;
2356 }
2357
2358 // PAGINATION
2359
2360 if ( get_query_var( 'paged' ) ) {
2361 $paged = get_query_var( 'paged' );
2362 } elseif ( get_query_var( 'page' ) ) {
2363 $paged = get_query_var( 'page' );
2364 } else {
2365 $paged = 1;
2366 }
2367
2368 // #PAGINATION
2369
2370 /* STICKY POST DA FARE ARRAY PER SCRITTURA IN ARRAY */
2371
2372 $sticky = get_option( 'sticky_posts' );
2373 $sticky = array_slice( $sticky, 0, 5 );
2374 if ( $view_order == 'views' ) {
2375 $query = array(
2376 'post_type' => 'post',
2377 'post_status' => 'publish',
2378 'orderby' => $orderby,
2379 'order' => $order,
2380 'category_name' => $categories,
2381 'posts_per_page' => $num_posts,
2382 'meta_key' => 'wpb_post_views_count',
2383 'paged' => $paged,
2384 'post__in' => $sticky,
2385 'ignore_sticky_posts' => 1,
2386 );
2387 } else {
2388 $query = array(
2389 'post_type' => 'post',
2390 'post_status' => 'publish',
2391 'orderby' => $orderby,
2392 'order' => $order,
2393 'category_name' => $categories,
2394 'posts_per_page' => $num_posts,
2395 'paged' => $paged,
2396 'post__in' => $sticky,
2397 'ignore_sticky_posts' => 1,
2398 );
2399 }
2400 } // #all_posts
2401
2402 return $query;
2403 }
2404
2405
2406 /** Get Category **/
2407 public static function jltma_get_category( $source, $posts_type, $css_link, $limit = 1 ) {
2408 $separator = ' ';
2409 $output = '';
2410 $count = 1;
2411 if ( $source == 'wp_posts' ) {
2412 $categories = get_the_category();
2413 if ( $categories ) {
2414 foreach ( $categories as $category ) {
2415 $output .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . esc_attr( /* translators: %s: Categories */sprintf( __( 'View all posts in %s', 'master-addons' ), $category->name ) ) . '" ' . $css_link . '>' . esc_html( $category->cat_name ) . '</a>' . esc_html( $separator );
2416 if ( $count == $limit ) {
2417 break;
2418 }
2419 ++$count;
2420 }
2421 }
2422 } elseif ( $source == 'post_type' ) {
2423 global $post;
2424 $taxonomy_names = get_object_taxonomies( $posts_type );
2425 $term_list = wp_get_post_terms( $post->ID, $taxonomy_names );
2426 if ( $term_list ) {
2427 foreach ( $term_list as $tax_term ) {
2428 /* translators: %s: Taxonomy term name. */
2429 $output .= '<a href="' . esc_attr( get_term_link( $tax_term, $posts_type ) ) . '" title="' . esc_attr( sprintf( __( 'View all posts in %s', 'master-addons' ), $tax_term->name ) ) . '" ' . $css_link . '>' . esc_html( $tax_term->name ) . '</a>' . esc_html( $separator );
2430 }
2431 }
2432 }
2433 $return = trim( $output, $separator );
2434 return $return;
2435 }
2436
2437
2438 /** Get Author **/
2439 public static function jltma_get_author( $css_link ) {
2440 $return = '<a href="' . get_author_posts_url( get_the_author_meta( 'ID' ) ) . '" ' . $css_link . '>' . get_the_author_meta( 'display_name' ) . '</a>';
2441 return $return;
2442 }
2443
2444 /** Get Blog Exceprt */
2445 public static function jltma_get_blogs_excerpt( $excerpt = 'default', $readmore = 'on', $css_link = '' ) {
2446 global $post;
2447 if ( $excerpt == 'default' ) :
2448 $return = get_the_excerpt();
2449 else :
2450 $return = substr( get_the_excerpt(), 0, $excerpt );
2451 if ( $readmore == 'on' ) :
2452 $return .= '<a class="article-read-more" href="' . get_permalink( $post->ID ) . '" ' . $css_link . '>' . esc_html__( 'Read More', 'master-addons' ) . '</a>';
2453 else :
2454 $return .= '...';
2455 endif;
2456 endif;
2457 return $return;
2458 }
2459
2460
2461 /** Post Social Share **/
2462 public static function jltma_post_social_share( $css_link ) {
2463
2464 $return = '<div class="container-social">
2465 <a target="_blank" href="http://www.facebook.com/sharer.php?u=' . get_the_permalink() . '&amp;t=' . get_the_title() . '" title="' . esc_html__( 'Click to share this post on Facebook', 'master-addons' ) . '" ' . $css_link . '><i class="fa fa-facebook"></i></a>
2466 <a target="_blank" href="http://twitter.com/home?status=' . get_the_permalink() . '" title="' . esc_html__( 'Click to share this post on Twitter', 'master-addons' ) . '"><i class="fa fa-twitter" ' . $css_link . '></i></a>
2467 <a target="_blank" href="http://www.linkedin.com/shareArticle?mini=true&amp;url=' . get_the_permalink() . '" title="' . esc_html__( 'Click to share this post on Linkedin', 'master-addons' ) . '"><i class="fa fa-linkedin" ' . $css_link . '></i></a></div>';
2468
2469 return $return;
2470 }
2471
2472 /** Check Post Format **/
2473 public static function jltma_check_post_format() {
2474 global $post;
2475 $format = get_post_format_string( get_post_format() );
2476 if ( $format == 'Video' ) :
2477 $return = '<span class="fpg-format-type fa fa-play-circle-o"></span>';
2478 elseif ( $format == 'Audio' ) :
2479 $return = '<span class="fpg-format-type fa fa-headphones"></span>';
2480 else :
2481 $return = '';
2482 endif;
2483 return $return;
2484 }
2485
2486 /** Get Thumbnails **/
2487 public static function jltma_get_thumb( $thumbs_size = 'thumbnail' ) {
2488 global $post;
2489 $link = get_the_permalink();
2490 if ( has_post_thumbnail() ) {
2491 $id_post = get_the_id();
2492 $single_image = wp_get_attachment_image_src( get_post_thumbnail_id( $id_post ), $thumbs_size );
2493 $return = '<a href="' . esc_url( $link ) . '"><img class="fpg-thumbs" src="' . $single_image[0] . '" alt="' . get_the_title() . '"></a>';
2494 } else {
2495 $return = '';
2496 }
2497 return $return;
2498 }
2499
2500
2501 /** Get Blog Thumbnails **/
2502 public static function jltma_get_blogs_thumb( $columns, $post_id ) {
2503 global $post;
2504 if ( $columns == '1' ) :
2505 $return = self::jltma_get_thumb( 'large' );
2506 elseif ( $columns == '2' ) :
2507 $return = self::jltma_get_thumb( 'medium' );
2508 else :
2509 $return = self::jltma_get_thumb( 'small' );
2510 endif;
2511 return $return;
2512 }
2513
2514 // Get Template Part
2515 public static function jltma_get_template_part( $jltma_template, $jltma_data = array() ) {
2516 extract( $jltma_data );
2517 include JLTMA_PATH . 'inc/post-templates/' . $jltma_template . '.php';
2518 }
2519
2520 // Get Featured Image URL
2521 public static function jltma_get_featured_image_url() {
2522 $featured_image_full_url = wp_get_attachment_image_src( get_post_thumbnail_id(), 'full' );
2523 if ( isset( $featured_image_full_url[0] ) && strlen( $featured_image_full_url[0] ) > 0 ) {
2524 return $featured_image_full_url[0];
2525 } else {
2526 return false;
2527 }
2528 }
2529
2530 // Get Featured Image URL
2531 public static function jltma_excerpt_truncate( $jltma_string, $jltma_length = 80, $jltma_etc = '... ', $jltma_break_words = false, $jltma_middle = false ) {
2532 if ( $jltma_length == 0 ) {
2533 return '';
2534 }
2535
2536 if ( mb_strlen( $jltma_string, 'utf8' ) > $jltma_length ) {
2537 $jltma_length -= mb_strlen( $jltma_etc, 'utf8' );
2538 if ( ! $jltma_break_words && ! $jltma_middle ) {
2539 $jltma_string = preg_replace( '/\s+\S+\s*$/su', '', mb_substr( $jltma_string, 0, $jltma_length + 1, 'utf8' ) );
2540 }
2541 if ( ! $jltma_middle ) {
2542 return mb_substr( $jltma_string, 0, $jltma_length, 'utf8' ) . $jltma_etc;
2543 } else {
2544 return mb_substr( $jltma_string, 0, $jltma_length / 2, 'utf8' ) . $jltma_etc . mb_substr( $jltma_string, -$jltma_length / 2, utf8 );
2545 }
2546 } else {
2547 return $jltma_string;
2548 }
2549 }
2550
2551
2552 public static function jltma_pro_notice_html( $args = array() ) {
2553
2554 $defaults = array(
2555 'show_icon' => true,
2556 'show_heading' => true,
2557 );
2558 $args = wp_parse_args( $args, $defaults );
2559
2560 // Get Pro_Upgrade instance to access promo data
2561 $pro_upgrade = new \MasterAddons\Inc\Classes\Pro_Upgrade();
2562
2563 // Check if campaign is active, otherwise use fallback
2564 if ( 'FALSE' === $pro_upgrade->get_content( 'is_campaign' ) ) {
2565 $notice = 'Use "SPECIAL40" to Get Flat 40% OFF';
2566 $btn_url = 'https://master-addons.com/pricing/';
2567 $btn_text = 'GET THE DEAL';
2568 } else {
2569 $notice = $pro_upgrade->get_content( 'notice' );
2570 $btn_url = $pro_upgrade->get_content( 'button_url' );
2571 $btn_text = $pro_upgrade->get_content( 'button_text' );
2572 }
2573
2574 $end_date = $pro_upgrade->counter_date();
2575
2576 ob_start();
2577 ?>
2578 <div class="jltma-upgrade-banner" id="jltma-upgrade-banner">
2579 <div class="jltma-upgrade-banner-content">
2580 <?php if ( $args['show_icon'] ) : ?>
2581 <!-- Crown Icon with Speech Bubble Tail -->
2582 <div class="jltma-upgrade-banner-icon-wrapper">
2583 <div class="jltma-upgrade-banner-icon">
2584 <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
2585 <path d="M6 30V26L3 12L12 18L20 8L28 18L37 12L34 26V30H6Z" fill="white"/>
2586 <circle cx="20" cy="22" r="2.5" fill="#6814cd"/>
2587 </svg>
2588 </div>
2589 </div>
2590 <?php endif; ?>
2591
2592 <?php if ( $args['show_heading'] ) : ?>
2593 <!-- Main Heading -->
2594 <h2 class="jltma-upgrade-banner-title"><?php echo esc_html__( 'Upgrade to unlock every powerful feature and faster performance', 'master-addons' ); ?></h2>
2595 <?php endif; ?>
2596
2597 <!-- Countdown Timer -->
2598 <div class="jltma-popup-countdown" style="display: none;">
2599 <?php if ( ! empty( $notice ) ) { ?>
2600 <span data-counter="notice" style="color:#F4B740; font-size:14px; padding-bottom:20px; font-style:italic;">
2601 <?php echo esc_html__( 'Notice:', 'master-addons' ); ?> <?php echo esc_html( $notice ); ?>
2602 </span>
2603 <?php } ?>
2604 <span class="jltma-popup-countdown-text"><?php echo esc_html__( 'Offer Ends In', 'master-addons' ); ?></span>
2605 <div class="jltma-popup-countdown-time">
2606 <div>
2607 <span data-counter="days">00</span>
2608 <span><?php echo esc_html__( 'Days', 'master-addons' ); ?></span>
2609 </div>
2610 <span>:</span>
2611 <div>
2612 <span data-counter="hours">00</span>
2613 <span><?php echo esc_html__( 'Hours', 'master-addons' ); ?></span>
2614 </div>
2615 <span>:</span>
2616 <div>
2617 <span data-counter="minutes">00</span>
2618 <span><?php echo esc_html__( 'Minutes', 'master-addons' ); ?></span>
2619 </div>
2620 <span>:</span>
2621 <div>
2622 <span data-counter="seconds">00</span>
2623 <span><?php echo esc_html__( 'Seconds', 'master-addons' ); ?></span>
2624 </div>
2625 </div>
2626 </div>
2627
2628 <!-- Upgrade Button -->
2629 <a class="jltma-upgrade-banner-button" target="_blank" href="https://master-addons.com/pricing"><?php echo esc_html__( 'Upgrade Now', 'master-addons' ); ?></a>
2630 </div>
2631 </div>
2632
2633 <script>
2634 (function() {
2635 var $container = jQuery('#jltma-upgrade-banner');
2636
2637 // Update Counter
2638 function updateCounter(seconds) {
2639 const $counter = $container.find(".jltma-popup-countdown-time");
2640 const $days = $counter.find("[data-counter='days']");
2641 const $hours = $counter.find("[data-counter='hours']");
2642 const $minutes = $counter.find("[data-counter='minutes']");
2643 const $seconds = $counter.find("[data-counter='seconds']");
2644 const days = Math.floor(seconds / (3600 * 24));
2645 seconds -= days * 3600 * 24;
2646 const hrs = Math.floor(seconds / 3600);
2647 seconds -= hrs * 3600;
2648 const mnts = Math.floor(seconds / 60);
2649 seconds -= mnts * 60;
2650
2651 $days.text(days);
2652 $hours.text(hrs);
2653 $minutes.text(mnts);
2654 $seconds.text(seconds);
2655 }
2656
2657 // initCounter
2658 function initCounter(last_date) {
2659 const countdown = () => {
2660 // system time
2661 const now = new Date().getTime();
2662
2663 // set end time to 11:59:59 PM
2664 const endDate = new Date(last_date);
2665 endDate.setHours(23);
2666 endDate.setMinutes(59);
2667 endDate.setSeconds(59);
2668
2669 const seconds = Math.floor((endDate.getTime() - now) / 1000);
2670
2671 if (seconds < 0) {
2672 return false;
2673 }
2674
2675 updateCounter(seconds);
2676 return true;
2677 }
2678
2679 let result = countdown();
2680
2681 if (result) {
2682 $container.find(".jltma-popup-countdown").show(0);
2683 } else {
2684 $container.find(".jltma-popup-countdown").hide(0);
2685 }
2686
2687 // update counter every 1 second
2688 const counter = setInterval(() => {
2689 const result = countdown();
2690 if (!result) {
2691 clearInterval(counter);
2692 $container.find(".jltma-popup-countdown").hide(0);
2693 }
2694 }, 1000);
2695 }
2696
2697 // Initialize countdown when DOM is ready
2698 jQuery(document).ready(function() {
2699 initCounter('<?php echo esc_attr( $end_date ); ?>');
2700 });
2701 })();
2702 </script>
2703
2704 <?php // Auto-open Elementor sections that contain upgrade banners ?>
2705 <script>
2706 (function(){
2707 if (window.jltmaUpgradeSectionAutoOpen) return;
2708 window.jltmaUpgradeSectionAutoOpen = true;
2709 var panel = document.getElementById("elementor-panel-content-wrapper");
2710 if (!panel) return;
2711 function openUpgradeSections() {
2712 var banners = panel.querySelectorAll(".jltma-upgrade-banner");
2713 banners.forEach(function(banner) {
2714 var section = banner.closest(".elementor-control-type-section");
2715 if (section && !section.classList.contains("elementor-open")) {
2716 section.classList.add("elementor-open");
2717 }
2718 });
2719 }
2720 var observer = new MutationObserver(openUpgradeSections);
2721 observer.observe(panel, {childList: true, subtree: true});
2722 openUpgradeSections();
2723 })();
2724 </script>
2725 <?php
2726
2727 $notice_html = ob_get_clean();
2728 return $notice_html;
2729 }
2730
2731
2732 public static function jltma_premium(){
2733 // Check Freemius license first (most reliable — respects actual license status)
2734 if (function_exists('ma_el_fs')) {
2735 return ma_el_fs()->can_use_premium_code__premium_only();
2736 }
2737
2738 // Fallback: If pro addon plugin is installed (JLTMA_PRO_PATH is defined by pro plugin)
2739 if (defined('JLTMA_PRO_PATH') && is_dir(JLTMA_PRO_PATH . 'premium/')) {
2740 return true;
2741 }
2742
2743 // Fallback: If premium modules directory exists, this is a pro build
2744 if (defined('JLTMA_PRO_EXTENSIONS') && is_dir(JLTMA_PRO_EXTENSIONS)) {
2745 return true;
2746 }
2747
2748 return apply_filters('master_addons/is_premium', false);
2749 }
2750
2751 /**
2752 * Get widget statistics for admin dashboard
2753 * Returns counts for all widgets, core, third party, and active widgets
2754 *
2755 * @return array Statistics array with totals and percentages
2756 */
2757 public static function jltma_get_widget_stats() {
2758 // Get saved settings
2759 $element_settings = \MasterAddons\Inc\Admin\Settings\Settings::get_addons() ?: [];
2760 $extension_settings = \MasterAddons\Inc\Admin\Settings\Settings::get_extensions() ?: [];
2761
2762 // Initialize counters
2763 $core_widgets = [];
2764 $third_party_widgets = [];
2765
2766 // Use unified config to get all addons
2767 $addons = \MasterAddons\Inc\Admin\Config::get_addons();
2768 foreach ($addons as $key => $addon) {
2769 $core_widgets[] = [
2770 'key' => $key,
2771 'type' => 'element'
2772 ];
2773 }
2774
2775 // Get all extensions
2776 $extensions = \MasterAddons\Inc\Admin\Config::get_extensions();
2777 foreach ($extensions as $key => $extension) {
2778 $core_widgets[] = [
2779 'key' => $key,
2780 'type' => 'extension'
2781 ];
2782 }
2783
2784 // Get third party plugins
2785 $plugins = \MasterAddons\Inc\Admin\Config::get_plugins();
2786 foreach ($plugins as $key => $plugin) {
2787 $third_party_widgets[] = [
2788 'key' => $key,
2789 'type' => 'third_party'
2790 ];
2791 }
2792
2793 // Calculate active counts
2794 $core_active = 0;
2795 $core_total = count($core_widgets);
2796 foreach ($core_widgets as $widget) {
2797 $settings = ($widget['type'] === 'extension') ? $extension_settings : $element_settings;
2798 if (isset($settings[$widget['key']]) && $settings[$widget['key']] == 1) {
2799 $core_active++;
2800 }
2801 }
2802
2803 $third_party_active = 0;
2804 $third_party_total = count($third_party_widgets);
2805 // Third party plugins don't have the same active/inactive mechanism
2806
2807 // Calculate totals
2808 $all_total = $core_total + $third_party_total;
2809 $all_active = $core_active + $third_party_active;
2810
2811 return [
2812 'all' => [
2813 'total' => $all_total,
2814 'active' => $all_active,
2815 'inactive' => $all_total - $all_active,
2816 'percentage' => $all_total > 0 ? round(($all_active / $all_total) * 100) : 0
2817 ],
2818 'core' => [
2819 'total' => $core_total,
2820 'active' => $core_active,
2821 'inactive' => $core_total - $core_active,
2822 'percentage' => $core_total > 0 ? round(($core_active / $core_total) * 100) : 0
2823 ],
2824 'third_party' => [
2825 'total' => $third_party_total,
2826 'active' => $third_party_active,
2827 'inactive' => $third_party_total - $third_party_active,
2828 'percentage' => $third_party_total > 0 ? round(($third_party_active / $third_party_total) * 100) : 0
2829 ],
2830 'active' => [
2831 'total' => $all_active,
2832 'active' => $all_active,
2833 'inactive' => 0,
2834 'percentage' => 100
2835 ]
2836 ];
2837 }
2838 }
2839