PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 4.5.1
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v4.5.1
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 / Gutenberg / EmbedPressBlockRenderer.php
embedpress / EmbedPress / Gutenberg Last commit date
BlockManager.php 2 months ago EmbedPressBlockRenderer.php 3 months ago FallbackHandler.php 9 months ago InitBlocks.php 9 months ago
EmbedPressBlockRenderer.php
1780 lines
1 <?php
2
3 namespace EmbedPress\Gutenberg;
4
5 use EmbedPress\Includes\Classes\Helper;
6 use EmbedPress\Shortcode;
7 use Exception;
8
9 if (!defined('ABSPATH')) {
10 exit;
11 }
12
13 /**
14 * EmbedPress Block Renderer
15 *
16 * Handles rendering of EmbedPress blocks for Gutenberg editor
17 * Manages dynamic content, content protection, and various embed configurations
18 *
19 * @package EmbedPress\Gutenberg
20 * @since 1.0.0
21 */
22 class EmbedPressBlockRenderer
23 {
24 /**
25 * Dynamic providers that require real-time content fetching
26 *
27 * @var array
28 */
29 private static $dynamic_providers = [
30 'photos.app.goo.gl',
31 'photos.google.com',
32 'instagram.com',
33 'opensea.io',
34 'wistia.com',
35 'wistia.net',
36 ];
37
38 /**
39 * Alignment mapping for CSS classes
40 *
41 * @var array
42 */
43 private static $alignment_classes = [
44 'left' => 'alignleft',
45 'right' => 'alignright',
46 'wide' => 'alignwide',
47 'full' => 'alignfull',
48 'center' => 'aligncenter',
49 ];
50
51 /**
52 * Check if URL belongs to a dynamic provider
53 *
54 * @param string $url The URL to check
55 * @return bool True if dynamic provider, false otherwise
56 */
57 public static function is_dynamic_provider($url)
58 {
59 foreach (self::$dynamic_providers as $provider) {
60 if (strpos($url, $provider) !== false) {
61 return true;
62 }
63 }
64
65 return false;
66 }
67
68 /**
69 * Render dynamic content using EmbedPress shortcode parsing
70 *
71 * @param array $attributes Block attributes
72 * @return string|null Rendered content or null on failure
73 */
74 public static function render_dynamic_content($attributes)
75 {
76 $url = $attributes['url'] ?? '';
77
78 if (!class_exists('\\EmbedPress\\Shortcode')) {
79 return null;
80 }
81
82 // Map Meetup-specific Gutenberg attributes to shortcode attributes
83 if (!empty($url) && strpos($url, 'meetup.com') !== false) {
84 if (isset($attributes['meetupOrderBy'])) {
85 $attributes['orderby'] = $attributes['meetupOrderBy'];
86 }
87 if (isset($attributes['meetupOrder'])) {
88 $attributes['order'] = $attributes['meetupOrder'];
89 }
90 if (isset($attributes['meetupPerPage'])) {
91 $attributes['per_page'] = $attributes['meetupPerPage'];
92 }
93 if (isset($attributes['meetupEnablePagination'])) {
94 $attributes['enable_pagination'] = $attributes['meetupEnablePagination'];
95 }
96 if (isset($attributes['meetupTimezone'])) {
97 $attributes['timezone'] = $attributes['meetupTimezone'];
98 }
99 if (isset($attributes['meetupDateFormat'])) {
100 $attributes['date_format'] = $attributes['meetupDateFormat'];
101 }
102 if (isset($attributes['meetupTimeFormat'])) {
103 $attributes['time_format'] = $attributes['meetupTimeFormat'];
104 }
105 }
106
107 try {
108 $embed_result = Shortcode::parseContent($url, false, $attributes);
109
110 if (is_object($embed_result) && isset($embed_result->embed) && !empty($embed_result->embed)) {
111 return $embed_result->embed;
112 }
113 } catch (Exception $e) {
114 if (defined('WP_DEBUG') && WP_DEBUG) {
115 error_log('EmbedPress: Shortcode parsing failed: ' . $e->getMessage());
116 }
117 }
118
119 return null;
120 }
121
122 /**
123 * Main render method for EmbedPress blocks
124 *
125 * @param array $attributes Block attributes
126 * @param string $content Block content
127 * @param object $block Block object (unused but kept for compatibility)
128 * @return string Rendered HTML content
129 */
130 public static function render($attributes, $content = '', $block = null)
131 {
132 // Extract basic attributes
133 $url = $attributes['url'] ?? '';
134 $client_id = !empty($attributes['clientId']) ? md5($attributes['clientId']) : '';
135
136 // Handle content protection
137 $protection_data = self::extract_protection_data($attributes, $client_id);
138 $should_display_content = self::should_display_content($protection_data);
139 $isAdManager = !empty($attributes['adManager']) ? true : false;
140
141
142 // Early return for non-dynamic providers with displayable content
143 if ((!empty($content) && !self::is_dynamic_provider($url)) && $should_display_content && !$isAdManager) {
144 return $content;
145 }
146
147 // Process embed HTML if available
148 if (!empty($attributes['embedHTML'])) {
149 return self::render_embed_html($attributes, $attributes['embedHTML'], $protection_data, $should_display_content);
150 }
151
152 return '';
153 }
154
155
156 /**
157 * Legacy PDF render method - organized following current structure
158 *
159 * @param array $attributes Block attributes
160 * @return string Rendered HTML content
161 */
162 public static function embedpress_pdf_legacy_render_block($attributes)
163 {
164 // Extract basic attributes for PDF block
165 $href = $attributes['href'] ?? '';
166 $id = $attributes['id'] ?? 'embedpress-pdf-' . rand(100, 10000);
167 $client_id = md5($id);
168
169 // If no href is provided, return empty
170 if (empty($href)) {
171 return '';
172 }
173
174 // Handle content protection using existing methods
175 $protection_data = self::extract_protection_data($attributes, $client_id);
176 $should_display_content = self::should_display_content($protection_data);
177
178 // Build styling configuration using existing method
179 $styling = self::build_styling_config($attributes, $protection_data);
180
181 // Generate legacy PDF HTML
182 return self::render_legacy_pdf_html($attributes, $protection_data, $should_display_content, $styling);
183 }
184
185 /**
186 * Render legacy PDF HTML structure
187 *
188 * @param array $attributes Block attributes
189 * @param array $protection_data Protection data
190 * @param bool $should_display_content Whether content should be displayed
191 * @param array $styling Styling configuration
192 * @return string Rendered HTML
193 */
194 private static function render_legacy_pdf_html($attributes, $protection_data, $should_display_content, $styling)
195 {
196 $href = $attributes['href'];
197 $id = $attributes['id'] ?? 'embedpress-pdf-' . rand(100, 10000);
198 $client_id = md5($id);
199
200 // Lightbox mode: render thumbnail instead of inline viewer
201 $displayMode = $attributes['displayMode'] ?? 'inline';
202 if ($displayMode === 'lightbox' && $should_display_content) {
203 return self::render_pdf_lightbox_thumbnail($attributes, $client_id);
204 }
205 if (in_array($displayMode, ['button', 'link', 'text']) && $should_display_content) {
206 return self::render_pdf_trigger($attributes, $client_id, $displayMode);
207 }
208
209 // Extract legacy-specific configurations
210 $legacy_config = self::extract_legacy_pdf_config($attributes);
211
212 // Generate embed code
213 $embed_code = self::generate_legacy_embed_code($attributes, $legacy_config);
214
215 // Build wrapper classes
216 $wrapper_classes = self::build_legacy_wrapper_classes($attributes, $styling, $legacy_config);
217
218 ob_start();
219 ?>
220 <div id="ep-gutenberg-content-<?php echo esc_attr($client_id) ?>" class="ep-gutenberg-content <?php echo esc_attr($wrapper_classes); ?>">
221 <div class="embedpress-inner-iframe <?php echo esc_attr($legacy_config['unit_class']); ?> ep-doc-<?php echo esc_attr($client_id); ?>" style="<?php echo esc_attr($legacy_config['style_attr']); ?>" id="<?php echo esc_attr($id); ?>">
222 <div <?php echo esc_attr($styling['ads_attrs']); ?>>
223 <?php
224 do_action('embedpress_pdf_gutenberg_after_embed', $client_id, 'pdf', $attributes, $href);
225
226 if ($should_display_content) {
227 self::render_legacy_displayable_content($embed_code, $attributes, $styling);
228 } else {
229 self::render_legacy_protected_content($embed_code, $attributes, $protection_data, $styling);
230 }
231
232 // Render ad template if enabled
233 if (!empty($attributes['adManager'])) {
234 $embed_code = apply_filters('embedpress/generate_ad_template', $embed_code, $client_id, $attributes, 'gutenberg');
235 }
236 ?>
237 </div>
238 </div>
239 </div>
240 <?php
241 return ob_get_clean();
242 }
243
244 /**
245 * Extract legacy PDF configuration
246 *
247 * @param array $attributes Block attributes
248 * @return array Legacy configuration
249 */
250 private static function extract_legacy_pdf_config($attributes)
251 {
252 $unitoption = $attributes['unitoption'] ?? 'px';
253 $width = !empty($attributes['width']) ? $attributes['width'] . $unitoption : (Helper::get_options_value('enableEmbedResizeWidth') ?: 600) . 'px';
254 $height = !empty($attributes['height']) ? $attributes['height'] . 'px' : (Helper::get_options_value('enableEmbedResizeHeight') ?: 600) . 'px';
255
256 $width_class = ($unitoption == '%') ? 'ep-percentage-width' : 'ep-fixed-width';
257 $unit_class = ($unitoption === '%') ? 'emebedpress-unit-percent' : '';
258
259 $style_attr = ($unitoption === '%' && !empty($attributes['width']))
260 ? 'max-width:' . $attributes['width'] . '%'
261 : 'max-width:100%';
262
263 $dimension = "width:$width;height:$height";
264
265 return [
266 'unitoption' => $unitoption,
267 'width' => $width,
268 'height' => $height,
269 'width_class' => $width_class,
270 'unit_class' => $unit_class,
271 'style_attr' => $style_attr,
272 'dimension' => $dimension,
273 ];
274 }
275
276 /**
277 * Generate legacy embed code
278 *
279 * @param array $attributes Block attributes
280 * @param array $legacy_config Legacy configuration
281 * @return string Embed code
282 */
283 private static function generate_legacy_embed_code($attributes, $legacy_config)
284 {
285 $href = $attributes['href'];
286 $id = $attributes['id'] ?? 'embedpress-pdf-' . rand(100, 10000);
287 $renderer = Helper::get_pdf_renderer();
288
289 $src = $renderer . ((strpos($renderer, '?') == false) ? '?' : '&') . 'file=' . urlencode($href) . self::generate_pdf_params($attributes);
290
291 $iframe_title = self::get_iframe_title_from_url($href);
292
293 $embed_code = '<iframe title="' . esc_attr($iframe_title) . '" class="embedpress-embed-document-pdf ' . esc_attr($id) . '" style="' . esc_attr($legacy_config['dimension']) . '; max-width:100%; display: inline-block" src="' . esc_url($src) . '" frameborder="0" oncontextmenu="return false;"></iframe> ';
294
295 // Handle flip-book viewer style
296 if (isset($attributes['viewerStyle']) && $attributes['viewerStyle'] === 'flip-book') {
297 $src = urlencode($href) . self::generate_pdf_params($attributes);
298 $renderer = Helper::get_flipbook_renderer();
299 $src_url = $renderer . ((strpos($renderer, '?') == false) ? '?' : '&') . 'file=' . $src;
300 $embed_code = '<iframe title="' . esc_attr(Helper::get_file_title($href)) . '" class="embedpress-embed-document-pdf ' . esc_attr($id) . '" style="' . esc_attr($legacy_config['dimension']) . '; max-width:100%; display: inline-block" src="' . esc_url($src_url) . '" frameborder="0" oncontextmenu="return false;"></iframe> ';
301 }
302
303 // Add powered by if enabled
304 $gen_settings = get_option(EMBEDPRESS_PLG_NAME);
305 $powered_by = isset($gen_settings['embedpress_document_powered_by']) && 'yes' === $gen_settings['embedpress_document_powered_by'];
306 if (isset($attributes['powered_by'])) {
307 $powered_by = $attributes['powered_by'];
308 }
309
310 if ($powered_by) {
311 $embed_code .= sprintf('<p class="embedpress-el-powered">%s</p>', __('Powered By EmbedPress', 'embedpress'));
312 }
313
314 return $embed_code;
315 }
316
317 /**
318 * Build legacy wrapper classes
319 *
320 * @param array $attributes Block attributes
321 * @param array $styling Styling configuration
322 * @param array $legacy_config Legacy configuration
323 * @return string CSS classes
324 */
325 private static function build_legacy_wrapper_classes($attributes, $styling, $legacy_config)
326 {
327 return trim(sprintf(
328 '%s %s %s %s %s',
329 $styling['alignment'],
330 $legacy_config['width_class'],
331 $styling['content_share_class'],
332 $styling['share_position_class'],
333 $styling['content_protection_class']
334 ));
335 }
336
337 /**
338 * Render legacy displayable content
339 *
340 * @param string $embed_code Embed code
341 * @param array $attributes Block attributes
342 * @param array $styling Styling configuration
343 */
344 private static function render_legacy_displayable_content($embed_code, $attributes, $styling)
345 {
346 $share_position = $attributes['sharePosition'] ?? 'right';
347 $content_id = $attributes['id'];
348
349 echo '<div class="ep-embed-content-wraper">';
350 $embed = '<div class="position-' . esc_attr($share_position) . '-wraper gutenberg-pdf-wraper">';
351 $embed .= $embed_code;
352 $embed .= '</div>';
353
354 if (!empty($attributes['contentShare'])) {
355 $embed .= Helper::embed_content_share($content_id, $attributes);
356 }
357 echo $embed;
358 echo '</div>';
359 }
360
361 /**
362 * Render legacy protected content
363 *
364 * @param string $embed_code Embed code
365 * @param array $attributes Block attributes
366 * @param array $protection_data Protection data
367 * @param array $styling Styling configuration
368 */
369 private static function render_legacy_protected_content($embed_code, $attributes, $protection_data, $styling)
370 {
371 $share_position = $attributes['sharePosition'] ?? 'right';
372 $client_id = $protection_data['client_id'];
373
374 // Initialize $embed variable
375 $embed = $embed_code;
376
377 if (!empty($attributes['contentShare'])) {
378 $content_id = $attributes['clientId'];
379 $embed = '<div class="position-' . esc_attr($share_position) . '-wraper gutenberg-pdf-wraper">';
380 $embed .= $embed_code;
381 $embed .= '</div>';
382 $embed .= Helper::embed_content_share($content_id, $attributes);
383 }
384
385 echo '<div class="ep-embed-content-wraper">';
386 if ($attributes['protectionType'] == 'password') {
387 echo '<div id="ep-gutenberg-content-' . esc_attr($client_id) . '" class="ep-gutenberg-content">';
388 do_action('embedpress/display_password_form', $client_id, $embed, $styling['pass_hash_key'], $attributes);
389 echo '</div>';
390 } else {
391 do_action('embedpress/content_protection_content', $client_id, $attributes['protectionMessage'], $attributes['userRole']);
392 }
393 echo '</div>';
394 }
395
396 public static function render_embedpress_pdf($attributes, $content = '', $block = null)
397 {
398
399 // Extract basic attributes for PDF block
400 $href = $attributes['href'] ?? '';
401 $client_id = !empty($attributes['id']) ? md5($attributes['id']) : '';
402
403 // Handle content protection
404 $protection_data = self::extract_protection_data($attributes, $client_id);
405 $should_display_content = self::should_display_content($protection_data);
406 $isAdManager = !empty($attributes['adManager']) ? true : false;
407
408
409 // For PDF blocks, if we have saved content and should display it, return the content
410 if (!empty($content) && $should_display_content && !$isAdManager) {
411 return $content;
412 }
413
414 // If no href is provided, return empty
415 if (empty($href)) {
416 return '';
417 }
418
419
420 if (empty($content)) {
421 return self::embedpress_pdf_legacy_render_block($attributes);
422 }
423
424
425 // Render PDF-specific HTML
426 return self::render_embedpress_pdf_html($attributes, $content, $protection_data, $should_display_content);
427 }
428
429 public static function render_document($attributes, $content = '', $block = null)
430 {
431
432 // Extract basic attributes for PDF block
433 $href = $attributes['href'] ?? '';
434 $client_id = !empty($attributes['id']) ? md5($attributes['id']) : '';
435
436 // Handle content protection
437 $protection_data = self::extract_protection_data($attributes, $client_id);
438 $should_display_content = self::should_display_content($protection_data);
439 $isAdManager = !empty($attributes['adManager']) ? true : false;
440
441 // For PDF blocks, if we have saved content and should display it, return the content
442 if (!empty($content) && $should_display_content && !$isAdManager) {
443 return $content;
444 }
445
446 // If no href is provided, return empty
447 if (empty($href)) {
448 return '';
449 }
450
451
452 // Render PDF-specific HTML
453 return self::render_embedpress_document_html($attributes, $content, $protection_data, $should_display_content);
454 }
455
456 /**
457 * Extract content protection related data from attributes
458 *
459 * @param array $attributes Block attributes
460 * @param string $client_id Client ID for the block
461 * @return array Protection data array
462 */
463 private static function extract_protection_data($attributes, $client_id)
464 {
465 $content_password = $attributes['contentPassword'] ?? '';
466 $hash_pass = hash('sha256', wp_salt(32) . md5($content_password));
467 $password_correct = $_COOKIE['password_correct_' . $client_id] ?? '';
468 return [
469 'content_password' => $content_password,
470 'hash_pass' => $hash_pass,
471 'password_correct' => $password_correct,
472 'protection_type' => $attributes['protectionType'] ?? '',
473 'lock_content' => $attributes['lockContent'] ?? '',
474 'user_role' => $attributes['userRole'] ?? '',
475 'content_share' => $attributes['contentShare'] ?? '',
476 'protection_message' => $attributes['protectionMessage'] ?? '',
477 'content_id' => $attributes['clientId'] ?? '',
478 'client_id' => $client_id,
479 ];
480 }
481
482 /**
483 * Determine if content should be displayed based on protection settings
484 *
485 * @param array $protection_data Protection data array
486 * @return bool True if content should be displayed
487 */
488 private static function should_display_content($protection_data)
489 {
490 return (
491 !apply_filters('embedpress/is_allow_rander', false) ||
492 empty($protection_data['lock_content']) ||
493 ($protection_data['protection_type'] === 'password' && empty($protection_data['content_password'])) ||
494 ($protection_data['protection_type'] === 'password' &&
495 !empty(Helper::is_password_correct($protection_data['client_id'])) &&
496 ($protection_data['hash_pass'] === $protection_data['password_correct'])) ||
497 ($protection_data['protection_type'] === 'user-role' &&
498 Helper::has_content_allowed_roles($protection_data['user_role']))
499 );
500 }
501
502 /**
503 * Render the embed HTML with all configurations
504 *
505 * @param array $attributes Block attributes
506 * @param string $content Block content
507 * @param array $protection_data Protection data
508 * @param bool $should_display_content Whether content should be displayed
509 * @return string Rendered HTML
510 */
511 private static function render_embed_html($attributes, $content, $protection_data, $should_display_content)
512 {
513 // Extract basic configuration
514 $config = self::extract_basic_config($attributes);
515
516 // Build carousel configuration
517 $carousel_config = self::build_carousel_config($attributes, $protection_data['client_id']);
518
519 // Build player configuration
520 $player_config = self::build_player_config($attributes, $protection_data['client_id']);
521
522 // Get dynamic content
523 $embed = self::get_embed_content($attributes, $content);
524
525 // Inject iframeTitle derived from URL
526 $url = $attributes['url'] ?? '';
527 $title = self::get_iframe_title_from_url($url);
528
529 if (!empty($title)) {
530 if (is_array($embed) && isset($embed['html'])) {
531 $embed['html'] = preg_replace('/<iframe(.*?)>/i', '<iframe$1 title="' . esc_attr($title) . '">', $embed['html']);
532 } elseif (is_string($embed)) {
533 $embed = preg_replace('/<iframe(.*?)>/i', '<iframe$1 title="' . esc_attr($title) . '">', $embed);
534 }
535 }
536
537 // Build CSS classes and styling
538 $styling = self::build_styling_config($attributes, $protection_data);
539
540 // Generate final HTML
541 return self::generate_final_html($attributes, $embed, $config, $carousel_config, $player_config, $styling, $protection_data, $should_display_content);
542 }
543
544 private static function render_embedpress_document_html($attributes, $content, $protection_data, $should_display_content)
545 {
546
547 $href = $attributes['href'] ?? '';
548 if (empty($href)) return '';
549
550 $id = $attributes['id'] ?? 'embedpress-document-' . rand(100, 10000);
551 $client_id = $attributes['clientId'] ?? md5($id);
552 $contentShare = $attributes['contentShare'] ?? false;
553 $styling = self::build_styling_config($attributes, $protection_data);
554
555
556 ob_start();
557 ?>
558 <div class="wp-block-embedpress-document" data-embed-type="Document">
559 <?php self::render_embed_content($content, $contentShare, $id, $attributes, $should_display_content, $protection_data, $styling); ?>
560 <?php self::render_ad_template($attributes, $content, $client_id); ?>
561 </div>
562 <?php
563
564 return ob_get_clean();
565 }
566
567
568
569 private static function render_embedpress_pdf_html($attributes, $content, $protection_data, $should_display_content)
570 {
571 // Extract PDF-specific attributes
572 $href = $attributes['href'] ?? '';
573 if (empty($href)) {
574 return '';
575 }
576
577 $id = $attributes['id'] ?? 'embedpress-pdf-' . rand(100, 10000);
578 $client_id = md5($id);
579 $contentShare = $attributes['contentShare'] ?? false;
580
581 $styling = self::build_styling_config($attributes, $protection_data);
582
583 // Build the complete HTML structure
584 ob_start();
585 ?>
586 <div class="wp-block-embedpress-pdf" data-embed-type="PDF">
587 <?php self::render_embed_content($content, $contentShare, $id, $attributes, $should_display_content, $protection_data, $styling); ?>
588 <?php self::render_ad_template($attributes, $content, $client_id); ?>
589 </div>
590 <?php
591
592 return ob_get_clean();
593 }
594
595 /**
596 * Generate PDF parameters for viewer configuration
597 * Based on the self::generate_pdf_params function from the old implementation
598 */
599 /**
600 * Render PDF as a clickable thumbnail that opens in a lightbox
601 */
602 private static function render_pdf_lightbox_thumbnail($attributes, $client_id)
603 {
604 $href = $attributes['href'];
605 $viewerStyle = $attributes['viewerStyle'] ?? 'modern';
606 $unitoption = ($attributes['unitoption'] ?? 'px') === '%' ? '%' : 'px';
607 $width = !empty($attributes['width']) ? $attributes['width'] . $unitoption : '600px';
608 $powered_by = !empty($attributes['powered_by']);
609 $lightboxThumbnail = $attributes['lightboxThumbnail'] ?? '';
610 $lightboxAlign = $attributes['lightboxAlign'] ?? 'left';
611
612 $alignStyle = '';
613 if ($lightboxAlign === 'center') {
614 $alignStyle = 'text-align: center;';
615 } elseif ($lightboxAlign === 'right') {
616 $alignStyle = 'text-align: right;';
617 }
618
619 // Generate base64 viewer params
620 $urlParamData = self::build_pdf_param_array($attributes);
621 $queryString = http_build_query($urlParamData);
622 if (function_exists('mb_convert_encoding')) {
623 $queryString = mb_convert_encoding($queryString, 'UTF-8');
624 }
625 $viewerParams = base64_encode($queryString);
626
627 $pdfTitle = Helper::get_file_title($href);
628
629 ob_start();
630 ?>
631 <div id="ep-gutenberg-content-<?php echo esc_attr($client_id); ?>" class="ep-gutenberg-content">
632 <div class="embedpress-document-embed ep-doc-<?php echo esc_attr($client_id); ?>"
633 style="max-width: <?php echo esc_attr($width); ?>; <?php echo esc_attr($alignStyle); ?>"
634 data-embed-type="PDF">
635 <div class="ep-pdf-thumbnail-card">
636 <div class="ep-pdf-thumbnail-wrap"
637 data-pdf-url="<?php echo esc_url($href); ?>"
638 data-viewer-style="<?php echo esc_attr($viewerStyle); ?>"
639 data-viewer-params="<?php echo esc_attr($viewerParams); ?>">
640 <div class="ep-pdf-thumbnail-inner">
641 <?php if (!empty($lightboxThumbnail)): ?>
642 <img class="ep-pdf-thumbnail-custom" src="<?php echo esc_url($lightboxThumbnail); ?>" alt="<?php echo esc_attr($pdfTitle); ?>" />
643 <?php else: ?>
644 <canvas class="ep-pdf-thumbnail-canvas"
645 data-pdf-url="<?php echo esc_url($href); ?>"
646 data-loading="true"></canvas>
647 <?php endif; ?>
648 <div class="ep-pdf-thumbnail-overlay">
649 <div class="ep-pdf-thumbnail-icon-circle">
650 <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8 5v14l11-7z"/></svg>
651 </div>
652 </div>
653 </div>
654 </div>
655
656 </div>
657 <?php if ($powered_by): ?>
658 <p class="embedpress-el-powered"><?php esc_html_e('Powered By EmbedPress', 'embedpress'); ?></p>
659 <?php endif; ?>
660 </div>
661 </div>
662 <?php
663 return ob_get_clean();
664 }
665
666 /**
667 * Render PDF as a button, link, or text trigger that opens in a lightbox
668 */
669 private static function render_pdf_trigger($attributes, $client_id, $mode)
670 {
671 $href = $attributes['href'];
672 $viewerStyle = $attributes['viewerStyle'] ?? 'modern';
673 $triggerText = !empty($attributes['triggerText']) ? $attributes['triggerText'] : 'View PDF';
674 $lightboxAlign = $attributes['lightboxAlign'] ?? 'left';
675
676 $alignStyle = '';
677 if ($lightboxAlign === 'center') {
678 $alignStyle = 'text-align: center;';
679 } elseif ($lightboxAlign === 'right') {
680 $alignStyle = 'text-align: right;';
681 }
682
683 // Build inline styles for trigger element
684 $triggerStyles = [];
685 if (!empty($attributes['triggerColor'])) {
686 $triggerStyles[] = 'color:' . esc_attr($attributes['triggerColor']);
687 }
688 if (!empty($attributes['triggerFontSize'])) {
689 $triggerStyles[] = 'font-size:' . intval($attributes['triggerFontSize']) . 'px';
690 }
691 if ($mode === 'button') {
692 if (!empty($attributes['triggerBgColor'])) {
693 $triggerStyles[] = 'background-color:' . esc_attr($attributes['triggerBgColor']);
694 }
695 if (!empty($attributes['triggerBorderRadius'])) {
696 $triggerStyles[] = 'border-radius:' . intval($attributes['triggerBorderRadius']) . 'px';
697 }
698 }
699 $triggerStyleAttr = !empty($triggerStyles) ? implode(';', $triggerStyles) : '';
700
701 // Generate base64 viewer params
702 $urlParamData = self::build_pdf_param_array($attributes);
703 $queryString = http_build_query($urlParamData);
704 if (function_exists('mb_convert_encoding')) {
705 $queryString = mb_convert_encoding($queryString, 'UTF-8');
706 }
707 $viewerParams = base64_encode($queryString);
708
709 ob_start();
710 ?>
711 <div id="ep-gutenberg-content-<?php echo esc_attr($client_id); ?>" class="ep-gutenberg-content">
712 <div class="embedpress-document-embed ep-doc-<?php echo esc_attr($client_id); ?>"
713 style="<?php echo esc_attr($alignStyle); ?>"
714 data-embed-type="PDF">
715 <div class="ep-pdf-thumbnail-wrap"
716 data-pdf-url="<?php echo esc_url($href); ?>"
717 data-viewer-style="<?php echo esc_attr($viewerStyle); ?>"
718 data-viewer-params="<?php echo esc_attr($viewerParams); ?>">
719 <span class="ep-pdf-trigger ep-pdf-trigger--<?php echo esc_attr($mode); ?>"<?php if ($triggerStyleAttr) echo ' style="' . esc_attr($triggerStyleAttr) . '"'; ?>><?php echo esc_html($triggerText); ?></span>
720 </div>
721 </div>
722 </div>
723 <?php
724 return ob_get_clean();
725 }
726
727 /**
728 * Build the PDF param data array (shared by generate_pdf_params and render_pdf_lightbox_thumbnail)
729 */
730 private static function build_pdf_param_array($attributes)
731 {
732 $urlParamData = array(
733 'themeMode' => !empty($attributes['themeMode']) ? $attributes['themeMode'] : 'default',
734 'toolbar' => !empty($attributes['toolbar']) ? 'true' : 'false',
735 'position' => $attributes['position'] ?? 'top',
736 'presentation' => !empty($attributes['presentation']) ? 'true' : 'false',
737 'lazyLoad' => !empty($attributes['lazyLoad']) ? 'true' : 'false',
738 'download' => !empty($attributes['download']) ? 'true' : 'false',
739 'copy_text' => !empty($attributes['copy_text']) ? 'true' : 'false',
740 'add_text' => !empty($attributes['add_text']) ? 'true' : 'false',
741 'draw' => !empty($attributes['draw']) ? 'true' : 'false',
742 'doc_rotation' => !empty($attributes['doc_rotation']) ? 'true' : 'false',
743 'add_image' => !empty($attributes['add_image']) ? 'true' : 'false',
744 'doc_details' => !empty($attributes['doc_details']) ? 'true' : 'false',
745 'zoom_in' => !empty($attributes['zoomIn']) ? 'true' : 'false',
746 'zoom_out' => !empty($attributes['zoomOut']) ? 'true' : 'false',
747 'fit_view' => !empty($attributes['fitView']) ? 'true' : 'false',
748 'bookmark' => !empty($attributes['bookmark']) ? 'true' : 'false',
749 'flipbook_toolbar_position' => !empty($attributes['flipbook_toolbar_position']) ? $attributes['flipbook_toolbar_position'] : 'bottom',
750 'selection_tool' => isset($attributes['selection_tool']) ? esc_attr($attributes['selection_tool']) : '0',
751 'scrolling' => isset($attributes['scrolling']) ? esc_attr($attributes['scrolling']) : '-1',
752 'spreads' => isset($attributes['spreads']) ? esc_attr($attributes['spreads']) : '-1',
753 'watermark_text' => defined('EMBEDPRESS_SL_ITEM_SLUG') && !empty($attributes['watermarkText']) ? esc_attr($attributes['watermarkText']) : '',
754 'watermark_font_size' => defined('EMBEDPRESS_SL_ITEM_SLUG') && !empty($attributes['watermarkFontSize']) ? esc_attr($attributes['watermarkFontSize']) : '48',
755 'watermark_color' => defined('EMBEDPRESS_SL_ITEM_SLUG') && !empty($attributes['watermarkColor']) ? esc_attr($attributes['watermarkColor']) : '#000000',
756 'watermark_opacity' => defined('EMBEDPRESS_SL_ITEM_SLUG') && isset($attributes['watermarkOpacity']) ? esc_attr($attributes['watermarkOpacity']) : '15',
757 'watermark_style' => defined('EMBEDPRESS_SL_ITEM_SLUG') && !empty($attributes['watermarkStyle']) ? esc_attr($attributes['watermarkStyle']) : 'center',
758 );
759
760 if ($urlParamData['themeMode'] === 'custom') {
761 $urlParamData['customColor'] = !empty($attributes['customColor']) ? $attributes['customColor'] : '#403A81';
762 }
763
764 return $urlParamData;
765 }
766
767 private static function generate_pdf_params($attributes)
768 {
769 $urlParamData = array(
770 'themeMode' => !empty($attributes['themeMode']) ? $attributes['themeMode'] : 'default',
771 'toolbar' => !empty($attributes['toolbar']) ? 'true' : 'false',
772 'position' => $attributes['position'] ?? 'top',
773 'presentation' => !empty($attributes['presentation']) ? 'true' : 'false',
774 'lazyLoad' => !empty($attributes['lazyLoad']) ? 'true' : 'false',
775 'download' => !empty($attributes['download']) ? 'true' : 'false',
776 'copy_text' => !empty($attributes['copy_text']) ? 'true' : 'false',
777 'add_text' => !empty($attributes['add_text']) ? 'true' : 'false',
778 'draw' => !empty($attributes['draw']) ? 'true' : 'false',
779 'doc_rotation' => !empty($attributes['doc_rotation']) ? 'true' : 'false',
780 'add_image' => !empty($attributes['add_image']) ? 'true' : 'false',
781 'doc_details' => !empty($attributes['doc_details']) ? 'true' : 'false',
782 'zoom_in' => !empty($attributes['zoomIn']) ? 'true' : 'false',
783 'zoom_out' => !empty($attributes['zoomOut']) ? 'true' : 'false',
784 'fit_view' => !empty($attributes['fitView']) ? 'true' : 'false',
785 'bookmark' => !empty($attributes['bookmark']) ? 'true' : 'false',
786 'flipbook_toolbar_position' => !empty($attributes['flipbook_toolbar_position']) ? $attributes['flipbook_toolbar_position'] : 'bottom',
787 'selection_tool' => isset($attributes['selection_tool']) ? esc_attr($attributes['selection_tool']) : '0',
788 'scrolling' => isset($attributes['scrolling']) ? esc_attr($attributes['scrolling']) : '-1',
789 'spreads' => isset($attributes['spreads']) ? esc_attr($attributes['spreads']) : '-1',
790 'watermark_text' => defined('EMBEDPRESS_SL_ITEM_SLUG') && !empty($attributes['watermarkText']) ? esc_attr($attributes['watermarkText']) : '',
791 'watermark_font_size' => defined('EMBEDPRESS_SL_ITEM_SLUG') && !empty($attributes['watermarkFontSize']) ? esc_attr($attributes['watermarkFontSize']) : '48',
792 'watermark_color' => defined('EMBEDPRESS_SL_ITEM_SLUG') && !empty($attributes['watermarkColor']) ? esc_attr($attributes['watermarkColor']) : '#000000',
793 'watermark_opacity' => defined('EMBEDPRESS_SL_ITEM_SLUG') && isset($attributes['watermarkOpacity']) ? esc_attr($attributes['watermarkOpacity']) : '15',
794 'watermark_style' => defined('EMBEDPRESS_SL_ITEM_SLUG') && !empty($attributes['watermarkStyle']) ? esc_attr($attributes['watermarkStyle']) : 'center',
795 );
796
797 // Add custom color for custom theme mode
798 if ($urlParamData['themeMode'] === 'custom') {
799 $urlParamData['customColor'] = !empty($attributes['customColor']) ? $attributes['customColor'] : '#403A81';
800 }
801
802 // Handle flip-book viewer style
803 if (isset($attributes['viewerStyle']) && $attributes['viewerStyle'] === 'flip-book') {
804 return "&key=" . base64_encode(mb_convert_encoding(http_build_query($urlParamData), 'UTF-8'));
805 }
806
807 return "#key=" . base64_encode(mb_convert_encoding(http_build_query($urlParamData), 'UTF-8'));
808 }
809
810 /**
811 * Generate document parameters for viewer configuration
812 * Based on document-specific attributes
813 */
814 private static function generate_document_params($attributes)
815 {
816 $urlParamData = array(
817 'theme_mode' => !empty($attributes['themeMode']) ? $attributes['themeMode'] : 'default',
818 'presentation' => !empty($attributes['presentation']) ? 'true' : 'false',
819 'position' => $attributes['position'] ?? 'top',
820 'download' => !empty($attributes['download']) ? 'true' : 'false',
821 'draw' => !empty($attributes['draw']) ? 'true' : 'false',
822 );
823
824 // Add custom color for custom theme mode
825 if ($urlParamData['theme_mode'] === 'custom') {
826 $urlParamData['custom_color'] = !empty($attributes['customColor']) ? $attributes['customColor'] : '#343434';
827 }
828
829 return '?' . http_build_query($urlParamData);
830 }
831
832 /**
833 * Extract basic configuration from attributes
834 *
835 * @param array $attributes Block attributes
836 * @return array Basic configuration
837 */
838 private static function extract_basic_config($attributes)
839 {
840 return [
841 'block_id' => !empty($attributes['clientId']) ? $attributes['clientId'] : '',
842 'custom_player' => !empty($attributes['customPlayer']) ? $attributes['customPlayer'] : 0,
843 'insta_layout' => !empty($attributes['instaLayout']) ? ' ' . $attributes['instaLayout'] : ' insta-grid',
844 'mode' => !empty($attributes['mode']) ? ' ep-google-photos-' . $attributes['mode'] : '',
845 'embed_type' => !empty($attributes['cEmbedType']) ? ' ' . $attributes['cEmbedType'] : '',
846 'url' => $attributes['url'] ?? '',
847 ];
848 }
849
850 /**
851 * Build carousel configuration
852 *
853 * @param array $attributes Block attributes
854 * @param string $client_id Client ID
855 * @return array Carousel configuration
856 */
857 private static function build_carousel_config($attributes, $client_id)
858 {
859 $carousel_options = '';
860 $carousel_id = '';
861
862 if (!empty($attributes['instaLayout']) && $attributes['instaLayout'] === 'insta-carousel') {
863 $carousel_id = 'data-carouselid=' . esc_attr($client_id);
864
865 $options = [
866 'layout' => $attributes['instaLayout'],
867 'slideshow' => !empty($attributes['slidesShow']) ? $attributes['slidesShow'] : 5,
868 'autoplay' => !empty($attributes['carouselAutoplay']) ? $attributes['carouselAutoplay'] : 0,
869 'autoplayspeed' => !empty($attributes['autoplaySpeed']) ? $attributes['autoplaySpeed'] : 3000,
870 'transitionspeed' => !empty($attributes['transitionSpeed']) ? $attributes['transitionSpeed'] : 1000,
871 'loop' => !empty($attributes['carouselLoop']) ? $attributes['carouselLoop'] : 0,
872 'arrows' => !empty($attributes['carouselArrows']) ? $attributes['carouselArrows'] : 0,
873 'spacing' => !empty($attributes['carouselSpacing']) ? $attributes['carouselSpacing'] : 0
874 ];
875
876 $carousel_options = 'data-carousel-options=' . htmlentities(json_encode($options), ENT_QUOTES);
877 }
878
879 return [
880 'carousel_id' => $carousel_id,
881 'carousel_options' => $carousel_options,
882 ];
883 }
884
885 /**
886 * Build player configuration
887 *
888 * @param array $attributes Block attributes
889 * @param string $client_id Client ID
890 * @return array Player configuration
891 */
892 private static function build_player_config($attributes, $client_id)
893 {
894 $custom_player = '';
895 $player_options = '';
896 $custom_player_enabled = !empty($attributes['customPlayer']) ? $attributes['customPlayer'] : 0;
897
898 if (!empty($custom_player_enabled)) {
899 $is_self_hosted = Helper::check_media_format($attributes['url']);
900 $custom_player = 'data-playerid=' . esc_attr($client_id);
901
902 $options = self::build_player_options($attributes, $is_self_hosted);
903 $player_options = 'data-options=' . htmlentities(json_encode($options), ENT_QUOTES);
904 }
905
906 return [
907 'custom_player' => $custom_player,
908 'player_options' => $player_options,
909 ];
910 }
911
912 /**
913 * Build player options array
914 *
915 * @param array $attributes Block attributes
916 * @param array $is_self_hosted Self-hosted media info
917 * @return array Player options
918 */
919 private static function build_player_options($attributes, $is_self_hosted)
920 {
921 $options = [
922 'rewind' => !empty($attributes['playerRewind']),
923 'restart' => !empty($attributes['playerRestart']),
924 'pip' => !empty($attributes['playerPip']),
925 'poster_thumbnail' => $attributes['posterThumbnail'] ?? '',
926 'player_color' => $attributes['playerColor'] ?? '',
927 'player_preset' => $attributes['playerPreset'] ?? 'preset-default',
928 'fast_forward' => !empty($attributes['playerFastForward']),
929 'player_tooltip' => !empty($attributes['playerTooltip']),
930 'hide_controls' => !empty($attributes['playerHideControls']),
931 'download' => !empty($attributes['playerDownload']),
932 ];
933
934 // Add conditional options
935 $conditional_options = [
936 'fullscreen' => 'fullscreen',
937 'starttime' => 'start',
938 'endtime' => 'end',
939 'relatedvideos' => 'rel',
940 'muteVideo' => 'mute',
941 'vstarttime' => 't',
942 'vautoplay' => 'vautoplay',
943 'vautopause' => 'autopause',
944 'vdnt' => 'dnt',
945 ];
946
947 foreach ($conditional_options as $attr_key => $option_key) {
948 if (!empty($attributes[$attr_key])) {
949 $options[$option_key] = $attributes[$attr_key];
950 }
951 }
952
953 // Add self-hosted options
954 if (!empty($is_self_hosted['selhosted'])) {
955 $options['self_hosted'] = $is_self_hosted['selhosted'];
956 $options['hosted_format'] = $is_self_hosted['format'];
957 }
958
959 return $options;
960 }
961
962 /**
963 * Get embed content with dynamic rendering
964 *
965 * @param array $attributes Block attributes
966 * @param string $content Block content
967 * @return string Embed content
968 */
969 private static function get_embed_content($attributes, $content)
970 {
971 return apply_filters('embedpress_render_dynamic_content', $content, $attributes);
972 }
973
974 /**
975 * Build styling configuration
976 *
977 * @param array $attributes Block attributes
978 * @param array $protection_data Protection data
979 * @return array Styling configuration
980 */
981 private static function build_styling_config($attributes, $protection_data)
982 {
983 $client_id = $protection_data['client_id'];
984
985 // Content sharing classes
986 $content_share_class = !empty($attributes['contentShare']) ? 'ep-content-share-enabled' : '';
987 $share_position = $attributes['sharePosition'] ?? 'right';
988 $share_position_class = !empty($attributes['contentShare']) ? 'ep-share-position-' . $share_position : '';
989
990 // Content protection classes
991 $password_correct = $_COOKIE['password_correct_' . $client_id] ?? '';
992 $hash_pass = hash('sha256', wp_salt(32) . md5($attributes['contentPassword'] ?? ''));
993 $content_protection_class = 'ep-content-protection-enabled';
994
995 if (empty($attributes['lockContent']) || empty($attributes['contentPassword']) || $hash_pass === $password_correct) {
996 $content_protection_class = 'ep-content-protection-disabled';
997 }
998
999 // Alignment classes
1000 $alignment = self::get_alignment_class($attributes['align'] ?? '');
1001
1002 // Ad manager attributes
1003 $ads_attrs = self::build_ads_attributes($attributes, $client_id);
1004
1005 // Custom branding styles and HTML
1006 $custom_branding = self::build_custom_branding($attributes, $client_id);
1007
1008 // Media format classes
1009 $hosted_format = self::get_hosted_format($attributes);
1010 $yt_channel_class = (isset($attributes['url']) && Helper::is_youtube_channel($attributes['url'])) ? 'embedded-youtube-channel' : '';
1011
1012 $auto_pause = !empty($attributes['autoPause']) ? ' enabled-auto-pause' : '';
1013
1014 return [
1015 'content_share_class' => $content_share_class,
1016 'share_position_class' => $share_position_class,
1017 'content_protection_class' => $content_protection_class,
1018 'alignment' => $alignment,
1019 'ads_attrs' => $ads_attrs,
1020 'custom_branding' => $custom_branding,
1021 'hosted_format' => $hosted_format,
1022 'yt_channel_class' => $yt_channel_class,
1023 'auto_pause' => $auto_pause,
1024 'pass_hash_key' => isset($attributes['contentPassword']) ? md5($attributes['contentPassword']) : '',
1025 ];
1026 }
1027
1028 /**
1029 * Get alignment CSS class
1030 *
1031 * @param string $align Alignment value
1032 * @return string CSS class
1033 */
1034 private static function get_alignment_class($align)
1035 {
1036 return isset(self::$alignment_classes[$align])
1037 ? self::$alignment_classes[$align] . ' clear'
1038 : 'aligncenter';
1039 }
1040
1041 /**
1042 * Build ad manager attributes
1043 *
1044 * @param array $attributes Block attributes
1045 * @param string $client_id Client ID
1046 * @return string Ad attributes
1047 */
1048 private static function build_ads_attributes($attributes, $client_id)
1049 {
1050 if (empty($attributes['adManager'])) {
1051 return '';
1052 }
1053
1054 $ad = base64_encode(json_encode($attributes));
1055 return "data-sponsored-id=$client_id data-sponsored-attrs=$ad class=sponsored-mask";
1056 }
1057
1058 /**
1059 * Get hosted media format
1060 *
1061 * @param array $attributes Block attributes
1062 * @return string Media format
1063 */
1064 private static function get_hosted_format($attributes)
1065 {
1066 if (empty($attributes['customPlayer'])) {
1067 return '';
1068 }
1069
1070 $self_hosted = Helper::check_media_format($attributes['url']);
1071 return $self_hosted['format'] ?? '';
1072 }
1073
1074 /**
1075 * Build custom branding configuration
1076 *
1077 * @param array $attributes Block attributes
1078 * @param string $client_id Client ID
1079 * @return array Custom branding configuration
1080 */
1081 private static function build_custom_branding($attributes, $client_id)
1082 {
1083 $custom_branding = [
1084 'html' => '',
1085 'styles' => ''
1086 ];
1087
1088 // Check if custom logo is enabled
1089 if (empty($attributes['customlogo'])) {
1090 return $custom_branding;
1091 }
1092
1093 $logo_url = $attributes['customlogo'];
1094 $logo_x = $attributes['logoX'] ?? 5;
1095 $logo_y = $attributes['logoY'] ?? 10;
1096 $logo_opacity = $attributes['logoOpacity'] ?? 1;
1097 $custom_logo_url = $attributes['customlogoUrl'] ?? '';
1098
1099 // Generate custom logo styles
1100 $custom_branding['styles'] = sprintf(
1101 '#ep-gutenberg-content-%s img.watermark {
1102 border: 0;
1103 position: absolute;
1104 bottom: %s%%;
1105 right: %s%%;
1106 max-width: 150px;
1107 max-height: 75px;
1108 -o-transition: opacity 0.5s ease-in-out;
1109 -moz-transition: opacity 0.5s ease-in-out;
1110 -webkit-transition: opacity 0.5s ease-in-out;
1111 transition: opacity 0.5s ease-in-out;
1112 z-index: 1;
1113 opacity: %s;
1114 }
1115 #ep-gutenberg-content-%s img.watermark:hover {
1116 opacity: 1;
1117 }',
1118 esc_attr($client_id),
1119 esc_attr($logo_y),
1120 esc_attr($logo_x),
1121 esc_attr($logo_opacity),
1122 esc_attr($client_id)
1123 );
1124
1125 // Generate custom logo HTML
1126 $logo_html = sprintf(
1127 '<img decoding="async" src="%s" class="watermark ep-custom-logo" width="auto" height="auto" alt="">',
1128 esc_url($logo_url)
1129 );
1130
1131 // Wrap with link if URL is provided
1132 if (!empty($custom_logo_url)) {
1133 $logo_html = sprintf(
1134 '<a href="%s" target="_blank">%s</a>',
1135 esc_url($custom_logo_url),
1136 $logo_html
1137 );
1138 }
1139
1140 $custom_branding['html'] = $logo_html;
1141
1142 return $custom_branding;
1143 }
1144
1145 /**
1146 * Generate the final HTML output
1147 *
1148 * @param array $attributes Block attributes
1149 * @param string $embed Embed content
1150 * @param array $config Basic configuration
1151 * @param array $carousel_config Carousel configuration
1152 * @param array $player_config Player configuration
1153 * @param array $styling Styling configuration
1154 * @param array $protection_data Protection data
1155 * @param bool $should_display_content Whether content should be displayed
1156 * @return string Final HTML output
1157 */
1158 private static function generate_final_html($attributes, $embed, $config, $carousel_config, $player_config, $styling, $protection_data, $should_display_content)
1159 {
1160 ob_start();
1161
1162 // Extract variables for template
1163 $url = $config['url'];
1164 $block_id = $config['block_id'];
1165 $client_id = $protection_data['client_id'];
1166 $content_id = $protection_data['content_id'];
1167 $content_share = $protection_data['content_share'];
1168
1169 // Build wrapper classes
1170 $wrapper_classes = self::build_wrapper_classes($styling, $config);
1171 $embed_wrapper_classes = self::build_embed_wrapper_classes($attributes);
1172 $content_wrapper_classes = self::build_content_wrapper_classes($attributes, $config, $styling);
1173
1174 ?>
1175 <?php if (!empty($styling['custom_branding']['styles'])): ?>
1176 <style>
1177 <?php echo $styling['custom_branding']['styles']; ?>
1178 </style>
1179 <?php endif; ?>
1180
1181 <div class="embedpress-gutenberg-wrapper source-provider-<?php echo Helper::get_provider_name($url); ?> <?php echo esc_attr($wrapper_classes); ?>" id="<?php echo esc_attr($block_id); ?>" data-embed-type="<?php echo Helper::get_provider_name($url); ?> ">
1182 <div class="wp-block-embed__wrapper <?php echo esc_attr($embed_wrapper_classes); ?>">
1183 <div id="ep-gutenberg-content-<?php echo esc_attr($client_id) ?>" class="ep-gutenberg-content<?php echo esc_attr($styling['auto_pause']); ?>">
1184 <div <?php echo esc_attr($styling['ads_attrs']); ?>>
1185 <div class="ep-embed-content-wraper <?php echo esc_attr($content_wrapper_classes); ?>"
1186 <?php echo esc_attr($player_config['custom_player']); ?>
1187 <?php echo esc_attr($player_config['player_options']); ?>
1188 <?php echo esc_attr($carousel_config['carousel_id']); ?>
1189 <?php echo esc_attr($carousel_config['carousel_options']); ?>>
1190
1191 <?php
1192 self::render_embed_content($embed, $content_share, $content_id, $attributes, $should_display_content, $protection_data, $styling);
1193 ?>
1194 </div>
1195
1196 <?php self::render_ad_template($attributes, $embed, $client_id); ?>
1197 </div>
1198 </div>
1199 </div>
1200 </div>
1201 <?php
1202
1203 return ob_get_clean();
1204 }
1205
1206 /**
1207 * Build wrapper CSS classes
1208 *
1209 * @param array $styling Styling configuration
1210 * @param array $config Basic configuration
1211 * @return string CSS classes
1212 */
1213 private static function build_wrapper_classes($styling, $config)
1214 {
1215 return trim(sprintf(
1216 '%s %s %s %s%s',
1217 $styling['alignment'],
1218 $styling['content_share_class'],
1219 $styling['share_position_class'],
1220 $styling['content_protection_class'],
1221 $config['embed_type']
1222 ));
1223 }
1224
1225 /**
1226 * Build embed wrapper CSS classes
1227 *
1228 * @param array $attributes Block attributes
1229 * @return string CSS classes
1230 */
1231 private static function build_embed_wrapper_classes($attributes)
1232 {
1233 $classes = [];
1234
1235 if (!empty($attributes['contentShare'])) {
1236 $share_position = $attributes['sharePosition'] ?? 'right';
1237 $classes[] = 'position-' . $share_position . '-wraper';
1238 }
1239
1240 if (($attributes['videosize'] ?? '') === 'responsive') {
1241 $classes[] = 'ep-video-responsive';
1242 }
1243
1244 return implode(' ', $classes);
1245 }
1246
1247 /**
1248 * Build content wrapper CSS classes
1249 *
1250 * @param array $attributes Block attributes
1251 * @param array $config Basic configuration
1252 * @param array $styling Styling configuration
1253 * @return string CSS classes
1254 */
1255 private static function build_content_wrapper_classes($attributes, $config, $styling)
1256 {
1257 return trim(sprintf(
1258 '%s%s%s %s %s',
1259 $attributes['playerPreset'] ?? '',
1260 $config['insta_layout'],
1261 $config['mode'],
1262 $styling['hosted_format'],
1263 $styling['yt_channel_class']
1264 ));
1265 }
1266
1267 /**
1268 * Render embed content with protection logic
1269 *
1270 * @param string $embed Embed content
1271 * @param string $content_share Content share setting
1272 * @param string $content_id Content ID
1273 * @param array $attributes Block attributes
1274 * @param bool $should_display_content Whether content should be displayed
1275 * @param array $protection_data Protection data
1276 * @param array $styling Styling configuration
1277 */
1278 private static function render_embed_content($embed, $content_share, $content_id, $attributes, $should_display_content, $protection_data, $styling)
1279 {
1280 if ($should_display_content) {
1281 self::render_displayable_content($embed, $content_share, $content_id, $attributes, $styling);
1282 } else {
1283 self::render_protected_content($embed, $content_share, $content_id, $attributes, $protection_data, $styling);
1284 }
1285 }
1286
1287 /**
1288 * Render displayable content
1289 *
1290 * @param string $embed Embed content
1291 * @param string $content_share Content share setting
1292 * @param string $content_id Content ID
1293 * @param array $attributes Block attributes
1294 * @param array $styling Styling configuration (optional)
1295 */
1296 private static function render_displayable_content($embed, $content_share, $content_id, $attributes, $styling = [])
1297 {
1298 // Add custom branding if available
1299 if (!empty($styling['custom_branding']['html'])) {
1300 if (is_array($embed)) {
1301 $embed['html'] .= $styling['custom_branding']['html'];
1302 } else {
1303 $embed .= $styling['custom_branding']['html'];
1304 }
1305 }
1306
1307 if (!empty($content_share)) {
1308 $embed .= Helper::embed_content_share($content_id, $attributes);
1309 }
1310
1311 if (is_array($embed)) {
1312 echo $embed['html'];
1313 } else {
1314 echo $embed;
1315 }
1316 }
1317
1318 /**
1319 * Render protected content
1320 *
1321 * @param string $embed Embed content
1322 * @param string $content_share Content share setting
1323 * @param string $content_id Content ID
1324 * @param array $attributes Block attributes
1325 * @param array $protection_data Protection data
1326 * @param array $styling Styling configuration
1327 */
1328 private static function render_protected_content($embed, $content_share, $content_id, $attributes, $protection_data, $styling)
1329 {
1330 // Add custom branding if available
1331 if (!empty($styling['custom_branding']['html'])) {
1332 if (is_array($embed)) {
1333 $embed['html'] .= $styling['custom_branding']['html'];
1334 } else {
1335 $embed .= $styling['custom_branding']['html'];
1336 }
1337 }
1338
1339 if (!empty($content_share)) {
1340 $embed .= Helper::embed_content_share($content_id, $attributes);
1341 }
1342
1343 if ($protection_data['protection_type'] === 'password') {
1344 echo '<div id="ep-gutenberg-content-' . esc_attr($protection_data['client_id']) . '" class="ep-gutenberg-content">';
1345 do_action('embedpress/display_password_form', $protection_data['client_id'], $embed, $styling['pass_hash_key'], $attributes);
1346 echo '</div>';
1347 } else {
1348 do_action('embedpress/content_protection_content', $protection_data['client_id'], $protection_data['protection_message'], $protection_data['user_role']);
1349 }
1350 }
1351
1352 /**
1353 * Render ad template if enabled
1354 *
1355 * @param array $attributes Block attributes
1356 * @param string $embed Embed content
1357 * @param string $client_id Client ID
1358 */
1359 private static function render_ad_template($attributes, $embed, $client_id)
1360 {
1361 if (!empty($attributes['adManager'])) {
1362 $embed = apply_filters('embedpress/generate_ad_template', $embed, $client_id, $attributes, 'gutenberg');
1363 }
1364 }
1365
1366 /**
1367 * YouTube block legacy render method
1368 *
1369 * @param array $attributes Block attributes
1370 * @param string $content Block content
1371 * @param object $block Block object (unused but kept for compatibility)
1372 * @return string Rendered HTML content
1373 */
1374 public static function render_youtube_block($attributes, $content = '', $block = null)
1375 {
1376
1377 if (!empty($content)) {
1378 return $content;
1379 }
1380 // Extract basic attributes for YouTube block
1381 $iframe_src = $attributes['iframeSrc'] ?? '';
1382 $align = $attributes['align'] ?? 'center';
1383
1384 // If no iframe source is provided, return empty
1385 if (empty($iframe_src)) {
1386 return '';
1387 }
1388
1389 // Validate YouTube URL
1390 if (!self::is_youtube_url($iframe_src)) {
1391 return '';
1392 }
1393
1394 // Apply YouTube parameters filter
1395 $youtube_params = apply_filters('embedpress_gutenberg_youtube_params', []);
1396 $processed_iframe_url = $iframe_src;
1397
1398 foreach ($youtube_params as $param => $value) {
1399 $processed_iframe_url = add_query_arg($param, $value, $processed_iframe_url);
1400 }
1401
1402 // Build alignment class
1403 $align_class = 'align' . $align;
1404
1405 // Extract width/height from attributes
1406 $width = isset($attributes['width']) ? intval($attributes['width']) : 640;
1407 $height = isset($attributes['height']) ? intval($attributes['height']) : 360;
1408
1409 // Generate YouTube block HTML
1410 ob_start();
1411 ?>
1412 <div class="ose-youtube responsive wp-block-embed-youtube ose-youtube-single-video <?php echo esc_attr($align_class); ?>" style="max-width: 100%;">
1413 <iframe src="<?php echo esc_url($processed_iframe_url); ?>"
1414 allowtransparency="true"
1415 allowfullscreen="true"
1416 frameborder="0"
1417 style="max-width: 100%;"
1418 width="<?php echo esc_attr($width); ?>" height="<?php echo esc_attr($height); ?>">
1419 </iframe>
1420 </div>
1421 <?php
1422 return ob_get_clean();
1423 }
1424
1425 /**
1426 * Validate if URL is a YouTube URL
1427 *
1428 * @param string $url URL to validate
1429 * @return bool True if valid YouTube URL, false otherwise
1430 */
1431 private static function is_youtube_url($url)
1432 {
1433 $pattern = '/^(https?:\/\/)?(www\.)?(youtube\.com\/(watch\?(.*&)?v=|(embed|v)\/))|youtu.be\/([a-zA-Z0-9_-]{11})/';
1434 return preg_match($pattern, $url);
1435 }
1436
1437 /**
1438 * Wistia block legacy render method
1439 *
1440 * @param array $attributes Block attributes
1441 * @param string $content Block content
1442 * @param object $block Block object (unused but kept for compatibility)
1443 * @return string Rendered HTML content
1444 */
1445 public static function render_wistia_block($attributes, $content = '', $block = null)
1446 {
1447 if (!empty($content)) {
1448 return $content;
1449 }
1450
1451 // Extract basic attributes for Wistia block
1452 $url = $attributes['url'] ?? '';
1453 $iframe_src = $attributes['iframeSrc'] ?? '';
1454 $align = $attributes['align'] ?? 'center';
1455
1456 // If no URL is provided, return empty
1457 if (empty($url)) {
1458 return '';
1459 }
1460
1461 // Extract Wistia media ID from URL
1462 $wistia_id = self::extract_wistia_id($url);
1463 if (empty($wistia_id)) {
1464 return '';
1465 }
1466
1467 // Build alignment class
1468 $align_class = 'align' . $align;
1469
1470 // Generate Wistia block HTML
1471 ob_start();
1472 ?>
1473 <div class="ose-wistia wp-block-embed-youtube <?php echo esc_attr($align_class); ?>" id="wistia_<?php echo esc_attr($wistia_id); ?>">
1474 <iframe src="<?php echo esc_url($iframe_src); ?>"
1475 allowtransparency="true"
1476 frameborder="0"
1477 class="wistia_embed"
1478 name="wistia_embed"
1479 width="600"
1480 height="330">
1481 </iframe>
1482 <?php do_action('embedpress_gutenberg_wistia_block_after_embed', $attributes); ?>
1483 </div>
1484 <?php
1485 return ob_get_clean();
1486 }
1487
1488 /**
1489 * Extract Wistia media ID from URL
1490 *
1491 * @param string $url Wistia URL
1492 * @return string|false Wistia media ID or false if not found
1493 */
1494 private static function extract_wistia_id($url)
1495 {
1496 preg_match('~medias/(.*)~i', esc_url($url), $matches);
1497 return isset($matches[1]) ? $matches[1] : false;
1498 }
1499
1500 /**
1501 * Calendar block render method
1502 *
1503 * @param array $attributes Block attributes
1504 * @param string $content Block content
1505 * @param object $block Block object (unused but kept for compatibility)
1506 * @return string Rendered HTML content
1507 */
1508 public static function render_embedpress_calendar($attributes, $content = '', $block = null)
1509 {
1510 if (!empty($content)) {
1511 return $content;
1512 }
1513
1514 // Extract basic attributes for Calendar block
1515 $url = $attributes['url'] ?? '';
1516 $width = $attributes['width'] ?? '600';
1517 $height = $attributes['height'] ?? '600';
1518 $powered_by = $attributes['powered_by'] ?? false;
1519 $is_public = $attributes['is_public'] ?? true;
1520 $align = $attributes['align'] ?? 'center';
1521
1522 // If no URL is provided, return empty
1523 if (empty($url)) {
1524 return '';
1525 }
1526
1527 // Validate Google Calendar URL
1528 if (!self::is_google_calendar_url($url)) {
1529 return '<p class="embedpress-el-powered">' . esc_html__('Invalid Calendar Link', 'embedpress') . '</p>';
1530 }
1531
1532 // Build alignment class
1533 $align_class = 'align' . $align;
1534
1535 // Sanitize URL
1536 $sanitized_url = esc_url($url);
1537
1538 // Generate Calendar block HTML
1539 ob_start();
1540 ?>
1541 <figure class="wp-block-embedpress-embedpress-calendar <?php echo esc_attr($align_class); ?>" style="width: <?php echo esc_attr($width); ?>px; height: <?php echo esc_attr($height); ?>px;">
1542 <?php if ($is_public && self::is_google_calendar_url($url)) : ?>
1543 <iframe src="<?php echo esc_url($sanitized_url); ?>"
1544 width="<?php echo esc_attr($width); ?>"
1545 height="<?php echo esc_attr($height); ?>"
1546 frameborder="0"
1547 scrolling="no"
1548 title="<?php echo esc_attr(self::get_iframe_title_from_url($url)); ?>">
1549 </iframe>
1550 <?php endif; ?>
1551
1552 <?php if ($powered_by && self::is_google_calendar_url($url)) : ?>
1553 <p class="embedpress-el-powered"><?php echo esc_html__('Powered By EmbedPress', 'embedpress'); ?></p>
1554 <?php endif; ?>
1555 </figure>
1556 <?php
1557 return ob_get_clean();
1558 }
1559
1560 /**
1561 * Validate if URL is a Google Calendar URL
1562 *
1563 * @param string $url URL to validate
1564 * @return bool True if valid Google Calendar URL, false otherwise
1565 */
1566 private static function is_google_calendar_url($url)
1567 {
1568 $pattern = '/^https:\/\/calendar\.google\.com\/calendar\/(?:u\/\d+\/)?embed\?.*/';
1569 return preg_match($pattern, $url);
1570 }
1571
1572 /**
1573 * Get iframe title from URL
1574 *
1575 * @param string $url URL to derive title from
1576 * @return string Derived title
1577 */
1578 private static function get_iframe_title_from_url($url)
1579 {
1580 if (empty($url)) {
1581 return '';
1582 }
1583
1584 // Try getting title from WordPress attachment if it's a local file
1585 $file_title = Helper::get_file_title($url);
1586 if (!empty($file_title)) {
1587 return $file_title;
1588 }
1589
1590 // Try to get filename from URL
1591 $path = parse_url($url, PHP_URL_PATH);
1592 if ($path) {
1593 $filename = basename($path);
1594 // Remove extension
1595 $filename = preg_replace('/\.[^.]+$/', '', $filename);
1596 // Decode URL encoding
1597 $filename = urldecode($filename);
1598 // Replace hyphens/underscores with spaces
1599 $filename = str_replace(['-', '_'], ' ', $filename);
1600
1601 if (!empty($filename)) {
1602 return ucfirst($filename);
1603 }
1604 }
1605
1606 // Fallback to domain name
1607 $host = parse_url($url, PHP_URL_HOST);
1608 if ($host) {
1609 return $host;
1610 }
1611
1612 return $url;
1613 }
1614
1615 /**
1616 * Render PDF Gallery block
1617 */
1618 public static function render_pdf_gallery($attributes, $content = '', $block = null)
1619 {
1620 // If save.js produced valid content, return it (frontend JS will enhance it)
1621 if (!empty($content)) {
1622 return $content;
1623 }
1624
1625 $items = isset($attributes['pdfItems']) ? $attributes['pdfItems'] : [];
1626 if (empty($items)) {
1627 return '';
1628 }
1629
1630 $layout = isset($attributes['layout']) ? esc_attr($attributes['layout']) : 'grid';
1631 $bookshelf_style = isset($attributes['bookshelfStyle']) ? esc_attr($attributes['bookshelfStyle']) : 'dark-wood';
1632
1633 // Pro gate: bookshelf requires Pro
1634 if (($layout === 'bookshelf' || $layout === 'carousel') && !defined('EMBEDPRESS_SL_ITEM_SLUG')) {
1635 $layout = 'grid';
1636 }
1637
1638 $columns = isset($attributes['columns']) ? intval($attributes['columns']) : 3;
1639 $columns_tablet = isset($attributes['columnsTablet']) ? intval($attributes['columnsTablet']) : 2;
1640 $columns_mobile = isset($attributes['columnsMobile']) ? intval($attributes['columnsMobile']) : 1;
1641 $gap = isset($attributes['gap']) ? intval($attributes['gap']) : 20;
1642 $border_radius = isset($attributes['thumbnailBorderRadius']) ? intval($attributes['thumbnailBorderRadius']) : 8;
1643 $aspect_ratio = isset($attributes['thumbnailAspectRatio']) ? esc_attr($attributes['thumbnailAspectRatio']) : '4:3';
1644 $viewer_style = isset($attributes['viewerStyle']) ? esc_attr($attributes['viewerStyle']) : 'modern';
1645 $client_id = isset($attributes['clientId']) ? esc_attr($attributes['clientId']) : '';
1646 $gallery_id = 'ep-gallery-' . substr(md5(serialize($items)), 0, 8);
1647
1648 // Build viewer params
1649 $viewer_params = self::generate_gallery_viewer_params($attributes);
1650
1651 // Carousel options
1652 $carousel_options = '';
1653 if ($layout === 'carousel' || $layout === 'bookshelf') {
1654 $carousel_options = wp_json_encode([
1655 'autoplay' => !empty($attributes['carouselAutoplay']),
1656 'autoplaySpeed' => isset($attributes['carouselAutoplaySpeed']) ? intval($attributes['carouselAutoplaySpeed']) : 3000,
1657 'loop' => isset($attributes['carouselLoop']) ? (bool)$attributes['carouselLoop'] : true,
1658 'arrows' => isset($attributes['carouselArrows']) ? (bool)$attributes['carouselArrows'] : true,
1659 'dots' => !empty($attributes['carouselDots']),
1660 'slidesPerView' => isset($attributes['slidesPerView']) ? intval($attributes['slidesPerView']) : 3,
1661 ]);
1662 }
1663
1664 $style = sprintf(
1665 '--ep-gallery-columns-desktop:%d;--ep-gallery-columns-tablet:%d;--ep-gallery-columns-mobile:%d;--ep-gallery-gap:%dpx;--ep-gallery-radius:%dpx;',
1666 $columns, $columns_tablet, $columns_mobile, $gap, $border_radius
1667 );
1668
1669 ob_start();
1670 ?>
1671 <div class="ep-pdf-gallery"
1672 data-layout="<?php echo $layout; ?>"
1673 data-shelf-style="<?php echo esc_attr($bookshelf_style); ?>"
1674 data-columns="<?php echo $columns; ?>"
1675 data-columns-tablet="<?php echo $columns_tablet; ?>"
1676 data-columns-mobile="<?php echo $columns_mobile; ?>"
1677 data-gap="<?php echo $gap; ?>"
1678 data-border-radius="<?php echo $border_radius; ?>"
1679 data-viewer-style="<?php echo $viewer_style; ?>"
1680 data-viewer-params="<?php echo esc_attr($viewer_params); ?>"
1681 data-gallery-id="<?php echo esc_attr($gallery_id); ?>"
1682 <?php if ($carousel_options): ?>data-carousel-options="<?php echo esc_attr($carousel_options); ?>"<?php endif; ?>
1683 style="<?php echo esc_attr($style); ?>">
1684
1685 <?php if ($layout === 'carousel' || $layout === 'bookshelf'): ?>
1686 <div class="ep-pdf-gallery__carousel">
1687 <div class="ep-pdf-gallery__carousel-track">
1688 <?php else: ?>
1689 <div class="ep-pdf-gallery__grid">
1690 <?php endif; ?>
1691
1692 <?php foreach ($items as $index => $item):
1693 $pdf_url = isset($item['url']) ? esc_url($item['url']) : '';
1694 $pdf_name = isset($item['fileName']) ? esc_attr($item['fileName']) : '';
1695 $custom_thumb = isset($item['customThumbnailUrl']) ? esc_url($item['customThumbnailUrl']) : '';
1696 $auto_thumb = isset($item['autoThumbnailUrl']) ? esc_url($item['autoThumbnailUrl']) : '';
1697 $thumb_url = $custom_thumb ?: $auto_thumb;
1698 ?>
1699 <div class="ep-pdf-gallery__item"
1700 data-pdf-url="<?php echo $pdf_url; ?>"
1701 data-pdf-index="<?php echo intval($index); ?>"
1702 data-pdf-name="<?php echo $pdf_name; ?>">
1703 <div class="ep-pdf-gallery__thumbnail-wrap" data-ratio="<?php echo $aspect_ratio; ?>">
1704 <?php if ($thumb_url): ?>
1705 <img src="<?php echo $thumb_url; ?>" alt="<?php echo $pdf_name; ?>" />
1706 <?php else: ?>
1707 <canvas class="ep-pdf-gallery__canvas" data-pdf-src="<?php echo $pdf_url; ?>" data-loading="true"></canvas>
1708 <?php endif; ?>
1709 <div class="ep-pdf-gallery__overlay">
1710 <svg class="ep-pdf-gallery__view-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
1711 <path d="M8 5v14l11-7z"/>
1712 </svg>
1713 </div>
1714 </div>
1715 <div class="ep-pdf-gallery__book-title"><?php echo esc_html($pdf_name); ?></div>
1716 </div>
1717 <?php endforeach; ?>
1718
1719 <?php if ($layout === 'carousel' || $layout === 'bookshelf'): ?>
1720 </div>
1721 <button class="ep-pdf-gallery__carousel-prev" aria-label="Previous">
1722 <svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
1723 </button>
1724 <button class="ep-pdf-gallery__carousel-next" aria-label="Next">
1725 <svg viewBox="0 0 24 24"><path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z"/></svg>
1726 </button>
1727 <div class="ep-pdf-gallery__carousel-dots"></div>
1728 </div>
1729 <?php else: ?>
1730 </div>
1731 <?php endif; ?>
1732 </div>
1733 <?php
1734 return ob_get_clean();
1735 }
1736
1737 /**
1738 * Generate base64-encoded viewer params for PDF gallery
1739 */
1740 private static function generate_gallery_viewer_params($attributes)
1741 {
1742 $theme_mode = isset($attributes['themeMode']) ? $attributes['themeMode'] : 'default';
1743
1744 $params = [
1745 'themeMode' => esc_attr($theme_mode),
1746 'toolbar' => !empty($attributes['toolbar']) ? 'true' : 'false',
1747 'position' => isset($attributes['position']) ? esc_attr($attributes['position']) : 'top',
1748 'flipbook_toolbar_position' => isset($attributes['flipbook_toolbar_position']) ? esc_attr($attributes['flipbook_toolbar_position']) : 'bottom',
1749 'presentation' => !empty($attributes['presentation']) ? 'true' : 'false',
1750 'download' => !empty($attributes['download']) ? 'true' : 'false',
1751 'copy_text' => !empty($attributes['copy_text']) ? 'true' : 'false',
1752 'add_text' => !empty($attributes['add_text']) ? 'true' : 'false',
1753 'draw' => !empty($attributes['draw']) ? 'true' : 'false',
1754 'doc_rotation' => !empty($attributes['doc_rotation']) ? 'true' : 'false',
1755 'doc_details' => !empty($attributes['doc_details']) ? 'true' : 'false',
1756 'add_image' => !empty($attributes['add_image']) ? 'true' : 'false',
1757 'zoom_in' => !empty($attributes['zoomIn']) ? 'true' : 'false',
1758 'zoom_out' => !empty($attributes['zoomOut']) ? 'true' : 'false',
1759 'fit_view' => !empty($attributes['fitView']) ? 'true' : 'false',
1760 'bookmark' => !empty($attributes['bookmark']) ? 'true' : 'false',
1761 'watermark_text' => defined('EMBEDPRESS_SL_ITEM_SLUG') && isset($attributes['watermarkText']) ? esc_attr($attributes['watermarkText']) : '',
1762 'watermark_font_size' => defined('EMBEDPRESS_SL_ITEM_SLUG') && isset($attributes['watermarkFontSize']) ? intval($attributes['watermarkFontSize']) : 48,
1763 'watermark_color' => defined('EMBEDPRESS_SL_ITEM_SLUG') && isset($attributes['watermarkColor']) ? esc_attr($attributes['watermarkColor']) : '#000000',
1764 'watermark_opacity' => defined('EMBEDPRESS_SL_ITEM_SLUG') && isset($attributes['watermarkOpacity']) ? intval($attributes['watermarkOpacity']) : 15,
1765 'watermark_style' => defined('EMBEDPRESS_SL_ITEM_SLUG') && isset($attributes['watermarkStyle']) ? esc_attr($attributes['watermarkStyle']) : 'center',
1766 ];
1767
1768 if ($theme_mode === 'custom') {
1769 $params['customColor'] = isset($attributes['customColor']) ? esc_attr($attributes['customColor']) : '#403A81';
1770 }
1771
1772 $query_string = http_build_query($params);
1773 if (function_exists('mb_convert_encoding')) {
1774 $query_string = mb_convert_encoding($query_string, 'UTF-8');
1775 }
1776
1777 return base64_encode($query_string);
1778 }
1779 }
1780 ?>