PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.5.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.5.0
2.11.0 2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 All 78 releases
fluent-community / app / Hooks / Handlers / FluentBlockEditorHandler.php

FluentBlockEditorHandler.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.5.0, at app/Hooks/Handlers/FluentBlockEditorHandler.php

1,125 lines 47.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\App\Hooks\Handlers;
4
5 use FluentCommunity\App\Functions\Utility;
6 use FluentCommunity\App\Models\BaseSpace;
7 use FluentCommunity\App\Services\Helper;
8 use FluentCommunity\Framework\Support\Arr;
9 use FluentCommunity\Modules\Course\Model\CourseLesson;
10
11 class FluentBlockEditorHandler
12 {
13 public function register()
14 {
15 add_action('init', function () {
16
17 register_post_type('fcom-dummy', [
18 'label' => 'Lesson',
19 'public' => false,
20 'show_in_rest' => true,
21 'supports' => ['title', 'editor', 'thumbnail'],
22 ]);
23
24 register_post_type('fcom-lockscreen', [
25 'label' => 'Lockscreen',
26 'public' => false,
27 'show_in_rest' => true,
28 'supports' => ['editor'],
29 ]);
30
31 if (!isset($_REQUEST['fluent_community_block_editor'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
32 return;
33 }
34
35 if (!defined('IFRAME_REQUEST')) {
36 define('IFRAME_REQUEST', true); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
37 }
38
39 remove_action('enqueue_block_editor_assets', 'wp_enqueue_editor_block_directory_assets');
40 add_action('fluent_community/block_editor_head', function () {
41 $url = FLUENT_COMMUNITY_PLUGIN_URL . 'Modules/Gutenberg/editor/index.css';
42 $contentStylingUrl = FLUENT_COMMUNITY_PLUGIN_URL . 'Modules/Gutenberg/editor/content_styling.css';
43 // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet -- emitted into a custom non-wp_head action hook, wp_enqueue_style not applicable
44 ?>
45 <link rel="stylesheet"
46 href="<?php echo esc_url($url); ?>?version=<?php echo esc_attr(FLUENT_COMMUNITY_PLUGIN_VERSION); ?>"
47 media="screen"/>
48 <link rel="stylesheet"
49 href="<?php echo esc_url($contentStylingUrl); ?>?version=<?php echo esc_attr(FLUENT_COMMUNITY_PLUGIN_VERSION); ?>"
50 media="screen"/>
51 <?php // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet ?>
52
53 <style>
54 <?php echo wp_strip_all_tags($this->getColorSchemaCss()); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- generated CSS, no user input ?>
55 </style>
56
57 <?php
58 });
59 add_filter('should_load_separate_core_block_assets', '__return_false', 20);
60 $this->renderCustomEditor($_REQUEST); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
61
62 $actionHook = 'template_redirect';
63 if(is_admin()) {
64 $actionHook = 'admin_init';
65 }
66
67 add_action($actionHook, function () {
68 $this->renderPage();
69 exit(200);
70 }, -1000);
71 }, 2);
72 }
73
74 public function renderCustomEditor($data = [])
75 {
76 do_action('litespeed_control_set_nocache', 'fluentcommunity api request'); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
77 // set no cache headers
78 nocache_headers();
79
80 $hasAccess = false;
81 $postType = 'fcom-dummy';
82 $context = Arr::get($data, 'context');
83
84 $lesson = null;
85
86 if ($context === 'course_lesson') {
87 $lessonId = Arr::get($data, 'lesson_id');
88 if ($lessonId) {
89 $lesson = CourseLesson::find($lessonId);
90 $hasAccess = $lesson && $lesson->course && $lesson->course->isCourseAdmin();
91 }
92 }
93
94 if ($context === 'lockscreen') {
95 $postType = 'fcom-lockscreen';
96 $spaceId = Arr::get($data, 'space_id');
97 if ($spaceId) {
98 $space = BaseSpace::query()->onlyMain()->find($spaceId);
99 $hasAccess = $space && $space->isAdmin(get_current_user_id(), true);
100 }
101 }
102
103 if (!$hasAccess) {
104 echo '<h3 style="padding: 100px; text-align: center;">Sorry, you do not have access to this page.</h3>';
105 exit(200);
106 }
107
108 add_filter('should_load_separate_core_block_assets', '__return_false', 20);
109 show_admin_bar(false);
110
111 $firstPost = Utility::getApp('db')->table('posts')
112 ->where('post_type', $postType)
113 ->first();
114
115 if ($firstPost) {
116 $simulatedPost = get_post($firstPost->ID);
117 $simulatedPost->post_content = '<!-- wp:paragraph --><p> </p><!-- /wp:paragraph -->';
118 } else {
119 $newPostId = wp_insert_post(array(
120 'post_title' => $context === 'course_lesson' ? 'Demo Lesson Title' : '',
121 'post_content' => '<!-- wp:paragraph --><p> </p><!-- /wp:paragraph -->',
122 'post_type' => $postType,
123 'post_status' => 'draft',
124 ));
125
126 $simulatedPost = get_post($newPostId);
127 }
128
129 global $post;
130 $post = $simulatedPost;
131
132 if ($lesson) {
133 $post->post_title = $lesson->title;
134 $post->post_content = $lesson->message ?: '<!-- wp:paragraph --><p> </p><!-- /wp:paragraph -->';
135 }
136
137 $enqueueHook = 'wp_enqueue_scripts';
138
139 if(is_admin()) {
140 $enqueueHook = 'admin_enqueue_scripts';
141 }
142
143 add_action($enqueueHook, function () use ($post) {
144 wp_enqueue_script('postbox', admin_url('js/postbox.min.js'), array('jquery-ui-sortable'), FLUENT_COMMUNITY_PLUGIN_VERSION, true);
145 wp_enqueue_style('dashicons');
146 wp_enqueue_style('media');
147 wp_enqueue_style('admin-menu');
148 wp_enqueue_style('admin-bar');
149 wp_enqueue_style('l10n');
150
151 wp_add_inline_script(
152 'wp-api-fetch',
153 \sprintf(
154 'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );',
155 wp_json_encode(
156 array(
157 '/wp/v2/' . $post->post_type . '/' . $post->ID . '?context=edit' => array(
158 'body' => array(
159 'id' => $post->ID,
160 'title' => array('raw' => $post->post_title),
161 'content' => array(
162 'block_format' => 1,
163 'raw' => $post->post_content,
164 ),
165 'excerpt' => array('raw' => ''),
166 'date' => '',
167 'date_gmt' => '',
168 'modified' => '',
169 'modified_gmt' => '',
170 'link' => home_url('/'),
171 'guid' => array(),
172 'parent' => 0,
173 'menu_order' => 0,
174 'author' => 0,
175 'featured_media' => 0,
176 'comment_status' => 'closed',
177 'ping_status' => 'closed',
178 'template' => '',
179 'meta' => array(),
180 '_links' => array(),
181 'type' => $post->post_type,
182 'status' => 'pending', // pending is the best state to remove draft saving possibilities.
183 'slug' => '',
184 'generated_slug' => '',
185 'permalink_template' => home_url('/'),
186 ),
187 ),
188 )
189 )
190 ),
191 'after'
192 );
193 }, 11);
194
195 add_action('wp_enqueue_scripts', function ($hook) use ($post) {
196 // Gutenberg requires the post-locking functions defined within:
197 // See `show_post_locked_dialog` and `get_post_metadata` filters below.
198 include_once ABSPATH . 'wp-admin/includes/post.php';
199 $this->gutenberg_editor_scripts_and_styles($hook, $post);
200 });
201
202 // Disable post locking dialogue.
203 add_filter('show_post_locked_dialog', '__return_false');
204
205 // Everyone can richedit! This avoids a case where a page can be cached where a user can't richedit.
206 $GLOBALS['wp_rich_edit'] = true;
207 add_filter('user_can_richedit', '__return_true', 1000);
208
209 // Homepage is always locked by @wordpressdotorg
210 // This prevents other logged-in users taking a lock of the post on the front-end.
211 add_filter('get_post_metadata', function ($value, $post_id, $meta_key) {
212 if ($meta_key !== '_edit_lock') {
213 return $value;
214 }
215 return time() . ':' . get_current_user_id(); // WordPressdotorg user ID
216 }, 10, 3);
217
218 // Disable Jetpack Blocks for now.
219 add_filter('jetpack_gutenberg', '__return_false');
220 }
221
222 private function gutenberg_editor_scripts_and_styles($hook, $post)
223 {
224 $initial_edits = array(
225 'title' => $post->post_title,
226 'content' => $post->post_content,
227 'excerpt' => $post->post_excerpt,
228 );
229
230 $editor_settings = $this->getEditorSettings($post);
231
232 $init_script =
233 "(function() {
234 window._wpLoadBlockEditor = new Promise(function(resolve) {
235 wp.domReady(function() {
236 resolve(wp.editPost.initializeEditor('editor', \"%s\", %d, %s, %s));
237 });
238 });
239 })();";
240
241 $script = sprintf(
242 $init_script,
243 $post->post_type,
244 $post->ID,
245 wp_json_encode($editor_settings),
246 wp_json_encode($initial_edits)
247 );
248 wp_add_inline_script('wp-edit-post', $script);
249
250 /**
251 * Scripts
252 */
253 wp_enqueue_media(
254 array(
255 'post' => null
256 )
257 );
258
259 add_filter('user_can_richedit', '__return_true');
260 wp_tinymce_inline_scripts();
261 wp_enqueue_editor();
262
263 /**
264 * Styles
265 */
266 wp_enqueue_style('wp-edit-post');
267
268 // Include block styles needed when user is not signed in. See: https://github.com/WordPress/wporg-gutenberg/issues/26
269 wp_enqueue_style('global-styles');
270 wp_enqueue_style('wp-block-library');
271 wp_enqueue_style('wp-block-image');
272 wp_enqueue_style('wp-block-group');
273 wp_enqueue_style('wp-block-heading');
274 wp_enqueue_style('wp-block-button');
275 wp_enqueue_style('wp-block-paragraph');
276 wp_enqueue_style('wp-block-separator');
277 wp_enqueue_style('wp-block-columns');
278 wp_enqueue_style('wp-block-cover');
279 wp_enqueue_style('global-styles-css-custom-properties');
280 wp_enqueue_style('wp-block-spacer');
281
282 wp_register_style('fluent_com_editor_styles', FLUENT_COMMUNITY_PLUGIN_URL . 'Modules/Gutenberg/editor/style.css', false, FLUENT_COMMUNITY_PLUGIN_VERSION, 'all');
283
284 add_action('fluent_enqueue_block_editor_assets', 'wp_enqueue_editor_format_library_assets');
285
286 /**
287 * Fires after block assets have been enqueued for the editing interface.
288 *
289 * Call `add_action` on any hook before 'admin_enqueue_scripts'.
290 *
291 * In the function call you supply, simply use `wp_enqueue_script` and
292 * `wp_enqueue_style` to add your functionality to the Gutenberg editor.
293 *
294 * @since 0.4.0
295 */
296 do_action('fluent_enqueue_block_editor_assets');
297
298 wp_enqueue_script('fcom_editor_custom', FLUENT_COMMUNITY_PLUGIN_URL . 'Modules/Gutenberg/editor/index.js', ['react', 'wp-components', 'wp-compose', 'wp-data', 'wp-edit-post', 'wp-i18n', 'wp-plugins'], FLUENT_COMMUNITY_PLUGIN_VERSION . time(), true);
299 wp_localize_script('fcom_editor_custom', 'fcomEditorI18n', $this->getEditorI18nStrings());
300 }
301
302 private function getEditorI18nStrings()
303 {
304 $strings = [
305 'Enable Video Embed' => __('Enable Video Embed', 'fluent-community'),
306 'Enable Comments' => __('Enable Comments', 'fluent-community'),
307 'Free Preview Lesson' => __('Free Preview Lesson', 'fluent-community'),
308 'If enabled, public users can view this lesson without enrolling the course.' => __('If enabled, public users can view this lesson without enrolling the course.', 'fluent-community'),
309 'Media Embed' => __('Media Embed', 'fluent-community'),
310 'Documents & Files' => __('Documents & Files', 'fluent-community'),
311 'Smartcodes' => __('Smartcodes', 'fluent-community'),
312 'You may use following smartcode in your lesson:' => __('You may use following smartcode in your lesson:', 'fluent-community'),
313 "User's Name:" => __("User's Name:", 'fluent-community'),
314 "User's Email:" => __("User's Email:", 'fluent-community'),
315 "User's photo HTML:" => __("User's photo HTML:", 'fluent-community'),
316 "User's Profile Link:" => __("User's Profile Link:", 'fluent-community'),
317 'Failed to fetch embed. Please check the URL.' => __('Failed to fetch embed. Please check the URL.', 'fluent-community'),
318 'Video thumbnail' => __('Video thumbnail', 'fluent-community'),
319 'Media embedded successfully' => __('Media embedded successfully', 'fluent-community'),
320 'Edit media' => __('Edit media', 'fluent-community'),
321 'Oembed' => __('Oembed', 'fluent-community'),
322 'Custom HTML' => __('Custom HTML', 'fluent-community'),
323 'Custom HTML Code' => __('Custom HTML Code', 'fluent-community'),
324 'Paste an iframe code' => __('Paste an iframe code', 'fluent-community'),
325 'Embed' => __('Embed', 'fluent-community'),
326 'Paste a URL to embed' => __('Paste a URL to embed', 'fluent-community'),
327 'Embed from Vimeo, YouTube, Wistia and more' => __('Embed from Vimeo, YouTube, Wistia and more', 'fluent-community'),
328 'Lesson Duration' => __('Lesson Duration', 'fluent-community'),
329 'Minutes' => __('Minutes', 'fluent-community'),
330 'Seconds' => __('Seconds', 'fluent-community'),
331 'View' => __('View', 'fluent-community'),
332 'No documents attached yet.' => __('No documents attached yet.', 'fluent-community'),
333 'Manage Documents & Files' => __('Manage Documents & Files', 'fluent-community'),
334 "User's Name" => __("User's Name", 'fluent-community'),
335 "User's Email" => __("User's Email", 'fluent-community'),
336 "User's photo HTML" => __("User's photo HTML", 'fluent-community'),
337 'Profile Link' => __('Profile Link', 'fluent-community'),
338 ];
339
340 return apply_filters('fluent_community/editor_i18n_strings', $strings);
341 }
342
343 private function gutenberg_get_available_image_sizes()
344 {
345 $size_names = apply_filters(
346 'fluent_community/image_size_names_choose',
347 array(
348 'thumbnail' => __('Thumbnail', 'fluent-community'),
349 'medium' => __('Medium', 'fluent-community'),
350 'large' => __('Large', 'fluent-community'),
351 'full' => __('Full Size', 'fluent-community'),
352 )
353 );
354 $all_sizes = array();
355 foreach ($size_names as $size_slug => $size_name) {
356 $all_sizes[] = array(
357 'slug' => $size_slug,
358 'name' => $size_name,
359 );
360 }
361 return $all_sizes;
362 }
363
364 protected function renderPage()
365 {
366
367 remove_action( 'wp_print_styles', 'print_emoji_styles' );
368
369 add_action('fluent_community/block_editor_footer', function () {
370 wp_underscore_playlist_templates();
371 wp_print_footer_scripts();
372 wp_print_media_templates();
373 wp_enqueue_global_styles();
374 wp_enqueue_stored_styles();
375 wp_maybe_inline_styles();
376 });
377
378 add_action('fluent_block_editor/head', 'wp_enqueue_scripts', 1);
379 add_action('fluent_block_editor/head', 'wp_resource_hints', 2);
380 add_action('fluent_block_editor/head', 'wp_preload_resources', 1);
381 add_action('fluent_block_editor/head', 'wp_print_styles', 8);
382 add_action('fluent_block_editor/head', 'wp_print_head_scripts', 9);
383 add_action('fluent_block_editor/head', 'wp_custom_css_cb', 101);
384
385 $this->unloadOtherScripts();
386 ?>
387 <!DOCTYPE html>
388 <html <?php language_attributes(); ?>>
389 <head>
390 <title>FluentCommunity Block Editor</title>
391 <meta charset='utf-8'>
392 <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover"/>
393 <meta name="mobile-web-app-capable" content="yes">
394 <meta name="robots" content="noindex">
395 <?php do_action('fluent_block_editor/head'); ?>
396 <?php do_action('fluent_community/block_editor_head'); ?>
397 </head>
398 <body class="fcom_custom_editor">
399 <div class="wp-site-blocks">
400 <div id="editor" class="gutenberg__editor"></div>
401 </div>
402 <?php
403 do_action('fluent_community/block_editor_footer');
404 ?>
405 </body>
406 </html>
407 <?php
408 }
409
410 private function shouldBlockAsset(string $src, string $pluginUrl, string $themesUrl, string $approvedPattern): bool
411 {
412 $isPlugin = strpos($src, $pluginUrl) !== false;
413 $isTheme = strpos($src, $themesUrl) !== false;
414
415 if (!$isPlugin && !$isTheme) {
416 return false;
417 }
418
419 return !preg_match('#' . $approvedPattern . '#', $src);
420 }
421
422 private function unloadOtherScripts()
423 {
424 $isSkip = apply_filters('fluent_com_editor/skip_no_conflict', false);
425 if ($isSkip) {
426 return;
427 }
428
429 /**
430 * Define the list of approved slugs for FluentCRM assets.
431 *
432 * This filter allows modification of the list of slugs that are approved for FluentCRM assets.
433 *
434 * @param array $approvedSlugs An array of approved slugs for FluentCRM assets.
435 */
436 $approvedSlugs = apply_filters('fluent_com_editor/asset_listed_slugs', [
437 '\/gutenberg\/'
438 ]);
439 $approvedSlugs[] = 'fluent-community';
440 $approvedSlugs = array_unique($approvedSlugs);
441 $approvedSlugs = implode('|', $approvedSlugs);
442
443 $pluginUrl = str_replace(['http:', 'https:'], '', plugins_url());
444
445 $themesUrl = str_replace(['http:', 'https:'], '', get_theme_root_uri());
446
447 add_filter('script_loader_src', function ($src, $handle) use ($approvedSlugs, $pluginUrl, $themesUrl) {
448 if (!$src) {
449 return $src;
450 }
451
452 if ($this->shouldBlockAsset($src, $pluginUrl, $themesUrl, $approvedSlugs)) {
453 return false;
454 }
455
456 return $src;
457 }, 1, 2);
458
459 add_action('wp_print_scripts', function () use ($approvedSlugs, $pluginUrl, $themesUrl) {
460 global $wp_scripts;
461 if (!$wp_scripts) {
462 return;
463 }
464
465 foreach ($wp_scripts->queue as $script) {
466 if (empty($wp_scripts->registered[$script]) || empty($wp_scripts->registered[$script]->src)) {
467 continue;
468 }
469
470 $src = $wp_scripts->registered[$script]->src;
471 if ($this->shouldBlockAsset($src, $pluginUrl, $themesUrl, $approvedSlugs)) {
472 wp_dequeue_script($wp_scripts->registered[$script]->handle);
473 }
474 }
475 }, 1);
476
477 add_action('wp_print_styles', function () {
478 $isSkip = apply_filters('fluent_community/skip_no_conflict', false, 'styles');
479
480 if ($isSkip) {
481 return;
482 }
483
484 global $wp_styles;
485 if (!$wp_styles) {
486 return;
487 }
488
489 $approvedSlugs = apply_filters('fluent_community/asset_listed_slugs', [
490 '\/gutenberg\/',
491 ]);
492
493 $approvedSlugs[] = '\/fluent-community\/';
494
495 $approvedSlugs = array_unique($approvedSlugs);
496 $approvedSlugs = implode('|', $approvedSlugs);
497
498 $pluginUrl = plugins_url();
499 $themeUrl = get_theme_root_uri();
500
501 $pluginUrl = str_replace(['http:', 'https:'], '', $pluginUrl);
502 $themeUrl = str_replace(['http:', 'https:'], '', $themeUrl);
503
504 foreach ($wp_styles->queue as $script) {
505
506 if (empty($wp_styles->registered[$script]) || empty($wp_styles->registered[$script]->src)) {
507 continue;
508 }
509
510 $src = $wp_styles->registered[$script]->src;
511 $pluginMatched = (strpos($src, $pluginUrl) !== false) && !preg_match('#' . $approvedSlugs . '#', $src);
512 $themeMatched = (strpos($src, $themeUrl) !== false) && !preg_match('#' . $approvedSlugs . '#', $src);
513
514 if (!$pluginMatched && !$themeMatched) {
515 continue;
516 }
517
518 wp_dequeue_style($wp_styles->registered[$script]->handle);
519 }
520 }, 999999);
521 }
522
523 private function getEditorSettings($post)
524 {
525 // Media settings.
526 $max_upload_size = wp_max_upload_size();
527 if (!$max_upload_size) {
528 $max_upload_size = 0;
529 }
530
531 $lock_details = array(
532 'isLocked' => false,
533 'user' => '',
534 );
535
536 $editor_settings = array(
537 'maxUploadFileSize' => $max_upload_size,
538 'allowedMimeTypes' => get_allowed_mime_types(),
539 'postLock' => $lock_details,
540 'postLockUtils' => array(
541 'nonce' => wp_create_nonce('lock-post_' . $post->ID),
542 'unlockNonce' => wp_create_nonce('update-post_' . $post->ID),
543 'ajaxUrl' => admin_url('admin-ajax.php'),
544 ),
545 '__experimentalFeatures' => $this->getExperimentalFeatures(),
546 'colors' => $this->getColorPalette(),
547 '__experimentalDiscussionSettings' => [
548 'avatarURL' => 'https://secure.gravatar.com/avatar/?s=96&f=y&r=g',
549 'commentOrder' => 'asc',
550 'commentsPerPage' => '50',
551 'defaultCommentsPage' => 'newest',
552 'defaultCommentStatus' => 'open',
553 'pageComments' => '',
554 'threadComments' => '1',
555 'threadCommentsDepth' => '5'
556 ],
557 '__unstableGalleryWithImageBlocks' => false,
558 '__unstableIsBlockBasedTheme' => false,
559 'enableCustomUnits' => [
560 'px',
561 'em',
562 'rem',
563 '%',
564 'vh',
565 'vw'
566 ],
567 'fontSizes' => [
568 [
569 'name' => 'Small',
570 'size' => 'var(--fcom-font-size-small)',
571 'slug' => 'small'
572 ],
573 [
574 'name' => 'Medium',
575 'size' => 'var(--fcom-font-size-medium)',
576 'slug' => 'medium'
577 ],
578 [
579 'name' => 'Large',
580 'size' => 'var(--fcom-font-size-large)',
581 'slug' => 'large'
582 ],
583 [
584 'name' => 'Larger',
585 'size' => 'var(--fcom-font-size-larger)',
586 'slug' => 'larger'
587 ],
588 [
589 'name' => 'XX-Large',
590 'size' => 'var(--fcom-font-size-xxlarge)',
591 'slug' => 'xxlarge'
592 ]
593 ],
594 'fullscreenMode' => 1,
595 'enableCustomSpacing' => 1,
596 'enableCustomLineHeight' => 1,
597 'enableCustomFields' => false,
598 'disablePostFormats' => true,
599 'disableLayoutStyles' => false,
600 'disableCustomSpacingSizes' => false,
601 'disableCustomGradients' => 1,
602 'alignWide' => true,
603 'disableCustomFontSizes' => false,
604 'disableCustomColors' => false,
605 'canUpdateBlockBindings' => false,
606 'bodyPlaceholder' => __('Start writing or type / to choose a block for your lesson content', 'fluent-community'),
607 'allowedBlockTypes' => apply_filters('fluent_community/allowed_block_types', [
608 'core/audio',
609 'core/block',
610 'core/buttons',
611 'core/button',
612 'core/code',
613 'core/columns',
614 'core/column',
615 'core/cover',
616 'core/embed',
617 'core/footnotes',
618 'core/freeform',
619 'core/gallery',
620 'core/group',
621 'core/heading',
622 'core/html',
623 'core/image',
624 'core/latest-posts',
625 'core/list',
626 'core/list-item',
627 'core/media-text',
628 'core/missing',
629 'core/paragraph',
630 'core/preformatted',
631 'core/pullquote',
632 'core/quote',
633 'core/rss',
634 'core/separator',
635 'core/social-link',
636 'core/social-links',
637 'core/spacer',
638 'core/table',
639 'core/text-columns',
640 'core/verse',
641 'core/freeform'
642 ]),
643 'gradients' => [],
644 'imageDefaultSize' => 'large',
645 'imageEditing' => true,
646 'isRTL' => Helper::isRtl(),
647 'autosaveInterval' => 999,
648 'localAutosaveInterval' => 999,
649 'richEditingEnabled' => true,
650 'spacingSizes' => [
651 [
652 'name' => '2X-Small',
653 'size' => '0.44rem',
654 'slug' => '20'
655 ],
656 [
657 'name' => 'X-Small',
658 'size' => '0.67rem',
659 'slug' => '30'
660 ],
661 [
662 'name' => 'Small',
663 'size' => '1rem',
664 'slug' => '40'
665 ],
666 [
667 'name' => 'Medium',
668 'size' => '1.5rem',
669 'slug' => '50'
670 ],
671 [
672 'name' => 'Large',
673 'size' => '2.25rem',
674 'slug' => '60'
675 ],
676 [
677 'name' => 'X-Large',
678 'size' => '3.38rem',
679 'slug' => '70'
680 ],
681 [
682 'name' => '2X-Large',
683 'size' => '5.06rem',
684 'slug' => '80'
685 ]
686 ],
687 'titlePlaceholder' => __('Add Lesson title', 'fluent-community')
688 );
689
690 $editor_settings['styles'] = $this->getEditorStyles();
691 $editor_settings['__unstableResolvedAssets'] = $this->getResolvedAssets();
692 $editor_settings['defaultEditorStyles'] = $this->getDefaultEditorStyles();
693 $editor_settings['imageSizes'] = $this->gutenberg_get_available_image_sizes();
694
695 $editor_settings = apply_filters('fluent_community/block_editor_settings', $editor_settings);
696 return $editor_settings;
697 }
698
699 private function getExperimentalFeatures()
700 {
701 return array(
702 'appearanceTools' => true,
703 'useRootPaddingAwareAlignments' => false,
704 'border' => [
705 'color' => 1,
706 'radius' => 1,
707 'style' => 1,
708 'width' => 1,
709 ],
710 'color' => [
711 'background' => true,
712 'button' => 1,
713 'caption' => 1,
714 'customDuotone' => 0,
715 'defaultDuotone' => 0,
716 'defaultGradients' => 0,
717 'defaultPalette' => [],
718 'duotone' => [],
719 'gradients' => [],
720 'heading' => 1,
721 'link' => 1,
722 'palette' => [
723 'default' => [],
724 'theme' => [
725 [
726 'name' => 'Accent',
727 'slug' => 'theme-palette-color-1',
728 'color' => 'var(--theme-palette-color-1)',
729 ],
730 [
731 'name' => 'Accent - alt',
732 'slug' => 'theme-palette-color-2',
733 'color' => 'var(--theme-palette-color-2)',
734 ],
735 [
736 'name' => 'Strongest text',
737 'slug' => 'theme-palette-color-3',
738 'color' => 'var(--theme-palette-color-3)',
739 ],
740 [
741 'name' => 'Strong Text',
742 'slug' => 'theme-palette-color-4',
743 'color' => 'var(--theme-palette-color-4)',
744 ],
745 [
746 'name' => 'Medium text',
747 'slug' => 'theme-palette-color-5',
748 'color' => 'var(--theme-palette-color-5)',
749 ],
750 [
751 'name' => 'Subtle Text',
752 'slug' => 'theme-palette-color-6',
753 'color' => 'var(--theme-palette-color-6)',
754 ],
755 [
756 'name' => 'Subtle Background',
757 'slug' => 'theme-palette-color-7',
758 'color' => 'var(--theme-palette-color-7)',
759 ],
760 [
761 'name' => 'Lighter Background',
762 'slug' => 'theme-palette-color-8',
763 'color' => 'var(--theme-palette-color-8)',
764 ]
765 ]
766 ],
767 'text' => true,
768 ],
769 'dimensions' => [
770 'defaultAspectRatios' => true,
771 'aspectRatios' => [
772 'default' => [
773 [
774 'name' => 'Square - 1:1',
775 'slug' => 'square',
776 'ratio' => '1',
777 ],
778 [
779 'name' => 'Standard - 4:3',
780 'slug' => '4-3',
781 'ratio' => '4/3',
782 ],
783 [
784 'name' => 'Portrait - 3:4',
785 'slug' => '3-4',
786 'ratio' => '3/4',
787 ],
788 [
789 'name' => 'Classic - 3:2',
790 'slug' => '3-2',
791 'ratio' => '3/2',
792 ],
793 [
794 'name' => 'Classic Portrait - 2:3',
795 'slug' => '2-3',
796 'ratio' => '2/3',
797 ],
798 [
799 'name' => 'Wide - 16:9',
800 'slug' => '16-9',
801 'ratio' => '16/9',
802 ],
803 [
804 'name' => 'Tall - 9:16',
805 'slug' => '9-16',
806 'ratio' => '9/16',
807 ],
808 ]
809 ],
810 'aspectRatio' => 1,
811 'minHeight' => 1,
812 ],
813 'shadow' => [
814 'defaultPresets' => true,
815 'presets' => [
816 'default' => [
817 [
818 'name' => 'Natural',
819 'slug' => 'natural',
820 'shadow' => '6px 6px 9px rgba(0, 0, 0, 0.2)',
821 ],
822 [
823 'name' => 'Deep',
824 'slug' => 'deep',
825 'shadow' => '12px 12px 50px rgba(0, 0, 0, 0.4)',
826 ],
827 [
828 'name' => 'Sharp',
829 'slug' => 'sharp',
830 'shadow' => '6px 6px 0px rgba(0, 0, 0, 0.2)',
831 ],
832 [
833 'name' => 'Outlined',
834 'slug' => 'outlined',
835 'shadow' => '6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1)',
836 ],
837 [
838 'name' => 'Crisp',
839 'slug' => 'crisp',
840 'shadow' => '6px 6px 0px rgba(0, 0, 0, 1)',
841 ],
842 ],
843 ],
844 ],
845 'spacing' => [
846 'blockGap' => 1,
847 'margin' => 1,
848 'padding' => 1,
849 'defaultSpacingSizes' => true,
850 'spacingScale' => [
851 'default' => [
852 'operator' => '*',
853 'increment' => 1.5,
854 'steps' => 7,
855 'mediumStep' => 1.5,
856 'unit' => 'rem',
857 ],
858 ],
859 'spacingSizes' => [
860 'default' => [
861 [
862 'name' => '2X-Small',
863 'slug' => '20',
864 'size' => '0.44rem',
865 ],
866 [
867 'name' => 'X-Small',
868 'slug' => '30',
869 'size' => '0.67rem',
870 ],
871 [
872 'name' => 'Small',
873 'slug' => '40',
874 'size' => '1rem',
875 ],
876 [
877 'name' => 'Medium',
878 'slug' => '50',
879 'size' => '1.5rem',
880 ],
881 [
882 'name' => 'Large',
883 'slug' => '60',
884 'size' => '2.25rem',
885 ],
886 [
887 'name' => 'X-Large',
888 'slug' => '70',
889 'size' => '3.38rem',
890 ],
891 [
892 'name' => '2X-Large',
893 'slug' => '80',
894 'size' => '5.06rem',
895 ],
896 ],
897 ],
898 ],
899 'typography' => [
900 'defaultFontSizes' => NULL,
901 'dropCap' => true,
902 'fontSizes' => [
903 'default' => [
904 [
905 'name' => 'Small',
906 'slug' => 'small',
907 'size' => '13px',
908 ],
909 [
910 'name' => 'Medium',
911 'slug' => 'medium',
912 'size' => '20px',
913 ],
914 [
915 'name' => 'Large',
916 'slug' => 'large',
917 'size' => '36px',
918 ],
919 [
920 'name' => 'Extra Large',
921 'slug' => 'x-large',
922 'size' => '42px',
923 ],
924 ],
925 'theme' => [
926 [
927 'name' => 'Small',
928 'slug' => 'small',
929 'size' => 'var(--fcom-font-size-small)',
930 ],
931 [
932 'name' => 'Medium',
933 'slug' => 'medium',
934 'size' => 'var(--fcom-font-size-medium)',
935 ],
936 [
937 'name' => 'Large',
938 'slug' => 'large',
939 'size' => 'var(--fcom-font-size-large)',
940 ],
941 [
942 'name' => 'Larger',
943 'slug' => 'larger',
944 'size' => 'var(--fcom-font-size-larger)',
945 ],
946 [
947 'name' => 'XX-Large',
948 'slug' => 'xxlarge',
949 'size' => 'var(--fcom-font-size-xxlarge)',
950 ],
951 ],
952 ],
953 'fontStyle' => true,
954 'fontWeight' => true,
955 'letterSpacing' => true,
956 'textAlign' => true,
957 'textDecoration' => true,
958 'textTransform' => true,
959 'writingMode' => false,
960 'fluid' => 0,
961 ],
962 'blocks' => [
963 'core/button' => [
964 'border' => [
965 'radius' => true,
966 ]
967 ],
968 'core/image' => [
969 'lightbox' => [
970 'allowEditing' => true,
971 ]
972 ],
973 'core/pullquote' => [
974 'border' => [
975 'color' => true,
976 'radius' => true,
977 'style' => true,
978 'width' => true,
979 ]
980 ],
981 'core/paragraph' => [
982 'spacing' => [
983 'margin' => 1,
984 'padding' => 1,
985 ]
986 ]
987 ],
988 'layout' => [
989 'contentSize' => 'var(--theme-block-max-width)',
990 'wideSize' => 'var(--theme-block-wide-max-width)',
991 ],
992 'background' => [
993 'backgroundImage' => 1,
994 'backgroundSize' => 1,
995 ],
996 'position' => [
997 'sticky' => 0,
998 ]
999 );
1000 }
1001
1002 private function getColorPalette()
1003 {
1004 return [
1005 [
1006 'color' => 'var(--fcom-primary-bg, #ffffff)',
1007 'name' => 'Accent',
1008 'slug' => 'theme-palette-color-1'
1009 ],
1010 [
1011 'color' => 'var(--fcom-secondary-bg, #f0f2f5)',
1012 'name' => 'Accent - alt',
1013 'slug' => 'theme-palette-color-2'
1014 ],
1015 [
1016 'color' => 'var(--fcom-secondary-text, #525866)',
1017 'name' => 'Strongest text',
1018 'slug' => 'theme-palette-color-3'
1019 ],
1020 [
1021 'color' => 'var(--fcom-secondary-content-bg, #f0f3f5)',
1022 'name' => 'Strong Text',
1023 'slug' => 'theme-palette-color-4'
1024 ],
1025 [
1026 'color' => 'var(--fcom-active-bg, #f0f3f5)',
1027 'name' => 'Medium text',
1028 'slug' => 'theme-palette-color-5'
1029 ],
1030 [
1031 'color' => 'var(--fcom-light-bg, #E1E4EA)',
1032 'name' => 'Subtle Text',
1033 'slug' => 'theme-palette-color-6'
1034 ],
1035 [
1036 'color' => 'var(--fcom-deep-bg, #E1E4EA)',
1037 'name' => 'Subtle Background',
1038 'slug' => 'theme-palette-color-7'
1039 ],
1040 [
1041 'color' => 'var(--fcom-primary-text, #19283a)',
1042 'name' => 'Lighter Background',
1043 'slug' => 'theme-palette-color-8'
1044 ]
1045 ];
1046 }
1047
1048 private function getEditorStyles()
1049 {
1050 $editorDir = FLUENT_COMMUNITY_PLUGIN_DIR . 'Modules/Gutenberg/editor/';
1051
1052 return [
1053 [
1054 '__unstableType' => 'colorSchema',
1055 'css' => $this->getColorSchemaCss(),
1056 'isGlobalStyles' => true
1057 ],
1058 [
1059 '__unstableType' => 'theme',
1060 'css' => file_get_contents($editorDir . 'editor-iframe-styles.css') ?: '',
1061 'isGlobalStyles' => true
1062 ],
1063 [
1064 'css' => file_get_contents($editorDir . 'editor.css') ?: '',
1065 '__unstableType' => 'user'
1066 ]
1067 ];
1068 }
1069
1070 private function getResolvedAssets()
1071 {
1072 $resolvedStyles = [
1073 'wp-components-css' => includes_url('/css/dist/components/style.min.css'),
1074 'wp-preferences-css' => includes_url('/css/dist/preferences/style.min.css'),
1075 'wp-block-editor-css' => includes_url('/css/dist/block-editor/style.min.css'),
1076 'wp-reusable-blocks-css' => includes_url('/css/dist/reusable-blocks/style.min.css'),
1077 'wp-patterns-css' => includes_url('/css/dist/patterns/style.min.css'),
1078 'wp-editor-css' => includes_url('/css/dist/editor/style.min.css'),
1079 'wp-block-library-css' => includes_url('/css/dist/block-library/style.min.css'),
1080 'wp-block-editor-content-css' => includes_url('/css/dist/block-editor/content.min.css'),
1081 'wp-edit-blocks-css' => includes_url('/css/dist/block-library/editor.min.css'),
1082 'fcom-content-styling' => FLUENT_COMMUNITY_PLUGIN_URL . 'Modules/Gutenberg/editor/content_styling.css'
1083 ];
1084
1085 global $wp_version;
1086 $cssFiles = '';
1087 foreach ($resolvedStyles as $name => $file) {
1088 $cssFiles .= "<link rel='stylesheet' id='{$name}' href='{$file}?ver={$wp_version}' media='all' />\n"; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
1089 }
1090
1091 return [
1092 'scripts' => '<script src="' . includes_url('/js/dist/vendor/wp-polyfill.min.js?ver=3.15.0') . '" id="wp-polyfill-js"></script>', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
1093 'styles' => $cssFiles
1094 ];
1095 }
1096
1097 private function getDefaultEditorStyles()
1098 {
1099 return [
1100 [
1101 '__unstableType' => 'user',
1102 'css' => ':root{--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0, 124, 186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0, 107, 161;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0, 90, 135;--wp-admin-border-width-focus:2px;--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122, 0, 223;--wp-bound-block-color:var(--wp-block-synced-color);}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px;}}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;font-size:18px;line-height:1.5;--wp--style--block-gap:2em;}p{line-height:1.8;}.editor-post-title__block{font-size:2.5em;font-weight:800;margin-bottom:1em;margin-top:2em;}'
1103 ]
1104 ];
1105 }
1106
1107 private function getColorSchemaCss()
1108 {
1109 $colorSchema = Utility::getColorSchemaConfig();
1110
1111 $darkSchemaConfig = Arr::get($colorSchema, 'dark');
1112
1113 $colorSchemaCss = ':root {';
1114 foreach (Arr::get($darkSchemaConfig, 'body', []) as $colorKey => $value) {
1115 if ($value) {
1116 $cssVar = ' --fcom-' . str_replace('_', '-', $colorKey);
1117 $colorSchemaCss .= $cssVar . ':' . $value . '; ';
1118 }
1119 }
1120 $colorSchemaCss .= '}';
1121
1122 return $colorSchemaCss;
1123 }
1124 }
1125