PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 4.5.6
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v4.5.6
4.6.5 4.6.4 4.6.3 4.6.2 4.6.1 4.6.0 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 2 months ago Database 3 months ago DynamicFieldResolver.php 2 months ago Elementor_Enhancer.php 7 months ago EmbedPress_Core_Installer.php 6 years ago EmbedPress_Notice.php 4 months ago EmbedPress_Plugin_Usage_Tracker.php 2 months ago Extend_CustomPlayer_Controls.php 3 months ago Extend_Elementor_Controls.php 1 year ago FeatureNoticeManager.php 9 months ago FeatureNotices.php 9 months ago Feature_Enhancer.php 2 months ago Helper.php 2 months ago Pdf_Thumbnail_Handler.php 4 months ago PermalinkHelper.php 1 year ago README_FEATURE_NOTICES.md 9 months ago View_Count_Display.php 2 months ago
Helper.php
1832 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 $path = parse_url((string) $url, PHP_URL_PATH);
137 if (empty($path)) {
138 $path = (string) $url;
139 }
140 $urlSplit = explode(".", $path);
141 $ext = end($urlSplit);
142 return strtolower($ext);
143 }
144
145
146 public static function is_instagram_feed($url)
147 {
148 return (bool) preg_match('~(?:https?://)?(?:www\.)?instagram\.com/(?!p/|reel/|tv/|stories/)[^/]+/?$~i', (string) $url);
149 }
150
151 public static function is_file_url($url)
152 {
153 $pattern = '/\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/i';
154 return preg_match($pattern, $url) === 1;
155 }
156
157 public static function is_opensea($url)
158 {
159 return strpos($url, "opensea.io") !== false;
160 }
161 public static function is_youtube_channel($url)
162 {
163 return (bool) (preg_match('~(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/)(?:channel\/|c\/|user\/|@)(\w+)~i', (string) $url));
164 }
165
166 public static function is_youtube_playlist($url)
167 {
168 // /playlist?list=PL… OR /watch?…&list=… (Mix radio, video-in-playlist).
169 $u = str_replace(['&#038;', '&amp;'], '&', (string) $url);
170 return (bool) (preg_match('~^https?://(?:www\.)?youtube\.com/(?:playlist|watch)\?(?:[^#]*&)?list=([\w-]+)~i', $u));
171 }
172
173 public static function is_youtube_channel_or_playlist($url)
174 {
175 return self::is_youtube_channel($url) || self::is_youtube_playlist($url);
176 }
177
178 public static function is_youtube($url)
179 {
180 return (bool) (preg_match('~(?:https?://)?(?:www\.)?(?:youtube\.com|youtu\.be)/watch\?v=([^&]+)~i', (string) $url));
181 }
182
183 // Saved sources data temporary in wp_options table
184 public static function get_source_data($blockid, $source_url, $source_option_name, $source_temp_option_name)
185 {
186 if (self::is_youtube_channel($source_url)) {
187 $source_name = 'YoutubeChannel';
188 } else if (self::is_youtube($source_url)) {
189 $source_name = 'Youtube';
190 } else if (!empty(self::is_file_url($source_url))) {
191 $source_name = 'document_' . self::get_extension_from_file_url($source_url);
192 } else if (self::is_opensea($source_url)) {
193 $source_name = 'OpenSea';
194 } else if (self::is_instagram_feed($source_url)) {
195 $source_name = 'InstagramFeed';
196 } else {
197 Shortcode::get_embera_instance();
198 $collectios = Shortcode::get_collection();
199 $provider = $collectios->findProviders($source_url);
200
201 if (!empty($provider[$source_url])) {
202 $source_name = $provider[$source_url]->getProviderName();
203 } else {
204 $host = parse_url($source_url, PHP_URL_HOST);
205 if ($host) {
206 $parts = explode('.', $host);
207 if (count($parts) > 1) {
208 $source_name = $parts[1];
209 } else {
210 // Handle the case where the host doesn't have at least two parts
211 $source_name = $host;
212 }
213 } else {
214 // Handle the case where parse_url fails
215 $source_name = 'unknown';
216 }
217 }
218 }
219
220 if (!empty($blockid) && $blockid != 'undefined') {
221 $sources = json_decode(get_option($source_temp_option_name), true);
222
223 if (!$sources) {
224 $sources = array();
225 }
226 $exists = false;
227
228 foreach ($sources as $i => $source) {
229 if ($source['id'] === $blockid) {
230 $sources[$i]['source']['name'] = $source_name;
231 $sources[$i]['source']['url'] = $source_url;
232 $exists = true;
233 break;
234 }
235 }
236
237 if (!$exists) {
238 $sources[] = array('id' => $blockid, 'source' => array('name' => $source_name, 'url' => $source_url, 'count' => 1));
239 }
240
241 update_option($source_temp_option_name, json_encode($sources));
242 }
243 }
244
245 /**
246 * One-time scan of existing post content to seed the source-data options.
247 *
248 * Uses two SQL-prefiltered queries (post_content + _elementor_data postmeta)
249 * so a site with thousands of posts only loads the rows that actually
250 * mention "embedpress" — avoiding the N+1 round-trips of get_posts() +
251 * per-post get_post_field() / get_post_meta().
252 */
253 public static function seed_source_data_from_existing_content()
254 {
255 if (get_option('embedpress_source_data_seeded')) {
256 return;
257 }
258
259 global $wpdb;
260
261 $limit = (int) apply_filters('embedpress_seed_source_data_limit', 2000);
262 $like = '%' . $wpdb->esc_like('embedpress') . '%';
263
264 // Posts whose content mentions embedpress (blocks or shortcodes).
265 $content_rows = $wpdb->get_results($wpdb->prepare(
266 "SELECT ID, post_content
267 FROM {$wpdb->posts}
268 WHERE post_status IN ('publish','draft','private','future','pending')
269 AND post_type NOT IN ('revision','attachment','nav_menu_item','customize_changeset','oembed_cache')
270 AND post_content LIKE %s
271 LIMIT %d",
272 $like,
273 $limit
274 ));
275
276 if ($content_rows) {
277 foreach ($content_rows as $row) {
278 $post_id = (int) $row->ID;
279 $content = (string) $row->post_content;
280
281 // Gutenberg: <!-- wp:embedpress/* {"url":"..."} -->
282 if (preg_match_all('/wp:embedpress[^>]*?"url"\s*:\s*"([^"]+)"/', $content, $m)) {
283 foreach ($m[1] as $i => $url) {
284 self::get_source_data(
285 md5("seed-{$post_id}-g-{$i}"),
286 wp_unslash($url),
287 'gutenberg_source_data',
288 'gutenberg_temp_source_data'
289 );
290 }
291 }
292
293 // Shortcode: [embedpress ...]URL[/embedpress]
294 if (preg_match_all('/\[embedpress[^\]]*\](.*?)\[\/embedpress\]/s', $content, $m)) {
295 foreach ($m[1] as $i => $url) {
296 $url = trim(wp_unslash($url));
297 if ($url === '') continue;
298 self::get_source_data(
299 md5("seed-{$post_id}-s-{$i}"),
300 $url,
301 'gutenberg_source_data',
302 'gutenberg_temp_source_data'
303 );
304 }
305 }
306 }
307 }
308
309 // Elementor widgets — postmeta-level prefilter.
310 $meta_rows = $wpdb->get_results($wpdb->prepare(
311 "SELECT post_id, meta_value
312 FROM {$wpdb->postmeta}
313 WHERE meta_key = %s
314 AND meta_value LIKE %s
315 LIMIT %d",
316 '_elementor_data',
317 $like,
318 $limit
319 ));
320
321 if ($meta_rows) {
322 foreach ($meta_rows as $row) {
323 $post_id = (int) $row->post_id;
324 $el = (string) $row->meta_value;
325 if (preg_match_all('/"widgetType":"embedpress[^"]*".*?"(?:embedpress_pro_embeded_link|embed_url|url|pdf_source|src)":"([^"]+)"/', $el, $m)) {
326 foreach ($m[1] as $i => $url) {
327 self::get_source_data(
328 md5("seed-{$post_id}-e-{$i}"),
329 stripslashes($url),
330 'elementor_source_data',
331 'elementor_temp_source_data'
332 );
333 }
334 }
335 }
336 }
337
338 // Promote temp → real without needing save_post.
339 self::get_save_source_data_on_post_update('gutenberg_source_data', 'gutenberg_temp_source_data');
340 self::get_save_source_data_on_post_update('elementor_source_data', 'elementor_temp_source_data');
341
342 update_option('embedpress_source_data_seeded', time(), false);
343 }
344
345 // Saved source data when post updated
346 public static function get_save_source_data_on_post_update($source_option_name, $source_temp_option_name)
347 {
348
349 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
350 return;
351 }
352 $temp_data = json_decode(get_option($source_temp_option_name), true);
353 $source_data = json_decode(get_option($source_option_name), true);
354 if (!$temp_data) {
355 $temp_data = array();
356 }
357 if (!$source_data) {
358 $source_data = array();
359 }
360
361 $sources = array_merge($temp_data, $source_data);
362
363 $unique_sources = array();
364 foreach ($sources as $source) {
365 $unique_sources[$source['id']] = $source;
366 }
367
368 $unique_sources = array_values($unique_sources);
369
370 delete_option($source_temp_option_name);
371
372 update_option($source_option_name, json_encode($unique_sources));
373 }
374
375 //Delete source temporary data when reload without update or publish
376 public static function get_delete_source_temp_data_on_reload($source_temp_option_name)
377 {
378 $source_temp_data = json_decode(get_option($source_temp_option_name), true);
379 if ($source_temp_data) {
380 delete_option($source_temp_option_name);
381 }
382 }
383
384 public static function get_file_title($url)
385 {
386 return get_the_title(attachment_url_to_postid($url));
387 }
388
389 public static function get_hash()
390 {
391 $hash_key = get_option(EMBEDPRESS_PLG_NAME . '_hash_key');
392 if (!$hash_key) {
393 $hash_key = wp_hash_password(wp_generate_password(30));
394 update_option(EMBEDPRESS_PLG_NAME . '_hash_key', $hash_key);
395 }
396 return $hash_key;
397 }
398
399 public function lock_content_form_handler() {
400 // print_r($embedHTML);
401
402 $client_id = isset($_POST['client_id']) ? sanitize_text_field($_POST['client_id']) : '';
403 $password = isset($_POST['password']) ? sanitize_text_field($_POST['password']) : '';
404 $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0;
405
406 $epbase64 = get_post_meta( $post_id, 'ep_base_' .$client_id, true );
407 $hash_key = get_post_meta( $post_id, 'hash_key_' .$client_id, true );
408
409 // Set the decryption key and initialization vector (IV)
410 $key = Helper::get_hash();
411
412 // Decode the base64 encoded cipher
413 $cipher = base64_decode($epbase64);
414 // Decrypt the cipher using AES-128-CBC encryption
415
416 $wp_pass_key = hash('sha256', wp_salt(32) . md5($password));
417 $iv = substr($wp_pass_key, 0, 16);
418
419 if ($wp_pass_key === $hash_key) {
420
421 $embed = openssl_decrypt($cipher, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv) . '<script>
422 var now = new Date();
423 var time = now.getTime();
424 var expireTime = time + 1000 * 60 * 60 * 24 * 30;
425 now.setTime(expireTime);
426 document.cookie = "password_correct_'.esc_js($client_id).'='.esc_js($hash_key).'; expires=" + now.toUTCString() + "; path=/";
427 </script>';
428
429 }
430 else{
431 $embed = 0;
432 }
433
434 // Process the form data and return a response
435 $response = array(
436 'success' => true,
437 'password' => $password,
438 'embedHtml' => $embed,
439 'post_id' => $post_id
440 );
441
442 wp_send_json($response);
443
444 }
445
446 public function gutenberg_password_check()
447 {
448 $client_id = isset($_POST['client_id']) ? sanitize_text_field($_POST['client_id']) : '';
449 $password = isset($_POST['password']) ? sanitize_text_field($_POST['password']) : '';
450 $content_password = isset($_POST['content_password']) ? sanitize_text_field($_POST['content_password']) : '';
451
452 // Verify password
453 if ($password === $content_password) {
454 // Set cookie for authentication
455 $hash_pass = hash('sha256', wp_salt(32) . md5($password));
456 setcookie("password_correct_" . $client_id, $hash_pass, time() + 3600, '/');
457
458 $response = array(
459 'success' => true,
460 'message' => 'Password correct'
461 );
462 } else {
463 $response = array(
464 'success' => false,
465 'message' => 'Incorrect password'
466 );
467 }
468
469 wp_send_json($response);
470 }
471
472 public static function display_password_form($client_id = '', $embedHtml = '', $pass_hash_key = '', $attributes = [])
473 {
474 $lock_heading = !empty($attributes['lockHeading']) ? sanitize_text_field($attributes['lockHeading']) : '';
475 $lock_subheading = !empty($attributes['lockSubHeading']) ? sanitize_text_field($attributes['lockSubHeading']) : '';
476 $lock_error_message = !empty($attributes['lockErrorMessage']) ? sanitize_text_field($attributes['lockErrorMessage']) : '';
477 $footer_message = !empty($attributes['footerMessage']) ? sanitize_text_field($attributes['footerMessage']) : '';
478 $password_placeholder = !empty($attributes['passwordPlaceholder']) ? sanitize_text_field($attributes['passwordPlaceholder']) : '';
479 $button_text = !empty($attributes['submitButtonText']) ? sanitize_text_field($attributes['submitButtonText']) : '';
480 $unlocking_text = !empty($attributes['submitUnlockingText']) ? sanitize_text_field($attributes['submitUnlockingText']) : '';
481 $enable_footer_message = !empty($attributes['enableFooterMessage']) ? sanitize_text_field($attributes['enableFooterMessage']) : '';
482
483
484 // Set the encryption key and initialization vector (IV)
485 $key = self::get_hash();
486
487 $salt = wp_salt(32);
488 $wp_hash_key = hash('sha256', $salt . $pass_hash_key);
489 $iv = substr($wp_hash_key, 0, 16);
490
491
492 // Encrypt the plaintext using AES-128-CBC encryption
493 $cipher = openssl_encrypt($embedHtml, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
494
495 // Base64 encode the encrypted cipher
496 $encrypted_data = base64_encode($cipher);
497
498 update_post_meta(get_the_ID(), 'ep_base_' . $client_id, $encrypted_data);
499 update_post_meta(get_the_ID(), 'hash_key_' . $client_id, $wp_hash_key);
500
501 $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>';
502
503 echo '
504 <div class="password-form-container sd">
505 <h2>' . esc_html($lock_heading) . '</h2>
506 <p>' . esc_html($lock_subheading) . ' </p>
507 <form class="password-form" method="post" class="password-form" data-unlocking-text="' . esc_attr($unlocking_text) . '">
508
509 <div class="password-field">
510 <span class="lock-icon">' . $lock_icon . '</span>
511 <input type="password" name="pass_' . esc_attr($client_id) . '" placeholder="' . esc_attr($password_placeholder) . '" required>
512 </div>
513 <input type="hidden" name="ep_client_id" value="' . esc_attr($client_id) . '">
514 <input type="hidden" name="post_id" value="' . esc_attr(get_the_ID()) . '">
515
516 <input type="submit" name="password_submit" value="' . esc_attr($button_text) . '">
517 <div class="error-message hidden">' . esc_html($lock_error_message) . '</div>
518 </form>
519 ' . (!empty($enable_footer_message) ? '<p class="need-access-message">' . esc_html($footer_message) . '</p>' : '') . '
520 </div>
521 ';
522 }
523
524 // Check if the user has already entered the correct password
525 public static function is_password_correct($client_id)
526 {
527 if (isset($_COOKIE['password_correct_' . $client_id])) {
528 return $_COOKIE['password_correct_' . $client_id];
529 } else {
530 return false;
531 }
532 }
533
534 public static function customLogo($embedHTML, $atts)
535 {
536 $x = !empty($atts['logoX']) ? $atts['logoX'] : 0;
537 $y = !empty($atts['logoY']) ? $atts['logoY'] : 0;
538 $uniqid = !empty($atts['url']) ? '.ose-uid-' . md5($atts['url']) : '';
539
540 $brandUrl = !empty($atts['customlogoUrl']) ? $atts['customlogoUrl'] : '';
541 $opacity = !empty($atts['logoOpacity']) ? $atts['logoOpacity'] : '';
542
543 $cssClass = !empty($atts['url']) ? '.ose-uid-' . md5($atts['url']) : '.ose-youtube';
544
545
546
547 ob_start(); ?>
548 <style type="text/css">
549 <?php echo esc_html($cssClass); ?> {
550 position: relative;
551 }
552
553 <?php echo esc_html($cssClass); ?>.watermark {
554 border: 0;
555 position: absolute;
556 bottom: <?php echo esc_html($y); ?>%;
557 right: <?php echo esc_html($x); ?>%;
558 max-width: 150px;
559 max-height: 75px;
560 opacity: 0.25;
561 z-index: 5;
562 -o-transition: opacity 0.5s ease-in-out;
563 -moz-transition: opacity 0.5s ease-in-out;
564 -webkit-transition: opacity 0.5s ease-in-out;
565 transition: opacity 0.5s ease-in-out;
566 opacity: <?php echo esc_html($opacity); ?>;
567 }
568
569 <?php echo esc_html($cssClass); ?>.watermark:hover {
570 opacity: 1;
571 }
572 </style>
573 <?php
574
575
576 $style = ob_get_clean();
577
578 if (!class_exists('\simple_html_dom')) {
579 include_once EMBEDPRESS_PATH_CORE . 'simple_html_dom.php';
580 }
581
582 $cta = '';
583 $img = '';
584
585 if (!empty($atts['customlogo'])) {
586 $img = '<img src="' . esc_url($atts['customlogo']) . '"/>';
587
588 $imgDom = str_get_html($img);
589 $imgDom = $imgDom->find('img', 0);
590 $imgDom->setAttribute('class', 'watermark ep-custom-logo');
591 $imgDom->removeAttribute('style');
592 $imgDom->setAttribute('width', 'auto');
593 $imgDom->setAttribute('height', 'auto');
594 ob_start();
595 echo $imgDom;
596
597 $cta .= ob_get_clean();
598
599 $imgDom->clear();
600 unset($img, $imgDom);
601
602 if (!empty($brandUrl)) {
603 $cta = '<a href="' . esc_url($brandUrl) . '" target="_blank">' . $cta . '</a>';
604 }
605 $dom = str_get_html($embedHTML);
606
607 $wrapDiv = $dom->find($uniqid, 0);
608
609 if (!empty($wrapDiv) && is_object($wrapDiv)) {
610 $wrapDiv->innertext .= $cta;
611 }
612
613 ob_start();
614 echo $wrapDiv;
615
616 $markup = ob_get_clean();
617
618 $dom->clear();
619 unset($dom, $wrapDiv);
620
621 $embedHTML = $style . $markup;
622 }
623
624 return $embedHTML;
625 }
626
627
628 public static function embed_content_share($content_id = '', $attributes = [])
629 {
630 $share_position = !empty($attributes['sharePosition']) ? $attributes['sharePosition'] : 'right';
631 $custom_thumnail = !empty($attributes['customThumbnail']) ? $attributes['customThumbnail'] : '';
632 $custom_title = !empty($attributes['customTitle']) ? $attributes['customTitle'] : '';
633 $custom_description = !empty($attributes['customDescription']) ? $attributes['customDescription'] : '';
634
635 // Create a unique hash based on content attributes
636 $content_hash = md5($custom_thumnail . $custom_title . $custom_description . $content_id);
637
638 // Encode for URL usage
639 $custom_thumnail = urlencode($custom_thumnail);
640 $custom_title = urlencode($custom_title);
641 $custom_description = urlencode($custom_description);
642
643 // Get social share options with defaults
644 $facebook_enabled = isset($attributes['shareFacebook']) ? $attributes['shareFacebook'] !== false : true;
645 $twitter_enabled = isset($attributes['shareTwitter']) ? $attributes['shareTwitter'] !== false : true;
646 $pinterest_enabled = isset($attributes['sharePinterest']) ? $attributes['sharePinterest'] !== false : true;
647 $linkedin_enabled = isset($attributes['shareLinkedin']) ? $attributes['shareLinkedin'] !== false : true;
648 $style = isset($attributes['width']) ? 'style="max-width: ' . esc_attr($attributes['width']) . 'px;"' : '';
649
650
651 $page_url = urlencode(get_permalink() . '?hash=' . $content_id . '&unique=' . $content_hash);
652
653 $social_icons = '<div class="ep-social-share-wraper"' . $style . ' ><div class="ep-social-share share-position-' . esc_attr($share_position) . '">';
654
655
656 // Facebook
657 if ($facebook_enabled) {
658 $social_icons .= '<a href="https://www.facebook.com/sharer/sharer.php?u=' . $page_url . '" class="ep-social-icon facebook" target="_blank">
659 <svg width="64px" height="64px" fill="#000000" viewBox="0 -6 512 512" xmlns="http://www.w3.org/2000/svg">
660 <path d="M0 0h512v500H0z" fill="#475a96"/>
661 <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"/>
662 </svg>
663 </a>';
664 }
665
666 // Twitter
667 if ($twitter_enabled) {
668 $social_icons .= '<a href="https://twitter.com/intent/tweet?url=' . $page_url . '&text=' . $custom_title . '" class="ep-social-icon twitter" target="_blank">
669 <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>
670 </a>';
671 }
672
673 // Pinterest
674 if ($pinterest_enabled) {
675 $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">
676
677 <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>
678
679 </a>';
680 }
681
682 // LinkedIn
683 if ($linkedin_enabled) {
684 $social_icons .= '<a href="https://www.linkedin.com/shareArticle?mini=true&url=' . $page_url . '" class="ep-social-icon linkedin" target="_blank">
685
686 <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"
687 viewBox="0 0 310 310" xml:space="preserve">
688 <g id="XMLID_801_">
689 <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
690 C77.16,101.969,74.922,99.73,72.16,99.73z"/>
691 <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
692 c22.626,0,41.033-18.41,41.033-41.038C82.1,18.743,63.692,0.341,41.066,0.341z"/>
693 <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
694 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
695 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
696 C310,145.43,300.549,94.761,230.454,94.761z"/>
697 </g>
698 </svg>
699 </a>';
700 }
701
702 $social_icons .= '</div></div>';
703
704 return $social_icons;
705 }
706
707 public static function ep_get_elementor_widget_settings($page_settings = '', $id = '', $widgetType = '')
708 {
709 if (empty($page_settings)) {
710 return [];
711 }
712
713 // Handle both string and array cases for elementor data
714 if (is_string($page_settings)) {
715 $data = json_decode($page_settings, true);
716 } else {
717 // Data might already be an array in older versions
718 $data = $page_settings;
719 }
720 $element_setting = null;
721
722 Plugin::$instance->db->iterate_data($data, function ($element) use (&$element_setting, $widgetType, $id) {
723
724 if ($element['id'] == $id && $element['elType'] == 'widget' && $element['widgetType'] == $widgetType) {
725 $element_setting[] = $element['settings'];
726 }
727 });
728
729 return $element_setting;
730 }
731
732
733
734 public static function ep_get_popup_icon()
735 {
736 $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>';
737
738 return $svg;
739 }
740 public static function ep_get_download_icon()
741 {
742 $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>';
743
744 return $svg;
745 }
746
747 public static function ep_get_print_icon()
748 {
749 $svg = '<div class="ep-doc-print-icon" ><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24">
750 <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"/>
751 </svg></div>';
752
753 return $svg;
754 }
755
756 public static function ep_get_fullscreen_icon()
757 {
758 $svg = '<div class="ep-doc-fullscreen-icon"><svg width="25" height="25" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
759 <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"/>
760 </svg></div>';
761
762 return $svg;
763 }
764 public static function ep_get_minimize_icon()
765 {
766 $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>';
767
768 return $svg;
769 }
770 public static function ep_get_draw_icon()
771 {
772 $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>';
773
774 return $svg;
775 }
776
777 public static function get_insta_video_icon()
778 {
779 $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">
780 <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>';
781
782 return $svg;
783 }
784
785 public static function get_insta_image_carousel_icon()
786 {
787 $svg = '<svg aria-label="Carousel" class="x1lliihq x1n2onr6" color="#FFF" fill="#FFF" height="25" viewBox="0 0 43.636 43.636" width="25">
788 <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>';
789
790 return $svg;
791 }
792
793 public static function get_insta_image_icon()
794 {
795 $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>';
796
797 return $svg;
798 }
799
800 public static function get_insta_like_icon()
801 {
802 $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>';
803
804 return $svg;
805 }
806 public static function get_insta_comment_icon()
807 {
808 $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>';
809
810 return $svg;
811 }
812 public static function get_instagram_icon()
813 {
814 $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>';
815
816 return $svg;
817 }
818
819 public static function get_google_presentation_url($embedded_url)
820 {
821 $parsed_url = parse_url($embedded_url);
822 $base_url = $parsed_url['scheme'] . '://' . $parsed_url['host'] . $parsed_url['path'];
823 $base_url = strtok($base_url, '?');
824 $base_url = rtrim($base_url, '/');
825 return $base_url;
826 }
827
828 public static function check_media_format($url)
829 {
830 // Strip query/hash so signed streaming URLs (Mux, CloudFront) match.
831 $path = preg_replace('/[?#].*$/', '', (string) $url);
832 $pattern1 = '/\.(mp4|mov|avi|wmv|flv|mkv|webm|mpeg|mpg|m3u8|mpd)$/i';
833 $pattern2 = '/\.(mp3|wav|ogg|aac)$/i';
834
835 $isVideo = preg_match($pattern1, $path);
836 $isAudio = preg_match($pattern2, $path);
837
838 $is_self_hosted = false;
839 $format = '';
840
841 if (!empty($isVideo) || !empty($isAudio)) {
842 $is_self_hosted = true;
843 if (!empty($isVideo)) {
844 $format = 'video';
845 } else if (!empty($isAudio)) {
846 $format = 'audio';
847 }
848 }
849
850 if (!$is_self_hosted) {
851 return [
852 'selhosted' => false,
853 ];
854 }
855
856 return [
857 'selhosted' => true,
858 'format' => $format,
859 ];
860 }
861
862 // Ajax Methods get instagram feed data
863 public function loadmore_data_handler()
864 {
865 $connected_account_type = isset($_POST['connected_account_type']) ? sanitize_text_field($_POST['connected_account_type']) : 'personal';
866 $hashtag_id = isset($_POST['hashtag_id']) ? sanitize_text_field($_POST['hashtag_id']) : '';
867 $feed_type = isset($_POST['feed_type']) ? sanitize_text_field($_POST['feed_type']) : 'user_aacount_type';
868 $user_id = isset($_POST['user_id']) ? sanitize_text_field($_POST['user_id']) : '';
869 $loadmore_key = isset($_POST['loadmore_key']) ? sanitize_text_field($_POST['loadmore_key']) : '';
870 $nonce = isset($_POST['_nonce']) ? sanitize_text_field($_POST['_nonce']) : '';
871 $params = isset($_POST['params']) ? sanitize_text_field($_POST['params']) : '';
872 // $params = json_decode($params, true);
873 $params = stripslashes($params); // Remove extra backslashes
874 $params = json_decode($params, true);
875
876 // Verify nonce
877 if (!wp_verify_nonce($nonce, 'ep_nonce')) {
878 wp_send_json_error('Invalid nonce');
879 wp_die(); // Terminate script execution if nonce is invalid
880 }
881
882 $feeds_data = get_option('ep_instagram_feed_data');
883 $user_data = $feeds_data[$user_id]['feed_userinfo'];
884
885 if ($feed_type == 'hashtag_type') {
886 $feeds_data = get_option('ep_instagram_hashtag_feed');
887 }
888
889
890 $profile_picture_url = isset($user_data['profile_picture_url']) ? $user_data['profile_picture_url'] : '';
891
892 if ($feed_type === 'user_account_type' && isset($feeds_data[$loadmore_key]['feed_posts'])) {
893 $feed_posts = $feeds_data[$loadmore_key]['feed_posts'];
894 } else if ($feed_type === 'hashtag_type' && isset($feeds_data[$loadmore_key])) {
895 $feed_posts = $feeds_data[$loadmore_key];
896 } else {
897 $feed_posts = ['error'];
898 }
899
900
901 if (is_array($feed_posts) && count($feed_posts) > 0) {
902 $loaded_posts = isset($_POST['loaded_posts']) ? intval($_POST['loaded_posts']) : 0;
903 $posts_per_page = isset($_POST['posts_per_page']) ? intval($_POST['posts_per_page']) : 0;
904
905 $post_index = $loaded_posts + 1;
906 $start_index = $loaded_posts;
907
908 $next_posts = array_slice($feed_posts, $start_index, $posts_per_page);
909
910 ob_start();
911
912 if (is_array($next_posts) && count($next_posts) > 0) :
913 foreach ($next_posts as $post) :
914 $caption = !empty($post['caption']) ? $post['caption'] : '';
915 $media_type = !empty($post['media_type']) ? $post['media_type'] : '';
916 $media_url = !empty($post['media_url']) ? $post['media_url'] : '';
917 $permalink = !empty($post['permalink']) ? $post['permalink'] : '';
918 $timestamp = !empty($post['timestamp']) ? $post['timestamp'] : '';
919 $username = !empty($post['username']) ? $post['username'] : '';
920 $like_count = !empty($post['like_count']) ? $post['like_count'] : 0;
921 $comments_count = !empty($post['comments_count']) ? $post['comments_count'] : 0;
922
923 $post['profile_picture_url'] = $profile_picture_url;
924 $post['show_likes_count'] = isset($params['show_likes_count']) ? $params['show_likes_count'] : false;
925 $post['show_comments_count'] = isset($params['show_comments_count']) ? $params['show_comments_count'] : false;
926 $post['popup_follow_button'] = isset($params['popup_follow_button']) ? $params['popup_follow_button'] : true;
927 $post['popup_follow_button_text'] = isset($params['popup_follow_button_text']) ? $params['popup_follow_button_text'] : 'Follow';
928 ?>
929
930 <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); ?>">
931 <?php
932
933 if (!empty($hashtag_id) && $media_type == 'CAROUSEL_ALBUM') {
934 if (isset($post['children']['data'][0]['media_url'])) {
935 $hashtag_media_url = $post['children']['data'][0]['media_url'];
936 $hashtag_media_type = $post['children']['data'][0]['media_type'];
937
938 if ($hashtag_media_type == 'VIDEO') {
939 echo '<video class="insta-gallery-image" src="' . esc_url($hashtag_media_url) . '"></video>';
940 } else {
941 echo ' <img class="insta-gallery-image" src="' . esc_url($hashtag_media_url) . '" alt="' . esc_attr('image') . '">';
942 }
943 }
944 } else {
945 if ($media_type == 'VIDEO') {
946 echo '<video class="insta-gallery-image" src="' . esc_url($media_url) . '"></video>';
947 } else {
948 echo ' <img class="insta-gallery-image" src="' . esc_url($media_url) . '" alt="' . esc_attr('image') . '">';
949 }
950 }
951 ?>
952
953 <div class="insta-gallery-item-type">
954 <div class="insta-gallery-item-type-icon">
955 <?php
956 if ($media_type == 'VIDEO') {
957 echo Helper::get_insta_video_icon();
958 } else if ($media_type == 'CAROUSEL_ALBUM') {
959 echo Helper::get_insta_image_carousel_icon();
960 } else {
961 echo Helper::get_insta_image_icon();
962 }
963 ?>
964 </div>
965 </div>
966 <div class="insta-gallery-item-info">
967 <?php if (apply_filters('embedpress/is_allow_rander', false)): ?>
968 <div class="insta-item-reaction-count">
969 <div class="insta-gallery-item-likes">
970 <?php echo Helper::get_insta_like_icon();
971 echo esc_html($like_count); ?>
972 </div>
973 <div class="insta-gallery-item-comments">
974 <?php echo Helper::get_insta_comment_icon();
975 echo esc_html($comments_count); ?>
976 </div>
977 </div>
978 <?php else : ?>
979 <div class="insta-gallery-item-permalink">
980 <?php echo Helper::get_instagram_icon(); ?>
981 </div>
982 <?php endif; ?>
983 </div>
984 </div>
985
986 <?php $post_index++;
987 endforeach;
988 endif;
989
990 $feed_item = ob_get_clean();
991
992 $next_start_index = $start_index + count($next_posts);
993
994 wp_send_json(array(
995 'html' => $feed_item,
996 'next_post_index' => $next_start_index,
997 'total_feed_posts' => count($feed_posts)
998 ));
999 } else {
1000 wp_send_json('');
1001 }
1002 }
1003
1004 public static function getCalendlyUuid($url)
1005 {
1006 $pattern = '/\/([0-9a-fA-F-]+)$/';
1007 if (preg_match($pattern, $url, $matches)) {
1008 $uuid = $matches[1];
1009 return $uuid;
1010 }
1011 return '';
1012 }
1013
1014 public static function getCalendlyUserInfo($access_token)
1015 {
1016 $transient_name = 'calendly_user_info_' . $access_token;
1017 $user_info = get_transient($transient_name);
1018 if (false === $user_info) {
1019 $user_endpoint = 'https://api.calendly.com/users/me';
1020 $headers = array(
1021 'Authorization' => "Bearer $access_token",
1022 'Content-Type' => 'application/json',
1023 );
1024 $args = array(
1025 'headers' => $headers,
1026 );
1027 $response = wp_remote_get($user_endpoint, $args);
1028 if (!is_wp_error($response) && 200 === wp_remote_retrieve_response_code($response)) {
1029 $user_info = wp_remote_retrieve_body($response);
1030 set_transient($transient_name, $user_info, 3600);
1031 } else {
1032 return false;
1033 }
1034 }
1035
1036 return $user_info;
1037 }
1038
1039
1040
1041 public static function getCalaendlyEventTypes($user_uri, $access_token)
1042 {
1043 // Attempt to retrieve the data from the transient
1044 $events_list = get_transient('calendly_events_list_' . md5($access_token));
1045
1046 if (false === $events_list) {
1047 // If the data is not in the transient, fetch it from the API
1048 $events_endpoint = "https://api.calendly.com/event_types?user=$user_uri";
1049
1050 $headers = array(
1051 'Authorization' => "Bearer $access_token",
1052 'Content-Type' => 'application/json',
1053 );
1054
1055 $args = array(
1056 'headers' => $headers,
1057 );
1058
1059 $response = wp_remote_get($events_endpoint, $args);
1060
1061 if (!is_wp_error($response)) {
1062 $body = wp_remote_retrieve_body($response);
1063 $events_list = json_decode($body, true);
1064
1065 // Store the data in a transient for a specified time (e.g., 1 hour)
1066 set_transient('calendly_events_list', $events_list, HOUR_IN_SECONDS);
1067
1068 return $events_list;
1069 }
1070 }
1071
1072 return $events_list;
1073 }
1074
1075 public static function getListEventInvitee($uuid, $access_token)
1076 {
1077 // Attempt to retrieve the data from the transient
1078 $invitee_list = get_transient('calendly_invitee_list_' . md5($access_token));
1079
1080 if (false === $invitee_list) {
1081 // If the data is not in the transient, fetch it from the API
1082 $events_endpoint = "https://api.calendly.com/scheduled_events/$uuid/invitees";
1083
1084 $headers = array(
1085 'Authorization' => "Bearer $access_token",
1086 'Content-Type' => 'application/json',
1087 );
1088
1089 $args = array(
1090 'headers' => $headers,
1091 );
1092
1093 $response = wp_remote_get($events_endpoint, $args);
1094
1095 if (!is_wp_error($response)) {
1096 $body = wp_remote_retrieve_body($response);
1097 $invitee_list = json_decode($body, true);
1098
1099 // Store the data in a transient for a specified time (e.g., 1 hour)
1100 set_transient('calendly_invitee_list', $invitee_list, HOUR_IN_SECONDS);
1101
1102 return $invitee_list;
1103 }
1104 }
1105
1106 return $invitee_list;
1107 }
1108
1109 public static function getCalaendlyScheduledEvents($user_uri, $access_token)
1110 {
1111 // Attempt to retrieve the data from the transient
1112 $events_list = get_transient('calendly_events_list_' . md5($access_token));
1113
1114 if (false === $events_list) {
1115 // If the data is not in the transient, fetch it from the API
1116 $events_endpoint = "https://api.calendly.com/scheduled_events?user=$user_uri";
1117
1118 $headers = array(
1119 'Authorization' => "Bearer $access_token",
1120 'Content-Type' => 'application/json',
1121 );
1122
1123 $args = array(
1124 'headers' => $headers,
1125 );
1126
1127 $response = wp_remote_get($events_endpoint, $args);
1128
1129 if (!is_wp_error($response)) {
1130 $body = wp_remote_retrieve_body($response);
1131 $events_list = json_decode($body, true);
1132
1133 // Store the data in a transient for a specified time (e.g., 1 hour)
1134 set_transient('calendly_events_list', $events_list, HOUR_IN_SECONDS);
1135
1136 return $events_list;
1137 }
1138 }
1139
1140 return $events_list;
1141 }
1142
1143
1144 public static function parseDuration($durationString)
1145 {
1146 list($minutes, $seconds) = explode(':', $durationString);
1147 return intval($minutes) * 60 + intval($seconds);
1148 }
1149
1150
1151
1152
1153 public static function is_pro_active()
1154 {
1155 if (defined('EMBEDPRESS_SL_ITEM_SLUG')) {
1156 return true;
1157 }
1158 return false;
1159 }
1160
1161 /**
1162 * Check if pro features should be enabled based on license status
1163 *
1164 * @return bool True if pro features should be enabled, false otherwise
1165 */
1166 public static function is_pro_features_enabled()
1167 {
1168 // First check if pro plugin is active
1169 if (!self::is_pro_active()) {
1170 return false;
1171 }
1172
1173 // Get license status
1174 $license_status = get_option('embedpress_pro_software__license_status', '');
1175
1176 // Pro features are enabled only if license is valid
1177 return $license_status === 'valid';
1178 }
1179
1180 /**
1181 * Get detailed license information
1182 *
1183 * @return array License information including status, key, and data
1184 */
1185 public static function get_license_info()
1186 {
1187 $is_pro_active = self::is_pro_active();
1188 $license_status = '';
1189 $license_key = '';
1190 $license_data = [];
1191 $is_features_enabled = false;
1192
1193 if ($is_pro_active) {
1194 $license_status = get_option('embedpress_pro_software__license_status', '');
1195 $license_data_raw = get_transient('embedpress_pro_software__license_data');
1196
1197 if ($license_data_raw) {
1198 $license_data = json_decode(json_encode($license_data_raw), true);
1199 $license_key = isset($license_data['license_key']) ? $license_data['license_key'] : '';
1200 }
1201
1202 $is_features_enabled = ($license_status === 'valid');
1203 }
1204
1205 return [
1206 'is_pro_active' => $is_pro_active,
1207 'license_status' => $license_status,
1208 'license_key' => $license_key,
1209 'license_data' => $license_data,
1210 'is_features_enabled' => $is_features_enabled,
1211 'status_message' => self::get_license_status_message($is_pro_active, $license_status)
1212 ];
1213 }
1214
1215 /**
1216 * Display license warning notice for pro features
1217 *
1218 * @param string $context Context where the notice is displayed (e.g., 'analytics', 'branding')
1219 * @return string HTML for the license warning notice
1220 */
1221 public static function get_pro_feature_notice($context = '')
1222 {
1223 $license_info = self::get_license_info();
1224
1225 if (!$license_info['is_pro_active']) {
1226 return '<div class="embedpress-pro-notice embedpress-notice-warning">
1227 <p><strong>' . __('EmbedPress Pro Required', 'embedpress') . '</strong></p>
1228 <p>' . __('This feature requires EmbedPress Pro. Please install and activate EmbedPress Pro to access this feature.', 'embedpress') . '</p>
1229 </div>';
1230 }
1231
1232 if (!$license_info['is_features_enabled']) {
1233 $message = $license_info['status_message'];
1234 $action_text = '';
1235 $action_link = admin_url('admin.php?page=embedpress&page_type=license');
1236
1237 switch ($license_info['license_status']) {
1238 case 'expired':
1239 $action_text = __('Renew License', 'embedpress');
1240 break;
1241 case 'invalid':
1242 case 'site_inactive':
1243 case 'disabled':
1244 case 'revoked':
1245 $action_text = __('Activate License', 'embedpress');
1246 break;
1247 default:
1248 $action_text = __('Activate License', 'embedpress');
1249 break;
1250 }
1251
1252 return '<div class="embedpress-pro-notice embedpress-notice-error">
1253 <p><strong>' . __('Pro Features Disabled', 'embedpress') . '</strong></p>
1254 <p>' . esc_html($message) . '</p>
1255 <p><a href="' . esc_url($action_link) . '" class="button button-primary">' . esc_html($action_text) . '</a></p>
1256 </div>';
1257 }
1258
1259 return '';
1260 }
1261
1262 /**
1263 * Initialize license checking hooks
1264 */
1265 public static function init_license_hooks()
1266 {
1267 // Add filter to disable pro features when license is not valid
1268 add_filter('embedpress_pro_features_enabled', [__CLASS__, 'is_pro_features_enabled']);
1269
1270 // Add action to show license notices in admin
1271 add_action('admin_notices', [__CLASS__, 'show_license_admin_notices']);
1272
1273 // Add styles for license notices
1274 add_action('admin_head', [__CLASS__, 'add_license_notice_styles']);
1275 }
1276
1277 /**
1278 * Show license admin notices
1279 */
1280 public static function show_license_admin_notices()
1281 {
1282 // Only show on EmbedPress admin pages
1283 if (!isset($_GET['page']) || $_GET['page'] !== 'embedpress') {
1284 return;
1285 }
1286
1287 $license_info = self::get_license_info();
1288
1289 if ($license_info['is_pro_active'] && !$license_info['is_features_enabled']) {
1290 $message = $license_info['status_message'];
1291 $action_link = admin_url('admin.php?page=embedpress&page_type=license');
1292 $action_text = $license_info['license_status'] === 'expired' ? __('Renew License', 'embedpress') : __('Activate License', 'embedpress');
1293
1294 echo '<div class="notice notice-warning is-dismissible">
1295 <p><strong>' . __('EmbedPress Pro Features Disabled', 'embedpress') . '</strong></p>
1296 <p>' . esc_html($message) . '</p>
1297 <p><a href="' . esc_url($action_link) . '" class="button button-primary">' . esc_html($action_text) . '</a></p>
1298 </div>';
1299 }
1300 }
1301
1302 /**
1303 * Add CSS styles for license notices
1304 */
1305 public static function add_license_notice_styles()
1306 {
1307 echo '<style>
1308 .embedpress-pro-notice {
1309 padding: 15px;
1310 margin: 15px 0;
1311 border-left: 4px solid #dc3545;
1312 background: #fff;
1313 box-shadow: 0 1px 1px rgba(0,0,0,.04);
1314 }
1315 .embedpress-pro-notice.embedpress-notice-warning {
1316 border-left-color: #ffb900;
1317 }
1318 .embedpress-pro-notice.embedpress-notice-error {
1319 border-left-color: #dc3545;
1320 }
1321 .embedpress-pro-notice p {
1322 margin: 0.5em 0;
1323 }
1324 .embedpress-pro-notice strong {
1325 color: #23282d;
1326 }
1327 .embedpress-text-error {
1328 color: #dc3545 !important;
1329 }
1330 .embedpress-text-warning {
1331 color: #ffb900 !important;
1332 }
1333 </style>';
1334 }
1335
1336 /**
1337 * Get user-friendly license status message
1338 *
1339 * @param bool $is_pro_active Whether pro plugin is active
1340 * @param string $license_status Current license status
1341 * @return string User-friendly status message
1342 */
1343 public static function get_license_status_message($is_pro_active, $license_status)
1344 {
1345 if (!$is_pro_active) {
1346 return __('EmbedPress Pro is not installed or activated.', 'embedpress');
1347 }
1348
1349 switch ($license_status) {
1350 case 'valid':
1351 return __('Your license is active and valid.', 'embedpress');
1352 case 'expired':
1353 return __('Your license has expired. Please renew to continue receiving updates and support.', 'embedpress');
1354 case 'invalid':
1355 case 'site_inactive':
1356 return __('Your license is not active for this URL. Please activate your license.', 'embedpress');
1357 case 'disabled':
1358 case 'revoked':
1359 return __('Your license key has been disabled or revoked.', 'embedpress');
1360 case 'missing':
1361 return __('License key is missing. Please enter your license key.', 'embedpress');
1362 case 'http_error':
1363 return __('Unable to verify license due to connection issues. Please try again later.', 'embedpress');
1364 case '':
1365 case false:
1366 default:
1367 return __('Please activate your license key to enable EmbedPress Pro features.', 'embedpress');
1368 }
1369 }
1370
1371
1372 public static function getInstagramUserInfo($accessToken, $accountType, $userId, $is_sync = false)
1373 {
1374 if ($is_sync) {
1375 // If $is_sync is true, don't use transient
1376 $use_transient = false;
1377 } else {
1378 // If $is_sync is false, use transient
1379 $transient_key = 'instagram_user_info_' . $userId;
1380 $use_transient = true;
1381 }
1382
1383 if ($use_transient && false !== ($userInfo = get_transient($transient_key))) {
1384 // If transient exists, return cached user info
1385 return $userInfo;
1386 }
1387
1388 if (strtolower($accountType) === 'personal') {
1389 $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;
1390 } else {
1391 $api_url = 'https://graph.facebook.com/' . $userId . '?fields=biography,id,username,website,followers_count,media_count,profile_picture_url,name&access_token=' . $accessToken;
1392 }
1393
1394 $connected_account_type = $accountType;
1395
1396 $userInfoResponse = wp_remote_get($api_url);
1397
1398 if (is_wp_error($userInfoResponse)) {
1399 echo 'Error: Unable to retrieve Instagram user information.';
1400 } else {
1401 $userInfoBody = wp_remote_retrieve_body($userInfoResponse);
1402 $userInfo = json_decode($userInfoBody, true);
1403
1404 $userInfo['connected_account_type'] = $connected_account_type;
1405 $userInfo['access_token'] = $accessToken;
1406
1407
1408 if (!isset($userInfo['profile_picture_url'])) {
1409 $userInfo['profile_picture_url'] = '';
1410 }
1411
1412 // If not using transient, cache the user info for an hour
1413 if ($use_transient) {
1414 set_transient($transient_key, $userInfo, HOUR_IN_SECONDS);
1415 }
1416
1417 return $userInfo;
1418 }
1419 }
1420
1421
1422 // Get Instagram posts, videos, reels
1423 public static function getInstagramPosts($access_token, $account_type, $userId, $limit = 100, $is_sync = false)
1424 {
1425 if ($is_sync) {
1426 // If $is_sync is true, don't use transient
1427 $use_transient = false;
1428 } else {
1429 // If $is_sync is false, use transient
1430 $transient_key = 'instagram_posts_' . $userId;
1431 $use_transient = true;
1432 }
1433
1434 if ($use_transient && false !== ($posts = get_transient($transient_key))) {
1435 // If transient exists, return cached posts
1436 return $posts;
1437 }
1438
1439 if (strtolower($account_type) === 'personal') {
1440 $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;
1441 } else {
1442 $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;
1443 }
1444
1445 $postsResponse = wp_remote_get($api_url);
1446
1447 if (is_wp_error($postsResponse)) {
1448 echo 'Error: Unable to retrieve Instagram posts.';
1449 } else {
1450 $postsBody = wp_remote_retrieve_body($postsResponse);
1451 $posts = json_decode($postsBody, true);
1452
1453 if (empty($posts['data'])) {
1454 return 'Please add Instagram Access Token';
1455 }
1456
1457 // If not using transient, cache the posts for an hour
1458 if ($use_transient) {
1459 set_transient($transient_key, $posts['data'], HOUR_IN_SECONDS);
1460 }
1461
1462 return $posts['data'];
1463 }
1464 }
1465
1466 public static function get_enable_settings_data_for_scripts($settings)
1467 {
1468 $settings_data = [
1469 'enabled_ads' => isset($settings['adManager']) && $settings['adManager'] === 'yes' ? 'yes' : '',
1470
1471 'enabled_custom_player' => isset($settings['emberpress_custom_player']) && $settings['emberpress_custom_player'] === 'yes' ? 'yes' : '',
1472
1473 'enabled_instafeed' => isset($settings['embedpress_pro_embeded_source']) && $settings['embedpress_pro_embeded_source'] === 'instafeed' ? 'yes' : '',
1474
1475 'enabled_docs_custom_viewer' => isset($settings['embedpress_document_viewer']) && $settings['embedpress_document_viewer'] === 'custom' ? 'yes' : '',
1476 ];
1477
1478 update_option('enabled_elementor_scripts', $settings_data);
1479 }
1480
1481 public static function get_options_value($key)
1482 {
1483 $g_settings = get_option(EMBEDPRESS_PLG_NAME);
1484
1485 if (isset($g_settings['enableEmbedResizeWidth']) && $g_settings['enableEmbedResizeWidth'] == 1) {
1486 $g_settings['enableEmbedResizeWidth'] = 600;
1487 update_option(EMBEDPRESS_PLG_NAME, $g_settings);
1488 }
1489 if (isset($g_settings['enableEmbedResizeHeight']) && $g_settings['enableEmbedResizeHeight'] == 1) {
1490 $g_settings['enableEmbedResizeHeight'] = 600;
1491 update_option(EMBEDPRESS_PLG_NAME, $g_settings);
1492 }
1493
1494 if (isset($g_settings[$key])) {
1495 return $g_settings[$key];
1496 }
1497
1498 return '';
1499 }
1500
1501
1502
1503 public static function get_branding_value($key, $provider)
1504 {
1505 $settings = get_option(EMBEDPRESS_PLG_NAME . ':' . $provider, []);
1506
1507 // Check if provider has custom branding enabled and the specific key set
1508 if (isset($settings['branding']) && $settings['branding'] === 'yes') {
1509 // If provider has custom logo, use it
1510 if (isset($settings[$key]) && !empty($settings[$key])) {
1511 return $settings[$key];
1512 }
1513
1514 // If branding is enabled but no custom logo, use global brand as fallback
1515 if ($key === 'logo_url') {
1516 $global_logo = self::get_global_brand_logo_url();
1517 if (!empty($global_logo)) {
1518 return $global_logo;
1519 }
1520 }
1521 }
1522
1523 return '';
1524 }
1525
1526 /**
1527 * Get global brand logo URL
1528 *
1529 * @return string
1530 */
1531 public static function get_global_brand_logo_url()
1532 {
1533 $global_brand_settings = get_option(EMBEDPRESS_PLG_NAME . ':global_brand', []);
1534 return isset($global_brand_settings['logo_url']) ? $global_brand_settings['logo_url'] : '';
1535 }
1536
1537 /**
1538 * Get global brand logo ID
1539 *
1540 * @return int
1541 */
1542 public static function get_global_brand_logo_id()
1543 {
1544 $global_brand_settings = get_option(EMBEDPRESS_PLG_NAME . ':global_brand', []);
1545 return isset($global_brand_settings['logo_id']) ? intval($global_brand_settings['logo_id']) : 0;
1546 }
1547
1548
1549 public static function format_number($number)
1550 {
1551 if ($number >= 1000000000) {
1552 return number_format($number / 1000000000, 1) . 'b';
1553 } elseif ($number >= 1000000) {
1554 return number_format($number / 1000000, 1) . 'm';
1555 } elseif ($number >= 1000) {
1556 return number_format($number / 1000, 1) . 'k';
1557 } else {
1558 return $number;
1559 }
1560 }
1561
1562 public static function get_id($item)
1563 {
1564 $vid = isset($item->snippet->resourceId->videoId) ? $item->snippet->resourceId->videoId : null;
1565 $vid = $vid ? $vid : (isset($item->id->videoId) ? $item->id->videoId : null);
1566 $vid = $vid ? $vid : (isset($item->id) ? $item->id : null);
1567 return $vid;
1568 }
1569
1570 public static function clean_api_error($raw_message)
1571 {
1572 return htmlspecialchars(strip_tags(preg_replace('@&key=[^& ]+@i', '&key=*******', $raw_message)));
1573 }
1574
1575 public static function clean_api_error_html($raw_message)
1576 {
1577 $clean_html = '';
1578 if ((defined('REST_REQUEST') && REST_REQUEST) || current_user_can('manage_options')) {
1579 $clean_html = '<div>' . __('EmbedPress: ', 'embedpress') . self::clean_api_error($raw_message) . '</div>';
1580 }
1581 return $clean_html;
1582 }
1583
1584 public static function get_thumbnail_url($item, $quality, $privacyStatus)
1585 {
1586 $url = "";
1587 if ($privacyStatus == 'private') {
1588 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/private.png';
1589 } elseif (isset($item->snippet->thumbnails->{$quality}->url)) {
1590 $url = $item->snippet->thumbnails->{$quality}->url;
1591 } elseif (isset($item->snippet->thumbnails->medium->url)) {
1592 $url = $item->snippet->thumbnails->medium->url;
1593 } elseif (isset($item->snippet->thumbnails->default->url)) {
1594 $url = $item->snippet->thumbnails->default->url;
1595 } elseif (isset($item->snippet->thumbnails->high->url)) {
1596 $url = $item->snippet->thumbnails->high->url;
1597 } else {
1598 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/deleted-video-thumb.png';
1599 }
1600 return $url;
1601 }
1602
1603 public static function compare_vid_date($a, $b)
1604 {
1605 $dateA = strtotime($a->snippet->publishedAt);
1606 $dateB = strtotime($b->snippet->publishedAt);
1607
1608 // Sort in descending order (newest first)
1609 return $dateB - $dateA;
1610 }
1611
1612
1613 public static function get_youtube_video_data($api_key, $video_id)
1614 {
1615 // Set a unique transient name based on the video ID
1616 $transient_name = 'youtube_video_data_' . $video_id;
1617
1618 // Try to get data from the transient cache
1619 $video_data = get_transient($transient_name);
1620
1621 // If no cached data, fetch from the API
1622 if ($video_data === false) {
1623 // YouTube Data API URL
1624 $url = "https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id={$video_id}&key={$api_key}";
1625
1626 // Fetch the data from the API
1627 $response = wp_remote_get($url);
1628
1629 if (is_wp_error($response)) {
1630 return false; // Return false if there is an error
1631 }
1632
1633 $body = wp_remote_retrieve_body($response);
1634 $video_data = json_decode($body, true);
1635
1636 if (isset($video_data['items'][0])) {
1637 $video_data = $video_data['items'][0];
1638
1639 // Cache the data in a transient for 12 hours
1640 set_transient($transient_name, $video_data, 24 * HOUR_IN_SECONDS);
1641 } else {
1642 return false; // Return false if no data found
1643 }
1644 }
1645
1646 return $video_data;
1647 }
1648
1649 public static function trimTitle($title, $wordCount)
1650 {
1651 $words = explode(' ', $title);
1652
1653 if (count($words) <= $wordCount) {
1654 return $title; // No trimming needed
1655 }
1656
1657 $trimmedWords = array_slice($words, 0, $wordCount);
1658
1659 return implode(' ', $trimmedWords) . ' ...';
1660 }
1661
1662 public static function timeAgo($datetime)
1663 {
1664 $now = new \DateTime();
1665 $date = new \DateTime($datetime);
1666 $interval = $now->diff($date);
1667
1668 if ($interval->y > 0) {
1669 return $interval->y . ' year' . ($interval->y > 1 ? 's' : '') . ' ago';
1670 } elseif ($interval->m > 0) {
1671 return $interval->m . ' month' . ($interval->m > 1 ? 's' : '') . ' ago';
1672 } elseif ($interval->d > 0) {
1673 return $interval->d . ' day' . ($interval->d > 1 ? 's' : '') . ' ago';
1674 } elseif ($interval->h > 0) {
1675 return $interval->h . ' hour' . ($interval->h > 1 ? 's' : '') . ' ago';
1676 } elseif ($interval->i > 0) {
1677 return $interval->i . ' minute' . ($interval->i > 1 ? 's' : '') . ' ago';
1678 } else {
1679 return 'just now';
1680 }
1681 }
1682
1683 public static function removeQuote($attributes)
1684 {
1685 $parsedAttributes = [];
1686
1687 $regex = '/^on.*/i';
1688
1689 foreach ($attributes as $key => $value) {
1690 if (is_string($value)) {
1691 $cleanValue = str_replace(['"', "'"], '', $value);
1692 } else {
1693 $cleanValue = $value;
1694 }
1695
1696 if (!preg_match($regex, $key)) {
1697 $parsedAttributes[$key] = $cleanValue;
1698 }
1699 }
1700
1701 return $parsedAttributes;
1702 }
1703
1704 public static function getBooleanParam($param, $default = false)
1705 {
1706 if (in_array($param, [true, 'true', 'yes', 1, '1'], true)) {
1707 return true;
1708 }
1709 if (in_array($param, [false, 'false', 'no', 0, '0'], true)) {
1710 return false;
1711 }
1712 return (bool) $default;
1713 }
1714
1715 public static function has_allowed_roles($allowed_roles = [])
1716 {
1717
1718 if (empty($allowed_roles) || (count($allowed_roles) == 1 && empty($allowed_roles[0]))) {
1719 return true;
1720 }
1721 $current_user = wp_get_current_user();
1722 $user_roles = $current_user->roles;
1723
1724 return !empty(array_intersect($user_roles, $allowed_roles));
1725 }
1726
1727 public static function get_elementor_global_color($settings, $key)
1728 {
1729
1730 $global_color = $settings[$key];
1731
1732 if (isset($settings['__globals__'][$key])) {
1733 $color_setting = $settings['__globals__'][$key];
1734
1735 if (strpos($color_setting, 'globals/colors?id=') === 0) {
1736 // It's a global color reference
1737 $global_id = str_replace('globals/colors?id=', '', $color_setting);
1738
1739 $kit = Plugin::$instance->kits_manager->get_current_settings();
1740
1741 $system_colors = isset($kit['system_colors']) ? $kit['system_colors'] : [];
1742 $custom_colors = isset($kit['custom_colors']) ? $kit['custom_colors'] : [];
1743 $global_colors = array_merge($system_colors, $custom_colors);
1744
1745 foreach ($global_colors as $color) {
1746
1747 if ($color['_id'] === $global_id) {
1748 $global_color = $color['color']; // Found a match, set the color
1749 break;
1750 }
1751 }
1752 }
1753 }
1754 return $global_color;
1755 }
1756
1757 public static function get_provider_name($source_url)
1758 {
1759 if (self::is_youtube_channel($source_url)) {
1760 $source_name = 'YoutubeChannel';
1761 } else if (self::is_youtube($source_url)) {
1762 $source_name = 'Youtube';
1763 } else if (!empty(self::is_file_url($source_url))) {
1764 $source_name = 'document_' . self::get_extension_from_file_url($source_url);
1765 } else if (self::is_opensea($source_url)) {
1766 $source_name = 'OpenSea';
1767 } else if (self::is_instagram_feed($source_url)) {
1768 $source_name = 'InstagramFeed';
1769 }else {
1770 Shortcode::get_embera_instance();
1771 $collectios = Shortcode::get_collection();
1772 $provider = $collectios->findProviders($source_url);
1773
1774 if (!empty($provider[$source_url])) {
1775 $source_name = $provider[$source_url]->getProviderName();
1776 } else {
1777 $host = parse_url($source_url, PHP_URL_HOST);
1778 if ($host) {
1779 $parts = explode('.', $host);
1780 if (count($parts) > 1) {
1781 $source_name = $parts[1];
1782 } else {
1783 // Handle the case where the host doesn't have at least two parts
1784 $source_name = $host;
1785 }
1786 } else {
1787 // Handle the case where parse_url fails
1788 $source_name = '';
1789 }
1790 }
1791 }
1792
1793 return $source_name;
1794 }
1795
1796 public static function get_user_roles()
1797 {
1798 global $wp_roles; // Access global roles object
1799 $user_roles = [];
1800
1801 if (isset($wp_roles->roles) && is_array($wp_roles->roles)) {
1802 foreach ($wp_roles->roles as $role_key => $role_data) {
1803 $user_roles[] = [
1804 'value' => $role_key, // Machine-readable key
1805 'label' => $role_data['name'], // Human-readable name
1806 ];
1807 }
1808 }
1809
1810 return $user_roles;
1811 }
1812
1813 public static function has_content_allowed_roles($allowed_roles = [])
1814 {
1815 // Ensure it's always an array
1816 if (!is_array($allowed_roles)) {
1817 $allowed_roles = [];
1818 }
1819
1820 if (count($allowed_roles) === 1 && empty($allowed_roles[0])) {
1821 return true;
1822 }
1823
1824 $current_user = wp_get_current_user();
1825 $user_roles = $current_user->roles;
1826
1827 return !empty(array_intersect($user_roles, $allowed_roles));
1828 }
1829
1830
1831 }
1832