Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I am trying to use get_transient() method in my word-press ,have read the document and seems like i am doing what has been described in the docs.

I need to show Weather in my Website and i am using third part weather API which use to get updated in every 6 hours.

we are creating a local cache of weather so that API should get call only after expiry time (other reason is number of call per hour to API)

this is my code

$country   = 'India';
$API_Key  = 'xxxxxxxxxxxxxx';
$url        = 'http://weatherAPI.com/feed/weather.ashx?q='.$latlong.'&format=json&num_of_days=4&key='.$API_Key;

$weather = get_transient($location);
if (false === $weather) {
        $ch = curl_init();
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 0);
        $weather = curl_exec($ch);
        curl_close($ch);
        set_transient($location, $weather, 60*60*6);
 }

When i am sending a location to get weather (say delhi) and if its not there in the cache, i was expecting that it will return me false while its returning me following string

'{ "data": { "error": [ {"msg": "Unable to find any matching weather location to the query submitted!" } ] }}'

i used var_dump($weather ); to check value of $weather

Can anyone correct me where i am doing wrong?

share|improve this question
1  
This isn't related to get_transient() - but with the API request: as given by the error message. Apart from recommending you use wp_remote_post you'll just need to make sure the request being sent is a valid one. –  Stephen Harris Nov 22 '12 at 17:30
    
@StephenHarris:I am not sure about the call as its only being given inside if (false === $weather).i have updated my question –  Umesh Awasthi Nov 23 '12 at 1:29
1  
The point is cache will store whatever you give it - and in this case you're giving an error message from the weather API. The cache will only return false if there isn't anything stored - so you should check the response from the weather API and if its valid - store it. –  Stephen Harris Nov 23 '12 at 16:12
    
@StephenHarris:aha i got your point just missed it completely.i just started with PHP and i simply ignored everything and not even looked carefully at the code :) –  Umesh Awasthi Nov 23 '12 at 17:28
add comment

2 Answers 2

up vote 5 down vote accepted

Catching the weather API remote data

The msg, you're showing in your question is basically the result from the weather API. And it says, that there's no data available for your location.

The first thing you want to do is some research in the Codex and the "WP HTTP API".

The right/WP way to grab remote data

After you've learned about the WP HTTP API, you'll see that the common way to do it is (simplified like this):

$response = wp_remote_request( 'http://example.com?some=parameter', array(
    'ssl_verify' => true
) );

If there's an error (as shown in your example), then you'll be able to catch it using the WP_Error class:

is_wp_error( $response ) AND printf(
     'There was an ERROR in your request.<br />Code: %s<br />Message: %s'
    ,$response->get_error_code()
    ,$response->get_error_message()
);

Then it's time to get the appropriate data. This will show 200 and OK, if everything on the remote side worked out. IMPORTANT: The remote data will likely follow no standard than their internal one. So there can be errors, but you will still get the positive 200/OK message back from them.

$response_code   = wp_remote_retrieve_response_code( $response );
$response_status = wp_remote_retrieve_response_message( $response );

Get the result

Finally it's time to inspect the result. First, we get rid of leading/trailing white space(s). In the following sample, you see how to use the WP HTTP API to check the header. If we caught JSON, then we go with json_decode() and if we got XML, then we go with PHPs native SimpleXML class.

// Prepare the data:
$content = trim( wp_remote_retrieve_body( $response ) );
// Convert output to JSON
if (
    strstr(
         wp_remote_retrieve_header( $response, 'content-type' )
        ,'json'
    ) )
{
    $content = json_decode( $content );
}
// … else, after a double check, we simply go with XML string
elseif (
    strstr(
         wp_remote_retrieve_header( $response, 'content-type' )
        ,'application/xhtml+xml'
    ) )
{
    // Lets make sure it is really an XML file
    // We also get cases where it's "<?XML" and "<?xml"
    if ( '<?xml' !== strtolower( substr( $content, 0, 5 ) ) )
        return false;

    // Also return stuff wrapped up in <![CDATA[Foo]]>
    $content = simplexml_load_string( $content, null, LIBXML_NOCDATA );
}
// If both didn't work out, then we maybe got a CSV, or something else...

In case of a CSV file, you'll have to find a custom solution or search for a PHP class on the interwebs. But honestly: If they're using CSV, it's easier to search for another service.

Cache the data with a Transient

The Transient API offers a pretty nice way to do this:

// Set Transient
$transient = set_transient(
     'Your cache key'
    ,$content
    ,60*60*6
);

You should then be able to catch the transient with get_transient().

Common errors

An often encountered error is that the SSL verification doesn't work. Gladly you can turn it on/off pretty easy:

// ON:
add_filter( 'https_ssl_verify', '__return_true' );
// OFF:
add_filter( 'https_ssl_verify', '__return_false' );

There's one pretty funny thing, as you'll find out when inspecting the appropriate core file: Core also got a filter for local requests. But don't get fooled by this one. This filter is only meant to get used in case you're A) providing a remote service from within your WP install and B) also consuming it yourself! I know, this can be quite a #WTF?! moment that this isn't a switch for you to use different SSL verification settings between your local install and your production environment/server, but it also has an idea behind it: It's to test services that you provide yourself as I also explained to the WP G+ community here.

// Debug your own service without SSL verification.
add_filter( 'https_local_ssl_verify', '__return_false' );

Debugging the request & its results

Without diggin' too deep into the update process, but the WP HTTP API uses the WP_HTTP class. It also offers a nice thing: A debug hook.

do_action( 'http_api_debug', $response, 'response', $class, $args, $url );

Where $response can also be a WP_Error object that maybe tells you more.

Note: From a brief test, this filter seems to only (for some reason) work if you place it as close to where you're actually doing the request. So maybe you need to call it from within a callback on one of the below filters.

Y NO CURL?

Easy. All the funkiness of the "WP HTTP API", that I've shown above, is basically a function based wrapper for the WP_HTTP class internals, which acts as base class (and will be extended for different scenarios). The extending WP_HTTP_* classes are Fsockopen, Streams, Curl, Proxy, Cookie, Encoding. If you hook a callback to the 'http_api_debug'-action, then the third argument will tell you which class was used for your request. You don't have to call the classes directly. Just use the functions.

For most remote/HTTP API requests, it's the WP_HTTP_curl class, which is a wrapper for PHPs native curl library.

Inside the WP_HTTP_curl Class, you'll find the request() method. This method offers two filters to intercept the SSL behavior: One for local requests 'https_local_ssl_verify' and one for remote requests 'https_ssl_verify'. WP will likely define local as localhost and what you get in return from get_option( 'siteurl' );.

share|improve this answer
    
Note: This answer can be read as extension to this answer I gave. –  kaiser Nov 22 '12 at 17:37
    
Thanks for the inputs, i am not sure about the response from the waether API as its being getting called only when we have no data, i checked the URL for the API and its returning me valid data.Will try to debug it more –  Umesh Awasthi Nov 23 '12 at 1:26
    
@UmeshAwasthi Please try what I've written above - step by step. First see what you get back from wp_remote_request() with your URL, then go further with the answer. It's a pretty complete tutorial and shows you the right way to make HTTP requests in WP. To clarify a bite more: You don't have to call the WP_HTTP_curl class, as WordPress already does this for you, when you use the functions shown above. –  kaiser Nov 23 '12 at 1:39
    
i am on way to test this.will updated once i complete it :) –  Umesh Awasthi Nov 23 '12 at 1:44
1  
though the problem was something else, but i marked your answer as accepted as its provides a better way to do same work and i am of opinion that if platform is providing some API, its better to use them Thanks!! –  Umesh Awasthi Nov 26 '12 at 1:29
add comment

The problem is not with the 'transients' function. That looks like an error message returned from your third party API. You probably need to check that before you use set_transient. set_transient will insert whatever it is given and get_transient will retrieve whatever is in the DB. In other words, I am fairly sure the problem is not where you think it is.

$weather = get_transient($location);
if (false === $weather) {
        $ch = curl_init();
        curl_setopt ($ch, CURLOPT_URL, $url);
        curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 0);
        $weather = curl_exec($ch);
        curl_close($ch);
        // now check $weather to see if you got a valid result
        $check = json_decode($weather);
        if (isset($check->data->error)) {
          // there is a problem; do not insert; try something else
        } else {
          set_transient($location, $weather, 60*60*6);
        }
 }

I am guessing about some of the output from your weather API so you may need to tweak that to get the results you want.

Note: You API is returning JSON. Your example decodes to:

stdClass::__set_state(array(
   'data' => 
  stdClass::__set_state(array(
     'error' => 
    array (
      0 => 
      stdClass::__set_state(array(
         'msg' => 'Unable to find any matching weather location to the query submitted!',
      )),
    ),
  )),
))
share|improve this answer
    
Thanks for the input, but it seems a quite strange to me as only call to API is given only inside if (false === $weather) statement.I was not aware of WP_HTTP_curl class will try to use that –  Umesh Awasthi Nov 23 '12 at 1:28
    
@UmeshAwasthi, there is nothing strange about that conditional. If you have current data in the transients cache you don't want to retrieve it from the API. It is only if your transients cache is out of date that you pull new information. –  s_ha_dum Nov 26 '12 at 2:44
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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