PluginProbe
wp-forecast / 9.8
wp-forecast v9.8
10.0 trunk 1.4 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3..5 3..8 3.0 3.1 3.2 3.3 3.4 3.6 All 86 releases
wp-forecast / wp-forecast.php

wp-forecast.php in wp-forecast 9.8, at wp-forecast.php

537 lines 15.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: wp-forecast
4 * Plugin URI: http://www.tuxlog.de
5 * Description: wp-forecast is a highly customizable plugin for WordPress, showing weather-data from Open-Meteo or OpenWeathermMap.
6 * Version: 9.8
7 * Author: Hans Matzen
8 * Author URI: http://www.tuxlog.de
9 * License: GPLv2
10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
11 * Domain Path: lang
12 * Text Domain: wp-forecast
13 *
14 * @package wp-forecast
15 */
16
17 /**
18 * Copyright 2006-2025 Hans Matzen
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 */
34
35 //
36 // maximal number of widgets to use.
37 //
38 $wpf_maxwidgets = 8;
39
40 /*
41 ---------- no parameters to change after this point --------------------
42 */
43 // define path to wp-forecast plugin.
44 define( 'WPF_PATH', plugin_dir_path( __FILE__ ) );
45
46 // OpenWeathermap functions.
47 require_once 'func-openweathermap.php';
48 require_once 'func-openweathermap-v2.php';
49 // Open-Meteo functions.
50 require_once 'func-openmeteo.php';
51
52 // OpenUV data functions.
53 require_once 'func-openuv.php';
54 // ipstack functions.
55 require_once 'func-ipstack.php';
56
57 // generic functions.
58 require_once 'funclib.php';
59 // include setup functions.
60 require_once 'wpf-setup.php';
61 // include admin options page.
62 require_once 'wp-forecast-admin.php';
63 // display functions.
64 require_once 'wp-forecast-show.php';
65 // shortcodes.
66 require_once 'shortcodes.php';
67 // support for WordPress autoupdate.
68 require_once 'wpf-autoupdate.php';
69 // virtual page class.
70 require_once 'class-wpf-virtualpage.php';
71
72
73 global $blog_id;
74
75 /**
76 * Set cache with weather data for current parameters
77 * a wrapper function called via the init hook.
78 */
79 function wp_forecast_init() {
80 $count = (int) wpf_get_option( 'wp-forecast-count' );
81
82 $weather = array();
83
84 for ( $i = 0;$i < $count;$i++ ) {
85 $wpfcid = get_widget_id( $i );
86
87 $wpf_vars = get_wpf_opts( $wpfcid );
88
89 // use visitors location for weather and UV.
90 if ( isset( $wpf_vars['visitorlocation'] ) && $wpf_vars['visitorlocation'] ) {
91 // get users ip address.
92 $vip = ipstack_get_visitor_ip();
93
94 // get location information about ip address.
95 $vloc = ipstack_get_data( wpf_get_option( 'wp-forecast-ipstackapikey' ), $vip );
96
97 // find matching locations from open-meteo.
98 // search locations for openmeteo.
99 $openmeteo_loc = get_loclist( $wpf_vars['OPENMETEO_LOC_URI'], ( ! isset( $vloc['city'] ) ? '' : $vloc['city'] ) );
100
101 // guess the locations which might be correct matching the country.
102 $locations = array();
103
104 // prefilter list of found locations to reduce runtime.
105 foreach ( $openmeteo_loc as $al ) {
106 if ( strpos( $al['country'], $vloc['country_name'] ) !== false ) {
107 $locations[] = $al;
108 }
109 }
110
111 if ( count( $locations ) == 1 ) {
112 // if there is only one location in the array take this one.
113 $wpf_vars['location'] = $locations[0]['name'];
114 $wpf_vars['locname'] = $locations[0]['name'];
115 $wpf_vars['loclatitude'] = $locations[0]['latitude'];
116 $wpf_vars['loclongitude'] = $locations[0]['longitude'];
117 } else {
118 // get the weather data of all the weather locations in the array and find the best match on lat and lon.
119 $ldist = 99000.0;
120 $lat1 = ( ! isset( $vloc['latitude'] ) ? '' : $vloc['latitude'] );
121 $lon1 = ( ! isset( $vloc['longitude'] ) ? '' : $vloc['longitude'] );
122 $tloc = '';
123 $tname = '';
124 foreach ( $locations as $ll ) {
125 $lat2 = $ll['latitude'];
126 $lon2 = $ll['longitude'];
127 $cdist = distanceCalculation( $lat1, $lon1, $lat2, $lon2 );
128
129 if ( $cdist < $ldist ) {
130 $ldist = $cdist;
131 $tloc = $ll['name'];
132 $tname = $ll['name'];
133 $tlat = $ll['latitude'];
134 $tlon = $ll['longitude'];
135 }
136 }
137
138 if ( '' != $tloc ) {
139 $wpf_vars['locname'] = $tname;
140 $wpf_vars['location'] = $tloc;
141 $wpf_vars['loclatitude'] = $tlan;
142 $wpf_vars['loclongitude'] = $tlon;
143 } else {
144 // nothing found set default values.
145 $wpf_vars['location'] = 'Berlin Alexanderplatz';
146 $wpf_vars['locname'] = 'Berlin Alexanderplatz';
147 $wpf_vars['loclatitude'] = '52.521918';
148 $wpf_vars['loclongitude'] = '13.413215';
149 }
150 }
151
152 // make sure weather data is updated.
153 $wpf_vars['expire'] = 0;
154
155 // update wpf_vars in case we changed lat and lon.
156 wpf_update_option( 'wp-forecast-opts' . $wpfcid, serialize( $wpf_vars ) );
157 }
158
159 // check if we have to fetch the weather data or if we can use the cache.
160 if ( $wpf_vars['expire'] < time() ) {
161 switch ( $wpf_vars['service'] ) {
162 case 'openweathermap':
163 $w = openweathermap_get_weather_v2( $wpf_vars['OPENWEATHERMAP_BASE_URI'], $wpf_vars['apikey1'], $wpf_vars['loclatitude'], $wpf_vars['loclongitude'], $wpf_vars['metric'] );
164 $weather = openweathermap_get_data_v2( $w, $wpf_vars );
165 break;
166
167 case 'openweathermap3':
168 $w = openweathermap_get_weather( $wpf_vars['OPENWEATHERMAP_BASE_URI_V3'], $wpf_vars['apikey1'], $wpf_vars['loclatitude'], $wpf_vars['loclongitude'], $wpf_vars['metric'] );
169 $weather = openweathermap_get_data( $w, $wpf_vars );
170 break;
171 case 'openmeteo':
172 $w = openmeteo_get_weather( $wpf_vars['OPENMETEO_BASE_URI'], $wpf_vars['loclatitude'], $wpf_vars['loclongitude'], $wpf_vars['metric'] );
173 $weather = openmeteo_get_data( $w, $wpf_vars );
174 break;
175 }
176
177 // get OpenUV data if wanted.
178 if ( isset( $wpf_vars['ouv_apikey'] ) && trim( $wpf_vars['ouv_apikey'] ) != '' ) {
179 $ouv = openuv_get_data( $wpf_vars['ouv_apikey'], $weather['lat'], $weather['lon'] );
180 if ( is_wp_error( $ouv ) ) {
181 $weather['openuv'] = '';
182 $weather['failure'] = $ouv->get_error_message();
183 } else {
184 $weather['openuv'] = $ouv;
185 }
186 }
187
188 // store weather to database and set expire time.
189 // if the current data wasnt available use old data.
190 if ( count( $weather ) > 0 ) {
191 wpf_update_option( 'wp-forecast-cache' . $wpfcid, serialize( $weather ) );
192 if ( empty( $weather['failure'] ) || '' == $weather['failure'] ) {
193 wpf_update_option( 'wp-forecast-expire' . $wpfcid, time() + $wpf_vars['refresh'] );
194 } else {
195 wpf_update_option( 'wp-forecast-expire' . $wpfcid, 0 );
196 }
197 }
198 }
199 }
200
201 // javascript hinzufügen fuer ajax widget.
202 if ( ! is_admin() && get_option( 'wpf_sem_ajaxload' ) > 0 ) {
203 wp_enqueue_script( 'wpf_update', plugins_url( 'wpf_update.js', __FILE__ ), array( 'jquery' ), '9999' );
204 }
205 // javascript hinzufügen für suche im admin dialog.
206 if ( is_admin() ) {
207 wp_enqueue_script( 'wp-color-picker' );
208 wp_enqueue_script( 'wp-forecast-search', plugins_url( 'wp-forecast-admin.js', __FILE__ ), array( 'jquery' ), '9999' );
209 }
210
211 // add css attribute display to the list of safe css styles for pulldown widget.
212 add_filter(
213 'safe_style_css',
214 function( $styles ) {
215 $styles[] = 'display';
216 return $styles;
217 }
218 );
219 }
220
221
222 /**
223 * This function is called from your template
224 * to insert your weather data at the place you want it to be
225 * support to select language on a per call basis from Robert Lang.
226 *
227 * @param array $args Default parameters.
228 * @param string $wpfcid The Widget ID.
229 * @param string $language_override ISO Code of the language.
230 */
231 function wp_forecast_widget( $args = array(), $wpfcid = 'A', $language_override = null ) {
232 if ( '?' == $wpfcid ) {
233 $wpf_vars = get_wpf_opts( 'A' );
234 } else {
235 $wpf_vars = get_wpf_opts( $wpfcid );
236 }
237
238 if ( ! empty( $language_override ) ) {
239 $wpf_vars['wpf_language'] = $language_override;
240 }
241
242 if ( '?' == $wpfcid ) {
243 $weather = maybe_unserialize( wpf_get_option( 'wp-forecast-cacheA' ) );
244 } else {
245 $weather = maybe_unserialize( wpf_get_option( 'wp-forecast-cache' . $wpfcid ) );
246 }
247
248 show( $wpfcid, $args, $wpf_vars );
249 }
250
251 /**
252 * This is the wrapper function for displaying from sidebar.php
253 * and not as a widget. since the parameters are different we need this.
254 *
255 * @param string $wpfcid The Widget ID.
256 * @param string $language_override ISO Code of the language.
257 */
258 function wp_forecast( $wpfcid = 'A', $language_override = null ) {
259 wp_forecast_widget( array(), $wpfcid, $language_override );
260 }
261
262 /**
263 * A function to show a range of widgets at once.
264 *
265 * @param int $from Lowest widget number to display.
266 * @param int $to Highest widget number to display.
267 * @param int $numpercol Number of widgets per column.
268 * @param string $language_override ISO Code of the language.
269 */
270 function wp_forecast_range( $from = 0, $to = 0, $numpercol = 1, $language_override = null ) {
271 global $wpf_maxwidgets;
272 $wcount = 1;
273
274 // check min and max limit.
275 if ( $from < 0 ) {
276 $from = 0;
277 }
278
279 if ( $to > $wpf_maxwidgets ) {
280 $to = $wpf_maxwidgets;
281 }
282
283 // output table header.
284 echo '<table><tr>';
285
286 // out put widgets in a table.
287 for ( $i = $from;$i <= $to;$i++ ) {
288
289 if ( 1 == $wcount % $numpercol ) {
290 echo '<tr>';
291 }
292
293 echo '<td>';
294 wp_forecast( get_widget_id( $i ), $language_override );
295 echo '</td>';
296
297 if ( ( 0 == $wcount % $numpercol ) && ( $i < $to ) ) {
298 echo '</tr>';
299 }
300
301 ++$wcount;
302 }
303
304 // output table footer.
305 echo '</tr></table>';
306 }
307
308 /**
309 * A function to show a set of widgets at once.
310 *
311 * @param array $wset Array with numbers of widgets to display.
312 * @param int $numpercol Number of widgets per column.
313 * @param string $language_override ISO Code of the language.
314 */
315 function wp_forecast_set( $wset, $numpercol = 1, $language_override = null ) {
316 global $wpf_maxwidgets;
317 $wcount = 1;
318 $wset_max = count( $wset ) - 1;
319
320 // output table header.
321 echo '<table><tr>';
322
323 // out put widgets in a table.
324 for ( $i = 0;$i <= $wset_max;$i++ ) {
325
326 if ( 1 == $wcount % $numpercol ) {
327 echo '<tr>';
328 }
329
330 echo '<td>';
331 wp_forecast( $wset[ $i ], $language_override );
332 echo '</td>';
333
334 if ( ( 0 == $wcount % $numpercol ) && ( $i < $wset_max ) ) {
335 echo '</tr>';
336 }
337
338 ++$wcount;
339 }
340
341 // output table footer.
342 echo '</tr></table>';
343 }
344
345 /**
346 * Returns the widget data as an array.
347 *
348 * @param string $wpfcid The Widget ID.
349 * @param string $language_override ISO Code of the language.
350 */
351 function wp_forecast_data( $wpfcid = 'A', $language_override = null ) {
352 $wpf_vars = get_wpf_opts( $wpfcid );
353
354 if ( ! empty( $language_override ) ) {
355 $wpf_vars['wpf_language'] = $language_override;
356 }
357
358 $w = maybe_unserialize( wpf_get_option( 'wp-forecast-cache' . $wpfcid ) );
359
360 $weather_arr = array();
361
362 // read service dependent weather data.
363 switch ( $wpf_vars['service'] ) {
364 case 'openweathermap':
365 $weather_arr = openweathermap_forecast_data_v2( $wpfcid, $language_override );
366 break;
367 case 'openweathermap3':
368 $weather_arr = openweathermap_forecast_data( $wpfcid, $language_override );
369 break;
370 case 'openmeteo':
371 $weather_arr = openmeteo_forecast_data( $wpfcid, $language_override );
372 break;
373 }
374
375 // add openuv data to weather_arr.
376 if ( is_array( $w ) && array_key_exists( 'openuv', $w ) ) {
377 $weather_arr['openuv'] = $w['openuv'];
378 } else {
379 $weather_arr['openuv'] = array();
380 }
381
382 return $weather_arr;
383 }
384
385
386 /**
387 * Register the wp-forecast widget
388 */
389 function reg_wpf_widget() {
390 return register_widget( 'wpf_widget' );
391 }
392 /**
393 * Register the UV Widget
394 */
395 function reg_wpf_uv_widget() {
396 return register_widget( 'WpfUvWidget' );
397 }
398
399 /**
400 * Init the wp-forecast widgets.
401 */
402 function widget_wp_forecast_init() {
403 global $wp_version,$wpf_maxwidgets, $wpf_lang_dict;
404
405 // include widget class.
406 require_once 'class-wpf-widget.php';
407 require_once 'class-wpfuvwidget.php';
408
409 $count = (int) wpf_get_option( 'wp-forecast-count' );
410
411 // check for widget support.
412 if ( ! function_exists( 'register_sidebar_widget' ) ) {
413 return;
414 }
415
416 // add fetch weather data to init the cache before any headers are sent.
417 add_action( 'init', 'wp_forecast_init' );
418 add_action( 'admin_init', 'wp_forecast_admin_init' );
419
420 // add css.
421 add_action( 'wp_enqueue_scripts', 'wp_forecast_css' );
422
423 for ( $i = 0;$i <= $wpf_maxwidgets;$i++ ) {
424 $wpfcid = get_widget_id( $i );
425
426 // register our widget and add a control.
427 // translators: %s is for the Widget ID.
428 $name = sprintf( __( 'wp-forecast %s' ), $wpfcid );
429 $id = "wp-forecast-$wpfcid";
430
431 // translators: %s is for the widget ID.
432 $uvname = sprintf( __( 'wp-forecast-uv %s' ), $wpfcid );
433 $uvid = "wp-forecast-uv-$wpfcid";
434
435 // add widget.
436 add_action( 'widgets_init', 'reg_wpf_widget' );
437 add_action( 'widgets_init', 'reg_wpf_uv_widget' );
438
439 wp_unregister_sidebar_widget( $i >= $count ? 'wp_forecast_widget' . $wpfcid : '' );
440
441 wp_register_widget_control(
442 $id,
443 $name,
444 $i < $count ? 'wpf_admin_hint' : '',
445 array(
446 'width' => 300,
447 'height' => 150,
448 )
449 );
450
451 wp_unregister_widget_control( $i >= $count ? 'wpf_admin_hint' . $wpfcid : '' );
452 }
453 }
454
455 /**
456 * Filters the REQUEST_URI for virtual page slug
457 * to show weather in an iframe.
458 */
459 function wpf_filter_url() {
460 $url = ( isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '' );
461 $url = trim( parse_url( $url, PHP_URL_PATH ), '/' );
462
463 // determine if it is a wpf virtual page call.
464 if ( strpos( $url, 'wp-forecast-direct' ) !== false ) {
465 $wpfcid = ( isset( $_GET['wpfcid'] ) ? sanitize_text_field( wp_unslash( $_GET['wpfcid'] ) ) : 'A' );
466 $language_override = ( isset( $_GET['language_override'] ) ? sanitize_text_field( wp_unslash( $_GET['language_override'] ) ) : '' );
467 $header = ( isset( $_GET['header'] ) ? sanitize_text_field( wp_unslash( $_GET['header'] ) ) : '' );
468 $selector = ( isset( $_GET['selector'] ) ? sanitize_text_field( wp_unslash( $_GET['selector'] ) ) : '' );
469
470 if ( '1' == $selector ) {
471 $selector = '?';
472 }
473 $args = array();
474 $wpf_vars = get_wpf_opts( $wpfcid );
475
476 if ( ! empty( $language_override ) ) {
477 $wpf_vars['wpf_language'] = $language_override;
478 }
479
480 $weather = maybe_unserialize( wpf_get_option( 'wp-forecast-cache' . $wpfcid ) );
481
482 // only show weather html without page or header.
483 if ( ! $header || 0 == $header ) {
484 show( $selector . $wpfcid, $args, $wpf_vars );
485 exit;
486 }
487
488 if ( 1 == $header ) {
489 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
490 echo '<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="' . esc_attr( str_replace( '_', '-', $wpf_vars['wpf_language'] ) ) . '">' . "\n";
491 echo "<head><title>wp-forecast iframe</title>\n";
492 echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />' . "\n";
493 echo '<style>' . wp_kses( wp_forecast_get_nowp_css(), wpf_allowed_tags() ) . '</style>' . "\n";
494 echo "</head>\n<body>\n";
495
496 show( $selector . $wpfcid, $args, $wpf_vars );
497
498 echo "</body></html>\n";
499 exit;
500 }
501
502 if ( 2 == $header ) {
503 // create weather html.
504 // add css.
505 add_action( 'wp_enqueue_scripts', 'wp_forecast_css_nowp' );
506 ob_start();
507 show( $selector . $wpfcid, $args, $wpf_vars );
508 $out = ob_get_contents();
509 ob_end_clean();
510
511 // create virtual page and display it.
512 $args = array(
513 'slug' => 'wp-forecast-direct',
514 'title' => 'wp-forecast weather',
515 'content' => $out,
516 );
517 $pg4 = new Wpf_VirtualPage( $args );
518 }
519 }
520 }
521
522
523 // MAIN.
524
525 // activating deactivating the plugin.
526 register_activation_hook( __FILE__, 'wp_forecast_activate' );
527 register_deactivation_hook( __FILE__, 'wp_forecast_deactivate' );
528
529 // add option page.
530 add_action( 'admin_menu', 'wp_forecast_admin' );
531
532 // Run our code later in case this loads prior to any required plugins.
533 add_action( 'plugins_loaded', 'widget_wp_forecast_init' );
534
535 // add virtual page filter.
536 add_action( 'init', 'wpf_filter_url' );
537