I wrote a plugin to hit an API and display results on a page. When I was testing, every time I hit "preview", the plugin would hit the API and retrieve the most recent data. Now that the plugin is live, when I navigate to the live page, no calls are being made to the API.
Through research I believe this is a caching issue, since we want real time data, we would like that every time a user navigates to the page, the plugin fires off to the API and the most recent values are returned.
Here is a snippet of my code:
function get_count(){
//get response from api
$request = wp_remote_get('');
if(is_wp_error($request)){
return false;
}
//get the body from the response
$body= json_decode(wp_remote_retrieve_body($request));
//parse the body and get the count attribute
$statistic=($body->payload->count);
return '<div id="value" class="number">'. $statistic . '</div>';
}
add_shortcode('real_time_count','get_count');
How can I make this execute every time a user navigates to a page that has this shortcode?
I wrote a plugin to hit an API and display results on a page. When I was testing, every time I hit "preview", the plugin would hit the API and retrieve the most recent data. Now that the plugin is live, when I navigate to the live page, no calls are being made to the API.
Through research I believe this is a caching issue, since we want real time data, we would like that every time a user navigates to the page, the plugin fires off to the API and the most recent values are returned.
Here is a snippet of my code:
function get_count(){
//get response from api
$request = wp_remote_get('https://myapi/count');
if(is_wp_error($request)){
return false;
}
//get the body from the response
$body= json_decode(wp_remote_retrieve_body($request));
//parse the body and get the count attribute
$statistic=($body->payload->count);
return '<div id="value" class="number">'. $statistic . '</div>';
}
add_shortcode('real_time_count','get_count');
How can I make this execute every time a user navigates to a page that has this shortcode?
If you want to make sure the data bypasses any front-end caching, you should use AJAX to request the data and print it on the page.
What I'd suggest is keeping your shortcode, but using AJAX to update it but creating a REST API endpoint. To do this you would abstract away the API request into its own function, and then have the shortcode and API response both use that function:
/**
* Function for retrieving the count from the API.
*/
function wpse_330377_get_count() {
$request = wp_remote_get( 'https://myapi/count' );
if( is_wp_error( $request ) ) {
return false;
}
$body = json_decode( wp_remote_retrieve_body( $request ) );
$statistic = $body->payload->count;
return $statistic;
}
/**
* Shortcode for outputting the count.
*/
function wpse_330377_count_shortcode() {
$statistic = wpse_330377_get_count();
return '<div id="value" class="number">'. $statistic . '</div>';
}
add_shortcode( 'real_time_count', 'wpse_330377_count_shortcode' );
/**
* REST API endpoint for getting the count.
*/
function wpse_330377_register_rest_route() {
register_rest_route(
'wpse_330377',
'count',
[
'method' => 'GET',
'callback' => 'wpse_330377_get_count'
]
);
}
add_action( 'rest_api_init', 'wpse_330377_register_rest_route' );
Now you can use JavaScript to send a request to the new API endpoint, /wp-json/wpse_330377/count
, which will give us the new value that we can use to update the #value
div.
Create a JavaScript file like this, in your theme or plugin:
jQuery.get(
{
url: wpse330377.apiUrl,
success: function( data ) {
jQuery( '#value' ).html( data );
}
}
);
And then enqueue it and pass it the correct URL:
function wpse_330377_enqueue_script() {
wp_enqueue_script( 'wpse_330377_count', 'URL TO SCRIPT GOES HERE', [ 'jquery' ], null, true );
wp_localize_script(
'wpse_330377_count',
'wpse330377',
[
'apiUrl' => rest_url( 'wpse_330377/count' ),
]
);
}
add_action( 'wp_enqueue_scripts', 'wpse_330377_enqueue_script' );
Just replace URL TO SCRIPT GOES HERE
with the actual URL. Use get_theme_file_uri()
to get the URL for a file in your theme, or plugins_url()
if it's in a plugin.
PS: Note that I've used wpse_330377
as a prefix and namespace in many places. You should use a prefix like this to prevent conflicts with WordPress and other themes or plugins. Ideally it would be something specific to your project.
I missed the last part of your question :facepalm:
In this case, it depends on what your caching mechanism is on your site. Some plugins, like W3 Total Cache, allow you to mark sections of a page as non-cacheable. If this isn't an option, then Jacob's answer about using AJAX is probably the way to go. This way, you can request the data "fresh" every time.
You should check a couple of things. The only caching that might affect wp_remote_get
would be on the response side of things, since WordPress does not cache anything it gets back in the WP_Http
class's request
method.
As Mike commented, do you get the same "empty" response using curl
? Try this on the command line if you have curl
available:
curl https://myapi/count
Does the response look the same as doing
curl https://myapi/count?foo=134134234234
?
If the responses differ, then your myapi
server may be caching the response. If not, you need to figure out why the remote server is not sending back the expected response.
If it's not caching, you should do something like this:
// In your wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', WP_DEBUG );
In your function above:
if ( is_wp_error( $request ) ) {
error_log( $request->get_error_message() );
}
Now, run your script, and then check the contents of /wp-content/debug.log
to see if there are any errors related to your request.
If your certificate for myapi
isn't "valid" (i.e. signed by a CA), you should look at the arg sslverify
for wp_remote_get
:
@type bool $sslverify Whether to verify SSL for the request. Default true.
Which can be modified like so:
wp_remote_get( 'https://myapi/count`, [ 'sslverify' => false ] );
You can use the current time to bust the cache of each request, like so:
$request = wp_remote_get( 'https://myapi/count?time=' . time() );