PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / trunk
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more vtrunk
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 3 weeks ago EmbedPressBlockRenderer.php 1 week ago FallbackHandler.php 9 months ago InitBlocks.php 9 months ago
BlockManager.php
1952 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 'pdf-gallery' => [
73 'name' => 'embedpress/pdf-gallery',
74 'render_callback' => [EmbedPressBlockRenderer::class, 'render_pdf_gallery'],
75 'setting_key' => 'pdf-gallery',
76 'supports_save_function' => true
77 ],
78 ];
79
80 /**
81 * Get instance
82 */
83 public static function get_instance()
84 {
85 if (null === self::$instance) {
86 self::$instance = new self();
87 }
88 return self::$instance;
89 }
90
91 /**
92 * Constructor
93 */
94 private function __construct()
95 {
96 // Use src directory if it exists (development), otherwise use built assets (production/distribution)
97 if (file_exists(EMBEDPRESS_PATH_BASE . 'src/Blocks/')) {
98 $this->blocks_path = EMBEDPRESS_PATH_BASE . 'src/Blocks/';
99 $this->blocks_url = EMBEDPRESS_URL_STATIC . '../src/Blocks/';
100 } else {
101 // Fallback to built assets directory when src is not available (distribution)
102 $this->blocks_path = EMBEDPRESS_PATH_BASE . 'assets/blocks/';
103 $this->blocks_url = EMBEDPRESS_URL_ASSETS . 'blocks/';
104 }
105
106
107 // AssetManager is initialized in Core/init.php
108
109 add_action('init', [$this, 'register_blocks']);
110 add_action('admin_enqueue_scripts', [$this, 'enqueue_block_assets']);
111 add_action('admin_enqueue_scripts', [$this, 'enqueue_editor_assets']);
112
113 // Register PDF gallery thumbnail AJAX handlers
114 // Uses Pdf_Thumbnail_Handler (no Elementor dependency) so this works with Gutenberg-only setups
115 add_action('wp_ajax_ep_upload_pdf_thumbnail', ['EmbedPress\Includes\Classes\Pdf_Thumbnail_Handler', 'ajax_upload_pdf_thumbnail']);
116 add_action('wp_ajax_ep_generate_pdf_thumbnail', ['EmbedPress\Includes\Classes\Pdf_Thumbnail_Handler', 'ajax_generate_pdf_thumbnail']);
117 }
118
119 /**
120 * Register all blocks
121 */
122 public function register_blocks()
123 {
124 if (!function_exists('register_block_type')) {
125 return;
126 }
127
128 $elements = (array) get_option(EMBEDPRESS_PLG_NAME . ":elements", []);
129 $g_blocks = isset($elements['gutenberg']) ? (array) $elements['gutenberg'] : [];
130
131
132 // Ensure embedpress block is enabled by default if no settings exist
133 if (empty($elements) || !isset($elements['gutenberg'])) {
134 $this->ensure_default_blocks_enabled();
135 $elements = (array) get_option(EMBEDPRESS_PLG_NAME . ":elements", []);
136 $g_blocks = isset($elements['gutenberg']) ? (array) $elements['gutenberg'] : [];
137 }
138
139 foreach ($this->available_blocks as $block_folder => $block_config) {
140 $setting_key = $block_config['setting_key'];
141
142 // Check if block is enabled in settings
143 if (!empty($g_blocks[$setting_key])) {
144 $this->register_single_block($block_folder, $block_config);
145 } else {
146 // Unregister if disabled
147 if (\WP_Block_Type_Registry::get_instance()->is_registered($block_config['name'])) {
148 unregister_block_type($block_config['name']);
149 }
150 }
151 }
152 }
153
154 /**
155 * Register a single block
156 */
157 private function register_single_block($block_folder, $block_config)
158 {
159 $block_path = $this->blocks_path . $block_folder;
160 $block_json_path = $block_path . '/block.json';
161
162 // Check if we're in development mode (src directory exists) or distribution mode
163 $is_development_mode = file_exists(EMBEDPRESS_PATH_BASE . 'src/Blocks/');
164
165 if ($is_development_mode && file_exists($block_json_path)) {
166 // Development mode: Use block.json files
167 $block_args = [];
168
169 // For blocks that support save function, render_callback is only used for dynamic content
170 if (isset($block_config['render_callback'])) {
171 $block_args['render_callback'] = $block_config['render_callback'];
172 }
173
174 // Add attributes from the old system for compatibility
175 if ($block_config['name'] === 'embedpress/embedpress') {
176 $block_args['attributes'] = $this->get_embedpress_block_attributes();
177 } else if ($block_config['name'] === 'embedpress/embedpress-pdf') {
178 $block_args['attributes'] = $this->get_embedpress_pdf_attributes();
179 } else if ($block_config['name'] === 'embedpress/document') {
180 $block_args['attributes'] = $this->get_embedpress_doc_attributes();
181 } else if ($block_config['name'] === 'embedpress/youtube-block') {
182 $block_args['attributes'] = $this->get_youtube_block_attributes();
183 } else if ($block_config['name'] === 'embedpress/wistia-block') {
184 $block_args['attributes'] = $this->get_wistia_block_attributes();
185 } else if ($block_config['name'] === 'embedpress/pdf-gallery') {
186 $block_args['attributes'] = $this->get_pdf_gallery_attributes();
187 }
188
189 register_block_type($block_json_path, $block_args);
190 } else {
191 // Distribution mode: Register blocks directly without block.json
192 // The JavaScript registration is handled by the bundled blocks.build.js file
193 // We only need to register the server-side render callbacks
194
195 $block_args = [
196 'render_callback' => $block_config['render_callback'] ?? null,
197 ];
198
199 // Add attributes for server-side rendering
200 if ($block_config['name'] === 'embedpress/embedpress') {
201 $block_args['attributes'] = $this->get_embedpress_block_attributes();
202 } else if ($block_config['name'] === 'embedpress/embedpress-pdf') {
203 $block_args['attributes'] = $this->get_embedpress_pdf_attributes();
204 } else if ($block_config['name'] === 'embedpress/document') {
205 $block_args['attributes'] = $this->get_embedpress_doc_attributes();
206 } else if ($block_config['name'] === 'embedpress/youtube-block') {
207 $block_args['attributes'] = $this->get_youtube_block_attributes();
208 } else if ($block_config['name'] === 'embedpress/wistia-block') {
209 $block_args['attributes'] = $this->get_wistia_block_attributes();
210 } else if ($block_config['name'] === 'embedpress/pdf-gallery') {
211 $block_args['attributes'] = $this->get_pdf_gallery_attributes();
212 }
213
214 // Only register if not already registered by JavaScript
215 if (!\WP_Block_Type_Registry::get_instance()->is_registered($block_config['name'])) {
216 register_block_type($block_config['name'], $block_args);
217 } else {
218 // Block already registered by JavaScript, just update the render callback
219 $block_type = \WP_Block_Type_Registry::get_instance()->get_registered($block_config['name']);
220 if ($block_type && isset($block_config['render_callback'])) {
221 $block_type->render_callback = $block_config['render_callback'];
222 }
223 }
224 }
225 }
226
227 /**
228 * Get EmbedPress block attributes for compatibility
229 */
230 private function get_embedpress_block_attributes()
231 {
232 // Base attributes for all embeds
233 $attributes = [
234 // Core attributes
235 'clientId' => [
236 'type' => 'string',
237 ],
238 'url' => [
239 'type' => 'string',
240 'default' => ''
241 ],
242 'providerName' => [
243 'type' => 'string',
244 'default' => ''
245 ],
246 'embedHTML' => [
247 'type' => 'string',
248 'default' => ''
249 ],
250 'height' => [
251 'type' => 'string',
252 'default' => '600'
253 ],
254 'width' => [
255 'type' => 'string',
256 'default' => '600'
257 ],
258
259 // State attributes
260 'editingURL' => [
261 'type' => 'boolean',
262 'default' => false
263 ],
264 'fetching' => [
265 'type' => 'boolean',
266 'default' => false
267 ],
268 'cannotEmbed' => [
269 'type' => 'boolean',
270 'default' => false
271 ],
272 'interactive' => [
273 'type' => 'boolean',
274 'default' => false
275 ],
276 'align' => [
277 'type' => 'string',
278 'default' => 'center'
279 ],
280
281
282 // Custom Player
283 'customPlayer' => [
284 'type' => 'boolean',
285 'default' => false
286 ],
287 'playerPreset' => [
288 'type' => 'string',
289 'default' => 'preset-default'
290 ],
291 'playerColor' => [
292 'type' => 'string',
293 'default' => '#5b4e96',
294 ],
295 'autoPause' => [
296 'type' => 'boolean',
297 'default' => false
298 ],
299 'posterThumbnail' => [
300 'type' => 'string',
301 'default' => ''
302 ],
303 'playerPip' => [
304 'type' => 'boolean',
305 'default' => true
306 ],
307 'playerRestart' => [
308 'type' => 'boolean',
309 'default' => true
310 ],
311 'playerRewind' => [
312 'type' => 'boolean',
313 'default' => false
314 ],
315 'playerFastForward' => [
316 'type' => 'boolean',
317 'default' => false
318 ],
319 'playerTooltip' => [
320 'type' => 'boolean',
321 'default' => true
322 ],
323 'playerHideControls' => [
324 'type' => 'boolean',
325 'default' => false
326 ],
327 'playerDownload' => [
328 'type' => 'boolean',
329 'default' => true
330 ],
331 // Pro Custom Player features (PRD #81243). These MUST mirror
332 // attributes.js or the render_callback receives stripped values
333 // and the Pro filter (AdvancedPlayerHandlers::build_options)
334 // falls back to schema defaults — e.g. "Show Replay" stays on
335 // even when the editor toggle is off, because the false value
336 // never reaches PHP.
337 'playerAutoResume' => [
338 'type' => 'boolean',
339 'default' => false
340 ],
341 'playerAutoResumeThreshold' => [
342 'type' => 'number',
343 'default' => 30
344 ],
345 'playerEndScreen' => [
346 'type' => 'boolean',
347 'default' => false
348 ],
349 'playerEndScreenMode' => [
350 'type' => 'string',
351 'default' => 'message'
352 ],
353 'playerEndScreenMessage' => [
354 'type' => 'string',
355 'default' => 'Thanks for watching!'
356 ],
357 'playerEndScreenButtonText' => [
358 'type' => 'string',
359 'default' => 'Learn more'
360 ],
361 'playerEndScreenButtonUrl' => [
362 'type' => 'string',
363 'default' => ''
364 ],
365 'playerEndScreenRedirectUrl' => [
366 'type' => 'string',
367 'default' => ''
368 ],
369 'playerEndScreenRedirectNewWindow' => [
370 'type' => 'boolean',
371 'default' => false
372 ],
373 'playerEndScreenCountdown' => [
374 'type' => 'number',
375 'default' => 5
376 ],
377 'playerEndScreenShowReplay' => [
378 'type' => 'boolean',
379 'default' => true
380 ],
381 'playerPrivacyMode' => [
382 'type' => 'boolean',
383 'default' => false
384 ],
385 'playerPrivacyMessage' => [
386 'type' => 'string',
387 'default' => 'Click to load. By playing, you accept third-party cookies.'
388 ],
389 'playerTimedCTA' => [
390 'type' => 'boolean',
391 'default' => false
392 ],
393 'playerTimedCTAItems' => [
394 'type' => 'array',
395 'default' => []
396 ],
397 'playerChapters' => [
398 'type' => 'boolean',
399 'default' => false
400 ],
401 'playerChaptersItems' => [
402 'type' => 'array',
403 'default' => []
404 ],
405 'playerChaptersShowTitle' => [
406 'type' => 'boolean',
407 'default' => true
408 ],
409 'playerEmailCapture' => [
410 'type' => 'boolean',
411 'default' => false
412 ],
413 'playerEmailCaptureTime' => [
414 'type' => 'number',
415 'default' => 30
416 ],
417 'playerEmailCaptureUnit' => [
418 'type' => 'string',
419 'default' => 'seconds'
420 ],
421 'playerEmailCaptureHeadline' => [
422 'type' => 'string',
423 'default' => 'Enter your email to keep watching'
424 ],
425 'playerEmailCaptureRequireName' => [
426 'type' => 'boolean',
427 'default' => false
428 ],
429 'playerEmailCaptureAllowSkip' => [
430 'type' => 'boolean',
431 'default' => false
432 ],
433 'playerEmailCaptureButtonText' => [
434 'type' => 'string',
435 'default' => 'Continue'
436 ],
437 'playerActionLock' => [
438 'type' => 'boolean',
439 'default' => false
440 ],
441 'playerActionLockType' => [
442 'type' => 'string',
443 'default' => 'share'
444 ],
445 'playerActionLockHeadline' => [
446 'type' => 'string',
447 'default' => 'Unlock this video'
448 ],
449 'playerActionLockMessage' => [
450 'type' => 'string',
451 'default' => 'Complete the action below to continue watching.'
452 ],
453 'playerActionLockShareNetworks' => [
454 'type' => 'array',
455 'default' => ['facebook', 'twitter', 'linkedin']
456 ],
457 'playerActionLockShareUrl' => [
458 'type' => 'string',
459 'default' => ''
460 ],
461 'playerActionLockLinkUrl' => [
462 'type' => 'string',
463 'default' => ''
464 ],
465 'playerActionLockLinkText' => [
466 'type' => 'string',
467 'default' => 'Open link'
468 ],
469 'playerActionLockBypassAdmins' => [
470 'type' => 'boolean',
471 'default' => true
472 ],
473 'playerAdaptiveStreaming' => [
474 'type' => 'boolean',
475 'default' => false
476 ],
477 'playerCountryRestriction' => [
478 'type' => 'boolean',
479 'default' => false
480 ],
481 'playerCountryMode' => [
482 'type' => 'string',
483 'default' => 'block'
484 ],
485 'playerCountryList' => [
486 'type' => 'string',
487 'default' => ''
488 ],
489 'playerCountryMessage' => [
490 'type' => 'string',
491 'default' => 'Sorry, this video is not available in your country.'
492 ],
493 'playerLmsTracking' => [
494 'type' => 'boolean',
495 'default' => false
496 ],
497 'playerLmsThreshold' => [
498 'type' => 'number',
499 'default' => 90
500 ],
501 'playerHeatmap' => [
502 'type' => 'boolean',
503 'default' => false
504 ],
505 'playerCdnEnabled' => [
506 'type' => 'boolean',
507 'default' => true
508 ],
509 'powered_by' => [
510 'type' => 'boolean',
511 'default' => true
512 ],
513 ];
514
515 // Add provider-specific attributes
516 $attributes = array_merge($attributes, $this->get_youtube_attributes());
517 $attributes = array_merge($attributes, $this->get_vimeo_attributes());
518 $attributes = array_merge($attributes, $this->get_wistia_attributes());
519 $attributes = array_merge($attributes, $this->get_instagram_attributes());
520 $attributes = array_merge($attributes, $this->get_calendly_attributes());
521 $attributes = array_merge($attributes, $this->get_podcast_attributes());
522 $attributes = array_merge($attributes, $this->get_google_photos_attributes());
523 $attributes = array_merge($attributes, $this->get_nft_attributes());
524 $attributes = array_merge($attributes, $this->get_ad_manager_attributes());
525 $attributes = array_merge($attributes, $this->get_content_protection_attributes());
526 $attributes = array_merge($attributes, $this->get_social_sharing_attributes());
527 $attributes = array_merge($attributes, $this->get_custom_branding_attributes());
528
529 return $attributes;
530 }
531
532 /**
533 * Get PDF-specific attributes
534 */
535 private function get_embedpress_pdf_attributes()
536 {
537 $attributes = [
538 'clientId' => [
539 'type' => 'string',
540 ],
541 'id' => [
542 'type' => 'string'
543 ],
544 'href' => [
545 'type' => 'string'
546 ],
547 'fileName' => [
548 'type' => 'string',
549 ],
550 'mime' => [
551 'type' => 'string',
552 ],
553 'url' => [
554 'type' => 'string',
555 'default' => ''
556 ],
557 'height' => [
558 'type' => 'string',
559 'default' => '600'
560 ],
561 'width' => [
562 'type' => 'string',
563 'default' => '600'
564 ],
565 'pageNumber' => [
566 'type' => 'number',
567 'default' => 1
568 ],
569 'viewerStyle' => [
570 'type' => 'string',
571 'default' => 'modern'
572 ],
573 'displayMode' => [
574 'type' => 'string',
575 'default' => 'inline'
576 ],
577 'lightboxThumbnail' => [
578 'type' => 'string',
579 'default' => ''
580 ],
581 'lightboxAlign' => [
582 'type' => 'string',
583 'default' => 'left'
584 ],
585 'triggerText' => [
586 'type' => 'string',
587 'default' => 'View PDF'
588 ],
589 'triggerColor' => [
590 'type' => 'string',
591 'default' => ''
592 ],
593 'triggerBgColor' => [
594 'type' => 'string',
595 'default' => ''
596 ],
597 'triggerFontSize' => [
598 'type' => 'string',
599 'default' => ''
600 ],
601 'triggerBorderRadius' => [
602 'type' => 'string',
603 'default' => ''
604 ],
605 'themeMode' => [
606 'type' => 'string',
607 'default' => 'default'
608 ],
609 'customColor' => [
610 'type' => 'string',
611 'default' => '#403A81'
612 ],
613 'toolbar' => [
614 'type' => 'boolean',
615 'default' => true
616 ],
617 'presentation' => [
618 'type' => 'boolean',
619 'default' => true
620 ],
621 'lazyLoad' => [
622 'type' => 'boolean',
623 'default' => false
624 ],
625 'position' => [
626 'type' => 'string',
627 'default' => 'top'
628 ],
629 'flipbook_toolbar_position' => [
630 'type' => 'string',
631 'default' => 'bottom'
632 ],
633 'download' => [
634 'type' => 'boolean',
635 'default' => true
636 ],
637 'open' => [
638 'type' => 'boolean',
639 'default' => false
640 ],
641 'copy_text' => [
642 'type' => 'boolean',
643 'default' => true
644 ],
645 'add_text' => [
646 'type' => 'boolean',
647 'default' => true
648 ],
649 'draw' => [
650 'type' => 'boolean',
651 'default' => true
652 ],
653 'add_image' => [
654 'type' => 'boolean',
655 'default' => true
656 ],
657 'zoomIn' => [
658 'type' => 'boolean',
659 'default' => true
660 ],
661 'zoomOut' => [
662 'type' => 'boolean',
663 'default' => true
664 ],
665 'fitView' => [
666 'type' => 'boolean',
667 'default' => true
668 ],
669 'bookmark' => [
670 'type' => 'boolean',
671 'default' => true
672 ],
673 'doc_details' => [
674 'type' => 'boolean',
675 'default' => true
676 ],
677 'doc_rotation' => [
678 'type' => 'boolean',
679 'default' => true
680 ],
681 'unitoption' => [
682 'type' => 'string',
683 'default' => '%'
684 ],
685 'powered_by' => [
686 'type' => 'boolean',
687 'default' => true
688 ],
689 'watermarkText' => [
690 'type' => 'string',
691 'default' => ''
692 ],
693 'watermarkFontSize' => [
694 'type' => 'number',
695 'default' => 48
696 ],
697 'watermarkColor' => [
698 'type' => 'string',
699 'default' => '#000000'
700 ],
701 'watermarkOpacity' => [
702 'type' => 'number',
703 'default' => 15
704 ],
705 'watermarkStyle' => [
706 'type' => 'string',
707 'default' => 'center'
708 ],
709
710 ];
711
712 $attributes = array_merge($attributes, $this->get_content_protection_attributes());
713 $attributes = array_merge($attributes, $this->get_social_sharing_attributes());
714 $attributes = array_merge($attributes, $this->get_custom_branding_attributes());
715
716 return $attributes;
717 }
718
719 /**
720 * Get PDF Gallery block attributes
721 */
722 private function get_pdf_gallery_attributes()
723 {
724 return [
725 'clientId' => ['type' => 'string'],
726 'pdfItems' => ['type' => 'array', 'default' => []],
727 'layout' => ['type' => 'string', 'default' => 'grid'],
728 'columns' => ['type' => 'number', 'default' => 3],
729 'columnsTablet' => ['type' => 'number', 'default' => 2],
730 'columnsMobile' => ['type' => 'number', 'default' => 1],
731 'gap' => ['type' => 'number', 'default' => 20],
732 'thumbnailAspectRatio' => ['type' => 'string', 'default' => '4:3'],
733 'thumbnailBorderRadius' => ['type' => 'number', 'default' => 8],
734 'carouselAutoplay' => ['type' => 'boolean', 'default' => false],
735 'carouselAutoplaySpeed' => ['type' => 'number', 'default' => 3000],
736 'carouselLoop' => ['type' => 'boolean', 'default' => true],
737 'carouselArrows' => ['type' => 'boolean', 'default' => true],
738 'carouselDots' => ['type' => 'boolean', 'default' => false],
739 'slidesPerView' => ['type' => 'number', 'default' => 3],
740 'viewerStyle' => ['type' => 'string', 'default' => 'modern'],
741 'themeMode' => ['type' => 'string', 'default' => 'default'],
742 'customColor' => ['type' => 'string', 'default' => '#403A81'],
743 'toolbar' => ['type' => 'boolean', 'default' => true],
744 'position' => ['type' => 'string', 'default' => 'top'],
745 'flipbook_toolbar_position' => ['type' => 'string', 'default' => 'bottom'],
746 'presentation' => ['type' => 'boolean', 'default' => true],
747 'download' => ['type' => 'boolean', 'default' => true],
748 'copy_text' => ['type' => 'boolean', 'default' => true],
749 'draw' => ['type' => 'boolean', 'default' => true],
750 'add_text' => ['type' => 'boolean', 'default' => true],
751 'add_image' => ['type' => 'boolean', 'default' => true],
752 'doc_rotation' => ['type' => 'boolean', 'default' => true],
753 'doc_details' => ['type' => 'boolean', 'default' => true],
754 'zoomIn' => ['type' => 'boolean', 'default' => true],
755 'zoomOut' => ['type' => 'boolean', 'default' => true],
756 'fitView' => ['type' => 'boolean', 'default' => true],
757 'bookmark' => ['type' => 'boolean', 'default' => true],
758 'powered_by' => ['type' => 'boolean', 'default' => true],
759 'watermarkText' => ['type' => 'string', 'default' => ''],
760 'watermarkFontSize' => ['type' => 'number', 'default' => 48],
761 'watermarkColor' => ['type' => 'string', 'default' => '#000000'],
762 'watermarkOpacity' => ['type' => 'number', 'default' => 15],
763 'watermarkStyle' => ['type' => 'string', 'default' => 'center'],
764 ];
765 }
766
767 private function get_embedpress_doc_attributes()
768 {
769 $attributes = [
770 'clientId' => [
771 'type' => 'string',
772 ],
773
774 'id' => [
775 'type' => 'string',
776 ],
777 'href' => [
778 'type' => 'string',
779 ],
780 'height' => [
781 'type' => 'string',
782 'default' => '600'
783 ],
784 'width' => [
785 'type' => 'string',
786 'default' => '600'
787 ],
788 'fileName' => [
789 'type' => 'string',
790 ],
791 'mime' => [
792 'type' => 'string',
793 ],
794 'powered_by' => [
795 'type' => 'boolean',
796 'default' => true,
797 ],
798 'presentation' => [
799 'type' => 'boolean',
800 'default' => true,
801 ],
802 'docViewer' => [
803 'type' => 'string',
804 'default' => 'custom',
805 ],
806 'themeMode' => [
807 'type' => 'string',
808 'default' => 'default',
809 ],
810 'customColor' => [
811 'type' => 'string',
812 'default' => '#403A81',
813 ],
814 'position' => [
815 'type' => 'string',
816 'default' => 'top',
817 ],
818 'download' => [
819 'type' => 'boolean',
820 'default' => true,
821 ],
822 'open' => [
823 'type' => 'boolean',
824 'default' => false,
825 ],
826 'copy_text' => [
827 'type' => 'boolean',
828 'default' => true,
829 ],
830 'draw' => [
831 'type' => 'boolean',
832 'default' => true,
833 ],
834 'toolbar' => [
835 'type' => 'boolean',
836 'default' => true,
837 ],
838 'doc_rotation' => [
839 'type' => 'boolean',
840 'default' => true,
841 ],
842 ];
843
844 $attributes = array_merge($attributes, $this->get_content_protection_attributes());
845 $attributes = array_merge($attributes, $this->get_social_sharing_attributes());
846 $attributes = array_merge($attributes, $this->get_custom_branding_attributes());
847
848 return $attributes;
849 }
850
851 /**
852 * Get YouTube block-specific attributes (for legacy youtube-block)
853 */
854 private function get_youtube_block_attributes()
855 {
856 return [
857 'url' => [
858 'type' => 'string',
859 'default' => ''
860 ],
861 'iframeSrc' => [
862 'type' => 'string',
863 'default' => ''
864 ],
865 'mediaId' => [
866 'type' => 'string',
867 'default' => ''
868 ],
869 'align' => [
870 'type' => 'string',
871 'default' => 'center'
872 ]
873 ];
874 }
875
876 /**
877 * Get Wistia block-specific attributes (for legacy wistia-block)
878 */
879 private function get_wistia_block_attributes()
880 {
881 return [
882 'url' => [
883 'type' => 'string',
884 'default' => ''
885 ],
886 'iframeSrc' => [
887 'type' => 'string',
888 'default' => ''
889 ],
890 'align' => [
891 'type' => 'string',
892 'default' => 'center'
893 ]
894 ];
895 }
896
897 /**
898 * Get ContenProtection-specific attributes
899 */
900 private function get_content_protection_attributes()
901 {
902 return [
903 'lockContent' => [
904 'type' => 'boolean',
905 'default' => false
906 ],
907 'protectionType' => [
908 'type' => 'string',
909 'default' => 'password'
910 ],
911 'userRole' => [
912 'type' => 'array',
913 'default' => []
914 ],
915 'protectionMessage' => [
916 'type' => 'string',
917 'default' => 'You do not have access to this content. Only users with the following roles can view it: [user_roles]'
918 ],
919 'contentPassword' => [
920 'type' => 'string',
921 'default' => ''
922 ],
923 'lockHeading' => [
924 'type' => 'string',
925 'default' => 'Content Locked'
926 ],
927 'lockSubHeading' => [
928 'type' => 'string',
929 'default' => 'Content is locked and requires password to access it.'
930 ],
931 'lockErrorMessage' => [
932 'type' => 'string',
933 'default' => 'Oops, that wasn\'t the right password. Try again.'
934 ],
935 'passwordPlaceholder' => [
936 'type' => 'string',
937 'default' => 'Password'
938 ],
939 'submitButtonText' => [
940 'type' => 'string',
941 'default' => 'Unlock'
942 ],
943 'submitUnlockingText' => [
944 'type' => 'string',
945 'default' => 'Unlocking'
946 ],
947 'enableFooterMessage' => [
948 'type' => 'boolean',
949 'default' => false
950 ],
951 'footerMessage' => [
952 'type' => 'string',
953 'default' => 'In case you don\'t have the password, kindly reach out to content owner or administrator to request access.'
954 ],
955 ];
956 }
957
958 /**
959 * Get SocialSharing-specific attributes
960 */
961 private function get_social_sharing_attributes()
962 {
963 return [
964 'contentShare' => [
965 'type' => 'boolean',
966 'default' => false
967 ],
968 'sharePosition' => [
969 'type' => 'string',
970 'default' => 'right'
971 ],
972 'customTitle' => [
973 'type' => 'string',
974 'default' => ''
975 ],
976 'customDescription' => [
977 'type' => 'string',
978 'default' => ''
979 ],
980 'customThumbnail' => [
981 'type' => 'string',
982 'default' => ''
983 ],
984 'shareFacebook' => [
985 'type' => 'boolean',
986 'default' => true
987 ],
988 'shareTwitter' => [
989 'type' => 'boolean',
990 'default' => true
991 ],
992 'sharePinterest' => [
993 'type' => 'boolean',
994 'default' => true
995 ],
996 'shareLinkedin' => [
997 'type' => 'boolean',
998 'default' => true
999 ],
1000 ];
1001 }
1002
1003 /**
1004 * Get CustomBranding-specific attributes
1005 */
1006 private function get_custom_branding_attributes()
1007 {
1008 return [
1009 'customlogo' => [
1010 'type' => 'string',
1011 'default' => ''
1012 ],
1013 'logoX' => [
1014 'type' => 'number',
1015 'default' => 5
1016 ],
1017 'logoY' => [
1018 'type' => 'number',
1019 'default' => 10
1020 ],
1021 'customlogoUrl' => [
1022 'type' => 'string',
1023 ],
1024 'logoOpacity' => [
1025 'type' => 'number',
1026 'default' => 0.6
1027 ],
1028 ];
1029 }
1030
1031
1032 /**
1033 * Get YouTube-specific attributes
1034 */
1035 private function get_youtube_attributes()
1036 {
1037 return [
1038 // YouTube specific attributes
1039 'ispagination' => [
1040 'type' => 'boolean',
1041 'default' => true
1042 ],
1043 'ytChannelLayout' => [
1044 // CHANNEL URLs only. Empty default lets the provider use the
1045 // gallery default. Inspector's explicit pick still overrides.
1046 'type' => 'string',
1047 'default' => ''
1048 ],
1049 'ytPlaylistLayout' => [
1050 // PLAYLIST URLs only — separate dropdown so channel pick can't
1051 // leak in. Values: '' (default: queue) | 'queue' | 'theatre'.
1052 'type' => 'string',
1053 'default' => ''
1054 ],
1055 'ytPlaylistMode' => [
1056 // 'playlist' renders the queue/gallery/list/grid/carousel UI for
1057 // any URL with list=…. 'single' renders just the v= video.
1058 'type' => 'string',
1059 'default' => 'playlist'
1060 ],
1061 'pagesize' => [
1062 'type' => 'string',
1063 'default' => '6'
1064 ],
1065 'columns' => [
1066 'type' => 'string',
1067 'default' => '3'
1068 ],
1069 'gapbetweenvideos' => [
1070 'type' => 'number',
1071 'default' => 30
1072 ],
1073 'videosize' => [
1074 'type' => 'string',
1075 'default' => 'fixed',
1076 ],
1077 'starttime' => [
1078 'type' => 'string',
1079 ],
1080 'endtime' => [
1081 'type' => 'string',
1082 ],
1083 'autoplay' => [
1084 'type' => 'boolean',
1085 'default' => false,
1086 ],
1087 'muteVideo' => [
1088 'type' => 'boolean',
1089 'default' => true,
1090 ],
1091 'controls' => [
1092 'type' => 'string',
1093 ],
1094 'fullscreen' => [
1095 'type' => 'boolean',
1096 'default' => true,
1097 ],
1098 'videoannotations' => [
1099 'type' => 'boolean',
1100 'default' => true,
1101 ],
1102 'progressbarcolor' => [
1103 'type' => 'string',
1104 'default' => 'red'
1105 ],
1106 'closedcaptions' => [
1107 'type' => 'boolean',
1108 'default' => true,
1109 ],
1110 'modestbranding' => [
1111 'type' => 'string',
1112 ],
1113 'relatedvideos' => [
1114 'type' => 'boolean',
1115 'default' => true,
1116 ],
1117 'showinfo' => [
1118 'type' => 'boolean',
1119 'default' => true,
1120 ],
1121 'showLoop' => [
1122 'type' => 'boolean',
1123 'default' => true,
1124 ],
1125 ];
1126 }
1127
1128 /**
1129 * Get Vimeo-specific attributes
1130 */
1131 private function get_vimeo_attributes()
1132 {
1133 return [
1134 'vimeoAutoplay' => [
1135 'type' => 'boolean',
1136 'default' => false,
1137 ],
1138 'vimeoLoop' => [
1139 'type' => 'boolean',
1140 'default' => false,
1141 ],
1142 'vimeoPortrait' => [
1143 'type' => 'boolean',
1144 'default' => true,
1145 ],
1146 'vimeoTitle' => [
1147 'type' => 'boolean',
1148 'default' => true,
1149 ],
1150 'vimeoByline' => [
1151 'type' => 'boolean',
1152 'default' => true,
1153 ],
1154 'vimeoColor' => [
1155 'type' => 'string',
1156 'default' => '#00adef'
1157 ],
1158 'vimeoDnt' => [
1159 'type' => 'boolean',
1160 'default' => false,
1161 ],
1162 // Additional Vimeo attributes
1163 'vstarttime' => [
1164 'type' => 'string',
1165 ],
1166 'vautoplay' => [
1167 'type' => 'boolean',
1168 'default' => false
1169 ],
1170 'vscheme' => [
1171 'type' => 'string',
1172 ],
1173 'vtitle' => [
1174 'type' => 'boolean',
1175 'default' => true
1176 ],
1177 'vauthor' => [
1178 'type' => 'boolean',
1179 'default' => true
1180 ],
1181 'vavatar' => [
1182 'type' => 'boolean',
1183 'default' => true
1184 ],
1185 'vloop' => [
1186 'type' => 'boolean',
1187 'default' => false
1188 ],
1189 'vautopause' => [
1190 'type' => 'boolean',
1191 'default' => false
1192 ],
1193 'vdnt' => [
1194 'type' => 'boolean',
1195 'default' => false
1196 ],
1197 ];
1198 }
1199
1200 /**
1201 * Get Wistia-specific attributes
1202 */
1203 private function get_wistia_attributes()
1204 {
1205 return [
1206 'wstarttime' => [
1207 'type' => 'string',
1208 ],
1209 'wautoplay' => [
1210 'type' => 'boolean',
1211 'default' => true
1212 ],
1213 'scheme' => [
1214 'type' => 'string',
1215 ],
1216 'captions' => [
1217 'type' => 'boolean',
1218 'default' => true
1219 ],
1220 'playbutton' => [
1221 'type' => 'boolean',
1222 'default' => true
1223 ],
1224 'smallplaybutton' => [
1225 'type' => 'boolean',
1226 'default' => true
1227 ],
1228 'playbar' => [
1229 'type' => 'boolean',
1230 'default' => true
1231 ],
1232 'resumable' => [
1233 'type' => 'boolean',
1234 'default' => true
1235 ],
1236 'wistiafocus' => [
1237 'type' => 'boolean',
1238 'default' => true
1239 ],
1240 'volumecontrol' => [
1241 'type' => 'boolean',
1242 'default' => true
1243 ],
1244 'volume' => [
1245 'type' => 'number',
1246 'default' => 100
1247 ],
1248 'rewind' => [
1249 'type' => 'boolean',
1250 'default' => false
1251 ],
1252 'wfullscreen' => [
1253 'type' => 'boolean',
1254 'default' => true
1255 ],
1256 ];
1257 }
1258
1259 /**
1260 * Get Instagram-specific attributes
1261 */
1262 private function get_instagram_attributes()
1263 {
1264 return [
1265 'instaLayout' => [
1266 'type' => 'string',
1267 'default' => 'insta-grid'
1268 ],
1269 'carouselArrows' => [
1270 'type' => 'boolean',
1271 'default' => true
1272 ],
1273 'carouselSpacing' => [
1274 'type' => 'string',
1275 'default' => '0'
1276 ],
1277 'carouselDots' => [
1278 'type' => 'boolean',
1279 'default' => false
1280 ],
1281 // Instagram Feed attributes
1282 'instafeedFeedType' => [
1283 'type' => 'string',
1284 'default' => 'user_account_type',
1285 ],
1286 'instafeedAccountType' => [
1287 'type' => 'string',
1288 'default' => 'personal',
1289 ],
1290 'instafeedProfileImage' => [
1291 'type' => 'boolean',
1292 'default' => true,
1293 ],
1294 'instafeedProfileImageUrl' => [
1295 'type' => 'string',
1296 'default' => '',
1297 ],
1298 'instafeedFollowBtn' => [
1299 'type' => 'boolean',
1300 'default' => true,
1301 ],
1302 'instafeedFollowBtnLabel' => [
1303 'type' => 'string',
1304 'default' => 'Follow',
1305 ],
1306 'instafeedPostsCount' => [
1307 'type' => 'boolean',
1308 'default' => true,
1309 ],
1310 'instafeedPostsCountText' => [
1311 'type' => 'string',
1312 'default' => '[count] posts',
1313 ],
1314 'instafeedFollowersCount' => [
1315 'type' => 'boolean',
1316 'default' => true,
1317 ],
1318 'instafeedFollowersCountText' => [
1319 'type' => 'string',
1320 'default' => '[count] followers',
1321 ],
1322 'instafeedAccName' => [
1323 'type' => 'boolean',
1324 'default' => true,
1325 ],
1326 'instafeedColumns' => [
1327 'type' => 'string',
1328 'default' => '3'
1329 ],
1330 'instafeedColumnsGap' => [
1331 'type' => 'string',
1332 'default' => '5'
1333 ],
1334 'instafeedPostsPerPage' => [
1335 'type' => 'string',
1336 'default' => '12'
1337 ],
1338 'instafeedTab' => [
1339 'type' => 'boolean',
1340 'default' => true,
1341 ],
1342 'instafeedLikesCount' => [
1343 'type' => 'boolean',
1344 'default' => true,
1345 ],
1346 'instafeedCommentsCount' => [
1347 'type' => 'boolean',
1348 'default' => true,
1349 ],
1350 'instafeedPopup' => [
1351 'type' => 'boolean',
1352 'default' => true,
1353 ],
1354 'instafeedPopupFollowBtn' => [
1355 'type' => 'boolean',
1356 'default' => true,
1357 ],
1358 'instafeedPopupFollowBtnLabel' => [
1359 'type' => 'string',
1360 'default' => 'Follow',
1361 ],
1362 'instafeedLoadmore' => [
1363 'type' => 'boolean',
1364 'default' => true,
1365 ],
1366 'instafeedLoadmoreLabel' => [
1367 'type' => 'string',
1368 'default' => 'Load More',
1369 ],
1370 'slidesShow' => [
1371 'type' => 'string',
1372 'default' => '4'
1373 ],
1374 'slidesScroll' => [
1375 'type' => 'string',
1376 'default' => '4'
1377 ],
1378 'carouselAutoplay' => [
1379 'type' => 'boolean',
1380 'default' => false
1381 ],
1382 'autoplaySpeed' => [
1383 'type' => 'string',
1384 'default' => '3000'
1385 ],
1386 'transitionSpeed' => [
1387 'type' => 'string',
1388 'default' => '1000'
1389 ],
1390 'carouselLoop' => [
1391 'type' => 'boolean',
1392 'default' => true
1393 ],
1394 ];
1395 }
1396
1397 /**
1398 * Get Calendly-specific attributes
1399 */
1400 private function get_calendly_attributes()
1401 {
1402 return [
1403 'cEmbedType' => [
1404 'type' => 'string',
1405 'default' => 'inline'
1406 ],
1407 'calendlyData' => [
1408 'type' => 'boolean',
1409 'default' => false
1410 ],
1411 'hideCookieBanner' => [
1412 'type' => 'boolean',
1413 'default' => false
1414 ],
1415 'hideEventTypeDetails' => [
1416 'type' => 'boolean',
1417 'default' => false
1418 ],
1419 'cBackgroundColor' => [
1420 'type' => 'string',
1421 'default' => 'ffffff'
1422 ],
1423 'cTextColor' => [
1424 'type' => 'string',
1425 'default' => '1A1A1A'
1426 ],
1427 'cButtonLinkColor' => [
1428 'type' => 'string',
1429 'default' => '0000FF'
1430 ],
1431 'cPopupButtonText' => [
1432 'type' => 'string',
1433 'default' => 'Schedule time with me'
1434 ],
1435 'cPopupButtonBGColor' => [
1436 'type' => 'string',
1437 'default' => '0000FF'
1438 ],
1439 'cPopupButtonTextColor' => [
1440 'type' => 'string',
1441 'default' => 'FFFFFF'
1442 ],
1443 'cPopupLinkText' => [
1444 'type' => 'string',
1445 'default' => 'Schedule time with me'
1446 ],
1447 ];
1448 }
1449
1450 /**
1451 * Get Podcast-specific attributes (Spreaker)
1452 */
1453 private function get_podcast_attributes()
1454 {
1455 return [
1456 // Spreaker attributes
1457 'theme' => [
1458 'type' => 'string',
1459 'default' => 'light'
1460 ],
1461 'color' => [
1462 'type' => 'string',
1463 'default' => ''
1464 ],
1465 'coverImageUrl' => [
1466 'type' => 'string',
1467 'default' => ''
1468 ],
1469 'playlist' => [
1470 'type' => 'boolean',
1471 'default' => false
1472 ],
1473 'playlistContinuous' => [
1474 'type' => 'boolean',
1475 'default' => false
1476 ],
1477 'playlistLoop' => [
1478 'type' => 'boolean',
1479 'default' => false
1480 ],
1481 'playlistAutoupdate' => [
1482 'type' => 'boolean',
1483 'default' => true
1484 ],
1485 'chaptersImage' => [
1486 'type' => 'boolean',
1487 'default' => true
1488 ],
1489 'episodeImagePosition' => [
1490 'type' => 'string',
1491 'default' => 'right'
1492 ],
1493 'hideLikes' => [
1494 'type' => 'boolean',
1495 'default' => false
1496 ],
1497 'hideComments' => [
1498 'type' => 'boolean',
1499 'default' => false
1500 ],
1501 'hideSharing' => [
1502 'type' => 'boolean',
1503 'default' => false
1504 ],
1505 'hideLogo' => [
1506 'type' => 'boolean',
1507 'default' => false
1508 ],
1509 'hideEpisodeDescription' => [
1510 'type' => 'boolean',
1511 'default' => false
1512 ],
1513 'hidePlaylistDescriptions' => [
1514 'type' => 'boolean',
1515 'default' => false
1516 ],
1517 'hidePlaylistImages' => [
1518 'type' => 'boolean',
1519 'default' => false
1520 ],
1521 'hideDownload' => [
1522 'type' => 'boolean',
1523 'default' => false
1524 ],
1525 ];
1526 }
1527
1528 /**
1529 * Get Google Photos-specific attributes
1530 */
1531 private function get_google_photos_attributes()
1532 {
1533 return [
1534 'mode' => [
1535 'type' => 'string',
1536 'default' => 'carousel'
1537 ],
1538 'imageWidth' => [
1539 'type' => 'number',
1540 'default' => 800
1541 ],
1542 'imageHeight' => [
1543 'type' => 'number',
1544 'default' => 600
1545 ],
1546 'showTitle' => [
1547 'type' => 'boolean',
1548 'default' => true
1549 ],
1550 'playerAutoplay' => [
1551 'type' => 'boolean',
1552 'default' => false
1553 ],
1554 'delay' => [
1555 'type' => 'number',
1556 'default' => 5
1557 ],
1558 'repeat' => [
1559 'type' => 'boolean',
1560 'default' => true
1561 ],
1562 'mediaitemsAspectRatio' => [
1563 'type' => 'boolean',
1564 'default' => true
1565 ],
1566 'mediaitemsEnlarge' => [
1567 'type' => 'boolean',
1568 'default' => false
1569 ],
1570 'mediaitemsStretch' => [
1571 'type' => 'boolean',
1572 'default' => false
1573 ],
1574 'mediaitemsCover' => [
1575 'type' => 'boolean',
1576 'default' => false
1577 ],
1578 'backgroundColor' => [
1579 'type' => 'string',
1580 'default' => '#000000'
1581 ],
1582 'expiration' => [
1583 'type' => 'number',
1584 'default' => 60
1585 ],
1586 ];
1587 }
1588
1589 /**
1590 * Get NFT/OpenSea-specific attributes
1591 */
1592 private function get_nft_attributes()
1593 {
1594 return [
1595 'limit' => [
1596 'type' => 'number',
1597 'default' => 20
1598 ],
1599 'itemperpage' => [
1600 'type' => 'number',
1601 'default' => 9
1602 ],
1603 'loadmore' => [
1604 'type' => 'boolean',
1605 'default' => false
1606 ],
1607 'loadmorelabel' => [
1608 'type' => 'text',
1609 'default' => 'Load More'
1610 ],
1611 'orderby' => [
1612 'type' => 'string',
1613 'default' => 'desc'
1614 ],
1615 'gapbetweenitem' => [
1616 'type' => 'number',
1617 'default' => 30
1618 ],
1619 'layout' => [
1620 'type' => 'string',
1621 'default' => 'ep-grid'
1622 ],
1623 'preset' => [
1624 'type' => 'string',
1625 'default' => 'preset-default'
1626 ],
1627 'nftperrow' => [
1628 'type' => 'number',
1629 'default' => 3
1630 ],
1631 'collectionname' => [
1632 'type' => 'boolean',
1633 'default' => true
1634 ],
1635 'nftimage' => [
1636 'type' => 'boolean',
1637 'default' => true
1638 ],
1639 'nfttitle' => [
1640 'type' => 'boolean',
1641 'default' => true
1642 ],
1643 'nftcreator' => [
1644 'type' => 'boolean',
1645 'default' => true
1646 ],
1647 'prefix_nftcreator' => [
1648 'type' => 'string',
1649 'default' => 'Created By'
1650 ],
1651 'nftprice' => [
1652 'type' => 'boolean',
1653 'default' => true
1654 ],
1655 'prefix_nftprice' => [
1656 'type' => 'string',
1657 'default' => 'Current Price'
1658 ],
1659 'nftlastsale' => [
1660 'type' => 'boolean',
1661 'default' => true
1662 ],
1663 'prefix_nftlastsale' => [
1664 'type' => 'string',
1665 'default' => 'Last Sale'
1666 ],
1667 'nftbutton' => [
1668 'type' => 'boolean',
1669 'default' => true
1670 ],
1671 'nftrank' => [
1672 'type' => 'boolean',
1673 'default' => true
1674 ],
1675 'label_nftrank' => [
1676 'type' => 'string',
1677 'default' => 'Rank'
1678 ],
1679 'nftdetails' => [
1680 'type' => 'boolean',
1681 'default' => true
1682 ],
1683 'label_nftdetails' => [
1684 'type' => 'string',
1685 'default' => 'Details'
1686 ],
1687 'label_nftbutton' => [
1688 'type' => 'string',
1689 'default' => 'See Details'
1690 ],
1691 'alignment' => [
1692 'type' => 'string',
1693 'default' => 'ep-item-center'
1694 ],
1695 // Color and Typography for NFT
1696 'itemBGColor' => [
1697 'type' => 'string',
1698 ],
1699 'collectionNameColor' => [
1700 'type' => 'string',
1701 ],
1702 'collectionNameFZ' => [
1703 'type' => 'number',
1704 ],
1705 'titleColor' => [
1706 'type' => 'string',
1707 ],
1708 'titleFontsize' => [
1709 'type' => 'number',
1710 ],
1711 'creatorColor' => [
1712 'type' => 'string',
1713 ],
1714 'creatorFontsize' => [
1715 'type' => 'number',
1716 ],
1717 'creatorLinkColor' => [
1718 'type' => 'string',
1719 ],
1720 'creatorLinkFontsize' => [
1721 'type' => 'number',
1722 ],
1723 'priceLabelColor' => [
1724 'type' => 'string',
1725 ],
1726 'priceLabelFontsize' => [
1727 'type' => 'number',
1728 ],
1729 'priceColor' => [
1730 'type' => 'string',
1731 ],
1732 'priceFontsize' => [
1733 'type' => 'number',
1734 ],
1735 'priceUSDColor' => [
1736 'type' => 'string',
1737 ],
1738 'priceUSDFontsize' => [
1739 'type' => 'number',
1740 ],
1741 'lastSaleLabelColor' => [
1742 'type' => 'string',
1743 ],
1744 'lastSaleLabelFontsize' => [
1745 'type' => 'number',
1746 ],
1747 'lastSaleColor' => [
1748 'type' => 'string',
1749 ],
1750 'lastSaleFontsize' => [
1751 'type' => 'number',
1752 ],
1753 'lastSaleUSDColor' => [
1754 'type' => 'string',
1755 ],
1756 'lastSaleUSDFontsize' => [
1757 'type' => 'number',
1758 ],
1759 'buttonTextColor' => [
1760 'type' => 'string',
1761 ],
1762 'buttonBackgroundColor' => [
1763 'type' => 'string',
1764 ],
1765 'buttonTextFontsize' => [
1766 'type' => 'number',
1767 ],
1768 'loadmoreTextColor' => [
1769 'type' => 'string',
1770 ],
1771 'loadmoreBackgroundColor' => [
1772 'type' => 'string',
1773 ],
1774 'loadmoreTextFontsize' => [
1775 'type' => 'number',
1776 ],
1777 'rankBtnColor' => [
1778 'type' => 'string',
1779 ],
1780 'rankBtnBorderColor' => [
1781 'type' => 'string',
1782 ],
1783 'rankBtnFZ' => [
1784 'type' => 'number',
1785 ],
1786 'rankLabelColor' => [
1787 'type' => 'string',
1788 ],
1789 'rankLabelFZ' => [
1790 'type' => 'number',
1791 ],
1792 'detialTitleColor' => [
1793 'type' => 'string',
1794 ],
1795 'detialTitleFZ' => [
1796 'type' => 'number',
1797 ],
1798 'detailTextColor' => [
1799 'type' => 'string',
1800 ],
1801 'detailTextLinkColor' => [
1802 'type' => 'string',
1803 ],
1804 'detailTextFZ' => [
1805 'type' => 'number',
1806 ],
1807 ];
1808 }
1809
1810 /**
1811 * Get Ad Manager-specific attributes
1812 */
1813 private function get_ad_manager_attributes()
1814 {
1815 return [
1816 'adManager' => [
1817 'type' => 'boolean',
1818 'default' => false
1819 ],
1820 'adSource' => [
1821 'type' => 'string',
1822 'default' => 'video'
1823 ],
1824 'adContent' => [
1825 'type' => 'object',
1826 ],
1827 'adFileUrl' => [
1828 'type' => 'string',
1829 'default' => ''
1830 ],
1831 'adWidth' => [
1832 'type' => 'string',
1833 'default' => '300'
1834 ],
1835 'adHeight' => [
1836 'type' => 'string',
1837 'default' => '200'
1838 ],
1839 'adXPosition' => [
1840 'type' => 'number',
1841 'default' => 25
1842 ],
1843 'adYPosition' => [
1844 'type' => 'number',
1845 'default' => 10
1846 ],
1847 'adUrl' => [
1848 'type' => 'string',
1849 'default' => ''
1850 ],
1851 'adStart' => [
1852 'type' => 'string',
1853 'default' => '10'
1854 ],
1855 'adSkipButton' => [
1856 'type' => 'boolean',
1857 'default' => true
1858 ],
1859 'adSkipButtonAfter' => [
1860 'type' => 'string',
1861 'default' => '5'
1862 ],
1863 ];
1864 }
1865
1866 /**
1867 * Enqueue block assets for both frontend and backend
1868 * Now handled by AssetManager
1869 */
1870 public function enqueue_block_assets()
1871 {
1872 // Assets are now handled by the centralized AssetManager
1873 // This method is kept for backward compatibility
1874 }
1875
1876 /**
1877 * Enqueue editor assets
1878 */
1879 public function enqueue_editor_assets()
1880 {
1881 // Assets are now handled by AssetManager, but we still need to localize the script
1882 $this->localize_editor_script();
1883 }
1884
1885 /**
1886 * Localize editor script with necessary data
1887 * Note: Localization is now handled by LocalizationManager
1888 */
1889 private function localize_editor_script()
1890 {
1891 // Localization is now handled by LocalizationManager
1892 // This method is kept for backward compatibility but functionality has been moved
1893 }
1894
1895 /**
1896 * Add a new block to the available blocks list
1897 */
1898 public function add_block($folder_name, $config)
1899 {
1900 $this->available_blocks[$folder_name] = $config;
1901 }
1902
1903 /**
1904 * Ensure default blocks are enabled if no settings exist
1905 */
1906 private function ensure_default_blocks_enabled()
1907 {
1908 $elements = (array) get_option(EMBEDPRESS_PLG_NAME . ":elements", []);
1909
1910 // If no gutenberg settings exist, create default ones
1911 if (!isset($elements['gutenberg'])) {
1912 $elements['gutenberg'] = [];
1913 }
1914
1915 // Enable embedpress block by default
1916 if (!isset($elements['gutenberg']['embedpress'])) {
1917 $elements['gutenberg']['embedpress'] = 'embedpress';
1918 }
1919
1920 // Enable embedpress-pdf block by default
1921 if (!isset($elements['gutenberg']['embedpress-pdf'])) {
1922 $elements['gutenberg']['embedpress-pdf'] = 'embedpress-pdf';
1923 }
1924
1925 // Enable youtube-block by default for legacy support
1926 if (!isset($elements['gutenberg']['youtube-block'])) {
1927 $elements['gutenberg']['youtube-block'] = 'youtube-block';
1928 }
1929
1930 // Enable wistia-block by default for legacy support
1931 if (!isset($elements['gutenberg']['wistia-block'])) {
1932 $elements['gutenberg']['wistia-block'] = 'wistia-block';
1933 }
1934
1935 // Enable pdf-gallery block by default
1936 if (!isset($elements['gutenberg']['pdf-gallery'])) {
1937 $elements['gutenberg']['pdf-gallery'] = 'pdf-gallery';
1938 }
1939
1940 // Update options if any changes were made
1941 update_option(EMBEDPRESS_PLG_NAME . ":elements", $elements);
1942 }
1943
1944 /**
1945 * Get available blocks
1946 */
1947 public function get_available_blocks()
1948 {
1949 return $this->available_blocks;
1950 }
1951 }
1952