Sidekick - Version 2.2.0

Version Description

  • SIDEKICK can now be embeded within other plugins!
  • Custom walkthrough plans are now supported within MultiSite auto activation
  • Wildcard compatibility matching added
  • Captioning support added
  • Fixes issues with general UI elements
  • Fixes issues with walkthrough preview
  • Fixes issues with Safari alignment on settings page
Download this release

Release Info

Developer raptor235
Plugin Icon 128x128 Sidekick
Version 2.2.0
Comparing to
See all releases

Code changes from version 2.0.1 to 2.2.0

js/sidekick_admin.js ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Single Site
2
+
3
+ var currently_disabled_wts;
4
+ var currently_disabled_network_wts;
5
+ var lastTimeout;
6
+ var loadCount = 0;
7
+
8
+ function sk_populate(data){
9
+
10
+ jQuery('.sk_walkthrough_list').html('');
11
+
12
+ _.each(data.products,function(item,key){
13
+
14
+ if (!item.cacheId) {
15
+ return false;
16
+ }
17
+
18
+ jQuery('.sk_walkthrough_list').append('<div class="sk_product" id="' + item.cacheId + '"><b>' + item.name + '</b> (<span class="select_all">Toggle All</span>)</div>');
19
+
20
+
21
+ if (sk_config.disable_wts) {
22
+ currently_disabled_wts = sk_config.disable_wts;
23
+ sk_config.disable_wts = null;
24
+ }
25
+
26
+ if (sk_config.disable_network_wts) {
27
+ currently_disabled_network_wts = sk_config.disable_network_wts;
28
+ sk_config.disable_network_wts = null;
29
+ }
30
+
31
+ jQuery.ajax({
32
+ url:sk_config.library + 'products/cache?cacheId=' + item.cacheId,
33
+ cacheId: item.cacheId,
34
+ success: function(data,cacheId){
35
+
36
+ // console.log('SUCCESS %o',arguments);
37
+ loadCount++;
38
+
39
+ if (data.payload && data.payload.buckets) {
40
+
41
+ // Clear out disabled wts so that compatibility doesn't screen out wts from this screen. Put it back after we're done.
42
+
43
+ console.groupCollapsed('Checking Compatibilities');
44
+
45
+ _.each(data.payload.buckets,function(bucket,key){
46
+
47
+ clearTimeout(lastTimeout);
48
+ lastTimeout = setTimeout(function(){setup_events();},1000);
49
+
50
+ if (typeof sk_config.disable_wts_in_root_bucket_ids !== 'undefined' && jQuery.inArray( bucket.id, sk_config.disable_wts_in_root_bucket_ids ) > -1) {
51
+ // Don't draw root bucket
52
+ return false;
53
+ }
54
+
55
+ jQuery('#' + item.cacheId).append("<li class='sk_bucket' id='sk_bucket_" + bucket.id + "'>" + bucket.name + " (<span class=\"select_all\">Toggle All</span>)<ul></ul></li>");
56
+
57
+ var pass_data = {
58
+ bucket_id: bucket.id,
59
+ all_walkthroughs: data.payload.walkthroughs
60
+ };
61
+
62
+ _.each(bucket.walkthroughs,function(walkthrough,key){
63
+
64
+ var pass = false;
65
+
66
+ if (typeof sk_ms_admin === 'undefined' || !sk_ms_admin && jQuery.inArray(parseInt(key,10),currently_disabled_network_wts) > -1) {
67
+ // If single site and network disabled walkthroughs then don't even show it.
68
+ return;
69
+ }
70
+
71
+ if (sidekick.compatibilityModel.check_compatiblity_array(this.all_walkthroughs[key]) || (typeof sk_ms_admin !== 'undefined' && sk_ms_admin)){
72
+ // Only check compatibilities for single sites not network admin page
73
+ pass = true;
74
+ }
75
+
76
+ if (pass){
77
+ var checked = false;
78
+ var selected = false;
79
+
80
+ if (jQuery.inArray(parseInt(key,10),currently_disabled_wts) > -1 || jQuery.inArray(parseInt(key,10),currently_disabled_network_wts) > -1) {
81
+ checked = 'CHECKED';
82
+ }
83
+
84
+ if (sk_config.autostart_walkthrough_id !== 'undefined' && sk_config.autostart_walkthrough_id == parseInt(key,10)) {
85
+ selected = 'SELECTED';
86
+ }
87
+
88
+ jQuery('#sk_bucket_' + this.bucket_id).find('ul').append("<li class=\" sk_walkthrough\"><span><input type=\"checkbox\" " + checked + " value='" + key + "' name=\"disable_wts[]\"></span><span class='title'>" + this.all_walkthroughs[key].title + "</span></li>");
89
+ jQuery('[name="sk_autostart_walkthrough_id"]').append('<option ' + selected + ' value="' + key + '">' + this.all_walkthroughs[key].title + '</option>');
90
+
91
+ }
92
+ clearTimeout(lastTimeout);
93
+ lastTimeout = setTimeout(function(){setup_events();},1000);
94
+ },pass_data);
95
+
96
+ }); //
97
+
98
+ jQuery('.configure').show(); //
99
+
100
+ console.groupEnd();//
101
+
102
+ } else { //
103
+ jQuery('#' + this.cacheId).remove();
104
+ }
105
+
106
+ }
107
+ });
108
+ }); //
109
+ } //
110
+
111
+ function setup_events(){
112
+ // console.log('setup_events');
113
+
114
+ jQuery('.select_all').click(function(){
115
+ var checkBoxes = jQuery(this).parent().find('input[type="checkbox"]');
116
+
117
+ _.each(checkBoxes,function(item,key){
118
+ jQuery(item).attr("checked", !jQuery(item).attr("checked"));
119
+ });
120
+ });
121
+
122
+ jQuery('[name="disable_wts[]"]').click(function(e){
123
+
124
+ if (e.currentTarget.checked) {
125
+ jQuery('input[value="' + e.currentTarget.value + '"]').attr('checked',true);
126
+ } else {
127
+ jQuery('input[value="' + e.currentTarget.value + '"]').attr('checked',false);
128
+ }
129
+
130
+ });
131
+
132
+ jQuery('.activate_all').click(function(){
133
+ jQuery('.activate_sk').each(function(key,item){
134
+ setTimeout(function() {
135
+ jQuery(item).trigger('click');
136
+ }, key*1000);
137
+ });
138
+ });
139
+
140
+ jQuery('.sk_bucket').not(':has(li)').remove();
141
+ jQuery('.sk_product').not(':has(li)').remove();
142
+
143
+ // Set the disable_wts back to original state
144
+ sk_config.disable_wts = currently_disabled_wts;
145
+ sk_config.disable_network_wts = currently_disabled_network_wts;
146
+ }
147
+
148
+ function load_sk_library($key){
149
+
150
+ // console.log('BBBB load_sk_library %o', $key);
151
+ var sk_url;
152
+
153
+ if (loadCount > 5) {
154
+ console.warn('Something is wrong...');
155
+ return false;
156
+ }
157
+
158
+ if ($key) {
159
+ sk_url = sk_config.library + 'domains/cache?domainKey=' + $key;
160
+ } else {
161
+ sk_url = sk_config.library + 'platform/cache?platformId=1';
162
+ }
163
+
164
+ loadCount++;
165
+
166
+ jQuery.ajax({
167
+ url: sk_url,
168
+ error: function(data){
169
+ jQuery('.sk_license_status span').html('Invalid Key').css({color: 'red'});
170
+ jQuery('.sk_upgrade').show();
171
+ load_sk_library();
172
+ },
173
+ success: function(data){
174
+
175
+ if (sk_config.library + 'domains/cache?domainKey=' + sk_config.activation_id == sk_url) {
176
+ if (!data.payload) {
177
+ jQuery('.sk_license_status').html('Invalid Key').css({color: 'red'});
178
+ } else {
179
+ jQuery('.sk_license_status').html('Valid').css({color: 'green'});
180
+ }
181
+ }
182
+
183
+ if (!data.payload) {
184
+ load_sk_library();
185
+ return false;
186
+ }
187
+
188
+ if (data.payload) {
189
+ sk_populate(data.payload);
190
+ }
191
+ }
192
+ });
193
+ }
194
+
195
+ jQuery(document).ready(function($) {
196
+
197
+ if (jQuery('.sidekick_admin').length === 0) {
198
+ return;
199
+ }
200
+
201
+ if (typeof sk_ms_admin !== 'undefined' && sk_ms_admin) {
202
+
203
+ // Multisite
204
+
205
+ var clicked_button;
206
+
207
+ if (typeof last_site_key !== 'undefined') {
208
+ load_sk_library(last_site_key);
209
+ } else {
210
+ jQuery('.sk_box.configure').html('Need to activate at least one site to configure walkthroughs').show();
211
+ }
212
+
213
+ jQuery('.activate_sk').click(function(){
214
+
215
+ clicked_button = this;
216
+ jQuery('.single_activation_error').html('');
217
+
218
+ var data = {
219
+ action: 'sk_activate_single',
220
+ blog_id: jQuery(this).data('blogid'),
221
+ user_id: jQuery(this).data('userid'),
222
+ domain: jQuery(this).data('domain'),
223
+ path: jQuery(this).data('path')
224
+ };
225
+
226
+ jQuery.post(ajaxurl, data, function(e){
227
+
228
+ if (!e.success) {
229
+ jQuery('.single_activation_error').html(e.message);
230
+ jQuery(clicked_button).parent().html('- <span class="not_active">Error Activating</span>');
231
+ } else if (e.success) {
232
+ jQuery(clicked_button).parent().html('- <span class="green">Activated</span>');
233
+ }
234
+ },'json');
235
+
236
+ });
237
+
238
+ if (jQuery('select[name="sk_selected_subscription"]').val().indexOf('roduct') > -1) {
239
+ jQuery('.walkthrough_library').show();
240
+ }
241
+
242
+ jQuery('select[name="sk_selected_subscription"]').on('change',function(){
243
+ if (jQuery('select[name="sk_selected_subscription"]').val().indexOf('roduct') > -1) {
244
+ jQuery('.walkthrough_library').show();
245
+ } else {
246
+ jQuery('.walkthrough_library').val(0);
247
+ jQuery('.walkthrough_library').hide();
248
+ }
249
+ });
250
+
251
+ } else {
252
+ jQuery(document).ready(function($) {
253
+ if (sk_config.activation_id) {
254
+ load_sk_library(sk_config.activation_id);
255
+ } else {
256
+ jQuery('.sk_upgrade').show();
257
+ }
258
+
259
+ jQuery('h3:contains(My Sidekick Account)').click(function(e){
260
+ if (e.shiftKey) {
261
+ jQuery('.advanced').show();
262
+ }
263
+ });
264
+
265
+ });
266
+ }
267
+
268
+ });
269
+
270
+
libs/admin_page.php CHANGED
@@ -4,6 +4,11 @@
4
  }
5
  var last_site_key = null;
6
  var sk_ms_admin = false;
 
 
 
 
 
7
  </script>
8
 
9
  <div class="page-header"><h2><a id="pluginlogo_32" class="header-icon32" href="http://www.sidekick.pro/modules/wordpress-core-module-premium/?utm_source=plugin&utm_medium=settings&utm_campaign=header" target="_blank"></a>Sidekick Dashboard</h2></div>
@@ -42,7 +47,7 @@
42
  <tbody>
43
  <tr valign="top">
44
  <th scope="row" valign="top">Activation ID</th>
45
- <?php if (defined('MULTISITE')): ?>
46
  <?php if (isset($activation_id) && $activation_id): ?>
47
  <td><input class='regular-text' style='color: gray;' type='text' name='activation_id' value='xxxxxxxx-xxxx-xxxx-xxxx-<?php echo substr($activation_id, 25,20) ?>'></input></td>
48
  <?php else: ?>
4
  }
5
  var last_site_key = null;
6
  var sk_ms_admin = false;
7
+
8
+ jQuery(document).ready(function($) {
9
+ mixpanel.track('Settings Page Visit - Plugin');
10
+ });
11
+
12
  </script>
13
 
14
  <div class="page-header"><h2><a id="pluginlogo_32" class="header-icon32" href="http://www.sidekick.pro/modules/wordpress-core-module-premium/?utm_source=plugin&utm_medium=settings&utm_campaign=header" target="_blank"></a>Sidekick Dashboard</h2></div>
47
  <tbody>
48
  <tr valign="top">
49
  <th scope="row" valign="top">Activation ID</th>
50
+ <?php if (defined('MULTISITE') && MULTISITE): ?>
51
  <?php if (isset($activation_id) && $activation_id): ?>
52
  <td><input class='regular-text' style='color: gray;' type='text' name='activation_id' value='xxxxxxxx-xxxx-xxxx-xxxx-<?php echo substr($activation_id, 25,20) ?>'></input></td>
53
  <?php else: ?>
libs/licensing.php CHANGED
@@ -1,166 +1,192 @@
1
  <?php
2
 
3
- class sidekickMassActivator{
4
 
5
- function activate($blog_id, $user_id, $domain, $path){
6
- // mlog('FUNCTION: activate');
7
 
8
- $sk_auto_activations = get_option( 'sk_auto_activations');
9
 
10
- if ($sk_auto_activations) {
 
11
 
12
- $user = get_user_by('id',$user_id);
13
- $email = ($user) ? $user->user_email : 'unknown';
14
 
15
- // TODO: Send Domain for good measure
16
 
17
- $sk_selected_subscription = get_option("sk_selected_subscription");
 
18
 
19
- $result = $this->send_request('post','/domains',array('domainName' => $domain . $path, 'subscriptionId' => $sk_selected_subscription));
20
 
21
- if (isset($result->success) && $result->success == true && $result->payload->domainKey) {
 
22
 
23
- if (!get_option('sk_activation_id')) {
24
- // Use the first site's activation key for the network key
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  update_option('sk_activation_id',$result->payload->domainKey);
 
 
 
 
 
 
 
 
 
 
 
26
  }
 
 
 
 
27
 
28
- switch_to_blog($blog_id);
29
- update_option('sk_activation_id',$result->payload->domainKey);
30
- update_option('sk_email',$email);
31
- restore_current_blog();
 
32
 
33
- delete_option('sk_auto_activation_error');
34
- } else {
35
- update_option('sk_auto_activation_error',$result->message);
36
- wp_mail( 'support@sidekick.pro', 'Failed Mass Domain Add', json_encode($result));
37
  }
38
- return $result;
39
  }
40
- return false;
41
- }
42
 
43
- function activate_single(){
44
- die(json_encode($this->activate($_POST['blog_id'], $_POST['user_id'], $_POST['domain'], $_POST['path'])));
45
- }
46
 
47
- function send_request_curl($url, $post){
48
- $ch = curl_init($url);
49
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
50
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
51
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
52
- curl_setopt($ch, CURLOPT_POSTFIELDS,json_encode($post));
53
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
54
- $result = curl_exec($ch);
55
- curl_close($ch);
56
- return $result;
57
- }
58
 
59
- function send_request($type,$end_point, $data = null,$second_attempt = null){
60
  // var_dump('send_request');
61
  //var_dump("FUNCTION: send_request");
62
 
63
- if (strpos($_SERVER['SERVER_PROTOCOL'], 'https') === false) {
64
- $protocol = 'http:';
65
- } else {
66
- $protocol = 'https:';
67
- }
68
-
69
- $url = $protocol . SK_API . $end_point;
70
- $sk_token = get_transient('sk_token');
71
 
72
- if (!$sk_token && $end_point !== '/login') {
73
- $this->login();
74
  $sk_token = get_transient('sk_token');
75
- }
76
 
77
- $headers = array('Content-Type:application/json');
 
 
 
78
 
79
- if ($sk_token && $end_point !== '/login') {
80
- $headers[] = "Authorization: $sk_token";
81
- }
82
 
83
- $ch = curl_init($url);
84
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($type));
85
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
86
- curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
87
- if ($data) {
88
- curl_setopt($ch, CURLOPT_POSTFIELDS,json_encode($data));
89
- }
90
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
91
- $result = curl_exec($ch);
92
- curl_close($ch);
93
-
94
- // echo $result;
95
- // var_dump($url);
96
- // var_dump($headers);
97
- // var_dump($data);
98
- // var_dump($result);
99
- // die();
100
-
101
- if ($result == 'HTTP/1.1 401 Unauthorized' && !$second_attempt) {
102
- // var_dump('Getting rid of token and trying again');
103
- $this->login();
104
- delete_transient('sk_token');
105
- $this->send_request('post',$type,$data,true);
106
- }
107
 
108
- return json_decode($result);
109
- }
 
 
 
 
 
 
 
 
110
 
111
- function setup_menu(){
112
- add_submenu_page( 'settings.php', 'Sidekick - Licensing', 'Sidekick - Licensing', 'activate_plugins','sidekick-licensing', array(&$this,'admin_page'));
113
- }
114
 
115
- function login(){
116
- global $login_error;
117
- //var_dump("FUNCTION: login");
118
- $email = get_option('sk_account');
119
- $password = get_option('sk_password');
 
120
 
121
- if (!$password || !$email) {
122
- return false;
123
  }
124
 
125
- // mlog('$email',$email);
126
- // mlog('$password',$password);
 
 
 
 
127
 
128
- // $password = $e->decrypt($password, 'key');
 
 
129
 
130
- $string = $password;
131
- $key = 'hash';
132
- $decrypted_password = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($password), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
133
 
134
- $result = $this->send_request('post','/login',array('email' => $email, 'password' => $decrypted_password));
 
 
135
 
136
- // var_dump($result);
 
 
 
 
 
 
 
 
 
 
137
 
138
- if (!isset($result) || !$result->success) {
139
- delete_option( 'sk_token' );
140
- return array('error' => $result->message);
141
- } else {
142
- set_transient( 'sk_token', $result->payload->token->value, 24 * HOUR_IN_SECONDS );
143
- $this->load_subscriptions($result->payload->token->value);
144
- return array('success' => true);
145
  }
146
- }
147
 
148
- function load_user_data(){
149
- return $this->send_request('get','/users/');
150
- }
 
 
 
151
 
152
- function load_subscriptions(){
153
- // var_dump('load_subscriptions');
154
- $result = $this->send_request('get','/users/subscriptions');
155
- // var_dump($result);
156
- if ($result->success) {
157
- foreach ($result->payload as &$sub) {
158
- if ($sub->PlanId == 1) {
159
- // Basics or Enterprise can only be used right now
160
- update_option( 'sk_selected_subscription', $sub->id );
161
- $current_subscription = $sub;
162
  }
163
- // var_dump($sub->Domains);
 
 
 
 
164
  if (count($sub->Domains) > 0) {
165
  foreach ($sub->Domains as &$domain) {
166
  if (!$domain->DomainSubscription->end) {
@@ -171,68 +197,103 @@ class sidekickMassActivator{
171
  }
172
  }
173
  }
 
 
 
 
 
 
 
 
174
  } else {
175
  $sub->activeDomainCount = 0;
176
  }
177
 
 
 
 
 
 
 
 
 
 
 
178
  }
179
- $data['subscriptions'] = $result->payload;
180
- if (isset($current_subscription)) {
181
- $data['current_subscription'] = $current_subscription;
182
- } else {
183
- delete_option('sk_auto_activations');
184
- }
185
- return $data;
186
  }
187
- return null;
188
- }
189
 
190
- function admin_page(){
191
- if (isset($_POST['sk_account'])) {
 
 
 
 
192
 
193
- if (isset($_POST['sk_password']) && $_POST['sk_password'] && isset($_POST['sk_account']) && $_POST['sk_account']) {
194
- $key = 'hash';
195
- $string = $_POST['sk_password'];
 
 
 
 
196
 
197
- $encrypted_password = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
198
- $decrypted_password = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted_password), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
199
 
200
- update_option( 'sk_account', $_POST['sk_account'] );
201
- update_option( 'sk_password', $encrypted_password );
202
- $login_status = $this->login();
203
  delete_option('sk_auto_activation_error');
204
- } else {
205
- update_option( 'sk_selected_subscription', $_POST['sk_selected_subscription'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  }
207
 
208
- if (isset($_POST['sk_auto_activations'])) {
209
- update_option( 'sk_auto_activations', true );
210
- } else {
211
- delete_option( 'sk_auto_activations');
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  }
213
- }
214
 
215
- $sk_token = get_transient('sk_token');
216
- if (!$sk_token) {
217
- $login_status = $this->login();
218
  }
219
- $sk_subs = $this->load_subscriptions();
220
- $user_data = $this->load_user_data();
221
- $sk_auto_activations = get_option( 'sk_auto_activations');
222
- $sk_auto_activation_error = get_option('sk_auto_activation_error');
223
- $sk_selected_subscription = get_option('sk_selected_subscription');
224
- $is_ms_admin = true;
225
- $curl = function_exists('curl_version') ? true : false;
226
- $fgets = file_get_contents(__FILE__) ? true : false;
227
- $fgets_url = ini_get('allow_url_fopen') ? true : false;
228
-
229
- // var_dump($sk_subs);
230
-
231
- if ($curl && (!$fgets || !$fgets_url)) {
232
- $error = "Sorry, SIDEKICK MultiSite activations require <b>CURL</b> or <b>file_get_contents</b> functions enabled in PHP.";
233
- }
234
-
235
- include('ms_admin_page.php');
236
  }
237
  }
238
 
 
1
  <?php
2
 
3
+ // licensing.php
4
 
5
+ if (!class_exists('sidekickMassActivator')) {
 
6
 
7
+ class sidekickMassActivator{
8
 
9
+ function activate($blog_id, $user_id, $domain, $path){
10
+ // mlog('FUNCTION: activate');
11
 
12
+ $sk_auto_activations = get_option( 'sk_auto_activations');
 
13
 
14
+ if ($sk_auto_activations) {
15
 
16
+ $user = get_user_by('id',$user_id);
17
+ $email = ($user) ? $user->user_email : 'unknown';
18
 
19
+ // TODO: Send Domain for good measure
20
 
21
+ $sk_selected_subscription = get_option("sk_selected_subscription");
22
+ $sk_selected_product = get_option("sk_selected_product");
23
 
24
+ if (isset($sk_selected_product) && $sk_selected_product) {
25
+ $data = array('domainName' => $domain . $path, 'productId' => $sk_selected_product);
26
+ } else if (strpos($sk_selected_subscription,'subscription-') !== false) {
27
+ $sk_selected_subscription = explode('subscription-',$sk_selected_subscription);
28
+ $data = array('domainName' => $domain . $path, 'subscriptionId' => $sk_selected_subscription[1]);
29
+ }
30
+
31
+ $result = $this->send_request('post','/domains',$data);
32
+
33
+ if (isset($result->success) && $result->success == true && $result->payload->domainKey) {
34
+
35
+ if (!get_option('sk_activation_id')) {
36
+ // Use the first site's activation key for the network key
37
+ update_option('sk_activation_id',$result->payload->domainKey);
38
+ }
39
+
40
+ switch_to_blog($blog_id);
41
  update_option('sk_activation_id',$result->payload->domainKey);
42
+ update_option('sk_email',$email);
43
+ restore_current_blog();
44
+
45
+ $this->track('Mass Activate',array('domain' => $domain,'email' => $email));
46
+
47
+ delete_option('sk_auto_activation_error');
48
+ } else {
49
+
50
+ $this->track('Mass Activate Error',array('domain' => $domain, 'message' => $result->message,'email' => $email));
51
+ update_option('sk_auto_activation_error',$result->message);
52
+ wp_mail( 'support@sidekick.pro', 'Failed Mass Domain Add', json_encode($result));
53
  }
54
+ return $result;
55
+ }
56
+ return false;
57
+ }
58
 
59
+ function track($event,$data){
60
+ if (file_exists(realpath(dirname(__FILE__)) . '/mixpanel/Mixpanel.php')) {
61
+ require_once(realpath(dirname(__FILE__)) . '/mixpanel/Mixpanel.php');
62
+ $mp = Mixpanel::getInstance("965556434c5ae652a44f24b85b442263");
63
+ $domain = str_replace("http://","",$_SERVER["SERVER_NAME"]);
64
 
65
+ $mp->track($event, $data);
 
 
 
66
  }
 
67
  }
 
 
68
 
69
+ function activate_single(){
70
+ die(json_encode($this->activate($_POST['blog_id'], $_POST['user_id'], $_POST['domain'], $_POST['path'])));
71
+ }
72
 
73
+ function send_request_curl($url, $post){
74
+ $ch = curl_init($url);
75
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
76
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
77
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
78
+ curl_setopt($ch, CURLOPT_POSTFIELDS,json_encode($post));
79
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
80
+ $result = curl_exec($ch);
81
+ curl_close($ch);
82
+ return $result;
83
+ }
84
 
85
+ function send_request($type,$end_point, $data = null,$second_attempt = null){
86
  // var_dump('send_request');
87
  //var_dump("FUNCTION: send_request");
88
 
89
+ if (strpos($_SERVER['SERVER_PROTOCOL'], 'https') === false) {
90
+ $protocol = 'http:';
91
+ } else {
92
+ $protocol = 'https:';
93
+ }
 
 
 
94
 
95
+ $url = $protocol . SK_API . $end_point;
 
96
  $sk_token = get_transient('sk_token');
 
97
 
98
+ if (!$sk_token && $end_point !== '/login') {
99
+ $this->login();
100
+ $sk_token = get_transient('sk_token');
101
+ }
102
 
103
+ $headers = array('Content-Type:application/json');
 
 
104
 
105
+ if ($sk_token && $end_point !== '/login') {
106
+ $headers[] = "Authorization: $sk_token";
107
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
+ $ch = curl_init($url);
110
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($type));
111
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
112
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
113
+ if ($data) {
114
+ curl_setopt($ch, CURLOPT_POSTFIELDS,json_encode($data));
115
+ }
116
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
117
+ $result = curl_exec($ch);
118
+ curl_close($ch);
119
 
120
+ // echo $result; var_dump($url); var_dump($headers); var_dump($data); var_dump($result); die();
 
 
121
 
122
+ if ($result == 'HTTP/1.1 401 Unauthorized' && !$second_attempt) {
123
+ // var_dump('Getting rid of token and trying again');
124
+ $this->login();
125
+ delete_transient('sk_token');
126
+ $this->send_request('post',$type,$data,true);
127
+ }
128
 
129
+ return json_decode($result);
 
130
  }
131
 
132
+ function setup_menu(){
133
+ add_submenu_page( 'settings.php', 'Sidekick - Licensing', 'Sidekick - Licensing', 'activate_plugins','sidekick-licensing', array(&$this,'admin_page'));
134
+ }
135
+
136
+ function login(){
137
+ global $login_error;
138
 
139
+ $email = get_option('sk_account');
140
+ $password = get_option('sk_password');
141
+ delete_option('sk_auto_activation_error');
142
 
143
+ if (!$password || !$email) {
144
+ return false;
145
+ }
146
 
147
+ $string = $password;
148
+ $key = 'hash';
149
+ $decrypted_password = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($password), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
150
 
151
+ $result = $this->send_request('post','/login',array('email' => $email, 'password' => $decrypted_password));
152
+
153
+ if (!isset($result) || !$result->success) {
154
+ delete_option( 'sk_token' );
155
+ return array('error' => $result->message);
156
+ } else {
157
+ set_transient( 'sk_token', $result->payload->token->value, 24 * HOUR_IN_SECONDS );
158
+ $this->load_subscriptions($result->payload->token->value);
159
+ return array('success' => true);
160
+ }
161
+ }
162
 
163
+ function load_user_data(){
164
+ return $this->send_request('get','/users/');
 
 
 
 
 
165
  }
 
166
 
167
+ function load_subscriptions(){
168
+
169
+ $result = $this->send_request('get','/users/subscriptions');
170
+ $load_products = false;
171
+
172
+ if (isset($result->success) && isset($result->payload)) {
173
 
174
+ $sub = $result->payload[0];
175
+
176
+ if (isset($sub->Plan->CreatableProductType) && $sub->Plan->CreatableProductType->name == 'Public') {
177
+ $this->logout();
178
+ update_option( 'sk_auto_activation_error', 'Public accounts are not compatible with MultiSite activations.');
179
+ return false;
180
+ } if (isset($sub->Plan->CreatableProductType) && $sub->Plan->CreatableProductType->name == 'Private') {
181
+ update_option( 'sk_selected_subscription', 'product-' . $sub->id );
182
+ } else {
183
+ update_option( 'sk_selected_subscription', 'subscription-' . $sub->id );
184
  }
185
+
186
+ if (isset($sub->Plan->CreatableProductType) && isset($sub->Plan->CreatableProductType->name) && $sub->Plan->CreatableProductType->name == 'Private') {
187
+ $load_products = true;
188
+ }
189
+
190
  if (count($sub->Domains) > 0) {
191
  foreach ($sub->Domains as &$domain) {
192
  if (!$domain->DomainSubscription->end) {
197
  }
198
  }
199
  }
200
+ } if (count($sub->PrivateProductSubscriptions) > 0) {
201
+ foreach ($sub->PrivateProductSubscriptions as &$domain) {
202
+ if (isset($sub->activeDomainCount)) {
203
+ $sub->activeDomainCount++;
204
+ } else {
205
+ $sub->activeDomainCount = 1;
206
+ }
207
+ }
208
  } else {
209
  $sub->activeDomainCount = 0;
210
  }
211
 
212
+ $data['subscriptions'] = $result->payload;
213
+
214
+ if ($load_products) {
215
+ $data['products'] = $this->load_products();
216
+ }
217
+
218
+ return $data;
219
+ } else if (isset($result->message) && strpos($result->message, 'Invalid Token') !== false) {
220
+ $this->logout();
221
+ update_option( 'sk_auto_activation_error', 'Please authorize SIDEKICK by logging in.');
222
  }
223
+ return null;
 
 
 
 
 
 
224
  }
 
 
225
 
226
+ function logout(){
227
+ delete_option( 'sk_account');
228
+ delete_option( 'sk_password');
229
+ delete_option( 'sk_selected_subscription');
230
+ delete_option( 'sk_selected_product');
231
+ }
232
 
233
+ function load_products(){
234
+ $result = $this->send_request('get','/products');
235
+ if ($result->success) {
236
+ return $result->payload->products;
237
+ }
238
+ return null;
239
+ }
240
 
241
+ function admin_page(){
242
+ if (isset($_POST['sk_account'])) {
243
 
 
 
 
244
  delete_option('sk_auto_activation_error');
245
+
246
+ if (isset($_POST['sk_password']) && $_POST['sk_password'] && isset($_POST['sk_account']) && $_POST['sk_account']) {
247
+ $key = 'hash';
248
+ $string = $_POST['sk_password'];
249
+
250
+ $encrypted_password = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
251
+ $decrypted_password = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted_password), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
252
+
253
+ update_option( 'sk_account', $_POST['sk_account'] );
254
+ update_option( 'sk_password', $encrypted_password );
255
+ $login_status = $this->login();
256
+ delete_option('sk_auto_activation_error');
257
+ } else {
258
+ update_option( 'sk_selected_subscription', $_POST['sk_selected_subscription'] );
259
+ }
260
+
261
+ if (isset($_POST['sk_auto_activations'])) {
262
+ update_option( 'sk_auto_activations', true );
263
+ } else {
264
+ delete_option( 'sk_auto_activations');
265
+ }
266
+
267
+ if (isset($_POST['sk_selected_product']) && $_POST['sk_selected_product'] !== '0' && isset($_POST['sk_selected_subscription']) && strpos($_POST['sk_selected_subscription'], 'product') !== false) {
268
+ update_option( 'sk_selected_product', $_POST['sk_selected_product'] );
269
+ } else {
270
+ delete_option( 'sk_selected_product');
271
+ }
272
+
273
  }
274
 
275
+ $sk_token = get_transient('sk_token');
276
+ if (!$sk_token) {
277
+ $login_status = $this->login();
278
+ }
279
+ $sk_subs = $this->load_subscriptions();
280
+ $user_data = $this->load_user_data();
281
+ $sk_auto_activations = get_option( 'sk_auto_activations');
282
+ $sk_auto_activation_error = get_option('sk_auto_activation_error');
283
+ $sk_selected_subscription = get_option('sk_selected_subscription');
284
+ $sk_selected_product = get_option('sk_selected_product');
285
+ $is_ms_admin = true;
286
+ $curl = function_exists('curl_version') ? true : false;
287
+ $fgets = file_get_contents(__FILE__) ? true : false;
288
+ $fgets_url = ini_get('allow_url_fopen') ? true : false;
289
+
290
+ if ($curl && (!$fgets || !$fgets_url)) {
291
+ $error = "Sorry, SIDEKICK MultiSite activations require <b>CURL</b> or <b>file_get_contents</b> functions enabled in PHP.";
292
  }
 
293
 
294
+ require_once('ms_admin_page.php');
 
 
295
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  }
297
  }
298
 
299
+ // //licensing.php
libs/mixpanel/Base/MixpanelBase.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * This a Base class which all Mixpanel classes extend from to provide some very basic
5
+ * debugging and logging functionality. It also serves to persist $_options across the library.
6
+ *
7
+ */
8
+ class Base_MixpanelBase {
9
+
10
+
11
+ /**
12
+ * Default options that can be overridden via the $options constructor arg
13
+ * @var array
14
+ */
15
+ private $_defaults = array(
16
+ "max_batch_size" => 50, // the max batch size Mixpanel will accept is 50,
17
+ "max_queue_size" => 1000, // the max num of items to hold in memory before flushing
18
+ "debug" => false, // enable/disable debug mode
19
+ "consumer" => "curl", // which consumer to use
20
+ "host" => "api.mixpanel.com", // the host name for api calls
21
+ "events_endpoint" => "/track", // host relative endpoint for events
22
+ "people_endpoint" => "/engage", // host relative endpoint for people updates
23
+ "use_ssl" => true, // use ssl when available
24
+ "error_callback" => null // callback to use on consumption failures
25
+ );
26
+
27
+
28
+ /**
29
+ * An array of options to be used by the Mixpanel library.
30
+ * @var array
31
+ */
32
+ protected $_options = array();
33
+
34
+
35
+ /**
36
+ * Construct a new MixpanelBase object and merge custom options with defaults
37
+ * @param array $options
38
+ */
39
+ public function __construct($options = array()) {
40
+ $options = array_merge($this->_defaults, $options);
41
+ $this->_options = $options;
42
+ }
43
+
44
+
45
+ /**
46
+ * Log a message to PHP's error log
47
+ * @param $msg
48
+ */
49
+ protected function _log($msg) {
50
+ $arr = debug_backtrace();
51
+ $class = $arr[0]['class'];
52
+ $line = $arr[0]['line'];
53
+ error_log ( "[ $class - line $line ] : " . $msg );
54
+ }
55
+
56
+
57
+ /**
58
+ * Returns true if in debug mode, false if in production mode
59
+ * @return bool
60
+ */
61
+ protected function _debug() {
62
+ return array_key_exists("debug", $this->_options) && $this->_options["debug"] == true;
63
+ }
64
+
65
+ }
libs/mixpanel/ConsumerStrategies/AbstractConsumer.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/../Base/MixpanelBase.php");
3
+
4
+ /**
5
+ * Provides some base methods for use by a Consumer implementation
6
+ */
7
+ abstract class ConsumerStrategies_AbstractConsumer extends Base_MixpanelBase {
8
+
9
+ /**
10
+ * Creates a new AbstractConsumer
11
+ * @param array $options
12
+ */
13
+ function __construct($options = array()) {
14
+
15
+ parent::__construct($options);
16
+
17
+ if ($this->_debug()) {
18
+ $this->_log("Instantiated new Consumer");
19
+ }
20
+
21
+ }
22
+
23
+ /**
24
+ * Encode an array to be persisted
25
+ * @param array $params
26
+ * @return string
27
+ */
28
+ protected function _encode($params) {
29
+ return base64_encode(json_encode($params));
30
+ }
31
+
32
+ /**
33
+ * Handles errors that occur in a consumer
34
+ * @param $code
35
+ * @param $msg
36
+ */
37
+ protected function _handleError($code, $msg) {
38
+ if (isset($this->_options['error_callback'])) {
39
+ $handler = $this->_options['error_callback'];
40
+ call_user_func($handler, $code, $msg);
41
+ }
42
+
43
+ if ($this->_debug()) {
44
+ $arr = debug_backtrace();
45
+ $class = get_class($arr[0]['object']);
46
+ $line = $arr[0]['line'];
47
+ error_log ( "[ $class - line $line ] : " . print_r($msg, true) );
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Persist a batch of messages in whatever way the implementer sees fit
53
+ * @param array $batch an array of messages to consume
54
+ * @return boolean success or fail
55
+ */
56
+ abstract function persist($batch);
57
+ }
libs/mixpanel/ConsumerStrategies/CurlConsumer.php ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/AbstractConsumer.php");
3
+
4
+ /**
5
+ * Consumes messages and sends them to a host/endpoint using cURL
6
+ */
7
+ class ConsumerStrategies_CurlConsumer extends ConsumerStrategies_AbstractConsumer {
8
+
9
+ /**
10
+ * @var string the host to connect to (e.g. api.mixpanel.com)
11
+ */
12
+ protected $_host;
13
+
14
+
15
+ /**
16
+ * @var string the host-relative endpoint to write to (e.g. /engage)
17
+ */
18
+ protected $_endpoint;
19
+
20
+
21
+ /**
22
+ * @var int connect_timeout The number of seconds to wait while trying to connect. Default is 5 seconds.
23
+ */
24
+ protected $_connect_timeout;
25
+
26
+
27
+ /**
28
+ * @var int timeout The maximum number of seconds to allow cURL call to execute. Default is 30 seconds.
29
+ */
30
+ protected $_timeout;
31
+
32
+
33
+ /**
34
+ * @var string the protocol to use for the cURL connection
35
+ */
36
+ protected $_protocol;
37
+
38
+
39
+ /**
40
+ * @var bool|null true to fork the cURL process (using exec) or false to use PHP's cURL extension. false by default
41
+ */
42
+ protected $_fork = null;
43
+
44
+
45
+ /**
46
+ * Creates a new CurlConsumer and assigns properties from the $options array
47
+ * @param array $options
48
+ * @throws Exception
49
+ */
50
+ function __construct($options) {
51
+ parent::__construct($options);
52
+
53
+ $this->_host = $options['host'];
54
+ $this->_endpoint = $options['endpoint'];
55
+ $this->_connect_timeout = array_key_exists('connect_timeout', $options) ? $options['connect_timeout'] : 5;
56
+ $this->_timeout = array_key_exists('timeout', $options) ? $options['timeout'] : 30;
57
+ $this->_protocol = array_key_exists('use_ssl', $options) && $options['use_ssl'] == true ? "https" : "http";
58
+ $this->_fork = array_key_exists('fork', $options) ? ($options['fork'] == true) : false;
59
+
60
+ // ensure the environment is workable for the given settings
61
+ if ($this->_fork == true) {
62
+ $exists = function_exists('exec');
63
+ if (!$exists) {
64
+ throw new Exception('The "exec" function must exist to use the cURL consumer in "fork" mode. Try setting fork = false or use another consumer.');
65
+ }
66
+ $disabled = explode(', ', ini_get('disable_functions'));
67
+ $enabled = !in_array('exec', $disabled);
68
+ if (!$enabled) {
69
+ throw new Exception('The "exec" function must be enabled to use the cURL consumer in "fork" mode. Try setting fork = false or use another consumer.');
70
+ }
71
+ } else {
72
+ if (!function_exists('curl_init')) {
73
+ throw new Exception('The cURL PHP extension is required to use the cURL consumer with fork = false. Try setting fork = true or use another consumer.');
74
+ }
75
+ }
76
+ }
77
+
78
+
79
+ /**
80
+ * Write to the given host/endpoint using either a forked cURL process or using PHP's cURL extension
81
+ * @param array $batch
82
+ * @return bool
83
+ */
84
+ public function persist($batch) {
85
+ if (count($batch) > 0) {
86
+ $data = "data=" . $this->_encode($batch);
87
+ $url = $this->_protocol . "://" . $this->_host . $this->_endpoint;
88
+ if ($this->_fork) {
89
+ return $this->_execute_forked($url, $data);
90
+ } else {
91
+ return $this->_execute($url, $data);
92
+ }
93
+ } else {
94
+ return true;
95
+ }
96
+ }
97
+
98
+
99
+ /**
100
+ * Write using the cURL php extension
101
+ * @param $url
102
+ * @param $data
103
+ * @return bool
104
+ */
105
+ protected function _execute($url, $data) {
106
+ if ($this->_debug()) {
107
+ $this->_log("Making blocking cURL call to $url");
108
+ }
109
+
110
+ $ch = curl_init();
111
+ curl_setopt($ch, CURLOPT_URL, $url);
112
+ curl_setopt($ch, CURLOPT_HEADER, 0);
113
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->_connect_timeout);
114
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->_timeout);
115
+ curl_setopt($ch, CURLOPT_POST, 1);
116
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
117
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
118
+ $response = curl_exec($ch);
119
+ if (false === $response) {
120
+ $curl_error = curl_error($ch);
121
+ $curl_errno = curl_errno($ch);
122
+ curl_close($ch);
123
+ $this->_handleError($curl_errno, $curl_error);
124
+ return false;
125
+ } else {
126
+ curl_close($ch);
127
+ if (trim($response) == "1") {
128
+ return true;
129
+ } else {
130
+ $this->_handleError(0, $response);
131
+ return false;
132
+ }
133
+ }
134
+ }
135
+
136
+
137
+ /**
138
+ * Write using a forked cURL process
139
+ * @param $url
140
+ * @param $data
141
+ * @return bool
142
+ */
143
+ protected function _execute_forked($url, $data) {
144
+
145
+ if ($this->_debug()) {
146
+ $this->_log("Making forked cURL call to $url");
147
+ }
148
+
149
+ $exec = 'curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d ' . $data . ' "' . $url . '"';
150
+
151
+ if(!$this->_debug()) {
152
+ $exec .= " >/dev/null 2>&1 &";
153
+ }
154
+
155
+ exec($exec, $output, $return_var);
156
+
157
+ if ($return_var != 0) {
158
+ $this->_handleError($return_var, $output);
159
+ }
160
+
161
+ return $return_var == 0;
162
+ }
163
+
164
+ /**
165
+ * @return int
166
+ */
167
+ public function getConnectTimeout()
168
+ {
169
+ return $this->_connect_timeout;
170
+ }
171
+
172
+ /**
173
+ * @return string
174
+ */
175
+ public function getEndpoint()
176
+ {
177
+ return $this->_endpoint;
178
+ }
179
+
180
+ /**
181
+ * @return bool|null
182
+ */
183
+ public function getFork()
184
+ {
185
+ return $this->_fork;
186
+ }
187
+
188
+ /**
189
+ * @return string
190
+ */
191
+ public function getHost()
192
+ {
193
+ return $this->_host;
194
+ }
195
+
196
+ /**
197
+ * @return array
198
+ */
199
+ public function getOptions()
200
+ {
201
+ return $this->_options;
202
+ }
203
+
204
+ /**
205
+ * @return string
206
+ */
207
+ public function getProtocol()
208
+ {
209
+ return $this->_protocol;
210
+ }
211
+
212
+ /**
213
+ * @return int
214
+ */
215
+ public function getTimeout()
216
+ {
217
+ return $this->_timeout;
218
+ }
219
+
220
+
221
+ }
libs/mixpanel/ConsumerStrategies/FileConsumer.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/AbstractConsumer.php");
3
+ /**
4
+ * Consumes messages and writes them to a file
5
+ */
6
+ class ConsumerStrategies_FileConsumer extends ConsumerStrategies_AbstractConsumer {
7
+
8
+ /**
9
+ * @var string path to a file that we want to write the messages to
10
+ */
11
+ private $_file;
12
+
13
+
14
+ /**
15
+ * Creates a new FileConsumer and assigns properties from the $options array
16
+ * @param array $options
17
+ */
18
+ function __construct($options) {
19
+ parent::__construct($options);
20
+
21
+ // what file to write to?
22
+ $this->_file = array_key_exists("file", $options) ? $options['file'] : dirname(__FILE__)."/../../messages.txt";
23
+ }
24
+
25
+
26
+ /**
27
+ * Append $batch to a file
28
+ * @param array $batch
29
+ * @return bool
30
+ */
31
+ public function persist($batch) {
32
+ if (count($batch) > 0) {
33
+ return file_put_contents($this->_file, json_encode($batch)."\n", FILE_APPEND | LOCK_EX) !== false;
34
+ } else {
35
+ return true;
36
+ }
37
+ }
38
+ }
libs/mixpanel/ConsumerStrategies/SocketConsumer.php ADDED
@@ -0,0 +1,308 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Portions of this class were borrowed from
4
+ * https://github.com/segmentio/analytics-php/blob/master/lib/Analytics/Consumer/Socket.php.
5
+ * Thanks for the work!
6
+ *
7
+ * WWWWWW||WWWWWW
8
+ * W W W||W W W
9
+ * ||
10
+ * ( OO )__________
11
+ * / | \
12
+ * /o o| MIT \
13
+ * \___/||_||__||_|| *
14
+ * || || || ||
15
+ * _||_|| _||_||
16
+ * (__|__|(__|__|
17
+ * (The MIT License)
18
+ *
19
+ * Copyright (c) 2013 Segment.io Inc. friends@segment.io
20
+ *
21
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
22
+ * documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the
23
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
24
+ * permit persons to whom the Software is furnished to do so, subject to the following conditions:
25
+ *
26
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
27
+ * Software.
28
+ *
29
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
30
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
31
+ * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
32
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
+ */
34
+ require_once(dirname(__FILE__) . "/AbstractConsumer.php");
35
+
36
+ /**
37
+ * Consumes messages and writes them to host/endpoint using a persistent socket
38
+ */
39
+ class ConsumerStrategies_SocketConsumer extends ConsumerStrategies_AbstractConsumer {
40
+
41
+ /**
42
+ * @var string the host to connect to (e.g. api.mixpanel.com)
43
+ */
44
+ private $_host;
45
+
46
+
47
+ /**
48
+ * @var string the host-relative endpoint to write to (e.g. /engage)
49
+ */
50
+ private $_endpoint;
51
+
52
+
53
+ /**
54
+ * @var int connect_timeout the socket connection timeout in seconds
55
+ */
56
+ private $_connect_timeout;
57
+
58
+
59
+ /**
60
+ * @var string the protocol to use for the socket connection
61
+ */
62
+ private $_protocol;
63
+
64
+
65
+ /**
66
+ * @var resource holds the socket resource
67
+ */
68
+ private $_socket;
69
+
70
+ /**
71
+ * @var bool whether or not to wait for a response
72
+ */
73
+ private $_async;
74
+
75
+
76
+ /**
77
+ * Creates a new SocketConsumer and assigns properties from the $options array
78
+ * @param array $options
79
+ */
80
+ public function __construct($options = array()) {
81
+ parent::__construct($options);
82
+
83
+
84
+ $this->_host = $options['host'];
85
+ $this->_endpoint = $options['endpoint'];
86
+ $this->_connect_timeout = array_key_exists('connect_timeout', $options) ? $options['connect_timeout'] : 5;
87
+ $this->_async = array_key_exists('async', $options) && $options['async'] === false ? false : true;
88
+
89
+ if (array_key_exists('use_ssl', $options) && $options['use_ssl'] == true) {
90
+ $this->_protocol = "ssl";
91
+ $this->_port = 443;
92
+ } else {
93
+ $this->_protocol = "tcp";
94
+ $this->_port = 80;
95
+ }
96
+ }
97
+
98
+
99
+ /**
100
+ * Write using a persistent socket connection.
101
+ * @param array $batch
102
+ * @return bool
103
+ */
104
+ public function persist($batch) {
105
+
106
+ $socket = $this->_getSocket();
107
+ if (!is_resource($socket)) {
108
+ return false;
109
+ }
110
+
111
+ $data = "data=".$this->_encode($batch);
112
+
113
+ $body = "";
114
+ $body.= "POST ".$this->_endpoint." HTTP/1.1\r\n";
115
+ $body.= "Host: " . $this->_host . "\r\n";
116
+ $body.= "Content-Type: application/x-www-form-urlencoded\r\n";
117
+ $body.= "Accept: application/json\r\n";
118
+ $body.= "Content-length: " . strlen($data) . "\r\n";
119
+ $body.= "\r\n";
120
+ $body.= $data;
121
+
122
+ return $this->_write($socket, $body);
123
+ }
124
+
125
+
126
+ /**
127
+ * Return cached socket if open or create a new persistent socket
128
+ * @return bool|resource
129
+ */
130
+ private function _getSocket() {
131
+ if(is_resource($this->_socket)) {
132
+
133
+ if ($this->_debug()) {
134
+ $this->_log("Using existing socket");
135
+ }
136
+
137
+ return $this->_socket;
138
+ } else {
139
+
140
+ if ($this->_debug()) {
141
+ $this->_log("Creating new socket at ".time());
142
+ }
143
+
144
+ return $this->_createSocket();
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Attempt to open a new socket connection, cache it, and return the resource
150
+ * @param bool $retry
151
+ * @return bool|resource
152
+ */
153
+ private function _createSocket($retry = true) {
154
+ try {
155
+ $socket = pfsockopen($this->_protocol . "://" . $this->_host, $this->_port, $err_no, $err_msg, $this->_connect_timeout);
156
+
157
+ if ($this->_debug()) {
158
+ $this->_log("Opening socket connection to " . $this->_protocol . "://" . $this->_host . ":" . $this->_port);
159
+ }
160
+
161
+ if ($err_no != 0) {
162
+ $this->_handleError($err_no, $err_msg);
163
+ return $retry == true ? $this->_createSocket(false) : false;
164
+ } else {
165
+ // cache the socket
166
+ $this->_socket = $socket;
167
+ return $socket;
168
+ }
169
+
170
+ } catch (Exception $e) {
171
+ $this->_handleError($e->getCode(), $e->getMessage());
172
+ return $retry == true ? $this->_createSocket(false) : false;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Attempt to close and dereference a socket resource
178
+ */
179
+ private function _destroySocket() {
180
+ $socket = $this->_socket;
181
+ $this->_socket = null;
182
+ fclose($socket);
183
+ }
184
+
185
+
186
+ /**
187
+ * Write $data through the given $socket
188
+ * @param $socket
189
+ * @param $data
190
+ * @param bool $retry
191
+ * @return bool
192
+ */
193
+ private function _write($socket, $data, $retry = true) {
194
+
195
+ $bytes_sent = 0;
196
+ $bytes_total = strlen($data);
197
+ $socket_closed = false;
198
+ $success = true;
199
+ $max_bytes_per_write = 8192;
200
+
201
+ // if we have no data to write just return true
202
+ if ($bytes_total == 0) {
203
+ return true;
204
+ }
205
+
206
+ // try to write the data
207
+ while (!$socket_closed && $bytes_sent < $bytes_total) {
208
+
209
+ try {
210
+ $bytes = fwrite($socket, $data, $max_bytes_per_write);
211
+
212
+ if ($this->_debug()) {
213
+ $this->_log("Socket wrote ".$bytes." bytes");
214
+ }
215
+
216
+ // if we actually wrote data, then remove the written portion from $data left to write
217
+ if ($bytes > 0) {
218
+ $data = substr($data, $max_bytes_per_write);
219
+ }
220
+
221
+ } catch (Exception $e) {
222
+ $this->_handleError($e->getCode(), $e->getMessage());
223
+ $socket_closed = true;
224
+ }
225
+
226
+ if (isset($bytes) && $bytes) {
227
+ $bytes_sent += $bytes;
228
+ } else {
229
+ $socket_closed = true;
230
+ }
231
+ }
232
+
233
+ // create a new socket if the current one is closed and retry the message
234
+ if ($socket_closed) {
235
+
236
+ $this->_destroySocket();
237
+
238
+ if ($retry) {
239
+ if ($this->_debug()) {
240
+ $this->_log("Retrying socket write...");
241
+ }
242
+ $socket = $this->_getSocket();
243
+ if ($socket) return $this->_write($socket, $data, false);
244
+ }
245
+
246
+ return false;
247
+ }
248
+
249
+
250
+ // only wait for the response in debug mode or if we explicitly want to be synchronous
251
+ if ($this->_debug() || !$this->_async) {
252
+ $res = $this->handleResponse(fread($socket, 2048));
253
+ if ($res["status"] != "200") {
254
+ $this->_handleError($res["status"], $res["body"]);
255
+ $success = false;
256
+ }
257
+ }
258
+
259
+ return $success;
260
+ }
261
+
262
+
263
+ /**
264
+ * Parse the response from a socket write (only used for debugging)
265
+ * @param $response
266
+ * @return array
267
+ */
268
+ private function handleResponse($response) {
269
+
270
+ $lines = explode("\n", $response);
271
+
272
+ // extract headers
273
+ $headers = array();
274
+ foreach($lines as $line) {
275
+ $kvsplit = explode(":", $line);
276
+ if (count($kvsplit) == 2) {
277
+ $header = $kvsplit[0];
278
+ $value = $kvsplit[1];
279
+ $headers[$header] = trim($value);
280
+ }
281
+
282
+ }
283
+
284
+ // extract status
285
+ $line_one_exploded = explode(" ", $lines[0]);
286
+ $status = $line_one_exploded[1];
287
+
288
+ // extract body
289
+ $body = $lines[count($lines) - 1];
290
+
291
+ // if the connection has been closed lets kill the socket
292
+ if ($headers['Connection'] == "close") {
293
+ $this->_destroySocket();
294
+ if ($this->_debug()) {
295
+ $this->_log("Server told us connection closed so lets destroy the socket so it'll reconnect on next call");
296
+ }
297
+ }
298
+
299
+ $ret = array(
300
+ "status" => $status,
301
+ "body" => $body,
302
+ );
303
+
304
+ return $ret;
305
+ }
306
+
307
+
308
+ }
libs/mixpanel/Mixpanel.php ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__) . "/Base/MixpanelBase.php");
4
+ require_once(dirname(__FILE__) . "/Producers/MixpanelPeople.php");
5
+ require_once(dirname(__FILE__) . "/Producers/MixpanelEvents.php");
6
+
7
+ /**
8
+ * This is the main class for the Mixpanel PHP Library which provides all of the methods you need to track events and
9
+ * create/update profiles.
10
+ *
11
+ * Architecture
12
+ * -------------
13
+ *
14
+ * This library is built such that all messages are buffered in an in-memory "queue"
15
+ * The queue will be automatically flushed at the end of every request. Alternatively, you can call "flush()" manually
16
+ * at any time. Flushed messages will be passed to a Consumer's "persist" method. The library comes with a handful of
17
+ * Consumers. The "CurlConsumer" is used by default which will send the messages to Mixpanel using forked cURL processes.
18
+ * You can implement your own custom Consumer to customize how a message is sent to Mixpanel. This can be useful when
19
+ * you want to put messages onto a distributed queue (such as ActiveMQ or Kestrel) instead of writing to Mixpanel in
20
+ * the user thread.
21
+ *
22
+ * Options
23
+ * -------------
24
+ *
25
+ * <table width="100%" cellpadding="5">
26
+ * <tr>
27
+ * <th>Option</th>
28
+ * <th>Description</th>
29
+ * <th>Default</th>
30
+ * </tr>
31
+ * <tr>
32
+ * <td>max_queue_size</td>
33
+ * <td>The maximum number of items to buffer in memory before flushing</td>
34
+ * <td>1000</td>
35
+ * </tr>
36
+ * <tr>
37
+ * <td>debug</td>
38
+ * <td>Enable/disable debug mode</td>
39
+ * <td>false</td>
40
+ * </tr>
41
+ * <tr>
42
+ * <td>consumer</td>
43
+ * <td>The consumer to use for writing messages</td>
44
+ * <td>curl</td>
45
+ * </tr>
46
+ * <tr>
47
+ * <td>consumers</td>
48
+ * <td>An array of custom consumers in the format array(consumer_key => class_name)</td>
49
+ * <td>null</td>
50
+ * </tr>
51
+ * <tr>
52
+ * <td>host</td>
53
+ * <td>The host name for api calls (used by some consumers)</td>
54
+ * <td>api.mixpanel.com</td>
55
+ * </tr>
56
+ * <tr>
57
+ * <td>events_endpoint</td>
58
+ * <td>The endpoint for tracking events (relative to the host)</td>
59
+ * <td>/events</td>
60
+ * </tr>
61
+ * <tr>
62
+ * <td>people_endpoint</td>
63
+ * <td>The endpoint for making people updates (relative to the host)</td>
64
+ * <td>/engage</td>
65
+ * </tr>
66
+ * <tr>
67
+ * <td>use_ssl</td>
68
+ * <td>Tell the consumer whether or not to use ssl (when available)</td>
69
+ * <td>true</td>
70
+ * </tr>
71
+ * <tr>
72
+ * <td>error_callback</td>
73
+ * <td>The name of a function to be called on consumption failures</td>
74
+ * <td>null</td>
75
+ * </tr>
76
+ * <tr>
77
+ * <td>connect_timeout</td>
78
+ * <td>In both the SocketConsumer and CurlConsumer, this is used for the connection timeout (i.e. How long it has take to actually make a connection).
79
+ * <td>5</td>
80
+ * </tr>
81
+ * <tr>
82
+ * <td>timeout</td>
83
+ * <td>In the CurlConsumer (non-forked), it is used to determine how long the cURL call has to execute.
84
+ * <td>30</td>
85
+ * </tr>
86
+ * </table>
87
+ *
88
+ * Example: Tracking an Event
89
+ * -------------
90
+ *
91
+ * $mp = Mixpanel::getInstance("MY_TOKEN");
92
+ *
93
+ * $mp->track("My Event");
94
+ *
95
+ * Example: Setting Profile Properties
96
+ * -------------
97
+ *
98
+ * $mp = Mixpanel::getInstance("MY_TOKEN", array("use_ssl" => false));
99
+ *
100
+ * $mp->people->set(12345, array(
101
+ * '$first_name' => "John",
102
+ * '$last_name' => "Doe",
103
+ * '$email' => "john.doe@example.com",
104
+ * '$phone' => "5555555555",
105
+ * 'Favorite Color' => "red"
106
+ * ));
107
+ *
108
+ */
109
+ class Mixpanel extends Base_MixpanelBase {
110
+
111
+
112
+ /**
113
+ * An instance of the MixpanelPeople class (used to create/update profiles)
114
+ * @var MixpanelPeople
115
+ */
116
+ public $people;
117
+
118
+
119
+ /**
120
+ * An instance of the MixpanelEvents class
121
+ * @var Producers_MixpanelEvents
122
+ */
123
+ private $_events;
124
+
125
+
126
+ /**
127
+ * An instance of the Mixpanel class (for singleton use)
128
+ * @var Mixpanel
129
+ */
130
+ private static $_instance;
131
+
132
+
133
+ /**
134
+ * Instantiates a new Mixpanel instance.
135
+ * @param $token
136
+ * @param array $options
137
+ */
138
+ public function __construct($token, $options = array()) {
139
+ parent::__construct($options);
140
+ $this->people = new Producers_MixpanelPeople($token, $options);
141
+ $this->_events = new Producers_MixpanelEvents($token, $options);
142
+ }
143
+
144
+
145
+ /**
146
+ * Returns a singleton instance of Mixpanel
147
+ * @param $token
148
+ * @param array $options
149
+ * @return Mixpanel
150
+ */
151
+ public static function getInstance($token, $options = array()) {
152
+ if(!isset(self::$_instance)) {
153
+ self::$_instance = new Mixpanel($token, $options);
154
+ }
155
+ return self::$_instance;
156
+ }
157
+
158
+
159
+ /**
160
+ * Add an array representing a message to be sent to Mixpanel to the in-memory queue.
161
+ * @param array $message
162
+ */
163
+ public function enqueue($message = array()) {
164
+ $this->_events->enqueue($message);
165
+ }
166
+
167
+
168
+ /**
169
+ * Add an array representing a list of messages to be sent to Mixpanel to a queue.
170
+ * @param array $messages
171
+ */
172
+ public function enqueueAll($messages = array()) {
173
+ $this->_events->enqueueAll($messages);
174
+ }
175
+
176
+
177
+ /**
178
+ * Flush the events queue
179
+ * @param int $desired_batch_size
180
+ */
181
+ public function flush($desired_batch_size = 50) {
182
+ $this->_events->flush($desired_batch_size);
183
+ }
184
+
185
+
186
+ /**
187
+ * Empty the events queue
188
+ */
189
+ public function reset() {
190
+ $this->_events->reset();
191
+ }
192
+
193
+
194
+ /**
195
+ * Identify the user you want to associate to tracked events
196
+ * @param string|int $user_id
197
+ */
198
+ public function identify($user_id) {
199
+ $this->_events->identify($user_id);
200
+ }
201
+
202
+ /**
203
+ * Track an event defined by $event associated with metadata defined by $properties
204
+ * @param string $event
205
+ * @param array $properties
206
+ */
207
+ public function track($event, $properties = array()) {
208
+ $this->_events->track($event, $properties);
209
+ }
210
+
211
+
212
+ /**
213
+ * Register a property to be sent with every event.
214
+ *
215
+ * If the property has already been registered, it will be
216
+ * overwritten. NOTE: Registered properties are only persisted for the life of the Mixpanel class instance.
217
+ * @param string $property
218
+ * @param mixed $value
219
+ */
220
+ public function register($property, $value) {
221
+ $this->_events->register($property, $value);
222
+ }
223
+
224
+
225
+ /**
226
+ * Register multiple properties to be sent with every event.
227
+ *
228
+ * If any of the properties have already been registered,
229
+ * they will be overwritten. NOTE: Registered properties are only persisted for the life of the Mixpanel class
230
+ * instance.
231
+ * @param array $props_and_vals
232
+ */
233
+ public function registerAll($props_and_vals = array()) {
234
+ $this->_events->registerAll($props_and_vals);
235
+ }
236
+
237
+
238
+ /**
239
+ * Register a property to be sent with every event.
240
+ *
241
+ * If the property has already been registered, it will NOT be
242
+ * overwritten. NOTE: Registered properties are only persisted for the life of the Mixpanel class instance.
243
+ * @param $property
244
+ * @param $value
245
+ */
246
+ public function registerOnce($property, $value) {
247
+ $this->_events->registerOnce($property, $value);
248
+ }
249
+
250
+
251
+ /**
252
+ * Register multiple properties to be sent with every event.
253
+ *
254
+ * If any of the properties have already been registered,
255
+ * they will NOT be overwritten. NOTE: Registered properties are only persisted for the life of the Mixpanel class
256
+ * instance.
257
+ * @param array $props_and_vals
258
+ */
259
+ public function registerAllOnce($props_and_vals = array()) {
260
+ $this->_events->registerAllOnce($props_and_vals);
261
+ }
262
+
263
+
264
+ /**
265
+ * Un-register an property to be sent with every event.
266
+ * @param string $property
267
+ */
268
+ public function unregister($property) {
269
+ $this->_events->unregister($property);
270
+ }
271
+
272
+
273
+ /**
274
+ * Un-register a list of properties to be sent with every event.
275
+ * @param array $properties
276
+ */
277
+ public function unregisterAll($properties) {
278
+ $this->_events->unregisterAll($properties);
279
+ }
280
+
281
+
282
+ /**
283
+ * Get a property that is set to be sent with every event
284
+ * @param string $property
285
+ * @return mixed
286
+ */
287
+ public function getProperty($property)
288
+ {
289
+ return $this->_events->getProperty($property);
290
+ }
291
+
292
+
293
+ /**
294
+ * Alias an existing id with a different unique id. This is helpful when you want to associate a generated id
295
+ * (such as a session id) to a user id or username.
296
+ * @param string|int $original_id
297
+ * @param string|int $new_id
298
+ */
299
+ public function createAlias($original_id, $new_id) {
300
+ $this->_events->createAlias($original_id, $new_id);
301
+ }
302
+ }
libs/mixpanel/Producers/MixpanelBaseProducer.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/../Base/MixpanelBase.php");
3
+ require_once(dirname(__FILE__) . "/../ConsumerStrategies/FileConsumer.php");
4
+ require_once(dirname(__FILE__) . "/../ConsumerStrategies/CurlConsumer.php");
5
+ require_once(dirname(__FILE__) . "/../ConsumerStrategies/SocketConsumer.php");
6
+
7
+ if (!function_exists('json_encode')) {
8
+ throw new Exception('The JSON PHP extension is required.');
9
+ }
10
+
11
+ /**
12
+ * Provides some base methods for use by a message Producer
13
+ */
14
+ abstract class Producers_MixpanelBaseProducer extends Base_MixpanelBase {
15
+
16
+
17
+ /**
18
+ * @var string a token associated to a Mixpanel project
19
+ */
20
+ protected $_token;
21
+
22
+
23
+ /**
24
+ * @var array a queue to hold messages in memory before flushing in batches
25
+ */
26
+ private $_queue = array();
27
+
28
+
29
+ /**
30
+ * @var ConsumerStrategies_AbstractConsumer the consumer to use when flushing messages
31
+ */
32
+ private $_consumer = null;
33
+
34
+
35
+ /**
36
+ * @var array The list of available consumers
37
+ */
38
+ private $_consumers = array(
39
+ "file" => "ConsumerStrategies_FileConsumer",
40
+ "curl" => "ConsumerStrategies_CurlConsumer",
41
+ "socket" => "ConsumerStrategies_SocketConsumer"
42
+ );
43
+
44
+
45
+ /**
46
+ * If the queue reaches this size we'll auto-flush to prevent out of memory errors
47
+ * @var int
48
+ */
49
+ protected $_max_queue_size = 1000;
50
+
51
+
52
+ /**
53
+ * Creates a new MixpanelBaseProducer, assings Mixpanel project token, registers custom Consumers, and instantiates
54
+ * the desired consumer
55
+ * @param $token
56
+ * @param array $options
57
+ */
58
+ public function __construct($token, $options = array()) {
59
+
60
+ parent::__construct($options);
61
+
62
+ // register any customer consumers
63
+ if (array_key_exists("consumers", $options)) {
64
+ $this->_consumers = array_merge($this->_consumers, $options['consumers']);
65
+ }
66
+
67
+ // set max queue size
68
+ if (array_key_exists("max_queue_size", $options)) {
69
+ $this->_max_queue_size = $options['max_queue_size'];
70
+ }
71
+
72
+ // associate token
73
+ $this->_token = $token;
74
+
75
+ if ($this->_debug()) {
76
+ $this->_log("Using token: ".$this->_token);
77
+ }
78
+
79
+ // instantiate the chosen consumer
80
+ $this->_consumer = $this->_getConsumer();
81
+
82
+ }
83
+
84
+
85
+ /**
86
+ * Flush the queue when we destruct the client with retries
87
+ */
88
+ public function __destruct() {
89
+ $attempts = 0;
90
+ $max_attempts = 10;
91
+ $success = false;
92
+ while (!$success && $attempts < $max_attempts) {
93
+ if ($this->_debug()) {
94
+ $this->_log("destruct flush attempt #".($attempts+1));
95
+ }
96
+ $success = $this->flush();
97
+ $attempts++;
98
+ }
99
+ }
100
+
101
+
102
+ /**
103
+ * Iterate the queue and write in batches using the instantiated Consumer Strategy
104
+ * @param int $desired_batch_size
105
+ * @return bool whether or not the flush was successful
106
+ */
107
+ public function flush($desired_batch_size = 50) {
108
+ $queue_size = count($this->_queue);
109
+ $succeeded = true;
110
+ if ($this->_debug()) {
111
+ $this->_log("Flush called - queue size: ".$queue_size);
112
+ }
113
+
114
+ while($queue_size > 0 && $succeeded) {
115
+ $batch_size = min(array($queue_size, $desired_batch_size, $this->_options['max_batch_size']));
116
+ $batch = array_splice($this->_queue, 0, $batch_size);
117
+ $succeeded = $this->_persist($batch);
118
+
119
+ if (!$succeeded) {
120
+ if ($this->_debug()) {
121
+ $this->_log("Batch consumption failed!");
122
+ }
123
+ $this->_queue = array_merge($batch, $this->_queue);
124
+
125
+ if ($this->_debug()) {
126
+ $this->_log("added batch back to queue, queue size is now $queue_size");
127
+ }
128
+ }
129
+
130
+ $queue_size = count($this->_queue);
131
+
132
+ if ($this->_debug()) {
133
+ $this->_log("Batch of $batch_size consumed, queue size is now $queue_size");
134
+ }
135
+ }
136
+ return $succeeded;
137
+ }
138
+
139
+
140
+ /**
141
+ * Empties the queue without persisting any of the messages
142
+ */
143
+ public function reset() {
144
+ $this->_queue = array();
145
+ }
146
+
147
+
148
+ /**
149
+ * Returns the in-memory queue
150
+ * @return array
151
+ */
152
+ public function getQueue() {
153
+ return $this->_queue;
154
+ }
155
+
156
+ /**
157
+ * Returns the current Mixpanel project token
158
+ * @return string
159
+ */
160
+ public function getToken() {
161
+ return $this->_token;
162
+ }
163
+
164
+
165
+ /**
166
+ * Given a strategy type, return a new PersistenceStrategy object
167
+ * @return ConsumerStrategies_AbstractConsumer
168
+ */
169
+ protected function _getConsumer() {
170
+ $key = $this->_options['consumer'];
171
+ $Strategy = $this->_consumers[$key];
172
+ if ($this->_debug()) {
173
+ $this->_log("Using consumer: " . $key . " -> " . $Strategy);
174
+ }
175
+ $this->_options['endpoint'] = $this->_getEndpoint();
176
+
177
+ return new $Strategy($this->_options);
178
+ }
179
+
180
+
181
+ /**
182
+ * Add an array representing a message to be sent to Mixpanel to a queue.
183
+ * @param array $message
184
+ */
185
+ public function enqueue($message = array()) {
186
+ array_push($this->_queue, $message);
187
+
188
+ // force a flush if we've reached our threshold
189
+ if (count($this->_queue) > $this->_max_queue_size) {
190
+ $this->flush();
191
+ }
192
+
193
+ if ($this->_debug()) {
194
+ $this->_log("Queued message: ".json_encode($message));
195
+ }
196
+ }
197
+
198
+
199
+ /**
200
+ * Add an array representing a list of messages to be sent to Mixpanel to a queue.
201
+ * @param array $messages
202
+ */
203
+ public function enqueueAll($messages = array()) {
204
+ foreach($messages as $message) {
205
+ $this->enqueue($message);
206
+ }
207
+
208
+ }
209
+
210
+
211
+ /**
212
+ * Given an array of messages, persist it with the instantiated Persistence Strategy
213
+ * @param $message
214
+ * @return mixed
215
+ */
216
+ protected function _persist($message) {
217
+ return $this->_consumer->persist($message);
218
+ }
219
+
220
+
221
+
222
+
223
+ /**
224
+ * Return the endpoint that should be used by a consumer that consumes messages produced by this producer.
225
+ * @return string
226
+ */
227
+ abstract function _getEndpoint();
228
+
229
+ }
libs/mixpanel/Producers/MixpanelEvents.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/MixpanelBaseProducer.php");
3
+ require_once(dirname(__FILE__) . "/MixpanelPeople.php");
4
+ require_once(dirname(__FILE__) . "/../ConsumerStrategies/CurlConsumer.php");
5
+
6
+ /**
7
+ * Provides an API to track events on Mixpanel
8
+ */
9
+ class Producers_MixpanelEvents extends Producers_MixpanelBaseProducer {
10
+
11
+ /**
12
+ * An array of properties to attach to every tracked event
13
+ * @var array
14
+ */
15
+ private $_super_properties = array("mp_lib" => "php");
16
+
17
+
18
+ /**
19
+ * Track an event defined by $event associated with metadata defined by $properties
20
+ * @param string $event
21
+ * @param array $properties
22
+ */
23
+ public function track($event, $properties = array()) {
24
+
25
+ // if no token is passed in, use current token
26
+ if (!array_key_exists("token", $properties)) $properties['token'] = $this->_token;
27
+
28
+ // if no time is passed in, use the current time
29
+ if (!array_key_exists('time', $properties)) $properties['time'] = time();
30
+
31
+ $params['event'] = $event;
32
+ $params['properties'] = array_merge($this->_super_properties, $properties);
33
+
34
+ $this->enqueue($params);
35
+ }
36
+
37
+
38
+ /**
39
+ * Register a property to be sent with every event. If the property has already been registered, it will be
40
+ * overwritten.
41
+ * @param string $property
42
+ * @param mixed $value
43
+ */
44
+ public function register($property, $value) {
45
+ $this->_super_properties[$property] = $value;
46
+ }
47
+
48
+
49
+ /**
50
+ * Register multiple properties to be sent with every event. If any of the properties have already been registered,
51
+ * they will be overwritten.
52
+ * @param array $props_and_vals
53
+ */
54
+ public function registerAll($props_and_vals = array()) {
55
+ foreach($props_and_vals as $property => $value) {
56
+ $this->register($property, $value);
57
+ }
58
+ }
59
+
60
+
61
+ /**
62
+ * Register a property to be sent with every event. If the property has already been registered, it will NOT be
63
+ * overwritten.
64
+ * @param $property
65
+ * @param $value
66
+ */
67
+ public function registerOnce($property, $value) {
68
+ if (!isset($this->_super_properties[$property])) {
69
+ $this->register($property, $value);
70
+ }
71
+ }
72
+
73
+
74
+ /**
75
+ * Register multiple properties to be sent with every event. If any of the properties have already been registered,
76
+ * they will NOT be overwritten.
77
+ * @param array $props_and_vals
78
+ */
79
+ public function registerAllOnce($props_and_vals = array()) {
80
+ foreach($props_and_vals as $property => $value) {
81
+ if (!isset($this->_super_properties[$property])) {
82
+ $this->register($property, $value);
83
+ }
84
+ }
85
+ }
86
+
87
+
88
+ /**
89
+ * Un-register an property to be sent with every event.
90
+ * @param string $property
91
+ */
92
+ public function unregister($property) {
93
+ unset($this->_super_properties[$property]);
94
+ }
95
+
96
+
97
+ /**
98
+ * Un-register a list of properties to be sent with every event.
99
+ * @param array $properties
100
+ */
101
+ public function unregisterAll($properties) {
102
+ foreach($properties as $property) {
103
+ $this->unregister($property);
104
+ }
105
+ }
106
+
107
+
108
+ /**
109
+ * Get a property that is set to be sent with every event
110
+ * @param string $property
111
+ * @return mixed
112
+ */
113
+ public function getProperty($property) {
114
+ return $this->_super_properties[$property];
115
+ }
116
+
117
+
118
+ /**
119
+ * Identify the user you want to associate to tracked events
120
+ * @param string|int $user_id
121
+ */
122
+ public function identify($user_id) {
123
+ $this->register("distinct_id", $user_id);
124
+ }
125
+
126
+
127
+ /**
128
+ * Alias an existing id with a different unique id. This is helpful when you want to associate a generated id to
129
+ * a username or e-mail address.
130
+ *
131
+ * Because aliasing can be extremely vulnerable to race conditions and ordering issues, we'll make a synchronous
132
+ * call directly to Mixpanel when this method is called. If it fails we'll throw an Exception as subsequent
133
+ * events are likely to be incorrectly tracked.
134
+ * @param string|int $original_id
135
+ * @param string|int $new_id
136
+ * @return array $msg
137
+ * @throws Exception
138
+ */
139
+ public function createAlias($original_id, $new_id) {
140
+ $msg = array(
141
+ "event" => '$create_alias',
142
+ "properties" => array("distinct_id" => $original_id, "alias" => $new_id, "token" => $this->_token)
143
+ );
144
+
145
+ $options = array_merge($this->_options, array("endpoint" => $this->_getEndpoint(), "fork" => false));
146
+ $curlConsumer = new ConsumerStrategies_CurlConsumer($options);
147
+ $success = $curlConsumer->persist(array($msg));
148
+ if (!$success) {
149
+ error_log("Creating Mixpanel Alias (original id: $original_id, new id: $new_id) failed");
150
+ throw new Exception("Tried to create an alias but the call was not successful");
151
+ } else {
152
+ return $msg;
153
+ }
154
+ }
155
+
156
+
157
+ /**
158
+ * Returns the "events" endpoint
159
+ * @return string
160
+ */
161
+ function _getEndpoint() {
162
+ return $this->_options['events_endpoint'];
163
+ }
164
+ }
libs/mixpanel/Producers/MixpanelPeople.php ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require_once(dirname(__FILE__) . "/MixpanelBaseProducer.php");
3
+
4
+ /**
5
+ * Provides an API to create/update profiles on Mixpanel
6
+ */
7
+ class Producers_MixpanelPeople extends Producers_MixpanelBaseProducer {
8
+
9
+ /**
10
+ * Internal method to prepare a message given the message data
11
+ * @param $distinct_id
12
+ * @param $operation
13
+ * @param $value
14
+ * @param null $ip
15
+ * @return array
16
+ */
17
+ private function _constructPayload($distinct_id, $operation, $value, $ip = null, $ignore_time = false) {
18
+ $payload = array(
19
+ '$token' => $this->_token,
20
+ '$distinct_id' => $distinct_id,
21
+ $operation => $value
22
+ );
23
+ if ($ip !== null) $payload['$ip'] = $ip;
24
+ if ($ignore_time === true) $payload['$ignore_time'] = true;
25
+ return $payload;
26
+ }
27
+
28
+ /**
29
+ * Set properties on a user record. If the profile does not exist, it creates it with these properties.
30
+ * If it does exist, it sets the properties to these values, overwriting existing values.
31
+ * @param string|int $distinct_id the distinct_id or alias of a user
32
+ * @param array $props associative array of properties to set on the profile
33
+ * @param string|null $ip the ip address of the client (used for geo-location)
34
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
35
+ */
36
+ public function set($distinct_id, $props, $ip = null, $ignore_time = false) {
37
+ $payload = $this->_constructPayload($distinct_id, '$set', $props, $ip, $ignore_time);
38
+ $this->enqueue($payload);
39
+ }
40
+
41
+ /**
42
+ * Set properties on a user record. If the profile does not exist, it creates it with these properties.
43
+ * If it does exist, it sets the properties to these values but WILL NOT overwrite existing values.
44
+ * @param string|int $distinct_id the distinct_id or alias of a user
45
+ * @param array $props associative array of properties to set on the profile
46
+ * @param string|null $ip the ip address of the client (used for geo-location)
47
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
48
+ */
49
+ public function setOnce($distinct_id, $props, $ip = null, $ignore_time = false) {
50
+ $payload = $this->_constructPayload($distinct_id, '$set_once', $props, $ip, $ignore_time);
51
+ $this->enqueue($payload);
52
+ }
53
+
54
+ /**
55
+ * Unset properties on a user record. If the profile does not exist, it creates it with no properties.
56
+ * If it does exist, it unsets these properties. NOTE: In other libraries we use 'unset' which is
57
+ * a reserved word in PHP.
58
+ * @param string|int $distinct_id the distinct_id or alias of a user
59
+ * @param array $props associative array of properties to unset on the profile
60
+ * @param string|null $ip the ip address of the client (used for geo-location)
61
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
62
+ */
63
+ public function remove($distinct_id, $props, $ip = null, $ignore_time = false) {
64
+ $payload = $this->_constructPayload($distinct_id, '$unset', $props, $ip, $ignore_time);
65
+ $this->enqueue($payload);
66
+ }
67
+
68
+ /**
69
+ * Increments the value of a property on a user record. If the profile does not exist, it creates it and sets the
70
+ * property to the increment value.
71
+ * @param string|int $distinct_id the distinct_id or alias of a user
72
+ * @param $prop string the property to increment
73
+ * @param int $val the amount to increment the property by
74
+ * @param string|null $ip the ip address of the client (used for geo-location)
75
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
76
+ */
77
+ public function increment($distinct_id, $prop, $val, $ip = null, $ignore_time = false) {
78
+ $payload = $this->_constructPayload($distinct_id, '$add', array("$prop" => $val), $ip, $ignore_time);
79
+ $this->enqueue($payload);
80
+ }
81
+
82
+ /**
83
+ * Adds $val to a list located at $prop. If the property does not exist, it will be created. If $val is a string
84
+ * and the list is empty or does not exist, a new list with one value will be created.
85
+ * @param string|int $distinct_id the distinct_id or alias of a user
86
+ * @param string $prop the property that holds the list
87
+ * @param string|array $val items to add to the list
88
+ * @param string|null $ip the ip address of the client (used for geo-location)
89
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
90
+ */
91
+ public function append($distinct_id, $prop, $val, $ip = null, $ignore_time = false) {
92
+ $operation = gettype($val) == "array" ? '$union' : '$append';
93
+ $payload = $this->_constructPayload($distinct_id, $operation, array("$prop" => $val), $ip, $ignore_time);
94
+ $this->enqueue($payload);
95
+ }
96
+
97
+ /**
98
+ * Adds a transaction to the user's profile for revenue tracking
99
+ * @param string|int $distinct_id the distinct_id or alias of a user
100
+ * @param string $amount the transaction amount e.g. "20.50"
101
+ * @param null $timestamp the timestamp of when the transaction occurred (default to current timestamp)
102
+ * @param string|null $ip the ip address of the client (used for geo-location)
103
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
104
+ */
105
+ public function trackCharge($distinct_id, $amount, $timestamp = null, $ip = null, $ignore_time = false) {
106
+ $timestamp = $timestamp == null ? time() : $timestamp;
107
+ $date_iso = date("c", $timestamp);
108
+ $transaction = array(
109
+ '$time' => $date_iso,
110
+ '$amount' => $amount
111
+ );
112
+ $val = array('$transactions' => $transaction);
113
+ $payload = $this->_constructPayload($distinct_id, '$append', $val, $ip, $ignore_time);
114
+ $this->enqueue($payload);
115
+ }
116
+
117
+ /**
118
+ * Clear all transactions stored on a user's profile
119
+ * @param string|int $distinct_id the distinct_id or alias of a user
120
+ * @param string|null $ip the ip address of the client (used for geo-location)
121
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
122
+ */
123
+ public function clearCharges($distinct_id, $ip = null, $ignore_time = false) {
124
+ $payload = $this->_constructPayload($distinct_id, '$set', array('$transactions' => array()), $ip, $ignore_time);
125
+ $this->enqueue($payload);
126
+ }
127
+
128
+ /**
129
+ * Delete this profile from Mixpanel
130
+ * @param string|int $distinct_id the distinct_id or alias of a user
131
+ * @param string|null $ip the ip address of the client (used for geo-location)
132
+ * @param boolean $ignore_time If the $ignore_time property is true, Mixpanel will not automatically update the "Last Seen" property of the profile. Otherwise, Mixpanel will add a "Last Seen" property associated with the current time
133
+ */
134
+ public function deleteUser($distinct_id, $ip = null, $ignore_time = false) {
135
+ $payload = $this->_constructPayload($distinct_id, '$delete', "", $ip, $ignore_time);
136
+ $this->enqueue($payload);
137
+ }
138
+
139
+ /**
140
+ * Returns the "engage" endpoint
141
+ * @return string
142
+ */
143
+ function _getEndpoint() {
144
+ return $this->_options['people_endpoint'];
145
+ }
146
+
147
+ }
libs/ms_admin_page.php CHANGED
@@ -1,9 +1,16 @@
 
 
1
  <script type="text/javascript">
2
  if (typeof ajax_url === 'undefined') {
3
  ajax_url = '<?php echo admin_url() ?>admin-ajax.php';
4
  }
5
  var last_site_key = null;
6
  var sk_ms_admin = true;
 
 
 
 
 
7
  </script>
8
 
9
  <div class="page-header"><h2><a id="pluginlogo_32" class="header-icon32" href="http://www.sidekick.pro" target="_blank"></a>Sidekick Licensing</h2></div>
@@ -40,8 +47,6 @@
40
  </div>
41
  <?php endif ?>
42
 
43
-
44
-
45
  <div class="sidekick_admin">
46
 
47
  <div class="sk_box left">
@@ -69,24 +74,32 @@
69
  <input class='regular-text' type='password' name='sk_password' placeholder='********'></input>
70
  </td>
71
  </tr>
72
- <tr valign="top">
73
  <th scope="row" valign="top">Subscription</th>
74
  <td>
75
  <select name='sk_selected_subscription'>
76
  <?php if (isset($sk_subs['subscriptions']) && count($sk_subs['subscriptions']) > 0): ?>
77
  <?php foreach ($sk_subs['subscriptions'] as $key => $sub): ?>
78
  <?php
79
- if ($sub->PlanId !== 1) {
80
  continue;
81
  }
82
- if ($sk_selected_subscription == $sub->id) {
 
 
 
 
 
 
 
 
83
  $selected_sub = $sub;
84
  $selected = 'SELECTED';
85
  } else {
86
  $selected = '';
87
  }
88
  ?>
89
- <option <?php echo $selected ?> value='<?php echo $sub->id ?>'><?php echo $sub->Plan->name . ' - ' . $sub->CurrentTier->name ?></option>
90
  <?php endforeach ?>
91
  <?php if (!isset($selected_sub)): ?>
92
  <option value='0'>No Compatible Subscriptions</option>
@@ -97,17 +110,38 @@
97
  </select>
98
  </td>
99
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  <tr valign="top">
101
  <th scope="row" valign="top">Enable Auto-Activations</th>
102
  <td>
103
- <?php if (!isset($selected_sub)): ?>
104
  <input class='checkbox' type='checkbox' name='sk_auto_activations' DISABLED>
105
  <?php else: ?>
106
  <input class='checkbox' type='checkbox' name='sk_auto_activations' <?php echo ($sk_auto_activations) ? 'CHECKED' : '' ?>>
107
  <?php endif ?>
108
  </td>
109
  </tr>
110
- <?php if (isset($selected_sub)): ?>
 
111
  <tr>
112
  <th scope="row" valign="top">Active Domains</th>
113
  <td><?php echo $selected_sub->activeDomainCount ?>/ <?php echo ($selected_sub->CurrentTier->numberOfDomains == -1) ? 'Unlimited' : $selected_sub->CurrentTier->numberOfDomains ?> (<a href='https://www.sidekick.pro/profile/#/overview' target='_blank'>Manage</a>)
@@ -212,6 +246,6 @@
212
 
213
  </div>
214
 
215
-
216
 
217
 
1
+ <!-- ms_admin_page.php -->
2
+
3
  <script type="text/javascript">
4
  if (typeof ajax_url === 'undefined') {
5
  ajax_url = '<?php echo admin_url() ?>admin-ajax.php';
6
  }
7
  var last_site_key = null;
8
  var sk_ms_admin = true;
9
+
10
+ jQuery(document).ready(function($) {
11
+ mixpanel.track('Network Settings Page Visit - Plugin');
12
+ });
13
+
14
  </script>
15
 
16
  <div class="page-header"><h2><a id="pluginlogo_32" class="header-icon32" href="http://www.sidekick.pro" target="_blank"></a>Sidekick Licensing</h2></div>
47
  </div>
48
  <?php endif ?>
49
 
 
 
50
  <div class="sidekick_admin">
51
 
52
  <div class="sk_box left">
74
  <input class='regular-text' type='password' name='sk_password' placeholder='********'></input>
75
  </td>
76
  </tr>
77
+ <tr valign="top" style='display: none'>
78
  <th scope="row" valign="top">Subscription</th>
79
  <td>
80
  <select name='sk_selected_subscription'>
81
  <?php if (isset($sk_subs['subscriptions']) && count($sk_subs['subscriptions']) > 0): ?>
82
  <?php foreach ($sk_subs['subscriptions'] as $key => $sub): ?>
83
  <?php
84
+ if ($sub->PlanId !== 1 && $sub->Plan->CreatableProductType->name !== 'Private') {
85
  continue;
86
  }
87
+
88
+ if (isset($sub->Plan->CreatableProductType->name) && $sub->Plan->CreatableProductType->name == 'Private') {
89
+ $type = 'product';
90
+ } else {
91
+ $type = 'subscription';
92
+ }
93
+
94
+
95
+ if ($sk_selected_subscription == ($type . '-' . $sub->id) || !isset($selected_sub)) {
96
  $selected_sub = $sub;
97
  $selected = 'SELECTED';
98
  } else {
99
  $selected = '';
100
  }
101
  ?>
102
+ <option <?php echo $selected ?> value='<?php echo (isset($sub->Plan->CreatableProductType->name) && $sub->Plan->CreatableProductType->name == 'Private') ? "product-" : "subscription-"; echo $sub->id ?>'><?php echo $sub->Plan->name . ' - ' . $sub->CurrentTier->name ?></option>
103
  <?php endforeach ?>
104
  <?php if (!isset($selected_sub)): ?>
105
  <option value='0'>No Compatible Subscriptions</option>
110
  </select>
111
  </td>
112
  </tr>
113
+ <?php if (isset($sk_subs['products'])): ?>
114
+
115
+ <tr valign="top" style='display: none' class='walkthrough_library'>
116
+ <th scope="row" valign="top">Library</th>
117
+ <td>
118
+ <select name='sk_selected_product'>
119
+ <?php if (isset($sk_subs['products']) && count($sk_subs['products']) > 0): ?>
120
+ <?php foreach ($sk_subs['products'] as $key => $product): ?>
121
+ <option <?php echo ($sk_selected_product == $product->id) ? 'SELECTED' : '' ?> value='<?php echo $product->id ?>'><?php echo $product->name ?></option>
122
+ <?php endforeach ?>
123
+ <?php else: ?>
124
+ <option style='color: red' value='0'>No Libraries Found!</option>
125
+ <?php $no_product = true; delete_option( 'sk_auto_activations') ?>
126
+ <?php endif ?>
127
+ </select>
128
+ </td>
129
+ </tr>
130
+
131
+ <?php endif ?>
132
+
133
  <tr valign="top">
134
  <th scope="row" valign="top">Enable Auto-Activations</th>
135
  <td>
136
+ <?php if (!isset($selected_sub) || isset($no_product)): ?>
137
  <input class='checkbox' type='checkbox' name='sk_auto_activations' DISABLED>
138
  <?php else: ?>
139
  <input class='checkbox' type='checkbox' name='sk_auto_activations' <?php echo ($sk_auto_activations) ? 'CHECKED' : '' ?>>
140
  <?php endif ?>
141
  </td>
142
  </tr>
143
+ <?php //var_dump($selected_sub); ?>
144
+ <?php if (isset($selected_sub) && !isset($no_product)): ?>
145
  <tr>
146
  <th scope="row" valign="top">Active Domains</th>
147
  <td><?php echo $selected_sub->activeDomainCount ?>/ <?php echo ($selected_sub->CurrentTier->numberOfDomains == -1) ? 'Unlimited' : $selected_sub->CurrentTier->numberOfDomains ?> (<a href='https://www.sidekick.pro/profile/#/overview' target='_blank'>Manage</a>)
246
 
247
  </div>
248
 
249
+ <!-- //ms_admin_page.php -->
250
 
251
 
libs/sk_config_data.php CHANGED
@@ -1,205 +1,200 @@
1
  <?php
 
2
 
3
- class sk_config_data{
4
- function get_domain(){
5
- $site_url = get_site_url();
6
- if(substr($site_url, -1) == '/') {
7
- $site_url = substr($site_url, 0, -1);
 
 
 
 
 
8
  }
9
- $site_url = str_replace(array("http://","https://"),array(""),$site_url);
10
- return $site_url;
11
- }
12
 
13
- function get_post_types(){
14
- global $wpdb;
15
- $query = "SELECT post_type, count(distinct ID) as count from {$wpdb->prefix}posts group by post_type";
16
- $counts = $wpdb->get_results($query);
17
- $output = '';
18
 
19
- foreach ($counts as $key => $type) {
20
- $type->post_type = str_replace('-', '_', $type->post_type);
21
- $output .= "\n post_type_{$type->post_type} : $type->count,";
 
 
22
  }
23
- return $output;
24
- }
25
 
26
- function get_themes(){
27
- $themes = wp_get_themes( array( 'allowed' => true ) );
28
- return count($themes);
29
- }
30
 
31
- function get_post_types_and_statuses(){
32
- global $wpdb;
33
- $query = "SELECT post_type, post_status, count(distinct ID) as count from {$wpdb->prefix}posts group by post_type, post_status";
34
- $counts = $wpdb->get_results($query);
35
- $output = '';
36
 
37
- foreach ($counts as $key => $type) {
38
- $type->post_type = str_replace('-', '_', $type->post_type);
39
- $type->post_status = str_replace('-', '_', $type->post_status);
40
 
41
- $output .= "\n post_type_{$type->post_type}_{$type->post_status} : $type->count,";
 
 
42
  }
43
- return $output;
44
- }
45
 
46
- function get_taxonomies(){
47
- global $wpdb;
48
- $query = "SELECT count(distinct term_taxonomy_id) as count, taxonomy from {$wpdb->prefix}term_taxonomy group by taxonomy";
49
- $counts = $wpdb->get_results($query);
50
- $output = '';
51
 
52
- foreach ($counts as $key => $taxonomy) {
53
- $taxonomy->taxonomy = str_replace('-', '_', $taxonomy->taxonomy);
54
- $output .= "\n taxonomy_{$taxonomy->taxonomy} : $taxonomy->count,";
 
 
55
  }
56
- return $output;
57
- }
58
 
59
- function get_comments(){
60
- global $wpdb;
61
- $query = "SELECT count(distinct comment_ID) as count from {$wpdb->prefix}comments";
62
- $counts = $wpdb->get_var($query);
63
- if (!$counts) $counts = 0;
64
- return "\n comment_count : $counts,";
65
- }
66
 
67
- function get_post_statuses(){
68
- global $wpdb;
69
- $query = "SELECT post_status, count(ID) as count from {$wpdb->prefix}posts group by post_status";
70
- $counts = $wpdb->get_results($query);
71
- $output = '';
72
 
73
- foreach ($counts as $key => $type) {
74
- $type->post_status = str_replace('-', '_', $type->post_status);
75
- $output .= "\n post_status_{$type->post_status} : $type->count,";
 
 
76
  }
77
- return $output;
78
- }
79
 
80
- function get_user_data(){
81
- global $current_user;
82
 
83
- $data = get_userdata($current_user->ID);
84
- $output = "\n user_id : $current_user->ID,";
85
 
86
- foreach ($data->allcaps as $cap => $val) {
87
- $cap = sanitize_title($cap);
88
- $cap = str_replace('-', '_', $cap);
89
- if (!$val) $val = 0;
90
- $output .= "\n cap_{$cap} : $val,";
 
 
91
  }
92
- return $output;
93
- }
94
 
95
- function get_framework(){
96
- global $current_user;
97
 
98
- $frameworks = array('genesis');
99
 
100
- $output = "\n theme_framework : false,";
101
 
102
- foreach ($frameworks as $framework) {
103
- switch ($framework) {
104
- case 'genesis':
105
- if (function_exists( 'genesis' ) ) {
106
- if (defined('PARENT_THEME_VERSION')) {
107
- $output = "\n theme_framework : {name: '" . $framework . "', version: '" . PARENT_THEME_VERSION . "'},";
 
108
  }
 
109
  }
110
- break;
111
  }
 
112
  }
113
- return $output;
114
- }
115
 
116
- function get_current_url() {
117
- if (isset($_SERVER['REQUEST_URI'])) {
118
- return 'http'.(empty($_SERVER['HTTPS'])?'':'s').'://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
119
- } else if (isset($_SERVER['PATH_INFO'])) {
120
- return $_SERVER['PATH_INFO'];
121
- } else {
122
- $host = $_SERVER['HTTP_HOST'];
123
- $port = $_SERVER['SERVER_PORT'];
124
- $request = $_SERVER['PHP_SELF'];
125
- $query = isset($_SERVER['argv']) ? substr($_SERVER['argv'][0], strpos($_SERVER['argv'][0], ';') + 1) : '';
126
- $toret = $protocol . '://' . $host . ($port == $protocol_port ? '' : ':' . $port) . $request . (empty($query) ? '' : '?' . $query);
127
- return $toret;
 
128
  }
129
- }
130
 
131
- function get_disabled_wts(){
132
- $wts = str_replace('"', '', get_option('sk_disabled_wts'));
133
- if ($wts) {
134
- return $wts;
 
 
135
  }
136
- return 'false';
137
- }
138
-
139
- function get_disabled_network_wts(){
140
- $wts = str_replace('"', '', get_site_option('sk_disabled_wts'));
141
 
142
- if ($wts) {
143
- return $wts;
 
 
 
 
 
 
144
  }
145
- return 'false';
146
- }
147
-
148
- function get_plugins(){
149
- $active_plugins = wp_get_active_and_valid_plugins();
150
- $mu_plugins = get_mu_plugins();
151
-
152
- $printed = false;
153
 
154
- $output = '[';
155
- $count = 0;
156
 
157
- if (is_array($active_plugins)) {
158
- foreach ($active_plugins as $plugins_key => $plugin) {
159
- $data = get_plugin_data( $plugin, false, false );
160
 
161
- $plugins[addslashes($data['Name'])] = $data['Version'];
162
- if ($plugins_key > 0) $output .= ',';
163
- $data['Name'] = addslashes($data['Name']);
164
- $output .= "{'{$data['Name']}' : '{$data['Version']}'}";
165
- $printed = true;
166
- $count++;
 
167
  }
168
- }
169
 
170
- if (is_array($mu_plugins)) {
171
- foreach ($mu_plugins as $plugins_key => $plugin) {
172
- $plugins[addslashes($plugin['Name'])] = $plugin['Version'];
173
- if ($printed) $output .= ',';
174
- $plugin['Name'] = addslashes($plugin['Name']);
175
- $output .= "{'{$plugin['Name']}' : '{$plugin['Version']}'}";
176
- $printed = true;
177
- $count++;
178
  }
 
179
  }
180
- $output .= ']';
181
- return array('plugins' => $output, 'count' => $count);
182
- }
183
 
184
- function get_user_role(){
185
- global $current_user, $wp_roles;
186
 
187
- if (is_super_admin($current_user->ID)) {
188
- return 'administrator';
189
- }
190
-
191
- if(!isset($current_user->caps) || count($current_user->caps) < 1){
192
- // In MS in some specific pages current user is returning empty caps so this is a work around for that case.
193
- if (current_user_can('activate_plugins')){
194
  return 'administrator';
195
  }
196
- }
197
- foreach($wp_roles->role_names as $role => $Role) {
198
- if (array_key_exists($role, $current_user->caps)){
199
- $user_role = $role;
200
- break;
 
201
  }
 
 
 
 
 
 
 
202
  }
203
- return $user_role;
204
  }
205
- }
 
 
1
  <?php
2
+ // sk_config_data.php
3
 
4
+ if (!class_exists('sk_config_data')) {
5
+
6
+ class sk_config_data{
7
+ function get_domain(){
8
+ $site_url = get_site_url();
9
+ if(substr($site_url, -1) == '/') {
10
+ $site_url = substr($site_url, 0, -1);
11
+ }
12
+ $site_url = str_replace(array("http://","https://"),array(""),$site_url);
13
+ return $site_url;
14
  }
 
 
 
15
 
16
+ function get_post_types(){
17
+ global $wpdb;
18
+ $query = "SELECT post_type, count(distinct ID) as count from {$wpdb->prefix}posts group by post_type";
19
+ $counts = $wpdb->get_results($query);
20
+ $output = '';
21
 
22
+ foreach ($counts as $key => $type) {
23
+ $type->post_type = str_replace('-', '_', $type->post_type);
24
+ $output .= "\n post_type_{$type->post_type} : $type->count,";
25
+ }
26
+ return $output;
27
  }
 
 
28
 
29
+ function get_themes(){
30
+ $themes = wp_get_themes( array( 'allowed' => true ) );
31
+ return count($themes);
32
+ }
33
 
34
+ function get_post_types_and_statuses(){
35
+ global $wpdb;
36
+ $query = "SELECT post_type, post_status, count(distinct ID) as count from {$wpdb->prefix}posts group by post_type, post_status";
37
+ $counts = $wpdb->get_results($query);
38
+ $output = '';
39
 
40
+ foreach ($counts as $key => $type) {
41
+ $type->post_type = str_replace('-', '_', $type->post_type);
42
+ $type->post_status = str_replace('-', '_', $type->post_status);
43
 
44
+ $output .= "\n post_type_{$type->post_type}_{$type->post_status} : $type->count,";
45
+ }
46
+ return $output;
47
  }
 
 
48
 
49
+ function get_taxonomies(){
50
+ global $wpdb;
51
+ $query = "SELECT count(distinct term_taxonomy_id) as count, taxonomy from {$wpdb->prefix}term_taxonomy group by taxonomy";
52
+ $counts = $wpdb->get_results($query);
53
+ $output = '';
54
 
55
+ foreach ($counts as $key => $taxonomy) {
56
+ $taxonomy->taxonomy = str_replace('-', '_', $taxonomy->taxonomy);
57
+ $output .= "\n taxonomy_{$taxonomy->taxonomy} : $taxonomy->count,";
58
+ }
59
+ return $output;
60
  }
 
 
61
 
62
+ function get_comments(){
63
+ global $wpdb;
64
+ $query = "SELECT count(distinct comment_ID) as count from {$wpdb->prefix}comments";
65
+ $counts = $wpdb->get_var($query);
66
+ if (!$counts) $counts = 0;
67
+ return "\n comment_count : $counts,";
68
+ }
69
 
70
+ function get_post_statuses(){
71
+ global $wpdb;
72
+ $query = "SELECT post_status, count(ID) as count from {$wpdb->prefix}posts group by post_status";
73
+ $counts = $wpdb->get_results($query);
74
+ $output = '';
75
 
76
+ foreach ($counts as $key => $type) {
77
+ $type->post_status = str_replace('-', '_', $type->post_status);
78
+ $output .= "\n post_status_{$type->post_status} : $type->count,";
79
+ }
80
+ return $output;
81
  }
 
 
82
 
83
+ function get_user_data(){
84
+ global $current_user;
85
 
86
+ $data = get_userdata($current_user->ID);
87
+ $output = "\n user_id : $current_user->ID,";
88
 
89
+ foreach ($data->allcaps as $cap => $val) {
90
+ $cap = sanitize_title($cap);
91
+ $cap = str_replace('-', '_', $cap);
92
+ if (!$val) $val = 0;
93
+ $output .= "\n cap_{$cap} : $val,";
94
+ }
95
+ return $output;
96
  }
 
 
97
 
98
+ function get_framework(){
99
+ global $current_user;
100
 
101
+ $frameworks = array('genesis');
102
 
103
+ $output = "\n theme_framework : false,";
104
 
105
+ foreach ($frameworks as $framework) {
106
+ switch ($framework) {
107
+ case 'genesis':
108
+ if (function_exists( 'genesis' ) ) {
109
+ if (defined('PARENT_THEME_VERSION')) {
110
+ $output = "\n theme_framework : {name: '" . $framework . "', version: '" . PARENT_THEME_VERSION . "'},";
111
+ }
112
  }
113
+ break;
114
  }
 
115
  }
116
+ return $output;
117
  }
 
 
118
 
119
+ function get_current_url() {
120
+ if (isset($_SERVER['REQUEST_URI'])) {
121
+ return 'http'.(empty($_SERVER['HTTPS'])?'':'s').'://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
122
+ } else if (isset($_SERVER['PATH_INFO'])) {
123
+ return $_SERVER['PATH_INFO'];
124
+ } else {
125
+ $host = $_SERVER['HTTP_HOST'];
126
+ $port = $_SERVER['SERVER_PORT'];
127
+ $request = $_SERVER['PHP_SELF'];
128
+ $query = isset($_SERVER['argv']) ? substr($_SERVER['argv'][0], strpos($_SERVER['argv'][0], ';') + 1) : '';
129
+ $toret = $protocol . '://' . $host . ($port == $protocol_port ? '' : ':' . $port) . $request . (empty($query) ? '' : '?' . $query);
130
+ return $toret;
131
+ }
132
  }
 
133
 
134
+ function get_disabled_wts(){
135
+ $wts = str_replace('"', '', get_option('sk_disabled_wts'));
136
+ if ($wts) {
137
+ return $wts;
138
+ }
139
+ return 'false';
140
  }
 
 
 
 
 
141
 
142
+ function get_disabled_network_wts(){
143
+ if (is_multisite()) {
144
+ $wts = str_replace('"', '', get_site_option('sk_disabled_wts'));
145
+ if ($wts) {
146
+ return $wts;
147
+ }
148
+ }
149
+ return 'false';
150
  }
 
 
 
 
 
 
 
 
151
 
152
+ function get_plugins(){
 
153
 
154
+ $active_plugins = wp_get_active_and_valid_plugins();
155
+ $mu_plugins = get_mu_plugins();
156
+ $output = array();
157
 
158
+ if (is_array($active_plugins)) {
159
+ foreach ($active_plugins as $plugins_key => $plugin) {
160
+ $data = get_plugin_data( $plugin, false, false );
161
+ $slug = explode('/',plugin_basename($plugin));
162
+ $slug = str_replace('.php', '', $slug[1]);
163
+ $output[$slug] = $data['Version'];
164
+ }
165
  }
 
166
 
167
+ if (is_array($mu_plugins)) {
168
+ foreach ($mu_plugins as $plugins_key => $plugin) {
169
+ $slug = str_replace('.php', '', $plugins_key);
170
+ $output[$slug] = '1.0.0';
171
+ }
 
 
 
172
  }
173
+ return $output;
174
  }
 
 
 
175
 
176
+ function get_user_role(){
177
+ global $current_user, $wp_roles;
178
 
179
+ if (is_super_admin($current_user->ID)) {
 
 
 
 
 
 
180
  return 'administrator';
181
  }
182
+
183
+ if(!isset($current_user->caps) || count($current_user->caps) < 1){
184
+ // In MS in some specific pages current user is returning empty caps so this is a work around for that case.
185
+ if (current_user_can('activate_plugins')){
186
+ return 'administrator';
187
+ }
188
  }
189
+ foreach($wp_roles->role_names as $role => $Role) {
190
+ if (array_key_exists($role, $current_user->caps)){
191
+ $user_role = $role;
192
+ break;
193
+ }
194
+ }
195
+ return $user_role;
196
  }
 
197
  }
198
+ }
199
+
200
+ // //sk_config_data.php
libs/walkthrough_config.php CHANGED
@@ -19,9 +19,11 @@
19
 
20
  <div class="sk_box configure">
21
  <div class="well">
22
- <h3>Configure - Turn Off Walkthroughs</h3>
23
-
24
  <form method='post'>
 
 
 
 
25
  <p>Below you can turn off specific Walkthroughs for this website.</p>
26
  <p>Please note, incompatible multisite walkthroughs will be disabled automatically on individual sites already. Here you're being show the raw unfiltered list of all available walkthroughs.</p>
27
  <div class='sk_walkthrough_list wrapper_wts'>
19
 
20
  <div class="sk_box configure">
21
  <div class="well">
 
 
22
  <form method='post'>
23
+
24
+ <input class='top-right button button-primary alignright' type='submit' value='Save'/>
25
+ <h3>Configure - Turn Off Walkthroughs</h3>
26
+
27
  <p>Below you can turn off specific Walkthroughs for this website.</p>
28
  <p>Please note, incompatible multisite walkthroughs will be disabled automatically on individual sites already. Here you're being show the raw unfiltered list of all available walkthroughs.</p>
29
  <div class='sk_walkthrough_list wrapper_wts'>
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: http://www.sidekick.pro
4
  Tags: help, tutorial, training, learn, learning, sidekick, guide, teach, video, manual, videos, wphelp, support, instructions, question, questions, answers, answer, clippy, q&a, wpuniversity, helper, walkthrough
5
  Requires at least: 3.7
6
  Tested up to: 4.1
7
- Stable tag: 2.0.1
8
  License: GNU Version 2 or Any Later Version
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -130,7 +130,21 @@ Absolutely. In fact, we rely on users like you to tell us about things that nee
130
 
131
  == Changelog ==
132
 
133
- = 2.0.1 =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  * Multisite Walkthrough Management Support
135
  * Multisite Auto Activations
136
  * Multisite Mass Activations
4
  Tags: help, tutorial, training, learn, learning, sidekick, guide, teach, video, manual, videos, wphelp, support, instructions, question, questions, answers, answer, clippy, q&a, wpuniversity, helper, walkthrough
5
  Requires at least: 3.7
6
  Tested up to: 4.1
7
+ Stable tag: 2.2.0
8
  License: GNU Version 2 or Any Later Version
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
130
 
131
  == Changelog ==
132
 
133
+ = 2.2.0 =
134
+ * SIDEKICK can now be embeded within other plugins!
135
+ * Custom walkthrough plans are now supported within MultiSite auto activation
136
+ * Wildcard compatibility matching added
137
+ * Captioning support added
138
+ * Fixes issues with general UI elements
139
+ * Fixes issues with walkthrough preview
140
+ * Fixes issues with Safari alignment on settings page
141
+
142
+ = 2.1.1 =
143
+ * Added SIDEKICK version check
144
+ * Fixes issues with saving autostart walkthroughs
145
+ * Fixes issues with disabling walkthroughs
146
+
147
+ = 2.1.0 =
148
  * Multisite Walkthrough Management Support
149
  * Multisite Auto Activations
150
  * Multisite Mass Activations
sidekick.php CHANGED
@@ -4,436 +4,485 @@
4
  Plugin Name: Sidekick
5
  Plugin URL: http://wordpress.org/plugins/sidekick/
6
  Description: Adds a real-time WordPress training walkthroughs right in your Dashboard
7
- Requires at least: 3.8
8
- Tested up to: 4.0
9
- Version: 2.0.1
10
  Author: Sidekick.pro
11
  Author URI: http://www.sidekick.pro
12
  */
13
 
14
 
15
- if ( ! defined( 'PLAYER_PATH' ) ) define( 'PLAYER_PATH', 'tag/latest' );
16
- if ( ! defined( 'PLAYER_FILE' ) ) define( 'PLAYER_FILE', 'sidekick.min.js' );
17
- if ( ! defined( 'COMPOSER_PATH' ) ) define( 'COMPOSER_PATH', 'tag/latest' );
18
- if ( ! defined( 'SK_SL_PLUGIN_DIR' ) ) define( 'SK_SL_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
19
- if ( ! defined( 'SK_SL_PLUGIN_URL' ) ) define( 'SK_SL_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
20
- if ( ! defined( 'SK_SL_PLUGIN_FILE' ) ) define( 'SK_SL_PLUGIN_FILE', __FILE__ );
21
  if ( ! function_exists('mlog')) {
22
  function mlog(){}
23
  }
24
 
25
- class Sidekick{
26
 
27
- function __construct(){
28
- if (!defined('SK_TRACKING_API')) define('SK_TRACKING_API','//tracking.sidekick.pro/');
29
- if (!defined('SK_COMPOSER_API')) define('SK_COMPOSER_API','//apiv2.sidekick.pro');
30
- if (!defined('SK_API')) define('SK_API','//apiv2.sidekick.pro/');
31
- if (!defined('SK_LIBRARY')) define('SK_LIBRARY','//librarycache.sidekick.pro/');
32
- if (!defined('SK_ASSETS')) define('SK_ASSETS','//assets.sidekick.pro/');
33
- if (!defined('SK_AUDIO')) define('SK_AUDIO','//audio.sidekick.pro/');
34
- }
35
 
36
- function enqueue_required(){
37
- wp_enqueue_script('jquery' , null );
38
- wp_enqueue_script('underscore' , null, array('underscore'));
39
- wp_enqueue_script('backbone' , null, array('jquery','underscore'));
40
- wp_enqueue_script('jquery-ui-core' , null, array('jquery') );
41
- wp_enqueue_script('jquery-ui-position' , null, array('jquery-ui-core') );
42
- wp_enqueue_script('jquery-ui-draggable' , null, array('jquery-ui-core') );
43
- wp_enqueue_script('jquery-ui-droppable' , null, array('jquery-ui-core') );
44
- wp_enqueue_script('jquery-effects-scale' , null, array('jquery-ui-core') );
45
- wp_enqueue_script('jquery-effects-highlight' , null, array('jquery-ui-core') );
46
- wp_enqueue_script('sidekick-admin' ,plugins_url( '/js/sidekick_admin.js' , __FILE__ ),array( 'jquery' ));
47
- }
48
 
49
- function is_https() {
50
- if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443 || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) {
51
- return true;
52
- } else {
53
- return false;
 
 
 
 
 
 
54
  }
55
- }
56
 
57
- function enqueue(){
58
- wp_enqueue_script('sidekick' ,"//player.sidekick.pro/" . PLAYER_PATH . "/" . PLAYER_FILE, array('backbone','jquery','underscore','jquery-effects-highlight'),null);
59
- wp_enqueue_style('wp-pointer');
60
- wp_enqueue_script('wp-pointer');
61
- }
62
 
63
- function setup_menu(){
64
- add_submenu_page( 'options-general.php', 'Sidekick', 'Sidekick', 'activate_plugins','sidekick', array(&$this,'admin_page'));
65
- }
66
 
67
- function ajax_save(){
68
- if (isset($_POST['sk_composer_button']) && $_POST['sk_composer_button'] == "true") {
69
- update_option( 'sk_composer_button', true );
70
- } elseif (isset($_POST['sk_composer_button']) && $_POST['sk_composer_button'] == "false") {
71
- delete_option('sk_composer_button');
 
72
  }
73
- }
74
 
75
- function admin_page(){
76
- if ( empty( $_POST ) || check_admin_referer( 'update_sk_settings' ) ) {
77
 
78
- if (isset($_POST['option_page']) && $_POST['option_page'] == 'sk_license') {
79
 
80
- if (isset($_POST['activation_id']) && $_POST['activation_id'] && strpos($_POST['activation_id'], '-xxxx-xxxx') === false){
81
- $result = $this->activate(true);
82
- } else if (isset($_POST['activation_id']) && strpos($_POST['activation_id'], '-xxxx-xxxx') === false) {
83
- delete_option('sk_activation_id');
84
- }
85
 
86
- if (isset($_POST['sk_composer_button'])) {
87
- update_option( 'sk_composer_button', true );
88
- } else {
89
- delete_option('sk_composer_button');
90
- }
 
 
 
 
 
 
91
 
92
- if (isset($_POST['sk_track_data'])) {
93
- update_option( 'sk_track_data', true );
94
- } else {
95
- delete_option('sk_track_data');
 
 
 
 
96
  }
97
 
98
- update_option( 'sk_activated', true );
99
- die('<script>window.open("' . get_site_url() . '/wp-admin/options-general.php?page=sidekick","_self")</script>');
100
  }
101
 
102
- if (isset($_POST['sk_api'])) {
103
- update_option( 'sk_api', $_POST['sk_api'] );
104
- } else {
105
- delete_option('sk_api');
 
 
 
 
 
 
106
  }
107
- }
108
 
109
- $activation_id = (get_option( "sk_activation_id" ) ? get_option( "sk_activation_id" ) : '');
110
- $sk_track_data = get_option( 'sk_track_data' );
111
- $current_user = wp_get_current_user();
112
- $status = 'Free';
113
- $error = null;
114
 
115
- if (isset($SK_PAID_LIBRARY_FILE) && $activation_id) {
116
- $_POST['activation_id'] = $activation_id;
117
- $check_activation = $this->activate(true);
118
- $status = 'Checking...';
119
- }
120
 
121
- global $wp_version;
122
- if (version_compare($wp_version, '3.9', '<=')) {
123
- $error = "Sorry, Sidekick requires WordPress 3.9 or higher to function.";
124
- }
125
 
126
- if (!$activation_id) {
127
- $warn = "You're using the <b>free</b> version of Sidekick, to upgrade or get your license key, visit your <a target='_blank' href='http://www.sidekick.pro/plans/#/login?utm_source=plugin&utm_medium=settings&utm_campaign=upgrade_nag'>account page</a> or <a target='_blank' href='http://www.sidekick.pro/plans/?utm_source=plugin&utm_medium=settings&utm_campaign=upgrade_nag'>sign-up</a> for a paid plan.";
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }
129
 
130
- if(preg_match('/(?i)msie [6-8]/',$_SERVER['HTTP_USER_AGENT'])){
131
- $error = "Sorry, Sidekick requires Internet Explorer 9 or higher to function.";
 
 
 
 
 
 
 
 
 
 
132
  }
133
 
134
- ?>
135
-
136
- <?php if (get_option('sk_firstuse') == true): ?>
137
- <?php delete_option('sk_firstuse') ?>
138
- <script type="text/javascript">
139
- jQuery(document).ready(function($) {
140
- jQuery('#sidekick #logo').trigger('click');
141
- });
142
- </script>
143
- <?php endif ?>
144
-
145
- <div class="wrap">
146
- <?php include('libs/admin_page.php') ?>
147
- </div>
148
- <?php
149
- }
150
-
151
- function set_disabled_wts(){
152
- if (isset($_POST['disable_wts']) && $_POST['disable_wts']) {
153
- update_option('sk_disabled_wts',json_encode($_POST['disable_wts']));
154
- update_site_option('sk_disabled_wts',json_encode($_POST['disable_wts']));
155
- } else {
156
- delete_option('sk_disabled_wts');
157
- delete_site_option('sk_disabled_wts');
158
  }
159
- }
160
 
161
- function set_autostart_wt(){
162
- if (isset($_POST['sk_autostart_walkthrough_id']) && intval($_POST['sk_autostart_walkthrough_id']) > 0){
163
- update_option('sk_autostart_walkthrough_id',$_POST['sk_autostart_walkthrough_id']);
164
- update_site_option('sk_autostart_walkthrough_id',$_POST['sk_autostart_walkthrough_id']);
165
- } else {
166
- delete_option('sk_autostart_walkthrough_id');
167
- delete_site_option('sk_autostart_walkthrough_id');
168
  }
169
- }
170
 
171
- function footer(){
172
- global $current_user;
173
-
174
- require_once('libs/sk_config_data.php');
175
-
176
- $sk_config_data = new sk_config_data;
177
- $current_user = wp_get_current_user();
178
- $sk_just_activated = get_option( 'sk_just_activated' );
179
- $sk_track_data = get_option( 'sk_track_data' );
180
- $sk_composer_button = get_option( 'sk_composer_button' );
181
- $activation_id = (get_option( "sk_activation_id" ) ? get_option( "sk_activation_id" ) : '');
182
- $autostart_network_walkthrough_id = (get_site_option('sk_autostart_walkthrough_id') ? get_site_option('sk_autostart_walkthrough_id') : 'null' );
183
- $autostart_walkthrough_id = (get_option('sk_autostart_walkthrough_id') ? get_option('sk_autostart_walkthrough_id') : $autostart_network_walkthrough_id );
184
- $custom_class = (get_option( "sk_custom_class" ) ? get_option( "sk_custom_class" ) : '');
185
- $theme = wp_get_theme();
186
- $not_supported_ie = false;
187
- $user_email = '';
188
- if ($sk_track_data) {
189
- $user_email = $current_user->user_email;
190
- }
191
 
192
- $user_role = $sk_config_data->get_user_role();
193
- $site_url = $sk_config_data->get_domain();
194
- $plugin_data = $sk_config_data->get_plugins();
195
- $disabled_wts = $sk_config_data->get_disabled_wts();
196
- $disabled_network_wts = $sk_config_data->get_disabled_network_wts();
197
- $current_url = $sk_config_data->get_current_url();
198
- $post_types = $sk_config_data->get_post_types();
199
- $taxonomies = $sk_config_data->get_taxonomies();
200
- $user_data = $sk_config_data->get_user_data();
201
- $comments = $sk_config_data->get_comments();
202
- $post_statuses = $sk_config_data->get_post_statuses();
203
- $post_types_and_statuses = $sk_config_data->get_post_types_and_statuses();
204
- $number_of_themes = $sk_config_data->get_themes();
205
- $frameworks = $sk_config_data->get_framework();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
 
 
207
 
 
 
 
 
208
 
 
 
 
 
209
 
210
- $installed_plugins = $plugin_data['plugins'];
211
- $plugin_count = $plugin_data['count'];
 
212
 
213
- // $sk_composer_button = true; // BETA
 
 
 
 
 
 
214
 
215
- delete_option( 'sk_just_activated' );
216
- if(preg_match('/(?i)msie [6-8]/',$_SERVER['HTTP_USER_AGENT'])) $not_supported_ie = true;
 
 
 
 
 
 
 
 
 
 
217
 
218
- ?>
 
 
 
 
219
 
220
- <?php if (!$not_supported_ie): ?>
 
 
 
 
 
 
 
 
 
221
 
222
- <script type="text/javascript">
 
 
 
 
 
 
 
 
 
223
 
224
- var sk_config = {
225
- // Compatibility
226
-
227
- compatibilities: {
228
- <?php echo $post_types ?>
229
- <?php echo $taxonomies ?>
230
- <?php echo $user_data ?>
231
- <?php echo $comments ?>
232
- <?php echo $post_statuses ?>
233
- <?php echo $frameworks ?>
234
- <?php echo $post_types_and_statuses ?>
235
- installed_plugins: <?php echo $installed_plugins ?>,
236
- plugin_count: <?php echo $plugin_count ?>,
237
- is_multisite: <?php echo (is_multisite()) ? "true" : "false" ?>,
238
- number_of_themes: <?php echo $number_of_themes ?>,
239
- installed_theme: '<?php echo $theme->Name ?>',
240
- main_soft_version: '<?php echo get_bloginfo("version") ?>',
241
- theme_version: '<?php echo $theme->Version ?>',
242
- user_level: '<?php echo $user_role ?>',
243
- main_soft_name: 'WordPress',
244
- role: '<?php echo $user_role ?>'
245
- },
246
-
247
- disable_wts: <?php echo $disabled_wts ?>,
248
- disable_network_wts: <?php echo $disabled_network_wts ?>,
249
- main_soft_name: 'WordPress',
250
-
251
- // User Settings
252
- activation_id: '<?php echo $activation_id ?>',
253
- auto_open_root_bucket_id: 79,
254
- auto_open_product: 'default',
255
- disable_wts_in_root_bucket_ids: [5,87],
256
- autostart_walkthrough_id: <?php echo $autostart_walkthrough_id ?>,
257
- sk_composer_button: <?php echo ($sk_composer_button ? "true" : "false") ?>,
258
- track_data: '<?php echo $sk_track_data ?>',
259
- user_email: '<?php echo $user_email ?>',
260
- custom_class: '<?php echo $custom_class ?>',
261
-
262
- // Toggles
263
- path_not_found_continue: true,
264
- show_powered_by: true,
265
- show_powered_by_link: true,
266
- sk_autostart_only_once: true,
267
- use_native_controls: false,
268
- composer_upgrade_off: false,
269
- basics_upgrade: true,
270
-
271
- // Platform Info
272
- library_version: 2,
273
- platform_id: 1,
274
-
275
- // Generic Info
276
- just_activated: <?php echo ($sk_just_activated) ? "true" : "false" ?>,
277
- platform_version: null,
278
- plugin_version: '2.0.1',
279
- show_login: <?php echo ($sk_just_activated) ? "true" : "false" ?>,
280
-
281
- // SIDEKICK URLS
282
- assets: '<?php echo SK_ASSETS ?>',
283
- api: '<?php echo SK_API ?>',
284
- tracking_api: '<?php echo SK_TRACKING_API ?>',
285
- sk_path: '<?php echo PLAYER_PATH ?>',
286
- audio: '<?php echo SK_AUDIO ?>',
287
- library: '<?php echo SK_LIBRARY ?>',
288
-
289
- // URLS
290
- site_url: '<?php echo $site_url ?>',
291
- domain: '<?php echo str_replace("http://","",$_SERVER["SERVER_NAME"]) ?>',
292
- domain_used: '//player.sidekick.pro/',
293
- plugin_url: '<?php echo admin_url("admin.php?page=sidekick") ?>',
294
- base_url: '<?php echo site_url() ?>',
295
- current_url: '<?php echo $current_url ?>',
296
- // fallback_notfication_mp3: '//assets.sidekick.pro/fallback.mp3'
297
- }
298
 
299
- var skc_config = {
300
- js: '//composer.sidekick.pro/<?php echo COMPOSER_PATH ?>/sidekick-composer.js',
301
- css: '//composer.sidekick.pro/<?php echo COMPOSER_PATH ?>/sidekick-composer.css',
302
- apiUrl: '<?php echo SK_COMPOSER_API ?>',
303
- baseSiteUrl: sk_config.base_url,
304
- platformId: 1,
305
- compatibilities: sk_config.compatibilities,
306
- audioBaseUrl: '<?php echo SK_AUDIO ?>',
307
- audioPlaceholderUrl: '//assets.sidekick.pro/walkthrough-audio-placeholder.mp3',
308
- siteAjaxUrl: window.ajaxurl || '',
309
- trackingUrl: '//tracking.sidekick.pro/'
310
- }
311
 
312
- </script>
313
- <?php endif ?>
314
 
315
- <?php
316
- }
317
 
318
- function track($data){
319
- $response = wp_remote_post( SK_TRACKING_API . 'event', array(
320
- 'method' => 'POST',
321
- 'timeout' => 45,
322
- 'redirection' => 5,
323
- 'httpversion' => '1.0',
324
- 'blocking' => true,
325
- 'headers' => array(),
326
- 'body' => $data,
327
- 'cookies' => array()
328
- )
329
- );
330
- }
331
 
332
- function activate($return = false){
333
- if (isset($_POST['activation_id'])) {
334
- update_option('sk_activation_id',$_POST['activation_id']);
335
- }
336
- }
337
 
338
- function activate_plugin(){
339
- update_option( 'sk_firstuse', true );
340
- update_option( 'sk_do_activation_redirect', true );
341
- $data = array(
342
- 'source' => 'plugin',
343
- 'action' => 'track',
344
- 'type' => 'activate'
345
- );
346
- $this->track($data);
347
- }
348
 
349
- function curl_get_data($url){
350
- $ch = curl_init();
351
- $timeout = 5;
352
- curl_setopt($ch, CURLOPT_URL, $url);
353
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
354
- curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
355
- $data = curl_exec($ch);
356
- curl_close($ch);
357
- return $data;
358
- }
359
 
360
- function redirect(){
361
- if (get_option('sk_do_activation_redirect', false)) {
362
- delete_option('sk_do_activation_redirect');
363
- $siteurl = get_site_url();
364
- wp_redirect($siteurl . "/wp-admin/options-general.php?page=sidekick");
365
  die();
366
  }
367
- }
368
 
369
- function admin_notice() {
370
- global $current_user ;
371
 
372
- if ( ! get_user_meta($current_user->ID, 'sk_ignore_notice') ) {
373
- printf ('<div class="updated"><p>Need help with WordPress? Click HELP ME in the bottom left corner to get started! <a href="%1$s">Hide</a></p></div>','?sk_ignore_notice=1');
 
374
  }
375
- }
376
 
377
- function admin_notice_ignore() {
378
- global $current_user;
379
- if ( isset($_GET['sk_ignore_notice'])) {
380
- add_user_meta($current_user->ID, 'sk_ignore_notice', true);
 
381
  }
382
- }
383
 
384
- function deactivate_plugin(){
385
- $data = array(
386
- 'source' => 'plugin',
387
- 'action' => 'track',
388
- 'type' => 'deactivate',
389
- 'user' => get_option( "activation_id" )
390
- );
391
- $this->track($data);
392
- ?>
393
- <script type="text/javascript">
394
- window._gaq = window._gaq || [];
395
- window._gaq.push(['sk._setAccount', 'UA-39283622-1']);
396
-
397
- (function() {
398
- var ga_wpu = document.createElement('script'); ga_sk.type = 'text/javascript'; ga_sk.async = true;
399
- ga_sk.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
400
- var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga_wpu, s);
401
- })();
402
- window._gaq.push(['sk._trackEvent', 'Plugin - Deactivate', '', <?php echo plugin_version ?>, 0,true]);
403
- </script>
404
- <?php
405
- delete_option( 'sk_activated' );
 
406
  }
407
- }
 
 
408
 
409
- $sidekick = new Sidekick;
410
- register_activation_hook( __FILE__, array($sidekick,'activate_plugin') );
411
- register_deactivation_hook( __FILE__, array($sidekick,'deactivate_plugin') );
 
412
 
413
- add_action('admin_menu', array($sidekick,'setup_menu'));
414
- add_action('admin_init', array($sidekick,'redirect'));
415
- add_action('wp_ajax_sk_activate', array($sidekick,'activate'));
416
- add_action('wp_ajax_sk_save', array($sidekick,'ajax_save'));
417
- add_action('admin_notices', array($sidekick,'admin_notice'));
418
- add_action('admin_init', array($sidekick,'admin_notice_ignore'));
419
 
420
- if (isset($_POST['sk_setting_disabled'])) {
421
- $sidekick->set_disabled_wts();
422
- }
423
- if (isset($_POST['sk_setting_autostart'])) {
424
- $sidekick->set_autostart_wt();
425
- }
 
426
 
427
 
428
- if (!defined('SK_PLUGIN_DEGBUG'))
429
- require_once('sk_init.php');
430
 
431
- if (!(isset($_GET['tab']) && $_GET['tab'] == 'plugin-information') && !defined('IFRAME_REQUEST')) {
432
- add_action('admin_footer', array($sidekick,'footer'));
433
- add_action('customize_controls_print_footer_scripts', array($sidekick,'footer'));
 
434
  }
435
 
436
 
 
437
  // Multisite Licensing
438
 
439
  if (defined('MULTISITE')) {
4
  Plugin Name: Sidekick
5
  Plugin URL: http://wordpress.org/plugins/sidekick/
6
  Description: Adds a real-time WordPress training walkthroughs right in your Dashboard
7
+ Requires at least: 4.0
8
+ Tested up to: 4.1.1
9
+ Version: 2.2.0
10
  Author: Sidekick.pro
11
  Author URI: http://www.sidekick.pro
12
  */
13
 
14
 
15
+ if ( ! defined( 'PLAYER_DOMAIN' ) ) define( 'PLAYER_DOMAIN', 'player.sidekick.pro' );
16
+ if ( ! defined( 'PLAYER_PATH' ) ) define( 'PLAYER_PATH', 'tag/latest' );
17
+ if ( ! defined( 'PLAYER_FILE' ) ) define( 'PLAYER_FILE', 'sidekick.min.js' );
18
+ if ( ! defined( 'COMPOSER_DOMAIN' ) ) define( 'COMPOSER_DOMAIN', 'composer.sidekick.pro' );
19
+ if ( ! defined( 'COMPOSER_PATH' ) ) define( 'COMPOSER_PATH', 'tag/latest' );
 
20
  if ( ! function_exists('mlog')) {
21
  function mlog(){}
22
  }
23
 
24
+ if (!class_exists('Sidekick')){
25
 
26
+ class Sidekick{
 
 
 
 
 
 
 
27
 
28
+ function __construct(){
29
+ if (!defined('SK_TRACKING_API')) define('SK_TRACKING_API','//tracking.sidekick.pro/');
30
+ if (!defined('SK_COMPOSER_API')) define('SK_COMPOSER_API','//apiv2.sidekick.pro');
31
+ if (!defined('SK_API')) define('SK_API','//apiv2.sidekick.pro/');
32
+ if (!defined('SK_LIBRARY')) define('SK_LIBRARY','//librarycache.sidekick.pro/');
33
+ if (!defined('SK_ASSETS')) define('SK_ASSETS','//assets.sidekick.pro/');
34
+ if (!defined('SK_AUDIO')) define('SK_AUDIO','//audio.sidekick.pro/');
35
+ }
 
 
 
 
36
 
37
+ function enqueue_required(){
38
+ wp_enqueue_script('jquery' , null );
39
+ wp_enqueue_script('underscore' , null, array('underscore'));
40
+ wp_enqueue_script('backbone' , null, array('jquery','underscore'));
41
+ wp_enqueue_script('jquery-ui-core' , null, array('jquery') );
42
+ wp_enqueue_script('jquery-ui-position' , null, array('jquery-ui-core') );
43
+ wp_enqueue_script('jquery-ui-draggable' , null, array('jquery-ui-core') );
44
+ wp_enqueue_script('jquery-ui-droppable' , null, array('jquery-ui-core') );
45
+ wp_enqueue_script('jquery-effects-scale' , null, array('jquery-ui-core') );
46
+ wp_enqueue_script('jquery-effects-highlight' , null, array('jquery-ui-core') );
47
+ wp_enqueue_script('sidekick-admin' , '//assets.sidekick.pro/plugin/tag/latest/js/sidekick_admin.js',array( 'jquery' ));
48
  }
 
49
 
50
+ function enqueue(){
51
+ wp_enqueue_script('sidekick' ,"//" . PLAYER_DOMAIN ."/" . PLAYER_PATH . "/" . PLAYER_FILE, array('backbone','jquery','underscore','jquery-effects-highlight'),null);
52
+ wp_enqueue_style('wp-pointer');
53
+ wp_enqueue_script('wp-pointer');
54
+ }
55
 
56
+ function setup_menu(){
57
+ add_submenu_page( 'options-general.php', 'Sidekick', 'Sidekick', 'activate_plugins','sidekick', array(&$this,'admin_page'));
58
+ }
59
 
60
+ function ajax_save(){
61
+ if (isset($_POST['sk_composer_button']) && $_POST['sk_composer_button'] == "true") {
62
+ update_option( 'sk_composer_button', true );
63
+ } elseif (isset($_POST['sk_composer_button']) && $_POST['sk_composer_button'] == "false") {
64
+ delete_option('sk_composer_button');
65
+ }
66
  }
 
67
 
68
+ function admin_page(){
 
69
 
70
+ if ( empty( $_POST ) || check_admin_referer( 'update_sk_settings' ) ) {
71
 
72
+ if (isset($_POST['option_page']) && $_POST['option_page'] == 'sk_license') {
 
 
 
 
73
 
74
+ if (isset($_POST['activation_id']) && $_POST['activation_id'] && strpos($_POST['activation_id'], '-xxxx-xxxx') === false){
75
+ $result = $this->activate(true);
76
+ } else if (isset($_POST['activation_id']) && strpos($_POST['activation_id'], '-xxxx-xxxx') === false) {
77
+ delete_option('sk_activation_id');
78
+ }
79
+
80
+ if (isset($_POST['sk_composer_button'])) {
81
+ update_option( 'sk_composer_button', true );
82
+ } else {
83
+ delete_option('sk_composer_button');
84
+ }
85
 
86
+ if (isset($_POST['sk_track_data'])) {
87
+ update_option( 'sk_track_data', true );
88
+ } else {
89
+ delete_option('sk_track_data');
90
+ }
91
+
92
+ update_option( 'sk_activated', true );
93
+ die('<script>window.open("' . get_site_url() . '/wp-admin/options-general.php?page=sidekick","_self")</script>');
94
  }
95
 
 
 
96
  }
97
 
98
+ $activation_id = (get_option( "sk_activation_id" ) ? get_option( "sk_activation_id" ) : '');
99
+ $sk_track_data = get_option( 'sk_track_data' );
100
+ $current_user = wp_get_current_user();
101
+ $status = 'Free';
102
+ $error = null;
103
+
104
+ if (isset($SK_PAID_LIBRARY_FILE) && $activation_id) {
105
+ $_POST['activation_id'] = $activation_id;
106
+ $check_activation = $this->activate(true);
107
+ $status = 'Checking...';
108
  }
 
109
 
110
+ global $wp_version;
111
+ if (version_compare($wp_version, '3.9', '<=')) {
112
+ $error = "Sorry, Sidekick requires WordPress 3.9 or higher to function.";
113
+ }
 
114
 
115
+ if (!$activation_id) {
116
+ $warn = "You're using the <b>free</b> version of Sidekick, to upgrade or get your license key, visit your <a target='_blank' href='http://www.sidekick.pro/plans/#/login?utm_source=plugin&utm_medium=settings&utm_campaign=upgrade_nag'>account page</a> or <a target='_blank' href='http://www.sidekick.pro/plans/?utm_source=plugin&utm_medium=settings&utm_campaign=upgrade_nag'>sign-up</a> for a paid plan.";
117
+ }
 
 
118
 
119
+ if(preg_match('/(?i)msie [6-8]/',$_SERVER['HTTP_USER_AGENT'])){
120
+ $error = "Sorry, Sidekick requires Internet Explorer 9 or higher to function.";
121
+ }
 
122
 
123
+ ?>
124
+
125
+ <?php if (get_option('sk_firstuse') == true): ?>
126
+ <?php delete_option('sk_firstuse') ?>
127
+ <script type="text/javascript">
128
+ jQuery(document).ready(function($) {
129
+ jQuery('#sidekick #logo').trigger('click');
130
+ });
131
+ </script>
132
+ <?php endif ?>
133
+
134
+ <div class="wrap">
135
+ <?php include('libs/admin_page.php') ?>
136
+ </div>
137
+ <?php
138
  }
139
 
140
+ function set_disabled_wts(){
141
+ if (isset($_POST['disable_wts']) && $_POST['disable_wts']) {
142
+ update_option('sk_disabled_wts',json_encode($_POST['disable_wts']));
143
+ if (is_network_admin()) {
144
+ update_site_option('sk_disabled_wts',json_encode($_POST['disable_wts']));
145
+ }
146
+ } else {
147
+ delete_option('sk_disabled_wts');
148
+ if (is_network_admin()) {
149
+ delete_site_option('sk_disabled_wts');
150
+ }
151
+ }
152
  }
153
 
154
+ function set_autostart_wt(){
155
+ if (isset($_POST['sk_autostart_walkthrough_id']) && intval($_POST['sk_autostart_walkthrough_id']) > 0){
156
+ if (is_network_admin()) {
157
+ update_site_option('sk_autostart_walkthrough_id',$_POST['sk_autostart_walkthrough_id']);
158
+ }
159
+ update_option('sk_autostart_walkthrough_id',$_POST['sk_autostart_walkthrough_id']);
160
+ } else {
161
+ delete_option('sk_autostart_walkthrough_id');
162
+ if (is_network_admin()) {
163
+ delete_site_option('sk_autostart_walkthrough_id');
164
+ }
165
+ }
 
 
 
 
 
 
 
 
 
 
 
 
166
  }
 
167
 
168
+ function set_api(){
169
+ if (isset($_POST['sk_api'])){
170
+ update_option('sk_api',$_POST['sk_api']);
171
+ update_site_option('sk_api',$_POST['sk_api']);
172
+ }
 
 
173
  }
 
174
 
175
+ function footer(){
176
+ global $current_user;
177
+
178
+ require_once('libs/sk_config_data.php');
179
+
180
+ $sk_config_data = new sk_config_data;
181
+ $current_user = wp_get_current_user();
182
+ $sk_just_activated = get_option( 'sk_just_activated' );
183
+ $sk_track_data = get_option( 'sk_track_data' );
184
+ $sk_composer_button = get_option( 'sk_composer_button' );
185
+ $activation_id = (get_option( "sk_activation_id" ) ? get_option( "sk_activation_id" ) : '');
186
+ $autostart_network_walkthrough_id = (get_site_option('sk_autostart_walkthrough_id') ? get_site_option('sk_autostart_walkthrough_id') : 'null' );
187
+ $autostart_walkthrough_id = (get_option('sk_autostart_walkthrough_id') ? get_option('sk_autostart_walkthrough_id') : $autostart_network_walkthrough_id );
188
+ $custom_class = (get_option( "sk_custom_class" ) ? get_option( "sk_custom_class" ) : '');
189
+ $theme = wp_get_theme();
190
+ $not_supported_ie = false;
191
+ $user_email = '';
192
+ if ($sk_track_data) {
193
+ $user_email = $current_user->user_email;
194
+ }
195
 
196
+ $disabled_wts = (!is_network_admin()) ? $sk_config_data->get_disabled_wts() : '[]';
197
+ $user_role = $sk_config_data->get_user_role();
198
+ $site_url = $sk_config_data->get_domain();
199
+ $installed_plugins = $sk_config_data->get_plugins();
200
+ $plugin_count = (isset($plugins) && is_array($plugins)) ? count($plugins) : array();
201
+ $disabled_network_wts = $sk_config_data->get_disabled_network_wts();
202
+ $current_url = $sk_config_data->get_current_url();
203
+ $post_types = $sk_config_data->get_post_types();
204
+ $taxonomies = $sk_config_data->get_taxonomies();
205
+ $user_data = $sk_config_data->get_user_data();
206
+ $comments = $sk_config_data->get_comments();
207
+ $post_statuses = $sk_config_data->get_post_statuses();
208
+ $post_types_and_statuses = $sk_config_data->get_post_types_and_statuses();
209
+ $number_of_themes = $sk_config_data->get_themes();
210
+ $frameworks = $sk_config_data->get_framework();
211
+
212
+ delete_option( 'sk_just_activated' );
213
+ if(preg_match('/(?i)msie [6-8]/',$_SERVER['HTTP_USER_AGENT'])) $not_supported_ie = true;
214
+
215
+ ?>
216
+
217
+
218
+ <?php if (!$not_supported_ie): ?>
219
+
220
+ <script type="text/javascript">
221
+
222
+ <?php if (is_network_admin()): ?>var is_network_admin = true; <?php endif ?>
223
+
224
+ var sk_config = {
225
+ // Compatibility
226
+
227
+ compatibilities: {
228
+ <?php echo $post_types ?>
229
+ <?php echo $taxonomies ?>
230
+ <?php echo $user_data ?>
231
+ <?php echo $comments ?>
232
+ <?php echo $post_statuses ?>
233
+ <?php echo $frameworks ?>
234
+ <?php echo $post_types_and_statuses ?>
235
+ installed_plugins: <?php echo json_encode($installed_plugins) ?>,
236
+ plugin_count: <?php echo ($plugin_count) ? $plugin_count : 0 ?>,
237
+ is_multisite: <?php echo (is_multisite()) ? "true" : "false" ?>,
238
+ number_of_themes: <?php echo $number_of_themes ?>,
239
+ installed_theme: {'<?php echo sanitize_title($theme->Name) ?>' : '<?php echo $theme->Version ?>'},
240
+ theme_version: '<?php echo $theme->Version ?>',
241
+ main_soft_version: '<?php echo get_bloginfo("version") ?>',
242
+ user_level: '<?php echo $user_role ?>',
243
+ main_soft_name: 'WordPress',
244
+ role: '<?php echo $user_role ?>'
245
+ },
246
+
247
+ disable_wts: <?php echo $disabled_wts ?>,
248
+ disable_network_wts: <?php echo $disabled_network_wts ?>,
249
+ main_soft_name: 'WordPress',
250
+ embeded: false,
251
+
252
+ // User Settings
253
+ activation_id: '<?php echo $activation_id ?>',
254
+ auto_open_root_bucket_id: 79,
255
+ auto_open_product: 'default',
256
+ disable_wts_in_root_bucket_ids: [5,87],
257
+ autostart_walkthrough_id: <?php echo $autostart_walkthrough_id ?>,
258
+ sk_composer_button: <?php echo ($sk_composer_button ? "true" : "false") ?>,
259
+ track_data: '<?php echo $sk_track_data ?>',
260
+ user_email: '<?php echo $user_email ?>',
261
+ custom_class: '<?php echo $custom_class ?>',
262
+
263
+ // Toggles
264
+ path_not_found_continue: true,
265
+ show_powered_by: true,
266
+ show_powered_by_link: true,
267
+ sk_autostart_only_once: true,
268
+ use_native_controls: false,
269
+ composer_upgrade_off: false,
270
+ basics_upgrade: true,
271
+
272
+ // Platform Info
273
+ library_version: 2,
274
+ platform_id: 1,
275
+
276
+ // Generic Info
277
+ just_activated: <?php echo ($sk_just_activated) ? "true" : "false" ?>,
278
+ platform_version: null,
279
+ plugin_version: '2.2.0',
280
+ show_login: <?php echo ($sk_just_activated) ? "true" : "false" ?>,
281
+
282
+ // SIDEKICK URLS
283
+ assets: '<?php echo SK_ASSETS ?>',
284
+ api: '<?php echo SK_API ?>',
285
+ tracking_api: '<?php echo SK_TRACKING_API ?>',
286
+ sk_path: '<?php echo PLAYER_PATH ?>',
287
+ audio: '<?php echo SK_AUDIO ?>',
288
+ library: '<?php echo SK_LIBRARY ?>',
289
+
290
+ // URLS
291
+ site_url: '<?php echo $site_url ?>',
292
+ domain: '<?php echo str_replace("http://","",$_SERVER["SERVER_NAME"]) ?>',
293
+ domain_used: '//<?php echo PLAYER_DOMAIN ?>/',
294
+ plugin_url: '<?php echo admin_url("admin.php?page=sidekick") ?>',
295
+ base_url: '<?php echo site_url() ?>',
296
+ current_url: '<?php echo $current_url ?>'
297
+ // fallback_notfication_mp3: '//assets.sidekick.pro/fallback.mp3'
298
+ }
299
+
300
+ var skc_config = {
301
+ audioPlaceholderUrl: '<?php echo SK_ASSETS ?>walkthrough-audio-placeholder.mp3',
302
+ audioBaseUrl: '<?php echo SK_AUDIO ?>',
303
+ apiUrl: '<?php echo SK_COMPOSER_API ?>',
304
+ trackingUrl: '<?php echo SK_TRACKING_API ?>',
305
+ js: '//<?php echo COMPOSER_DOMAIN ?>/<?php echo COMPOSER_PATH ?>/sidekick-composer.js',
306
+ css: '//<?php echo COMPOSER_DOMAIN ?>/<?php echo COMPOSER_PATH ?>/sidekick-composer.css',
307
+ baseSiteUrl: sk_config.base_url,
308
+ platformId: 1,
309
+ compatibilities: sk_config.compatibilities,
310
+ siteAjaxUrl: window.ajaxurl || ''
311
+ }
312
+
313
+ </script>
314
+ <?php endif ?>
315
+
316
+ <?php
317
+ }
318
 
319
+ function track($data){
320
+ mlog('track');
321
 
322
+ if (file_exists(realpath(dirname(__FILE__)) . '/libs/mixpanel/Mixpanel.php')) {
323
+ require_once(realpath(dirname(__FILE__)) . '/libs/mixpanel/Mixpanel.php');
324
+ $mp = Mixpanel::getInstance("965556434c5ae652a44f24b85b442263");
325
+ $domain = str_replace("http://","",$_SERVER["SERVER_NAME"]);
326
 
327
+ switch ($data['type']) {
328
+ case 'activate':
329
+ $mp->track("Activate - Plugin", array("domain" => $domain));
330
+ break;
331
 
332
+ case 'deactivate':
333
+ $mp->track("Deactivate - Plugin", array("domain" => $domain));
334
+ break;
335
 
336
+ default:
337
+ if (isset($data['event'])) {
338
+ $mp->track($data['event'], array("domain" => $domain));
339
+ }
340
+ break;
341
+ }
342
+ }
343
 
344
+ $response = wp_remote_post( SK_TRACKING_API . 'event', array(
345
+ 'method' => 'POST',
346
+ 'timeout' => 45,
347
+ 'redirection' => 5,
348
+ 'httpversion' => '1.0',
349
+ 'blocking' => true,
350
+ 'headers' => array(),
351
+ 'body' => $data,
352
+ 'cookies' => array()
353
+ )
354
+ );
355
+ }
356
 
357
+ function activate($return = false){
358
+ if (isset($_POST['activation_id'])) {
359
+ update_option('sk_activation_id',$_POST['activation_id']);
360
+ }
361
+ }
362
 
363
+ function activate_plugin(){
364
+ update_option( 'sk_firstuse', true );
365
+ update_option( 'sk_do_activation_redirect', true );
366
+ $data = array(
367
+ 'source' => 'plugin',
368
+ 'action' => 'track',
369
+ 'type' => 'activate'
370
+ );
371
+ $this->track($data);
372
+ }
373
 
374
+ function curl_get_data($url){
375
+ $ch = curl_init();
376
+ $timeout = 5;
377
+ curl_setopt($ch, CURLOPT_URL, $url);
378
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
379
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
380
+ $data = curl_exec($ch);
381
+ curl_close($ch);
382
+ return $data;
383
+ }
384
 
385
+ function redirect(){
386
+ if (get_option('sk_do_activation_redirect', false)) {
387
+ delete_option('sk_do_activation_redirect');
388
+ $siteurl = get_site_url();
389
+ wp_redirect($siteurl . "/wp-admin/options-general.php?page=sidekick");
390
+ die();
391
+ }
392
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
 
394
+ function check_ver(){
 
 
 
 
 
 
 
 
 
 
 
395
 
396
+ $data = json_encode('2.2.0');
 
397
 
398
+ if(array_key_exists('callback', $_GET)){
 
399
 
400
+ header('Content-Type: text/javascript; charset=utf8');
401
+ header('Access-Control-Allow-Origin: http://www.example.com/');
402
+ header('Access-Control-Max-Age: 3628800');
403
+ header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
 
 
 
 
 
 
 
 
 
404
 
405
+ $callback = $_GET['callback'];
406
+ echo $callback.'('.$data.');';
 
 
 
407
 
408
+ }else{
409
+ header('Content-Type: application/json; charset=utf8');
 
 
 
 
 
 
 
 
410
 
411
+ echo $data;
412
+ }
 
 
 
 
 
 
 
 
413
 
 
 
 
 
 
414
  die();
415
  }
 
416
 
417
+ function admin_notice() {
418
+ global $current_user ;
419
 
420
+ if ( ! get_user_meta($current_user->ID, 'sk_ignore_notice') ) {
421
+ printf ('<div class="updated"><p>Need help with WordPress? Click HELP ME in the bottom left corner to get started! <a href="%1$s">Hide</a></p></div>','?sk_ignore_notice=1');
422
+ }
423
  }
 
424
 
425
+ function admin_notice_ignore() {
426
+ global $current_user;
427
+ if ( isset($_GET['sk_ignore_notice'])) {
428
+ add_user_meta($current_user->ID, 'sk_ignore_notice', true);
429
+ }
430
  }
 
431
 
432
+ function deactivate_plugin(){
433
+ $data = array(
434
+ 'source' => 'plugin',
435
+ 'action' => 'track',
436
+ 'type' => 'deactivate',
437
+ 'user' => get_option( "activation_id" )
438
+ );
439
+ $this->track($data);
440
+ ?>
441
+ <script type="text/javascript">
442
+ window._gaq = window._gaq || [];
443
+ window._gaq.push(['sk._setAccount', 'UA-39283622-1']);
444
+
445
+ (function() {
446
+ var ga_wpu = document.createElement('script'); ga_sk.type = 'text/javascript'; ga_sk.async = true;
447
+ ga_sk.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
448
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga_wpu, s);
449
+ })();
450
+ window._gaq.push(['sk._trackEvent', 'Plugin - Deactivate', '', null, 0,true]);
451
+ </script>
452
+ <?php
453
+ delete_option( 'sk_activated' );
454
+ }
455
  }
456
+ $sidekick = new Sidekick;
457
+ register_activation_hook( __FILE__, array($sidekick,'activate_plugin') );
458
+ register_deactivation_hook( __FILE__, array($sidekick,'deactivate_plugin') );
459
 
460
+ if (isset($_POST['sk_setting_disabled'])) $sidekick->set_disabled_wts();
461
+ if (isset($_POST['sk_setting_autostart'])) $sidekick->set_autostart_wt();
462
+ if (isset($_POST['sk_api'])) $sidekick->set_api();
463
+ if (isset($_GET['sk_ver_check'])) $sidekick->check_ver();
464
 
 
 
 
 
 
 
465
 
466
+ add_action('admin_menu', array($sidekick,'setup_menu'));
467
+ add_action('admin_init', array($sidekick,'redirect'));
468
+ add_action('wp_ajax_sk_activate', array($sidekick,'activate'));
469
+ add_action('wp_ajax_sk_save', array($sidekick,'ajax_save'));
470
+ add_action('admin_notices', array($sidekick,'admin_notice'));
471
+ add_action('admin_init', array($sidekick,'admin_notice_ignore'));
472
+
473
 
474
 
475
+ if (!defined('SK_PLUGIN_DEGBUG'))
476
+ require_once('sk_init.php');
477
 
478
+ if (!(isset($_GET['tab']) && $_GET['tab'] == 'plugin-information') && !defined('IFRAME_REQUEST')) {
479
+ add_action('admin_footer', array($sidekick,'footer'));
480
+ add_action('customize_controls_print_footer_scripts', array($sidekick,'footer'));
481
+ }
482
  }
483
 
484
 
485
+
486
  // Multisite Licensing
487
 
488
  if (defined('MULTISITE')) {
sidekick_embed.php ADDED
@@ -0,0 +1,495 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Plugin Name: Sidekick
5
+ Plugin URL: http://wordpress.org/plugins/sidekick/
6
+ Description: Adds a real-time WordPress training walkthroughs right in your Dashboard
7
+ Requires at least: 4.0
8
+ Tested up to: 4.1.1
9
+ Version: %%version%%
10
+ Author: Sidekick.pro
11
+ Author URI: http://www.sidekick.pro
12
+ */
13
+
14
+
15
+ if ( ! defined( 'PLAYER_DOMAIN' ) ) define( 'PLAYER_DOMAIN', 'player.sidekick.pro' );
16
+ if ( ! defined( 'PLAYER_PATH' ) ) define( 'PLAYER_PATH', 'tag/latest' );
17
+ if ( ! defined( 'PLAYER_FILE' ) ) define( 'PLAYER_FILE', 'sidekick.min.js' );
18
+ if ( ! defined( 'COMPOSER_DOMAIN' ) ) define( 'COMPOSER_DOMAIN', 'composer.sidekick.pro' );
19
+ if ( ! defined( 'COMPOSER_PATH' ) ) define( 'COMPOSER_PATH', 'tag/latest' );
20
+ if ( ! function_exists('mlog')) {
21
+ function mlog(){}
22
+ }
23
+
24
+ if (!class_exists('Sidekick')){
25
+
26
+ class Sidekick{
27
+
28
+ function __construct(){
29
+ if (!defined('SK_TRACKING_API')) define('SK_TRACKING_API','//tracking.sidekick.pro/');
30
+ if (!defined('SK_COMPOSER_API')) define('SK_COMPOSER_API','//apiv2.sidekick.pro');
31
+ if (!defined('SK_API')) define('SK_API','//apiv2.sidekick.pro/');
32
+ if (!defined('SK_LIBRARY')) define('SK_LIBRARY','//librarycache.sidekick.pro/');
33
+ if (!defined('SK_ASSETS')) define('SK_ASSETS','//assets.sidekick.pro/');
34
+ if (!defined('SK_AUDIO')) define('SK_AUDIO','//audio.sidekick.pro/');
35
+ }
36
+
37
+ function enqueue_required(){
38
+ wp_enqueue_script('jquery' , null );
39
+ wp_enqueue_script('underscore' , null, array('underscore'));
40
+ wp_enqueue_script('backbone' , null, array('jquery','underscore'));
41
+ wp_enqueue_script('jquery-ui-core' , null, array('jquery') );
42
+ wp_enqueue_script('jquery-ui-position' , null, array('jquery-ui-core') );
43
+ wp_enqueue_script('jquery-ui-draggable' , null, array('jquery-ui-core') );
44
+ wp_enqueue_script('jquery-ui-droppable' , null, array('jquery-ui-core') );
45
+ wp_enqueue_script('jquery-effects-scale' , null, array('jquery-ui-core') );
46
+ wp_enqueue_script('jquery-effects-highlight' , null, array('jquery-ui-core') );
47
+ wp_enqueue_script('sidekick-admin' , '//assets.sidekick.pro/plugin/tag/latest/js/sidekick_admin.js',array( 'jquery' ));
48
+ }
49
+
50
+ function enqueue(){
51
+ wp_enqueue_script('sidekick' ,"//" . PLAYER_DOMAIN ."/" . PLAYER_PATH . "/" . PLAYER_FILE, array('backbone','jquery','underscore','jquery-effects-highlight'),null);
52
+ wp_enqueue_style('wp-pointer');
53
+ wp_enqueue_script('wp-pointer');
54
+ }
55
+
56
+ function setup_menu(){
57
+ add_submenu_page( 'options-general.php', 'Sidekick', 'Sidekick', 'activate_plugins','sidekick', array(&$this,'admin_page'));
58
+ }
59
+
60
+ function ajax_save(){
61
+ if (isset($_POST['sk_composer_button']) && $_POST['sk_composer_button'] == "true") {
62
+ update_option( 'sk_composer_button', true );
63
+ } elseif (isset($_POST['sk_composer_button']) && $_POST['sk_composer_button'] == "false") {
64
+ delete_option('sk_composer_button');
65
+ }
66
+ }
67
+
68
+ function admin_page(){
69
+
70
+ if ( empty( $_POST ) || check_admin_referer( 'update_sk_settings' ) ) {
71
+
72
+ if (isset($_POST['option_page']) && $_POST['option_page'] == 'sk_license') {
73
+
74
+ if (isset($_POST['activation_id']) && $_POST['activation_id'] && strpos($_POST['activation_id'], '-xxxx-xxxx') === false){
75
+ $result = $this->activate(true);
76
+ } else if (isset($_POST['activation_id']) && strpos($_POST['activation_id'], '-xxxx-xxxx') === false) {
77
+ delete_option('sk_activation_id');
78
+ }
79
+
80
+ if (isset($_POST['sk_composer_button'])) {
81
+ update_option( 'sk_composer_button', true );
82
+ } else {
83
+ delete_option('sk_composer_button');
84
+ }
85
+
86
+ if (isset($_POST['sk_track_data'])) {
87
+ update_option( 'sk_track_data', true );
88
+ } else {
89
+ delete_option('sk_track_data');
90
+ }
91
+
92
+ update_option( 'sk_activated', true );
93
+ die('<script>window.open("' . get_site_url() . '/wp-admin/options-general.php?page=sidekick","_self")</script>');
94
+ }
95
+
96
+ }
97
+
98
+ $activation_id = (get_option( "sk_activation_id" ) ? get_option( "sk_activation_id" ) : '');
99
+ $sk_track_data = get_option( 'sk_track_data' );
100
+ $current_user = wp_get_current_user();
101
+ $status = 'Free';
102
+ $error = null;
103
+
104
+ if (isset($SK_PAID_LIBRARY_FILE) && $activation_id) {
105
+ $_POST['activation_id'] = $activation_id;
106
+ $check_activation = $this->activate(true);
107
+ $status = 'Checking...';
108
+ }
109
+
110
+ global $wp_version;
111
+ if (version_compare($wp_version, '3.9', '<=')) {
112
+ $error = "Sorry, Sidekick requires WordPress 3.9 or higher to function.";
113
+ }
114
+
115
+ if (!$activation_id) {
116
+ $warn = "You're using the <b>free</b> version of Sidekick, to upgrade or get your license key, visit your <a target='_blank' href='http://www.sidekick.pro/plans/#/login?utm_source=plugin&utm_medium=settings&utm_campaign=upgrade_nag'>account page</a> or <a target='_blank' href='http://www.sidekick.pro/plans/?utm_source=plugin&utm_medium=settings&utm_campaign=upgrade_nag'>sign-up</a> for a paid plan.";
117
+ }
118
+
119
+ if(preg_match('/(?i)msie [6-8]/',$_SERVER['HTTP_USER_AGENT'])){
120
+ $error = "Sorry, Sidekick requires Internet Explorer 9 or higher to function.";
121
+ }
122
+
123
+ ?>
124
+
125
+ <?php if (get_option('sk_firstuse') == true): ?>
126
+ <?php delete_option('sk_firstuse') ?>
127
+ <script type="text/javascript">
128
+ jQuery(document).ready(function($) {
129
+ jQuery('#sidekick #logo').trigger('click');
130
+ });
131
+ </script>
132
+ <?php endif ?>
133
+
134
+ <div class="wrap">
135
+ <?php include('libs/admin_page.php') ?>
136
+ </div>
137
+ <?php
138
+ }
139
+
140
+ function set_disabled_wts(){
141
+ if (isset($_POST['disable_wts']) && $_POST['disable_wts']) {
142
+ update_option('sk_disabled_wts',json_encode($_POST['disable_wts']));
143
+ if (is_network_admin()) {
144
+ update_site_option('sk_disabled_wts',json_encode($_POST['disable_wts']));
145
+ }
146
+ } else {
147
+ delete_option('sk_disabled_wts');
148
+ if (is_network_admin()) {
149
+ delete_site_option('sk_disabled_wts');
150
+ }
151
+ }
152
+ }
153
+
154
+ function set_autostart_wt(){
155
+ if (isset($_POST['sk_autostart_walkthrough_id']) && intval($_POST['sk_autostart_walkthrough_id']) > 0){
156
+ if (is_network_admin()) {
157
+ update_site_option('sk_autostart_walkthrough_id',$_POST['sk_autostart_walkthrough_id']);
158
+ }
159
+ update_option('sk_autostart_walkthrough_id',$_POST['sk_autostart_walkthrough_id']);
160
+ } else {
161
+ delete_option('sk_autostart_walkthrough_id');
162
+ if (is_network_admin()) {
163
+ delete_site_option('sk_autostart_walkthrough_id');
164
+ }
165
+ }
166
+ }
167
+
168
+ function set_api(){
169
+ if (isset($_POST['sk_api'])){
170
+ update_option('sk_api',$_POST['sk_api']);
171
+ update_site_option('sk_api',$_POST['sk_api']);
172
+ }
173
+ }
174
+
175
+ function footer(){
176
+ global $current_user;
177
+
178
+ require_once('libs/sk_config_data.php');
179
+
180
+ $sk_config_data = new sk_config_data;
181
+ $current_user = wp_get_current_user();
182
+ $sk_just_activated = get_option( 'sk_just_activated' );
183
+ $sk_track_data = get_option( 'sk_track_data' );
184
+ $sk_composer_button = get_option( 'sk_composer_button' );
185
+ $activation_id = (get_option( "sk_activation_id" ) ? get_option( "sk_activation_id" ) : '');
186
+ $autostart_network_walkthrough_id = (get_site_option('sk_autostart_walkthrough_id') ? get_site_option('sk_autostart_walkthrough_id') : 'null' );
187
+ $autostart_walkthrough_id = (get_option('sk_autostart_walkthrough_id') ? get_option('sk_autostart_walkthrough_id') : $autostart_network_walkthrough_id );
188
+ $custom_class = (get_option( "sk_custom_class" ) ? get_option( "sk_custom_class" ) : '');
189
+ $theme = wp_get_theme();
190
+ $not_supported_ie = false;
191
+ $user_email = '';
192
+ if ($sk_track_data) {
193
+ $user_email = $current_user->user_email;
194
+ }
195
+
196
+ $disabled_wts = (!is_network_admin()) ? $sk_config_data->get_disabled_wts() : '[]';
197
+ $user_role = $sk_config_data->get_user_role();
198
+ $site_url = $sk_config_data->get_domain();
199
+ $installed_plugins = $sk_config_data->get_plugins();
200
+ $plugin_count = (isset($plugins) && is_array($plugins)) ? count($plugins) : array();
201
+ $disabled_network_wts = $sk_config_data->get_disabled_network_wts();
202
+ $current_url = $sk_config_data->get_current_url();
203
+ $post_types = $sk_config_data->get_post_types();
204
+ $taxonomies = $sk_config_data->get_taxonomies();
205
+ $user_data = $sk_config_data->get_user_data();
206
+ $comments = $sk_config_data->get_comments();
207
+ $post_statuses = $sk_config_data->get_post_statuses();
208
+ $post_types_and_statuses = $sk_config_data->get_post_types_and_statuses();
209
+ $number_of_themes = $sk_config_data->get_themes();
210
+ $frameworks = $sk_config_data->get_framework();
211
+
212
+ delete_option( 'sk_just_activated' );
213
+ if(preg_match('/(?i)msie [6-8]/',$_SERVER['HTTP_USER_AGENT'])) $not_supported_ie = true;
214
+
215
+ ?>
216
+
217
+
218
+ <?php if (!$not_supported_ie): ?>
219
+
220
+ <script type="text/javascript">
221
+
222
+ <?php if (is_network_admin()): ?>var is_network_admin = true; <?php endif ?>
223
+
224
+ var sk_config = {
225
+ // Compatibility
226
+
227
+ compatibilities: {
228
+ <?php echo $post_types ?>
229
+ <?php echo $taxonomies ?>
230
+ <?php echo $user_data ?>
231
+ <?php echo $comments ?>
232
+ <?php echo $post_statuses ?>
233
+ <?php echo $frameworks ?>
234
+ <?php echo $post_types_and_statuses ?>
235
+ installed_plugins: <?php echo json_encode($installed_plugins) ?>,
236
+ plugin_count: <?php echo ($plugin_count) ? $plugin_count : 0 ?>,
237
+ is_multisite: <?php echo (is_multisite()) ? "true" : "false" ?>,
238
+ number_of_themes: <?php echo $number_of_themes ?>,
239
+ installed_theme: {'<?php echo sanitize_title($theme->Name) ?>' : '<?php echo $theme->Version ?>'},
240
+ theme_version: '<?php echo $theme->Version ?>',
241
+ main_soft_version: '<?php echo get_bloginfo("version") ?>',
242
+ user_level: '<?php echo $user_role ?>',
243
+ main_soft_name: 'WordPress',
244
+ role: '<?php echo $user_role ?>'
245
+ },
246
+
247
+ disable_wts: <?php echo $disabled_wts ?>,
248
+ disable_network_wts: <?php echo $disabled_network_wts ?>,
249
+ main_soft_name: 'WordPress',
250
+ embeded: false,
251
+
252
+ // User Settings
253
+ activation_id: '<?php echo $activation_id ?>',
254
+ auto_open_root_bucket_id: 79,
255
+ auto_open_product: 'default',
256
+ disable_wts_in_root_bucket_ids: [5,87],
257
+ autostart_walkthrough_id: <?php echo $autostart_walkthrough_id ?>,
258
+ sk_composer_button: <?php echo ($sk_composer_button ? "true" : "false") ?>,
259
+ track_data: '<?php echo $sk_track_data ?>',
260
+ user_email: '<?php echo $user_email ?>',
261
+ custom_class: '<?php echo $custom_class ?>',
262
+
263
+ // Toggles
264
+ path_not_found_continue: true,
265
+ show_powered_by: true,
266
+ show_powered_by_link: true,
267
+ sk_autostart_only_once: true,
268
+ use_native_controls: false,
269
+ composer_upgrade_off: false,
270
+ basics_upgrade: true,
271
+
272
+ // Platform Info
273
+ library_version: 2,
274
+ platform_id: 1,
275
+
276
+ // Generic Info
277
+ just_activated: <?php echo ($sk_just_activated) ? "true" : "false" ?>,
278
+ platform_version: null,
279
+ plugin_version: '%%version%%',
280
+ show_login: <?php echo ($sk_just_activated) ? "true" : "false" ?>,
281
+
282
+ // SIDEKICK URLS
283
+ assets: '<?php echo SK_ASSETS ?>',
284
+ api: '<?php echo SK_API ?>',
285
+ tracking_api: '<?php echo SK_TRACKING_API ?>',
286
+ sk_path: '<?php echo PLAYER_PATH ?>',
287
+ audio: '<?php echo SK_AUDIO ?>',
288
+ library: '<?php echo SK_LIBRARY ?>',
289
+
290
+ // URLS
291
+ site_url: '<?php echo $site_url ?>',
292
+ domain: '<?php echo str_replace("http://","",$_SERVER["SERVER_NAME"]) ?>',
293
+ domain_used: '//<?php echo PLAYER_DOMAIN ?>/',
294
+ plugin_url: '<?php echo admin_url("admin.php?page=sidekick") ?>',
295
+ base_url: '<?php echo site_url() ?>',
296
+ current_url: '<?php echo $current_url ?>'
297
+ // fallback_notfication_mp3: '//assets.sidekick.pro/fallback.mp3'
298
+ }
299
+
300
+ var skc_config = {
301
+ audioPlaceholderUrl: '<?php echo SK_ASSETS ?>walkthrough-audio-placeholder.mp3',
302
+ audioBaseUrl: '<?php echo SK_AUDIO ?>',
303
+ apiUrl: '<?php echo SK_COMPOSER_API ?>',
304
+ trackingUrl: '<?php echo SK_TRACKING_API ?>',
305
+ js: '//<?php echo COMPOSER_DOMAIN ?>/<?php echo COMPOSER_PATH ?>/sidekick-composer.js',
306
+ css: '//<?php echo COMPOSER_DOMAIN ?>/<?php echo COMPOSER_PATH ?>/sidekick-composer.css',
307
+ baseSiteUrl: sk_config.base_url,
308
+ platformId: 1,
309
+ compatibilities: sk_config.compatibilities,
310
+ siteAjaxUrl: window.ajaxurl || ''
311
+ }
312
+
313
+ </script>
314
+ <?php endif ?>
315
+
316
+ <?php
317
+ }
318
+
319
+ function track($data){
320
+ mlog('track');
321
+
322
+ if (file_exists(realpath(dirname(__FILE__)) . '/libs/mixpanel/Mixpanel.php')) {
323
+ require_once(realpath(dirname(__FILE__)) . '/libs/mixpanel/Mixpanel.php');
324
+ $mp = Mixpanel::getInstance("965556434c5ae652a44f24b85b442263");
325
+ $domain = str_replace("http://","",$_SERVER["SERVER_NAME"]);
326
+
327
+ switch ($data['type']) {
328
+ case 'activate':
329
+ $mp->track("Activate - Plugin", array("domain" => $domain));
330
+ break;
331
+
332
+ case 'deactivate':
333
+ $mp->track("Deactivate - Plugin", array("domain" => $domain));
334
+ break;
335
+
336
+ default:
337
+ if (isset($data['event'])) {
338
+ $mp->track($data['event'], array("domain" => $domain));
339
+ }
340
+ break;
341
+ }
342
+ }
343
+
344
+ $response = wp_remote_post( SK_TRACKING_API . 'event', array(
345
+ 'method' => 'POST',
346
+ 'timeout' => 45,
347
+ 'redirection' => 5,
348
+ 'httpversion' => '1.0',
349
+ 'blocking' => true,
350
+ 'headers' => array(),
351
+ 'body' => $data,
352
+ 'cookies' => array()
353
+ )
354
+ );
355
+ }
356
+
357
+ function activate($return = false){
358
+ if (isset($_POST['activation_id'])) {
359
+ update_option('sk_activation_id',$_POST['activation_id']);
360
+ }
361
+ }
362
+
363
+ function activate_plugin(){
364
+ update_option( 'sk_firstuse', true );
365
+ update_option( 'sk_do_activation_redirect', true );
366
+ $data = array(
367
+ 'source' => 'plugin',
368
+ 'action' => 'track',
369
+ 'type' => 'activate'
370
+ );
371
+ $this->track($data);
372
+ }
373
+
374
+ function curl_get_data($url){
375
+ $ch = curl_init();
376
+ $timeout = 5;
377
+ curl_setopt($ch, CURLOPT_URL, $url);
378
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
379
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
380
+ $data = curl_exec($ch);
381
+ curl_close($ch);
382
+ return $data;
383
+ }
384
+
385
+ function redirect(){
386
+ if (get_option('sk_do_activation_redirect', false)) {
387
+ delete_option('sk_do_activation_redirect');
388
+ $siteurl = get_site_url();
389
+ wp_redirect($siteurl . "/wp-admin/options-general.php?page=sidekick");
390
+ die();
391
+ }
392
+ }
393
+
394
+ function check_ver(){
395
+
396
+ $data = json_encode('%%version%%');
397
+
398
+ if(array_key_exists('callback', $_GET)){
399
+
400
+ header('Content-Type: text/javascript; charset=utf8');
401
+ header('Access-Control-Allow-Origin: http://www.example.com/');
402
+ header('Access-Control-Max-Age: 3628800');
403
+ header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
404
+
405
+ $callback = $_GET['callback'];
406
+ echo $callback.'('.$data.');';
407
+
408
+ }else{
409
+ header('Content-Type: application/json; charset=utf8');
410
+
411
+ echo $data;
412
+ }
413
+
414
+ die();
415
+ }
416
+
417
+ function admin_notice() {
418
+ global $current_user ;
419
+
420
+ if ( ! get_user_meta($current_user->ID, 'sk_ignore_notice') ) {
421
+ printf ('<div class="updated"><p>Need help with WordPress? Click HELP ME in the bottom left corner to get started! <a href="%1$s">Hide</a></p></div>','?sk_ignore_notice=1');
422
+ }
423
+ }
424
+
425
+ function admin_notice_ignore() {
426
+ global $current_user;
427
+ if ( isset($_GET['sk_ignore_notice'])) {
428
+ add_user_meta($current_user->ID, 'sk_ignore_notice', true);
429
+ }
430
+ }
431
+
432
+ function deactivate_plugin(){
433
+ $data = array(
434
+ 'source' => 'plugin',
435
+ 'action' => 'track',
436
+ 'type' => 'deactivate',
437
+ 'user' => get_option( "activation_id" )
438
+ );
439
+ $this->track($data);
440
+ ?>
441
+ <script type="text/javascript">
442
+ window._gaq = window._gaq || [];
443
+ window._gaq.push(['sk._setAccount', 'UA-39283622-1']);
444
+
445
+ (function() {
446
+ var ga_wpu = document.createElement('script'); ga_sk.type = 'text/javascript'; ga_sk.async = true;
447
+ ga_sk.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
448
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga_wpu, s);
449
+ })();
450
+ window._gaq.push(['sk._trackEvent', 'Plugin - Deactivate', '', null, 0,true]);
451
+ </script>
452
+ <?php
453
+ delete_option( 'sk_activated' );
454
+ }
455
+ }
456
+ $sidekick = new Sidekick;
457
+ register_activation_hook( __FILE__, array($sidekick,'activate_plugin') );
458
+ register_deactivation_hook( __FILE__, array($sidekick,'deactivate_plugin') );
459
+
460
+ if (isset($_POST['sk_setting_disabled'])) $sidekick->set_disabled_wts();
461
+ if (isset($_POST['sk_setting_autostart'])) $sidekick->set_autostart_wt();
462
+ if (isset($_POST['sk_api'])) $sidekick->set_api();
463
+ if (isset($_GET['sk_ver_check'])) $sidekick->check_ver();
464
+
465
+
466
+ add_action('admin_menu', array($sidekick,'setup_menu'));
467
+ add_action('admin_init', array($sidekick,'redirect'));
468
+ add_action('wp_ajax_sk_activate', array($sidekick,'activate'));
469
+ add_action('wp_ajax_sk_save', array($sidekick,'ajax_save'));
470
+ add_action('admin_notices', array($sidekick,'admin_notice'));
471
+ add_action('admin_init', array($sidekick,'admin_notice_ignore'));
472
+
473
+
474
+
475
+ if (!defined('SK_PLUGIN_DEGBUG'))
476
+ require_once('sk_init.php');
477
+
478
+ if (!(isset($_GET['tab']) && $_GET['tab'] == 'plugin-information') && !defined('IFRAME_REQUEST')) {
479
+ add_action('admin_footer', array($sidekick,'footer'));
480
+ add_action('customize_controls_print_footer_scripts', array($sidekick,'footer'));
481
+ }
482
+ }
483
+
484
+
485
+
486
+ // Multisite Licensing
487
+
488
+ if (defined('MULTISITE')) {
489
+ require_once('libs/licensing.php');
490
+ $sidekickMassActivator = new sidekickMassActivator;
491
+ add_action('wpmu_new_blog',array($sidekickMassActivator,'activate'),10,6);
492
+ add_action('network_admin_menu', array($sidekickMassActivator,'setup_menu'));
493
+ add_action('wp_ajax_sk_activate_single', array($sidekickMassActivator,'activate_single'));
494
+ }
495
+