_options = [ 'parent_slug' => ACADLIX_SLUG, 'page_title' => __('Acadlix Lessons', 'acadlix'), 'menu_title' => __('Lessons', 'acadlix'), 'capability' => 'acadlix_show_lesson', 'menu_slug' => 'acadlix_lesson', 'callback' => [$this, 'lesson_callback'], 'position' => 800 ]; } public function get_position() { return $this->_options['position'] ?? 800; } public function add_submenu() { $page = add_submenu_page( $this->_options['parent_slug'], $this->_options['page_title'], $this->_options['menu_title'], $this->_options['capability'], $this->_options['menu_slug'], $this->_options['callback'], $this->_options['position'] ); add_action("admin_print_scripts-{$page}", [$this, 'admin_print_scripts']); } public function localize_options() { global $post; // Create a mock post if one doesn't exist so the settings generator doesn't fail if (!($post instanceof \WP_Post)) { $post = new \WP_Post((object) [ 'ID' => 0, 'post_type' => 'post', 'post_status' => 'draft', ]); } // 🌟 THIS IS THE MAGIC NATIVE FUNCTION 🌟 // It fetches all theme.json configs, flexbox rules, typography, and editor styles $editor_settings = get_block_editor_settings(array(), $post); $current_user = wp_get_current_user(); $is_super = is_super_admin($current_user->ID); $capabilities = $current_user->exists() ? array_keys(array_filter((array) $current_user->allcaps)) : []; return [ 'api_url' => acadlix()->helper()->acadlix_get_api_url(), 'max_execution_time' => acadlix()->helper()->acadlix_max_execution_time(), 'nonce' => acadlix()->helper()->acadlix_get_wp_rest_nonce(), 'settings' => acadlix()->helper()->acadlix_get_all_options(), 'theme_settings' => acadlix()->helper()->acadlix_get_option('acadlix_theme_settings'), 'default_img_url' => esc_url(ACADLIX_ASSETS_IMAGE_URL . "demo-course.jpg"), 'user_id' => get_current_user_id(), 'isSuperAdmin' => $is_super, 'capabilities' => $is_super ? ['*'] : $capabilities, 'acadlix_docs_url' => ACADLIX_DOCUMENTATION_URL, 'isActive' => acadlix()->license()->isActive ?? false, 'block_settings' => $editor_settings, 'isBunnyNetIntegrationActive' => acadlix()->helper()->is_bunny_net_integration_addon_active(), ]; } public function admin_print_scripts() { // 1. SETUP MOCK CONTEXT FIRST (CRITICAL) // Third-party plugins check this screen context during script enqueuing! global $post, $current_screen; $original_post = $post; if (!($post instanceof \WP_Post)) { $post = new \WP_Post((object) [ 'ID' => 0, 'post_type' => 'post', 'post_status' => 'draft', 'post_title' => '', 'post_content' => '', ]); } if ($current_screen && method_exists($current_screen, 'is_block_editor')) { $current_screen->is_block_editor(true); } // 2. ENQUEUE CORE SCRIPTS wp_enqueue_editor(); wp_enqueue_media(); wp_enqueue_script('wp-element'); wp_enqueue_script('wp-i18n'); wp_enqueue_script('wp-blocks'); wp_enqueue_script('wp-block-editor'); wp_enqueue_script('wp-components'); wp_enqueue_script('wp-editor'); wp_enqueue_script('wp-plugins'); wp_enqueue_script('wp-format-library'); wp_enqueue_script('wp-api-fetch'); wp_enqueue_script('wp-server-side-render'); // 3. THE MAGIC FIX: BOOTSTRAP SERVER-SIDE BLOCK.JSON DATA // This feeds the missing 'title' and 'attributes' natively to block.json plugins $registry = \WP_Block_Type_Registry::get_instance(); $server_blocks = []; foreach ($registry->get_all_registered() as $block_name => $block_type) { if (strpos($block_name, 'core/') === 0) { continue; } // Fallback formatting if title is completely missing $fallback_title = ucwords(str_replace(['-', '_'], ' ', explode('/', $block_name)[1] ?? $block_name)); $block_data = [ 'name' => $block_name, 'title' => !empty($block_type->title) ? $block_type->title : $fallback_title, 'category' => !empty($block_type->category) ? $block_type->category : 'widgets', ]; // 🚨 THE CRITICAL FIX: Only attach these if they are not empty! // Passing empty arrays here overwrites JS defaults and strips classes like 'wp-block-table'. if (!empty($block_type->icon)) $block_data['icon'] = $block_type->icon; if (!empty($block_type->description)) $block_data['description'] = $block_type->description; if (!empty($block_type->supports)) $block_data['supports'] = $block_type->supports; if (!empty($block_type->attributes)) $block_data['attributes'] = $block_type->attributes; if (!empty($block_type->uses_context)) $block_data['usesContext'] = $block_type->uses_context; if (!empty($block_type->provides_context)) $block_data['providesContext'] = $block_type->provides_context; $server_blocks[$block_name] = $block_data; } // Inject this directly into wp.blocks exactly how WordPress Core does $bootstrap_json = wp_json_encode($server_blocks); $bootstrap_script = " if ( window.wp && window.wp.blocks && window.wp.blocks.unstable__bootstrapServerSideBlockDefinitions ) { window.wp.blocks.unstable__bootstrapServerSideBlockDefinitions( {$bootstrap_json} ); } "; wp_add_inline_script('wp-blocks', $bootstrap_script, 'after'); // 4. LOAD ENQUEUED BLOCK STYLES wp_enqueue_style('wp-components'); wp_enqueue_style('wp-block-editor'); wp_enqueue_style('wp-block-library'); wp_enqueue_style('wp-block-library-theme'); wp_enqueue_style('wp-format-library'); if (wp_style_is('wp-edit-post', 'registered')) { wp_enqueue_style('wp-edit-post'); } if (function_exists('wp_get_global_stylesheet')) { wp_add_inline_style('wp-block-library', wp_get_global_stylesheet()); } // 5. TRIGGER STANDARD BLOCK ASSETS HOOKS if (function_exists('wp_enqueue_registered_block_scripts_and_styles')) { wp_enqueue_registered_block_scripts_and_styles(); } do_action('enqueue_block_assets'); try { do_action('enqueue_block_editor_assets'); } catch (\Throwable $e) { error_log('Acadlix enqueue_block_editor_assets exception: ' . $e->getMessage()); } // 6. RESTORE GLOBAL STATE $post = $original_post; if ($current_screen && method_exists($current_screen, 'is_block_editor')) { $current_screen->is_block_editor(false); } // 7. LOAD YOUR CUSTOM APP ASSETS if (function_exists('acadlix') && acadlix()->assets()) { acadlix()->assets()->manager()->load_assets('admin_lesson', $this->localize_options()); } } public function lesson_callback() { echo '

' . esc_html__('Loading...', 'acadlix') . '

'; } public static function instance() { if (is_null(self::$_instance)) { self::$_instance = new self(); } return self::$_instance; } }