'mcb-block-editor', 'editor_style' => 'mcb-block-editor-style', 'render_callback' => array(__CLASS__, 'render_block'), 'attributes' => array( 'repository' => array( 'type' => 'string', 'default' => '' ), 'theme' => array( 'type' => 'string', 'default' => 'dark' ), 'height' => array( 'type' => 'string', 'default' => '600px' ), 'showLineNumbers' => array( 'type' => 'boolean', 'default' => true ), 'initialFile' => array( 'type' => 'string', 'default' => '' ), 'title' => array( 'type' => 'string', 'default' => '' ), 'align' => array( 'type' => 'string', 'default' => 'none' ), 'className' => array( 'type' => 'string', 'default' => '' ) ), 'supports' => array( 'align' => array('wide', 'full'), 'className' => true, 'customClassName' => true, 'html' => false, 'anchor' => true ), 'example' => array( 'attributes' => array( 'repository' => 'facebook/react', 'theme' => 'dark', 'height' => '400px', 'title' => 'React Source Code Example' ) ) )); // Add block variations wp_register_script( 'mcb-block-variations', MCB_PLUGIN_URL . 'assets/js/block-variations.js', array('wp-blocks', 'wp-dom-ready'), MCB_PLUGIN_VERSION, true ); wp_enqueue_script('mcb-block-variations'); } /** * Render the block on the frontend */ public static function render_block($attributes, $content) { // Validate required attributes if (empty($attributes['repository'])) { return '
Please specify a repository (e.g., owner/repository)
'; } // Sanitize attributes $repository = sanitize_text_field($attributes['repository']); // Validate repository format if (!MCB_Security::validate_repo_format($repository)) { return '
Invalid repository format. Use: owner/repository
'; } // Build shortcode attributes $shortcode_atts = array( 'repo' => $repository, 'theme' => sanitize_text_field($attributes['theme'] ?? 'dark'), 'height' => sanitize_text_field($attributes['height'] ?? '600px'), 'show_line_numbers' => $attributes['showLineNumbers'] ? 'true' : 'false', 'initial_file' => sanitize_text_field($attributes['initialFile'] ?? ''), 'title' => sanitize_text_field($attributes['title'] ?? '') ); // Add alignment class if needed $wrapper_class = 'mcb-block-wrapper'; if (!empty($attributes['align'])) { $wrapper_class .= ' align' . esc_attr($attributes['align']); } if (!empty($attributes['className'])) { $wrapper_class .= ' ' . esc_attr($attributes['className']); } // Generate shortcode $shortcode = '[maple_code_block'; foreach ($shortcode_atts as $key => $value) { if (!empty($value)) { $shortcode .= ' ' . $key . '="' . esc_attr($value) . '"'; } } $shortcode .= ']'; // Render with wrapper return sprintf( '
%s
', esc_attr($wrapper_class), do_shortcode($shortcode) ); } /** * Enqueue block editor assets */ public static function enqueue_block_editor_assets() { // Debug log error_log('MCB: Enqueueing block editor assets'); // Make sure our script is registered if (!wp_script_is('mcb-block-editor', 'registered')) { error_log('MCB: Script not registered, registering now'); wp_register_script( 'mcb-block-editor', MCB_PLUGIN_URL . 'assets/js/block-editor.js', array('wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n', 'wp-data'), MCB_PLUGIN_VERSION, true ); } // Localize script with data for the editor wp_localize_script('mcb-block-editor', 'mcbBlockData', array( 'pluginUrl' => MCB_PLUGIN_URL, 'themes' => array( array('label' => 'Dark', 'value' => 'dark'), array('label' => 'Light', 'value' => 'light'), array('label' => 'Monokai', 'value' => 'monokai'), array('label' => 'Solarized', 'value' => 'solarized') ), 'defaultHeight' => '600px', 'popularRepos' => array( 'facebook/react', 'vuejs/vue', 'angular/angular', 'microsoft/vscode', 'torvalds/linux', 'tensorflow/tensorflow', 'kubernetes/kubernetes', 'nodejs/node', 'rust-lang/rust', 'golang/go' ), 'nonce' => wp_create_nonce('mcb_block_nonce') )); } /** * Enqueue frontend block assets */ public static function enqueue_block_assets() { // Only enqueue on frontend if (!is_admin()) { // These will be enqueued by the shortcode handler // We just need to ensure the block wrapper styles are loaded wp_enqueue_style( 'mcb-block-style', MCB_PLUGIN_URL . 'assets/css/block-style.css', array(), MCB_PLUGIN_VERSION ); } } /** * Add custom block category */ public static function add_block_category($categories, $post) { return array_merge( array( array( 'slug' => 'maple-code-blocks', 'title' => __('Maple Code Blocks', 'maple-code-blocks'), 'icon' => 'editor-code' ) ), $categories ); } /** * Register REST API endpoint for repository validation */ public static function register_rest_routes() { register_rest_route('maple-code-blocks/v1', '/validate-repo', array( 'methods' => 'POST', 'callback' => array(__CLASS__, 'validate_repository'), 'permission_callback' => function() { return current_user_can('edit_posts'); }, 'args' => array( 'repository' => array( 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ) ) )); register_rest_route('maple-code-blocks/v1', '/get-files', array( 'methods' => 'POST', 'callback' => array(__CLASS__, 'get_repository_files'), 'permission_callback' => function() { return current_user_can('edit_posts'); }, 'args' => array( 'repository' => array( 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field' ) ) )); } /** * Validate repository via REST API */ public static function validate_repository($request) { $repository = $request->get_param('repository'); // Validate format if (!MCB_Security::validate_repo_format($repository)) { return new WP_Error('invalid_format', 'Invalid repository format. Use: owner/repository'); } // Quick check with GitHub API $github_api = new MCB_GitHub_API(); $result = $github_api->validate_repository_exists($repository); if (is_wp_error($result)) { return $result; } return array( 'valid' => true, 'repository' => $repository ); } /** * Get repository files for block editor preview */ public static function get_repository_files($request) { $repository = $request->get_param('repository'); // Validate format if (!MCB_Security::validate_repo_format($repository)) { return new WP_Error('invalid_format', 'Invalid repository format'); } $github_api = new MCB_GitHub_API(); $files = $github_api->get_repository_files($repository); if (is_wp_error($files)) { return $files; } // Return only file names for the editor $file_list = array_map(function($file) { return array( 'path' => $file['path'], 'name' => $file['name'] ); }, array_slice($files, 0, 10)); // Limit to 10 files for preview return array( 'files' => $file_list, 'total' => count($files) ); } } // Initialize block editor support add_action('init', array('MCB_Block_Editor', 'init')); add_action('rest_api_init', array('MCB_Block_Editor', 'register_rest_routes'));