Version Description
- 10-1-19 =
- Added: 'mainwp_child_branding_init_options' filter for disabling custom branding
- Updated: support for the WPVulnDB API v3
- Removed: unused code and files
Download this release
Release Info
Developer | mainwp |
Plugin | MainWP Child |
Version | 4.0.3 |
Comparing to | |
See all releases |
Code changes from version 4.0.2 to 4.0.3
- class/class-mainwp-child-branding.php +3 -1
- class/class-mainwp-child-vulnerability-checker.php +23 -16
- class/class-mainwp-child.php +10 -92
- class/class-mainwp-heatmap-tracker.php +0 -424
- js/heatmap.js +0 -362
- js/heatmapinit.js +0 -41
- js/tracker.js +0 -62
- mainwp-child.php +1 -5
- readme.txt +6 -1
class/class-mainwp-child-branding.php
CHANGED
@@ -56,7 +56,9 @@ class MainWP_Child_Branding {
|
|
56 |
$opts['branding_preserve_title'] = stripslashes( $branding_header['name'] );
|
57 |
}
|
58 |
}
|
59 |
-
}
|
|
|
|
|
60 |
return $opts;
|
61 |
}
|
62 |
|
56 |
$opts['branding_preserve_title'] = stripslashes( $branding_header['name'] );
|
57 |
}
|
58 |
}
|
59 |
+
}
|
60 |
+
|
61 |
+
$opts = apply_filters( 'mainwp_child_branding_init_options', $opts );
|
62 |
return $opts;
|
63 |
}
|
64 |
|
class/class-mainwp-child-vulnerability-checker.php
CHANGED
@@ -19,8 +19,10 @@
|
|
19 |
class MainWP_Child_Vulnerability_Checker {
|
20 |
|
21 |
public static $instance = null;
|
|
|
|
|
22 |
|
23 |
-
|
24 |
if ( null === MainWP_Child_Vulnerability_Checker::$instance ) {
|
25 |
MainWP_Child_Vulnerability_Checker::$instance = new MainWP_Child_Vulnerability_Checker();
|
26 |
}
|
@@ -28,18 +30,22 @@ class MainWP_Child_Vulnerability_Checker {
|
|
28 |
}
|
29 |
|
30 |
public function __construct() {
|
31 |
-
|
32 |
}
|
33 |
|
34 |
public function action() {
|
35 |
$information = array();
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
|
|
|
|
|
|
43 |
MainWP_Helper::write( $information );
|
44 |
}
|
45 |
|
@@ -66,7 +72,7 @@ class MainWP_Child_Vulnerability_Checker {
|
|
66 |
$string = explode('/',$plug);
|
67 |
$plug_vuln = get_transient('mainwp_vulnche_trans_plug_'.$string[0]);
|
68 |
if(false === $plug_vuln || $force) {
|
69 |
-
$plug_vuln = $this->vulnche_get_content('
|
70 |
set_transient('mainwp_vulnche_trans_plug_'.$string[0],$plug_vuln, 1 * DAY_IN_SECONDS);
|
71 |
}
|
72 |
if ($plug_vuln) {
|
@@ -115,7 +121,7 @@ class MainWP_Child_Vulnerability_Checker {
|
|
115 |
$wp_vuln = get_transient('mainwp_vulnche_trans_wp_json');
|
116 |
$wp_version = str_replace('.', '', get_bloginfo('version'));
|
117 |
if(false === $wp_vuln || $force) {
|
118 |
-
$wp_vuln = $this->vulnche_get_content('
|
119 |
set_transient('mainwp_vulnche_trans_wp_json', $wp_vuln, 1 * DAY_IN_SECONDS);
|
120 |
}
|
121 |
return $wp_vuln;
|
@@ -138,7 +144,7 @@ class MainWP_Child_Vulnerability_Checker {
|
|
138 |
if(empty($th['parent'])) {
|
139 |
$th_vuln = get_transient('mainwp_vulnche_trans_theme_' . $th['id']);
|
140 |
if (false === $th_vuln || $force) {
|
141 |
-
$th_vuln = $this->vulnche_get_content('
|
142 |
set_transient('mainwp_vulnche_trans_theme_' . $th['id'], $th_vuln, 1 * DAY_IN_SECONDS);
|
143 |
}
|
144 |
|
@@ -190,12 +196,13 @@ class MainWP_Child_Vulnerability_Checker {
|
|
190 |
}
|
191 |
|
192 |
|
193 |
-
function vulnche_get_content ($url) {
|
194 |
-
|
195 |
$ch = curl_init();
|
196 |
|
197 |
-
curl_setopt($ch, CURLOPT_URL, $url);
|
198 |
curl_setopt($ch, CURLOPT_HEADER, 0);
|
|
|
199 |
curl_setopt($ch, CURLOPT_USERAGENT, $this->get_random_user_agent());
|
200 |
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
|
201 |
|
@@ -205,7 +212,7 @@ class MainWP_Child_Vulnerability_Checker {
|
|
205 |
curl_close($ch);
|
206 |
if ($output === false || $info != 200) {
|
207 |
$output = null;
|
208 |
-
}
|
209 |
return $output;
|
210 |
}
|
211 |
|
19 |
class MainWP_Child_Vulnerability_Checker {
|
20 |
|
21 |
public static $instance = null;
|
22 |
+
private $wpvulndb_api = 'https://wpvulndb.com/api/v3/';
|
23 |
+
private $wpvulndb_token = false;
|
24 |
|
25 |
+
static function Instance() {
|
26 |
if ( null === MainWP_Child_Vulnerability_Checker::$instance ) {
|
27 |
MainWP_Child_Vulnerability_Checker::$instance = new MainWP_Child_Vulnerability_Checker();
|
28 |
}
|
30 |
}
|
31 |
|
32 |
public function __construct() {
|
33 |
+
$this->wpvulndb_token = get_option('mainwp_child_wpvulndb_token', '');
|
34 |
}
|
35 |
|
36 |
public function action() {
|
37 |
$information = array();
|
38 |
+
|
39 |
+
if ( ! empty( $this->wpvulndb_token ) ) {
|
40 |
+
if ( isset( $_POST['mwp_action'] ) ) {
|
41 |
+
switch ( $_POST['mwp_action'] ) {
|
42 |
+
case 'vulner_recheck':
|
43 |
+
$information = $this->vulner_recheck();
|
44 |
+
break;
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
MainWP_Helper::write( $information );
|
50 |
}
|
51 |
|
72 |
$string = explode('/',$plug);
|
73 |
$plug_vuln = get_transient('mainwp_vulnche_trans_plug_'.$string[0]);
|
74 |
if(false === $plug_vuln || $force) {
|
75 |
+
$plug_vuln = $this->vulnche_get_content( $this->wpvulndb_api . 'plugins/' . $string[0]);
|
76 |
set_transient('mainwp_vulnche_trans_plug_'.$string[0],$plug_vuln, 1 * DAY_IN_SECONDS);
|
77 |
}
|
78 |
if ($plug_vuln) {
|
121 |
$wp_vuln = get_transient('mainwp_vulnche_trans_wp_json');
|
122 |
$wp_version = str_replace('.', '', get_bloginfo('version'));
|
123 |
if(false === $wp_vuln || $force) {
|
124 |
+
$wp_vuln = $this->vulnche_get_content( $this->wpvulndb_api . 'wordpresses/' . $wp_version);
|
125 |
set_transient('mainwp_vulnche_trans_wp_json', $wp_vuln, 1 * DAY_IN_SECONDS);
|
126 |
}
|
127 |
return $wp_vuln;
|
144 |
if(empty($th['parent'])) {
|
145 |
$th_vuln = get_transient('mainwp_vulnche_trans_theme_' . $th['id']);
|
146 |
if (false === $th_vuln || $force) {
|
147 |
+
$th_vuln = $this->vulnche_get_content( $this->wpvulndb_api . 'themes/' . $th['id']);
|
148 |
set_transient('mainwp_vulnche_trans_theme_' . $th['id'], $th_vuln, 1 * DAY_IN_SECONDS);
|
149 |
}
|
150 |
|
196 |
}
|
197 |
|
198 |
|
199 |
+
function vulnche_get_content ( $url ) {
|
200 |
+
|
201 |
$ch = curl_init();
|
202 |
|
203 |
+
curl_setopt($ch, CURLOPT_URL, $url);
|
204 |
curl_setopt($ch, CURLOPT_HEADER, 0);
|
205 |
+
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Token token=' . $this->wpvulndb_token));
|
206 |
curl_setopt($ch, CURLOPT_USERAGENT, $this->get_random_user_agent());
|
207 |
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
|
208 |
|
212 |
curl_close($ch);
|
213 |
if ($output === false || $info != 200) {
|
214 |
$output = null;
|
215 |
+
}
|
216 |
return $output;
|
217 |
}
|
218 |
|
class/class-mainwp-child.php
CHANGED
@@ -115,7 +115,7 @@ if ( isset( $_GET['skeleton_keyuse_nonce_key'] ) && isset( $_GET['skeleton_keyus
|
|
115 |
}
|
116 |
|
117 |
class MainWP_Child {
|
118 |
-
public static $version = '4.0.
|
119 |
private $update_version = '1.5';
|
120 |
|
121 |
private $callableFunctions = array(
|
@@ -165,7 +165,6 @@ class MainWP_Child {
|
|
165 |
'createBackupPoll' => 'backupPoll',
|
166 |
'page_speed' => 'page_speed',
|
167 |
'woo_com_status' => 'woo_com_status',
|
168 |
-
'heatmaps' => 'heatmaps',
|
169 |
'links_checker' => 'links_checker',
|
170 |
'wordfence' => 'wordfence',
|
171 |
'delete_backup' => 'delete_backup',
|
@@ -376,7 +375,6 @@ class MainWP_Child {
|
|
376 |
'mainwp_child_remove_scripts_version',
|
377 |
'mainwp_child_remove_styles_version',
|
378 |
'mainwp_child_remove_readme',
|
379 |
-
'heatMapEnabled',
|
380 |
'mainwp_child_clone_sites',
|
381 |
'mainwp_child_pluginDir',
|
382 |
'mainwp_premium_updates',
|
@@ -433,10 +431,6 @@ class MainWP_Child {
|
|
433 |
'mainwp_child_fix_htaccess',
|
434 |
'mainwp_child_pluginDir',
|
435 |
'mainwp_child_htaccess_set',
|
436 |
-
'heatMapEnabled',
|
437 |
-
'heatMapsIndividualOverrideSetting',
|
438 |
-
'heatMapExtensionLoaded',
|
439 |
-
'heatMapsIndividualDisable',
|
440 |
'mainwp_child_nossl',
|
441 |
'mainwp_updraftplus_ext_enabled',
|
442 |
'mainwpKeywordLinks',
|
@@ -1087,43 +1081,6 @@ class MainWP_Child {
|
|
1087 |
return;
|
1088 |
}
|
1089 |
|
1090 |
-
// if ( 'hidden' === ( get_option( 'mainwp_child_pluginDir' ) ) && ( $hard || 'yes' !== ( get_option( 'mainwp_child_htaccess_set' ) ) ) ) {
|
1091 |
-
|
1092 |
-
// include_once( ABSPATH . '/wp-admin/includes/misc.php' );
|
1093 |
-
//
|
1094 |
-
// $snPluginDir = basename( $this->plugin_dir );
|
1095 |
-
//
|
1096 |
-
// $rules = null;
|
1097 |
-
// if ( ( '1' !== get_option( 'heatMapsIndividualOverrideSetting' ) && '0' !== get_option( 'heatMapEnabled' ) ) ||
|
1098 |
-
// ( '1' === get_option( 'heatMapsIndividualOverrideSetting' ) && '1' !== get_option( 'heatMapsIndividualDisable' ) ) ||
|
1099 |
-
// get_option( 'mainwp_kwl_enable_statistic' )
|
1100 |
-
// ) {
|
1101 |
-
// //Heatmap enabled
|
1102 |
-
// //Make the plugin invisible, except heatmap
|
1103 |
-
// $rules = $this->mod_rewrite_rules( array( 'wp-content/plugins/' . $snPluginDir . '/([^js\/]*)$' => 'wp-content/plugins/THIS_PLUGIN_DOES_NOT_EXIST' ) );
|
1104 |
-
// } else {
|
1105 |
-
// //Make the plugin invisible
|
1106 |
-
// $rules = $this->mod_rewrite_rules( array( 'wp-content/plugins/' . $snPluginDir . '/(.*)$' => 'wp-content/plugins/THIS_PLUGIN_DOES_NOT_EXIST' ) );
|
1107 |
-
// }
|
1108 |
-
//
|
1109 |
-
// $home_path = ABSPATH;
|
1110 |
-
// $htaccess_file = $home_path . '.htaccess';
|
1111 |
-
// if ( function_exists( 'save_mod_rewrite_rules' ) ) {
|
1112 |
-
// $rules = explode( "\n", $rules );
|
1113 |
-
//
|
1114 |
-
// // $ch = @fopen($htaccess_file,'w');
|
1115 |
-
// // if (@flock($ch, LOCK_EX))
|
1116 |
-
// // {
|
1117 |
-
// insert_with_markers( $htaccess_file, 'MainWP', $rules );
|
1118 |
-
// // }
|
1119 |
-
// // @flock($ch, LOCK_UN);
|
1120 |
-
// // @fclose($ch);
|
1121 |
-
//
|
1122 |
-
// }
|
1123 |
-
// MainWP_Helper::update_option( 'mainwp_child_htaccess_set', 'yes', 'yes' );
|
1124 |
-
//
|
1125 |
-
// } else
|
1126 |
-
|
1127 |
if ( $hard ) {
|
1128 |
include_once( ABSPATH . '/wp-admin/includes/misc.php' );
|
1129 |
|
@@ -1469,18 +1426,6 @@ class MainWP_Child {
|
|
1469 |
exit();
|
1470 |
}
|
1471 |
|
1472 |
-
// remove_action( 'admin_init', 'send_frame_options_header' );
|
1473 |
-
// remove_action( 'login_init', 'send_frame_options_header' );
|
1474 |
-
|
1475 |
-
// Call Heatmap
|
1476 |
-
if ( 'yes' === get_option( 'heatMapExtensionLoaded' ) ) {
|
1477 |
-
if ( ( '1' !== get_option( 'heatMapsIndividualOverrideSetting' ) && '0' !== get_option( 'heatMapEnabled' ) ) ||
|
1478 |
-
( '1' !== get_option( 'heatMapsIndividualOverrideSetting' ) && '1' !== get_option( 'heatMapsIndividualDisable' ) )
|
1479 |
-
) {
|
1480 |
-
new MainWP_Heatmap_Tracker();
|
1481 |
-
}
|
1482 |
-
}
|
1483 |
-
|
1484 |
/**
|
1485 |
* Security
|
1486 |
*/
|
@@ -3627,22 +3572,6 @@ class MainWP_Child {
|
|
3627 |
function updateExternalSettings() {
|
3628 |
$update_htaccess = false;
|
3629 |
|
3630 |
-
if ( isset( $_POST['heatMap'] ) ) {
|
3631 |
-
if ( '1' === $_POST['heatMap'] ) {
|
3632 |
-
if ( '1' !== get_option( 'heatMapEnabled' ) ) {
|
3633 |
-
$update_htaccess = true;
|
3634 |
-
}
|
3635 |
-
MainWP_Helper::update_option( 'heatMapEnabled', '1', 'yes' );
|
3636 |
-
MainWP_Helper::update_option( 'heatMapExtensionLoaded', 'yes', 'yes' );
|
3637 |
-
} else {
|
3638 |
-
if ( '0' !== get_option( 'heatMapEnabled' ) ) {
|
3639 |
-
$update_htaccess = true;
|
3640 |
-
}
|
3641 |
-
MainWP_Helper::update_option( 'heatMapEnabled', '0', 'yes' );
|
3642 |
-
MainWP_Helper::update_option( 'heatMapExtensionLoaded', '', 'yes' );
|
3643 |
-
}
|
3644 |
-
}
|
3645 |
-
|
3646 |
if ( isset( $_POST['cloneSites'] ) ) {
|
3647 |
if ( '0' !== $_POST['cloneSites'] ) {
|
3648 |
$arr = @json_decode( urldecode( $_POST['cloneSites'] ), 1 );
|
@@ -3690,7 +3619,7 @@ class MainWP_Child {
|
|
3690 |
MainWP_Child_Themes_Check::Instance()->cleanup_deactivation( false );
|
3691 |
}
|
3692 |
}
|
3693 |
-
|
3694 |
$information['version'] = self::$version;
|
3695 |
$information['wpversion'] = $wp_version;
|
3696 |
$information['siteurl'] = get_option( 'siteurl' );
|
@@ -4055,7 +3984,14 @@ class MainWP_Child {
|
|
4055 |
if ( ! is_array( $othersData ) ) {
|
4056 |
$othersData = array();
|
4057 |
}
|
4058 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4059 |
try{
|
4060 |
$information = apply_filters( 'mainwp-site-sync-others-data', $information, $othersData );
|
4061 |
} catch(Exception $e) {
|
@@ -5696,24 +5632,6 @@ class MainWP_Child {
|
|
5696 |
MainWP_Child_WooCommerce_Status::Instance()->action();
|
5697 |
}
|
5698 |
|
5699 |
-
function heatmaps() {
|
5700 |
-
$need_update = true;
|
5701 |
-
if ( isset( $_POST['heatMapsOverride'] ) ) {
|
5702 |
-
$override = $_POST['heatMapsOverride'] ? '1' : '0';
|
5703 |
-
$disable = $_POST['heatMapsDisable'] ? '1' : '0';
|
5704 |
-
if ( get_option( 'heatMapsIndividualOverrideSetting' ) === $override && get_option( 'heatMapsIndividualDisable' ) === $disable ) {
|
5705 |
-
$need_update = false;
|
5706 |
-
}
|
5707 |
-
if ( $need_update ) {
|
5708 |
-
MainWP_Helper::update_option( 'heatMapsIndividualOverrideSetting', $override, 'yes' );
|
5709 |
-
MainWP_Helper::update_option( 'heatMapsIndividualDisable', $disable, 'yes' );
|
5710 |
-
$this->update_htaccess( true );
|
5711 |
-
}
|
5712 |
-
MainWP_Helper::write( array( 'result' => 'success' ) );
|
5713 |
-
}
|
5714 |
-
MainWP_Helper::write( array( 'result' => 'fail' ) );
|
5715 |
-
}
|
5716 |
-
|
5717 |
function links_checker() {
|
5718 |
MainWP_Child_Links_Checker::Instance()->action();
|
5719 |
}
|
115 |
}
|
116 |
|
117 |
class MainWP_Child {
|
118 |
+
public static $version = '4.0.3';
|
119 |
private $update_version = '1.5';
|
120 |
|
121 |
private $callableFunctions = array(
|
165 |
'createBackupPoll' => 'backupPoll',
|
166 |
'page_speed' => 'page_speed',
|
167 |
'woo_com_status' => 'woo_com_status',
|
|
|
168 |
'links_checker' => 'links_checker',
|
169 |
'wordfence' => 'wordfence',
|
170 |
'delete_backup' => 'delete_backup',
|
375 |
'mainwp_child_remove_scripts_version',
|
376 |
'mainwp_child_remove_styles_version',
|
377 |
'mainwp_child_remove_readme',
|
|
|
378 |
'mainwp_child_clone_sites',
|
379 |
'mainwp_child_pluginDir',
|
380 |
'mainwp_premium_updates',
|
431 |
'mainwp_child_fix_htaccess',
|
432 |
'mainwp_child_pluginDir',
|
433 |
'mainwp_child_htaccess_set',
|
|
|
|
|
|
|
|
|
434 |
'mainwp_child_nossl',
|
435 |
'mainwp_updraftplus_ext_enabled',
|
436 |
'mainwpKeywordLinks',
|
1081 |
return;
|
1082 |
}
|
1083 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1084 |
if ( $hard ) {
|
1085 |
include_once( ABSPATH . '/wp-admin/includes/misc.php' );
|
1086 |
|
1426 |
exit();
|
1427 |
}
|
1428 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1429 |
/**
|
1430 |
* Security
|
1431 |
*/
|
3572 |
function updateExternalSettings() {
|
3573 |
$update_htaccess = false;
|
3574 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3575 |
if ( isset( $_POST['cloneSites'] ) ) {
|
3576 |
if ( '0' !== $_POST['cloneSites'] ) {
|
3577 |
$arr = @json_decode( urldecode( $_POST['cloneSites'] ), 1 );
|
3619 |
MainWP_Child_Themes_Check::Instance()->cleanup_deactivation( false );
|
3620 |
}
|
3621 |
}
|
3622 |
+
|
3623 |
$information['version'] = self::$version;
|
3624 |
$information['wpversion'] = $wp_version;
|
3625 |
$information['siteurl'] = get_option( 'siteurl' );
|
3984 |
if ( ! is_array( $othersData ) ) {
|
3985 |
$othersData = array();
|
3986 |
}
|
3987 |
+
|
3988 |
+
if ( isset( $othersData['wpvulndbToken'] ) ) {
|
3989 |
+
$wpvulndb_token = get_option( 'mainwp_child_wpvulndb_token', '' );
|
3990 |
+
if ( $wpvulndb_token != $othersData['wpvulndbToken'] ) {
|
3991 |
+
MainWP_Helper::update_option( 'mainwp_child_wpvulndb_token', $othersData['wpvulndbToken'] );
|
3992 |
+
}
|
3993 |
+
}
|
3994 |
+
|
3995 |
try{
|
3996 |
$information = apply_filters( 'mainwp-site-sync-others-data', $information, $othersData );
|
3997 |
} catch(Exception $e) {
|
5632 |
MainWP_Child_WooCommerce_Status::Instance()->action();
|
5633 |
}
|
5634 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5635 |
function links_checker() {
|
5636 |
MainWP_Child_Links_Checker::Instance()->action();
|
5637 |
}
|
class/class-mainwp-heatmap-tracker.php
DELETED
@@ -1,424 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Class for tracking click heatmap
|
5 |
-
*
|
6 |
-
* Uses $wpdb object
|
7 |
-
*
|
8 |
-
* @version 1.0
|
9 |
-
* @author Jeffri Hong
|
10 |
-
*/
|
11 |
-
class MainWP_Heatmap_Tracker {
|
12 |
-
protected static $instance;
|
13 |
-
protected $server;
|
14 |
-
protected $dbVersion = 1000;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Class constructor
|
18 |
-
*
|
19 |
-
* @param boolean $checkDb Do checking the database if set to true
|
20 |
-
*/
|
21 |
-
public function __construct( $checkDb = false ) {
|
22 |
-
self::$instance = $this;
|
23 |
-
$this->server = get_option( 'mainwp_child_server' );
|
24 |
-
add_action( 'template_redirect', array( $this, 'trackerJs' ) );
|
25 |
-
add_action( 'wp_ajax_heatmapSaveClick', array( $this, 'saveClickCallback' ) );
|
26 |
-
add_action( 'wp_ajax_nopriv_heatmapSaveClick', array( $this, 'saveClickCallback' ) );
|
27 |
-
}
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Get Instance
|
31 |
-
*/
|
32 |
-
public static function getInstance() {
|
33 |
-
if ( self::$instance instanceof HeatmapTracker ) {
|
34 |
-
return self::$instance;
|
35 |
-
}
|
36 |
-
self::$instance = new HeatmapTracker( true );
|
37 |
-
|
38 |
-
return self::$instance;
|
39 |
-
}
|
40 |
-
|
41 |
-
/**
|
42 |
-
* Parse which page we are on using URL
|
43 |
-
*/
|
44 |
-
public function getPageObject( $pageUrl ) {
|
45 |
-
global $wp_rewrite;
|
46 |
-
// If post type, we are using url_to_postid function
|
47 |
-
$postId = url_to_postid( $pageUrl );
|
48 |
-
if ( $postId ) {
|
49 |
-
$postType = get_post_type_object( get_post( $postId )->post_type );
|
50 |
-
|
51 |
-
return array(
|
52 |
-
'value' => $postId,
|
53 |
-
'title' => get_the_title( $postId ),
|
54 |
-
'type' => get_post( $postId )->post_type,
|
55 |
-
'label' => ( is_array( $postType->labels ) ? $postType->labels['name'] : $postType->labels->name ),
|
56 |
-
);
|
57 |
-
}
|
58 |
-
$path = str_replace( get_site_url(), '', $pageUrl );
|
59 |
-
$path = trim( $path, '/' );
|
60 |
-
// If path is empty, then it is front page
|
61 |
-
if ( empty( $path ) ) {
|
62 |
-
return array(
|
63 |
-
'value' => get_option( 'page_on_front' ) ? get_option( 'page_on_front' ) : '',
|
64 |
-
'title' => '',
|
65 |
-
'type' => 'front_page',
|
66 |
-
'label' => __( 'Home Page' ),
|
67 |
-
);
|
68 |
-
}
|
69 |
-
// Otherwise, we will try to match through rewrite or by query
|
70 |
-
$rewrite = $wp_rewrite->wp_rewrite_rules();
|
71 |
-
if ( is_array( $rewrite ) && count( $rewrite ) > 0 ) {
|
72 |
-
foreach ( $rewrite as $match => $query ) {
|
73 |
-
if ( preg_match( "#^$match#", $path, $matches ) || preg_match( "#^$match#", urldecode( $path ), $matches ) ) {
|
74 |
-
$query = preg_replace( '!^.*\?!', '', $query );
|
75 |
-
$query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
|
76 |
-
parse_str( $query, $query_vars );
|
77 |
-
break;
|
78 |
-
}
|
79 |
-
}
|
80 |
-
} else {
|
81 |
-
$query = preg_replace( '!^.*\?!', '', $path );
|
82 |
-
parse_str( $query, $query_vars );
|
83 |
-
}
|
84 |
-
// Workaround for fail pagename rewrite match
|
85 |
-
if ( isset( $query_vars['pagename'] ) && strpos( $query_vars['pagename'], '?' ) !== false ) {
|
86 |
-
$query = preg_replace( '!^.*\?!', '', $query_vars['pagename'] );
|
87 |
-
parse_str( $query, $query_vars );
|
88 |
-
}
|
89 |
-
$querypost = new WP_Query( $query_vars );
|
90 |
-
if ( $querypost->is_date() ) {
|
91 |
-
if ( $querypost->query_vars['m'] ) {
|
92 |
-
$date = $querypost->query_vars['m'];
|
93 |
-
} else if ( $querypost->is_day() ) {
|
94 |
-
$date = $querypost->query_vars['year'] . zeroise( $querypost->query_vars['monthnum'], 2 ) . zeroise( $querypost->query_vars['day'], 2 );
|
95 |
-
} else if ( $querypost->is_month() ) {
|
96 |
-
$date = $querypost->query_vars['year'] . zeroise( $querypost->query_vars['monthnum'], 2 );
|
97 |
-
} else if ( $querypost->is_year() ) {
|
98 |
-
$date = $querypost->query_vars['year'];
|
99 |
-
}
|
100 |
-
|
101 |
-
return array(
|
102 |
-
'value' => $date,
|
103 |
-
'title' => '',
|
104 |
-
'type' => 'archive',
|
105 |
-
'label' => __( 'Archive' ),
|
106 |
-
);
|
107 |
-
} else if ( $querypost->is_category() || $querypost->is_tag() || $querypost->is_tax() ) {
|
108 |
-
$tax_query = $querypost->tax_query->queries;
|
109 |
-
$taxonomy = get_taxonomy( $tax_query[0]['taxonomy'] );
|
110 |
-
if ( 'term_id' === $tax_query[0]['field'] ) {
|
111 |
-
$term_id = $tax_query[0]['terms'][0];
|
112 |
-
} else if ( 'slug' === $tax_query[0]['field'] ) {
|
113 |
-
$term_id = get_term_by( 'slug', $tax_query[0]['terms'][0], $taxonomy->name )->term_id;
|
114 |
-
}
|
115 |
-
|
116 |
-
return array(
|
117 |
-
'value' => $term_id,
|
118 |
-
'title' => get_term( $term_id, $taxonomy->name )->name,
|
119 |
-
'type' => $taxonomy->name,
|
120 |
-
'label' => ( is_array( $taxonomy->labels->name ) ? $taxonomy->labels['name'] : $taxonomy->labels->name ),
|
121 |
-
);
|
122 |
-
} else if ( $querypost->is_search() ) {
|
123 |
-
return array(
|
124 |
-
'value' => $querypost->query_vars['s'],
|
125 |
-
'title' => '',
|
126 |
-
'type' => 'search',
|
127 |
-
'label' => __( 'Search' ),
|
128 |
-
);
|
129 |
-
} else if ( $querypost->is_home() ) {
|
130 |
-
return array(
|
131 |
-
'value' => '',
|
132 |
-
'title' => '',
|
133 |
-
'type' => 'home',
|
134 |
-
'label' => __( 'Blog Home Page' ),
|
135 |
-
);
|
136 |
-
}
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* Save click callback for AJAX processing
|
141 |
-
*/
|
142 |
-
public function saveClickCallback() {
|
143 |
-
if ( ! wp_verify_nonce( $_POST['nonce'], 'heatmapSaveClick' ) ) {
|
144 |
-
return false;
|
145 |
-
}
|
146 |
-
$data = isset( $_POST['data'] ) && is_array( $_POST['data'] ) ? $_POST['data'] : array();
|
147 |
-
$storeData = get_option( 'mainwp_child_click_data' );
|
148 |
-
if ( ! is_array( $storeData ) ) {
|
149 |
-
$storeData = array();
|
150 |
-
}
|
151 |
-
foreach ( $data as $d ) {
|
152 |
-
$coord = isset( $d['coord'] ) && preg_match( '/^\d+,\d+$/', $d['coord'] ) ? explode( ',', $d['coord'] ) : null;
|
153 |
-
$type = isset( $d['type'] ) && preg_match( '/^(left|right|middle)$/', $d['type'] ) ? $d['type'] : 'left';
|
154 |
-
$viewport = isset( $d['viewport'] ) && preg_match( '/^\d+,\d+$/', $d['viewport'] ) ? explode( ',', $d['viewport'] ) : null;
|
155 |
-
$element = isset( $d['element'] ) && preg_match( '/^[A-Za-z0-9#:().>_-]+$/is', $d['element'] ) ? $d['element'] : null;
|
156 |
-
$attr = array();
|
157 |
-
if ( isset( $d['url'] ) && $d['url'] ) {
|
158 |
-
$attr['url'] = esc_url_raw( $d['url'] );
|
159 |
-
}
|
160 |
-
if ( isset( $d['title'] ) && $d['title'] ) {
|
161 |
-
$attr['title'] = sanitize_text_field( $d['title'] );
|
162 |
-
}
|
163 |
-
if ( isset( $d['alt'] ) && $d['alt'] ) {
|
164 |
-
$attr['alt'] = sanitize_text_field( $d['alt'] );
|
165 |
-
}
|
166 |
-
if ( isset( $d['text'] ) && $d['text'] ) {
|
167 |
-
$attr['text'] = sanitize_text_field( $d['text'] );
|
168 |
-
}
|
169 |
-
$useragent = $_SERVER['HTTP_USER_AGENT'];
|
170 |
-
$object = $this->getPageObject( $_SERVER['HTTP_REFERER'] );
|
171 |
-
if ( ! is_null( $coord ) && ! is_null( $viewport ) && ! is_null( $element ) ) {
|
172 |
-
$storeData[] = array(
|
173 |
-
'url' => $_SERVER['HTTP_REFERER'],
|
174 |
-
'object' => $object,
|
175 |
-
'coord' => $coord,
|
176 |
-
'viewport' => $viewport,
|
177 |
-
'type' => $type,
|
178 |
-
'element' => $element,
|
179 |
-
'attr' => $attr,
|
180 |
-
'useragent' => $useragent,
|
181 |
-
'date' => current_time( 'mysql' ),
|
182 |
-
);
|
183 |
-
}
|
184 |
-
}
|
185 |
-
MainWP_Helper::update_option( 'mainwp_child_click_data', $storeData );
|
186 |
-
// Customize when we need to send the data
|
187 |
-
$this->sendClick();
|
188 |
-
exit;
|
189 |
-
}
|
190 |
-
|
191 |
-
public function sendClick() {
|
192 |
-
$url = $this->server . 'admin-ajax.php';
|
193 |
-
$clickData = get_option( 'mainwp_child_click_data' );
|
194 |
-
$key = get_option( 'mainwp_child_pubkey' );
|
195 |
-
if ( ! is_array( $clickData ) ) {
|
196 |
-
return false;
|
197 |
-
}
|
198 |
-
// send 1000 record per time to fix memory bug
|
199 |
-
$sendNow = array();
|
200 |
-
if ( count( $clickData ) > 1000 ) {
|
201 |
-
for ( $i = 0; $i < 1000; $i ++ ) {
|
202 |
-
$sendNow[] = $clickData[ $i ];
|
203 |
-
}
|
204 |
-
} else {
|
205 |
-
$sendNow = $clickData;
|
206 |
-
}
|
207 |
-
|
208 |
-
$timestamp = time();
|
209 |
-
$signature = $this->createSignature( $key, $timestamp, $sendNow );
|
210 |
-
|
211 |
-
$params = array(
|
212 |
-
'headers' => array(
|
213 |
-
'Referer' => site_url(),
|
214 |
-
),
|
215 |
-
'body' => array(
|
216 |
-
'timestamp' => $timestamp,
|
217 |
-
'signature' => $signature,
|
218 |
-
'data' => base64_encode( serialize( $sendNow ) ),
|
219 |
-
'action' => 'heatmapSendClick',
|
220 |
-
),
|
221 |
-
'timeout' => 30,
|
222 |
-
);
|
223 |
-
|
224 |
-
if ( strpos( $url, 'https://' ) === 0 ) {
|
225 |
-
$params['sslverify'] = false;
|
226 |
-
}
|
227 |
-
|
228 |
-
$request = wp_remote_post( $url, $params );
|
229 |
-
|
230 |
-
if ( is_array( $request ) && isset( $request['response']['code'] ) && 200 === (int) $request['response']['code'] ) {
|
231 |
-
if ( count( $clickData ) > 1000 ) {
|
232 |
-
$saveData = array();
|
233 |
-
$clickDataLength = count( $clickData );
|
234 |
-
for ( $i = 1000; $i < $clickDataLength; $i ++ ) {
|
235 |
-
$saveData[] = $clickData[ $i ];
|
236 |
-
}
|
237 |
-
MainWP_Helper::update_option( 'mainwp_child_click_data', $saveData );
|
238 |
-
} else {
|
239 |
-
delete_option( 'mainwp_child_click_data' );
|
240 |
-
}
|
241 |
-
}
|
242 |
-
}
|
243 |
-
|
244 |
-
public function checkSignature( $signature, $timestamp, $data ) {
|
245 |
-
$key = get_option( 'mainwp_child_pubkey' );
|
246 |
-
if ( ! $key ) {
|
247 |
-
return false;
|
248 |
-
}
|
249 |
-
$createSign = $this->createSignature( $key, $timestamp, $data );
|
250 |
-
|
251 |
-
return ( $signature === $createSign );
|
252 |
-
}
|
253 |
-
|
254 |
-
public function createSignature( $key, $timestamp, $data ) {
|
255 |
-
$datamd5 = md5( $timestamp . base64_encode( serialize( $data ) ) );
|
256 |
-
$signature = md5( $key . $datamd5 );
|
257 |
-
|
258 |
-
return $signature;
|
259 |
-
}
|
260 |
-
|
261 |
-
/**
|
262 |
-
* Whether the heatmap is requested to display or not
|
263 |
-
*/
|
264 |
-
public function displayHeatmap() {
|
265 |
-
return ( isset( $_REQUEST['heatmap'] ) && '1' === $_REQUEST['heatmap'] );
|
266 |
-
/*return ( ( isset($_REQUEST['heatmap']) && $_REQUEST['heatmap'] == '1' ) &&
|
267 |
-
( isset($_REQUEST['signature']) && isset($_REQUEST['timestamp']) && isset($_REQUEST['data']) &&
|
268 |
-
$this->checkSignature($_REQUEST['signature'], $_REQUEST['timestamp'], $_REQUEST['data']) )
|
269 |
-
);*/
|
270 |
-
}
|
271 |
-
|
272 |
-
/**
|
273 |
-
* Add tracker Javascript
|
274 |
-
*/
|
275 |
-
public function trackerJs() {
|
276 |
-
if ( ! is_admin() ) {
|
277 |
-
wp_enqueue_script( 'jquery' );
|
278 |
-
wp_enqueue_script( 'heatmapTracker', plugins_url( '/js/tracker.js', dirname( __FILE__ ) ) );
|
279 |
-
if ( $this->displayHeatmap() ) {
|
280 |
-
wp_enqueue_script( 'heatmapJs', plugins_url( '/js/heatmap.js', dirname( __FILE__ ) ) );
|
281 |
-
wp_enqueue_script( 'heatmapInit', plugins_url( '/js/heatmapinit.js', dirname( __FILE__ ) ) );
|
282 |
-
}
|
283 |
-
add_action( 'wp_head', array( $this, 'trackerJsInline' ), 1 );
|
284 |
-
}
|
285 |
-
}
|
286 |
-
|
287 |
-
/**
|
288 |
-
* Add necessary inline tracker Javascript
|
289 |
-
*/
|
290 |
-
public function trackerJsInline() {
|
291 |
-
echo '<script type="text/javascript">';
|
292 |
-
echo 'var trackerAjaxUrl="' . admin_url( 'admin-ajax.php' ) . '"; var trackerNonce="' . wp_create_nonce( 'heatmapSaveClick' ) . '";';
|
293 |
-
if ( $this->displayHeatmap() ) {
|
294 |
-
wp_deregister_script( 'admin-bar' );
|
295 |
-
wp_deregister_style( 'admin-bar' );
|
296 |
-
remove_action( 'wp_footer', 'wp_admin_bar_render', 1000 );
|
297 |
-
remove_action( 'wp_head', '_admin_bar_bump_cb' );
|
298 |
-
$pageUrl = sprintf( '%s%s', preg_replace( '#^((http|https)://([^/]+)).*#is', '$1', site_url() ), $_SERVER['REQUEST_URI'] );
|
299 |
-
$pageUrl = preg_replace( '#(&|\?)heatmap(|_start|_end|_browser|_browser_version|_platform|_width)=?([^&]*)#is', '', $pageUrl );
|
300 |
-
$page = $this->getPageObject( $pageUrl );
|
301 |
-
$start = isset( $_GET['heatmap_start'] ) && preg_match( '/^[2][01][0-9]{2}[\/\-][01][0-9][\/\-][0123][0-9]$/is', $_GET['heatmap_start'] ) ? $_GET['heatmap_start'] : null;
|
302 |
-
$end = isset( $_GET['heatmap_end'] ) && preg_match( '/^[2][01][0-9]{2}[\/\-][01][0-9][\/\-][0123][0-9]$/is', $_GET['heatmap_end'] ) ? $_GET['heatmap_end'] : null;
|
303 |
-
$browser = isset( $_GET['heatmap_browser'] ) ? strtolower( $_GET['heatmap_browser'] ) : '';
|
304 |
-
$browserVersion = isset( $_GET['heatmap_browser_version'] ) ? $_GET['heatmap_browser_version'] : '';
|
305 |
-
$platform = isset( $_GET['heatmap_platform'] ) ? strtolower( $_GET['heatmap_platform'] ) : '';
|
306 |
-
$width = isset( $_GET['heatmap_width'] ) && is_numeric( $_GET['heatmap_width'] ) ? $_GET['heatmap_width'] : '';
|
307 |
-
$args = array();
|
308 |
-
if ( $start ) {
|
309 |
-
$args['start'] = $start;
|
310 |
-
}
|
311 |
-
if ( $end ) {
|
312 |
-
$args['end'] = $end;
|
313 |
-
}
|
314 |
-
if ( $browser ) {
|
315 |
-
$args['browser'] = $browser;
|
316 |
-
}
|
317 |
-
if ( $browser && $browserVersion ) {
|
318 |
-
$args['browserVersion'] = $browserVersion;
|
319 |
-
}
|
320 |
-
if ( $platform ) {
|
321 |
-
$args['platform'] = $platform;
|
322 |
-
}
|
323 |
-
if ( $width ) {
|
324 |
-
$args['width'] = $width;
|
325 |
-
}
|
326 |
-
$this->generateHeatmap( $page['type'], $page['value'], $args );
|
327 |
-
}
|
328 |
-
echo '</script>';
|
329 |
-
}
|
330 |
-
|
331 |
-
/**
|
332 |
-
* Generate heatmap, print click data variable (wrap it on <script></script>)
|
333 |
-
*
|
334 |
-
* Available args:
|
335 |
-
* string $start Start date (d/m/Y)
|
336 |
-
* string $end End date (d/m/Y)
|
337 |
-
* string $browser Filter to only click by specified browser, see getBrowser method for list of supported browser name
|
338 |
-
* string $browserVersion The specific browser version to target at, could use some wildcard (for example: 7.*)
|
339 |
-
* string $platform Filter to only click by specified platform, see getBrowser method for list of supported platform name
|
340 |
-
* int $width Filter to width
|
341 |
-
*
|
342 |
-
* @param string $object_type Object type
|
343 |
-
* @param int|string $object_value Object value
|
344 |
-
* @param array $args Additional arguments
|
345 |
-
*
|
346 |
-
*/
|
347 |
-
public function generateHeatmap( $object_type, $object_value, $args ) {
|
348 |
-
global $wpdb;
|
349 |
-
$defaults = array(
|
350 |
-
'start' => '',
|
351 |
-
'end' => '',
|
352 |
-
'browser' => 'all',
|
353 |
-
'browserVersion' => 'all',
|
354 |
-
'platform' => 'all',
|
355 |
-
'width' => 0,
|
356 |
-
);
|
357 |
-
$args = wp_parse_args( $args, $defaults );
|
358 |
-
extract( $args );
|
359 |
-
|
360 |
-
$data = array();
|
361 |
-
$data['object_type'] = $object_type;
|
362 |
-
$data['object_value'] = $object_value;
|
363 |
-
$data['start_date'] = $start;
|
364 |
-
$data['end_date'] = $end;
|
365 |
-
$data['browser'] = $browser;
|
366 |
-
$data['platform'] = $platform;
|
367 |
-
$data['width'] = $width;
|
368 |
-
|
369 |
-
$url = $this->server . 'admin-ajax.php';
|
370 |
-
$key = get_option( 'mainwp_child_pubkey' );
|
371 |
-
$timestamp = time();
|
372 |
-
$signature = $this->createSignature( $key, $timestamp, $data );
|
373 |
-
|
374 |
-
$params = array(
|
375 |
-
'headers' => array(
|
376 |
-
'Referer' => site_url(),
|
377 |
-
),
|
378 |
-
'body' => array(
|
379 |
-
'timestamp' => $timestamp,
|
380 |
-
'signature' => $signature,
|
381 |
-
'data' => base64_encode( serialize( $data ) ),
|
382 |
-
'action' => 'heatmapGetClickData',
|
383 |
-
),
|
384 |
-
'timeout' => 60,
|
385 |
-
);
|
386 |
-
|
387 |
-
if ( strpos( $url, 'https://' ) === 0 ) {
|
388 |
-
$params['sslverify'] = false;
|
389 |
-
}
|
390 |
-
|
391 |
-
$request = wp_remote_post( $url, $params );
|
392 |
-
|
393 |
-
if ( is_array( $request ) ) {
|
394 |
-
$clicks = array();
|
395 |
-
if (! empty($request['body']) ) {
|
396 |
-
if (preg_match('/<heatmap>(.*)<\/heatmap>/', $request['body'], $results) > 0) {
|
397 |
-
$result = $results[1];
|
398 |
-
$clicks = json_decode($result);
|
399 |
-
}
|
400 |
-
}
|
401 |
-
$clickData = array();
|
402 |
-
if ( is_array( $clicks ) ) {
|
403 |
-
foreach ($clicks as $click) {
|
404 |
-
$clickData[] = array(
|
405 |
-
'x' => $click->x,
|
406 |
-
'y' => $click->y,
|
407 |
-
'w' => $click->w,
|
408 |
-
'h' => $click->h,
|
409 |
-
);
|
410 |
-
}
|
411 |
-
}
|
412 |
-
?>
|
413 |
-
var heatmapClick = <?php echo json_encode( $clickData ) ?>;
|
414 |
-
var heatmapError = 0;
|
415 |
-
<?php
|
416 |
-
} else {
|
417 |
-
?>
|
418 |
-
var heatmapError = 1;
|
419 |
-
<?php
|
420 |
-
}
|
421 |
-
}
|
422 |
-
}
|
423 |
-
|
424 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/heatmap.js
DELETED
@@ -1,362 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
* heatmap.js 1.0 - JavaScript Heatmap Library
|
3 |
-
*
|
4 |
-
* Copyright (c) 2011, Patrick Wied (http://www.patrick-wied.at)
|
5 |
-
* Dual-licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
6 |
-
* and the Beerware (http://en.wikipedia.org/wiki/Beerware) license.
|
7 |
-
*/
|
8 |
-
|
9 |
-
(function(w){
|
10 |
-
// the heatmapFactory creates heatmap instances
|
11 |
-
var heatmapFactory = (function(){
|
12 |
-
|
13 |
-
// store object constructor
|
14 |
-
// a heatmap contains a store
|
15 |
-
// the store has to know about the heatmap in order to trigger heatmap updates when datapoints get added
|
16 |
-
function store(hmap){
|
17 |
-
|
18 |
-
var _ = {
|
19 |
-
// data is a two dimensional array
|
20 |
-
// a datapoint gets saved as data[point-x-value][point-y-value]
|
21 |
-
// the value at [point-x-value][point-y-value] is the occurrence of the datapoint
|
22 |
-
data: [],
|
23 |
-
// tight coupling of the heatmap object
|
24 |
-
heatmap: hmap
|
25 |
-
};
|
26 |
-
// the max occurrence - the heatmaps radial gradient alpha transition is based on it
|
27 |
-
this.max = 0;
|
28 |
-
|
29 |
-
this.get = function(key){
|
30 |
-
return _[key];
|
31 |
-
},
|
32 |
-
this.set = function(key, value){
|
33 |
-
_[key] = value;
|
34 |
-
};
|
35 |
-
};
|
36 |
-
|
37 |
-
store.prototype = {
|
38 |
-
// function for adding datapoints to the store
|
39 |
-
// datapoints are usually defined by x and y but could also contain a third parameter which represents the occurrence
|
40 |
-
addDataPoint: function(x, y){
|
41 |
-
if(x < 0 || y < 0)
|
42 |
-
return;
|
43 |
-
|
44 |
-
var heatmap = this.get("heatmap"),
|
45 |
-
data = this.get("data");
|
46 |
-
|
47 |
-
if(!data[x]) data[x] = [];
|
48 |
-
if(!data[x][y]) data[x][y] = 1;
|
49 |
-
// if count parameter is set increment by count otherwise by 1
|
50 |
-
data[x][y]+=(arguments.length<3)?1:arguments[2];
|
51 |
-
|
52 |
-
// do we have a new maximum?
|
53 |
-
if(this.max < data[x][y]){
|
54 |
-
this.max = data[x][y];
|
55 |
-
// max changed, we need to redraw all existing(lower) datapoints
|
56 |
-
heatmap.get("actx").clearRect(0,0,heatmap.get("width"),heatmap.get("height"));
|
57 |
-
for(var one in data)
|
58 |
-
for(var two in data[one])
|
59 |
-
heatmap.drawAlpha(one, two, data[one][two]);
|
60 |
-
|
61 |
-
// @TODO
|
62 |
-
// implement feature
|
63 |
-
// heatmap.drawLegend(); ?
|
64 |
-
return;
|
65 |
-
}
|
66 |
-
heatmap.drawAlpha(x, y, data[x][y]);
|
67 |
-
},
|
68 |
-
setDataSet: function(obj){
|
69 |
-
|
70 |
-
this.max = obj.max;
|
71 |
-
var heatmap = this.get("heatmap"),
|
72 |
-
data = this.get("data"),
|
73 |
-
d = obj.data,
|
74 |
-
dlen = d.length;
|
75 |
-
// clear the heatmap before the data set gets drawn
|
76 |
-
heatmap.clear();
|
77 |
-
|
78 |
-
while(dlen--){
|
79 |
-
var point = d[dlen];
|
80 |
-
heatmap.drawAlpha(point.x, point.y, point.count);
|
81 |
-
if(!data[point.x]) data[point.x] = [];
|
82 |
-
if(!data[point.x][point.y]) data[point.x][point.y] = 1;
|
83 |
-
data[point.x][point.y]+=point.count;
|
84 |
-
}
|
85 |
-
// Add event after all done
|
86 |
-
// 10-22-2011 by Jeffri Hong
|
87 |
-
if ( typeof(obj.callback) == 'function' )
|
88 |
-
obj.callback();
|
89 |
-
},
|
90 |
-
exportDataSet: function(){
|
91 |
-
var data = this.get("data");
|
92 |
-
var exportData = [];
|
93 |
-
for(var one in data){
|
94 |
-
// jump over undefined indexes
|
95 |
-
if(one === undefined)
|
96 |
-
continue;
|
97 |
-
for(var two in data[one]){
|
98 |
-
if(two === undefined)
|
99 |
-
continue;
|
100 |
-
// if both indexes are defined, push the values into the array
|
101 |
-
exportData.push({x: parseInt(one, 10), y: parseInt(two, 10), count: data[one][two]});
|
102 |
-
}
|
103 |
-
}
|
104 |
-
|
105 |
-
return exportData;
|
106 |
-
},
|
107 |
-
generateRandomDataSet: function(points){
|
108 |
-
var heatmap = this.get("heatmap"),
|
109 |
-
w = heatmap.get("width"),
|
110 |
-
h = heatmap.get("height");
|
111 |
-
var randomset = {},
|
112 |
-
max = Math.floor(Math.random()*1000+1);
|
113 |
-
randomset.max = max;
|
114 |
-
var data = [];
|
115 |
-
while(points--){
|
116 |
-
data.push({x: Math.floor(Math.random()*w+1), y: Math.floor(Math.random()*h+1), count: Math.floor(Math.random()*max+1)});
|
117 |
-
}
|
118 |
-
randomset.data = data;
|
119 |
-
this.setDataSet(randomset);
|
120 |
-
}
|
121 |
-
};
|
122 |
-
|
123 |
-
|
124 |
-
// heatmap object constructor
|
125 |
-
function heatmap(config){
|
126 |
-
// private variables
|
127 |
-
var _ = {
|
128 |
-
radiusIn : 20,
|
129 |
-
radiusOut : 40,
|
130 |
-
element : {},
|
131 |
-
canvas : {},
|
132 |
-
acanvas: {},
|
133 |
-
ctx : {},
|
134 |
-
actx : {},
|
135 |
-
visible : true,
|
136 |
-
width : 0,
|
137 |
-
height : 0,
|
138 |
-
max : false,
|
139 |
-
gradient : false,
|
140 |
-
opacity: 180
|
141 |
-
};
|
142 |
-
// heatmap store containing the datapoints and information about the maximum
|
143 |
-
// accessible via instance.store
|
144 |
-
this.store = new store(this);
|
145 |
-
|
146 |
-
this.get = function(key){
|
147 |
-
return _[key];
|
148 |
-
},
|
149 |
-
this.set = function(key, value){
|
150 |
-
_[key] = value;
|
151 |
-
};
|
152 |
-
// configure the heatmap when an instance gets created
|
153 |
-
this.configure(config);
|
154 |
-
// and initialize it
|
155 |
-
this.init();
|
156 |
-
};
|
157 |
-
|
158 |
-
// public functions
|
159 |
-
heatmap.prototype = {
|
160 |
-
configure: function(config){
|
161 |
-
if(config.radius){
|
162 |
-
var rout = config.radius,
|
163 |
-
rin = parseInt(rout/2);
|
164 |
-
}
|
165 |
-
this.set("radiusIn", rin || 15),
|
166 |
-
this.set("radiusOut", rout || 40),
|
167 |
-
this.set("element", (config.element instanceof Object)?config.element:document.getElementById(config.element));
|
168 |
-
this.set("visible", config.visible);
|
169 |
-
this.set("max", config.max || false);
|
170 |
-
this.set("gradient", config.gradient || { 0.45: "rgb(0,0,255)", 0.55: "rgb(0,255,255)", 0.65: "rgb(0,255,0)", 0.95: "yellow", 1.0: "rgb(255,0,0)"}); // default is the common blue to red gradient
|
171 |
-
this.set("opacity", parseInt(255/(100/config.opacity), 10) || 180);
|
172 |
-
this.set("width", config.width || 0);
|
173 |
-
this.set("height", config.height || 0);
|
174 |
-
},
|
175 |
-
init: function(){
|
176 |
-
this.initColorPalette();
|
177 |
-
var canvas = document.createElement("canvas"),
|
178 |
-
acanvas = document.createElement("canvas"),
|
179 |
-
element = this.get("element");
|
180 |
-
this.set("canvas", canvas);
|
181 |
-
this.set("acanvas", acanvas);
|
182 |
-
canvas.width = acanvas.width = element.style.width.replace(/px/,"") || this.getWidth(element);
|
183 |
-
this.set("width", canvas.width);
|
184 |
-
canvas.height = acanvas.height = element.style.height.replace(/px/,"") || this.getHeight(element);
|
185 |
-
this.set("height", canvas.height);
|
186 |
-
canvas.style.position = acanvas.style.position = "absolute";
|
187 |
-
canvas.style.top = acanvas.style.top = "0";
|
188 |
-
canvas.style.left = acanvas.style.left = "0";
|
189 |
-
canvas.style.zIndex = 1000000;
|
190 |
-
if(!this.get("visible"))
|
191 |
-
canvas.style.display = "none";
|
192 |
-
|
193 |
-
this.get("element").appendChild(canvas);
|
194 |
-
this.set("ctx", canvas.getContext("2d"));
|
195 |
-
this.set("actx", acanvas.getContext("2d"));
|
196 |
-
},
|
197 |
-
initColorPalette: function(){
|
198 |
-
|
199 |
-
var canvas = document.createElement("canvas");
|
200 |
-
canvas.width = "1";
|
201 |
-
canvas.height = "256";
|
202 |
-
var ctx = canvas.getContext("2d");
|
203 |
-
var grad = ctx.createLinearGradient(0,0,1,256),
|
204 |
-
gradient = this.get("gradient");
|
205 |
-
for(var x in gradient){
|
206 |
-
grad.addColorStop(x, gradient[x]);
|
207 |
-
}
|
208 |
-
|
209 |
-
ctx.fillStyle = grad;
|
210 |
-
ctx.fillRect(0,0,1,256);
|
211 |
-
|
212 |
-
this.set("gradient", ctx.getImageData(0,0,1,256).data);
|
213 |
-
delete canvas;
|
214 |
-
delete grad;
|
215 |
-
delete ctx;
|
216 |
-
},
|
217 |
-
getWidth: function(element){
|
218 |
-
var width = element.offsetWidth;
|
219 |
-
if(element.style.paddingLeft)
|
220 |
-
width+=element.style.paddingLeft;
|
221 |
-
if(element.style.paddingRight)
|
222 |
-
width+=element.style.paddingRight;
|
223 |
-
|
224 |
-
return width;
|
225 |
-
},
|
226 |
-
getHeight: function(element){
|
227 |
-
var height = element.offsetHeight;
|
228 |
-
if(element.style.paddingTop)
|
229 |
-
height+=element.style.paddingTop;
|
230 |
-
if(element.style.paddingBottom)
|
231 |
-
height+=element.style.paddingBottom;
|
232 |
-
|
233 |
-
return height;
|
234 |
-
},
|
235 |
-
colorize: function(x, y){
|
236 |
-
// get the private variables
|
237 |
-
var width = this.get("width"),
|
238 |
-
radiusOut = this.get("radiusOut"),
|
239 |
-
height = this.get("height"),
|
240 |
-
actx = this.get("actx"),
|
241 |
-
ctx = this.get("ctx");
|
242 |
-
|
243 |
-
var x2 = radiusOut*2;
|
244 |
-
|
245 |
-
if(x+x2>width)
|
246 |
-
x=width-x2;
|
247 |
-
if(x<0)
|
248 |
-
x=0;
|
249 |
-
if(y<0)
|
250 |
-
y=0;
|
251 |
-
if(y+x2>height)
|
252 |
-
y=height-x2;
|
253 |
-
// get the image data for the mouse movement area
|
254 |
-
var image = actx.getImageData(x,y,x2,x2),
|
255 |
-
// some performance tweaks
|
256 |
-
imageData = image.data,
|
257 |
-
length = imageData.length,
|
258 |
-
palette = this.get("gradient"),
|
259 |
-
opacity = this.get("opacity");
|
260 |
-
// loop thru the area
|
261 |
-
for(var i=3; i < length; i+=4){
|
262 |
-
|
263 |
-
// [0] -> r, [1] -> g, [2] -> b, [3] -> alpha
|
264 |
-
var alpha = imageData[i],
|
265 |
-
offset = alpha*4;
|
266 |
-
|
267 |
-
if(!offset)
|
268 |
-
continue;
|
269 |
-
|
270 |
-
// we ve started with i=3
|
271 |
-
// set the new r, g and b values
|
272 |
-
imageData[i-3]=palette[offset];
|
273 |
-
imageData[i-2]=palette[offset+1];
|
274 |
-
imageData[i-1]=palette[offset+2];
|
275 |
-
// we want the heatmap to have a gradient from transparent to the colors
|
276 |
-
// as long as alpha is lower than the defined opacity (maximum), we'll use the alpha value
|
277 |
-
imageData[i] = (alpha < opacity)?alpha:opacity;
|
278 |
-
}
|
279 |
-
// the rgb data manipulation didn't affect the ImageData object(defined on the top)
|
280 |
-
// after the manipulation process we have to set the manipulated data to the ImageData object
|
281 |
-
image.data = imageData;
|
282 |
-
ctx.putImageData(image,x,y);
|
283 |
-
},
|
284 |
-
drawAlpha: function(x, y, count){
|
285 |
-
// storing the variables because they will be often used
|
286 |
-
var r1 = this.get("radiusIn"),
|
287 |
-
r2 = this.get("radiusOut"),
|
288 |
-
ctx = this.get("actx"),
|
289 |
-
max = this.get("max"),
|
290 |
-
// create a radial gradient with the defined parameters. we want to draw an alphamap
|
291 |
-
rgr = ctx.createRadialGradient(x,y,r1,x,y,r2),
|
292 |
-
xb = x-r2, yb = y-r2, mul = 2*r2;
|
293 |
-
// the center of the radial gradient has .1 alpha value
|
294 |
-
rgr.addColorStop(0, 'rgba(0,0,0,'+((count)?(count/this.store.max):'0.1')+')');
|
295 |
-
// and it fades out to 0
|
296 |
-
rgr.addColorStop(1, 'rgba(0,0,0,0)');
|
297 |
-
// drawing the gradient
|
298 |
-
ctx.fillStyle = rgr;
|
299 |
-
ctx.fillRect(xb,yb,mul,mul);
|
300 |
-
// finally colorize the area
|
301 |
-
this.colorize(xb,yb);
|
302 |
-
|
303 |
-
},
|
304 |
-
toggleDisplay: function(){
|
305 |
-
var visible = this.get("visible"),
|
306 |
-
canvas = this.get("canvas");
|
307 |
-
|
308 |
-
if(!visible)
|
309 |
-
canvas.style.display = "block";
|
310 |
-
else
|
311 |
-
canvas.style.display = "none";
|
312 |
-
|
313 |
-
this.set("visible", !visible);
|
314 |
-
},
|
315 |
-
// dataURL export
|
316 |
-
getImageData: function(){
|
317 |
-
return this.get("canvas").toDataURL();
|
318 |
-
},
|
319 |
-
clear: function(){
|
320 |
-
var w = this.get("width"),
|
321 |
-
h = this.get("height");
|
322 |
-
this.store.set("data",[]);
|
323 |
-
// @TODO: reset stores max to 1
|
324 |
-
//this.store.max = 1;
|
325 |
-
this.get("ctx").clearRect(0,0,w,h);
|
326 |
-
this.get("actx").clearRect(0,0,w,h);
|
327 |
-
}
|
328 |
-
};
|
329 |
-
|
330 |
-
return {
|
331 |
-
create: function(config){
|
332 |
-
return new heatmap(config);
|
333 |
-
},
|
334 |
-
util: {
|
335 |
-
mousePosition: function(ev){
|
336 |
-
// this doesn't work right
|
337 |
-
// rather use
|
338 |
-
/*
|
339 |
-
// this = element to observe
|
340 |
-
var x = ev.pageX - this.offsetLeft;
|
341 |
-
var y = ev.pageY - this.offsetTop;
|
342 |
-
|
343 |
-
*/
|
344 |
-
var x, y;
|
345 |
-
|
346 |
-
if (ev.layerX) { // Firefox
|
347 |
-
x = ev.layerX;
|
348 |
-
y = ev.layerY;
|
349 |
-
} else if (ev.offsetX) { // Opera
|
350 |
-
x = ev.offsetX;
|
351 |
-
y = ev.offsetY;
|
352 |
-
}
|
353 |
-
if(typeof(x)=='undefined')
|
354 |
-
return;
|
355 |
-
|
356 |
-
return [x,y];
|
357 |
-
}
|
358 |
-
}
|
359 |
-
};
|
360 |
-
})();
|
361 |
-
w.h337 = w.heatmapFactory = heatmapFactory;
|
362 |
-
})(window);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/heatmapinit.js
DELETED
@@ -1,41 +0,0 @@
|
|
1 |
-
/**
|
2 |
-
* Initiate heatmap object
|
3 |
-
*/
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
jQuery(window).load(function(){
|
8 |
-
if ( heatmapError == 0 )
|
9 |
-
{
|
10 |
-
jQuery('body').append( '<div id="hmap_loading" style="position:fixed;top:0;left:50%;margin-left:-200px;width:400px;height:30px;line-height:30px;background:#ffd;border:1px solid #bb9;border-top:none;text-align:center;font-weight:bold;border-bottom-left-radius:8px;border-bottom-right-radius:8px;">Loading...</div>' );
|
11 |
-
setTimeout(generate_heatmap, 1000);
|
12 |
-
}
|
13 |
-
else
|
14 |
-
{
|
15 |
-
jQuery('body').append( '<div id="hmap_error" style="position:fixed;top:0;left:50%;margin-left:-200px;width:400px;height:30px;line-height:30px;background:#fee;border:1px solid #b99;border-top:none;text-align:center;font-weight:bold;border-bottom-left-radius:8px;border-bottom-right-radius:8px;">An error occured.</div>' );
|
16 |
-
}
|
17 |
-
});
|
18 |
-
|
19 |
-
|
20 |
-
function generate_heatmap()
|
21 |
-
{
|
22 |
-
var hmap = h337.create({"element":document.body, "radius":15, "visible":true});
|
23 |
-
var width = jQuery(document).width();
|
24 |
-
var data = [];
|
25 |
-
for ( i in heatmapClick )
|
26 |
-
{
|
27 |
-
data.push({
|
28 |
-
x: ( heatmapClick[i].w-width > 0 ? heatmapClick[i].x - ( Math.floor(heatmapClick[i].w-width)/2 ) : heatmapClick[i].x ),
|
29 |
-
y: heatmapClick[i].y,
|
30 |
-
count: 1
|
31 |
-
});
|
32 |
-
}
|
33 |
-
var max = Math.floor(data.length/10);
|
34 |
-
hmap.store.setDataSet({
|
35 |
-
max: ( max > 5 ? Math.floor(data.length/max) : 5 ),
|
36 |
-
data: data,
|
37 |
-
callback: function(){
|
38 |
-
jQuery('#hmap_loading').fadeOut(500);
|
39 |
-
}
|
40 |
-
});
|
41 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/tracker.js
DELETED
@@ -1,62 +0,0 @@
|
|
1 |
-
/**
|
2 |
-
* Mouse click tracking
|
3 |
-
*/
|
4 |
-
|
5 |
-
var trackerData = [];
|
6 |
-
|
7 |
-
jQuery(document).ready(function($){
|
8 |
-
|
9 |
-
|
10 |
-
$(document).click(function(e){
|
11 |
-
var element = $(e.target).parents().map(getSelector).get().reverse().join(">");
|
12 |
-
element += '>'+$(e.target).map(getSelector).get();
|
13 |
-
var url = ( $(e.target).attr('href') ) ? $(e.target).attr('href') : $(e.target).attr('src');
|
14 |
-
var title = $(e.target).attr('title');
|
15 |
-
var alt = $(e.target).attr('alt');
|
16 |
-
var text = ( $(e.target).text().length == $(e.target).html().length ) ? $(e.target).text().substring(0, 511) : '';
|
17 |
-
trackerData.push({
|
18 |
-
coord: e.pageX+','+e.pageY,
|
19 |
-
type: 'left',
|
20 |
-
viewport: $(window).width()+','+$(window).height(),
|
21 |
-
element: element,
|
22 |
-
url: url,
|
23 |
-
title: title,
|
24 |
-
alt: alt,
|
25 |
-
text: text
|
26 |
-
});
|
27 |
-
});
|
28 |
-
|
29 |
-
$(window).unload(function(){
|
30 |
-
sendTrackData(false); // Make sure to send track data before going off from page, set it synchronious
|
31 |
-
});
|
32 |
-
|
33 |
-
function getSelector()
|
34 |
-
{
|
35 |
-
var el_class = $(this).attr('class');
|
36 |
-
var el_id = $(this).attr('id');
|
37 |
-
var el_index = $(this).index();
|
38 |
-
return this.tagName + ( el_id ? '#'+el_id : '' ) +
|
39 |
-
( el_class ? '.'+el_class.match(/^\S+/) : '' ) +
|
40 |
-
( el_index > 0 ? ':eq('+(el_index)+')' : '' );
|
41 |
-
}
|
42 |
-
|
43 |
-
function sendTrackData( sync )
|
44 |
-
{
|
45 |
-
if ( trackerData.length < 1 )
|
46 |
-
return;
|
47 |
-
$.ajax({
|
48 |
-
data : {
|
49 |
-
data: trackerData,
|
50 |
-
action: 'heatmapSaveClick',
|
51 |
-
nonce: trackerNonce
|
52 |
-
},
|
53 |
-
complete: function(){
|
54 |
-
trackerData = [];
|
55 |
-
},
|
56 |
-
async: ( sync ) ? false : true,
|
57 |
-
type: 'POST',
|
58 |
-
url: trackerAjaxUrl
|
59 |
-
});
|
60 |
-
}
|
61 |
-
setInterval(function(){ sendTrackData(false); }, 10000);
|
62 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mainwp-child.php
CHANGED
@@ -6,12 +6,8 @@
|
|
6 |
Author: MainWP
|
7 |
Author URI: https://mainwp.com
|
8 |
Text Domain: mainwp-child
|
9 |
-
Version: 4.0.
|
10 |
*/
|
11 |
-
//if ( ( isset( $_REQUEST['heatmap'] ) && '1' === $_REQUEST['heatmap'] ) || ( isset( $_REQUEST['mainwpsignature'] ) && ( ! empty( $_REQUEST['mainwpsignature'] ) ) ) ) {
|
12 |
-
// header( 'X-Frame-Options: ALLOWALL' );
|
13 |
-
//}
|
14 |
-
//header('X-Frame-Options: GOFORIT');
|
15 |
include_once( ABSPATH . 'wp-includes' . DIRECTORY_SEPARATOR . 'version.php' ); //Version information from wordpress
|
16 |
|
17 |
define( 'MAINWP_DEBUG', FALSE );
|
6 |
Author: MainWP
|
7 |
Author URI: https://mainwp.com
|
8 |
Text Domain: mainwp-child
|
9 |
+
Version: 4.0.3
|
10 |
*/
|
|
|
|
|
|
|
|
|
11 |
include_once( ABSPATH . 'wp-includes' . DIRECTORY_SEPARATOR . 'version.php' ); //Version information from wordpress
|
12 |
|
13 |
define( 'MAINWP_DEBUG', FALSE );
|
readme.txt
CHANGED
@@ -7,7 +7,7 @@ Plugin URI: https://mainwp.com
|
|
7 |
Requires at least: 3.6
|
8 |
Tested up to: 5.2.3
|
9 |
Requires PHP: 5.6
|
10 |
-
Stable tag: 4.0.
|
11 |
License: GPLv2 or later
|
12 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
13 |
|
@@ -71,6 +71,11 @@ To see full documentation and FAQs please visit [MainWP Documentation](https://m
|
|
71 |
|
72 |
== Changelog ==
|
73 |
|
|
|
|
|
|
|
|
|
|
|
74 |
= 4.0.2 - 9-6-19 =
|
75 |
* Fixed: an issue incorrect backups count in the Client Reports system
|
76 |
|
7 |
Requires at least: 3.6
|
8 |
Tested up to: 5.2.3
|
9 |
Requires PHP: 5.6
|
10 |
+
Stable tag: 4.0.3
|
11 |
License: GPLv2 or later
|
12 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
13 |
|
71 |
|
72 |
== Changelog ==
|
73 |
|
74 |
+
= 4.0.3 - 10-1-19 =
|
75 |
+
* Added: 'mainwp_child_branding_init_options' filter for disabling custom branding
|
76 |
+
* Updated: support for the WPVulnDB API v3
|
77 |
+
* Removed: unused code and files
|
78 |
+
|
79 |
= 4.0.2 - 9-6-19 =
|
80 |
* Fixed: an issue incorrect backups count in the Client Reports system
|
81 |
|