Skip to content

Commit

Permalink
Google Map: Add block
Browse files Browse the repository at this point in the history
  • Loading branch information
iandunn committed Aug 28, 2023
1 parent f2e8309 commit 26bfa1a
Show file tree
Hide file tree
Showing 17 changed files with 2,154 additions and 1,308 deletions.
40 changes: 40 additions & 0 deletions mu-plugins/blocks/google-map/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Google Map

intended for programmatic usage in block theme templates etc, no UI available for adding markers


this started as a port of [link to wp20 map]
it currently doesn't utilitze all the abilities of the google-map-react lib, but we can expand this over time


## Usage

1. `require_once .../google-map/blocks.php` file.
1. Add `<!-- wp:wporg/google-map /-->` with the required attributes to the theme's `block-templates/*.html` files.

todo add markers, show example


example like


$map_options = array(
'id' => 'all-upcoming-events',
'markers' => array (
3044664 => array ( 'id' => 3044664, 'name' => 'Rome 2023 Training', 'dates' => 'August 8, 2024', 'location' => 'Rome. Italy', 'venueName' => '', 'url' => 'https://events.wordpress.test/rome/2023/training/', 'latitude' => 41.9027835, 'longitude' => 12.4963655, 'iconURL' => 'icon-marker-upcoming-2x.png', ),
3043497 => array ( 'id' => 3043497, 'name' => 'WordCamp Miscellaneous 2014', 'dates' => 'June 5, 2014-June 6, 2014', 'location' => 'misc', 'venueName' => '', 'url' => 'https://misc.wordcamp.test/2014/', 'latitude' => 43.8041334, 'longitude' => -120.5542012, 'iconURL' => 'icon-marker-past-2x.png', ), 3043462 => array ( 'id' => 3043462, 'name' => 'WordCamp Seattle', 'dates' => 'November 9, 2019', 'location' => 'Seattle, WA, WA', 'venueName' => 'Washington Convention Center', 'url' => 'https://seattle.wordcamp.test/2019/', 'latitude' => 47.61212769999999, 'longitude' => -122.3318833, 'iconURL' => 'icon-marker-past-2x.png', ), 3043432 => array ( 'id' => 3043432, 'name' => 'WordCamp Nashville, TN, USA', 'dates' => 'February 12, 2019-February 13, 2019', 'location' => 'Nashville, TN, USA', 'venueName' => '', 'url' => 'https://nashville.wordcamp.org/2020/', 'latitude' => 36.11297709999999, 'longitude' => -86.7773139, 'iconURL' => 'icon-marker-past-2x.png', ), 3043323 => array ( 'id' => 3043323, 'name' => 'WordCamp Rhode Island', 'dates' => 'January 6, 2016', 'location' => 'Rhode Island', 'venueName' => '', 'url' => 'https://rhodeisland.wordcamp.test/2015/', 'latitude' => 41.5800945, 'longitude' => -71.4774291, 'iconURL' => 'icon-marker-past-2x.png', ), 3043307 => array ( 'id' => 3043307, 'name' => 'WordCamp Seattle', 'dates' => 'October 14, 2014-October 15, 2014', 'location' => 'Seattle, WA, USA', 'venueName' => '', 'url' => 'https://seattle.wordcamp.test/2014/', 'latitude' => 47.61524060000001, 'longitude' => -122.3411273, 'iconURL' => 'icon-marker-past-2x.png', ), 69672 => array ( 'id' => 69672, 'name' => 'WordCamp Columbus', 'dates' => 'November 6, 2014', 'location' => 'Columbus, OH', 'venueName' => '', 'url' => 'https://columbus.wordcamp.test/2014/', 'latitude' => 39.9993865, 'longitude' => -83.0227103, 'iconURL' => 'icon-marker-past-2x.png', ), 2323709 => array ( 'id' => 2323709, 'name' => 'WordCamp US', 'dates' => 'September 9, 2022-September 11, 2022', 'location' => 'Seattle, WA', 'venueName' => 'SPU', 'url' => 'https://us.wordcamp.test/2015/', 'latitude' => 47.6062095, 'longitude' => -122.3320708, 'iconURL' => 'icon-marker-past-2x.png', ), 2323647 => array ( 'id' => 2323647, 'name' => 'BuddyCamp Brighton', 'dates' => 'March 12, 2015-March 12, 2015', 'location' => 'Brighton, UK', 'venueName' => 'an old castle', 'url' => 'https://brighton.buddycamp.test/2015/', 'latitude' => 50.8261064, 'longitude' => -0.1356647, 'iconURL' => 'icon-marker-past-2x.png', ), 2323611 => array ( 'id' => 2323611, 'name' => 'WordCamp San Francisco', 'dates' => 'October 25, 2014-October 26, 2014', 'location' => 'SF, USA', 'venueName' => 'HUB at UW', 'url' => 'https://sf.wordcamp.test/2014/', 'latitude' => 37.7681279, 'longitude' => -122.3931417, 'iconURL' => 'icon-marker-past-2x.png', ), 2323609 => array ( 'id' => 2323609, 'name' => 'WordCamp Toronto', 'dates' => 'November 15, 2015', 'location' => 'Toronto, CA', 'venueName' => 'asdf', 'url' => 'https://toronto.wordcamp.test/2014/', 'latitude' => 43.65555690000001, 'longitude' => -79.3833209, 'iconURL' => 'icon-marker-past-2x.png', ), 70413 => array ( 'id' => 70413, 'name' => 'WordCamp Portland, OR, USA', 'dates' => 'November 16, 2017-May 11, 2016', 'location' => 'Portland, OR, USA', 'venueName' => 'Example Venue', 'url' => 'https://central.wordcamp.test/wordcamps/wordcamp-portland-or-usa-2/', 'latitude' => 45.5230622, 'longitude' => -122.6764816, 'iconURL' => 'icon-marker-past-2x.png', ), 41719 => array ( 'id' => 41719, 'name' => 'WordCamp Seattle', 'dates' => 'June 28, 2015', 'location' => 'Seattle, WA', 'venueName' => 'HUB at UW', 'url' => 'https://seattle.wordcamp.test/2015-experienced/', 'latitude' => 47.6182373, 'longitude' => -122.3543407, 'iconURL' => 'icon-marker-past-2x.png', ), 10 => array ( 'id' => 10, 'name' => 'WordCamp Atlanta', 'dates' => 'May 12, 2014-May 13, 2014', 'location' => 'Atlanta, GA, USA', 'venueName' => 'Example Venue', 'url' => 'https://atlanta.wordcamp.test/2014/', 'latitude' => 48.8668055, 'longitude' => 15.7346559, 'iconURL' => 'icon-marker-past-2x.png', ), 8 => array ( 'id' => 8, 'name' => 'WordCamp Miscellaneous', 'dates' => 'September 9, 2022-September 10, 2022', 'location' => 'Seattle, USA', 'venueName' => '', 'url' => 'https://misc.wordcamp.test/2016/', 'latitude' => 32.715738, 'longitude' => -117.1610838, 'iconURL' => 'icon-marker-past-2x.png', ), 6 => array ( 'id' => 6, 'name' => 'Content', 'dates' => 'September 9, 2016-September 11, 2016', 'location' => 'Seattle, WA, USA', 'venueName' => '', 'url' => 'https://content.wordcamp.test/2014/', 'latitude' => 27.7172453, 'longitude' => 85.3239605, 'iconURL' => 'icon-marker-past-2x.png', ),
)
);

<!-- wp:wporg/google-map <?php echo wp_json_encode( $map_options ); ?> /-->

## Attributes

todo - cant this be in block.json or somewhere where it's not redundant/out of sync?

| Name | Type | Description |
| ------------ | ------ | ------------------------------------------------------------------------ |
| link | string | `href` for `<a>` |
| preview-link | string | `url` that is passed to `mShots` |
| version | string | Used to cache break [mShots](https://github.com/Automattic/mShots) cache |

4 changes: 4 additions & 0 deletions mu-plugins/blocks/google-map/images/cluster-background.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions mu-plugins/blocks/google-map/images/map-marker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions mu-plugins/blocks/google-map/index.php
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();
}
18 changes: 18 additions & 0 deletions mu-plugins/blocks/google-map/postcss/style.pcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* These are foundational styles that provide a reasonable default for any theme.
*/

.wp-block-wporg-google-map {
position: relative;
background-color: #aadaff;

width: 100%;
max-width: 100%;
height: 100%;

@media screen and ( max-width: 385px ) {
width: 100vw;
height: 100vh;
max-height: calc(100vh - 10%); /* Make sure there's enough room to scroll past it using mobile gestures. */
}
}
30 changes: 30 additions & 0 deletions mu-plugins/blocks/google-map/src/block.json
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"
}
63 changes: 63 additions & 0 deletions mu-plugins/blocks/google-map/src/components/map.js
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 mu-plugins/blocks/google-map/src/components/marker-content.js
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;
}
25 changes: 25 additions & 0 deletions mu-plugins/blocks/google-map/src/front.js
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 );
27 changes: 27 additions & 0 deletions mu-plugins/blocks/google-map/src/index.js
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,
} );
Loading

0 comments on commit 26bfa1a

Please sign in to comment.