> */ private static array $render_queue = array(); /** * Whether frontend assets have been enqueued for this page load. * * @var bool */ private static bool $assets_enqueued = false; /** * Registers the shortcode and footer hook. * * @since 1.0.0 * @return void */ public function register(): void { add_shortcode( 'breznflow', array( $this, 'render' ) ); add_action( 'wp_footer', array( $this, 'output_script_data' ), 1 ); } /** * Renders the [breznflow] shortcode. * * @param array $atts Shortcode attributes. * @return string HTML output. */ public function render( $atts ): string { $settings = SettingsPage::get_defaults(); $saved = get_option( 'breznflow_settings', array() ); $settings = array_merge( $settings, $saved ); $atts = shortcode_atts( array( 'id' => 0, 'mode' => '', 'show_title' => '', 'show_infobox' => '', 'show_download' => '', 'show_minimap' => '', 'zoom' => '', 'max_code_lines' => '', 'preset' => '', 'show_share' => '', 'show_embed' => '', 'show_get_json' => '', 'theme' => '', ), $atts, 'breznflow' ); $post_id = (int) $atts['id']; if ( $post_id <= 0 ) { return ''; } $post = get_post( $post_id ); if ( ! $post || 'breznflow_workflow' !== $post->post_type || 'publish' !== $post->post_status ) { return ''; } $raw_json = get_post_meta( $post_id, '_breznflow_raw_json', true ); if ( ! $raw_json ) { return ''; } $workflow = json_decode( $raw_json, true ); if ( ! is_array( $workflow ) ) { return ''; } // Resolve settings from meta, overridden by shortcode attrs. $att_mode = $atts['mode']; $meta_mode = get_post_meta( $post_id, '_breznflow_default_mode', true ); $mode = $att_mode ? $att_mode : ( $meta_mode ? $meta_mode : $settings['default_mode'] ); $mode = in_array( $mode, array( 'visual', 'info', 'compact' ), true ) ? $mode : 'visual'; $zoom = '' !== $atts['zoom'] ? max( 10, min( 200, (int) $atts['zoom'] ) ) : (int) get_post_meta( $post_id, '_breznflow_default_zoom', true ); $show_title = '' !== $atts['show_title'] ? (bool) $atts['show_title'] : (bool) get_post_meta( $post_id, '_breznflow_show_title', true ); $show_infobox = '' !== $atts['show_infobox'] ? (bool) $atts['show_infobox'] : (bool) get_post_meta( $post_id, '_breznflow_show_infobox', true ); // Download: shortcode can only disable if meta has it enabled (not enable if meta disables). $meta_download = (bool) get_post_meta( $post_id, '_breznflow_show_download', true ); $global_download = (bool) $settings['allow_download']; $allow_download = $meta_download && $global_download; if ( '' !== $atts['show_download'] && ! (bool) $atts['show_download'] ) { $allow_download = false; } $allow_share = (bool) $settings['allow_share']; if ( '' !== $atts['show_share'] && ! (bool) $atts['show_share'] ) { $allow_share = false; } // Embed: dual-gate (global + per-post meta). $meta_embed = (bool) get_post_meta( $post_id, '_breznflow_show_embed', true ); $allow_embed = $meta_embed && (bool) $settings['allow_embed']; if ( '' !== $atts['show_embed'] && ! (bool) $atts['show_embed'] ) { $allow_embed = false; } $allow_get_json = (bool) $settings['allow_get_json']; if ( '' !== $atts['show_get_json'] && ! (bool) $atts['show_get_json'] ) { $allow_get_json = false; } $allowed_themes = ThemeRegistry::get_theme_ids(); $att_theme = $atts['theme']; $meta_theme = get_post_meta( $post_id, '_breznflow_default_theme', true ); $theme = $att_theme ? $att_theme : ( $meta_theme ? $meta_theme : ( $settings['default_theme'] ?? 'dark' ) ); $theme = in_array( $theme, $allowed_themes, true ) ? $theme : 'dark'; $meta_minimap = get_post_meta( $post_id, '_breznflow_show_minimap', true ); $show_minimap = '' !== $atts['show_minimap'] ? (bool) $atts['show_minimap'] : ( '' !== $meta_minimap ? (bool) $meta_minimap : true ); $max_code_lines = '' !== $atts['max_code_lines'] ? max( 1, (int) $atts['max_code_lines'] ) : (int) $settings['max_code_lines']; // Increment view count. ViewCounter::increment( $post_id ); // Enqueue assets once. if ( ! self::$assets_enqueued ) { $this->enqueue_assets( $settings ); self::$assets_enqueued = true; } // Queue workflow data for JS output. self::$render_queue[] = array( 'id' => $post_id, 'workflow' => $workflow, 'mode' => $mode, 'zoom' => $zoom ? $zoom : 100, 'autofit_threshold' => (int) ( $settings['autofit_threshold'] ?? 30 ), 'show_title' => $show_title, 'show_infobox' => $show_infobox, 'show_download' => $allow_download, 'show_minimap' => $show_minimap, 'max_code_lines' => $max_code_lines, 'download_label' => esc_html( $settings['download_label'] ), 'download_url' => $allow_download ? esc_url( add_query_arg( 'breznflow_download', $post_id, home_url( '/' ) ) ) : '', 'show_share' => $allow_share, 'show_embed' => $allow_embed, 'show_get_json' => $allow_get_json, 'permalink' => $allow_share ? esc_url( get_permalink() ) : '', 'anchor_id' => 'breznflow-' . $post_id, 'workflow_title' => esc_html( $post->post_title ), 'node_count' => (int) get_post_meta( $post_id, '_breznflow_node_count', true ), 'is_ai_powered' => (bool) get_post_meta( $post_id, '_breznflow_has_ai_nodes', true ), 'blog_name' => esc_html( get_bloginfo( 'name' ) ), 'blog_url' => esc_url( home_url( '/' ) ), 'embed_url' => $allow_embed ? esc_url( add_query_arg( 'breznflow_embed', $post_id, home_url( '/' ) ) ) : '', 'theme' => $theme, ); // Build HTML placeholder. $html = ''; if ( $show_title ) { $html .= '