admin管理员组

文章数量:1279042

I built a plugin, but now on end, I am not sure whether my nonce integrated correctly, and I'm not sure how to test them.

Can anyone help me test it or let me know if the nonce is integrated correctly?

Here is one example from my code:

PHP:

public function __construct() {
    if ( ! is_admin() ) {
        add_action( 'wp_head', 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' ) );
}

public function pp_html_template() {
    ?>
    <form id="pp-form-submit" name="pp-form-submit" class="pp-form-submit" enctype="multipart/form-data">
        <?php wp_nonce_field( 'pp_publisher_save', 'pp_publisher_name' ); ?>
        <div class="pp-row">
            <label for="pp-title"><?php esc_attr_e( 'Title', 'post-publisher' ) ?></label>
            <input type="text" id="pp-title" name="pp_title" required>
        </div>
    
        <div class="pp-row">
            <label for="pp-content"><?php esc_attr_e( 'Content', 'post-publisher' ) ?></label>
            <textarea id="pp-content" name="pp_content" cols="30" rows="10" required></textarea>
        </div>
    
        <div class="pp-row">
            <label for="pp-featured-image"><?php esc_attr_e( 'Featured Image', 'post-publisher' ) ?></label>
            <input type="file" id="pp-featured-image" name="pp_featured_image" required>
        </div>
        <input type="hidden" name="action" value="pp_html_process"/>
        <div class="pp-row">
            <input type="submit" name="pp_submit" id="pp-submit">
        </div>
    
        <div class="pp-row">
            <div id="pp-response"></div>
            <div class="pp-posts-area"></div>
        </div>
    </form>
<?php }

public function pp_html_process() {
    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 {
            $inc = new Pp_Includes();
            $inc->pp_post_data('pp_title', 'pp_content', 'pp_featured_image');

            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' ] );

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

            $post_id = wp_insert_post( $arg, 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 ( is_wp_error( $featured_image ) ) {
                wp_die( $featured_image );
            }

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

            if ( wp_doing_ajax() ) {
                wp_die();
            }
        }
    }
}

Here is the localized script:

public function pp_enqueue_public_styles() {
    wp_enqueue_script( 'pp_public_ajax', plugins_url( '/assets/js/pp-public-ajax.js', __FILE__ ), array( 'jquery' ), null, true );
    wp_localize_script( 'pp_public_ajax', 'pp_public_ajax',
        array(
            'pp_ajaxurl'             => admin_url( 'admin-ajax.php' ),
            'pp_publisher_name'      => wp_create_nonce( 'pp_publisher_save' )
        )
    );
}

AJAX:

function ppAjaxSubmit() {
    var ppFormData = new FormData(this);

    ppFormData.append('pp_submit', 1);
    ppFormData.append('security', pp_public_ajax.pp_publisher_name)

    $.ajax({
        action: 'pp_featured_image',
        type: 'POST',
        url: pp_public_ajax.pp_ajaxurl,
        data: ppFormData,
        processData: false,
        contentType: false,
        success: function () {
            console.log(data);
        },
        error: function () {
            console.log(err)
        }
    });

    return false;
}

$('#pp-form-submit').submit(ppAjaxSubmit);

Any advice would be appreciated.

I built a plugin, but now on end, I am not sure whether my nonce integrated correctly, and I'm not sure how to test them.

Can anyone help me test it or let me know if the nonce is integrated correctly?

Here is one example from my code:

PHP:

public function __construct() {
    if ( ! is_admin() ) {
        add_action( 'wp_head', 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' ) );
}

public function pp_html_template() {
    ?>
    <form id="pp-form-submit" name="pp-form-submit" class="pp-form-submit" enctype="multipart/form-data">
        <?php wp_nonce_field( 'pp_publisher_save', 'pp_publisher_name' ); ?>
        <div class="pp-row">
            <label for="pp-title"><?php esc_attr_e( 'Title', 'post-publisher' ) ?></label>
            <input type="text" id="pp-title" name="pp_title" required>
        </div>
    
        <div class="pp-row">
            <label for="pp-content"><?php esc_attr_e( 'Content', 'post-publisher' ) ?></label>
            <textarea id="pp-content" name="pp_content" cols="30" rows="10" required></textarea>
        </div>
    
        <div class="pp-row">
            <label for="pp-featured-image"><?php esc_attr_e( 'Featured Image', 'post-publisher' ) ?></label>
            <input type="file" id="pp-featured-image" name="pp_featured_image" required>
        </div>
        <input type="hidden" name="action" value="pp_html_process"/>
        <div class="pp-row">
            <input type="submit" name="pp_submit" id="pp-submit">
        </div>
    
        <div class="pp-row">
            <div id="pp-response"></div>
            <div class="pp-posts-area"></div>
        </div>
    </form>
<?php }

public function pp_html_process() {
    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 {
            $inc = new Pp_Includes();
            $inc->pp_post_data('pp_title', 'pp_content', 'pp_featured_image');

            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' ] );

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

            $post_id = wp_insert_post( $arg, 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 ( is_wp_error( $featured_image ) ) {
                wp_die( $featured_image );
            }

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

            if ( wp_doing_ajax() ) {
                wp_die();
            }
        }
    }
}

Here is the localized script:

public function pp_enqueue_public_styles() {
    wp_enqueue_script( 'pp_public_ajax', plugins_url( '/assets/js/pp-public-ajax.js', __FILE__ ), array( 'jquery' ), null, true );
    wp_localize_script( 'pp_public_ajax', 'pp_public_ajax',
        array(
            'pp_ajaxurl'             => admin_url( 'admin-ajax.php' ),
            'pp_publisher_name'      => wp_create_nonce( 'pp_publisher_save' )
        )
    );
}

AJAX:

function ppAjaxSubmit() {
    var ppFormData = new FormData(this);

    ppFormData.append('pp_submit', 1);
    ppFormData.append('security', pp_public_ajax.pp_publisher_name)

    $.ajax({
        action: 'pp_featured_image',
        type: 'POST',
        url: pp_public_ajax.pp_ajaxurl,
        data: ppFormData,
        processData: false,
        contentType: false,
        success: function () {
            console.log(data);
        },
        error: function () {
            console.log(err)
        }
    });

    return false;
}

$('#pp-form-submit').submit(ppAjaxSubmit);

Any advice would be appreciated.

Share Improve this question edited Sep 28, 2021 at 15:40 upss1988 asked Sep 28, 2021 at 13:25 upss1988upss1988 178 bronze badges 8
  • note that this won't run for logged out users, but I'm curious, is there a reason you chose the old legacy admin AJAX to handle your JS requests instead of a modern REST API route? – Tom J Nowell Commented Sep 28, 2021 at 14:07
  • @TomJNowell I'm aware that it's working only with the logged-in user. I'm not entirely familiar with the REST API route, so that is why this way. Any feedback on my question, maybe? – upss1988 Commented Sep 28, 2021 at 14:20
  • A REST API route would handle the nonce for you out of the box as part of the authentication process, and provide parameters letting you pass it functions that deal directly with what you're asking about. The REST API does a lot of things for you that admin AJAX forces you to build yourself ( e.g. validating nonces ) – Tom J Nowell Commented Sep 28, 2021 at 14:27
  • @TomJNowell Ok, thank you. – upss1988 Commented Sep 28, 2021 at 14:28
  • Also remember these are comments, nobody has written a solution to your question yet. As this isn't a discussion forum, you need a question that's specific enough that someone can give a concrete objective factual answer that thoroughly answers it, not just an opinion or comment. That's why I left a comment instead of an answer. – Tom J Nowell Commented Sep 28, 2021 at 14:30
 |  Show 3 more comments

1 Answer 1

Reset to default 1

I see some issues:

  1. You ajax action can be only used by logged users. If this is correct, I recommend you add a nopriv action that returns a error message.
    // Inside Constructor    
    add_action( 'wp_ajax_nopriv_pp_html_process', array( $this, 'pp_html_process_not_logged' ) );

And create this function :

    public function pp_html_process_not_logged () {
        // Status can be used to identify via JS if the operation is OK or KO and print an error with jQuery or a modal window, whatever you prefer.
        wp_send_json([
            'status' => false,
            'error' => __('Error. This service is only for logged users.', 'your_plugin_lang_slug')
        ]);
    }
  1. You create a wp_nonce field that will not be used (later in JS you are creating other with the same name / action). Remove this line in your "pp_html_template" function:
    <?php wp_nonce_field( 'pp_publisher_save', 'pp_publisher_name' ); ?>
  
  1. wp_head prints your HTML inside the HEAD tag and that's is not "allowed". This form needs to be inside BODY tag. Maybe you can add it in footer or a better solution is create a shortcode with add_shortcode function and put the shortcode in pages or post you want to display this form.

  2. Remove this lines in your constructor because reason explained in 3 and because you are creating an AJAX action and ajax actions are processed by wp_ajax_{$action} hook.

    if ( ! is_admin() ) {
        add_action( 'wp_head', array( $this, 'pp_html_template' ) );
        add_action( 'init', array( $this, 'pp_html_process' ) );
    }
  1. Ensure "pp_enqueue_public_styles" is called in "wp_enqueue_scripts" or "admin_enqueue_scripts" if it only appears on Dashboard. If you decide to create a shortcode, you can call this function before form.

  2. In your JS file change this lines:

    ppFormData.append('pp_submit', 1);
    ppFormData.append('security', window.pp_public_ajax.pp_publisher_name)
    ppFormData.append('action', 'pp_html_process');
    

And remove this line inside AJAX function:

    action: 'pp_featured_image',

  1. You have an error in your "pp_enqueue_public_styles" function:
public function pp_enqueue_public_styles() {
    // Register the script first!!
    wp_register_script( 'pp_public_ajax', plugins_url( '/assets/js/pp-public-ajax.js', __FILE__ ), array( 'jquery' ), null, true );    
    wp_localize_script( 'pp_public_ajax', 'pp_public_ajax',
        array(
            'pp_ajaxurl'             => admin_url( 'admin-ajax.php' ),
            'pp_publisher_name'      => wp_create_nonce( 'pp_publisher_save' )
        )
    );
    wp_enqueue_script('pp_public_ajax');
}

本文标签: phpHow to test nonce with AJAXPlugin development