I'm using the Wordpress Rest API to import content from a Wordpress website into a PHP application. It's nothing complex, just a main page with the list of posts and the pages for individual posts.
I added some fields to the API response, in particular one to get the url of the first image inserted in the post.
This is the code for this part:
add_action('rest_api_init', function () {
register_rest_field('post', 'post_images', array(
'get_callback' => 'get_first_image',
'update_callback' => null,
'schema' => null
));
});
function get_first_image($obj, $name, $request)
{
$images = get_attached_media('image', $obj['id']);
$imagesArray = (array) $images;
reset($imagesArray);
$firstImageId = current($imagesArray)->ID;
$imageSrc = wp_get_attachment_image_url($firstImageId);
return $imageSrc;
}
It works fine when I'm listing posts in the main page, but from the individual post page the field is empty. The only explanation I can come up with for this is that I have this custom endpoint for the single posts:
function post_by_slug(WP_REST_Request $request)
{
$postSlug = $request->get_param('post_slug');
$lang = $request->get_param('my_lang');
$myPost = get_page_by_path($postSlug, OBJECT, 'post');
$targetPostId = apply_filters('wpml_object_id', $myPost->ID, 'post',
false, $lang);
$targetPost = get_post($targetPostId);
$postController = new \WP_REST_Posts_Controller($targetPost->post_type);
$response = $postController->prepare_item_for_response($targetPost,
$request);
return rest_ensure_response($response);
}
add_action('rest_api_init', function () {
register_rest_route('pc/v1',
"/post-slug/(?P<post_slug>\S+)/(?P<my_lang>\w+)", [
'methods' => 'GET',
'callback' => 'post_by_slug',
'args' => [
'post_slug' => 'required',
'my_lang' => 'required'
]
]);
});
From my app, I call it this way:
$client = new Client([
'base_uri' => 'http://example.com/wp-json/pc/v1/',
'headers' => [
'Content-Type' => 'application/json',
"Accept" => "application/json",
],
'verify' => false,
]);
var_dump(json_decode($client->get("post-slug/$slug/$lang")
->getBody()->getContents()));
What's strange is that accessing the same endpoint directly from the browser I can see all the fields correctly. Am I missing something ovious?
Just answering my own question because I've found what was causing the endpoint to work correctly from my browser but not when accessed through Guzzle.
The problem was that I was logged in as an admin, so the WPML plugin that I'm using to manage multiple languages on the website was setting this cookie:
wp-wpml_current_admin_language_d41d8cd98f00b204e9800998ecf8427e:"de"
So the problem was related to this plugin, which I'm actually using in the post_by_slug
function.
Somehow, specifying the language as I do here is not enough, or just serves a different purpose, not sure:
$targetPostId = apply_filters('wpml_object_id', $myPost->ID, 'post', false, $lang);
There are two solutions I could find:
1) explicitly setting the languge using the plugin switch_lang()
method:
function post_by_slug(WP_REST_Request $request) {
global $sitepress;
$postSlug = $request->get_param('post_slug');
$lang = $request->get_param('my_lang');
$sitepress->switch_lang($lang);
2) change the guzzle GET request to pass the language as a query parameter, which seems to automatically work with the plugin:
$response = $client->get("post-slug/$slug", ['query' => ['lang' => $lang]])->getBody()->getContents();
I realize that this is a very specific problem, but maybe it will be of help to someone else.