| @@ -34,9 +34,13 @@ | ||
| 34 | 34 | // Get params from request. |
| 35 | 35 | $params = $request->get_params(); |
| 36 | 36 | |
| 37 | 37 | // check parama is empty or not and is an array and consist form_data key. |
| 38 | - if ( empty( $params ) || ! is_array( $params ) || ! isset( $params['form_data'] ) || 0 === count( $params['form_data'] ) ) { | |
| 38 | + // count() is guarded by is_array(): a non-array form_data is a TypeError in PHP 8, | |
| 39 | + // and this endpoint is reachable with any JSON value. It falls through to the | |
| 40 | + // invalid_form_data check below instead. | |
| 41 | + if ( empty( $params ) || ! is_array( $params ) || ! isset( $params['form_data'] ) | |
| 42 | + || ( is_array( $params['form_data'] ) && 0 === count( $params['form_data'] ) ) ) { | |
| 39 | 43 | return new WP_Error( |
| 40 | 44 | 'srfm_ai_mapping_missing_form_data', |
| 41 | 45 | __( 'The AI form data is missing. Please try again.', 'sureforms' ), |
| 42 | 46 | [ 'status' => 400 ] |
| @@ -107,8 +111,39 @@ | ||
| 107 | 111 | 'help' => isset( $question['helpText'] ) ? sanitize_text_field( $question['helpText'] ) : '', |
| 108 | 112 | 'slug' => isset( $question['slug'] ) ? sanitize_text_field( $question['slug'] ) : '', |
| 109 | 113 | ] |
| 110 | 114 | ); |
| 115 | + | |
| 116 | + // Forward `placeholder` to the block attrs. Every input-like | |
| 117 | + // block (`input`, `email`, `url`, `phone`, `number`, | |
| 118 | + // `textarea`, `dropdown`) declares a `placeholder` attribute | |
| 119 | + // in its block.json; without this passthrough the value is | |
| 120 | + // silently dropped by the mapper even when the caller (AI, | |
| 121 | + // MCP, or the HTML-form converter) supplied it. | |
| 122 | + if ( isset( $question['placeholder'] ) && is_string( $question['placeholder'] ) && '' !== $question['placeholder'] ) { | |
| 123 | + // Bound the placeholder to 500 chars: other string fields | |
| 124 | + // in this mapper are implicitly bounded by their upstream | |
| 125 | + // schema, but `placeholder` lands here from three call | |
| 126 | + // sites (AI, MCP, HTML converter) and a pathological | |
| 127 | + // caller could push a multi-MB string into the block's | |
| 128 | + // `_srfm_*` post meta. `wp_html_excerpt` strips HTML | |
| 129 | + // first, then truncates safely on word boundaries. | |
| 130 | + $merged_attributes['placeholder'] = wp_html_excerpt( sanitize_text_field( $question['placeholder'] ), 500 ); | |
| 131 | + } | |
| 132 | + | |
| 133 | + // Forward `className` (Additional CSS Class) to the block attrs. | |
| 134 | + // Field blocks inherit core's className support and render it onto the | |
| 135 | + // field wrapper (see inc/fields/base.php::set_properties()). Lands from | |
| 136 | + // multiple callers (AI, MCP, HTML converter), so sanitize each token. | |
| 137 | + if ( isset( $question['className'] ) && is_string( $question['className'] ) && '' !== $question['className'] ) { | |
| 138 | + $classes = preg_split( '/\s+/', trim( $question['className'] ) ); | |
| 139 | + if ( is_array( $classes ) ) { | |
| 140 | + $clean = implode( ' ', array_filter( array_map( 'sanitize_html_class', $classes ) ) ); | |
| 141 | + if ( '' !== $clean ) { | |
| 142 | + $merged_attributes['className'] = $clean; | |
| 143 | + } | |
| 144 | + } | |
| 145 | + } | |
| 111 | 146 | |
| 112 | 147 | // Apply filter to modify field type. |
| 113 | 148 | $field_type = apply_filters( 'srfm_ai_field_modify_field_type', $question['fieldType'], $question, $is_conversational, $form_type ); |
| 114 | 149 | |