PluginProbe
Parse.ly / 3.24.2
Parse.ly v3.24.2
3.24.2 3.24.1 3.24.0 3.23.7 3.23.6 3.23.5 3.23.4 3.23.3 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.17.0 3.18.0 3.18.1 3.19.0 3.19.1 3.19.2 3.19.3 3.2.0 3.2.1 3.20.0 3.20.1 3.20.2 All 106 releases
wp-parsely / src / js / telemetry / block-change.tsx

block-change.tsx in Parse.ly 3.24.2, at src/js/telemetry/block-change.tsx

117 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * WordPress dependencies
3 */
4 // eslint-disable-next-line import/named
5 import { BlockInstance } from '@wordpress/blocks';
6 import { select, subscribe } from '@wordpress/data';
7 import { useEffect } from '@wordpress/element';
8
9 /**
10 * External dependencies
11 */
12 // eslint-disable-next-line import/no-extraneous-dependencies
13 import debounce from 'lodash/debounce';
14 import { isEditorReady } from '../../content-helper/common/utils/functions';
15
16 /**
17 * Internal dependencies
18 */
19 import { Telemetry } from './telemetry';
20
21 /**
22 * BlockChangeMonitor is a React component that monitors changes in the WordPress block editor.
23 * It tracks the addition and removal of blocks that start with the 'wp-parsely/' prefix.
24 * This component does not render anything.
25 *
26 * @since 3.12.0
27 *
28 * @return {null} This component does not render anything.
29 */
30 export const BlockChangeMonitor = (): null => {
31 /**
32 * The prefix of the blocks to monitor.
33 *
34 * @since 3.12.0
35 */
36 const parselyBlockPrefix: string = 'wp-parsely/';
37
38 /**
39 * This useEffect hook is used to monitor changes in the WordPress block editor.
40 * It delays the initialization to avoid reacting to the initial block load.
41 * It subscribes to changes in the block editor when the component is mounted.
42 * When the block editor changes, it checks if blocks have been added or removed by comparing the current
43 * list of blocks with the previous one.
44 * If a block has been added or removed, it sends a telemetry event to the server.
45 * When the component is unmounted, it clears the initialization timeout.
46 *
47 * @since 3.12.0
48 * @since 3.14.0 Improved detection by comparing current and previous block states directly.
49 */
50 useEffect( () => {
51 // Debounce interval to save CPU cycles with the frequent editor updates.
52 const debounceInterval = 1000; // In milliseconds.
53
54 let unsubscribe: () => void;
55 const initialize = () => {
56 let previousBlocks = select( 'core/block-editor' ).getBlocks();
57
58 /**
59 * Checks if blocks have been added or removed and sends telemetry events accordingly.
60 *
61 * @since 3.14.0
62 */
63 const checkBlocks = () => {
64 const currentBlocks: BlockInstance[] = select(
65 'core/block-editor'
66 ).getBlocks();
67 const currentBlockIds = currentBlocks.map( ( block ) => block.clientId );
68 const previousBlockIds = previousBlocks.map(
69 ( block: BlockInstance ) => block.clientId
70 );
71
72 // Find added blocks.
73 const addedBlocks = currentBlocks.filter(
74 ( block ) => ! previousBlockIds.includes( block.clientId ),
75 );
76 addedBlocks.forEach( ( block ) => {
77 if ( block.name.startsWith( parselyBlockPrefix ) ) {
78 Telemetry.trackEvent( 'block_added', { block: block.name } );
79 }
80 } );
81
82 // Find removed blocks.
83 const removedBlockIds = previousBlockIds.filter(
84 ( id: string ) => ! currentBlockIds.includes( id )
85 );
86 removedBlockIds.forEach( ( id: string ) => {
87 const removedBlock = previousBlocks.find(
88 ( block: BlockInstance ) => block.clientId === id
89 );
90 if ( removedBlock && removedBlock.name.startsWith( parselyBlockPrefix ) ) {
91 Telemetry.trackEvent( 'block_removed', { block: removedBlock.name } );
92 }
93 } );
94
95 // Update the previousBlocks for the next check.
96 previousBlocks = currentBlocks;
97 };
98
99 // Debounce the checkBlocks function to save CPU cycles with the frequent editor updates.
100 const debouncedCheckBlocks = debounce( checkBlocks, debounceInterval );
101 unsubscribe = subscribe( debouncedCheckBlocks, 'core/block-editor' );
102 return unsubscribe;
103 };
104
105 // Initialize the block change monitor when the editor is ready.
106 isEditorReady().then( initialize );
107
108 return () => {
109 if ( unsubscribe ) {
110 unsubscribe();
111 }
112 };
113 }, [] );
114
115 return null; // This component does not render anything.
116 };
117