-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
2,153 additions
and
1,308 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Google Map | ||
|
||
Displays a Google Map with markers for each event. Markers will be clustered for performance and UX. | ||
|
||
Currently only supports programmatic usage in block theme templates etc. There's no UI available for adding markers. | ||
|
||
This doesn't currently utilize all the abilities of the `google-map-react`` lib, but we can expand it over time. | ||
|
||
|
||
## Usage | ||
|
||
Place something like this in a pattern: | ||
|
||
```php | ||
<?php | ||
|
||
$map_options = array( | ||
'id' => 'all-upcoming-events', | ||
'markers' => get_all_upcoming_events(), | ||
); | ||
|
||
?> | ||
|
||
<!-- wp:wporg/google-map <?php echo wp_json_encode( $map_options ); ?> /--> | ||
``` | ||
|
||
`markers` should be an array of objects with the fields in the example below. The `timestamp` field should be a true Unix timestamp, meaning it assumes UTC. The time | ||
|
||
```php | ||
array( | ||
0 => (object) array( ‘id’ => ‘72190236’, ‘type’ => ‘meetup’, ‘title’ => ‘WordPress For Beginners – WPSyd’, ‘url’ => ‘https://www.meetup.com/wordpress-sydney/events/294365830’, ‘meetup’ => ‘WordPress Sydney’, ‘location’ => ‘Sydney, Australia’, ‘latitude’ => ‘-33.865295’, ‘longitude’ => ‘151.2053’, ‘tz_offset’ => ‘36000’, ‘timestamp’ => 1693209600, ), | ||
1 => (object) array( ‘id’ => ‘72190237’, ‘type’ => ‘meetup’, ‘title’ => ‘WordPress Help Desk’, ‘url’ => ‘https://www.meetup.com/wordpress-gwinnett/events/292032515’, ‘meetup’ => ‘WordPress Gwinnett’, ‘location’ => ‘online’, ‘latitude’ => ‘33.94’, ‘longitude’ => ‘-83.96’, ‘tz_offset’ => ‘-14400’, ‘timestamp’ => 1693260000, ), | ||
2 => (object) array( ‘id’ => ‘72190235’, ‘type’ => ‘meetup’, ‘title’ => ‘WordPress Warwickshire Virtual Meetup ‘, ‘url’ => ‘https://www.meetup.com/wordpress-warwickshire-meetup/events/295325208’, ‘meetup’ => ‘WordPress Warwickshire Meetup’, ‘location’ => ‘online’, ‘latitude’ => ‘52.52’, ‘longitude’ => ‘-1.47’, ‘tz_offset’ => ‘3600’, ‘timestamp’ => 1693245600, ), | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<?php | ||
|
||
/** | ||
* Block Name: WordPress.org Google Map | ||
* Description: Renders a Google Map in a block template (no editor UI). | ||
*/ | ||
|
||
namespace WordPressdotorg\MU_Plugins\Google_Map; | ||
|
||
add_action( 'init', __NAMESPACE__ . '\init' ); | ||
|
||
|
||
/** | ||
* Registers the block from `block.json`. | ||
*/ | ||
function init() { | ||
register_block_type( | ||
__DIR__ . '/build', | ||
array( | ||
'render_callback' => __NAMESPACE__ . '\render', | ||
) | ||
); | ||
} | ||
|
||
/** | ||
* Render the block content. | ||
* | ||
* @param array $attributes Block attributes. | ||
* @param string $content Block default content. | ||
* @param WP_Block $block Block instance. | ||
* | ||
* @return string Returns the block markup. | ||
*/ | ||
function render( $attributes, $content, $block ) { | ||
$attributes['id'] = 'wp-block-wporg-google-map-' . $attributes['id']; | ||
|
||
if ( empty( $attributes['apiKey'] ) ) { | ||
$default_key = 'production' === wp_get_environment_type() ? 'WORDCAMP_PROD_GOOGLE_MAPS_API_KEY' : 'WORDCAMP_DEV_GOOGLE_MAPS_API_KEY'; | ||
|
||
if ( defined( $default_key ) ) { | ||
$attributes['apiKey'] = constant( $default_key ); | ||
} | ||
} | ||
|
||
$attributes['icon'] = array( | ||
'markerUrl' => plugins_url( 'images/map-marker.svg', __FILE__ ), | ||
'markerAnchorXOffset' => 34, | ||
'markerHeight' => 68, | ||
'markerWidth' => 68, | ||
'clusterUrl' => plugins_url( 'images/cluster-background.svg', __FILE__ ), | ||
'clusterWidth' => 38, | ||
'clusterHeight' => 38, | ||
); | ||
|
||
wp_add_inline_script( | ||
$block->block_type->view_script_handles[0], | ||
sprintf( | ||
'const wporgGoogleMap = %s;', | ||
wp_json_encode( $attributes ) | ||
), | ||
'before' | ||
); | ||
|
||
$wrapper_attributes = get_block_wrapper_attributes( array( 'id' => $attributes['id'] ) ); | ||
|
||
ob_start(); | ||
|
||
?> | ||
|
||
<div <?php echo wp_kses_data( $wrapper_attributes ); ?>> | ||
Loading... | ||
</div> | ||
|
||
<?php | ||
|
||
return ob_get_clean(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* These are foundational styles that provide a reasonable default for any theme. | ||
*/ | ||
|
||
.wp-block-wporg-google-map { | ||
position: relative; | ||
width: 100%; | ||
max-width: 100%; | ||
background-color: #aadaff; | ||
|
||
/* | ||
* This is a bit too opinionated, but it's required to prevent the map from collapsing. The theme can override it when needed. | ||
* @link https://developers.google.com/maps/documentation/javascript/overview#Map_DOM_Elements | ||
*/ | ||
height: clamp(200px, 50vh, 90vh); | ||
|
||
@media screen and ( max-width: 385px ) { | ||
width: 100vw; | ||
|
||
/* Make sure there's enough room to scroll past it using mobile gestures. */ | ||
max-height: 90vh; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"$schema": "https://schemas.wp.org/trunk/block.json", | ||
"apiVersion": 2, | ||
"name": "wporg/google-map", | ||
"title": "WordPress.org Google Map", | ||
"icon": "admin-site-alt", | ||
"category": "layout", | ||
"description": "Displays a Google Map with markers and information windows.", | ||
"textdomain": "wporg", | ||
"attributes": { | ||
"id": { | ||
"type": "string", | ||
"default": "" | ||
}, | ||
"apiKey": { | ||
"type": "string", | ||
"default": "" | ||
}, | ||
"markers": { | ||
"type": "array", | ||
"default": [] | ||
} | ||
}, | ||
"supports": { | ||
"inserter": false | ||
}, | ||
"editorScript": "file:./index.js", | ||
"viewScript": "file:./front.js", | ||
"style": "file:./style.css" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import GoogleMapReact from 'google-map-react'; | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useCallback, useState } from '@wordpress/element'; | ||
import { Spinner } from '@wordpress/components'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { mapStyles } from '../utilities/map-styles'; | ||
import { createClusteredMarkers } from '../utilities/google-maps-api'; | ||
|
||
/** | ||
* Render a Google Map with info windows for the given markers. | ||
* | ||
* @see https://github.com/google-map-react/google-map-react#use-google-maps-api | ||
* | ||
* @param {Object} props | ||
* @param {string} props.apiKey | ||
* @param {Array} props.markers | ||
* @param {Object} props.icon | ||
* | ||
* @return {JSX.Element} | ||
*/ | ||
export default function Map( { apiKey, markers, icon } ) { | ||
const [ loaded, setLoaded ] = useState( false ); | ||
|
||
const options = { | ||
zoomControl: true, | ||
mapTypeControl: false, | ||
streetViewControl: false, | ||
styles: mapStyles, | ||
}; | ||
|
||
const mapLoaded = useCallback( ( { map, maps } ) => { | ||
createClusteredMarkers( map, maps, markers, icon ); | ||
setLoaded( true ); | ||
}, [] ); | ||
|
||
return ( | ||
// Container height must be set explicitly. | ||
<> | ||
{ ! loaded && <Spinner /> } | ||
|
||
<GoogleMapReact | ||
defaultZoom={ 1 } | ||
defaultCenter={ { | ||
lat: 30.0, | ||
lng: 10.0, | ||
} } | ||
bootstrapURLKeys={ { key: apiKey } } | ||
yesIWantToUseGoogleMapApiInternals | ||
onGoogleApiLoaded={ mapLoaded } | ||
options={ options } | ||
/> | ||
</> | ||
); | ||
} |
98 changes: 98 additions & 0 deletions
98
mu-plugins/blocks/google-map/src/components/marker-content.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Internal dependencies | ||
*/ | ||
import { getEventDateTime } from '../utilities/date-time'; | ||
|
||
/** | ||
* Render the content for a map marker. | ||
* | ||
* @param {Object} props | ||
* | ||
* @return {JSX.Element} | ||
*/ | ||
export default function MarkerContent( props ) { | ||
const { type } = props; | ||
|
||
switch ( type ) { | ||
case 'wordcamp': | ||
return <WordCampMarker { ...props } />; | ||
|
||
case 'meetup': | ||
return <MeetupMarker { ...props } />; | ||
|
||
default: | ||
throw 'Component not defined for marker type: ' + type; | ||
} | ||
} | ||
|
||
/** | ||
* Render the content for a WordCamp event. | ||
* | ||
* @param {Object} props | ||
* @param {string} props.id | ||
* @param {string} props.title | ||
* @param {string} props.url | ||
* @param {string} props.timestamp | ||
* @param {string} props.location | ||
* | ||
* @return {JSX.Element} | ||
*/ | ||
function WordCampMarker( { id, title, url, timestamp, location } ) { | ||
return ( | ||
<div id={ 'wporg-map-marker__id-' + id } className="wporg-map-marker"> | ||
<h3 className="wporg-map-marker__title">{ title }</h3> | ||
|
||
<p className="wporg-map-marker__url"> | ||
<a href={ url }>{ title }</a> | ||
</p> | ||
|
||
<p className="wporg-map-marker__location">{ formatLocation( location ) }</p> | ||
|
||
<p className="wporg-map-marker__date-time">{ getEventDateTime( timestamp ) }</p> | ||
</div> | ||
); | ||
} | ||
|
||
/** | ||
* Render the content for a meetup event. | ||
* | ||
* @param {Object} props | ||
* @param {string} props.id | ||
* @param {string} props.title | ||
* @param {string} props.url | ||
* @param {string} props.meetup | ||
* @param {string} props.timestamp | ||
* @param {string} props.location | ||
* | ||
* @return {JSX.Element} | ||
*/ | ||
function MeetupMarker( { id, title, url, meetup, timestamp, location } ) { | ||
return ( | ||
<div id={ 'wporg-map-marker__id-' + id } className="wporg-map-marker"> | ||
<h3 className="wporg-map-marker__title">{ meetup }</h3> | ||
|
||
<p className="wporg-map-marker__url"> | ||
<a href={ url }>{ title }</a> | ||
</p> | ||
|
||
<p className="wporg-map-marker__location">{ formatLocation( location ) }</p> | ||
|
||
<p className="wporg-map-marker__date-time">{ getEventDateTime( timestamp ) }</p> | ||
</div> | ||
); | ||
} | ||
|
||
/** | ||
* Format the `online` location type for display. | ||
* | ||
* @param {string} location | ||
* | ||
* @return {string} | ||
*/ | ||
function formatLocation( location ) { | ||
if ( 'online' === location ) { | ||
location = 'Online'; | ||
} | ||
|
||
return location; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* global wporgGoogleMap */ | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { createRoot } from '@wordpress/element'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import Map from './components/map'; | ||
|
||
const init = () => { | ||
const wrapper = document.getElementById( wporgGoogleMap.id ); | ||
|
||
if ( ! wrapper ) { | ||
throw "Map container element isn't present in the DOM."; | ||
} | ||
|
||
const root = createRoot( wrapper ); | ||
|
||
root.render( <Map { ...wporgGoogleMap } /> ); | ||
}; | ||
|
||
document.addEventListener( 'DOMContentLoaded', init ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
import { registerBlockType } from '@wordpress/blocks'; | ||
import { Placeholder } from '@wordpress/components'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import metadata from './block.json'; | ||
|
||
function Edit() { | ||
return ( | ||
<Placeholder | ||
instructions={ __( | ||
'This is a placeholder for the editor. Data is supplied to this block via the pattern that includes it.', | ||
'wporg' | ||
) } | ||
label={ __( 'WordPress.org Google Map', 'wporg' ) } | ||
/> | ||
); | ||
} | ||
|
||
registerBlockType( metadata.name, { | ||
edit: Edit, | ||
} ); |
Oops, something went wrong.