MODX Community

Dark Sky API Forecast Snippet

I am trying to create a snippet that will take in a Dark Sky API key, latitude, longitude, number of hours to be forecasted, and return an hourly forecast formatted by a chunk. I am completely new to php, and programming in general, so please bear with me as I cobbled this together from a youtube tutorial :grimacing:

I would like the content to populate the tags [[+hour]] [[+temp]] [[+humidity]] [[+windspeed]] [[+summary]] with the proper information from the returned JSON. The hour using the date() function to format properly. I can loop through it, but I am completely lost in how to proceed from there, and confused by documentation.

Snippet call:
[[darkSkyWeatherHourly?
     &api=`API KEY HERE`
     &lat=`39.331913`
     &lng=`-76.646173`
     &hours=`4`
     &tpl=`weatherHourlyTpl`
]]

Snippet:

$coordinates = $lat.','.$lng
$api_url = 'https://api.darksky.net/forecast/'.$api.'/'.$coordinates;
$forecast = json_decode(file_get_contents($api_url));
date_default_timezone_set($forecast->timezone);

$i = 0;
foreach($forecast->hourly->data as $hour) {

    // Originally just an echo call, unsure how to proceed to work with chunk.
    $temp = round($hour->temperature)

    $i++;
    if($i==$hours) break;
}
1 Like

@ShatteredSite, first make sure to end lines 1 and 11 with a “;”.

Assuming the rest of your PHP lines up, I think all you are missing in your snippet is something like this:

$modx->setPlaceholder('hour', $hr);
$modx->setPlaceholder('temp', $temp);
$modx->setPlaceholder('humidity', $hum);
$modx->setPlaceholder('windspeed', $spd);

Maybe prepend “weather_” to them to be safe?-Wait, there might be a more efficient way of writing this… :thinking:

Eureka!!! Do this instead…

$modx->setPlaceholders(array(
   'hour' => $hr,
   'temp' => $temp,
   'humidity' => $hum,
   'windspeed' => $spd
),'weather.');

Learn more about this here.

Then in your chunk: weather.hour, weather.humidity

Remember to check out any errors in your log (Nav: Manage > Reports > Error Log).

1 Like

So something like this? This doesn’t seem complete, but this is what I got thus far. How does this take into account the tpl parameter passed to the chunk?

<?php
    $coordinates = $lat.','.$lng;
    $api_url = 'https://api.darksky.net/forecast/'.$api.'/'.$coordinates;
    $forecast = json_decode(file_get_contents($api_url));
	date_default_timezone_set($forecast->timezone);

	$i = 0;
	foreach($forecast->hourly->data as $hour) {
        $modx->setPlaceholders(array(
             'hour' => date("g a",$hour->time),
             'temp' => round($hour->temperature),
             'humidity' => $hour->humidity*100,
             'windspeed' => round($hour->windSpeed)
        ),'weather.');

	    $i++;

	    if($i==$hours) break;
	}

The chunk being this?

<li class="list-group-item d-flex justify-content-between">
    <p class="lead m-0">
        [[+weather.time]]
    </p>
    <p class="lead m-0">
        [[+weather.temp]]&deg;
    </p>
    <p class="lead m-0">
        [[+weather.humidity]]
    </p>
    <p class="lead m-0">
        [[+weather.windspeed]]
    </p>
</li>

I think that you want this

$modx->getChunk('chunkName',array(
   'hour' => date("g a",$hour->time),
   'temp' => round($hour->temperature),
   'humidity' => $hour->humidity*100,
   'windspeed' => round($hour->windSpeed)
));

you can leave out the weather. on the placeholder names.

Ok I replaced it with the getChunk and removed the .weather in the placeholder names, but no output as of yet. What is the last step?

<?php
$coordinates = $lat.','.$lng;
    $api_url = 'https://api.darksky.net/forecast/'.$api.'/'.$coordinates;
    $forecast = json_decode(file_get_contents($api_url));
	//Set timezone based on location searched
	date_default_timezone_set($forecast->timezone);
	//Set counter at zero
	$i = 0;
	// Start the foreach loop to get hourly forecast
	foreach($forecast->hourly->data as $hour) {
        $modx->getChunk($tpl,array(
           'hour' => date("g a",$hour->time),
           'temp' => round($hour->temperature),
           'humidity' => $hour->humidity*100,
           'windspeed' => round($hour->windSpeed)
        ));
	    // Increase counter by one for each iteration
	    $i++;
	    //Stop after set number of iterations
	    if($i==$hours) break;
	}

anything in the error log?

@ShatteredSite, I apologize, I don’t think I understanding your question. But it looks like you have everything you need…

Snippet (darkSkyWeatherHourly)

<?php
    $coordinates = $lat.','.$lng;
    $api_url = 'https://api.darksky.net/forecast/'.$api.'/'.$coordinates;
    $forecast = json_decode(file_get_contents($api_url));
    date_default_timezone_set($forecast->timezone);

    $i = 0;
    foreach($forecast->hourly->data as $hour) {
        $modx->setPlaceholders(array(
            'hour' => date("g a",$hour->time),
            'temp' => round($hour->temperature),
            'humidity' => $hour->humidity*100,
            'windspeed' => round($hour->windSpeed)
        ),'weather.');
        $i++;
        if($i==$hours) break;
    }
?>

Chunk (ChunkName)

[[darkSkyWeatherHourly?
     &api=`API KEY HERE`
     &lat=`39.331913`
     &lng=`-76.646173`
     &hours=`4`
     &tpl=`weatherHourlyTpl`
]]

<li class="list-group-item d-flex justify-content-between">
    <p class="lead m-0">
        [[+weather.time]]
    </p>
    <p class="lead m-0">
        [[+weather.temp]]&deg;
    </p>
    <p class="lead m-0">
        [[+weather.humidity]]
    </p>
    <p class="lead m-0">
        [[+weather.windspeed]]
    </p>
</li>

Template

[[$ChunkName]]

No errors when using the getChunk() function with no prefixes on the tag names. Same goes for using the setPlaceholders() function Mr_JimWest used, but I think that was for another use. getChunk() seems the way to go.

@Mr_JimWest Yes I think you misunderstood me. I don’t want it to fill in tags in the page, I want it to loop through records, and outputting them using a chunk with placeholders. Similar to how getResources works, but calling information from Dark Sky API JSON.

So just to clarify, since this thread got a bit jumbled, I should have been more descriptive. Here is what I have, but get no output at all, not even the html in the chunk, and no errors in the error log. I just get nothing.

Snippet:

<?php
    $coordinates = $lat.','.$lng;
    $api_url = 'https://api.darksky.net/forecast/'.$api.'/'.$coordinates;
    $forecast = json_decode(file_get_contents($api_url));
	//Set timezone based on location searched
	date_default_timezone_set($forecast->timezone);
	//Set counter at zero
	$i = 0;
	// Start the foreach loop to get hourly forecast
	foreach($forecast->hourly->data as $hour) {
        $modx->getChunk($tpl,array(
           'hour' => date("g a",$hour->time),
           'temp' => round($hour->temperature),
           'humidity' => $hour->humidity*100,
           'windspeed' => round($hour->windSpeed)
        ));
	    // Increase counter by one for each iteration
	    $i++;
	    //Stop after set number of iterations
	    if($i==$hours) break;
	}

Snippet call in page template, called uncached for testing: (api key will change once this thread closes).

        [[!darkSkyWeatherHourly?
            &api=`79c8c6a56f026dcd6bbde3c0658cdd35`
            &lat=`39.331913`
            &lng=`-76.646173`
            &hours=`4`
            &tpl=`weatherHourlyTpl`
        ]]

Chunk (tpl):

<li class="list-group-item d-flex justify-content-between">
    <p class="lead m-0">
        [[+time]]
    </p>
    <p class="lead m-0">
        [[+temp]]&deg;
    </p>
    <p class="lead m-0">
        [[+humidity]]
    </p>
    <p class="lead m-0">
        [[+windspeed]]
    </p>
</li>

Assign the result of $modx->getChunk() to a variable, and return that at the end of the snippet.

For example:

<?php

$output = [];
$coordinates = $lat . ',' . $lng;
$api_url = 'https://api.darksky.net/forecast/' . $api . '/' . $coordinates;
$forecast = json_decode(file_get_contents($api_url));
//Set timezone based on location searched
date_default_timezone_set($forecast->timezone);
//Set counter at zero
$i = 0;
// Start the foreach loop to get hourly forecast
foreach ($forecast->hourly->data as $hour) {
    $output[] = $modx->getChunk($tpl, [
        'hour' => date('g a', $hour->time),
        'temp' => round($hour->temperature),
        'humidity' => $hour->humidity * 100,
        'windspeed' => round($hour->windSpeed)
    ]);
    // Increase counter by one for each iteration
    $i++;
    //Stop after set number of iterations
    if ($i == $hours) {
        break;
    }
}

return implode("\n", $output);
1 Like

Perfect! Thanks Mark!

So the snippet is working perfectly, at least from the front end. I am getting errors in the log though. Is this something to be concerned about?

[2020-01-05 17:05:43] (ERROR @ /home/activat6/core/cache/includes/elements/modsnippet/147.include.cache.php : 11) PHP warning: Invalid argument supplied for foreach()
[2020-01-05 17:05:43] (ERROR @ /home/activat6/core/cache/includes/elements/modsnippet/147.include.cache.php : 5) PHP warning: file_get_contents(https://api.darksky.net/forecast//,): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request

That would mean the snippet is trying to run at least once where the $api and $coordinates variables don’t have values.

The errors are referring to cache files though. Are you still running the snippet uncached?

Yes I am running it uncached. Considering it needs to refresh every 10 minutes, the page and snippet are both uncached.

As a quick fix for the error messages, you could add some validation to make sure the variables have values before running the snippet. For example:

<?php
// Early return if there are no values.
if(!$api || !$coordinates) return '';

$output = [];
$coordinates = $lat . ',' . $lng;
$api_url = 'https://api.darksky.net/forecast/' . $api . '/' . $coordinates;
$forecast = json_decode(file_get_contents($api_url));
//Set timezone based on location searched
date_default_timezone_set($forecast->timezone);
//Set counter at zero
$i = 0;
// Start the foreach loop to get hourly forecast
foreach ($forecast->hourly->data as $hour) {
    $output[] = $modx->getChunk($tpl, [
        'hour' => date('g a', $hour->time),
        'temp' => round($hour->temperature),
        'humidity' => $hour->humidity * 100,
        'windspeed' => round($hour->windSpeed)
    ]);
    // Increase counter by one for each iteration
    $i++;
    //Stop after set number of iterations
    if ($i == $hours) {
        break;
    }
}

return implode("\n", $output);

But that’s not solving the underlying issue as to why it’s happening in the first place.
Is your error_page system setting set to the same resource you’re running the snippet on by any chance?

No, the error_page setting does not match the resource.