Skip to content

Commit

Permalink
Merge pull request #41 from humanmade/block-events
Browse files Browse the repository at this point in the history
Add support for setting GTM events via editor
  • Loading branch information
roborourke authored Aug 28, 2024
2 parents 3740505 + 4084da3 commit 151343d
Show file tree
Hide file tree
Showing 4 changed files with 306 additions and 3 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,23 @@ You can explore and view the `dataLayer` variables by previewing your container

### Custom event tracking

In the block editor you can add event tracking to any block via the settings panel in the block sidebar. This calls `dataLayer.push()` with the event data specified.

All blocks are opted in to support this by default, but you can set block support to false with the following during block registration, or via `block.json`. For example:

```php
register_block_type( 'my-plugin/my-block', [
'supports' => [
'gtm' => false,
],
) );
```

By default the plugin will look for elements with special data attributes in your markup and listen to the specified event to push events to the data layer.

The data attributes are:

- `data-gtm-on`: _enum_ [click|submit|keyup|focus|blur] The JS event to listen for, defaults to 'click'.
- `data-gtm-on`: _enum_ [click|submit|keyup|focusin|focusout|mouseenter|mouseleave] The JS event to listen for, defaults to 'click'.
- `data-gtm-event`: _string_ The name or action of the event eg. "play".
- `data-gtm-category`: _string_ Optional group the event belongs to.
- `data-gtm-label`: _string_ Optional human readable label for the event.
Expand Down
170 changes: 170 additions & 0 deletions assets/blocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
const addFilter = wp.hooks.addFilter;
const InspectorControls = wp.blockEditor.InspectorControls;
const hasBlockSupport = wp.blocks.hasBlockSupport;
const TextControl = wp.components.TextControl;
const SelectControl = wp.components.SelectControl;
const PanelBody = wp.components.PanelBody;
const __ = wp.i18n.__;

function HMGTMEvents(BlockEdit) {
return function (props) {
const attributes = props.attributes;
const setAttributes = props.setAttributes;

const supportsGTM = attributes?.gtm !== undefined;

// Check if the block supports "gtm"
if (!supportsGTM) {
return wp.element.createElement(BlockEdit, props);
}

function update( settings ) {
setAttributes({ gtm: { ...(attributes.gtm || {}), ...settings } });
}

return (
wp.element.createElement(
wp.element.Fragment,
null,
wp.element.createElement(
BlockEdit,
props
),
wp.element.createElement(
InspectorControls,
null,
wp.element.createElement(
PanelBody,
{ title: __( 'Google Tag Manager', 'hm-gtm' ), initialOpen: false },
wp.element.createElement(
'p',
{},
__( 'The following options allow you to push an event to GTM when this block is interacted with.', 'hm-gtm' )
),
wp.element.createElement(
SelectControl,
{
label: __( 'Event Trigger', 'hm-gtm' ),
value: attributes?.gtm?.trigger || 'click',
options: [
{ label: __( 'Click', 'hm-gtm' ), value: 'click' },
{ label: __( 'Submit', 'hm-gtm' ), value: 'submit' },
{ label: __( 'Focus', 'hm-gtm' ), value: 'focusin' },
{ label: __( 'Blur', 'hm-gtm' ), value: 'focusout' },
{ label: __( 'Key up', 'hm-gtm' ), value: 'keyup' },
{ label: __( 'Mouseover', 'hm-gtm' ), value: 'mouseenter' },
{ label: __( 'Mouseout', 'hm-gtm' ), value: 'mouseleave' }
],
onChange: function (value) {
update({ trigger: value });
}
}
),
wp.element.createElement(
TextControl,
{
label: __( 'Event Name', 'hm-gtm' ),
value: attributes.gtm?.event || '',
onChange: function (value) {
update({ event: value });
}
}
),
wp.element.createElement(
TextControl,
{
label: __( 'Action', 'hm-gtm' ),
value: attributes.gtm?.action || '',
onChange: function (value) {
update({ action: value });
}
}
),
wp.element.createElement(
TextControl,
{
label: __( 'Category', 'hm-gtm' ),
value: attributes.gtm?.category || '',
onChange: function (value) {
update({ category: value });
}
}
),
wp.element.createElement(
TextControl,
{
label: __( 'Label', 'hm-gtm' ),
value: attributes.gtm?.label || '',
onChange: function (value) {
update({ label: value });
}
}
),
wp.element.createElement(
TextControl,
{
label: __( 'Value', 'hm-gtm' ),
value: attributes.gtm?.value || '',
onChange: function (value) {
update({ value: value });
}
}
)
)
)
)
);
};
}

addFilter(
'editor.BlockEdit',
'hm-gtm/events',
HMGTMEvents,
5000
);

function addGTMAttribute(settings) {
if ( ! hasBlockSupport( settings.name, 'gtm', true ) ) {
return settings;
}

return {
...settings,
attributes: {
...settings.attributes,
gtm: {
type: 'object',
default: {},
properties: {
trigger: {
type: 'string',
enum: [ 'click', 'submit', 'focusin', 'focusout', 'keyup', 'mouseenter', 'mouseleave' ]
},
event: {
type: 'string'
},
action: {
type: 'string'
},
category: {
type: 'string'
},
label: {
type: 'string'
},
value: {
type: 'string'
}
}
},
},
};
}

wp.hooks.addFilter(
'blocks.registerBlockType',
'hm-gtm/add-gtm-attribute',
addGTMAttribute,
5000
);
121 changes: 121 additions & 0 deletions inc/namespace.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
namespace HM\GTM;

use WP_Admin_Bar;
use WP_Block_Supports;
use WP_Block_Type;
use WP_HTML_Tag_Processor;
use WP_REST_Request;

/**
Expand Down Expand Up @@ -39,6 +42,49 @@ function bootstrap() {

if ( $enable_event_tracking ) {
add_action( 'wp_enqueue_scripts', __NAMESPACE__ . '\\enqueue_scripts' );

// Block UI.
add_action( 'enqueue_block_editor_assets', __NAMESPACE__ . '\\block_editor_enqueue_scripts' );
add_filter( 'render_block', __NAMESPACE__ . '\\filter_render_block', 10, 3 );
WP_Block_Supports::get_instance()->register(
'gtm',
[
'register_attribute' => function ( WP_Block_Type $block_type ) {
if ( ! block_has_support( $block_type, 'gtm', true ) ) {
return [];
}

if ( ! $block_type->attributes ) {
$block_type->attributes = [];
}

$block_type->attributes['gtm'] = [
'type' => 'object',
'properties' => [
'trigger' => [
'type' => 'string',
'enum' => [ 'click', 'submit', 'focusin', 'focusout', 'mouseenter', 'mouseleave' ],
],
'event' => [
'type' => 'string',
],
'action' => [
'type' => 'string',
],
'category' => [
'type' => 'string',
],
'label' => [
'type' => 'string',
],
'value' => [
'type' => 'string',
],
],
];
},
]
);
}

// dataLayer display.
Expand Down Expand Up @@ -510,6 +556,81 @@ function enqueue_scripts() {
] );
}

/**
* Enqueue block editor settings panel.
*/
function block_editor_enqueue_scripts() {
wp_enqueue_script( 'hm-gtm-blocks', plugins_url( '/assets/blocks.js', dirname( __FILE__ ) ), [
'wp-blocks',
'wp-block-editor',
'wp-hooks',
'wp-components',
], VERSION, [
'in_footer' => false,
'strategy' => 'defer',
] );
}

/**
* Filters the content of a single block.
*
* @param string $block_content The block content.
* @param array $block The full block, including name and attributes.
* @return string The block content.
*/
function filter_render_block( string $block_content, array $block ) : string {

// Check minimum requirements.
if ( empty( $block['attrs']['gtm'] ) || empty( $block['attrs']['gtm']['event'] ) ) {
return $block_content;
}

$attributes = [];
$attributes['data-gtm-on'] = $block['attrs']['gtm']['trigger'] ?? 'click';

foreach ( [ 'event', 'action', 'category', 'label', 'value' ] as $key ) {
if ( ! empty( $block['attrs']['gtm'][ $key ] ) ) {
$attributes["data-gtm-{$key}"] = $block['attrs']['gtm'][ $key ];
}
}

$block = new WP_HTML_Tag_Processor( $block_content );
$block->set_bookmark( 'root' );

$query = null;

switch ( $attributes['data-gtm-on'] ) {
case 'click':
$query = [ 'tag_name' => 'a' ];
// Test for an anchor tag.
if ( ! $block->next_tag( [ 'tag_name' => $query ] ) ) {
// Update to test for a button.
$query['tag_name'] = 'button';
$block->seek( 'root' );
}
// Test for a button tag.
if ( ! $block->next_tag( [ 'tag_name' => $query ] ) ) {
// Reset to first/wrapper tag.
$query = null;
}
$block->seek( 'root' );
$block->next_tag( $query );
break;
case 'submit':
// Must be a form tag.
$block->next_tag( [ 'tag_name' => 'form' ] );
break;
default:
$block->next_tag();
}

foreach ( $attributes as $name => $value ) {
$block->set_attribute( $name, $value );
}

return (string) $block;
}

/**
* Modify the admin bar to show dataLayer variables.
*
Expand Down
4 changes: 2 additions & 2 deletions plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
* Plugin Name: Google Tag Manager tools
* Description: Provides GTM integration per site or for an entire multisite network.
* Author: Human Made Limited
* Version: 3.0.0
* Version: 3.1.0
* Author URI: https://humanmade.com
*/

namespace HM\GTM;

const VERSION = '3.0.0';
const VERSION = '3.1.0';

require_once __DIR__ . '/inc/namespace.php';
require_once __DIR__ . '/inc/template-tags.php';
Expand Down

0 comments on commit 151343d

Please sign in to comment.