Nonce WordPress API for React App inside WordPress

Δημοσιεύθηκε 23/07/2024

Διαβάστε πρώτα το άρθρο React App inside WordPress.

GET method

useEffect(() => {
      fetch('/wp-json/wp/v2/posts')
          .then(response => response.json())
          .then(data => console.log(data))
          .catch(error => console.error('Error:', error));
  }, []);

POST method

Γενικά, για να εκτελέσουμε POST request στο WordPress API, απαιτείται οι χρήστες να είναι authenticated. Επειδή το React είναι μια frontend τεχνολογία και δεν μπορεί να κρατήσει κρυφές τις πληροφορίες σύνδεσης, δημιουργούμε ένα nonce και το προσθέτουμε στο script του React App μέσω του wp_localize_script.

Στο functions.php:

wp_enqueue_script(
	'react-app-js',
	get_template_directory_uri() . '/bodyreact/static/js/main.js',
	array('wp-element'),
	filemtime(get_template_directory() . '/bodyreact/static/js/main.js'),
	true
);

wp_localize_script('react-app-js', 'wpApiSettings', array(
	'root' => esc_url_raw(rest_url()),
	'nonce' => wp_create_nonce('wp_rest'),
));

Επιπλέον, για να τρέχει το React App POST, δημιουργώ custom rest route, για την εκάστοτε ανάγκη. Στο παρακάτω παράδειγμα, υλοποιείται η λειτουργία του POST για ένα post, μέσω React App.

function register_public_post_route() {
    register_rest_route('public/v1', '/create-post', array(
        'methods' => 'POST',
        'callback' => 'handle_public_post',
        'permission_callback' => '__return_true',
    ));
}
add_action('rest_api_init', 'register_public_post_route');

function handle_public_post(WP_REST_Request $request) {
    $params = $request->get_json_params();
    $title = sanitize_text_field($params['title']);
    $content = sanitize_textarea_field($params['content']);

    // Implement your own security check, e.g., a captcha or a custom token
    if (!my_custom_security_check($params)) {
        return new WP_Error('invalid_security', 'Security check failed', array('status' => 403));
    }

    $new_post = array(
        'post_title'   => $title,
        'post_content' => $content,
        'post_status'  => 'publish',
        'post_author'  => 1,
    );

    $post_id = wp_insert_post($new_post);

    if (is_wp_error($post_id)) {
        return new WP_Error('post_creation_failed', 'Post creation failed', array('status' => 500));
    }

    return rest_ensure_response(array('post_id' => $post_id));
}

function my_custom_security_check($params) {
    // Implement your security checks here (e.g., captcha validation)
    return true; // Change this to your actual security check
}

Και στο React App η υλοποίηση είναι ως εξής:
[πάνω πάνω στο αρχείο δηλώνω το: /* global wpApiSettings */ ]

 /* global wpApiSettings */


/*******************************/


const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [message, setMessage] = useState('');

const handleSubmit = async (e) => {
    e.preventDefault();

    const postData = {
        title: title,
        content: content,
    };

    try {
        const response = await fetch(`${wpApiSettings.root}public/v1/create-post`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': wpApiSettings.nonce,
            },
            body: JSON.stringify(postData),
        });

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        const data = await response.json();
        setMessage('Post created successfully!');
        console.log('Post created:', data);
    } catch (error) {
        setMessage('Error creating post');
        console.error('Error:', error);
    }
};


/*******************************/


<div>
    <h2>Create a New Post</h2>
    <form onSubmit={handleSubmit}>
        <div>
            <label>Title:</label>
            <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} />
        </div>
        <div>
            <label>Content:</label>
            <textarea value={content} onChange={(e) => setContent(e.target.value)} />
        </div>
        <button type="submit">Create Post</button>
    </form>
    {message && <p>{message}</p>}
</div>