Using preventDefault(); with a php form

Viewed 2050

I'm pretty new to programming in the middle of 2 Udemy courses. one for Javascript and one for PHP, anyways I'm not sure how to tackle this problem. On my site, if you click the Sign-Up link, the nav slides out a sign up form. the problem is if the input has an error like it's blank or something it closes the nav automatically instead of just displaying the error. so I have to click Signup again to see the error. I can't make the nav stay open. So I found a possible solution to my problem called preventDefault(); which makes the form not reload the page finally, but it now it does not submit the data and display error messages now. My site is a WordPress site if that makes a difference. All my google answers I've looked at say preventDefault(); is the answer but if you look at this from w3schools.com.

The preventDefault() method cancels the event if it is cancelable, meaning that the default action that belongs to the event will not occur.

For example, this can be useful when:

Clicking on a "Submit" button, prevent it from submitting a form

so I'm very confused about how this function can fix my problem. here's my code

HTML / PHP

        <?php
        global $wpdb, $user_ID;
        //Check whether the user is already logged in 
        if ( !$user_ID ) {
            // Default page shows register form. 
            // To show Login form set query variable action=login
            $action = ( isset( $_GET[ 'action' ] ) ) ? $_GET[ 'action' ] : 0;
            // Login Page
            if ( $action === "login" ) {
        ?>
        <?php
        $login = ( isset( $_GET[ 'login' ] ) ) ? $_GET[ 'login' ] : 0;
        if ( $login === "failed" ) {
            echo '<div class="col-12 register-error"><strong>ERROR:</strong> Invalid username and/or password.</div>';
        } elseif ( $login === "empty" ) {
            echo '<div class="col-12 register-error"><strong>ERROR:</strong> Username and/or Password is empty.</div>';
        } elseif ( $login === "false" ) {
            echo '<div class="col-12 register-error"><strong>ERROR:</strong> You are logged out.</div>';
        }
        ?>
        <div class="col-md-5">
            <?php
            $args = array(
                'redirect' => home_url(),
            );
            wp_login_form( $args );
            ?>
            <p class="text-center"><a class="mr-2" href="<?php echo wp_registration_url(); ?>">Register Now</a> <span clas="mx-2">·</span><a class="ml-2" href="<?php echo wp_lostpassword_url( ); ?>" title="Lost Password">Lost Password?</a></p>
        </div>
        <?php
        } else { // Register Page ?>
        <?php
        if ( $_POST ) {
            $error = 0;
            $username = esc_sql( $_REQUEST[ 'username' ] );
            if ( empty( $username ) ) {
                echo '<div class="col-12 register-error">User name should not be empty.</div>';
                $error = 1;
            }
            $email = esc_sql( $_REQUEST[ 'email' ] );
            if ( !preg_match( "/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/", $email ) ) {
                echo '<div class="col-12 register-error">Please enter a valid email.</div>';
                $error = 1;
            }
            if ( $error == 0 ) {
                $random_password = wp_generate_password( 12, false );
                $status = wp_create_user( $username, $random_password, $email );
                if ( is_wp_error( $status ) ) {
                    echo '<div class="col-12 register-error">Username already exists. Please try another one.</div>';
                } else {
                    $from = get_option( 'admin_email' );
                    $headers = 'From: ' . $from . "\r\n";
                    $subject = "Registration successful";
                    $message = "Registration successful.\nYour login details\nUsername: $username\nPassword: $random_password";
                    // Email password and other details to the user
                    wp_mail( $email, $subject, $message, $headers );
                    echo "Please check your email for login details.";
                    $error = 2; // We will check for this variable before showing the sign up form. 
                }
            }
        }
        if ( $error != 2 ) {
        ?>
        <?php if(get_option('users_can_register')) { ?>
        <div class="col-md-5 manual-register-form">
            <form id="sign-up" action="index.php" method="post">
                <p>
                    <label for="user_login">Username</label>
                    <input type="text" name="username" class="register-input mb-4" value="<?php if( ! empty($username) ) echo $username; ?>" />
                    <br />
                </p>
                <p>
                    <label for="user_email">Email</label>
                    <br>
                    <input type="text" name="email" class="register-input mb-4" value="<?php if( ! empty($email) ) echo $email; ?>" />
                    <br>
                </p>
                <input type="submit" id="register-submit-btn" class="mb-4" name="submit" value="Sign Up" />
            </form>
            <p>Already have an account? <a href="index.php">Login</a></p>
        </div>
        <?php
        } else {
            echo "Registration is currently disabled. Please try again later.";
        }
        }
        ?>
        <?php
        }
        } else {
        ?>
        <p>You are logged in. Click <a href="<?php bloginfo('wpurl'); ?>">here to go home</a></p>
        <?php } ?>

JQuery

 var frm = jQuery('#sign-up');
    frm.submit(function (ev) {
        jQuery.ajax({
            type: frm.attr('method'),
            url: frm.attr('action'),
            data: frm.serialize(),
            success: function (data) {
                alert('ok');
            }
        });

        ev.preventDefault();
    });

functions.php

function hideout_scripts() {
    wp_enqueue_script( 'sign-up', get_template_directory_uri() . '/js/login-signup-jquery.js', array('jquery'), '1.0.0', true );
    }
add_action( 'wp_enqueue_scripts', 'hideout_scripts' );
1 Answers

The Event.preventDefault() could work if you would first check your fields on the frontend and / or use AJAX to send the fields to the backend. Now there are multiple options to consider.

Required input fields

HTML5 <input> elements already have some built in validation. With the right attributes they can stop a user from submitting a form if they have they don't meet the requirements for submitting.

Adding a required attribute will let the browser know that this field has to be filled in mandatorily. In combination with a pattern attribute you could add complexity to the requirement, like omitting specific symbols or requiring only alphanumeric characters.

The type attribute can also help here. For example, you have an email field. With the type="email" attribute you can tell the browser that this needs to be a valid email.

<form id="sign-up" action="index.php" method="post">
  <label for="user-name">Username</label>
  <input id="user-name" type="text" name="username" required/>

  <label for="user-email">Email</label>
  <input id="user-email" type="email" name="email" required/>

  <input type="submit" name="submit" value="Sign Up" />
</form>

Though, inputs can be manipulated by the user by inspecting the element. So don't rely solely on the validity of these attributes.

Check all available input types here.


JavaScript Validation

Like validating in PHP you can also validate in JavaScript, or a combination of both, but we'll get to that later on.

Some of the logic, like checking the username and email fields can be transported over to JavaScript. This is similar to the method above with the attributes but is safer to use because you are in full control, nobody can mess with this behavior.

You will have to check each individual field if they are valid and manually add a message if they don't.

var $form = $('#sign-up');
var regex = /^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/g;
var error = {
  emptyUserName: 'User name should not be empty.',
  invalidEmail: 'Please enter a valid email.',
}

// Listen for the submit event.
$form.on('submit', function(event) {
  // Create a flag to check form validity with.
  var isValidForm = true;
  
  // Select the input fields.
  var $userName = $('#user-name');
  var $userEmail = $('#user-email');
  
  // Check the user name for empty string.
  if ($userName.val() === '') {
    console.log(error.emptyUserName);
    isValidForm = false;
  }
  
  // Check the email for a valid email with the regex.
  if (!regex.test($userEmail.val())) {
    console.log(error.invalidEmail);
    isValidForm = false;
  }
  
  // If the form is not completely valid, stop.
  // Otherwise, do nothing and let the form submit.
  if (!isValidForm) {
    event.preventDefault();
    return;
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form id="sign-up" action="index.php" method="post">
  <label for="user-name">Username</label>
  <input id="user-name" type="text" name="username"/>

  <label for="user-email">Email</label>
  <input id="user-email" type="email" name="email"/>

  <input type="submit" name="submit" value="Sign Up" />
</form>

The only problem here is checking doing backend checks, like the if the user already exists. You were on the right path by using AJAX to do that, but it needs to be improved.

AJAX Request

So first thing is that you'll need a way to communicate with the backend. You can do that by sending to the admin-ajax.php file. From there you can specify what you want to do with the received data.

First modify your functions.php so that it will output the URL for the AJAX request. We can do that by outputting it as JSON inside an inline script tag so that the URL is available in JavaScript.

// This will create a JSON string with the AJAX url in it.
$wp_data = json_encode( array(
  'ajax' => admin_url( 'admin-ajax.php' ),
) );

function hideout_scripts() {
  wp_register_script( 'sign-up', get_template_directory_uri() . '/js/login-signup-jquery.js', array( 'jquery' ), '1.0.0', true );

  // That JSON string will be put in an inline script tag before the main script.
  // This means that we can use the URL in our main script for an AJAX request.
  // The ugly __wp__ name is to ensure that this property will not be overwritten, ever by another script, and therefor breaking our code.
  wp_add_inline_script( 'sign-up', "window.__wp__ = {$wp_data}", 'before' );

  wp_enqueue_script( 'sign-up' );
}
add_action( 'wp_enqueue_scripts', 'hideout_scripts' );

Now the admin-url.php URL is available in our form validation script. We'll stay in the functions.php and add a hook to which we will be able to communicate to when we want to send a request. Something like an endpoint.

function sign_up_ajax() {
  $user_name = isset( $_POST[ 'username' ] ) ? $_POST[ 'username' ] : '';
  $user_email = isset( $_POS[ 'email' ] ) ? $_POST[ 'email' ] : '';

  // Write your validation and checks here.

  echo 'Everything is okay';
  die();
}
add_action( 'wp_ajax_nopriv_sign_up_ajax', 'sign_up_ajax') ;
add_action( 'wp_ajax_sign_up_ajax', 'sign_up_ajax') ;

So what I did here is use the wp_ajax_nopriv and wp_ajax hooks to register a sign_up_ajax action endpoint. Whenever we call a HTTP request to the admin-url.php endpoint with an action=sign_up_ajax value it will know that we want to call the sign_up_ajax function.

Now for JavaScript. You already had a large part of the AJAX request. All you have to do it set the URL to the admin-ajax.php file, which is stored in window.__wp__.ajax and add a ?action=sign_up_ajax string after it so the endpoint knows what function to call.

var $form = $('#sign-up');
var regex = /^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/g;
var error = {
  emptyUserName: 'User name should not be empty.',
  invalidEmail: 'Please enter a valid email.',
}

// Listen for the submit event.
$form.on('submit', function(event) {
  // Prevent the submit right away.
  event.preventDefault();

  // Create a flag to check form validity with.
  var isValidForm = true;
  
  // Select the input fields.
  var $userName = $('#user-name');
  var $userEmail = $('#user-email');
  
  // Check the user name for empty string.
  if ($userName.val() === '') {
    console.log(error.emptyUserName);
    isValidForm = false;
  }
  
  // Check the email for a valid email with the regex.
  if (!regex.test($userEmail.val())) {
    console.log(error.invalidEmail);
    isValidForm = false;
  }
  
  // If the form is not completely valid, stop.
  // Otherwise, do nothing and let the form submit.
  if (!isValidForm) {
    return;
  }

  // From here we send a AJAX request. The ajax URL is available
  // on the window object in the __wp__ property.
  $.ajax({
    url: window.__wp__.ajax + '?action=sign_up_ajax',
    method: 'POST',
    data: $form.serialize(),
    success: function(data) {
      console.log(data);
      // Check your data, and finally submit the form if the data is good. :)
      // if (data === 'Everything is okay') {
      //   $form.submit();
      // }
    }
  })
});

That's the gist of it. Handling forms is no easy feat in WordPress, but I hope that these examples will help you get further.

Related