diff --git a/README.md b/README.md index 7a0bbab..72d2a92 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ # URI Tides Widget -Add the `[uri-tides]` shortcode to a page and a tides widget appears. +Add the `[uri-tides]` shortcode to a page and a tides widget appears. Requires the [URI Tides Updater](https://github.com/uriweb/uri-tides-updater) plugin to be installed and activated on at least one site in a multisite network. -The widget pulls in live water temp and tide prediction data from NOAA and graphically displays the current position of the tide. By default, data is pulled from the station at Quonset Point, RI, but a different station or buoy can be set if desired. +## How do I get set up? + +1. Install [URI Tides Updater](https://github.com/uriweb/uri-tides-updater). For multisite networks, activate it only on one site (e.g. the homepage) to avoid cron job duplication. +2. Install [URI Tides](https://github.com/uriweb/uri-tides/archive/refs/heads/master.zip) and activate it where you intend to use it. Network-activation may be appropriate. +3. Configure the shortcode to taste. ## Attributes The tides widget is somewhat configurable by adding attributes to the shortcode: -**`station`** (num)(optional) -The NOAA station ID from which to retrieve data. The default is Quonset Point, RI. (default: `8454049`) -Find a station on NOAA's [tides and currents website](https://tidesandcurrents.noaa.gov/stations.html). - **`height`** (num)(optional) Set a height in pixels for the tide chart (do not include units). The water temp will scale accordingly. (default: `30`) @@ -26,5 +26,5 @@ Set custom CSS class(s) (default: none) Contributors: Brandon Fuller, John Pennypacker Tags: widgets Requires at least: 4.0 -Tested up to: 4.9 -Stable tag: 1.1.1 \ No newline at end of file +Tested up to: 6.0 +Stable tag: 2.0 diff --git a/js/tides.js b/js/tides.js index b283408..4115a03 100644 --- a/js/tides.js +++ b/js/tides.js @@ -2,15 +2,6 @@ 'use strict'; - /* - * See CO-OPS JSON API documentation at https://tidesandcurrents.noaa.gov/api/ - */ - var parameters = { - 'timezone' : 'GMT', - 'baseURL' : 'https://tidesandcurrents.noaa.gov/api/datagetter?' - }; - - // Wait for the window to load... window.addEventListener('load', function(){ uriTidesInit(); @@ -95,12 +86,11 @@ 'padding' : h * (1/6) }; - // Set the station id - var station = els[i].getAttribute('data-station'); - - helpers.status(els[i], 'Initiating tide data...'); - buildChart(els[i], curve, station, ); - }; + if ( tides ) { + helpers.status(els[i], 'Initiating tide data...'); + buildChart(els[i], curve ); + } + } } @@ -109,10 +99,9 @@ * @param el el the tide widget element * @param curve obj the curve dimensions */ - function buildChart(el, curve, station) { + function buildChart(el, curve) { - var tideHeight, - output, + var output, tide = tides.tide.predictions, temp = tides.temperature.data, display = { @@ -178,9 +167,9 @@ var x = (2 * Math.PI) / m.cycle * m.x; m.y = Math.sin(x) + 1; - // prepare the date of tide retrieval for display + // prepare the date of tide retrieval for display var retrieved = new Date(tides.date * 1000); - var options = { year: 'numeric', month: 'short', day: 'numeric', hour: "2-digit", minute: "2-digit" }; + var options = { year: 'numeric', month: 'short', day: 'numeric', hour: "2-digit", minute: "2-digit" }; var fillcolor = el.classList.contains('darkmode') ? '#fff' : '#555'; @@ -193,7 +182,7 @@ output += ''; output += ''; - output += '
Pull fresh tides and cache them'; - - $tides_data = uri_tides_query_buoy(); - - if($tides_data !== FALSE) { - uri_tides_write_cache($tides_data); - } else { - // the cache is expired, but the fresh buoy response is invalid. - // extend the cache's lifespan for an hour - $expires_on = strtotime( '+1 hour', strtotime('now') ); - $tides_data = _uri_tides_load_cache(); - uri_tides_write_cache($tides_data, $expires_on); - - // notify the administrator of a problem - // _uri_tides_notify_administrator( $tides_data ); - - } - - } - // reload the tides data from the database to capitalize on cache updates - $tides_data = _uri_tides_load_cache(); - - return $tides_data; -} - -/** - * Send a notification to the administrator about the cache status - * @param $tides_data arr the tides data - * @return bool - */ -function _uri_tides_notify_administrator( $tides_data ) { - // @todo: identify which site is sending the error - $to = get_option('admin_email'); - if( empty ( $to ) ) { - $to = 'jpennypacker@uri.edu'; - } - $timezone = get_option('timezone_string'); - $date = (new DateTime('@' . $tides_data['date']))->setTimezone(new DateTimeZone( $timezone )); - $expiry = (new DateTime('@' . $tides_data['expires_on']))->setTimezone(new DateTimeZone( $timezone )); - - $subject = 'URI Tides failed to update tide data'; - $message = "The last time that tides data was refreshed successfully was on: " . $date->format( 'Y-m-d\TH:i:s' ); - $message .= "\n\n"; - $message .= "The site will try to refresh tides information on: " . $expiry->format( 'Y-m-d\TH:i:s' ); - - return wp_mail($to, $subject, $message ); -} - -/** - * Retrieve the tides data from the database - */ -function _uri_tides_load_cache() { - $tides_data = get_site_option( 'uri_tides_cache', FALSE); - if ( empty( $tides_data ) ) { - $tides_data = array(); - $tides_data['date'] = strtotime('now -10 seconds'); - $tides_data['expires_on'] = strtotime('now -10 seconds'); - } - return $tides_data; -} - -/** - * Query the NOAA buoy - * @return mixed; arr on success, bool false on failure - */ -function uri_tides_query_buoy() { - $station = '8454049'; - $tides_data = array(); - $tides_data['temperature'] = _uri_tides_query( _uri_tides_build_url ( 'temperature', $station ) ); - $tides_data['tide'] = _uri_tides_query( _uri_tides_build_url ( 'tide', $station ) ); - - if ( $tides_data['temperature'] !== FALSE && $tides_data['tide'] !== FALSE ) { - return $tides_data; - } else { - // - return FALSE; - } -} - -/** - * Build the URL for the tides request - * @param str $subject is the three letter subject code - * @return str - */ -function _uri_tides_build_url( $q='temperature', $station='8454049' ) { - $base = 'https://tidesandcurrents.noaa.gov/api/datagetter?'; - $application = 'NOS.COOPS.TAC.' . ($q == 'temperature') ? 'PHYSOCEAN' : 'WL'; - - if($q == 'temperature' ) { - $url = $base . 'product=water_temperature&application=' . $application . - '&date=latest&station=' . $station . - '&time_zone=GMT&units=english&interval=6&format=json'; - } else { - $start_date = date( 'Ymd', strtotime( 'yesterday' ) ); - $end_date = date( 'Ymd', strtotime( '+2 days' ) ); - - $url = $base . 'product=predictions&application=' . - $application . '&begin_date=' . $start_date . '&end_date=' . $end_date . - '&datum=MLLW&station=' . $station . - '&time_zone=GMT&units=english&interval=hilo&format=json'; - - } - - return $url; -} - -/** - * Save the data retrieved from the NOAA buoy as a WordPress site-wide option - * @param arr $tides_data is an array of tides data [temperature, tide] - * @param str $expires_on expects a date object for some time in the future, if empty, - * it'll use the value set in the admin preferences (or the default five minutes) - */ -function uri_tides_write_cache( $tides_data, $expires_on='' ) { - - // if expires on is empty or not in the future, set a new expiry date - if ( empty ( $expires_on ) || !($expires_on > strtotime('now')) ) { - $recency = get_site_option( 'uri_tides_recency', '5 minutes' ); - $expires_on = strtotime( '+'.$recency, strtotime('now') ); - } - - $tides_data['date'] = strtotime('now'); - $tides_data['expires_on'] = $expires_on; - update_site_option( 'uri_tides_cache', $tides_data, TRUE ); -} - - -/** - * check if a date has recency - * @param int date - * @return bool - */ -function uri_tides_is_expired( $date ) { - return ( $date < strtotime('now') ); -} - - - -/** - * Query the buoy for tide level - * @return mixed arr on success; FALSE on failure - */ -function _uri_tides_query( $url ) { - - $args = array( - 'user-agent' => 'URI Tides WordPress Plugin', // So the endpoint can figure out who we are - 'headers' => [ ], - 'timeout' => 5 // limit query time to 5 seconds - ); - - - $response = wp_safe_remote_get ( $url, $args ); - - - if( is_wp_error ($response) ) { - // there was an error making the API call - // echo 'The error message is: ' . $response->get_error_message(); - return FALSE; - } - - // still here? good. it means WP got an acceptable response. Let's validate it. - if ( isset( $response['body'] ) && !empty( $response['body'] ) && wp_remote_retrieve_response_code($response) == '200' ) { - $data = json_decode ( wp_remote_retrieve_body ( $response ) ); - // check that the response has a body and that it contains the properties that we're looking for - if( ( isset($data->metadata) || isset($data->predictions) ) ) { - // hooray, all is well! - return $data; - } - } - - // still here? Then the content from API has been rejected - // @todo: log sensible debugging information - - return FALSE; - -} -