Variation Swatches for WooCommerce - Version 1.0.6

Version Description

  • New - Add a notice in admin area to restore attribute types after re-activating the plugin.
  • Tweak - Rename the tooltip CSS class following WooCommerce standard.
  • Tweak - Remove opacity from swatches.
  • Security - Using $wpdb->prepare to get attribute data.
Download this release

Release Info

Developer themealien
Plugin Icon 128x128 Variation Swatches for WooCommerce
Version 1.0.6
Comparing to
See all releases

Code changes from version 1.0.5 to 1.0.6

appsero/src/Client.php DELETED
@@ -1,210 +0,0 @@
1
- <?php
2
- namespace Appsero;
3
-
4
- /**
5
- * Appsero Client
6
- *
7
- * This class is necessary to set project data
8
- */
9
- class Client {
10
-
11
- /**
12
- * The client version
13
- *
14
- * @var string
15
- */
16
- public $version = '1.1.9';
17
-
18
- /**
19
- * Hash identifier of the plugin
20
- *
21
- * @var string
22
- */
23
- public $hash;
24
-
25
- /**
26
- * Name of the plugin
27
- *
28
- * @var string
29
- */
30
- public $name;
31
-
32
- /**
33
- * The plugin/theme file path
34
- * @example .../wp-content/plugins/test-slug/test-slug.php
35
- *
36
- * @var string
37
- */
38
- public $file;
39
-
40
- /**
41
- * Main plugin file
42
- * @example test-slug/test-slug.php
43
- *
44
- * @var string
45
- */
46
- public $basename;
47
-
48
- /**
49
- * Slug of the plugin
50
- * @example test-slug
51
- *
52
- * @var string
53
- */
54
- public $slug;
55
-
56
- /**
57
- * The project version
58
- *
59
- * @var string
60
- */
61
- public $project_version;
62
-
63
- /**
64
- * The project type
65
- *
66
- * @var string
67
- */
68
- public $type;
69
-
70
- /**
71
- * textdomain
72
- *
73
- * @var string
74
- */
75
- public $textdomain;
76
-
77
- /**
78
- * Initialize the class
79
- *
80
- * @param string $hash hash of the plugin
81
- * @param string $name readable name of the plugin
82
- * @param string $file main plugin file path
83
- */
84
- public function __construct( $hash, $name, $file ) {
85
- $this->hash = $hash;
86
- $this->name = $name;
87
- $this->file = $file;
88
-
89
- $this->set_basename_and_slug();
90
- }
91
-
92
- /**
93
- * Initialize insights class
94
- *
95
- * @return Appsero\Insights
96
- */
97
- public function insights() {
98
-
99
- if ( ! class_exists( __NAMESPACE__ . '\Insights') ) {
100
- require_once __DIR__ . '/Insights.php';
101
- }
102
-
103
- return new Insights( $this );
104
- }
105
-
106
- /**
107
- * Initialize plugin/theme updater
108
- *
109
- * @return Appsero\Updater
110
- */
111
- public function updater() {
112
-
113
- if ( ! class_exists( __NAMESPACE__ . '\Updater') ) {
114
- require_once __DIR__ . '/Updater.php';
115
- }
116
-
117
- return new Updater( $this );
118
- }
119
-
120
- /**
121
- * Initialize license checker
122
- *
123
- * @return Appsero\License
124
- */
125
- public function license() {
126
-
127
- if ( ! class_exists( __NAMESPACE__ . '\License') ) {
128
- require_once __DIR__ . '/License.php';
129
- }
130
-
131
- return new License( $this );
132
- }
133
-
134
- /**
135
- * API Endpoint
136
- *
137
- * @return string
138
- */
139
- public function endpoint() {
140
- $endpoint = apply_filters( 'appsero_endpoint', 'https://api.appsero.com' );
141
-
142
- return trailingslashit( $endpoint );
143
- }
144
-
145
- /**
146
- * Set project basename, slug and version
147
- *
148
- * @return void
149
- */
150
- protected function set_basename_and_slug() {
151
-
152
- if ( strpos( $this->file, WP_CONTENT_DIR . '/themes/' ) === false ) {
153
-
154
- $this->basename = plugin_basename( $this->file );
155
-
156
- list( $this->slug, $mainfile) = explode( '/', $this->basename );
157
-
158
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
159
-
160
- $plugin_data = get_plugin_data( $this->file );
161
-
162
- $this->project_version = $plugin_data['Version'];
163
- $this->type = 'plugin';
164
- $this->textdomain = $this->slug;
165
-
166
- } else {
167
-
168
- $this->basename = str_replace( WP_CONTENT_DIR . '/themes/', '', $this->file );
169
-
170
- list( $this->slug, $mainfile) = explode( '/', $this->basename );
171
-
172
- $theme = wp_get_theme( $this->slug );
173
-
174
- $this->project_version = $theme->version;
175
- $this->type = 'theme';
176
-
177
- }
178
- }
179
-
180
- /**
181
- * Send request to remote endpoint
182
- *
183
- * @param array $params
184
- * @param string $route
185
- *
186
- * @return array|WP_Error Array of results including HTTP headers or WP_Error if the request failed.
187
- */
188
- public function send_request( $params, $route, $blocking = false ) {
189
- $url = $this->endpoint() . $route;
190
-
191
- $headers = array(
192
- 'user-agent' => 'Appsero/' . md5( esc_url( home_url() ) ) . ';',
193
- 'Accept' => 'application/json',
194
- );
195
-
196
- $response = wp_remote_post( $url, array(
197
- 'method' => 'POST',
198
- 'timeout' => 30,
199
- 'redirection' => 5,
200
- 'httpversion' => '1.0',
201
- 'blocking' => $blocking,
202
- 'headers' => $headers,
203
- 'body' => array_merge( $params, array( 'client' => $this->version ) ),
204
- 'cookies' => array()
205
- ) );
206
-
207
- return $response;
208
- }
209
-
210
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
appsero/src/Insights.php DELETED
@@ -1,962 +0,0 @@
1
- <?php
2
- namespace Appsero;
3
-
4
- /**
5
- * Appsero Insights
6
- *
7
- * This is a tracker class to track plugin usage based on if the customer has opted in.
8
- * No personal information is being tracked by this class, only general settings, active plugins, environment details
9
- * and admin email.
10
- */
11
- class Insights {
12
-
13
- /**
14
- * The notice text
15
- *
16
- * @var string
17
- */
18
- public $notice;
19
-
20
- /**
21
- * Wheather to the notice or not
22
- *
23
- * @var boolean
24
- */
25
- protected $show_notice = true;
26
-
27
- /**
28
- * If extra data needs to be sent
29
- *
30
- * @var array
31
- */
32
- protected $extra_data = array();
33
-
34
- /**
35
- * AppSero\Client
36
- *
37
- * @var object
38
- */
39
- protected $client;
40
-
41
- /**
42
- * Initialize the class
43
- *
44
- * @param AppSero\Client
45
- */
46
- public function __construct( $client, $name = null, $file = null ) {
47
-
48
- if ( is_string( $client ) && ! empty( $name ) && ! empty( $file ) ) {
49
- $client = new Client( $client, $name, $file );
50
- }
51
-
52
- if ( is_object( $client ) && is_a( $client, 'Appsero\Client' ) ) {
53
- $this->client = $client;
54
- }
55
- }
56
-
57
- /**
58
- * Don't show the notice
59
- *
60
- * @return \self
61
- */
62
- public function hide_notice() {
63
- $this->show_notice = false;
64
-
65
- return $this;
66
- }
67
-
68
- /**
69
- * Add extra data if needed
70
- *
71
- * @param array $data
72
- *
73
- * @return \self
74
- */
75
- public function add_extra( $data = array() ) {
76
- $this->extra_data = $data;
77
-
78
- return $this;
79
- }
80
-
81
- /**
82
- * Set custom notice text
83
- *
84
- * @param string $text
85
- *
86
- * @return \self
87
- */
88
- public function notice( $text ) {
89
- $this->notice = $text;
90
-
91
- return $this;
92
- }
93
-
94
- /**
95
- * Initialize insights
96
- *
97
- * @return void
98
- */
99
- public function init() {
100
- if ( $this->client->type == 'plugin' ) {
101
- $this->init_plugin();
102
- } else if ( $this->client->type == 'theme' ) {
103
- $this->init_theme();
104
- }
105
- }
106
-
107
- /**
108
- * Initialize theme hooks
109
- *
110
- * @return void
111
- */
112
- public function init_theme() {
113
- $this->init_common();
114
-
115
- add_action( 'switch_theme', array( $this, 'deactivation_cleanup' ) );
116
- add_action( 'switch_theme', array( $this, 'theme_deactivated' ), 12, 3 );
117
- }
118
-
119
- /**
120
- * Initialize plugin hooks
121
- *
122
- * @return void
123
- */
124
- public function init_plugin() {
125
- // plugin deactivate popup
126
- if ( ! $this->is_local_server() ) {
127
- add_filter( 'plugin_action_links_' . $this->client->basename, array( $this, 'plugin_action_links' ) );
128
- add_action( 'admin_footer', array( $this, 'deactivate_scripts' ) );
129
- }
130
-
131
- $this->init_common();
132
-
133
- register_activation_hook( $this->client->file, array( $this, 'activate_plugin' ) );
134
- register_deactivation_hook( $this->client->file, array( $this, 'deactivation_cleanup' ) );
135
- }
136
-
137
- /**
138
- * Initialize common hooks
139
- *
140
- * @return void
141
- */
142
- protected function init_common() {
143
-
144
- if ( $this->show_notice ) {
145
- // tracking notice
146
- add_action( 'admin_notices', array( $this, 'admin_notice' ) );
147
- }
148
-
149
- add_action( 'admin_init', array( $this, 'handle_optin_optout' ) );
150
-
151
- // uninstall reason
152
- add_action( 'wp_ajax_' . $this->client->slug . '_submit-uninstall-reason', array( $this, 'uninstall_reason_submission' ) );
153
-
154
- // cron events
155
- add_filter( 'cron_schedules', array( $this, 'add_weekly_schedule' ) );
156
- add_action( $this->client->slug . '_tracker_send_event', array( $this, 'send_tracking_data' ) );
157
- // add_action( 'admin_init', array( $this, 'send_tracking_data' ) ); // test
158
- }
159
-
160
- /**
161
- * Send tracking data to AppSero server
162
- *
163
- * @param boolean $override
164
- *
165
- * @return void
166
- */
167
- public function send_tracking_data( $override = false ) {
168
- // skip on AJAX Requests
169
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
170
- return;
171
- }
172
-
173
- if ( ! $this->tracking_allowed() && ! $override ) {
174
- return;
175
- }
176
-
177
- // Send a maximum of once per week
178
- $last_send = $this->get_last_send();
179
-
180
- if ( $last_send && $last_send > strtotime( '-1 week' ) ) {
181
- return;
182
- }
183
-
184
- $response = $this->client->send_request( $this->get_tracking_data(), 'track' );
185
-
186
- update_option( $this->client->slug . '_tracking_last_send', time() );
187
- }
188
-
189
- /**
190
- * Get the tracking data points
191
- *
192
- * @return array
193
- */
194
- protected function get_tracking_data() {
195
- $all_plugins = $this->get_all_plugins();
196
-
197
- $users = get_users( array(
198
- 'role' => 'administrator',
199
- 'orderby' => 'ID',
200
- 'order' => 'ASC',
201
- 'number' => 1,
202
- 'paged' => 1,
203
- ) );
204
-
205
- $admin_user = ( is_array( $users ) && ! empty( $users ) ) ? $users[0] : false;
206
- $first_name = $last_name = '';
207
-
208
- if ( $admin_user ) {
209
- $first_name = $admin_user->first_name ? $admin_user->first_name : $admin_user->display_name;
210
- $last_name = $admin_user->last_name;
211
- }
212
-
213
- $data = array(
214
- 'version' => $this->client->project_version,
215
- 'url' => esc_url( home_url() ),
216
- 'site' => $this->get_site_name(),
217
- 'admin_email' => get_option( 'admin_email' ),
218
- 'first_name' => $first_name,
219
- 'last_name' => $last_name,
220
- 'hash' => $this->client->hash,
221
- 'server' => $this->get_server_info(),
222
- 'wp' => $this->get_wp_info(),
223
- 'users' => $this->get_user_counts(),
224
- 'active_plugins' => count( $all_plugins['active_plugins'] ),
225
- 'inactive_plugins' => count( $all_plugins['inactive_plugins'] ),
226
- 'ip_address' => $this->get_user_ip_address(),
227
- 'theme' => get_stylesheet(),
228
- 'version' => $this->client->project_version,
229
- );
230
-
231
- // Add metadata
232
- if ( $extra = $this->get_extra_data() ) {
233
- $data['extra'] = $extra;
234
- }
235
-
236
- return apply_filters( $this->client->slug . '_tracker_data', $data );
237
- }
238
-
239
- /**
240
- * If a child class wants to send extra data
241
- *
242
- * @return mixed
243
- */
244
- protected function get_extra_data() {
245
- if ( is_callable( $this->extra_data ) ) {
246
- return call_user_func( $this->extra_data );
247
- }
248
-
249
- if ( is_array( $this->extra_data ) ) {
250
- return $this->extra_data;
251
- }
252
-
253
- return array();
254
- }
255
-
256
- /**
257
- * Explain the user which data we collect
258
- *
259
- * @return string
260
- */
261
- protected function data_we_collect() {
262
- $data = array(
263
- 'Server environment details (php, mysql, server, WordPress versions)',
264
- 'Number of users in your site',
265
- 'Site language',
266
- 'Number of active and inactive plugins',
267
- 'Site name and url',
268
- 'Your name and email address',
269
- );
270
-
271
- return $data;
272
- }
273
-
274
- /**
275
- * Check if the user has opted into tracking
276
- *
277
- * @return bool
278
- */
279
- public function tracking_allowed() {
280
- $allow_tracking = get_option( $this->client->slug . '_allow_tracking', 'no' );
281
-
282
- return $allow_tracking == 'yes';
283
- }
284
-
285
- /**
286
- * Get the last time a tracking was sent
287
- *
288
- * @return false|string
289
- */
290
- private function get_last_send() {
291
- return get_option( $this->client->slug . '_tracking_last_send', false );
292
- }
293
-
294
- /**
295
- * Check if the notice has been dismissed or enabled
296
- *
297
- * @return boolean
298
- */
299
- private function notice_dismissed() {
300
- $hide_notice = get_option( $this->client->slug . '_tracking_notice', null );
301
-
302
- if ( 'hide' == $hide_notice ) {
303
- return true;
304
- }
305
-
306
- return false;
307
- }
308
-
309
- /**
310
- * Check if the current server is localhost
311
- *
312
- * @return boolean
313
- */
314
- private function is_local_server() {
315
- return false;
316
-
317
- $is_local = in_array( $_SERVER['REMOTE_ADDR'], array( '127.0.0.1', '::1' ) );
318
-
319
- return apply_filters( 'appsero_is_local', $is_local );
320
- }
321
-
322
- /**
323
- * Schedule the event weekly
324
- *
325
- * @return void
326
- */
327
- private function schedule_event() {
328
- $hook_name = $this->client->slug . '_tracker_send_event';
329
-
330
- if ( ! wp_next_scheduled( $hook_name ) ) {
331
- wp_schedule_event( time(), 'weekly', $hook_name );
332
- }
333
- }
334
-
335
- /**
336
- * Clear any scheduled hook
337
- *
338
- * @return void
339
- */
340
- private function clear_schedule_event() {
341
- wp_clear_scheduled_hook( $this->client->slug . '_tracker_send_event' );
342
- }
343
-
344
- /**
345
- * Display the admin notice to users that have not opted-in or out
346
- *
347
- * @return void
348
- */
349
- public function admin_notice() {
350
-
351
- if ( $this->notice_dismissed() ) {
352
- return;
353
- }
354
-
355
- if ( $this->tracking_allowed() ) {
356
- return;
357
- }
358
-
359
- if ( ! current_user_can( 'manage_options' ) ) {
360
- return;
361
- }
362
-
363
- // don't show tracking if a local server
364
- if ( ! $this->is_local_server() ) {
365
- $optin_url = add_query_arg( $this->client->slug . '_tracker_optin', 'true' );
366
- $optout_url = add_query_arg( $this->client->slug . '_tracker_optout', 'true' );
367
-
368
- if ( empty( $this->notice ) ) {
369
- $notice = sprintf( __( 'Want to help make <strong>%1$s</strong> even more awesome? Allow %1$s to collect non-sensitive diagnostic data and usage information.', $this->client->textdomain ), $this->client->name );
370
- } else {
371
- $notice = $this->notice;
372
- }
373
-
374
- $notice .= ' (<a class="' . $this->client->slug . '-insights-data-we-collect" href="#">' . __( 'what we collect', $this->client->textdomain ) . '</a>)';
375
- $notice .= '<p class="description" style="display:none;">' . implode( ', ', $this->data_we_collect() ) . '. No sensitive data is tracked. ';
376
- $notice .= 'We are using Appsero to collect your data. <a href="https://appsero.com/privacy-policy/">Learn more</a> about how Appsero collects and handle your data.</p>';
377
-
378
- echo '<div class="updated"><p>';
379
- echo $notice;
380
- echo '</p><p class="submit">';
381
- echo '&nbsp;<a href="' . esc_url( $optin_url ) . '" class="button-primary button-large">' . __( 'Allow', $this->client->textdomain ) . '</a>';
382
- echo '&nbsp;<a href="' . esc_url( $optout_url ) . '" class="button-secondary button-large">' . __( 'No thanks', $this->client->textdomain ) . '</a>';
383
- echo '</p></div>';
384
-
385
- echo "<script type='text/javascript'>jQuery('." . $this->client->slug . "-insights-data-we-collect').on('click', function(e) {
386
- e.preventDefault();
387
- jQuery(this).parents('.updated').find('p.description').slideToggle('fast');
388
- });
389
- </script>
390
- ";
391
- }
392
- }
393
-
394
- /**
395
- * handle the optin/optout
396
- *
397
- * @return void
398
- */
399
- public function handle_optin_optout() {
400
-
401
- if ( isset( $_GET[ $this->client->slug . '_tracker_optin' ] ) && $_GET[ $this->client->slug . '_tracker_optin' ] == 'true' ) {
402
- $this->optin();
403
-
404
- wp_redirect( remove_query_arg( $this->client->slug . '_tracker_optin' ) );
405
- exit;
406
- }
407
-
408
- if ( isset( $_GET[ $this->client->slug . '_tracker_optout' ] ) && $_GET[ $this->client->slug . '_tracker_optout' ] == 'true' ) {
409
- $this->optout();
410
-
411
- wp_redirect( remove_query_arg( $this->client->slug . '_tracker_optout' ) );
412
- exit;
413
- }
414
- }
415
-
416
- /**
417
- * Tracking optin
418
- *
419
- * @return void
420
- */
421
- public function optin() {
422
- update_option( $this->client->slug . '_allow_tracking', 'yes' );
423
- update_option( $this->client->slug . '_tracking_notice', 'hide' );
424
-
425
- $this->clear_schedule_event();
426
- $this->schedule_event();
427
- $this->send_tracking_data();
428
- }
429
-
430
- /**
431
- * Optout from tracking
432
- *
433
- * @return void
434
- */
435
- public function optout() {
436
- update_option( $this->client->slug . '_allow_tracking', 'no' );
437
- update_option( $this->client->slug . '_tracking_notice', 'hide' );
438
-
439
- $this->clear_schedule_event();
440
- }
441
-
442
- /**
443
- * Get the number of post counts
444
- *
445
- * @param string $post_type
446
- *
447
- * @return integer
448
- */
449
- public function get_post_count( $post_type ) {
450
- global $wpdb;
451
-
452
- return (int) $wpdb->get_var( "SELECT count(ID) FROM $wpdb->posts WHERE post_type = '$post_type' and post_status = 'publish'");
453
- }
454
-
455
- /**
456
- * Get server related info.
457
- *
458
- * @return array
459
- */
460
- private static function get_server_info() {
461
- global $wpdb;
462
-
463
- $server_data = array();
464
-
465
- if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
466
- $server_data['software'] = $_SERVER['SERVER_SOFTWARE'];
467
- }
468
-
469
- if ( function_exists( 'phpversion' ) ) {
470
- $server_data['php_version'] = phpversion();
471
- }
472
-
473
- $server_data['mysql_version'] = $wpdb->db_version();
474
-
475
- $server_data['php_max_upload_size'] = size_format( wp_max_upload_size() );
476
- $server_data['php_default_timezone'] = date_default_timezone_get();
477
- $server_data['php_soap'] = class_exists( 'SoapClient' ) ? 'Yes' : 'No';
478
- $server_data['php_fsockopen'] = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
479
- $server_data['php_curl'] = function_exists( 'curl_init' ) ? 'Yes' : 'No';
480
-
481
- return $server_data;
482
- }
483
-
484
- /**
485
- * Get WordPress related data.
486
- *
487
- * @return array
488
- */
489
- private function get_wp_info() {
490
- $wp_data = array();
491
-
492
- $wp_data['memory_limit'] = WP_MEMORY_LIMIT;
493
- $wp_data['debug_mode'] = ( defined('WP_DEBUG') && WP_DEBUG ) ? 'Yes' : 'No';
494
- $wp_data['locale'] = get_locale();
495
- $wp_data['version'] = get_bloginfo( 'version' );
496
- $wp_data['multisite'] = is_multisite() ? 'Yes' : 'No';
497
-
498
- return $wp_data;
499
- }
500
-
501
- /**
502
- * Get the list of active and inactive plugins
503
- *
504
- * @return array
505
- */
506
- private function get_all_plugins() {
507
- // Ensure get_plugins function is loaded
508
- if ( ! function_exists( 'get_plugins' ) ) {
509
- include ABSPATH . '/wp-admin/includes/plugin.php';
510
- }
511
-
512
- $plugins = get_plugins();
513
- $active_plugins_keys = get_option( 'active_plugins', array() );
514
- $active_plugins = array();
515
-
516
- foreach ( $plugins as $k => $v ) {
517
- // Take care of formatting the data how we want it.
518
- $formatted = array();
519
- $formatted['name'] = strip_tags( $v['Name'] );
520
-
521
- if ( isset( $v['Version'] ) ) {
522
- $formatted['version'] = strip_tags( $v['Version'] );
523
- }
524
-
525
- if ( isset( $v['Author'] ) ) {
526
- $formatted['author'] = strip_tags( $v['Author'] );
527
- }
528
-
529
- if ( isset( $v['Network'] ) ) {
530
- $formatted['network'] = strip_tags( $v['Network'] );
531
- }
532
-
533
- if ( isset( $v['PluginURI'] ) ) {
534
- $formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
535
- }
536
-
537
- if ( in_array( $k, $active_plugins_keys ) ) {
538
- // Remove active plugins from list so we can show active and inactive separately
539
- unset( $plugins[$k] );
540
- $active_plugins[$k] = $formatted;
541
- } else {
542
- $plugins[$k] = $formatted;
543
- }
544
- }
545
-
546
- return array( 'active_plugins' => $active_plugins, 'inactive_plugins' => $plugins );
547
- }
548
-
549
- /**
550
- * Get user totals based on user role.
551
- *
552
- * @return array
553
- */
554
- public function get_user_counts() {
555
- $user_count = array();
556
- $user_count_data = count_users();
557
- $user_count['total'] = $user_count_data['total_users'];
558
-
559
- // Get user count based on user role
560
- foreach ( $user_count_data['avail_roles'] as $role => $count ) {
561
- $user_count[ $role ] = $count;
562
- }
563
-
564
- return $user_count;
565
- }
566
-
567
- /**
568
- * Add weekly cron schedule
569
- *
570
- * @param array $schedules
571
- *
572
- * @return array
573
- */
574
- public function add_weekly_schedule( $schedules ) {
575
-
576
- $schedules['weekly'] = array(
577
- 'interval' => DAY_IN_SECONDS * 7,
578
- 'display' => 'Once Weekly',
579
- );
580
-
581
- return $schedules;
582
- }
583
-
584
- /**
585
- * Plugin activation hook
586
- *
587
- * @return void
588
- */
589
- public function activate_plugin() {
590
- $allowed = get_option( $this->client->slug . '_allow_tracking', 'no' );
591
-
592
- // if it wasn't allowed before, do nothing
593
- if ( 'yes' !== $allowed ) {
594
- return;
595
- }
596
-
597
- // re-schedule and delete the last sent time so we could force send again
598
- $hook_name = $this->client->slug . '_tracker_send_event';
599
- if ( ! wp_next_scheduled( $hook_name ) ) {
600
- wp_schedule_event( time(), 'weekly', $hook_name );
601
- }
602
-
603
- delete_option( $this->client->slug . '_tracking_last_send' );
604
-
605
- $this->send_tracking_data( true );
606
- }
607
-
608
- /**
609
- * Clear our options upon deactivation
610
- *
611
- * @return void
612
- */
613
- public function deactivation_cleanup() {
614
- $this->clear_schedule_event();
615
-
616
- if ( 'theme' == $this->client->type ) {
617
- delete_option( $this->client->slug . '_tracking_last_send' );
618
- delete_option( $this->client->slug . '_allow_tracking' );
619
- }
620
-
621
- delete_option( $this->client->slug . '_tracking_notice' );
622
- }
623
-
624
- /**
625
- * Hook into action links and modify the deactivate link
626
- *
627
- * @param array $links
628
- *
629
- * @return array
630
- */
631
- public function plugin_action_links( $links ) {
632
-
633
- if ( array_key_exists( 'deactivate', $links ) ) {
634
- $links['deactivate'] = str_replace( '<a', '<a class="' . $this->client->slug . '-deactivate-link"', $links['deactivate'] );
635
- }
636
-
637
- return $links;
638
- }
639
-
640
- private function get_uninstall_reasons() {
641
- $reasons = array(
642
- array(
643
- 'id' => 'could-not-understand',
644
- 'text' => 'I couldn\'t understand how to make it work',
645
- 'type' => 'textarea',
646
- 'placeholder' => 'Would you like us to assist you?'
647
- ),
648
- array(
649
- 'id' => 'found-better-plugin',
650
- 'text' => 'I found a better plugin',
651
- 'type' => 'text',
652
- 'placeholder' => 'Which plugin?'
653
- ),
654
- array(
655
- 'id' => 'not-have-that-feature',
656
- 'text' => 'The plugin is great, but I need specific feature that you don\'t support',
657
- 'type' => 'textarea',
658
- 'placeholder' => 'Could you tell us more about that feature?'
659
- ),
660
- array(
661
- 'id' => 'is-not-working',
662
- 'text' => 'The plugin is not working',
663
- 'type' => 'textarea',
664
- 'placeholder' => 'Could you tell us a bit more whats not working?'
665
- ),
666
- array(
667
- 'id' => 'looking-for-other',
668
- 'text' => 'It\'s not what I was looking for',
669
- 'type' => '',
670
- 'placeholder' => ''
671
- ),
672
- array(
673
- 'id' => 'did-not-work-as-expected',
674
- 'text' => 'The plugin didn\'t work as expected',
675
- 'type' => 'textarea',
676
- 'placeholder' => 'What did you expect?'
677
- ),
678
- array(
679
- 'id' => 'other',
680
- 'text' => 'Other',
681
- 'type' => 'textarea',
682
- 'placeholder' => 'Could you tell us a bit more?'
683
- ),
684
- );
685
-
686
- return $reasons;
687
- }
688
-
689
- /**
690
- * Plugin deactivation uninstall reason submission
691
- *
692
- * @return void
693
- */
694
- public function uninstall_reason_submission() {
695
-
696
- if ( ! isset( $_POST['reason_id'] ) ) {
697
- wp_send_json_error();
698
- }
699
-
700
- $current_user = wp_get_current_user();
701
-
702
- $data = array(
703
- 'hash' => $this->client->hash,
704
- 'reason_id' => sanitize_text_field( $_POST['reason_id'] ),
705
- 'reason_info' => isset( $_REQUEST['reason_info'] ) ? trim( stripslashes( $_REQUEST['reason_info'] ) ) : '',
706
- 'site' => $this->get_site_name(),
707
- 'url' => esc_url( home_url() ),
708
- 'admin_email' => get_option( 'admin_email' ),
709
- 'user_email' => $current_user->user_email,
710
- 'first_name' => $current_user->first_name,
711
- 'last_name' => $current_user->last_name,
712
- 'server' => $this->get_server_info(),
713
- 'wp' => $this->get_wp_info(),
714
- 'ip_address' => $this->get_user_ip_address(),
715
- 'theme' => get_stylesheet(),
716
- 'version' => $this->client->project_version,
717
- );
718
-
719
- // Add metadata
720
- if ( $extra = $this->get_extra_data() ) {
721
- $data['extra'] = $extra;
722
- }
723
-
724
- $this->client->send_request( $data, 'deactivate' );
725
-
726
- wp_send_json_success();
727
- }
728
-
729
- /**
730
- * Handle the plugin deactivation feedback
731
- *
732
- * @return void
733
- */
734
- public function deactivate_scripts() {
735
- global $pagenow;
736
-
737
- if ( 'plugins.php' != $pagenow ) {
738
- return;
739
- }
740
-
741
- $reasons = $this->get_uninstall_reasons();
742
- ?>
743
-
744
- <div class="wd-dr-modal" id="<?php echo $this->client->slug; ?>-wd-dr-modal">
745
- <div class="wd-dr-modal-wrap">
746
- <div class="wd-dr-modal-header">
747
- <h3><?php _e( 'If you have a moment, please let us know why you are deactivating:', $this->client->textdomain ); ?></h3>
748
- </div>
749
-
750
- <div class="wd-dr-modal-body">
751
- <ul class="reasons">
752
- <?php foreach ($reasons as $reason) { ?>
753
- <li data-type="<?php echo esc_attr( $reason['type'] ); ?>" data-placeholder="<?php echo esc_attr( $reason['placeholder'] ); ?>">
754
- <label><input type="radio" name="selected-reason" value="<?php echo $reason['id']; ?>"> <?php echo $reason['text']; ?></label>
755
- </li>
756
- <?php } ?>
757
- </ul>
758
- <p class="wd-dr-modal-reasons-bottom">We share your data with <a href="https://appsero.com/">Appsero</a> to troubleshoot problems &amp; make product improvements. <a href="https://appsero.com/privacy-policy/">Learn more</a> about how Appsero handles your data.</p>
759
- </div>
760
-
761
- <div class="wd-dr-modal-footer">
762
- <a href="#" class="dont-bother-me"><?php _e( 'I rather wouldn\'t say', $this->client->textdomain ); ?></a>
763
- <button class="button-secondary"><?php _e( 'Submit & Deactivate', $this->client->textdomain ); ?></button>
764
- <button class="button-primary"><?php _e( 'Cancel', $this->client->textdomain ); ?></button>
765
- </div>
766
- </div>
767
- </div>
768
-
769
- <style type="text/css">
770
- .wd-dr-modal {
771
- position: fixed;
772
- z-index: 99999;
773
- top: 0;
774
- right: 0;
775
- bottom: 0;
776
- left: 0;
777
- background: rgba(0,0,0,0.5);
778
- display: none;
779
- }
780
-
781
- .wd-dr-modal.modal-active {
782
- display: block;
783
- }
784
-
785
- .wd-dr-modal-wrap {
786
- width: 475px;
787
- position: relative;
788
- margin: 10% auto;
789
- background: #fff;
790
- }
791
-
792
- .wd-dr-modal-header {
793
- border-bottom: 1px solid #eee;
794
- padding: 8px 20px;
795
- }
796
-
797
- .wd-dr-modal-header h3 {
798
- line-height: 150%;
799
- margin: 0;
800
- }
801
-
802
- .wd-dr-modal-body {
803
- padding: 5px 20px 20px 20px;
804
- }
805
-
806
- .wd-dr-modal-body .reason-input {
807
- margin-top: 5px;
808
- margin-left: 20px;
809
- }
810
- .wd-dr-modal-footer {
811
- border-top: 1px solid #eee;
812
- padding: 12px 20px;
813
- text-align: right;
814
- }
815
- .wd-dr-modal-reasons-bottom {
816
- margin: 15px 0 0 0;
817
- }
818
- </style>
819
-
820
- <script type="text/javascript">
821
- (function($) {
822
- $(function() {
823
- var modal = $( '#<?php echo $this->client->slug; ?>-wd-dr-modal' );
824
- var deactivateLink = '';
825
-
826
- $( '#the-list' ).on('click', 'a.<?php echo $this->client->slug; ?>-deactivate-link', function(e) {
827
- e.preventDefault();
828
-
829
- modal.addClass('modal-active');
830
- deactivateLink = $(this).attr('href');
831
- modal.find('a.dont-bother-me').attr('href', deactivateLink).css('float', 'left');
832
- });
833
-
834
- modal.on('click', 'button.button-primary', function(e) {
835
- e.preventDefault();
836
-
837
- modal.removeClass('modal-active');
838
- });
839
-
840
- modal.on('click', 'input[type="radio"]', function () {
841
- var parent = $(this).parents('li:first');
842
-
843
- modal.find('.reason-input').remove();
844
-
845
- var inputType = parent.data('type'),
846
- inputPlaceholder = parent.data('placeholder'),
847
- reasonInputHtml = '<div class="reason-input">' + ( ( 'text' === inputType ) ? '<input type="text" size="40" />' : '<textarea rows="5" cols="45"></textarea>' ) + '</div>';
848
-
849
- if ( inputType !== '' ) {
850
- parent.append( $(reasonInputHtml) );
851
- parent.find('input, textarea').attr('placeholder', inputPlaceholder).focus();
852
- }
853
- });
854
-
855
- modal.on('click', 'button.button-secondary', function(e) {
856
- e.preventDefault();
857
-
858
- var button = $(this);
859
-
860
- if ( button.hasClass('disabled') ) {
861
- return;
862
- }
863
-
864
- var $radio = $( 'input[type="radio"]:checked', modal );
865
-
866
- var $selected_reason = $radio.parents('li:first'),
867
- $input = $selected_reason.find('textarea, input[type="text"]');
868
-
869
- $.ajax({
870
- url: ajaxurl,
871
- type: 'POST',
872
- data: {
873
- action: '<?php echo $this->client->slug; ?>_submit-uninstall-reason',
874
- reason_id: ( 0 === $radio.length ) ? 'none' : $radio.val(),
875
- reason_info: ( 0 !== $input.length ) ? $input.val().trim() : ''
876
- },
877
- beforeSend: function() {
878
- button.addClass('disabled');
879
- button.text('Processing...');
880
- },
881
- complete: function() {
882
- window.location.href = deactivateLink;
883
- }
884
- });
885
- });
886
- });
887
- }(jQuery));
888
- </script>
889
-
890
- <?php
891
- }
892
-
893
- /**
894
- * Run after theme deactivated
895
- * @param string $new_name
896
- * @param object $new_theme
897
- * @param object $old_theme
898
- * @return void
899
- */
900
- public function theme_deactivated( $new_name, $new_theme, $old_theme ) {
901
- // Make sure this is appsero theme
902
- if ( $old_theme->get_template() == $this->client->slug ) {
903
- $current_user = wp_get_current_user();
904
-
905
- $data = array(
906
- 'hash' => $this->client->hash,
907
- 'reason_id' => 'none',
908
- 'reason_info' => '',
909
- 'site' => $this->get_site_name(),
910
- 'url' => esc_url( home_url() ),
911
- 'admin_email' => get_option( 'admin_email' ),
912
- 'user_email' => $current_user->user_email,
913
- 'first_name' => $current_user->first_name,
914
- 'last_name' => $current_user->last_name,
915
- 'server' => $this->get_server_info(),
916
- 'wp' => $this->get_wp_info(),
917
- 'ip_address' => $this->get_user_ip_address(),
918
- 'theme' => get_stylesheet(),
919
- 'version' => $this->client->project_version,
920
- );
921
-
922
- $this->client->send_request( $data, 'deactivate' );
923
- }
924
- }
925
-
926
- /**
927
- * Get user IP Address
928
- */
929
- private function get_user_ip_address() {
930
- $response = wp_remote_get( 'https://icanhazip.com/' );
931
-
932
- if ( is_wp_error( $response ) ) {
933
- return '';
934
- }
935
-
936
- $ip = trim( wp_remote_retrieve_body( $response ) );
937
-
938
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
939
- return '';
940
- }
941
-
942
- return $ip;
943
- }
944
-
945
- /**
946
- * Get site name
947
- */
948
- private function get_site_name() {
949
- $site_name = get_bloginfo( 'name' );
950
-
951
- if ( empty( $site_name ) ) {
952
- $site_name = get_bloginfo( 'description' );
953
- $site_name = wp_trim_words( $site_name, 3, '' );
954
- }
955
-
956
- if ( empty( $site_name ) ) {
957
- $site_name = get_bloginfo( 'url' );
958
- }
959
-
960
- return $site_name;
961
- }
962
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
appsero/src/License.php DELETED
@@ -1,701 +0,0 @@
1
- <?php
2
- namespace Appsero;
3
-
4
- /**
5
- * Appsero License Checker
6
- *
7
- * This class will check, active and deactive license
8
- */
9
- class License {
10
-
11
- /**
12
- * AppSero\Client
13
- *
14
- * @var object
15
- */
16
- protected $client;
17
-
18
- /**
19
- * Arguments of create menu
20
- *
21
- * @var array
22
- */
23
- protected $menu_args;
24
-
25
- /**
26
- * `option_name` of `wp_options` table
27
- *
28
- * @var string
29
- */
30
- protected $option_key;
31
-
32
- /**
33
- * Error message of HTTP request
34
- *
35
- * @var string
36
- */
37
- public $error;
38
-
39
- /**
40
- * Success message on form submit
41
- *
42
- * @var string
43
- */
44
- public $success;
45
-
46
- /**
47
- * Corn schedule hook name
48
- *
49
- * @var string
50
- */
51
- protected $schedule_hook;
52
-
53
- /**
54
- * Set value for valid licnese
55
- *
56
- * @var boolean
57
- */
58
- private $is_valid_licnese = null;
59
-
60
- /**
61
- * Initialize the class
62
- *
63
- * @param Appsero\Client
64
- */
65
- public function __construct( Client $client ) {
66
- $this->client = $client;
67
-
68
- $this->option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license';
69
-
70
- $this->schedule_hook = $this->client->slug . '_license_check_event';
71
-
72
- // Run hook to check license status daily
73
- add_action( $this->schedule_hook, array( $this, 'check_license_status' ) );
74
-
75
- // Active/Deactive corn schedule
76
- $this->run_schedule();
77
- }
78
-
79
- /**
80
- * Check license
81
- *
82
- * @return boolean
83
- */
84
- public function check( $license_key ) {
85
- $route = 'public/license/' . $this->client->hash . '/check';
86
-
87
- return $this->send_request( $license_key, $route );
88
- }
89
-
90
- /**
91
- * Active a license
92
- *
93
- * @return boolean
94
- */
95
- public function activate( $license_key ) {
96
- $route = 'public/license/' . $this->client->hash . '/activate';
97
-
98
- return $this->send_request( $license_key, $route );
99
- }
100
-
101
- /**
102
- * Deactivate a license
103
- *
104
- * @return boolean
105
- */
106
- public function deactivate( $license_key ) {
107
- $route = 'public/license/' . $this->client->hash . '/deactivate';
108
-
109
- return $this->send_request( $license_key, $route );
110
- }
111
-
112
- /**
113
- * Send common request
114
- *
115
- * @param $license_key
116
- * @param $route
117
- *
118
- * @return array
119
- */
120
- protected function send_request( $license_key, $route ) {
121
- $params = array(
122
- 'license_key' => $license_key,
123
- 'url' => esc_url( home_url() ),
124
- );
125
-
126
- $response = $this->client->send_request( $params, $route, true );
127
-
128
- if ( is_wp_error( $response ) ) {
129
- return array(
130
- 'success' => false,
131
- 'error' => $response->get_error_message()
132
- );
133
- }
134
-
135
- $response = json_decode( wp_remote_retrieve_body( $response ), true );
136
-
137
- if ( empty( $response ) || isset( $response['exception'] )) {
138
- return array(
139
- 'success' => false,
140
- 'error' => 'Unknown error occurred, Please try again.'
141
- );
142
- }
143
-
144
- if ( isset( $response['errors'] ) && isset( $response['errors']['license_key'] ) ) {
145
- $response = array(
146
- 'success' => false,
147
- 'error' => $response['errors']['license_key'][0]
148
- );
149
- }
150
-
151
- return $response;
152
- }
153
-
154
- /**
155
- * Add settings page for license
156
- *
157
- * @param array $args
158
- *
159
- * @return void
160
- */
161
- public function add_settings_page( $args = array() ) {
162
- $defaults = array(
163
- 'type' => 'menu', // Can be: menu, options, submenu
164
- 'page_title' => 'Manage License',
165
- 'menu_title' => 'Manage License',
166
- 'capability' => 'manage_options',
167
- 'menu_slug' => $this->client->slug . '-manage-license',
168
- 'icon_url' => '',
169
- 'position' => null,
170
- 'parent_slug' => '',
171
- );
172
-
173
- $this->menu_args = wp_parse_args( $args, $defaults );
174
-
175
- add_action( 'admin_menu', array( $this, 'admin_menu' ), 99 );
176
- }
177
-
178
- /**
179
- * Admin Menu hook
180
- *
181
- * @return void
182
- */
183
- public function admin_menu() {
184
- switch ( $this->menu_args['type'] ) {
185
- case 'menu':
186
- $this->add_menu_page();
187
- break;
188
-
189
- case 'submenu':
190
- $this->add_submenu_page();
191
- break;
192
-
193
- case 'options':
194
- $this->add_options_page();
195
- break;
196
- }
197
- }
198
-
199
- /**
200
- * License menu output
201
- */
202
- public function menu_output() {
203
-
204
- if ( isset( $_POST['submit'] ) ) {
205
- $this->license_form_submit( $_POST );
206
- }
207
-
208
- $license = get_option( $this->option_key, null );
209
- $action = ( $license && isset( $license['status'] ) && 'activate' == $license['status'] ) ? 'deactive' : 'active';
210
- $this->licenses_style();
211
- ?>
212
-
213
- <div class="wrap appsero-license-settings-wrapper">
214
- <h1>License Settings</h1>
215
-
216
- <?php
217
- $this->show_license_page_notices();
218
- do_action( 'before_appsero_license_section' );
219
- ?>
220
-
221
- <div class="appsero-license-settings appsero-license-section">
222
- <?php $this->show_license_page_card_header(); ?>
223
-
224
- <div class="appsero-license-details">
225
- <p>Active <strong><?php echo $this->client->name; ?></strong> by your license key to get professional support and automatic update from your WordPress dashboard.</p>
226
- <form method="post" action="<?php $this->formActionUrl(); ?>" novalidate="novalidate" spellcheck="false">
227
- <input type="hidden" name="_action" value="<?php echo $action; ?>">
228
- <input type="hidden" name="_nonce" value="<?php echo wp_create_nonce( $this->client->name ); ?>">
229
- <div class="license-input-fields">
230
- <div class="license-input-key">
231
- <svg enable-background="new 0 0 512 512" version="1.1" viewBox="0 0 512 512" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
232
- <path d="m463.75 48.251c-64.336-64.336-169.01-64.335-233.35 1e-3 -43.945 43.945-59.209 108.71-40.181 167.46l-185.82 185.82c-2.813 2.813-4.395 6.621-4.395 10.606v84.858c0 8.291 6.709 15 15 15h84.858c3.984 0 7.793-1.582 10.605-4.395l21.211-21.226c3.237-3.237 4.819-7.778 4.292-12.334l-2.637-22.793 31.582-2.974c7.178-0.674 12.847-6.343 13.521-13.521l2.974-31.582 22.793 2.651c4.233 0.571 8.496-0.85 11.704-3.691 3.193-2.856 5.024-6.929 5.024-11.206v-27.929h27.422c3.984 0 7.793-1.582 10.605-4.395l38.467-37.958c58.74 19.043 122.38 4.929 166.33-39.046 64.336-64.335 64.336-169.01 0-233.35zm-42.435 106.07c-17.549 17.549-46.084 17.549-63.633 0s-17.549-46.084 0-63.633 46.084-17.549 63.633 0 17.548 46.084 0 63.633z"/>
233
- </svg>
234
- <input type="text" value="<?php echo $this->get_input_license_value( $action, $license ); ?>"
235
- placeholder="Enter your license key to activate" name="license_key"
236
- <?php echo ( 'deactive' == $action ) ? 'readonly="readonly"' : ''; ?>
237
- />
238
- </div>
239
- <button type="submit" name="submit" class="<?php echo 'deactive' == $action ? 'deactive-button' : ''; ?>">
240
- <?php echo $action == 'active' ? 'Activate License' : 'Deactivate License' ; ?>
241
- </button>
242
- </div>
243
- </form>
244
-
245
- <?php
246
- if ( 'deactive' == $action && isset( $license['remaining'] ) ) {
247
- $this->show_active_license_info( $license );
248
- }
249
- ?>
250
- </div>
251
- </div> <!-- /.appsero-license-settings -->
252
-
253
- <?php do_action( 'after_appsero_license_section' ); ?>
254
- </div>
255
- <?php
256
- }
257
-
258
- /**
259
- * License form submit
260
- */
261
- public function license_form_submit( $form ) {
262
- if ( ! isset( $form['_nonce'], $form['_action'] ) ) {
263
- $this->error = "Please add all information";
264
- return;
265
- }
266
-
267
- if ( ! wp_verify_nonce( $form['_nonce'], $this->client->name ) ) {
268
- $this->error = "You don't have permission to manage license.";
269
- return;
270
- }
271
-
272
- switch ( $form['_action'] ) {
273
- case 'active':
274
- $this->active_client_license( $form );
275
- break;
276
-
277
- case 'deactive':
278
- $this->deactive_client_license( $form );
279
- break;
280
- }
281
- }
282
-
283
- /**
284
- * Check license status on schedule
285
- */
286
- public function check_license_status() {
287
- $license = get_option( $this->option_key, null );
288
-
289
- if ( isset( $license['key'] ) && ! empty( $license['key'] ) ) {
290
- $response = $this->check( $license['key'] );
291
-
292
- if ( isset( $response['success'] ) && $response['success'] ) {
293
- $license['status'] = 'activate';
294
- $license['remaining'] = $response['remaining'];
295
- $license['activation_limit'] = $response['activation_limit'];
296
- $license['expiry_days'] = $response['expiry_days'];
297
- $license['title'] = $response['title'];
298
- $license['source_id'] = $response['source_identifier'];
299
- $license['recurring'] = $response['recurring'];
300
- } else {
301
- $license['status'] = 'deactivate';
302
- $license['expiry_days'] = 0;
303
- }
304
-
305
- update_option( $this->option_key, $license, false );
306
- }
307
- }
308
-
309
- /**
310
- * Check this is a valid license
311
- */
312
- public function is_valid() {
313
- if ( null !== $this->is_valid_licnese ) {
314
- return $this->is_valid_licnese;
315
- }
316
-
317
- $license = get_option( $this->option_key, null );
318
- if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) {
319
- $this->is_valid_licnese = true;
320
- } else {
321
- $this->is_valid_licnese = false;
322
- }
323
-
324
- return $this->is_valid_licnese;
325
- }
326
-
327
- /**
328
- * Check this is a valid license
329
- */
330
- public function is_valid_by( $option, $value ) {
331
- $license = get_option( $this->option_key, null );
332
-
333
- if ( ! empty( $license['key'] ) && isset( $license['status'] ) && $license['status'] == 'activate' ) {
334
- if ( isset( $license[ $option ] ) && $license[ $option ] == $value ) {
335
- return true;
336
- }
337
- }
338
-
339
- return false;
340
- }
341
-
342
- /**
343
- * Styles for licenses page
344
- */
345
- private function licenses_style() {
346
- ?>
347
- <style type="text/css">
348
- .appsero-license-section {
349
- width: 100%;
350
- max-width: 1100px;
351
- min-height: 1px;
352
- box-sizing: border-box;
353
- }
354
- .appsero-license-settings {
355
- background-color: #fff;
356
- box-shadow: 0px 3px 10px rgba(16, 16, 16, 0.05);
357
- }
358
- .appsero-license-settings * {
359
- box-sizing: border-box;
360
- }
361
- .appsero-license-title {
362
- background-color: #F8FAFB;
363
- border-bottom: 2px solid #EAEAEA;
364
- display: flex;
365
- align-items: center;
366
- padding: 10px 20px;
367
- }
368
- .appsero-license-title svg {
369
- width: 30px;
370
- height: 30px;
371
- fill: #0082BF;
372
- }
373
- .appsero-license-title span {
374
- font-size: 17px;
375
- color: #444444;
376
- margin-left: 10px;
377
- }
378
- .appsero-license-details {
379
- padding: 20px;
380
- }
381
- .appsero-license-details p {
382
- font-size: 15px;
383
- margin: 0 0 20px 0;
384
- }
385
- .license-input-key {
386
- position: relative;
387
- flex: 0 0 72%;
388
- max-width: 72%;
389
- }
390
- .license-input-key input {
391
- background-color: #F9F9F9;
392
- padding: 10px 15px 10px 48px;
393
- border: 1px solid #E8E5E5;
394
- border-radius: 3px;
395
- height: 45px;
396
- font-size: 16px;
397
- color: #71777D;
398
- width: 100%;
399
- box-shadow: 0 0 0 transparent;
400
- }
401
- .license-input-key input:focus {
402
- outline: 0 none;
403
- border: 1px solid #E8E5E5;
404
- box-shadow: 0 0 0 transparent;
405
- }
406
- .license-input-key svg {
407
- width: 22px;
408
- height: 22px;
409
- fill: #0082BF;
410
- position: absolute;
411
- left: 14px;
412
- top: 13px;
413
- }
414
- .license-input-fields {
415
- display: flex;
416
- justify-content: space-between;
417
- margin-bottom: 30px;
418
- max-width: 850px;
419
- width: 100%;
420
- }
421
- .license-input-fields button {
422
- color: #fff;
423
- font-size: 17px;
424
- padding: 8px;
425
- height: 46px;
426
- background-color: #0082BF;
427
- border-radius: 3px;
428
- cursor: pointer;
429
- flex: 0 0 25%;
430
- max-width: 25%;
431
- border: 1px solid #0082BF;
432
- }
433
- .license-input-fields button.deactive-button {
434
- background-color: #E40055;
435
- border-color: #E40055;
436
- }
437
- .license-input-fields button:focus {
438
- outline: 0 none;
439
- }
440
- .active-license-info {
441
- display: flex;
442
- }
443
- .single-license-info {
444
- min-width: 220px;
445
- flex: 0 0 30%;
446
- }
447
- .single-license-info h3 {
448
- font-size: 18px;
449
- margin: 0 0 12px 0;
450
- }
451
- .single-license-info p {
452
- margin: 0;
453
- color: #00C000;
454
- }
455
- .single-license-info p.occupied {
456
- color: #E40055;
457
- }
458
- </style>
459
- <?php
460
- }
461
-
462
- /**
463
- * Show active license information
464
- */
465
- private function show_active_license_info( $license ) {
466
- ?>
467
- <div class="active-license-info">
468
- <div class="single-license-info">
469
- <h3>Activation Remaining</h3>
470
- <?php if ( empty( $license['activation_limit'] ) ): ?>
471
- <p>Unlimited</p>
472
- <?php else: ?>
473
- <p class="<?php echo $license['remaining'] ? '' : 'occupied'; ?>">
474
- <?php echo $license['remaining']; ?> out of <?php echo $license['activation_limit']; ?>
475
- </p>
476
- <?php endif; ?>
477
- </div>
478
- <div class="single-license-info">
479
- <h3>Expires in</h3>
480
- <?php
481
- if ( $license['recurring'] && false !== $license['expiry_days'] ) {
482
- $occupied = $license['expiry_days'] > 10 ? '' : 'occupied';
483
- echo '<p class="' . $occupied . '">' . $license['expiry_days'] . ' days</p>';
484
- } else {
485
- echo '<p>Never</p>';
486
- }
487
- ?>
488
- </div>
489
- </div>
490
- <?php
491
- }
492
-
493
- /**
494
- * Show license settings page notices
495
- */
496
- private function show_license_page_notices() {
497
- if ( ! empty( $this->error ) ) :
498
- ?>
499
- <div class="notice notice-error is-dismissible appsero-license-section">
500
- <p><?php echo $this->error; ?></p>
501
- </div>
502
- <?php
503
- endif;
504
- if ( ! empty( $this->success ) ) :
505
- ?>
506
- <div class="notice notice-success is-dismissible appsero-license-section">
507
- <p><?php echo $this->success; ?></p>
508
- </div>
509
- <?php
510
- endif;
511
- echo '<br />';
512
- }
513
-
514
- /**
515
- * Card header
516
- */
517
- private function show_license_page_card_header() {
518
- ?>
519
- <div class="appsero-license-title">
520
- <svg enable-background="new 0 0 299.995 299.995" version="1.1" viewBox="0 0 300 300" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
521
- <path d="m150 161.48c-8.613 0-15.598 6.982-15.598 15.598 0 5.776 3.149 10.807 7.817 13.505v17.341h15.562v-17.341c4.668-2.697 7.817-7.729 7.817-13.505 0-8.616-6.984-15.598-15.598-15.598z"/>
522
- <path d="m150 85.849c-13.111 0-23.775 10.665-23.775 23.775v25.319h47.548v-25.319c-1e-3 -13.108-10.665-23.775-23.773-23.775z"/>
523
- <path d="m150 1e-3c-82.839 0-150 67.158-150 150 0 82.837 67.156 150 150 150s150-67.161 150-150c0-82.839-67.161-150-150-150zm46.09 227.12h-92.173c-9.734 0-17.626-7.892-17.626-17.629v-56.919c0-8.491 6.007-15.582 14.003-17.25v-25.697c0-27.409 22.3-49.711 49.711-49.711 27.409 0 49.709 22.3 49.709 49.711v25.697c7.993 1.673 14 8.759 14 17.25v56.919h2e-3c0 9.736-7.892 17.629-17.626 17.629z"/>
524
- </svg>
525
- <span>Activate License</span>
526
- </div>
527
- <?php
528
- }
529
-
530
- /**
531
- * Active client license
532
- */
533
- private function active_client_license( $form ) {
534
- if ( empty( $form['license_key'] ) ) {
535
- $this->error = 'The license key field is required.';
536
- return;
537
- }
538
-
539
- $license_key = sanitize_text_field( $form['license_key'] );
540
- $response = $this->activate( $license_key );
541
-
542
- if ( ! $response['success'] ) {
543
- $this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.';
544
- return;
545
- }
546
-
547
- $data = array(
548
- 'key' => $license_key,
549
- 'status' => 'activate',
550
- 'remaining' => $response['remaining'],
551
- 'activation_limit' => $response['activation_limit'],
552
- 'expiry_days' => $response['expiry_days'],
553
- 'title' => $response['title'],
554
- 'source_id' => $response['source_identifier'],
555
- 'recurring' => $response['recurring'],
556
- );
557
-
558
- update_option( $this->option_key, $data, false );
559
-
560
- $this->success = 'License activated successfully.';
561
- }
562
-
563
- /**
564
- * Deactive client license
565
- */
566
- private function deactive_client_license( $form ) {
567
- $license = get_option( $this->option_key, null );
568
-
569
- if ( empty( $license['key'] ) ) {
570
- $this->error = 'License key not found.';
571
- return;
572
- }
573
-
574
- $response = $this->deactivate( $license['key'] );
575
-
576
- $data = array(
577
- 'key' => '',
578
- 'status' => 'deactivate',
579
- );
580
-
581
- update_option( $this->option_key, $data, false );
582
-
583
- if ( ! $response['success'] ) {
584
- $this->error = $response['error'] ? $response['error'] : 'Unknown error occurred.';
585
- return;
586
- }
587
-
588
- $this->success = 'License deactivated successfully.';
589
- }
590
-
591
- /**
592
- * Add license menu page
593
- */
594
- private function add_menu_page() {
595
- add_menu_page(
596
- $this->menu_args['page_title'],
597
- $this->menu_args['menu_title'],
598
- $this->menu_args['capability'],
599
- $this->menu_args['menu_slug'],
600
- array( $this, 'menu_output' ),
601
- $this->menu_args['icon_url'],
602
- $this->menu_args['position']
603
- );
604
- }
605
-
606
- /**
607
- * Add submenu page
608
- */
609
- private function add_submenu_page() {
610
- add_submenu_page(
611
- $this->menu_args['parent_slug'],
612
- $this->menu_args['page_title'],
613
- $this->menu_args['menu_title'],
614
- $this->menu_args['capability'],
615
- $this->menu_args['menu_slug'],
616
- array( $this, 'menu_output' ),
617
- $this->menu_args['position']
618
- );
619
- }
620
-
621
- /**
622
- * Add submenu page
623
- */
624
- private function add_options_page() {
625
- add_options_page(
626
- $this->menu_args['page_title'],
627
- $this->menu_args['menu_title'],
628
- $this->menu_args['capability'],
629
- $this->menu_args['menu_slug'],
630
- array( $this, 'menu_output' ),
631
- $this->menu_args['position']
632
- );
633
- }
634
-
635
- /**
636
- * Schedule daily sicense checker event
637
- */
638
- public function schedule_cron_event() {
639
- if ( ! wp_next_scheduled( $this->schedule_hook ) ) {
640
- wp_schedule_event( time(), 'daily', $this->schedule_hook );
641
-
642
- wp_schedule_single_event( time() + 20, $this->schedule_hook );
643
- }
644
- }
645
-
646
- /**
647
- * Clear any scheduled hook
648
- */
649
- public function clear_scheduler() {
650
- wp_clear_scheduled_hook( $this->schedule_hook );
651
- }
652
-
653
- /**
654
- * Enable/Disable schedule
655
- */
656
- private function run_schedule() {
657
- switch ( $this->client->type ) {
658
- case 'plugin':
659
- register_activation_hook( $this->client->file, array( $this, 'schedule_cron_event' ) );
660
- register_deactivation_hook( $this->client->file, array( $this, 'clear_scheduler' ) );
661
- break;
662
-
663
- case 'theme':
664
- add_action( 'after_switch_theme', array( $this, 'schedule_cron_event' ) );
665
- add_action( 'switch_theme', array( $this, 'clear_scheduler' ) );
666
- break;
667
- }
668
- }
669
-
670
- /**
671
- * Form action URL
672
- */
673
- private function formActionUrl() {
674
- echo add_query_arg(
675
- array( 'page' => $_GET['page'] ),
676
- admin_url( basename( $_SERVER['SCRIPT_NAME'] ) )
677
- );
678
- }
679
-
680
- /**
681
- * Get input license key
682
- * @param $action
683
- * @return $license
684
- */
685
- private function get_input_license_value( $action, $license ) {
686
- if ( 'active' == $action ) {
687
- return isset( $license['key'] ) ? $license['key'] : '';
688
- }
689
-
690
- if ( 'deactive' == $action ) {
691
- $key_length = strlen( $license['key'] );
692
-
693
- return str_pad(
694
- substr( $license['key'], 0, $key_length / 2 ), $key_length, '*'
695
- );
696
- }
697
-
698
- return '';
699
- }
700
-
701
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
appsero/src/Updater.php DELETED
@@ -1,247 +0,0 @@
1
- <?php
2
- namespace Appsero;
3
-
4
- /**
5
- * Appsero Updater
6
- *
7
- * This class will show new updates project
8
- */
9
- class Updater {
10
-
11
- /**
12
- * Appsero\Client
13
- *
14
- * @var object
15
- */
16
- protected $client;
17
-
18
- /**
19
- * Initialize the class
20
- *
21
- * @param Appsero\Client
22
- */
23
- public function __construct( Client $client ) {
24
-
25
- $this->client = $client;
26
- $this->cache_key = 'appsero_' . md5( $this->client->slug ) . '_version_info';
27
-
28
- // Run hooks.
29
- if ( $this->client->type == 'plugin' ) {
30
- $this->run_plugin_hooks();
31
- } elseif ( $this->client->type == 'theme' ) {
32
- $this->run_theme_hooks();
33
- }
34
- }
35
-
36
- /**
37
- * Set up WordPress filter to hooks to get update.
38
- *
39
- * @return void
40
- */
41
- public function run_plugin_hooks() {
42
- add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'check_plugin_update' ) );
43
- add_filter( 'plugins_api', array( $this, 'plugins_api_filter' ), 10, 3 );
44
- }
45
-
46
- /**
47
- * Set up WordPress filter to hooks to get update.
48
- *
49
- * @return void
50
- */
51
- public function run_theme_hooks() {
52
- add_filter( 'pre_set_site_transient_update_themes', array( $this, 'check_theme_update' ) );
53
- }
54
-
55
- /**
56
- * Check for Update for this specific project
57
- */
58
- public function check_plugin_update( $transient_data ) {
59
- global $pagenow;
60
-
61
- if ( ! is_object( $transient_data ) ) {
62
- $transient_data = new \stdClass;
63
- }
64
-
65
- if ( 'plugins.php' == $pagenow && is_multisite() ) {
66
- return $transient_data;
67
- }
68
-
69
- if ( ! empty( $transient_data->response ) && ! empty( $transient_data->response[ $this->client->basename ] ) ) {
70
- return $transient_data;
71
- }
72
-
73
- $version_info = $this->get_cached_version_info();
74
-
75
- if ( false === $version_info ) {
76
- $version_info = $this->get_project_latest_version();
77
- $this->set_cached_version_info( $version_info );
78
- }
79
-
80
- if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
81
-
82
- if ( version_compare( $this->client->project_version, $version_info->new_version, '<' ) ) {
83
- unset( $version_info->sections );
84
- $transient_data->response[ $this->client->basename ] = $version_info;
85
- }
86
-
87
- $transient_data->last_checked = time();
88
- $transient_data->checked[ $this->client->basename ] = $this->client->project_version;
89
- }
90
-
91
- return $transient_data;
92
- }
93
-
94
- /**
95
- * Get version info from database
96
- *
97
- * @return Object or Boolean
98
- */
99
- private function get_cached_version_info() {
100
-
101
- $value = get_transient( $this->cache_key );
102
-
103
- if( ! $value && ! isset( $value->name ) ) {
104
- return false; // Cache is expired
105
- }
106
-
107
- // We need to turn the icons into an array
108
- if ( isset( $value->icons ) ) {
109
- $value->icons = (array) $value->icons;
110
- }
111
-
112
- // We need to turn the banners into an array
113
- if ( isset( $value->banners ) ) {
114
- $value->banners = (array) $value->banners;
115
- }
116
-
117
- if ( isset( $value->sections ) ) {
118
- $value->sections = (array) $value->sections;
119
- }
120
-
121
- return $value;
122
- }
123
-
124
- /**
125
- * Set version info to database
126
- */
127
- private function set_cached_version_info( $value ) {
128
- if ( ! $value ) {
129
- return;
130
- }
131
-
132
- set_transient( $this->cache_key, $value, 3 * HOUR_IN_SECONDS );
133
- }
134
-
135
- /**
136
- * Get plugin info from Appsero
137
- */
138
- private function get_project_latest_version() {
139
-
140
- $license_option_key = 'appsero_' . md5( $this->client->slug ) . '_manage_license';
141
- $license = get_option( $license_option_key, null );
142
-
143
- $params = array(
144
- 'version' => $this->client->project_version,
145
- 'name' => $this->client->name,
146
- 'slug' => $this->client->slug,
147
- 'basename' => $this->client->basename,
148
- 'license_key' => ! empty( $license ) && isset( $license['key'] ) ? $license['key'] : '',
149
- );
150
-
151
- $route = 'update/' . $this->client->hash . '/check';
152
-
153
- $response = $this->client->send_request( $params, $route, true );
154
-
155
- if ( is_wp_error( $response ) ) {
156
- return false;
157
- }
158
-
159
- $response = json_decode( wp_remote_retrieve_body( $response ) );
160
-
161
- if ( ! isset( $response->slug ) ) {
162
- return false;
163
- }
164
-
165
- if ( isset( $response->icons ) ) {
166
- $response->icons = (array) $response->icons;
167
- }
168
-
169
- if ( isset( $response->banners ) ) {
170
- $response->banners = (array) $response->banners;
171
- }
172
-
173
- if ( isset( $response->sections ) ) {
174
- $response->sections = (array) $response->sections;
175
- }
176
-
177
- return $response;
178
- }
179
-
180
- /**
181
- * Updates information on the "View version x.x details" page with custom data.
182
- *
183
- * @param mixed $data
184
- * @param string $action
185
- * @param object $args
186
- *
187
- * @return object $data
188
- */
189
- public function plugins_api_filter( $data, $action = '', $args = null ) {
190
-
191
- if ( $action != 'plugin_information' ) {
192
- return $data;
193
- }
194
-
195
- if ( ! isset( $args->slug ) || ( $args->slug != $this->client->slug ) ) {
196
- return $data;
197
- }
198
-
199
- $version_info = $this->get_cached_version_info();
200
-
201
- if ( false === $version_info ) {
202
- $version_info = $this->get_project_latest_version();
203
- $this->set_cached_version_info( $version_info );
204
- }
205
-
206
- return $version_info;
207
- }
208
-
209
- /**
210
- * Check theme upate
211
- */
212
- public function check_theme_update( $transient_data ) {
213
- global $pagenow;
214
-
215
- if ( ! is_object( $transient_data ) ) {
216
- $transient_data = new \stdClass;
217
- }
218
-
219
- if ( 'themes.php' == $pagenow && is_multisite() ) {
220
- return $transient_data;
221
- }
222
-
223
- if ( ! empty( $transient_data->response ) && ! empty( $transient_data->response[ $this->client->slug ] ) ) {
224
- return $transient_data;
225
- }
226
-
227
- $version_info = $this->get_cached_version_info();
228
-
229
- if ( false === $version_info ) {
230
- $version_info = $this->get_project_latest_version();
231
- $this->set_cached_version_info( $version_info );
232
- }
233
-
234
- if ( false !== $version_info && is_object( $version_info ) && isset( $version_info->new_version ) ) {
235
-
236
- if ( version_compare( $this->client->project_version, $version_info->new_version, '<' ) ) {
237
- $transient_data->response[ $this->client->slug ] = (array) $version_info;
238
- }
239
-
240
- $transient_data->last_checked = time();
241
- $transient_data->checked[ $this->client->slug ] = $this->client->project_version;
242
- }
243
-
244
- return $transient_data;
245
- }
246
-
247
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/css/frontend.css CHANGED
@@ -4,7 +4,7 @@
4
  }
5
 
6
  .tawcvs-swatches {
7
- overflow: hidden;
8
  padding: 5px;
9
  }
10
 
@@ -26,7 +26,6 @@
26
  cursor: pointer;
27
  border: 1px solid transparent;
28
  position: relative;
29
- opacity: 0.5;
30
  }
31
 
32
  .tawcvs-swatches .swatch.selected {
@@ -34,7 +33,6 @@
34
  -moz-box-shadow: 0 0 5px;
35
  box-shadow: 0 0 5px;
36
  border-color: #999;
37
- opacity: 1;
38
  }
39
 
40
  .tawcvs-swatches .swatch.disabled {
@@ -42,9 +40,8 @@
42
  }
43
 
44
  .tawcvs-swatches .swatch-color {
45
- text-indent: -9999px;
46
  border: 2px solid #ccc;
47
- position: relative;
48
  }
49
 
50
  .tawcvs-swatches .swatch-color.selected {
@@ -52,9 +49,9 @@
52
  }
53
 
54
  .tawcvs-swatches .swatch-color.selected:before {
55
- -webkit-transform: rotate(45deg);
56
- -moz-transform: rotate(45deg);
57
- transform: rotate(45deg);
58
  content: "";
59
  width: 6px;
60
  height: 10px;
@@ -62,8 +59,9 @@
62
  border: solid #eee;
63
  border-width: 0 2px 2px 0;
64
  position: absolute;
65
- top: 8px;
66
- left: 11px;
 
67
  }
68
 
69
  .tawcvs-swatches .swatch-label {
@@ -74,56 +72,49 @@
74
  overflow: hidden;
75
  }
76
 
77
-
78
- /*--------*/
79
- .tawcvs-swatches .swatch{
80
- opacity: 1;
81
- }
82
- .tawcvs-swatches .swatch-color {
83
- position: relative;
84
- }
85
- .tawcvs-swatches .cv-tooltip {
86
- position: absolute;
87
- background: #444;
88
- z-index: 2;
89
- width: 110px;
90
- bottom: 43px;
91
- color: #fff;
92
- margin: 0;
93
- left: 50%;
94
- transform: translateX(-50%);
95
- text-indent: initial;
96
- font-size: 14px;
97
- font-weight: 500;
98
- padding: 5px 5px;
99
- border-radius: 3px;
100
- opacity: 0;
101
- visibility: hidden;
102
- transition: all 0.3s ease;
103
- }
104
- .tawcvs-swatches .cv-tooltip:after {
105
- content: "";
106
- position: absolute;
107
- width: 12px;
108
- height: 12px;
109
- background: #444;
110
- bottom: -4px;
111
- left: 50%;
112
- margin-left: -6px;
113
- transform: rotate(45deg);
114
  }
115
- .swatch:hover .cv-tooltip {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  opacity: 1;
117
  visibility: visible;
118
- }
119
- .tawcvs-swatches,
120
- .variations{
121
- overflow: visible;
122
- }
123
-
124
- .tawcvs-swatches .swatch-image {
125
- overflow: visible;
126
- }
127
- .tawcvs-swatches .swatch-image img {
128
- border-radius: 100%;
129
- }
4
  }
5
 
6
  .tawcvs-swatches {
7
+ /*overflow: hidden;*/
8
  padding: 5px;
9
  }
10
 
26
  cursor: pointer;
27
  border: 1px solid transparent;
28
  position: relative;
 
29
  }
30
 
31
  .tawcvs-swatches .swatch.selected {
33
  -moz-box-shadow: 0 0 5px;
34
  box-shadow: 0 0 5px;
35
  border-color: #999;
 
36
  }
37
 
38
  .tawcvs-swatches .swatch.disabled {
40
  }
41
 
42
  .tawcvs-swatches .swatch-color {
43
+ text-indent: -9999em;
44
  border: 2px solid #ccc;
 
45
  }
46
 
47
  .tawcvs-swatches .swatch-color.selected {
49
  }
50
 
51
  .tawcvs-swatches .swatch-color.selected:before {
52
+ -webkit-transform: translate(-50%, -50%) rotate(45deg);
53
+ -moz-transform: translate(-50%, -50%) rotate(45deg);
54
+ transform: translate(-50%, -50%) rotate(45deg);
55
  content: "";
56
  width: 6px;
57
  height: 10px;
59
  border: solid #eee;
60
  border-width: 0 2px 2px 0;
61
  position: absolute;
62
+ top: 50%;
63
+ left: 50%;
64
+ margin: -2px -2px 0 0;
65
  }
66
 
67
  .tawcvs-swatches .swatch-label {
72
  overflow: hidden;
73
  }
74
 
75
+ .tawcvs-swatches .swatch__tooltip {
76
+ -webkit-transform: translate(-50%, -100%);
77
+ -moz-transform: translate(-50%, -100%);
78
+ transform: translate(-50%, -100%);
79
+ -webkit-transition: all 0.3s;
80
+ -moz-transition: all 0.3s;
81
+ -ms-transition: all 0.3s;
82
+ -o-transition: all 0.3s;
83
+ transition: all 0.3s;
84
+ -webkit-border-radius: 3px;
85
+ -moz-border-radius: 3px;
86
+ border-radius: 3px;
87
+ position: absolute;
88
+ left: 50%;
89
+ top: 0;
90
+ background: #333;
91
+ z-index: 2;
92
+ color: #fff;
93
+ margin: -15px 0 0 0;
94
+ padding: 5px 10px;
95
+ text-indent: initial;
96
+ font-size: 14px;
97
+ font-weight: 500;
98
+ opacity: 0;
99
+ visibility: hidden;
100
+ user-select: none;
 
 
 
 
 
 
 
 
 
 
 
101
  }
102
+
103
+ .tawcvs-swatches .swatch__tooltip:after {
104
+ -webkit-transform: rotate(45deg);
105
+ -moz-transform: rotate(45deg);
106
+ transform: rotate(45deg);
107
+ content: "";
108
+ position: absolute;
109
+ width: 12px;
110
+ height: 12px;
111
+ background: #333;
112
+ bottom: -4px;
113
+ left: 50%;
114
+ margin-left: -6px;
115
+ }
116
+ .tawcvs-swatches .swatch:hover .swatch__tooltip {
117
  opacity: 1;
118
  visibility: visible;
119
+ user-select: auto;
120
+ }
 
 
 
 
 
 
 
 
 
 
includes/class-admin-product.php CHANGED
@@ -1,184 +1,184 @@
1
- <?php
2
-
3
- /**
4
- * Class TA_WC_Variation_Swatches_Admin_Product
5
- */
6
- class TA_WC_Variation_Swatches_Admin_Product {
7
- /**
8
- * Class constructor.
9
- */
10
- public function __construct() {
11
- add_action( 'woocommerce_product_option_terms', array( $this, 'product_option_terms' ), 10, 2 );
12
-
13
- add_action( 'wp_ajax_tawcvs_add_new_attribute', array( $this, 'add_new_attribute_ajax' ) );
14
- add_action( 'admin_footer', array( $this, 'add_attribute_term_template' ) );
15
- }
16
-
17
- /**
18
- * Add selector for extra attribute types
19
- *
20
- * @param $taxonomy
21
- * @param $index
22
- */
23
- public function product_option_terms( $taxonomy, $index ) {
24
- if ( ! array_key_exists( $taxonomy->attribute_type, TA_WCVS()->types ) ) {
25
- return;
26
- }
27
-
28
- $taxonomy_name = wc_attribute_taxonomy_name( $taxonomy->attribute_name );
29
- global $thepostid;
30
-
31
- $product_id = isset( $_POST['post_id'] ) ? absint( sanitize_text_field($_POST['post_id']) ) : $thepostid;
32
- ?>
33
-
34
- <select multiple="multiple" data-placeholder="<?php esc_attr_e( 'Select terms', 'wcvs' ); ?>" class="multiselect attribute_values wc-enhanced-select" name="attribute_values[<?php echo $index; ?>][]">
35
- <?php
36
-
37
- $all_terms = get_terms( $taxonomy_name, apply_filters( 'woocommerce_product_attribute_terms', array( 'orderby' => 'name', 'hide_empty' => false ) ) );
38
- if ( $all_terms ) {
39
- foreach ( $all_terms as $term ) {
40
- echo '<option value="' . esc_attr( $term->term_id ) . '" ' . selected( has_term( absint( $term->term_id ), $taxonomy_name, $product_id ), true, false ) . '>' . esc_attr( apply_filters( 'woocommerce_product_attribute_term_name', $term->name, $term ) ) . '</option>';
41
- }
42
- }
43
- ?>
44
- </select>
45
- <button class="button plus select_all_attributes"><?php esc_html_e( 'Select all', 'wcvs' ); ?></button>
46
- <button class="button minus select_no_attributes"><?php esc_html_e( 'Select none', 'wcvs' ); ?></button>
47
- <button class="button fr plus tawcvs_add_new_attribute" data-type="<?php echo $taxonomy->attribute_type ?>"><?php esc_html_e( 'Add new', 'wcvs' ); ?></button>
48
-
49
- <?php
50
- }
51
-
52
- /**
53
- * Ajax function handles adding new attribute term
54
- */
55
- public function add_new_attribute_ajax() {
56
- $nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : '';
57
- $tax = isset( $_POST['taxonomy'] ) ? sanitize_text_field($_POST['taxonomy']) : '';
58
- $type = isset( $_POST['type'] ) ? sanitize_text_field($_POST['type']) : '';
59
- $name = isset( $_POST['name'] ) ? sanitize_text_field($_POST['name']) : '';
60
- $slug = isset( $_POST['slug'] ) ? sanitize_text_field($_POST['slug']) : '';
61
- $swatch = isset( $_POST['swatch'] ) ? sanitize_text_field($_POST['swatch']) : '';
62
-
63
- if ( ! wp_verify_nonce( $nonce, '_tawcvs_create_attribute' ) ) {
64
- wp_send_json_error( esc_html__( 'Wrong request', 'wcvs' ) );
65
- }
66
-
67
- if ( empty( $name ) || empty( $swatch ) || empty( $tax ) || empty( $type ) ) {
68
- wp_send_json_error( esc_html__( 'Not enough data', 'wcvs' ) );
69
- }
70
-
71
- if ( ! taxonomy_exists( $tax ) ) {
72
- wp_send_json_error( esc_html__( 'Taxonomy is not exists', 'wcvs' ) );
73
- }
74
-
75
- if ( term_exists( sanitize_text_field($_POST['name']), sanitize_text_field($_POST['tax']) ) ) {
76
- wp_send_json_error( esc_html__( 'This term is exists', 'wcvs' ) );
77
- }
78
-
79
- $term = wp_insert_term( $name, $tax, array( 'slug' => $slug ) );
80
-
81
- if ( is_wp_error( $term ) ) {
82
- wp_send_json_error( $term->get_error_message() );
83
- } else {
84
- $term = get_term_by( 'id', $term['term_id'], $tax );
85
- update_term_meta( $term->term_id, $type, $swatch );
86
- }
87
-
88
- wp_send_json_success(
89
- array(
90
- 'msg' => esc_html__( 'Added successfully', 'wcvs' ),
91
- 'id' => $term->term_id,
92
- 'slug' => $term->slug,
93
- 'name' => $term->name,
94
- )
95
- );
96
- }
97
-
98
- /**
99
- * Print HTML of modal at admin footer and add js templates
100
- */
101
- public function add_attribute_term_template() {
102
- global $pagenow, $post;
103
-
104
- if ( $pagenow != 'post.php' || ( isset( $post ) && get_post_type( $post->ID ) != 'product' ) ) {
105
- return;
106
- }
107
- ?>
108
-
109
- <div id="tawcvs-modal-container" class="tawcvs-modal-container">
110
- <div class="tawcvs-modal">
111
- <button type="button" class="button-link media-modal-close tawcvs-modal-close">
112
- <span class="media-modal-icon"></span></button>
113
- <div class="tawcvs-modal-header"><h2><?php esc_html_e( 'Add new term', 'wcvs' ) ?></h2></div>
114
- <div class="tawcvs-modal-content">
115
- <p class="tawcvs-term-name">
116
- <label>
117
- <?php esc_html_e( 'Name', 'wcvs' ) ?>
118
- <input type="text" class="widefat tawcvs-input" name="name">
119
- </label>
120
- </p>
121
- <p class="tawcvs-term-slug">
122
- <label>
123
- <?php esc_html_e( 'Slug', 'wcvs' ) ?>
124
- <input type="text" class="widefat tawcvs-input" name="slug">
125
- </label>
126
- </p>
127
- <div class="tawcvs-term-swatch">
128
-
129
- </div>
130
- <div class="hidden tawcvs-term-tax"></div>
131
-
132
- <input type="hidden" class="tawcvs-input" name="nonce" value="<?php echo wp_create_nonce( '_tawcvs_create_attribute' ) ?>">
133
- </div>
134
- <div class="tawcvs-modal-footer">
135
- <button class="button button-secondary tawcvs-modal-close"><?php esc_html_e( 'Cancel', 'wcvs' ) ?></button>
136
- <button class="button button-primary tawcvs-new-attribute-submit"><?php esc_html_e( 'Add New', 'wcvs' ) ?></button>
137
- <span class="message"></span>
138
- <span class="spinner"></span>
139
- </div>
140
- </div>
141
- <div class="tawcvs-modal-backdrop media-modal-backdrop"></div>
142
- </div>
143
-
144
- <script type="text/template" id="tmpl-tawcvs-input-color">
145
-
146
- <label><?php esc_html_e( 'Color', 'wcvs' ) ?></label><br>
147
- <input type="text" class="tawcvs-input tawcvs-input-color" name="swatch">
148
-
149
- </script>
150
-
151
- <script type="text/template" id="tmpl-tawcvs-input-image">
152
-
153
- <label><?php esc_html_e( 'Image', 'wcvs' ) ?></label><br>
154
- <div class="tawcvs-term-image-thumbnail" style="float:left;margin-right:10px;">
155
- <img src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/placeholder.png' ) ?>" width="60px" height="60px" />
156
- </div>
157
- <div style="line-height:60px;">
158
- <input type="hidden" class="tawcvs-input tawcvs-input-image tawcvs-term-image" name="swatch" value="" />
159
- <button type="button" class="tawcvs-upload-image-button button"><?php esc_html_e( 'Upload/Add image', 'wcvs' ); ?></button>
160
- <button type="button" class="tawcvs-remove-image-button button hidden"><?php esc_html_e( 'Remove image', 'wcvs' ); ?></button>
161
- </div>
162
-
163
- </script>
164
-
165
- <script type="text/template" id="tmpl-tawcvs-input-label">
166
-
167
- <label>
168
- <?php esc_html_e( 'Label', 'wcvs' ) ?>
169
- <input type="text" class="widefat tawcvs-input tawcvs-input-label" name="swatch">
170
- </label>
171
-
172
- </script>
173
-
174
- <script type="text/template" id="tmpl-tawcvs-input-tax">
175
-
176
- <input type="hidden" class="tawcvs-input" name="taxonomy" value="{{data.tax}}">
177
- <input type="hidden" class="tawcvs-input" name="type" value="{{data.type}}">
178
-
179
- </script>
180
- <?php
181
- }
182
- }
183
-
184
- new TA_WC_Variation_Swatches_Admin_Product();
1
+ <?php
2
+
3
+ /**
4
+ * Class TA_WC_Variation_Swatches_Admin_Product
5
+ */
6
+ class TA_WC_Variation_Swatches_Admin_Product {
7
+ /**
8
+ * Class constructor.
9
+ */
10
+ public function __construct() {
11
+ add_action( 'woocommerce_product_option_terms', array( $this, 'product_option_terms' ), 10, 2 );
12
+
13
+ add_action( 'wp_ajax_tawcvs_add_new_attribute', array( $this, 'add_new_attribute_ajax' ) );
14
+ add_action( 'admin_footer', array( $this, 'add_attribute_term_template' ) );
15
+ }
16
+
17
+ /**
18
+ * Add selector for extra attribute types
19
+ *
20
+ * @param $taxonomy
21
+ * @param $index
22
+ */
23
+ public function product_option_terms( $taxonomy, $index ) {
24
+ if ( ! array_key_exists( $taxonomy->attribute_type, TA_WCVS()->types ) ) {
25
+ return;
26
+ }
27
+
28
+ $taxonomy_name = wc_attribute_taxonomy_name( $taxonomy->attribute_name );
29
+ global $thepostid;
30
+
31
+ $product_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : $thepostid;
32
+ ?>
33
+
34
+ <select multiple="multiple" data-placeholder="<?php esc_attr_e( 'Select terms', 'wcvs' ); ?>" class="multiselect attribute_values wc-enhanced-select" name="attribute_values[<?php echo $index; ?>][]">
35
+ <?php
36
+
37
+ $all_terms = get_terms( $taxonomy_name, apply_filters( 'woocommerce_product_attribute_terms', array( 'orderby' => 'name', 'hide_empty' => false ) ) );
38
+ if ( $all_terms ) {
39
+ foreach ( $all_terms as $term ) {
40
+ echo '<option value="' . esc_attr( $term->term_id ) . '" ' . selected( has_term( absint( $term->term_id ), $taxonomy_name, $product_id ), true, false ) . '>' . esc_attr( apply_filters( 'woocommerce_product_attribute_term_name', $term->name, $term ) ) . '</option>';
41
+ }
42
+ }
43
+ ?>
44
+ </select>
45
+ <button class="button plus select_all_attributes"><?php esc_html_e( 'Select all', 'wcvs' ); ?></button>
46
+ <button class="button minus select_no_attributes"><?php esc_html_e( 'Select none', 'wcvs' ); ?></button>
47
+ <button class="button fr plus tawcvs_add_new_attribute" data-type="<?php echo $taxonomy->attribute_type ?>"><?php esc_html_e( 'Add new', 'wcvs' ); ?></button>
48
+
49
+ <?php
50
+ }
51
+
52
+ /**
53
+ * Ajax function handles adding new attribute term
54
+ */
55
+ public function add_new_attribute_ajax() {
56
+ $nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : '';
57
+ $tax = isset( $_POST['taxonomy'] ) ? sanitize_text_field( $_POST['taxonomy'] ) : '';
58
+ $type = isset( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : '';
59
+ $name = isset( $_POST['name'] ) ? sanitize_text_field( $_POST['name'] ) : '';
60
+ $slug = isset( $_POST['slug'] ) ? sanitize_text_field( $_POST['slug'] ) : '';
61
+ $swatch = isset( $_POST['swatch'] ) ? sanitize_text_field( $_POST['swatch'] ) : '';
62
+
63
+ if ( ! wp_verify_nonce( $nonce, '_tawcvs_create_attribute' ) ) {
64
+ wp_send_json_error( esc_html__( 'Wrong request', 'wcvs' ) );
65
+ }
66
+
67
+ if ( empty( $name ) || empty( $swatch ) || empty( $tax ) || empty( $type ) ) {
68
+ wp_send_json_error( esc_html__( 'Not enough data', 'wcvs' ) );
69
+ }
70
+
71
+ if ( ! taxonomy_exists( $tax ) ) {
72
+ wp_send_json_error( esc_html__( 'Taxonomy is not exists', 'wcvs' ) );
73
+ }
74
+
75
+ if ( term_exists( $_POST['name'], $_POST['tax'] ) ) {
76
+ wp_send_json_error( esc_html__( 'This term is exists', 'wcvs' ) );
77
+ }
78
+
79
+ $term = wp_insert_term( $name, $tax, array( 'slug' => $slug ) );
80
+
81
+ if ( is_wp_error( $term ) ) {
82
+ wp_send_json_error( $term->get_error_message() );
83
+ } else {
84
+ $term = get_term_by( 'id', $term['term_id'], $tax );
85
+ update_term_meta( $term->term_id, $type, $swatch );
86
+ }
87
+
88
+ wp_send_json_success(
89
+ array(
90
+ 'msg' => esc_html__( 'Added successfully', 'wcvs' ),
91
+ 'id' => $term->term_id,
92
+ 'slug' => $term->slug,
93
+ 'name' => $term->name,
94
+ )
95
+ );
96
+ }
97
+
98
+ /**
99
+ * Print HTML of modal at admin footer and add js templates
100
+ */
101
+ public function add_attribute_term_template() {
102
+ global $pagenow, $post;
103
+
104
+ if ( $pagenow != 'post.php' || ( isset( $post ) && get_post_type( $post->ID ) != 'product' ) ) {
105
+ return;
106
+ }
107
+ ?>
108
+
109
+ <div id="tawcvs-modal-container" class="tawcvs-modal-container">
110
+ <div class="tawcvs-modal">
111
+ <button type="button" class="button-link media-modal-close tawcvs-modal-close">
112
+ <span class="media-modal-icon"></span></button>
113
+ <div class="tawcvs-modal-header"><h2><?php esc_html_e( 'Add new term', 'wcvs' ) ?></h2></div>
114
+ <div class="tawcvs-modal-content">
115
+ <p class="tawcvs-term-name">
116
+ <label>
117
+ <?php esc_html_e( 'Name', 'wcvs' ) ?>
118
+ <input type="text" class="widefat tawcvs-input" name="name">
119
+ </label>
120
+ </p>
121
+ <p class="tawcvs-term-slug">
122
+ <label>
123
+ <?php esc_html_e( 'Slug', 'wcvs' ) ?>
124
+ <input type="text" class="widefat tawcvs-input" name="slug">
125
+ </label>
126
+ </p>
127
+ <div class="tawcvs-term-swatch">
128
+
129
+ </div>
130
+ <div class="hidden tawcvs-term-tax"></div>
131
+
132
+ <input type="hidden" class="tawcvs-input" name="nonce" value="<?php echo wp_create_nonce( '_tawcvs_create_attribute' ) ?>">
133
+ </div>
134
+ <div class="tawcvs-modal-footer">
135
+ <button class="button button-secondary tawcvs-modal-close"><?php esc_html_e( 'Cancel', 'wcvs' ) ?></button>
136
+ <button class="button button-primary tawcvs-new-attribute-submit"><?php esc_html_e( 'Add New', 'wcvs' ) ?></button>
137
+ <span class="message"></span>
138
+ <span class="spinner"></span>
139
+ </div>
140
+ </div>
141
+ <div class="tawcvs-modal-backdrop media-modal-backdrop"></div>
142
+ </div>
143
+
144
+ <script type="text/template" id="tmpl-tawcvs-input-color">
145
+
146
+ <label><?php esc_html_e( 'Color', 'wcvs' ) ?></label><br>
147
+ <input type="text" class="tawcvs-input tawcvs-input-color" name="swatch">
148
+
149
+ </script>
150
+
151
+ <script type="text/template" id="tmpl-tawcvs-input-image">
152
+
153
+ <label><?php esc_html_e( 'Image', 'wcvs' ) ?></label><br>
154
+ <div class="tawcvs-term-image-thumbnail" style="float:left;margin-right:10px;">
155
+ <img src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/placeholder.png' ) ?>" width="60px" height="60px" />
156
+ </div>
157
+ <div style="line-height:60px;">
158
+ <input type="hidden" class="tawcvs-input tawcvs-input-image tawcvs-term-image" name="swatch" value="" />
159
+ <button type="button" class="tawcvs-upload-image-button button"><?php esc_html_e( 'Upload/Add image', 'wcvs' ); ?></button>
160
+ <button type="button" class="tawcvs-remove-image-button button hidden"><?php esc_html_e( 'Remove image', 'wcvs' ); ?></button>
161
+ </div>
162
+
163
+ </script>
164
+
165
+ <script type="text/template" id="tmpl-tawcvs-input-label">
166
+
167
+ <label>
168
+ <?php esc_html_e( 'Label', 'wcvs' ) ?>
169
+ <input type="text" class="widefat tawcvs-input tawcvs-input-label" name="swatch">
170
+ </label>
171
+
172
+ </script>
173
+
174
+ <script type="text/template" id="tmpl-tawcvs-input-tax">
175
+
176
+ <input type="hidden" class="tawcvs-input" name="taxonomy" value="{{data.tax}}">
177
+ <input type="hidden" class="tawcvs-input" name="type" value="{{data.type}}">
178
+
179
+ </script>
180
+ <?php
181
+ }
182
+ }
183
+
184
+ new TA_WC_Variation_Swatches_Admin_Product();
includes/class-admin.php CHANGED
@@ -32,6 +32,10 @@ class TA_WC_Variation_Swatches_Admin {
32
  add_action( 'admin_init', array( $this, 'init_attribute_hooks' ) );
33
  add_action( 'admin_print_scripts', array( $this, 'enqueue_scripts' ) );
34
 
 
 
 
 
35
  // Display attribute fields
36
  add_action( 'tawcvs_product_attribute_field', array( $this, 'attribute_fields' ), 10, 3 );
37
  }
@@ -94,6 +98,83 @@ class TA_WC_Variation_Swatches_Admin {
94
  );
95
  }
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  /**
98
  * Create hook to add fields to add attribute term screen
99
  *
@@ -114,6 +195,7 @@ class TA_WC_Variation_Swatches_Admin {
114
  public function edit_attribute_fields( $term, $taxonomy ) {
115
  $attr = TA_WCVS()->get_tax_attribute( $taxonomy );
116
  $value = get_term_meta( $term->term_id, $attr->attribute_type, true );
 
117
  do_action( 'tawcvs_product_attribute_field', $attr->attribute_type, $value, 'edit' );
118
  }
119
 
@@ -174,10 +256,9 @@ class TA_WC_Variation_Swatches_Admin {
174
  * @param int $tt_id
175
  */
176
  public function save_term_meta( $term_id, $tt_id ) {
177
-
178
  foreach ( TA_WCVS()->types as $type => $label ) {
179
  if ( isset( $_POST[$type] ) ) {
180
- update_term_meta( $term_id, $type, sanitize_text_field($_POST[$type]) );
181
  }
182
  }
183
  }
32
  add_action( 'admin_init', array( $this, 'init_attribute_hooks' ) );
33
  add_action( 'admin_print_scripts', array( $this, 'enqueue_scripts' ) );
34
 
35
+ // Restore attributes
36
+ add_action( 'admin_notices', array( $this, 'restore_attributes_notice' ) );
37
+ add_action( 'admin_init', array( $this, 'restore_attribute_types' ) );
38
+
39
  // Display attribute fields
40
  add_action( 'tawcvs_product_attribute_field', array( $this, 'attribute_fields' ), 10, 3 );
41
  }
98
  );
99
  }
100
 
101
+ /**
102
+ * Display a notice of restoring attribute types
103
+ */
104
+ public function restore_attributes_notice() {
105
+ if ( get_transient( 'tawcvs_attribute_taxonomies' ) && ! get_option( 'tawcvs_restore_attributes_time' ) ) {
106
+ ?>
107
+ <div class="notice-warning notice is-dismissible">
108
+ <p>
109
+ <?php
110
+ esc_html_e( 'Found a backup of product attributes types. This backup was generated at', 'wcvs' );
111
+ echo ' ' . date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), get_option( 'tawcvs_backup_attributes_time' ) ) . '.';
112
+ ?>
113
+ </p>
114
+ <p>
115
+ <a href="<?php echo esc_url( add_query_arg( array( 'tawcvs_action' => 'restore_attributes_types', 'tawcvs_nonce' => wp_create_nonce( 'restore_attributes_types' ) ) ) ); ?>">
116
+ <strong><?php esc_html_e( 'Restore product attributes types', 'wcvs' ); ?></strong>
117
+ </a>
118
+ |
119
+ <a href="<?php echo esc_url( add_query_arg( array( 'tawcvs_action' => 'dismiss_restore_notice', 'tawcvs_nonce' => wp_create_nonce( 'dismiss_restore_notice' ) ) ) ); ?>">
120
+ <strong><?php esc_html_e( 'Dismiss this notice', 'wcvs' ); ?></strong>
121
+ </a>
122
+ </p>
123
+ </div>
124
+ <?php
125
+ } elseif ( isset( $_GET['tawcvs_message'] ) && 'restored' == $_GET['tawcvs_message'] ) {
126
+ ?>
127
+ <div class="notice-warning settings-error notice is-dismissible">
128
+ <p><?php esc_html_e( 'All attributes types have been restored.', 'wcvs' ) ?></p>
129
+ </div>
130
+ <?php
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Restore attribute types
136
+ */
137
+ public function restore_attribute_types() {
138
+ if ( ! isset( $_GET['tawcvs_action'] ) || ! isset( $_GET['tawcvs_nonce'] ) ) {
139
+ return;
140
+ }
141
+
142
+ if ( ! wp_verify_nonce( $_GET['tawcvs_nonce'], $_GET['tawcvs_action'] ) ) {
143
+ return;
144
+ }
145
+
146
+ if ( 'restore_attributes_types' == $_GET['tawcvs_action'] ) {
147
+ global $wpdb;
148
+
149
+ $attribute_taxnomies = get_transient( 'tawcvs_attribute_taxonomies' );
150
+
151
+ foreach ( $attribute_taxnomies as $id => $attribute ) {
152
+ $wpdb->update(
153
+ $wpdb->prefix . 'woocommerce_attribute_taxonomies',
154
+ array( 'attribute_type' => $attribute->attribute_type ),
155
+ array( 'attribute_id' => $id ),
156
+ array( '%s' ),
157
+ array( '%d' )
158
+ );
159
+ }
160
+
161
+ update_option( 'tawcvs_restore_attributes_time', time() );
162
+ delete_transient( 'tawcvs_attribute_taxonomies' );
163
+ delete_transient( 'wc_attribute_taxonomies' );
164
+
165
+ $url = remove_query_arg( array( 'tawcvs_action', 'tawcvs_nonce' ) );
166
+ $url = add_query_arg( array( 'tawcvs_message' => 'restored' ), $url );
167
+ } elseif ( 'dismiss_restore_notice' == $_GET['tawcvs_action'] ) {
168
+ update_option( 'tawcvs_restore_attributes_time', 'ignored' );
169
+ $url = remove_query_arg( array( 'tawcvs_action', 'tawcvs_nonce' ) );
170
+ }
171
+
172
+ if ( isset( $url ) ) {
173
+ wp_redirect( $url );
174
+ exit;
175
+ }
176
+ }
177
+
178
  /**
179
  * Create hook to add fields to add attribute term screen
180
  *
195
  public function edit_attribute_fields( $term, $taxonomy ) {
196
  $attr = TA_WCVS()->get_tax_attribute( $taxonomy );
197
  $value = get_term_meta( $term->term_id, $attr->attribute_type, true );
198
+
199
  do_action( 'tawcvs_product_attribute_field', $attr->attribute_type, $value, 'edit' );
200
  }
201
 
256
  * @param int $tt_id
257
  */
258
  public function save_term_meta( $term_id, $tt_id ) {
 
259
  foreach ( TA_WCVS()->types as $type => $label ) {
260
  if ( isset( $_POST[$type] ) ) {
261
+ update_term_meta( $term_id, $type, sanitize_text_field( $_POST[$type] ) );
262
  }
263
  }
264
  }
includes/class-frontend.php CHANGED
@@ -38,7 +38,7 @@ class TA_WC_Variation_Swatches_Frontend {
38
  * Enqueue scripts and stylesheets
39
  */
40
  public function enqueue_scripts() {
41
- wp_enqueue_style( 'tawcvs-frontend', plugins_url( 'assets/css/frontend.css', dirname( __FILE__ ) ), array(), '20160615' );
42
  wp_enqueue_script( 'tawcvs-frontend', plugins_url( 'assets/js/frontend.js', dirname( __FILE__ ) ), array( 'jquery' ), '20160615', true );
43
  }
44
 
@@ -51,9 +51,9 @@ class TA_WC_Variation_Swatches_Frontend {
51
  * @return string
52
  */
53
  public function get_swatch_html( $html, $args ) {
54
-
55
  $swatch_types = TA_WCVS()->types;
56
  $attr = TA_WCVS()->get_tax_attribute( $args['attribute'] );
 
57
  // Return if this is normal attribute
58
  if ( empty( $attr ) ) {
59
  return $html;
@@ -69,6 +69,9 @@ class TA_WC_Variation_Swatches_Frontend {
69
  $class = "variation-selector variation-select-{$attr->attribute_type}";
70
  $swatches = '';
71
 
 
 
 
72
  if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
73
  $attributes = $product->get_variation_attributes();
74
  $options = $attributes[$attribute];
@@ -87,7 +90,7 @@ class TA_WC_Variation_Swatches_Frontend {
87
  }
88
 
89
  if ( ! empty( $swatches ) ) {
90
- $class .= ' hidden';
91
  $swatches = '<div class="tawcvs-swatches" data-attribute_name="attribute_' . esc_attr( $attribute ) . '">' . $swatches . '</div>';
92
  $html = '<div class="' . esc_attr( $class ) . '">' . $html . '</div>' . $swatches;
93
  }
@@ -109,12 +112,10 @@ class TA_WC_Variation_Swatches_Frontend {
109
  public function swatch_html( $html, $term, $type, $args ) {
110
  $selected = sanitize_title( $args['selected'] ) == $term->slug ? 'selected' : '';
111
  $name = esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) );
 
112
 
113
- if ($term->description) {
114
- $tooltip = $term->description;
115
- }
116
- else {
117
- $tooltip = $name;
118
  }
119
 
120
  switch ( $type ) {
@@ -122,15 +123,14 @@ class TA_WC_Variation_Swatches_Frontend {
122
  $color = get_term_meta( $term->term_id, 'color', true );
123
  list( $r, $g, $b ) = sscanf( $color, "#%02x%02x%02x" );
124
  $html = sprintf(
125
- '<span class="swatch swatch-color swatch-%s %s" style="background-color:%s;color:%s;" data-value="%s">%s<p class="cv-tooltip">%s</p></span>',
126
  esc_attr( $term->slug ),
127
  $selected,
128
  esc_attr( $color ),
129
  "rgba($r,$g,$b,0.5)",
130
- // esc_attr( $term->description ),
131
  esc_attr( $term->slug ),
132
  $name,
133
- esc_attr( $tooltip )
134
  );
135
  break;
136
 
@@ -139,15 +139,14 @@ class TA_WC_Variation_Swatches_Frontend {
139
  $image = $image ? wp_get_attachment_image_src( $image ) : '';
140
  $image = $image ? $image[0] : WC()->plugin_url() . '/assets/images/placeholder.png';
141
  $html = sprintf(
142
- '<span class="swatch swatch-image swatch-%s %s" data-value="%s"><img src="%s" alt="%s"><p class="cv-tooltip">%s</p></span>',
143
  esc_attr( $term->slug ),
144
  $selected,
145
- // esc_attr( $term->description ),
146
  esc_attr( $term->slug ),
147
  esc_url( $image ),
148
  esc_attr( $name ),
149
- // esc_attr( $name ),
150
- esc_attr( $tooltip )
151
  );
152
  break;
153
 
@@ -155,17 +154,16 @@ class TA_WC_Variation_Swatches_Frontend {
155
  $label = get_term_meta( $term->term_id, 'label', true );
156
  $label = $label ? $label : $name;
157
  $html = sprintf(
158
- '<span class="swatch swatch-label swatch-%s %s" data-value="%s">%s<p class="cv-tooltip">%s</p></span>',
159
  esc_attr( $term->slug ),
160
  $selected,
161
- // esc_attr( $term->description ),
162
  esc_attr( $term->slug ),
163
  esc_html( $label ),
164
- esc_attr( $tooltip )
165
  );
166
  break;
167
  }
168
 
169
  return $html;
170
  }
171
- }
38
  * Enqueue scripts and stylesheets
39
  */
40
  public function enqueue_scripts() {
41
+ wp_enqueue_style( 'tawcvs-frontend', plugins_url( 'assets/css/frontend.css', dirname( __FILE__ ) ), array(), '20200222' );
42
  wp_enqueue_script( 'tawcvs-frontend', plugins_url( 'assets/js/frontend.js', dirname( __FILE__ ) ), array( 'jquery' ), '20160615', true );
43
  }
44
 
51
  * @return string
52
  */
53
  public function get_swatch_html( $html, $args ) {
 
54
  $swatch_types = TA_WCVS()->types;
55
  $attr = TA_WCVS()->get_tax_attribute( $args['attribute'] );
56
+
57
  // Return if this is normal attribute
58
  if ( empty( $attr ) ) {
59
  return $html;
69
  $class = "variation-selector variation-select-{$attr->attribute_type}";
70
  $swatches = '';
71
 
72
+ // Add new option for tooltip to $args variable.
73
+ $args['tooltip'] = wc_string_to_bool( get_option( 'tawcvs_enable_tooltip', 'yes' ) );
74
+
75
  if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) {
76
  $attributes = $product->get_variation_attributes();
77
  $options = $attributes[$attribute];
90
  }
91
 
92
  if ( ! empty( $swatches ) ) {
93
+ $class .= ' hidden';
94
  $swatches = '<div class="tawcvs-swatches" data-attribute_name="attribute_' . esc_attr( $attribute ) . '">' . $swatches . '</div>';
95
  $html = '<div class="' . esc_attr( $class ) . '">' . $html . '</div>' . $swatches;
96
  }
112
  public function swatch_html( $html, $term, $type, $args ) {
113
  $selected = sanitize_title( $args['selected'] ) == $term->slug ? 'selected' : '';
114
  $name = esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) );
115
+ $tooltip = '';
116
 
117
+ if ( $args['tooltip'] ) {
118
+ $tooltip = '<span class="swatch__tooltip">' . ( $term->description ? $term->description : $name ) . '</span>';
 
 
 
119
  }
120
 
121
  switch ( $type ) {
123
  $color = get_term_meta( $term->term_id, 'color', true );
124
  list( $r, $g, $b ) = sscanf( $color, "#%02x%02x%02x" );
125
  $html = sprintf(
126
+ '<span class="swatch swatch-color swatch-%s %s" style="background-color:%s;color:%s;" data-value="%s">%s%s</span>',
127
  esc_attr( $term->slug ),
128
  $selected,
129
  esc_attr( $color ),
130
  "rgba($r,$g,$b,0.5)",
 
131
  esc_attr( $term->slug ),
132
  $name,
133
+ $tooltip
134
  );
135
  break;
136
 
139
  $image = $image ? wp_get_attachment_image_src( $image ) : '';
140
  $image = $image ? $image[0] : WC()->plugin_url() . '/assets/images/placeholder.png';
141
  $html = sprintf(
142
+ '<span class="swatch swatch-image swatch-%s %s" data-value="%s"><img src="%s" alt="%s">%s%s</span>',
143
  esc_attr( $term->slug ),
144
  $selected,
 
145
  esc_attr( $term->slug ),
146
  esc_url( $image ),
147
  esc_attr( $name ),
148
+ $name,
149
+ $tooltip
150
  );
151
  break;
152
 
154
  $label = get_term_meta( $term->term_id, 'label', true );
155
  $label = $label ? $label : $name;
156
  $html = sprintf(
157
+ '<span class="swatch swatch-label swatch-%s %s" data-value="%s">%s%s</span>',
158
  esc_attr( $term->slug ),
159
  $selected,
 
160
  esc_attr( $term->slug ),
161
  esc_html( $label ),
162
+ $tooltip
163
  );
164
  break;
165
  }
166
 
167
  return $html;
168
  }
169
+ }
includes/class-variation-swatches.php CHANGED
@@ -1,141 +1,141 @@
1
- <?php
2
-
3
- /**
4
- * The main plugin class
5
- */
6
- final class TA_WC_Variation_Swatches {
7
- /**
8
- * The single instance of the class
9
- *
10
- * @var TA_WC_Variation_Swatches
11
- */
12
- protected static $instance = null;
13
-
14
- /**
15
- * Extra attribute types
16
- *
17
- * @var array
18
- */
19
- public $types = array();
20
-
21
- /**
22
- * Main instance
23
- *
24
- * @return TA_WC_Variation_Swatches
25
- */
26
- public static function instance() {
27
- if ( null == self::$instance ) {
28
- self::$instance = new self();
29
- }
30
-
31
- return self::$instance;
32
- }
33
-
34
- /**
35
- * Class constructor.
36
- */
37
- public function __construct() {
38
- $this->types = array(
39
- 'color' => esc_html__( 'Color', 'wcvs' ),
40
- 'image' => esc_html__( 'Image', 'wcvs' ),
41
- 'label' => esc_html__( 'Label', 'wcvs' ),
42
- );
43
-
44
- $this->includes();
45
- $this->init_hooks();
46
- }
47
-
48
- /**
49
- * Include required core files used in admin and on the frontend.
50
- */
51
- public function includes() {
52
- require_once dirname( __FILE__ ) . '/class-frontend.php';
53
-
54
- if ( is_admin() ) {
55
- require_once dirname( __FILE__ ) . '/class-admin.php';
56
- }
57
- }
58
-
59
- /**
60
- * Initialize hooks
61
- */
62
- public function init_hooks() {
63
- add_action( 'init', array( $this, 'load_textdomain' ) );
64
-
65
- add_filter( 'product_attributes_type_selector', array( $this, 'add_attribute_types' ) );
66
-
67
- if ( is_admin() ) {
68
- add_action( 'init', array( 'TA_WC_Variation_Swatches_Admin', 'instance' ) );
69
- }
70
-
71
- if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
72
- add_action( 'init', array( 'TA_WC_Variation_Swatches_Frontend', 'instance' ) );
73
- }
74
- }
75
-
76
- /**
77
- * Load plugin text domain
78
- */
79
- public function load_textdomain() {
80
- load_plugin_textdomain( 'wcvs', false, dirname( plugin_basename( TAWC_VS_PLUGIN_FILE ) ) . '/languages/' );
81
- }
82
-
83
- /**
84
- * Add extra attribute types
85
- * Add color, image and label type
86
- *
87
- * @param array $types
88
- *
89
- * @return array
90
- */
91
- public function add_attribute_types( $types ) {
92
- $types = array_merge( $types, $this->types );
93
-
94
- return $types;
95
- }
96
-
97
- /**
98
- * Get attribute's properties
99
- *
100
- * @param string $taxonomy
101
- *
102
- * @return object
103
- */
104
- public function get_tax_attribute( $taxonomy ) {
105
- global $wpdb;
106
-
107
- $attr = substr( $taxonomy, 3 );
108
- $attr = $wpdb->get_row( "SELECT * FROM " . $wpdb->prefix . "woocommerce_attribute_taxonomies WHERE attribute_name = '$attr'" );
109
-
110
- return $attr;
111
- }
112
-
113
- /**
114
- * Instance of admin
115
- *
116
- * @return object
117
- */
118
- public function admin() {
119
- return TA_WC_Variation_Swatches_Admin::instance();
120
- }
121
-
122
- /**
123
- * Instance of frontend
124
- *
125
- * @return object
126
- */
127
- public function frontend() {
128
- return TA_WC_Variation_Swatches_Frontend::instance();
129
- }
130
- }
131
-
132
- if ( ! function_exists( 'TA_WCVS' ) ) {
133
- /**
134
- * Main instance of plugin
135
- *
136
- * @return TA_WC_Variation_Swatches
137
- */
138
- function TA_WCVS() {
139
- return TA_WC_Variation_Swatches::instance();
140
- }
141
  }
1
+ <?php
2
+
3
+ /**
4
+ * The main plugin class
5
+ */
6
+ final class TA_WC_Variation_Swatches {
7
+ /**
8
+ * The single instance of the class
9
+ *
10
+ * @var TA_WC_Variation_Swatches
11
+ */
12
+ protected static $instance = null;
13
+
14
+ /**
15
+ * Extra attribute types
16
+ *
17
+ * @var array
18
+ */
19
+ public $types = array();
20
+
21
+ /**
22
+ * Main instance
23
+ *
24
+ * @return TA_WC_Variation_Swatches
25
+ */
26
+ public static function instance() {
27
+ if ( null == self::$instance ) {
28
+ self::$instance = new self();
29
+ }
30
+
31
+ return self::$instance;
32
+ }
33
+
34
+ /**
35
+ * Class constructor.
36
+ */
37
+ public function __construct() {
38
+ $this->types = array(
39
+ 'color' => esc_html__( 'Color', 'wcvs' ),
40
+ 'image' => esc_html__( 'Image', 'wcvs' ),
41
+ 'label' => esc_html__( 'Label', 'wcvs' ),
42
+ );
43
+
44
+ $this->includes();
45
+ $this->init_hooks();
46
+ }
47
+
48
+ /**
49
+ * Include required core files used in admin and on the frontend.
50
+ */
51
+ public function includes() {
52
+ require_once dirname( __FILE__ ) . '/class-frontend.php';
53
+
54
+ if ( is_admin() ) {
55
+ require_once dirname( __FILE__ ) . '/class-admin.php';
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Initialize hooks
61
+ */
62
+ public function init_hooks() {
63
+ add_action( 'init', array( $this, 'load_textdomain' ) );
64
+
65
+ add_filter( 'product_attributes_type_selector', array( $this, 'add_attribute_types' ) );
66
+
67
+ if ( is_admin() ) {
68
+ add_action( 'init', array( 'TA_WC_Variation_Swatches_Admin', 'instance' ) );
69
+ }
70
+
71
+ if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
72
+ add_action( 'init', array( 'TA_WC_Variation_Swatches_Frontend', 'instance' ) );
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Load plugin text domain
78
+ */
79
+ public function load_textdomain() {
80
+ load_plugin_textdomain( 'wcvs', false, dirname( plugin_basename( TAWC_VS_PLUGIN_FILE ) ) . '/languages/' );
81
+ }
82
+
83
+ /**
84
+ * Add extra attribute types
85
+ * Add color, image and label type
86
+ *
87
+ * @param array $types
88
+ *
89
+ * @return array
90
+ */
91
+ public function add_attribute_types( $types ) {
92
+ $types = array_merge( $types, $this->types );
93
+
94
+ return $types;
95
+ }
96
+
97
+ /**
98
+ * Get attribute's properties
99
+ *
100
+ * @param string $taxonomy
101
+ *
102
+ * @return object
103
+ */
104
+ public function get_tax_attribute( $taxonomy ) {
105
+ global $wpdb;
106
+
107
+ $attr = substr( $taxonomy, 3 );
108
+ $attr = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM " . $wpdb->prefix . "woocommerce_attribute_taxonomies WHERE attribute_name = %s", $attr ) );
109
+
110
+ return $attr;
111
+ }
112
+
113
+ /**
114
+ * Instance of admin
115
+ *
116
+ * @return object
117
+ */
118
+ public function admin() {
119
+ return TA_WC_Variation_Swatches_Admin::instance();
120
+ }
121
+
122
+ /**
123
+ * Instance of frontend
124
+ *
125
+ * @return object
126
+ */
127
+ public function frontend() {
128
+ return TA_WC_Variation_Swatches_Frontend::instance();
129
+ }
130
+ }
131
+
132
+ if ( ! function_exists( 'TA_WCVS' ) ) {
133
+ /**
134
+ * Main instance of plugin
135
+ *
136
+ * @return TA_WC_Variation_Swatches
137
+ */
138
+ function TA_WCVS() {
139
+ return TA_WC_Variation_Swatches::instance();
140
+ }
141
  }
languages/wcvs.pot CHANGED
@@ -1,127 +1,153 @@
1
- #, fuzzy
2
- msgid ""
3
- msgstr ""
4
- "Project-Id-Version: PACKAGE VERSION\n"
5
- "Report-Msgid-Bugs-To: \n"
6
- "POT-Creation-Date: 2017-01-14 10:16+0000\n"
7
- "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
8
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
9
- "Language-Team: \n"
10
- "Language: \n"
11
- "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
12
- "MIME-Version: 1.0\n"
13
- "Content-Type: text/plain; charset=UTF-8\n"
14
- "Content-Transfer-Encoding: 8bit\n"
15
- "X-Generator: Loco https://localise.biz/"
16
-
17
- #: woocommerce-variation-swatches.php:57 includes/class-admin.php:303
18
- msgid "Color"
19
- msgstr ""
20
-
21
- #: woocommerce-variation-swatches.php:58 includes/class-admin.php:310
22
- msgid "Image"
23
- msgstr ""
24
-
25
- #: woocommerce-variation-swatches.php:59 includes/class-admin.php:325
26
- msgid "Label"
27
- msgstr ""
28
-
29
- #: woocommerce-variation-swatches.php:161
30
- msgid ""
31
- "Soo Product Attribute Swatches is enabled but not effective. It requires "
32
- "WooCommerce in order to work."
33
- msgstr ""
34
-
35
- #: includes/class-admin.php:87
36
- msgid "Choose an image"
37
- msgstr ""
38
-
39
- #: includes/class-admin.php:88
40
- msgid "Use image"
41
- msgstr ""
42
-
43
- #: includes/class-admin.php:147 includes/class-admin.php:316
44
- msgid "Upload/Add image"
45
- msgstr ""
46
-
47
- #: includes/class-admin.php:148 includes/class-admin.php:317
48
- msgid "Remove image"
49
- msgstr ""
50
-
51
- #: includes/class-admin.php:193
52
- msgid "Select terms"
53
- msgstr ""
54
-
55
- #: includes/class-admin.php:204
56
- msgid "Select all"
57
- msgstr ""
58
-
59
- #: includes/class-admin.php:205
60
- msgid "Select none"
61
- msgstr ""
62
-
63
- #: includes/class-admin.php:206
64
- msgid "Add new"
65
- msgstr ""
66
-
67
- #: includes/class-admin.php:270
68
- msgid "Add new term"
69
- msgstr ""
70
-
71
- #: includes/class-admin.php:274
72
- msgid "Name"
73
- msgstr ""
74
-
75
- #: includes/class-admin.php:280
76
- msgid "Slug"
77
- msgstr ""
78
-
79
- #: includes/class-admin.php:292
80
- msgid "Cancel"
81
- msgstr ""
82
-
83
- #: includes/class-admin.php:293
84
- msgid "Add New"
85
- msgstr ""
86
-
87
- #: includes/class-admin.php:352
88
- msgid "Wrong request"
89
- msgstr ""
90
-
91
- #: includes/class-admin.php:356
92
- msgid "Not enough data"
93
- msgstr ""
94
-
95
- #: includes/class-admin.php:360
96
- msgid "Taxonomy is not exists"
97
- msgstr ""
98
-
99
- #: includes/class-admin.php:364
100
- msgid "This term is exists"
101
- msgstr ""
102
-
103
- #: includes/class-admin.php:378
104
- msgid "Added successfully"
105
- msgstr ""
106
-
107
- #. Name of the plugin
108
- msgid "WooCommerce Variation Swatches"
109
- msgstr ""
110
-
111
- #. Description of the plugin
112
- msgid ""
113
- "An extension of WooCommerce to make variation products be more beauty and "
114
- "friendly with users."
115
- msgstr ""
116
-
117
- #. URI of the plugin
118
- msgid "http://themealien.com/wordpress-plugin/woocommerce-variation-swatches"
119
- msgstr ""
120
-
121
- #. Author of the plugin
122
- msgid "ThemeAlien"
123
- msgstr ""
124
-
125
- #. Author URI of the plugin
126
- msgid "http://themealien.com/"
127
- msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #, fuzzy
2
+ msgid ""
3
+ msgstr ""
4
+ "Project-Id-Version: PACKAGE VERSION\n"
5
+ "Report-Msgid-Bugs-To: \n"
6
+ "POT-Creation-Date: 2020-02-22 10:41+0000\n"
7
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
8
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
9
+ "Language-Team: \n"
10
+ "Language: \n"
11
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
12
+ "MIME-Version: 1.0\n"
13
+ "Content-Type: text/plain; charset=UTF-8\n"
14
+ "Content-Transfer-Encoding: 8bit\n"
15
+ "X-Generator: Loco https://localise.biz/"
16
+
17
+ #: variation-swatches-for-woocommerce.php:35
18
+ msgid ""
19
+ "Variation Swatcher for WooCommerce is enabled but not effective. It requires "
20
+ "WooCommerce in order to work."
21
+ msgstr ""
22
+
23
+ #: variation-swatches-for-woocommerce.php:50
24
+ msgid ""
25
+ "No need to activate the free version of Variation Swatcher for WooCommerce "
26
+ "plugin while the pro version is activated."
27
+ msgstr ""
28
+
29
+ #: includes/class-admin-product.php:34
30
+ msgid "Select terms"
31
+ msgstr ""
32
+
33
+ #: includes/class-admin-product.php:45
34
+ msgid "Select all"
35
+ msgstr ""
36
+
37
+ #: includes/class-admin-product.php:46
38
+ msgid "Select none"
39
+ msgstr ""
40
+
41
+ #: includes/class-admin-product.php:47
42
+ msgid "Add new"
43
+ msgstr ""
44
+
45
+ #: includes/class-admin-product.php:64
46
+ msgid "Wrong request"
47
+ msgstr ""
48
+
49
+ #: includes/class-admin-product.php:68
50
+ msgid "Not enough data"
51
+ msgstr ""
52
+
53
+ #: includes/class-admin-product.php:72
54
+ msgid "Taxonomy is not exists"
55
+ msgstr ""
56
+
57
+ #: includes/class-admin-product.php:76
58
+ msgid "This term is exists"
59
+ msgstr ""
60
+
61
+ #: includes/class-admin-product.php:90
62
+ msgid "Added successfully"
63
+ msgstr ""
64
+
65
+ #: includes/class-admin-product.php:113
66
+ msgid "Add new term"
67
+ msgstr ""
68
+
69
+ #: includes/class-admin-product.php:117
70
+ msgid "Name"
71
+ msgstr ""
72
+
73
+ #: includes/class-admin-product.php:123
74
+ msgid "Slug"
75
+ msgstr ""
76
+
77
+ #: includes/class-admin-product.php:135
78
+ msgid "Cancel"
79
+ msgstr ""
80
+
81
+ #: includes/class-admin-product.php:136
82
+ msgid "Add New"
83
+ msgstr ""
84
+
85
+ #: includes/class-admin-product.php:146
86
+ #: includes/class-variation-swatches.php:39
87
+ msgid "Color"
88
+ msgstr ""
89
+
90
+ #: includes/class-admin-product.php:153
91
+ #: includes/class-variation-swatches.php:40
92
+ msgid "Image"
93
+ msgstr ""
94
+
95
+ #: includes/class-admin-product.php:159 includes/class-admin.php:235
96
+ msgid "Upload/Add image"
97
+ msgstr ""
98
+
99
+ #: includes/class-admin-product.php:160 includes/class-admin.php:236
100
+ msgid "Remove image"
101
+ msgstr ""
102
+
103
+ #: includes/class-admin-product.php:168
104
+ #: includes/class-variation-swatches.php:41
105
+ msgid "Label"
106
+ msgstr ""
107
+
108
+ #: includes/class-admin.php:93
109
+ msgid "Choose an image"
110
+ msgstr ""
111
+
112
+ #: includes/class-admin.php:94
113
+ msgid "Use image"
114
+ msgstr ""
115
+
116
+ #: includes/class-admin.php:110
117
+ msgid ""
118
+ "Found a backup of product attributes types. This backup was generated at"
119
+ msgstr ""
120
+
121
+ #: includes/class-admin.php:116
122
+ msgid "Restore product attributes types"
123
+ msgstr ""
124
+
125
+ #: includes/class-admin.php:120
126
+ msgid "Dismiss this notice"
127
+ msgstr ""
128
+
129
+ #: includes/class-admin.php:128
130
+ msgid "All attributes types have been restored."
131
+ msgstr ""
132
+
133
+ #. Name of the plugin
134
+ msgid "Variation Swatcher for WooCommerce"
135
+ msgstr ""
136
+
137
+ #. Description of the plugin
138
+ msgid ""
139
+ "An extension of WooCommerce to make variable products be more beauty and "
140
+ "friendly to users."
141
+ msgstr ""
142
+
143
+ #. URI of the plugin
144
+ msgid "http://themealien.com/wordpress-plugin/woocommerce-variation-swatches"
145
+ msgstr ""
146
+
147
+ #. Author of the plugin
148
+ msgid "ThemeAlien"
149
+ msgstr ""
150
+
151
+ #. Author URI of the plugin
152
+ msgid "http://themealien.com/"
153
+ msgstr ""
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Variation Swatches for WooCommerce ===
2
- Contributors: rextheme, coderexco, themealien
3
  Tags: woocommerce, product attribute, product color, product size, variation swatches, variable products
4
  Requires at least: 4.5
5
  Tested up to: 5.3
6
- Stable tag: 1.0.5
7
  License: GPLv2 or later
8
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -25,16 +25,7 @@ With a friendly and easy-to-use interface, you can add default color, image or l
25
  * Create attribute label/text swatches
26
  * Manage attribute globally
27
  * Create new attribute swatch in product editing page
28
- * New options in WooCommerce Settings that help control swatches easier without touching code
29
 
30
- ## Privacy Policy
31
- Variation Swatches for WooCommerce uses [Appsero](https://appsero.com) SDK to collect some telemetry data upon user's confirmation. This helps us to troubleshoot problems faster & make product improvements.
32
-
33
- Appsero SDK **does not gather any data by default.** The SDK only starts gathering basic telemetry data **when a user allows it via the admin notice**. We collect the data to ensure great user experience for all our users.
34
-
35
- Integrating Appsero SDK **DOES NOT IMMEDIATELY** start gathering data, **without confirmation from users in any case.**
36
-
37
- Learn more how [Appsero collects and uses this data](https://appsero.com/privacy-policy/).
38
 
39
  == Installation ==
40
 
@@ -84,8 +75,14 @@ Yes, it will work with any theme, but may require some styling to make it match
84
 
85
  == Changelog ==
86
 
 
 
 
 
 
 
87
  = 1.0.5 =
88
- * Added variation description on hover.
89
 
90
  = 1.0.4 =
91
  * Fix the issue of product attributes are not saved.
@@ -101,4 +98,4 @@ Yes, it will work with any theme, but may require some styling to make it match
101
  * Add "swatches-support" class to the variations form
102
 
103
  = 1.0.0 =
104
- * Initial release.
1
  === Variation Swatches for WooCommerce ===
2
+ Contributors: themealien, coderexco
3
  Tags: woocommerce, product attribute, product color, product size, variation swatches, variable products
4
  Requires at least: 4.5
5
  Tested up to: 5.3
6
+ Stable tag: 1.0.6
7
  License: GPLv2 or later
8
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
9
 
25
  * Create attribute label/text swatches
26
  * Manage attribute globally
27
  * Create new attribute swatch in product editing page
 
28
 
 
 
 
 
 
 
 
 
29
 
30
  == Installation ==
31
 
75
 
76
  == Changelog ==
77
 
78
+ = 1.0.6 =
79
+ * New - Add a notice in admin area to restore attribute types after re-activating the plugin.
80
+ * Tweak - Rename the tooltip CSS class following WooCommerce standard.
81
+ * Tweak - Remove opacity from swatches.
82
+ * Security - Using $wpdb->prepare to get attribute data.
83
+
84
  = 1.0.5 =
85
+ * Add tooltip
86
 
87
  = 1.0.4 =
88
  * Fix the issue of product attributes are not saved.
98
  * Add "swatches-support" class to the variations form
99
 
100
  = 1.0.0 =
101
+ * Initial release.
variation-swatches-for-woocommerce.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
2
  /**
3
- * Plugin Name: Variation Swatches for WooCommerce
4
- * Plugin URI: https://rextheme.com/variation-swatches-for-woocommerce/
5
  * Description: An extension of WooCommerce to make variable products be more beauty and friendly to users.
6
- * Version: 1.0.5
7
- * Author: RexTheme
8
- * Author URI: https://rextheme.com
9
  * Requires at least: 4.5
10
  * Tested up to: 5.3
11
  * License: GPLv2 or later
@@ -32,7 +32,7 @@ if ( ! function_exists( 'ta_wc_variation_swatches_wc_notice' ) ) {
32
  ?>
33
 
34
  <div class="error">
35
- <p><?php esc_html_e( 'Variation Swatches for WooCommerce is enabled but not effective. It requires WooCommerce in order to work.', 'wcvs' ); ?></p>
36
  </div>
37
 
38
  <?php
@@ -47,7 +47,7 @@ if ( ! function_exists( 'ta_wc_variation_swatches_pro_notice' ) ) {
47
  ?>
48
 
49
  <div class="error">
50
- <p><?php esc_html_e( 'No need to activate the free version of Variation Swatches for WooCommerce plugin while the pro version is activated.', 'wcvs' ); ?></p>
51
  </div>
52
 
53
  <?php
@@ -99,7 +99,7 @@ if ( ! function_exists( 'ta_wc_variation_swatches_deactivate' ) ) {
99
  switch_to_blog( $blog_id );
100
  }
101
 
102
- // Backup attribute types
103
  $attributes = wc_get_attribute_taxonomies();
104
  $default_types = array( 'text', 'select' );
105
  $ta_wcvs_attributes = array();
@@ -118,7 +118,7 @@ if ( ! function_exists( 'ta_wc_variation_swatches_deactivate' ) ) {
118
  update_option( 'tawcvs_backup_attributes_time', time() );
119
  }
120
 
121
- // Reset attributes
122
  if ( ! empty( $ta_wcvs_attributes ) ) {
123
  foreach ( $ta_wcvs_attributes as $id => $attribute ) {
124
  $wpdb->update(
@@ -131,8 +131,8 @@ if ( ! function_exists( 'ta_wc_variation_swatches_deactivate' ) ) {
131
  }
132
  }
133
 
134
- // Delete the ignore restore
135
- delete_option( 'tawcvs_ignore_restore_attributes' );
136
  }
137
 
138
  if ( $network ) {
@@ -143,22 +143,3 @@ if ( ! function_exists( 'ta_wc_variation_swatches_deactivate' ) ) {
143
 
144
  add_action( 'plugins_loaded', 'ta_wc_variation_swatches_constructor', 20 );
145
  register_deactivation_hook( __FILE__, 'ta_wc_variation_swatches_deactivate' );
146
-
147
- /**
148
- * Initialize the plugin tracker
149
- *
150
- * @return void
151
- */
152
- function appsero_init_tracker_variation_swatches_for_woocommerce() {
153
-
154
- if ( ! class_exists( 'Appsero\Client' ) ) {
155
- require_once __DIR__ . '/appsero/src/Client.php';
156
- }
157
-
158
- $client = new Appsero\Client( '454ebec6-6008-4065-b639-ba70ed7f9640', 'variation-swatches-for-woocommerce', __FILE__ );
159
- $client->insights()->init();
160
- $client->updater();
161
-
162
- }
163
-
164
- appsero_init_tracker_variation_swatches_for_woocommerce();
1
  <?php
2
  /**
3
+ * Plugin Name: Variation Swatcher for WooCommerce
4
+ * Plugin URI: http://themealien.com/wordpress-plugin/woocommerce-variation-swatches
5
  * Description: An extension of WooCommerce to make variable products be more beauty and friendly to users.
6
+ * Version: 1.0.6
7
+ * Author: ThemeAlien
8
+ * Author URI: http://themealien.com/
9
  * Requires at least: 4.5
10
  * Tested up to: 5.3
11
  * License: GPLv2 or later
32
  ?>
33
 
34
  <div class="error">
35
+ <p><?php esc_html_e( 'Variation Swatcher for WooCommerce is enabled but not effective. It requires WooCommerce in order to work.', 'wcvs' ); ?></p>
36
  </div>
37
 
38
  <?php
47
  ?>
48
 
49
  <div class="error">
50
+ <p><?php esc_html_e( 'No need to activate the free version of Variation Swatcher for WooCommerce plugin while the pro version is activated.', 'wcvs' ); ?></p>
51
  </div>
52
 
53
  <?php
99
  switch_to_blog( $blog_id );
100
  }
101
 
102
+ // Backup attribute types.
103
  $attributes = wc_get_attribute_taxonomies();
104
  $default_types = array( 'text', 'select' );
105
  $ta_wcvs_attributes = array();
118
  update_option( 'tawcvs_backup_attributes_time', time() );
119
  }
120
 
121
+ // Reset attributes.
122
  if ( ! empty( $ta_wcvs_attributes ) ) {
123
  foreach ( $ta_wcvs_attributes as $id => $attribute ) {
124
  $wpdb->update(
131
  }
132
  }
133
 
134
+ // Delete the option of restoring time.
135
+ delete_option( 'tawcvs_restore_attributes_time' );
136
  }
137
 
138
  if ( $network ) {
143
 
144
  add_action( 'plugins_loaded', 'ta_wc_variation_swatches_constructor', 20 );
145
  register_deactivation_hook( __FILE__, 'ta_wc_variation_swatches_deactivate' );