register_block(); add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_editor_assets' ] ); } /** * Registers the Gutenberg block using block.json. */ public function register_block(): void { $block_json_path = ADPRESSO_ABSPATH . 'admin/assets/block/src/'; if ( file_exists( $block_json_path . 'block.json' ) ) { register_block_type_from_metadata( $block_json_path, [ 'render_callback' => [ $this, 'render_block_callback' ], ] ); } elseif ( RuntimeDebugger::is_active( 2 ) ) { RuntimeDebugger::add_doing_it_wrong_entry( esc_html( 'AdPresso Block: block.json not found at ' . $block_json_path ) ); } } /** * Enqueues JavaScript and CSS assets for the block editor. * Also localizes data needed by the block's edit component. */ public function enqueue_editor_assets(): void { if ( ! is_admin() || ! function_exists( 'get_current_screen' ) || ! get_current_screen() || ! get_current_screen()->is_block_editor() ) { return; } $script_asset_path = ADPRESSO_ABSPATH . 'admin/assets/block/build/index.asset.php'; $script_url = ADPRESSO_BASE_URL . 'admin/assets/block/build/index.js'; if ( ! file_exists( $script_asset_path ) ) { RuntimeDebugger::add_doing_it_wrong_entry( esc_html( 'AdPresso Block: Asset manifest (index.asset.php) not found at ' . $script_asset_path ) ); return; } $script_asset = require( $script_asset_path ); wp_enqueue_script( 'adpresso-ad-inserter-block-editor', $script_url, $script_asset['dependencies'], $script_asset['version'], true ); // Prepare data for the block editor select field. $data_for_js = [ 'ads' => adpresso_get_ad_repository()->get_ads_for_select(), 'groups' => adpresso_get_group_repository()->get_groups_for_select(), 'manualPlacements' => $this->get_manual_placements_for_select(), 'editLinks' => [ 'ad' => admin_url( 'admin.php?page=adpresso-list-tables&tab=ads&action=edit&entity_type=ads&entity_id=%ID%' ), 'group' => admin_url( 'admin.php?page=adpresso-list-tables&tab=groups&action=edit&entity_type=groups&entity_id=%ID%' ), 'placement' => admin_url( 'admin.php?page=adpresso-list-tables&tab=placements&action=edit&entity_type=placements&entity_id=%ID%' ), ], 'i18n' => [ 'blockTitle' => __( 'AdPresso', 'adpresso' ), 'selectItem' => __( 'Select Ad, Group, or Manual Placement...', 'adpresso' ), 'adsOptgroup' => __( 'Ads', 'adpresso' ), 'groupsOptgroup' => __( 'Groups', 'adpresso' ), 'placementsOptgroup' => __( 'Manual Placements', 'adpresso' ), ], ]; $data_for_js['legacyAdvads'] = A2BlockTakeover::get_editor_data(); wp_localize_script( 'adpresso-ad-inserter-block-editor', 'adpressoBlockAdInserterData', $data_for_js ); } /** * Prepares the data for Manual Placements for the select field in the block editor. */ private function get_manual_placements_for_select(): array { if ( $this->placement_repo === null ) { $this->placement_repo = adpresso_get_placement_repository(); } $all_placements = $this->placement_repo->get_by_type( 'manual' ); $options = []; foreach ( $all_placements as $placement ) { if ( $placement instanceof Placement && $placement->is_type( 'manual' ) && $placement->is_backend_valid ) { /* translators: %d is the placement id. */ $options[] = [ 'value' => $placement->get_id(), 'label' => $placement->get_title() ?: sprintf( __( 'Manual Placement #%d', 'adpresso' ), $placement->get_id() ) ]; } } return $options; } /** * Server-side rendering callback for the Block. * * @param array $attributes The saved attributes from the block. * @param string $content The inner content of the block. Not used for dynamic blocks. * * @return string The HTML to output in the frontend. */ public function render_block_callback( array $attributes, string $content ): string { $item_id = absint( $attributes['selectedItem'] ?? 0 ); if ( ! $item_id ) { return ''; } $entity = Util::get_entity_from_post( $item_id ); $atts = self::attributes_to_atts( $attributes ); if ( $entity instanceof Ad || $entity instanceof Group ) { return FrontendHooks::render_virtual_entity( $entity, 'manual_block', $atts ); } // If it's not an ad or group, we assume that it's a manual placement. It keeps its own layout. return FrontendHooks::render_manual_placement( $item_id, 'manual_block', array_intersect_key( $atts, array_flip( [ 'class', 'inline' ] ) ) ); } /** * Maps the block's layout attributes onto the shortcode attributes, so both share one render path. * * @param array $attributes The saved block attributes. * * @return array Shortcode attributes for FrontendHooks::apply_shortcode_overrides(). */ public static function attributes_to_atts( array $attributes ): array { $atts = []; $position = (string) ( $attributes['position'] ?? 'none' ); if ( '' !== $position && 'none' !== $position ) { $atts['align'] = $position; } $margin = is_array( $attributes['margin'] ?? null ) ? $attributes['margin'] : []; $sides = []; foreach ( [ 'top', 'right', 'bottom', 'left' ] as $side ) { $sides[] = is_numeric( $margin[ $side ] ?? null ) ? (int) $margin[ $side ] . 'px' : null; } if ( array_filter( $sides, 'is_string' ) ) { // Unset sides become 0, the shorthand needs all four. $atts['margin'] = implode( ' ', array_map( static fn( ?string $side ): string => $side ?? '0', $sides ) ); } if ( ! empty( $attributes['className'] ) ) { $atts['class'] = (string) $attributes['className']; } foreach ( [ 'width', 'height' ] as $size ) { if ( ! empty( $attributes[ $size ] ) && absint( $attributes[ $size ] ) > 0 ) { $atts[ $size ] = absint( $attributes[ $size ] ); } } if ( ! empty( $attributes['inline'] ) ) { $atts['inline'] = 'true'; } return $atts; } }