diff --git a/packages/playground/website/src/components/layout/index.tsx b/packages/playground/website/src/components/layout/index.tsx
index ee6906d1a5..b4ebf3bec4 100644
--- a/packages/playground/website/src/components/layout/index.tsx
+++ b/packages/playground/website/src/components/layout/index.tsx
@@ -33,6 +33,7 @@ import {
setSiteManagerOpen,
} from '../../lib/state/redux/slice-ui';
import { ImportFormModal } from '../import-form/modal';
+import { logErrorEvent } from '../../lib/tracking';
acquireOAuthTokenIfNeeded();
@@ -42,8 +43,8 @@ export const modalSlugs = {
START_ERROR: 'start-error',
IMPORT_FORM: 'import-form',
GITHUB_IMPORT: 'github-import',
- GITHUB_EXPORT: 'github-export'
-}
+ GITHUB_EXPORT: 'github-export',
+};
const displayMode = getDisplayModeFromQuery();
function getDisplayModeFromQuery(): DisplayMode {
@@ -159,6 +160,8 @@ function Modals(blueprint: Blueprint) {
useEffect(() => {
addCrashListener(logger, (e) => {
const error = e as CustomEvent;
+ logErrorEvent(error.detail?.source);
+
if (error.detail?.source === 'php-wasm') {
dispatch(setActiveModal(modalSlugs.ERROR_REPORT));
}
@@ -179,39 +182,43 @@ function Modals(blueprint: Blueprint) {
} else if (currentModal === modalSlugs.IMPORT_FORM) {
return ;
} else if (currentModal === modalSlugs.GITHUB_IMPORT) {
- return {
- setGithubExportValues({
- repoUrl: url,
- prNumber: pr?.toString(),
- toPathInRepo: path,
- prAction: pr ? 'update' : 'create',
+ return (
+ ;
+ urlInformation: { owner, repo, type, pr },
+ }) => {
+ setGithubExportValues({
+ repoUrl: url,
+ prNumber: pr?.toString(),
+ toPathInRepo: path,
+ prAction: pr ? 'update' : 'create',
+ contentType,
+ plugin: pluginOrThemeName,
+ theme: pluginOrThemeName,
+ });
+ setGithubExportFiles(files);
+ }}
+ />
+ );
} else if (currentModal === modalSlugs.GITHUB_EXPORT) {
- return {
- setGithubExportValues(formValues);
- setGithubExportFiles(undefined);
- }}
- />;
+ return (
+ {
+ setGithubExportValues(formValues);
+ setGithubExportFiles(undefined);
+ }}
+ />
+ );
}
if (query.get('gh-ensure-auth') === 'yes') {
diff --git a/packages/playground/website/src/lib/state/redux/boot-site-client.ts b/packages/playground/website/src/lib/state/redux/boot-site-client.ts
index 6ae9b4664e..cdafb5ea87 100644
--- a/packages/playground/website/src/lib/state/redux/boot-site-client.ts
+++ b/packages/playground/website/src/lib/state/redux/boot-site-client.ts
@@ -10,8 +10,12 @@ import {
removeClientInfo,
updateClientInfo,
} from './slice-clients';
-import { logTrackingEvent } from '../../tracking';
-import { Blueprint, StepDefinition } from '@wp-playground/blueprints';
+import {
+ logBlueprintStepEvent,
+ logErrorEvent,
+ logTrackingEvent,
+} from '../../tracking';
+import { Blueprint } from '@wp-playground/blueprints';
import { logger } from '@php-wasm/logger';
import { setupPostMessageRelay } from '@php-wasm/web';
import { startPlaygroundWeb } from '@wp-playground/client';
@@ -100,17 +104,6 @@ export function bootSiteClient(
blueprint = site.metadata.runtimeConfiguration;
} else {
blueprint = site.metadata.originalBlueprint;
- // Log the names of provided Blueprint's steps.
- // Only the names (e.g. "runPhp" or "login") are logged. Step options like
- // code, password, URLs are never sent anywhere.
- const steps = (blueprint?.steps || [])
- ?.filter(
- (step: any) => !!(typeof step === 'object' && step?.step)
- )
- .map((step) => (step as StepDefinition).step);
- for (const step of steps) {
- logTrackingEvent('step', { step });
- }
}
let playground: PlaygroundClient;
@@ -125,6 +118,9 @@ export function bootSiteClient(
onClientConnected: (playground) => {
(window as any)['playground'] = playground;
},
+ onBlueprintStepCompleted: (result, step) => {
+ logBlueprintStepEvent(step);
+ },
mounts: mountDescriptor
? [
{
@@ -177,6 +173,7 @@ export function bootSiteClient(
}
} catch (e) {
logger.error(e);
+ logErrorEvent('boot');
dispatch(setActiveSiteError('site-boot-failed'));
dispatch(setActiveModal(modalSlugs.ERROR_REPORT));
return;
diff --git a/packages/playground/website/src/lib/tracking.ts b/packages/playground/website/src/lib/tracking.ts
index 1dbc0b85a0..1cf36f84f8 100644
--- a/packages/playground/website/src/lib/tracking.ts
+++ b/packages/playground/website/src/lib/tracking.ts
@@ -1,23 +1,94 @@
+import { StepDefinition } from '@wp-playground/blueprints';
+
/**
* Declare the global window.gtag function
*/
declare global {
- interface Window { gtag: any; }
+ interface Window {
+ gtag: any;
+ }
}
/**
* Google Analytics event names
*/
-type GAEvent = 'load' | 'step';
+type GAEvent = 'load' | 'step' | 'install' | 'error';
/**
* Log a tracking event to Google Analytics
* @param GAEvent The event name
* @param Object Event data
*/
-export const logTrackingEvent = (event: GAEvent, data?: {[key: string]: string}) => {
- if (typeof window === 'undefined' || !window.gtag) {
- return;
- }
- window.gtag('event', event, data);
-}
+export const logTrackingEvent = (
+ event: GAEvent,
+ data?: { [key: string]: string }
+) => {
+ if (typeof window === 'undefined' || !window.gtag) {
+ return;
+ }
+ window.gtag('event', event, data);
+};
+
+/**
+ * Log Plugin install events
+ * @param step The Blueprint step
+ */
+export const logPluginInstallEvent = (step: StepDefinition) => {
+ const pluginData = (step as any).pluginData;
+ if (pluginData.slug) {
+ logTrackingEvent('install', {
+ plugin: pluginData.slug,
+ });
+ } else if (pluginData.url) {
+ logTrackingEvent('install', {
+ plugin: pluginData.url,
+ });
+ }
+};
+
+/**
+ * Log Theme install events
+ * @param step The Blueprint step
+ */
+export const logThemeInstallEvent = (step: StepDefinition) => {
+ const themeData = (step as any).themeData;
+ if (themeData.slug) {
+ logTrackingEvent('install', {
+ theme: themeData.slug,
+ });
+ } else if (themeData.url) {
+ logTrackingEvent('install', {
+ theme: themeData.url,
+ });
+ }
+};
+
+/**
+ * Log Blueprint step events
+ * @param step The Blueprint step
+ */
+export const logBlueprintStepEvent = (step: StepDefinition) => {
+ /**
+ * Log the names of provided Blueprint's steps.
+ * Only the names (e.g. "runPhp" or "login") are logged. Step options like
+ * code, password, URLs are never sent anywhere.
+ */
+ logTrackingEvent('step', { step: step.step });
+
+ if (step.step === 'installPlugin') {
+ logPluginInstallEvent(step);
+ } else if (step.step === 'installTheme') {
+ logThemeInstallEvent(step);
+ }
+};
+
+/**
+ * Log error events
+ *
+ * @param error The error
+ */
+export const logErrorEvent = (source: string) => {
+ logTrackingEvent('error', {
+ source,
+ });
+};