I'm writing some code that updates options using update_option
using the REST API and apiFetch.
I'm used to doing this using AJAX where I would pass a nonce along in the request to my PHP function, as well as check for current user capabilities.
Using the REST API and apiFetch feels much better than using AJAX, but I feel like I'm missing something when it comes to security.
Here's an idea of what I'm doing:
register_rest_route(
$namespace,
'/update_settings/',
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_settings' ),
'permission_callback' => array( $this, 'update_settings_permission' ),
)
);
My permission_callback
looks like this:
public function update_settings_permission() {
if ( ! current_user_can( 'manage_options' ) ) {
return $this->error( 'user_dont_have_permission', __( 'You do not have permission to change options.' ) );
}
return true;
}
My update_settings function looks like this:
public function update_settings( WP_REST_Request $request ) {
$new_settings = $request->get_param( 'settings' );
if ( is_array( $new_settings ) ) {
$current_settings = get_option( 'my_options', array() );
update_option( 'my_options', array_merge( $current_settings, $new_settings ) );
}
return $this->success( true );
}
And then the request itself is quite standard:
apiFetch( {
path: 'namespace/v1/update_settings',
method: 'POST',
data: {
settings: this.state.settings,
},
} ).then( ( result ) => {
// all done.
} );
This all works perfectly, but it seems too easy. Should I be passing a nonce along somewhere? It seems like apiFetch has some middlewares that include a nonce - is this all done for us by default?
settings
rather thanupdate_settings
, as it's the HTTP method not the name of the endpoint that's meant to indicate the action, e.g.GET
retrieves data,POST
/UPDATE
/PUT
adds or updates data,DELETE
deletes it