gtag_tracking_inst = new Fiftyonedegrees_Tracking_Gtag();
}
/**
* Authenticate with Google Analytics.
* @param string $key_google_token Access Code
* @return boolean true for successful authentication.
*/
public function google_analytics_authenticate($key_google_token) {
try {
update_option(Options::GA_AUTH_CODE, $key_google_token);
$client = $this->authenticate();
if ($client) {
$service = $this->get_google_analytics_service( $client );
$this->get_analytics_properties_list($service);
return true;
}
else {
error_log("Could not authenticate with the user.");
}
}
catch (Exception $e) {
error_log($e->getMessage());
}
return false;
}
/**
* Authenticates with backend PHP server using Google Client.
* @return boolean status flag
*/
public function authenticate() {
$client = new Google_Client();
$client->setApprovalPrompt(FIFTYONEDEGREES_PROMPT);
$client->setAccessType(FIFTYONEDEGREES_ACCESS_TYPE);
$client->setClientId(FIFTYONEDEGREES_CLIENT_ID);
$client->setClientSecret(FIFTYONEDEGREES_CLIENT_SECRET);
$client->setRedirectUri(FIFTYONEDEGREES_REDIRECT);
$client->setScopes(Google_Service_Analytics::ANALYTICS_READONLY);
$ga_google_authtoken = get_option(Options::GA_TOKEN);
if (!empty($ga_google_authtoken)) {
$client->setAccessToken($ga_google_authtoken);
}
else {
$auth_code = get_option(Options::GA_AUTH_CODE);
if (empty($auth_code)) {
update_option(
Options::GA_ERROR,
"Please enter Access Code to authenticate.");
return false;
}
try {
$access_token = $client->authenticate($auth_code);
if (isset($access_token["error_description"])) {
update_option(
Options::GA_ERROR,
"Authentication request has returned " .
$access_token["error_description"] . "");
}
else if (isset($access_token["scope"]) &&
strpos(
$access_token["scope"],
Google_Service_Analytics::ANALYTICS_READONLY) === false) {
update_option(
Options::GA_ERROR,
'Please ensure you tick the See and download your ' .
'Google Analytics data box when logging into ' .
'Google Analytics.');
return false;
}
else if (isset($access_token["scope"]) &&
strpos(
$access_token["scope"],
Google_Service_Analytics::ANALYTICS_EDIT) === false) {
update_option(
Options::GA_ERROR,
'Please ensure you tick the Edit Google Analytics ' .
'management entities box when logging into ' .
'Google Analytics.');
return false;
}
}
catch (Analytify_Google_Auth_Exception $e) {
update_option(
Options::GA_ERROR,
"Authentication request has returned an error. " .
"Please enter valid Access Code.");
error_log($e->getMessage());
return false;
}
catch (Exception $e) {
update_option(
Options::GA_ERROR,
"Authentication request has returned an error. " .
"Please enter valid Access Code.");
error_log($e->getMessage());
return false;
}
if ($access_token) {
$client->setAccessToken($access_token);
update_option(Options::GA_TOKEN, $access_token);
update_option(
Options::GA_AUTH_DATE,
date( 'l jS F Y h:i:s A' ) . date_default_timezone_get());
}
else {
return false;
}
}
return $client;
}
/**
* Retrieves Google Analytics Object
* @param Google_Client $client
* @return Google_Service_Analytics service service object
*/
public function get_google_analytics_service ($client) {
try {
// Create an authorized analytics service object.
$service = new Google_Service_Analytics($client);
}
catch (Google_Service_Exception $e) {
error_log($e->getMessage());
}
catch (Exception $e) {
error_log($e->getMessage());
}
return $service;
}
/**
* Retrieves web properties list for the authorized user.
* @param Google_Service_Analytics $analytics_service
* @return array properties list
*/
public function get_analytics_properties_list($analytics_service) {
if (!get_option(Options::GA_TOKEN)) {
echo "You must authenticate to access your Analytics Account.";
return;
}
try {
// Get the list of accounts for the authorized user.
$properties = $analytics_service->management_webproperties->listManagementWebproperties('~all');
$propertiesList = array();
if (count($properties->getItems()) > 0) {
foreach ($properties->getItems() as $property) {
$propertyId = $property->getId();
$propertyName = $property->getName();
$property = array();
$property["id"] = $propertyId;
$property["name"] = $propertyName . " (" . $propertyId . ") ";
array_push($propertiesList, $property);
}
}
else {
echo 'No Properties found for this user.';
return;
}
}
catch (Exception $e) {
error_log($e->getMessage());
}
update_option(Options::GA_PROPERTIES , $propertiesList);
return $propertiesList;
}
/**
* Retrieves account id for the web property being used.
* @param Google_Service_Analytics $analytics_service
* @param string $trackingId
* @return string accountId
*/
public function get_account_id($analytics_service, $trackingId) {
if (!empty($trackingId)) {
try {
// Get the list of accounts and web properties.
$accounts = $analytics_service->management_accountSummaries->listManagementAccountSummaries();
foreach ($accounts->getItems() as $account) {
$accountId = $account->getId();
foreach ($account->getWebProperties() as $property) {
if ($property->getId() === $trackingId) {
return $accountId;
}
}
}
}
catch (apiServiceException $e) {
error_log('There was an Analytics API service error ' .
$e->getCode() . ':' . $e->getMessage());
return "";
}
catch (apiException $e) {
error_log('There was a general API error ' .
$e->getCode() . ':' . $e->getMessage());
return "";
}
}
return "";
}
/**
* Retrieves custom dimensions for the authorized user.
*
* @return array array containing custom dimensions list
* and max available custom dimension index
*/
public function get_custom_dimensions() {
$trackingId = get_option(Options::GA_TRACKING_ID);
$maxCustomDimIndex = get_option(Options::GA_MAX_DIMENSIONS);
$client = $this->authenticate();
if ($client) {
$service = $this->get_google_analytics_service($client);
// Get accountId from tracking Id
$accountId = $this->get_account_id($service, $trackingId);
update_option(Options::GA_ACCOUNT_ID, $accountId);
// Get the list of custom dimensions for the web property.
$customDimensions = $service->management_customDimensions->listManagementCustomDimensions($accountId, $trackingId);
// Create a map with custom dimensions name and indices.
$custom_dimensions_map = array();
foreach ($customDimensions->getItems() as $customDimension) {
$customDimensionName = $customDimension->getName();
$customDimensionIndex = $customDimension->getIndex();
$custom_dimensions_map[$customDimensionName] = $customDimensionIndex;
}
// Get Maximum Custom Dimension Index
$maxCustomDimIndex = count($customDimensions->getItems());
update_option(Options::GA_MAX_DIMENSIONS, $maxCustomDimIndex);
}
else {
error_log("User is not authenticated.");
}
return array(
"cust_dims_map" => $custom_dimensions_map,
"max_cust_dim_index" => $maxCustomDimIndex );
}
/**
* Inserts Custom Dimension into analytics account.
*
* @return int number of new custom dimensions inserted.
*/
public function insert_custom_dimensions() {
$calls = 0;
$accountId = get_option(Options::GA_ACCOUNT_ID);
$trackingId = get_option(Options::GA_TRACKING_ID);
$cust_dim_map = get_option(Options::GA_CUSTOM_DIMENSIONS_MAP);
$client = $this->authenticate();
if ($client) {
$service = $this->get_google_analytics_service($client);
foreach ($cust_dim_map as $dimension) {
$custDimName = $dimension["custom_dimension_name"];
$custDimGAIndex = $dimension["custom_dimension_ga_index"];
$custDimIndex = $dimension["custom_dimension_index"];
if ($custDimGAIndex === -1) {
$customDimension = new CustomDimension();
$customDimension->setName($custDimName);
$customDimension->setIndex($custDimIndex);
$customDimension->setScope(FIFTYONEDEGREES_CUSTOM_DIMENSION_SCOPE);
$customDimension->setActive(true);
try {
// Insert Custom Dimension in Google Analytics
$result = $service->management_customDimensions->insert($accountId, $trackingId, $customDimension);
$calls = $calls + 1;
}
catch (Exception $e) {
$jsonError = json_decode($e->getMessage(), $assoc = true);
$message = "Could not insert Custom Dimensions in Google " .
"Analytics account.";
if (strpos($e->getMessage(), "maximum allowed entities")
!== false) {
$message = $message . " Your Analytics account " .
"allows a maximum of " .
$this->get_custom_dimensions()['max_cust_dim_index'] .
" Custom Dimensions.";
}
update_option(
Options::GA_ERROR,
$message . " Error message from Google was: '" .
$jsonError["error"]["message"] . "'");
error_log($e->getMessage());
return -1;
}
}
}
}
else {
error_log("User is not authenticated.");
return -1;
}
return $calls;
}
/**
* Setup action hooks for the plugin. These hooks are handled
* by wordpress.
*
* See available actions:
* https://codex.wordpress.org/Plugin_API/Action_Reference
*
* @access private
* @since 1.0.11
* @return void
*/
public function setup_wp_actions() {
add_action(
'admin_init',
array($this, 'fiftyonedegrees_ga_authentication'));
add_action(
'admin_init',
array($this, 'fiftyonedegrees_ga_logout'));
add_action(
'admin_init',
array($this, 'fiftyonedegrees_ga_set_tracking_id'));
add_action(
'admin_init',
array($this, 'fiftyonedegrees_ga_update_cd_indices'));
add_action(
'admin_init',
array($this, 'fiftyonedegrees_ga_change_screen'));
add_action(
'admin_init',
array($this, 'fiftyonedegrees_ga_enable_tracking'));
// Head actions. These are actions to run before generating an HTML
// head section.
add_action(
'wp_head',
array($this, 'fiftyonedegrees_ga_add_analytics_code'),
10);
}
/**
* Construct a list of Google Analytics custom dimensions and store in
* an option.
*
* This is called either when GA is enabled, or when the custom dimensions
* are updated.
*
* @param array $cachedPipeline 51Degrees pipeline
* @return void
*/
function populate_selected_dimensions($cachedPipeline) {
if (!isset($cachedPipeline['error'])) {
$passed_dimensions = array();
foreach ($_POST as $key=>$dimension) {
if (strpos($key, "51D_") !== false) {
$key = sanitize_text_field(wp_unslash(
str_replace("51D_","", $key)));
$passed_dimensions[$key] =
sanitize_text_field(wp_unslash($dimension));
}
}
update_option(
Options::GA_DIMENSIONS,
$passed_dimensions);
update_option(
Options::GA_DIMENSIONS_UPDATED,
true);
}
}
/**
* If a POST has been made with new Google Analytics custom dimensions,
* then update them within the plugin.
*
* @return void
*/
function fiftyonedegrees_ga_update_cd_indices() {
if (isset($_POST["fiftyonedegrees_ga_update_cd_indices"])) {
if ("Update Custom Dimension Mappings" ===
$_POST["fiftyonedegrees_ga_update_cd_indices"]) {
$this->populate_selected_dimensions(
get_option(Options::PIPELINE));
}
wp_redirect(get_admin_url() .
'options-general.php?page=51Degrees&tab=google-analytics');
}
}
/**
* Add Google Analytics JavaScript to the page.
*
* @return void
*/
function fiftyonedegrees_ga_add_analytics_code() {
echo sprintf(
esc_html('%1$s'),
get_option(Options::GA_JS));
}
/**
* If a POST has been made to enable/disable Google Analytics,
* then enable it and update the custom dimensions within the plugin.
*
* @return void
*/
function fiftyonedegrees_ga_enable_tracking() {
if (isset($_POST[Options::ENABLE_GA])) {
if ("Enable Google Analytics Tracking" ===
$_POST[Options::ENABLE_GA]) {
$cachedPipeline =
get_option(Options::PIPELINE);
$this->populate_selected_dimensions($cachedPipeline);
if (!isset($cachedPipeline['error'])) {
$this->execute_ga_tracking_steps();
}
}
else {
delete_option(Options::GA_JS);
delete_option(Options::ENABLE_GA);
}
delete_option(Options::RESOURCE_KEY_UPDATED);
delete_option(Options::GA_ID_UPDATED);
delete_option(Options::GA_SEND_PAGE_VIEW_UPDATED);
delete_option(Options::GA_DIMENSIONS_UPDATED);
wp_redirect(get_admin_url() .
'options-general.php?page=51Degrees&tab=google-analytics');
}
}
/**
* Sets up the options needed to add custom dimentions to Google Analytics.
*
* @return void
*/
function execute_ga_tracking_steps() {
//Prepare Custom Dimensions
$customDimensionsTable = new Fiftyonedegrees_Custom_Dimensions();
$customDimensionsTable->prepare_items();
// Get Google analytics Tracking Javascript to be added to the
// header.
$gtag_code = $this->gtag_tracking_inst->output_ga_tracking_code();
update_option(Options::GA_JS, $gtag_code);
// Insert Custom Dimensions in Google Analytics
$added = $this->insert_custom_dimensions();
// Mark tracking is enabled.
if ($added >= 0) {
update_option(Options::ENABLE_GA, "enabled");
}
}
/**
* Run if a POST is recieved to update Google Analytics options.
*
* @return void
*/
function fiftyonedegrees_ga_change_screen() {
if (isset($_POST["fiftyonedegrees_ga_change_settings"])) {
delete_option(Options::GA_CUSTOM_DIMENSIONS_SCREEN);
wp_redirect(get_admin_url() .
'options-general.php?page=51Degrees&tab=google-analytics' );
}
}
/**
* If a change is made to the Google Analytics token, then update all
* the relevant options.
*
* @return void
*/
function fiftyonedegrees_ga_set_tracking_id() {
if (get_option(Options::GA_TOKEN)) {
if (isset($_POST['submit']) &&
"Save Changes" === $_POST['submit']) {
delete_option(Options::GA_TRACKING_ID_ERROR);
update_option(Options::GA_CUSTOM_DIMENSIONS_SCREEN, "enabled");
if (isset($_POST[Options::GA_TRACKING_ID]) &&
"Select Analytics Property" ===
$_POST[Options::GA_TRACKING_ID]) {
update_option(Options::GA_TRACKING_ID_ERROR, true);
delete_option(Options::GA_CUSTOM_DIMENSIONS_SCREEN);
}
else if (isset($_POST[Options::GA_TRACKING_ID])) {
$ga_tracking_id = sanitize_text_field(wp_unslash(
$_POST[Options::GA_TRACKING_ID]));
update_option(
Options::GA_TRACKING_ID,
$ga_tracking_id);
if (isset($_POST[Options::GA_SEND_PAGE_VIEW]) &&
"on" === $_POST[Options::GA_SEND_PAGE_VIEW]) {
update_option(
Options::GA_SEND_PAGE_VIEW,
'true');
update_option(Options::GA_SEND_PAGE_VIEW_VAL, "On");
}
else {
delete_option(Options::GA_SEND_PAGE_VIEW);
update_option(Options::GA_SEND_PAGE_VIEW_VAL, "Off");
}
}
wp_redirect(get_admin_url() .
'options-general.php?page=51Degrees&tab=google-analytics' );
}
}
}
/**
* If a new Google Analytics token is set in the admin interface, then
* authenticate it in the Google Analytics service. This will then set
* the GA_TOKEN option.
*
* @return void
*/
function fiftyonedegrees_ga_authentication() {
if (isset($_POST["fiftyonedegrees_ga_code"]) &&
isset($_POST['submit'])) {
$key_google_token = sanitize_text_field(wp_unslash(
$_POST["fiftyonedegrees_ga_code"]));
$this->google_analytics_authenticate(
$key_google_token);
delete_option(Options::GA_TRACKING_ID_ERROR);
wp_redirect(get_admin_url() .
'options-general.php?page=51Degrees&tab=google-analytics' );
if (defined('ABSPATH')) { exit; }
}
}
/**
* If logout from Google Analytics is requested in the admin interface,
* then remove all existing options relating to Google Analytics.
*
* @return void
*/
function fiftyonedegrees_ga_logout() {
if (isset($_POST['ga_log_out'])) {
$this->delete_ga_options();
wp_redirect(get_admin_url() .
'options-general.php?page=51Degrees&tab=google-analytics' );
}
}
/**
* Delete all the options relating to Google Analytics. This will disable
* the Google Analytics feature.
*/
function delete_ga_options() {
delete_option(Options::GA_AUTH_CODE);
delete_option(Options::GA_TOKEN);
delete_option(Options::GA_PROPERTIES);
delete_option(Options::GA_TRACKING_ID);
delete_option(Options::GA_ACCOUNT_ID);
delete_option(Options::GA_MAX_DIMENSIONS);
delete_option(Options::GA_SEND_PAGE_VIEW);
delete_option(Options::GA_JS);
delete_option(Options::ENABLE_GA);
delete_option(Options::GA_ERROR);
delete_option(Options::RESOURCE_KEY_UPDATED);
delete_option(Options::GA_DIMENSIONS);
delete_option(Options::GA_DIMENSIONS_UPDATED);
delete_option(Options::GA_ID_UPDATED);
delete_option(Options::GA_SEND_PAGE_VIEW_UPDATED);
delete_option(Options::GA_TRACKING_ID_ERROR);
delete_option(Options::GA_CUSTOM_DIMENSIONS_SCREEN);
}
}