mbacon40 mbacon40 - 1 month ago 7
Javascript Question

WordPress REST API - Allow anyone to POST

I am building an application on WordPress that requires a simple front end form where anyone can submit information that needs to be saved in the database. I am attempting to handle this through the REST API. (Due to the nature of the application, there can not be any redirection of the page when this information is submitted.)

I have no problem setting up the REST API (v2) so that I can submit a post. It works great when I am logged into WordPress. When I try to fill out the form when I am not logged in to WordPress, I receive an error.


Failed to load resource: the server responded with a status of 403 (Forbidden)


How can I set the API to receive a POST from anyone without authentication?

Here is my javascript:

$( '#post-submission-form' ).on( 'submit', function(e) {
e.preventDefault();
var title = $( '#post-submission-title' ).val();
var excerpt = $( '#post-submission-excerpt' ).val();
var content = $( '#post-submission-content' ).val();
var status = 'draft';

var data = {
title: title,
excerpt: excerpt,
content: content
};

$.ajax({
method: "POST",
url: POST_SUBMITTER.root + 'wp/v2/posts',
data: data,
beforeSend: function ( xhr ) {
//xhr.setRequestHeader( 'X-WP-Nonce', POST_SUBMITTER.nonce );
},
success : function( response ) {
console.log( response );
alert( POST_SUBMITTER.success );
},
fail : function( response ) {
console.log( response );
alert( POST_SUBMITTER.failure );
}

});

});


Here is how I am initializing my javascript:

function holiday_scripts() {

// Onload JS
wp_enqueue_script( 'holiday-js', get_template_directory_uri() . '/js/holiday.js', array(), false, true );

//localize data for script
wp_localize_script( 'holiday-js', 'POST_SUBMITTER', array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'success' => __( 'Thanks for your submission!', 'your-text-domain' ),
'failure' => __( 'Your submission could not be processed.', 'your-text-domain' ),
'current_user_id' => 9
)
);
}
add_action( 'wp_enqueue_scripts', 'holiday_scripts' );


Does anyone have any idea on how to accomplish this?

Thanks!

Answer Source

There are three different options to authenticate to the REST API:

  1. Cookie - this is what you are using now
  2. OAuth - requires the OAuth plugin and embedding key on the front end
  3. Basic - requires embedding the username/password on the front end

See the documentation on using these methods here: http://v2.wp-api.org/guide/authentication/.

There are obvious security risks when embedding the auth info on the front end, which is required by OAuth and Basic as anyone will be able to authenticate as the user the key is associated with. I'm not familiar enough with the WP OAuth plugin to know how granularly you can control access, but I don't think you really can.

The easiest solution is to write your own method outside the REST API to handle these updates (or contribute to the project to make unauthenticated requests possible). I wrote up a guide for Creating AJAX Functions on my website, but basically you want to attach a function to the wp_ajax_nopriv_* hook, where the * is the "action" parameter of your request. In your hooked PHP function you handle the post insertion and respond with JSON (you could even match the WP REST API format).

PHP

// insert new post
function create_post_33741541() {
    // use the $_POST to create your post
    $args = array(
         'post_title' => isset( $_POST['title'] )? $_POST['title'] : 'Empty Title',
         // more parameters....
    );
    $post_id = wp_insert_post( $args );

    // make a response
    $response = array( 'post_id' => $post_id, 'message' => 'post created!' );

    // set the content type and return json encode response, then exit
    header( 'Content-type: application/json' );
    die( json_encode( $response ) );
}
// use wp_ajax_nopriv to access from front end
add_action( 'wp_ajax_nopriv_create_post_33741541', 'create_post_33741541' );
add_action( 'wp_ajax_create_post_33741541', 'create_post_33741541' );

JavaScript

function createThePost(){
    var data = {
        // use the part after "wp_ajax_nopriv" as the action
        action: 'create_post_33741541'
        title: 'Your title',
        // other params
    };

    $.ajax({
        method: "POST",
        url: ajaxurl,
        data: data,
        // your handlers
    });
}