예제 #1
0
 public static function register_climacons_css()
 {
     wp_register_style('tkeventw-climacons', TkEventWeather__FuncSetup::plugin_dir_url_vendor() . 'climacons/climacons-font.css', array(), null);
 }
 public function handleShortcode($atts)
 {
     $output = '';
     $template_data = array();
     // sent to view template to render output
     $plugin_options = TkEventWeather__Functions::plugin_options();
     if (empty($plugin_options)) {
         return TkEventWeather__Functions::invalid_shortcode_message('Please complete the initial setup');
     } else {
         $api_key_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'darksky_api_key');
         $gmaps_api_key_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'google_maps_api_key');
         $display_template_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'display_template');
         $cutoff_past_days_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'cutoff_past_days', 30);
         $cutoff_future_days_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'cutoff_future_days', 365);
         $units_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'darksky_units', 'auto');
         $transients_off_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'transients_off');
         $transients_expiration_hours_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'transients_expiration_hours', 12);
         $utc_offset_type_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'utc_offset_type');
         $sunrise_sunset_off_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'sunrise_sunset_off');
         //$icons_option = TkEventWeather__Functions::array_get_value_by_key ( $plugin_options, 'icons' );
         $plugin_credit_link_on_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'plugin_credit_link_on');
         $darksky_credit_link_off_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'darksky_credit_link_off');
         $debug_on_option = TkEventWeather__Functions::array_get_value_by_key($plugin_options, 'debug_on');
     }
     /*
      * Required:
      * api_key
      * lat/long
      * start time
      */
     // Attributes
     $defaults = array('api_key' => $api_key_option, 'gmaps_api_key' => $gmaps_api_key_option, 'post_id' => get_the_ID(), 'lat_long' => '', 'lat_long_custom_field' => '', 'lat' => '', 'lat_custom_field' => '', 'long' => '', 'long_custom_field' => '', 'location' => '', 'location_custom_field' => '', 'start_time' => '', 'start_time_custom_field' => '', 'end_time' => '', 'end_time_custom_field' => '', 'cutoff_past' => $cutoff_past_days_option, 'cutoff_future' => $cutoff_future_days_option, 'exclude' => '', 'transients_off' => $transients_off_option, 'transients_expiration' => $transients_expiration_hours_option, 'units' => '', 'utc_offset_type' => $utc_offset_type_option, 'sunrise_sunset_off' => $sunrise_sunset_off_option, 'icons' => '', 'plugin_credit_link_on' => $plugin_credit_link_on_option, 'darksky_credit_link_off' => $darksky_credit_link_off_option, 'class' => '', 'template' => $display_template_option, 'debug_on' => $debug_on_option);
     $atts = shortcode_atts($defaults, $atts, 'tk-event-weather');
     // extract( $atts ); // convert each array item to individual variable
     // load CSS file for Administrators so error messages get styled even if there are no valid shortcodes on page
     // if non-Administrator and no valid shortcode, CSS file will not load
     if (current_user_can('edit_theme_options')) {
         TkEventWeather__Functions::register_css();
         wp_enqueue_style(sanitize_html_class(TkEventWeather__FuncSetup::shortcode_name_hyphenated()));
     }
     // Code
     $debug = (bool) $atts['debug_on'];
     // if false === $transients, clear existing and set new transients
     if (!empty($atts['transients_off']) && 'true' == $atts['transients_off']) {
         $transients = false;
     } else {
         $transients = true;
     }
     // @link https://developer.wordpress.org/reference/functions/sanitize_key/
     $api_key = sanitize_key($atts['api_key']);
     if (empty($api_key)) {
         return TkEventWeather__Functions::invalid_shortcode_message('Please enter your Dark Sky API Key');
     }
     // manually entered override custom field
     $post_id = $atts['post_id'];
     // if post does not exist by ID, clear out $post_id variable
     // @link https://developer.wordpress.org/reference/functions/get_post_status/
     if (!empty($post_id)) {
         if (false === get_post_status($post_id)) {
             // The post does not exist
             $post_id = '';
         }
     }
     $template_data['post_id'] = $post_id;
     // the variable to send to Dark Sky API -- to be built via the code below
     $latitude_longitude = '';
     // only used temporarily if separate lat and long need to be combined into $latitude_longitude
     $latitude = '';
     $longitude = '';
     // combined lat,long (manual then custom field)
     if (!empty($atts['lat_long'])) {
         $latitude_longitude = $atts['lat_long'];
     } elseif (!empty($post_id) && !empty($atts['lat_long_custom_field'])) {
         $latitude_longitude = get_post_meta($post_id, $atts['lat_long_custom_field'], true);
     }
     $latitude_longitude = TkEventWeather__Functions::valid_lat_long($latitude_longitude);
     // if no lat,long yet then build via separate lat and long
     if (empty($latitude_longitude)) {
         // latitude
         if (!empty($atts['lat'])) {
             $latitude = $atts['lat'];
         } elseif (!empty($post_id) && !empty($atts['lat_custom_field'])) {
             $latitude = get_post_meta($post_id, $atts['lat_custom_field'], true);
         }
         // longitude
         if (!empty($atts['long'])) {
             $longitude = $atts['long'];
         } elseif (!empty($post_id) && !empty($atts['long_custom_field'])) {
             $longitude = get_post_meta($post_id, $atts['long_custom_field'], true);
         }
         // build comma-separated $latitude_longitude
         $latitude_longitude = sprintf('%F,%F', $latitude, $longitude);
         $latitude_longitude = TkEventWeather__Functions::valid_lat_long($latitude_longitude);
     }
     // Fetch from Google Maps Geocoding API
     $location = '';
     $location_api_data = '';
     if (empty($latitude_longitude)) {
         if (!empty($atts['location'])) {
             $location = $atts['location'];
         } elseif (!empty($post_id) && !empty($atts['location_custom_field'])) {
             $location = get_post_meta($post_id, $atts['location_custom_field'], true);
         }
         $location = trim($location);
     }
     // Google Maps Transient
     if (!empty($location)) {
         // build transient
         $location_transient_name = sprintf('%s_gmaps_%s', TkEventWeather__FuncSetup::$transient_name_prepend, TkEventWeather__Functions::remove_all_whitespace($location));
         $location_transient_name = TkEventWeather__Functions::sanitize_transient_name($location_transient_name);
         $location_transient_value = TkEventWeather__Functions::transient_get_or_delete($location_transient_name, $transients);
         if (!empty($location_transient_value)) {
             if (!is_object($location_transient_value) || is_wp_error($location_transient_value)) {
                 $location_transient_value = '';
                 delete_transient($location_transient_name);
             }
         }
         if (!empty($location_transient_value)) {
             $location_api_data = $location_transient_value;
         } else {
             // make an API call
             $location_request_uri = sprintf('https://maps.googleapis.com/maps/api/geocode/json?address=%s', urlencode($location));
             $location_request_uri_query_args = array();
             $gmaps_api_key = TkEventWeather__Functions::sanitize_key_allow_uppercase($atts['gmaps_api_key']);
             if (!empty($gmaps_api_key)) {
                 $location_request_uri_query_args['key'] = urlencode($gmaps_api_key);
             }
             if (!empty($location_request_uri_query_args)) {
                 $location_request_uri = add_query_arg($location_request_uri_query_args, $location_request_uri);
             }
             $location_request = wp_safe_remote_get(esc_url_raw($location_request_uri));
             if (is_wp_error($location_request)) {
                 return TkEventWeather__Functions::invalid_shortcode_message('Google Maps Geocoding API request sent but resulted in a WordPress Error. Please troubleshoot');
             }
             // @link https://developer.wordpress.org/reference/functions/wp_remote_retrieve_body/
             $location_body = wp_remote_retrieve_body($location_request);
             if (empty($location_body)) {
                 return TkEventWeather__Functions::invalid_shortcode_message('Google Maps Geocoding API request sent but nothing received. Please troubleshoot');
             }
             $location_api_data = json_decode($location_body);
             if (empty($location_api_data)) {
                 return TkEventWeather__Functions::invalid_shortcode_message('Google Maps Geocoding API response received but some sort of data inconsistency. Please troubleshoot');
             }
             // inside here because if using transient, $location_request will not be set
             if (!empty($debug)) {
                 $output .= sprintf('<!--%1$sTK Event Weather -- Google Maps Geocoding API -- Request URI%1$s%2$s%1$s-->%1$s', PHP_EOL, $location_request_uri);
             }
             /* Example Debug Output:
             <!--
             TK Event Weather -- Google Maps Geocoding API -- Request URI
             https://maps.googleapis.com/maps/api/geocode/json?address=The+White+House
             -->
             */
         }
         // do stuff with Google Maps Geocoding API data
         // see https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes
         if ('OK' != $location_api_data->status) {
             return TkEventWeather__Functions::invalid_shortcode_message('The Google Maps Geocoding API resulted in an error: ' . $location_api_data->status . '. See https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes');
         }
         if (!empty($location_api_data->results[0]->geometry->location->lat)) {
             $latitude = $location_api_data->results[0]->geometry->location->lat;
             $longitude = $location_api_data->results[0]->geometry->location->lng;
         }
         // build comma-separated $latitude_longitude
         $latitude_longitude = sprintf('%F,%F', $latitude, $longitude);
         $latitude_longitude = TkEventWeather__Functions::valid_lat_long($latitude_longitude);
         // now $api_data is set for sure (better be to have gotten this far)
         if (!empty($debug)) {
             $output .= sprintf('<!--%1$sTK Event Weather -- Google Maps Geocoding API -- JSON Data%1$s%2$s%1$s-->%1$s', PHP_EOL, json_encode($location_api_data, JSON_PRETTY_PRINT));
             // requires PHP 5.4
         }
         /* Example Debug Output:
         <!--
         TK Event Weather -- Google Maps Geocoding API -- JSON Data
         {
         		"results": [
         				{
         						"address_components": [
         								{
         										"long_name": "The White House",
         										"short_name": "The White House",
         										"types": [
         												"point_of_interest",
         												"establishment"
         										]
         								},
         								{
         										"long_name": "1600",
         										"short_name": "1600",
         										"types": [
         												"street_number"
         										]
         								},
         								{
         										"long_name": "Pennsylvania Avenue Northwest",
         										"short_name": "Pennsylvania Ave NW",
         										"types": [
         												"route"
         										]
         								},
         								{
         										"long_name": "Northwest Washington",
         										"short_name": "Northwest Washington",
         										"types": [
         												"neighborhood",
         												"political"
         										]
         								},
         								{
         										"long_name": "Washington",
         										"short_name": "Washington",
         										"types": [
         												"locality",
         												"political"
         										]
         								},
         								{
         										"long_name": "District of Columbia",
         										"short_name": "DC",
         										"types": [
         												"administrative_area_level_1",
         												"political"
         										]
         								},
         								{
         										"long_name": "United States",
         										"short_name": "US",
         										"types": [
         												"country",
         												"political"
         										]
         								},
         								{
         										"long_name": "20500",
         										"short_name": "20500",
         										"types": [
         												"postal_code"
         										]
         								}
         						],
         						"formatted_address": "The White House, 1600 Pennsylvania Ave NW, Washington, DC 20500, USA",
         						"geometry": {
         								"location": {
         										"lat": 38.8976763,
         										"lng": -77.0365298
         								},
         								"location_type": "APPROXIMATE",
         								"viewport": {
         										"northeast": {
         												"lat": 38.899025280291,
         												"lng": -77.035180819709
         										},
         										"southwest": {
         												"lat": 38.896327319708,
         												"lng": -77.037878780292
         										}
         								}
         						},
         						"partial_match": true,
         						"place_id": "ChIJ37HL3ry3t4kRv3YLbdhpWXE",
         						"types": [
         								"point_of_interest",
         								"establishment"
         						]
         				}
         		],
         		"status": "OK"
         }
         -->
         */
         // set transient if API call resulted in usable data
         if (true === $transients && !empty($latitude_longitude)) {
             set_transient($location_transient_name, $location_api_data, 30 * DAY_IN_SECONDS);
             // allowed to store for up to 30 calendar days, per https://developers.google.com/maps/terms#10-license-restrictions
         }
     }
     if (empty($latitude_longitude)) {
         return TkEventWeather__Functions::invalid_shortcode_message('Please enter valid Latitude and Longitude coordinates (or a Location that Google Maps can get coordinates for)');
     }
     $template_data['latitude_longitude'] = $latitude_longitude;
     // Start Time
     // ISO 8601 datetime or Unix timestamp
     if ('' != $atts['start_time']) {
         $start_time = $atts['start_time'];
     } elseif (!empty($post_id) && !empty($atts['start_time_custom_field'])) {
         $start_time = get_post_meta($post_id, $atts['lat_long_custom_field'], true);
     } else {
         $start_time = '';
     }
     if ('' != $start_time) {
         // check ISO 8601 first because it's stricter
         if (true === TkEventWeather__Functions::valid_iso_8601_date_time($start_time, 'bool')) {
             $start_time = TkEventWeather__Functions::valid_iso_8601_date_time($start_time);
             $start_time_iso_8601 = $start_time;
             $start_time_timestamp = date('U', strtotime($start_time));
         } elseif (true === TkEventWeather__Functions::valid_timestamp($start_time, 'bool')) {
             $start_time = TkEventWeather__Functions::valid_timestamp($start_time);
             $start_time_iso_8601 = date(DateTime::ATOM, $start_time);
             // DateTime::ATOM is same as 'c'
             $start_time_timestamp = $start_time;
         } else {
             $start_time = '';
         }
     }
     $start_time_timestamp = TkEventWeather__Functions::valid_timestamp($start_time_timestamp);
     if (empty($start_time_timestamp)) {
         return TkEventWeather__Functions::invalid_shortcode_message('Please enter a valid Start Time format');
     }
     $template_data['start_time_timestamp'] = $start_time_timestamp;
     $weather_first_hour_timestamp = TkEventWeather__Functions::timestamp_truncate_minutes($start_time_timestamp);
     $template_data['weather_first_hour_timestamp'] = $weather_first_hour_timestamp;
     // cutoff_past
     // strtotime date relative to $weather_first_hour_timestamp
     if (!empty($atts['cutoff_past'])) {
         $cutoff_past = $atts['cutoff_past'];
     } else {
         $cutoff_past = '';
     }
     if (empty($cutoff_past)) {
         // not set or set to zero (which means "no limit" per plugin option)
         $min_timestamp = '';
     } else {
         if (is_int($cutoff_past)) {
             // if is_int, use that number of NEGATIVE (past) days, per plugin option
             $min_timestamp = strtotime(sprintf('-%d days', absint($cutoff_past)));
         } else {
             // else, use raw input, hopefully formatted correctly (e.g. cutoff_past="2 weeks")
             $min_timestamp = strtotime(esc_html($cutoff_past));
             // returns false on bad input
         }
     }
     $min_timestamp = TkEventWeather__Functions::valid_timestamp($min_timestamp);
     if (!empty($min_timestamp) && '' != $weather_first_hour_timestamp) {
         if ($min_timestamp > $weather_first_hour_timestamp) {
             return TkEventWeather__Functions::invalid_shortcode_message('Event Start Time needs to be more recent than the Past Cutoff Time');
         }
     }
     // max 60 years in the past, per API docs
     if (strtotime('-60 years') > $weather_first_hour_timestamp) {
         return TkEventWeather__Functions::invalid_shortcode_message('Event Start Time needs to be more recent than 60 years in the past, per Dark Sky API docs,');
     }
     // End Time
     // ISO 8601 datetime or Unix timestamp
     if ('' != $atts['end_time']) {
         $end_time = $atts['end_time'];
     } elseif (!empty($post_id) && !empty($atts['end_time_custom_field'])) {
         $end_time = get_post_meta($post_id, $atts['lat_long_custom_field'], true);
     } else {
         $end_time = '';
     }
     if ('' != $end_time) {
         // check ISO 8601 first because it's stricter
         if (true === TkEventWeather__Functions::valid_iso_8601_date_time($end_time, 'bool')) {
             $end_time = TkEventWeather__Functions::valid_iso_8601_date_time($end_time);
             $end_time_iso_8601 = $end_time;
             $end_time_timestamp = TkEventWeather__Functions::valid_timestamp(date('U', strtotime($end_time)));
             // date() returns a string
         } elseif (true === TkEventWeather__Functions::valid_timestamp($end_time, 'bool')) {
             $end_time = TkEventWeather__Functions::valid_timestamp($end_time);
             $end_time_iso_8601 = date(DateTime::ATOM, $end_time);
             // DateTime::ATOM is same as 'c'
             $end_time_timestamp = $end_time;
         } else {
             $end_time = '';
         }
     }
     $end_time_timestamp = TkEventWeather__Functions::valid_timestamp($end_time_timestamp);
     if ('' == $end_time_timestamp) {
         return TkEventWeather__Functions::invalid_shortcode_message('Please enter a valid End Time format');
     }
     // if Event Start and End times are the same
     if ($weather_first_hour_timestamp == $end_time_timestamp) {
         return TkEventWeather__Functions::invalid_shortcode_message('Please make sure Event Start Time and Event End Time are not the same');
     }
     // if Event End time is before Start time
     if ($weather_first_hour_timestamp > $end_time_timestamp) {
         return TkEventWeather__Functions::invalid_shortcode_message('Event Start Time must be earlier than Event End Time');
     }
     $template_data['end_time_timestamp'] = $end_time_timestamp;
     /**
      * $weather_last_hour_timestamp helps with setting 'sunset_to_be_inserted'
      * 
      * if event ends at 7:52pm, set $weather_last_hour_timestamp to 8pm
      * if event ends at 7:00:00pm, set $weather_last_hour_timestamp to 7pm
      * 
      **/
     $end_time_hour_timestamp = TkEventWeather__Functions::timestamp_truncate_minutes($end_time_timestamp);
     // e.g. 7pm instead of 7:52pm
     $end_time_hour_timestamp_plus_one_hour = 3600 + $end_time_hour_timestamp;
     // e.g. 8pm
     if ($end_time_timestamp == $end_time_hour_timestamp) {
         // e.g. event ends at 7:00:00
         $weather_last_hour_timestamp = $end_time_hour_timestamp;
     } else {
         $weather_last_hour_timestamp = $end_time_hour_timestamp_plus_one_hour;
     }
     $template_data['weather_last_hour_timestamp'] = TkEventWeather__Functions::valid_timestamp($weather_last_hour_timestamp);
     //
     // cutoff_future
     // strtotime date relative to $end_time_timestamp
     if (!empty($atts['cutoff_future'])) {
         $cutoff_future = $atts['cutoff_future'];
     } else {
         $cutoff_future = '';
     }
     if (empty($cutoff_future)) {
         // not set or set to zero (which means "no limit" per plugin option)
         $max_timestamp = '';
     } else {
         if (is_int($cutoff_future)) {
             // if is_int, use that number of POSITIVE (future) days, per plugin option
             $max_timestamp = strtotime(sprintf('+%d days', absint($cutoff_future)));
         } else {
             // else, use raw input, hopefully formatted correctly (e.g. cutoff_future="2 weeks")
             $max_timestamp = strtotime(esc_html($cutoff_future));
             // returns false on bad input
         }
     }
     $max_timestamp = TkEventWeather__Functions::valid_timestamp($max_timestamp);
     if (!empty($max_timestamp) && '' != $end_time_timestamp) {
         if ($end_time_timestamp > $max_timestamp) {
             return TkEventWeather__Functions::invalid_shortcode_message('Event End Time needs to be more recent than Future Cutoff Time');
         }
     }
     // max 10 years future, per API docs
     if ($end_time_timestamp > strtotime('+10 years')) {
         return TkEventWeather__Functions::invalid_shortcode_message('Event End Time needs to be less than 10 years in the future, per Dark Sky API docs,');
     }
     //
     // $weather_first_hour_timestamp is equal to or greater than $min_timestamp and $end_time_timestamp is less than or equal to $max_timestamp
     // or $min_timestamp and/or $max_timestamp were set to zero (i.e. no limits)
     // so continue...
     //
     // units
     $units = TkEventWeather__Functions::remove_all_whitespace(strtolower($atts['units']));
     $units_default = apply_filters('tk_event_weather_darksky_units_default', $units_option);
     if (!array_key_exists($units, TkEventWeather__Functions::darksky_option_units())) {
         $units = $units_default;
     }
     // exclude
     $exclude = '';
     $exclude_default = apply_filters('tk_event_weather_darksky_exclude_default', 'minutely,alerts');
     // shortcode argument's value
     $exclude_arg = TkEventWeather__Functions::remove_all_whitespace(strtolower($atts['exclude']));
     if (empty($exclude_arg) || $exclude_default == $exclude_arg) {
         $exclude = $exclude_default;
     } else {
         // array of shortcode argument's value
         $exclude_arg_array = explode(',', $exclude_arg);
         if (is_array($exclude_arg_array)) {
             sort($exclude_arg_array);
             $possible_excludes = TkEventWeather__Functions::darksky_option_exclude();
             foreach ($exclude_arg_array as $key => $value) {
                 // if valid 'exclude' then keep it, else ignore it
                 if (array_key_exists($value, $possible_excludes)) {
                     if (empty($exclude)) {
                         // if first to be added to $exclude
                         $exclude .= $value;
                     } else {
                         // if not first one added to $exclude
                         $exclude .= ',';
                         $exclude .= $value;
                     }
                 } else {
                 }
             }
             // foreach()
         }
         // is_array()
     }
     // else
     // Prepare $exclude_for_transient (first letter of each $exclude, not separated by any character)
     $exclude_for_transient = '';
     $exclude_array = explode(',', $exclude);
     if (is_array($exclude_array)) {
         sort($exclude_array);
         foreach ($exclude_array as $key => $value) {
             if (empty($exclude_for_transient)) {
                 $exclude_for_transient .= substr($value, 0, 1);
             } else {
                 // $exclude_for_transient .= '_';
                 $exclude_for_transient .= substr($value, 0, 1);
             }
         }
     }
     // Transients
     // @link https://codex.wordpress.org/Transients_API
     // @link https://codex.wordpress.org/Easier_Expression_of_Time_Constants
     // build transient
     $transient_name = sprintf('%s_fio_%s_%s_%s_%s_%d', TkEventWeather__FuncSetup::$transient_name_prepend, $units, $exclude_for_transient, substr(strstr($latitude_longitude, ',', true), 0, 6), substr(strstr($latitude_longitude, ',', false), 0, 6), substr($weather_first_hour_timestamp, -5, 5));
     $transient_name = TkEventWeather__Functions::sanitize_transient_name($transient_name);
     $transient_value = TkEventWeather__Functions::transient_get_or_delete($transient_name, $transients);
     // Make API call if nothing from Transients
     // e.g. https://api.darksky.net/forecast/APIKEY/LATITUDE,LONGITUDE,TIME
     // if invalid API key, returns 400 Bad Request
     // API does not want any querying wrapped in brackets, as may be shown in the documentation -- brackets indicates OPTIONAL parameters, not to actually wrap in brackets for your request
     //
     // $api_data->currently is either 'right now' if no TIMESTAMP is part of the API or is the weather for the given TIMESTAMP even if in the past or future (yes, it still is called 'currently')
     //
     /*
     *
     *
     * Example:
     * Weather for the White House on Feb 1 at 4:30pm Eastern Time (as of 2016-01-25T03:01:09-06:00)
     * API call in ISO 8601 format
     * https://api.darksky.net/forecast/_______API_KEY_______/36.281445,-75.794662,2016-02-01T16:30:00-05:00?units=auto&exclude=alerts,daily,flags,hourly,minutely
     * API call in Unix Timestamp format (same result)
     * https://api.darksky.net/forecast/_______API_KEY_______/36.281445,-75.794662,1454362200?units=auto&exclude=alerts,daily,flags,hourly,minutely
     * result:
     <!--
     TK Event Weather JSON Data
     {
     		"latitude": 36.281445,
     		"longitude": -75.794662,
     		"timezone": "America\/New_York",
     		"offset": -5,
     		"currently": {
     	"time": 1454362200,
     	"summary": "Clear",
     	"icon": "clear-day",
     	"precipIntensity": 0.0008,
     	"precipProbability": 0.01,
     	"precipType": "rain",
     	"temperature": 56.9,
     	"apparentTemperature": 56.9,
     	"dewPoint": 48.64,
     	"humidity": 0.74,
     	"windSpeed": 1.91,
     	"windBearing": 163,
     	"cloudCover": 0,
     	"pressure": 1016.99,
     	"ozone": 280.52
     		}
     }
     -->
     
     
     
     
     
     
     // if API doesn't TECHNICALLY error out but does return an API error message
     examples:
     {"code":400,"error":"An invalid time was specified."}
     {"code":400,"error":"An invalid units parameter was provided."}
     *
     *
     */
     if (!empty($transient_value)) {
         $api_data = $transient_value;
         if (empty($api_data)) {
             delete_transient($transient_name);
             // return TkEventWeather__Functions::invalid_shortcode_message( 'Data from Transient used but some sort of data inconsistency. Transient deleted. May or may not need to troubleshoot' );
         }
         if (!empty($api_data->error)) {
             delete_transient($transient_name);
             // return TkEventWeather__Functions::invalid_shortcode_message( 'Data from Transient used but an error: ' . $api_data->error . '. Transient deleted. May or may not need to troubleshoot' );
         }
     }
     // $api_data not yet set because $transient_value was bad so just run through new API call as if transient did not exist (got deleted a few lines above)
     if (empty($api_data)) {
         delete_transient($transient_name);
         // delete any expired transient by this name
         $request_uri = sprintf('https://api.darksky.net/forecast/%s/%s,%s', $api_key, $latitude_longitude, $start_time_timestamp);
         $request_uri_query_args = array();
         if (!empty($units)) {
             $request_uri_query_args['units'] = $units;
         }
         if (!empty($exclude)) {
             $request_uri_query_args['exclude'] = $exclude;
         }
         if (!empty($request_uri_query_args)) {
             $request_uri = add_query_arg($request_uri_query_args, $request_uri);
         }
         // GET STUFF FROM API
         // @link https://codex.wordpress.org/Function_Reference/esc_url_raw
         // @link https://developer.wordpress.org/reference/functions/wp_safe_remote_get/
         $request = wp_safe_remote_get(esc_url_raw($request_uri));
         // @link https://developer.wordpress.org/reference/functions/is_wp_error/
         if (is_wp_error($request)) {
             return TkEventWeather__Functions::invalid_shortcode_message('Dark Sky API request sent but resulted in a WordPress Error. Please troubleshoot');
         }
         // @link https://developer.wordpress.org/reference/functions/wp_remote_retrieve_body/
         $body = wp_remote_retrieve_body($request);
         if (empty($body)) {
             return TkEventWeather__Functions::invalid_shortcode_message('Dark Sky API request sent but nothing received. Please troubleshoot');
         }
         $api_data = json_decode($body);
         if (empty($api_data)) {
             return TkEventWeather__Functions::invalid_shortcode_message('Dark Sky API response received but some sort of data inconsistency. Please troubleshoot');
         }
         if (!empty($api_data->error)) {
             return TkEventWeather__Functions::invalid_shortcode_message('Dark Sky API responded with an error: ' . $api_data->error . ' - Please troubleshoot');
         }
         if (empty($api_data->hourly->data)) {
             return TkEventWeather__Functions::invalid_shortcode_message('Dark Sky API responded but without hourly data. Please troubleshoot');
         }
         // inside here because if using transient, $request will not be set
         if (!empty($debug)) {
             $output .= sprintf('<!--%1$sTK Event Weather -- Dark Sky API -- Request URI%1$s%2$s%1$s-->%1$s', PHP_EOL, $request_uri);
         }
         /* Example Debug Output:
         <!--
         TK Event Weather -- Dark Sky API -- Request URI
         https://api.darksky.net/forecast/___API_KEY___/38.897676,-77.036530,1464604200?units=auto&exclude=minutely,alerts
         -->
         */
         if (true === $transients) {
             $transients_expiration_hours = absint($atts['transients_expiration']);
             if (0 >= $transients_expiration_hours) {
                 $transients_expiration_hours = absint($transients_expiration_hours_option);
             }
             set_transient($transient_name, $api_data, $transients_expiration_hours * HOUR_IN_SECONDS);
             // e.g. 12 hours
         }
     }
     /*
     	Example var_dump($request) when bad data, like https://api.darksky.net/forecast/___API_KEY___/0.000000,0.000000,1466199900?exclude=minutely
     object(stdClass)[100]
     public 'latitude' => int 0
     public 'longitude' => int 0
     public 'timezone' => string 'Etc/GMT' (length=7)
     public 'offset' => int 0
     public 'currently' => 
     	object(stdClass)[677]
     		public 'time' => int 1466199900
     public 'flags' => 
     	object(stdClass)[96]
     		public 'sources' => 
     			array (size=0)
     				empty
     		public 'units' => string 'us' (length=2)
     */
     // now $api_data is set for sure (better be to have gotten this far)
     if (!empty($debug)) {
         $output .= sprintf('<!--%1$sTK Event Weather -- Dark Sky API -- JSON Data%1$s%2$s%1$s-->%1$s', PHP_EOL, json_encode($api_data, JSON_PRETTY_PRINT));
         // requires PHP 5.4
     }
     /* Example Debug Output:
     <!--
     TK Event Weather -- Dark Sky API -- JSON Data
     {
     		"latitude": 38.897676,
     		"longitude": -77.03653,
     		"timezone": "America\/New_York",
     		"offset": -4,
     		"currently": {
     				"time": 1464604200,
     				"summary": "Partly Cloudy",
     				"icon": "partly-cloudy-day",
     				"precipType": "rain",
     				"temperature": 65.66,
     				"temperatureError": 6.32,
     				"apparentTemperature": 65.66,
     				"dewPoint": 58.39,
     				"dewPointError": 5,
     				"humidity": 0.77,
     				"humidityError": 0.14,
     				"windSpeed": 4.08,
     				"windSpeedError": 4.12,
     				"windBearing": 234,
     				"windBearingError": 45.29,
     				"visibility": 9.46,
     				"visibilityError": 6.28,
     				"cloudCover": 0.58,
     				"cloudCoverError": 0.4,
     				"pressure": 1015.95,
     				"pressureError": 5.5
     		},
     		"hourly": {
     				"summary": "Mostly cloudy throughout the day.",
     				"icon": "partly-cloudy-day",
     				"data": [
     						{
     								"time": 1464580800,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 69.52,
     								"temperatureError": 4.89,
     								"apparentTemperature": 69.52,
     								"dewPoint": 59.34,
     								"dewPointError": 4.05,
     								"humidity": 0.7,
     								"humidityError": 0.1,
     								"windSpeed": 4.37,
     								"windSpeedError": 3.09,
     								"windBearing": 193,
     								"windBearingError": 35.28,
     								"visibility": 10,
     								"visibilityError": 4.97,
     								"cloudCover": 0.55,
     								"cloudCoverError": 0.28,
     								"pressure": 1015.86,
     								"pressureError": 5.51
     						},
     						{
     								"time": 1464584400,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 68.56,
     								"temperatureError": 4.88,
     								"apparentTemperature": 68.56,
     								"dewPoint": 59.29,
     								"dewPointError": 3.85,
     								"humidity": 0.72,
     								"humidityError": 0.1,
     								"windSpeed": 4.62,
     								"windSpeedError": 3.12,
     								"windBearing": 205,
     								"windBearingError": 34.05,
     								"visibility": 10,
     								"visibilityError": 4.87,
     								"cloudCover": 0.54,
     								"cloudCoverError": 0.29,
     								"pressure": 1015.76,
     								"pressureError": 5.51
     						},
     						{
     								"time": 1464588000,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 67.67,
     								"temperatureError": 5.04,
     								"apparentTemperature": 67.67,
     								"dewPoint": 59.2,
     								"dewPointError": 3.86,
     								"humidity": 0.74,
     								"humidityError": 0.1,
     								"windSpeed": 4.63,
     								"windSpeedError": 3.24,
     								"windBearing": 218,
     								"windBearingError": 35,
     								"visibility": 10,
     								"visibilityError": 4.95,
     								"cloudCover": 0.54,
     								"cloudCoverError": 0.31,
     								"pressure": 1015.6,
     								"pressureError": 5.51
     						},
     						{
     								"time": 1464591600,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 66.85,
     								"temperatureError": 5.31,
     								"apparentTemperature": 66.85,
     								"dewPoint": 59.05,
     								"dewPointError": 4.03,
     								"humidity": 0.76,
     								"humidityError": 0.11,
     								"windSpeed": 4.45,
     								"windSpeedError": 3.43,
     								"windBearing": 226,
     								"windBearingError": 37.58,
     								"visibility": 10,
     								"visibilityError": 5.16,
     								"cloudCover": 0.54,
     								"cloudCoverError": 0.33,
     								"pressure": 1015.47,
     								"pressureError": 5.51
     						},
     						{
     								"time": 1464595200,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 66.14,
     								"temperatureError": 5.63,
     								"apparentTemperature": 66.14,
     								"dewPoint": 58.86,
     								"dewPointError": 4.28,
     								"humidity": 0.77,
     								"humidityError": 0.12,
     								"windSpeed": 4.28,
     								"windSpeedError": 3.65,
     								"windBearing": 230,
     								"windBearingError": 40.47,
     								"visibility": 10,
     								"visibilityError": 5.47,
     								"cloudCover": 0.55,
     								"cloudCoverError": 0.36,
     								"pressure": 1015.43,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464598800,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 65.65,
     								"temperatureError": 5.95,
     								"apparentTemperature": 65.65,
     								"dewPoint": 58.65,
     								"dewPointError": 4.57,
     								"humidity": 0.78,
     								"humidityError": 0.13,
     								"windSpeed": 4.13,
     								"windSpeedError": 3.87,
     								"windBearing": 233,
     								"windBearingError": 43.12,
     								"visibility": 9.87,
     								"visibilityError": 5.81,
     								"cloudCover": 0.56,
     								"cloudCoverError": 0.39,
     								"pressure": 1015.54,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464602400,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 65.5,
     								"temperatureError": 6.22,
     								"apparentTemperature": 65.5,
     								"dewPoint": 58.46,
     								"dewPointError": 4.86,
     								"humidity": 0.78,
     								"humidityError": 0.13,
     								"windSpeed": 4.05,
     								"windSpeedError": 4.05,
     								"windBearing": 234,
     								"windBearingError": 45.05,
     								"visibility": 9.56,
     								"visibilityError": 6.14,
     								"cloudCover": 0.57,
     								"cloudCoverError": 0.4,
     								"pressure": 1015.78,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464606000,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 65.82,
     								"temperatureError": 6.42,
     								"apparentTemperature": 65.82,
     								"dewPoint": 58.33,
     								"dewPointError": 5.15,
     								"humidity": 0.77,
     								"humidityError": 0.14,
     								"windSpeed": 4.12,
     								"windSpeedError": 4.2,
     								"windBearing": 234,
     								"windBearingError": 45.53,
     								"visibility": 9.35,
     								"visibilityError": 6.42,
     								"cloudCover": 0.59,
     								"cloudCoverError": 0.4,
     								"pressure": 1016.12,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464609600,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 66.67,
     								"temperatureError": 6.56,
     								"apparentTemperature": 66.67,
     								"dewPoint": 58.27,
     								"dewPointError": 5.48,
     								"humidity": 0.74,
     								"humidityError": 0.14,
     								"windSpeed": 4.58,
     								"windSpeedError": 4.29,
     								"windBearing": 231,
     								"windBearingError": 43.15,
     								"visibility": 9.3,
     								"visibilityError": 6.64,
     								"cloudCover": 0.61,
     								"cloudCoverError": 0.4,
     								"pressure": 1016.48,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464613200,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 68.07,
     								"temperatureError": 6.67,
     								"apparentTemperature": 68.07,
     								"dewPoint": 58.26,
     								"dewPointError": 5.88,
     								"humidity": 0.71,
     								"humidityError": 0.15,
     								"windSpeed": 6.02,
     								"windSpeedError": 4.36,
     								"windBearing": 234,
     								"windBearingError": 35.88,
     								"visibility": 9.48,
     								"visibilityError": 6.81,
     								"cloudCover": 0.62,
     								"cloudCoverError": 0.38,
     								"pressure": 1016.77,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464616800,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 69.93,
     								"temperatureError": 6.78,
     								"apparentTemperature": 69.93,
     								"dewPoint": 58.24,
     								"dewPointError": 6.42,
     								"humidity": 0.66,
     								"humidityError": 0.15,
     								"windSpeed": 6.84,
     								"windSpeedError": 4.41,
     								"windBearing": 241,
     								"windBearingError": 32.79,
     								"visibility": 9.87,
     								"visibilityError": 6.94,
     								"cloudCover": 0.64,
     								"cloudCoverError": 0.37,
     								"pressure": 1016.89,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464620400,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 72.07,
     								"temperatureError": 6.92,
     								"apparentTemperature": 72.07,
     								"dewPoint": 58.16,
     								"dewPointError": 7.14,
     								"humidity": 0.62,
     								"humidityError": 0.15,
     								"windSpeed": 7.48,
     								"windSpeedError": 4.46,
     								"windBearing": 243,
     								"windBearingError": 30.78,
     								"visibility": 10,
     								"visibilityError": 7.07,
     								"cloudCover": 0.65,
     								"cloudCoverError": 0.35,
     								"pressure": 1016.8,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464624000,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 74.26,
     								"temperatureError": 7.11,
     								"apparentTemperature": 74.26,
     								"dewPoint": 57.96,
     								"dewPointError": 8.07,
     								"humidity": 0.57,
     								"humidityError": 0.16,
     								"windSpeed": 8.09,
     								"windSpeedError": 4.52,
     								"windBearing": 244,
     								"windBearingError": 29.16,
     								"visibility": 10,
     								"visibilityError": 7.21,
     								"cloudCover": 0.66,
     								"cloudCoverError": 0.34,
     								"pressure": 1016.51,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464627600,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 76.22,
     								"temperatureError": 7.33,
     								"apparentTemperature": 76.22,
     								"dewPoint": 57.69,
     								"dewPointError": 9.14,
     								"humidity": 0.53,
     								"humidityError": 0.17,
     								"windSpeed": 8.57,
     								"windSpeedError": 4.58,
     								"windBearing": 243,
     								"windBearingError": 28.13,
     								"visibility": 10,
     								"visibilityError": 7.37,
     								"cloudCover": 0.66,
     								"cloudCoverError": 0.33,
     								"pressure": 1016.05,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464631200,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 77.74,
     								"temperatureError": 7.54,
     								"apparentTemperature": 77.74,
     								"dewPoint": 57.46,
     								"dewPointError": 10.19,
     								"humidity": 0.5,
     								"humidityError": 0.18,
     								"windSpeed": 8.84,
     								"windSpeedError": 4.64,
     								"windBearing": 240,
     								"windBearingError": 27.69,
     								"visibility": 10,
     								"visibilityError": 7.52,
     								"cloudCover": 0.66,
     								"cloudCoverError": 0.34,
     								"pressure": 1015.52,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464634800,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 78.65,
     								"temperatureError": 7.71,
     								"apparentTemperature": 78.65,
     								"dewPoint": 57.39,
     								"dewPointError": 10.97,
     								"humidity": 0.48,
     								"humidityError": 0.18,
     								"windSpeed": 8.87,
     								"windSpeedError": 4.67,
     								"windBearing": 235,
     								"windBearingError": 27.78,
     								"visibility": 10,
     								"visibilityError": 7.63,
     								"cloudCover": 0.66,
     								"cloudCoverError": 0.35,
     								"pressure": 1015.01,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464638400,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 78.87,
     								"temperatureError": 7.76,
     								"apparentTemperature": 78.87,
     								"dewPoint": 57.56,
     								"dewPointError": 11.22,
     								"humidity": 0.48,
     								"humidityError": 0.19,
     								"windSpeed": 8.63,
     								"windSpeedError": 4.65,
     								"windBearing": 228,
     								"windBearingError": 28.31,
     								"visibility": 10,
     								"visibilityError": 7.67,
     								"cloudCover": 0.65,
     								"cloudCoverError": 0.35,
     								"pressure": 1014.64,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464642000,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 78.45,
     								"temperatureError": 7.66,
     								"apparentTemperature": 78.45,
     								"dewPoint": 57.93,
     								"dewPointError": 10.84,
     								"humidity": 0.49,
     								"humidityError": 0.18,
     								"windSpeed": 8.13,
     								"windSpeedError": 4.56,
     								"windBearing": 219,
     								"windBearingError": 29.27,
     								"visibility": 10,
     								"visibilityError": 7.6,
     								"cloudCover": 0.64,
     								"cloudCoverError": 0.36,
     								"pressure": 1014.46,
     								"pressureError": 5.5
     						},
     						{
     								"time": 1464645600,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 77.5,
     								"temperatureError": 7.39,
     								"apparentTemperature": 77.5,
     								"dewPoint": 58.4,
     								"dewPointError": 9.94,
     								"humidity": 0.52,
     								"humidityError": 0.18,
     								"windSpeed": 7.42,
     								"windSpeedError": 4.38,
     								"windBearing": 208,
     								"windBearingError": 30.58,
     								"visibility": 10,
     								"visibilityError": 7.39,
     								"cloudCover": 0.63,
     								"cloudCoverError": 0.35,
     								"pressure": 1014.5,
     								"pressureError": 5.51
     						},
     						{
     								"time": 1464649200,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 76.21,
     								"temperatureError": 6.98,
     								"apparentTemperature": 76.21,
     								"dewPoint": 58.84,
     								"dewPointError": 8.73,
     								"humidity": 0.55,
     								"humidityError": 0.17,
     								"windSpeed": 6.69,
     								"windSpeedError": 4.15,
     								"windBearing": 198,
     								"windBearingError": 31.77,
     								"visibility": 10,
     								"visibilityError": 7.04,
     								"cloudCover": 0.61,
     								"cloudCoverError": 0.34,
     								"pressure": 1014.72,
     								"pressureError": 5.51
     						},
     						{
     								"time": 1464652800,
     								"summary": "Mostly Cloudy",
     								"icon": "partly-cloudy-day",
     								"precipType": "rain",
     								"temperature": 74.76,
     								"temperatureError": 6.46,
     								"apparentTemperature": 74.76,
     								"dewPoint": 59.18,
     								"dewPointError": 7.44,
     								"humidity": 0.58,
     								"humidityError": 0.15,
     								"windSpeed": 6.09,
     								"windSpeedError": 3.87,
     								"windBearing": 191,
     								"windBearingError": 32.41,
     								"visibility": 10,
     								"visibilityError": 6.59,
     								"cloudCover": 0.6,
     								"cloudCoverError": 0.33,
     								"pressure": 1015.06,
     								"pressureError": 5.51
     						},
     						{
     								"time": 1464656400,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 73.31,
     								"temperatureError": 5.92,
     								"apparentTemperature": 73.31,
     								"dewPoint": 59.41,
     								"dewPointError": 6.25,
     								"humidity": 0.62,
     								"humidityError": 0.14,
     								"windSpeed": 5.66,
     								"windSpeedError": 3.58,
     								"windBearing": 187,
     								"windBearingError": 32.32,
     								"visibility": 10,
     								"visibilityError": 6.1,
     								"cloudCover": 0.58,
     								"cloudCoverError": 0.31,
     								"pressure": 1015.41,
     								"pressureError": 5.51
     						},
     						{
     								"time": 1464660000,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 71.97,
     								"temperatureError": 5.43,
     								"apparentTemperature": 71.97,
     								"dewPoint": 59.53,
     								"dewPointError": 5.25,
     								"humidity": 0.65,
     								"humidityError": 0.12,
     								"windSpeed": 5.41,
     								"windSpeedError": 3.33,
     								"windBearing": 187,
     								"windBearingError": 31.62,
     								"visibility": 10,
     								"visibilityError": 5.62,
     								"cloudCover": 0.57,
     								"cloudCoverError": 0.29,
     								"pressure": 1015.7,
     								"pressureError": 5.52
     						},
     						{
     								"time": 1464663600,
     								"summary": "Partly Cloudy",
     								"icon": "partly-cloudy-night",
     								"precipType": "rain",
     								"temperature": 70.78,
     								"temperatureError": 5.06,
     								"apparentTemperature": 70.78,
     								"dewPoint": 59.58,
     								"dewPointError": 4.5,
     								"humidity": 0.68,
     								"humidityError": 0.11,
     								"windSpeed": 5.32,
     								"windSpeedError": 3.16,
     								"windBearing": 188,
     								"windBearingError": 30.7,
     								"visibility": 10,
     								"visibilityError": 5.22,
     								"cloudCover": 0.55,
     								"cloudCoverError": 0.28,
     								"pressure": 1015.87,
     								"pressureError": 5.52
     						}
     				]
     		},
     		"daily": {
     				"data": [
     						{
     								"time": 1464580800,
     								"summary": "Mostly cloudy throughout the day.",
     								"icon": "partly-cloudy-day",
     								"sunriseTime": 1464601606,
     								"sunsetTime": 1464654461,
     								"moonPhase": 0.8,
     								"precipType": "rain",
     								"temperatureMin": 65.5,
     								"temperatureMinError": 6.22,
     								"temperatureMinTime": 1464602400,
     								"temperatureMax": 78.87,
     								"temperatureMaxError": 7.76,
     								"temperatureMaxTime": 1464638400,
     								"apparentTemperatureMin": 65.5,
     								"apparentTemperatureMinTime": 1464602400,
     								"apparentTemperatureMax": 78.87,
     								"apparentTemperatureMaxTime": 1464638400,
     								"dewPoint": 58.54,
     								"dewPointError": 7.19,
     								"humidity": 0.64,
     								"humidityError": 0.15,
     								"windSpeed": 5.78,
     								"windSpeedError": 4.05,
     								"windBearing": 222,
     								"windBearingError": 34.98,
     								"visibility": 10,
     								"visibilityError": 6.49,
     								"cloudCover": 0.6,
     								"cloudCoverError": 0.34,
     								"pressure": 1015.67,
     								"pressureError": 5.5
     						}
     				]
     		},
     		"flags": {
     				"sources": [
     						"isd"
     				],
     				"isd-stations": [
     						"724050-13743",
     						"997314-99999",
     						"999999-13710",
     						"999999-13751",
     						"999999-93725"
     				],
     				"units": "us"
     		}
     }
     -->
     */
     // Build Weather data that we'll use
     // https://developer.wordpress.org/reference/functions/wp_list_pluck/
     $api_data_houly_hours = wp_list_pluck($api_data->hourly->data, 'time');
     $api_data_houly_hours_keys = array_keys($api_data_houly_hours);
     // First hour to start pulling for Hourly Data
     foreach ($api_data_houly_hours as $key => $value) {
         if (intval($value) == intval($weather_first_hour_timestamp)) {
             $weather_hourly_start_key = $key;
             // so we know where to start when pulling hourly weather
             break;
         }
     }
     // Protect against odd hourly weather scenarios like location only having data from midnight to 8am and event start time is 9am
     if (!isset($weather_hourly_start_key)) {
         // need to allow for zero due to numeric array
         return TkEventWeather__Functions::invalid_shortcode_message('Event Start Time error. API did not return enough hourly data. Please troubleshoot');
     }
     // End Time Weather
     foreach ($api_data_houly_hours as $key => $value) {
         if (intval($value) >= intval($end_time_timestamp)) {
             $weather_hourly_end_key = $key;
             break;
         }
     }
     // if none, just get last hour of the day (e.g. if Event End Time is next day 2am, just get 11pm same day as Event Start Time (not perfect but may be better than 2nd API call)
     if (!isset($weather_hourly_end_key)) {
         // need to allow for zero due to numeric array
         $weather_hourly_end_key = end($api_data_houly_hours_keys);
     }
     if (!isset($weather_hourly_end_key)) {
         // need to allow for zero due to numeric array
         return TkEventWeather__Functions::invalid_shortcode_message('Event End Time is out of range. Please troubleshoot');
     }
     // UTC Offset -- only use is when displaying a timestamp
     $utc_offset = TkEventWeather__Functions::remove_all_whitespace(strtolower($atts['utc_offset_type']));
     if ('wp' == $utc_offset) {
         $utc_offset = 'wordpress';
     }
     if (!array_key_exists($utc_offset, TkEventWeather__Functions::valid_utc_offset_types())) {
         $utc_offset = 'api';
     }
     $utc_offset_hours = '';
     if ('api' == $utc_offset) {
         $utc_offset_hours = $api_data->offset;
     }
     $template_data['utc_offset_hours'] = $utc_offset_hours;
     $sunrise_sunset = array('on' => false, 'sunrise_timestamp' => false, 'sunrise_hour_timestamp' => false, 'sunset_timestamp' => false, 'sunset_hour_timestamp' => false, 'sunrise_to_be_inserted' => false, 'sunset_to_be_inserted' => false);
     if (empty($atts['sunrise_sunset_off']) || 'true' != $atts['sunrise_sunset_off']) {
         $sunrise_sunset['on'] = true;
     }
     if (true === $sunrise_sunset['on']) {
         $sunrise_sunset['sunrise_timestamp'] = TkEventWeather__Functions::valid_timestamp($api_data->daily->data[0]->sunriseTime);
         $sunrise_sunset['sunrise_hour_timestamp'] = TkEventWeather__Functions::timestamp_truncate_minutes($sunrise_sunset['sunrise_timestamp']);
         if ($sunrise_sunset['sunrise_timestamp'] >= $weather_first_hour_timestamp) {
             $sunrise_sunset['sunrise_to_be_inserted'] = true;
         }
         $sunrise_sunset['sunset_timestamp'] = TkEventWeather__Functions::valid_timestamp($api_data->daily->data[0]->sunsetTime);
         $sunrise_sunset['sunset_hour_timestamp'] = TkEventWeather__Functions::timestamp_truncate_minutes($sunrise_sunset['sunset_timestamp']);
         if ($weather_last_hour_timestamp >= $sunrise_sunset['sunset_timestamp']) {
             $sunrise_sunset['sunset_to_be_inserted'] = true;
         }
     }
     $template_data['sunrise_sunset'] = $sunrise_sunset;
     // Icons
     $icons = $atts['icons'];
     if ('climacons' == $icons) {
         $icons = 'climacons_font';
     }
     if (empty($icons) || !in_array($icons, TkEventWeather__Functions::valid_icon_type())) {
         $icons = 'climacons_font';
     }
     // enqueue CSS file if using Climacons Icon Font
     if ('climacons_font' == $icons) {
         TkEventWeather__Functions::register_climacons_css();
         wp_enqueue_style('tkeventw-climacons');
     }
     // Hourly Weather
     // any internal pointers to reset first?
     $weather_hourly = array();
     $index = $weather_hourly_start_key;
     if (is_integer($index)) {
         foreach ($api_data->hourly->data as $key => $value) {
             if ($key > $weather_hourly_end_key) {
                 break;
             }
             if ($index == $key) {
                 $weather_hourly[$index] = $value;
                 $index++;
             }
         }
     }
     //$weather_hourly = TkEventWeather__Functions::sort_multidim_array_by_sub_key( $weather_hourly, 'time' );
     $template_data['weather_hourly'] = $weather_hourly;
     // Get Low and High from Hourly
     // https://developer.wordpress.org/reference/functions/wp_list_pluck/
     $weather_hourly_temperatures = wp_list_pluck($weather_hourly, 'temperature');
     // if nothing, will be an empty array
     $template_data['weather_hourly_temperatures'] = $weather_hourly_temperatures;
     $weather_hourly_high = '';
     if (!empty($weather_hourly_temperatures) && is_array($weather_hourly_temperatures)) {
         $weather_hourly_high = max($weather_hourly_temperatures);
     }
     $template_data['weather_hourly_high'] = $weather_hourly_high;
     $weather_hourly_low = '';
     if (!empty($weather_hourly_temperatures) && is_array($weather_hourly_temperatures)) {
         $weather_hourly_low = min($weather_hourly_temperatures);
     }
     $template_data['weather_hourly_low'] = $weather_hourly_low;
     $temperature_units = TkEventWeather__Functions::temperature_units($api_data->flags->units);
     $template_data['temperature_units'] = $temperature_units;
     $wind_speed_units = TkEventWeather__Functions::wind_speed_units($api_data->flags->units);
     $template_data['wind_speed_units'] = $wind_speed_units;
     // class
     $class = sanitize_html_class($atts['class']);
     if (!empty($class)) {
         $class = ' ' . $class;
     }
     $display_template = TkEventWeather__Functions::remove_all_whitespace(strtolower($atts['template']));
     if (!array_key_exists($display_template, TkEventWeather__Functions::valid_display_templates())) {
         $display_template = 'hourly_horizontal';
     }
     $template_data['template'] = $display_template;
     $template_class_name = TkEventWeather__Functions::template_class_name($display_template);
     $template_data['template_class_name'] = $template_class_name;
     // if Debug Mode is true, set $debug_vars to true for admins only
     if (!empty($debug) && current_user_can('edit_theme_options')) {
         // var_dump( get_defined_vars() ); // uncomment if you REALLY want to display this information
     }
     TkEventWeather__Functions::register_css();
     wp_enqueue_style(sanitize_html_class(TkEventWeather__FuncSetup::shortcode_name_hyphenated()));
     /**
      * Start Building Output!!!
      * All data should be set by now!!!
      */
     // cannot do <style> tags inside template because it will break any open div (e.g. wrapper div)
     $output .= sprintf('<div class="tk-event-weather__wrapper%s">', $class);
     $output .= PHP_EOL;
     $output .= sprintf('<div class="tk-event-weather-template %s">', $template_data['template_class_name']);
     $output .= PHP_EOL;
     // https://github.com/GaryJones/Gamajo-Template-Loader/issues/13#issuecomment-196046201
     ob_start();
     TkEventWeather__Functions::load_template($display_template, $template_data);
     $output .= ob_get_clean();
     if ('true' == $atts['plugin_credit_link_on']) {
         $output .= TkEventWeather__Functions::plugin_credit_link();
     }
     if (empty($atts['darksky_credit_link_off'])) {
         $output .= TkEventWeather__Functions::darksky_credit_link();
     }
     $output .= '</div>';
     // .tk-event-weather-template
     $output .= PHP_EOL;
     $output .= '</div>';
     // .tk-event-weather--wrapper
     $output .= PHP_EOL;
     return $output;
 }
 /**
  * If your subclass of this class lives in a different directory,
  * override this method with the exact same code. Since __FILE__ will
  * be different, you will then get the right dir returned.
  * @return string
  *
  * @link https://developer.wordpress.org/reference/functions/plugin_dir_path/
  */
 protected function getPluginDir()
 {
     return TkEventWeather__FuncSetup::plugin_dir_path_root();
 }
예제 #4
0
    /**
     * Creates HTML for the Administration page to set options for this plugin.
     * Override this method to create a customized page.
     * @return void
     */
    public function settingsPage()
    {
        if (!current_user_can('manage_options')) {
            wp_die(__('You do not have sufficient permissions to access this page.', 'tk-event-weather'));
        }
        // HTML for the page
        $settingsGroup = get_class($this) . '-settings-group';
        ?>
				
								
				<div class="wrap">
					<h1><?php 
        echo $this->getPluginDisplayName();
        echo ' ';
        _e('Settings', 'tk-event-weather');
        ?>
</h1>
						
				<?php 
        // Greeting Box
        ?>
				<div style="width: 80%; padding: 20px; margin: 20px; background-color: #fff; font-size: 120%;">
				<?php 
        $tourkick_logo = TkEventWeather__FuncSetup::plugin_dir_url_images() . 'tourkick-logo-square-300.png';
        printf('<a href="http://tourkick.com/" target="_blank"><img style="float: left; margin: 5px 40px 10px 10px;" width="100" height="100" src="%s"></a>', $tourkick_logo);
        ?>
						<?php 
        $addons_url = tk_event_weather_freemius()->addon_url('');
        if (!empty($addons_url)) {
            ?>
				<p style="font-size: 120%;">
				<?php 
            printf(esc_html__('Check out the %sTK Event Weather add-on plugins%s to automatically integrate with popular WordPress calendars!', 'tk-event-weather'), '<a href="' . tk_event_weather_freemius()->addon_url('') . '">', '</a>');
            ?>
						<ul style="list-style: disc; list-style-position: inside;">
							<li>TK Event Weather for The Events Calendar by Modern Tribe</li>
						</ul>
					</p>
			<?php 
        }
        ?>
					<br>
					<p>
						<a href="http://b.tourkick.com/tkeventw-rate-5-stars" target="_blank"><?php 
        esc_html_e('Share your 5-Star Review on WordPress.org', 'tk-event-weather');
        ?>
</a>
				</p>
					<p>
					<a href="http://b.tourkick.com/github-tk-event-weather" target="_blank">Contribute via GitHub</a>				</p>
					<p><?php 
        esc_html_e('Find me online', 'tk-event-weather');
        ?>
: <a href="http://b.tourkick.com/twitter-follow-tourkick" target="_blank">Twitter</a> | <a href="http://b.tourkick.com/facebook-tourkick" target="_blank">Facebook</a> | <a href="http://b.tourkick.com/cliffpaulick-w-org-profile-plugins" target="_blank">WordPress Profile</a> | <a href="http://b.tourkick.com/tourkick-com" target="_blank">Website</a></p>
					<hr>
					<p style="font-style: italic;"><?php 
        echo tk_event_weather_terms_agreement_text();
        ?>
</p>
				</div>
				
				
				
						
						<?php 
        $active_tab = isset($_GET['tab']) ? $_GET['tab'] : 'options';
        $active_tab = wp_kses_post(esc_attr($active_tab));
        ?>
						<h2 class="nav-tab-wrapper">
							<a href="<?php 
        printf('?page=%s&tab=options', $this->getSettingsSlug());
        ?>
" class="nav-tab <?php 
        echo $active_tab == 'options' ? 'nav-tab-active' : '';
        ?>
"><?php 
        esc_html_e('Options', 'tk-event-weather');
        ?>
</a>
							<a href="<?php 
        printf('?page=%s&tab=tools', $this->getSettingsSlug());
        ?>
" class="nav-tab <?php 
        echo $active_tab == 'tools' ? 'nav-tab-active' : '';
        ?>
"><?php 
        esc_html_e('Tools', 'tk-event-weather');
        ?>
</a>
							<a href="<?php 
        printf('?page=%s&tab=help', $this->getSettingsSlug());
        ?>
" class="nav-tab <?php 
        echo $active_tab == 'help' ? 'nav-tab-active' : '';
        ?>
"><?php 
        esc_html_e('Help', 'tk-event-weather');
        ?>
</a>
						</h2>
						<?php 
        if ($active_tab == 'options') {
            ?>
						<p><?php 
            _e("This plugin uses the WordPress Customizer to set its options.", 'tk-event-weather');
            ?>
</p>
						<p><?php 
            _e("Click the button below to be taken directly to this plugin's section within the WordPress Customizer.", 'tk-event-weather');
            ?>
</p>
						<p>
								<a href="<?php 
            echo apply_filters('tk_event_weather_customizer_link', get_admin_url(get_current_blog_id(), 'customize.php'));
            ?>
" class="button-primary">
									<?php 
            _e('Edit Plugin Settings in WP Customizer', 'tk-event-weather');
            ?>
								</a>
						</p>
						<br><br>
						<?php 
            /**
            	* Commented out until method exists to return a string for direct URL to re-prompt anonymous users with opt-in -- https://github.com/Freemius/wordpress-sdk/issues/42
            	* because connect_again() doesn't return a string to be used like this (as-is will re-prompt anonymous users every time they visit the plugin's settings page)
            	* and because Edit Freemius Settings button (then click Delete All Accounts button) is only for my development/testing, not for users
            	*
            if ( ! empty ( tk_event_weather_freemius()->is_anonymous() ) ) {
            	printf ( '<p><a href="%s" class="button-secondary">%s</a></p>', tk_event_weather_freemius()->connect_again(), __( 'Connect to Freemius!', 'tk-event-weather' ) );
            } else {
            	// maybe https://developer.wordpress.org/reference/functions/network_admin_url/ ?
            	printf ( '<p><a href="%s" class="button-secondary">%s</a></p>', admin_url( 'admin.php?page=freemius' ), __( 'Edit Freemius Settings', 'tk-event-weather' ) );
            	} // freemius is_anonymous()
            */
        } elseif ($active_tab == 'tools') {
            ?>
						<h2><?php 
            _e('Shortcode Examples', 'tk-event-weather');
            ?>
</h2>
						<p><?php 
            _e('Multiple ways to display the weather for the White House on February 1, 2016, from 4:30pm&ndash;9:45pm Eastern Time', 'tk-event-weather');
            ?>
:</p>
						<div style="margin-left: 20px;">
				<?php 
            esc_html_e('A) with single Latitude/Longitude shortcode argument and ISO 8601 datetime format', 'tk-event-weather');
            ?>
:
					<ul style="list-style-type:disc; list-style-position: inside;"><li>[tk_event_weather lat_long="38.897676,-77.03653" start_time="2016-02-01T16:30:00-05:00" end_time="2016-02-01T21:45:00-05:00"]</li></ul>
				<?php 
            esc_html_e('B) or separate shortcode arguments for Latitude and Longitude', 'tk-event-weather');
            ?>
:
					<ul style="list-style-type:disc; list-style-position: inside;"><li>[tk_event_weather lat="38.897676" long="-77.03653" start_time="2016-02-01T16:30:00-05:00" end_time="2016-02-01T21:45:00-05:00"]</li></ul>
				<?php 
            esc_html_e('C) or with Unix timestamps', 'tk-event-weather');
            ?>
:
					<ul style="list-style-type:disc; list-style-position: inside;"><li>[tk_event_weather lat_long="38.897676,-77.03653" start_time="1454362200" end_time="1454381100"]</li></ul>
				<?php 
            esc_html_e('D) Just like Example A but with Location shortcode argument (a Place name)', 'tk-event-weather');
            ?>
:
					<ul style="list-style-type:disc; list-style-position: inside;"><li>[tk_event_weather location="The White House" start_time="1454362200" end_time="1454381100"]</li></ul>
				<?php 
            esc_html_e('E) Just like Example D but with Location shortcode argument (a full address)', 'tk-event-weather');
            ?>
:
					<ul style="list-style-type:disc; list-style-position: inside;"><li>[tk_event_weather location="1600 Pennsylvania Ave NW, Washington, DC 20500, USA" start_time="1454362200" end_time="1454381100"]</li></ul>
						</div>
						<br>
						<h2><?php 
            _e('Google Maps', 'tk-event-weather');
            ?>
</h2>
						<p style="font-style: italic;"><?php 
            printf(__('By using Google Maps, including the %slocation%s shortcode argument, you are agreeing to be bound by %s (link opens in new window).', 'tk-event-weather'), '<strong>', '</strong>', '<a href="https://developers.google.com/maps/terms" target="_blank">Google\'s Terms of Service</a>');
            ?>
</p>
						<p><?php 
            _e('Powered by Google.', 'tk-event-weather');
            ?>
</p>
						<h2><?php 
            _e('Geocoding&mdash;Find Latitude and Longitude Coordinates', 'tk-event-weather');
            ?>
</h2>
						<p><?php 
            printf(__('To help you find the Latitude and Longitude of a location to use in your shortcode, you may do a Google Maps lookup here without %sAPI usage limitations%s (link opens in new window). Type an address or place name, get the coordinates, manually paste them into wherever you are using the shortcode', 'tk-event-weather'), '<a href="https://developers.google.com/maps/faq#usage-limits" target="_blank">', '</a>');
            ?>
:</p>
			<iframe style="text-align: center; margin-left: 10%; margin-right: 10%; width: 80%; min-width: 300px;" name="Google Maps API Geocoder Tool" src="http://b.tourkick.com/google-maps-geocoder" height="575" width="800">
				<p>Your browser does not support iframes. Please visit the <a href="http://b.tourkick.com/google-maps-geocoder" target="_blank">Google Maps API Geocoder Tool</a> directly.</p>
			</iframe>
						<br><br>
						<?php 
        } elseif ($active_tab == 'help') {
            // modified from https://github.com/woothemes/woocommerce/blob/master/includes/admin/views/html-admin-page-status-report.php
            // reference (outdated screenshots): https://docs.woothemes.com/document/understanding-the-woocommerce-system-status-report/
            ?>
						<style>
							table.tkeventw_status_table {
									margin-bottom: 1em
							}
							
							table.tkeventw_status_table tr:nth-child(2n) td,
							table.tkeventw_status_table tr:nth-child(2n) th {
									background: #fcfcfc
							}
							
							table.tkeventw_status_table th {
									font-weight: 700;
									padding: 9px
							}
							
							table.tkeventw_status_table td:first-child {
									width: 33%
							}
							
							table.tkeventw_status_table td mark {
									background: 0 0
							}
							
							table.tkeventw_status_table td mark.yes {
									color: #7ad03a
							}
							
							table.tkeventw_status_table td mark.no {
									color: #999
							}
							
							table.tkeventw_status_table td mark.error {
									color: #a00
							}
							
							#debug-report {
									display: none;
									margin: 10px 0;
									padding: 0;
									position: relative
							}
							
							#debug-report textarea {
									font-family: monospace;
									width: 100%;
									margin: 0;
									height: 300px;
									padding: 20px;
									-moz-border-radius: 0;
									-webkit-border-radius: 0;
									border-radius: 0;
									resize: none;
									font-size: 12px;
									line-height: 20px;
									outline: 0
							}
						</style>
						<div class="updated inline">
							<p><?php 
            _e('Please copy and paste this information in your ticket when contacting support:', 'tk-event-weather');
            ?>
 </p>
							<p class="submit"><a href="#" class="button-primary debug-report"><?php 
            _e('Get System Report', 'tk-event-weather');
            ?>
</a></p>
							<div id="debug-report">
								<textarea readonly="readonly"></textarea>
								<h3 id="copy-for-support">&#x21b3;
									<?php 
            // http://htmlarrows.com/arrows/down-arrow-with-tip-right/
            _e('Copy and send to Support', 'tk-event-weather');
            // http://htmlarrows.com/arrows/down-arrow-with-corner-left/
            ?>
								&#x21b5;
								</h3>
								<hr>
								<p><?php 
            _e('And/Or you might want to send your personal computer specifications:', 'tk-event-weather');
            ?>
</p>
								<p><a target="_blank" href="<?php 
            printf('http://supportdetails.com/?sender_name=%s&sender=%s&recipient=%s', urlencode(get_home_url()), urlencode(get_bloginfo('admin_email')), urlencode(TkEventWeather__FuncSetup::$support_email_address));
            ?>
" class="button-secondary support-details"><?php 
            _e('Get Personal Computer Details', 'tk-event-weather');
            ?>
</a></p>
								<p><em><?php 
            _e('Then click the "Send Details" button from that site!', 'tk-event-weather');
            ?>
</em></p>
							</div>
						</div>
						
						<table class="tkeventw_status_table widefat" cellspacing="0" id="status">
							<thead>
								<tr>
									<th colspan="3" data-export-label="WordPress Environment"><h2><?php 
            _e('WordPress Environment', 'tk-event-weather');
            ?>
</h2></th>
								</tr>
							</thead>
							<tbody>
								<tr>
									<td data-export-label="Home URL"><?php 
            _e('Home URL', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            form_option('home');
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="Site URL"><?php 
            _e('Site URL', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            form_option('siteurl');
            ?>
</td>
								</tr>
								
								<tr>
									<td data-export-label="WP Version"><?php 
            _e('WP Version', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            $wordpress_version = get_bloginfo('version');
            if (version_compare($wordpress_version, TkEventWeather__FuncSetup::$min_allowed_version_wordpress, '<')) {
                echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf(__('%s - This plugin requires a minimum WordPress version of %s. See: %s', 'tk-event-weather'), esc_html($wordpress_version), TkEventWeather__FuncSetup::$min_allowed_version_wordpress, '<a href="https://codex.wordpress.org/WordPress_Versions" target="_blank">' . __('WordPress Version History', 'tk-event-weather') . '</a>') . '</mark>';
            } else {
                echo '<mark class="yes">' . esc_html($wordpress_version) . '</mark>';
            }
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="WP Multisite"><?php 
            _e('WP Multisite Enabled', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            if (is_multisite()) {
                echo '<span class="dashicons dashicons-yes"></span>';
            } else {
                echo '&ndash;';
            }
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="WP Memory Limit"><?php 
            _e('WP Memory Limit', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            $memory = WP_MEMORY_LIMIT;
            if (function_exists('memory_get_usage')) {
                $system_memory = @ini_get('memory_limit');
                $memory = max($memory, $system_memory);
            }
            if ($memory < 67108864) {
                echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf(__('%s - We recommend setting memory to at least 64MB. See: %s', 'tk-event-weather'), size_format($memory), '<a href="http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP" target="_blank">' . __('Increasing memory allocated to PHP', 'tk-event-weather') . '</a>') . '</mark>';
            } else {
                echo '<mark class="yes">' . size_format($memory) . '</mark>';
            }
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="WP Debug Mode"><?php 
            _e('WP Debug Mode', 'tk-event-weather');
            ?>
:</td>
									<td>
										<?php 
            if (defined('WP_DEBUG') && WP_DEBUG) {
                ?>
											<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>
										<?php 
            } else {
                ?>
											<mark class="no">&ndash;</mark>
										<?php 
            }
            ?>
									</td>
								</tr>
								<tr>
									<td data-export-label="WP Cron"><?php 
            _e('WP Cron', 'tk-event-weather');
            ?>
:</td>
									<td>
										<?php 
            if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON) {
                ?>
											<mark class="no">&ndash;</mark>
										<?php 
            } else {
                ?>
											<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>
										<?php 
            }
            ?>
									</td>
								</tr>
								<tr>
									<td data-export-label="Language"><?php 
            _e('WordPress Language', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            echo get_locale();
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="Permalinks"><?php 
            _e('Permalink Structure', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            echo esc_html(get_option('permalink_structure'));
            ?>
</td>
								</tr>
							</tbody>
						</table>
						<table class="tkeventw_status_table widefat" cellspacing="0">
							<thead>
								<tr>
									<th colspan="3" data-export-label="Server Environment"><h2><?php 
            _e('Server Environment', 'tk-event-weather');
            ?>
</h2></th>
								</tr>
							</thead>
							<tbody>
								<tr>
									<td data-export-label="Server Info"><?php 
            _e('Server Info', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            echo esc_html($_SERVER['SERVER_SOFTWARE']);
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="PHP Version"><?php 
            _e('PHP Version', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            // Check if phpversion function exists.
            if (function_exists('phpversion')) {
                $php_version = phpversion();
                if (version_compare($php_version, TkEventWeather__FuncSetup::$min_allowed_version_php, '<')) {
                    echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf(__('%s - This plugin requires a minimum PHP version of %s. See: %s', 'tk-event-weather'), esc_html($php_version), TkEventWeather__FuncSetup::$min_allowed_version_php, '<a href="http://docs.woothemes.com/document/how-to-update-your-php-version/" target="_blank">' . __('How to update your PHP version', 'tk-event-weather') . '</a>') . '</mark>';
                } else {
                    echo '<mark class="yes">' . esc_html($php_version) . '</mark>';
                }
            } else {
                _e("Couldn't determine PHP version because phpversion() doesn't exist.", 'tk-event-weather');
            }
            ?>
</td>
								</tr>
								<?php 
            if (function_exists('ini_get')) {
                ?>
									<tr>
										<td data-export-label="PHP Post Max Size"><?php 
                _e('PHP Post Max Size', 'tk-event-weather');
                ?>
:</td>
										<td><?php 
                echo size_format(ini_get('post_max_size'));
                ?>
</td>
									</tr>
									<tr>
										<td data-export-label="PHP Time Limit"><?php 
                _e('PHP Timeout Limit', 'tk-event-weather');
                ?>
:</td>
										<td><?php 
                echo ini_get('max_execution_time');
                ?>
</td>
									</tr>
									<tr>
										<td data-export-label="PHP Max Input Vars"><?php 
                _e('PHP Max Input Variables', 'tk-event-weather');
                ?>
:</td>
										<td><?php 
                echo ini_get('max_input_vars');
                ?>
</td>
									</tr>
									<tr>
										<td data-export-label="SUHOSIN Installed"><?php 
                _e('SUHOSIN Installed', 'tk-event-weather');
                ?>
:</td>
										<td><?php 
                echo extension_loaded('suhosin') ? '<span class="dashicons dashicons-yes"></span>' : '&ndash;';
                ?>
</td>
									</tr>
								<?php 
            }
            ?>
								<tr>
									<td data-export-label="MySQL Version"><?php 
            _e('MySQL Version', 'tk-event-weather');
            ?>
:</td>
									<td>
										<?php 
            /** @global wpdb $wpdb */
            global $wpdb;
            $mysql_version = $wpdb->db_version();
            if (version_compare($mysql_version, TkEventWeather__FuncSetup::$min_allowed_version_mysql, '<')) {
                echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf(__('%s - This plugin requires a minimum MySQL version of %s. See: %s', 'tk-event-weather'), esc_html($mysql_version), TkEventWeather__FuncSetup::$min_allowed_version_mysql, '<a href="https://wordpress.org/about/requirements/" target="_blank">' . __('WordPress Requirements', 'tk-event-weather') . '</a>') . '</mark>';
            } else {
                echo '<mark class="yes">' . esc_html($mysql_version) . '</mark>';
            }
            ?>
									</td>
								</tr>
								<tr>
									<td data-export-label="Max Upload Size"><?php 
            _e('Max Upload Size', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            echo size_format(wp_max_upload_size());
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="Default Timezone is UTC"><?php 
            _e('Default Server Timezone is UTC', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            $default_timezone = date_default_timezone_get();
            if ('UTC' !== $default_timezone) {
                echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf(__('Default timezone is %s - it should be UTC', 'tk-event-weather'), $default_timezone) . '</mark>';
            } else {
                echo '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>';
            }
            ?>
									</td>
								</tr>
								<?php 
            $posting = array();
            // fsockopen/cURL.
            $posting['fsockopen_curl']['name'] = 'fsockopen/cURL';
            if (function_exists('fsockopen') || function_exists('curl_init')) {
                $posting['fsockopen_curl']['success'] = true;
            } else {
                $posting['fsockopen_curl']['success'] = false;
                $posting['fsockopen_curl']['note'] = __('Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider.', 'tk-event-weather');
            }
            // SOAP.
            $posting['soap_client']['name'] = 'SoapClient';
            if (class_exists('SoapClient')) {
                $posting['soap_client']['success'] = true;
            } else {
                $posting['soap_client']['success'] = false;
                $posting['soap_client']['note'] = sprintf(__('Your server does not have the %s class enabled - some gateway plugins which use SOAP may not work as expected.', 'tk-event-weather'), '<a href="http://php.net/manual/en/class.soapclient.php">SoapClient</a>');
            }
            // DOMDocument.
            $posting['dom_document']['name'] = 'DOMDocument';
            if (class_exists('DOMDocument')) {
                $posting['dom_document']['success'] = true;
            } else {
                $posting['dom_document']['success'] = false;
                $posting['dom_document']['note'] = sprintf(__('Your server does not have the %s class enabled - HTML/Multipart emails, and also some extensions, will not work without DOMDocument.', 'tk-event-weather'), '<a href="http://php.net/manual/en/class.domdocument.php">DOMDocument</a>');
            }
            // GZIP.
            $posting['gzip']['name'] = 'GZip';
            if (is_callable('gzopen')) {
                $posting['gzip']['success'] = true;
            } else {
                $posting['gzip']['success'] = false;
                $posting['gzip']['note'] = sprintf(__('Your server does not support the %s function - this is required to use the GeoIP database from MaxMind. The API fallback will be used instead for geolocation.', 'tk-event-weather'), '<a href="http://php.net/manual/en/zlib.installation.php">gzopen</a>');
            }
            // Multibyte String.
            $posting['mbstring']['name'] = 'Multibyte String';
            if (extension_loaded('mbstring')) {
                $posting['mbstring']['success'] = true;
            } else {
                $posting['mbstring']['success'] = false;
                $posting['mbstring']['note'] = sprintf(__('Your server does not support the %s functions - this is required for better character encoding. Some fallbacks will be used instead for it.', 'tk-event-weather'), '<a href="http://php.net/manual/en/mbstring.installation.php">mbstring</a>');
            }
            // WP Remote Get Check.
            $posting['wp_remote_get']['name'] = __('Remote Get', 'tk-event-weather');
            $response = wp_safe_remote_get('http://www.woothemes.com/wc-api/product-key-api?request=ping&network=' . (is_multisite() ? '1' : '0'));
            if (!is_wp_error($response) && $response['response']['code'] >= 200 && $response['response']['code'] < 300) {
                $posting['wp_remote_get']['success'] = true;
            } else {
                $posting['wp_remote_get']['note'] = __('wp_remote_get() failed. This plugin won\'t work with your server. Contact your hosting provider.', 'tk-event-weather');
                if (is_wp_error($response)) {
                    $posting['wp_remote_get']['note'] .= ' ' . sprintf(__('Error: %s', 'tk-event-weather'), TkEventWeather__Functions::tk_clean_var($response->get_error_message()));
                } else {
                    $posting['wp_remote_get']['note'] .= ' ' . sprintf(__('Status code: %s', 'tk-event-weather'), TkEventWeather__Functions::tk_clean_var($response['response']['code']));
                }
                $posting['wp_remote_get']['success'] = false;
            }
            // $posting = apply_filters( 'woocommerce_debug_posting', $posting );
            foreach ($posting as $post) {
                $mark = !empty($post['success']) ? 'yes' : 'error';
                ?>
										<tr>
											<td data-export-label="<?php 
                echo esc_html($post['name']);
                ?>
"><?php 
                echo esc_html($post['name']);
                ?>
:</td>
											<td>
												<mark class="<?php 
                echo $mark;
                ?>
">
													<?php 
                echo !empty($post['success']) ? '<span class="dashicons dashicons-yes"></span>' : '<span class="dashicons dashicons-no-alt"></span>';
                ?>
 <?php 
                echo !empty($post['note']) ? wp_kses_data($post['note']) : '';
                ?>
												</mark>
											</td>
										</tr>
										<?php 
            }
            ?>
							</tbody>
						</table>
						<table class="tkeventw_status_table widefat" cellspacing="0">
							<thead>
								<tr>
									<th colspan="3" data-export-label="TK Event Weather Plugin Options"><h2><?php 
            _e('TK Event Weather Plugin Options', 'tk-event-weather');
            ?>
</h2></th>
								</tr>
							</thead>
							<tbody>
								<?php 
            $plugin_options = TkEventWeather__Functions::plugin_options();
            if (!empty($plugin_options) && is_array($plugin_options)) {
                foreach ($plugin_options as $key => $option) {
                    ?>
											<tr>
												<td><?php 
                    echo esc_html('Core - ' . $key);
                    ?>
</td>
												<td><?php 
                    echo esc_html($option);
                    ?>
</td>
											</tr>
											<?php 
                }
            }
            // allow add-ons to output their settings too
            $addon_plugin_options = apply_filters('tk_event_weather_add_on_plugin_options_array', array());
            if (!empty($addon_plugin_options) && is_array($addon_plugin_options)) {
                foreach ($addon_plugin_options as $key => $option) {
                    ?>
											<tr>
												<td><?php 
                    echo esc_html('Addon - ' . $key);
                    ?>
</td>
												<td><?php 
                    echo esc_html($option);
                    ?>
</td>
											</tr>
											<?php 
                }
            }
            ?>
							</tbody>
						</table>
						<table class="tkeventw_status_table widefat" cellspacing="0">
							<thead>
								<tr>
									<th colspan="3" data-export-label="Active Plugins (<?php 
            echo count((array) get_option('active_plugins'));
            ?>
)"><h2><?php 
            _e('Active Plugins', 'tk-event-weather');
            ?>
 (<?php 
            echo count((array) get_option('active_plugins'));
            ?>
)</h2></th>
								</tr>
							</thead>
							<tbody>
								<?php 
            $active_plugins = (array) get_option('active_plugins', array());
            if (is_multisite()) {
                $network_activated_plugins = array_keys(get_site_option('active_sitewide_plugins', array()));
                $active_plugins = array_merge($active_plugins, $network_activated_plugins);
            }
            foreach ($active_plugins as $plugin) {
                $plugin_data = @get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin);
                $dirname = dirname($plugin);
                $version_string = '';
                $network_string = '';
                if (!empty($plugin_data['Name'])) {
                    // Link the plugin name to the plugin url if available.
                    $plugin_name = esc_html($plugin_data['Name']);
                    if (!empty($plugin_data['PluginURI'])) {
                        $plugin_name = '<a href="' . esc_url($plugin_data['PluginURI']) . '" title="' . esc_attr__('Visit plugin homepage', 'tk-event-weather') . '" target="_blank">' . $plugin_name . '</a>';
                    }
                    ?>
										<tr>
											<td><?php 
                    echo $plugin_name;
                    ?>
</td>
											<td><?php 
                    echo sprintf(_x('by %s', 'by author', 'tk-event-weather'), $plugin_data['Author']) . ' &ndash; ' . esc_html($plugin_data['Version']) . $version_string . $network_string;
                    ?>
</td>
										</tr>
										<?php 
                }
            }
            ?>
							</tbody>
						</table>
						<table class="tkeventw_status_table widefat" cellspacing="0">
							<thead>
								<tr>
									<th colspan="3" data-export-label="Theme"><h2><?php 
            _e('Theme', 'tk-event-weather');
            ?>
</h2></th>
								</tr>
							</thead>
								<?php 
            include_once ABSPATH . 'wp-admin/includes/theme-install.php';
            $active_theme = wp_get_theme();
            $theme_version = $active_theme->Version;
            ?>
							<tbody>
								<tr>
									<td data-export-label="Name"><?php 
            _e('Current Active Theme', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            echo esc_html($active_theme->Name);
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="Version"><?php 
            _e('Current Active Theme Version', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            echo is_child_theme() ? __('N/A - Child Theme in use', 'tk-event-weather') : esc_html($theme_version);
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="Author URL"><?php 
            _e('Current Active Theme Author URL', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            echo $active_theme->{'Author URI'};
            ?>
</td>
								</tr>
								<tr>
									<td data-export-label="Child Theme"><?php 
            _e('Current Active Theme is a Child Theme', 'tk-event-weather');
            ?>
:</td>
									<td><?php 
            echo is_child_theme() ? '<mark class="yes"><span class="dashicons dashicons-yes"></span></mark>' : '<span class="dashicons dashicons-no-alt"></span>';
            ?>
</td>
								</tr>
								<?php 
            if (is_child_theme()) {
                $parent_theme = wp_get_theme($active_theme->Template);
                ?>
								<tr>
									<td data-export-label="Parent Theme Name"><?php 
                _e('Parent Theme Name', 'tk-event-weather');
                ?>
:</td>
									<td><?php 
                echo esc_html($parent_theme->Name);
                ?>
</td>
								</tr>
								<tr>
									<td data-export-label="Parent Theme Version"><?php 
                _e('Parent Theme Version', 'tk-event-weather');
                ?>
:</td>
									<td><?php 
                echo esc_html($parent_theme->Version);
                ?>
</td>
								</tr>
								<tr>
									<td data-export-label="Parent Theme Author URL"><?php 
                _e('Parent Theme Author URL', 'tk-event-weather');
                ?>
:</td>
									<td><?php 
                echo $parent_theme->{'Author URI'};
                ?>
</td>
								</tr>
								<?php 
            }
            ?>
							</tbody>
						</table>
						
						<script type="text/javascript">
							jQuery( 'a.debug-report' ).click( function() {
								var report = '';
								jQuery( '.tkeventw_status_table thead, .tkeventw_status_table tbody' ).each( function() {
									if ( jQuery( this ).is( 'thead' ) ) {
										var label = jQuery( this ).find( 'th:eq(0)' ).data( 'export-label' ) || jQuery( this ).text();
										report = report + '\n### ' + jQuery.trim( label ) + ' ###\n\n';
									} else {
										jQuery( 'tr', jQuery( this ) ).each( function() {
											var label			= jQuery( this ).find( 'td:eq(0)' ).data( 'export-label' ) || jQuery( this ).find( 'td:eq(0)' ).text();
											var the_name		= jQuery.trim( label ).replace( /(<([^>]+)>)/ig, '' ); // Remove HTML.
											// Find value
											var $value_html = jQuery( this ).find( 'td:eq(1)' ).clone(); // 2nd <td>
											$value_html.find( '.private' ).remove();
											$value_html.find( '.dashicons-yes' ).replaceWith( '&#10004;' );
											$value_html.find( '.dashicons-no-alt, .dashicons-warning' ).replaceWith( '&#10060;' );
											// Format value
											var the_value	= jQuery.trim( $value_html.text() );
											var value_array = the_value.split( ', ' );
											if ( value_array.length > 1 ) {
												// If value have a list of plugins ','.
												// Split to add new line.
												var temp_line ='';
												jQuery.each( value_array, function( key, line ) {
													temp_line = temp_line + line + '\n';
												});
												the_value = temp_line;
											}
											report = report + '' + the_name + ': ' + the_value + '\n';
										});
									}
								});
								try {
									jQuery( '#debug-report' ).slideDown().find( 'textarea' ).val( '`' + report + '`' ).focus().select();
									jQuery( this ).fadeOut();
									return false;
								} catch ( e ) {
									/* jshint devel: true */
									console.log( e );
								}
								return false;
							});
						</script>
						<?php 
        } else {
            // nothing
        }
        ?>

				</div>
				<?php 
    }