the wp_verify_nonce() keep returning false
If you were logged-in to your (WordPress) site when you used the form, then the above is normal. Here’s why so:
-
Your form submits to a custom REST API endpoint (at
/wp-json/ilms_plugin/new_membership
) and the default authentication method used by the REST API is cookie-based, i.e. it checks if a nonce with the action namedwp_rest
is set and that it’s valid (not yet expired), and if not (not set or it’s invalid/expired), then WordPress sets the current user to0
which affects all nonce-related functions including but not limited towp_verify_nonce()
. -
In simple words, it means functions like
wp_verify_nonce()
will return false because nonces are based on the current user, so if the user is logged-in to your site (when filling in the form), but not the REST API (when the form submission/data is processed), thenwp_verify_nonce()
will return false because the user ID becomes0
in the REST API.
Check out the REST API handbook for more details about the authentication: https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/
How to fix the issue
Just add wp_nonce_field( 'wp_rest', '_wpnonce', false );
somewhere in your form, e.g. right after the opening <form>
tag: (Note that I escaped the URL using esc_url()
)
<form action="<?php echo esc_url( get_rest_url( null, 'ilms_plugin/new_membership' ) ); ?>" ...>
<?php wp_nonce_field( 'wp_rest', '_wpnonce', false ); ?>
...
Additional Notes
-
Instead of
get_rest_url( null, 'ilms_plugin/new_membership' )
, you could userest_url( 'ilms_plugin/new_membership' )
which usesrest_url()
and is shorter.. 🙂 -
Instead of using
$wpdb->query()
, I would use$wpdb->insert()
to insert the data to the database. -
A REST API endpoint should always set a
permission_callback
and you should also use theargs
argument to define the parameters for the endpoint like thetest_nonce
in your case. Nonetheless, refer to Adding Custom Endpoints in the REST API handbook for further details.