Skip to content

Commit

Permalink
exploring basic Pendo tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
smithjw1 committed Dec 10, 2024
1 parent c82dc65 commit 55024be
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 1 deletion.
3 changes: 2 additions & 1 deletion 000-vip-init.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,10 @@
__DIR__ . '/telemetry/tracks/class-tracks-event.php',
__DIR__ . '/telemetry/tracks/class-tracks-client.php',
__DIR__ . '/telemetry/tracks/tracks-utils.php',
__DIR__ . '/telemetry/class-pendo.php',
__DIR__ . '/telemetry/pendo/pendo-utils.php',
];

// If there is a missing file, the loop will break and the telemetry files will not be loaded at all
do {
foreach ( $require_telemetry_files as $file ) {
if ( ! file_exists( $file ) ) {
Expand Down
83 changes: 83 additions & 0 deletions telemetry/class-pendo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php
/**
* Telemetry: Pendo class
*
* @package Automattic\VIP\Telemetry
*/

declare(strict_types=1);

namespace Automattic\VIP\Telemetry;

use WP_Error;

/**
* This class comprises the mechanics of including Pendo tracking.
*/
class Pendo {


/**
* @param array<string, mixed> Visitor properties.
*/
private array $visitor_properties = [];

/**
* @param array<string, mixed> Visitor properties.
*/
private array $account_properties = [];

/**
* Pendo constructor.
*
*/
public function __construct() {
$this->visitor_properties = Pendo\get_base_properties_of_pendo_user();
$this->account_properties = [ 'id' => 'VIP' ];
}

/**
* Inserts the Pendo tracking JavaScript code into the page.
*
* If the event doesn't pass validation, it gets silently discarded.
*
* @return bool|WP_Error True if recording the event succeeded.
* False if telemetry is disabled.
* WP_Error if recording the event failed.
*/
public function include_script(): bool|WP_Error {
if ( $this->is_enabled() ) {
$this->output_pendo_agent();
$this->output_pendo_ini();
}
return true;
}

private function is_enabled(): bool {
if ( [] === $this->visitor_properties || [] === $this->account_properties ) {
//don't enable if we can't track an actual visitor or account
return false;
}
if ( ( false === WPCOM_IS_VIP_ENV || true === WPCOM_SANDBOXED ) ) {
//limit tracking to production
return false;
}
if ( defined( 'VIP_IS_FEDRAMP' ) && true === VIP_DISABLE_PENDO ) {
//don't track in FedRAMP environments
return false;
}
// Check on a new constant to see if Pendo is disabled by the org.
return false;
}
private function output_pendo_agent(): void {
wp_enqueue_script( 'vip-pendo-agent-script', plugins_url( '/pendo/pendo-agent.js', __FILE__ ), [ 'common' ], '0.4', true );
}
private function output_pendo_ini(): void {
wp_enqueue_script( 'vip-pendo-ini-script', plugins_url( '/pendo/pendo-ini.js', __FILE__ ), [ 'common' ], '0.4', true );
$variables = 'const vip_pendo = ' . wp_json_encode( [
'visitor' => $this->visitor_properties,
'account' => $this->account_properties,
] ) . '; ';
wp_add_inline_script( 'vip-pendo-ini-script', $variables, 'before' );
}
}
16 changes: 16 additions & 0 deletions telemetry/pendo/pendo-agent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
if (!window.pendo) {
(function (apiKey) {
(function (p, e, n, d, o) {
var v, w, x, y, z; o = p[d] = p[d] || {}; o._q = o._q || [];

v = ['initialize', 'identify', 'updateOptions', 'pageLoad', 'track']; for (w = 0, x = v.length; w < x; ++w)(function (m) {

o[m] = o[m] || function () { o._q[m === v[0] ? 'unshift' : 'push']([m].concat([].slice.call(arguments, 0))); };
})(v[w]);

y = e.createElement(n); y.async = !0; y.src = 'https://cdn.pendo.io/agent/static/' + apiKey + '/pendo.js';

z = e.getElementsByTagName(n)[0]; z.parentNode.insertBefore(y, z);
})(window, document, 'script', 'pendo');
})('c04bb66e-a34f-4b7c-6907-c9dbea86209b');
}
12 changes: 12 additions & 0 deletions telemetry/pendo/pendo-ini.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
if (window.pendo && window.pendo.apiKey === "c04bb66e-a34f-4b7c-6907-c9dbea86209b") {
pendo.initialize({
visitor: {
id: vip_pendo.visitor.id,
full_name: vip_pendo.visitor.full_name,
role: vip_pendo.visitor.role,
},
account: {
id: account.id,
}
});
}
45 changes: 45 additions & 0 deletions telemetry/pendo/pendo-utils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php
/**
* Telemetry: Pendo Utils
*
* @package Automattic\VIP\Telemetry\Pendo
*/

declare(strict_types=1);

namespace Automattic\VIP\Telemetry\Pendo;

/**
* Returns the base properties for a track user.
*
* @return array<string, mixed> The base properties.
*/
function get_base_properties_of_pendo_user(): array {
if ( ! function_exists( 'wp_get_current_user' ) ) {
return [];
}

$props = [];

// Only track logged-in users.
$wp_user = wp_get_current_user();
if ( 0 === $wp_user->ID ) {
return $props;
}

// Set anonymized event user ID; it should be consistent across environments.
// VIP_TELEMETRY_SALT is a private constant shared across the platform.
if ( ! defined( 'VIP_TELEMETRY_SALT' ) && $wp_user->user_email ) {
// If we can't set the user ID, don't track the user.
return $props;
}

$salt = constant( 'VIP_TELEMETRY_SALT' );
$tracks_user_id = hash_hmac( 'sha256', $wp_user->user_email, $salt );

$props['id'] = $tracks_user_id;
$props['full_name'] = $wp_user->display_name;
$props['role'] = $wp_user->roles[0];

return $props;
}

0 comments on commit 55024be

Please sign in to comment.