7

Consider the following class.

<?php
class MCQAcademy_Endpoint extends WP_REST_Controller {

    /**
     * Register the routes for the objects of the controller.
     */
    public function register_routes() {
        $version = '1';
        $namespace = 'custompath/v' . $version;
        $base = 'endpointbase';

        register_rest_route(
            $namespace,
            '/' . $base,
            array(
                array(
                    'methods'         => WP_REST_Server::READABLE,
                    'callback'        => array( $this, 'get_items' ),
                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
                    'args'            => array(),
                )
            )
        );
    }

    /**
     *
     */
    public function get_items( $request ) {
        $rs = array(
            'data' => array(),
            'request' => array(
                'lang' => 'en',
            ),
        );

        $args = array();
        $items = get_posts( $args );

        foreach( $items as $item ) {
            $itemdata = $this->prepare_item_for_response( $item, $request );
            $rs['data'][] = $this->prepare_response_for_collection( $itemdata );
        }

        $rs['wp_get_current_user'] = wp_get_current_user(); // Does not output as expected

        return new WP_REST_Response( $rs, 200 );
    }

    /**
     * Check if a given request has access to get items
     */
    public function get_items_permissions_check( $request ) {
        return true; // to make readable by all
    }


    /**
     * Prepare the item for create or update operation
     */
    protected function prepare_item_for_database( $request ) {
        return $request;
    }

    /**
     * Prepare the item for the REST response
     */
    public function prepare_item_for_response( $item, $request ) {
        $data = array(
            'ID' => $item->ID,
            'post_content' => wpautop($item->post_content),
            'post_title' => $item->post_title,
        );

        return $data;
    }

    /**
     * Get the query params for collections
     */
    public function get_collection_params() {
        return array(
            'page'     => array(
                'description'        => 'Current page of the collection.',
                'type'               => 'integer',
                'default'            => 1,
                'sanitize_callback'  => 'absint',
            ),
            'per_page' => array(
                'description'        => 'Maximum number of items to be returned in result set.',
                'type'               => 'integer',
                'default'            => 10,
                'sanitize_callback'  => 'absint',
            ),
            'search'   => array(
                'description'        => 'Limit results to those matching a string.',
                'type'               => 'string',
                'sanitize_callback'  => 'sanitize_text_field',
            ),
        );
    }

    // Register our REST Server
    public function hook_rest_server(){
        add_action( 'rest_api_init', array( $this, 'register_routes' ) );
    }
}

$myEndpoint = new MCQAcademy_Endpoint();
$myEndpoint->hook_rest_server();

Everything is going well except calling the wp_get_current_user() function in the get_items() function return empty user even though the user is logged in in the website.

10

Logged in on your website doesn't mean the user is authenticated in the REST API request, that's why you are not getting the correct user or a Id = 0

Please take a look to the REST API authentication methods on the docs:
https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/

For developers making manual Ajax requests, the nonce will need to be passed with each request. The API uses nonces with the action set to wp_rest. These can then be passed to the API via the _wpnonce data parameter (either POST data or in the query for GET requests), or via the X-WP-Nonce header. If no nonce is provided the API will set the current user to 0, turning the request into an unauthenticated request, even if you’re logged into WordPress.

For remote authentication I'd recommend the JWT plugin for a quick start:
https://es.wordpress.org/plugins/jwt-authentication-for-wp-rest-api/

Or you can use the ones suggested on the docs:
https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/#authentication-plugins

  • 1
    I need user id if the user is loggedin in the site. Since the endpoint is open, no need to check permission. – Shah Alom Apr 4 '18 at 21:36
  • This line return false always even though the user is loggedin in the website. $rs['wp_get_current_user'] = is_user_logged_in() ? get_current_user_id() : false; – Shah Alom Apr 4 '18 at 21:46
  • 2
    For cookie authentication: For developers making manual Ajax requests, the nonce will need to be passed with each request. The API uses nonces with the action set to wp_rest. These can then be passed to the API via the _wpnonce data parameter (either POST data or in the query for GET requests), or via the X-WP-Nonce header. If no nonce is provided the API will set the current user to 0, turning the request into an unauthenticated request, even if you’re logged into WordPress. – Pabamato Apr 4 '18 at 21:53
  • 1
    Even with JWT authentication, you still need to pass the X-WP-Nonce header to get the current user, in example if you need to access users/me still returns 401, same for query users by role, and so on. The "non manual" AJAX requests are "special" just because the official API client, includes that header, but nothing else. – Jesús Franco Apr 7 '18 at 5:14
  • 2
    @JesúsFranco you are right, for server side requests(my case), the token will be enough, for client side/manual ajax calls, you have to include the nonce to avoid CSRF, there is no need to include the token since you already have a logged in user and client side is cookie based – Pabamato Apr 10 '18 at 19:40
1

To have a fully working code sample here comes a sample plugin on how to retrieve the current user's ID via REST.

my-plugin.php

class MyPlugin {

  public function __construct() {

    add_action('wp_enqueue_scripts', [$this, 'scripts']);
    add_action('rest_api_init', [$this, 'rest']);
  }

  function scripts() {

    // Add JS.
    wp_enqueue_script('my-plugin', plugin_dir_url(__FILE__) . 'js/scripts.js', ['jquery'], NULL, TRUE);
    // Pass nonce to JS.
    wp_localize_script('my-plugin', 'MyPluginSettings', [
      'nonce' => wp_create_nonce('wp_rest'),
    ]);
  }

  function rest() {

    // Register route.
    register_rest_route('my-plugin/v1', '/uid', [
      'methods'  => WP_REST_Server::READABLE,
      'callback' => [$this, 'rest_callback'],
    ]);
  }

  function rest_callback($data) {

    // Get current user ID.
    $data = [
      'uid' => get_current_user_id(),
    ];

    $response = new WP_REST_Response($data, 200);
    // Set headers.
    $response->set_headers(['Cache-Control' => 'must-revalidate, no-cache, no-store, private']);

    return $response;
  }

}

new MyPlugin();

js/scripts.js

(function($) {

  $(document).ready(function() {

    var settings = MyPluginSettings;

    $.ajax({
      url: '/wp-json/my-plugin/v1/uid',
      method: 'GET',
      beforeSend: function(xhr) {
        xhr.setRequestHeader('X-WP-Nonce', settings.nonce);
      }
    }).done(function(response) {

      // Will return your UID.
      console.log(response);
    });

  });

})(jQuery);

Resource: https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/

  • I do not understand how 'MyPluginSettings' is passed to script. Possible things to consider: I'm currently not using JQuery but "vanilla" JavaScript ... I was insterting my script in html <script> tags when need, but I tried including them with wp_enqueue_script and got the same issue. – TTT Apr 10 at 18:00
  • 1
    I got this working, I had written some wrong path when adapting for wp_enqueue_script() . But also, I had multiple scripts, and I just understood that the first parameter of wp_enqueue_script() isn't actually specific to plug-in but is specific to script ( maybe you should change 'my-plugin' in you answer because that's confusing. – TTT Apr 10 at 18:12
  • @TTT – Swap it with my-script for example? Yes, it just should be some unique handle name, often containing the name of the plugin or theme. – leymannx Apr 10 at 20:38
1

wp_get_current_user() does not work because your user is not set perfectly. See below code in /wp-includes/user.php for reference.

if ( ! empty( $current_user ) ) {
    if ( $current_user instanceof WP_User ) {
        return $current_user;
    }

    // Upgrade stdClass to WP_User
    if ( is_object( $current_user ) && isset( $current_user->ID ) ) {
        $cur_id       = $current_user->ID;
        $current_user = null;
        wp_set_current_user( $cur_id );
        return $current_user;
    }

    // $current_user has a junk value. Force to WP_User with ID 0.
    $current_user = null;
    wp_set_current_user( 0 );
    return $current_user;
}

if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
    wp_set_current_user( 0 );
    return $current_user;
}

All you need to do is wp_set_current_user( {user_id} ) at the start of your API.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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