PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / trunk
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits vtrunk
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 trunk, at inc/classes/helper.php

2,980 lines 91.0 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 <support@jeweltheme.com>
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 <support@jeweltheme.com>
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 <support@jeweltheme.com>
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 /**
1765 * Whether this site may import pro templates.
1766 *
1767 * Two things can say yes and they do not agree on how. Freemius knows
1768 * whether a licence is active; the template config knows whether a key was
1769 * entered by hand. Asking only for the key locked out a site licensed
1770 * through Freemius, and asking only for the status let through an install
1771 * whose status read "valid" with no licence behind it at all.
1772 *
1773 * @return bool
1774 */
1775 public static function jltma_can_use_pro_templates() {
1776 if ( function_exists( 'ma_el_fs' ) ) {
1777 $fs = ma_el_fs();
1778
1779 foreach ( array( 'has_active_valid_license', 'is_paying', 'can_use_premium_code__premium_only' ) as $check ) {
1780 if ( method_exists( $fs, $check ) && $fs->$check() ) {
1781 return true;
1782 }
1783 }
1784 }
1785
1786 if ( function_exists( '\MasterAddons\Inc\Admin\Templates\master_addons_templates' ) ) {
1787 $config = \MasterAddons\Inc\Admin\Templates\master_addons_templates()->config;
1788 $key = $config->get( 'key' );
1789
1790 if ( ! empty( $key ) && 'valid' === $config->get( 'status' ) ) {
1791 return true;
1792 }
1793 }
1794
1795 return (bool) apply_filters( 'jltma_can_use_pro_templates', false );
1796 }
1797
1798
1799 /**
1800 * The licence key the template library should be asked with.
1801 *
1802 * The remote library unlocks a pro template for a request that carries a
1803 * licence; a request without one comes back with no content at all. A site
1804 * licensed through Freemius holds its key there, so read it from the
1805 * licence rather than from the template config, which never stored one.
1806 *
1807 * @return string Empty when the site has no licence to send.
1808 */
1809 public static function jltma_template_license_key() {
1810 if ( ! self::jltma_can_use_pro_templates() ) {
1811 return '';
1812 }
1813
1814 if ( function_exists( 'ma_el_fs' ) ) {
1815 $fs = ma_el_fs();
1816
1817 if ( method_exists( $fs, '_get_license' ) ) {
1818 $license = $fs->_get_license();
1819
1820 if ( is_object( $license ) && ! empty( $license->secret_key ) ) {
1821 return (string) $license->secret_key;
1822 }
1823 }
1824 }
1825
1826 if ( function_exists( '\MasterAddons\Inc\Admin\Templates\master_addons_templates' ) ) {
1827 $key = \MasterAddons\Inc\Admin\Templates\master_addons_templates()->config->get( 'key' );
1828
1829 if ( ! empty( $key ) ) {
1830 return (string) $key;
1831 }
1832 }
1833
1834 return '';
1835 }
1836
1837
1838 /**
1839 * A title no post of this type is using yet.
1840 *
1841 * Importing the same template twice left two posts with identical titles --
1842 * WordPress only made the slugs unique, so the list table showed the same
1843 * name twice with nothing to tell them apart. The second copy is numbered
1844 * the way WordPress numbers a duplicate slug.
1845 *
1846 * @param string $title
1847 * @param string $post_type
1848 * @return string
1849 */
1850 public static function jltma_unique_post_title( $title, $post_type = 'page' ) {
1851 $title = trim( (string) $title );
1852
1853 if ( '' === $title ) {
1854 return $title;
1855 }
1856
1857 $candidate = $title;
1858 $suffix = 1;
1859
1860 // A hundred copies of one template is already absurd; the guard is only
1861 // there so a broken query cannot spin.
1862 while ( $suffix < 100 ) {
1863 $existing = get_posts( array(
1864 'post_type' => $post_type,
1865 'post_status' => 'any',
1866 'title' => $candidate,
1867 'posts_per_page' => 1,
1868 'fields' => 'ids',
1869 'no_found_rows' => true,
1870 'update_post_meta_cache' => false,
1871 'update_post_term_cache' => false,
1872 ) );
1873
1874 if ( empty( $existing ) ) {
1875 return $candidate;
1876 }
1877
1878 $suffix++;
1879 $candidate = $title . ' ' . $suffix;
1880 }
1881
1882 return $candidate;
1883 }
1884
1885
1886 public static function jltma_set_global_authordata() {
1887 global $authordata;
1888
1889 if ( isset( $authordata->ID ) ) {
1890 return;
1891 }
1892
1893 // On an author archive the author is the thing being queried, and a
1894 // theme-builder template renders outside the loop -- so nothing has set
1895 // $authordata and get_the_author_meta() comes back empty, which left
1896 // the name blank and the avatar on the anonymous gravatar.
1897 if ( is_author() ) {
1898 $queried = get_queried_object();
1899
1900 if ( $queried instanceof \WP_User ) {
1901 $authordata = $queried; // WPCS: override ok.
1902 return;
1903 }
1904 }
1905
1906 $post = get_post();
1907
1908 if ( $post ) {
1909 $authordata = get_userdata( $post->post_author ); // WPCS: override ok.
1910 }
1911 }
1912
1913
1914 public static function jltma_get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
1915 global $wp_taxonomies;
1916
1917 $field = ( 'names' === $output ) ? 'name' : false;
1918
1919 // Handle 'object_type' separately.
1920 if ( isset( $args['object_type'] ) ) {
1921 $object_type = (array) $args['object_type'];
1922 unset( $args['object_type'] );
1923 }
1924
1925 $taxonomies = wp_filter_object_list( $wp_taxonomies, $args, $operator );
1926
1927 if ( isset( $object_type ) ) {
1928 foreach ( $taxonomies as $tax => $tax_data ) {
1929 if ( ! array_intersect( $object_type, $tax_data->object_type ) ) {
1930 unset( $taxonomies[ $tax ] );
1931 }
1932 }
1933 }
1934
1935 if ( $field ) {
1936 $taxonomies = wp_list_pluck( $taxonomies, $field );
1937 }
1938
1939 return $taxonomies;
1940 }
1941
1942
1943
1944 public static function is_plugin_installed( $plugin_slug, $plugin_file ) {
1945 $installed_plugins = get_plugins();
1946 return isset( $installed_plugins[ $plugin_file ] );
1947 }
1948
1949
1950 // Get Page Title
1951 public static function jltma_get_page_title( $include_context = true ) {
1952 $title = '';
1953
1954 if ( is_singular() ) {
1955 /* translators: %s: Search term. */
1956 $title = get_the_title();
1957
1958 if ( $include_context ) {
1959 $post_type_obj = get_post_type_object( get_post_type() );
1960 $title = sprintf( '%s: %s', $post_type_obj->labels->singular_name, $title );
1961 }
1962 } elseif ( is_search() ) {
1963 /* translators: %s: Search term. */
1964 $title = sprintf( __( 'Search Results for: %s', 'master-addons' ), get_search_query() );
1965
1966 if ( get_query_var( 'paged' ) ) {
1967 /* translators: %s is the page number. */
1968 $title .= sprintf( __( '&nbsp;&ndash; Page %s', 'master-addons' ), get_query_var( 'paged' ) );
1969 }
1970 } elseif ( is_category() ) {
1971 $title = single_cat_title( '', false );
1972
1973 if ( $include_context ) {
1974 /* translators: Category archive title. 1: Category name */
1975 $title = sprintf( __( 'Category: %s', 'master-addons' ), $title );
1976 }
1977 } elseif ( is_tag() ) {
1978 $title = single_tag_title( '', false );
1979 if ( $include_context ) {
1980 /* translators: Tag archive title. 1: Tag name */
1981 $title = sprintf( __( 'Tag: %s', 'master-addons' ), $title );
1982 }
1983 } elseif ( is_author() ) {
1984 $title = '<span class="vcard">' . get_the_author() . '</span>';
1985
1986 if ( $include_context ) {
1987 /* translators: Author archive title. 1: Author name */
1988 $title = sprintf( __( 'Author: %s', 'master-addons' ), $title );
1989 }
1990 } elseif ( is_year() ) {
1991 $title = get_the_date( _x( 'Y', 'yearly archives date format', 'master-addons' ) );
1992
1993 if ( $include_context ) {
1994 /* translators: Yearly archive title. 1: Year */
1995 $title = sprintf( __( 'Year: %s', 'master-addons' ), $title );
1996 }
1997 } elseif ( is_month() ) {
1998 $title = get_the_date( _x( 'F Y', 'monthly archives date format', 'master-addons' ) );
1999
2000 if ( $include_context ) {
2001 /* translators: Monthly archive title. 1: Month name and year */
2002 $title = sprintf( __( 'Month: %s', 'master-addons' ), $title );
2003 }
2004 } elseif ( is_day() ) {
2005 $title = get_the_date( _x( 'F j, Y', 'daily archives date format', 'master-addons' ) );
2006
2007 if ( $include_context ) {
2008 /* translators: Daily archive title. 1: Date */
2009 $title = sprintf( __( 'Day: %s', 'master-addons' ), $title );
2010 }
2011 } elseif ( is_tax( 'post_format' ) ) {
2012 if ( is_tax( 'post_format', 'post-format-aside' ) ) {
2013 $title = _x( 'Asides', 'post format archive title', 'master-addons' );
2014 } elseif ( is_tax( 'post_format', 'post-format-gallery' ) ) {
2015 $title = _x( 'Galleries', 'post format archive title', 'master-addons' );
2016 } elseif ( is_tax( 'post_format', 'post-format-image' ) ) {
2017 $title = _x( 'Images', 'post format archive title', 'master-addons' );
2018 } elseif ( is_tax( 'post_format', 'post-format-video' ) ) {
2019 $title = _x( 'Videos', 'post format archive title', 'master-addons' );
2020 } elseif ( is_tax( 'post_format', 'post-format-quote' ) ) {
2021 $title = _x( 'Quotes', 'post format archive title', 'master-addons' );
2022 } elseif ( is_tax( 'post_format', 'post-format-link' ) ) {
2023 $title = _x( 'Links', 'post format archive title', 'master-addons' );
2024 } elseif ( is_tax( 'post_format', 'post-format-status' ) ) {
2025 $title = _x( 'Statuses', 'post format archive title', 'master-addons' );
2026 } elseif ( is_tax( 'post_format', 'post-format-audio' ) ) {
2027 $title = _x( 'Audio', 'post format archive title', 'master-addons' );
2028 } elseif ( is_tax( 'post_format', 'post-format-chat' ) ) {
2029 $title = _x( 'Chats', 'post format archive title', 'master-addons' );
2030 }
2031 } elseif ( is_post_type_archive() ) {
2032 $title = post_type_archive_title( '', false );
2033
2034 if ( $include_context ) {
2035 /* translators: Post type archive title. 1: Post type name */
2036 $title = sprintf( __( 'Archives: %s', 'master-addons' ), $title );
2037 }
2038 } elseif ( is_tax() ) {
2039 $title = single_term_title( '', false );
2040
2041 if ( $include_context ) {
2042 $tax = get_taxonomy( get_queried_object()->taxonomy );
2043 /* translators: Taxonomy term archive title. 1: Taxonomy singular name, 2: Current taxonomy term */
2044 $title = sprintf( __( '%1$s: %2$s', 'master-addons' ), $tax->labels->singular_name, $title );
2045 }
2046 } elseif ( is_404() ) {
2047 $title = __( 'Page Not Found', 'master-addons' );
2048 } // End if().
2049
2050 $title = apply_filters( 'jltma/core_elements/get_the_archive_title', $title );
2051
2052 return $title;
2053 }
2054
2055
2056
2057 // Archive URL
2058 public static function jltma_get_the_archive_url() {
2059 $url = '';
2060 if ( is_category() || is_tag() || is_tax() ) {
2061 $url = get_term_link( get_queried_object() );
2062 } elseif ( is_author() ) {
2063 $url = get_author_posts_url( get_queried_object_id() );
2064 } elseif ( is_year() ) {
2065 $url = get_year_link( get_query_var( 'year' ) );
2066 } elseif ( is_month() ) {
2067 $url = get_month_link( get_query_var( 'year' ), get_query_var( 'monthnum' ) );
2068 } elseif ( is_day() ) {
2069 $url = get_day_link( get_query_var( 'year' ), get_query_var( 'monthnum' ), get_query_var( 'day' ) );
2070 } elseif ( is_post_type_archive() ) {
2071 $url = get_post_type_archive_link( get_post_type() );
2072 }
2073
2074 return $url;
2075 }
2076
2077 public static function jltma_blend_options() {
2078 $blend_options = array(
2079 'multiply' => esc_html__( 'Multiply', 'master-addons' ),
2080 'screen' => esc_html__( 'Screen', 'master-addons' ),
2081 'overlay' => esc_html__( 'Overlay', 'master-addons' ),
2082 'darken' => esc_html__( 'Darken', 'master-addons' ),
2083 'lighten' => esc_html__( 'Lighten', 'master-addons' ),
2084 'color-dodge' => esc_html__( 'Color-Dodge', 'master-addons' ),
2085 'color-burn' => esc_html__( 'Color-Burn', 'master-addons' ),
2086 'hard-light' => esc_html__( 'Hard-Light', 'master-addons' ),
2087 'soft-light' => esc_html__( 'Soft-Light', 'master-addons' ),
2088 'difference' => esc_html__( 'Difference', 'master-addons' ),
2089 'exclusion' => esc_html__( 'Exclusion', 'master-addons' ),
2090 'hue' => esc_html__( 'Hue', 'master-addons' ),
2091 'saturation' => esc_html__( 'Saturation', 'master-addons' ),
2092 'color' => esc_html__( 'Color', 'master-addons' ),
2093 'luminosity' => esc_html__( 'Luminosity', 'master-addons' ),
2094 );
2095
2096 return $blend_options;
2097 }
2098
2099 public static function jltma_carousel_navigation_position() {
2100 $position_options = array(
2101 'top-left' => esc_html__( 'Top Left', 'master-addons' ),
2102 'top-center' => esc_html__( 'Top Center', 'master-addons' ),
2103 'top-right' => esc_html__( 'Top Right', 'master-addons' ),
2104 'center' => esc_html__( 'Center', 'master-addons' ),
2105 'bottom-left' => esc_html__( 'Bottom Left', 'master-addons' ),
2106 'bottom-center' => esc_html__( 'Bottom Center', 'master-addons' ),
2107 'bottom-right' => esc_html__( 'Bottom Right', 'master-addons' ),
2108 );
2109
2110 return $position_options;
2111 }
2112
2113
2114 public static function jltma_carousel_pagination_position() {
2115 $position_options = array(
2116 'top-left' => esc_html__( 'Top Left', 'master-addons' ),
2117 'top-center' => esc_html__( 'Top Center', 'master-addons' ),
2118 'top-right' => esc_html__( 'Top Right', 'master-addons' ),
2119 'bottom-left' => esc_html__( 'Bottom Left', 'master-addons' ),
2120 'bottom-center' => esc_html__( 'Bottom Center', 'master-addons' ),
2121 'bottom-right' => esc_html__( 'Bottom Right', 'master-addons' ),
2122 );
2123
2124 return $position_options;
2125 }
2126
2127 public static function jltma_get_preloadable_previews() {
2128 $position_options = array(
2129 'no' => esc_html__( 'Blank', 'master-addons' ),
2130 'yes' => esc_html__( 'Blurred placeholder image', 'master-addons' ),
2131 'progress-box' => esc_html__( 'In-progress box animation', 'master-addons' ),
2132 'simple-spinner' => esc_html__( 'Loading spinner (blue)', 'master-addons' ),
2133 'simple-spinner-light' => esc_html__( 'Loading spinner (light)', 'master-addons' ),
2134 'simple-spinner-dark' => esc_html__( 'Loading spinner (dark)', 'master-addons' ),
2135 );
2136 return $position_options;
2137 }
2138
2139 public static function jltma_get_array_value( $array, $key, $default = '' ) {
2140 return isset( $array[ $key ] ) ? $array[ $key ] : $default;
2141 }
2142
2143
2144
2145 public static function render_image( $image_id, $settings, $class = '' ) {
2146 $image_size = $settings;
2147
2148 if ( 'custom' === $image_size ) {
2149 $image_src = \Elementor\Group_Control_Image_Size::get_attachment_image_src( $image_id, $image_size, $settings );
2150 } else {
2151 $image_src = wp_get_attachment_image_src( $image_id, $image_size );
2152 $image_src = $image_src[0];
2153 }
2154
2155 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 ) ) );
2156 }
2157
2158
2159 /**
2160 * Get Elementor Pro Locked Html
2161 *
2162 * Returns the markup to display when a feature requires Elementor Pro
2163 *
2164 * @since 2.1.0
2165 * @return \Elementor\Plugin|$instace
2166 */
2167 public static function jltma_pro_locked_html() {
2168 return '<div class="elementor-nerd-box">
2169 <i class="elementor-nerd-box-icon eicon-hypster"></i>
2170 <div class="elementor-nerd-box-title">' .
2171 __( 'Oups, hang on!', 'master-addons' ) .
2172 '</div>
2173 <div class="elementor-nerd-box-message">' .
2174 __( 'This feature is only available if you have Master Addons Pro.', 'master-addons' ) .
2175 '</div>
2176 <a class="elementor-nerd-box-link elementor-button elementor-button-default elementor-go-pro" href="https://master-addons.com/pricing" target="_blank">' .
2177 __( 'Go Pro', 'master-addons' ) .
2178 '</a>
2179 </div>';
2180 }
2181
2182
2183 public static function jltma_tooltip_options() {
2184 return array(
2185 '' => esc_html__( 'Top (Default)', 'master-addons' ),
2186
2187 'top-start' => esc_html__( 'Top Start', 'master-addons' ),
2188 'top-end' => esc_html__( 'Top End', 'master-addons' ),
2189
2190 'right' => esc_html__( 'Right', 'master-addons' ),
2191 'right-start' => esc_html__( 'Right Start', 'master-addons' ),
2192 'right-end' => esc_html__( 'Right End', 'master-addons' ),
2193
2194 'bottom' => esc_html__( 'Bottom', 'master-addons' ),
2195 'bottom-start' => esc_html__( 'Bottom Start', 'master-addons' ),
2196 'bottom-end' => esc_html__( 'Bottom End', 'master-addons' ),
2197
2198 'left' => esc_html__( 'Left', 'master-addons' ),
2199 'left-start' => esc_html__( 'Left Start', 'master-addons' ),
2200 'left-end' => esc_html__( 'Left End', 'master-addons' ),
2201
2202 'auto' => esc_html__( 'Auto', 'master-addons' ),
2203 'auto-start' => esc_html__( 'Auto Start', 'master-addons' ),
2204 'auto-end' => esc_html__( 'Auto End', 'master-addons' ),
2205 );
2206 }
2207
2208 public static function jltma_tooltip_animations() {
2209 return array(
2210 'none' => esc_html__( 'None', 'master-addons' ),
2211 '' => esc_html__( 'Fade', 'master-addons' ),
2212 'shift-away' => esc_html__( 'Shift-Away', 'master-addons' ),
2213 'shift-toward' => esc_html__( 'Shift-Toward', 'master-addons' ),
2214 'scale' => esc_html__( 'Scale', 'master-addons' ),
2215 'perspective' => esc_html__( 'Perspective', 'master-addons' ),
2216 'fill' => esc_html__( 'Fill Effect', 'master-addons' ),
2217 );
2218 }
2219
2220 public static function jltma_placeholder_images() {
2221 $demo_images =
2222 array(
2223 'id' => 0,
2224 'url' => Utils::get_placeholder_image_src(),
2225 );
2226 return $demo_images;
2227 }
2228
2229 public static function find_widget_elements_by_id( $elements, $id ) {
2230 static $widget = null;
2231
2232 foreach ( $elements as $element ) {
2233 if ( $id === $element['id'] ) {
2234 $widget = $element;
2235
2236 break;
2237 } elseif ( isset( $element['elements'] ) ) {
2238 self::find_widget_elements_by_id( $element['elements'], $id );
2239 }
2240 }
2241
2242 return $widget;
2243 }
2244
2245
2246 public static function get_client_ip_as_key() {
2247 return str_replace( '.', '_', self::get_client_ip() );
2248 }
2249
2250 public static function get_client_ip() {
2251 $ip = self::IP_LOCAL;
2252
2253 $server_ip_keys = array(
2254 'REMOTE_ADDR',
2255 'HTTP_CLIENT_IP',
2256 'HTTP_X_FORWARDED_FOR',
2257 'HTTP_X_FORWARDED',
2258 'HTTP_X_CLUSTER_CLIENT_IP',
2259 'HTTP_FORWARDED_FOR',
2260 'HTTP_FORWARDED',
2261 );
2262
2263 foreach ( $server_ip_keys as $key ) {
2264 if ( isset( $_SERVER[ $key ] ) && filter_var( wp_unslash( $_SERVER[ $key ] ), FILTER_VALIDATE_IP ) ) {
2265 $ip = sanitize_text_field( wp_unslash( $_SERVER[ $key ] ) );
2266
2267 break;
2268 }
2269 }
2270
2271 return apply_filters( 'jltma_elementor/utils/client_ip', $ip );
2272 }
2273
2274
2275 public static function short_number( $number ) {
2276 $abbrevs = array(
2277 12 => 'T',
2278 9 => 'B',
2279 6 => 'M',
2280 3 => 'K',
2281 0 => '',
2282 );
2283
2284 foreach ( $abbrevs as $exponent => $abbrev ) {
2285 if ( abs( $number ) >= pow( 10, $exponent ) ) {
2286 $display = $number / pow( 10, $exponent );
2287 $decimals = ( $exponent >= 3 && round( $display ) < 100 ) ? 1 : 0;
2288 $number = number_format( $display, $decimals ) . $abbrev;
2289 break;
2290 }
2291 }
2292
2293 return $number;
2294 }
2295
2296 public static function array_merge_recursive( $array1, $array2 ) {
2297 $merged = $array1;
2298
2299 foreach ( $array2 as $key => &$value ) {
2300 if ( is_array( $value ) && isset( $merged[ $key ] ) && is_array( $merged[ $key ] ) ) {
2301 $merged[ $key ] = self::array_merge_recursive( $merged[ $key ], $value );
2302 } elseif ( is_numeric( $key ) ) {
2303 if ( ! in_array( $value, $merged, true ) ) {
2304 $merged[] = $value;
2305 }
2306 } else {
2307 $merged[ $key ] = $value;
2308 }
2309 }
2310
2311 return $merged;
2312 }
2313
2314 /**
2315 * Get current elementor document id
2316 *
2317 * @return int|false
2318 */
2319 public static function get_document_id() {
2320 $document = self::jltma_elementor()->documents->get_current();
2321
2322 if ( $document ) {
2323 return $document->get_main_id();
2324 }
2325
2326 return $document;
2327 }
2328
2329 public static function get_ob_html( $callback ) {
2330 if ( ! is_callable( $callback ) ) {
2331 return '';
2332 }
2333
2334 ob_start();
2335
2336 call_user_func( $callback );
2337
2338 return ob_get_clean();
2339 }
2340
2341 public static function render_icon( $icon_setting, $attributes = array() ) {
2342 if ( empty( $icon_setting['value'] ) ) {
2343 return;
2344 }
2345
2346 echo '<span class="jltma-wrap-icon">';
2347
2348 Icons_Manager::render_icon( $icon_setting, $attributes );
2349
2350 echo '</span>';
2351 }
2352
2353 /**
2354 * Render Icon
2355 *
2356 * Used to render Icon for \Elementor\Controls_Manager::ICONS
2357 *
2358 * @param array $icon Icon Type, Icon value
2359 * @param array $attributes Icon HTML Attributes
2360 */
2361 public static function get_render_icon( $icon_setting, $attributes = array() ) {
2362 return self::get_ob_html(
2363 function () use ( $icon_setting, $attributes ) {
2364 self::render_icon( $icon_setting, $attributes );
2365 }
2366 );
2367 }
2368
2369
2370 /**
2371 * Prepare css var.
2372 *
2373 * @param string $control_id Control id.
2374 * @param string $value Control selectors value.
2375 *
2376 * @return string Control id that prepared for css vars.
2377 */
2378 public static function prepare_css_var( $control_id, $value = '' ) {
2379 $var_key = '--' . str_replace( '_', '-', $control_id );
2380
2381 if ( empty( $value ) ) {
2382 return $var_key;
2383 }
2384
2385 return $var_key . ': ' . $value . ';';
2386 }
2387
2388 public static function get_available_image_sizes() {
2389 $glob_sizes = wp_get_additional_image_sizes();
2390 $image_sizes = get_intermediate_image_sizes();
2391 $sizes = array();
2392
2393 if ( is_array( $image_sizes ) && $image_sizes ) {
2394 foreach ( $image_sizes as $size ) {
2395 if ( in_array( $size, array( 'thumbnail', 'medium', 'medium_large', 'large' ), true ) ) {
2396 $sizes[ $size ] = array(
2397 'width' => get_option( "{$size}_size_w" ),
2398 'height' => get_option( "{$size}_size_h" ),
2399 'crop' => (bool) get_option( "{$size}_crop" ),
2400 );
2401 } elseif ( isset( $glob_sizes[ $size ] ) ) {
2402 $sizes[ $size ] = array(
2403 'width' => $glob_sizes[ $size ]['width'],
2404 'height' => $glob_sizes[ $size ]['height'],
2405 'crop' => $glob_sizes[ $size ]['crop'],
2406 );
2407 }
2408
2409 if ( 0 === (int) $sizes[ $size ]['width'] || 0 === (int) $sizes[ $size ]['height'] ) {
2410 unset( $sizes[ $size ] );
2411 }
2412 }
2413 }
2414
2415 return $sizes;
2416 }
2417
2418 public static function jltma_animate_class( $addon_animate, $effect, $delay ) {
2419 if ( $addon_animate == 'on' ) :
2420 $animate_class = ' animate-in" data-anim-type="' . $effect . '" data-anim-delay="' . $delay . '"';
2421 else :
2422 $animate_class = '"';
2423 endif;
2424 return $animate_class;
2425 }
2426
2427
2428
2429 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 ) {
2430
2431 if ( $orderby == 'views' ) {
2432 $orderby = 'meta_value_num';
2433 $view_order = 'views';
2434 } else {
2435 $view_order = '';
2436 }
2437
2438 if ( $source == 'post_type' ) {
2439 $posts_source = 'all_posts';
2440 }
2441
2442 if ( $posts_source == 'all_posts' ) {
2443
2444 $query = 'post_type=Post&post_status=publish&ignore_sticky_posts=1&orderby=' . $orderby . '&order=' . $order . '';
2445
2446 // CUSTOM POST TYPE
2447 if ( $source == 'post_type' ) {
2448 $query .= '&post_type=' . $posts_type . '';
2449 }
2450
2451 if ( $view_order == 'views' ) {
2452 $query .= '&meta_key=wpb_post_views_count';
2453 }
2454
2455 // CATEGORIES POST TYPE
2456 if ( $categories_post_type != '' && ! empty( $categories_post_type ) && $source == 'post_type' ) {
2457 $taxonomy_names = get_object_taxonomies( $posts_type );
2458 $query .= '&' . $taxonomy_names[0] . '=' . $categories_post_type . '';
2459 }
2460
2461 // CATEGORIES POSTS
2462 if ( $categories != '' && $categories != 'all' && ! empty( $categories ) && $source == 'wp_posts' ) {
2463 $query .= '&category_name=' . $categories . '';
2464 }
2465
2466 if ( $pagination == 'yes' || $pagination == 'load-more' ) {
2467 $query .= '&posts_per_page=' . $num_posts_page . '';
2468 } else {
2469 if ( $num_posts == '' ) {
2470 $num_posts = '-1';
2471 }
2472 $query .= '&posts_per_page=' . $num_posts . '';
2473 }
2474
2475 // PAGINATION
2476 if ( $pagination == 'yes' || $pagination == 'load-more' ) {
2477 if ( get_query_var( 'paged' ) ) {
2478 $paged = get_query_var( 'paged' );
2479 } elseif ( get_query_var( 'page' ) ) {
2480 $paged = get_query_var( 'page' );
2481 } else {
2482 $paged = 1;
2483 }
2484 $query .= '&paged=' . $paged . '';
2485 }
2486 // #PAGINATION
2487
2488 } else { // IF STICKY
2489
2490 if ( $pagination == 'yes' || $pagination == 'load-more' ) {
2491 $num_posts = $num_posts_page;
2492 } else {
2493 if ( $num_posts == '' ) {
2494 $num_posts = '-1';
2495 }
2496 $num_posts = $num_posts;
2497 }
2498
2499 // PAGINATION
2500
2501 if ( get_query_var( 'paged' ) ) {
2502 $paged = get_query_var( 'paged' );
2503 } elseif ( get_query_var( 'page' ) ) {
2504 $paged = get_query_var( 'page' );
2505 } else {
2506 $paged = 1;
2507 }
2508
2509 // #PAGINATION
2510
2511 /* STICKY POST DA FARE ARRAY PER SCRITTURA IN ARRAY */
2512
2513 $sticky = get_option( 'sticky_posts' );
2514 $sticky = array_slice( $sticky, 0, 5 );
2515 if ( $view_order == 'views' ) {
2516 $query = array(
2517 'post_type' => 'post',
2518 'post_status' => 'publish',
2519 'orderby' => $orderby,
2520 'order' => $order,
2521 'category_name' => $categories,
2522 'posts_per_page' => $num_posts,
2523 'meta_key' => 'wpb_post_views_count',
2524 'paged' => $paged,
2525 'post__in' => $sticky,
2526 'ignore_sticky_posts' => 1,
2527 );
2528 } else {
2529 $query = array(
2530 'post_type' => 'post',
2531 'post_status' => 'publish',
2532 'orderby' => $orderby,
2533 'order' => $order,
2534 'category_name' => $categories,
2535 'posts_per_page' => $num_posts,
2536 'paged' => $paged,
2537 'post__in' => $sticky,
2538 'ignore_sticky_posts' => 1,
2539 );
2540 }
2541 } // #all_posts
2542
2543 return $query;
2544 }
2545
2546
2547 /** Get Category **/
2548 public static function jltma_get_category( $source, $posts_type, $css_link, $limit = 1 ) {
2549 $separator = ' ';
2550 $output = '';
2551 $count = 1;
2552 if ( $source == 'wp_posts' ) {
2553 $categories = get_the_category();
2554 if ( $categories ) {
2555 foreach ( $categories as $category ) {
2556 $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 );
2557 if ( $count == $limit ) {
2558 break;
2559 }
2560 ++$count;
2561 }
2562 }
2563 } elseif ( $source == 'post_type' ) {
2564 global $post;
2565 $taxonomy_names = get_object_taxonomies( $posts_type );
2566 $term_list = wp_get_post_terms( $post->ID, $taxonomy_names );
2567 if ( $term_list ) {
2568 foreach ( $term_list as $tax_term ) {
2569 /* translators: %s: Taxonomy term name. */
2570 $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 );
2571 }
2572 }
2573 }
2574 $return = trim( $output, $separator );
2575 return $return;
2576 }
2577
2578
2579 /** Get Author **/
2580 public static function jltma_get_author( $css_link ) {
2581 $return = '<a href="' . get_author_posts_url( get_the_author_meta( 'ID' ) ) . '" ' . $css_link . '>' . get_the_author_meta( 'display_name' ) . '</a>';
2582 return $return;
2583 }
2584
2585 /** Get Blog Exceprt */
2586 public static function jltma_get_blogs_excerpt( $excerpt = 'default', $readmore = 'on', $css_link = '' ) {
2587 global $post;
2588 if ( $excerpt == 'default' ) :
2589 $return = get_the_excerpt();
2590 else :
2591 $return = substr( get_the_excerpt(), 0, $excerpt );
2592 if ( $readmore == 'on' ) :
2593 $return .= '<a class="article-read-more" href="' . get_permalink( $post->ID ) . '" ' . $css_link . '>' . esc_html__( 'Read More', 'master-addons' ) . '</a>';
2594 else :
2595 $return .= '...';
2596 endif;
2597 endif;
2598 return $return;
2599 }
2600
2601
2602 /** Post Social Share **/
2603 public static function jltma_post_social_share( $css_link ) {
2604
2605 $return = '<div class="container-social">
2606 <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>
2607 <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>
2608 <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>';
2609
2610 return $return;
2611 }
2612
2613 /** Check Post Format **/
2614 public static function jltma_check_post_format() {
2615 global $post;
2616 $format = get_post_format_string( get_post_format() );
2617 if ( $format == 'Video' ) :
2618 $return = '<span class="fpg-format-type fa fa-play-circle-o"></span>';
2619 elseif ( $format == 'Audio' ) :
2620 $return = '<span class="fpg-format-type fa fa-headphones"></span>';
2621 else :
2622 $return = '';
2623 endif;
2624 return $return;
2625 }
2626
2627 /** Get Thumbnails **/
2628 public static function jltma_get_thumb( $thumbs_size = 'thumbnail' ) {
2629 global $post;
2630 $link = get_the_permalink();
2631 if ( has_post_thumbnail() ) {
2632 $id_post = get_the_id();
2633 $single_image = wp_get_attachment_image_src( get_post_thumbnail_id( $id_post ), $thumbs_size );
2634 $return = '<a href="' . esc_url( $link ) . '"><img class="fpg-thumbs" src="' . $single_image[0] . '" alt="' . get_the_title() . '"></a>';
2635 } else {
2636 $return = '';
2637 }
2638 return $return;
2639 }
2640
2641
2642 /** Get Blog Thumbnails **/
2643 public static function jltma_get_blogs_thumb( $columns, $post_id ) {
2644 global $post;
2645 if ( $columns == '1' ) :
2646 $return = self::jltma_get_thumb( 'large' );
2647 elseif ( $columns == '2' ) :
2648 $return = self::jltma_get_thumb( 'medium' );
2649 else :
2650 $return = self::jltma_get_thumb( 'small' );
2651 endif;
2652 return $return;
2653 }
2654
2655 // Get Template Part
2656 public static function jltma_get_template_part( $jltma_template, $jltma_data = array() ) {
2657 extract( $jltma_data );
2658 include JLTMA_PATH . 'inc/post-templates/' . $jltma_template . '.php';
2659 }
2660
2661 // Get Featured Image URL
2662 public static function jltma_get_featured_image_url() {
2663 $featured_image_full_url = wp_get_attachment_image_src( get_post_thumbnail_id(), 'full' );
2664 if ( isset( $featured_image_full_url[0] ) && strlen( $featured_image_full_url[0] ) > 0 ) {
2665 return $featured_image_full_url[0];
2666 } else {
2667 return false;
2668 }
2669 }
2670
2671 // Get Featured Image URL
2672 public static function jltma_excerpt_truncate( $jltma_string, $jltma_length = 80, $jltma_etc = '... ', $jltma_break_words = false, $jltma_middle = false ) {
2673 if ( $jltma_length == 0 ) {
2674 return '';
2675 }
2676
2677 if ( mb_strlen( $jltma_string, 'utf8' ) > $jltma_length ) {
2678 $jltma_length -= mb_strlen( $jltma_etc, 'utf8' );
2679 if ( ! $jltma_break_words && ! $jltma_middle ) {
2680 $jltma_string = preg_replace( '/\s+\S+\s*$/su', '', mb_substr( $jltma_string, 0, $jltma_length + 1, 'utf8' ) );
2681 }
2682 if ( ! $jltma_middle ) {
2683 return mb_substr( $jltma_string, 0, $jltma_length, 'utf8' ) . $jltma_etc;
2684 } else {
2685 return mb_substr( $jltma_string, 0, $jltma_length / 2, 'utf8' ) . $jltma_etc . mb_substr( $jltma_string, -$jltma_length / 2, utf8 );
2686 }
2687 } else {
2688 return $jltma_string;
2689 }
2690 }
2691
2692
2693 public static function jltma_pro_notice_html( $args = array() ) {
2694
2695 $defaults = array(
2696 'show_icon' => true,
2697 'show_heading' => true,
2698 );
2699 $args = wp_parse_args( $args, $defaults );
2700
2701 // Get Pro_Upgrade instance to access promo data
2702 $pro_upgrade = new \MasterAddons\Inc\Classes\Pro_Upgrade();
2703
2704 // Check if campaign is active, otherwise use fallback
2705 if ( 'FALSE' === $pro_upgrade->get_content( 'is_campaign' ) ) {
2706 $notice = 'Use "SPECIAL40" to Get Flat 40% OFF';
2707 $btn_url = 'https://master-addons.com/pricing/';
2708 $btn_text = 'GET THE DEAL';
2709 } else {
2710 $notice = $pro_upgrade->get_content( 'notice' );
2711 $btn_url = $pro_upgrade->get_content( 'button_url' );
2712 $btn_text = $pro_upgrade->get_content( 'button_text' );
2713 }
2714
2715 $end_date = $pro_upgrade->counter_date();
2716
2717 ob_start();
2718 ?>
2719 <div class="jltma-upgrade-banner" id="jltma-upgrade-banner">
2720 <div class="jltma-upgrade-banner-content">
2721 <?php if ( $args['show_icon'] ) : ?>
2722 <!-- Crown Icon with Speech Bubble Tail -->
2723 <div class="jltma-upgrade-banner-icon-wrapper">
2724 <div class="jltma-upgrade-banner-icon">
2725 <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
2726 <path d="M6 30V26L3 12L12 18L20 8L28 18L37 12L34 26V30H6Z" fill="white"/>
2727 <circle cx="20" cy="22" r="2.5" fill="#6814cd"/>
2728 </svg>
2729 </div>
2730 </div>
2731 <?php endif; ?>
2732
2733 <?php if ( $args['show_heading'] ) : ?>
2734 <!-- Main Heading -->
2735 <h2 class="jltma-upgrade-banner-title"><?php echo esc_html__( 'Upgrade to unlock every powerful feature and faster performance', 'master-addons' ); ?></h2>
2736 <?php endif; ?>
2737
2738 <!-- Countdown Timer -->
2739 <div class="jltma-popup-countdown" style="display: none;">
2740 <?php if ( ! empty( $notice ) ) { ?>
2741 <span data-counter="notice" style="color:#F4B740; font-size:14px; padding-bottom:20px; font-style:italic;">
2742 <?php echo esc_html__( 'Notice:', 'master-addons' ); ?> <?php echo esc_html( $notice ); ?>
2743 </span>
2744 <?php } ?>
2745 <span class="jltma-popup-countdown-text"><?php echo esc_html__( 'Offer Ends In', 'master-addons' ); ?></span>
2746 <div class="jltma-popup-countdown-time">
2747 <div>
2748 <span data-counter="days">00</span>
2749 <span><?php echo esc_html__( 'Days', 'master-addons' ); ?></span>
2750 </div>
2751 <span>:</span>
2752 <div>
2753 <span data-counter="hours">00</span>
2754 <span><?php echo esc_html__( 'Hours', 'master-addons' ); ?></span>
2755 </div>
2756 <span>:</span>
2757 <div>
2758 <span data-counter="minutes">00</span>
2759 <span><?php echo esc_html__( 'Minutes', 'master-addons' ); ?></span>
2760 </div>
2761 <span>:</span>
2762 <div>
2763 <span data-counter="seconds">00</span>
2764 <span><?php echo esc_html__( 'Seconds', 'master-addons' ); ?></span>
2765 </div>
2766 </div>
2767 </div>
2768
2769 <!-- Upgrade Button -->
2770 <a class="jltma-upgrade-banner-button" target="_blank" href="https://master-addons.com/pricing"><?php echo esc_html__( 'Upgrade Now', 'master-addons' ); ?></a>
2771 </div>
2772 </div>
2773
2774 <script>
2775 (function() {
2776 var $container = jQuery('#jltma-upgrade-banner');
2777
2778 // Update Counter
2779 function updateCounter(seconds) {
2780 const $counter = $container.find(".jltma-popup-countdown-time");
2781 const $days = $counter.find("[data-counter='days']");
2782 const $hours = $counter.find("[data-counter='hours']");
2783 const $minutes = $counter.find("[data-counter='minutes']");
2784 const $seconds = $counter.find("[data-counter='seconds']");
2785 const days = Math.floor(seconds / (3600 * 24));
2786 seconds -= days * 3600 * 24;
2787 const hrs = Math.floor(seconds / 3600);
2788 seconds -= hrs * 3600;
2789 const mnts = Math.floor(seconds / 60);
2790 seconds -= mnts * 60;
2791
2792 $days.text(days);
2793 $hours.text(hrs);
2794 $minutes.text(mnts);
2795 $seconds.text(seconds);
2796 }
2797
2798 // initCounter
2799 function initCounter(last_date) {
2800 const countdown = () => {
2801 // system time
2802 const now = new Date().getTime();
2803
2804 // set end time to 11:59:59 PM
2805 const endDate = new Date(last_date);
2806 endDate.setHours(23);
2807 endDate.setMinutes(59);
2808 endDate.setSeconds(59);
2809
2810 const seconds = Math.floor((endDate.getTime() - now) / 1000);
2811
2812 if (seconds < 0) {
2813 return false;
2814 }
2815
2816 updateCounter(seconds);
2817 return true;
2818 }
2819
2820 let result = countdown();
2821
2822 if (result) {
2823 $container.find(".jltma-popup-countdown").show(0);
2824 } else {
2825 $container.find(".jltma-popup-countdown").hide(0);
2826 }
2827
2828 // update counter every 1 second
2829 const counter = setInterval(() => {
2830 const result = countdown();
2831 if (!result) {
2832 clearInterval(counter);
2833 $container.find(".jltma-popup-countdown").hide(0);
2834 }
2835 }, 1000);
2836 }
2837
2838 // Initialize countdown when DOM is ready
2839 jQuery(document).ready(function() {
2840 initCounter('<?php echo esc_attr( $end_date ); ?>');
2841 });
2842 })();
2843 </script>
2844
2845 <?php // Auto-open Elementor sections that contain upgrade banners ?>
2846 <script>
2847 (function(){
2848 if (window.jltmaUpgradeSectionAutoOpen) return;
2849 window.jltmaUpgradeSectionAutoOpen = true;
2850 var panel = document.getElementById("elementor-panel-content-wrapper");
2851 if (!panel) return;
2852 function openUpgradeSections() {
2853 var banners = panel.querySelectorAll(".jltma-upgrade-banner");
2854 banners.forEach(function(banner) {
2855 var section = banner.closest(".elementor-control-type-section");
2856 if (section && !section.classList.contains("elementor-open")) {
2857 section.classList.add("elementor-open");
2858 }
2859 });
2860 }
2861 var observer = new MutationObserver(openUpgradeSections);
2862 observer.observe(panel, {childList: true, subtree: true});
2863 openUpgradeSections();
2864 })();
2865 </script>
2866 <?php
2867
2868 $notice_html = ob_get_clean();
2869 return $notice_html;
2870 }
2871
2872
2873 public static function jltma_premium(){
2874 // Check Freemius license first (most reliable — respects actual license status)
2875 if (function_exists('ma_el_fs')) {
2876 return ma_el_fs()->can_use_premium_code__premium_only();
2877 }
2878
2879 // Fallback: If pro addon plugin is installed (JLTMA_PRO_PATH is defined by pro plugin)
2880 if (defined('JLTMA_PRO_PATH') && is_dir(JLTMA_PRO_PATH . 'premium/')) {
2881 return true;
2882 }
2883
2884 // Fallback: If premium modules directory exists, this is a pro build
2885 if (defined('JLTMA_PRO_EXTENSIONS') && is_dir(JLTMA_PRO_EXTENSIONS)) {
2886 return true;
2887 }
2888
2889 return apply_filters('master_addons/is_premium', false);
2890 }
2891
2892 /**
2893 * Get widget statistics for admin dashboard
2894 * Returns counts for all widgets, core, third party, and active widgets
2895 *
2896 * @return array Statistics array with totals and percentages
2897 */
2898 public static function jltma_get_widget_stats() {
2899 // Get saved settings
2900 $element_settings = \MasterAddons\Inc\Admin\Settings\Settings::get_addons() ?: [];
2901 $extension_settings = \MasterAddons\Inc\Admin\Settings\Settings::get_extensions() ?: [];
2902
2903 // Initialize counters
2904 $core_widgets = [];
2905 $third_party_widgets = [];
2906
2907 // Use unified config to get all addons
2908 $addons = \MasterAddons\Inc\Admin\Config::get_addons();
2909 foreach ($addons as $key => $addon) {
2910 $core_widgets[] = [
2911 'key' => $key,
2912 'type' => 'element'
2913 ];
2914 }
2915
2916 // Get all extensions
2917 $extensions = \MasterAddons\Inc\Admin\Config::get_extensions();
2918 foreach ($extensions as $key => $extension) {
2919 $core_widgets[] = [
2920 'key' => $key,
2921 'type' => 'extension'
2922 ];
2923 }
2924
2925 // Get third party plugins
2926 $plugins = \MasterAddons\Inc\Admin\Config::get_plugins();
2927 foreach ($plugins as $key => $plugin) {
2928 $third_party_widgets[] = [
2929 'key' => $key,
2930 'type' => 'third_party'
2931 ];
2932 }
2933
2934 // Calculate active counts
2935 $core_active = 0;
2936 $core_total = count($core_widgets);
2937 foreach ($core_widgets as $widget) {
2938 $settings = ($widget['type'] === 'extension') ? $extension_settings : $element_settings;
2939 if (isset($settings[$widget['key']]) && $settings[$widget['key']] == 1) {
2940 $core_active++;
2941 }
2942 }
2943
2944 $third_party_active = 0;
2945 $third_party_total = count($third_party_widgets);
2946 // Third party plugins don't have the same active/inactive mechanism
2947
2948 // Calculate totals
2949 $all_total = $core_total + $third_party_total;
2950 $all_active = $core_active + $third_party_active;
2951
2952 return [
2953 'all' => [
2954 'total' => $all_total,
2955 'active' => $all_active,
2956 'inactive' => $all_total - $all_active,
2957 'percentage' => $all_total > 0 ? round(($all_active / $all_total) * 100) : 0
2958 ],
2959 'core' => [
2960 'total' => $core_total,
2961 'active' => $core_active,
2962 'inactive' => $core_total - $core_active,
2963 'percentage' => $core_total > 0 ? round(($core_active / $core_total) * 100) : 0
2964 ],
2965 'third_party' => [
2966 'total' => $third_party_total,
2967 'active' => $third_party_active,
2968 'inactive' => $third_party_total - $third_party_active,
2969 'percentage' => $third_party_total > 0 ? round(($third_party_active / $third_party_total) * 100) : 0
2970 ],
2971 'active' => [
2972 'total' => $all_active,
2973 'active' => $all_active,
2974 'inactive' => 0,
2975 'percentage' => 100
2976 ]
2977 ];
2978 }
2979 }
2980