0

Trying to create a form with AJAX call on the Frontend where the users can submit a post.

There is one text field, one textarea, and one file field.

Here is the form:

public function pp_html_template() {
    if ( is_user_logged_in() ) {
        return '<h2>' . __( 'Publish your post', 'post-publisher' ) . '</h2>
        <form id="pp-form-submit" class="pp-form-submit" enctype="multipart/form-data">' .
       wp_nonce_field( 'pp_publisher_save', 'pp_publisher_name' )
       . '<div class="pp-row">
                <label for="pp_title">' . esc_attr__( 'Title', 'post-publisher' ) . '</label>
                <input type="text" id="pp_title" name="pp_title">
            </div>

            <div class="pp-row">
                <label for="pp_content">' . esc_attr__( 'Content', 'post-publisher' ) . '</label>
                <textarea name="pp_content" id="pp_content" name="pp_content" cols="30" rows="10"></textarea>
            </div>
            
            <div class="pp-row">
                <label for="pp_featured_image">' . esc_attr__( 'Featured Image', 'post-publisher' ) . '</label>
                <input type="file" id="pp_featured_image" name="pp_featured_image">
            </div>
            <input type="hidden" name="action" value="pp_html_process"/>
            <div class="pp-row">
                <input type="submit" name="pp_submit" id="pp_submit">
            </div>
        </form>';
    }
}

Here is the processing:

public function pp_html_process() {

    // Process the form
    if ( isset( $_POST['pp_submit'] ) ) {
        if ( ! isset( $_POST['pp_publisher_name'] ) || ! wp_verify_nonce( $_POST['pp_publisher_name'], 'pp_publisher_save' ) ) {
            esc_attr__( 'Sorry, this action is not allowed.', 'post-publisher' );
            exit;
        } else {
            global $current_user;

            $user_login   = $current_user->user_login;
            $user_id      = $current_user->ID;
            $post_title   = sanitize_text_field( $_POST['pp_title'] );
            $post_content = sanitize_textarea_field( $_POST['pp_content'] );

            $new_post = array(
                'post_title'   => $post_title,
                'post_content' => $post_content,
                'post_type'    => 'post',
                'post_status'  => 'draft',
                'post_name'    => str_replace( ' ', '-', $post_title ),
            );

            $post_id = wp_insert_post( $new_post, true );

            if ( ! function_exists( 'wp_generate_attachment_metadata' ) ) {
                require_once( ABSPATH . "wp-admin" . '/includes/image.php' );
                require_once( ABSPATH . "wp-admin" . '/includes/file.php' );
                require_once( ABSPATH . "wp-admin" . '/includes/media.php' );
            }


            $featured_image = media_handle_upload( 'pp_featured_image', $post_id );
            if ( $featured_image > 0 ) {
                update_post_meta( $post_id, '_thumbnail_id', $featured_image );
            }
        }
    }
}

And __construct()

public function __construct() {
    if ( ! is_admin() ) {
        add_shortcode( 'pp_html_template', array( $this, 'pp_html_template' ) );
        add_action( 'init', array( $this, 'pp_html_process' ) );
    }

    add_action( 'wp_ajax_pp_html_process', array( $this, 'pp_html_process' ) );
    add_action( 'wp_ajax_nopriv_pp_html_process', array( $this, 'pp_html_process' ) );
}

jQuery:

jQuery(document).ready(function ($) {
    $('#pp-form-submit').submit(ajaxSubmit);

    function ajaxSubmit() {
        var newCustomerForm = $(this).serialize();

        jQuery.ajax({
            type: "POST",
            url: "/codeable/wp-admin/admin-ajax.php",
            data: $("#pp-form-submit").serialize(),
            success: function (response) {
                console.log(response);
            }
        });
        return false;
    }
});

I'm not getting any errors in the console. Post without AJAX is working perfectly fine, but with AJAX, it's returning 0.

Any advice will be helpful.

3
  • jQuery doesn't serialize submit button value (see here), which means the pp_submit input was never submitted to the server, hence the if ( isset( $_POST['pp_submit'] ) ) returned false. So you just needed to manually include pp_submit in your AJAX form data. However, your form contains a file input and therefore, you should instead use the FormData API and not jQuery's .serialize().
    – Sally CJ
    Commented Sep 19, 2021 at 10:24
  • @SallyCJ Can you provide me any short example of how to do that? Thank you so much
    – upss1988
    Commented Sep 19, 2021 at 11:28
  • Yes, see my answer (and if you've seen it already, ignore my previous comment, which I've deleted). Let me know.
    – Sally CJ
    Commented Sep 20, 2021 at 5:12

1 Answer 1

1

Post without AJAX is working perfectly fine, but with AJAX, it's returning 0.

Simply put, that's because your AJAX request doesn't include the pp_submit input which is required by pp_html_process() — the callback for both regular and AJAX form submission.

I.e. As I said in the comments:

jQuery doesn't serialize submit button value (see here), which means the pp_submit input was never submitted to the server, hence the if ( isset( $_POST['pp_submit'] ) ) returned false. So you just needed to manually include pp_submit in your AJAX form data. However, your form contains a file input and therefore, you should instead use the FormData API and not jQuery's .serialize().

So for example, I'd do it like so:

function ajaxSubmit() {
    var formData = new FormData( this );

    // Yes, even when using FormData, you still need to manually include the pp_submit.
    formData.append( 'pp_submit', 1 );

    jQuery.ajax({
        type: 'POST',
        url: '/codeable/wp-admin/admin-ajax.php',
        data: formData,
        processData: false,
        contentType: false,
        success: function ( response ) {
            console.log( 'success', response );
        },
        error: function ( response ) {
            console.log( 'error!', response );
        }
    });

    return false;
}

And I've tested that with your exact PHP/HTML code, which means I simply replaced the above JS function, and then everything worked for me — the post was created successfully and the post thumbnail was also set correctly. However, I added wp_die() to prevent a 0 in the response. (see the 1st note below)

Additional Notes

  1. You should call wp_die() after you've set the post thumbnail, to exit the page and prevent WordPress from echoing a 0:

    // set the post thumbnail:
    // if ( $featured_image > 0 ) { ... your code here }
    
    // then call wp_die():
    if ( wp_doing_ajax() ) {
        echo 'Post created! ID: ' . $post_id;
        wp_die();
    }
    

    PS: I'd use the set_post_thumbnail() function to set the post thumbnail.

  2. I used url: '/codeable/wp-admin/admin-ajax.php' above because that's what you used, but you really should localize your AJAX/JS parameters and then for example, use url: my_ajax_obj.ajax_url instead of hard-coding the admin-ajax.php URL/path into the url property.

  3. I strongly suggest you to use the modern WordPress REST API which:

    • Has a better error handling — e.g. with the admin-ajax.php endpoint, if your AJAX action isn't registered correctly, you'd simply get a 400 Bad Request status with a 0 response; but with the REST API, if a route is not registered correctly, you'd see a human-readable error explaining what happened.

    • Has existing endpoints that one could simply use for creating posts, medias (attachment posts), terms, etc.

    • Allows you to create your own custom endpoint with a "pretty" URL (if permalinks are enabled on the site, of course) like https://example.com/wp-json/your-plugin/v1/pp-html-process and you could also easily set the endpoint to be public or be available to certain users/roles only.

    • Accepts many request formats including JSON payload (which is not supported by admin-ajax.php) and the response body/header also defaults to JSON.

    • ... and many other features which you can find in the handbook here.

7
  • Thank you for the detailed explanation. Now I'm getting Bad request and error in the console: VM12:1 POST http://localhost:8888/dbl/wp-admin/admin-ajax.php 400 (Bad Request) and error! {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
    – upss1988
    Commented Sep 20, 2021 at 20:57
  • Can you share on Pastebin.com the full JS code you have now, and also include the PHP code that you've changed?
    – Sally CJ
    Commented Sep 20, 2021 at 22:20
  • Here is the complete JS code: codepen.io/upss1988/pen/RwgJbXQ Nothing has been changed except that I have localized the script. Please check the edited question above.
    – upss1988
    Commented Sep 21, 2021 at 10:13
  • Could you please undo your question's edit (i.e. roll back to the original version) because the way you edited your question invalidated my answer. (You should've just appended new code at the bottom) And from what I could see, you've forgotten to add wp_die() - it's necessary to end the PHP execution and avoid WordPress from printing a 0.
    – Sally CJ
    Commented Sep 21, 2021 at 10:37
  • But the actual problem is the if ( ! is_admin() ) check in your class constructor. Your constructor should look like it was originally as you could see here. I.e. Put the wp_ajax_ actions outside that if block.
    – Sally CJ
    Commented Sep 21, 2021 at 10:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.