PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 4.4.10
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v4.4.10
4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / Includes / Classes / Helper.php
embedpress / EmbedPress / Includes / Classes Last commit date
Analytics 7 months ago Database 5 months ago Elementor_Enhancer.php 6 months ago EmbedPress_Core_Installer.php 6 years ago EmbedPress_Notice.php 2 years ago EmbedPress_Plugin_Usage_Tracker.php 1 year ago Extend_CustomPlayer_Controls.php 1 year ago Extend_Elementor_Controls.php 1 year ago FeatureNoticeManager.php 8 months ago FeatureNotices.php 8 months ago Feature_Enhancer.php 6 months ago Helper.php 5 months ago PermalinkHelper.php 10 months ago README_FEATURE_NOTICES.md 8 months ago
Helper.php
1742 lines
1 <?php
2
3 namespace EmbedPress\Includes\Classes;
4
5 use EmbedPress\Providers\TemplateLayouts\YoutubeLayout;
6 use EmbedPress\Shortcode;
7
8 use Elementor\Plugin;
9
10
11 if (!defined('ABSPATH')) {
12 exit;
13 } // Exit if accessed directly
14
15 class Helper
16 {
17
18 /**
19 * Parse a query string into an associative array.
20 *
21 * If multiple values are found for the same key, the value of that key
22 * value pair will become an array. This function does not parse nested
23 * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
24 * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
25 *
26 * @param string $str Query string to parse
27 * @param int|bool $urlEncoding How the query string is encoded
28 *
29 * @return array
30 */
31
32 public function __construct()
33 {
34 add_action('wp_ajax_lock_content_form_handler', [$this, 'lock_content_form_handler']);
35 add_action('wp_ajax_nopriv_lock_content_form_handler', [$this, 'lock_content_form_handler']);
36
37 add_action('wp_ajax_embedpress_gutenberg_password_check', [$this, 'gutenberg_password_check']);
38 add_action('wp_ajax_nopriv_embedpress_gutenberg_password_check', [$this, 'gutenberg_password_check']);
39
40
41 add_action('wp_ajax_loadmore_data_handler', [$this, 'loadmore_data_handler']);
42 add_action('wp_ajax_nopriv_loadmore_data_handler', [$this, 'loadmore_data_handler']);
43
44
45 add_action('wp_ajax_fetch_video_description', [$this, 'ajax_video_popup_description']);
46 add_action('wp_ajax_nopriv_fetch_video_description', [$this, 'ajax_video_popup_description']);
47 }
48
49 public function ajax_video_popup_description()
50 {
51 if (isset($_POST['vid'])) {
52 $api_key = self::get_api_key();
53 $vid = sanitize_text_field($_POST['vid']);
54
55 $video_data = Helper::get_youtube_video_data($api_key, $vid);
56
57 if ($video_data) {
58 ob_start();
59 ?>
60 <div class="video-description">
61 <?php echo YoutubeLayout::generate_youtube_video_description($video_data); ?>
62 </div>
63 <?php
64 $description_html = ob_get_clean();
65 wp_send_json_success(['description' => $description_html]);
66 } else {
67 wp_send_json_error(['error' => 'Failed to fetch video data.']);
68 }
69 } else {
70 wp_send_json_error(['error' => 'Invalid video ID.']);
71 }
72 }
73
74 public static function get_api_key()
75 {
76 $settings = (array) get_option(EMBEDPRESS_PLG_NAME . ':youtube', []);
77 return !empty($settings['api_key']) ? $settings['api_key'] : '';
78 }
79
80 public static function parse_query($str, $urlEncoding = true)
81 {
82 $result = [];
83
84 if ($str === '') {
85 return $result;
86 }
87
88 if ($urlEncoding === true) {
89 $decoder = function ($value) {
90 return rawurldecode(str_replace('+', ' ', $value));
91 };
92 } elseif ($urlEncoding === PHP_QUERY_RFC3986) {
93 $decoder = 'rawurldecode';
94 } elseif ($urlEncoding === PHP_QUERY_RFC1738) {
95 $decoder = 'urldecode';
96 } else {
97 $decoder = function ($str) {
98 return $str;
99 };
100 }
101
102 foreach (explode('&', $str) as $kvp) {
103 $parts = explode('=', $kvp, 2);
104 $key = $decoder($parts[0]);
105 $value = isset($parts[1]) ? $decoder($parts[1]) : null;
106 if (!isset($result[$key])) {
107 $result[$key] = $value;
108 } else {
109 if (!is_array($result[$key])) {
110 $result[$key] = [$result[$key]];
111 }
112 $result[$key][] = $value;
113 }
114 }
115
116 return $result;
117 }
118 public static function get_pdf_renderer()
119 {
120 // $renderer = EMBEDPRESS_URL_ASSETS. 'pdf/web/viewer.html';
121
122 $renderer = admin_url('admin-ajax.php?action=get_viewer');
123
124 // @TODO; apply settings query args here
125 return $renderer;
126 }
127
128 public static function get_flipbook_renderer()
129 {
130 $renderer = admin_url('admin-ajax.php?action=get_flipbook_viewer');
131 return $renderer;
132 }
133
134 public static function get_extension_from_file_url($url)
135 {
136 $urlSplit = explode(".", $url);
137 $ext = end($urlSplit);
138 return $ext;
139 }
140
141
142 public static function is_instagram_feed($url)
143 {
144 return (bool) preg_match('~(?:https?://)?(?:www\.)?instagram\.com/(?!p/|reel/|tv/|stories/)[^/]+/?$~i', (string) $url);
145 }
146
147 public static function is_file_url($url)
148 {
149 $pattern = '/\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/i';
150 return preg_match($pattern, $url) === 1;
151 }
152
153 public static function is_opensea($url)
154 {
155 return strpos($url, "opensea.io") !== false;
156 }
157 public static function is_youtube_channel($url)
158 {
159 return (bool) (preg_match('~(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/)(?:channel\/|c\/|user\/|@)(\w+)~i', (string) $url));
160 }
161
162 public static function is_youtube($url)
163 {
164 return (bool) (preg_match('~(?:https?://)?(?:www\.)?(?:youtube\.com|youtu\.be)/watch\?v=([^&]+)~i', (string) $url));
165 }
166
167 // Saved sources data temporary in wp_options table
168 public static function get_source_data($blockid, $source_url, $source_option_name, $source_temp_option_name)
169 {
170 if (self::is_youtube_channel($source_url)) {
171 $source_name = 'YoutubeChannel';
172 } else if (self::is_youtube($source_url)) {
173 $source_name = 'Youtube';
174 } else if (!empty(self::is_file_url($source_url))) {
175 $source_name = 'document_' . self::get_extension_from_file_url($source_url);
176 } else if (self::is_opensea($source_url)) {
177 $source_name = 'OpenSea';
178 } else if (self::is_instagram_feed($source_url)) {
179 $source_name = 'InstagramFeed';
180 } else {
181 Shortcode::get_embera_instance();
182 $collectios = Shortcode::get_collection();
183 $provider = $collectios->findProviders($source_url);
184
185 if (!empty($provider[$source_url])) {
186 $source_name = $provider[$source_url]->getProviderName();
187 } else {
188 $host = parse_url($source_url, PHP_URL_HOST);
189 if ($host) {
190 $parts = explode('.', $host);
191 if (count($parts) > 1) {
192 $source_name = $parts[1];
193 } else {
194 // Handle the case where the host doesn't have at least two parts
195 $source_name = $host;
196 }
197 } else {
198 // Handle the case where parse_url fails
199 $source_name = 'unknown';
200 }
201 }
202 }
203
204 if (!empty($blockid) && $blockid != 'undefined') {
205 $sources = json_decode(get_option($source_temp_option_name), true);
206
207 if (!$sources) {
208 $sources = array();
209 }
210 $exists = false;
211
212 foreach ($sources as $i => $source) {
213 if ($source['id'] === $blockid) {
214 $sources[$i]['source']['name'] = $source_name;
215 $sources[$i]['source']['url'] = $source_url;
216 $exists = true;
217 break;
218 }
219 }
220
221 if (!$exists) {
222 $sources[] = array('id' => $blockid, 'source' => array('name' => $source_name, 'url' => $source_url, 'count' => 1));
223 }
224
225 update_option($source_temp_option_name, json_encode($sources));
226 }
227 }
228
229 // Saved source data when post updated
230 public static function get_save_source_data_on_post_update($source_option_name, $source_temp_option_name)
231 {
232
233 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
234 return;
235 }
236 $temp_data = json_decode(get_option($source_temp_option_name), true);
237 $source_data = json_decode(get_option($source_option_name), true);
238 if (!$temp_data) {
239 $temp_data = array();
240 }
241 if (!$source_data) {
242 $source_data = array();
243 }
244
245 $sources = array_merge($temp_data, $source_data);
246
247 $unique_sources = array();
248 foreach ($sources as $source) {
249 $unique_sources[$source['id']] = $source;
250 }
251
252 $unique_sources = array_values($unique_sources);
253
254 delete_option($source_temp_option_name);
255
256 update_option($source_option_name, json_encode($unique_sources));
257 }
258
259 //Delete source data from option table when widget is removed
260 public static function get_delete_source_data($blockid, $source_option_name, $source_temp_option_name)
261 {
262 if (!empty($blockid) && $blockid != 'undefined') {
263 $sources = json_decode(get_option($source_option_name), true);
264 $temp_sources = json_decode(get_option($source_temp_option_name), true);
265 if ($sources) {
266 foreach ($sources as $i => $source) {
267 if ($source['id'] === $blockid) {
268 unset($sources[$i]);
269 break;
270 }
271 }
272 update_option($source_option_name, json_encode(array_values($sources)));
273 }
274 if ($temp_sources) {
275 foreach ($temp_sources as $i => $source) {
276 if ($source['id'] === $blockid) {
277 unset($temp_sources[$i]);
278 break;
279 }
280 }
281 update_option($source_temp_option_name, json_encode(array_values($temp_sources)));
282 }
283 }
284 wp_die();
285 }
286
287 //Delete source temporary data when reload without update or publish
288 public static function get_delete_source_temp_data_on_reload($source_temp_option_name)
289 {
290 $source_temp_data = json_decode(get_option($source_temp_option_name), true);
291 if ($source_temp_data) {
292 delete_option($source_temp_option_name);
293 }
294 }
295
296 public static function get_file_title($url)
297 {
298 return get_the_title(attachment_url_to_postid($url));
299 }
300
301 public static function get_hash()
302 {
303 $hash_key = get_option(EMBEDPRESS_PLG_NAME . '_hash_key');
304 if (!$hash_key) {
305 $hash_key = wp_hash_password(wp_generate_password(30));
306 update_option(EMBEDPRESS_PLG_NAME . '_hash_key', $hash_key);
307 }
308 return $hash_key;
309 }
310
311 public function lock_content_form_handler() {
312 // print_r($embedHTML);
313
314 $client_id = isset($_POST['client_id']) ? sanitize_text_field($_POST['client_id']) : '';
315 $password = isset($_POST['password']) ? sanitize_text_field($_POST['password']) : '';
316 $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
317
318 $epbase64 = get_post_meta( $post_id, 'ep_base_' .$client_id, true );
319 $hash_key = get_post_meta( $post_id, 'hash_key_' .$client_id, true );
320
321 // Set the decryption key and initialization vector (IV)
322 $key = Helper::get_hash();
323
324 // Decode the base64 encoded cipher
325 $cipher = base64_decode($epbase64);
326 // Decrypt the cipher using AES-128-CBC encryption
327
328 $wp_pass_key = hash('sha256', wp_salt(32) . md5($password));
329 $iv = substr($wp_pass_key, 0, 16);
330
331 if ($wp_pass_key === $hash_key) {
332
333 $embed = openssl_decrypt($cipher, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv) . '<script>
334 var now = new Date();
335 var time = now.getTime();
336 var expireTime = time + 1000 * 60 * 60 * 24 * 30;
337 now.setTime(expireTime);
338 document.cookie = "password_correct_'.esc_js($client_id).'='.esc_js($hash_key).'; expires=" + now.toUTCString() + "; path=/";
339 </script>';
340
341 }
342 else{
343 $embed = 0;
344 }
345
346 // Process the form data and return a response
347 $response = array(
348 'success' => true,
349 'password' => $password,
350 'embedHtml' => $embed,
351 'post_id' => $post_id
352 );
353
354 wp_send_json($response);
355
356 }
357
358 public function gutenberg_password_check()
359 {
360 $client_id = isset($_POST['client_id']) ? sanitize_text_field($_POST['client_id']) : '';
361 $password = isset($_POST['password']) ? sanitize_text_field($_POST['password']) : '';
362 $content_password = isset($_POST['content_password']) ? sanitize_text_field($_POST['content_password']) : '';
363
364 // Verify password
365 if ($password === $content_password) {
366 // Set cookie for authentication
367 $hash_pass = hash('sha256', wp_salt(32) . md5($password));
368 setcookie("password_correct_" . $client_id, $hash_pass, time() + 3600, '/');
369
370 $response = array(
371 'success' => true,
372 'message' => 'Password correct'
373 );
374 } else {
375 $response = array(
376 'success' => false,
377 'message' => 'Incorrect password'
378 );
379 }
380
381 wp_send_json($response);
382 }
383
384 public static function display_password_form($client_id = '', $embedHtml = '', $pass_hash_key = '', $attributes = [])
385 {
386 $lock_heading = !empty($attributes['lockHeading']) ? sanitize_text_field($attributes['lockHeading']) : '';
387 $lock_subheading = !empty($attributes['lockSubHeading']) ? sanitize_text_field($attributes['lockSubHeading']) : '';
388 $lock_error_message = !empty($attributes['lockErrorMessage']) ? sanitize_text_field($attributes['lockErrorMessage']) : '';
389 $footer_message = !empty($attributes['footerMessage']) ? sanitize_text_field($attributes['footerMessage']) : '';
390 $password_placeholder = !empty($attributes['passwordPlaceholder']) ? sanitize_text_field($attributes['passwordPlaceholder']) : '';
391 $button_text = !empty($attributes['submitButtonText']) ? sanitize_text_field($attributes['submitButtonText']) : '';
392 $unlocking_text = !empty($attributes['submitUnlockingText']) ? sanitize_text_field($attributes['submitUnlockingText']) : '';
393 $enable_footer_message = !empty($attributes['enableFooterMessage']) ? sanitize_text_field($attributes['enableFooterMessage']) : '';
394
395
396 // Set the encryption key and initialization vector (IV)
397 $key = self::get_hash();
398
399 $salt = wp_salt(32);
400 $wp_hash_key = hash('sha256', $salt . $pass_hash_key);
401 $iv = substr($wp_hash_key, 0, 16);
402
403
404 // Encrypt the plaintext using AES-128-CBC encryption
405 $cipher = openssl_encrypt($embedHtml, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
406
407 // Base64 encode the encrypted cipher
408 $encrypted_data = base64_encode($cipher);
409
410 update_post_meta(get_the_ID(), 'ep_base_' . $client_id, $encrypted_data);
411 update_post_meta(get_the_ID(), 'hash_key_' . $client_id, $wp_hash_key);
412
413 $lock_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><g fill="#6354a5" class="color134563 svgShape"><path d="M46.3 28.7h-3v-6.4C43.3 16.1 38.2 11 32 11c-6.2 0-11.3 5.1-11.3 11.3v6.4h-3v-6.4C17.7 14.4 24.1 8 32 8s14.3 6.4 14.3 14.3v6.4" fill="#6354a5" class="color000000 svgShape"></path><path d="M44.8 55.9H19.2c-2.6 0-4.8-2.2-4.8-4.8V31.9c0-2.6 2.2-4.8 4.8-4.8h25.6c2.6 0 4.8 2.2 4.8 4.8v19.2c0 2.7-2.2 4.8-4.8 4.8zM19.2 30.3c-.9 0-1.6.7-1.6 1.6v19.2c0 .9.7 1.6 1.6 1.6h25.6c.9 0 1.6-.7 1.6-1.6V31.9c0-.9-.7-1.6-1.6-1.6H19.2z" fill="#6354a5" class="color000000 svgShape"></path><path d="M35.2 36.7c0 1.8-1.4 3.2-3.2 3.2s-3.2-1.4-3.2-3.2 1.4-3.2 3.2-3.2 3.2 1.5 3.2 3.2" fill="#6354a5" class="color000000 svgShape"></path><path d="M32.8 36.7h-1.6l-1.6 9.6h4.8l-1.6-9.6" fill="#6354a5" class="color000000 svgShape"></path></g></svg>';
414
415 echo '
416 <div class="password-form-container sd">
417 <h2>' . esc_html($lock_heading) . '</h2>
418 <p>' . esc_html($lock_subheading) . ' </p>
419 <form class="password-form" method="post" class="password-form" data-unlocking-text="' . esc_attr($unlocking_text) . '">
420
421 <div class="password-field">
422 <span class="lock-icon">' . $lock_icon . '</span>
423 <input type="password" name="pass_' . esc_attr($client_id) . '" placeholder="' . esc_attr($password_placeholder) . '" required>
424 </div>
425 <input type="hidden" name="ep_client_id" value="' . esc_attr($client_id) . '">
426 <input type="hidden" name="post_id" value="' . esc_attr(get_the_ID()) . '">
427
428 <input type="submit" name="password_submit" value="' . esc_attr($button_text) . '">
429 <div class="error-message hidden">' . esc_html($lock_error_message) . '</div>
430 </form>
431 ' . (!empty($enable_footer_message) ? '<p class="need-access-message">' . esc_html($footer_message) . '</p>' : '') . '
432 </div>
433 ';
434 }
435
436 // Check if the user has already entered the correct password
437 public static function is_password_correct($client_id)
438 {
439 if (isset($_COOKIE['password_correct_' . $client_id])) {
440 return $_COOKIE['password_correct_' . $client_id];
441 } else {
442 return false;
443 }
444 }
445
446 public static function customLogo($embedHTML, $atts)
447 {
448 $x = !empty($atts['logoX']) ? $atts['logoX'] : 0;
449 $y = !empty($atts['logoY']) ? $atts['logoY'] : 0;
450 $uniqid = !empty($atts['url']) ? '.ose-uid-' . md5($atts['url']) : '';
451
452 $brandUrl = !empty($atts['customlogoUrl']) ? $atts['customlogoUrl'] : '';
453 $opacity = !empty($atts['logoOpacity']) ? $atts['logoOpacity'] : '';
454
455 $cssClass = !empty($atts['url']) ? '.ose-uid-' . md5($atts['url']) : '.ose-youtube';
456
457
458
459 ob_start(); ?>
460 <style type="text/css">
461 <?php echo esc_html($cssClass); ?> {
462 position: relative;
463 }
464
465 <?php echo esc_html($cssClass); ?>.watermark {
466 border: 0;
467 position: absolute;
468 bottom: <?php echo esc_html($y); ?>%;
469 right: <?php echo esc_html($x); ?>%;
470 max-width: 150px;
471 max-height: 75px;
472 opacity: 0.25;
473 z-index: 5;
474 -o-transition: opacity 0.5s ease-in-out;
475 -moz-transition: opacity 0.5s ease-in-out;
476 -webkit-transition: opacity 0.5s ease-in-out;
477 transition: opacity 0.5s ease-in-out;
478 opacity: <?php echo esc_html($opacity); ?>;
479 }
480
481 <?php echo esc_html($cssClass); ?>.watermark:hover {
482 opacity: 1;
483 }
484 </style>
485 <?php
486
487
488 $style = ob_get_clean();
489
490 if (!class_exists('\simple_html_dom')) {
491 include_once EMBEDPRESS_PATH_CORE . 'simple_html_dom.php';
492 }
493
494 $cta = '';
495 $img = '';
496
497 if (!empty($atts['customlogo'])) {
498 $img = '<img src="' . esc_url($atts['customlogo']) . '"/>';
499
500 $imgDom = str_get_html($img);
501 $imgDom = $imgDom->find('img', 0);
502 $imgDom->setAttribute('class', 'watermark ep-custom-logo');
503 $imgDom->removeAttribute('style');
504 $imgDom->setAttribute('width', 'auto');
505 $imgDom->setAttribute('height', 'auto');
506 ob_start();
507 echo $imgDom;
508
509 $cta .= ob_get_clean();
510
511 $imgDom->clear();
512 unset($img, $imgDom);
513
514 if (!empty($brandUrl)) {
515 $cta = '<a href="' . esc_url($brandUrl) . '" target="_blank">' . $cta . '</a>';
516 }
517 $dom = str_get_html($embedHTML);
518
519 $wrapDiv = $dom->find($uniqid, 0);
520
521 if (!empty($wrapDiv) && is_object($wrapDiv)) {
522 $wrapDiv->innertext .= $cta;
523 }
524
525 ob_start();
526 echo $wrapDiv;
527
528 $markup = ob_get_clean();
529
530 $dom->clear();
531 unset($dom, $wrapDiv);
532
533 $embedHTML = $style . $markup;
534 }
535
536 return $embedHTML;
537 }
538
539
540 public static function embed_content_share($content_id = '', $attributes = [])
541 {
542 $share_position = !empty($attributes['sharePosition']) ? $attributes['sharePosition'] : 'right';
543 $custom_thumnail = !empty($attributes['customThumbnail']) ? $attributes['customThumbnail'] : '';
544 $custom_title = !empty($attributes['customTitle']) ? $attributes['customTitle'] : '';
545 $custom_description = !empty($attributes['customDescription']) ? $attributes['customDescription'] : '';
546
547 // Create a unique hash based on content attributes
548 $content_hash = md5($custom_thumnail . $custom_title . $custom_description . $content_id);
549
550 // Encode for URL usage
551 $custom_thumnail = urlencode($custom_thumnail);
552 $custom_title = urlencode($custom_title);
553 $custom_description = urlencode($custom_description);
554
555 // Get social share options with defaults
556 $facebook_enabled = isset($attributes['shareFacebook']) ? $attributes['shareFacebook'] !== false : true;
557 $twitter_enabled = isset($attributes['shareTwitter']) ? $attributes['shareTwitter'] !== false : true;
558 $pinterest_enabled = isset($attributes['sharePinterest']) ? $attributes['sharePinterest'] !== false : true;
559 $linkedin_enabled = isset($attributes['shareLinkedin']) ? $attributes['shareLinkedin'] !== false : true;
560 $style = isset($attributes['width']) ? 'style="max-width: ' . esc_attr($attributes['width']) . 'px;"' : '';
561
562
563 $page_url = urlencode(get_permalink() . '?hash=' . $content_id . '&unique=' . $content_hash);
564
565 $social_icons = '<div class="ep-social-share-wraper"' . $style . ' ><div class="ep-social-share share-position-' . esc_attr($share_position) . '">';
566
567
568 // Facebook
569 if ($facebook_enabled) {
570 $social_icons .= '<a href="https://www.facebook.com/sharer/sharer.php?u=' . $page_url . '" class="ep-social-icon facebook" target="_blank">
571 <svg width="64px" height="64px" fill="#000000" viewBox="0 -6 512 512" xmlns="http://www.w3.org/2000/svg">
572 <path d="M0 0h512v500H0z" fill="#475a96"/>
573 <path d="m375.72 112.55h-237.43c-8.137 0-14.73 6.594-14.73 14.73v237.43c0 8.135 6.594 14.73 14.73 14.73h127.83v-103.36h-34.781v-40.28h34.781v-29.705c0-34.473 21.055-53.244 51.807-53.244 14.73 0 27.391 1.097 31.08 1.587v36.026l-21.328 0.01c-16.725 0-19.963 7.947-19.963 19.609v25.717h39.887l-5.193 40.28h-34.693v103.36h68.012c8.135 0 14.73-6.596 14.73-14.73v-237.43c-1e-3 -8.137-6.596-14.73-14.731-14.73z" fill="#fff"/>
574 </svg>
575 </a>';
576 }
577
578 // Twitter
579 if ($twitter_enabled) {
580 $social_icons .= '<a href="https://twitter.com/intent/tweet?url=' . $page_url . '&text=' . $custom_title . '" class="ep-social-icon twitter" target="_blank">
581 <svg viewBox="0 0 24 24" aria-hidden="true" fill="#fff" class="r-4qtqp9 r-yyyyoo r-dnmrzs r-bnwqim r-lrvibr r-m6rgpd r-lrsllp r-1nao33i r-16y2uox r-8kz0gk"><g><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path></g></svg>
582 </a>';
583 }
584
585 // Pinterest
586 if ($pinterest_enabled) {
587 $social_icons .= '<a href="http://pinterest.com/pin/create/button/?url=' . $page_url . '&media=' . $custom_thumnail . '&description=' . $custom_description . '" class="ep-social-icon pinterest" target="_blank">
588
589 <svg xmlns="http://www.w3.org/2000/svg" height="800" width="1200" viewBox="-36.42015 -60.8 315.6413 364.8"><path d="M121.5 0C54.4 0 0 54.4 0 121.5 0 173 32 217 77.2 234.7c-1.1-9.6-2-24.4.4-34.9 2.2-9.5 14.2-60.4 14.2-60.4s-3.6-7.3-3.6-18c0-16.9 9.8-29.5 22-29.5 10.4 0 15.4 7.8 15.4 17.1 0 10.4-6.6 26-10.1 40.5-2.9 12.1 6.1 22 18 22 21.6 0 38.2-22.8 38.2-55.6 0-29.1-20.9-49.4-50.8-49.4-34.6 0-54.9 25.9-54.9 52.7 0 10.4 4 21.6 9 27.7 1 1.2 1.1 2.3.8 3.5-.9 3.8-3 12.1-3.4 13.8-.5 2.2-1.8 2.7-4.1 1.6-15.2-7.1-24.7-29.2-24.7-47.1 0-38.3 27.8-73.5 80.3-73.5 42.1 0 74.9 30 74.9 70.2 0 41.9-26.4 75.6-63 75.6-12.3 0-23.9-6.4-27.8-14 0 0-6.1 23.2-7.6 28.9-2.7 10.6-10.1 23.8-15.1 31.9 11.4 3.5 23.4 5.4 36 5.4 67.1 0 121.5-54.4 121.5-121.5C243 54.4 188.6 0 121.5 0z" fill="#fff"/></svg>
590
591 </a>';
592 }
593
594 // LinkedIn
595 if ($linkedin_enabled) {
596 $social_icons .= '<a href="https://www.linkedin.com/shareArticle?mini=true&url=' . $page_url . '" class="ep-social-icon linkedin" target="_blank">
597
598 <svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
599 viewBox="0 0 310 310" xml:space="preserve">
600 <g id="XMLID_801_">
601 <path id="XMLID_802_" d="M72.16,99.73H9.927c-2.762,0-5,2.239-5,5v199.928c0,2.762,2.238,5,5,5H72.16c2.762,0,5-2.238,5-5V104.73
602 C77.16,101.969,74.922,99.73,72.16,99.73z"/>
603 <path id="XMLID_803_" d="M41.066,0.341C18.422,0.341,0,18.743,0,41.362C0,63.991,18.422,82.4,41.066,82.4
604 c22.626,0,41.033-18.41,41.033-41.038C82.1,18.743,63.692,0.341,41.066,0.341z"/>
605 <path id="XMLID_804_" d="M230.454,94.761c-24.995,0-43.472,10.745-54.679,22.954V104.73c0-2.761-2.238-5-5-5h-59.599
606 c-2.762,0-5,2.239-5,5v199.928c0,2.762,2.238,5,5,5h62.097c2.762,0,5-2.238,5-5v-98.918c0-33.333,9.054-46.319,32.29-46.319
607 c25.306,0,27.317,20.818,27.317,48.034v97.204c0,2.762,2.238,5,5,5H305c2.762,0,5-2.238,5-5V194.995
608 C310,145.43,300.549,94.761,230.454,94.761z"/>
609 </g>
610 </svg>
611 </a>';
612 }
613
614 $social_icons .= '</div></div>';
615
616 return $social_icons;
617 }
618
619 public static function ep_get_elementor_widget_settings($page_settings = '', $id = '', $widgetType = '')
620 {
621 if (empty($page_settings)) {
622 return [];
623 }
624
625 // Handle both string and array cases for elementor data
626 if (is_string($page_settings)) {
627 $data = json_decode($page_settings, true);
628 } else {
629 // Data might already be an array in older versions
630 $data = $page_settings;
631 }
632 $element_setting = null;
633
634 Plugin::$instance->db->iterate_data($data, function ($element) use (&$element_setting, $widgetType, $id) {
635
636 if ($element['id'] == $id && $element['elType'] == 'widget' && $element['widgetType'] == $widgetType) {
637 $element_setting[] = $element['settings'];
638 }
639 });
640
641 return $element_setting;
642 }
643
644
645
646 public static function ep_get_popup_icon()
647 {
648 $svg = '<div class="ep-doc-popup-icon" ><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" xml:space="preserve"><path fill="#fff" d="M5 3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-6l-2-2v8H5V5h8l-2-2H5zm9 0 2.7 2.7-7.5 7.5 1.7 1.7 7.5-7.5L21 10V3h-7z"/><path style="fill:none" d="M0 0h24v24H0z"/></svg></div>';
649
650 return $svg;
651 }
652 public static function ep_get_download_icon()
653 {
654 $svg = '<div class="ep-doc-download-icon" ><svg width="25" height="25" viewBox="0 0 0.6 0.6" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" fill-rule="evenodd" d="M.525.4A.025.025 0 0 1 .55.422v.053A.075.075 0 0 1 .479.55H.125A.075.075 0 0 1 .05.479V.425A.025.025 0 0 1 .1.422v.053A.025.025 0 0 0 .122.5h.353A.025.025 0 0 0 .5.478V.425A.025.025 0 0 1 .525.4ZM.3.05a.025.025 0 0 1 .025.025v.24L.357.283A.025.025 0 0 1 .39.281l.002.002a.025.025 0 0 1 .002.033L.392.318.317.393.316.394.314.395.311.397.308.398.305.399.301.4H.295L.292.399.289.398.287.397.285.395A.025.025 0 0 1 .283.393L.208.318A.025.025 0 0 1 .241.281l.002.002.032.032v-.24A.025.025 0 0 1 .3.05Z"/></svg></div>';
655
656 return $svg;
657 }
658
659 public static function ep_get_print_icon()
660 {
661 $svg = '<div class="ep-doc-print-icon" ><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24">
662 <path d="M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z" fill="#fff"/>
663 </svg></div>';
664
665 return $svg;
666 }
667
668 public static function ep_get_fullscreen_icon()
669 {
670 $svg = '<div class="ep-doc-fullscreen-icon"><svg width="25" height="25" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
671 <path d="m3 15 .117.007a1 1 0 0 1 .876.876L4 16v4h4l.117.007a1 1 0 0 1 0 1.986L8 22H3l-.117-.007a1 1 0 0 1-.876-.876L2 21v-5l.007-.117a1 1 0 0 1 .876-.876L3 15Zm18 0a1 1 0 0 1 .993.883L22 16v5a1 1 0 0 1-.883.993L21 22h-5a1 1 0 0 1-.117-1.993L16 20h4v-4a1 1 0 0 1 .883-.993L21 15ZM8 2a1 1 0 0 1 .117 1.993L8 4H4v4a1 1 0 0 1-.883.993L3 9a1 1 0 0 1-.993-.883L2 8V3a1 1 0 0 1 .883-.993L3 2h5Zm13 0 .117.007a1 1 0 0 1 .876.876L22 3v5l-.007.117a1 1 0 0 1-.876.876L21 9l-.117-.007a1 1 0 0 1-.876-.876L20 8V4h-4l-.117-.007a1 1 0 0 1 0-1.986L16 2h5Z" fill="#fff"/>
672 </svg></div>';
673
674 return $svg;
675 }
676 public static function ep_get_minimize_icon()
677 {
678 $svg = '<div class="ep-doc-minimize-icon" style="display:none"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" style="enable-background:new 0 0 385.331 385.331" xml:space="preserve" width="20" height="20"><path fill="#fff" d="M13.751 8.131h5.62c0.355 0 0.619 -0.28 0.619 -0.634 0 -0.355 -0.265 -0.615 -0.619 -0.614h-4.995V1.878c0 -0.355 -0.27 -0.624 -0.624 -0.624s-0.624 0.27 -0.624 0.624v5.62c0 0.002 0.001 0.003 0.001 0.004 0 0.002 -0.001 0.003 -0.001 0.005 0 0.348 0.276 0.625 0.624 0.624zM6.244 1.259c-0.354 0 -0.614 0.265 -0.614 0.619v4.995H0.624c-0.355 0 -0.624 0.27 -0.624 0.624 0 0.355 0.27 0.624 0.624 0.624h5.62c0.002 0 0.003 -0.001 0.004 -0.001 0.002 0 0.003 0.001 0.005 0.001 0.348 0 0.624 -0.276 0.624 -0.624V1.878c0 -0.354 -0.28 -0.619 -0.634 -0.619zm0.005 10.61H0.629c-0.355 0.001 -0.619 0.28 -0.619 0.634 0 0.355 0.265 0.615 0.619 0.614h4.995v5.005c0 0.355 0.27 0.624 0.624 0.624 0.355 0 0.624 -0.27 0.624 -0.624V12.502c0 -0.002 -0.001 -0.003 -0.001 -0.004 0 -0.002 0.001 -0.003 0.001 -0.005 0 -0.348 -0.276 -0.624 -0.624 -0.624zm13.127 0H13.756c-0.002 0 -0.003 0.001 -0.004 0.001 -0.002 0 -0.003 -0.001 -0.005 -0.001 -0.348 0 -0.624 0.276 -0.624 0.624v5.62c0 0.355 0.28 0.619 0.634 0.619 0.354 0.001 0.614 -0.265 0.614 -0.619v-4.995H19.376c0.355 0 0.624 -0.27 0.624 -0.624s-0.27 -0.624 -0.624 -0.625z"/><g/><g/><g/><g/><g/><g/></svg></div>';
679
680 return $svg;
681 }
682 public static function ep_get_draw_icon()
683 {
684 $svg = '<div class="ep-doc-draw-icon"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="m15 7.5 2.5 2.5m-10 10L19.25 8.25c0.69 -0.69 0.69 -1.81 0 -2.5v0c-0.69 -0.69 -1.81 -0.69 -2.5 0L5 17.5V20h2.5Zm0 0h8.379C17.05 20 18 19.05 18 17.879v0c0 -0.563 -0.224 -1.103 -0.621 -1.5L17 16M4.5 5c2 -2 5.5 -1 5.5 1 0 2.5 -6 2.5 -6 5 0 0.876 0.533 1.526 1.226 2" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>';
685
686 return $svg;
687 }
688
689 public static function get_insta_video_icon()
690 {
691 $svg = '<svg class="insta-video-icon" aria-label="Clip" class="x1lliihq x1n2onr6" color="#FFF" fill="#FFF" height="20" viewBox="1.111 1.111 24.444 24.447" width="20">
692 <path d="m14.248 1.111 3.304 5.558h-6.2L8.408 1.146c.229-.014.466-.024.713-.03l.379-.005Zm2.586 0h.331c3.4 0 4.964.838 6.267 2.097a6.674 6.674 0 0 1 1.773 3.133l.078.328H20.14l-3.307-5.558ZM6.093 1.53l2.74 5.139H1.382a6.678 6.678 0 0 1 4.38-5.033ZM16.91 15.79l-5.05-2.916a1.01 1.01 0 0 0-1.507.742l-.009.133v5.831a1.011 1.011 0 0 0 1.394.933l.121-.059 5.05-2.916a1.01 1.01 0 0 0 .111-1.674l-.111-.076-5.05-2.916ZM1.132 8.891h24.404l.017.4.003.21v7.666c0 3.401-.839 4.966-2.098 6.267-1.279 1.238-2.778 2.062-5.922 2.121l-.371.003H9.501c-3.4 0-4.963-.839-6.267-2.099-1.238-1.278-2.06-2.776-2.12-5.922l-.003-.37V9.501l.003-.21Z" fill-rule="evenodd" /></svg>';
693
694 return $svg;
695 }
696
697 public static function get_insta_image_carousel_icon()
698 {
699 $svg = '<svg aria-label="Carousel" class="x1lliihq x1n2onr6" color="#FFF" fill="#FFF" height="25" viewBox="0 0 43.636 43.636" width="25">
700 <path d="M31.636 27V10a4.695 4.695 0 0 0-4.727-4.727H10A4.695 4.695 0 0 0 5.273 10v17A4.695 4.695 0 0 0 10 31.727h17c2.545-.091 4.636-2.182 4.636-4.727zm4-13.364v14.636c0 4.091-3.364 7.455-7.455 7.455H13.545c-.545 0-.818.636-.455 1 .909 1 2.182 1.636 3.727 1.636h12.182a9.35 9.35 0 0 0 9.364-9.364V16.818a5.076 5.076 0 0 0-1.636-3.727c-.455-.364-1.091 0-1.091.545z" /></svg>';
701
702 return $svg;
703 }
704
705 public static function get_insta_image_icon()
706 {
707 $svg = '<svg width="22" height="22" viewBox="0 0 0.6 0.6" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M.175.05A.125.125 0 0 0 .05.175v.25A.125.125 0 0 0 .175.55h.25A.125.125 0 0 0 .55.425v-.25A.125.125 0 0 0 .425.05h-.25ZM.2.225a.025.025 0 1 1 .05 0 .025.025 0 0 1-.05 0ZM.225.15a.075.075 0 1 0 0 .15.075.075 0 0 0 0-.15Zm.138.205A.025.025 0 0 1 .398.351l.048.042A.025.025 0 1 0 .479.355L.43.312a.075.075 0 0 0-.107.011l-.04.05a.024.024 0 0 1-.032.005.074.074 0 0 0-.099.015L.118.432a.025.025 0 0 0 .038.033l.035-.04A.024.024 0 0 1 .223.42.074.074 0 0 0 .322.405l.04-.05Z" fill="#fff"/></svg>';
708
709 return $svg;
710 }
711
712 public static function get_insta_like_icon()
713 {
714 $svg = '<svg version="1.1" id="Uploaded to svgrepo.com" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 0.8 0.8" xml:space="preserve"><path d="M.225.25C.225.264.214.275.2.275S.175.264.175.25.186.225.2.225.225.236.225.25zM.75.3C.75.453.589.582.485.65a1.06 1.06 0 0 1-.073.044.025.025 0 0 1-.024 0A1.049 1.049 0 0 1 .315.65C.211.582.05.453.05.3a.2.2 0 0 1 .2-.2.199.199 0 0 1 .15.068A.199.199 0 0 1 .55.1a.2.2 0 0 1 .2.2zM.25.25a.05.05 0 1 0-.1 0 .05.05 0 0 0 .1 0z" style="fill:#fff"/></svg>';
715
716 return $svg;
717 }
718 public static function get_insta_comment_icon()
719 {
720 $svg = '<svg fill="#fff" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 2.5 2.5" xml:space="preserve"><path d="M2.374.446a.063.063 0 0 0-.061-.057H.991a.063.063 0 0 0-.063.057H.927v.328h.559c.029 0 .053.022.056.051h.001v.731h.275l.162.162a.063.063 0 0 0 .116-.035v-.127h.217a.063.063 0 0 0 .06-.051h.002V.446h-.001z"/><path d="M1.361.899H.18A.056.056 0 0 0 .125.95v.946h.001a.057.057 0 0 0 .054.045h.194v.113a.057.057 0 0 0 .104.032l.145-.145h.738c.027 0 .05-.02.056-.045h.001V.95h-.001a.056.056 0 0 0-.056-.051z"/></svg>';
721
722 return $svg;
723 }
724 public static function get_instagram_icon()
725 {
726 $svg = '<svg version="1.1" id="Icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" xml:space="preserve" width="1285" height="400"><style>.st0{fill:none;stroke:#fff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}</style><path class="st0" d="M14.375 19.375h-8.75c-2.75 0-5-2.25-5-5v-8.75c0-2.75 2.25-5 5-5h8.75c2.75 0 5 2.25 5 5v8.75c0 2.75-2.25 5-5 5z"/><path class="st0" d="M14.375 10A4.375 4.375 0 0 1 10 14.375 4.375 4.375 0 0 1 5.625 10a4.375 4.375 0 0 1 8.75 0zm1.25-5.625A.625.625 0 0 1 15 5a.625.625 0 0 1-.625-.625.625.625 0 0 1 1.25 0z"/></svg>';
727
728 return $svg;
729 }
730
731 public static function get_google_presentation_url($embedded_url)
732 {
733 $parsed_url = parse_url($embedded_url);
734 $base_url = $parsed_url['scheme'] . '://' . $parsed_url['host'] . $parsed_url['path'];
735 $base_url = strtok($base_url, '?');
736 $base_url = rtrim($base_url, '/');
737 return $base_url;
738 }
739
740 public static function check_media_format($url)
741 {
742 $pattern1 = '/\.(mp4|mov|avi|wmv|flv|mkv|webm|mpeg|mpg)$/i';
743 $pattern2 = '/\.(mp3|wav|ogg|aac)$/i';
744
745 $isVideo = preg_match($pattern1, $url);
746 $isAudio = preg_match($pattern2, $url);
747
748 $is_self_hosted = false;
749 $format = '';
750
751 if (!empty($isVideo) || !empty($isAudio)) {
752 $is_self_hosted = true;
753 if (!empty($isVideo)) {
754 $format = 'video';
755 } else if (!empty($isAudio)) {
756 $format = 'audio';
757 }
758 }
759
760 if (!$is_self_hosted) {
761 return [
762 'selhosted' => false,
763 ];
764 }
765
766 return [
767 'selhosted' => true,
768 'format' => $format,
769 ];
770 }
771
772 // Ajax Methods get instagram feed data
773 public function loadmore_data_handler()
774 {
775 $connected_account_type = isset($_POST['connected_account_type']) ? sanitize_text_field($_POST['connected_account_type']) : 'personal';
776 $hashtag_id = isset($_POST['hashtag_id']) ? sanitize_text_field($_POST['hashtag_id']) : '';
777 $feed_type = isset($_POST['feed_type']) ? sanitize_text_field($_POST['feed_type']) : 'user_aacount_type';
778 $user_id = isset($_POST['user_id']) ? sanitize_text_field($_POST['user_id']) : '';
779 $loadmore_key = isset($_POST['loadmore_key']) ? sanitize_text_field($_POST['loadmore_key']) : '';
780 $nonce = isset($_POST['_nonce']) ? sanitize_text_field($_POST['_nonce']) : '';
781 $params = isset($_POST['params']) ? sanitize_text_field($_POST['params']) : '';
782 // $params = json_decode($params, true);
783 $params = stripslashes($params); // Remove extra backslashes
784 $params = json_decode($params, true);
785
786 // Verify nonce
787 if (!wp_verify_nonce($nonce, 'ep_nonce')) {
788 wp_send_json_error('Invalid nonce');
789 wp_die(); // Terminate script execution if nonce is invalid
790 }
791
792 $feeds_data = get_option('ep_instagram_feed_data');
793 $user_data = $feeds_data[$user_id]['feed_userinfo'];
794
795 if ($feed_type == 'hashtag_type') {
796 $feeds_data = get_option('ep_instagram_hashtag_feed');
797 }
798
799
800 $profile_picture_url = isset($user_data['profile_picture_url']) ? $user_data['profile_picture_url'] : '';
801
802 if ($feed_type === 'user_account_type' && isset($feeds_data[$loadmore_key]['feed_posts'])) {
803 $feed_posts = $feeds_data[$loadmore_key]['feed_posts'];
804 } else if ($feed_type === 'hashtag_type' && isset($feeds_data[$loadmore_key])) {
805 $feed_posts = $feeds_data[$loadmore_key];
806 } else {
807 $feed_posts = ['error'];
808 }
809
810
811 if (is_array($feed_posts) && count($feed_posts) > 0) {
812 $loaded_posts = isset($_POST['loaded_posts']) ? intval($_POST['loaded_posts']) : 0;
813 $posts_per_page = isset($_POST['posts_per_page']) ? intval($_POST['posts_per_page']) : 0;
814
815 $post_index = $loaded_posts + 1;
816 $start_index = $loaded_posts;
817
818 $next_posts = array_slice($feed_posts, $start_index, $posts_per_page);
819
820 ob_start();
821
822 if (is_array($next_posts) && count($next_posts) > 0) :
823 foreach ($next_posts as $post) :
824 $caption = !empty($post['caption']) ? $post['caption'] : '';
825 $media_type = !empty($post['media_type']) ? $post['media_type'] : '';
826 $media_url = !empty($post['media_url']) ? $post['media_url'] : '';
827 $permalink = !empty($post['permalink']) ? $post['permalink'] : '';
828 $timestamp = !empty($post['timestamp']) ? $post['timestamp'] : '';
829 $username = !empty($post['username']) ? $post['username'] : '';
830 $like_count = !empty($post['like_count']) ? $post['like_count'] : 0;
831 $comments_count = !empty($post['comments_count']) ? $post['comments_count'] : 0;
832
833 $post['profile_picture_url'] = $profile_picture_url;
834 $post['show_likes_count'] = isset($params['show_likes_count']) ? $params['show_likes_count'] : false;
835 $post['show_comments_count'] = isset($params['show_comments_count']) ? $params['show_comments_count'] : false;
836 $post['popup_follow_button'] = isset($params['popup_follow_button']) ? $params['popup_follow_button'] : true;
837 $post['popup_follow_button_text'] = isset($params['popup_follow_button_text']) ? $params['popup_follow_button_text'] : 'Follow';
838 ?>
839
840 <div class="insta-gallery-item cg-carousel__slide js-carousel__slide" data-insta-postid="<?php echo esc_attr($post['id']) ?>" data-postindex="<?php echo esc_attr($post_index); ?>" data-postdata="<?php echo htmlspecialchars(json_encode($post), ENT_QUOTES, 'UTF-8'); ?>" data-media-type="<?php echo esc_attr($media_type); ?>">
841 <?php
842
843 if (!empty($hashtag_id) && $media_type == 'CAROUSEL_ALBUM') {
844 if (isset($post['children']['data'][0]['media_url'])) {
845 $hashtag_media_url = $post['children']['data'][0]['media_url'];
846 $hashtag_media_type = $post['children']['data'][0]['media_type'];
847
848 if ($hashtag_media_type == 'VIDEO') {
849 echo '<video class="insta-gallery-image" src="' . esc_url($hashtag_media_url) . '"></video>';
850 } else {
851 echo ' <img class="insta-gallery-image" src="' . esc_url($hashtag_media_url) . '" alt="' . esc_attr('image') . '">';
852 }
853 }
854 } else {
855 if ($media_type == 'VIDEO') {
856 echo '<video class="insta-gallery-image" src="' . esc_url($media_url) . '"></video>';
857 } else {
858 echo ' <img class="insta-gallery-image" src="' . esc_url($media_url) . '" alt="' . esc_attr('image') . '">';
859 }
860 }
861 ?>
862
863 <div class="insta-gallery-item-type">
864 <div class="insta-gallery-item-type-icon">
865 <?php
866 if ($media_type == 'VIDEO') {
867 echo Helper::get_insta_video_icon();
868 } else if ($media_type == 'CAROUSEL_ALBUM') {
869 echo Helper::get_insta_image_carousel_icon();
870 } else {
871 echo Helper::get_insta_image_icon();
872 }
873 ?>
874 </div>
875 </div>
876 <div class="insta-gallery-item-info">
877 <?php if (apply_filters('embedpress/is_allow_rander', false)): ?>
878 <div class="insta-item-reaction-count">
879 <div class="insta-gallery-item-likes">
880 <?php echo Helper::get_insta_like_icon();
881 echo esc_html($like_count); ?>
882 </div>
883 <div class="insta-gallery-item-comments">
884 <?php echo Helper::get_insta_comment_icon();
885 echo esc_html($comments_count); ?>
886 </div>
887 </div>
888 <?php else : ?>
889 <div class="insta-gallery-item-permalink">
890 <?php echo Helper::get_instagram_icon(); ?>
891 </div>
892 <?php endif; ?>
893 </div>
894 </div>
895
896 <?php $post_index++;
897 endforeach;
898 endif;
899
900 $feed_item = ob_get_clean();
901
902 $next_start_index = $start_index + count($next_posts);
903
904 wp_send_json(array(
905 'html' => $feed_item,
906 'next_post_index' => $next_start_index,
907 'total_feed_posts' => count($feed_posts)
908 ));
909 } else {
910 wp_send_json('');
911 }
912 }
913
914 public static function getCalendlyUuid($url)
915 {
916 $pattern = '/\/([0-9a-fA-F-]+)$/';
917 if (preg_match($pattern, $url, $matches)) {
918 $uuid = $matches[1];
919 return $uuid;
920 }
921 return '';
922 }
923
924 public static function getCalendlyUserInfo($access_token)
925 {
926 $transient_name = 'calendly_user_info_' . $access_token;
927 $user_info = get_transient($transient_name);
928 if (false === $user_info) {
929 $user_endpoint = 'https://api.calendly.com/users/me';
930 $headers = array(
931 'Authorization' => "Bearer $access_token",
932 'Content-Type' => 'application/json',
933 );
934 $args = array(
935 'headers' => $headers,
936 );
937 $response = wp_remote_get($user_endpoint, $args);
938 if (!is_wp_error($response) && 200 === wp_remote_retrieve_response_code($response)) {
939 $user_info = wp_remote_retrieve_body($response);
940 set_transient($transient_name, $user_info, 3600);
941 } else {
942 return false;
943 }
944 }
945
946 return $user_info;
947 }
948
949
950
951 public static function getCalaendlyEventTypes($user_uri, $access_token)
952 {
953 // Attempt to retrieve the data from the transient
954 $events_list = get_transient('calendly_events_list_' . md5($access_token));
955
956 if (false === $events_list) {
957 // If the data is not in the transient, fetch it from the API
958 $events_endpoint = "https://api.calendly.com/event_types?user=$user_uri";
959
960 $headers = array(
961 'Authorization' => "Bearer $access_token",
962 'Content-Type' => 'application/json',
963 );
964
965 $args = array(
966 'headers' => $headers,
967 );
968
969 $response = wp_remote_get($events_endpoint, $args);
970
971 if (!is_wp_error($response)) {
972 $body = wp_remote_retrieve_body($response);
973 $events_list = json_decode($body, true);
974
975 // Store the data in a transient for a specified time (e.g., 1 hour)
976 set_transient('calendly_events_list', $events_list, HOUR_IN_SECONDS);
977
978 return $events_list;
979 }
980 }
981
982 return $events_list;
983 }
984
985 public static function getListEventInvitee($uuid, $access_token)
986 {
987 // Attempt to retrieve the data from the transient
988 $invitee_list = get_transient('calendly_invitee_list_' . md5($access_token));
989
990 if (false === $invitee_list) {
991 // If the data is not in the transient, fetch it from the API
992 $events_endpoint = "https://api.calendly.com/scheduled_events/$uuid/invitees";
993
994 $headers = array(
995 'Authorization' => "Bearer $access_token",
996 'Content-Type' => 'application/json',
997 );
998
999 $args = array(
1000 'headers' => $headers,
1001 );
1002
1003 $response = wp_remote_get($events_endpoint, $args);
1004
1005 if (!is_wp_error($response)) {
1006 $body = wp_remote_retrieve_body($response);
1007 $invitee_list = json_decode($body, true);
1008
1009 // Store the data in a transient for a specified time (e.g., 1 hour)
1010 set_transient('calendly_invitee_list', $invitee_list, HOUR_IN_SECONDS);
1011
1012 return $invitee_list;
1013 }
1014 }
1015
1016 return $invitee_list;
1017 }
1018
1019 public static function getCalaendlyScheduledEvents($user_uri, $access_token)
1020 {
1021 // Attempt to retrieve the data from the transient
1022 $events_list = get_transient('calendly_events_list_' . md5($access_token));
1023
1024 if (false === $events_list) {
1025 // If the data is not in the transient, fetch it from the API
1026 $events_endpoint = "https://api.calendly.com/scheduled_events?user=$user_uri";
1027
1028 $headers = array(
1029 'Authorization' => "Bearer $access_token",
1030 'Content-Type' => 'application/json',
1031 );
1032
1033 $args = array(
1034 'headers' => $headers,
1035 );
1036
1037 $response = wp_remote_get($events_endpoint, $args);
1038
1039 if (!is_wp_error($response)) {
1040 $body = wp_remote_retrieve_body($response);
1041 $events_list = json_decode($body, true);
1042
1043 // Store the data in a transient for a specified time (e.g., 1 hour)
1044 set_transient('calendly_events_list', $events_list, HOUR_IN_SECONDS);
1045
1046 return $events_list;
1047 }
1048 }
1049
1050 return $events_list;
1051 }
1052
1053
1054 public static function parseDuration($durationString)
1055 {
1056 list($minutes, $seconds) = explode(':', $durationString);
1057 return intval($minutes) * 60 + intval($seconds);
1058 }
1059
1060
1061
1062
1063 public static function is_pro_active()
1064 {
1065 if (defined('EMBEDPRESS_SL_ITEM_SLUG')) {
1066 return true;
1067 }
1068 return false;
1069 }
1070
1071 /**
1072 * Check if pro features should be enabled based on license status
1073 *
1074 * @return bool True if pro features should be enabled, false otherwise
1075 */
1076 public static function is_pro_features_enabled()
1077 {
1078 // First check if pro plugin is active
1079 if (!self::is_pro_active()) {
1080 return false;
1081 }
1082
1083 // Get license status
1084 $license_status = get_option('embedpress_pro_software__license_status', '');
1085
1086 // Pro features are enabled only if license is valid
1087 return $license_status === 'valid';
1088 }
1089
1090 /**
1091 * Get detailed license information
1092 *
1093 * @return array License information including status, key, and data
1094 */
1095 public static function get_license_info()
1096 {
1097 $is_pro_active = self::is_pro_active();
1098 $license_status = '';
1099 $license_key = '';
1100 $license_data = [];
1101 $is_features_enabled = false;
1102
1103 if ($is_pro_active) {
1104 $license_status = get_option('embedpress_pro_software__license_status', '');
1105 $license_data_raw = get_transient('embedpress_pro_software__license_data');
1106
1107 if ($license_data_raw) {
1108 $license_data = json_decode(json_encode($license_data_raw), true);
1109 $license_key = isset($license_data['license_key']) ? $license_data['license_key'] : '';
1110 }
1111
1112 $is_features_enabled = ($license_status === 'valid');
1113 }
1114
1115 return [
1116 'is_pro_active' => $is_pro_active,
1117 'license_status' => $license_status,
1118 'license_key' => $license_key,
1119 'license_data' => $license_data,
1120 'is_features_enabled' => $is_features_enabled,
1121 'status_message' => self::get_license_status_message($is_pro_active, $license_status)
1122 ];
1123 }
1124
1125 /**
1126 * Display license warning notice for pro features
1127 *
1128 * @param string $context Context where the notice is displayed (e.g., 'analytics', 'branding')
1129 * @return string HTML for the license warning notice
1130 */
1131 public static function get_pro_feature_notice($context = '')
1132 {
1133 $license_info = self::get_license_info();
1134
1135 if (!$license_info['is_pro_active']) {
1136 return '<div class="embedpress-pro-notice embedpress-notice-warning">
1137 <p><strong>' . __('EmbedPress Pro Required', 'embedpress') . '</strong></p>
1138 <p>' . __('This feature requires EmbedPress Pro. Please install and activate EmbedPress Pro to access this feature.', 'embedpress') . '</p>
1139 </div>';
1140 }
1141
1142 if (!$license_info['is_features_enabled']) {
1143 $message = $license_info['status_message'];
1144 $action_text = '';
1145 $action_link = admin_url('admin.php?page=embedpress&page_type=license');
1146
1147 switch ($license_info['license_status']) {
1148 case 'expired':
1149 $action_text = __('Renew License', 'embedpress');
1150 break;
1151 case 'invalid':
1152 case 'site_inactive':
1153 case 'disabled':
1154 case 'revoked':
1155 $action_text = __('Activate License', 'embedpress');
1156 break;
1157 default:
1158 $action_text = __('Activate License', 'embedpress');
1159 break;
1160 }
1161
1162 return '<div class="embedpress-pro-notice embedpress-notice-error">
1163 <p><strong>' . __('Pro Features Disabled', 'embedpress') . '</strong></p>
1164 <p>' . esc_html($message) . '</p>
1165 <p><a href="' . esc_url($action_link) . '" class="button button-primary">' . esc_html($action_text) . '</a></p>
1166 </div>';
1167 }
1168
1169 return '';
1170 }
1171
1172 /**
1173 * Initialize license checking hooks
1174 */
1175 public static function init_license_hooks()
1176 {
1177 // Add filter to disable pro features when license is not valid
1178 add_filter('embedpress_pro_features_enabled', [__CLASS__, 'is_pro_features_enabled']);
1179
1180 // Add action to show license notices in admin
1181 add_action('admin_notices', [__CLASS__, 'show_license_admin_notices']);
1182
1183 // Add styles for license notices
1184 add_action('admin_head', [__CLASS__, 'add_license_notice_styles']);
1185 }
1186
1187 /**
1188 * Show license admin notices
1189 */
1190 public static function show_license_admin_notices()
1191 {
1192 // Only show on EmbedPress admin pages
1193 if (!isset($_GET['page']) || $_GET['page'] !== 'embedpress') {
1194 return;
1195 }
1196
1197 $license_info = self::get_license_info();
1198
1199 if ($license_info['is_pro_active'] && !$license_info['is_features_enabled']) {
1200 $message = $license_info['status_message'];
1201 $action_link = admin_url('admin.php?page=embedpress&page_type=license');
1202 $action_text = $license_info['license_status'] === 'expired' ? __('Renew License', 'embedpress') : __('Activate License', 'embedpress');
1203
1204 echo '<div class="notice notice-warning is-dismissible">
1205 <p><strong>' . __('EmbedPress Pro Features Disabled', 'embedpress') . '</strong></p>
1206 <p>' . esc_html($message) . '</p>
1207 <p><a href="' . esc_url($action_link) . '" class="button button-primary">' . esc_html($action_text) . '</a></p>
1208 </div>';
1209 }
1210 }
1211
1212 /**
1213 * Add CSS styles for license notices
1214 */
1215 public static function add_license_notice_styles()
1216 {
1217 echo '<style>
1218 .embedpress-pro-notice {
1219 padding: 15px;
1220 margin: 15px 0;
1221 border-left: 4px solid #dc3545;
1222 background: #fff;
1223 box-shadow: 0 1px 1px rgba(0,0,0,.04);
1224 }
1225 .embedpress-pro-notice.embedpress-notice-warning {
1226 border-left-color: #ffb900;
1227 }
1228 .embedpress-pro-notice.embedpress-notice-error {
1229 border-left-color: #dc3545;
1230 }
1231 .embedpress-pro-notice p {
1232 margin: 0.5em 0;
1233 }
1234 .embedpress-pro-notice strong {
1235 color: #23282d;
1236 }
1237 .embedpress-text-error {
1238 color: #dc3545 !important;
1239 }
1240 .embedpress-text-warning {
1241 color: #ffb900 !important;
1242 }
1243 </style>';
1244 }
1245
1246 /**
1247 * Get user-friendly license status message
1248 *
1249 * @param bool $is_pro_active Whether pro plugin is active
1250 * @param string $license_status Current license status
1251 * @return string User-friendly status message
1252 */
1253 public static function get_license_status_message($is_pro_active, $license_status)
1254 {
1255 if (!$is_pro_active) {
1256 return __('EmbedPress Pro is not installed or activated.', 'embedpress');
1257 }
1258
1259 switch ($license_status) {
1260 case 'valid':
1261 return __('Your license is active and valid.', 'embedpress');
1262 case 'expired':
1263 return __('Your license has expired. Please renew to continue receiving updates and support.', 'embedpress');
1264 case 'invalid':
1265 case 'site_inactive':
1266 return __('Your license is not active for this URL. Please activate your license.', 'embedpress');
1267 case 'disabled':
1268 case 'revoked':
1269 return __('Your license key has been disabled or revoked.', 'embedpress');
1270 case 'missing':
1271 return __('License key is missing. Please enter your license key.', 'embedpress');
1272 case 'http_error':
1273 return __('Unable to verify license due to connection issues. Please try again later.', 'embedpress');
1274 case '':
1275 case false:
1276 default:
1277 return __('Please activate your license key to enable EmbedPress Pro features.', 'embedpress');
1278 }
1279 }
1280
1281
1282 public static function getInstagramUserInfo($accessToken, $accountType, $userId, $is_sync = false)
1283 {
1284 if ($is_sync) {
1285 // If $is_sync is true, don't use transient
1286 $use_transient = false;
1287 } else {
1288 // If $is_sync is false, use transient
1289 $transient_key = 'instagram_user_info_' . $userId;
1290 $use_transient = true;
1291 }
1292
1293 if ($use_transient && false !== ($userInfo = get_transient($transient_key))) {
1294 // If transient exists, return cached user info
1295 return $userInfo;
1296 }
1297
1298 if (strtolower($accountType) === 'personal') {
1299 $api_url = 'https://graph.instagram.com/v24.0/me?fields=biography,id,username,website,followers_count,media_count,profile_picture_url,name&access_token=' . $accessToken;
1300 } else {
1301 $api_url = 'https://graph.facebook.com/' . $userId . '?fields=biography,id,username,website,followers_count,media_count,profile_picture_url,name&access_token=' . $accessToken;
1302 }
1303
1304 $connected_account_type = $accountType;
1305
1306 $userInfoResponse = wp_remote_get($api_url);
1307
1308 if (is_wp_error($userInfoResponse)) {
1309 echo 'Error: Unable to retrieve Instagram user information.';
1310 } else {
1311 $userInfoBody = wp_remote_retrieve_body($userInfoResponse);
1312 $userInfo = json_decode($userInfoBody, true);
1313
1314 $userInfo['connected_account_type'] = $connected_account_type;
1315 $userInfo['access_token'] = $accessToken;
1316
1317
1318 if (!isset($userInfo['profile_picture_url'])) {
1319 $userInfo['profile_picture_url'] = '';
1320 }
1321
1322 // If not using transient, cache the user info for an hour
1323 if ($use_transient) {
1324 set_transient($transient_key, $userInfo, HOUR_IN_SECONDS);
1325 }
1326
1327 return $userInfo;
1328 }
1329 }
1330
1331
1332 // Get Instagram posts, videos, reels
1333 public static function getInstagramPosts($access_token, $account_type, $userId, $limit = 100, $is_sync = false)
1334 {
1335 if ($is_sync) {
1336 // If $is_sync is true, don't use transient
1337 $use_transient = false;
1338 } else {
1339 // If $is_sync is false, use transient
1340 $transient_key = 'instagram_posts_' . $userId;
1341 $use_transient = true;
1342 }
1343
1344 if ($use_transient && false !== ($posts = get_transient($transient_key))) {
1345 // If transient exists, return cached posts
1346 return $posts;
1347 }
1348
1349 if (strtolower($account_type) === 'personal') {
1350 $api_url = 'https://graph.instagram.com/v24.0/me/media?fields=id,caption,media_type,media_url,children{media_url,id,media_type},permalink,timestamp,username,thumbnail_url,comments_count,like_count&limit=' . $limit . '&access_token=' . $access_token;
1351 } else {
1352 $api_url = 'https://graph.facebook.com/v17.0/' . $userId . '/media?fields=media_url,media_product_type,thumbnail_url,caption,id,media_type,timestamp,username,comments_count,like_count,permalink,children%7Bmedia_url,id,media_type,timestamp,permalink,thumbnail_url%7D&limit=' . $limit . '&access_token=' . $access_token;
1353 }
1354
1355 $postsResponse = wp_remote_get($api_url);
1356
1357 if (is_wp_error($postsResponse)) {
1358 echo 'Error: Unable to retrieve Instagram posts.';
1359 } else {
1360 $postsBody = wp_remote_retrieve_body($postsResponse);
1361 $posts = json_decode($postsBody, true);
1362
1363 if (empty($posts['data'])) {
1364 return 'Please add Instagram Access Token';
1365 }
1366
1367 // If not using transient, cache the posts for an hour
1368 if ($use_transient) {
1369 set_transient($transient_key, $posts['data'], HOUR_IN_SECONDS);
1370 }
1371
1372 return $posts['data'];
1373 }
1374 }
1375
1376 public static function get_enable_settings_data_for_scripts($settings)
1377 {
1378 $settings_data = [
1379 'enabled_ads' => isset($settings['adManager']) && $settings['adManager'] === 'yes' ? 'yes' : '',
1380
1381 'enabled_custom_player' => isset($settings['emberpress_custom_player']) && $settings['emberpress_custom_player'] === 'yes' ? 'yes' : '',
1382
1383 'enabled_instafeed' => isset($settings['embedpress_pro_embeded_source']) && $settings['embedpress_pro_embeded_source'] === 'instafeed' ? 'yes' : '',
1384
1385 'enabled_docs_custom_viewer' => isset($settings['embedpress_document_viewer']) && $settings['embedpress_document_viewer'] === 'custom' ? 'yes' : '',
1386 ];
1387
1388 update_option('enabled_elementor_scripts', $settings_data);
1389 }
1390
1391 public static function get_options_value($key)
1392 {
1393 $g_settings = get_option(EMBEDPRESS_PLG_NAME);
1394
1395 if (isset($g_settings['enableEmbedResizeWidth']) && $g_settings['enableEmbedResizeWidth'] == 1) {
1396 $g_settings['enableEmbedResizeWidth'] = 600;
1397 update_option(EMBEDPRESS_PLG_NAME, $g_settings);
1398 }
1399 if (isset($g_settings['enableEmbedResizeHeight']) && $g_settings['enableEmbedResizeHeight'] == 1) {
1400 $g_settings['enableEmbedResizeHeight'] = 600;
1401 update_option(EMBEDPRESS_PLG_NAME, $g_settings);
1402 }
1403
1404 if (isset($g_settings[$key])) {
1405 return $g_settings[$key];
1406 }
1407
1408 return '';
1409 }
1410
1411
1412
1413 public static function get_branding_value($key, $provider)
1414 {
1415 $settings = get_option(EMBEDPRESS_PLG_NAME . ':' . $provider, []);
1416
1417 // Check if provider has custom branding enabled and the specific key set
1418 if (isset($settings['branding']) && $settings['branding'] === 'yes') {
1419 // If provider has custom logo, use it
1420 if (isset($settings[$key]) && !empty($settings[$key])) {
1421 return $settings[$key];
1422 }
1423
1424 // If branding is enabled but no custom logo, use global brand as fallback
1425 if ($key === 'logo_url') {
1426 $global_logo = self::get_global_brand_logo_url();
1427 if (!empty($global_logo)) {
1428 return $global_logo;
1429 }
1430 }
1431 }
1432
1433 return '';
1434 }
1435
1436 /**
1437 * Get global brand logo URL
1438 *
1439 * @return string
1440 */
1441 public static function get_global_brand_logo_url()
1442 {
1443 $global_brand_settings = get_option(EMBEDPRESS_PLG_NAME . ':global_brand', []);
1444 return isset($global_brand_settings['logo_url']) ? $global_brand_settings['logo_url'] : '';
1445 }
1446
1447 /**
1448 * Get global brand logo ID
1449 *
1450 * @return int
1451 */
1452 public static function get_global_brand_logo_id()
1453 {
1454 $global_brand_settings = get_option(EMBEDPRESS_PLG_NAME . ':global_brand', []);
1455 return isset($global_brand_settings['logo_id']) ? intval($global_brand_settings['logo_id']) : 0;
1456 }
1457
1458
1459 public static function format_number($number)
1460 {
1461 if ($number >= 1000000000) {
1462 return number_format($number / 1000000000, 1) . 'b';
1463 } elseif ($number >= 1000000) {
1464 return number_format($number / 1000000, 1) . 'm';
1465 } elseif ($number >= 1000) {
1466 return number_format($number / 1000, 1) . 'k';
1467 } else {
1468 return $number;
1469 }
1470 }
1471
1472 public static function get_id($item)
1473 {
1474 $vid = isset($item->snippet->resourceId->videoId) ? $item->snippet->resourceId->videoId : null;
1475 $vid = $vid ? $vid : (isset($item->id->videoId) ? $item->id->videoId : null);
1476 $vid = $vid ? $vid : (isset($item->id) ? $item->id : null);
1477 return $vid;
1478 }
1479
1480 public static function clean_api_error($raw_message)
1481 {
1482 return htmlspecialchars(strip_tags(preg_replace('@&key=[^& ]+@i', '&key=*******', $raw_message)));
1483 }
1484
1485 public static function clean_api_error_html($raw_message)
1486 {
1487 $clean_html = '';
1488 if ((defined('REST_REQUEST') && REST_REQUEST) || current_user_can('manage_options')) {
1489 $clean_html = '<div>' . __('EmbedPress: ', 'embedpress') . self::clean_api_error($raw_message) . '</div>';
1490 }
1491 return $clean_html;
1492 }
1493
1494 public static function get_thumbnail_url($item, $quality, $privacyStatus)
1495 {
1496 $url = "";
1497 if ($privacyStatus == 'private') {
1498 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/private.png';
1499 } elseif (isset($item->snippet->thumbnails->{$quality}->url)) {
1500 $url = $item->snippet->thumbnails->{$quality}->url;
1501 } elseif (isset($item->snippet->thumbnails->medium->url)) {
1502 $url = $item->snippet->thumbnails->medium->url;
1503 } elseif (isset($item->snippet->thumbnails->default->url)) {
1504 $url = $item->snippet->thumbnails->default->url;
1505 } elseif (isset($item->snippet->thumbnails->high->url)) {
1506 $url = $item->snippet->thumbnails->high->url;
1507 } else {
1508 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/deleted-video-thumb.png';
1509 }
1510 return $url;
1511 }
1512
1513 public static function compare_vid_date($a, $b)
1514 {
1515 $dateA = strtotime($a->snippet->publishedAt);
1516 $dateB = strtotime($b->snippet->publishedAt);
1517
1518 // Sort in descending order (newest first)
1519 return $dateB - $dateA;
1520 }
1521
1522
1523 public static function get_youtube_video_data($api_key, $video_id)
1524 {
1525 // Set a unique transient name based on the video ID
1526 $transient_name = 'youtube_video_data_' . $video_id;
1527
1528 // Try to get data from the transient cache
1529 $video_data = get_transient($transient_name);
1530
1531 // If no cached data, fetch from the API
1532 if ($video_data === false) {
1533 // YouTube Data API URL
1534 $url = "https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id={$video_id}&key={$api_key}";
1535
1536 // Fetch the data from the API
1537 $response = wp_remote_get($url);
1538
1539 if (is_wp_error($response)) {
1540 return false; // Return false if there is an error
1541 }
1542
1543 $body = wp_remote_retrieve_body($response);
1544 $video_data = json_decode($body, true);
1545
1546 if (isset($video_data['items'][0])) {
1547 $video_data = $video_data['items'][0];
1548
1549 // Cache the data in a transient for 12 hours
1550 set_transient($transient_name, $video_data, 24 * HOUR_IN_SECONDS);
1551 } else {
1552 return false; // Return false if no data found
1553 }
1554 }
1555
1556 return $video_data;
1557 }
1558
1559 public static function trimTitle($title, $wordCount)
1560 {
1561 $words = explode(' ', $title);
1562
1563 if (count($words) <= $wordCount) {
1564 return $title; // No trimming needed
1565 }
1566
1567 $trimmedWords = array_slice($words, 0, $wordCount);
1568
1569 return implode(' ', $trimmedWords) . ' ...';
1570 }
1571
1572 public static function timeAgo($datetime)
1573 {
1574 $now = new \DateTime();
1575 $date = new \DateTime($datetime);
1576 $interval = $now->diff($date);
1577
1578 if ($interval->y > 0) {
1579 return $interval->y . ' year' . ($interval->y > 1 ? 's' : '') . ' ago';
1580 } elseif ($interval->m > 0) {
1581 return $interval->m . ' month' . ($interval->m > 1 ? 's' : '') . ' ago';
1582 } elseif ($interval->d > 0) {
1583 return $interval->d . ' day' . ($interval->d > 1 ? 's' : '') . ' ago';
1584 } elseif ($interval->h > 0) {
1585 return $interval->h . ' hour' . ($interval->h > 1 ? 's' : '') . ' ago';
1586 } elseif ($interval->i > 0) {
1587 return $interval->i . ' minute' . ($interval->i > 1 ? 's' : '') . ' ago';
1588 } else {
1589 return 'just now';
1590 }
1591 }
1592
1593 public static function removeQuote($attributes)
1594 {
1595 $parsedAttributes = [];
1596
1597 $regex = '/^on.*/i';
1598
1599 foreach ($attributes as $key => $value) {
1600 if (is_string($value)) {
1601 $cleanValue = str_replace(['"', "'"], '', $value);
1602 } else {
1603 $cleanValue = $value;
1604 }
1605
1606 if (!preg_match($regex, $key)) {
1607 $parsedAttributes[$key] = $cleanValue;
1608 }
1609 }
1610
1611 return $parsedAttributes;
1612 }
1613
1614 public static function getBooleanParam($param, $default = false)
1615 {
1616 if (in_array($param, [true, 'true', 'yes', 1, '1'], true)) {
1617 return true;
1618 }
1619 if (in_array($param, [false, 'false', 'no', 0, '0'], true)) {
1620 return false;
1621 }
1622 return (bool) $default;
1623 }
1624
1625 public static function has_allowed_roles($allowed_roles = [])
1626 {
1627
1628 if (empty($allowed_roles) || (count($allowed_roles) == 1 && empty($allowed_roles[0]))) {
1629 return true;
1630 }
1631 $current_user = wp_get_current_user();
1632 $user_roles = $current_user->roles;
1633
1634 return !empty(array_intersect($user_roles, $allowed_roles));
1635 }
1636
1637 public static function get_elementor_global_color($settings, $key)
1638 {
1639
1640 $global_color = $settings[$key];
1641
1642 if (isset($settings['__globals__'][$key])) {
1643 $color_setting = $settings['__globals__'][$key];
1644
1645 if (strpos($color_setting, 'globals/colors?id=') === 0) {
1646 // It's a global color reference
1647 $global_id = str_replace('globals/colors?id=', '', $color_setting);
1648
1649 $kit = Plugin::$instance->kits_manager->get_current_settings();
1650
1651 $system_colors = isset($kit['system_colors']) ? $kit['system_colors'] : [];
1652 $custom_colors = isset($kit['custom_colors']) ? $kit['custom_colors'] : [];
1653 $global_colors = array_merge($system_colors, $custom_colors);
1654
1655 foreach ($global_colors as $color) {
1656
1657 if ($color['_id'] === $global_id) {
1658 $global_color = $color['color']; // Found a match, set the color
1659 break;
1660 }
1661 }
1662 }
1663 }
1664 return $global_color;
1665 }
1666
1667 public static function get_provider_name($source_url)
1668 {
1669 if (self::is_youtube_channel($source_url)) {
1670 $source_name = 'YoutubeChannel';
1671 } else if (self::is_youtube($source_url)) {
1672 $source_name = 'Youtube';
1673 } else if (!empty(self::is_file_url($source_url))) {
1674 $source_name = 'document_' . self::get_extension_from_file_url($source_url);
1675 } else if (self::is_opensea($source_url)) {
1676 $source_name = 'OpenSea';
1677 } else if (self::is_instagram_feed($source_url)) {
1678 $source_name = 'InstagramFeed';
1679 }else {
1680 Shortcode::get_embera_instance();
1681 $collectios = Shortcode::get_collection();
1682 $provider = $collectios->findProviders($source_url);
1683
1684 if (!empty($provider[$source_url])) {
1685 $source_name = $provider[$source_url]->getProviderName();
1686 } else {
1687 $host = parse_url($source_url, PHP_URL_HOST);
1688 if ($host) {
1689 $parts = explode('.', $host);
1690 if (count($parts) > 1) {
1691 $source_name = $parts[1];
1692 } else {
1693 // Handle the case where the host doesn't have at least two parts
1694 $source_name = $host;
1695 }
1696 } else {
1697 // Handle the case where parse_url fails
1698 $source_name = '';
1699 }
1700 }
1701 }
1702
1703 return $source_name;
1704 }
1705
1706 public static function get_user_roles()
1707 {
1708 global $wp_roles; // Access global roles object
1709 $user_roles = [];
1710
1711 if (isset($wp_roles->roles) && is_array($wp_roles->roles)) {
1712 foreach ($wp_roles->roles as $role_key => $role_data) {
1713 $user_roles[] = [
1714 'value' => $role_key, // Machine-readable key
1715 'label' => $role_data['name'], // Human-readable name
1716 ];
1717 }
1718 }
1719
1720 return $user_roles;
1721 }
1722
1723 public static function has_content_allowed_roles($allowed_roles = [])
1724 {
1725 // Ensure it's always an array
1726 if (!is_array($allowed_roles)) {
1727 $allowed_roles = [];
1728 }
1729
1730 if (count($allowed_roles) === 1 && empty($allowed_roles[0])) {
1731 return true;
1732 }
1733
1734 $current_user = wp_get_current_user();
1735 $user_roles = $current_user->roles;
1736
1737 return !empty(array_intersect($user_roles, $allowed_roles));
1738 }
1739
1740
1741 }
1742