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
← All changes | funclib.php +588 -266 2.09.6 View file →
@@ -1,308 +1,630 @@
1 1 <?php
2 -/* This file is part of the wp-forecast plugin for wordpress */
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 + */
3 23
4 -/* Copyright 2006,2007,2008 Hans Matzen (email : webmaster at tuxlog.de)
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 + }
5 37
6 - This program is free software; you can redistribute it and/or modify
7 - it under the terms of the GNU General Public License as published by
8 - the Free Software Foundation; either version 2 of the License, or
9 - (at your option) any later version.
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 + }
10 71
11 - This program is distributed in the hope that it will be useful,
12 - but WITHOUT ANY WARRANTY; without even the implied warranty of
13 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 - GNU General Public License for more details.
15 72
16 - You should have received a copy of the GNU General Public License
17 - along with this program; if not, write to the Free Software
18 - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 -*/
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;
20 81
21 -if (!function_exists('fetchURL')) {
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 + }
22 93
23 -//
24 -// this function fetches an url an returns it as one whole string
25 -//
26 -function fetchURL($url)
27 -{
28 - global $wpf_debug;
29 -
30 - if ($wpf_debug > 0)
31 - pdebug("Start of fetchURL ()");
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;
32 102
33 - // get timeout parameter
34 - $timeout = get_option("wp-forecast-timeout");
35 - if ( $timeout =="")
36 - $timeout = 30;
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 + }
37 109
38 - $url_parsed = parse_url($url);
39 - $host = $url_parsed["host"];
40 - if (!isset($url_parsed["port"])) {
41 - $port = 80;
42 - }
43 - else {
44 - $port = $url_parsed["port"];
45 - }
46 - $path = $url_parsed["path"];
47 - if ($url_parsed["query"] != "") $path .= "?" . $url_parsed["query"];
48 - $out = "GET $path HTTP/1.0\r\nHost: $host\r\n\r\n";
49 - // open connection
50 - $fp = @fsockopen($host, $port, $errno, $errstr, $timeout);
51 -
52 - $in = "";
53 - if ($fp) {
54 - // set timeout for reading
55 - stream_set_timeout($fp, $timeout);
56 - // send request
57 - fwrite($fp, $out);
58 - $body = false;
59 - // read answer
60 - while (!feof($fp)) {
61 - $s = fgets($fp, 1024);
62 - if ($body) $in .= $s;
63 - if ($s == "\r\n") $body = true;
64 - }
65 - // close connection
66 - fclose($fp);
67 - } else {
68 - // error handling
69 - echo '<!-- Connection-Error, Error-No.: ' . $errno . ' >> ' . $errstr . "-->\n";
70 - }
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;
71 118
72 - if ($wpf_debug > 0)
73 - pdebug("End of fetchURL ()");
74 -
75 - return $in;
76 -}
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 + }
77 125
78 -//
79 -// converts an array to an cookie like string
80 -// e.g. a=5&b=6&c=7
81 -function arr2str($a)
82 -{
83 - global $wpf_debug;
84 -
85 - if ($wpf_debug > 0)
86 - pdebug("Start of arr2str ()");
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;
87 133
88 - $s="";
89 - foreach ($a as $name => $value){
90 - $s=$s . $name . "=" . $value . "&";
91 - }
134 + $av = array();
135 + $opt = wpf_get_option( 'wp-forecast-opts' . $wpfcid );
92 136
93 - if ($wpf_debug > 0)
94 - pdebug("End of arr2str ()");
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 + }
95 180
96 - return $s;
97 -}
181 + // add expire options.
182 + $av['expire'] = get_option( 'wp-forecast-expire' . $wpfcid );
98 183
99 -//
100 -// converts a cookie like string (see above) to an array
101 -//
102 -function str2arr($s)
103 -{
104 - global $wpf_debug;
105 -
106 - if ($wpf_debug > 0)
107 - pdebug("Start of str2arr ()");
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'] = '';
108 188
109 - $a=array();
110 - parse_str($s,$a);
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?';
111 192
112 - if ($wpf_debug > 0)
113 - pdebug("End of str2arr ()");
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?';
114 195
115 - return $a;
116 -}
196 + // if we use multisite then merge admin options.
197 + if ( function_exists( 'is_multisite' ) && is_multisite() && 1 != $blog_id ) {
117 198
118 -//
119 -// converts the given wind parameters into a suitable windstring
120 -//
121 -function windstr($metric,$wspeed,$windunit)
122 -{
123 - global $wpf_debug;
124 -
125 - if ($wpf_debug > 0)
126 - pdebug("Start of windstr ()");
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 + }
127 206
128 - // if its mph convert it to m/s
129 - if ($metric != 1)
130 - $wspeed = round($wspeed * 0.44704,0);
131 -
132 - // convert it to selected unit
133 - switch ($windunit) {
134 - case "ms":
135 - $wunit="m/s";
136 - break;
137 - case "kmh":
138 - $wspeed=round($wspeed*3.6,0);
139 - $wunit="km/h";
140 - break;
141 - case "mph":
142 - $wspeed=round($wspeed*2.23694,0);
143 - $wunit="mph";
144 - break;
145 - case "kts":
146 - $wspeed=round($wspeed*1.9438,0);
147 - $wunit="kts";
148 - break;
149 - }
150 -
151 - if ($wpf_debug > 0)
152 - pdebug("End of windstr ()");
153 -
154 - return $wspeed." ".$wunit;
155 -}
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 + }
156 212
213 + // map rest of fields.
214 + foreach ( $allowed as $f => $fswitch ) {
215 + $fname = substr( $f, 3 ); // strip ue_ prefix.
157 216
158 -function get_wpf_opts($wpfcid)
159 -{
160 - global $wpf_debug;
161 -
162 - if ($wpf_debug > 0)
163 - pdebug("Start of get_wpf_opts ()");
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 + }
164 227
165 - $av=array();
166 -
167 - // get options from database
168 - $av['location']=get_option("wp-forecast-location".$wpfcid);
169 - $av['locname']=get_option("wp-forecast-locname".$wpfcid);
170 - $av['refresh']=get_option("wp-forecast-refresh".$wpfcid);
171 - $av['metric']=get_option("wp-forecast-metric".$wpfcid);
172 - $av['wpf_language']=get_option("wp-forecast-language".$wpfcid);
173 - $av['daytime']=get_option("wp-forecast-daytime".$wpfcid);
174 - $av['nighttime']=get_option("wp-forecast-nighttime".$wpfcid);
175 - $av['fc_date_format']=get_option("date_format");
176 - $av['fc_time_format']=get_option("time_format");
177 - $av['dispconfig']=get_option("wp-forecast-dispconfig".$wpfcid);
178 - $av['windunit']=get_option("wp-forecast-windunit".$wpfcid);
179 - $av['currtime']=get_option("wp-forecast-currtime".$wpfcid);
180 - $av['title'] = get_option("wp-forecast-title".$wpfcid);
181 - $av['xmlerror']="";
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' ) {
182 235
183 - // set accuweather uri
184 - $av['BASE_URI']="http://forecastfox.accuweather.com/adcbin/forecastfox/weather_data.asp?";
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' );
185 239
186 - if ($wpf_debug > 0)
187 - pdebug("End of get_wpf_opts ()");
240 + $wpf_loadcss = wpf_get_option( 'wp-forecast-loadcss' );
241 + if ( 1 == $wpf_loadcss ) {
242 + return;
243 + }
188 244
189 - return $av;
190 -}
245 + $def = 'wp-forecast-default.css';
246 + $user = 'wp-forecast.css';
191 247
248 + if ( file_exists( WP_PLUGIN_DIR . '/wp-forecast/' . $user ) ) {
249 + $def = $user;
250 + }
192 251
193 -//
194 -// build the url from the parameters and fetch the weather-data
195 -// return it as one long string
196 -//
197 -function get_weather($uri,$loc,$metric)
198 -{
199 - global $wpf_debug;
200 -
201 - if ($wpf_debug > 0)
202 - pdebug("Start of get_weather ()");
252 + wp_enqueue_style( 'wp-forecast', plugin_dir_url( __FILE__ ) . $def, array(), '9999' );
253 + }
203 254
204 - $url=$uri . "location=" . urlencode($loc) . "&metric=" .
205 - $metric;// . "&partner=forecastfox";
206 -
207 - $xml = fetchURL($url);
208 255
209 - if ($wpf_debug > 0)
210 - pdebug("End of get_weather ()");
211 -
212 - return $xml;
213 -}
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' ) {
214 263
215 -//
216 -// just return the css link
217 -// this function is called via the wp_head hook
218 -//
219 -function wp_forecast_css($wpfcid="A") {
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' );
220 267
221 - global $wpf_debug;
222 -
223 - if ($wpf_debug > 0)
224 - pdebug("Start of function wp_forecast_css ()");
268 + $wpf_loadcss = wpf_get_option( 'wp-forecast-loadcss' );
269 + if ( 1 == $wpf_loadcss ) {
270 + return;
271 + }
225 272
226 - $plugin_path = get_settings('siteurl') . '/wp-content/plugins/wp-forecast';
227 - echo "<link rel=\"stylesheet\" href=\"". $plugin_path. "/wp-forecast.css\" type=\"text/css\" media=\"screen\" />\n";
273 + $def = 'wp-forecast-default-nowp.css';
274 + $user = 'wp-forecast-nowp.css';
228 275
229 -
230 - if ($wpf_debug > 0)
231 - pdebug("End of function wp_forecast_css ()");
232 -}
276 + if ( file_exists( WP_PLUGIN_DIR . '/wp-forecast/' . $user ) ) {
277 + $def = $user;
278 + }
233 279
280 + wp_enqueue_style( 'wp-forecast-nowp', plugin_dir_url( __FILE__ ) . $def, array(), '9999' );
281 + }
234 282
235 -//
236 -// just return the css link when not using wordpress
237 -// this function is called when showing widget directly via wp-forecast-show.php
238 -//
239 -function wp_forecast_css_nowp($wpfcid="A") {
240 -
241 - global $wpf_debug;
242 -
243 - if ($wpf_debug > 0)
244 - pdebug("Start of function wp_forecast_css_nowp ()");
245 -
246 - $plugin_path = get_settings('siteurl') . '/wp-content/plugins/wp-forecast';
247 - echo "<link rel=\"stylesheet\" href=\"". $plugin_path. "/wp-forecast-nowp.css\" type=\"text/css\" media=\"screen\" />\n";
248 -
249 -
250 - if ($wpf_debug > 0)
251 - pdebug("End of function wp_forecast_css ()");
252 -}
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 + }
253 292
293 + $def = 'wp-forecast-default-nowp.css';
294 + $user = 'wp-forecast-nowp.css';
254 295
255 -//
256 -// little debug output routine
257 -//
258 -function pdebug($dstr)
259 -{
260 - echo $dstr."<br />\n";
261 -}
296 + if ( file_exists( WP_PLUGIN_DIR . '/wp-forecast/' . $user ) ) {
297 + $def = $user;
298 + }
262 299
263 -//
264 -// returns the number's widget id used with wp-forecast
265 -// maximum is 999999 :-)
266 -//
267 -function get_widget_id($number)
268 -{
269 - // if negative take the first id
270 - if ($number < 0 )
271 - return "A";
300 + $res = '';
301 + $file = WP_PLUGIN_DIR . "/wp-forecast/$def";
302 + $f = fopen( $file, 'r' );
272 303
273 - // the first widgets use chars above we go with 0 padded numbers
274 - if ( $number <= 25 )
275 - return substr("ABCDEFGHIJKLMNOPQRSTUVWXYZ",$number,1);
276 - else
277 - return str_pad($number, 6, "0", STR_PAD_LEFT);
278 -}
304 + if ( $f ) {
305 + $res = fread( $f, filesize( $file ) );
306 + fclose( $f );
307 + }
279 308
280 -//
281 -// function tries to determine the icon path for icon number ino
282 -//
283 -function find_icon($ino)
284 -{
285 - $path = ABSPATH . "wp-content/plugins/wp-forecast/icons/".$ino;
286 - $ext=".gif";
287 -
288 - if ( file_exists($path.".gif") )
289 - $ext= ".gif";
290 - else if ( file_exists($path.".png") )
291 - $ext= ".png";
292 - else if ( file_exists($path.".jpg") )
293 - $ext= ".jpg";
294 - else if ( file_exists($path.".GIF") )
295 - $ext= ".GIF";
296 - else if ( file_exists($path.".PNG") )
297 - $ext= ".PNG";
298 - else if ( file_exists($path.".JPG") )
299 - $ext= ".JPG";
300 - else if ( file_exists($path.".jpeg") )
301 - $ext= ".jpeg";
302 - else if ( file_exists($path.".JPEG") )
303 - $ext= ".JPEG";
304 - return $ino . $ext;
305 -}
309 + return $res;
310 + }
306 311
307 -}
308 -?>
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