diff --git a/lib/API.class.php b/lib/API.class.php new file mode 100755 index 0000000..33631e7 --- /dev/null +++ b/lib/API.class.php @@ -0,0 +1,80 @@ + http_build_query( $data ), + ); + + if ( $version == 2 ) + $args['sslverify'] = false; + + $response = wp_remote_post( $url . $uri, $args ); + + if ( $response['response']['code'] != 200 ) { + //see if there's useful info in the body + $body = json_decode( $response['body'] ); + $error = ''; + if ( ! empty( $body->error ) ) + $error = $body->error; + else + $error = print_r( $response, true ); + + return new WP_Error( 'wp-strava_post', + sprintf( __( 'ERROR %s %s - %s', 'wp-strava'), $response['response']['code'], $response['response']['message'], $error ), + $response ); + } + + return json_decode( $response['body'] ); + } + + public function get( $uri, $args = NULL, $version = 2 ) { + $url = ( $version == 2 ) ? self::STRAVA_V2_API : self::STRAVA_V1_API; + + $url .= $uri; + + if ( ! empty( $args ) ) + $url = add_query_arg( $args, $url ); + + $response = wp_remote_get( $url ); + + if ( is_wp_error( $response ) ) + return $response; + + if ( $response['response']['code'] != 200 ) { + die($url); + //see if there's useful info in the body + $body = json_decode( $response['body'] ); + $error = ''; + if ( ! empty( $body->error ) ) + $error = $body->error; + else + $error = print_r( $response, true ); + + return new WP_Error( 'wp-strava_get', + sprintf( __( 'ERROR %s %s - %s', 'wp-strava'), $response['response']['code'], $response['response']['message'], $error ), + $response ); + } + + return json_decode( $response['body'] ); + } + +} // class API \ No newline at end of file diff --git a/lib/LatestMapWidget.class.php b/lib/LatestMapWidget.class.php new file mode 100644 index 0000000..a77ab73 --- /dev/null +++ b/lib/LatestMapWidget.class.php @@ -0,0 +1,142 @@ +som = WPStrava_SOM::get_som(); + + parent::__construct( + false, + 'Strava Latest Map', // Name + array( 'description' => __( 'Strava latest ride using static google map image', 'wp-strava' ), ) // Args + ); + } + + public function form( $instance ) { + // outputs the options form on admin + $distance_min = isset( $instance['distance_min'] ) ? esc_attr( $instance['distance_min'] ) : ''; + $ride_index_params = isset( $instance['ride_index_params'] ) ? esc_attr( $instance['ride_index_params'] ) : ''; + + //provide some defaults + //$ride_index_params = $ride_index_params ? $ride_index_params : 'athleteId=21'; + + ?> +

+ + +

+

+ + +

+ athlete->id}"; + } + */ + + //$instance['athlete_hash'] = strip_tags( $new_instance['athlete_hash'] ); + + return $instance; + } + + public function widget( $args, $instance ) { + extract( $args ); + $ride_index_params = $instance['ride_index_params']; + $distance_min = $instance['distance_min']; + $build_new = false; + + //try our transient first + $ride_transient = get_transient( 'strava_latest_map_ride' ); + $ride_option = get_option( 'strava_latest_map_ride' ); + + if ( $ride_transient ) + $ride = $ride_transient; + + if ( ! $ride ) { + $strava_rides = WPStrava::get_instance()->rides; + $ride_index_params = implode( '&', explode( "\n", $ride_index_params ) ); + parse_str( $ride_index_params, $params ); + $rides = $strava_rides->getRidesAdvanced( $params ); + + if ( ! empty( $rides ) ) { + + if ( ! empty( $distance_min ) ) + $rides = $strava_rides->getRidesLongerThan( $rides, $distance_min ); + + $ride = current( $rides ); + + //update transients & options + if ( $ride->id != $ride_option->id ) { + $build_new = true; + update_option( 'strava_latest_map_ride', $ride ); + } + + if ( $ride->id != $ride_transient->id ) + set_transient( 'strava_latest_map_ride', $ride, 60 * 60 ); //one hour + } + } + + if ( $ride ): + echo $before_widget; + ?>

Latest Ride

+ getStaticImage( $ride->id, $build_new ); + ?>latlng ); + $full_url = ''; + $max_chars = 1865; + + //get the longest usable URL + while ( $url_len + $point_len < $max_chars ) { + $mod = (int) ( $count / $num ); + $points = array(); + for ( $i = 0; $i < $count; $i += $mod ) { + $point = $map_details->latlng[$i]; + $points[] = number_format( $point[0], 4 ) . ',' . number_format( $point[1], 4 ); + } + + $url_points = join( '|', $points ); + $point_len = strlen( $url_points ); + if ( $url_len + $point_len < $max_chars ) + $full_url = $url . $url_points; + $num++; + } + + return ""; + } + + private function getStaticImage( $ride_id, $build_new ) { + $img = get_option( 'strava_latest_map' ); + + if ( $build_new || ! $img ) { + $map_details = WPStrava::get_instance()->rides->getMapDetails( $ride_id ); + $img = $this->buildImage( $map_details ); + update_option( 'strava_latest_map', $img ); + } + + return $img; + } + +} \ No newline at end of file diff --git a/lib/LatestRidesWidget.class.php b/lib/LatestRidesWidget.class.php index 6af3bad..e84a4bb 100644 --- a/lib/LatestRidesWidget.class.php +++ b/lib/LatestRidesWidget.class.php @@ -4,15 +4,15 @@ * WP Strava Latest Rides Widget Class */ class WPStrava_LatestRidesWidget extends WP_Widget { - + public function __construct() { $widget_ops = array('classname' => 'LatestRidesWidget', 'description' => __( 'Will publish your latest rides activity from strava.com.') ); parent::__construct('wp-strava', $name = 'Strava Latest Rides', $widget_ops); - wp_enqueue_style('wp-strava'); + wp_enqueue_style('wp-strava'); //TODO only load this when wigit is loaded } /** @see WP_Widget::widget */ - public function widget($args, $instance) { + public function widget( $args, $instance ) { extract($args); //$widget_id = $args['widget_id']; @@ -21,9 +21,7 @@ class WPStrava_LatestRidesWidget extends WP_Widget { $strava_search_id = empty($instance['strava_search_id']) ? '' : $instance['strava_search_id']; $quantity = empty($instance['quantity']) ? '5' : $instance['quantity']; - $wpstrava = WPStrava::get_instance(); - $strava_som_option = $wpstrava->settings->som; - + $this->som = WPStrava_SOM::get_som(); ?> @@ -86,54 +84,44 @@ class WPStrava_LatestRidesWidget extends WP_Widget { // The handler to the ajax call, we will avoid this if Strava support jsonp request and we can do it // the parsing directly on the jQuery ajax call, the returned text will be enclosed in the $response variable. private function strava_request_handler( $strava_search_option, $strava_search_id, $strava_som_option, $quantity ) { - $response = ""; //Check if the username is empty. - if (empty($strava_search_id)) { - $response .= __("Please configure the Strava search id on the widget options.", "wp-strava"); - } else { - require_once WPSTRAVA_PLUGIN_DIR . 'lib/Rides.class.php'; - $strava_rides = new WPStrava_Rides(); - $strava_rides->getLatestRides($strava_search_option, $strava_search_id, $quantity); - $rides_details = $strava_rides->getRidesDetails($strava_som_option); + if ( empty( $strava_search_id ) ) + return __("Please configure the Strava search id on the widget options.", "wp-strava"); + //else + $strava_rides = WPStrava::get_instance()->rides; - if ($strava_som_option == "metric") { - $units = array( - 'elapsedTime' => __('hours','wp-strava'), - 'movingTime' => __('hours','wp-strava'), - 'distance' => __('km','wp-strava'), - 'averageSpeed' => __('km/h','wp-strava'), - 'maximumSpeed' => __('km/h','wp-strava'), - 'elevationGain' => __('meters','wp-strava') - ); - } elseif ($strava_som_option == "english") { - $units = array( - 'elapsedTime' => __('hours','wp-strava'), - 'movingTime' => __('hours','wp-strava'), - 'distance' => __('miles','wp-strava'), - 'averageSpeed' => __('mph','wp-strava'), - 'maximumSpeed' => __('mph','wp-strava'), - 'elevationGain' => __('feet','wp-strava') - ); - } + $rides = $strava_rides->getRidesSimple( $strava_search_option, $strava_search_id ); + if ( is_wp_error( $rides ) ) + return $rides->get_error_message(); + + //adjust quantity + $rides = array_slice( $rides, 0, $quantity ); - $response .= ""; return $response; } // Function strava_request_handler diff --git a/lib/Rides.class.php b/lib/Rides.class.php index 019e3ac..d3e145b 100755 --- a/lib/Rides.class.php +++ b/lib/Rides.class.php @@ -3,135 +3,66 @@ * Rides is a class wrapper for the Strava REST API functions. */ class WPStrava_Rides { - private $rideUrl = "http://www.strava.com/api/v1/rides/:id"; - private $rideUrlV2 = "http://www.strava.com/api/v2/rides/:id"; - private $ridesUrl = "http://www.strava.com/api/v1/rides"; - private $authenticationUrl = "https://www.strava.com/api/v1/authentication/login"; - private $authenticationUrlV2 = "https://www.strava.com/api/v2/authentication/login"; - private $rideMapDetailsUrl = "http://www.strava.com/api/v1/rides/:id/map_details"; - private $rideMapDetailsUrlV2 = "http://www.strava.com/api/v2/rides/:id/map_details"; - - public $ridesLinkUrl = "http://app.strava.com/rides/"; - public $athletesLinkUrl = "http://app.strava.com/athletes/"; - public $stravaRides; - public $feedback; - - public function __construct() { - // Empty constructor - } // __construct - - public function getRideDetails($rideId, $systemOfMeasurement) { - $url = preg_replace('/:id/', $rideId, $this->rideUrl); - $json = file_get_contents($url); - if($json) { - $strava_ride = json_decode($json); - - //Transform data to a ready to be displayed format - $startDate = date("F j, Y - H:i a", strtotime($strava_ride->ride->startDateLocal)); - $elapsedTime = date("H:i:s", mktime(0, 0, $strava_ride->ride->elapsedTime)); - $movingTime = date("H:i:s", mktime(0, 0, $strava_ride->ride->movingTime)); - - if ($systemOfMeasurement == "metric") { - //To km - $distance = number_format($strava_ride->ride->distance/1000, 2); - //To km/h - $averageSpeed = number_format($strava_ride->ride->averageSpeed * 3.6, 2); - //To km/h - // Removed on version 2 of the Strava API - //$maximumSpeed = number_format($strava_ride->ride->maximumSpeed/1000, 2); - //It is already in meters - $elevationGain = number_format($strava_ride->ride->elevationGain, 2); - } elseif ($systemOfMeasurement == "english") { - //To miles - $distance = number_format($strava_ride->ride->distance/1609.34, 2); - //To miles/h - $averageSpeed = number_format($strava_ride->ride->averageSpeed * 2.2369, 2); - //To miles/h - // Removed on version 2 of the Strava API - //$maximumSpeed = number_format($strava_ride->ride->maximumSpeed/1609.34, 2); - //To foot - $elevationGain = number_format($strava_ride->ride->elevationGain/0.3048, 2); - } - - $ride_details = array( - 'id' => $rideId, - 'name' => $strava_ride->ride->name, - 'athleteId' => $strava_ride->ride->athlete->id, - 'athleteName' => $strava_ride->ride->athlete->name, - 'athleteUserName' => $strava_ride->ride->athlete->username, - 'startDate' => $startDate, - 'elapsedTime' => $elapsedTime, - 'movingTime' => $movingTime, - 'distance' => $distance, - 'averageSpeed' => $averageSpeed, - //'maximumSpeed' => $maximumSpeed, - 'elevationGain' => $elevationGain - ); - return $ride_details; - } else { - $this->feedback .= _e("Could not get information from strava.com for the ride id: ") . $stravaRide->id; - return false; - } - } // getRideDetails + const RIDES_URL = "http://app.strava.com/rides/"; + const ATHLETES_URL = "http://app.strava.com/athletes/"; - public function getRidesDetails($systemOfMeasurement) { - if($this->stravaRides) { - $rides_details = array(); - foreach($this->stravaRides as $stravaRide) { - $rides_details[] = $this->getRideDetails($stravaRide->id, $systemOfMeasurement); - } - return $rides_details; - } else { - $this->feedback .= _e("Please provide the rides array to be processed.", "wp-strava"); - return false; + public function getRideDetails( $rideId ) { + return WPStrava::get_instance()->api->get( "rides/{$rideId}" ); + } // getRideDetails + + public function getRidesDetails( $rides ) { + $rides_details = array(); + foreach ( $rides as $stravaRide ) { + $detail = $this->getRideDetails( $stravaRide->id ); + + if ( is_wp_error( $detail ) ) + return $detail; + + $rides_details[] = $detail; } + return $rides_details; } // getRidesDetails - public function getLatestRides($searchOption, $searchId, $quantity) { - $url = $this->ridesUrl; - //Get the json results using the constructor specified values. - if($searchOption == "athlete") { - if(is_numeric($searchId)) { - $json = file_get_contents($url . '?athleteId=' . urlencode($searchId)); - } else { - $json = file_get_contents($url . '?athleteName=' . urlencode($searchId)); - } - } elseif ($searchOption == "club" AND is_numeric($searchId)) { - $json = file_get_contents($url . '?clubId=' . urlencode($searchId)); - } else { - $this->feedback .= _e("There's an error on the widget options combination.", "wp-strava"); - } - if($json) { - $strava_rides = json_decode($json); - $this->stravaRides = array_slice($strava_rides->rides, 0, $quantity); - } else { - $this->feedback .= _e("There was an error pulling data of strava.com.", "wp-strava"); - return false; - } - } // getLatestRides - - public function getAuthenticationToken($email, $password) { - require_once WPSTRAVA_PLUGIN_DIR . 'lib/Util.class.php'; - $util = new WPStrava_Util(); - $data = array('email' => $email, 'password' => $password); - $json = $util->makePostRequest($this->authenticationUrlV2, $data); + public function getRidesSimple( $searchOption, $searchId ) { + $api = WPStrava::get_instance()->api; - if($json) { - $strava_login = json_decode($json); - if(!isset($strava_login->error)) { - $this->feedback .= __('Successfully authenticated.', 'wp-strava'); - return $strava_login->token; + $data = NULL; + //Get the json results using the constructor specified values. + if ( $searchOption == 'athlete' ) { + if ( is_numeric( $searchId ) ) { + $data = $api->get( 'rides', array( 'athleteId' => $searchId ), 1 ); } else { - $this->feedback .= __('Authentication failed, please check your credentials.', 'wp-strava'); - return false; + $data = $api->get( 'rides', array( 'athleteName' => $searchId ), 1 ); } + } elseif ($searchOption == 'club' && is_numeric($searchId)) { + $data = $api->get( 'rides', array( 'clubId' => $searchId ), 1 ); } else { - $this->feedback .= __('There was an error pulling data of strava.com.', 'wp-strava'); - return false; + return new WP_Error( 'wp-strava_options', __("There's an error in your simple options.", 'wp-strava') ); } - } // getAuthenticationToken - + + if ( is_wp_error( $data ) ) + return $data; + + if ( isset( $data->rides ) ) + return $data->rides; + + return array(); + + } // getRidesSimple + + public function getRidesAdvanced( $params ) { + $data = WPStrava::get_instance()->api->get( 'rides', $params, 1 ); //version 1 + + if ( is_wp_error( $data ) ) + return $data; + + if ( isset( $data->rides ) ) + return $data->rides; + + return array(); + } + public function getRideMap($rideId, $token, $efforts, $threshold) { if($rideId != 0 AND $token != "") { $url = preg_replace('/:id/', $rideId, $this->rideMapDetailsUrlV2); @@ -150,5 +81,27 @@ class WPStrava_Rides { return false; } } // getRideDetails + + public function getRidesLongerThan( $rides, $dist ) { + $som = WPStrava_SOM::get_som(); + $meters = $som->distance_inverse( $dist ); + + $long_rides = array(); + foreach ( $rides as $ride ) { + $ride_info = $this->getRideDetails( $ride->id ); + if ( $ride_info->ride->distance > $meters ) { + $long_rides[] = $ride_info; + } + } + + return $long_rides; + } + + public function getMapDetails( $ride_id ) { + $token = WPStrava::get_instance()->settings->token; + return WPStrava::get_instance()->api->get( "rides/{$ride_id}/map_details", array( 'token' => $token ) ); + } + + } // class Rides ?> diff --git a/lib/SOM.class.php b/lib/SOM.class.php new file mode 100644 index 0000000..7340d76 --- /dev/null +++ b/lib/SOM.class.php @@ -0,0 +1,32 @@ +settings->som; + if ( $som == 'metric' ) { + require_once WPSTRAVA_PLUGIN_DIR . 'lib/SOMMetric.class.php'; + return new WPStrava_SOMMetric(); + } else { + require_once WPSTRAVA_PLUGIN_DIR . 'lib/SOMEnglish.class.php'; + return new WPStrava_SOMEnglish(); + } + + } + + abstract public function distance( $m ); + abstract public function distance_inverse( $dist ); + abstract public function get_distance_label(); + abstract public function speed( $mps ); + abstract public function get_speed_label(); + abstract public function elevation( $m ); + abstract public function get_elevation_label(); + + public function time( $seconds ) { + return date( 'H:i:s', mktime( 0, 0, $seconds ) ); + } + + public function get_time_label() { + return __( 'hours', 'wp-strava' ); + } +} \ No newline at end of file diff --git a/lib/SOMEnglish.class.php b/lib/SOMEnglish.class.php new file mode 100644 index 0000000..8cc6103 --- /dev/null +++ b/lib/SOMEnglish.class.php @@ -0,0 +1,48 @@ +getAuthenticationToken( $email, $_POST['strava_password'] ); + $token = $this->get_authentication_token( $this->email, $_POST['strava_password'] ); if ( $token ) { - add_settings_error( 'strava_token', 'strava_token', sprintf( __( 'New Strava Token Retrieved: %s', 'wp-strava' ), $ride->feedback ) , 'updated' ); + add_settings_error( 'strava_token', 'strava_token', sprintf( __( 'New Strava Token Retrieved: %s', 'wp-strava' ), $this->feedback ) , 'updated' ); return $token; } else { - add_settings_error( 'strava_token', 'strava_token', $ride->feedback ); + add_settings_error( 'strava_token', 'strava_token', $this->feedback ); return NULL; } } @@ -96,6 +95,25 @@ class WPStrava_Settings { return $token; } + private function get_authentication_token( $email, $password ) { + $data = array( 'email' => $email, 'password' => $password ); + $strava_login = WPStrava::get_instance()->api->post( 'authentication/login', $data ); + + if( $strava_login ) { + if( ! isset( $strava_login->error ) ) { + $this->feedback .= __( 'Successfully authenticated.', 'wp-strava' ); + return $strava_login->token; + } else { + $this->feedback .= __( 'Authentication failed, please check your credentials.', 'wp-strava' ); + return false; + } + } else { + $this->feedback .= __( 'There was an error pulling data of strava.com.', 'wp-strava' ); + return false; + } + } // get_authentication_token + + public function print_options_label() { ?>

Options

settings = new WPStrava_Settings(); @@ -16,7 +20,8 @@ class WPStrava { } // Register StravaLatestRidesWidget widget - add_action( 'widgets_init', function() { return register_widget( 'WPStrava_LatestRidesWidget' ); } ); + add_action( 'widgets_init', function() { return register_widget( 'WPStrava_LatestRidesWidget' ); } ); + add_action( 'widgets_init', function() { return register_widget( 'WPStrava_LatestMapWidget' ); } ); } @@ -30,6 +35,31 @@ class WPStrava { if ( isset( $this->{$name} ) ) return $this->{$name}; + //on-demand classes + if ( $name == 'api' ) + return $this->get_api(); + + if ( $name == 'rides' ) + return $this->get_rides(); + return NULL; } + + public function get_api() { + if ( ! $this->api ) { + require_once WPSTRAVA_PLUGIN_DIR . 'lib/API.class.php'; + $this->api = new WPStrava_API(); + } + + return $this->api; + } + + public function get_rides() { + if ( ! $this->rides ) { + require_once WPSTRAVA_PLUGIN_DIR . 'lib/Rides.class.php'; + $this->rides = new WPStrava_Rides(); + } + + return $this->rides; + } } \ No newline at end of file diff --git a/lib/Util.class.php b/lib/Util.class.php deleted file mode 100755 index 462ddf9..0000000 --- a/lib/Util.class.php +++ /dev/null @@ -1,57 +0,0 @@ -feedback .= __('This function only support http and https', 'wp-strava'); - return false; - } - - $host = $url['host']; - $path = $url['path']; - $protocol = $url['scheme'] . "://"; - - // Open a socket connection to the specified port - timeout 30 seconds - $fp = fsockopen($domain . $host, $port, $error_number, $error_string, 30); - - if ($fp) { - // Build the request headers and data - $request = "POST " . $protocol . $host . $path . " HTTP/1.0\r\n"; - $request .= "Host: " . $host . "\r\n"; - $request .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $request .= "Content-Length: " . strlen($data) . "\r\n"; - $request .= "Connection: close\r\n\r\n"; - $request .= $data; - - fputs($fp, $request); - - $result = ""; - while (!feof($fp)) { - $result .= fgets($fp, 128); - } - } else { - $this->feedback .= __('ERROR - ' . $error_string . '-' . $error_number, 'wp-strava'); - return false; - } - - fclose($fp); - - // Split the result header from the content - $result = explode("\r\n\r\n", $result, 2); - $header = isset($result[0]) ? $result[0] : ''; - $content = isset($result[1]) ? $result[1] : ''; - - return $content; - } // makePostRequest -} // class Util \ No newline at end of file diff --git a/readme.txt b/readme.txt index 75afa85..c2c68d8 100755 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,5 @@ === Plugin Name === -Contributors: cmanon (@cmanon), jrfoell +Contributors: cmanon, jrfoell Donate link: http://cmanon.com/ Tags: bicycle, cycling, strava Requires at least: 2.0 @@ -16,6 +16,7 @@ This plugin uses the REST strava.com API to pull the data out and show the infor == Changelog == = 0.70 = +Use WordPress HTTP API for all remote calls Use WordPress Settings API for settings page = 0.62 = diff --git a/wp-strava.php b/wp-strava.php index e6e3eb4..045ab76 100755 --- a/wp-strava.php +++ b/wp-strava.php @@ -3,7 +3,7 @@ Plugin Name: WP Strava Plugin URI: http://cmanon.com Description: Plugin to show your strava.com information in your wordpress blog. Some Icons are Copyright © Yusuke Kamiyamane. All rights reserved. Licensed under a Creative Commons Attribution 3.0 license. -Version: 0.63 +Version: 0.70 Author: Carlos Santa Cruz (cmanon), Justin Foell Author URI: http://cmanon.com License: GPL2