: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
private function get_captcha( $provider ) {
$captcha_providers = $this->get_captcha_providers();
if ( ! isset( $captcha_providers[ $provider ] ) ) {
return $captcha_providers[ $provider ];
* Check if combined upload size exceeds allowed maximum.
* @param \WP_Post $form Form post object.
public function validate_combined_upload_size( $form ) {
$form_id = (int) $form->ID;
$upload_fields = wpforms_get_form_fields( $form, [ 'file-upload' ] );
if ( ! empty( $upload_fields ) && ! empty( $_FILES ) ) {
// Get $_FILES keys generated by WPForms only.
$files_keys = preg_filter( '/^/', 'wpforms_' . $form_id . '_', array_keys( $upload_fields ) );
// Filter uploads without errors. Individual errors are handled by WPForms_Field_File_Upload class.
$files = wp_list_filter( wp_array_slice_assoc( $_FILES, $files_keys ), [ 'error' => 0 ] );
$files_size = array_sum( wp_list_pluck( $files, 'size' ) );
$files_size_max = wpforms_max_upload( true );
if ( $files_size > $files_size_max ) {
// Add new header error preserving previous ones.
$this->errors[ $form_id ]['header'] = ! empty( $this->errors[ $form_id ]['header'] ) ? $this->errors[ $form_id ]['header'] . '<br>' : '';
$this->errors[ $form_id ]['header'] .= esc_html__( 'Uploaded files combined size exceeds allowed maximum.', 'wpforms-lite' );
* Validate the form return hash.
* @param string $hash Base64-encoded hash of form and entry IDs.
* @return array|false False for invalid or form id.
public function validate_return_hash( $hash = '' ) {
$query_args = base64_decode( $hash );
parse_str( $query_args, $output );
if ( wp_hash( $output['form_id'] . ',' . $output['entry_id'] ) !== $output['hash'] ) {
// Get lead and verify it is attached to the form we received with it.
$entry = wpforms()->get( 'entry' )->get( $output['entry_id'], [ 'cap' => false ] );
if ( empty( $entry->form_id ) ) {
if ( $output['form_id'] !== $entry->form_id ) {
'form_id' => absint( $output['form_id'] ),
'entry_id' => absint( $output['form_id'] ),
'fields' => $entry !== null && isset( $entry->fields ) ? $entry->fields : [],
* Check if the confirmation data are valid.
* @param array $data The confirmation data.
protected function is_valid_confirmation( $data ) {
if ( empty( $data['type'] ) ) {
// Confirmation type: redirect, page or message.
return isset( $data[ $type ] ) && ! wpforms_is_empty_string( $data[ $type ] );
* Redirect user to a page or URL specified in the form confirmation settings.
* @param array $form_data Form data and settings.
* @param string $hash Base64-encoded hash of form and entry IDs.
public function entry_confirmation_redirect( $form_data = [], $hash = '' ) {
// Maybe process return hash.
if ( ! empty( $hash ) ) {
$hash_data = $this->validate_return_hash( $hash );
if ( ! $hash_data || ! is_array( $hash_data ) ) {
$this->valid_hash = true;
$this->entry_id = absint( $hash_data['entry_id'] );
$this->fields = json_decode( $hash_data['fields'], true );
$this->form_data = wpforms()->get( 'form' )->get(
absint( $hash_data['form_id'] ),
$this->form_data = $form_data;
// Backward compatibility.
if ( empty( $this->form_data['settings']['confirmations'] ) ) {
$this->form_data['settings']['confirmations'][1]['type'] = ! empty( $this->form_data['settings']['confirmation_type'] ) ? $this->form_data['settings']['confirmation_type'] : 'message';
$this->form_data['settings']['confirmations'][1]['message'] = ! empty( $this->form_data['settings']['confirmation_message'] ) ? $this->form_data['settings']['confirmation_message'] : esc_html__( 'Thanks for contacting us! We will be in touch with you shortly.', 'wpforms-lite' );
$this->form_data['settings']['confirmations'][1]['message_scroll'] = ! empty( $this->form_data['settings']['confirmation_message_scroll'] ) ? $this->form_data['settings']['confirmation_message_scroll'] : 1;
$this->form_data['settings']['confirmations'][1]['page'] = ! empty( $this->form_data['settings']['confirmation_page'] ) ? $this->form_data['settings']['confirmation_page'] : '';
$this->form_data['settings']['confirmations'][1]['redirect'] = ! empty( $this->form_data['settings']['confirmation_redirect'] ) ? $this->form_data['settings']['confirmation_redirect'] : '';
if ( empty( $this->form_data['settings']['confirmations'] ) || ! is_array( $this->form_data['settings']['confirmations'] ) ) {
$confirmations = $this->form_data['settings']['confirmations'];
// Reverse sort confirmations by id to process newer ones first.
krsort( $confirmations );
$default_confirmation_key = min( array_keys( $confirmations ) );
foreach ( $confirmations as $confirmation_id => $confirmation ) {
// Last confirmation should execute in any case.
if ( $default_confirmation_key === $confirmation_id ) {
if ( ! $this->is_valid_confirmation( $confirmation ) ) {
// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName
* Process confirmation filter.
* @param bool $process Whether to process the logic or not.
* @param array $fields List of submitted fields.
* @param array $form_data Form data and settings.
* @param int $id Confirmation ID.
$process_confirmation = apply_filters( 'wpforms_entry_confirmation_process', true, $this->fields, $this->form_data, $confirmation_id );
// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName
if ( $process_confirmation ) {
// Redirect if needed, to either a page or URL, after form processing.
if ( ! empty( $confirmations[ $confirmation_id ]['type'] ) && 'message' !== $confirmations[ $confirmation_id ]['type'] ) {
if ( $confirmations[ $confirmation_id ]['type'] === 'redirect' ) {
$rawurlencode_callback = static function ( $value ) {
return $value === null ? null : rawurlencode( $value );
add_filter( 'wpforms_smarttags_process_field_id_value', $rawurlencode_callback );
$url = wpforms_process_smart_tags( $confirmations[ $confirmation_id ]['redirect'], $this->form_data, $this->fields, $this->entry_id );
remove_filter( 'wpforms_smarttags_process_field_id_value', $rawurlencode_callback );
if ( 'page' === $confirmations[ $confirmation_id ]['type'] ) {
$url = get_permalink( (int) $confirmations[ $confirmation_id ]['page'] );
$url = apply_filters( 'wpforms_process_redirect_url', $url, $this->form_data['id'], $this->fields, $this->form_data, $this->entry_id );
if ( wpforms_is_amp() ) {
/** This filter is documented in wp-includes/pluggable.php */
$url = apply_filters( 'wp_redirect', $url, 302 );
$url = wp_sanitize_redirect( $url );
header( sprintf( 'AMP-Redirect-To: %s', $url ) );
header( 'Access-Control-Expose-Headers: AMP-Redirect-To', false );
'message' => __( 'Redirecting…', 'wpforms-lite' ),
wp_redirect( esc_url_raw( $url ) ); // phpcs:ignore
do_action( 'wpforms_process_redirect', $this->form_data['id'] );
do_action( "wpforms_process_redirect_{$this->form_data['id']}", $this->form_data['id'] );
// Pass a message to a frontend if no redirection happened.
if ( ! empty( $confirmations[ $confirmation_id ]['type'] ) && 'message' === $confirmations[ $confirmation_id ]['type'] ) {
$this->confirmation = $confirmations[ $confirmation_id ];
$this->confirmation_message = $confirmations[ $confirmation_id ]['message'];
if ( ! empty( $confirmations[ $confirmation_id ]['message_scroll'] ) ) {
wpforms()->get( 'frontend' )->confirmation_message_scroll = true;
* Get confirmation message.
* @param array $form_data Form data and settings.
* @param array $fields Sanitized field data.
* @param int $entry_id Entry id.
* @return string Confirmation message.
public function get_confirmation_message( $form_data, $fields, $entry_id ) {
if ( empty( $this->confirmation_message ) ) {
$confirmation_message = wpforms_process_smart_tags( $this->confirmation_message, $form_data, $fields, $entry_id, 'confirmation' );
$confirmation_message = apply_filters( 'wpforms_frontend_confirmation_message', wpautop( $confirmation_message ), $form_data, $fields, $entry_id );
return $confirmation_message;
* Get current confirmation.
public function get_current_confirmation() {
return ! empty( $this->confirmation ) ? $this->confirmation : [];
* Catch the post_max_size overflow.
public function post_max_size_overflow() {
// phpcs:disable WordPress.Security.NonceVerification
if ( empty( $_SERVER['CONTENT_LENGTH'] ) || empty( $_GET['wpforms_form_id'] ) ) {
$form_id = (int) $_GET['wpforms_form_id'];
$total_size = (int) $_SERVER['CONTENT_LENGTH'];
$post_max_size = wpforms_size_to_bytes( ini_get( 'post_max_size' ) );
if ( ! ( $total_size > $post_max_size && empty( $_POST ) && $form_id > 0 ) ) {
// phpcs:enable WordPress.Security.NonceVerification
$error_msg = esc_html__( 'Form has not been submitted, please see the errors below.', 'wpforms-lite' );
$error_msg .= '<br>' . sprintf( /* translators: %1$.3f - total size of the selected files in megabytes, %2$.3f - allowed file upload limit in megabytes.*/
esc_html__( 'The total size of the selected files %1$.3f MB exceeds the allowed limit %2$.3f MB.', 'wpforms-lite' ),
esc_html( $total_size / 1048576 ),
esc_html( $post_max_size / 1048576 )
$this->errors[ $form_id ]['header'] = $error_msg;
* Send entry email notifications.
* @param array $fields List of fields.
* @param array $entry Submitted form entry.
* @param array $form_data Form data and settings.
* @param int $entry_id Saved entry id.
* @param string $context In which context this email is sent.
public function entry_email( $fields, $entry, $form_data, $entry_id, $context = '' ) {
// Check that the form was configured for email notifications.
if ( empty( $form_data['settings']['notification_enable'] ) ) {
* Allow entry email notifications to be disabled.
* @param bool $enabled Whether to send the email.
* @param array $fields List of fields.
* @param array $entry Form submission raw data.
* @param array $form_data Form data and settings.
if ( ! apply_filters( 'wpforms_entry_email', true, $fields, $entry, $form_data ) ) { // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
// Make sure we have and entry id.
if ( empty( $this->entry_id ) ) {
$this->entry_id = (int) $entry_id;
* Filter entry email notifications data.
* @param array $fields List of fields.
* @param array $entry Form submission raw data.
* @param array $form_data Form data and settings.
$fields = apply_filters( 'wpforms_entry_email_data', $fields, $entry, $form_data ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
// Backwards compatibility for notifications before v1.4.3.
if ( empty( $form_data['settings']['notifications'] ) && ! empty( $form_data['settings']['notification_email'] ) ) {
'email' => $form_data['settings']['notification_email'],
'subject' => $form_data['settings']['notification_subject'],
'sender_name' => $form_data['settings']['notification_fromname'],
'sender_address' => $form_data['settings']['notification_fromaddress'],
'replyto' => $form_data['settings']['notification_replyto'],
'message' => '{all_fields}',
$notifications = $form_data['settings']['notifications'];
foreach ( $notifications as $notification_id => $notification ) :
if ( empty( $notification['email'] ) ) {
* Allow entry email notifications to be disabled for a specific notification.
* @param bool $enabled Whether to send the email.
* @param array $fields List of fields.
* @param array $form_data Form data and settings.
* @param int $notification_id Notification ID.
* @param string $context In which context this email is sent.
$process_email = apply_filters( 'wpforms_entry_email_process', true, $fields, $form_data, $notification_id, $context );
if ( ! $process_email ) {
$is_carboncopy_enabled = wpforms_setting( 'email-carbon-copy', false );
// Setup email properties.
$email['subject'] = ! empty( $notification['subject'] ) ?
$notification['subject'] :
sprintf( /* translators: %s - form name. */
esc_html__( 'New %s Entry', 'wpforms-lite' ),
$form_data['settings']['form_title']
$email['address'] = explode( ',', wpforms_process_smart_tags( $notification['email'], $form_data, $fields, $this->entry_id, 'notification-send-to-email' ) );
$email['address'] = array_filter( array_map( 'sanitize_email', $email['address'] ) );
$email['sender_address'] = ! empty( $notification['sender_address'] ) ? $notification['sender_address'] : get_option( 'admin_email' );
$email['sender_name'] = ! empty( $notification['sender_name'] ) ? $notification['sender_name'] : get_bloginfo( 'name' );
$email['replyto'] = ! empty( $notification['replyto'] ) ? $notification['replyto'] : false;
$email['message'] = ! empty( $notification['message'] ) ? $notification['message'] : '{all_fields}';
$email['template'] = ! empty( $notification['template'] ) ? $notification['template'] : '';
if ( $is_carboncopy_enabled && ! empty( $notification['carboncopy'] ) ) {
$email['carboncopy'] = explode( ',', wpforms_process_smart_tags( $notification['carboncopy'], $form_data, $fields, $this->entry_id, 'notification-carboncopy' ) );
$email['carboncopy'] = array_filter( array_map( 'sanitize_email', $email['carboncopy'] ) );
* Filter entry email notifications attributes.
* @param array $email Email attributes.
* @param array $fields List of fields.
* @param array $entry Form submission raw data.
* @param array $form_data Form data and settings.
* @param int $notification_id Notification ID.
$email = apply_filters( 'wpforms_entry_email_atts', $email, $fields, $entry, $form_data, $notification_id ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
$emails = ( new WPForms\Emails\Notifications() )->init( $email['template'] );
$emails->__set( 'form_data', $form_data );
$emails->__set( 'fields', $fields );
$emails->__set( 'notification_id', $notification_id );
$emails->__set( 'entry_id', $this->entry_id );
$emails->__set( 'from_name', $email['sender_name'] );
$emails->__set( 'from_address', $email['sender_address'] );
$emails->__set( 'reply_to', $email['replyto'] );
if ( $is_carboncopy_enabled && ! empty( $email['carboncopy'] ) ) {
$emails->__set( 'cc', $email['carboncopy'] );
* Filter entry email notifications before sending.
* @param object $emails WPForms_WP_Emails instance.
$emails = apply_filters( 'wpforms_entry_email_before_send', $emails );
foreach ( $email['address'] as $address ) {
$emails->send( trim( $address ), $email['subject'], $email['message'] );
* Save entry to database.
* @param array $fields List of form fields.
* @param array $entry User submitted data.
* @param int $form_id Form ID.
* @param array $form_data Prepared form settings.
public function entry_save( $fields, $entry, $form_id, $form_data = [] ) {
$fields = $this->remove_raw_data_before_save( $fields );
* @param array $fields List of form fields.
* @param array $entry Form submission raw data.
* @param int $form_id Form ID.
* @param array $form_data Prepared form settings.
do_action( 'wpforms_process_entry_save', $fields, $entry, $form_id, $form_data );
* Remove raw data from fields before saving.
* This is needed to prevent raw password data from being saved to the database.