` block of its own * and **loads no dashicons**, so class hooks and icon fonts are both unavailable. */ class ProElementPreview { /** * Element types this class can mock. * * @return array */ public static function supported_types(): array { return [ 'donors_wall', 'faq', 'video' ]; } /** * Render a mock preview for a Pro element. * * @param string $type Element type. * @param array $settings Element settings as saved in the layout. Honoured * where practical so a downgraded campaign still * shows the author's real configuration. * @param bool $is_preview Must be strictly true. See the class docblock. * @return string HTML, or '' when not a builder preview / unsupported type. */ public static function render( string $type, array $settings, bool $is_preview ): string { if ( true !== $is_preview ) { return ''; } if ( ! in_array( $type, self::supported_types(), true ) ) { return ''; } // Whether the mock needs the "sample data" disclosure under it. Donors // Wall invents donors and FAQ echoes the author's own questions back at a // sample scale, so both must say so. The Video mock displays no data at // all — it is a drawn poster frame with no names, figures or copy that // could be mistaken for the user's — so the note has nothing to disclose // and only adds a line of grey text under the artwork. $show_note = true; switch ( $type ) { case 'donors_wall': $body = self::donors_wall( $settings ); $label = __( 'Donors Wall', 'better-payment' ); break; case 'faq': $body = self::faq( $settings ); $label = __( 'FAQ', 'better-payment' ); break; default: $body = self::video( $settings ); $label = __( 'Video', 'better-payment' ); $show_note = false; break; } return self::wrap( $body, $label, $show_note ); } /** * Chrome around every mock: a dashed frame plus a PRO ribbon, so a demo is * never mistaken for the real thing. * * @param string $body Already-escaped inner HTML. * @param string $label Element label. * @param bool $show_note Whether to print the "sample data" disclosure. * Defaults true: a mock that shows fabricated data * must say so, and that is the common case. Only the * Video frame opts out, because it displays no data * to disclose. The PRO ribbon is NOT optional — it is * what stops any mock being read as the real element. * @return string */ private static function wrap( string $body, string $label, bool $show_note = true ): string { $frame = 'position:relative;border:1px dashed #c3c4c7;border-radius:8px;' . 'padding:28px 16px 16px;margin:0 0 4px;background:#fff;'; // Pro-orange gradient — the exact fill of the "Get PRO to Unlock" button // (`.bp-lc-hotspot__pro-lock-btn`), so the ribbon reads as the same Pro // upsell affordance rather than a second, unrelated brand colour. $ribbon = 'position:absolute;top:0;left:0;display:inline-flex;align-items:center;gap:6px;' . 'background:linear-gradient(135deg,#f6a821,#ec6a2b);color:#fff;font-size:10px;font-weight:700;letter-spacing:.06em;' . 'text-transform:uppercase;padding:3px 10px;border-radius:8px 0 8px 0;'; $note = 'margin:12px 0 0;font-size:11px;line-height:1.5;color:#787c82;text-align:center;'; ob_start(); ?>

$4,820 37

+

> */ private static function sample_faq_items(): array { return [ [ 'question' => __( 'How will my donation be used?', 'better-payment' ), 'answer' => __( 'Your own answer appears here. Add the questions donors ask most, each with a short, direct answer.', 'better-payment' ), ], [ 'question' => __( 'Is my payment secure?', 'better-payment' ), 'answer' => __( 'Sample answer. Each question opens and closes on your live campaign.', 'better-payment' ), ], [ 'question' => __( 'Can I donate any amount?', 'better-payment' ), 'answer' => __( 'Sample answer. Add, remove and reorder questions as your campaign needs.', 'better-payment' ), ], ]; } /** * A poster frame, never a real embed. * * Rendering the actual `