ajax contact form not submit message

About sending emails:

  • wp_mail by default utilizes default PHP’s mailing setting, and PHP by default uses sendmail service so if you don’t have one functioning on localhost you’ll not be able to sendemails, you can use something like MailHog – to capture send emails for you on localhost and you’ll actually will be able to see those messages – it’s really good option for debugging.

  • on live sites host companies often just disable sendmail because they don’t want their IP addresses get blacklisted because of probably spam sent from their client’s hosted sites. So what you can do is you can install https://wordpress.org/plugins/wp-mail-smtp/ plugin and use your own let’s say gmail account to send emails through, for testing it will work well. But for production usage it’s still better to use some mail sending services like MailGun\SendGrid etc. While these services are paid they take care for you of issues for mass mailing sends.

And let’s dig into how you can improve your code so it will help you to diagnose what’s going on.

First if you make an ajax handler it’s good to leverage sending data back to js, via wp_send_json_success() and wp_send_json_error() functions so your $.ajax will go to .done() only if you’ve really returned successful response, with HTTP code 200, and it will go to .fail() if your php code returned an error.

Let’s see how our ajax handler may look like.

/**
 * Form contatti front-end
 */
function submit_contact_form() {
    if ( ! isset( $_POST['message_hash'] ) || ! wp_verify_nonce( $_POST['message_hash'], 'submit_message' ) ) {
        wp_send_json_error( array( 'error' => 'wrong_nonce' ) );
        exit;
    }
    // Customer contacts and message
    $email    = sanitize_email( $_POST['email'] );
    $fname    = sanitize_text_field( $_POST['fname'] );
    $lname    = sanitize_text_field( $_POST['lname'] );
    $phone    = sanitize_text_field( $_POST['phone'] );
    $subject  = sanitize_text_field( $_POST['subject'] );
    $message  = "Hai ricevuto un nuovo messaggio da: $fname $lname \n";
    $message .= "Puoi contattare l'utente utilizzando il numero:  $phone \n";
    $message .= "Testo del messaggio: \n";
    $message .= sanitize_textarea_field( $_POST['message'] );
    // send ticket
    $to        = '[email protected]';
    $headers[] = "From: $fname $lname <$email>";
    $mail_result = wp_mail( $to, $subject, $message, $headers );
    if( $mail_result ) {
        wp_send_json_success(['message'=>'mail_sent']);
    }else {
        wp_send_json_error(['error'=>'email_sending_error']);
    }
}
add_action( 'wp_ajax_send_message', 'submit_contact_form' );
add_action( 'wp_ajax_nopriv_send_message', 'submit_contact_form' );

And JS code which will handle it gracefully, to not blindly believe that if data was sent they were processed.

$('#submit-form').on('click', function(e){
    e.preventDefault();
    var data = $('#message-form').serialize();
    $.ajax({
        type: 'POST',
        url: wpcf.ajaxurl,
        data: data,
    }).done(function handleAjaxSuccess(response){
        console.log('success', response);
        $('#message-notice').css({'display':'block'});
        $('#message-form')[0].reset();
        setTimeout(function(){
            $('#message-notice').css({'display':'none'});
        }, 3000);
        console.log('Done!');
    }).fail(function handleAjaxError(jqXhr,errorText){
        console.warn('Error'); // just for you to see what's going on, here you can also display some error message to user.
        console.warn(errorText);
        console.warn(jqXhr);
    });
});

I’ve used named js functions so in case of error you’ll get better understanding where it has happened rather then relying on js anonymous functions.

And one small edit for localize script: It’s always better to first enqueue script then localize it.

wp_enqueue_script('main');
wp_localize_script('main', 'wpcf', $localize);

You can also simplify it to:

function _res() {
    wp_enqueue_style( 'my-plugin-style', get_template_directory_uri() . '/style.min.css' );
    wp_enqueue_script( 'my-plugin-main', get_template_directory_uri() . '/assets/js/main.js', array( 'jquery' ), null, true );
    wp_localize_script(
        'my-plugin-main',
        'wpcf',
        array(
            'ajaxurl' => admin_url( 'admin-ajax.php' ),
        )
    );
}
add_action( 'wp_enqueue_scripts', '_res' );

Also don’t forget to set unique handle names for css and js your are linking, because main is something really broad and you can override either some other plugin’s js\css code linkage or wp core’s. And it’s definitely not the thing we might want to do.

After making those changes you’ll be able to diagnose what’s going on in browser’s console seeing messages returned to you by php.