add_action( 'init', $this, 'register_block' ); // Backward-compat alias — same output as [minds_featured_projects]. add_shortcode( 'acc_featured_projects', [ $this, 'render' ] ); } public function register_block(): void { if ( ! function_exists( 'register_block_type' ) ) { return; } wp_register_script( 'acc-block-featured-projects', false, [ 'wp-blocks', 'wp-element', 'wp-server-side-render', 'wp-block-editor', 'wp-components', 'wp-i18n' ], ACADEMICCREW_VERSION, true ); wp_add_inline_script( 'acc-block-featured-projects', $this->editor_script() ); register_block_type( 'academiccrew/featured-projects', [ 'api_version' => 2, 'title' => __( 'AcademicCrew: Featured Projects', 'academiccrew' ), 'description' => __( 'Index-strip list of featured research projects.', 'academiccrew' ), 'category' => 'academiccrew', 'icon' => 'star-filled', 'supports' => [ 'html' => false, 'align' => [ 'wide', 'full' ] ], 'attributes' => [ 'limit' => [ 'type' => 'integer', 'default' => 4 ], ], 'render_callback' => [ $this, 'render' ], 'editor_script' => 'acc-block-featured-projects', 'editor_style_handles' => [ 'acc-system', 'acc-featured-projects' ], ] ); } // ------------------------------------------------------------------------- // Render // ------------------------------------------------------------------------- public function render( array $atts ): string { return ( new FeaturedProjectsStripShortcode() )->render( [ 'limit' => (int) ( $atts['limit'] ?? 4 ) ] ); } // ------------------------------------------------------------------------- // Gutenberg editor script (inline, no build step) // ------------------------------------------------------------------------- private function editor_script(): string { return <<<'JS' (function(blocks, el, SSR, blockEditor, components, i18n) { var __ = i18n.__; var InspectorControls = blockEditor.InspectorControls; var useBlockProps = blockEditor.useBlockProps; var PanelBody = components.PanelBody; var RangeControl = components.RangeControl; blocks.registerBlockType('academiccrew/featured-projects', { edit: function(props) { var attrs = props.attributes; var setA = props.setAttributes; var blockProps = useBlockProps({ style: { position: 'relative' } }); return el('div', blockProps, el(InspectorControls, { key: 'controls' }, el(PanelBody, { title: __('Settings', 'academiccrew'), initialOpen: true }, el(RangeControl, { label: __('Number of projects', 'academiccrew'), value: attrs.limit, min: 1, max: 12, step: 1, onChange: function(v) { setA({ limit: v }); } }) ) ), el('div', { key: 'preview', style: { pointerEvents: 'none' } }, el(SSR, { block: 'academiccrew/featured-projects', attributes: attrs }) ) ); }, save: function() { return null; } }); }(wp.blocks, wp.element.createElement, wp.serverSideRender, wp.blockEditor, wp.components, wp.i18n)); JS; } }