PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 4.4.9
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v4.4.9
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 / BlockManager.php
embedpress / EmbedPress / Gutenberg Last commit date
BlockManager.php 5 months ago EmbedPressBlockRenderer.php 5 months ago FallbackHandler.php 9 months ago InitBlocks.php 9 months ago
BlockManager.php
1632 lines
1 <?php
2
3 namespace EmbedPress\Gutenberg;
4
5 use EmbedPress\Includes\Classes\Helper;
6 use EmbedPress\Core\AssetManager;
7
8 /**
9 * Block Manager for EmbedPress
10 *
11 * Handles registration and management of all EmbedPress Gutenberg blocks
12 * using the new centralized structure.
13 */
14 class BlockManager
15 {
16
17 /**
18 * Instance of this class
19 */
20 private static $instance = null;
21
22 /**
23 * Blocks directory path
24 */
25 private $blocks_path;
26
27 /**
28 * Blocks directory URL
29 */
30 private $blocks_url;
31
32 /**
33 * Available blocks
34 */
35 private $available_blocks = [
36 'EmbedPress' => [
37 'name' => 'embedpress/embedpress',
38 'render_callback' => [EmbedPressBlockRenderer::class, 'render'],
39 'setting_key' => 'embedpress',
40 'supports_save_function' => true
41 ],
42 'embedpress-pdf' => [
43 'name' => 'embedpress/embedpress-pdf',
44 'render_callback' => [EmbedPressBlockRenderer::class, 'render_embedpress_pdf'],
45 'setting_key' => 'embedpress-pdf',
46 'supports_save_function' => true
47 ],
48 'document' => [
49 'name' => 'embedpress/document',
50 'render_callback' => [EmbedPressBlockRenderer::class, 'render_document'],
51 'setting_key' => 'document',
52 'supports_save_function' => true
53 ],
54 'embedpress-calendar' => [
55 'name' => 'embedpress/embedpress-calendar',
56 'render_callback' => [EmbedPressBlockRenderer::class, 'render_embedpress_calendar'],
57 'setting_key' => 'embedpress-calendar',
58 'supports_save_function' => true
59 ],
60 'youtube-block' => [
61 'name' => 'embedpress/youtube-block',
62 'render_callback' => [EmbedPressBlockRenderer::class, 'render_youtube_block'],
63 'setting_key' => 'youtube-block',
64 'supports_save_function' => false
65 ],
66 'wistia-block' => [
67 'name' => 'embedpress/wistia-block',
68 'render_callback' => [EmbedPressBlockRenderer::class, 'render_wistia_block'],
69 'setting_key' => 'wistia-block',
70 'supports_save_function' => false
71 ],
72 ];
73
74 /**
75 * Get instance
76 */
77 public static function get_instance()
78 {
79 if (null === self::$instance) {
80 self::$instance = new self();
81 }
82 return self::$instance;
83 }
84
85 /**
86 * Constructor
87 */
88 private function __construct()
89 {
90 // Use src directory if it exists (development), otherwise use built assets (production/distribution)
91 if (file_exists(EMBEDPRESS_PATH_BASE . 'src/Blocks/')) {
92 $this->blocks_path = EMBEDPRESS_PATH_BASE . 'src/Blocks/';
93 $this->blocks_url = EMBEDPRESS_URL_STATIC . '../src/Blocks/';
94 } else {
95 // Fallback to built assets directory when src is not available (distribution)
96 $this->blocks_path = EMBEDPRESS_PATH_BASE . 'assets/blocks/';
97 $this->blocks_url = EMBEDPRESS_URL_ASSETS . 'blocks/';
98 }
99
100
101 // AssetManager is initialized in Core/init.php
102
103 add_action('init', [$this, 'register_blocks']);
104 add_action('admin_enqueue_scripts', [$this, 'enqueue_block_assets']);
105 add_action('admin_enqueue_scripts', [$this, 'enqueue_editor_assets']);
106 }
107
108 /**
109 * Register all blocks
110 */
111 public function register_blocks()
112 {
113 if (!function_exists('register_block_type')) {
114 return;
115 }
116
117 $elements = (array) get_option(EMBEDPRESS_PLG_NAME . ":elements", []);
118 $g_blocks = isset($elements['gutenberg']) ? (array) $elements['gutenberg'] : [];
119
120
121 // Ensure embedpress block is enabled by default if no settings exist
122 if (empty($elements) || !isset($elements['gutenberg'])) {
123 $this->ensure_default_blocks_enabled();
124 $elements = (array) get_option(EMBEDPRESS_PLG_NAME . ":elements", []);
125 $g_blocks = isset($elements['gutenberg']) ? (array) $elements['gutenberg'] : [];
126 }
127
128 foreach ($this->available_blocks as $block_folder => $block_config) {
129 $setting_key = $block_config['setting_key'];
130
131 // Check if block is enabled in settings
132 if (!empty($g_blocks[$setting_key])) {
133 $this->register_single_block($block_folder, $block_config);
134 } else {
135 // Unregister if disabled
136 if (\WP_Block_Type_Registry::get_instance()->is_registered($block_config['name'])) {
137 unregister_block_type($block_config['name']);
138 }
139 }
140 }
141 }
142
143 /**
144 * Register a single block
145 */
146 private function register_single_block($block_folder, $block_config)
147 {
148 $block_path = $this->blocks_path . $block_folder;
149 $block_json_path = $block_path . '/block.json';
150
151 // Check if we're in development mode (src directory exists) or distribution mode
152 $is_development_mode = file_exists(EMBEDPRESS_PATH_BASE . 'src/Blocks/');
153
154 if ($is_development_mode && file_exists($block_json_path)) {
155 // Development mode: Use block.json files
156 $block_args = [];
157
158 // For blocks that support save function, render_callback is only used for dynamic content
159 if (isset($block_config['render_callback'])) {
160 $block_args['render_callback'] = $block_config['render_callback'];
161 }
162
163 // Add attributes from the old system for compatibility
164 if ($block_config['name'] === 'embedpress/embedpress') {
165 $block_args['attributes'] = $this->get_embedpress_block_attributes();
166 } else if ($block_config['name'] === 'embedpress/embedpress-pdf') {
167 $block_args['attributes'] = $this->get_embedpress_pdf_attributes();
168 } else if ($block_config['name'] === 'embedpress/document') {
169 $block_args['attributes'] = $this->get_embedpress_doc_attributes();
170 } else if ($block_config['name'] === 'embedpress/youtube-block') {
171 $block_args['attributes'] = $this->get_youtube_block_attributes();
172 } else if ($block_config['name'] === 'embedpress/wistia-block') {
173 $block_args['attributes'] = $this->get_wistia_block_attributes();
174 }
175
176 register_block_type($block_json_path, $block_args);
177 } else {
178 // Distribution mode: Register blocks directly without block.json
179 // The JavaScript registration is handled by the bundled blocks.build.js file
180 // We only need to register the server-side render callbacks
181
182 $block_args = [
183 'render_callback' => $block_config['render_callback'] ?? null,
184 ];
185
186 // Add attributes for server-side rendering
187 if ($block_config['name'] === 'embedpress/embedpress') {
188 $block_args['attributes'] = $this->get_embedpress_block_attributes();
189 } else if ($block_config['name'] === 'embedpress/embedpress-pdf') {
190 $block_args['attributes'] = $this->get_embedpress_pdf_attributes();
191 } else if ($block_config['name'] === 'embedpress/document') {
192 $block_args['attributes'] = $this->get_embedpress_doc_attributes();
193 } else if ($block_config['name'] === 'embedpress/youtube-block') {
194 $block_args['attributes'] = $this->get_youtube_block_attributes();
195 } else if ($block_config['name'] === 'embedpress/wistia-block') {
196 $block_args['attributes'] = $this->get_wistia_block_attributes();
197 }
198
199 // Only register if not already registered by JavaScript
200 if (!\WP_Block_Type_Registry::get_instance()->is_registered($block_config['name'])) {
201 register_block_type($block_config['name'], $block_args);
202 } else {
203 // Block already registered by JavaScript, just update the render callback
204 $block_type = \WP_Block_Type_Registry::get_instance()->get_registered($block_config['name']);
205 if ($block_type && isset($block_config['render_callback'])) {
206 $block_type->render_callback = $block_config['render_callback'];
207 }
208 }
209 }
210 }
211
212 /**
213 * Get EmbedPress block attributes for compatibility
214 */
215 private function get_embedpress_block_attributes()
216 {
217 // Base attributes for all embeds
218 $attributes = [
219 // Core attributes
220 'clientId' => [
221 'type' => 'string',
222 ],
223 'url' => [
224 'type' => 'string',
225 'default' => ''
226 ],
227 'providerName' => [
228 'type' => 'string',
229 'default' => ''
230 ],
231 'embedHTML' => [
232 'type' => 'string',
233 'default' => ''
234 ],
235 'height' => [
236 'type' => 'string',
237 'default' => '600'
238 ],
239 'width' => [
240 'type' => 'string',
241 'default' => '600'
242 ],
243
244 // State attributes
245 'editingURL' => [
246 'type' => 'boolean',
247 'default' => false
248 ],
249 'fetching' => [
250 'type' => 'boolean',
251 'default' => false
252 ],
253 'cannotEmbed' => [
254 'type' => 'boolean',
255 'default' => false
256 ],
257 'interactive' => [
258 'type' => 'boolean',
259 'default' => false
260 ],
261 'align' => [
262 'type' => 'string',
263 'default' => 'center'
264 ],
265
266
267 // Custom Player
268 'customPlayer' => [
269 'type' => 'boolean',
270 'default' => false
271 ],
272 'playerPreset' => [
273 'type' => 'string',
274 'default' => 'preset-default'
275 ],
276 'playerColor' => [
277 'type' => 'string',
278 'default' => '#5b4e96',
279 ],
280 'autoPause' => [
281 'type' => 'boolean',
282 'default' => false
283 ],
284 'posterThumbnail' => [
285 'type' => 'string',
286 'default' => ''
287 ],
288 'playerPip' => [
289 'type' => 'boolean',
290 'default' => true
291 ],
292 'playerRestart' => [
293 'type' => 'boolean',
294 'default' => true
295 ],
296 'playerRewind' => [
297 'type' => 'boolean',
298 'default' => false
299 ],
300 'playerFastForward' => [
301 'type' => 'boolean',
302 'default' => false
303 ],
304 'playerTooltip' => [
305 'type' => 'boolean',
306 'default' => true
307 ],
308 'playerHideControls' => [
309 'type' => 'boolean',
310 'default' => false
311 ],
312 'powered_by' => [
313 'type' => 'boolean',
314 'default' => true
315 ],
316 ];
317
318 // Add provider-specific attributes
319 $attributes = array_merge($attributes, $this->get_youtube_attributes());
320 $attributes = array_merge($attributes, $this->get_vimeo_attributes());
321 $attributes = array_merge($attributes, $this->get_wistia_attributes());
322 $attributes = array_merge($attributes, $this->get_instagram_attributes());
323 $attributes = array_merge($attributes, $this->get_calendly_attributes());
324 $attributes = array_merge($attributes, $this->get_podcast_attributes());
325 $attributes = array_merge($attributes, $this->get_google_photos_attributes());
326 $attributes = array_merge($attributes, $this->get_nft_attributes());
327 $attributes = array_merge($attributes, $this->get_ad_manager_attributes());
328 $attributes = array_merge($attributes, $this->get_content_protection_attributes());
329 $attributes = array_merge($attributes, $this->get_social_sharing_attributes());
330 $attributes = array_merge($attributes, $this->get_custom_branding_attributes());
331
332 return $attributes;
333 }
334
335 /**
336 * Get PDF-specific attributes
337 */
338 private function get_embedpress_pdf_attributes()
339 {
340 $attributes = [
341 'clientId' => [
342 'type' => 'string',
343 ],
344 'id' => [
345 'type' => 'string'
346 ],
347 'href' => [
348 'type' => 'string'
349 ],
350 'fileName' => [
351 'type' => 'string',
352 ],
353 'mime' => [
354 'type' => 'string',
355 ],
356 'url' => [
357 'type' => 'string',
358 'default' => ''
359 ],
360 'height' => [
361 'type' => 'string',
362 'default' => '600'
363 ],
364 'width' => [
365 'type' => 'string',
366 'default' => '600'
367 ],
368 'viewerStyle' => [
369 'type' => 'string',
370 'default' => 'modern'
371 ],
372 'themeMode' => [
373 'type' => 'string',
374 'default' => 'default'
375 ],
376 'customColor' => [
377 'type' => 'string',
378 'default' => '#403A81'
379 ],
380 'toolbar' => [
381 'type' => 'boolean',
382 'default' => true
383 ],
384 'presentation' => [
385 'type' => 'boolean',
386 'default' => true
387 ],
388 'lazyLoad' => [
389 'type' => 'boolean',
390 'default' => false
391 ],
392 'position' => [
393 'type' => 'string',
394 'default' => 'top'
395 ],
396 'flipbook_toolbar_position' => [
397 'type' => 'string',
398 'default' => 'bottom'
399 ],
400 'download' => [
401 'type' => 'boolean',
402 'default' => true
403 ],
404 'open' => [
405 'type' => 'boolean',
406 'default' => false
407 ],
408 'copy_text' => [
409 'type' => 'boolean',
410 'default' => true
411 ],
412 'add_text' => [
413 'type' => 'boolean',
414 'default' => true
415 ],
416 'draw' => [
417 'type' => 'boolean',
418 'default' => true
419 ],
420 'add_image' => [
421 'type' => 'boolean',
422 'default' => true
423 ],
424 'zoomIn' => [
425 'type' => 'boolean',
426 'default' => true
427 ],
428 'zoomOut' => [
429 'type' => 'boolean',
430 'default' => true
431 ],
432 'fitView' => [
433 'type' => 'boolean',
434 'default' => true
435 ],
436 'bookmark' => [
437 'type' => 'boolean',
438 'default' => true
439 ],
440 'doc_details' => [
441 'type' => 'boolean',
442 'default' => true
443 ],
444 'doc_rotation' => [
445 'type' => 'boolean',
446 'default' => true
447 ],
448 'unitoption' => [
449 'type' => 'string',
450 'default' => '%'
451 ],
452 'powered_by' => [
453 'type' => 'boolean',
454 'default' => true
455 ],
456
457 ];
458
459 $attributes = array_merge($attributes, $this->get_content_protection_attributes());
460 $attributes = array_merge($attributes, $this->get_social_sharing_attributes());
461 $attributes = array_merge($attributes, $this->get_custom_branding_attributes());
462
463 return $attributes;
464 }
465
466 private function get_embedpress_doc_attributes()
467 {
468 $attributes = [
469 'clientId' => [
470 'type' => 'string',
471 ],
472
473 'id' => [
474 'type' => 'string',
475 ],
476 'href' => [
477 'type' => 'string',
478 ],
479 'height' => [
480 'type' => 'string',
481 'default' => '600'
482 ],
483 'width' => [
484 'type' => 'string',
485 'default' => '600'
486 ],
487 'fileName' => [
488 'type' => 'string',
489 ],
490 'mime' => [
491 'type' => 'string',
492 ],
493 'powered_by' => [
494 'type' => 'boolean',
495 'default' => true,
496 ],
497 'presentation' => [
498 'type' => 'boolean',
499 'default' => true,
500 ],
501 'docViewer' => [
502 'type' => 'string',
503 'default' => 'custom',
504 ],
505 'themeMode' => [
506 'type' => 'string',
507 'default' => 'default',
508 ],
509 'customColor' => [
510 'type' => 'string',
511 'default' => '#403A81',
512 ],
513 'position' => [
514 'type' => 'string',
515 'default' => 'top',
516 ],
517 'download' => [
518 'type' => 'boolean',
519 'default' => true,
520 ],
521 'open' => [
522 'type' => 'boolean',
523 'default' => false,
524 ],
525 'copy_text' => [
526 'type' => 'boolean',
527 'default' => true,
528 ],
529 'draw' => [
530 'type' => 'boolean',
531 'default' => true,
532 ],
533 'toolbar' => [
534 'type' => 'boolean',
535 'default' => true,
536 ],
537 'doc_rotation' => [
538 'type' => 'boolean',
539 'default' => true,
540 ],
541 ];
542
543 $attributes = array_merge($attributes, $this->get_content_protection_attributes());
544 $attributes = array_merge($attributes, $this->get_social_sharing_attributes());
545 $attributes = array_merge($attributes, $this->get_custom_branding_attributes());
546
547 return $attributes;
548 }
549
550 /**
551 * Get YouTube block-specific attributes (for legacy youtube-block)
552 */
553 private function get_youtube_block_attributes()
554 {
555 return [
556 'url' => [
557 'type' => 'string',
558 'default' => ''
559 ],
560 'iframeSrc' => [
561 'type' => 'string',
562 'default' => ''
563 ],
564 'mediaId' => [
565 'type' => 'string',
566 'default' => ''
567 ],
568 'align' => [
569 'type' => 'string',
570 'default' => 'center'
571 ]
572 ];
573 }
574
575 /**
576 * Get Wistia block-specific attributes (for legacy wistia-block)
577 */
578 private function get_wistia_block_attributes()
579 {
580 return [
581 'url' => [
582 'type' => 'string',
583 'default' => ''
584 ],
585 'iframeSrc' => [
586 'type' => 'string',
587 'default' => ''
588 ],
589 'align' => [
590 'type' => 'string',
591 'default' => 'center'
592 ]
593 ];
594 }
595
596 /**
597 * Get ContenProtection-specific attributes
598 */
599 private function get_content_protection_attributes()
600 {
601 return [
602 'lockContent' => [
603 'type' => 'boolean',
604 'default' => false
605 ],
606 'protectionType' => [
607 'type' => 'string',
608 'default' => 'password'
609 ],
610 'userRole' => [
611 'type' => 'array',
612 'default' => []
613 ],
614 'protectionMessage' => [
615 'type' => 'string',
616 'default' => 'You do not have access to this content. Only users with the following roles can view it: [user_roles]'
617 ],
618 'contentPassword' => [
619 'type' => 'string',
620 'default' => ''
621 ],
622 'lockHeading' => [
623 'type' => 'string',
624 'default' => 'Content Locked'
625 ],
626 'lockSubHeading' => [
627 'type' => 'string',
628 'default' => 'Content is locked and requires password to access it.'
629 ],
630 'lockErrorMessage' => [
631 'type' => 'string',
632 'default' => 'Oops, that wasn\'t the right password. Try again.'
633 ],
634 'passwordPlaceholder' => [
635 'type' => 'string',
636 'default' => 'Password'
637 ],
638 'submitButtonText' => [
639 'type' => 'string',
640 'default' => 'Unlock'
641 ],
642 'submitUnlockingText' => [
643 'type' => 'string',
644 'default' => 'Unlocking'
645 ],
646 'enableFooterMessage' => [
647 'type' => 'boolean',
648 'default' => false
649 ],
650 'footerMessage' => [
651 'type' => 'string',
652 'default' => 'In case you don\'t have the password, kindly reach out to content owner or administrator to request access.'
653 ],
654 ];
655 }
656
657 /**
658 * Get SocialSharing-specific attributes
659 */
660 private function get_social_sharing_attributes()
661 {
662 return [
663 'contentShare' => [
664 'type' => 'boolean',
665 'default' => false
666 ],
667 'sharePosition' => [
668 'type' => 'string',
669 'default' => 'right'
670 ],
671 'customTitle' => [
672 'type' => 'string',
673 'default' => ''
674 ],
675 'customDescription' => [
676 'type' => 'string',
677 'default' => ''
678 ],
679 'customThumbnail' => [
680 'type' => 'string',
681 'default' => ''
682 ],
683 'shareFacebook' => [
684 'type' => 'boolean',
685 'default' => true
686 ],
687 'shareTwitter' => [
688 'type' => 'boolean',
689 'default' => true
690 ],
691 'sharePinterest' => [
692 'type' => 'boolean',
693 'default' => true
694 ],
695 'shareLinkedin' => [
696 'type' => 'boolean',
697 'default' => true
698 ],
699 ];
700 }
701
702 /**
703 * Get CustomBranding-specific attributes
704 */
705 private function get_custom_branding_attributes()
706 {
707 return [
708 'customlogo' => [
709 'type' => 'string',
710 'default' => ''
711 ],
712 'logoX' => [
713 'type' => 'number',
714 'default' => 5
715 ],
716 'logoY' => [
717 'type' => 'number',
718 'default' => 10
719 ],
720 'customlogoUrl' => [
721 'type' => 'string',
722 ],
723 'logoOpacity' => [
724 'type' => 'number',
725 'default' => 0.6
726 ],
727 ];
728 }
729
730
731 /**
732 * Get YouTube-specific attributes
733 */
734 private function get_youtube_attributes()
735 {
736 return [
737 // YouTube specific attributes
738 'ispagination' => [
739 'type' => 'boolean',
740 'default' => true
741 ],
742 'ytChannelLayout' => [
743 'type' => 'string',
744 'default' => 'gallery'
745 ],
746 'pagesize' => [
747 'type' => 'string',
748 'default' => '6'
749 ],
750 'columns' => [
751 'type' => 'string',
752 'default' => '3'
753 ],
754 'gapbetweenvideos' => [
755 'type' => 'number',
756 'default' => 30
757 ],
758 'videosize' => [
759 'type' => 'string',
760 'default' => 'fixed',
761 ],
762 'starttime' => [
763 'type' => 'string',
764 ],
765 'endtime' => [
766 'type' => 'string',
767 ],
768 'autoplay' => [
769 'type' => 'boolean',
770 'default' => false,
771 ],
772 'muteVideo' => [
773 'type' => 'boolean',
774 'default' => true,
775 ],
776 'controls' => [
777 'type' => 'string',
778 ],
779 'fullscreen' => [
780 'type' => 'boolean',
781 'default' => true,
782 ],
783 'videoannotations' => [
784 'type' => 'boolean',
785 'default' => true,
786 ],
787 'progressbarcolor' => [
788 'type' => 'string',
789 'default' => 'red'
790 ],
791 'closedcaptions' => [
792 'type' => 'boolean',
793 'default' => true,
794 ],
795 'modestbranding' => [
796 'type' => 'string',
797 ],
798 'relatedvideos' => [
799 'type' => 'boolean',
800 'default' => true,
801 ],
802 'showinfo' => [
803 'type' => 'boolean',
804 'default' => true,
805 ],
806 'showLoop' => [
807 'type' => 'boolean',
808 'default' => true,
809 ],
810 ];
811 }
812
813 /**
814 * Get Vimeo-specific attributes
815 */
816 private function get_vimeo_attributes()
817 {
818 return [
819 'vimeoAutoplay' => [
820 'type' => 'boolean',
821 'default' => false,
822 ],
823 'vimeoLoop' => [
824 'type' => 'boolean',
825 'default' => false,
826 ],
827 'vimeoPortrait' => [
828 'type' => 'boolean',
829 'default' => true,
830 ],
831 'vimeoTitle' => [
832 'type' => 'boolean',
833 'default' => true,
834 ],
835 'vimeoByline' => [
836 'type' => 'boolean',
837 'default' => true,
838 ],
839 'vimeoColor' => [
840 'type' => 'string',
841 'default' => '#00adef'
842 ],
843 'vimeoDnt' => [
844 'type' => 'boolean',
845 'default' => false,
846 ],
847 // Additional Vimeo attributes
848 'vstarttime' => [
849 'type' => 'string',
850 ],
851 'vautoplay' => [
852 'type' => 'boolean',
853 'default' => false
854 ],
855 'vscheme' => [
856 'type' => 'string',
857 ],
858 'vtitle' => [
859 'type' => 'boolean',
860 'default' => true
861 ],
862 'vauthor' => [
863 'type' => 'boolean',
864 'default' => true
865 ],
866 'vavatar' => [
867 'type' => 'boolean',
868 'default' => true
869 ],
870 'vloop' => [
871 'type' => 'boolean',
872 'default' => false
873 ],
874 'vautopause' => [
875 'type' => 'boolean',
876 'default' => false
877 ],
878 'vdnt' => [
879 'type' => 'boolean',
880 'default' => false
881 ],
882 ];
883 }
884
885 /**
886 * Get Wistia-specific attributes
887 */
888 private function get_wistia_attributes()
889 {
890 return [
891 'wstarttime' => [
892 'type' => 'string',
893 ],
894 'wautoplay' => [
895 'type' => 'boolean',
896 'default' => true
897 ],
898 'scheme' => [
899 'type' => 'string',
900 ],
901 'captions' => [
902 'type' => 'boolean',
903 'default' => true
904 ],
905 'playbutton' => [
906 'type' => 'boolean',
907 'default' => true
908 ],
909 'smallplaybutton' => [
910 'type' => 'boolean',
911 'default' => true
912 ],
913 'playbar' => [
914 'type' => 'boolean',
915 'default' => true
916 ],
917 'resumable' => [
918 'type' => 'boolean',
919 'default' => true
920 ],
921 'wistiafocus' => [
922 'type' => 'boolean',
923 'default' => true
924 ],
925 'volumecontrol' => [
926 'type' => 'boolean',
927 'default' => true
928 ],
929 'volume' => [
930 'type' => 'number',
931 'default' => 100
932 ],
933 'rewind' => [
934 'type' => 'boolean',
935 'default' => false
936 ],
937 'wfullscreen' => [
938 'type' => 'boolean',
939 'default' => true
940 ],
941 ];
942 }
943
944 /**
945 * Get Instagram-specific attributes
946 */
947 private function get_instagram_attributes()
948 {
949 return [
950 'instaLayout' => [
951 'type' => 'string',
952 'default' => 'insta-grid'
953 ],
954 'carouselArrows' => [
955 'type' => 'boolean',
956 'default' => true
957 ],
958 'carouselSpacing' => [
959 'type' => 'string',
960 'default' => '0'
961 ],
962 'carouselDots' => [
963 'type' => 'boolean',
964 'default' => false
965 ],
966 // Instagram Feed attributes
967 'instafeedFeedType' => [
968 'type' => 'string',
969 'default' => 'user_account_type',
970 ],
971 'instafeedAccountType' => [
972 'type' => 'string',
973 'default' => 'personal',
974 ],
975 'instafeedProfileImage' => [
976 'type' => 'boolean',
977 'default' => true,
978 ],
979 'instafeedProfileImageUrl' => [
980 'type' => 'string',
981 'default' => '',
982 ],
983 'instafeedFollowBtn' => [
984 'type' => 'boolean',
985 'default' => true,
986 ],
987 'instafeedFollowBtnLabel' => [
988 'type' => 'string',
989 'default' => 'Follow',
990 ],
991 'instafeedPostsCount' => [
992 'type' => 'boolean',
993 'default' => true,
994 ],
995 'instafeedPostsCountText' => [
996 'type' => 'string',
997 'default' => '[count] posts',
998 ],
999 'instafeedFollowersCount' => [
1000 'type' => 'boolean',
1001 'default' => true,
1002 ],
1003 'instafeedFollowersCountText' => [
1004 'type' => 'string',
1005 'default' => '[count] followers',
1006 ],
1007 'instafeedAccName' => [
1008 'type' => 'boolean',
1009 'default' => true,
1010 ],
1011 'instafeedColumns' => [
1012 'type' => 'string',
1013 'default' => '3'
1014 ],
1015 'instafeedColumnsGap' => [
1016 'type' => 'string',
1017 'default' => '5'
1018 ],
1019 'instafeedPostsPerPage' => [
1020 'type' => 'string',
1021 'default' => '12'
1022 ],
1023 'instafeedTab' => [
1024 'type' => 'boolean',
1025 'default' => true,
1026 ],
1027 'instafeedLikesCount' => [
1028 'type' => 'boolean',
1029 'default' => true,
1030 ],
1031 'instafeedCommentsCount' => [
1032 'type' => 'boolean',
1033 'default' => true,
1034 ],
1035 'instafeedPopup' => [
1036 'type' => 'boolean',
1037 'default' => true,
1038 ],
1039 'instafeedPopupFollowBtn' => [
1040 'type' => 'boolean',
1041 'default' => true,
1042 ],
1043 'instafeedPopupFollowBtnLabel' => [
1044 'type' => 'string',
1045 'default' => 'Follow',
1046 ],
1047 'instafeedLoadmore' => [
1048 'type' => 'boolean',
1049 'default' => true,
1050 ],
1051 'instafeedLoadmoreLabel' => [
1052 'type' => 'string',
1053 'default' => 'Load More',
1054 ],
1055 'slidesShow' => [
1056 'type' => 'string',
1057 'default' => '4'
1058 ],
1059 'slidesScroll' => [
1060 'type' => 'string',
1061 'default' => '4'
1062 ],
1063 'carouselAutoplay' => [
1064 'type' => 'boolean',
1065 'default' => false
1066 ],
1067 'autoplaySpeed' => [
1068 'type' => 'string',
1069 'default' => '3000'
1070 ],
1071 'transitionSpeed' => [
1072 'type' => 'string',
1073 'default' => '1000'
1074 ],
1075 'carouselLoop' => [
1076 'type' => 'boolean',
1077 'default' => true
1078 ],
1079 ];
1080 }
1081
1082 /**
1083 * Get Calendly-specific attributes
1084 */
1085 private function get_calendly_attributes()
1086 {
1087 return [
1088 'cEmbedType' => [
1089 'type' => 'string',
1090 'default' => 'inline'
1091 ],
1092 'calendlyData' => [
1093 'type' => 'boolean',
1094 'default' => false
1095 ],
1096 'hideCookieBanner' => [
1097 'type' => 'boolean',
1098 'default' => false
1099 ],
1100 'hideEventTypeDetails' => [
1101 'type' => 'boolean',
1102 'default' => false
1103 ],
1104 'cBackgroundColor' => [
1105 'type' => 'string',
1106 'default' => 'ffffff'
1107 ],
1108 'cTextColor' => [
1109 'type' => 'string',
1110 'default' => '1A1A1A'
1111 ],
1112 'cButtonLinkColor' => [
1113 'type' => 'string',
1114 'default' => '0000FF'
1115 ],
1116 'cPopupButtonText' => [
1117 'type' => 'string',
1118 'default' => 'Schedule time with me'
1119 ],
1120 'cPopupButtonBGColor' => [
1121 'type' => 'string',
1122 'default' => '0000FF'
1123 ],
1124 'cPopupButtonTextColor' => [
1125 'type' => 'string',
1126 'default' => 'FFFFFF'
1127 ],
1128 'cPopupLinkText' => [
1129 'type' => 'string',
1130 'default' => 'Schedule time with me'
1131 ],
1132 ];
1133 }
1134
1135 /**
1136 * Get Podcast-specific attributes (Spreaker)
1137 */
1138 private function get_podcast_attributes()
1139 {
1140 return [
1141 // Spreaker attributes
1142 'theme' => [
1143 'type' => 'string',
1144 'default' => 'light'
1145 ],
1146 'color' => [
1147 'type' => 'string',
1148 'default' => ''
1149 ],
1150 'coverImageUrl' => [
1151 'type' => 'string',
1152 'default' => ''
1153 ],
1154 'playlist' => [
1155 'type' => 'boolean',
1156 'default' => false
1157 ],
1158 'playlistContinuous' => [
1159 'type' => 'boolean',
1160 'default' => false
1161 ],
1162 'playlistLoop' => [
1163 'type' => 'boolean',
1164 'default' => false
1165 ],
1166 'playlistAutoupdate' => [
1167 'type' => 'boolean',
1168 'default' => true
1169 ],
1170 'chaptersImage' => [
1171 'type' => 'boolean',
1172 'default' => true
1173 ],
1174 'episodeImagePosition' => [
1175 'type' => 'string',
1176 'default' => 'right'
1177 ],
1178 'hideLikes' => [
1179 'type' => 'boolean',
1180 'default' => false
1181 ],
1182 'hideComments' => [
1183 'type' => 'boolean',
1184 'default' => false
1185 ],
1186 'hideSharing' => [
1187 'type' => 'boolean',
1188 'default' => false
1189 ],
1190 'hideLogo' => [
1191 'type' => 'boolean',
1192 'default' => false
1193 ],
1194 'hideEpisodeDescription' => [
1195 'type' => 'boolean',
1196 'default' => false
1197 ],
1198 'hidePlaylistDescriptions' => [
1199 'type' => 'boolean',
1200 'default' => false
1201 ],
1202 'hidePlaylistImages' => [
1203 'type' => 'boolean',
1204 'default' => false
1205 ],
1206 'hideDownload' => [
1207 'type' => 'boolean',
1208 'default' => false
1209 ],
1210 ];
1211 }
1212
1213 /**
1214 * Get Google Photos-specific attributes
1215 */
1216 private function get_google_photos_attributes()
1217 {
1218 return [
1219 'mode' => [
1220 'type' => 'string',
1221 'default' => 'carousel'
1222 ],
1223 'imageWidth' => [
1224 'type' => 'number',
1225 'default' => 800
1226 ],
1227 'imageHeight' => [
1228 'type' => 'number',
1229 'default' => 600
1230 ],
1231 'showTitle' => [
1232 'type' => 'boolean',
1233 'default' => true
1234 ],
1235 'playerAutoplay' => [
1236 'type' => 'boolean',
1237 'default' => false
1238 ],
1239 'delay' => [
1240 'type' => 'number',
1241 'default' => 5
1242 ],
1243 'repeat' => [
1244 'type' => 'boolean',
1245 'default' => true
1246 ],
1247 'mediaitemsAspectRatio' => [
1248 'type' => 'boolean',
1249 'default' => true
1250 ],
1251 'mediaitemsEnlarge' => [
1252 'type' => 'boolean',
1253 'default' => false
1254 ],
1255 'mediaitemsStretch' => [
1256 'type' => 'boolean',
1257 'default' => false
1258 ],
1259 'mediaitemsCover' => [
1260 'type' => 'boolean',
1261 'default' => false
1262 ],
1263 'backgroundColor' => [
1264 'type' => 'string',
1265 'default' => '#000000'
1266 ],
1267 'expiration' => [
1268 'type' => 'number',
1269 'default' => 60
1270 ],
1271 ];
1272 }
1273
1274 /**
1275 * Get NFT/OpenSea-specific attributes
1276 */
1277 private function get_nft_attributes()
1278 {
1279 return [
1280 'limit' => [
1281 'type' => 'number',
1282 'default' => 20
1283 ],
1284 'itemperpage' => [
1285 'type' => 'number',
1286 'default' => 9
1287 ],
1288 'loadmore' => [
1289 'type' => 'boolean',
1290 'default' => false
1291 ],
1292 'loadmorelabel' => [
1293 'type' => 'text',
1294 'default' => 'Load More'
1295 ],
1296 'orderby' => [
1297 'type' => 'string',
1298 'default' => 'desc'
1299 ],
1300 'gapbetweenitem' => [
1301 'type' => 'number',
1302 'default' => 30
1303 ],
1304 'layout' => [
1305 'type' => 'string',
1306 'default' => 'ep-grid'
1307 ],
1308 'preset' => [
1309 'type' => 'string',
1310 'default' => 'preset-default'
1311 ],
1312 'nftperrow' => [
1313 'type' => 'number',
1314 'default' => 3
1315 ],
1316 'collectionname' => [
1317 'type' => 'boolean',
1318 'default' => true
1319 ],
1320 'nftimage' => [
1321 'type' => 'boolean',
1322 'default' => true
1323 ],
1324 'nfttitle' => [
1325 'type' => 'boolean',
1326 'default' => true
1327 ],
1328 'nftcreator' => [
1329 'type' => 'boolean',
1330 'default' => true
1331 ],
1332 'prefix_nftcreator' => [
1333 'type' => 'string',
1334 'default' => 'Created By'
1335 ],
1336 'nftprice' => [
1337 'type' => 'boolean',
1338 'default' => true
1339 ],
1340 'prefix_nftprice' => [
1341 'type' => 'string',
1342 'default' => 'Current Price'
1343 ],
1344 'nftlastsale' => [
1345 'type' => 'boolean',
1346 'default' => true
1347 ],
1348 'prefix_nftlastsale' => [
1349 'type' => 'string',
1350 'default' => 'Last Sale'
1351 ],
1352 'nftbutton' => [
1353 'type' => 'boolean',
1354 'default' => true
1355 ],
1356 'nftrank' => [
1357 'type' => 'boolean',
1358 'default' => true
1359 ],
1360 'label_nftrank' => [
1361 'type' => 'string',
1362 'default' => 'Rank'
1363 ],
1364 'nftdetails' => [
1365 'type' => 'boolean',
1366 'default' => true
1367 ],
1368 'label_nftdetails' => [
1369 'type' => 'string',
1370 'default' => 'Details'
1371 ],
1372 'label_nftbutton' => [
1373 'type' => 'string',
1374 'default' => 'See Details'
1375 ],
1376 'alignment' => [
1377 'type' => 'string',
1378 'default' => 'ep-item-center'
1379 ],
1380 // Color and Typography for NFT
1381 'itemBGColor' => [
1382 'type' => 'string',
1383 ],
1384 'collectionNameColor' => [
1385 'type' => 'string',
1386 ],
1387 'collectionNameFZ' => [
1388 'type' => 'number',
1389 ],
1390 'titleColor' => [
1391 'type' => 'string',
1392 ],
1393 'titleFontsize' => [
1394 'type' => 'number',
1395 ],
1396 'creatorColor' => [
1397 'type' => 'string',
1398 ],
1399 'creatorFontsize' => [
1400 'type' => 'number',
1401 ],
1402 'creatorLinkColor' => [
1403 'type' => 'string',
1404 ],
1405 'creatorLinkFontsize' => [
1406 'type' => 'number',
1407 ],
1408 'priceLabelColor' => [
1409 'type' => 'string',
1410 ],
1411 'priceLabelFontsize' => [
1412 'type' => 'number',
1413 ],
1414 'priceColor' => [
1415 'type' => 'string',
1416 ],
1417 'priceFontsize' => [
1418 'type' => 'number',
1419 ],
1420 'priceUSDColor' => [
1421 'type' => 'string',
1422 ],
1423 'priceUSDFontsize' => [
1424 'type' => 'number',
1425 ],
1426 'lastSaleLabelColor' => [
1427 'type' => 'string',
1428 ],
1429 'lastSaleLabelFontsize' => [
1430 'type' => 'number',
1431 ],
1432 'lastSaleColor' => [
1433 'type' => 'string',
1434 ],
1435 'lastSaleFontsize' => [
1436 'type' => 'number',
1437 ],
1438 'lastSaleUSDColor' => [
1439 'type' => 'string',
1440 ],
1441 'lastSaleUSDFontsize' => [
1442 'type' => 'number',
1443 ],
1444 'buttonTextColor' => [
1445 'type' => 'string',
1446 ],
1447 'buttonBackgroundColor' => [
1448 'type' => 'string',
1449 ],
1450 'buttonTextFontsize' => [
1451 'type' => 'number',
1452 ],
1453 'loadmoreTextColor' => [
1454 'type' => 'string',
1455 ],
1456 'loadmoreBackgroundColor' => [
1457 'type' => 'string',
1458 ],
1459 'loadmoreTextFontsize' => [
1460 'type' => 'number',
1461 ],
1462 'rankBtnColor' => [
1463 'type' => 'string',
1464 ],
1465 'rankBtnBorderColor' => [
1466 'type' => 'string',
1467 ],
1468 'rankBtnFZ' => [
1469 'type' => 'number',
1470 ],
1471 'rankLabelColor' => [
1472 'type' => 'string',
1473 ],
1474 'rankLabelFZ' => [
1475 'type' => 'number',
1476 ],
1477 'detialTitleColor' => [
1478 'type' => 'string',
1479 ],
1480 'detialTitleFZ' => [
1481 'type' => 'number',
1482 ],
1483 'detailTextColor' => [
1484 'type' => 'string',
1485 ],
1486 'detailTextLinkColor' => [
1487 'type' => 'string',
1488 ],
1489 'detailTextFZ' => [
1490 'type' => 'number',
1491 ],
1492 ];
1493 }
1494
1495 /**
1496 * Get Ad Manager-specific attributes
1497 */
1498 private function get_ad_manager_attributes()
1499 {
1500 return [
1501 'adManager' => [
1502 'type' => 'boolean',
1503 'default' => false
1504 ],
1505 'adSource' => [
1506 'type' => 'string',
1507 'default' => 'video'
1508 ],
1509 'adContent' => [
1510 'type' => 'object',
1511 ],
1512 'adFileUrl' => [
1513 'type' => 'string',
1514 'default' => ''
1515 ],
1516 'adWidth' => [
1517 'type' => 'string',
1518 'default' => '300'
1519 ],
1520 'adHeight' => [
1521 'type' => 'string',
1522 'default' => '200'
1523 ],
1524 'adXPosition' => [
1525 'type' => 'number',
1526 'default' => 25
1527 ],
1528 'adYPosition' => [
1529 'type' => 'number',
1530 'default' => 10
1531 ],
1532 'adUrl' => [
1533 'type' => 'string',
1534 'default' => ''
1535 ],
1536 'adStart' => [
1537 'type' => 'string',
1538 'default' => '10'
1539 ],
1540 'adSkipButton' => [
1541 'type' => 'boolean',
1542 'default' => true
1543 ],
1544 'adSkipButtonAfter' => [
1545 'type' => 'string',
1546 'default' => '5'
1547 ],
1548 ];
1549 }
1550
1551 /**
1552 * Enqueue block assets for both frontend and backend
1553 * Now handled by AssetManager
1554 */
1555 public function enqueue_block_assets()
1556 {
1557 // Assets are now handled by the centralized AssetManager
1558 // This method is kept for backward compatibility
1559 }
1560
1561 /**
1562 * Enqueue editor assets
1563 */
1564 public function enqueue_editor_assets()
1565 {
1566 // Assets are now handled by AssetManager, but we still need to localize the script
1567 $this->localize_editor_script();
1568 }
1569
1570 /**
1571 * Localize editor script with necessary data
1572 * Note: Localization is now handled by LocalizationManager
1573 */
1574 private function localize_editor_script()
1575 {
1576 // Localization is now handled by LocalizationManager
1577 // This method is kept for backward compatibility but functionality has been moved
1578 }
1579
1580 /**
1581 * Add a new block to the available blocks list
1582 */
1583 public function add_block($folder_name, $config)
1584 {
1585 $this->available_blocks[$folder_name] = $config;
1586 }
1587
1588 /**
1589 * Ensure default blocks are enabled if no settings exist
1590 */
1591 private function ensure_default_blocks_enabled()
1592 {
1593 $elements = (array) get_option(EMBEDPRESS_PLG_NAME . ":elements", []);
1594
1595 // If no gutenberg settings exist, create default ones
1596 if (!isset($elements['gutenberg'])) {
1597 $elements['gutenberg'] = [];
1598 }
1599
1600 // Enable embedpress block by default
1601 if (!isset($elements['gutenberg']['embedpress'])) {
1602 $elements['gutenberg']['embedpress'] = 'embedpress';
1603 }
1604
1605 // Enable embedpress-pdf block by default
1606 if (!isset($elements['gutenberg']['embedpress-pdf'])) {
1607 $elements['gutenberg']['embedpress-pdf'] = 'embedpress-pdf';
1608 }
1609
1610 // Enable youtube-block by default for legacy support
1611 if (!isset($elements['gutenberg']['youtube-block'])) {
1612 $elements['gutenberg']['youtube-block'] = 'youtube-block';
1613 }
1614
1615 // Enable wistia-block by default for legacy support
1616 if (!isset($elements['gutenberg']['wistia-block'])) {
1617 $elements['gutenberg']['wistia-block'] = 'wistia-block';
1618 }
1619
1620 // Update options if any changes were made
1621 update_option(EMBEDPRESS_PLG_NAME . ":elements", $elements);
1622 }
1623
1624 /**
1625 * Get available blocks
1626 */
1627 public function get_available_blocks()
1628 {
1629 return $this->available_blocks;
1630 }
1631 }
1632