register_blocks(); add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts')); // Editor assets enqueued below; data endpoints are provided via REST (see includes/class-swi-foot-rest.php) add_action('enqueue_block_editor_assets', array($this, 'enqueue_editor_assets')); } public function register_blocks() { // Register blocks from metadata (block.json) and provide server-side render callbacks $base = dirname(__DIR__) . '/blocks'; // Register editor script and styles from webpack build $editor_js_url = SWI_FOOT_PLUGIN_URL . 'assets/build/editor-blocks.js'; wp_register_script( 'swi-foot-editor-blocks', $editor_js_url, array('wp-blocks', 'wp-element', 'wp-block-editor', 'wp-components', 'wp-i18n', 'wp-data', 'wp-rich-text'), SWI_FOOT_PLUGIN_VERSION ); $editor_css = SWI_FOOT_PLUGIN_URL . 'assets/blocks.css'; wp_register_style('swi-foot-editor-styles', $editor_css, array(), SWI_FOOT_PLUGIN_VERSION); if ( file_exists( $base . '/standings/block.json' ) ) { register_block_type_from_metadata( $base . '/standings', array( 'render_callback' => array( $this, 'render_standings_block' ), 'editor_script' => 'swi-foot-editor-blocks', 'editor_style' => 'swi-foot-editor-styles' ) ); } if ( file_exists( $base . '/context/block.json' ) ) { register_block_type_from_metadata( $base . '/context', array( 'render_callback' => function($attributes, $content, $block) { // Provide a transparent wrapper but push provider context to a global stack // so inner shortcodes and blocks can read it during rendering. $provided = is_array($attributes['swi_foot_context'] ?? null) ? $attributes['swi_foot_context'] : array(); $post_defaults = function_exists('swi_foot_resolve_context') ? swi_foot_resolve_context(get_the_ID()) : array(); $ctx = array_merge($post_defaults, $provided); global $swi_foot_context_stack; if (!isset($swi_foot_context_stack) || !is_array($swi_foot_context_stack)) { $swi_foot_context_stack = array(); } $swi_foot_context_stack[] = $ctx; // Render inner blocks (so shortcodes executed within this scope can read the global) $rendered = do_blocks($content); // Pop stack array_pop($swi_foot_context_stack); return $rendered; }, 'editor_script' => 'swi-foot-editor-blocks', 'editor_style' => 'swi-foot-editor-styles' ) ); } if ( file_exists( $base . '/schedule/block.json' ) ) { register_block_type_from_metadata( $base . '/schedule', array( 'render_callback' => array( $this, 'render_schedule_block' ), 'editor_script' => 'swi-foot-editor-blocks', 'editor_style' => 'swi-foot-editor-styles' ) ); } /** * Deprecated shortcode-inserter block * Kept for backwards compatibility only */ if ( file_exists( $base . '/shortcode-inserter/block.json' ) ) { register_block_type_from_metadata( $base . '/shortcode-inserter', array( 'render_callback' => array( $this, 'render_shortcode_inserter_block' ), 'editor_script' => 'swi-foot-editor-blocks', 'editor_style' => 'swi-foot-editor-styles', 'deprecated' => true, ) ); } // Register additional blocks (editor-only save shortcodes) if ( file_exists( $base . '/team-data/block.json' ) ) { register_block_type_from_metadata( $base . '/team-data', array( 'editor_script' => 'swi-foot-editor-blocks', 'editor_style' => 'swi-foot-editor-styles' ) ); } if ( file_exists( $base . '/match-roster/block.json' ) ) { register_block_type_from_metadata( $base . '/match-roster', array( 'render_callback' => array( $this, 'render_match_roster_block' ), 'editor_script' => 'swi-foot-editor-blocks', 'editor_style' => 'swi-foot-editor-styles' ) ); } if ( file_exists( $base . '/match-events/block.json' ) ) { register_block_type_from_metadata( $base . '/match-events', array( 'render_callback' => array( $this, 'render_match_events_block' ), 'editor_script' => 'swi-foot-editor-blocks', 'editor_style' => 'swi-foot-editor-styles' ) ); } } public function enqueue_scripts() { wp_enqueue_script('swi-foot-blocks', SWI_FOOT_PLUGIN_URL . 'assets/blocks.js', array('jquery'), SWI_FOOT_PLUGIN_VERSION, true); wp_enqueue_style('swi-foot-blocks', SWI_FOOT_PLUGIN_URL . 'assets/blocks.css', array(), SWI_FOOT_PLUGIN_VERSION); // Localize REST API data for frontend event refresh polling wp_localize_script('swi-foot-blocks', 'swiFootRest', array( 'rest_url' => rest_url('swi-foot/v1/'), 'rest_nonce' => wp_create_nonce('wp_rest') )); } /* public function enqueue_editor_assets() { wp_enqueue_script( 'swi-foot-editor-blocks', SWI_FOOT_PLUGIN_URL . 'assets/editor-blocks.js', array('wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n'), SWI_FOOT_PLUGIN_VERSION ); wp_localize_script('swi-foot-editor-blocks', 'swiFootData', array( 'teams' => $this->get_teams_for_editor(), 'shortcodes' => array( 'match' => __('Full Match Display', 'swi_foot_matchdata'), 'match_home_team' => __('Home Team', 'swi_foot_matchdata'), 'match_away_team' => __('Away Team', 'swi_foot_matchdata'), 'match_date' => __('Match Date', 'swi_foot_matchdata'), 'match_time' => __('Match Time', 'swi_foot_matchdata'), 'match_venue' => __('Venue', 'swi_foot_matchdata'), 'match_score' => __('Score', 'swi_foot_matchdata'), 'match_status' => __('Status', 'swi_foot_matchdata'), 'match_league' => __('League', 'swi_foot_matchdata'), 'match_round' => __('Round', 'swi_foot_matchdata') ) )); } */ public function enqueue_editor_assets() { // Enqueue the registered script handle (register_blocks() registers it on init) if ( ! wp_script_is( 'swi-foot-editor-blocks', 'enqueued' ) ) { wp_enqueue_script( 'swi-foot-editor-blocks' ); } // Enqueue editor styles globally to ensure block wrapper styling applies wp_enqueue_style( 'swi-foot-editor-styles' ); wp_localize_script('swi-foot-editor-blocks', 'swiFootEditorData', array( 'rest_url' => esc_url_raw(rest_url('swi-foot/v1')), 'rest_nonce' => wp_create_nonce('wp_rest'), )); } private function get_teams_for_editor() { $api = new Swi_Foot_API(); $teams = $api->get_teams(); if (is_wp_error($teams) || empty($teams)) { return array(); } $team_options = array(); foreach ($teams as $team) { $team_name = $team['teamName'] ?? ''; $league = $team['teamLeagueName'] ?? ''; // If league name is available, append in parentheses if (!empty($league)) { $team_name .= ' (' . $league . ')'; } $team_options[] = array( 'value' => $team['teamId'] ?? '', 'label' => $team_name ); } return $team_options; } public function render_standings_block($attributes, $content = '', $block = null) { // Resolve context: block context (from provider) overrides post meta defaults $provided = is_object($block) && !empty($block->context['swi-foot/context']) ? $block->context['swi-foot/context'] : null; $ctx = array(); if (is_array($provided)) $ctx = $provided; // Merge with post-level defaults (post meta -> plugin options) $post_defaults = function_exists('swi_foot_resolve_context') ? swi_foot_resolve_context(get_the_ID()) : array(); $ctx = array_merge($post_defaults, $ctx); // Team must come from context only $team_id = $ctx['team_id'] ?? null; if (empty($team_id)) { return '