Skip to content

Commit

Permalink
Map: Merge event filters into main block
Browse files Browse the repository at this point in the history
In hindsight, it's much simpler to have this as part of the main block rather than having a second. This fixes a rendering bug that is caused by wrapping the main block, and prevents having to build support for block styles into the wrapper block.
  • Loading branch information
iandunn committed Nov 20, 2023
1 parent 31b0a5b commit fe9219e
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 153 deletions.
42 changes: 0 additions & 42 deletions mu-plugins/blocks/google-map-event-filters/README.md

This file was deleted.

32 changes: 0 additions & 32 deletions mu-plugins/blocks/google-map-event-filters/src/block.json

This file was deleted.

26 changes: 0 additions & 26 deletions mu-plugins/blocks/google-map-event-filters/src/index.js

This file was deleted.

64 changes: 57 additions & 7 deletions mu-plugins/blocks/google-map/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,44 @@

Displays a Google Map with markers for each event. Markers will be clustered for performance and UX. Optionally, show a list of the same events, and a search feature.

Currently only supports programmatic usage in block theme templates etc. There's no UI available for adding markers.
Currently only supports programmatic usage in block theme templates etc. There's no UI available for selecting attributes and adding markers, but that can be added in the future.

This doesn't currently utilize all the abilities of the `google-map-react` lib, but we can expand it over time.

You can pass markers directly to the block via the `markers` attribute, or use a pre-defined event filter to display events matching certain criteria.

## Usage

Place something like the following in a block or pattern. If you're pulling events from a database, a block is better because Gutenberg loads all patterns at `init` on all pages, regardless of whether or not they're used on that page.
## Map Setup

```html
<!-- wp:wporg/google-map {"id":"my-map","apiKey":"WORDCAMP_DEV_GOOGLE_MAPS_API_KEY"} /-->
```

`id` will be used in the HTML element that wraps the map/list.

`apiKey` should be the _name_ of a constant, not the value. It's not private because it'll be exposed in the HTTP request to Google Maps, but it should still be stored in a constant in a config file instead of `post_content`. That allows for centralization, documentation, and tracking changes over time. It should be restricted in Google Cloud Console to only the sites where it will be used, to prevent abuse.

Next, choose how you want to provide the markers. You can pass them directly from your code, or use a pre-defined event filter. See below for more.


## Passing Markers Directly

Place something like the following in a block or pattern. If you'll be pulling events from a database, a block is better because Gutenberg loads all patterns at `init` on all pages, regardless of whether or not they're used on that page.

```php
<?php

$map_options = array(
'id' => 'all-upcoming-events',
'id' => 'my-map',
'apiKey' => 'MY_API_KEY_CONSTANT',
'markers' => get_all_upcoming_events(),
'markers' => get_my_markers()
);

?>

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

`apiKey` should be the _name_ of a constant, not the value. It's not private because it'll be exposed in the HTTP request to Google Maps, but it should still be stored in a constant in a config file instead of `post_content`. That allows for centralization, documentation, and tracking changes over time. It should be restricted in Google Cloud Console to only the sites where it will be used, to prevent abuse.

`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 `wporg_events` database table is one potential source for the events, but you can pass anything.

```php
Expand All @@ -42,3 +55,40 @@ If you have a small number of markers, you can manually json-encode them and the
```html
<!-- wp:wporg/google-map {"id":"wp20","apiKey":"WORDCAMP_DEV_GOOGLE_MAPS_API_KEY","markers":[{"id":"72190010","type":"meetup","title":"ONLINE DISCUSSION- Learn about your DIVI Theme- Divisociety.com","url":"https://www.meetup.com/milwaukee-wordpress-meetup/events/292286293","meetup":"Greater Milwaukee Area WordPress Meetup","location":"online","latitude":"43.04","longitude":"-87.92","tz_offset":"-21600","timestamp":1700006400},{"id":"72190007","type":"meetup","title":"Meetup Virtual - SEO Más allá del ranking","url":"https://www.meetup.com/wpsanjose/events/294644892","meetup":"WordPress Meetup San José","location":"online","latitude":"9.93","longitude":"-84.08","tz_offset":"-21600","timestamp":1700010000},{"id":"72190008","type":"meetup","title":"WordPress Developer Night - #IEWP","url":"https://www.meetup.com/inlandempirewp/events/292287676","meetup":"Inland Empire WordPress Meetup Group","location":"online","latitude":"33.99","longitude":"-117.37","tz_offset":"-28800","timestamp":1700017200}]} /-->
```


## Passing Markers with Event Filters

Instead of passing markers directly to the block, you can pass a `filterSlug` attribute, which corresponds to a pre-defined set of events. Some filters also support passing a start/end date, so you can restrict events to those dates.

Filters can be setup for anything, but some common examples are watch parties for WP anniversaries and the State of the Word.

1. If you're not using an existing filter, then add a new one to `get_events()` and/or `filter_potential_events()`. You can also use the `google_map_event_filters_{$filter_slug}` WP filter to register an event filter outside of this plugin. That can be useful in circumstances where the data is only used on a specific site, like WordCamp.org's `google_map_event_filters_city-landing-pages` filter.
1. Add the following to a pattern in your theme.

```php
$map_options = array(
'id' => 'wp20',
'apiKey' => 'WORDCAMP_DEV_GOOGLE_MAPS_API_KEY',
'filterSlug' => 'wp20',
'startDate' => 'April 21, 2023',
'endDate' => 'May 30, 2023',
);

?>

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

Alternatively, you could take that JSON and manually put it in the post source like this:

```html
<!-- wp:wporg/google-map {"id":"all-upcoming","apiKey":"WORDCAMP_DEV_GOOGLE_MAPS_API_KEY","filterSlug":"all-upcoming"} /-->

<!-- wp:wporg/google-map {"id":"sotw-2023","apiKey":"WORDCAMP_DEV_GOOGLE_MAPS_API_KEY","filterSlug":"sotw","startDate":"December 10, 2023","endDate":"January 12, 2024","className":"is-style-sotw-2023"} /-->

<!-- wp:wporg/google-map {"id":"wp20","apiKey":"WORDCAMP_DEV_GOOGLE_MAPS_API_KEY","filterSlug":"wp20","startDate":"April 21, 2023","endDate":"May 30, 2023"} /-->
```

1. View the page where the block is used. That will create the cron job that updates the data automatically in the future.
1. Run `wp cron event run prime_event_filters` to test the filtering. Look at each title, and add any false positives to `$false_positives` in `filter_potential_events()`. If any events that should be included were ignored, add a keyword from the title to `$keywords`. Run the command after those changes and make sure it's correct now.
Original file line number Diff line number Diff line change
@@ -1,47 +1,22 @@
<?php

namespace WordPressdotorg\MU_Plugins\Google_Map_Event_Filters;
use WP_Block;
namespace WordPressdotorg\MU_Plugins\Google_Map;

defined( 'WPINC' ) || die();

add_action( 'init', __NAMESPACE__ . '\init' );
add_action( 'prime_event_filters', __NAMESPACE__ . '\get_events', 10, 4 );


/**
* Registers the block from `block.json`.
* Schedule a cron job to update events that match the given filter/dates.
*/
function init() {
register_block_type(
__DIR__ . '/build',
array(
'render_callback' => __NAMESPACE__ . '\render',
)
);
}

/**
* Render the block content.
*/
function render( array $attributes, string $content, WP_Block $block ): string {
$attributes['startDate'] = strtotime( $attributes['startDate'] );
$attributes['endDate'] = strtotime( $attributes['endDate'] );
$wrapper_attributes = get_block_wrapper_attributes( array( 'id' => 'wp-block-wporg-google-map-event-filters-' . $attributes['filterSlug'] ) );

// The REST API doesn't support associative arrays, so this had to be defined as an object in this block. It
// needs to be an array when passed to the Google Map block though.
// See `rest_is_array()`.
$map_options = (array) $attributes['googleMapBlockAttributes'];
$map_options['markers'] = get_events( $attributes['filterSlug'], $attributes['startDate'], $attributes['endDate'] );

// This has to be called in `render()` to know which slug/dates to use.
$cron_args = array( $attributes['filterSlug'], $attributes['startDate'], $attributes['endDate'], true );
function schedule_filter_cron( string $filter_slug, string $start_date, string $end_date ): void {
$cron_args = array( $filter_slug, $start_date, $end_date, true );

// Some custom filter slugs using `google_map_event_filters_{$filter_slug}` to pass data may need to run their
// own cron to prime the cache.
// See WordCamp's `themes/wporg-events-2023/inc/city-landing-pages.php` for an example.
$register_cron = apply_filters( 'google-map-event-filters-register-cron', true, $attributes['filterSlug'] );
$register_cron = apply_filters( 'google-map-event-filters-register-cron', true, $filter_slug );

if ( $register_cron && ! wp_next_scheduled( 'prime_event_filters', $cron_args ) ) {
wp_schedule_event(
Expand All @@ -51,18 +26,6 @@ function render( array $attributes, string $content, WP_Block $block ): string {
$cron_args
);
}

ob_start();

?>

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

<?php

return do_blocks( ob_get_clean() );
}

/**
Expand Down Expand Up @@ -271,7 +234,7 @@ function filter_potential_events( string $filter_slug, array $potential_events )
}
}

print_results( $matched_events, $other_events );
print_results( $filter_slug, $matched_events, $other_events );

return $matched_events;
}
Expand All @@ -281,7 +244,7 @@ function filter_potential_events( string $filter_slug, array $potential_events )
*
* Run `wp cron event run prime_event_filters` to see this.
*/
function print_results( array $matched_events, array $other_events ) : void {
function print_results( string $filter, array $matched_events, array $other_events ) : void {
if ( 'cli' !== php_sapi_name() ) {
return;
}
Expand All @@ -292,9 +255,11 @@ function print_results( array $matched_events, array $other_events ) : void {
sort( $matched_names );
sort( $other_names );

printf( "\n\n============================== \nResults for $filter: \n==============================\n" );

echo "\nIgnored these events. Double check for false-negatives.\n\n";
print_r( $other_names );

echo "\Included these events. Double check for false-positives.\n\n";
echo "\nIncluded these events. Double check for false-positives.\n\n";
print_r( $matched_names );
}
12 changes: 12 additions & 0 deletions mu-plugins/blocks/google-map/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace WordPressdotorg\MU_Plugins\Google_Map;

require_once __DIR__ . '/inc/event-filters.php';

add_action( 'init', __NAMESPACE__ . '\init' );


Expand Down Expand Up @@ -37,6 +39,9 @@ function render( $attributes, $content, $block ) {
$attributes['apiKey'] = constant( $attributes['apiKey'] );
}

$attributes['startDate'] = (int) strtotime( $attributes['startDate'] );
$attributes['endDate'] = (int) strtotime( $attributes['endDate'] );

$attributes['searchIcon'] = plugins_url( 'images/search.svg', __FILE__ );

$attributes['markerIcon'] = array(
Expand All @@ -50,6 +55,13 @@ function render( $attributes, $content, $block ) {

$attributes['markerIcon']['markerAnchorXOffset'] = $attributes['markerIcon']['markerWidth'] / -4;

if ( ! empty( $attributes['filterSlug'] ) ) {
$attributes['markers'] = get_events( $attributes['filterSlug'], $attributes['startDate'], $attributes['endDate'] );

// This has to be called in `render()` to know which slug/dates to use.
schedule_filter_cron( $attributes['filterSlug'], $attributes['startDate'], $attributes['endDate'] );
}

$handles = array( $block->block_type->view_script_handles[0], $block->block_type->editor_script_handles[0] );

foreach ( $handles as $handle ) {
Expand Down
12 changes: 12 additions & 0 deletions mu-plugins/blocks/google-map/src/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@
"type": "string",
"default": ""
},
"filterSlug": {
"type": "string",
"default": ""
},
"startDate": {
"type": "string",
"default": ""
},
"endDate": {
"type": "string",
"default": ""
},
"markers": {
"type": "array",
"default": []
Expand Down
1 change: 0 additions & 1 deletion mu-plugins/loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
require_once __DIR__ . '/blocks/local-navigation-bar/index.php';
require_once __DIR__ . '/blocks/latest-news/latest-news.php';
require_once __DIR__ . '/blocks/link-wrapper/index.php';
require_once __DIR__ . '/blocks/google-map-event-filters/google-map-event-filters.php';
require_once __DIR__ . '/blocks/navigation/index.php';
require_once __DIR__ . '/blocks/notice/index.php';
require_once __DIR__ . '/blocks/query-filter/index.php';
Expand Down

0 comments on commit fe9219e

Please sign in to comment.