| @@ -44,14 +44,30 @@ | ||
| 44 | 44 | $form_id = (int) $form->ID; |
| 45 | 45 | $campaign_id = (int) $campaign_id; |
| 46 | 46 | $unique_form_id = 'suredonation-form-' . $form_id . '-' . wp_rand(); |
| 47 | 47 | $form_style = Form_Styling::get_style_attr( $form_id ); |
| 48 | + $custom_css = Form_Custom_CSS::get_style_block( $form_id ); | |
| 48 | 49 | $nonce_action = Helper::get_donation_nonce_action( $campaign_id ); |
| 49 | 50 | $blocks = parse_blocks( $form->post_content ); |
| 50 | 51 | |
| 52 | + // Marker class when default styling is disabled, so custom CSS can | |
| 53 | + // target the unstyled state (get_style_attr already returned ''). | |
| 54 | + $container_classes = 'sd-form-container'; | |
| 55 | + if ( Form_Styling::is_default_styling_disabled( $form_id ) ) { | |
| 56 | + $container_classes .= ' sd-styling-none'; | |
| 57 | + } | |
| 58 | + | |
| 51 | 59 | ob_start(); |
| 52 | 60 | ?> |
| 53 | - <div id="<?php echo esc_attr( $unique_form_id ); ?>" class="sd-form-container" data-form-id="<?php echo esc_attr( (string) $form_id ); ?>" data-campaign-id="<?php echo esc_attr( (string) $campaign_id ); ?>"<?php echo '' !== $form_style ? ' style="' . esc_attr( $form_style ) . '"' : ''; ?>> | |
| 61 | + <div id="<?php echo esc_attr( $unique_form_id ); ?>" class="<?php echo esc_attr( $container_classes ); ?>" data-form-id="<?php echo esc_attr( (string) $form_id ); ?>" data-campaign-id="<?php echo esc_attr( (string) $campaign_id ); ?>"<?php echo '' !== $form_style ? ' style="' . esc_attr( $form_style ) . '"' : ''; ?>> | |
| 62 | + <?php | |
| 63 | + // Generated markup whose CSS is already sanitized by | |
| 64 | + // Form_Custom_CSS::sanitize(). It must not go through | |
| 65 | + // Helper::get_allowed_form_html() like the block output below: that | |
| 66 | + // allowlist permits `style` attributes but not the `style` tag, so kses | |
| 67 | + // would strip the whole block. | |
| 68 | + echo $custom_css; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 69 | + ?> | |
| 54 | 70 | <form class="sd-form" method="post"> |
| 55 | 71 | <?php wp_nonce_field( $nonce_action, 'suredonation_nonce' ); ?> |
| 56 | 72 | <input type="hidden" name="form_id" value="<?php echo esc_attr( (string) $form_id ); ?>"> |
| 57 | 73 | <input type="hidden" name="campaign_id" value="<?php echo esc_attr( (string) $campaign_id ); ?>"> |
| @@ -69,9 +85,9 @@ | ||
| 69 | 85 | // finally to the end of the form. The anchor may be nested inside a |
| 70 | 86 | // layout block (Group/Columns), so match the top-level block that either |
| 71 | 87 | // is, or contains, the anchor. |
| 72 | 88 | $privacy_fields = \SureDonation\Inc\Privacy\Privacy_Frontend::render_form_fields(); |
| 73 | - $privacy_anchor = self::block_tree_contains( $blocks, 'suredonation/donate-button' ) ? 'suredonation/donate-button' : 'suredonation/payment'; | |
| 89 | + $privacy_anchor = Helper::block_tree_contains( $blocks, 'suredonation/donate-button' ) ? 'suredonation/donate-button' : 'suredonation/payment'; | |
| 74 | 90 | $privacy_injected = false; |
| 75 | 91 | foreach ( $blocks as $block ) { |
| 76 | 92 | if ( empty( $block['blockName'] ) ) { |
| 77 | 93 | continue; |
| @@ -76,15 +92,17 @@ | ||
| 76 | 92 | if ( empty( $block['blockName'] ) ) { |
| 77 | 93 | continue; |
| 78 | 94 | } |
| 79 | 95 | $is_anchor = $block['blockName'] === $privacy_anchor |
| 80 | - || ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) && self::block_tree_contains( $block['innerBlocks'], $privacy_anchor ) ); | |
| 96 | + || ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) && Helper::block_tree_contains( $block['innerBlocks'], $privacy_anchor ) ); | |
| 81 | 97 | if ( ! $privacy_injected && '' !== $privacy_fields && $is_anchor ) { |
| 82 | 98 | echo wp_kses( $privacy_fields, Helper::get_allowed_form_html() ); |
| 83 | 99 | $privacy_injected = true; |
| 84 | 100 | } |
| 85 | 101 | $block['attrs']['formId'] = $form_id; |
| 86 | - echo wp_kses( render_block( $block ), Helper::get_allowed_form_html() ); | |
| 102 | + // Allow the data: protocol so a lazy-load optimizer's inline SVG | |
| 103 | + // placeholder (Image block) survives this second kses pass. | |
| 104 | + echo wp_kses( render_block( $block ), Helper::get_allowed_form_html(), array_merge( wp_allowed_protocols(), [ 'data' ] ) ); | |
| 87 | 105 | } |
| 88 | 106 | if ( ! $privacy_injected && '' !== $privacy_fields ) { |
| 89 | 107 | echo wp_kses( $privacy_fields, Helper::get_allowed_form_html() ); |
| 90 | 108 | } |
| @@ -97,29 +115,6 @@ | ||
| 97 | 115 | </div> |
| 98 | 116 | <?php |
| 99 | 117 | $output = ob_get_clean(); |
| 100 | 118 | return false !== $output ? $output : ''; |
| 101 | - } | |
| 102 | - | |
| 103 | - /** | |
| 104 | - * Whether a (possibly nested) block tree contains a block of the given name. | |
| 105 | - * | |
| 106 | - * @since 1.2.0 | |
| 107 | - * @param array<int|string, mixed> $blocks Parsed blocks (parse_blocks output). | |
| 108 | - * @param string $target Block name to look for. | |
| 109 | - * @return bool | |
| 110 | - */ | |
| 111 | - private static function block_tree_contains( $blocks, $target ) { | |
| 112 | - foreach ( $blocks as $block ) { | |
| 113 | - if ( ! is_array( $block ) ) { | |
| 114 | - continue; | |
| 115 | - } | |
| 116 | - if ( isset( $block['blockName'] ) && $block['blockName'] === $target ) { | |
| 117 | - return true; | |
| 118 | - } | |
| 119 | - if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) && self::block_tree_contains( $block['innerBlocks'], $target ) ) { | |
| 120 | - return true; | |
| 121 | - } | |
| 122 | - } | |
| 123 | - return false; | |
| 124 | 119 | } |
| 125 | 120 | } |