Dashboard
PHP:
8.4.22
OS:
Linux
User:
provencez
/
/
home
/
provencez
/
www
/
wp-content
/
plugins
/
flexa-block
/
build
/
blocks
/
process-bar
📤 Upload
📝 New File
📁 New Folder
Close
Editing: render.php
<?php /** * Progress Bar block — server-side render. * * CSS is generated at save time by Process_Bar_CSS and printed inline on the * front end. This file outputs the bar itself: a line layout (a track div with a * width-driven fill) or a circle / semi-circle layout (an inline SVG with a track * ring and a stroke-dashoffset-driven fill). The final value is rendered * server-side so the correct figure shows without JavaScript; when the on-scroll * animation is enabled, view.js fills the bar (and counts the number up) from * zero when the block scrolls into view. Colours and typography inherit the theme * / a sensible default fill unless the user overrode them. * * @package Flexa\Block * * @var array $attributes Block attributes. * @var string $content Save content (unused — dynamic block). * @var WP_Block $block Block instance. */ if ( ! defined( 'ABSPATH' ) ) { exit; } // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- $attributes provided by WP block API. use Flexa\Block\HTML_Helpers; $block_id = $attributes['blockId'] ?? ''; $anchor = $attributes['anchor'] ?? ''; $html_tag = HTML_Helpers::get_html_tag( $attributes ); // Layout + value. $bar_type = in_array( $attributes['barType'] ?? 'line', [ 'line', 'circle', 'semicircle' ], true ) ? $attributes['barType'] : 'line'; $value_type = 'absolute' === ( $attributes['valueType'] ?? 'percent' ) ? 'absolute' : 'percent'; $value = (float) ( $attributes['value'] ?? 0 ); $max = (float) ( $attributes['max'] ?? 100 ); $total = 'absolute' === $value_type ? $max : 100.0; $fraction = $total > 0 ? $value / $total : 0.0; $fraction = max( 0.0, min( 1.0, $fraction ) ); $percent = round( $fraction * 100, 2 ); // Title + counter. $show_title = false !== ( $attributes['showTitle'] ?? true ); $title = (string) ( $attributes['title'] ?? '' ); $title_tags = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span', 'div' ]; $title_tag = in_array( $attributes['titleTag'] ?? 'div', $title_tags, true ) ? $attributes['titleTag'] : 'div'; $title_below = 'below' === ( $attributes['titlePosition'] ?? 'above' ); $show_counter = false !== ( $attributes['showCounter'] ?? true ); $divider_char = (string) ( $attributes['dividerChar'] ?? '/' ); // Animation. $animate = false !== ( $attributes['animateFill'] ?? true ); $duration = (int) ( $attributes['fillDuration'] ?? 1500 ); $duration = max( 100, min( 20000, $duration ) ); // SVG ring geometry (mirrors edit.tsx / view.ts). $ring_r = 42.0; $circ = 2 * M_PI * $ring_r; $semi_len = M_PI * $ring_r; $semi_path = 'M ' . ( 50 - $ring_r ) . ' 50 A ' . $ring_r . ' ' . $ring_r . ' 0 0 1 ' . ( 50 + $ring_r ) . ' 50'; $is_line = 'line' === $bar_type; // Title element. $title_html = ''; if ( $show_title && '' !== trim( $title ) ) { $title_html = '<' . $title_tag . ' class="flexa-process-bar__title">' . esc_html( $title ) . '</' . $title_tag . '>'; } // Counter readout: the value span carries data-target so view.js can count it up. $counter_html = ''; if ( $show_counter ) { $target_attr = $animate ? ' data-target="' . esc_attr( (string) $value ) . '"' : ''; if ( 'absolute' === $value_type ) { $counter_html = '<span class="flexa-process-bar__counter">' . '<span class="flexa-process-bar__counter-value"' . $target_attr . '>' . esc_html( (string) $value ) . '</span>' . '<span class="flexa-process-bar__counter-divider"> ' . esc_html( $divider_char ) . ' </span>' . '<span class="flexa-process-bar__counter-max">' . esc_html( (string) $max ) . '</span>' . '</span>'; } else { $counter_html = '<span class="flexa-process-bar__counter">' . '<span class="flexa-process-bar__counter-value"' . $target_attr . '>' . esc_html( (string) $value ) . '</span>' . '<span class="flexa-process-bar__counter-suffix">%</span>' . '</span>'; } } // The bar itself. if ( $is_line ) { $fill_html = '<div class="flexa-process-bar__fill" style="width:' . esc_attr( $percent . '%' ) . '"></div>'; $bar_html = '<div class="flexa-process-bar__bar flexa-process-bar__track">' . $fill_html . '</div>'; $header_html = ( '' !== $title_html || '' !== $counter_html ) ? '<div class="flexa-process-bar__header">' . $title_html . $counter_html . '</div>' : ''; $inner_html = $title_below ? $bar_html . $header_html : $header_html . $bar_html; } else { $is_semi = 'semicircle' === $bar_type; $len = $is_semi ? $semi_len : $circ; $offset = round( $len * ( 1 - $fraction ), 3 ); $dash = round( $len, 3 ); // The SVG is assembled from static tag/attribute names plus numeric geometry // escaped with esc_attr(), so it is safe to output directly. (It is NOT routed // through HTML_Helpers::svg_kses() because that whitelist strips // `stroke-dashoffset` — the attribute that drives the ring fill.) if ( $is_semi ) { $svg = '<svg class="flexa-process-bar__ring" viewBox="0 0 100 58" role="img" aria-hidden="true">' . '<path class="flexa-process-bar__ring-track" d="' . esc_attr( $semi_path ) . '" fill="none" />' . '<path class="flexa-process-bar__ring-fill" d="' . esc_attr( $semi_path ) . '" fill="none" stroke-dasharray="' . esc_attr( (string) $dash ) . '" stroke-dashoffset="' . esc_attr( (string) $offset ) . '" />' . '</svg>'; } else { $svg = '<svg class="flexa-process-bar__ring" viewBox="0 0 100 100" role="img" aria-hidden="true">' . '<circle class="flexa-process-bar__ring-track" cx="50" cy="50" r="' . esc_attr( (string) $ring_r ) . '" fill="none" />' . '<circle class="flexa-process-bar__ring-fill" cx="50" cy="50" r="' . esc_attr( (string) $ring_r ) . '" fill="none" transform="rotate(-90 50 50)" stroke-dasharray="' . esc_attr( (string) $dash ) . '" stroke-dashoffset="' . esc_attr( (string) $offset ) . '" />' . '</svg>'; } $circle_counter = '' !== $counter_html ? '<div class="flexa-process-bar__circle-counter">' . $counter_html . '</div>' : ''; $inner_html = $title_html . '<div class="flexa-process-bar__circle">' . $svg . $circle_counter . '</div>'; } // Wrapper classes + attributes. $classes = [ 'flexa-process-bar', 'flexa-process-bar--' . $bar_type ]; if ( '' !== $block_id ) { $classes[] = 'flexa-process-bar-' . sanitize_html_class( $block_id ); } $classes = HTML_Helpers::build_wrapper_classes( $classes, $attributes ); $wrapper_args = [ 'class' => implode( ' ', $classes ) ]; if ( $anchor ) { $wrapper_args['id'] = sanitize_html_class( $anchor ); } $wrapper_attributes = get_block_wrapper_attributes( $wrapper_args ); $data_attrs = HTML_Helpers::build_data_attrs( $attributes ); // Animation markers for view.js. $anim_attrs = ''; if ( $animate ) { $anim_attrs = ' data-flexa-process-bar data-bar-type="' . esc_attr( $bar_type ) . '" data-duration="' . esc_attr( (string) $duration ) . '"'; } // Lazy background marker. $background = $attributes['background'] ?? []; $is_lazy_bg = ! empty( $background['lazyLoad'] ) && 'image' === ( $background['type'] ?? 'none' ) && '' !== ( $background['image']['url'] ?? '' ); $lazy_marker = $is_lazy_bg ? ' data-flexa-lazy-bg' : ''; printf( '<%1$s %2$s%3$s%4$s%5$s>%6$s</%1$s>', esc_html( $html_tag ), $wrapper_attributes, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built via get_block_wrapper_attributes. $data_attrs, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- keys sanitized, values escaped in helper. $anim_attrs, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static keys, values esc_attr'd above. $lazy_marker, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static literal. $inner_html // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- title/counter esc_html'd, svg svg_kses'd, widths esc_attr'd above. );
Save
Cancel