Version Description
- Completely redesigned with new features!
- Updated with the latest Google Analytics code
- No need to find your GA property ID and copy it over, just sign in with Google and choose your site
- See analytics right inside the plugin, the past 7 days vs your previous 7 days
- Shows pageviews, users, pages per session and bounce rate + top 5 traffic referrals
- Wordpress Dashboard widget for 7, 30 or 90 days graph and top site usage stats
- Disable tracking for logged in users like admins or editors for more reliable analytics
Download this release
Release Info
Developer | ShareThis |
Plugin | Google Analytics |
Version | 2.0.0 |
Comparing to | |
See all releases |
Code changes from version 1.0.7 to 2.0.0
- class/Ga_Admin.php +558 -0
- class/Ga_Autoloader.php +30 -0
- class/Ga_Frontend.php +68 -0
- class/Ga_Helper.php +399 -0
- class/Ga_Hook.php +15 -0
- class/Ga_Stats.php +701 -0
- class/Ga_View.php +39 -0
- css/bootstrap.min.css +14 -0
- css/googleanalytics.css +172 -0
- googleanalytics.php +47 -67
- js/bootstrap.min.js +11 -0
- js/googleanalytics.js +28 -0
- js/googleanalytics_dashboard.js +133 -0
- js/googleanalytics_page.js +146 -0
- lib/Ga_Lib_Api_Client.php +212 -0
- lib/Ga_Lib_Api_Request.php +112 -0
- lib/Ga_Lib_Api_Response.php +38 -0
- overwrite/ga_overwrite.php +13 -0
- readme.txt +60 -27
- screenshot-1.png +0 -0
- screenshot-2.png +0 -0
- screenshot-3.png +0 -0
- screenshot-4.png +0 -0
- screenshot-5.png +0 -0
- view/ga_accounts_selector.php +26 -0
- view/ga_code.php +16 -0
- view/ga_dashboard_widget.php +69 -0
- view/ga_notice.php +13 -0
- view/ga_oauth_notice.php +5 -0
- view/page.php +152 -0
- view/statistics.php +6 -0
- view/stats.php +119 -0
class/Ga_Admin.php
ADDED
@@ -0,0 +1,558 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_Admin {
|
4 |
+
|
5 |
+
const GA_WEB_PROPERTY_ID_OPTION_NAME = 'googleanalytics_web_property_id';
|
6 |
+
|
7 |
+
const GA_EXCLUDE_ROLES_OPTION_NAME = 'googleanalytics_exclude_roles';
|
8 |
+
|
9 |
+
const GA_SHARETHIS_TERMS_OPTION_NAME = 'googleanalytics_sharethis_terms';
|
10 |
+
|
11 |
+
const GA_HIDE_TERMS_OPTION_NAME = 'googleanalytics_hide_terms';
|
12 |
+
|
13 |
+
const GA_VERSION_OPTION_NAME = 'googleanalytics_version';
|
14 |
+
|
15 |
+
const GA_SELECTED_ACCOUNT = 'googleanalytics_selected_account';
|
16 |
+
|
17 |
+
const GA_OAUTH_AUTH_CODE_OPTION_NAME = 'googleanalytics_oauth_auth_code';
|
18 |
+
|
19 |
+
const GA_OAUTH_AUTH_TOKEN_OPTION_NAME = 'googleanalytics_oauth_auth_token';
|
20 |
+
|
21 |
+
const GA_ACCOUNT_DATA_OPTION_NAME = 'googleanalytics_account_data';
|
22 |
+
|
23 |
+
const GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME = 'googleanalytics_web_property_id_manually';
|
24 |
+
|
25 |
+
const GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME = 'googleanalytics_web_property_id_manually_value';
|
26 |
+
|
27 |
+
const MIN_WP_VERSION = '3.8';
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Instantiate API client.
|
31 |
+
*
|
32 |
+
* @return Ga_Lib_Api_Client|null
|
33 |
+
*/
|
34 |
+
public static function api_client() {
|
35 |
+
$instance = Ga_Lib_Api_Client::get_instance();
|
36 |
+
$token = Ga_Helper::get_option( self::GA_OAUTH_AUTH_TOKEN_OPTION_NAME );
|
37 |
+
try {
|
38 |
+
if ( ! empty( $token ) ) {
|
39 |
+
$token = json_decode( $token, true );
|
40 |
+
$instance->set_access_token( $token );
|
41 |
+
}
|
42 |
+
} catch ( Exception $e ) {
|
43 |
+
Ga_Helper::ga_oauth_notice( $e->getMessage() );
|
44 |
+
}
|
45 |
+
|
46 |
+
return $instance;
|
47 |
+
}
|
48 |
+
|
49 |
+
/*
|
50 |
+
* Initializes plugin's options during plugin activation process.
|
51 |
+
*/
|
52 |
+
public static function activate_googleanalytics() {
|
53 |
+
add_option( self::GA_WEB_PROPERTY_ID_OPTION_NAME, Ga_Helper::GA_DEFAULT_WEB_ID );
|
54 |
+
add_option( self::GA_EXCLUDE_ROLES_OPTION_NAME, wp_json_encode( array() ) );
|
55 |
+
add_option( self::GA_SHARETHIS_TERMS_OPTION_NAME, false );
|
56 |
+
add_option( self::GA_HIDE_TERMS_OPTION_NAME, false );
|
57 |
+
add_option( self::GA_VERSION_OPTION_NAME );
|
58 |
+
add_option( self::GA_OAUTH_AUTH_CODE_OPTION_NAME );
|
59 |
+
add_option( self::GA_OAUTH_AUTH_TOKEN_OPTION_NAME );
|
60 |
+
add_option( self::GA_ACCOUNT_DATA_OPTION_NAME );
|
61 |
+
add_option( self::GA_SELECTED_ACCOUNT );
|
62 |
+
add_option( self::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME );
|
63 |
+
add_option( self::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME );
|
64 |
+
}
|
65 |
+
|
66 |
+
/*
|
67 |
+
* Deletes plugin's options during plugin activation process.
|
68 |
+
*/
|
69 |
+
public static function deactivate_googleanalytics() {
|
70 |
+
delete_option( self::GA_WEB_PROPERTY_ID_OPTION_NAME );
|
71 |
+
delete_option( self::GA_EXCLUDE_ROLES_OPTION_NAME );
|
72 |
+
delete_option( self::GA_OAUTH_AUTH_CODE_OPTION_NAME );
|
73 |
+
delete_option( self::GA_OAUTH_AUTH_TOKEN_OPTION_NAME );
|
74 |
+
delete_option( self::GA_ACCOUNT_DATA_OPTION_NAME );
|
75 |
+
delete_option( self::GA_SELECTED_ACCOUNT );
|
76 |
+
delete_option( self::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME );
|
77 |
+
delete_option( self::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME );
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Deletes plugin's options during plugin uninstallation process.
|
82 |
+
*/
|
83 |
+
public static function uninstall_googleanalytics() {
|
84 |
+
delete_option( self::GA_SHARETHIS_TERMS_OPTION_NAME );
|
85 |
+
delete_option( self::GA_HIDE_TERMS_OPTION_NAME );
|
86 |
+
delete_option( self::GA_VERSION_OPTION_NAME );
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Do actions during plugin load.
|
91 |
+
*/
|
92 |
+
public static function loaded_googleanalytics() {
|
93 |
+
self::update_googleanalytics();
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Update hook fires when plugin is being loaded.
|
98 |
+
*/
|
99 |
+
public static function update_googleanalytics() {
|
100 |
+
|
101 |
+
$installed_version = get_option( self::GA_VERSION_OPTION_NAME, '1.0.7' );
|
102 |
+
$old_property_value = Ga_Helper::get_option( 'web_property_id' );
|
103 |
+
if ( version_compare( $installed_version, GOOGLEANALYTICS_VERSION, 'eq' ) ) {
|
104 |
+
return;
|
105 |
+
}
|
106 |
+
if ( empty( $old_property_value ) && empty( get_option( self::GA_VERSION_OPTION_NAME) ) ) {
|
107 |
+
update_option( self::GA_SHARETHIS_TERMS_OPTION_NAME, true );
|
108 |
+
}
|
109 |
+
|
110 |
+
if ( version_compare( $installed_version, GOOGLEANALYTICS_VERSION, 'lt' ) ) {
|
111 |
+
|
112 |
+
if ( ! empty( $old_property_value ) ) {
|
113 |
+
Ga_Helper::update_option( self::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME, $old_property_value );
|
114 |
+
Ga_Helper::update_option( self::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME, 1 );
|
115 |
+
delete_option( 'web_property_id' );
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
update_option( self::GA_VERSION_OPTION_NAME, GOOGLEANALYTICS_VERSION );
|
120 |
+
}
|
121 |
+
|
122 |
+
|
123 |
+
public static function preupdate_exclude_roles( $new_value, $old_value ) {
|
124 |
+
if ( !Ga_Helper::are_terms_accepted()){
|
125 |
+
return '';
|
126 |
+
}
|
127 |
+
return wp_json_encode( $new_value );
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Pre-update hook for preparing JSON structure.
|
132 |
+
*
|
133 |
+
* @param $new_value
|
134 |
+
* @param $old_value
|
135 |
+
*
|
136 |
+
* @return mixed
|
137 |
+
*/
|
138 |
+
public static function preupdate_selected_account( $new_value, $old_value ) {
|
139 |
+
$data = explode( "_", $new_value );
|
140 |
+
if ( ! empty( $data[1] ) ) {
|
141 |
+
Ga_Helper::update_option( self::GA_WEB_PROPERTY_ID_OPTION_NAME, $data[1] );
|
142 |
+
}
|
143 |
+
|
144 |
+
return wp_json_encode( $data );
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Registers plugin's settings.
|
149 |
+
*/
|
150 |
+
public static function admin_init_googleanalytics() {
|
151 |
+
register_setting( GA_NAME, self::GA_WEB_PROPERTY_ID_OPTION_NAME );
|
152 |
+
register_setting( GA_NAME, self::GA_EXCLUDE_ROLES_OPTION_NAME );
|
153 |
+
register_setting( GA_NAME, self::GA_SELECTED_ACCOUNT );
|
154 |
+
register_setting( GA_NAME, self::GA_OAUTH_AUTH_CODE_OPTION_NAME );
|
155 |
+
register_setting( GA_NAME, self::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME );
|
156 |
+
register_setting( GA_NAME, self::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME );
|
157 |
+
add_filter( 'pre_update_option_' . Ga_Admin::GA_EXCLUDE_ROLES_OPTION_NAME, 'Ga_Admin::preupdate_exclude_roles', 1, 2 );
|
158 |
+
add_filter( 'pre_update_option_' . Ga_Admin::GA_SELECTED_ACCOUNT, 'Ga_Admin::preupdate_selected_account', 1, 2 );
|
159 |
+
}
|
160 |
+
|
161 |
+
public static function admin_menu_googleanalytics() {
|
162 |
+
if ( current_user_can( 'manage_options' ) ) {
|
163 |
+
add_menu_page( 'Google Analytics', 'Google Analytics', 'manage_options', 'googleanalytics', 'Ga_Admin::statistics_page_googleanalytics', 'dashicons-chart-line', 1000 );
|
164 |
+
add_submenu_page( 'googleanalytics', 'Google Analytics', __( 'Dashboard' ), 'manage_options', 'googleanalytics', 'Ga_Admin::statistics_page_googleanalytics' );
|
165 |
+
add_submenu_page( 'googleanalytics', 'Google Analytics', __( 'Settings' ), 'manage_options', 'googleanalytics/settings', 'Ga_Admin::options_page_googleanalytics' );
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
public static function update_terms() {
|
170 |
+
if ( !empty( $_GET['accept-terms'] ) && ( 'Y' === $_GET['accept-terms'] ) ) {
|
171 |
+
update_option( self::GA_SHARETHIS_TERMS_OPTION_NAME, true );
|
172 |
+
}
|
173 |
+
}
|
174 |
+
/**
|
175 |
+
* Prepares and displays plugin's stats page.
|
176 |
+
*/
|
177 |
+
public static function statistics_page_googleanalytics() {
|
178 |
+
|
179 |
+
if ( ! Ga_Helper::is_wp_version_valid() ) {
|
180 |
+
return false;
|
181 |
+
}
|
182 |
+
self::update_terms();
|
183 |
+
$data = self::get_stats_page();
|
184 |
+
Ga_View::load( 'statistics', array(
|
185 |
+
'data' => $data
|
186 |
+
) );
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Prepares and displays plugin's settings page.
|
191 |
+
*/
|
192 |
+
public static function options_page_googleanalytics() {
|
193 |
+
|
194 |
+
if ( ! Ga_Helper::is_wp_version_valid() ) {
|
195 |
+
return false;
|
196 |
+
}
|
197 |
+
self::update_terms();
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Keeps data to be extracted as variables in the view.
|
201 |
+
*
|
202 |
+
* @var array $data
|
203 |
+
*/
|
204 |
+
$data = array();
|
205 |
+
|
206 |
+
$data[ self::GA_WEB_PROPERTY_ID_OPTION_NAME ] = get_option( self::GA_WEB_PROPERTY_ID_OPTION_NAME );
|
207 |
+
$data[ self::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME ] = get_option( self::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME );
|
208 |
+
$data[ self::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME ] = get_option( self::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME );
|
209 |
+
|
210 |
+
$roles = Ga_Helper::get_user_roles();
|
211 |
+
$saved = json_decode( get_option( self::GA_EXCLUDE_ROLES_OPTION_NAME ), true );
|
212 |
+
|
213 |
+
$tmp = array();
|
214 |
+
if ( ! empty( $roles ) ) {
|
215 |
+
foreach ( $roles as $role ) {
|
216 |
+
$role_id = Ga_Helper::prepare_role_id( $role );
|
217 |
+
$tmp[] = array(
|
218 |
+
'name' => $role,
|
219 |
+
'id' => $role_id,
|
220 |
+
'checked' => ( ! empty( $saved[ $role_id ] ) && $saved[ $role_id ] === 'on' )
|
221 |
+
);
|
222 |
+
}
|
223 |
+
}
|
224 |
+
$data['roles'] = $tmp;
|
225 |
+
|
226 |
+
if ( Ga_Helper::is_authorized() ) {
|
227 |
+
$data['ga_accounts_selector'] = self::get_accounts_selector();
|
228 |
+
} else {
|
229 |
+
$data['popup_url'] = self::get_auth_popup_url();
|
230 |
+
}
|
231 |
+
|
232 |
+
Ga_View::load( 'page', array(
|
233 |
+
'data' => $data
|
234 |
+
) );
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Prepares and returns a plugin's URL to be opened in a popup window
|
239 |
+
* during Google authentication process.
|
240 |
+
*
|
241 |
+
* @return mixed
|
242 |
+
*/
|
243 |
+
public static function get_auth_popup_url() {
|
244 |
+
return admin_url( Ga_Helper::GA_SETTINGS_PAGE_URL . '&ga_action=ga_auth' );
|
245 |
+
}
|
246 |
+
|
247 |
+
/**
|
248 |
+
* Prepares and returns Google Account's dropdown code.
|
249 |
+
*
|
250 |
+
* @return string
|
251 |
+
*/
|
252 |
+
public static function get_accounts_selector() {
|
253 |
+
$selected = Ga_Helper::get_selected_account_data();
|
254 |
+
|
255 |
+
return Ga_View::load( 'ga_accounts_selector', array(
|
256 |
+
'selector' => json_decode( get_option( self::GA_ACCOUNT_DATA_OPTION_NAME ), true ),
|
257 |
+
'selected' => $selected ? implode( "_", $selected ) : null,
|
258 |
+
'add_manually_enabled' => Ga_Helper::is_code_manually_enabled()
|
259 |
+
), true );
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Adds Bootstrap scripts.
|
264 |
+
*/
|
265 |
+
public static function enqueue_bootstrap() {
|
266 |
+
wp_register_script( GA_NAME . '-bootstrap-js', GA_PLUGIN_URL . '/js/bootstrap.min.js', array(
|
267 |
+
'jquery'
|
268 |
+
) );
|
269 |
+
wp_register_style( GA_NAME . '-bootstrap-css', GA_PLUGIN_URL . '/css/bootstrap.min.css', false, null, 'all' );
|
270 |
+
wp_enqueue_script( GA_NAME . '-bootstrap-js' );
|
271 |
+
wp_enqueue_style( GA_NAME . '-bootstrap-css' );
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Adds JS scripts for the settings page.
|
276 |
+
*/
|
277 |
+
public static function enqueue_ga_scripts() {
|
278 |
+
wp_register_script( GA_NAME . '-page-js', GA_PLUGIN_URL . '/js/' . GA_NAME . '_page.js', array(
|
279 |
+
'jquery'
|
280 |
+
) );
|
281 |
+
wp_enqueue_script( GA_NAME . '-page-js' );
|
282 |
+
}
|
283 |
+
|
284 |
+
/**
|
285 |
+
* Adds CSS plugin's scripts.
|
286 |
+
*/
|
287 |
+
public static function enqueue_ga_css() {
|
288 |
+
wp_register_style( GA_NAME . '-css', GA_PLUGIN_URL . '/css/' . GA_NAME . '.css', false, null, 'all' );
|
289 |
+
wp_enqueue_style( GA_NAME . '-css' );
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Enqueues dashboard JS scripts.
|
294 |
+
*/
|
295 |
+
private static function enqueue_dashboard_scripts() {
|
296 |
+
wp_register_script( GA_NAME . '-dashboard-js', GA_PLUGIN_URL . '/js/' . GA_NAME . '_dashboard.js', array(
|
297 |
+
'jquery'
|
298 |
+
) );
|
299 |
+
wp_enqueue_script( GA_NAME . '-dashboard-js' );
|
300 |
+
}
|
301 |
+
|
302 |
+
/**
|
303 |
+
* Enqueues plugin's JS and CSS scripts.
|
304 |
+
*/
|
305 |
+
public static function enqueue_scripts() {
|
306 |
+
if ( Ga_Helper::is_dashboard_page() || Ga_Helper::is_plugin_page() ) {
|
307 |
+
wp_register_script( GA_NAME . '-js', GA_PLUGIN_URL . '/js/' . GA_NAME . '.js', array(
|
308 |
+
'jquery'
|
309 |
+
) );
|
310 |
+
wp_enqueue_script( GA_NAME . '-js' );
|
311 |
+
|
312 |
+
wp_register_script( 'googlecharts', 'https://www.gstatic.com/charts/loader.js', null, null, false );
|
313 |
+
wp_enqueue_script( 'googlecharts' );
|
314 |
+
|
315 |
+
self::enqueue_ga_css();
|
316 |
+
}
|
317 |
+
|
318 |
+
if ( Ga_Helper::is_dashboard_page() ) {
|
319 |
+
self::enqueue_dashboard_scripts();
|
320 |
+
}
|
321 |
+
|
322 |
+
if ( Ga_Helper::is_plugin_page() ) {
|
323 |
+
self::enqueue_bootstrap();
|
324 |
+
self::enqueue_ga_scripts();
|
325 |
+
}
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Prepares plugin's statistics page and return HTML code.
|
330 |
+
*
|
331 |
+
* @return string HTML code
|
332 |
+
*/
|
333 |
+
public static function get_stats_page() {
|
334 |
+
$selected = Ga_Helper::get_selected_account_data( true );
|
335 |
+
|
336 |
+
$query_params = Ga_Stats::get_query( 'main_chart', $selected['view_id'] );
|
337 |
+
$stats_data = self::api_client()->call( 'ga_api_data', array(
|
338 |
+
|
339 |
+
$query_params
|
340 |
+
) );
|
341 |
+
|
342 |
+
$boxes_data = self::api_client()->call( 'ga_api_data', array(
|
343 |
+
|
344 |
+
Ga_Stats::get_query( 'boxes', $selected['view_id'] )
|
345 |
+
) );
|
346 |
+
$sources_data = self::api_client()->call( 'ga_api_data', array(
|
347 |
+
|
348 |
+
Ga_Stats::get_query( 'sources', $selected['view_id'] )
|
349 |
+
) );
|
350 |
+
$chart = ! empty( $stats_data ) ? Ga_Stats::get_chart( $stats_data->getData() ) : array();
|
351 |
+
$boxes = ! empty( $boxes_data ) ? Ga_Stats::get_boxes( $boxes_data->getData() ) : array();
|
352 |
+
$last_chart_date = ! empty( $chart ) ? $chart['date'] : strtotime( 'now' );
|
353 |
+
unset( $chart['date'] );
|
354 |
+
$labels = array(
|
355 |
+
'thisWeek' => date( 'M d, Y', strtotime( '-6 day', $last_chart_date ) ) . ' - ' . date( 'M d, Y', $last_chart_date ),
|
356 |
+
'lastWeek' => date( 'M d, Y', strtotime( '-13 day', $last_chart_date ) ) . ' - ' . date( 'M d, Y', strtotime( '-7 day', $last_chart_date ) )
|
357 |
+
);
|
358 |
+
$sources = ! empty( $sources_data ) ? Ga_Stats::get_sources( $sources_data->getData() ) : array();
|
359 |
+
|
360 |
+
return Ga_Helper::get_chart_page( 'stats', array(
|
361 |
+
|
362 |
+
'chart' => $chart,
|
363 |
+
'boxes' => $boxes,
|
364 |
+
'labels' => $labels,
|
365 |
+
'sources' => $sources
|
366 |
+
) );
|
367 |
+
}
|
368 |
+
|
369 |
+
/**
|
370 |
+
* Shows plugin's notice on the admin area.
|
371 |
+
*/
|
372 |
+
public static function admin_notice_googleanalytics() {
|
373 |
+
|
374 |
+
if ( ( ! get_option( self::GA_SHARETHIS_TERMS_OPTION_NAME ) && Ga_Helper::is_plugin_page() ) || ( ! get_option( self::GA_SHARETHIS_TERMS_OPTION_NAME ) && ! get_option( self::GA_HIDE_TERMS_OPTION_NAME ) ) ) {
|
375 |
+
if ( !empty( $_GET['accept-terms'] ) && ( 'Y' === $_GET['accept-terms'] ) ) {
|
376 |
+
return;
|
377 |
+
}
|
378 |
+
$url = home_url( $_SERVER['REQUEST_URI'] . '&accept-terms=Y' );
|
379 |
+
Ga_View::load( 'ga_notice', array(
|
380 |
+
|
381 |
+
'url' => $url
|
382 |
+
) );
|
383 |
+
}
|
384 |
+
|
385 |
+
if ( ! Ga_Helper::is_wp_version_valid() ) {
|
386 |
+
Ga_View::load( 'ga_oauth_notice', array(
|
387 |
+
'msg' => _( 'Google Analytics plugin requires at least WordPress version ' . self::MIN_WP_VERSION )
|
388 |
+
) );
|
389 |
+
}
|
390 |
+
}
|
391 |
+
|
392 |
+
/**
|
393 |
+
* Hides plugin's notice
|
394 |
+
*/
|
395 |
+
public static function admin_notice_hide_googleanalytics() {
|
396 |
+
update_option( self::GA_HIDE_TERMS_OPTION_NAME, true );
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* Adds GA dashboard widget only for administrators.
|
401 |
+
*/
|
402 |
+
public static function add_dashboard_device_widget() {
|
403 |
+
if ( Ga_Helper::is_administrator() ) {
|
404 |
+
wp_add_dashboard_widget( 'ga_dashboard_widget', __( 'Google Analytics Dashboard' ), 'Ga_Helper::add_ga_dashboard_widget' );
|
405 |
+
}
|
406 |
+
}
|
407 |
+
|
408 |
+
/**
|
409 |
+
* Adds plugin's actions
|
410 |
+
*/
|
411 |
+
public static function add_actions() {
|
412 |
+
add_action( 'admin_init', 'Ga_Admin::admin_init_googleanalytics' );
|
413 |
+
add_action( 'admin_menu', 'Ga_Admin::admin_menu_googleanalytics' );
|
414 |
+
add_action( 'admin_enqueue_scripts', 'Ga_Admin::enqueue_scripts' );
|
415 |
+
add_action( 'wp_dashboard_setup', 'Ga_Admin::add_dashboard_device_widget' );
|
416 |
+
add_action( 'wp_ajax_ga_ajax_data_change', 'Ga_Admin::ga_ajax_data_change' );
|
417 |
+
add_action( 'admin_notices', 'Ga_Admin::admin_notice_googleanalytics' );
|
418 |
+
|
419 |
+
if ( ! get_option( self::GA_SHARETHIS_TERMS_OPTION_NAME ) && ! get_option( self::GA_HIDE_TERMS_OPTION_NAME ) ) {
|
420 |
+
add_action( 'wp_ajax_googleanalytics_hide_terms', 'Ga_Admin::admin_notice_hide_googleanalytics' );
|
421 |
+
}
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Adds plugin's filters
|
426 |
+
*/
|
427 |
+
public static function add_filters() {
|
428 |
+
add_filter( 'plugin_action_links', 'Ga_Admin::ga_action_links', 10, 5 );
|
429 |
+
}
|
430 |
+
|
431 |
+
/**
|
432 |
+
* Adds new action links on the plugin list.
|
433 |
+
*
|
434 |
+
* @param $actions
|
435 |
+
* @param $plugin_file
|
436 |
+
*
|
437 |
+
* @return mixed
|
438 |
+
*/
|
439 |
+
public static function ga_action_links( $actions, $plugin_file ) {
|
440 |
+
|
441 |
+
if ( basename( $plugin_file ) == GA_NAME . '.php' ) {
|
442 |
+
array_unshift( $actions, '<a href="' . esc_url( get_admin_url( null, Ga_Helper::GA_SETTINGS_PAGE_URL ) ) . '">' . _( 'Settings' ) . '</a>' );
|
443 |
+
}
|
444 |
+
|
445 |
+
return $actions;
|
446 |
+
}
|
447 |
+
|
448 |
+
public static function init_oauth() {
|
449 |
+
// $code = ! empty( $_GET['code'] ) ? $_GET['code'] : null;
|
450 |
+
$code = Ga_Helper::get_option( self::GA_OAUTH_AUTH_CODE_OPTION_NAME );
|
451 |
+
|
452 |
+
if ( ! Ga_Helper::is_authorized() && $code ) {
|
453 |
+
Ga_Helper::update_option( self::GA_OAUTH_AUTH_CODE_OPTION_NAME, "" );
|
454 |
+
|
455 |
+
// Get access token
|
456 |
+
$response = self::api_client()->call( 'ga_auth_get_access_token', $code );
|
457 |
+
|
458 |
+
self::save_access_token( $response );
|
459 |
+
self::api_client()->set_access_token( $response->getData() ); // sprawdzic
|
460 |
+
|
461 |
+
// Get accounts data
|
462 |
+
$account_summaries = self::api_client()->call( 'ga_api_account_summaries' );
|
463 |
+
self::save_ga_account_summaries( $account_summaries->getData() );
|
464 |
+
|
465 |
+
wp_redirect( admin_url( Ga_Helper::GA_SETTINGS_PAGE_URL ) );
|
466 |
+
}
|
467 |
+
}
|
468 |
+
|
469 |
+
public static function handle_actions() {
|
470 |
+
$action = ! empty( $_GET['ga_action'] ) ? $_GET['ga_action'] : null;
|
471 |
+
|
472 |
+
if ( $action ) {
|
473 |
+
$class = __CLASS__;
|
474 |
+
if ( is_callable( array(
|
475 |
+
|
476 |
+
$class,
|
477 |
+
$action
|
478 |
+
) ) ) {
|
479 |
+
$class::$action();
|
480 |
+
}
|
481 |
+
}
|
482 |
+
}
|
483 |
+
|
484 |
+
public static function ga_auth() {
|
485 |
+
if ( Ga_Helper::are_terms_accepted() ) {
|
486 |
+
header( 'Location:' . self::api_client()->create_auth_url() );
|
487 |
+
} else {
|
488 |
+
wp_die( Ga_Helper::ga_oauth_notice( __( 'Please accept the terms to use this feature' ) ) );
|
489 |
+
}
|
490 |
+
}
|
491 |
+
|
492 |
+
/**
|
493 |
+
* Save access token.
|
494 |
+
*
|
495 |
+
* @param Ga_Lib_Api_Response $response
|
496 |
+
*
|
497 |
+
* @return boolean
|
498 |
+
*/
|
499 |
+
public static function save_access_token( $response ) {
|
500 |
+
$access_token = $response->getData();
|
501 |
+
$access_token['created'] = time();
|
502 |
+
|
503 |
+
return update_option( self::GA_OAUTH_AUTH_TOKEN_OPTION_NAME, wp_json_encode( $access_token ) );
|
504 |
+
}
|
505 |
+
|
506 |
+
/**
|
507 |
+
* Saves Google Analytics account data.
|
508 |
+
*
|
509 |
+
* @param $data
|
510 |
+
*
|
511 |
+
* @return array
|
512 |
+
*/
|
513 |
+
public static function save_ga_account_summaries( $data ) {
|
514 |
+
$return = array();
|
515 |
+
if ( ! empty( $data['items'] ) ) {
|
516 |
+
foreach ( $data['items'] as $item ) {
|
517 |
+
$tmp = array();
|
518 |
+
$tmp['id'] = $item['id'];
|
519 |
+
$tmp['name'] = $item['name'];
|
520 |
+
if ( is_array( $item['webProperties'] ) ) {
|
521 |
+
foreach ( $item['webProperties'] as $property ) {
|
522 |
+
$profiles = array();
|
523 |
+
if ( is_array( $property['profiles'] ) ) {
|
524 |
+
foreach ( $property['profiles'] as $profile ) {
|
525 |
+
$profiles[] = array(
|
526 |
+
|
527 |
+
'id' => $profile['id'],
|
528 |
+
'name' => $profile['name']
|
529 |
+
);
|
530 |
+
}
|
531 |
+
}
|
532 |
+
|
533 |
+
$tmp['webProperties'][] = array(
|
534 |
+
|
535 |
+
'webPropertyId' => $property['id'],
|
536 |
+
'name' => $property['name'],
|
537 |
+
'profiles' => $profiles
|
538 |
+
);
|
539 |
+
}
|
540 |
+
}
|
541 |
+
|
542 |
+
$return[] = $tmp;
|
543 |
+
}
|
544 |
+
|
545 |
+
update_option( self::GA_ACCOUNT_DATA_OPTION_NAME, wp_json_encode( $return ) );
|
546 |
+
update_option( self::GA_WEB_PROPERTY_ID_OPTION_NAME, "" );
|
547 |
+
}
|
548 |
+
|
549 |
+
return $return;
|
550 |
+
}
|
551 |
+
|
552 |
+
public static function ga_ajax_data_change() {
|
553 |
+
$date_range = ! empty( $_POST['date_range'] ) ? $_POST['date_range'] : null;
|
554 |
+
$metric = ! empty( $_POST['metric'] ) ? $_POST['metric'] : null;
|
555 |
+
echo Ga_Helper::get_ga_dashboard_widget_data_json( $date_range, $metric, false, true );
|
556 |
+
wp_die();
|
557 |
+
}
|
558 |
+
}
|
class/Ga_Autoloader.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_Autoloader {
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Registers clas loader.
|
7 |
+
*/
|
8 |
+
public static function register() {
|
9 |
+
spl_autoload_register( "Ga_Autoloader::loader" );
|
10 |
+
}
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Class loader.
|
14 |
+
*
|
15 |
+
* @param $class_name
|
16 |
+
*/
|
17 |
+
private static function loader( $class_name ) {
|
18 |
+
$file_name = GA_PLUGIN_DIR . '/class/' . $class_name . '.php';
|
19 |
+
if ( file_exists( $file_name ) ) {
|
20 |
+
require $file_name;
|
21 |
+
}
|
22 |
+
|
23 |
+
if ( preg_match( '/Ga_Lib/', $class_name ) ) {
|
24 |
+
$file_name = GA_PLUGIN_DIR . '/lib/' . $class_name . '.php';
|
25 |
+
if ( file_exists( $file_name ) ) {
|
26 |
+
require $file_name;
|
27 |
+
}
|
28 |
+
}
|
29 |
+
}
|
30 |
+
}
|
class/Ga_Frontend.php
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_Frontend {
|
4 |
+
|
5 |
+
public static function insights_googleanalytics() {
|
6 |
+
if ( is_ssl() ) {
|
7 |
+
$url = 'https://ws.sharethis.com/button/st_insights.js';
|
8 |
+
} else {
|
9 |
+
$url = 'http://w.sharethis.com/button/st_insights.js';
|
10 |
+
}
|
11 |
+
$url = add_query_arg( array(
|
12 |
+
|
13 |
+
'publisher' => '75560ae7-5c5f-483e-936f-e426496af114',
|
14 |
+
'product' => 'GA'
|
15 |
+
), $url );
|
16 |
+
wp_register_script( GA_NAME . '-sharethis', $url, null, null, false );
|
17 |
+
wp_enqueue_script( GA_NAME . '-sharethis' );
|
18 |
+
}
|
19 |
+
|
20 |
+
public static function loader_tag_googleanalytics( $tag, $handle ) {
|
21 |
+
if ( GA_NAME . '-sharethis' === $handle ) {
|
22 |
+
$tag = str_replace( '<script', '<script id=\'st_insights_js\'', $tag );
|
23 |
+
}
|
24 |
+
|
25 |
+
return $tag;
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Adds frontend actions hooks.
|
30 |
+
*/
|
31 |
+
public static function add_actions() {
|
32 |
+
if ( Ga_Helper::can_add_ga_code() ) {
|
33 |
+
add_action( 'wp_head', 'Ga_Frontend::googleanalytics' );
|
34 |
+
if ( get_option( Ga_Admin::GA_SHARETHIS_TERMS_OPTION_NAME ) && Ga_Helper::is_sharethis_included() ) {
|
35 |
+
add_action( 'wp_enqueue_scripts', 'Ga_Frontend::insights_googleanalytics' );
|
36 |
+
add_filter( 'script_loader_tag', 'Ga_Frontend::loader_tag_googleanalytics', 10, 2 );
|
37 |
+
}
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Displays Google Analytics Tracking code.
|
43 |
+
*/
|
44 |
+
public static function googleanalytics() {
|
45 |
+
$web_property_id = self::get_web_property_id();
|
46 |
+
if ( Ga_Helper::is_configured( $web_property_id ) ) {
|
47 |
+
Ga_View::load( 'ga_code', array(
|
48 |
+
'data' => array(
|
49 |
+
Ga_Admin::GA_WEB_PROPERTY_ID_OPTION_NAME => $web_property_id
|
50 |
+
)
|
51 |
+
) );
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Gets and returns Web Property Id.
|
57 |
+
*
|
58 |
+
* @return string Web Property Id
|
59 |
+
*/
|
60 |
+
private static function get_web_property_id() {
|
61 |
+
$web_property_id = get_option( Ga_Admin::GA_WEB_PROPERTY_ID_OPTION_NAME );
|
62 |
+
if ( Ga_Helper::is_code_manually_enabled() ) {
|
63 |
+
$web_property_id = get_option( Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME );
|
64 |
+
}
|
65 |
+
|
66 |
+
return $web_property_id;
|
67 |
+
}
|
68 |
+
}
|
class/Ga_Helper.php
ADDED
@@ -0,0 +1,399 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_Helper {
|
4 |
+
|
5 |
+
const ROLE_ID_PREFIX = "role-id-";
|
6 |
+
|
7 |
+
const GA_DEFAULT_WEB_ID = "UA-0000000-0";
|
8 |
+
|
9 |
+
const GA_STATISTICS_PAGE_URL = "admin.php?page=googleanalytics";
|
10 |
+
|
11 |
+
const GA_SETTINGS_PAGE_URL = "admin.php?page=googleanalytics/settings";
|
12 |
+
|
13 |
+
const DASHBOARD_PAGE_NAME = "dashboard";
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Init plugin actions.
|
17 |
+
*
|
18 |
+
*/
|
19 |
+
public static function init() {
|
20 |
+
if ( ! is_admin() ) {
|
21 |
+
Ga_Frontend::add_actions();
|
22 |
+
}
|
23 |
+
|
24 |
+
if ( is_admin() ) {
|
25 |
+
Ga_Admin::add_filters();
|
26 |
+
Ga_Admin::add_actions();
|
27 |
+
Ga_Admin::init_oauth();
|
28 |
+
Ga_Admin::handle_actions();
|
29 |
+
}
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Checks if current page is a WordPress dashboard.
|
34 |
+
* @return int
|
35 |
+
*/
|
36 |
+
public static function is_plugin_page() {
|
37 |
+
$site = get_current_screen();
|
38 |
+
|
39 |
+
return preg_match( '/' . GA_NAME . '/', $site->base );
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Checks if current page is a WordPress dashboard.
|
44 |
+
* @return number
|
45 |
+
*/
|
46 |
+
public static function is_dashboard_page() {
|
47 |
+
$site = get_current_screen();
|
48 |
+
|
49 |
+
return preg_match( '/' . self::DASHBOARD_PAGE_NAME . '/', $site->base );
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Check whether the plugin is configured.
|
54 |
+
*
|
55 |
+
* @param String $web_id
|
56 |
+
*
|
57 |
+
* @return boolean
|
58 |
+
*/
|
59 |
+
public static function is_configured( $web_id ) {
|
60 |
+
return $web_id !== self::GA_DEFAULT_WEB_ID;
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Prepare an array of current site's user roles
|
65 |
+
*
|
66 |
+
* return array
|
67 |
+
*/
|
68 |
+
public static function get_user_roles() {
|
69 |
+
global $wp_roles;
|
70 |
+
if ( ! isset( $wp_roles ) ) {
|
71 |
+
$wp_roles = new WP_Roles();
|
72 |
+
}
|
73 |
+
|
74 |
+
return $wp_roles->get_names();
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Prepare a role ID.
|
79 |
+
*
|
80 |
+
* The role ID is derived from the role's name and will be used
|
81 |
+
* in its setting name in the additional settings.
|
82 |
+
*
|
83 |
+
* @param string $role_name Role name
|
84 |
+
*
|
85 |
+
* @return string
|
86 |
+
*/
|
87 |
+
public static function prepare_role_id( $role_name ) {
|
88 |
+
return self::ROLE_ID_PREFIX . strtolower( preg_replace( '/[\W]/', '-', before_last_bar( $role_name ) ) );
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Prepares role id.
|
93 |
+
*
|
94 |
+
* @param $v
|
95 |
+
* @param $k
|
96 |
+
*/
|
97 |
+
public static function prepare_role( &$v, $k ) {
|
98 |
+
$v = self::prepare_role_id( $v );
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Checks whether user role is excluded from adding UA code.
|
103 |
+
*
|
104 |
+
* @return boolean
|
105 |
+
*/
|
106 |
+
public static function can_add_ga_code() {
|
107 |
+
$current_user = wp_get_current_user();
|
108 |
+
$user_roles = ! empty( $current_user->roles ) ? $current_user->roles : array();
|
109 |
+
$exclude_roles = json_decode( get_option( Ga_Admin::GA_EXCLUDE_ROLES_OPTION_NAME ), true );
|
110 |
+
|
111 |
+
array_walk( $user_roles, 'Ga_Helper::prepare_role' );
|
112 |
+
|
113 |
+
$return = true;
|
114 |
+
foreach ( $user_roles as $role ) {
|
115 |
+
if ( ! empty( $exclude_roles[ $role ] ) ) {
|
116 |
+
$return = false;
|
117 |
+
break;
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
return $return;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Adds ga dashboard widget HTML code for a WordPress
|
126 |
+
* Dashboard widget hook.
|
127 |
+
*/
|
128 |
+
public static function add_ga_dashboard_widget() {
|
129 |
+
echo self::get_ga_dashboard_widget();
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Generates dashboard widget HTML code.
|
134 |
+
*
|
135 |
+
* @param string $date_range Google Analytics specific date range string.
|
136 |
+
* @param boolean $text_mode
|
137 |
+
* @param boolean $ajax
|
138 |
+
*
|
139 |
+
* @return null | string HTML dashboard widget code.
|
140 |
+
*/
|
141 |
+
public static function get_ga_dashboard_widget( $date_range = null, $text_mode = false, $ajax = false ) {
|
142 |
+
if ( empty( $date_range ) ) {
|
143 |
+
$date_range = '30daysAgo';
|
144 |
+
}
|
145 |
+
|
146 |
+
// Get chart and boxes data
|
147 |
+
$data = self::get_dashboard_widget_data( $date_range );
|
148 |
+
|
149 |
+
if ( $text_mode ) {
|
150 |
+
return self::get_chart_page( 'ga_dashboard_widget' . ( $ajax ? "_ajax" : "" ), array(
|
151 |
+
'chart' => $data['chart'],
|
152 |
+
'boxes' => $data['boxes']
|
153 |
+
) );
|
154 |
+
} else {
|
155 |
+
echo self::get_chart_page( 'ga_dashboard_widget' . ( $ajax ? "_ajax" : "" ), array(
|
156 |
+
'chart' => $data['chart'],
|
157 |
+
'boxes' => $data['boxes'],
|
158 |
+
'more_details_url' => admin_url( self::GA_STATISTICS_PAGE_URL )
|
159 |
+
) );
|
160 |
+
}
|
161 |
+
|
162 |
+
return null;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Generates JSON data string for AJAX calls.
|
167 |
+
*
|
168 |
+
* @param string $date_range
|
169 |
+
* @param string $metric
|
170 |
+
* @param boolean $text_mode
|
171 |
+
* @param boolean $ajax
|
172 |
+
*
|
173 |
+
* @return string|false Returns JSON data string
|
174 |
+
*/
|
175 |
+
public static function get_ga_dashboard_widget_data_json( $date_range = null, $metric = null, $text_mode = false, $ajax = false ) {
|
176 |
+
if ( empty( $date_range ) ) {
|
177 |
+
$date_range = '30daysAgo';
|
178 |
+
}
|
179 |
+
|
180 |
+
if ( empty( $metric ) ) {
|
181 |
+
$metric = 'pageviews';
|
182 |
+
}
|
183 |
+
|
184 |
+
$data = self::get_dashboard_widget_data( $date_range, $metric );
|
185 |
+
|
186 |
+
return wp_json_encode( $data );
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Gets dashboard widget data.
|
191 |
+
*
|
192 |
+
* @param date_range
|
193 |
+
* @param metric
|
194 |
+
*
|
195 |
+
* @return array Return chart and boxes data
|
196 |
+
*/
|
197 |
+
private static function get_dashboard_widget_data( $date_range, $metric = null ) {
|
198 |
+
$selected = self::get_selected_account_data( true );
|
199 |
+
|
200 |
+
$query_params = Ga_Stats::get_query( 'main_chart', $selected['view_id'], $date_range, $metric );
|
201 |
+
$stats_data = Ga_Admin::api_client()->call( 'ga_api_data', array(
|
202 |
+
|
203 |
+
$query_params
|
204 |
+
) );
|
205 |
+
|
206 |
+
$boxes_query = Ga_Stats::get_query( 'dashboard_boxes', $selected['view_id'], $date_range );
|
207 |
+
$boxes_data = Ga_Admin::api_client()->call( 'ga_api_data', array(
|
208 |
+
|
209 |
+
$boxes_query
|
210 |
+
) );
|
211 |
+
|
212 |
+
$chart = ! empty( $stats_data ) ? Ga_Stats::get_dashboard_chart( $stats_data->getData() ) : array();
|
213 |
+
$boxes = ! empty( $boxes_data ) ? Ga_Stats::get_dashboard_boxes_data( $boxes_data->getData() ) : array();
|
214 |
+
|
215 |
+
return array(
|
216 |
+
|
217 |
+
'chart' => $chart,
|
218 |
+
'boxes' => $boxes
|
219 |
+
);
|
220 |
+
}
|
221 |
+
|
222 |
+
public static function is_account_selected() {
|
223 |
+
return self::get_selected_account_data();
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Returns HTML code of the chart page or a notice.
|
228 |
+
*
|
229 |
+
* @param chart
|
230 |
+
*
|
231 |
+
* @return string Returns HTML code
|
232 |
+
*/
|
233 |
+
public static function get_chart_page( $view, $params ) {
|
234 |
+
|
235 |
+
$message = sprintf( __( 'Statistics can only be seen after you authenticate with your Google account on the <a href="%s">Settings page</a>.' ), admin_url( self::GA_SETTINGS_PAGE_URL ) );
|
236 |
+
|
237 |
+
if ( self::is_authorized() && ! self::is_code_manually_enabled() ) {
|
238 |
+
if ( self::is_account_selected() ) {
|
239 |
+
if ( $params ) {
|
240 |
+
return Ga_View::load( $view, $params, true );
|
241 |
+
} else {
|
242 |
+
return self::ga_oauth_notice( sprintf( 'Please configure your <a href="%s">Google Analytics settings</a>.', admin_url( self::GA_SETTINGS_PAGE_URL ) ) );
|
243 |
+
}
|
244 |
+
} else {
|
245 |
+
return self::ga_oauth_notice( $message );
|
246 |
+
}
|
247 |
+
} else {
|
248 |
+
return self::ga_oauth_notice( $message );
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Checks whether users is authorized with Google.
|
254 |
+
*
|
255 |
+
* @return boolean
|
256 |
+
*/
|
257 |
+
public static function is_authorized() {
|
258 |
+
return Ga_Admin::api_client()->get_instance()->is_authorized();
|
259 |
+
}
|
260 |
+
|
261 |
+
/**
|
262 |
+
* Wrapper for WordPress method get_option
|
263 |
+
*
|
264 |
+
* @param string $name Option name
|
265 |
+
*
|
266 |
+
* @return NULL|mixed|boolean
|
267 |
+
*/
|
268 |
+
public static function get_option( $name ) {
|
269 |
+
$opt = get_option( $name );
|
270 |
+
|
271 |
+
return ! empty( $opt ) ? $opt : null;
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Wrapper for WordPress method update_option
|
276 |
+
*
|
277 |
+
* @param string $name
|
278 |
+
* @param mixed $value
|
279 |
+
*
|
280 |
+
* @return NULL|boolean
|
281 |
+
*/
|
282 |
+
public static function update_option( $name, $value ) {
|
283 |
+
$opt = update_option( $name, $value );
|
284 |
+
|
285 |
+
return ! empty( $opt ) ? $opt : null;
|
286 |
+
}
|
287 |
+
|
288 |
+
/**
|
289 |
+
* Loads ga notice HTML code with gicen message included.
|
290 |
+
*
|
291 |
+
* @param string $message
|
292 |
+
*
|
293 |
+
* @return string
|
294 |
+
*/
|
295 |
+
public static function ga_oauth_notice( $message ) {
|
296 |
+
return Ga_View::load( 'ga_oauth_notice', array(
|
297 |
+
|
298 |
+
'msg' => $message
|
299 |
+
), true );
|
300 |
+
}
|
301 |
+
|
302 |
+
/**
|
303 |
+
* Gets data according to selected GA account.
|
304 |
+
*
|
305 |
+
* @param boolean $assoc
|
306 |
+
*
|
307 |
+
* @return mixed
|
308 |
+
*/
|
309 |
+
public static function get_selected_account_data( $assoc = false ) {
|
310 |
+
$data = json_decode( self::get_option( Ga_Admin::GA_SELECTED_ACCOUNT ) );
|
311 |
+
$data = ( ! empty( $data ) && count( $data ) == 3 ) ? $data : false;
|
312 |
+
|
313 |
+
if ( $data ) {
|
314 |
+
if ( $assoc ) {
|
315 |
+
return array(
|
316 |
+
|
317 |
+
'account_id' => $data[0],
|
318 |
+
'web_property_id' => $data[1],
|
319 |
+
'view_id' => $data[2]
|
320 |
+
);
|
321 |
+
} else {
|
322 |
+
return $data;
|
323 |
+
}
|
324 |
+
}
|
325 |
+
|
326 |
+
return false;
|
327 |
+
}
|
328 |
+
|
329 |
+
/**
|
330 |
+
* Chekcs whether option for manually UA-code
|
331 |
+
* @return NULL|mixed|boolean
|
332 |
+
*/
|
333 |
+
public static function is_code_manually_enabled() {
|
334 |
+
return Ga_Helper::get_option( Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME );
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Adds percent sign to the given text.
|
339 |
+
*
|
340 |
+
* @param $text
|
341 |
+
*
|
342 |
+
* @return string
|
343 |
+
*/
|
344 |
+
public static function format_percent( $text ) {
|
345 |
+
$text = self::add_plus( $text );
|
346 |
+
return $text . '%';
|
347 |
+
}
|
348 |
+
|
349 |
+
/**
|
350 |
+
* Adds plus sign before number.
|
351 |
+
*
|
352 |
+
* @param $number
|
353 |
+
*
|
354 |
+
* @return string
|
355 |
+
*/
|
356 |
+
public static function add_plus( $number ) {
|
357 |
+
if ( $number > 0 ){
|
358 |
+
return '+' . $number;
|
359 |
+
}
|
360 |
+
return $number;
|
361 |
+
}
|
362 |
+
|
363 |
+
/**
|
364 |
+
* Check whether current user has administrator privileges.
|
365 |
+
*
|
366 |
+
* @return bool
|
367 |
+
*/
|
368 |
+
public static function is_administrator() {
|
369 |
+
if ( current_user_can( 'administrator' ) ) {
|
370 |
+
return true;
|
371 |
+
}
|
372 |
+
|
373 |
+
return false;
|
374 |
+
}
|
375 |
+
|
376 |
+
public static function is_wp_version_valid() {
|
377 |
+
$wp_version = get_bloginfo( 'version' );
|
378 |
+
|
379 |
+
return version_compare( $wp_version, Ga_Admin::MIN_WP_VERSION, 'ge' );
|
380 |
+
}
|
381 |
+
|
382 |
+
/**
|
383 |
+
* Check if terms are accepted
|
384 |
+
*
|
385 |
+
* @return bool
|
386 |
+
*/
|
387 |
+
public static function are_terms_accepted() {
|
388 |
+
return self::get_option( Ga_Admin::GA_SHARETHIS_TERMS_OPTION_NAME );
|
389 |
+
}
|
390 |
+
|
391 |
+
/**
|
392 |
+
* Check if sharethis scripts enabled
|
393 |
+
*
|
394 |
+
* @return bool
|
395 |
+
*/
|
396 |
+
public static function is_sharethis_included() {
|
397 |
+
return GA_SHARETHIS_SCRIPTS_INCLUDED;
|
398 |
+
}
|
399 |
+
}
|
class/Ga_Hook.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_Hook {
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Adds WordPress hooks.
|
7 |
+
*
|
8 |
+
* @param string $plugin_file_path
|
9 |
+
*/
|
10 |
+
public static function add_hooks( $plugin_file_path ) {
|
11 |
+
register_activation_hook( $plugin_file_path, 'Ga_Admin::activate_googleanalytics' );
|
12 |
+
register_deactivation_hook( $plugin_file_path, 'Ga_Admin::deactivate_googleanalytics' );
|
13 |
+
register_uninstall_hook( $plugin_file_path, 'Ga_Admin::uninstall_googleanalytics' );
|
14 |
+
}
|
15 |
+
}
|
class/Ga_Stats.php
ADDED
@@ -0,0 +1,701 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Ga_Stats class
|
5 |
+
*
|
6 |
+
* Preparing request and parsing response from Google Analytics Reporting Api
|
7 |
+
*
|
8 |
+
* @author wle@adips.com
|
9 |
+
* @version 1.0
|
10 |
+
*/
|
11 |
+
class Ga_Stats {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Preparing query to get Analytics data
|
15 |
+
*
|
16 |
+
* @param string $query query type
|
17 |
+
* @param int $id_view The Analytics view ID from which to retrieve data.
|
18 |
+
* @param string $date_range The start date for the query in the format YYYY-MM-DD or '7daysAgo'
|
19 |
+
* @param string $metric A metric expression
|
20 |
+
*
|
21 |
+
* @return array Request query
|
22 |
+
*/
|
23 |
+
public static function get_query( $query, $id_view, $date_range = null, $metric = null ) {
|
24 |
+
if ( $query == 'main_chart' ) {
|
25 |
+
return self::main_chart_query( $id_view, $date_range, $metric );
|
26 |
+
} elseif ( $query == 'boxes' ) {
|
27 |
+
return self::boxes_query( $id_view );
|
28 |
+
} elseif ( $query == 'dashboard_boxes' ) {
|
29 |
+
return self::dashboard_boxes_query( $id_view, $date_range );
|
30 |
+
} elseif ( $query == 'sources' ) {
|
31 |
+
return self::sources_query( $id_view );
|
32 |
+
} else {
|
33 |
+
return array();
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Preparing query for top traffic sources table
|
39 |
+
*
|
40 |
+
* @param int $id_view The Analytics view ID from which to retrieve data.
|
41 |
+
*
|
42 |
+
* @return array Sources query
|
43 |
+
*/
|
44 |
+
public static function sources_query( $id_view ) {
|
45 |
+
$reports_requests = array();
|
46 |
+
$reports_requests[] = array(
|
47 |
+
'viewId' => $id_view,
|
48 |
+
'dateRanges' => self::set_date_ranges( '7daysAgo', 'yesterday' ),
|
49 |
+
'metrics' => self::set_metrics( array( 'ga:pageviews' ) ),
|
50 |
+
'includeEmptyRows' => true,
|
51 |
+
'pageSize' => 5,
|
52 |
+
'dimensions' => self::set_dimensions( 'ga:sourceMedium' ),
|
53 |
+
'orderBys' => self::set_order_bys( 'ga:pageviews', 'DESCENDING' ),
|
54 |
+
);
|
55 |
+
$query = array(
|
56 |
+
'reportRequests' => $reports_requests
|
57 |
+
);
|
58 |
+
|
59 |
+
return $query;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Preparing query for dashbord boxes
|
64 |
+
*
|
65 |
+
* @param int $id_view The Analytics view ID from which to retrieve data.
|
66 |
+
* @param string $date_range The start date for the query in the format YYYY-MM-DD or '7daysAgo'
|
67 |
+
*
|
68 |
+
* @return array Dashboard boxes query
|
69 |
+
*/
|
70 |
+
public static function dashboard_boxes_query( $id_view, $date_range ) {
|
71 |
+
$reports_requests = array();
|
72 |
+
$reports_requests[] = array(
|
73 |
+
'viewId' => $id_view,
|
74 |
+
'dateRanges' => self::set_date_ranges( $date_range, 'yesterday' ),
|
75 |
+
'metrics' => self::set_metrics( array(
|
76 |
+
'ga:sessions',
|
77 |
+
'ga:pageviews',
|
78 |
+
'ga:pageviewsPerSession',
|
79 |
+
'ga:BounceRate',
|
80 |
+
'ga:avgTimeOnPage',
|
81 |
+
'ga:percentNewSessions',
|
82 |
+
) ),
|
83 |
+
'includeEmptyRows' => true,
|
84 |
+
'dimensions' => self::set_dimensions( 'ga:date' )
|
85 |
+
);
|
86 |
+
$query = array(
|
87 |
+
'reportRequests' => $reports_requests
|
88 |
+
);
|
89 |
+
|
90 |
+
return $query;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Preparing query for stats boxes
|
95 |
+
*
|
96 |
+
* @param int $id_view The Analytics view ID from which to retrieve data.
|
97 |
+
*
|
98 |
+
* @return array Boxes query
|
99 |
+
*/
|
100 |
+
public static function boxes_query( $id_view ) {
|
101 |
+
$reports_requests = array();
|
102 |
+
$reports_requests[] = array(
|
103 |
+
'viewId' => $id_view,
|
104 |
+
'dateRanges' => self::set_date_ranges( '7daysAgo', 'yesterday', '14daysAgo', '8daysAgo' ),
|
105 |
+
'metrics' => self::set_metrics( array(
|
106 |
+
'ga:users',
|
107 |
+
'ga:pageviews',
|
108 |
+
'ga:pageviewsPerSession',
|
109 |
+
'ga:BounceRate'
|
110 |
+
) ),
|
111 |
+
'includeEmptyRows' => true,
|
112 |
+
'dimensions' => self::set_dimensions( 'ga:date' )
|
113 |
+
);
|
114 |
+
$query = array(
|
115 |
+
'reportRequests' => $reports_requests
|
116 |
+
);
|
117 |
+
|
118 |
+
return $query;
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Preparing query for chart
|
123 |
+
*
|
124 |
+
* @param int $id_view The Analytics view ID from which to retrieve data.
|
125 |
+
* @param string $date_range The start date for the query in the format YYYY-MM-DD or '7daysAgo'
|
126 |
+
* @param string $metric A metric expression
|
127 |
+
*
|
128 |
+
* @return array Chart query
|
129 |
+
*/
|
130 |
+
public static function main_chart_query( $id_view, $date_range = null, $metric = null ) {
|
131 |
+
if ( empty( $date_range ) ) {
|
132 |
+
$date_ranges = self::set_date_ranges( '7daysAgo', 'yesterday', '14daysAgo', '8daysAgo' );
|
133 |
+
} else {
|
134 |
+
$date_ranges = self::set_date_ranges( $date_range, 'yesterday' );
|
135 |
+
}
|
136 |
+
|
137 |
+
if ( empty( $metric ) ) {
|
138 |
+
$metric = 'ga:pageviews';
|
139 |
+
} else {
|
140 |
+
$metric = 'ga:' . $metric;
|
141 |
+
}
|
142 |
+
|
143 |
+
$reports_requests = array();
|
144 |
+
$reports_requests[] = array(
|
145 |
+
'viewId' => $id_view,
|
146 |
+
'dateRanges' => $date_ranges,
|
147 |
+
'metrics' => self::set_metrics( $metric ),
|
148 |
+
'includeEmptyRows' => true,
|
149 |
+
'dimensions' => self::set_dimensions( 'ga:date' )
|
150 |
+
);
|
151 |
+
$query = array(
|
152 |
+
'reportRequests' => $reports_requests
|
153 |
+
);
|
154 |
+
|
155 |
+
return $query;
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Setting order for requests
|
160 |
+
*
|
161 |
+
* @param string $name The field which to sort by. The default sort order is ascending. Example: ga:browser.
|
162 |
+
* @param string $sort The sorting order for the field. 'ASCENDING' or 'DESCENDING'
|
163 |
+
*
|
164 |
+
* @return array OrderBys
|
165 |
+
*/
|
166 |
+
public static function set_order_bys( $name, $sort ) {
|
167 |
+
$order = array();
|
168 |
+
$order[] = array(
|
169 |
+
'fieldName' => $name,
|
170 |
+
'sortOrder' => $sort,
|
171 |
+
);
|
172 |
+
|
173 |
+
return $order;
|
174 |
+
}
|
175 |
+
|
176 |
+
/**
|
177 |
+
* Setting metrics for requests
|
178 |
+
*
|
179 |
+
* @param mixed $expression A metric expression or array of expressions
|
180 |
+
*
|
181 |
+
* @return array Metrics
|
182 |
+
*/
|
183 |
+
public static function set_metrics( $expression ) {
|
184 |
+
$metrics = array();
|
185 |
+
if ( is_array( $expression ) ) {
|
186 |
+
foreach ( $expression as $exp ) {
|
187 |
+
$metrics[] = array(
|
188 |
+
'expression' => $exp
|
189 |
+
);
|
190 |
+
}
|
191 |
+
} else {
|
192 |
+
$metrics[] = array(
|
193 |
+
'expression' => $expression
|
194 |
+
);
|
195 |
+
}
|
196 |
+
|
197 |
+
return $metrics;
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Setting dimensions for requests
|
202 |
+
*
|
203 |
+
* @param string $name Name of the dimension to fetch, for example ga:browser.
|
204 |
+
*
|
205 |
+
* @return array Dimensions
|
206 |
+
*/
|
207 |
+
public static function set_dimensions( $name ) {
|
208 |
+
$dimensions = array();
|
209 |
+
$dimensions[] = array(
|
210 |
+
'name' => $name
|
211 |
+
);
|
212 |
+
|
213 |
+
return $dimensions;
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Setting date ranges for requests
|
218 |
+
*
|
219 |
+
* @param string $start_date The start date for the query in the format YYYY-MM-DD.
|
220 |
+
* @param string $end_date The end date for the query in the format YYYY-MM-DD.
|
221 |
+
* @param string $prev_start_date The start date (second range) for the query in the format YYYY-MM-DD.
|
222 |
+
* @param string $prev_end_date The start date (second range) for the query in the format YYYY-MM-DD.
|
223 |
+
*
|
224 |
+
* @return array Date ranges
|
225 |
+
*/
|
226 |
+
public static function set_date_ranges( $start_date, $end_date, $prev_start_date = '', $prev_end_date = '' ) {
|
227 |
+
$date_danges = array();
|
228 |
+
$date_danges[] = array(
|
229 |
+
'startDate' => $start_date,
|
230 |
+
'endDate' => $end_date
|
231 |
+
);
|
232 |
+
if ( ! empty( $prev_start_date ) and ! empty( $prev_end_date ) ) {
|
233 |
+
$date_danges[] = array(
|
234 |
+
'startDate' => $prev_start_date,
|
235 |
+
'endDate' => $prev_end_date
|
236 |
+
);
|
237 |
+
}
|
238 |
+
|
239 |
+
return $date_danges;
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* Preparing response for data received from analytics
|
244 |
+
*
|
245 |
+
* @param array $data Analytics response
|
246 |
+
*
|
247 |
+
* @return array Response rows
|
248 |
+
*/
|
249 |
+
public static function prepare_response( $data ) {
|
250 |
+
$data = self::get_reports_from_response( $data );
|
251 |
+
self::handle_more_reports( $data );
|
252 |
+
$report = self::get_single_report( $data );
|
253 |
+
self::get_report_column_header( $report );
|
254 |
+
$report_data = self::get_report_data( $report );
|
255 |
+
self::get_totals( $report_data );
|
256 |
+
self::get_row_count( $report_data );
|
257 |
+
$rows = self::get_rows( $report_data );
|
258 |
+
|
259 |
+
return $rows;
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Get dimensions from response row
|
264 |
+
*
|
265 |
+
* @param array $row Analytics response row
|
266 |
+
*
|
267 |
+
* @return array Dimensions
|
268 |
+
*/
|
269 |
+
public static function get_dimensions( $row ) {
|
270 |
+
if ( ! empty( $row['dimensions'] ) ) {
|
271 |
+
return $row['dimensions'];
|
272 |
+
}
|
273 |
+
|
274 |
+
return false;
|
275 |
+
}
|
276 |
+
|
277 |
+
/**
|
278 |
+
* Get metrics from response row
|
279 |
+
*
|
280 |
+
* @param array $row Analytics response row
|
281 |
+
*
|
282 |
+
* @return array Metrics
|
283 |
+
*/
|
284 |
+
public static function get_metrics( $row ) {
|
285 |
+
if ( ! empty( $row['metrics'] ) ) {
|
286 |
+
return $row['metrics'];
|
287 |
+
}
|
288 |
+
|
289 |
+
return false;
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* Get row from response report data
|
294 |
+
*
|
295 |
+
* @param array $report_data Analytics response report data
|
296 |
+
*
|
297 |
+
* @return array Rows
|
298 |
+
*/
|
299 |
+
public static function get_rows( $report_data ) {
|
300 |
+
if ( ! empty( $report_data['rows'] ) ) {
|
301 |
+
return $report_data['rows'];
|
302 |
+
}
|
303 |
+
|
304 |
+
return false;
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Get row count from response report data
|
309 |
+
*
|
310 |
+
* @param array $report_data Analytics response report data
|
311 |
+
*
|
312 |
+
* @return array Row count
|
313 |
+
*/
|
314 |
+
public static function get_row_count( $report_data ) {
|
315 |
+
if ( ! empty( $report_data['rowCount'] ) ) {
|
316 |
+
return $report_data['rowCount'];
|
317 |
+
}
|
318 |
+
|
319 |
+
return false;
|
320 |
+
}
|
321 |
+
|
322 |
+
/**
|
323 |
+
* Get totals from response report data
|
324 |
+
*
|
325 |
+
* @param array $report_data Analytics response report data
|
326 |
+
*
|
327 |
+
* @return array Totals
|
328 |
+
*/
|
329 |
+
public static function get_totals( $report_data ) {
|
330 |
+
if ( ! empty( $report_data['totals'] ) ) {
|
331 |
+
return $report_data['totals'];
|
332 |
+
}
|
333 |
+
|
334 |
+
return false;
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Get reports from response data
|
339 |
+
*
|
340 |
+
* @param array $data Analytics response data
|
341 |
+
*
|
342 |
+
* @return array Reports
|
343 |
+
*/
|
344 |
+
public static function get_reports_from_response( $data ) {
|
345 |
+
if ( ! empty( $data['reports'] ) ) {
|
346 |
+
return $data['reports'];
|
347 |
+
}
|
348 |
+
|
349 |
+
return false;
|
350 |
+
}
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Show info for multiple data
|
354 |
+
*
|
355 |
+
* @param array $data Analytics response data
|
356 |
+
*
|
357 |
+
*/
|
358 |
+
public static function handle_more_reports( $data ) {
|
359 |
+
if ( count( $data ) > 1 ) {
|
360 |
+
echo 'more than one report';
|
361 |
+
}
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Show info for multiple rows
|
366 |
+
*
|
367 |
+
* @param array $rows Analytics response rows
|
368 |
+
*
|
369 |
+
*/
|
370 |
+
public static function handle_more_rows( $rows ) {
|
371 |
+
if ( count( $rows ) > 1 ) {
|
372 |
+
echo 'more than one row';
|
373 |
+
}
|
374 |
+
}
|
375 |
+
|
376 |
+
/**
|
377 |
+
* Get single report from response data
|
378 |
+
*
|
379 |
+
* @param array $data Analytics response data
|
380 |
+
*
|
381 |
+
* @return array Report
|
382 |
+
*/
|
383 |
+
public static function get_single_report( $data ) {
|
384 |
+
if ( ! empty( $data ) ) {
|
385 |
+
foreach ( $data as $report ) {
|
386 |
+
if ( ! empty( $report ) ) {
|
387 |
+
return $report;
|
388 |
+
}
|
389 |
+
}
|
390 |
+
}
|
391 |
+
|
392 |
+
return false;
|
393 |
+
}
|
394 |
+
|
395 |
+
/**
|
396 |
+
* Get single row from response data rows
|
397 |
+
*
|
398 |
+
* @param array $rows Analytics response data rows
|
399 |
+
*
|
400 |
+
* @return array Row
|
401 |
+
*/
|
402 |
+
public static function get_single_row( $rows ) {
|
403 |
+
if ( ! empty( $rows ) ) {
|
404 |
+
foreach ( $rows as $row ) {
|
405 |
+
if ( ! empty( $row ) ) {
|
406 |
+
return $row;
|
407 |
+
}
|
408 |
+
}
|
409 |
+
}
|
410 |
+
|
411 |
+
return false;
|
412 |
+
}
|
413 |
+
|
414 |
+
/**
|
415 |
+
* Get column header from response data
|
416 |
+
*
|
417 |
+
* @param array $data Analytics response data
|
418 |
+
*
|
419 |
+
* @return array Column header
|
420 |
+
*/
|
421 |
+
public static function get_report_column_header( $data ) {
|
422 |
+
if ( ! empty( $data['columnHeader'] ) ) {
|
423 |
+
return $data['columnHeader'];
|
424 |
+
}
|
425 |
+
|
426 |
+
return false;
|
427 |
+
}
|
428 |
+
|
429 |
+
/**
|
430 |
+
* Get report data from response data
|
431 |
+
*
|
432 |
+
* @param array $data Analytics response data
|
433 |
+
*
|
434 |
+
* @return array data
|
435 |
+
*/
|
436 |
+
public static function get_report_data( $data ) {
|
437 |
+
if ( ! empty( $data['data'] ) ) {
|
438 |
+
return $data['data'];
|
439 |
+
}
|
440 |
+
|
441 |
+
return false;
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* Get chart from response data
|
446 |
+
*
|
447 |
+
* @param array $data Analytics response data
|
448 |
+
*
|
449 |
+
* @return array chart data
|
450 |
+
*/
|
451 |
+
public static function get_chart( $data ) {
|
452 |
+
$chart_data = array();
|
453 |
+
if ( ! empty( $data ) ) {
|
454 |
+
$data = $data['reports'][0]['data'];
|
455 |
+
$rows = $data['rows'];
|
456 |
+
if ( ! empty( $rows ) ) {
|
457 |
+
foreach ( $rows as $key => $row ) {
|
458 |
+
if ( $key < 7 ) {
|
459 |
+
$chart_data[ $key ]['previous'] = ! empty( $row['metrics'][1]['values'][0] ) ? $row['metrics'][1]['values'][0] : 0;
|
460 |
+
$chart_data[ $key ]['previous-day'] = date( 'M j', strtotime( $row['dimensions'][0] ) );
|
461 |
+
} else {
|
462 |
+
$chart_data[ $key - 7 ]['day'] = date( 'M j', strtotime( $row['dimensions'][0] ) );
|
463 |
+
$chart_data[ $key - 7 ]['current'] = ! empty( $row['metrics'][0]['values'][0] ) ? $row['metrics'][0]['values'][0] : 0;
|
464 |
+
$chart_data[ 'date'] = strtotime( $row['dimensions'][0] );
|
465 |
+
}
|
466 |
+
}
|
467 |
+
}
|
468 |
+
}
|
469 |
+
|
470 |
+
return $chart_data;
|
471 |
+
}
|
472 |
+
|
473 |
+
/**
|
474 |
+
* Get dasboard chart from response data
|
475 |
+
*
|
476 |
+
* @param array $data Analytics response data
|
477 |
+
*
|
478 |
+
* @return array dashboard chart data
|
479 |
+
*/
|
480 |
+
public static function get_dashboard_chart( $data ) {
|
481 |
+
$chart_data = array();
|
482 |
+
if ( ! empty( $data ) ) {
|
483 |
+
$data = $data['reports'][0]['data'];
|
484 |
+
$rows = $data['rows'];
|
485 |
+
|
486 |
+
if ( $rows ) {
|
487 |
+
foreach ( $rows as $row ) {
|
488 |
+
$chart_data[] = array(
|
489 |
+
'day' => date( 'M j', strtotime( $row['dimensions'][0] ) ),
|
490 |
+
'current' => ! empty( $row['metrics'][0]['values'][0] ) ? $row['metrics'][0]['values'][0] : 0
|
491 |
+
);
|
492 |
+
}
|
493 |
+
}
|
494 |
+
}
|
495 |
+
|
496 |
+
return $chart_data;
|
497 |
+
}
|
498 |
+
|
499 |
+
/**
|
500 |
+
* Get boxes from response data
|
501 |
+
*
|
502 |
+
* @param array $data Analytics response data
|
503 |
+
*
|
504 |
+
* @return array boxes data
|
505 |
+
*/
|
506 |
+
public static function get_boxes( $data ) {
|
507 |
+
if ( ! empty( $data ) ) {
|
508 |
+
$data = self::get_reports_from_response( $data );
|
509 |
+
self::handle_more_reports( $data );
|
510 |
+
$report = self::get_single_report( $data );
|
511 |
+
self::get_report_column_header( $report );
|
512 |
+
$report_data = self::get_report_data( $report );
|
513 |
+
$totals = self::get_totals( $report_data );
|
514 |
+
|
515 |
+
return self::get_boxes_from_totals( $totals );
|
516 |
+
}
|
517 |
+
}
|
518 |
+
|
519 |
+
/**
|
520 |
+
* Get boxes from totals
|
521 |
+
*
|
522 |
+
* @param array $totals Analytics response totals
|
523 |
+
*
|
524 |
+
* @return array boxes data
|
525 |
+
*/
|
526 |
+
public static function get_boxes_from_totals( $totals ) {
|
527 |
+
if ( ! empty( $totals ) ) {
|
528 |
+
$boxes_data = array();
|
529 |
+
foreach ( $totals as $key => $total ) {
|
530 |
+
if ( $key == 0 ) {
|
531 |
+
$boxes_data['Users']['current'] = $total['values'][0];
|
532 |
+
$boxes_data['Pageviews']['current'] = $total['values'][1];
|
533 |
+
$boxes_data['PageviewsPerSession']['current'] = $total['values'][2];
|
534 |
+
$boxes_data['BounceRate']['current'] = round( $total['values'][3], 2 ) . '%';
|
535 |
+
} else {
|
536 |
+
$boxes_data['Users']['previous'] = $total['values'][0];
|
537 |
+
$boxes_data['Pageviews']['previous'] = $total['values'][1];
|
538 |
+
$boxes_data['PageviewsPerSession']['previous'] = $total['values'][2];
|
539 |
+
$boxes_data['BounceRate']['previous'] = round( $total['values'][3], 2 ) . '%';
|
540 |
+
}
|
541 |
+
}
|
542 |
+
|
543 |
+
return self::prepare_boxes( $boxes_data );
|
544 |
+
}
|
545 |
+
|
546 |
+
return false;
|
547 |
+
}
|
548 |
+
|
549 |
+
/**
|
550 |
+
* Prepare boxes data
|
551 |
+
*
|
552 |
+
* @param array $boxes_data Boxes data
|
553 |
+
*
|
554 |
+
* @return array boxes data
|
555 |
+
*/
|
556 |
+
public static function prepare_boxes( $boxes_data ) {
|
557 |
+
$boxes_data['Users']['diff'] = ( $boxes_data['Users']['previous'] > 0 ) ? round( ( $boxes_data['Users']['current'] - $boxes_data['Users']['previous'] ) / $boxes_data['Users']['previous'] * 100, 2 ) : 100;
|
558 |
+
$boxes_data['Pageviews']['diff'] = ( $boxes_data['Pageviews']['previous'] > 0 ) ? round( ( $boxes_data['Pageviews']['current'] - $boxes_data['Pageviews']['previous'] ) / $boxes_data['Pageviews']['previous'] * 100, 2 ) : 100;
|
559 |
+
$boxes_data['PageviewsPerSession']['diff'] = ( $boxes_data['PageviewsPerSession']['previous'] > 0 ) ? round( ( $boxes_data['PageviewsPerSession']['current'] - $boxes_data['PageviewsPerSession']['previous'] ) / $boxes_data['PageviewsPerSession']['previous'] * 100, 2 ) : 100;
|
560 |
+
$boxes_data['BounceRate']['diff'] = ( $boxes_data['BounceRate']['previous'] > 0 ) ? round( ( $boxes_data['BounceRate']['current'] - $boxes_data['BounceRate']['previous'] ) / $boxes_data['BounceRate']['previous'] * 100, 2 ) : 100;
|
561 |
+
$boxes_data['BounceRate']['diff'] = ( $boxes_data['BounceRate']['previous'] == 0 && $boxes_data['BounceRate']['current'] == 0) ? 0 : $boxes_data['BounceRate']['diff'];
|
562 |
+
$boxes_data['Users']['label'] = 'Users';
|
563 |
+
$boxes_data['Pageviews']['label'] = 'Pageviews';
|
564 |
+
$boxes_data['PageviewsPerSession']['label'] = 'Pages / Session';
|
565 |
+
$boxes_data['BounceRate']['label'] = 'Bounce Rate';
|
566 |
+
$boxes_data['Users']['comparison'] = $boxes_data['Users']['current'] . ' vs ' . $boxes_data['Users']['previous'];
|
567 |
+
$boxes_data['Pageviews']['comparison'] = $boxes_data['Pageviews']['current'] . ' vs ' . $boxes_data['Pageviews']['previous'];
|
568 |
+
$boxes_data['PageviewsPerSession']['comparison'] = self::number_format_clean( $boxes_data['PageviewsPerSession']['current'], 2, '.', ',' ) . ' vs ' . self::number_format_clean( $boxes_data['PageviewsPerSession']['previous'], 2, '.', ',' );
|
569 |
+
$boxes_data['BounceRate']['comparison'] = self::number_format_clean( $boxes_data['BounceRate']['current'], 2, '.', ',' ) . '% vs ' . self::number_format_clean( $boxes_data['BounceRate']['previous'], 2, '.', ',' ) . '%';
|
570 |
+
$boxes_data['Users']['color'] = ( $boxes_data['Users']['diff'] > 0 ) ? 'green' : 'red';
|
571 |
+
$boxes_data['Pageviews']['color'] = ( $boxes_data['Pageviews']['diff'] > 0 ) ? 'green' : 'red';
|
572 |
+
$boxes_data['PageviewsPerSession']['color'] = ( $boxes_data['PageviewsPerSession']['diff'] > 0 ) ? 'green' : 'red';
|
573 |
+
$boxes_data['BounceRate']['color'] = ( $boxes_data['BounceRate']['diff'] > 0 ) ? 'red' : 'green';
|
574 |
+
$boxes_data['Users']['color'] = ( $boxes_data['Users']['diff'] != 0 ) ? $boxes_data['Users']['color'] : 'black';
|
575 |
+
$boxes_data['Pageviews']['color'] = ( $boxes_data['Pageviews']['diff'] != 0 ) ? $boxes_data['Pageviews']['color'] : 'black';
|
576 |
+
$boxes_data['PageviewsPerSession']['color'] = ( $boxes_data['PageviewsPerSession']['diff'] != 0 ) ? $boxes_data['PageviewsPerSession']['color'] : 'black';
|
577 |
+
$boxes_data['BounceRate']['color'] = ( $boxes_data['BounceRate']['diff'] != 0 ) ? $boxes_data['BounceRate']['color'] : 'black';
|
578 |
+
|
579 |
+
return $boxes_data;
|
580 |
+
}
|
581 |
+
|
582 |
+
/**
|
583 |
+
* Number format for boxes
|
584 |
+
*
|
585 |
+
* @param float $number Number to format
|
586 |
+
* @param int $precision Precision
|
587 |
+
* @param string $dec_point Decimal point
|
588 |
+
* @param string $thousands_sep Thousands Separator
|
589 |
+
*
|
590 |
+
* @return string clean number format
|
591 |
+
*/
|
592 |
+
public static function number_format_clean( $number, $precision = 0, $dec_point = '.', $thousands_sep = ',' ) {
|
593 |
+
if ( $number == 0 ) {
|
594 |
+
return 0;
|
595 |
+
} else {
|
596 |
+
$format = number_format( $number, $precision, $dec_point, $thousands_sep );
|
597 |
+
if ( substr( $format, 2 ) == '.00' ) {
|
598 |
+
return substr( $format, 0, - 3 );
|
599 |
+
}
|
600 |
+
|
601 |
+
return $format;
|
602 |
+
}
|
603 |
+
}
|
604 |
+
|
605 |
+
/**
|
606 |
+
* Get sources from analytics response data
|
607 |
+
*
|
608 |
+
* @param array $data Analytics response data
|
609 |
+
*
|
610 |
+
* @return array sources data
|
611 |
+
*/
|
612 |
+
public static function get_sources( $data ) {
|
613 |
+
if ( ! empty( $data ) ) {
|
614 |
+
$data = self::get_reports_from_response( $data );
|
615 |
+
self::handle_more_reports( $data );
|
616 |
+
$report = self::get_single_report( $data );
|
617 |
+
self::get_report_column_header( $report );
|
618 |
+
$report_data = self::get_report_data( $report );
|
619 |
+
$rows = self::get_rows( $report_data );
|
620 |
+
$totals = self::get_totals( $report_data );
|
621 |
+
if ( ! empty( $totals ) ) {
|
622 |
+
$totalCount = array();
|
623 |
+
foreach ( $totals as $key => $total ) {
|
624 |
+
$totalCount = $total['values'][0];
|
625 |
+
}
|
626 |
+
}
|
627 |
+
$sources = array(
|
628 |
+
'total' => $totalCount,
|
629 |
+
'sum' => 0,
|
630 |
+
'rows' => array(),
|
631 |
+
);
|
632 |
+
if ( ! empty( $rows ) ) {
|
633 |
+
$i = 1;
|
634 |
+
foreach ( $rows as $row ) {
|
635 |
+
if ( ! empty( $row ) ) {
|
636 |
+
foreach ( $row as $key => $value ) {
|
637 |
+
if ( $key == 'dimensions' ) {
|
638 |
+
$sources['rows'][ $i ]['name'] = $value[0];
|
639 |
+
$sources['rows'][ $i ]['url'] = 'http://' . substr( $value[0], 0, strpos( $value[0], '/' ) - 1 );
|
640 |
+
} elseif ( $key == 'metrics' ) {
|
641 |
+
$sources['rows'][ $i ]['number'] = $value[0]['values'][0];
|
642 |
+
$sources['rows'][ $i ]['percent'] = ( ! empty( $totalCount ) ) ? round( $value[0]['values'][0] / $totalCount * 100, 2 ) : 0;
|
643 |
+
$sources['sum'] += $value[0]['values'][0];
|
644 |
+
}
|
645 |
+
}
|
646 |
+
$i ++;
|
647 |
+
}
|
648 |
+
}
|
649 |
+
}
|
650 |
+
|
651 |
+
return $sources;
|
652 |
+
}
|
653 |
+
|
654 |
+
return false;
|
655 |
+
}
|
656 |
+
|
657 |
+
/**
|
658 |
+
* Get dashboard boxes data from analytics response data
|
659 |
+
*
|
660 |
+
* @param array $data Analytics response data
|
661 |
+
*
|
662 |
+
* @return array dashboard boxes data
|
663 |
+
*/
|
664 |
+
public static function get_dashboard_boxes_data( $data ) {
|
665 |
+
if ( ! empty( $data ) ) {
|
666 |
+
$data = self::get_reports_from_response( $data );
|
667 |
+
self::handle_more_reports( $data );
|
668 |
+
$report = self::get_single_report( $data );
|
669 |
+
self::get_report_column_header( $report );
|
670 |
+
$report_data = self::get_report_data( $report );
|
671 |
+
$totals = self::get_totals( $report_data );
|
672 |
+
$boxes_data = array();
|
673 |
+
$boxes_data['Sessions'] = array(
|
674 |
+
'label' => 'Visits',
|
675 |
+
'value' => $totals[0]['values'][0],
|
676 |
+
);
|
677 |
+
$boxes_data['Pageviews'] = array(
|
678 |
+
'label' => 'Pageviews',
|
679 |
+
'value' => $totals[0]['values'][1],
|
680 |
+
);
|
681 |
+
$boxes_data['pageviewsPerSession'] = array(
|
682 |
+
'label' => 'Pages / Visit',
|
683 |
+
'value' => self::number_format_clean( $totals[0]['values'][2], 2, '.', ',' ),
|
684 |
+
);
|
685 |
+
$boxes_data['BounceRate'] = array(
|
686 |
+
'label' => 'Bounce Rate',
|
687 |
+
'value' => self::number_format_clean( $totals[0]['values'][3], 2, '.', ',' ) . '%',
|
688 |
+
);
|
689 |
+
$boxes_data['avgTimeOnPage'] = array(
|
690 |
+
'label' => 'Avg. Time on Site',
|
691 |
+
'value' => gmdate("H:i:s", $totals[0]['values'][4]),
|
692 |
+
);
|
693 |
+
$boxes_data['percentNewSessions'] = array(
|
694 |
+
'label' => '% of New Visits',
|
695 |
+
'value' => self::number_format_clean( $totals[0]['values'][5], 2, '.', ',' ),
|
696 |
+
);
|
697 |
+
|
698 |
+
return $boxes_data;
|
699 |
+
}
|
700 |
+
}
|
701 |
+
}
|
class/Ga_View.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_View {
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Name of the view folder.
|
7 |
+
*/
|
8 |
+
const PATH = 'view';
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Loads given view file and it's data.
|
12 |
+
* Displays view or returns HTML code.
|
13 |
+
*
|
14 |
+
* @param string $view Filename
|
15 |
+
* @param array $data Data array
|
16 |
+
* @param bool $html Whether to display or return HTML code.
|
17 |
+
*
|
18 |
+
* @return string
|
19 |
+
*/
|
20 |
+
public static function load( $view, $data_array = array(), $html = false ) {
|
21 |
+
if ( ! empty( $view ) ) {
|
22 |
+
foreach ( $data_array as $k => $v ) {
|
23 |
+
$$k = $v;
|
24 |
+
}
|
25 |
+
ob_start();
|
26 |
+
include GA_PLUGIN_DIR . "/" . self::PATH . "/" . $view . ".php";
|
27 |
+
if ( $html ) {
|
28 |
+
return ob_get_clean();
|
29 |
+
} else {
|
30 |
+
echo ob_get_clean();
|
31 |
+
}
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
// private static function buffer($buffer) {
|
36 |
+
// $data = $data_array;
|
37 |
+
// return $buffer;
|
38 |
+
// }
|
39 |
+
}
|
css/bootstrap.min.css
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* Bootstrap v3.3.7 (http://getbootstrap.com)
|
3 |
+
* Copyright 2011-2016 Twitter, Inc.
|
4 |
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
5 |
+
*/
|
6 |
+
|
7 |
+
/*!
|
8 |
+
* Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=ddbeb97adad43a942be618a7956c300d)
|
9 |
+
* Config saved to config.json and https://gist.github.com/ddbeb97adad43a942be618a7956c300d
|
10 |
+
*//*!
|
11 |
+
* Bootstrap v3.3.7 (http://getbootstrap.com)
|
12 |
+
* Copyright 2011-2016 Twitter, Inc.
|
13 |
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
14 |
+
*//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:0.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:focus,.btn-default.focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active:hover,.btn-default.active:hover,.open>.dropdown-toggle.btn-default:hover,.btn-default:active:focus,.btn-default.active:focus,.open>.dropdown-toggle.btn-default:focus,.btn-default:active.focus,.btn-default.active.focus,.open>.dropdown-toggle.btn-default.focus{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:focus,.btn-primary.focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active:hover,.btn-primary.active:hover,.open>.dropdown-toggle.btn-primary:hover,.btn-primary:active:focus,.btn-primary.active:focus,.open>.dropdown-toggle.btn-primary:focus,.btn-primary:active.focus,.btn-primary.active.focus,.open>.dropdown-toggle.btn-primary.focus{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:focus,.btn-success.focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active:hover,.btn-success.active:hover,.open>.dropdown-toggle.btn-success:hover,.btn-success:active:focus,.btn-success.active:focus,.open>.dropdown-toggle.btn-success:focus,.btn-success:active.focus,.btn-success.active.focus,.open>.dropdown-toggle.btn-success.focus{color:#fff;background-color:#398439;border-color:#255625}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:focus,.btn-info.focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active:hover,.btn-info.active:hover,.open>.dropdown-toggle.btn-info:hover,.btn-info:active:focus,.btn-info.active:focus,.open>.dropdown-toggle.btn-info:focus,.btn-info:active.focus,.btn-info.active.focus,.open>.dropdown-toggle.btn-info.focus{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:focus,.btn-warning.focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active:hover,.btn-warning.active:hover,.open>.dropdown-toggle.btn-warning:hover,.btn-warning:active:focus,.btn-warning.active:focus,.open>.dropdown-toggle.btn-warning:focus,.btn-warning:active.focus,.btn-warning.active.focus,.open>.dropdown-toggle.btn-warning.focus{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:focus,.btn-danger.focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active:hover,.btn-danger.active:hover,.open>.dropdown-toggle.btn-danger:hover,.btn-danger:active:focus,.btn-danger.active:focus,.open>.dropdown-toggle.btn-danger:focus,.btn-danger:active.focus,.btn-danger.active.focus,.open>.dropdown-toggle.btn-danger.focus{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a,.panel-title>small,.panel-title>.small,.panel-title>small>a,.panel-title>.small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-left:15px;padding-right:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);-o-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform 0.3s ease-out;-o-transition:-o-transform 0.3s ease-out;transition:transform 0.3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);-webkit-background-clip:padding-box;background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.nav:before,.nav:after,.panel-body:before,.panel-body:after,.modal-header:before,.modal-header:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after,.nav:after,.panel-body:after,.modal-header:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}
|
css/googleanalytics.css
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@CHARSET "UTF-8";
|
2 |
+
|
3 |
+
.wrap.ga-wrap {
|
4 |
+
margin: 0px auto !important;
|
5 |
+
margin-top: 10px !important;
|
6 |
+
margin-right: 0px !important;
|
7 |
+
}
|
8 |
+
|
9 |
+
.ga_container {
|
10 |
+
margin-top: 25px;
|
11 |
+
}
|
12 |
+
|
13 |
+
#exTab1, #exTab2 {
|
14 |
+
margin-right: 15px !important;
|
15 |
+
}
|
16 |
+
|
17 |
+
#exTab1 .tab-content {
|
18 |
+
color: white;
|
19 |
+
background-color: #428bca;
|
20 |
+
padding: 5px 15px;
|
21 |
+
}
|
22 |
+
|
23 |
+
#exTab2 h3 {
|
24 |
+
color: white;
|
25 |
+
background-color: #428bca;
|
26 |
+
padding: 5px 15px;
|
27 |
+
}
|
28 |
+
|
29 |
+
/* remove border radius for the tab */
|
30 |
+
#exTab1 .nav-pills > li > a {
|
31 |
+
border-radius: 0;
|
32 |
+
}
|
33 |
+
|
34 |
+
/* change border radius for the tab , apply corners on top*/
|
35 |
+
#exTab3 .nav-pills > li > a {
|
36 |
+
border-radius: 4px 4px 0 0;
|
37 |
+
}
|
38 |
+
|
39 |
+
#exTab3 .tab-content {
|
40 |
+
color: white;
|
41 |
+
background-color: #428bca;
|
42 |
+
padding: 5px 15px;
|
43 |
+
}
|
44 |
+
|
45 |
+
label.ga_checkbox_label {
|
46 |
+
margin-top: 6px !important;
|
47 |
+
}
|
48 |
+
|
49 |
+
.form-table th {
|
50 |
+
width: 250px !important;
|
51 |
+
}
|
52 |
+
|
53 |
+
.wrap.ga-notice {
|
54 |
+
width: 100% !important;
|
55 |
+
margin-left: 0px !important;
|
56 |
+
margin-right: 10px !important;
|
57 |
+
}
|
58 |
+
|
59 |
+
.ga_warning {
|
60 |
+
font-size: 12px;
|
61 |
+
font-weight: normal;
|
62 |
+
margin-top: 10px;
|
63 |
+
}
|
64 |
+
|
65 |
+
.ga-boxes-container {
|
66 |
+
|
67 |
+
}
|
68 |
+
|
69 |
+
.ga-box-row {
|
70 |
+
display: table;
|
71 |
+
width: 100%;
|
72 |
+
table-layout: fixed;
|
73 |
+
border-spacing: 10px;
|
74 |
+
}
|
75 |
+
|
76 |
+
.ga-box-column {
|
77 |
+
display: table-cell;
|
78 |
+
-moz-box-shadow: 0 0 5px #e5e5e5;
|
79 |
+
-webkit-box-shadow: 0 0 5px #e5e5e5;
|
80 |
+
box-shadow: 0px 0px 5px #e5e5e5;
|
81 |
+
}
|
82 |
+
|
83 |
+
.ga-box-dashboard {
|
84 |
+
border: 1px solid #cccccc;
|
85 |
+
border-radius: 0px;
|
86 |
+
padding: 3px;
|
87 |
+
text-align: center;
|
88 |
+
}
|
89 |
+
|
90 |
+
.ga-box-centered {
|
91 |
+
text-align: center;
|
92 |
+
}
|
93 |
+
|
94 |
+
.ga-loader-wrapper {
|
95 |
+
float: right;
|
96 |
+
margin-top: 4px;
|
97 |
+
margin-right: 5px;
|
98 |
+
}
|
99 |
+
|
100 |
+
.ga-loader-wrapper.stats-page {
|
101 |
+
width: 45px;
|
102 |
+
text-align: center;
|
103 |
+
margin: 0 auto;
|
104 |
+
float: none;
|
105 |
+
}
|
106 |
+
|
107 |
+
.ga-loader {
|
108 |
+
border: 4px solid #f3f3f3; /* Light grey */
|
109 |
+
border-top: 4px solid #3498db; /* Blue */
|
110 |
+
border-radius: 50%;
|
111 |
+
width: 15px;
|
112 |
+
height: 15px;
|
113 |
+
animation: spin 2s linear infinite;
|
114 |
+
display: none;
|
115 |
+
}
|
116 |
+
|
117 |
+
.ga-loader.stats-page-loader {
|
118 |
+
width: 45px;
|
119 |
+
height: 45px;
|
120 |
+
border-width: 6px;
|
121 |
+
}
|
122 |
+
|
123 |
+
@keyframes spin {
|
124 |
+
0% {
|
125 |
+
transform: rotate(0deg);
|
126 |
+
}
|
127 |
+
100% {
|
128 |
+
transform: rotate(360deg);
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
.ga-chart {
|
133 |
+
}
|
134 |
+
|
135 |
+
.label-grey{
|
136 |
+
color:#ccc;
|
137 |
+
}
|
138 |
+
|
139 |
+
.ga-tooltip {
|
140 |
+
position: relative;
|
141 |
+
cursor: not-allowed;
|
142 |
+
}
|
143 |
+
|
144 |
+
.ga-tooltip input[disabled] {
|
145 |
+
cursor: not-allowed;
|
146 |
+
}
|
147 |
+
|
148 |
+
.ga-tooltiptext {
|
149 |
+
background-color: #ffe692;
|
150 |
+
border: 1px solid #ffb900;
|
151 |
+
border-radius: 4px;
|
152 |
+
color: #444;
|
153 |
+
font-size: 12px;
|
154 |
+
font-weight: 500;
|
155 |
+
margin-left: 10px;
|
156 |
+
margin-top: 30px;
|
157 |
+
padding: 3px 10px;
|
158 |
+
position: relative;
|
159 |
+
white-space: nowrap;
|
160 |
+
text-align: center;
|
161 |
+
visibility: hidden;
|
162 |
+
width: auto;
|
163 |
+
z-index: 1;
|
164 |
+
}
|
165 |
+
.ga-tt-abs{
|
166 |
+
display: inline-block;
|
167 |
+
position: absolute;
|
168 |
+
margin-top: 0px;
|
169 |
+
}
|
170 |
+
.ga-tooltip:hover .ga-tooltiptext {
|
171 |
+
visibility: visible;
|
172 |
+
}
|
googleanalytics.php
CHANGED
@@ -1,67 +1,47 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
|
4 |
-
Plugin
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
Author
|
9 |
-
|
10 |
-
|
11 |
-
if (!defined('WP_CONTENT_URL'))
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
if (!defined('
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
}
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
}
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
(
|
45 |
-
(
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
ga('create', '<?php echo $web_property_id ?>', 'auto');
|
50 |
-
ga('send', 'pageview');
|
51 |
-
</script>
|
52 |
-
<?php
|
53 |
-
}
|
54 |
-
|
55 |
-
register_activation_hook(__FILE__, 'activate_googleanalytics');
|
56 |
-
register_deactivation_hook(__FILE__, 'deactive_googleanalytics');
|
57 |
-
|
58 |
-
if (is_admin()) {
|
59 |
-
add_action('admin_init', 'admin_init_googleanalytics');
|
60 |
-
add_action('admin_menu', 'admin_menu_googleanalytics');
|
61 |
-
}
|
62 |
-
|
63 |
-
if (!is_admin()) {
|
64 |
-
add_action('wp_head', 'googleanalytics');
|
65 |
-
}
|
66 |
-
|
67 |
-
?>
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* Plugin Name: Google Analytics
|
5 |
+
* Plugin URI: http://wordpress.org/extend/plugins/googleanalytics/
|
6 |
+
* Description: Use Google Analytics on your Wordpress site without touching any code, and view visitor reports right in your Wordpress admin dashboard!
|
7 |
+
* Version: 2.0.0
|
8 |
+
* Author: ShareThis
|
9 |
+
* Author URI: http://sharethis.com
|
10 |
+
*/
|
11 |
+
if ( ! defined( 'WP_CONTENT_URL' ) ) {
|
12 |
+
define( 'WP_CONTENT_URL', get_option( 'siteurl' ) . '/wp-content' );
|
13 |
+
}
|
14 |
+
if ( ! defined( 'WP_CONTENT_DIR' ) ) {
|
15 |
+
define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
|
16 |
+
}
|
17 |
+
if ( ! defined( 'WP_PLUGIN_URL' ) ) {
|
18 |
+
define( 'WP_PLUGIN_URL', WP_CONTENT_URL . '/plugins' );
|
19 |
+
}
|
20 |
+
if ( ! defined( 'WP_PLUGIN_DIR' ) ) {
|
21 |
+
define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' );
|
22 |
+
}
|
23 |
+
if ( ! defined( 'GA_NAME' ) ) {
|
24 |
+
define( 'GA_NAME', 'googleanalytics' );
|
25 |
+
}
|
26 |
+
if ( ! defined( 'GA_PLUGIN_DIR' ) ) {
|
27 |
+
define( 'GA_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins/' . GA_NAME );
|
28 |
+
}
|
29 |
+
if ( ! defined( 'GA_PLUGIN_URL' ) ) {
|
30 |
+
define( 'GA_PLUGIN_URL', WP_CONTENT_URL . '/plugins/' . GA_NAME );
|
31 |
+
}
|
32 |
+
if ( ! defined( 'GA_MAIN_FILE_PATH' ) ) {
|
33 |
+
define( 'GA_MAIN_FILE_PATH', __FILE__ );
|
34 |
+
}
|
35 |
+
if ( ! defined( 'GA_SHARETHIS_SCRIPTS_INCLUDED' ) ) {
|
36 |
+
define( 'GA_SHARETHIS_SCRIPTS_INCLUDED', 0 );
|
37 |
+
}
|
38 |
+
define( 'GOOGLEANALYTICS_VERSION', '2.0.0' );
|
39 |
+
include_once GA_PLUGIN_DIR . '/overwrite/ga_overwrite.php';
|
40 |
+
include_once GA_PLUGIN_DIR . '/class/Ga_Autoloader.php';
|
41 |
+
Ga_Autoloader::register();
|
42 |
+
Ga_Hook::add_hooks( GA_MAIN_FILE_PATH );
|
43 |
+
|
44 |
+
add_action( 'plugins_loaded', 'Ga_Admin::loaded_googleanalytics' );
|
45 |
+
add_action( 'init', 'Ga_Helper::init' );
|
46 |
+
|
47 |
+
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/bootstrap.min.js
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* Bootstrap v3.3.7 (http://getbootstrap.com)
|
3 |
+
* Copyright 2011-2016 Twitter, Inc.
|
4 |
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
5 |
+
*/
|
6 |
+
|
7 |
+
/*!
|
8 |
+
* Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=ddbeb97adad43a942be618a7956c300d)
|
9 |
+
* Config saved to config.json and https://gist.github.com/ddbeb97adad43a942be618a7956c300d
|
10 |
+
*/
|
11 |
+
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(t){"use strict";var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||e[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(t){"use strict";function e(e,o){return this.each(function(){var s=t(this),n=s.data("bs.modal"),a=t.extend({},i.DEFAULTS,s.data(),"object"==typeof e&&e);n||s.data("bs.modal",n=new i(this,a)),"string"==typeof e?n[e](o):a.show&&n.show(o)})}var i=function(e,i){this.options=i,this.$body=t(document.body),this.$element=t(e),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,t.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};i.VERSION="3.3.7",i.TRANSITION_DURATION=300,i.BACKDROP_TRANSITION_DURATION=150,i.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},i.prototype.toggle=function(t){return this.isShown?this.hide():this.show(t)},i.prototype.show=function(e){var o=this,s=t.Event("show.bs.modal",{relatedTarget:e});this.$element.trigger(s),this.isShown||s.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',t.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){o.$element.one("mouseup.dismiss.bs.modal",function(e){t(e.target).is(o.$element)&&(o.ignoreBackdropClick=!0)})}),this.backdrop(function(){var s=t.support.transition&&o.$element.hasClass("fade");o.$element.parent().length||o.$element.appendTo(o.$body),o.$element.show().scrollTop(0),o.adjustDialog(),s&&o.$element[0].offsetWidth,o.$element.addClass("in"),o.enforceFocus();var n=t.Event("shown.bs.modal",{relatedTarget:e});s?o.$dialog.one("bsTransitionEnd",function(){o.$element.trigger("focus").trigger(n)}).emulateTransitionEnd(i.TRANSITION_DURATION):o.$element.trigger("focus").trigger(n)}))},i.prototype.hide=function(e){e&&e.preventDefault(),e=t.Event("hide.bs.modal"),this.$element.trigger(e),this.isShown&&!e.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),t(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),t.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",t.proxy(this.hideModal,this)).emulateTransitionEnd(i.TRANSITION_DURATION):this.hideModal())},i.prototype.enforceFocus=function(){t(document).off("focusin.bs.modal").on("focusin.bs.modal",t.proxy(function(t){document===t.target||this.$element[0]===t.target||this.$element.has(t.target).length||this.$element.trigger("focus")},this))},i.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",t.proxy(function(t){27==t.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},i.prototype.resize=function(){this.isShown?t(window).on("resize.bs.modal",t.proxy(this.handleUpdate,this)):t(window).off("resize.bs.modal")},i.prototype.hideModal=function(){var t=this;this.$element.hide(),this.backdrop(function(){t.$body.removeClass("modal-open"),t.resetAdjustments(),t.resetScrollbar(),t.$element.trigger("hidden.bs.modal")})},i.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},i.prototype.backdrop=function(e){var o=this,s=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var n=t.support.transition&&s;if(this.$backdrop=t(document.createElement("div")).addClass("modal-backdrop "+s).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",t.proxy(function(t){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(t.target===t.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),n&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!e)return;n?this.$backdrop.one("bsTransitionEnd",e).emulateTransitionEnd(i.BACKDROP_TRANSITION_DURATION):e()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var a=function(){o.removeBackdrop(),e&&e()};t.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",a).emulateTransitionEnd(i.BACKDROP_TRANSITION_DURATION):a()}else e&&e()},i.prototype.handleUpdate=function(){this.adjustDialog()},i.prototype.adjustDialog=function(){var t=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&t?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!t?this.scrollbarWidth:""})},i.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},i.prototype.checkScrollbar=function(){var t=window.innerWidth;if(!t){var e=document.documentElement.getBoundingClientRect();t=e.right-Math.abs(e.left)}this.bodyIsOverflowing=document.body.clientWidth<t,this.scrollbarWidth=this.measureScrollbar()},i.prototype.setScrollbar=function(){var t=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",t+this.scrollbarWidth)},i.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},i.prototype.measureScrollbar=function(){var t=document.createElement("div");t.className="modal-scrollbar-measure",this.$body.append(t);var e=t.offsetWidth-t.clientWidth;return this.$body[0].removeChild(t),e};var o=t.fn.modal;t.fn.modal=e,t.fn.modal.Constructor=i,t.fn.modal.noConflict=function(){return t.fn.modal=o,this},t(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(i){var o=t(this),s=o.attr("href"),n=t(o.attr("data-target")||s&&s.replace(/.*(?=#[^\s]+$)/,"")),a=n.data("bs.modal")?"toggle":t.extend({remote:!/#/.test(s)&&s},n.data(),o.data());o.is("a")&&i.preventDefault(),n.one("show.bs.modal",function(t){t.isDefaultPrevented()||n.one("hidden.bs.modal",function(){o.is(":visible")&&o.trigger("focus")})}),e.call(n,a,this)})}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var o=t(this),s=o.data("bs.tab");s||o.data("bs.tab",s=new i(this)),"string"==typeof e&&s[e]()})}var i=function(e){this.element=t(e)};i.VERSION="3.3.7",i.TRANSITION_DURATION=150,i.prototype.show=function(){var e=this.element,i=e.closest("ul:not(.dropdown-menu)"),o=e.data("target");if(o||(o=e.attr("href"),o=o&&o.replace(/.*(?=#[^\s]*$)/,"")),!e.parent("li").hasClass("active")){var s=i.find(".active:last a"),n=t.Event("hide.bs.tab",{relatedTarget:e[0]}),a=t.Event("show.bs.tab",{relatedTarget:s[0]});if(s.trigger(n),e.trigger(a),!a.isDefaultPrevented()&&!n.isDefaultPrevented()){var r=t(o);this.activate(e.closest("li"),i),this.activate(r,r.parent(),function(){s.trigger({type:"hidden.bs.tab",relatedTarget:e[0]}),e.trigger({type:"shown.bs.tab",relatedTarget:s[0]})})}}},i.prototype.activate=function(e,o,s){function n(){a.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),e.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),r?(e[0].offsetWidth,e.addClass("in")):e.removeClass("fade"),e.parent(".dropdown-menu").length&&e.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),s&&s()}var a=o.find("> .active"),r=s&&t.support.transition&&(a.length&&a.hasClass("fade")||!!o.find("> .fade").length);a.length&&r?a.one("bsTransitionEnd",n).emulateTransitionEnd(i.TRANSITION_DURATION):n(),a.removeClass("in")};var o=t.fn.tab;t.fn.tab=e,t.fn.tab.Constructor=i,t.fn.tab.noConflict=function(){return t.fn.tab=o,this};var s=function(i){i.preventDefault(),e.call(t(this),"show")};t(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',s).on("click.bs.tab.data-api",'[data-toggle="pill"]',s)}(jQuery);
|
js/googleanalytics.js
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Created by mdn on 2016-12-02.
|
3 |
+
*/
|
4 |
+
|
5 |
+
(function ($) {
|
6 |
+
ga_loader = {
|
7 |
+
show: function () {
|
8 |
+
$('.ga-loader').show();
|
9 |
+
},
|
10 |
+
hide: function () {
|
11 |
+
$('.ga-loader').hide();
|
12 |
+
}
|
13 |
+
};
|
14 |
+
|
15 |
+
ga_tools = {
|
16 |
+
getCurrentWidth: function (wrapperSelector) {
|
17 |
+
return $(wrapperSelector).width();
|
18 |
+
},
|
19 |
+
recomputeChartWidth: function (minWidth, offset, wrapperSelector) {
|
20 |
+
const currentWidth = ga_tools.getCurrentWidth(wrapperSelector);
|
21 |
+
if (currentWidth >= minWidth) {
|
22 |
+
return parseInt(currentWidth - offset);
|
23 |
+
} else {
|
24 |
+
return minWidth;
|
25 |
+
}
|
26 |
+
}
|
27 |
+
};
|
28 |
+
})(jQuery);
|
js/googleanalytics_dashboard.js
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(function ($) {
|
2 |
+
|
3 |
+
const wrapperSelector = '#ga_dashboard_widget';
|
4 |
+
const minWidth = 350;
|
5 |
+
const offset = 10;
|
6 |
+
|
7 |
+
ga_dashboard = {
|
8 |
+
chartData: [],
|
9 |
+
init: function (dataArr) {
|
10 |
+
ga_loader.show();
|
11 |
+
google.charts.load('current', {'packages': ['corechart']});
|
12 |
+
google.charts.setOnLoadCallback(function () {
|
13 |
+
ga_dashboard.drawChart(dataArr);
|
14 |
+
ga_dashboard.setChartData(dataArr);
|
15 |
+
});
|
16 |
+
},
|
17 |
+
events: function (data) {
|
18 |
+
$(document).ready(function () {
|
19 |
+
$('#range-selector').on('change', function () {
|
20 |
+
const selected = $(this).val();
|
21 |
+
const selected_name = $('#metrics-selector option:selected').html();
|
22 |
+
const selected_metric = $('#metrics-selector option:selected').val() || null;
|
23 |
+
|
24 |
+
ga_loader.show();
|
25 |
+
|
26 |
+
$.ajax({
|
27 |
+
type: "post",
|
28 |
+
dataType: "json",
|
29 |
+
url: ajaxurl,
|
30 |
+
data: {action: "ga_ajax_data_change", date_range: selected, metric: selected_metric},
|
31 |
+
success: function (response) {
|
32 |
+
|
33 |
+
ga_loader.hide();
|
34 |
+
|
35 |
+
var dataT = [['Day', selected_name]];
|
36 |
+
$.each(response.chart, function (k, v) {
|
37 |
+
dataT.push([v.day, parseInt(v.current)]);
|
38 |
+
});
|
39 |
+
|
40 |
+
$.each(response.boxes, function (k, v) {
|
41 |
+
$('#ga_box_dashboard_label_' + k).html(v.label)
|
42 |
+
$('#ga_box_dashboard_value_' + k).html(v.value);
|
43 |
+
});
|
44 |
+
|
45 |
+
ga_dashboard.drawChart(dataT, selected_name);
|
46 |
+
|
47 |
+
// Set new data
|
48 |
+
ga_dashboard.setChartData(dataT);
|
49 |
+
}
|
50 |
+
});
|
51 |
+
});
|
52 |
+
|
53 |
+
$('#metrics-selector').on('change', function () {
|
54 |
+
const selected = $(this).val();
|
55 |
+
const selected_name = $('#metrics-selector option:selected').html();
|
56 |
+
const selected_range = $('#range-selector option:selected').val() || null;
|
57 |
+
|
58 |
+
ga_loader.show();
|
59 |
+
|
60 |
+
$.ajax({
|
61 |
+
type: "post",
|
62 |
+
dataType: "json",
|
63 |
+
url: ajaxurl,
|
64 |
+
data: {action: "ga_ajax_data_change", metric: selected, date_range: selected_range},
|
65 |
+
success: function (response) {
|
66 |
+
ga_loader.hide();
|
67 |
+
var dataT = [['Day', selected_name]];
|
68 |
+
$.each(response.chart, function (k, v) {
|
69 |
+
dataT.push([v.day, parseInt(v.current)]);
|
70 |
+
});
|
71 |
+
ga_dashboard.drawChart(dataT, selected_name);
|
72 |
+
|
73 |
+
// Set new data
|
74 |
+
ga_dashboard.setChartData(dataT);
|
75 |
+
}
|
76 |
+
});
|
77 |
+
});
|
78 |
+
|
79 |
+
$(window).on('resize', function () {
|
80 |
+
ga_dashboard.drawChart(ga_dashboard.getChartData(), ga_tools.recomputeChartWidth(minWidth, offset, wrapperSelector));
|
81 |
+
});
|
82 |
+
});
|
83 |
+
},
|
84 |
+
/**
|
85 |
+
* Returns chart data array.
|
86 |
+
* @returns {Array}
|
87 |
+
*/
|
88 |
+
getChartData: function () {
|
89 |
+
return ga_dashboard.chartData;
|
90 |
+
},
|
91 |
+
/**
|
92 |
+
* Overwrites initial data array.
|
93 |
+
* @param new_data
|
94 |
+
*/
|
95 |
+
setChartData: function (new_data) {
|
96 |
+
ga_dashboard.chartData = new_data;
|
97 |
+
},
|
98 |
+
drawChart: function (dataArr, title) {
|
99 |
+
const chart_dom_element = document.getElementById('chart_div');
|
100 |
+
|
101 |
+
if (typeof title == 'undefined') {
|
102 |
+
title = 'Pageviews';
|
103 |
+
}
|
104 |
+
|
105 |
+
const data = google.visualization.arrayToDataTable(dataArr);
|
106 |
+
|
107 |
+
const options = {
|
108 |
+
/*title: title,*/
|
109 |
+
legend: 'top',
|
110 |
+
lineWidth: 2,
|
111 |
+
chartArea: {
|
112 |
+
left: 10,
|
113 |
+
top: 60,
|
114 |
+
bottom: 50,
|
115 |
+
right: 10
|
116 |
+
|
117 |
+
},
|
118 |
+
width: '95%',
|
119 |
+
height: 300,
|
120 |
+
hAxis: {title: 'Day', titleTextStyle: {color: '#333'}, direction: 1},
|
121 |
+
vAxis: {minValue: 0},
|
122 |
+
pointSize: 5
|
123 |
+
};
|
124 |
+
|
125 |
+
var chart = new google.visualization.AreaChart(chart_dom_element);
|
126 |
+
google.visualization.events.addListener(chart, 'ready', function () {
|
127 |
+
ga_loader.hide();
|
128 |
+
});
|
129 |
+
chart.draw(data, options);
|
130 |
+
}
|
131 |
+
};
|
132 |
+
|
133 |
+
})(jQuery);
|
js/googleanalytics_page.js
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const GA_ACCESS_CODE_MODAL_ID = "ga_access_code_modal";
|
2 |
+
const GA_ACCESS_CODE_TMP_ID = "ga_access_code_tmp";
|
3 |
+
const GA_ACCESS_CODE_ID = "ga_access_code";
|
4 |
+
const GA_FORM_ID = "ga_form";
|
5 |
+
|
6 |
+
(function ($) {
|
7 |
+
|
8 |
+
ga_popup = {
|
9 |
+
url: '',
|
10 |
+
authorize: function (e, url) {
|
11 |
+
e.preventDefault();
|
12 |
+
ga_popup.url = url;
|
13 |
+
$('#' + GA_ACCESS_CODE_MODAL_ID).appendTo("body").modal('show');
|
14 |
+
ga_popup.open();
|
15 |
+
},
|
16 |
+
open: function () {
|
17 |
+
const p_width = Math.round(screen.width / 2);
|
18 |
+
const p_height = Math.round(screen.height / 2);
|
19 |
+
const p_left = Math.round(p_width / 2);
|
20 |
+
const p_top = 300;
|
21 |
+
window.open(ga_popup.url, 'ga_auth_popup', 'width=' + p_width + ',height='
|
22 |
+
+ p_height + ',top=' + p_top + ',left=' + p_left);
|
23 |
+
},
|
24 |
+
saveAccessCode: function (e) {
|
25 |
+
e.preventDefault();
|
26 |
+
e.target.disabled = 'disabled';
|
27 |
+
ga_loader.show();
|
28 |
+
const ac_tmp = $('#' + GA_ACCESS_CODE_TMP_ID).val();
|
29 |
+
if (ac_tmp) {
|
30 |
+
$('#' + GA_ACCESS_CODE_ID).val(ac_tmp);
|
31 |
+
$('#' + GA_FORM_ID).submit();
|
32 |
+
}
|
33 |
+
}
|
34 |
+
};
|
35 |
+
ga_events = {
|
36 |
+
|
37 |
+
click: function (selector, callback) {
|
38 |
+
$(selector).live('click', callback);
|
39 |
+
},
|
40 |
+
codeManuallyCallback: function ( terms_accepted ) {
|
41 |
+
const button_disabled = $('#ga_authorize_with_google_button').attr('disabled');
|
42 |
+
const selector_disabled = $('#ga_account_selector').attr('disabled');
|
43 |
+
if ( terms_accepted ) {
|
44 |
+
if (button_disabled) {
|
45 |
+
$('#ga_authorize_with_google_button').removeAttr('disabled').next().hide();
|
46 |
+
} else {
|
47 |
+
$('#ga_authorize_with_google_button').attr('disabled',
|
48 |
+
'disabled').next().show();
|
49 |
+
}
|
50 |
+
|
51 |
+
if (selector_disabled) {
|
52 |
+
$('#ga_account_selector').removeAttr('disabled');
|
53 |
+
} else {
|
54 |
+
$('#ga_account_selector').attr('disabled', 'disabled');
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
$('#ga_manually_wrapper').toggle();
|
59 |
+
},
|
60 |
+
initModalEvents: function () {
|
61 |
+
$('#' + GA_ACCESS_CODE_MODAL_ID).on('shown.bs.modal', function () {
|
62 |
+
$('#' + GA_ACCESS_CODE_TMP_ID).focus();
|
63 |
+
});
|
64 |
+
|
65 |
+
$('#' + GA_ACCESS_CODE_MODAL_ID).on('hide.bs.modal', function () {
|
66 |
+
ga_loader.hide();
|
67 |
+
$('#ga_save_access_code').removeAttr('disabled');
|
68 |
+
});
|
69 |
+
}
|
70 |
+
};
|
71 |
+
|
72 |
+
$(document).ready(function () {
|
73 |
+
ga_events.initModalEvents();
|
74 |
+
});
|
75 |
+
|
76 |
+
const offset = 50;
|
77 |
+
const minWidth = 350;
|
78 |
+
const wrapperSelector = '#ga-stats-container';
|
79 |
+
const chartContainer = 'chart_div';
|
80 |
+
|
81 |
+
ga_charts = {
|
82 |
+
|
83 |
+
init: function (callback) {
|
84 |
+
$(document).ready(function () {
|
85 |
+
google.charts.load('current', {
|
86 |
+
'packages': ['corechart']
|
87 |
+
});
|
88 |
+
ga_loader.show();
|
89 |
+
google.charts.setOnLoadCallback(callback);
|
90 |
+
});
|
91 |
+
},
|
92 |
+
createTooltip: function (day, pageviews) {
|
93 |
+
return '<div style="padding:10px;width:100px;">' + '<strong>' + day
|
94 |
+
+ '</strong><br>' + 'Pageviews:<strong> ' + pageviews
|
95 |
+
+ '</strong>' + '</div>';
|
96 |
+
},
|
97 |
+
events: function (data) {
|
98 |
+
$(window).on('resize', function () {
|
99 |
+
ga_charts.drawChart(data, ga_tools.recomputeChartWidth(minWidth, offset, wrapperSelector));
|
100 |
+
});
|
101 |
+
},
|
102 |
+
drawChart: function (data, chartWidth) {
|
103 |
+
|
104 |
+
if (typeof chartWidth == 'undefined') {
|
105 |
+
chartWidth = ga_tools.recomputeChartWidth(minWidth, offset, wrapperSelector);
|
106 |
+
}
|
107 |
+
|
108 |
+
const options = {
|
109 |
+
/*title : 'Page Views',*/
|
110 |
+
lineWidth: 5,
|
111 |
+
pointSize: 10,
|
112 |
+
tooltip: {
|
113 |
+
isHtml: true
|
114 |
+
},
|
115 |
+
legend: {
|
116 |
+
position: (ga_tools.getCurrentWidth(wrapperSelector) <= minWidth ? 'top'
|
117 |
+
: 'top'),
|
118 |
+
maxLines: 5,
|
119 |
+
alignment: 'start',
|
120 |
+
textStyle: {color: '#000', fontSize: 12}
|
121 |
+
},
|
122 |
+
colors: ['#4285f4', '#ff9800'],
|
123 |
+
hAxis: {
|
124 |
+
title: 'Day',
|
125 |
+
titleTextStyle: {
|
126 |
+
color: '#333'
|
127 |
+
}
|
128 |
+
},
|
129 |
+
vAxis: {
|
130 |
+
minValue: 0
|
131 |
+
},
|
132 |
+
width: chartWidth,
|
133 |
+
height: 500,
|
134 |
+
chartArea: {
|
135 |
+
top: 50,
|
136 |
+
left: 50,
|
137 |
+
right: 30,
|
138 |
+
bottom: 100
|
139 |
+
},
|
140 |
+
};
|
141 |
+
var chart = new google.visualization.AreaChart(document
|
142 |
+
.getElementById(chartContainer));
|
143 |
+
chart.draw(data, options);
|
144 |
+
}
|
145 |
+
};
|
146 |
+
})(jQuery);
|
lib/Ga_Lib_Api_Client.php
ADDED
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_Lib_Api_Client {
|
4 |
+
|
5 |
+
const OAUTH2_REVOKE_ENDPOINT = 'https://accounts.google.com/o/oauth2/revoke';
|
6 |
+
|
7 |
+
const OAUTH2_TOKEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token';
|
8 |
+
|
9 |
+
const OAUTH2_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth';
|
10 |
+
|
11 |
+
const OAUTH2_FEDERATED_SIGNON_CERTS_ENDPOINT = 'https://www.googleapis.com/oauth2/v1/certs';
|
12 |
+
|
13 |
+
const GA_ACCOUNT_SUMMARIES_ENDPOINT = 'https://www.googleapis.com/analytics/v3/management/accountSummaries';
|
14 |
+
|
15 |
+
const GA_DATA_ENDPOINT = 'https://analyticsreporting.googleapis.com/v4/reports:batchGet';
|
16 |
+
|
17 |
+
const OAUTH2_CALLBACK_URI = 'urn:ietf:wg:oauth:2.0:oob';
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Pre-defined API credentials.
|
21 |
+
*
|
22 |
+
* @var array
|
23 |
+
*/
|
24 |
+
private $config = array(
|
25 |
+
'access_type' => 'offline',
|
26 |
+
'application_name' => 'Google Analytics',
|
27 |
+
'client_id' => '207216681371-433ldmujuv4l0743c1j7g8sci57cb51r.apps.googleusercontent.com',
|
28 |
+
'client_secret' => 'y0B-K-ODB1KZOam50aMEDhyc',
|
29 |
+
'scopes' => array( 'https://www.googleapis.com/auth/analytics.readonly' ),
|
30 |
+
'approval_prompt' => 'force'
|
31 |
+
);
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Keeps Access Token information.
|
35 |
+
*
|
36 |
+
* @var array
|
37 |
+
*/
|
38 |
+
private $token;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Returns API client instance.
|
42 |
+
*
|
43 |
+
* @return Ga_Lib_Api_Client|null
|
44 |
+
*/
|
45 |
+
public static function get_instance() {
|
46 |
+
static $instance = null;
|
47 |
+
if ( $instance === null ) {
|
48 |
+
$instance = new Ga_Lib_Api_Client();
|
49 |
+
}
|
50 |
+
|
51 |
+
return $instance;
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Calls api methods.
|
56 |
+
*
|
57 |
+
* @param string $callback
|
58 |
+
* @param mixed $args
|
59 |
+
*
|
60 |
+
* @return mixed
|
61 |
+
*/
|
62 |
+
public function call( $callback, $args = null ) {
|
63 |
+
try {
|
64 |
+
$callback = array( get_class( $this ), $callback );
|
65 |
+
if ( is_callable( $callback ) ) {
|
66 |
+
if ( ! empty( $args ) ) {
|
67 |
+
if ( is_array( $args ) ) {
|
68 |
+
return call_user_func_array( $callback, $args );
|
69 |
+
} else {
|
70 |
+
return call_user_func_array( $callback, array( $args ) );
|
71 |
+
}
|
72 |
+
} else {
|
73 |
+
return call_user_func( $callback );
|
74 |
+
}
|
75 |
+
} else {
|
76 |
+
throw new Exception( 'Unknown method: ' . $callback );
|
77 |
+
}
|
78 |
+
} catch ( Exception $e ) {
|
79 |
+
// @todo: need to add exception
|
80 |
+
echo $e->getMessage();
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Sets access token.
|
86 |
+
*
|
87 |
+
* @param $token
|
88 |
+
*/
|
89 |
+
public function set_access_token( $token ) {
|
90 |
+
$this->token = $token;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Returns Google Oauth2 redirect URL.
|
95 |
+
*
|
96 |
+
* @return string
|
97 |
+
*/
|
98 |
+
private function get_redirect_uri() {
|
99 |
+
return self::OAUTH2_CALLBACK_URI;
|
100 |
+
}
|
101 |
+
|
102 |
+
/**
|
103 |
+
* Creates Google Oauth2 authorization URL.
|
104 |
+
*
|
105 |
+
* @return string
|
106 |
+
*/
|
107 |
+
public function create_auth_url() {
|
108 |
+
$params = array(
|
109 |
+
'response_type' => 'code',
|
110 |
+
'redirect_uri' => $this->get_redirect_uri(),
|
111 |
+
'client_id' => urlencode( $this->config['client_id'] ),
|
112 |
+
'scope' => implode( " ", $this->config['scopes'] ),
|
113 |
+
'access_type' => urlencode( $this->config['access_type'] ),
|
114 |
+
'approval_prompt' => urlencode( $this->config['approval_prompt'] )
|
115 |
+
);
|
116 |
+
|
117 |
+
return self::OAUTH2_AUTH_ENDPOINT . "?" . http_build_query( $params );
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Sends request for Access Token during Oauth2 process.
|
122 |
+
*
|
123 |
+
* @param $access_code
|
124 |
+
*
|
125 |
+
* @return Ga_Lib_Api_Response Returns response object
|
126 |
+
*/
|
127 |
+
private function ga_auth_get_access_token( $access_code ) {
|
128 |
+
$request = array(
|
129 |
+
'code' => $access_code,
|
130 |
+
'grant_type' => 'authorization_code',
|
131 |
+
'redirect_uri' => $this->get_redirect_uri(),
|
132 |
+
'client_id' => $this->config['client_id'],
|
133 |
+
'client_secret' => $this->config['client_secret']
|
134 |
+
);
|
135 |
+
|
136 |
+
$response = Ga_Lib_Api_Request::get_instance()->make_request( self::OAUTH2_TOKEN_ENDPOINT, $request );
|
137 |
+
|
138 |
+
return new Ga_Lib_Api_Response( $response );
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Get list of the analytics accounts.
|
143 |
+
*
|
144 |
+
* @return Ga_Lib_Api_Response Returns response object
|
145 |
+
*/
|
146 |
+
private function ga_api_account_summaries() {
|
147 |
+
$request = Ga_Lib_Api_Request::get_instance();
|
148 |
+
$request = $this->sign( $request );
|
149 |
+
$response = $request->make_request( self::GA_ACCOUNT_SUMMARIES_ENDPOINT );
|
150 |
+
|
151 |
+
return new Ga_Lib_Api_Response( $response );
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Sends request for Google Analytics data using given query parameters.
|
156 |
+
*
|
157 |
+
* @param $query_params
|
158 |
+
*
|
159 |
+
* @return Ga_Lib_Api_Response Returns response object
|
160 |
+
*/
|
161 |
+
private function ga_api_data( $query_params ) {
|
162 |
+
$request = Ga_Lib_Api_Request::get_instance();
|
163 |
+
$request = $this->sign( $request );
|
164 |
+
$response = $request->make_request( self::GA_DATA_ENDPOINT, wp_json_encode( $query_params ), true );
|
165 |
+
|
166 |
+
return new Ga_Lib_Api_Response( $response );
|
167 |
+
}
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Sign request with Access Token.
|
171 |
+
* Adds Access Token to the request's headers.
|
172 |
+
*
|
173 |
+
* @param Ga_Lib_Api_Request $request
|
174 |
+
*
|
175 |
+
* @return Ga_Lib_Api_Request Returns response object
|
176 |
+
*/
|
177 |
+
private function sign( Ga_Lib_Api_Request $request ) {
|
178 |
+
// Add the OAuth2 header to the request
|
179 |
+
$request->set_request_headers( array( 'Authorization: Bearer ' . $this->token['access_token'] ) );
|
180 |
+
|
181 |
+
return $request;
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Checks if Access Token is valid.
|
186 |
+
*
|
187 |
+
* @return bool
|
188 |
+
*/
|
189 |
+
public function is_authorized() {
|
190 |
+
$authorized = true;
|
191 |
+
if ( $this->is_access_token_expired() ) {
|
192 |
+
$authorized = false;
|
193 |
+
}
|
194 |
+
|
195 |
+
return $authorized;
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Returns if the access_token is expired.
|
200 |
+
* @return bool Returns True if the access_token is expired.
|
201 |
+
*/
|
202 |
+
public function is_access_token_expired() {
|
203 |
+
if ( null == $this->token ) {
|
204 |
+
return true;
|
205 |
+
}
|
206 |
+
|
207 |
+
// Check if the token is expired in the next 30 seconds.
|
208 |
+
$expired = ( $this->token['created'] + ( $this->token['expires_in'] - 30 ) ) < time();
|
209 |
+
|
210 |
+
return $expired;
|
211 |
+
}
|
212 |
+
}
|
lib/Ga_Lib_Api_Request.php
ADDED
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_Lib_Api_Request {
|
4 |
+
|
5 |
+
const HEADER_CONTENT_TYPE = "application/x-www-form-urlencoded";
|
6 |
+
|
7 |
+
const HEADER_CONTENT_TYPE_JSON = "Content-type: application/json";
|
8 |
+
|
9 |
+
const HEADER_ACCEPT = "Accept: application/json, text/javascript, */*; q=0.01";
|
10 |
+
|
11 |
+
const TIMEOUT = 30;
|
12 |
+
|
13 |
+
const USER_AGENT = 'googleanalytics-wordpress-plugin';
|
14 |
+
|
15 |
+
private $headers = array();
|
16 |
+
|
17 |
+
function __construct() {
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Returns API client instance.
|
22 |
+
*
|
23 |
+
* @return Ga_Lib_Api_Request|null
|
24 |
+
*/
|
25 |
+
public static function get_instance() {
|
26 |
+
static $instance = null;
|
27 |
+
if ( $instance === null ) {
|
28 |
+
$instance = new Ga_Lib_Api_Request();
|
29 |
+
}
|
30 |
+
|
31 |
+
return $instance;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Sets request headers.
|
36 |
+
*
|
37 |
+
* @param $headers
|
38 |
+
*/
|
39 |
+
public function set_request_headers( $headers ) {
|
40 |
+
if ( is_array( $headers ) ) {
|
41 |
+
$this->headers = array_merge( $this->headers, $headers );
|
42 |
+
} else {
|
43 |
+
$this->headers[] = $headers;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Perform HTTP request.
|
49 |
+
*
|
50 |
+
* @param string $url URL address
|
51 |
+
* @param string $rawPostBody
|
52 |
+
*
|
53 |
+
* @return string Response
|
54 |
+
* @throws Exception
|
55 |
+
*/
|
56 |
+
public function make_request( $url, $rawPostBody = null, $json = false ) {
|
57 |
+
if ( ! function_exists( 'curl_init' ) ) {
|
58 |
+
throw new Exception( 'cURL functions are not available' );
|
59 |
+
}
|
60 |
+
|
61 |
+
// Set default headers
|
62 |
+
$this->set_request_headers( array(
|
63 |
+
( $json ? self::HEADER_CONTENT_TYPE_JSON : self::HEADER_CONTENT_TYPE ),
|
64 |
+
self::HEADER_ACCEPT,
|
65 |
+
'Expect: 200-OK'
|
66 |
+
) );
|
67 |
+
|
68 |
+
$ch = curl_init( $url );
|
69 |
+
$headers = $this->headers;
|
70 |
+
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
|
71 |
+
|
72 |
+
$curl_timeout = self::TIMEOUT;
|
73 |
+
$php_execution_time = ini_get( 'max_execution_time' );
|
74 |
+
if ( ! empty( $php_execution_time ) && is_numeric( $php_execution_time ) ) {
|
75 |
+
if ( $php_execution_time < 36 && $php_execution_time > 9 ) {
|
76 |
+
$curl_timeout = $php_execution_time - 5;
|
77 |
+
} elseif ( $php_execution_time < 10 ) {
|
78 |
+
$curl_timeout = 5;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $curl_timeout );
|
83 |
+
curl_setopt( $ch, CURLOPT_TIMEOUT, $curl_timeout );
|
84 |
+
curl_setopt( $ch, CURLOPT_HEADER, true );
|
85 |
+
curl_setopt( $ch, CURLINFO_HEADER_OUT, true );
|
86 |
+
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
|
87 |
+
curl_setopt( $ch, CURLOPT_USERAGENT, self::USER_AGENT );
|
88 |
+
|
89 |
+
// POST body
|
90 |
+
if ( ! empty( $rawPostBody ) ) {
|
91 |
+
curl_setopt( $ch, CURLOPT_POST, true );
|
92 |
+
curl_setopt( $ch, CURLOPT_POSTFIELDS, $rawPostBody );
|
93 |
+
}
|
94 |
+
|
95 |
+
// Execute request
|
96 |
+
$response = curl_exec( $ch );
|
97 |
+
|
98 |
+
if ( $error = curl_error( $ch ) ) {
|
99 |
+
$errno = curl_errno( $ch );
|
100 |
+
curl_close( $ch );
|
101 |
+
throw new Exception( $error . ' (' . $errno . ')' );
|
102 |
+
} else {
|
103 |
+
|
104 |
+
$headerSize = curl_getinfo( $ch, CURLINFO_HEADER_SIZE );
|
105 |
+
$header = substr( $response, 0, $headerSize );
|
106 |
+
$body = substr( $response, $headerSize, strlen( $response ) );
|
107 |
+
curl_close( $ch );
|
108 |
+
|
109 |
+
return array( $header, $body );
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
lib/Ga_Lib_Api_Response.php
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class Ga_Lib_Api_Response {
|
4 |
+
|
5 |
+
private $header;
|
6 |
+
private $body;
|
7 |
+
private $data;
|
8 |
+
|
9 |
+
function __construct( $raw_response ) {
|
10 |
+
$this->setHeader( $raw_response[0] );
|
11 |
+
$this->setBody( $raw_response[1] );
|
12 |
+
$this->setData( json_decode( $raw_response[1], true ) );
|
13 |
+
}
|
14 |
+
|
15 |
+
public function setHeader( $header ) {
|
16 |
+
$this->header = $header;
|
17 |
+
}
|
18 |
+
|
19 |
+
public function getHeader() {
|
20 |
+
return $this->header;
|
21 |
+
}
|
22 |
+
|
23 |
+
public function setBody( $body ) {
|
24 |
+
$this->body = $body;
|
25 |
+
}
|
26 |
+
|
27 |
+
public function getBody() {
|
28 |
+
return $this->body;
|
29 |
+
}
|
30 |
+
|
31 |
+
public function setData( $data ) {
|
32 |
+
$this->data = $data;
|
33 |
+
}
|
34 |
+
|
35 |
+
public function getData() {
|
36 |
+
return $this->data;
|
37 |
+
}
|
38 |
+
}
|
overwrite/ga_overwrite.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Created by PhpStorm.
|
4 |
+
* User: mdn
|
5 |
+
* Date: 2016-12-08
|
6 |
+
* Time: 09:15
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! function_exists( 'wp_json_encode' ) ) {
|
10 |
+
function wp_json_encode( $data ) {
|
11 |
+
return json_encode( $data );
|
12 |
+
}
|
13 |
+
}
|
readme.txt
CHANGED
@@ -1,27 +1,60 @@
|
|
1 |
-
=== Google Analytics ===
|
2 |
-
Contributors:
|
3 |
-
Tags: javascript, google, analytics
|
4 |
-
Requires at least:
|
5 |
-
Tested up to: 4.
|
6 |
-
Stable tag:
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
== Description ==
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Google Analytics ===
|
2 |
+
Contributors: ShareThis
|
3 |
+
Tags: analytics, dashboard, google, google analytics, google analytics plugin, javascript, marketing, pageviews, statistics, stats, tracking, visits, web stats, widget, analytics dashboard, google analytics dashboard, google analytics widget, google analytics dashboard
|
4 |
+
Requires at least: 3.8
|
5 |
+
Tested up to: 4.7.0
|
6 |
+
Stable tag: 2.0.0
|
7 |
+
|
8 |
+
Use Google Analytics on your Wordpress site without touching any code, and view visitor reports right in your Wordpress admin dashboard!
|
9 |
+
|
10 |
+
== Description ==
|
11 |
+
|
12 |
+
Google Analytics plugin from ShareThis is the best way to add GA tracking code to your website without modifying any files. Just log in with Google right from your WP admin dashboard and choose which website you want to link. Then you can disable GA tracking of specific users, so that when you are browsing your own site it won't affect your analytics.
|
13 |
+
|
14 |
+
Also, you will be able to see Google Analytics reports in the same interface you already us every day to write and manage your posts - in your Wordpress dashboard. Now you can stay informed on how your website is doing without having to log into a separate tool.
|
15 |
+
|
16 |
+
But wait, there's more! All feature of the Google Analytics plugin are free, with no subscriptions fees or add-ons!
|
17 |
+
|
18 |
+
Features:
|
19 |
+
|
20 |
+
* Simple setup - Adds latest version of Google Analytics javascript to every page
|
21 |
+
* Account linking - no need to copy and paste any code or know your GA ID, just log in with Google, select the required website and it will automatically include the appropriate code
|
22 |
+
* Visitor trends - Shows a summary dashboard with page views, users, pages per session and bounce rate for the past 7 days as compared to the previous 7 days
|
23 |
+
* Traffic sources - Shows top 5 traffic sources so you know where your visitors are coming from
|
24 |
+
* Only track real visitors - Allows you to disable tracking for Admins, Editors, Authors, Contributors, and/or
|
25 |
+
* Subscribers so your analytics represent real visitors
|
26 |
+
* Mobile - Fully optimized for mobile, so you can view your dashboards on any device
|
27 |
+
* More updates coming - Continually updated and supported by a team of top Wordpress developers
|
28 |
+
|
29 |
+
If you don't have a Google Analytics account, you can sign up for free here: https://www.google.com/analytics/
|
30 |
+
|
31 |
+
By downloading and installing this plugin you are agreeing to the <a href="http://www.sharethis.com/privacy/" target="_blank">Privacy Policy</a> and <a href="http://www.sharethis.com/publisher-terms-of-use/" target="_blank">Terms of Service</a>.
|
32 |
+
|
33 |
+
== Installation ==
|
34 |
+
|
35 |
+
1. Install Google Analytics either via WordPress.org plugin repository or directly by uploading the files to your server
|
36 |
+
2. Activate the plugin through the Plugins menu in your WordPress dashboard
|
37 |
+
3. Navigate to the Plugin settings in the WordPress sidebar
|
38 |
+
4. Authenticate via Google, copy and paste the access code and choose your property from the dropdown. You can also add the web property ID from Google Analytics manually but dashboards won't show up in this case.
|
39 |
+
|
40 |
+
== Screenshots ==
|
41 |
+
|
42 |
+
1. Overall site performance - the past 7 days vs previous 7 days
|
43 |
+
2. The top 5 traffic sources for the past 7 days
|
44 |
+
3. Directly authenticate Google Analytics, and exclude sets of logged in users
|
45 |
+
4. Just click to authenticate, then copy the API key and add it to the plugin
|
46 |
+
5. View different time ranges and key metrics in the Wordpress Google Analytics widget
|
47 |
+
|
48 |
+
== Changelog ==
|
49 |
+
|
50 |
+
= 2.0.0 =
|
51 |
+
* Completely redesigned with new features!
|
52 |
+
* Updated with the latest Google Analytics code
|
53 |
+
* No need to find your GA property ID and copy it over, just sign in with Google and choose your site
|
54 |
+
* See analytics right inside the plugin, the past 7 days vs your previous 7 days
|
55 |
+
* Shows pageviews, users, pages per session and bounce rate + top 5 traffic referrals
|
56 |
+
* Wordpress Dashboard widget for 7, 30 or 90 days graph and top site usage stats
|
57 |
+
* Disable tracking for logged in users like admins or editors for more reliable analytics
|
58 |
+
|
59 |
+
= 1.0.7 =
|
60 |
+
* Added ability to include Google Analytics tracking code on every WordPress page
|
screenshot-1.png
CHANGED
Binary file
|
screenshot-2.png
CHANGED
Binary file
|
screenshot-3.png
ADDED
Binary file
|
screenshot-4.png
ADDED
Binary file
|
screenshot-5.png
ADDED
Binary file
|
view/ga_accounts_selector.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wrap">
|
2 |
+
<input type="hidden" name="<?php echo esc_attr( Ga_Admin::GA_SELECTED_ACCOUNT ); ?>"
|
3 |
+
value="<?php echo esc_attr( $selected ); ?>">
|
4 |
+
<select id="ga_account_selector"
|
5 |
+
name="<?php echo esc_attr( Ga_Admin::GA_SELECTED_ACCOUNT ); ?>" <?php echo esc_attr( $add_manually_enabled ? 'disabled="disabled"' : '' ); ?>>
|
6 |
+
<option><?php _e( 'Please select your Google Analytics account:' ); ?></option>
|
7 |
+
<?php
|
8 |
+
if ( ! empty( $selector ) ) {
|
9 |
+
foreach ( $selector as $account ) {
|
10 |
+
?>
|
11 |
+
<optgroup label="<?php echo $account['name']; ?>">
|
12 |
+
<?php foreach ( $account['webProperties'] as $property ): ?>
|
13 |
+
<?php foreach ( $property['profiles'] as $profile ): ?>
|
14 |
+
<option
|
15 |
+
value="<?php echo esc_attr( $account['id'] . "_" . $property['webPropertyId'] . "_" . $profile['id'] ) ?>"
|
16 |
+
<?php echo( $selected === $account['id'] . "_" . $property['webPropertyId'] . "_" . $profile['id'] ? 'selected="selected"' : '' ); ?>><?php echo esc_html( $property['name'] . " [" . $property['webPropertyId'] . "][" . $profile['id'] . "]" ) ?></option>
|
17 |
+
<?php endforeach; ?>
|
18 |
+
<?php endforeach; ?>
|
19 |
+
</optgroup>
|
20 |
+
<?php
|
21 |
+
}
|
22 |
+
}
|
23 |
+
?>
|
24 |
+
</select>
|
25 |
+
</div>
|
26 |
+
|
view/ga_code.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script>
|
2 |
+
(function (i, s, o, g, r, a, m) {
|
3 |
+
i['GoogleAnalyticsObject'] = r;
|
4 |
+
i[r] = i[r] || function () {
|
5 |
+
(i[r].q = i[r].q || []).push(arguments)
|
6 |
+
}, i[r].l = 1 * new Date();
|
7 |
+
a = s.createElement(o),
|
8 |
+
m = s.getElementsByTagName(o)[0];
|
9 |
+
a.async = 1;
|
10 |
+
a.src = g;
|
11 |
+
m.parentNode.insertBefore(a, m)
|
12 |
+
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
|
13 |
+
|
14 |
+
ga('create', '<?php echo esc_attr( $data[ Ga_Admin::GA_WEB_PROPERTY_ID_OPTION_NAME ] ); ?>', 'auto');
|
15 |
+
ga('send', 'pageview');
|
16 |
+
</script>
|
view/ga_dashboard_widget.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wrap ga-wrap">
|
2 |
+
|
3 |
+
<div class="form-group">
|
4 |
+
<select id="range-selector" autocomplete="off">
|
5 |
+
<option value="7daysAgo">Last 7 Days</option>
|
6 |
+
<option value="30daysAgo" selected="selected">Last 30 Days</option>
|
7 |
+
<option value="90daysAgo">Last 90 Days</option>
|
8 |
+
</select>
|
9 |
+
|
10 |
+
<select id="metrics-selector" autocomplete="off">
|
11 |
+
<option value="pageviews">Pageviews</option>
|
12 |
+
<option value="sessions">Visits</option>
|
13 |
+
<option value="users">Users</option>
|
14 |
+
<option value="organicSearches">Organic Search</option>
|
15 |
+
<option value="visitBounceRate">Bounce Rate</option>
|
16 |
+
</select>
|
17 |
+
|
18 |
+
<div class="ga-loader-wrapper">
|
19 |
+
<div class="ga-loader"></div>
|
20 |
+
</div>
|
21 |
+
</div>
|
22 |
+
|
23 |
+
<div>
|
24 |
+
<div id="chart_div" style="width: 100%;"></div>
|
25 |
+
<div>
|
26 |
+
<div id="boxes-container">
|
27 |
+
<div class="ga-box-row">
|
28 |
+
<?php if ( ! empty( $boxes ) ) : ?>
|
29 |
+
<?php $iter = 1; ?>
|
30 |
+
<?php foreach ( $boxes as $k => $v ) : ?>
|
31 |
+
<div class="ga-box-column ga-box-dashboard">
|
32 |
+
<div style="color: grey; font-size: 13px;"
|
33 |
+
id="ga_box_dashboard_label_<?php echo $k; ?>"><?php echo $v['label'] ?></div>
|
34 |
+
<div style="font-size: 15px;"
|
35 |
+
id="ga_box_dashboard_value_<?php echo $k; ?>"><?php echo $v['value'] ?></div>
|
36 |
+
</div>
|
37 |
+
<?php if ( ( ( $iter ++ ) % 3 ) == 0 ) : ?>
|
38 |
+
</div>
|
39 |
+
<div class="ga-box-row">
|
40 |
+
<?php endif; ?>
|
41 |
+
<?php endforeach; ?>
|
42 |
+
<?php endif; ?>
|
43 |
+
</div>
|
44 |
+
</div>
|
45 |
+
</div>
|
46 |
+
</div>
|
47 |
+
|
48 |
+
<div style="margin-top: 5px;"><?php echo sprintf( '<a href="%s">' . __( 'Show more details' ) . '</a>', $more_details_url ); ?></div>
|
49 |
+
</div>
|
50 |
+
|
51 |
+
<script type="text/javascript">
|
52 |
+
|
53 |
+
dataArr = [['Day', 'Pageviews'],<?php
|
54 |
+
if ( $chart ) {
|
55 |
+
$arr = "";
|
56 |
+
foreach ( $chart as $row ) {
|
57 |
+
if ( $arr ) {
|
58 |
+
$arr .= ",";
|
59 |
+
}
|
60 |
+
$arr .= "['" . $row['day'] . "'," . $row['current'] . "]";
|
61 |
+
}
|
62 |
+
}
|
63 |
+
echo $arr;
|
64 |
+
?>];
|
65 |
+
|
66 |
+
ga_dashboard.init(dataArr);
|
67 |
+
ga_dashboard.events(dataArr);
|
68 |
+
|
69 |
+
</script>
|
view/ga_notice.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div id="googleanalytics_terms_notice" class="notice notice-warning <?php echo ( Ga_Helper::is_plugin_page() ) ? : 'is-dismissible' ?>">
|
2 |
+
<p>
|
3 |
+
Google Analytics <?php echo esc_html( GOOGLEANALYTICS_VERSION ); ?> plugin <a href="http://www.sharethis.com/news/2016/12/sharethis-adds-analytics-plugin-to-suite-of-tools/" target="_blank">has joined the ShareThis family.</a> <strong>A host of new features</strong> has been added in this version, including Google Analytics dashboards and roles management, and the update requires agreeing to the <a href="http://www.sharethis.com/privacy/" target="_blank">privacy policy</a> and <a href="http://www.sharethis.com/publisher-terms-of-use/" target="_blank">terms of use</a> to enable them. <a href="<?php echo esc_url( $url ); ?>"><span class="button button-primary">I accept</span></a>
|
4 |
+
</p>
|
5 |
+
</div>
|
6 |
+
<script type="text/javascript">
|
7 |
+
jQuery( document ).ready( function () {
|
8 |
+
jQuery( '#googleanalytics_terms_notice .notice-dismiss' ).live( 'click', function ( event ) {
|
9 |
+
event.preventDefault();
|
10 |
+
jQuery.post( ajaxurl, { action: 'googleanalytics_hide_terms' } );
|
11 |
+
} );
|
12 |
+
} );
|
13 |
+
</script>
|
view/ga_oauth_notice.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wrap ga-notice">
|
2 |
+
<div class="alert alert-warning">
|
3 |
+
<?php echo $msg; ?>
|
4 |
+
</div>
|
5 |
+
</div>
|
view/page.php
ADDED
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div id="ga_access_code_modal" class="modal fade" tabindex="-1" role="dialog" style="z-index: 1000000">
|
2 |
+
<div class="modal-dialog" role="document">
|
3 |
+
<div class="modal-content">
|
4 |
+
<div class="modal-header">
|
5 |
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
6 |
+
aria-hidden="true">×</span></button>
|
7 |
+
<h4 class="modal-title"><?php _e( 'Please paste the access code obtained from Google below:' ) ?></h4>
|
8 |
+
</div>
|
9 |
+
<div class="modal-body">
|
10 |
+
<label for="ga_access_code"><strong><?php _e( 'Access Code' ); ?></strong>:</label>
|
11 |
+
<input id="ga_access_code_tmp" type="text" style="width: 350px"
|
12 |
+
placeholder="<?php _e( 'Paste your access code here' ) ?>"/>
|
13 |
+
<div class="ga-loader-wrapper">
|
14 |
+
<div class="ga-loader"></div>
|
15 |
+
</div>
|
16 |
+
</div>
|
17 |
+
<div class="modal-footer">
|
18 |
+
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
19 |
+
<button type="button" class="btn btn-primary"
|
20 |
+
id="ga_save_access_code"
|
21 |
+
onclick="ga_popup.saveAccessCode(event)"><?php _e( 'Save Changes' ); ?></button>
|
22 |
+
</div>
|
23 |
+
</div><!-- /.modal-content -->
|
24 |
+
</div><!-- /.modal-dialog -->
|
25 |
+
</div><!-- /.modal -->
|
26 |
+
|
27 |
+
<div class="wrap ga-wrap">
|
28 |
+
<h2>Google Analytics - <?php _e( 'Settings' ); ?></h2>
|
29 |
+
<div class="ga_container">
|
30 |
+
<form id="ga_form" method="post" action="options.php">
|
31 |
+
<?php settings_fields( 'googleanalytics' ); ?>
|
32 |
+
<input id="ga_access_code" type="hidden"
|
33 |
+
name="<?php echo esc_attr( Ga_Admin::GA_OAUTH_AUTH_CODE_OPTION_NAME ); ?>" value=""/>
|
34 |
+
<table class="form-table">
|
35 |
+
<tr valign="top">
|
36 |
+
<?php if ( ! empty( $data['popup_url'] ) ): ?>
|
37 |
+
<th scope="row">
|
38 |
+
<label <?php echo ( ! Ga_Helper::are_terms_accepted() ) ? 'class="label-grey ga-tooltip"' : '' ?>><?php echo _e( 'Google Profile' ) ?>
|
39 |
+
:
|
40 |
+
<span class="ga-tooltiptext ga-tt-abs"><?php _e( 'Please accept the terms to use this feature' ); ?></span>
|
41 |
+
</label>
|
42 |
+
</th>
|
43 |
+
<td <?php echo ( ! Ga_Helper::are_terms_accepted() ) ? 'class="ga-tooltip"' : ''; ?>>
|
44 |
+
<button id="ga_authorize_with_google_button" class="btn btn-primary"
|
45 |
+
<?php if ( Ga_Helper::are_terms_accepted() ) : ?>
|
46 |
+
onclick="ga_popup.authorize(event, '<?php echo esc_attr( $data['popup_url'] ); ?>')"
|
47 |
+
<?php endif; ?>
|
48 |
+
<?php echo( ( esc_attr( $data[ Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME ] ) || ! Ga_Helper::are_terms_accepted() ) ? 'disabled="disabled"' : '' ); ?>
|
49 |
+
><?php _e( 'Authenticate
|
50 |
+
with Google' ) ?>
|
51 |
+
</button>
|
52 |
+
<span class="ga-tooltiptext"><?php _e( 'Please accept the terms to use this feature' ); ?></span>
|
53 |
+
<?php if ( ! empty( $data[ Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME ] ) ): ?>
|
54 |
+
<div class="ga_warning">
|
55 |
+
<strong><?php _e( 'Notice' ) ?></strong>: <?php _e( 'Please uncheck the "Manually enter Tracking ID" option to authenticate and view statistics.' ); ?>
|
56 |
+
</div>
|
57 |
+
<?php endif; ?>
|
58 |
+
</td>
|
59 |
+
<?php endif; ?>
|
60 |
+
|
61 |
+
<?php if ( ! empty( $data['ga_accounts_selector'] ) ): ?>
|
62 |
+
<th scope="row"><?php echo _e( 'Google Analytics Account' ) ?>:</th>
|
63 |
+
<td><?php echo $data['ga_accounts_selector']; ?></td>
|
64 |
+
<?php endif; ?>
|
65 |
+
|
66 |
+
</tr>
|
67 |
+
|
68 |
+
<tr valign="top">
|
69 |
+
|
70 |
+
<th scope="row">
|
71 |
+
<div class="checkbox">
|
72 |
+
<label class="ga_checkbox_label <?php echo ( ! Ga_Helper::are_terms_accepted() ) ? 'label-grey ga-tooltip' : '' ?>"
|
73 |
+
for="ga_enter_code_manually"> <input
|
74 |
+
<?php if ( Ga_Helper::are_terms_accepted() ) : ?>
|
75 |
+
onclick="ga_events.click( this, ga_events.codeManuallyCallback( <?php echo Ga_Helper::are_terms_accepted() ? 1 : 0; ?> ) )"
|
76 |
+
<?php endif; ?>
|
77 |
+
type="checkbox"
|
78 |
+
<?php echo ( ! Ga_Helper::are_terms_accepted() ) ? 'disabled="disabled"' : ''; ?>
|
79 |
+
name="<?php echo esc_attr( Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME ); ?>"
|
80 |
+
id="ga_enter_code_manually"
|
81 |
+
value="1"
|
82 |
+
<?php echo( ( $data[ Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME ] || ! Ga_Helper::are_terms_accepted() ) ? 'checked="checked"' : '' ); ?>/>
|
83 |
+
<?php _e( 'Manually enter Tracking ID' ) ?>
|
84 |
+
<span class="ga-tooltiptext ga-tt-abs"><?php _e( 'Please accept the terms to use this feature' ); ?></span>
|
85 |
+
</label>
|
86 |
+
</div>
|
87 |
+
</th>
|
88 |
+
<td></td>
|
89 |
+
</tr>
|
90 |
+
<tr valign="top"
|
91 |
+
id="ga_manually_wrapper" <?php echo( ( $data[ Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_OPTION_NAME ] || ! Ga_Helper::are_terms_accepted() ) ? '' : 'style="display: none"' ); ?> >
|
92 |
+
|
93 |
+
<th scope="row"><?php _e( 'Tracking ID' ) ?>:</th>
|
94 |
+
<td>
|
95 |
+
<input type="text"
|
96 |
+
name="<?php echo esc_attr( Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME ); ?>"
|
97 |
+
value="<?php echo esc_attr( $data[ Ga_Admin::GA_WEB_PROPERTY_ID_MANUALLY_VALUE_OPTION_NAME ] ); ?>"
|
98 |
+
id="ga_manually_input"/>
|
99 |
+
<div class="ga_warning">
|
100 |
+
<strong><?php _e( 'Warning' ); ?></strong>: <?php _e( 'If you enter your Tracking ID manually, Analytics statistics will not be shown.' ); ?>
|
101 |
+
<br>
|
102 |
+
<?php _e( 'We strongly recommend to authenticate with Google using the button above.' ); ?>
|
103 |
+
</div>
|
104 |
+
</td>
|
105 |
+
|
106 |
+
</tr>
|
107 |
+
|
108 |
+
<tr valign="top">
|
109 |
+
<th scope="row">
|
110 |
+
<label <?php echo ( ! Ga_Helper::are_terms_accepted() ) ? 'class="label-grey ga-tooltip"' : '' ?>><?php _e( 'Exclude Tracking for Roles' ) ?>
|
111 |
+
:
|
112 |
+
<span class="ga-tooltiptext ga-tt-abs"><?php _e( 'Please accept the terms to use this feature' ); ?></span>
|
113 |
+
</label>
|
114 |
+
</th>
|
115 |
+
<td>
|
116 |
+
|
117 |
+
|
118 |
+
<?php
|
119 |
+
if ( ! empty( $data['roles'] ) ) {
|
120 |
+
$roles = $data['roles'];
|
121 |
+
foreach ( $roles as $role ) {
|
122 |
+
|
123 |
+
?>
|
124 |
+
<div class="checkbox">
|
125 |
+
<label class="ga_checkbox_label <?php echo ( ! Ga_Helper::are_terms_accepted() ) ? 'label-grey ga-tooltip' : ''; ?>"
|
126 |
+
for="checkbox_<?php echo $role['id']; ?>">
|
127 |
+
<input id="checkbox_<?php echo $role['id']; ?>" type="checkbox"
|
128 |
+
<?php echo ( ! Ga_Helper::are_terms_accepted() ) ? 'disabled="disabled"' : ''; ?>
|
129 |
+
name="<?php echo esc_attr( Ga_Admin::GA_EXCLUDE_ROLES_OPTION_NAME . "[" . $role['id'] . "]" ); ?>"
|
130 |
+
id="<?php echo esc_attr( $role['id'] ); ?>"
|
131 |
+
<?php echo esc_attr( ( $role['checked'] ? 'checked="checked"' : '' ) ); ?> />
|
132 |
+
<?php echo esc_html( $role['name'] ); ?>
|
133 |
+
<span class="ga-tooltiptext"><?php _e( 'Please accept the terms to use this feature' ); ?></span>
|
134 |
+
</label>
|
135 |
+
</div>
|
136 |
+
<?php
|
137 |
+
}
|
138 |
+
}
|
139 |
+
?>
|
140 |
+
|
141 |
+
</td>
|
142 |
+
</tr>
|
143 |
+
|
144 |
+
</table>
|
145 |
+
|
146 |
+
<p class="submit">
|
147 |
+
<input type="submit" class="button-primary"
|
148 |
+
value="<?php _e( 'Save Changes' ) ?>"/>
|
149 |
+
</p>
|
150 |
+
</form>
|
151 |
+
</div>
|
152 |
+
</div>
|
view/statistics.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wrap ga-wrap">
|
2 |
+
<h2>Google Analytics - <?php _e( 'Dashboard' ); ?></h2>
|
3 |
+
<div class="ga_container" id="exTab2">
|
4 |
+
<?php echo $data ?>
|
5 |
+
</div>
|
6 |
+
</div>
|
view/stats.php
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wrap ga-wrap" id="ga-stats-container">
|
2 |
+
<div class="panel panel-default">
|
3 |
+
<div class="panel-heading"><strong><?php _e( "Pageviews - Last 7 days vs previous 7 days" ) ?></strong></div>
|
4 |
+
<div class="panel-body ga-chart">
|
5 |
+
<div id="chart_div" style="width: 100%;"></div>
|
6 |
+
<div class="ga-loader-wrapper stats-page">
|
7 |
+
<div class="ga-loader stats-page-loader"></div>
|
8 |
+
</div>
|
9 |
+
</div>
|
10 |
+
</div>
|
11 |
+
|
12 |
+
<div class="panel panel-default">
|
13 |
+
<div class="panel-heading"><strong><?php _e( "Comparison - Last 7 days vs previous 7 days" ) ?></strong></div>
|
14 |
+
<div class="panel-body">
|
15 |
+
<div id="boxes-container">
|
16 |
+
<div class="row">
|
17 |
+
<?php if ( ! empty( $boxes ) ) : ?>
|
18 |
+
<?php foreach ( $boxes as $box ) : ?>
|
19 |
+
<div class="col-md-3">
|
20 |
+
<div class="panel panel-default">
|
21 |
+
<div class="panel-body ga-box-centered">
|
22 |
+
<div style="font-size: 16px;"><?php echo $box['label'] ?></div>
|
23 |
+
<div style="color: <?php echo $box['color'] ?>; font-size: 24px;"><?php echo Ga_Helper::format_percent( $box['diff'] ); ?></div>
|
24 |
+
<div style="color: grey; font-size: 16px;"><?php echo $box['comparison'] ?></div>
|
25 |
+
</div>
|
26 |
+
</div>
|
27 |
+
</div>
|
28 |
+
<?php endforeach; ?>
|
29 |
+
<?php endif; ?>
|
30 |
+
</div>
|
31 |
+
</div>
|
32 |
+
</div>
|
33 |
+
</div>
|
34 |
+
<?php if ( ! empty( $sources ) ) : ?>
|
35 |
+
<div class="panel panel-default">
|
36 |
+
<div class="panel-heading"><strong><?php _e( "Top 5 Traffic Sources for the past 7 days" ) ?></strong></div>
|
37 |
+
<div class="panel-body">
|
38 |
+
|
39 |
+
<div id="table-container">
|
40 |
+
<table class="table table-bordered">
|
41 |
+
<tr>
|
42 |
+
<td colspan="2">
|
43 |
+
</td>
|
44 |
+
<th style="text-align: right;">
|
45 |
+
<?php _e( 'Pageviews' ); ?>
|
46 |
+
</th>
|
47 |
+
<th style="text-align: right;">
|
48 |
+
<?php echo '%'; ?>
|
49 |
+
</th>
|
50 |
+
</tr>
|
51 |
+
<tr>
|
52 |
+
<td style="width: 20%; font-size: 20px;text-align:center" colspan="2"></td>
|
53 |
+
<td class="col-md-2" style="text-align: right">
|
54 |
+
<div style="font-size: 16px;"><?php echo $sources['total'] ?></div>
|
55 |
+
<div style="color: grey; font-size: 10px;">% of
|
56 |
+
Total: <?php echo Ga_Helper::format_percent( ( ! empty( $sources['total'] ) ) ? number_format( $sources['sum'] / $sources['total'] * 100, 2, '.', ' ' ) : 100 ); ?>
|
57 |
+
(<?php echo $sources['sum'] ?>)
|
58 |
+
</div>
|
59 |
+
</td>
|
60 |
+
<td class="col-md-5" style="text-align: right">
|
61 |
+
<div style="font-size: 16px;"><?php echo $sources['total'] ?></div>
|
62 |
+
<div style="color: grey; font-size: 10px;">% of
|
63 |
+
Total: <?php echo Ga_Helper::format_percent( ( ! empty( $sources['total'] ) ) ? number_format( $sources['sum'] / $sources['total'] * 100, 2, '.', ' ' ) : 100 ); ?>
|
64 |
+
(<?php echo $sources['sum'] ?>)
|
65 |
+
</div>
|
66 |
+
</td>
|
67 |
+
</tr>
|
68 |
+
<?php foreach ( $sources['rows'] as $key => $source ): ?>
|
69 |
+
<tr>
|
70 |
+
<td style="width: 5%;text-align: right"><?php echo $key ?>.</td>
|
71 |
+
<td style="width: 10%;">
|
72 |
+
<?php if ( $source['name'] != '(direct) / (none)' ) : ?>
|
73 |
+
<a href="<?php echo $source['url'] ?>"
|
74 |
+
target="_blank"><?php echo $source['name'] ?></a>
|
75 |
+
<?php else: ?>
|
76 |
+
<?php echo $source['name'] ?>
|
77 |
+
<?php endif; ?>
|
78 |
+
</td>
|
79 |
+
<td style="text-align: right"><?php echo $source['number'] ?></td>
|
80 |
+
<td>
|
81 |
+
<div class="progress">
|
82 |
+
<div class="progress-bar" role="progressbar"
|
83 |
+
aria-valuenow="<?php echo $source['percent'] ?>" aria-valuemin="0"
|
84 |
+
aria-valuemax="100"
|
85 |
+
style="width: <?php echo $source['percent'] ?>%;"></div>
|
86 |
+
<span style="margin-left: 10px;"><?php echo Ga_Helper::format_percent( $source['percent'] ); ?></span>
|
87 |
+
</div>
|
88 |
+
</td>
|
89 |
+
</tr>
|
90 |
+
<?php endforeach; ?>
|
91 |
+
</table>
|
92 |
+
</div>
|
93 |
+
</div>
|
94 |
+
</div>
|
95 |
+
<?php endif; ?>
|
96 |
+
|
97 |
+
<?php if ( ! empty( $chart ) ) : ?>
|
98 |
+
<script type="text/javascript">
|
99 |
+
|
100 |
+
ga_charts.init(function () {
|
101 |
+
|
102 |
+
var data = new google.visualization.DataTable();
|
103 |
+
data.addColumn('string', 'Day');
|
104 |
+
data.addColumn('number', '<?php echo $labels['thisWeek'] ?>');
|
105 |
+
data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
|
106 |
+
data.addColumn('number', '<?php echo $labels['lastWeek'] ?>');
|
107 |
+
data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});
|
108 |
+
|
109 |
+
<?php foreach ( $chart as $row ) : ?>
|
110 |
+
data.addRow(['<?php echo $row['day'] ?>', <?php echo $row['current'] ?>, ga_charts.createTooltip('<?php echo $row['day'] ?>', '<?php echo $row['current'] ?>'), <?php echo $row['previous'] ?>, ga_charts.createTooltip('<?php echo $row['previous-day'] ?>', '<?php echo $row['previous'] ?>')]);
|
111 |
+
<?php endforeach; ?>
|
112 |
+
ga_charts.events(data);
|
113 |
+
ga_charts.drawChart(data);
|
114 |
+
ga_loader.hide();
|
115 |
+
}
|
116 |
+
);
|
117 |
+
</script>
|
118 |
+
<?php endif; ?>
|
119 |
+
</div>
|