Función wp_get_current_user() no funciona en callback de API REST
Considera la siguiente clase.
<?php
class MCQAcademy_Endpoint extends WP_REST_Controller {
/**
* Registra las rutas para los objetos del controlador.
*/
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(),
)
)
);
}
/**
* Obtiene los items
*/
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(); // No devuelve lo esperado
return new WP_REST_Response( $rs, 200 );
}
/**
* Verifica si una solicitud dada tiene acceso para obtener items
*/
public function get_items_permissions_check( $request ) {
return true; // para hacerlo legible por todos
}
/**
* Prepara el item para operaciones de creación o actualización
*/
protected function prepare_item_for_database( $request ) {
return $request;
}
/**
* Prepara el item para la respuesta REST
*/
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;
}
/**
* Obtiene los parámetros de consulta para colecciones
*/
public function get_collection_params() {
return array(
'page' => array(
'description' => 'Página actual de la colección.',
'type' => 'integer',
'default' => 1,
'sanitize_callback' => 'absint',
),
'per_page' => array(
'description' => 'Número máximo de items a devolver en el conjunto de resultados.',
'type' => 'integer',
'default' => 10,
'sanitize_callback' => 'absint',
),
'search' => array(
'description' => 'Limitar resultados a aquellos que coincidan con un string.',
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
);
}
// Registra nuestro servidor REST
public function hook_rest_server(){
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
}
}
$myEndpoint = new MCQAcademy_Endpoint();
$myEndpoint->hook_rest_server();
Todo funciona correctamente excepto cuando se llama a la función wp_get_current_user()
en la función get_items()
, que devuelve un usuario vacío a pesar de que el usuario está logueado
en el sitio web.

Iniciar sesión en tu sitio web no significa que el usuario esté autenticado en la solicitud de la API REST, por eso no estás obteniendo el usuario correcto o un Id = 0
Por favor, revisa los métodos de autenticación de la API REST en la documentación:
https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/
Para desarrolladores que realizan solicitudes Ajax manuales, el nonce deberá pasarse con cada solicitud. La API utiliza nonces con la acción establecida en wp_rest. Estos se pueden pasar a la API a través del parámetro de datos _wpnonce (ya sea en datos POST o en la consulta para solicitudes GET), o a través del encabezado X-WP-Nonce. Si no se proporciona un nonce, la API establecerá el usuario actual en 0, convirtiendo la solicitud en una solicitud no autenticada, incluso si has iniciado sesión en WordPress.
Para autenticación remota, recomendaría el plugin JWT para comenzar rápidamente:
O puedes usar los sugeridos en la documentación:

Necesito el ID de usuario si el usuario ha iniciado sesión en el sitio. Como el endpoint es abierto, no es necesario verificar permisos.

Esta línea siempre devuelve falso incluso cuando el usuario ha iniciado sesión en el sitio web.
$rs['wp_get_current_user'] = is_user_logged_in() ? get_current_user_id() : false;

Hola @ShahAlom como mencioné en mi respuesta, un usuario con sesión iniciada en el sitio web no es lo mismo que un usuario autenticado en la REST API, por favor revisa los métodos de autenticación de la REST API en la documentación: https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/

Para autenticación mediante cookies: Para desarrolladores que realizan solicitudes Ajax manuales, el nonce deberá pasarse con cada solicitud. La API utiliza nonces con la acción establecida como wp_rest. Estos pueden pasarse a la API a través del parámetro de datos _wpnonce (ya sea en datos POST o en la consulta para solicitudes GET), o a través de la cabecera X-WP-Nonce. Si no se proporciona un nonce, la API establecerá el usuario actual en 0, convirtiendo la solicitud en una solicitud no autenticada, incluso si estás conectado a WordPress.

Por favor actualiza tu respuesta con este último comentario para que pueda aceptarla como solución.

Incluso con autenticación JWT, aún necesitas pasar la cabecera X-WP-Nonce para obtener el usuario actual, por ejemplo si necesitas acceder a users/me sigue devolviendo 401, lo mismo para consultar usuarios por rol, y así sucesivamente. Las solicitudes AJAX "no manuales" son "especiales" solo porque el cliente oficial de la API incluye esa cabecera, pero nada más.

@JesúsFranco según mi experiencia usando el plugin JWT, no es necesario enviar ningún encabezado adicional, solo el encabezado Authorization con el token generado previamente para autenticación, /wp-v2/users/me
funciona para mí

Hmm, eso me hace pensar qué podría ser diferente entre configuraciones, ¿la versión del plugin? ¿Del core?

Pensando en cuáles podrían ser las diferencias, he observado dos tipos de solicitudes que son prohibidas sin usar el nonce, y también permitidas sin él. La diferencia que he notado es el entorno de la solicitud. Las solicitudes a través de un script PHP se permiten con solo el Token, las solicitudes a través del navegador no se permiten sin el nonce.

@JesúsFranco tienes razón, para las peticiones del lado del servidor (mi caso), el token será suficiente, para llamadas AJAX manuales/del lado del cliente, debes incluir el nonce para evitar CSRF, no es necesario incluir el token ya que ya tienes un usuario logueado y el lado del cliente está basado en cookies

Si llega una llamada API que no tiene un nonce establecido, WordPress desautenticará la solicitud, eliminando al usuario actual y haciendo que la solicitud no esté autenticada. Esta protección CSRF es automática, y no tienes que hacer nada para que funcione, aparte de incluir el nonce.
La forma de resolver esto es incluir un nonce. Algo como esto:
$_wpnonce = wp_create_nonce( 'wp_rest' );
echo "<input type = 'hidden' name = '_wpnonce' value = '$_wpnonce' />";
E inclúyelo en tu solicitud API. El nonce debe llamarse "_wpnonce" y la acción debe ser "wp_rest" para que la API funcione. Puede ir en la URL o en el cuerpo del post.

Para tener un ejemplo de código completamente funcional, aquí presentamos un plugin de ejemplo sobre cómo recuperar el ID del usuario actual mediante 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() {
// Agregar JS
wp_enqueue_script('my-plugin', plugin_dir_url(__FILE__) . 'js/scripts.js', ['jquery'], NULL, TRUE);
// Pasar nonce a JS
wp_localize_script('my-plugin', 'MyPluginSettings', [
'nonce' => wp_create_nonce('wp_rest'),
]);
}
function rest() {
// Registrar ruta
register_rest_route('my-plugin/v1', '/uid', [
'methods' => WP_REST_Server::READABLE,
'callback' => [$this, 'rest_callback'],
]);
}
function rest_callback($data) {
// Obtener ID del usuario actual
$data = [
'uid' => get_current_user_id(),
];
$response = new WP_REST_Response($data, 200);
// Establecer cabeceras
$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) {
// Devolverá tu UID
console.log(response);
});
});
})(jQuery);
Recurso: https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/

No entiendo cómo se pasa 'MyPluginSettings' al script. Cosas a considerar: actualmente no estoy usando JQuery sino JavaScript "vanilla"... Solía insertar mi script en etiquetas HTML <script> cuando lo necesitaba, pero intenté incluirlos con wp_enqueue_script y tuve el mismo problema.

Lo resolví, había escrito una ruta incorrecta al adaptarlo para wp_enqueue_script(). Además, tenía múltiples scripts, y recién entendí que el primer parámetro de wp_enqueue_script() no es específico del plugin sino del script (quizás deberías cambiar 'my-plugin' en tu respuesta porque es confuso).

wp_get_current_user()
no funciona porque tu usuario no está configurado correctamente. Consulta el siguiente código en /wp-includes/user.php
como referencia.
if ( ! empty( $current_user ) ) {
if ( $current_user instanceof WP_User ) {
return $current_user;
}
// Actualizar de stdClass a 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 tiene un valor incorrecto. Forzarlo a WP_User con 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;
}
Todo lo que necesitas hacer es wp_set_current_user( {user_id} )
al inicio de tu API.
