Merge pull request #82 from cmanon/feature/61-route-block

Feature/61 route block
This commit is contained in:
Justin Foell
2021-01-29 16:34:14 -06:00
committed by GitHub
15 changed files with 448 additions and 127 deletions
+10 -1
View File
@@ -4,7 +4,7 @@ Contributors: cmanon, jrfoell, lancewillett, dlintott, sebastianerb
Tags: strava, activity, bicycle, cycling, biking, running, run, swimming, swim, paddle, kayak, gps, shortcode, widget, plugin
Requires at least: 4.6
Tested up to: 5.6
Stable tag: 2.5.1
Stable tag: 2.6.0
Requires PHP: 5.3
License: GPLv2 or later
@@ -22,10 +22,16 @@ Using WP-Strava 2.0+ requires a working WordPress cron configuration. By default
= Blocks =
*Available in WordPress 5.0 and up.*
Strava Activity - embed an activity in any page or post. Shows a summary of the activity plus a map if a google maps key has been added.
Paste in the full activity URL from Strava, such as https://www.strava.com/activities/1793155844 and click "Embed." A preview map will be shown in the editor, similar to what will be displayed on the front-end. In the side-panel you can selection options to show the image only (without the details table), display markers at the start & finish points, and override the system of measure from your default selection under Settings -> Strava.
Strava Route - embed a route in any page or post. Shows a summary of the route plus a map if a google maps key has been added.
Paste in the full route URL from Strava, such as hhttps://www.strava.com/routes/2326567 and click "Embed." A preview map will be shown in the editor, similar to what will be displayed on the front-end. In the side-panel you can selection options to show the image only (without the details table), display markers at the start & finish points, and override the system of measure from your default selection under Settings -> Strava.
= Shortcodes =
[activity id=NUMBER] - add to any page or post. Shows a summary of the activity plus a map if a google maps key has been added.
@@ -112,6 +118,9 @@ On the WP-Strava settings page you cannot currently remove and add another athle
== Changelog ==
= 2.6.0 =
Make reusable components for embed screens and SOMOverride
Add Route Block
= 2.5.1 =
+15 -1
View File
@@ -62,6 +62,17 @@ class WPStrava {
return self::$instance;
}
/**
* Check if rest request to skip link rendering in block editor.
*
* @return boolean
* @author Justin Foell <justin@foell.org>
* @since 2.6.0
*/
public static function is_rest_request() {
return defined( 'REST_REQUEST' ) && REST_REQUEST;
}
/**
* Function to install hooks at WP runtime.
*
@@ -188,7 +199,10 @@ class WPStrava {
* @see https://wordpress.org/gutenberg/handbook/blocks/writing-your-first-block-type/#enqueuing-block-scripts
*/
public function register_blocks() {
static $blocks = array( 'WPStrava_Blocks_Activity' );
static $blocks = array(
'WPStrava_Blocks_Activity',
'WPStrava_Blocks_Route',
);
// automatically load dependencies and version
$asset_file = include WPSTRAVA_PLUGIN_DIR . 'build/index.asset.php';
+1 -12
View File
@@ -109,22 +109,11 @@ class WPStrava_Activity {
* @since 2.3.2
*/
public function get_activity_link( $activity_id, $text, $title = '' ) {
if ( $this->is_rest_request() || WPStrava::get_instance()->settings->no_link ) {
if ( WPStrava::is_rest_request() || WPStrava::get_instance()->settings->no_link ) {
return $text;
}
$url = esc_url( self::ACTIVITIES_URL . $activity_id );
$title_attr = $title ? " title='" . esc_attr( $title ) . "'" : '';
return "<a href='{$url}'{$title_attr}>{$text}</a>";
}
/**
* Check if rest request to skip link rendering in block editor.
*
* @return boolean
* @author Justin Foell <justin@foell.org>
* @since 2.5.1
*/
private function is_rest_request() {
return defined( 'REST_REQUEST' ) && REST_REQUEST;
}
}
+1 -1
View File
@@ -85,7 +85,7 @@ class WPStrava_Blocks_Activity implements WPStrava_Blocks_Interface {
}
/**
* Enqueue style if shortcode is being used.
* Enqueue style if block is being used.
*
* @author Justin Foell <justin@foell.org>
* @since 2.5.0
+98
View File
@@ -0,0 +1,98 @@
<?php
/*
* Route block.
*/
class WPStrava_Blocks_Route implements WPStrava_Blocks_Interface {
/**
* Whether or not to enqueue styles (if shortcode is present).
*
* @var boolean
* @author Justin Foell <justin@foell.org>
* @since 2.6.0
*/
private $add_script = false;
/**
* Register the wp-strava/route block.
*
* @author Justin Foell <justin@foell.org>
* @since 2.6.0
*/
public function register_block() {
register_block_type(
'wp-strava/route',
array(
'style' => 'wp-strava-block',
'editor_style' => 'wp-strava-block-editor',
'editor_script' => 'wp-strava-block',
'render_callback' => array( $this, 'render_block' ),
'attributes' => array(
'url' => array(
'type' => 'string',
'default' => '',
),
'imageOnly' => array(
'type' => 'boolean',
'default' => false,
),
'displayMarkers' => array(
'type' => 'boolean',
'default' => false,
),
'som' => array(
'type' => 'string',
'default' => null,
),
),
)
);
add_action( 'wp_footer', array( $this, 'print_scripts' ) );
}
/**
* Render for this block.
*
* @param array $attributes JSON attributes saved in the HTML comment for this block.
* @param string $content The content from JS save() for this block.
* @return string HTML for this block.
* @author Justin Foell <justin@foell.org>
* @since 2.6.0
*/
public function render_block( $attributes, $content ) {
if ( empty( $attributes['url'] ) ) {
return $content;
}
$this->add_script = true;
$matches = [];
preg_match( '/\/routes\/([0-9].*)$/', $attributes['url'], $matches );
if ( $matches[1] ) {
// Transform from block attributes to shortcode standard.
$attributes = array(
'id' => $matches[1],
'image_only' => isset( $attributes['imageOnly'] ) ? $attributes['imageOnly'] : false,
'markers' => isset( $attributes['displayMarkers'] ) ? $attributes['displayMarkers'] : false,
'som' => ! empty( $attributes['som'] ) ? $attributes['som'] : null,
);
$renderer = new WPStrava_RouteRenderer();
return $renderer->get_html( $attributes );
}
return $content;
}
/**
* Enqueue style if block is being used.
*
* @author Justin Foell <justin@foell.org>
* @since 2.6.0
*/
public function print_scripts() {
if ( $this->add_script ) {
wp_enqueue_style( 'wp-strava-style' );
}
}
}
+117
View File
@@ -0,0 +1,117 @@
<?php
/*
* RouteRenderer has all the markup for the Route Block & Shortcode.
*/
class WPStrava_RouteRenderer {
/**
* Get the HTML for a single route.
*
* @param array $atts
* @return string HTML for an route.
* @author Justin Foell <justin@foell.org>
* @since 2.6.0
*/
public function get_html( $atts ) {
$defaults = array(
'id' => 0,
'som' => WPStrava::get_instance()->settings->som,
'map_width' => '480',
'map_height' => '320',
'client_id' => WPStrava::get_instance()->settings->get_default_id(),
'markers' => false,
'image_only' => false,
);
$atts = wp_parse_args( $atts, $defaults );
/* Make sure boolean values are actually boolean
* @see https://wordpress.stackexchange.com/a/119299
*/
$atts['markers'] = filter_var( $atts['markers'], FILTER_VALIDATE_BOOLEAN );
$atts['image_only'] = filter_var( $atts['image_only'], FILTER_VALIDATE_BOOLEAN );
$route = WPStrava::get_instance()->routes;
$route_details = null;
try {
$route_details = $route->get_route( $atts['client_id'], $atts['id'] );
} catch ( WPStrava_Exception $e ) {
return $e->to_html();
}
$route_output = '';
if ( $route_details ) {
$route_output = '<div id="activity-header-' . $atts['id'] . '" class="wp-strava-activity-container">';
if ( ! $atts['image_only'] ) {
$route_output .= $this->get_table( $route_details, $atts['som'] );
}
// Sanitize width & height.
$map_width = str_replace( '%', '', $atts['map_width'] );
$map_height = str_replace( '%', '', $atts['map_height'] );
$map_width = str_replace( 'px', '', $map_width );
$map_height = str_replace( 'px', '', $map_height );
$route_output .= $route->get_route_link(
$route_details->id,
WPStrava_StaticMap::get_image_tag( $route_details, $map_height, $map_width, $atts['markers'], $route_details->name ),
$route_details->name
);
if ( ! empty( $route_details->description ) ) {
$route_output .= '<div class="wp-strava-activity-description">' . esc_html( $route_details->description ) . '</div>';
}
$route_output .= '</div>';
} // End if( $route_details ).
return $route_output;
}
/**
* The the route details in in HTML table.
*
* @param stdClass $route_details route details from the route class.
* @param string $som System of measure (english/metric).
* @return string HTML Table of route details.
* @author Justin Foell <justin@foell.org>
* @since 1.7.0
*/
private function get_table( $route_details, $som ) {
$strava_som = WPStrava_SOM::get_som( $som );
$elevation_title = '<th>' . __( 'Elevation Gain', 'wp-strava' ) . '</th>';
$elevation = '<td>' . $strava_som->elevation( $route_details->elevation_gain ) . '</td>';
$elevation_label = '<td>' . $strava_som->get_elevation_label() . '</td>';
if ( WPStrava::get_instance()->settings->hide_elevation ) {
$elevation = '';
$elevation_title = '';
$elevation_label = '';
}
return '
<table class="activity-details-table">
<thead>
<tr>
<th>' . __( 'Est. Moving Time', 'wp-strava' ) . '</th>
<th>' . __( 'Distance', 'wp-strava' ) . '</th>
' . $elevation_title . '
</tr>
</thead>
<tbody>
<tr class="activity-details-table-info">
<td>' . $strava_som->time( $route_details->estimated_moving_time ) . '</td>
<td>' . $strava_som->distance( $route_details->distance ) . '</td>
' . $elevation . '
</tr>
<tr class="activity-details-table-units">
<td>' . $strava_som->get_time_label() . '</td>
<td>' . $strava_som->get_distance_label() . '</td>
' . $elevation_label . '
</tr>
</tbody>
</table>
';
}
}
+2 -93
View File
@@ -51,99 +51,8 @@ class WPStrava_RouteShortcode {
$this->add_script = true;
$defaults = array(
'id' => 0,
'som' => WPStrava::get_instance()->settings->som,
'map_width' => '480',
'map_height' => '320',
'client_id' => WPStrava::get_instance()->settings->get_default_id(),
'markers' => false,
'image_only' => false,
);
$atts = shortcode_atts( $defaults, $atts, 'route' );
/* Make sure boolean values are actually boolean
* @see https://wordpress.stackexchange.com/a/119299
*/
$atts['markers'] = filter_var( $atts['markers'], FILTER_VALIDATE_BOOLEAN );
$atts['image_only'] = filter_var( $atts['image_only'], FILTER_VALIDATE_BOOLEAN );
$route = WPStrava::get_instance()->routes;
$route_details = null;
try {
$route_details = $route->get_route( $atts['id'] );
} catch ( WPStrava_Exception $e ) {
return $e->to_html();
}
$route_output = '';
if ( $route_details ) {
$route_output = '<div id="activity-header-' . $atts['id'] . '" class="wp-strava-activity-container">';
if ( ! $atts['image_only'] ) {
$route_output .= $this->get_table( $route_details, $atts['som'] );
}
// Sanitize width & height.
$map_width = str_replace( '%', '', $atts['map_width'] );
$map_height = str_replace( '%', '', $atts['map_height'] );
$map_width = str_replace( 'px', '', $map_width );
$map_height = str_replace( 'px', '', $map_height );
$route_output .= '<a title="' . $route_details->name . '" href="' . WPStrava_Routes::ROUTES_URL . $route_details->id . '">' .
WPStrava_StaticMap::get_image_tag( $route_details, $map_height, $map_width, $atts['markers'] ) .
'</a>
</div>';
} // End if( $route_details ).
return $route_output;
}
/**
* The the route details in in HTML table.
*
* @param stdClass $route_details route details from the route class.
* @param string $som System of measure (english/metric).
* @return string HTML Table of route details.
* @author Justin Foell <justin@foell.org>
* @since 1.7.0
*/
private function get_table( $route_details, $som ) {
$strava_som = WPStrava_SOM::get_som( $som );
$elevation_title = '<th>' . __( 'Elevation Gain', 'wp-strava' ) . '</th>';
$elevation = '<td>' . $strava_som->elevation( $route_details->elevation_gain ) . '</td>';
$elevation_label = '<td>' . $strava_som->get_elevation_label() . '</td>';
if ( WPStrava::get_instance()->settings->hide_elevation ) {
$elevation = '';
$elevation_title = '';
$elevation_label = '';
}
return '
<table class="activity-details-table">
<thead>
<tr>
<th>' . __( 'Est. Moving Time', 'wp-strava' ) . '</th>
<th>' . __( 'Distance', 'wp-strava' ) . '</th>
' . $elevation_title . '
</tr>
</thead>
<tbody>
<tr class="activity-details-table-info">
<td>' . $strava_som->time( $route_details->estimated_moving_time ) . '</td>
<td>' . $strava_som->distance( $route_details->distance ) . '</td>
' . $elevation . '
</tr>
<tr class="activity-details-table-units">
<td>' . $strava_som->get_time_label() . '</td>
<td>' . $strava_som->get_distance_label() . '</td>
' . $elevation_label . '
</tr>
</tbody>
</table>
';
$renderer = new WPStrava_RouteRenderer();
return $renderer->get_html( $atts );
}
/**
+27 -4
View File
@@ -12,11 +12,34 @@ class WPStrava_Routes {
/**
* Get single route by ID.
*
* @param int $route_id ID of activity to retrieve.
* @return object stdClass representing this route.
* @param string $client_id Client ID of athlete to retrieve for
* @param int $route_id ID of route to retrieve.
* @return object stdClass representing this route.
* @author Daniel Lintott
*
* @since 1.3.0
*/
public function get_route( $route_id ) {
return WPStrava::get_instance()->get_api()->get( "routes/{$route_id}" );
public function get_route( $client_id, $route_id ) {
return WPStrava::get_instance()->get_api( $client_id )->get( "routes/{$route_id}" );
}
/**
* Conditionally display a link based on settings.
*
* @param int $route_id Strava Route ID
* @param string $text Text (or HTML) that is the content of link.
* @param string $title Title attribute (default empty).
* @return void
* @author Justin Foell <justin@foell.org>
* @since 2.6.0
*/
public function get_route_link( $route_id, $text, $title = '' ) {
if ( WPStrava::is_rest_request() || WPStrava::get_instance()->settings->no_link ) {
return $text;
}
$url = esc_url( self::ROUTES_URL . $route_id );
$title_attr = $title ? " title='" . esc_attr( $title ) . "'" : '';
return "<a href='{$url}'{$title_attr}>{$text}</a>";
}
}
+11 -6
View File
@@ -1,6 +1,6 @@
/* global wp, wpStrava */
import EmbedPlaceholder from './embed-placeholder';
import EmbedControls from './embed-controls';
import EmbedPlaceholder from '../components/embed-placeholder';
import EmbedControls from '../components/embed-controls';
import SOMOverride from '../components/som-override';
const { __ } = wp.i18n;
@@ -69,7 +69,12 @@ class Edit extends Component {
return (
<EmbedPlaceholder
icon="chart-line"
label="Strava Activity"
label={ __( 'Strava Activity', 'wp-strava' ) }
instructions={ __(
'Paste a link to the Strava Activity you want to display on your site.',
'wp-strava'
) }
placeholder={ __( 'Enter Activity URL to embed here…', 'wp-strava' ) }
onSubmit={ this.setUrl }
value={ url }
onChange={ ( event ) =>
@@ -95,15 +100,15 @@ class Edit extends Component {
/>
<InspectorControls>
<PanelBody
title={ __( 'Display Options' ) }
title={ __( 'Display Options', 'wp-strava' ) }
>
<ToggleControl
label={ __( 'Image Only' ) }
label={ __( 'Image Only', 'wp-strava' ) }
checked={ imageOnly }
onChange={ ( checked ) => this.toggleImageOnly( checked ) }
/>
<ToggleControl
label={ __( 'Display Markers' ) }
label={ __( 'Display Markers', 'wp-strava' ) }
checked={ displayMarkers }
onChange={ (checked ) => this.toggleDisplayMarkers( checked ) }
/>
@@ -18,9 +18,11 @@ const EmbedControls = ( props ) => {
return (
<>
<BlockControls>
<Toolbar>
<Toolbar
label={ __( 'Options', 'wp-strava' ) }
>
<Button
label={ __( 'Edit URL' ) }
label={ __( 'Edit URL', 'wp-strava' ) }
onClick={ switchBackToURLInput }
>
<Icon icon="edit" />
@@ -11,6 +11,8 @@ const EmbedPlaceholder = ( props ) => {
const {
icon,
label,
instructions,
placeholder,
value,
onSubmit,
onChange,
@@ -21,9 +23,7 @@ const EmbedPlaceholder = ( props ) => {
icon={ <BlockIcon icon={ icon } showColors /> }
label={ label }
className="wp-block-embed"
instructions={ __(
'Paste a link to the Strava Activity you want to display on your site.'
) }
instructions={ instructions }
>
<form onSubmit={ onSubmit }>
<input
@@ -31,11 +31,11 @@ const EmbedPlaceholder = ( props ) => {
value={ value || '' }
className="components-placeholder__input"
aria-label={ label }
placeholder={ __( 'Enter Activity URL to embed here…' ) }
placeholder={ placeholder }
onChange={ onChange }
/>
<Button isPrimary type="submit">
{ _x( 'Embed', 'button label' ) }
{ _x( 'Embed', 'button label', 'wp-strava' ) }
</Button>
</form>
</Placeholder>
+125
View File
@@ -0,0 +1,125 @@
/* global wp, wpStrava */
import EmbedPlaceholder from '../components/embed-placeholder';
import EmbedControls from '../components/embed-controls';
import SOMOverride from '../components/som-override';
const { __ } = wp.i18n;
const { Component } = wp.element;
const { InspectorControls } = wp.editor;
const { PanelBody, ToggleControl, ServerSideRender } = wp.components;
const { isEmpty } = lodash;
class Edit extends Component {
constructor() {
super( ...arguments );
this.setUrl = this.setUrl.bind( this );
this.switchBackToURLInput = this.switchBackToURLInput.bind( this );
this.toggleImageOnly = this.toggleImageOnly.bind( this );
this.toggleDisplayMarkers = this.toggleDisplayMarkers.bind( this );
this.overrideSOM = this.overrideSOM.bind( this );
this.state = {
url: this.props.attributes.url,
imageOnly: this.props.attributes.imageOnly,
displayMarkers: this.props.attributes.displayMarkers,
som: this.props.attributes.som,
editingURL: isEmpty( this.props.attributes.url ) ? true : false,
};
}
setUrl( event ) {
if ( event ) {
event.preventDefault();
}
this.setState( { editingURL: false } );
this.props.setAttributes( { url: this.state.url } );
}
switchBackToURLInput() {
this.setState( { editingURL: true } );
}
toggleImageOnly( checked ) {
this.setState( { imageOnly: checked } );
this.props.setAttributes( { imageOnly: checked } );
}
toggleDisplayMarkers( checked ) {
this.setState( { displayMarkers: checked } );
this.props.setAttributes( { displayMarkers: checked } );
}
overrideSOM( newSOM ) {
this.setState( { som: newSOM } );
this.props.setAttributes( { som: newSOM } );
}
render() {
const {
url,
editingURL,
imageOnly,
displayMarkers,
som
} = this.state;
// Newly inserted block or we've clicked the edit button.
if ( editingURL ) {
return (
<EmbedPlaceholder
icon="location-alt"
label={ __( 'Strava Route', 'wp-strava' ) }
instructions={ __(
'Paste a link to the Strava Route you want to display on your site.',
'wp-strava'
) }
placeholder={ __( 'Enter Route URL to embed here…', 'wp-strava' ) }
onSubmit={ this.setUrl }
value={ url }
onChange={ ( event ) =>
this.setState( { url: event.target.value } )
}
/>
);
}
return (
<>
<EmbedControls
switchBackToURLInput={ this.switchBackToURLInput }
/>
<ServerSideRender
block="wp-strava/route"
attributes={ {
url: url,
imageOnly: imageOnly,
displayMarkers: displayMarkers,
som: som,
} }
/>
<InspectorControls>
<PanelBody
title={ __( 'Display Options', 'wp-strava' ) }
>
<ToggleControl
label={ __( 'Image Only', 'wp-strava' ) }
checked={ imageOnly }
onChange={ ( checked ) => this.toggleImageOnly( checked ) }
/>
<ToggleControl
label={ __( 'Display Markers', 'wp-strava' ) }
checked={ displayMarkers }
onChange={ (checked ) => this.toggleDisplayMarkers( checked ) }
/>
<SOMOverride
onChange={ this.overrideSOM }
/>
</PanelBody>
</InspectorControls>
</>
);
}
}
export default Edit;
+29
View File
@@ -0,0 +1,29 @@
/* global wp, wpStrava */
import { registerBlockType } from '@wordpress/blocks';
import edit from './edit';
registerBlockType( 'wp-strava/route', {
title: 'Strava Route',
icon: 'location-alt',
category: 'embed',
attributes: {
url: {
type: 'string',
default: '',
},
imageOnly: {
type: 'boolean',
default: false,
},
displayMarkers: {
type: 'boolean',
default: false,
},
som: {
type: 'string',
default: null,
},
},
edit,
save: () => null,
} );
+1
View File
@@ -1 +1,2 @@
import './blocks/activity';
import './blocks/route';
+2 -2
View File
@@ -3,7 +3,7 @@
* Plugin Name: WP Strava
* Plugin URI: https://wordpress.org/plugins/wp-strava/
* Description: Show your strava.com activity on your WordPress site. Some Icons are Copyright © Yusuke Kamiyamane. All rights reserved. Licensed under a Creative Commons Attribution 3.0 license.
* Version: 2.5.1
* Version: 2.6.0
* Author: Carlos Santa Cruz, Justin Foell, Lance Willett, Daniel Lintott, Sebastian Erb
* License: GPL2
* Text Domain: wp-strava
@@ -27,7 +27,7 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
define( 'WPSTRAVA_PLUGIN_VERSION', '2.5.1' );
define( 'WPSTRAVA_PLUGIN_VERSION', '2.6.0' );
define( 'WPSTRAVA_PLUGIN_FILE', __FILE__ );
define( 'WPSTRAVA_PLUGIN_DIR', trailingslashit( dirname( __FILE__ ) ) );
define( 'WPSTRAVA_PLUGIN_URL', plugins_url( '/', __FILE__ ) );