2, 'editor_script' => 'ai-schema-gen-block-editor', 'render_callback' => array( $this, 'render_block' ), 'attributes' => array( 'postId' => array( 'type' => 'number', 'default' => 0, ), ), ) ); // Enqueue block editor assets. add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) ); // Register post meta for REST API access. $this->register_block_meta(); } /** * Enqueue JavaScript and CSS for the block editor. * * Loads the Schema AI block editor bundle and localises it with * REST URL, nonce, and current post ID so the React sidebar panel * can communicate with the Schema AI REST API. */ public function enqueue_block_editor_assets() { $asset_file = SCHEMA_AI_PLUGIN_DIR . 'admin/js/build/block-editor.asset.php'; $deps = array( 'wp-plugins', 'wp-edit-post', 'wp-element', 'wp-components', 'wp-data', 'wp-api-fetch', 'wp-i18n' ); $version = SCHEMA_AI_VERSION; // Use the generated asset file if it exists (from wp-scripts build). if ( file_exists( $asset_file ) ) { $asset = require $asset_file; $deps = isset( $asset['dependencies'] ) ? $asset['dependencies'] : $deps; $version = isset( $asset['version'] ) ? $asset['version'] : $version; } $script_url = SCHEMA_AI_PLUGIN_URL . 'admin/js/build/block-editor.js'; // Fall back to non-build path if build does not exist. if ( ! file_exists( SCHEMA_AI_PLUGIN_DIR . 'admin/js/build/block-editor.js' ) ) { $script_url = SCHEMA_AI_PLUGIN_URL . 'admin/js/ai-schema-gen-block-editor.js'; } wp_enqueue_script( 'ai-schema-gen-block-editor', $script_url, $deps, $version, true ); // Localise script with data the React app needs. $post_id = 0; if ( function_exists( 'get_the_ID' ) ) { $post_id = get_the_ID(); } // If get_the_ID() did not work (common in block editor context), try the global post. if ( ! $post_id ) { global $post; if ( isset( $post->ID ) ) { $post_id = $post->ID; } } wp_localize_script( 'ai-schema-gen-block-editor', 'schemaAiBlock', array( 'restUrl' => esc_url_raw( rest_url( 'ai-schema-gen/v1/' ) ), 'nonce' => wp_create_nonce( 'wp_rest' ), 'postId' => absint( $post_id ), 'pluginUrl' => SCHEMA_AI_PLUGIN_URL, 'version' => SCHEMA_AI_VERSION, ) ); // Enqueue editor styles. $style_url = SCHEMA_AI_PLUGIN_URL . 'admin/css/ai-schema-gen-block-editor.css'; if ( file_exists( SCHEMA_AI_PLUGIN_DIR . 'admin/css/ai-schema-gen-block-editor.css' ) ) { wp_enqueue_style( 'ai-schema-gen-block-editor', $style_url, array(), SCHEMA_AI_VERSION ); } } /** * Server-side render callback for the ai-schema-gen/schema-panel block. * * Outputs a container div that the React application will hydrate * with the interactive Schema AI panel. * * @param array $attributes Block attributes. * @return string Rendered HTML. */ public function render_block( $attributes ) { $post_id = 0; if ( ! empty( $attributes['postId'] ) ) { $post_id = absint( $attributes['postId'] ); } if ( ! $post_id ) { $post_id = get_the_ID(); } $data_attrs = sprintf( 'data-post-id="%d" data-rest-url="%s" data-nonce="%s"', absint( $post_id ), esc_attr( rest_url( 'ai-schema-gen/v1/' ) ), esc_attr( wp_create_nonce( 'wp_rest' ) ) ); return sprintf( '
', $data_attrs ); } /** * Register post meta for schema data accessible via the REST API. * * Registers 'schema_ai_schema_data' as a post meta field on all post * types so that the block editor can read and update schema data * through the standard WordPress REST API. */ public function register_block_meta() { register_post_meta( '', 'schema_ai_schema_data', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', 'default' => '', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, 'sanitize_callback' => function ( $value ) { // Validate that the value is valid JSON if not empty. if ( empty( $value ) ) { return ''; } $decoded = json_decode( $value, true ); if ( null === $decoded && JSON_ERROR_NONE !== json_last_error() ) { return ''; } return wp_unslash( $value ); }, ) ); register_post_meta( '', 'schema_ai_schema_type', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', 'default' => '', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, 'sanitize_callback' => 'sanitize_text_field', ) ); register_post_meta( '', 'schema_ai_auto_generate', array( 'show_in_rest' => true, 'single' => true, 'type' => 'boolean', 'default' => false, 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); } }