Our account system is taking shape now that we have login, logout, and password reset implemented. Next we need to handle user registrations!
Lucky for us, WPGraphQL provides us with a user registration mutation we can use out of the box.
mutation registerUser {
registerUser(input: {
username:"new_user"
}) {
clientMutationId
user {
name
slug
}
}
}
Code language: JavaScript (javascript)
All we need to is build some client code to consume this. In this post I’ll be demonstrating this using ReactJS and the Apollo Client package (which I covered in a previous post) to make our requests to the server where WordPress and WPGraphQL are running.
Custom hooks
When we create a registration form it will need a way to send the form data to the server. For this we can create some custom React hooks.
useRegisterMutation
This hook provides us with a function named registerMutation
that accepts a username, email, and password and then uses Apollo Client useMutation
hook to make the GraphQL request. This function returns the result as a JavaScript promise.
/**
* External dependencies
*/
import { gql, useMutation } from '@apollo/client';
const REGISTER = gql`
mutation RegisterUser(
$username: String!
$email: String!
$password: String!
) {
registerUser(
input: { username: $username, email: $email, password: $password }
) {
clientMutationId
}
}
`;
export const useRegisterMutation = () => {
const [ mutation, mutationResults ] = useMutation( REGISTER );
const registerMutation = ( username, email, password ) => {
return mutation( {
variables: {
username,
email,
password,
},
} );
};
return { registerMutation, results: mutationResults };
};
Code language: JavaScript (javascript)
This hook can be used like this:
const { registerMutation, results } = useRegisterMutation();
Code language: JavaScript (javascript)
useRegistration
I created another custom hook that consumes useRegisterMutation
and does a little more handling for things such as error states and status that our registration form will later use.
One thing we do need to handle is error codes coming back from the WPGraphQL API—the codes are descriptive but need to be converted into a more human readable format if they are being displayed to the user:
const errorCodes = {
invalid_username:
'Invalid username or email address. Please check it and try again.',
invalid_email: 'Invalid email address. Please check it and try again.',
incorrect_password:
'Incorrect password. Please try again, or reset your password.',
empty_username: 'Please provide your username.',
empty_password: 'Please provide your password.',
};
Code language: JavaScript (javascript)
The hook itself uses the mutation hook we made earlier, tracks the status of requests (idle, resolving, resolved), and stores any error messages we get back from the server.
export const useRegistration = () => {
const [error, setError] = useState(null);
const [status, setStatus] = useState('idle');
const { registerMutation } = useRegisterMutation();
const register = (username, email, password) => {
setError(null);
setStatus('resolving');
return registerMutation(username, email, password)
.then(() => {
setStatus('resolved');
})
.catch((errors) => {
setError(errorCodes[errors.message] || errors.message);
setStatus('resolved');
});
};
return {
register,
error,
status,
};
};
Code language: JavaScript (javascript)
Creating the user registration form
The registration form needs fields for username, email address, and password. It also needs to use the status
and error
state from the useRegistration
hook we created earlier.
A basic version of the form in React would be as follows (I am using useState
here to store field values).
import { useState } from 'react';
import { useRegistration } from 'hooks';
export const RegisterForm = () => {
const [ username, setUsername ] = useState( '' );
const [ email, setEmail ] = useState( '' );
const [ password, setPassword ] = useState( '' );
const { register, error, status } = useRegistration();
const onRegister = ( e ) => {
e.preventDefault();
register( username, email, password );
};
return (
<form
onSubmit={ onRegister }
className="register-form"
autoComplete="on"
>
{ error && <div className="error-notice">{ error }</div> }
<label htmlFor={ `field-username` }>Username</label>
<input
type="text"
id="field-username"
value={ username }
autoComplete="username"
onChange={ ( value ) => setUsername( value ) }
disabled={ status === 'resolving' }
/>
<label htmlFor={ `field-email` }>Email</label>
<input
type="text"
id="field-email"
value={ email }
autoComplete="email"
onChange={ ( value ) => setEmail( value ) }
disabled={ status === 'resolving' }
/>
<label htmlFor={ `field-password` }>Password</label>
<input
type="password"
autoComplete="new-password"
value={ password }
onChange={ ( value ) => setPassword( value ) }
disabled={ status === 'resolving' }
/>
<button
className="button"
onClick={ onRegister }
disabled={ status === 'resolving' }
>
Create Account
</button>
</form>
);
};
export default RegisterForm;
Code language: JavaScript (javascript)
With this in place, our form looks like this:

Adding some basic form validation
To avoid making erroneous requests we can add some client side validation to our fields. We can add these validation rules in our form submit handler.
const [ passwordError, setPasswordError ] = useState( '' );
const onRegister = (e) => {
e.preventDefault();
setPasswordError( '' );
if ( username.length === 0 ) {
setPasswordError( 'Please enter a username.' );
return;
}
if ( email.length === 0 ) {
setPasswordError( 'Please enter your email address.' );
return;
}
if ( password.length === 0 ) {
setPasswordError( 'Please enter a password.' );
return;
}
register(username, email, password);
};
Code language: JavaScript (javascript)
With this change in place, registration will only be attempted if the username, email, and password fields are populated. This could be improved further by adding email format validation and so on.
Improving the password field
Our password field could be improved by giving some indication of password strength. For this I chose to use the React Password Strength Bar package. You can customise the scoreWords and shortScoreWord however you please to reflect password strength. For fun, I’m using a D&D theme 🙂
<PasswordStrengthBar
password={ password }
scoreWords={ [
'critical fail',
'okay',
'good',
'strong',
'critical roll!',
] }
shortScoreWord={ 'critical fail' }
/>
Code language: JavaScript (javascript)
In the above snippet we provide the current password, and it will access the strength and display it to the user:

You can see the final form on GitHub here.
Wrapping up
Our registration system is complete. The only other change I made (on the server side) was to disable new user emails:
remove_action( 'register_new_user', 'wp_send_new_user_notifications' );
Code language: PHP (php)
You can see a working example of the registration form in my D&D app here, and the source code is also public on GitHub.
As I’ve said before, it’s very useful that WPGraphQL includes some of the account mutations out of the box. Whilst this is not unique to GraphQL (we could use the WP REST API if we wanted), I have found it very easy to work with from the client side.