'; echo '

' . esc_html( $title ) . '

'; } /** * Page shell close, with the shared byline. * * @return void */ public static function close() { echo ''; echo ''; } /** * Brand hero. * * @param array $a { * @type string $eyebrow Small uppercase label. * @type string $title Headline. * @type string $sub Supporting line. * @type string $figure Optional big number (already escaped-safe text). * @type string $figure_label Label under the figure. * @type string $cta_url Optional CTA. * @type string $cta CTA label. * } * @return void */ public static function hero( $a ) { $a = wp_parse_args( $a, array( 'eyebrow' => '', 'title' => '', 'sub' => '', 'figure' => '', 'figure_label' => '', 'cta_url' => '', 'cta' => '', ) ); echo '
'; if ( $a['eyebrow'] ) { echo '

' . esc_html( $a['eyebrow'] ) . '

'; } echo '

' . esc_html( $a['title'] ) . '

'; if ( $a['sub'] ) { echo '

' . esc_html( $a['sub'] ) . '

'; } if ( $a['cta_url'] && $a['cta'] ) { echo '

' . esc_html( $a['cta'] ) . '

'; } echo '
'; if ( '' !== $a['figure'] ) { echo '
' . esc_html( $a['figure'] ) . ''; if ( $a['figure_label'] ) { echo '' . esc_html( $a['figure_label'] ) . ''; } echo '
'; } echo '
'; } /** * A stat tile. * * ⛔ $qualifier is REQUIRED and must be non-empty. There is no overload that * omits it. If a figure genuinely has nothing to qualify it, that itself is * the qualifier — say "not measured yet", never leave it bare. * * @param string $label What the number is. * @param string $value The number, pre-formatted. Empty string renders the empty branch. * @param string $qualifier Chip text: match rate, coverage, or why the value is absent. * @param string $tone Chip tone: pass|low|med|high|info. * @param string $empty Text shown when $value is ''. States the REASON. * @return void */ public static function stat( $label, $value, $qualifier, $tone = 'low', $empty = '' ) { if ( '' === trim( (string) $qualifier ) ) { // Fail visibly in development; never silently render a naked number. $qualifier = __( 'unqualified — report this', 'agentic-commerce-for-woocommerce' ); $tone = 'high'; } echo '
'; echo '

' . esc_html( $label ) . '

'; if ( '' === (string) $value ) { echo '
' . esc_html( $empty ? $empty : __( 'Not measured yet', 'agentic-commerce-for-woocommerce' ) ) . '
'; } else { echo '
' . esc_html( $value ) . '
'; } // chip() escapes both its text and its tone before returning, but the // sniff can't see through the call — and "it's already escaped" is // exactly the reasoning that ships an XSS, so run it through kses too. echo '
' . wp_kses_post( self::chip( $qualifier, $tone, false ) ) . '
'; echo '
'; } /** * A chip. * * @param string $text Label. * @param string $tone pass|low|med|high|info. * @param bool $echo_ Echo or return. * @return string */ public static function chip( $text, $tone = 'low', $echo_ = true ) { $allowed = array( 'pass', 'low', 'med', 'high', 'info' ); $tone = in_array( $tone, $allowed, true ) ? $tone : 'low'; $html = '' . esc_html( $text ) . ''; if ( $echo_ ) { echo wp_kses_post( $html ); } return $html; } /** * Score ring. The value is also rendered as text so colour is never the only * signal and a screen reader gets the number. * * @param int $score 0-100. * @param string $label Accessible label. * @return void */ public static function ring( $score, $label = '' ) { $score = max( 0, min( 100, (int) $score ) ); $offset = 327 - ( 327 * $score / 100 ); echo ''; } /** * A checklist row. * * @param string $state pass|med|high|low. * @param string $title What the check is. * @param string $detail Plain-English diagnosis — what is wrong and what it means. * @param string $action_url Optional fix link. * @param string $action_label Optional fix label. * @return void */ public static function check( $state, $title, $detail, $action_url = '', $action_label = '' ) { $allowed = array( 'pass', 'med', 'high', 'low' ); $state = in_array( $state, $allowed, true ) ? $state : 'low'; echo '
'; echo ''; echo '

' . esc_html( $title ) . '

' . esc_html( $detail ) . '

'; if ( $action_url && $action_label ) { echo '
' . esc_html( $action_label ) . '
'; } echo '
'; } /** * Empty state. * * ⛔ $reason is required. "No data" is not a reason; "we have never seen an AI * crawler on this store" is. * * @param string $headline Short statement of the state. * @param string $reason Why it is that way. * @param string $url Optional single action. * @param string $label Action label. * @return void */ public static function empty_state( $headline, $reason, $url = '', $label = '' ) { if ( '' === trim( (string) $reason ) ) { // Same posture as stat(): fail visibly rather than render a bare // headline, so the docblock's promise is actually true. $reason = __( 'no reason given — report this', 'agentic-commerce-for-woocommerce' ); } echo '
' . esc_html( $headline ) . '' . esc_html( $reason ); if ( $url && $label ) { echo '

' . esc_html( $label ) . '

'; } echo '
'; } /** * A callout. * * @param string $tone info|warn|bad. * @param string $html Already-escaped or kses-safe markup. * @return void */ public static function note( $tone, $html ) { $allowed = array( 'info', 'warn', 'bad' ); $tone = in_array( $tone, $allowed, true ) ? $tone : 'info'; echo '
' . wp_kses_post( $html ) . '
'; } /** * Section heading. * * @param string $title Title. * @param string $sub Supporting line. * @param string $aside Optional right-hand markup (kses-safe). * @return void */ public static function section( $title, $sub = '', $aside = '' ) { echo '

' . esc_html( $title ) . '

'; if ( $sub ) { echo '

' . esc_html( $sub ) . '

'; } echo '
'; if ( $aside ) { echo '
' . wp_kses_post( $aside ) . '
'; } echo '
'; } /** * Money formatter that never invents precision we do not have. * * @param float $amount Amount. * @return string */ public static function money( $amount ) { if ( function_exists( 'wc_price' ) ) { return wp_strip_all_tags( wc_price( (float) $amount ) ); } return number_format_i18n( (float) $amount, 2 ); } }