How to show daily meteorological conditions?

I have set HTML using Bootstrap CSS.

How to set a daily meteorological conditions using OpenWeather API and PHP:

<div class="">

<div class="container">

<div class="daily_list">Today</div>

<div>
<div class="daily_list_image1"><img src="sun.svg" width="60" height="60"></div>
<div class="temp-hi1">10°C</div>
<div class="temp-low1">-12°C</div>

</div></div>

<div class="container">

<div class="daily_list">Tomorrow</div><div>

<div class="daily_list_image1"><img src="cloudy.svg" width="60" height="60"></div>
<div class="temp-hi1">10°C</div>
<div class="temp-low1">-15°C</div>
</div></div>

</div>

Hi, you need OpenWeather’s One Call API 3.0, which includes daily forecasts.

The basic steps would be:

  • Get the latitude / longitude for the location (e.g. via the geocoding API).
  • Call the One Call endpoint to fetch the forecast as JSON.
  • Read the daily forecast data (today, tomorrow, etc.) and render it into your HTML.

Example in PHP (very untested):

$lat = 48.19;
$lon = 11.37;
$apiKey = 'YOUR_API_KEY';

$url = "https://api.openweathermap.org/data/3.0/onecall?lat=$lat&lon=$lon&units=metric&appid=$apiKey";
$response = file_get_contents($url);
$data = json_decode($response, true);

foreach (array_slice($data['daily'], 0, 2) as $index => $day) {
    $label = $index === 0 ? 'Today' : 'Tomorrow';
    $tempMax = round($day['temp']['max']);
    $tempMin = round($day['temp']['min']);
    $icon = $day['weather'][0]['icon'];

    echo "
    <div class='container'>
        <div class='daily_list'>$label</div>
        <div>
            <div class='daily_list_image1'>
                <img src='https://openweathermap.org/img/wn/$icon@2x.png' width='60' height='60'>
            </div>
            <div class='temp-hi1'>{$tempMax}°C</div>
            <div class='temp-low1'>{$tempMin}°C</div>
        </div>
    </div>
    ";
}

This way you don’t hardcode “Today” / “Tomorrow” or the temperatures in HTML, they’re generated dynamically from the API response.

I have defined PHP code as dynamically. How to push tempMax variable as today and separate tomorrow? We have two headers and two Min, Max. It means 2 index (i) from 0 to 1 and each day Min, Max not only one.

<?php
echo "
<div class=''>

<div class='container'>

<div class='header1'>$label</div>

<div>
<div class='image1'><img src='https://openweathermap.org/img/wn/$icon@2x.png' width='60' height='60' /></div>
<div class='temp-hi1'>{$tempMax}°C</div>
<div class='temp-low1'>{$tempMin}°C</div>

</div></div>

<div class='container'>

<div class='header2'>$label</div><div>

<div class='image1'><img src='https://openweathermap.org/img/wn/$icon@2x.png' width='60' height='60' /></div>
<div class='temp-hi1'>{$tempMax}°C</div>
<div class='temp-low1'>{$tempMin}°C</div>
</div></div>

</div>
    ";
?>

As far as I can see Jim’s code outputs two containers with unique values for each.

Couldn’t you add a similar line to label?

$header = $index === 0 ? 'header1' : 'header2';

or something along the lines of

class='header{$index+1}'

Then edit the echo container string accordingly.

Is this the correct PHP in this case or it can be better? It can be forecast managed 10 days in advance…

    $label = $index === 0 ? 'label_info_index_0' : 'label_info_index_1';
    $tempMax = $index === 0 ? 'tempMax_info_index_0' : 'tempMaxl_info_index_1';
    $tempMin = $index === 0 ? 'tempMin_info_index_0' : 'tempMinl_info_index_1';

and echo:

echo "

<div class=''>

<div class='container'>

<div class='header1'>$label_info_index_0</div>

<div>
<div class='image1'><img src='https://openweathermap.org/img/wn/$icon@2x.png' width='50' height='50' /></div>
<div class='temp-hi1'>{$tempMax_info_index_0}°C</div>
<div class='temp-low1'>{$tempMin_info_index_0}°C</div>

</div></div>

<div class='container'>

<div class='header2'>$label_info_index_1</div><div>

<div class='image1'><img src='https://openweathermap.org/img/wn/$icon@2x.png' width='50' height='50' /></div>
<div class='temp-hi1'>{$tempMax_info_index_1}°C</div>
<div class='temp-low1'>{$tempMin_info_index_1}°C</div>
</div></div>

</div>
    ";

Hi,

You don’t need separate variables like tempMax_info_index_0, tempMax_info_index_1, etc. That defeats the point of using a loop.

The correct way is one set of variables ($label, $tempMax, $tempMin, $icon) with one HTML template repeated by the loop (index 0 = today, 1 = tomorrow, 2 = next day, etc.)

Right now your problem is that you output two containers inside one loop iteration, so both use the same values. Instead, output one container per iteration:

foreach (array_slice($data['daily'], 0, 2) as $index => $day) {
    $label   = $index === 0 ? 'Today' : 'Tomorrow';
    $tempMax = round($day['temp']['max']);
    $tempMin = round($day['temp']['min']);
    $icon    = $day['weather'][0]['icon'];

    echo "
    <div class='container'>
        <div class='header".($index+1)."'>$label</div>
        <div>
            <div class='image1'>
                <img src='https://openweathermap.org/img/wn/$icon@2x.png' width='50' height='50'>
            </div>
            <div class='temp-hi1'>{$tempMax}°C</div>
            <div class='temp-low1'>{$tempMin}°C</div>
        </div>
    </div>
    ";
}

If later you want 10 days, just change it to: array_slice($data['daily'], 0, 10).

Thank you for the message!

I have tested and weather shows up. How to solve PHP error on website:

Fatal error: Uncaught TypeError: Cannot access offset of type string on string in

Is this HTML or PHP issue?

Hi,

As I mentioned, the snippet was untested and assumes the API response has the expected structure. That error means you’re accessing array offsets on a string, so this is a PHP/data issue, not HTML. In practice it usually means one of these:

  • $data is still a JSON string (not decoded with json_decode(..., true)), or
  • OpenWeather returned an error response, so $data['daily'] isn’t an array, or
  • you’re looping the wrong level of the response.

Before the loop, quickly verify that $data is an array and that $data['daily'] exists and is an array.

If you paste the output var_dump($data) that will help us debug.

It is working array.

How to block echo if JSON does not have an output or API is not working?

array(9) { [“lat”]=> float() [“lon”]=> float() [“timezone”]=> string(16) “” [“timezone_offset”]=> int(3600) [“current”]=> array(15) { [“dt”]=> int(1769266933) [“sunrise”]=> int(1769236405) [“sunset”]=> int(1769270007) [“temp”]=> float(3.07) [“feels_like”]=> float(3.07) [“pressure”]=> int(1005) [“humidity”]=> int(93) [“dew_point”]=> float(2.05) [“uvi”]=> float(0.01) [“clouds”]=> int(100) [“visibility”]=> int(2000) [“wind_speed”]=>

Fatal error: Uncaught TypeError: Cannot access offset of type string on string in

There has been a critical error on this website.

I do not see PHP error and issue as array value is pushed using JSON request:

<?php
$lat = '';
$lon = '';
$apiKey = '';

$url = "https://api.openweathermap.org/data/3.0/onecall?lat=$lat&lon=$lon&units=metric&appid=$apiKey";
$response = file_get_contents($url);
$data = json_decode($response, true);
//var_dump($data);
echo "
<nav class=''>

<div class=''>
";


foreach (array_slice($data['daily'], 0, 2) as $index => $day) {//10-Day Weather Forecast - City, array_slice($data['daily'], 0, 10) 
    $label = $index === 0 ? 'Today' : 'Tomorrow';
    $tempMax = round($day['temp']['max']);
    $tempMin = round($day['temp']['min']);
    $icon = $day['weather'][0]['icon'];
echo "
<div class='container".max(2, $index+1)."'>

<div class='header".($index+1)."'>$label</div>

<div>
<div class='image1'><img src='https://openweathermap.org/img/wn/$icon@2x.png' width='60' height='60' /></div>
<div class='temp-hi1'>{$tempMax}°C</div>
<div class='temp-low1'>{$tempMin}°C</div>

</div></div>
";
}

echo "
</div>

</nav>
";
?>

Hi, the problem is just that sometimes the API does not return daily (for example when the quota is hit, or OpenWeather returns an error message). Then your loop runs on invalid data and PHP crashes.

Just guard before the foreach:

if (!isset($data['daily']) || !is_array($data['daily'])) {
    // API call failed or no forecast data – don't output anything
    return;
}

Then run your loop as you do now.

HTH

I have put a code but weather is shown without an issue but result is the same:

Fatal error: Uncaught TypeError: Cannot access offset of type string on string in…

Is this an issue within WordPress theme but I am not sure…

Hi,

This is not likely a WordPress theme issue. That error will happen when PHP tries to do something like:

$day['temp']['max']

but $day is actually a string, not an array.

From your var_dump, I only see lat, lon, timezone, current, etc. But the output looks cut off and I don’t see daily. That could mean that you are getting some valid data back (e.g. current), but the crash happens when the code reaches the daily loop and the response isn’t the expected daily-forecast structure .

To help debug, add this just before your foreach:

var_dump(
    isset($data['daily']),
    gettype($data['daily'] ?? null),
    $data['message'] ?? null
);
exit;

Please let us know what that outputs.

Your code shows PHP error when validation is made.

Oh dear! Then let’s see what $data actually contains when the error happens. Please (temporarily) replace everything after json_decode with this:

echo '<pre>';
var_dump($data);
echo '</pre>';
exit;

Then reload the page and paste the output here.

Great, that makes sense :+1:

And yes, that check is in the right place to keep permanently:

if (!isset($data['daily']) || !is_array($data['daily'])) {
    echo "API call failed or no forecast data";
    return;
}

That way when the API works the forecast renders, but when OpenWeather returns an error / empty response there is no fatal error.

Your code will stop if data are not there. So, I guess this log validation should be placed.

if (!isset($data['daily']) || !is_array($data['daily'])) {
     echo "API call failed or no forecast data";
    return;
}

Also, when I test a error comes within MAX line. If we place 3 it will be thrown an error. If we have 2 as Max, it will not modify container as all the time it will be container 2 which should be container1 when index is 0. Index 0+1 =1. Next loop Index 1 + 1=2 and stop the loop.

<div class='container".max(2, $index+1)."'>

I think it should be more strict instruction inside PHP. As I understand PHP server can sometimes lose .max(2. Maybe I have Cache issue as WordPress lacks updates.

max(2, $index+1) is the reason you never get container1. It forces the number to be 2 or higher, so index 0 becomes 2.

If you want container1, container2, container3, etc. just do:

<div class='container".($index+1)."'>

Don’t assume there are always 3 days. Limit by what you actually received:

$days = $data['daily'] ?? [];
foreach (array_slice($days, 0, 3) as $index => $day) {
    ...
}

I want container1in the first loop.

The second loop , container2

The third loop , container2 stays. As I understand we have Max 2 due to this.

If your goal is:

  • first loop → container1
  • second loop → container2
  • third loop → container2 (and so on)

then don’t use max(). Just use the loop index directly:

$class = ($index === 0) ? 1 : 2;

and in your HTML:

<div class="container<?= $class ?>">

Did I get that right? Does that do what you want?