// Use a switch-case statement to handle specific field types.
switch ( $field['type'] ) {
$field_name = ! empty( $field['label'] ) ? str_repeat( '—', 3 ) . ' ' . $field['label'] . ' ' . str_repeat( '—', 3 ) : null;
$field_val = ! empty( $field['description'] ) ? $field['description'] : '';
// Skip if the position is 'bottom'.
if ( ! empty( $field['position'] ) && $field['position'] === 'bottom' ) {
$title = ! empty( $field['title'] ) ? $field['title'] : esc_html__( 'Page Break', 'wpforms-lite' );
$field_name = str_repeat( '—', 6 ) . ' ' . $title . ' ' . str_repeat( '—', 6 );
$field_name = ! empty( $field['name'] ) ? $field['name'] : esc_html__( 'HTML / Code Block', 'wpforms-lite' );
$field_val = $field['code'];
$field_name = esc_html__( 'Content', 'wpforms-lite' );
$field_val = wpforms_esc_richtext_field( $field['content'] );
return [ $field_name, $field_val ];
* Get the email reply to the address.
* This method has been overridden to add support for the Reply-to Name.
public function get_reply_to_address() {
$reply_to = $this->__get( 'reply_to' );
if ( ! empty( $reply_to ) ) {
// Optional custom format with a Reply-to Name specified: John Doe <john@doe.com>
// - starts with anything,
// - ends with <anything> (expected to be an email, validated later).
$regex = '/^(.+) (<.+>)$/';
if ( preg_match( $regex, $reply_to, $matches ) ) {
$reply_to_name = $this->sanitize( $matches[1] );
$reply_to = trim( $matches[2], '<> ' );
$reply_to = $this->process_tag( $reply_to, 'notification-reply-to' );
if ( ! is_email( $reply_to ) ) {
$reply_to = "$reply_to_name <{$reply_to}>";
* Filter the email reply-to address.
* @param string $reply_to Email reply-to address.
* @param object $this Instance of the Notifications class.
return apply_filters( 'wpforms_emails_notifications_get_reply_to_address', $reply_to, $this );
* This method has been overridden to add support for processing smart tags.
* @param string $input String to sanitize and process for smart tags.
* @param string $context Context of the smart tag.
public function sanitize( $input = '', $context = 'notification' ): string {
return wpforms_decode_string( $this->process_tag( $input, $context ) );
* Get the email content type.
* This method has been overridden to better declare the email template assigned to each notification.
public function get_content_type() {
$content_type = 'text/html';
if ( Helpers::is_plain_text_template( $this->current_template ) ) {
$content_type = 'text/plain';
* Filter the email content type.
* @param string $content_type The email content type.
* @param Notifications $this An instance of the "Notifications" class.
$content_type = apply_filters( 'wpforms_emails_notifications_get_content_type', $content_type, $this );
$this->__set( 'content_type', $content_type );
// Return the content type.
* Check if all emails are disabled.
public function is_email_disabled() {
* Filter to control email disabling.
* The "Notifications" class is designed to mirror the properties and methods
* provided by the "WPForms_WP_Emails" class for backward compatibility.
* @param bool $is_disabled Whether to disable all emails.
* @param Notifications $this An instance of the "Notifications" class.
return (bool) apply_filters( // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
'wpforms_disable_all_emails',
* Get the default field name as a fallback.
* @param int $field_id Field ID.
private function get_default_field_name( $field_id ) {
return sprintf( /* translators: %1$d - field ID. */
esc_html__( 'Field ID #%1$s', 'wpforms-lite' ),
wpforms_validate_field_id( $field_id )
* Wrap content in the 'tr' tag on the first level depth.
* @param string $content Processed smart tag content.
private function fix_table_body_markup( string $content ): string {
$content = trim( $content );
libxml_use_internal_errors( true );
$dom = new DOMDocument( '1.0', 'UTF-8' );
// We should encode `<` and `>` symbols to prevent unexpected HTML tags.
$html = '<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body>' . wp_pre_kses_less_than( $content ) . '</body></html>';
$dom->loadHTML( $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOERROR );
$body = $dom->getElementsByTagName( 'body' )->item( 0 );
return $this->wrap_content_with_row( $content );
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
foreach ( $body->childNodes as $node ) {
$node_text = $node->nodeType === XML_TEXT_NODE ? $node->nodeValue : $dom->saveHTML( $node );
if ( ! property_exists( $node, 'tagName' ) || $node->tagName !== 'tr' ) {
$content_to_wrap .= $node_text;
// Wrap content before the `tr` tag.
$modified_content .= $this->wrap_content_with_row( $content_to_wrap );
// Save the `tr` tag without wrapping.
$modified_content .= $node_text;
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
if ( ! wpforms_is_empty_string( $content_to_wrap ) ) {
$modified_content .= $this->wrap_content_with_row( $content_to_wrap );
return $modified_content;
* Wrap content to the `tr` tag.
* @param string $content Content.
private function wrap_content_with_row( string $content ): string {
$content = trim( $content );
if ( wpforms_is_empty_string( $content ) ) {
return sprintf( '<tr class="smart-tag"><td class="field-name field-value" colspan="2">%s</td></tr>', $content );
* Get the list of available email templates.
* Given a template name, this method will return the template data.
* If no template name is provided, all available templates will be returned.
* Templates will go through a conditional check to make sure they are available for the current plugin edition.
* @param string $template Template name. If empty, all available templates will be returned.
public static function get_available_templates( $template = '' ) {
$templates = self::get_all_templates();
// Filter the list of available email templates based on the edition of WPForms.
if ( ! wpforms()->is_pro() ) {
$templates = array_filter(
static function ( $instance ) {
return ! $instance['is_pro'];
return $templates[ $template ] ?? $templates;
* Get the list of all email templates.
* Given the name of a template, this method will return the template data.
* If the template is not found, all available templates will be returned.
* @param string $template Template name. If empty, all templates will be returned.
public static function get_all_templates( $template = '' ) {
'name' => esc_html__( 'Classic', 'wpforms-lite' ),
'path' => Templates\Classic::class,
'name' => esc_html__( 'Compact', 'wpforms-lite' ),
'path' => Templates\Compact::class,
'name' => esc_html__( 'Modern', 'wpforms-lite' ),
'name' => esc_html__( 'Elegant', 'wpforms-lite' ),
'path' => Elegant::class,
'name' => esc_html__( 'Tech', 'wpforms-lite' ),
'name' => esc_html__( 'Plain Text', 'wpforms-lite' ),
'path' => Templates\Plain::class,
// Make sure the current user can preview templates.
if ( wpforms_current_user_can() ) {
// Add a preview key to each template.
foreach ( $templates as $key => &$tmpl ) {
$tmpl['preview'] = wp_nonce_url(
'wpforms_email_preview' => '1',
'wpforms_email_template' => $key,
Preview::PREVIEW_NONCE_NAME
// Make sure to unset the reference to avoid unintended changes later.
return $templates[ $template ] ?? $templates;
* Get multiple field formatted value.
* @param string $value Field value.
* @param int $field_id Field ID.
* @param array $fields List of fields.
* @param string $field_key Field key to get value from.
* @noinspection PhpUnusedParameterInspection
public function get_multi_field_formatted_value( string $value, int $field_id, array $fields, string $field_key ): string {
$field_type = $fields[ $field_id ]['type'] ?? '';
// Leave early if the field type is not a multi-field.
if ( ! in_array( $field_type, wpforms_get_multi_fields(), true ) ) {
// Leave early if the template is set to plain text.
if ( Helpers::is_plain_text_template( $this->current_template ) ) {
// Replace <br/> tags with line breaks.
return str_replace( '<br/>', "\r\n", $value );
return str_replace( [ "\r\n", "\r", "\n" ], '<br/>', $value );
* Get the current template name.
public function get_current_template(): string {
return $this->current_template;
* Get the current field template markup.
public function get_current_field_template(): string {
return $this->field_template;