Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google Analytics: extract API into the package #37358

Merged
merged 18 commits into from
Jun 19, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add the GA API handling moved from Jetpack.
5 changes: 3 additions & 2 deletions projects/packages/google-analytics/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"type": "jetpack-library",
"license": "GPL-2.0-or-later",
"require": {
"php": ">=7.0"
"php": ">=7.0",
"automattic/jetpack-status": "@dev"
},
"require-dev": {
"yoast/phpunit-polyfills": "1.1.0",
Expand Down Expand Up @@ -42,7 +43,7 @@
"extra": {
"autotagger": true,
"branch-alias": {
"dev-trunk": "0.1.x-dev"
"dev-trunk": "0.2.x-dev"
},
"changelogger": {
"link-template": "https://github.com/Automattic/jetpack-google-analytics/compare/v${old}...v${new}"
Expand Down
2 changes: 1 addition & 1 deletion projects/packages/google-analytics/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@automattic/jetpack-google-analytics",
"version": "0.1.0",
"version": "0.2.0-alpha",
"description": "Set up Google Analytics without touching a line of code.",
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/google-analytics/#readme",
"bugs": {
Expand Down
192 changes: 191 additions & 1 deletion projects/packages/google-analytics/src/class-ga-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@

namespace Automattic\Jetpack\Google_Analytics;

use Automattic\Jetpack\Modules;
use WP_Error;

/**
* The Facade class of the package.
*/
class GA_Manager {

const PACKAGE_VERSION = '0.1.0';
const PACKAGE_VERSION = '0.2.0-alpha';

/**
* Jetpack_Google_Analytics singleton instance.
Expand All @@ -31,6 +34,34 @@ class GA_Manager {
*/
public static $analytics = false;

/**
* Defaults for the API version >=1.3.
*
* @var array
*/
private $api_defaults = array(
'1.3' => array(
'code' => '',
'anonymize_ip' => false,
'ec_track_purchases' => false,
'ec_track_add_to_cart' => false,
),
'1.4' => array(
'is_active' => false, // This default value will most likely be overwritten by the current status of the GA module.
'code' => '',
'anonymize_ip' => false,
'honor_dnt' => false,
'ec_track_purchases' => false,
'ec_track_add_to_cart' => false,
'enh_ec_tracking' => false,
'enh_ec_track_remove_from_cart' => false,
'enh_ec_track_prod_impression' => false,
'enh_ec_track_prod_click' => false,
'enh_ec_track_prod_detail_view' => false,
'enh_ec_track_checkout_started' => false,
),
);

/**
* This is our constructor, which is private to force the use of get_instance()
*
Expand All @@ -46,6 +77,12 @@ private function __construct() {
} else {
self::$analytics = new Legacy();
}

add_filter( 'site_settings_endpoint_get', array( $this, 'site_settings_fetch' ), 10, 2 );
add_filter( 'site_settings_endpoint_update_wga', array( $this, 'site_settings_update' ), 10, 2 );
add_filter( 'site_settings_endpoint_update_jetpack_wga', array( $this, 'site_settings_update' ) );
add_action( 'jetpack_activate_module_google-analytics', array( $this, 'set_status_from_module' ) );
add_action( 'jetpack_deactivate_module_google-analytics', array( $this, 'set_status_from_module' ) );
}

/**
Expand All @@ -59,6 +96,159 @@ public static function get_instance() {
return self::$instance;
}

/**
* Includes the GA settings into site settings during a fetch request.
*
* @phan-suppress PhanUndeclaredTypeParameter,PhanUndeclaredClassInstanceof,PhanUndeclaredClassProperty
*
* @param array $settings The fetched settings.
* @param \WPCOM_JSON_API_Site_Settings_Endpoint $api_handler The API handler object.
*
* @return array|mixed
*/
public function site_settings_fetch( $settings = array(), $api_handler = null ) {
if ( ! is_array( $settings ) || ! $api_handler instanceof \WPCOM_JSON_API_Site_Settings_Endpoint ) {
// Safeguard against something that should never happen.
return $settings;
}

$settings['wga'] = $this->get_google_analytics_settings();

if ( array_key_exists( $api_handler->min_version, $this->api_defaults ) ) {
$settings['wga'] = wp_parse_args( $settings['wga'], $this->api_defaults[ $api_handler->min_version ] );
}

return $settings;
}

/**
* Modifies the GA settings into site settings during an update request.
*
* @phan-suppress PhanUndeclaredTypeParameter,PhanUndeclaredClassInstanceof,PhanUndeclaredClassProperty
*
* @param array $value The settings to update.
* @param \WPCOM_JSON_API_Site_Settings_Endpoint $api_handler The API handler object.
*
* @return array|mixed
*/
public function site_settings_update( $value, $api_handler = null ) {
if ( ! is_array( $value ) || ! $api_handler instanceof \WPCOM_JSON_API_Site_Settings_Endpoint ) {
// This should never happen.
return $value;
}

if ( ! isset( $value['code'] ) || ! preg_match( '/^$|^(UA-\d+-\d+)|(G-[A-Z0-9]+)$/i', $value['code'] ) ) {
return new WP_Error( 'invalid_code', 'Invalid UA ID' );
}

$option_name = $this->get_google_analytics_option_name();

$wga = get_option( $option_name, array() );
$wga['code'] = $value['code'];

if ( ! array_key_exists( 'is_active', $wga ) ) {
// The `is_active` flag is missing from the settings, add a default value based on the module status.
$wga['is_active'] = ( new Modules() )->is_active( 'google-analytics', false );
}

/**
* Allow newer versions of this endpoint to filter in additional fields for Google Analytics
*
* @since Jetpack 5.4.0
* @since $$next-version$$
*
* @param array $wga Associative array of existing Google Analytics settings.
* @param array $value Associative array of new Google Analytics settings passed to the endpoint.
*/
$wga = apply_filters( 'site_settings_update_wga', $wga, $value );

if ( array_key_exists( $api_handler->min_version, $this->api_defaults ) ) {
$wga_keys = array_keys( $this->api_defaults[ $api_handler->min_version ] );
foreach ( $wga_keys as $wga_key ) {
// Skip code since it's already handled.
if ( 'code' === $wga_key ) {
continue;
}

// All our new keys are booleans, so let's coerce each key's value
// before updating the value in settings
if ( array_key_exists( $wga_key, $value ) ) {
$wga[ $wga_key ] = Utils::is_truthy( $value[ $wga_key ] );
}
}
}

$is_updated = update_option( $option_name, $wga );

$enabled_or_disabled = $wga['code'] ? 'enabled' : 'disabled';

/**
* Fires for each settings update.
*
* @since Jetpack 3.6.0
* @since $$next-version$$
*
* @param string $action_type Type of settings to track.
* @param string $val The settings value.
*/
do_action( 'jetpack_bump_stats_extras', 'google-analytics', $enabled_or_disabled );

return $is_updated ? $wga : null;
}

/**
* Update the `is_active` settings flag depending on the Google Analytics module status.
*
* @return void
*/
public function set_status_from_module() {
$option_name = $this->get_google_analytics_option_name();

$wga = get_option( $option_name, array() );
$is_active = ( new Modules() )->is_active( 'google-analytics', false );

if ( $is_active !== $wga['is_active'] ) {
$wga['is_active'] = $is_active;
}

update_option( $option_name, $wga );
}

/**
* Get the GA settings option name.
*
* @return string
*/
public function get_google_analytics_option_name() {
/**
* Filter whether the current site is a Jetpack site.
*
* @since Jetpack 3.3.0
* @since $$next-version$$
*
* @param bool $is_jetpack Is the current site a Jetpack site. Default to false.
* @param int $blog_id Blog ID.
*/
$is_jetpack = true === apply_filters( 'is_jetpack_site', false, get_current_blog_id() );
return $is_jetpack ? 'jetpack_wga' : 'wga';
}

/**
* Get GA settings.
*
* @return array
*/
public function get_google_analytics_settings() {
$settings = get_option( $this->get_google_analytics_option_name() );

// The `is_active` flag is missing from the settings, add a value based on the module status.
if ( is_array( $settings ) && ! array_key_exists( 'is_active', $settings ) ) {
$settings['is_active'] = ( new Modules() )->is_active( 'google-analytics', false );
}

return $settings;
}

/**
* Add amp-analytics tags.
*
Expand Down
32 changes: 32 additions & 0 deletions projects/packages/google-analytics/src/class-utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,36 @@ public static function is_dnt_enabled() {

return false;
}

/**
* Determine if a string is truthy. If it's not a string, which can happen with
* not well-formed data coming from Jetpack sites, we still consider it a truthy value.
*
* @since $$next-version$$
*
* @param mixed $value true, 1, "1", "t", and "true" (case insensitive) are truthy, everything else isn't.
* @return bool
*/
public static function is_truthy( $value ) {
if ( true === $value ) {
return true;
}

if ( 1 === $value ) {
return true;
}

if ( ! is_string( $value ) ) {
return false;
}

switch ( strtolower( $value ) ) {
case '1':
case 't':
case 'true':
return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Check for active modules among the unavailable ones.
20 changes: 14 additions & 6 deletions projects/packages/status/src/class-modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ class Modules {
* Check whether or not a Jetpack module is active.
*
* @param string $module The slug of a Jetpack module.
* @param bool $available_only Whether to only check among available modules.
*
* @return bool
*/
public function is_active( $module ) {
public function is_active( $module, $available_only = true ) {
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
return true;
}

return in_array( $module, self::get_active(), true );
return in_array( $module, self::get_active( $available_only ), true );
}

/**
Expand Down Expand Up @@ -184,8 +186,12 @@ public function get_file_data( $file, $headers ) {

/**
* Get a list of activated modules as an array of module slugs.
*
* @param bool $available_only Filter out the unavailable (deleted) modules.
*
* @return array
*/
public function get_active() {
public function get_active( $available_only = true ) {
$active = \Jetpack_Options::get_option( 'active_modules' );

if ( ! is_array( $active ) ) {
Expand All @@ -206,9 +212,11 @@ public function get_active() {
$active[] = 'protect';
}

// If it's not available, it shouldn't be active.
// We don't delete it from the options though, as it will be active again when a plugin gets reactivated.
$active = array_intersect( $active, $this->get_available() );
if ( $available_only ) {
// If it's not available, it shouldn't be active.
// We don't delete it from the options though, as it will be active again when a plugin gets reactivated.
$active = array_intersect( $active, $this->get_available() );
}

/**
* Allow filtering of the active modules.
Expand Down
2 changes: 1 addition & 1 deletion projects/plugins/jetpack/.phan/baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@
'json-endpoints/class.wpcom-json-api-render-endpoint.php' => ['PhanPluginSimplifyExpressionBool', 'PhanTypeMismatchArgument'],
'json-endpoints/class.wpcom-json-api-render-shortcode-endpoint.php' => ['PhanNoopNew', 'PhanTypeMismatchReturn'],
'json-endpoints/class.wpcom-json-api-sharing-buttons-endpoint.php' => ['PhanNoopNew', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanTypeMismatchArgument', 'PhanTypeMismatchReturn', 'PhanTypePossiblyInvalidDimOffset'],
'json-endpoints/class.wpcom-json-api-site-settings-endpoint.php' => ['PhanDeprecatedFunction', 'PhanNoopNew', 'PhanParamTooMany', 'PhanRedundantCondition', 'PhanRedundantConditionInLoop', 'PhanTypeMismatchArgument', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypePossiblyInvalidDimOffset'],
'json-endpoints/class.wpcom-json-api-site-settings-endpoint.php' => ['PhanDeprecatedFunction', 'PhanNoopNew', 'PhanParamTooMany', 'PhanRedundantCondition', 'PhanRedundantConditionInLoop', 'PhanTypeMismatchArgument', 'PhanTypeMismatchReturn', 'PhanTypePossiblyInvalidDimOffset'],
'json-endpoints/class.wpcom-json-api-site-settings-v1-2-endpoint.php' => ['PhanNoopNew'],
'json-endpoints/class.wpcom-json-api-site-settings-v1-3-endpoint.php' => ['PhanNoopNew'],
'json-endpoints/class.wpcom-json-api-site-settings-v1-4-endpoint.php' => ['PhanNoopNew'],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: other

Extract the Google Analytics API into the package.
5 changes: 3 additions & 2 deletions projects/plugins/jetpack/composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading