PluginProbe
wp-forecast / 9.6
wp-forecast v9.6
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 / funclib.php

funclib.php in wp-forecast 9.6, at funclib.php

631 lines 18.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This file is part of the wp-forecast plugin for WordPress
4 *
5 * Copyright 2006-2023 Hans Matzen (email : webmaster at tuxlog dot de)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * @package wp-forecast
22 */
23
24 if ( ! function_exists( 'get_wpf_opts' ) ) {
25 /**
26 * Converts the given wind parameters into a suitable windstring.
27 *
28 * @param string $metric the units to use.
29 * @param string $wspeed the wind speed.
30 * @param string $windunit the unit of the wind to convert.
31 */
32 function windstr( $metric, $wspeed, $windunit ) {
33 // if its mph convert it to m/s.
34 if ( 1 != $metric ) {
35 $wspeed = round( $wspeed * 0.44704, 0 );
36 }
37
38 // convert it to selected unit.
39 switch ( $windunit ) {
40 case 'ms':
41 $wunit = 'm/s';
42 break;
43 case 'kmh':
44 $wspeed = round( $wspeed * 3.6, 0 );
45 $wunit = 'km/h';
46 break;
47 case 'mph':
48 $wspeed = round( $wspeed * 2.23694, 0 );
49 $wunit = 'mph';
50 break;
51 case 'kts':
52 $wspeed = round( $wspeed * 1.9438, 0 );
53 $wunit = 'kts';
54 break;
55 case 'bft':
56 $wbft = 0;
57 $bft = array( 0.3, 1.6, 3.4, 5.5, 8.0, 10.8, 13.9, 17.2, 20.8, 24.5, 28.5, 32.7 );
58 foreach ( $bft as $b ) {
59 if ( $wspeed < $b ) {
60 $wbft--;
61 break;
62 }
63 $wbft++;
64 }
65 $wunit = 'bft';
66 $wspeed = $wbft;
67 break;
68 }
69 return $wspeed . ' ' . $wunit;
70 }
71
72
73 /**
74 * Wrapper to make sure the correct option is used whether multisite or wp is used.
75 * only wraps main parameters and pass through all others.
76 *
77 * @param string $name the name of the option to get.
78 */
79 function wpf_get_option( $name ) {
80 global $blog_id;
81
82 if ( ! function_exists( 'is_multisite' ) || ! is_multisite() || 1 == $blog_id ) {
83 return get_option( $name );
84 } else {
85 // this is the multisite part.
86 if ( 'wpf_sa_defaults' == $name || 'wpf_sa_allowed' == $name ) {
87 return get_blog_option( 1, $name );
88 } else {
89 return get_blog_option( $blog_id, $name );
90 }
91 }
92 }
93
94 /**
95 * Wrapper for update option to hide differences between wp and wpmu.
96 *
97 * @param string $name the name of the option.
98 * @param string $value the value of the option.
99 */
100 function wpf_update_option( $name, $value ) {
101 global $blog_id;
102
103 if ( ! function_exists( 'is_multisite' ) || ! is_multisite() || 1 == $blog_id ) {
104 update_option( $name, $value );
105 } else {
106 update_blog_option( $blog_id, $name, $value );
107 }
108 }
109
110 /**
111 * Wrapper for add option to hide differences between wp and wpmu.
112 *
113 * @param string $name the name of the option.
114 * @param string $value the value of the option.
115 */
116 function wpf_add_option( $name, $value ) {
117 global $blog_id;
118
119 if ( ! function_exists( 'is_multisite' ) || ! is_multisite() || 1 == $blog_id ) {
120 add_option( $name, $value );
121 } else {
122 add_blog_option( $blog_id, $name, $value );
123 }
124 }
125
126 /**
127 * Reads all wp-forecast options and returns an array.
128 *
129 * @param $string $wpfcid the id of th widget.
130 */
131 function get_wpf_opts( $wpfcid ) {
132 global $blog_id;
133
134 $av = array();
135 $opt = wpf_get_option( 'wp-forecast-opts' . $wpfcid );
136
137 if ( ! empty( $opt ) ) {
138 // unpack if necessary.
139 $av = maybe_unserialize( $opt );
140 } elseif ( get_option( 'wp-forecast-location' . $wpfcid ) != '' ) {
141 // get old widget options from database.
142 $av['service'] = get_option( 'wp-forecast-service' . $wpfcid );
143 $av['apikey1'] = get_option( 'wp-forecast-apikey1' . $wpfcid );
144 $av['apikey2'] = get_option( 'wp-forecast-apikey2' . $wpfcid );
145 $av['location'] = get_option( 'wp-forecast-location' . $wpfcid );
146 $av['locname'] = get_option( 'wp-forecast-locname' . $wpfcid );
147 $av['refresh'] = get_option( 'wp-forecast-refresh' . $wpfcid );
148 $av['metric'] = get_option( 'wp-forecast-metric' . $wpfcid );
149 $av['wpf_language'] = get_option( 'wp-forecast-language' . $wpfcid );
150 $av['daytime'] = get_option( 'wp-forecast-daytime' . $wpfcid );
151 $av['nighttime'] = get_option( 'wp-forecast-nighttime' . $wpfcid );
152 $av['dispconfig'] = get_option( 'wp-forecast-dispconfig' . $wpfcid );
153 $av['windunit'] = get_option( 'wp-forecast-windunit' . $wpfcid );
154 $av['currtime'] = get_option( 'wp-forecast-currtime' . $wpfcid );
155 $av['timeoffset'] = get_option( 'wp-forecast-timeoffset' . $wpfcid );
156 if ( '' == trim( $av['timeoffset'] ) ) {
157 $av['timeoffset'] = 0;
158 }
159 $av['title'] = get_option( 'wp-forecast-title' . $wpfcid );
160 // replace old options by new one row option.
161 wpf_add_option( 'wp-forecast-opts' . $wpfcid, serialize( $av ) );
162 // remove old options from database.
163 delete_option( 'wp-forecast-location' . $wpfcid );
164 delete_option( 'wp-forecast-locname' . $wpfcid );
165 delete_option( 'wp-forecast-refresh' . $wpfcid );
166 delete_option( 'wp-forecast-metric' . $wpfcid );
167 delete_option( 'wp-forecast-language' . $wpfcid );
168 delete_option( 'wp-forecast-daytime' . $wpfcid );
169 delete_option( 'wp-forecast-nighttime' . $wpfcid );
170 delete_option( 'wp-forecast-dispconfig' . $wpfcid );
171 delete_option( 'wp-forecast-windunit' . $wpfcid );
172 delete_option( 'wp-forecast-currtime' . $wpfcid );
173 delete_option( 'wp-forecast-title' . $wpfcid );
174 delete_option( 'wp-forecast-service' . $wpfcid );
175 delete_option( 'wp-forecast-apikey1' . $wpfcid );
176 delete_option( 'wp-forecast-apikey2' . $wpfcid );
177 } else {
178 $av = array();
179 }
180
181 // add expire options.
182 $av['expire'] = get_option( 'wp-forecast-expire' . $wpfcid );
183
184 // add generic options.
185 $av['fc_date_format'] = get_option( 'date_format' );
186 $av['fc_time_format'] = get_option( 'time_format' );
187 $av['xmlerror'] = '';
188
189 // set static uris for each provider.
190 $av['OPENWEATHERMAP_BASE_URI'] = 'https://api.openweathermap.org/data/2.5';
191 $av['OPENWEATHERMAP_BASE_URI_V3'] = 'https://api.openweathermap.org/data/3.0/onecall?';
192
193 $av['OPENMETEO_BASE_URI'] = 'https://api.open-meteo.com/v1/forecast?';
194 $av['OPENMETEO_LOC_URI'] = 'https://geocoding-api.open-meteo.com/v1/search?';
195
196 // if we use multisite then merge admin options.
197 if ( function_exists( 'is_multisite' ) && is_multisite() && 1 != $blog_id ) {
198
199 // read defaults and allowed fields.
200 $defaults = maybe_unserialize( wpf_get_option( 'wpf_sa_defaults' ) );
201 $allowed = maybe_unserialize( wpf_get_option( 'wpf_sa_allowed' ) );
202 // in case allowed is still empty.
203 if ( ! $allowed ) {
204 $allowed = array();
205 }
206
207 // set wpf_maxwidgets for users.
208 global $blog_id, $wpf_maxwidgets;
209 if ( $blog_id > '1' && isset( $defaults['wp-forecast-count'] ) ) {
210 $wpf_maxwidgets = $defaults['wp-forecast-count'];
211 }
212
213 // map rest of fields.
214 foreach ( $allowed as $f => $fswitch ) {
215 $fname = substr( $f, 3 ); // strip ue_ prefix.
216
217 if ( 1 != $fswitch || ! isset( $av[ $fname ] ) ) {
218 // replace value in av with forced default.
219 if ( array_key_exists( $fname, $defaults ) ) {
220 $av[ $fname ] = $defaults[ $fname ];
221 }
222 }
223 }
224 }
225 return $av;
226 }
227
228 /**
229 * Just return the css link.
230 * this function is called via the wp_head hook.
231 *
232 * @param string $wpfcid the widget id.
233 */
234 function wp_forecast_css( $wpfcid = 'A' ) {
235
236 // load weather icon font.
237 wp_enqueue_style( 'wp-forecast-weathericons', plugin_dir_url( __FILE__ ) . '/weather-icons/weather-icons.min.css', array(), '9999' );
238 wp_enqueue_style( 'wp-forecast-weathericons-wind', plugin_dir_url( __FILE__ ) . '/weather-icons/weather-icons-wind.min.css', array(), '9999' );
239
240 $wpf_loadcss = wpf_get_option( 'wp-forecast-loadcss' );
241 if ( 1 == $wpf_loadcss ) {
242 return;
243 }
244
245 $def = 'wp-forecast-default.css';
246 $user = 'wp-forecast.css';
247
248 if ( file_exists( WP_PLUGIN_DIR . '/wp-forecast/' . $user ) ) {
249 $def = $user;
250 }
251
252 wp_enqueue_style( 'wp-forecast', plugin_dir_url( __FILE__ ) . $def, array(), '9999' );
253 }
254
255
256 /**
257 * Just return the css link when not using WordPress
258 * this function is called when showing widget directly
259 *
260 * @param string $wpfcid the widget id.
261 */
262 function wp_forecast_css_nowp( $wpfcid = 'A' ) {
263
264 // load weather icon font.
265 wp_enqueue_style( 'wp-forecast-weathericons', plugin_dir_url( __FILE__ ) . '/weather-icons/weather-icons.min.css', array(), '9999' );
266 wp_enqueue_style( 'wp-forecast-weathericons-wind', plugin_dir_url( __FILE__ ) . '/weather-icons/weather-icons-wind.min.css', array(), '9999' );
267
268 $wpf_loadcss = wpf_get_option( 'wp-forecast-loadcss' );
269 if ( 1 == $wpf_loadcss ) {
270 return;
271 }
272
273 $def = 'wp-forecast-default-nowp.css';
274 $user = 'wp-forecast-nowp.css';
275
276 if ( file_exists( WP_PLUGIN_DIR . '/wp-forecast/' . $user ) ) {
277 $def = $user;
278 }
279
280 wp_enqueue_style( 'wp-forecast-nowp', plugin_dir_url( __FILE__ ) . $def, array(), '9999' );
281 }
282
283 /**
284 * Just return the css link when not using WordPress
285 * this function is called when showing widget directly
286 */
287 function wp_forecast_get_nowp_css() {
288 $wpf_loadcss = wpf_get_option( 'wp-forecast-loadcss' );
289 if ( 1 == $wpf_loadcss ) {
290 return '';
291 }
292
293 $def = 'wp-forecast-default-nowp.css';
294 $user = 'wp-forecast-nowp.css';
295
296 if ( file_exists( WP_PLUGIN_DIR . '/wp-forecast/' . $user ) ) {
297 $def = $user;
298 }
299
300 $res = '';
301 $file = WP_PLUGIN_DIR . "/wp-forecast/$def";
302 $f = fopen( $file, 'r' );
303
304 if ( $f ) {
305 $res = fread( $f, filesize( $file ) );
306 fclose( $f );
307 }
308
309 return $res;
310 }
311
312 /**
313 * Returns the number's widget id used with wp-forecast
314 * maximum is 999999 :-)
315 *
316 * @param int $number number of widgets to use.
317 */
318 function get_widget_id( $number ) {
319 // if negative take the first id.
320 if ( $number < 0 ) {
321 return 'A';
322 }
323
324 // the first widgets use chars above we go with 0 padded numbers.
325 if ( $number <= 25 ) {
326 return substr( 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', $number, 1 );
327 } else {
328 return str_pad( $number, 6, '0', STR_PAD_LEFT );
329 }
330 }
331
332 /**
333 * Function tries to determine the icon path for icon number ino.
334 *
335 * @param string $ino icon number.
336 */
337 function find_icon( $ino ) {
338 $path = WPF_PATH . '/icons/' . $ino;
339 $ext = '.gif';
340
341 if ( file_exists( $path . '.gif' ) ) {
342 $ext = '.gif';
343 } elseif ( file_exists( $path . '.png' ) ) {
344 $ext = '.png';
345 } elseif ( file_exists( $path . '.jpg' ) ) {
346 $ext = '.jpg';
347 } elseif ( file_exists( $path . '.GIF' ) ) {
348 $ext = '.GIF';
349 } elseif ( file_exists( $path . '.PNG' ) ) {
350 $ext = '.PNG';
351 } elseif ( file_exists( $path . '.JPG' ) ) {
352 $ext = '.JPG';
353 } elseif ( file_exists( $path . '.jpeg' ) ) {
354 $ext = '.jpeg';
355 } elseif ( file_exists( $path . '.JPEG' ) ) {
356 $ext = '.JPEG';
357 } elseif ( file_exists( $path . '.svg' ) ) {
358 $ext = '.svg';
359 } elseif ( file_exists( $path . '.SVG' ) ) {
360 $ext = '.SVG';
361 }
362
363 return $ino . $ext;
364 }
365
366 /**
367 * Translates the wind direction into another language
368 *
369 * @param string $wdir direction in degrees.
370 * @param string $tdom textdomain.
371 */
372 function translate_winddir( $wdir, $tdom ) {
373 // translate winddir char by char.
374 $winddir = '';
375 $l = strlen( $wdir );
376 for ( $i = 0;$i < $l;$i++ ) {
377 $winddir = $winddir . wpf__( $wdir[ $i ], $tdom );
378 }
379 return $winddir;
380 }
381
382 /**
383 * Translates the wind direction in degree to a string.
384 *
385 * @param string $wdir direction in degrees.
386 * @param string $tdom passhtrough.
387 */
388 function translate_winddir_degree( $wdir, $tdom ) {
389 $dir = '-';
390 if ( 0 <= $wdir ) {
391 $dir = 'N';
392 }
393 if ( 11.25 <= $wdir ) {
394 $dir = 'NNE';
395 }
396 if ( 33.75 <= $wdir ) {
397 $dir = 'NE';
398 }
399 if ( 56.25 <= $wdir ) {
400 $dir = 'ENE';
401 }
402 if ( 78.75 <= $wdir ) {
403 $dir = 'E';
404 }
405 if ( 101.25 <= $wdir ) {
406 $dir = 'ESE';
407 }
408 if ( 123.75 <= $wdir ) {
409 $dir = 'SE';
410 }
411 if ( 146.25 <= $wdir ) {
412 $dir = 'SSE';
413 }
414 if ( 168.75 <= $wdir ) {
415 $dir = 'S';
416 }
417 if ( 191.25 <= $wdir ) {
418 $dir = 'SSW';
419 }
420 if ( 213.75 <= $wdir ) {
421 $dir = 'SW';
422 }
423 if ( 236.25 <= $wdir ) {
424 $dir = 'WSW';
425 }
426 if ( 258.75 <= $wdir ) {
427 $dir = 'W';
428 }
429 if ( 281.25 <= $wdir ) {
430 $dir = 'WNW';
431 }
432 if ( 303.75 <= $wdir ) {
433 $dir = 'NW';
434 }
435 if ( 326.25 <= $wdir ) {
436 $dir = 'NNW';
437 }
438 if ( 348.75 <= $wdir ) {
439 $dir = 'N';
440 }
441
442 return translate_winddir( $dir, $tdom );
443 }
444
445
446 /**
447 * Function for plugin_locale filter hook.
448 * only returns the first parameter.
449 *
450 * @param string $locale iso code of the locale.
451 * @param string $domain complete domain of the .mo file.
452 */
453 function wpf_lplug( $locale, $domain ) {
454 // extract locale from domain.
455 $wpf_locale = substr( $domain, 12, 5 );
456 return $wpf_locale;
457 }
458
459 /**
460 * Return an array containgin all allowed HTML tags and attributes
461 */
462 function wpf_allowed_tags() {
463
464 $allowed_atts = array(
465 'align' => array(),
466 'class' => array(),
467 'type' => array(),
468 'id' => array(),
469 'dir' => array(),
470 'lang' => array(),
471 'style' => array(),
472 'xml:lang' => array(),
473 'src' => array(),
474 'alt' => array(),
475 'href' => array(),
476 'rel' => array(),
477 'rev' => array(),
478 'target' => array(),
479 'novalidate' => array(),
480 'type' => array(),
481 'value' => array(),
482 'name' => array(),
483 'tabindex' => array(),
484 'action' => array(),
485 'method' => array(),
486 'for' => array(),
487 'width' => array(),
488 'height' => array(),
489 'data' => array(),
490 'title' => array(),
491 'maxlength' => array(),
492 'border' => array(),
493 'onclick' => array(),
494 'checked' => array(),
495 'selected' => array(),
496 'size' => array(),
497 'onchange' => array(),
498 );
499
500 $allowedposttags['aside'] = $allowed_atts;
501 $allowedposttags['section'] = $allowed_atts;
502 $allowedposttags['nav'] = $allowed_atts;
503 $allowedposttags['form'] = $allowed_atts;
504 $allowedposttags['label'] = $allowed_atts;
505 $allowedposttags['input'] = $allowed_atts;
506 $allowedposttags['textarea'] = $allowed_atts;
507 $allowedposttags['select'] = $allowed_atts;
508 $allowedposttags['option'] = $allowed_atts;
509 $allowedposttags['iframe'] = $allowed_atts;
510 $allowedposttags['script'] = $allowed_atts;
511 $allowedposttags['style'] = $allowed_atts;
512 $allowedposttags['strong'] = $allowed_atts;
513 $allowedposttags['small'] = $allowed_atts;
514 $allowedposttags['table'] = $allowed_atts;
515 $allowedposttags['span'] = $allowed_atts;
516 $allowedposttags['abbr'] = $allowed_atts;
517 $allowedposttags['code'] = $allowed_atts;
518 $allowedposttags['pre'] = $allowed_atts;
519 $allowedposttags['div'] = $allowed_atts;
520 $allowedposttags['img'] = $allowed_atts;
521 $allowedposttags['h1'] = $allowed_atts;
522 $allowedposttags['h2'] = $allowed_atts;
523 $allowedposttags['h3'] = $allowed_atts;
524 $allowedposttags['h4'] = $allowed_atts;
525 $allowedposttags['h5'] = $allowed_atts;
526 $allowedposttags['h6'] = $allowed_atts;
527 $allowedposttags['ol'] = $allowed_atts;
528 $allowedposttags['ul'] = $allowed_atts;
529 $allowedposttags['li'] = $allowed_atts;
530 $allowedposttags['em'] = $allowed_atts;
531 $allowedposttags['hr'] = $allowed_atts;
532 $allowedposttags['br'] = $allowed_atts;
533 $allowedposttags['tr'] = $allowed_atts;
534 $allowedposttags['td'] = $allowed_atts;
535 $allowedposttags['p'] = $allowed_atts;
536 $allowedposttags['a'] = $allowed_atts;
537 $allowedposttags['b'] = $allowed_atts;
538 $allowedposttags['i'] = $allowed_atts;
539
540 return $allowedposttags;
541 }
542
543 /**
544 * Function to translate a string into another language
545 * using the wpf own translation mechanism
546 * this is necessary because WordPress does not allow
547 * more than one language per plugin
548 *
549 * @param string $s string to translate.
550 * @param string $d domain to translate to.
551 */
552 function wpf__( $s, $d ) {
553 global $wpf_lang_dict;
554
555 if ( ! isset( $wpf_lang_dict ) ) {
556 $wpf_lang_dict = array();
557 }
558
559 if ( array_key_exists( $d, $wpf_lang_dict ) && isset( $wpf_lang_dict[ $d ] ) ) {
560 if ( array_key_exists( $s, $wpf_lang_dict[ $d ] ) ) {
561 return $wpf_lang_dict[ $d ][ $s ];
562 }
563 }
564
565 // nothing found return original.
566 return $s;
567 }
568
569 /**
570 * Function to translate a string into another language
571 * using the wpf own translation mechanism
572 * this is necessary because WordPress does not allow
573 * more than one language per plugin
574 * This one echos the translation.
575 *
576 * @param string $s string to translate.
577 * @param string $d domain to translate to.
578 */
579 function wpf_e( $s, $d ) {
580 echo esc_attr( wpf__( $s, $d ) );
581 }
582
583 /**
584 * Function to translate a string into another language
585 * using the wpf own translation mechanism
586 * this is necessary because WordPress does not allow
587 * more than one language per plugin
588 * This one escape it too
589 *
590 * @param string $s string to translate.
591 * @param string $d domain to translate to.
592 */
593 function wpf_esc_attr__( $s, $d ) {
594 return esc_attr( wpf__( $s, $d ) );
595 }
596
597 /**
598 * Function to translate a string into another language
599 * using the wpf own translation mechanism
600 * this is necessary because WordPress does not allow
601 * more than one language per plugin
602 * This one escapes and echos the translation.
603 *
604 * @param string $s string to translate.
605 * @param string $d domain to translate to.
606 */
607 function wpf_esc_attr_e( $s, $d ) {
608 echo esc_attr( wpf__( $s, $d ) );
609 }
610
611 /**
612 * Echos the admin notice concerning the accuweather probem.
613 */
614 function wpf_accuweather_problem_notice() {
615 $flag = get_option( 'wpf-show-admin-notice' );
616 if ( false === $flag ) {
617 $out = '<div class="notice is-dismissible"><p>';
618 $out .= __(
619 'As of September 10, 2023 it seems Accuweather has discontinued the free api-service.
620 Please switch to either Openweathermap or Open-Meteo instead.
621 For use with OpenWeatherMap.org you will need a personal API-Key and have to register at their site.
622 All your Accuweather Widgets have been set to Open-Meteo to avoid errors on your website. Please check if all settings are correct.',
623 'wp-forecast'
624 );
625 $out .= '</p></div>';
626 echo wp_kses( $out, wpf_allowed_tags() );
627 update_option( 'wpf-show-admin-notice', 1 );
628 }
629 }
630 } // end of function_exists
631