Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions bundle/ios/App.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bundle/ios/App.js.map

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions src/analytics/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Internal dependencies
*/
import { initialize as initializeRedux } from './redux';

export default () => {
initializeRedux();
};
40 changes: 40 additions & 0 deletions src/analytics/redux/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* WordPress dependencies
*/
import { use } from '@wordpress/data';
/**
* Internal dependencies
*/
import { trackedEvents } from './tracked_events';

/**
* Initialize the Redux middleware
*/
export function initialize() {
use( ( registry ) => ( {
dispatch: ( namespace ) => {
const namespaceName =
typeof namespace === 'object' ? namespace.name : namespace;
const actions = { ...registry.dispatch( namespaceName ) };
const trackers = trackedEvents[ namespaceName ];

if ( trackers ) {
Object.keys( trackers ).forEach( ( actionName ) => {
const originalAction = actions[ actionName ];
const tracker = trackers[ actionName ];
actions[ actionName ] = ( ...args ) => {
try {
tracker( ...args );
} catch ( err ) {
// eslint-disable-next-line no-console
console.error( err );
}
return originalAction( ...args );
};
} );
}

return actions;
},
} ) );
}
84 changes: 84 additions & 0 deletions src/analytics/redux/tracked_events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* eslint-disable camelcase */
/**
* WordPress dependencies
*/
import { select } from '@wordpress/data';
import { sendEventToHost } from '@wordpress/react-native-bridge';

/**
* Retrieves a block object. If the block is not an object,
* it tries to retrieve the block from the store.
*
* @param {string|Object} block Block objectg or string identifier.
* @return {Object} block object or an empty object if not found.
*/
function getBlockObject( block ) {
if ( typeof block === 'object' ) {
return block;
}
return select( 'core/block-editor' ).getBlock( block ) || {};
}

/**
* Helper function to recursively track block events.
* Each inner block will be tracked as a separate event if block contains inner blocks.
*
* @param {Array|Object} blocks A single or collection of block objects or block identifiers.
* @param {string} eventName Event name used to track.
* @param {Function} propertiesHandler Callback to transform properties.
* @param {Object} parentBlock Parent block. optional
* @return {void}
*/
function trackBlocksHandler(
blocks,
eventName,
propertiesHandler = () => {},
parentBlock
) {
const blockArray = [ blocks ].flat();
if ( ! blocks || ! blockArray.length ) {
return;
}

blockArray.forEach( ( block ) => {
const blockObject = getBlockObject( block );
const eventProperties = {
...propertiesHandler( blockObject ),
inner_block: !! parentBlock,
};

if ( parentBlock ) {
eventProperties.parent_block_name = parentBlock.name;
}

sendEventToHost( eventName, eventProperties );

if ( blockObject.innerBlocks ) {
trackBlocksHandler(
blockObject.innerBlocks,
eventName,
propertiesHandler,
blockObject
);
}
} );
}

export const trackedEvents = {
'core/block-editor': {
insertBlock( blocks ) {
trackBlocksHandler(
blocks,
'editor_block_inserted',
( { name } ) => ( { block_name: name } )
);
},
insertBlocks( blocks ) {
Copy link
Contributor

@mchowning mchowning Oct 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can easily trigger insertBlock, but I'm not sure how to trigger insertBlocks from mobile. Any suggestions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From researching the usage of the insertBlocks action creator, it would appear splitting at the end of some rich text blocks causes a insertBlocks Redux action to trigger. E.g. placing a the cursor in a PullQuote block's citation input and pressing Return will trigger the action.

That said, neither WPAndroid or WPiOS implementations currently have sibling events defined for insertBlocks, so the resulting analytics event will not be sent. I plan to add the required sibling events.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following up to share that my plan is to rename the editor_blocks_inserted event to editor_block_inserted rather than add sibling events to WPAndroid and WPiOS. This approach mimics what Calypso does, as both insertBlock and insertBlocks leverage the same event name.

To me, this approach makes more sense, as we our goal is tracking the insertion of a block. Whether the insertBlock or insertBlocks action creator is leveraged is implementation details. In fact, the insertBlock action calls insertBlocks itself.

trackBlocksHandler(
blocks,
'editor_block_inserted',
( { name } ) => ( { block_name: name } )
);
},
},
};
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from './jetpack-editor-setup';
import setupBlockExperiments from './block-experiments-setup';
import initialHtml from './initial-html';
import initAnalytics from './analytics';

addAction( 'native.pre-render', 'gutenberg-mobile', ( props ) => {
require( './strings-overrides' );
Expand Down Expand Up @@ -60,4 +61,5 @@ addFilter( 'native.block_editor_props', 'gutenberg-mobile', ( editorProps ) => {
return editorProps;
} );

initAnalytics();
doGutenbergNativeSetup();