PluginProbe
wp-forecast / 9.3
wp-forecast v9.3
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.3, at wp-forecast.php

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