1: <?php
2: /**
3: * Weather support
4: *
5: * @package event-post
6: * @version 5.10.1
7: * @since 4.3.0
8: */
9:
10: namespace EventPost;
11:
12: $EventPostWeather = new Weather();
13:
14: /**
15: * Provides weather support thanks to OpenWeatherMap
16: * http://openweathermap.org
17: *
18: * License: Creative Commons (cc-by-sa)
19: * http://creativecommons.org/licenses/by-sa/2.0/.
20: *
21: *
22: * Get an API key
23: * http://openweathermap.org/appid#get
24: */
25: class Weather {
26:
27: var $META_WEATHER;
28:
29: var $api_key;
30: var $units;
31: var $unit_names;
32: var $theme;
33:
34: function __construct() {
35: // Hook into the plugin
36:
37: add_action('eventpost_getsettings_action', array(&$this, 'get_settings'), 1, 2);
38: add_action('eventpost_settings_form', array(&$this, 'settings_form'));
39: add_action('evenpost_init', array(&$this, 'init'));
40: }
41:
42: /**
43: * PHP4 constructor
44: */
45: function Weather() {
46: $this->__construct();
47: }
48:
49: /**
50: * Only for localization
51: *
52: * Available values:
53: *
54: * - clear sky
55: * - few clouds
56: * - scattered clouds
57: * - broken clouds
58: * - shower rain
59: * - rain
60: * - thunderstorm
61: * - snow
62: * - mist
63: */
64: function localize(){
65: __('clear sky', 'event-post');
66: __('few clouds', 'event-post');
67: __('scattered clouds', 'event-post');
68: __('broken clouds', 'event-post');
69: __('shower rain', 'event-post');
70: __('rain', 'event-post');
71: __('thunderstorm', 'event-post');
72: __('snow', 'event-post');
73: __('mist', 'event-post');
74:
75: }
76:
77: /**
78: * Get settings
79: *
80: * @param array reference &$ep_settings
81: * @param boolean reference &$reg_settings
82: */
83: function get_settings(&$ep_settings, &$reg_settings) {
84: if (!isset($ep_settings['weather_enabled'])) {
85: $ep_settings['weather_enabled'] = false;
86: $reg_settings = true;
87: }
88: if (!isset($ep_settings['weather_api_key'])) {
89: $ep_settings['weather_api_key'] = '';
90: $reg_settings = true;
91: }
92: if (!isset($ep_settings['weather_units'])) {
93: $ep_settings['weather_units'] = 'standard';
94: $reg_settings = true;
95: }
96: }
97:
98: /**
99: * Settings form
100: *
101: * @param type $ep_settings
102: */
103: function settings_form($ep_settings) {
104: ?>
105: <h2><?php _e('Weather', 'event-post'); ?></h2>
106: <?php // Translators: %s is a link to openweathermap.org ?>
107: <p class="description"><?php printf(__('Provided thanks to %s', 'event-post'), '<a href="http://openweathermap.org" target="_blank">openweathermap.org</a>'); ?></p>
108: <table class="form-table" id="eventpost-settings-table-weather">
109: <tbody>
110: <tr>
111: <th>
112: <?php _e('Enable weather', 'event-post') ?>
113: </th>
114: <td>
115: <label for="weather_enabled">
116: <input type="checkbox" name="ep_settings[weather_enabled]" id="weather_enabled" <?php if ($ep_settings['weather_enabled'] == '1') {
117: echo'checked';
118: } ?> value="1">
119: <?php _e('Enable weather feature', 'event-post') ?>
120: </label>
121: </td>
122: </tr>
123: <tr>
124: <th>
125: <label for="weather_api_key">
126: <?php _e('API key', 'event-post') ?>
127: </label>
128: </th>
129: <td>
130: <input type="text" name="ep_settings[weather_api_key]" id="weather_api_key" value="<?php echo $ep_settings['weather_api_key']; ?>" size="40">
131: <p class="description"><?php printf(__('Get a free API key at: %s', 'event-post'), '<a href="http://openweathermap.org/appid#get" target="_blank">openweathermap.org/appid#get</a>'); ?></p>
132: </td>
133: </tr>
134: <tr>
135: <th>
136: <label for="weather_units">
137: <?php _e('Units', 'event-post') ?>
138: </label>
139: </th>
140: <td>
141: <select name="ep_settings[weather_units]" id="weather_units">
142: <option value="standard" <?php selected($ep_settings['weather_units'], 'standard', true);?>>
143: <?php _e('Standard (Fahrenheit)', 'event-post') ?>
144: </option>
145: <option value="metric" <?php selected($ep_settings['weather_units'], 'metric', true);?>>
146: <?php _e('Metric (Celsius)', 'event-post') ?>
147: </option>
148: <option value="imperial" <?php selected($ep_settings['weather_units'], 'imperial', true);?>>
149: <?php _e('Imperial (Kelvin)', 'event-post') ?>
150: </option>
151: </select>
152: </td>
153: </tr>
154: </tbody>
155: </table><!-- #eventpost-settings-table-weather -->
156: <?php
157: }
158:
159: /**
160: * Initialization of weather support
161: *
162: * @param object $EP
163: *
164: * @return void
165: */
166: function init($EP) {
167: // Ensure OpenWeatherMap is required and available.
168: if (!$EP->settings['weather_enabled'] || !$EP->settings['weather_api_key']) {
169: return;
170: }
171:
172: $this->META_WEATHER = 'event_weather';
173: $this->api_key = $EP->settings['weather_api_key'];
174: $this->units = $EP->settings['weather_units'];
175: $this->theme = 'default';
176: $this->unit_names = array('standard'=>'F', 'metric'=>'C', 'imperial'=>'K');
177:
178: // Alter objects
179: add_filter('eventpost_params', array(&$this, 'params'));
180: add_filter('eventpost_retreive', array(&$this, 'retreive'));
181:
182: // Alter schema
183: add_filter('eventpost_item_scheme_entities', array(&$this, 'scheme_entities'));
184: add_filter('eventpost_item_scheme_values', array(&$this, 'scheme_values'), 1, 2);
185: add_filter('eventpost_default_list_shema', array(&$this, 'default_shema'));
186: add_filter('eventpost_get_single', array(&$this, 'get_single'), 1, 2);
187:
188:
189: add_action('eventpost_custom_box_date', array(&$this, 'get_weather'));
190:
191:
192: }
193:
194: /**
195: * Alters parameters
196: *
197: * @param array $params
198: *
199: * @return array
200: */
201: function params($params = array()) {
202: $params['weather'] = true;
203: return $params;
204: }
205:
206: /**
207: * Alters an event object
208: *
209: * @param WP_Post $event
210: *
211: * @return WP_Post
212: */
213: function retreive($event) {
214: $event->weather = get_post_meta($event->ID, $this->META_WEATHER, true);
215: return $event;
216: }
217:
218: /**
219: * Alters schema entities
220: *
221: * @param array $attr
222: *
223: * @return array
224: */
225: function scheme_entities($attr = array()) {
226: array_push($attr, '%event_weather%');
227: return $attr;
228: }
229:
230: /**
231: * Alters schema values
232: *
233: * @param array $values
234: *
235: * @return array
236: */
237: function scheme_values($values = array(), $post = null) {
238: array_push($values, $this->get_weather($post));
239: return $values;
240: }
241:
242: /**
243: * Alters default schema
244: *
245: * @param array $schema
246: *
247: * @return array
248: */
249: function default_shema($schema) {
250: $schema['item'] = str_replace('</%child%>', "%event_weather%\n</%child%>", $schema['item']);
251: return $schema;
252: }
253:
254: function get_single($event_datas, $post = null) {
255: return $event_datas . $this->get_weather($post);
256: }
257:
258: //From here, methods intends to get datas
259:
260: function get_weather_icons($weather){
261: $string = '';
262: foreach((array) $weather as $item){
263: $text = ucfirst(__(strtolower($item->description), 'event-post'));
264: $string.='<span class="eventpost-weather-'.str_replace('-', '', strtolower($item->description)).' eventpost-weather-'.$item->icon.'">'
265: . '<img src="'. plugins_url('../img/weather/'.$this->theme.'/'.$item->icon.'.png', __FILE__).'" alt="'.sprintf('%s icon', $text).'">'
266: . '<em class="eventpost-weather-text">'.$text.'</em>'
267: . '</span>';
268: }
269: return $string;
270: }
271: /**
272: * Get weather item
273: *
274: * @param object $item
275: *
276: * @return string
277: */
278: function get_weather_item($item){
279: $string = '';
280: $string.= '<div class="eventpost-weather-item">'
281: .'<span class="eventpost-weather-date">'.date_i18n(get_option('date_format').' '.get_option('time_format'), $item->dt).'</span> '
282: .'<span class="eventpost-weather-temp">'.round($item->main->temp).' &deg'.$this->unit_names[$this->units].'</span> '
283: .'<span class="eventpost-weather-list">'.$this->get_weather_icons($item->weather).'</span>'
284: .'</div>';
285: return $string;
286: }
287:
288: /**
289: * Get weather
290: *
291: * @param type $post
292: *
293: * @return string
294: */
295: function get_weather($post = null, $echo=false) {
296: global $EventPost;
297: $event = $EventPost->retreive($post);
298: if(false === $weather = $this->get_weather_datas($event)){
299: return '';
300: }
301: if(false == $weather['data']){
302: return '';
303: }
304:
305: $string='';
306:
307: switch ($weather['type']){
308: case 'current':
309: $string.=$this->get_weather_item($weather['data']);
310: break;
311: case 'history':
312: if(!isset($weather['data']->list) || !is_array($weather['data']->list)){
313: break;
314: }
315: foreach($weather['data']->list as $day){
316: if($day->dt >= $event->time_start && $day->dt <= $event->time_end){
317: $string.=$this->get_weather_item($day);
318: }
319: }
320: break;
321: case 'forecast':
322: if(!is_array($weather['data']->list)){
323: break;
324: }
325: foreach($weather['data']->list as $day){
326: if($day->dt >= $event->time_start && $day->dt <= $event->time_end){
327: $string.=$this->get_weather_item($day);
328: }
329: }
330: break;
331: }
332: if($echo){
333: echo $string;
334: }
335: return $string;
336: }
337:
338: /**
339: * Get weather datas
340: *
341: * @param type $event
342: *
343: * @return type
344: */
345: function get_weather_datas($event){
346: if (!$event->lat || !$event->long || !is_numeric($event->time_start) || !is_numeric($event->time_end)) {
347: return false;
348: }
349:
350: $now = current_time('timestamp');
351: $local_weather = $event->weather;
352:
353:
354:
355: // Datas are allready stored, we probably won't get better ones.
356: if(is_array($local_weather) && $local_weather['data'] && ($local_weather['type']=='current' || $local_weather['type']=='history')){
357: return $local_weather;
358: }
359:
360: // Finally, we have to fetch datas...
361: $weather = array('type'=>false, 'data'=>false);
362:
363: // For Current and history results, we definitly store datas
364: if ( $event->time_start<= $now && $event->time_end>=$now) {
365: $weather = array('type'=>'current', 'data'=>$this->get_current($event), 'fetched'=>time());
366: update_post_meta($event->ID, $this->META_WEATHER, $weather);
367: }
368: elseif ( $event->time_end<$now) {// History
369: $weather = array('type'=>'history', 'data'=>$this->get_history($event), 'fetched'=>time());
370: update_post_meta($event->ID, $this->META_WEATHER, $weather);
371: }
372: else {
373: // Forecast datas are only stored in cache for 24 hours
374: $transient_name = 'eventpost_weather_' . $event->ID;
375: $weather = get_transient($transient_name);
376: if (false === $weather || empty($weather)) {
377: $weather = array('type'=>'forecast', 'data'=>$this->get_forecast($event), 'fetched'=>time());
378: set_transient($transient_name, $weather, 1 * DAY_IN_SECONDS);
379: }
380: }
381: return $weather;
382: }
383:
384:
385: /**
386: * Generates the URL to call the API
387: *
388: * @param type $method
389: * @param type $params
390: *
391: * @return type
392: */
393: function get_url($method = 'weather', $params = array()) {
394: $params['APPID']= $this->api_key;
395: $params['units']= $this->units;
396: return 'http://api.openweathermap.org/data/2.5/' . $method . '?' . http_build_query($params);
397: }
398:
399: /**
400: * Current weather
401: * http://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&APPID=XXXX
402: *
403: * Return:
404: *
405: * {"coord":{"lon":139,"lat":35},
406: * "sys":{"country":"JP","sunrise":1369769524,"sunset":1369821049},
407: * "weather":[{"id":804,"main":"clouds","description":"overcast clouds","icon":"04n"}],
408: * "main":{"temp":289.5,"humidity":89,"pressure":1013,"temp_min":287.04,"temp_max":292.04},
409: * "wind":{"speed":7.31,"deg":187.002},
410: * "rain":{"3h":0},
411: * "clouds":{"all":92},
412: * "dt":1369824698,
413: * "id":1851632,
414: * "name":"Shuzenji",
415: * "cod":200}
416: *
417: * @param type $event
418: *
419: * @return object
420: */
421: function get_current($event){
422: if (!$event->lat || !$event->long) {
423: return;
424: }
425: return json_decode(wp_remote_retrieve_body(
426: wp_remote_get(
427: $this-> get_url('weather', array(
428: 'lat' => $event->lat,
429: 'lon' => $event->long,
430: ))
431: )
432: ));
433: }
434:
435: /**
436: * Forecast
437: * api.openweathermap.org/data/2.5/forecast?lat={lat}&lon={lon}&APPID=XXXX
438: *
439: * Return:
440: *
441: * {"city":{"id":1851632,"name":"Shuzenji",
442: * "coord":{"lon":138.933334,"lat":34.966671},
443: * "country":"JP",
444: * "cod":"200",
445: * "message":0.0045,
446: * "cnt":38,
447: * "list":[{
448: * "dt":1406106000,
449: * "main":{
450: * "temp":298.77,
451: * "temp_min":298.77,
452: * "temp_max":298.774,
453: * "pressure":1005.93,
454: * "sea_level":1018.18,
455: * "grnd_level":1005.93,
456: * "humidity":87
457: * "temp_kf":0.26},
458: * "weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],
459: * "clouds":{"all":88},
460: * "wind":{"speed":5.71,"deg":229.501},
461: * "sys":{"pod":"d"},
462: * "dt_txt":"2014-07-23 09:00:00"}
463: * ]}
464: *
465: * @param type $event
466: *
467: * @return type
468: */
469: function get_forecast($event){
470: if (!$event->lat || !$event->long) {
471: return;
472: }
473: return json_decode(wp_remote_retrieve_body(
474: wp_remote_get(
475: $this-> get_url('forecast', array(
476: 'lat' => $event->lat,
477: 'lon' => $event->long,
478: ))
479: )
480: ));
481: }
482:
483: /**
484: * ### history
485: * http://api.openweathermap.org/data/2.5/history/city?lat={lat}&lon={lon}&type=hour&start={start}&end={end}&APPID=XXXX
486: *
487: * Parameters:
488: * lat, lon coordinates of the location of your interest
489: * type type of the call, keep this parameter in the API call as 'hour'
490: * start start date (unix time, UTC time zone), e.g. start=1369728000
491: * end end date (unix time, UTC time zone), e.g. end=1369789200
492: * cnt amount of returned data (one per hour, can be used instead of 'end') *
493: * return:
494: * {"message":"","cod":"200","type":"tick","station_id":39419,"cnt":30,
495: * "list":[
496: * {"dt":1345291920,
497: * "main":{"temp":291.55,"humidity":95,"pressure":1009.3},
498: * "wind":{"speed":0,"gust":0.3},
499: * "rain":{"1h":0.6,"today":2.7},
500: * "calc":{"dewpoint":17.6} }
501: * ]}
502: *
503: * @param type $event
504: *
505: * @return type
506: */
507: function get_history($event) {
508: if (!$event->start || !$event->end || !$event->lat || !$event->long) {
509: return;
510: }
511: $history = json_decode(wp_remote_retrieve_body(
512: wp_remote_get(
513: $this-> get_url('history/city', array(
514: 'lat' => $event->lat,
515: 'lon' => $event->long,
516: 'start' => $event->time_start,
517: 'end' => $event->time_end,
518: 'type' => 'hour',
519: ))
520: )
521: ));
522: return $history ? $history : (object) array('result'=>false);
523: }
524:
525: }
526: