$fields Submission fields. * @param string $email_body email body. * @since 0.0.1 * @return string */ public function render( $fields, $email_body ) { $message = $this->get_header(); $message .= $this->process_all_data_tag( $fields, $email_body ); return $message . $this->get_footer(); } /** * Render email as raw HTML with no template wrapping. * * Returns the email body exactly as written with only smart tag * processing applied. No wrapper, no container, no layout, no * styles, no footer — true raw HTML output. * * @param array $fields Submission fields. * @param string $email_body Email body content. * @since 2.5.2 * @return string The raw email body with smart tags processed. */ public function render_raw( $fields, $email_body ) { return $this->process_all_data_tag( $fields, $email_body ); } /** * Remove border from the last table row in repeater table HTML. * * This method finds the last element in the provided HTML content * and removes the border-bottom style from all elements within it. * This is used to clean up the visual appearance of repeater tables. * * @param string $content HTML content containing table structure. * * @since 1.11.0 * @return string Modified HTML content with border removed from last row. */ public function remove_border_from_last_tr_td_table( $content ) { // Check if content contains table and tr elements. if ( empty( $content ) || ! preg_match( '/]*>/i', $content ) ) { return $content; } // Find and modify the last tr in one go. $modified_html = preg_replace_callback( '/(.*)(]*>.*?<\/tr>)(?!.*]*style\s*=\s*["\'])([^"\']*?)(["\'][^>]*>)/i', static function( $td_match ) { $start = $td_match[1]; $style = $td_match[2]; // Remove ONLY border-bottom (not border-bottom-width, etc.). $style = preg_replace( '/\s*border-bottom\s*:[^;]*;?/i', '', $style ); $style = is_string( $style ) ? $style : ''; // Clean up multiple semicolons and trim. $style = preg_replace( '/;+/', ';', $style ); $style = is_string( $style ) ? trim( $style, '; ' ) : ''; $end = $td_match[3]; return $start . $style . $end; }, $last_tr ); return $before_last_tr . $modified_tr; }, $content ); return is_string( $modified_html ) ? $modified_html : ''; } /** * Process the {all_data} smart tag in the email body. * * Replaces {all_data} with a formatted HTML table of all submission fields. * * @param array $fields Submission fields. * @param string $email_body Email body content. * @since 2.5.2 * @return string Email body with {all_data} replaced. */ private function process_all_data_tag( $fields, $email_body ) { if ( strpos( $email_body, '{all_data}' ) === false ) { return $email_body; } $excluded_fields = [ 'srfm-honeypot-field', 'g-recaptcha-response', 'srfm-sender-email-field' ]; $td_style = 'font-weight: 500;font-size: 14px;line-height: 20px;padding: 12px;text-align:left;word-break: break-word;border-bottom: 1px solid #E5E7EB;'; ob_start(); ?> $value ) { $values_array = []; if ( is_array( $value ) ) { $values_array = $value; } else { $value = Helper::get_string_value( $value ); } if ( in_array( $field_name, $excluded_fields, true ) || false === str_contains( $field_name, '-lbl-' ) ) { continue; } $label = explode( '-lbl-', $field_name )[1]; $label = explode( '-', $label )[0]; $field_label = $label ? Helper::decode( $label ) : ''; $field_block_name = Helper::get_block_name_from_field( $field_name ); /** * Fires before rendering a field in the all data section of emails. * * This action allows other packages (like Pro, Business) to process and render fields * with custom data structures that the core plugin cannot handle. Since the core plugin * does not know the structure of data from other packages, this action provides a way * for those packages to properly process and display their field data. * * @since 1.11.0 * * @param array $field_data Field data containing: * 'value' => mixed The field value * 'label' => string The field name/key * 'block_name' => string The block type identifier * 'processed_label' => string The human readable label, base64-decoded * out of the submitted field key. Submitter- * controlled and unauthenticated — escape it * for the output context (esc_html() for HTML). */ do_action( 'srfm_before_processing_all_data_field', [ 'value' => $value, 'label' => $field_name, 'block_name' => $field_block_name, 'processed_label' => $field_label, ] ); /** * Filters whether to add a field row in the all data section. * * This filter allows skipping rows for fields that cannot be processed with the * core plugin's structure. Fields from other packages may have complex data structures * that could cause fatal errors if processed normally. Those packages can use the * 'srfm_before_processing_all_data_field' action to render their fields and return false here * to prevent the core plugin from attempting to process them. * * @since 1.11.0 * * @param bool $should_add_field_row Whether to add the field row. Default true. * @param array $field_data Field data containing: * 'value' => mixed The field value * 'field_name' => string The field name/key * 'block_name' => string The block type identifier * * @return bool Whether to add the field row to the table. */ $should_add_field_row = apply_filters( 'srfm_all_data_field_row', true, [ 'value' => $value, 'field_name' => $field_name, 'block_name' => $field_block_name, ] ); if ( true !== $should_add_field_row ) { continue; } $is_array_value = is_array( $value ); if ( $is_array_value ) { $values_array = array_filter( $value, static function( $input_value ) { return ! empty( Helper::get_string_value( $input_value ) ); } ); } else { $value = Helper::get_string_value( $value ); } // Skip if both $value and $values_array are empty. if ( empty( $value ) || ( $is_array_value && empty( $values_array ) ) ) { continue; } ?>
:
1 ) { ?>
$field_name, 'submission_item_value' => $value, ] ); // Validate fallback. if ( empty( $render_url ) ) { ob_start(); ?> [ 'href' => [], 'target' => [], ], 'img' => [ 'src' => [], 'alt' => [], 'width' => [], ], ] ); } else { if ( strpos( Helper::get_string_value( $field_name ), 'srfm-input-multi-choice' ) !== false && strpos( Helper::get_string_value( $value ), '|' ) !== false ) { $options = array_map( 'trim', explode( '|', Helper::get_string_value( $value ) ) ); foreach ( $options as $index => $option ) { $border_style = $index < count( $options ) - 1 ? 'border-bottom:1px solid #E5E7EB;padding-bottom:4px;margin-bottom:4px;' : ''; echo '
' . esc_html( $option ) . '
'; } continue; } if ( is_string( $value ) ) { if ( false !== strpos( $field_name, 'srfm-textarea' ) ) { echo Helper::esc_textarea( html_entity_decode( $value ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- using a custom escaping function. } else { echo false !== strpos( $value, PHP_EOL ) ? wp_kses_post( wpautop( $value ) ) : wp_kses( $value, [ 'a' => [ 'href' => [], 'target' => [], ], ] ); } } } ?>
remove_border_from_last_tr_td_table( $current_table_data ); return str_replace( '{all_data}', $current_table_data, $email_body ); } }