-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds Tracks Analytics on backend (#155)
Adds Tracks Analytics by using the Telemetry library available in MU Plugins which will only work if site is hosted on VIP Platform or if the analytics is enabled via filter.
- Loading branch information
Showing
17 changed files
with
891 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace RemoteDataBlocks\Analytics; | ||
|
||
defined( 'ABSPATH' ) || exit(); | ||
|
||
use Automattic\VIP\Telemetry\Tracks; | ||
use function Automattic\VIP\Telemetry\Tracks\get_tracks_core_properties; | ||
|
||
/** | ||
* Class for environment configuration. | ||
* | ||
* This class abstracts WordPress-specific functions for easy mocking. | ||
*/ | ||
class EnvironmentConfig { | ||
/** | ||
* Tracks analytics core properties. | ||
* | ||
* This is set by the Tracks library available in MU Plugins. | ||
* | ||
* @var array<string, mixed> | ||
*/ | ||
private array $tracks_core_props = []; | ||
|
||
public function __construct() { | ||
if ( function_exists( 'Automattic\VIP\Telemetry\Tracks\get_tracks_core_properties' ) ) { | ||
add_action( 'init', function (): void { | ||
/** @psalm-suppress UndefinedFunction */ | ||
$this->tracks_core_props = get_tracks_core_properties(); | ||
} ); | ||
} | ||
} | ||
|
||
public function is_enabled_via_filter(): bool { | ||
return apply_filters( 'remote_data_blocks_enable_tracks_analytics', false ) ?? false; | ||
} | ||
|
||
public function get_tracks_lib_class(): ?string { | ||
if ( ! class_exists( 'Automattic\VIP\Telemetry\Tracks' ) ) { | ||
return null; | ||
} | ||
|
||
return Tracks::class; | ||
} | ||
|
||
public function is_wpvip_site(): bool { | ||
if ( ! isset( $this->tracks_core_props['hosting_provider'] ) ) { | ||
return false; | ||
} | ||
|
||
return 'wpvip' === $this->tracks_core_props['hosting_provider']; | ||
} | ||
|
||
public function is_local_env(): bool { | ||
if ( ! isset( $this->tracks_core_props['vipgo_env'] ) ) { | ||
return false; | ||
} | ||
|
||
return 'local' === $this->tracks_core_props['vipgo_env']; | ||
} | ||
|
||
public function is_remote_data_blocks_plugin( string|null $plugin_path ): bool { | ||
return 'remote-data-blocks/remote-data-blocks.php' === $plugin_path; | ||
} | ||
|
||
public function should_track_post_having_remote_data_blocks( int $post_id ): bool { | ||
// Ensure this is not an auto-save or revision. | ||
if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Get the core properties to be sent with each event. | ||
*/ | ||
public function get_tracks_core_properties(): array { | ||
return $this->tracks_core_props; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace RemoteDataBlocks\Analytics; | ||
|
||
defined( 'ABSPATH' ) || exit(); | ||
|
||
use RemoteDataBlocks\Editor\BlockManagement\ConfigStore; | ||
|
||
/** | ||
* Class to implement Tracks Analytics. | ||
*/ | ||
class TracksAnalytics { | ||
/** | ||
* The tracks instance (not using Tracks as type because it is present in MU Plugins codebase). | ||
*/ | ||
private static object|null $instance = null; | ||
|
||
/** | ||
* Environment configuration. | ||
*/ | ||
private static ?EnvironmentConfig $env_config = null; | ||
|
||
/** | ||
* Initialize Tracks Analytics based on the environment configuration. | ||
* | ||
* @param EnvironmentConfig $env_config Environment configuration. | ||
*/ | ||
public static function init( EnvironmentConfig $env_config ): void { | ||
self::$env_config = $env_config; | ||
|
||
// Do not track on local environment. | ||
if ( self::$env_config->is_local_env() ) { | ||
return; | ||
} | ||
|
||
$tracks_class = self::$env_config->get_tracks_lib_class(); | ||
if ( ! $tracks_class ) { | ||
return; | ||
} | ||
|
||
if ( self::$env_config->is_wpvip_site() || self::$env_config->is_enabled_via_filter() ) { | ||
self::$instance = new $tracks_class( '', self::get_global_properties() ); | ||
self::setup_tracking_via_hooks(); | ||
} | ||
} | ||
|
||
/** | ||
* Get `Tracks` global properties to be sent with each event. | ||
*/ | ||
public static function get_global_properties(): array { | ||
$rdb_specific_props = [ | ||
'plugin_version' => defined( 'REMOTE_DATA_BLOCKS__PLUGIN_VERSION' ) ? constant( 'REMOTE_DATA_BLOCKS__PLUGIN_VERSION' ) : '', | ||
]; | ||
|
||
return array_merge( $rdb_specific_props, self::$env_config->get_tracks_core_properties() ); | ||
} | ||
|
||
private static function setup_tracking_via_hooks(): void { | ||
// WordPress Dashboard Hooks. | ||
add_action( 'activated_plugin', [ __CLASS__, 'track_plugin_activation' ] ); | ||
add_action( 'deactivated_plugin', [ __CLASS__, 'track_plugin_deactivation' ] ); | ||
add_action( 'save_post', [ __CLASS__, 'track_remote_data_blocks_usage' ], 10, 2 ); | ||
} | ||
|
||
/** | ||
* Activation hook. | ||
* | ||
* @param string $plugin_path Path of the plugin that was activated. | ||
*/ | ||
public static function track_plugin_activation( string $plugin_path ): void { | ||
if ( ! self::$env_config->is_remote_data_blocks_plugin( $plugin_path ) ) { | ||
return; | ||
} | ||
|
||
self::record_event( 'remotedatablocks_plugin_toggle', [ 'action' => 'activate' ] ); | ||
} | ||
|
||
/** | ||
* Deactivation hook. | ||
* | ||
* @param string $plugin_path Path of the plugin that was deactivated. | ||
*/ | ||
public static function track_plugin_deactivation( string $plugin_path ): void { | ||
if ( ! self::$env_config->is_remote_data_blocks_plugin( $plugin_path ) ) { | ||
return; | ||
} | ||
|
||
self::record_event( 'remotedatablocks_plugin_toggle', [ 'action' => 'deactivate' ] ); | ||
} | ||
|
||
/** | ||
* Track usage of Remote Data Blocks. | ||
* | ||
* @param int $post_id Post ID. | ||
* @param \WP_Post $post Post object. | ||
*/ | ||
public static function track_remote_data_blocks_usage( int $post_id, object $post ): void { | ||
if ( ! self::$env_config->should_track_post_having_remote_data_blocks( $post_id ) ) { | ||
return; | ||
} | ||
|
||
$post_status = $post->post_status; | ||
if ( 'publish' !== $post_status ) { | ||
return; | ||
} | ||
|
||
// Regular expression to match all remote data blocks present in the post content. | ||
$reg_exp = '/<!--\s{1}wp:remote-data-blocks\/([^\s]+)\s/'; | ||
preg_match_all( $reg_exp, $post->post_content, $matches ); | ||
if ( count( $matches[1] ) === 0 ) { | ||
return; | ||
} | ||
|
||
// Get data source and track usage. | ||
$track_props = [ | ||
'post_status' => $post_status, | ||
'post_type' => $post->post_type, | ||
]; | ||
foreach ( $matches[1] as $match ) { | ||
$data_source_type = ConfigStore::get_data_source_type( 'remote-data-blocks/' . $match ); | ||
if ( ! $data_source_type ) { | ||
continue; | ||
} | ||
|
||
// Calculate stats of each remote data source. | ||
$key = $data_source_type . '_data_source_count'; | ||
$track_props[ $key ] = ( $track_props[ $key ] ?? 0 ) + 1; | ||
$track_props['remote_data_blocks_total_count'] = ( $track_props['remote_data_blocks_total_count'] ?? 0 ) + 1; | ||
} | ||
|
||
self::record_event( 'remotedatablocks_blocks_usage_stats', $track_props ); | ||
} | ||
|
||
/** | ||
* Record an event with Tracks. | ||
* | ||
* @param string $event_name The name of the event. | ||
* @param array $props The properties to send with the event. | ||
* | ||
* @return bool True if the event was recorded, false otherwise. | ||
*/ | ||
public static function record_event( string $event_name, array $props ): bool { | ||
if ( ! isset( self::$instance ) ) { | ||
return false; | ||
} | ||
|
||
self::$instance->record_event( $event_name, $props ); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Get the instance of Tracks. | ||
*/ | ||
public static function get_instance(): ?object { | ||
return self::$instance; | ||
} | ||
|
||
public static function get_env_config(): ?EnvironmentConfig { | ||
return self::$env_config; | ||
} | ||
|
||
/** | ||
* Reset class properties. | ||
*/ | ||
public static function reset(): void { | ||
self::$instance = null; | ||
self::$env_config = null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.