WooCommerce Cart Abandonment Recovery - Version 1.2.8

Version Description

Download this release

Release Info

Developer sandesh055
Plugin Icon 128x128 WooCommerce Cart Abandonment Recovery
Version 1.2.8
Comparing to
See all releases

Code changes from version 1.2.7 to 1.2.8

Files changed (33) hide show
  1. admin/assets/js/admin-email-templates.js +2 -1
  2. admin/bsf-analytics/Gruntfile.js +210 -0
  3. admin/bsf-analytics/assets/css/minified/style-rtl.min.css +1 -1
  4. admin/bsf-analytics/assets/css/minified/style.min.css +1 -1
  5. admin/bsf-analytics/assets/css/unminified/style-rtl.css +5 -5
  6. admin/bsf-analytics/assets/css/unminified/style.css +5 -5
  7. admin/bsf-analytics/class-bsf-analytics-loader.php +118 -0
  8. admin/bsf-analytics/class-bsf-analytics-stats.php +256 -256
  9. admin/bsf-analytics/class-bsf-analytics.php +197 -222
  10. admin/bsf-analytics/composer.json +22 -0
  11. admin/bsf-analytics/composer.lock +711 -0
  12. admin/bsf-analytics/package-lock.json +3978 -0
  13. admin/bsf-analytics/package.json +30 -0
  14. admin/bsf-analytics/phpcs.xml.dist +19 -0
  15. admin/bsf-analytics/version.json +4 -0
  16. changelog.txt +6 -2
  17. classes/class-cartflows-ca-loader.php +22 -2
  18. classes/class-cartflows-ca-settings.php +51 -0
  19. classes/class-cartflows-ca-update.php +92 -92
  20. classes/class-cartflows-ca-utils.php +115 -115
  21. languages/woo-cart-abandonment-recovery.pot +884 -878
  22. modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php +241 -241
  23. modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php +291 -291
  24. modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php +19 -6
  25. modules/cart-abandonment/class-cartflows-ca-email-templates-table.php +268 -268
  26. modules/cart-abandonment/class-cartflows-ca-email-templates.php +1096 -1096
  27. modules/cart-abandonment/class-cartflows-ca-module-loader.php +62 -62
  28. modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php +247 -249
  29. modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php +156 -156
  30. modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-tabs.php +118 -118
  31. readme.txt +7 -4
  32. uninstall.php +14 -14
  33. woo-cart-abandonment-recovery.php +2 -2
admin/assets/js/admin-email-templates.js CHANGED
@@ -288,15 +288,16 @@
288
  });
289
  },
290
  }
 
291
 
292
  $(document).ready(
293
  function () {
294
  EmailTemplatesAdmin.init();
295
  CartAbandonmentSettings.init();
296
  ZapierSettings.init();
297
-
298
  ToolTipHover.init();
299
  }
 
300
  );
301
 
302
 
288
  });
289
  },
290
  }
291
+
292
 
293
  $(document).ready(
294
  function () {
295
  EmailTemplatesAdmin.init();
296
  CartAbandonmentSettings.init();
297
  ZapierSettings.init();
 
298
  ToolTipHover.init();
299
  }
300
+
301
  );
302
 
303
 
admin/bsf-analytics/Gruntfile.js ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ module.exports = function (grunt) {
2
+ 'use strict';
3
+ // Project configuration
4
+ var autoprefixer = require('autoprefixer');
5
+ var flexibility = require('postcss-flexibility');
6
+
7
+ var pkgInfo = grunt.file.readJSON('package.json');
8
+
9
+ grunt.initConfig({
10
+ pkg: grunt.file.readJSON('package.json'),
11
+
12
+ rtlcss: {
13
+ options: {
14
+ // rtlcss options
15
+ config: {
16
+ preserveComments: true,
17
+ greedy: true
18
+ },
19
+ // generate source maps
20
+ map: false
21
+ },
22
+ dist: {
23
+ files: [
24
+ {
25
+ expand: true,
26
+ cwd: 'assets/css/unminified',
27
+ src: [
28
+ '*.css',
29
+ '!*-rtl.css',
30
+ ],
31
+ dest: 'assets/css/unminified',
32
+ ext: '-rtl.css'
33
+ },
34
+ ]
35
+ }
36
+ },
37
+
38
+ postcss: {
39
+ options: {
40
+ map: false,
41
+ processors: [
42
+ flexibility,
43
+ autoprefixer({
44
+ browsers: [
45
+ 'Android >= 2.1',
46
+ 'Chrome >= 21',
47
+ 'Edge >= 12',
48
+ 'Explorer >= 7',
49
+ 'Firefox >= 17',
50
+ 'Opera >= 12.1',
51
+ 'Safari >= 6.0'
52
+ ],
53
+ cascade: false
54
+ })
55
+ ]
56
+ },
57
+ style: {
58
+ expand: true,
59
+ src: [
60
+ 'assets/css/unminified/**.css',
61
+ '!assets/css/unminified/**-rtl.css'
62
+ ]
63
+ }
64
+ },
65
+
66
+ cssmin: {
67
+ options: {
68
+ keepSpecialComments: 0
69
+ },
70
+ css: {
71
+ files: [
72
+ {
73
+ src: 'assets/css/unminified/style.css',
74
+ dest: 'assets/css/minified/style.min.css',
75
+ },
76
+ {
77
+ src: 'assets/css/unminified/style-rtl.css',
78
+ dest: 'assets/css/minified/style-rtl.min.css',
79
+ },
80
+ ]
81
+ }
82
+ },
83
+
84
+ copy: {
85
+ main: {
86
+ options: {
87
+ mode: true
88
+ },
89
+ src: [
90
+ '**',
91
+ '!node_modules/**',
92
+ '!build/**',
93
+ '!css/sourcemap/**',
94
+ '!.git/**',
95
+ '!bin/**',
96
+ '!.gitlab-ci.yml',
97
+ '!bin/**',
98
+ '!tests/**',
99
+ '!phpunit.xml.dist',
100
+ '!*.sh',
101
+ '!*.map',
102
+ '!Gruntfile.js',
103
+ '!package.json',
104
+ '!.gitignore',
105
+ '!phpunit.xml',
106
+ '!README.md',
107
+ '!sass/**',
108
+ '!codesniffer.ruleset.xml',
109
+ '!vendor/**',
110
+ '!composer.json',
111
+ '!composer.lock',
112
+ '!package-lock.json',
113
+ '!phpcs.xml.dist',
114
+ ],
115
+ dest: 'bsf-analytics/'
116
+ }
117
+ },
118
+
119
+ compress: {
120
+ main: {
121
+ options: {
122
+ archive: 'bsf-analytics-' + pkgInfo.version + '.zip',
123
+ mode: 'zip'
124
+ },
125
+ files: [
126
+ {
127
+ src: [
128
+ './bsf-analytics/**'
129
+ ]
130
+
131
+ }
132
+ ]
133
+ }
134
+ },
135
+
136
+ clean: {
137
+ main: ["bsf-analytics"],
138
+ zip: ["*.zip"]
139
+
140
+ },
141
+
142
+ replace: {
143
+
144
+ analytics_const: {
145
+ src: ['class-bsf-analytics.php'],
146
+ overwrite: true,
147
+ replacements: [
148
+ {
149
+ from: /BSF_ANALYTICS_VERSION', '.*?'/g,
150
+ to: 'BSF_ANALYTICS_VERSION\', \'<%= pkg.version %>\''
151
+ }
152
+ ]
153
+ },
154
+
155
+ analytics_function_comment: {
156
+ src: [
157
+ '*.php',
158
+ '**/*.php',
159
+ '!node_modules/**',
160
+ '!php-tests/**',
161
+ '!bin/**',
162
+ ],
163
+ overwrite: true,
164
+ replacements: [
165
+ {
166
+ from: 'x.x.x',
167
+ to: '<%=pkg.version %>'
168
+ }
169
+ ]
170
+ },
171
+ },
172
+ }
173
+ );
174
+
175
+ // Load grunt tasks
176
+ grunt.loadNpmTasks('grunt-rtlcss');
177
+ grunt.loadNpmTasks( 'grunt-postcss' );
178
+
179
+ grunt.loadNpmTasks('grunt-contrib-cssmin');
180
+ grunt.loadNpmTasks('grunt-contrib-copy');
181
+ grunt.loadNpmTasks('grunt-contrib-compress');
182
+ grunt.loadNpmTasks('grunt-contrib-clean');
183
+
184
+ /* Version Bump Task */
185
+ grunt.loadNpmTasks( 'grunt-bumpup' );
186
+ grunt.loadNpmTasks( 'grunt-text-replace' );
187
+
188
+ // rtlcss, you will still need to install ruby and sass on your system manually to run this
189
+ grunt.registerTask('rtl', ['rtlcss']);
190
+
191
+ // Style
192
+ grunt.registerTask('style', ['rtl']);
193
+
194
+ // min all
195
+ grunt.registerTask('minify', ['style', 'cssmin:css']);
196
+
197
+ // Grunt release - Create installable package of the local files
198
+ grunt.registerTask('release', ['clean:zip', 'copy:main', 'compress:main', 'clean:main']);
199
+
200
+ // Version Bump `grunt bump-version --ver=<version-number>`
201
+ grunt.registerTask( 'bump-version', function() {
202
+
203
+ var newVersion = grunt.option('ver');
204
+
205
+ if ( newVersion ) {
206
+ grunt.task.run( 'bumpup:' + newVersion );
207
+ grunt.task.run( 'replace' );
208
+ }
209
+ } );
210
+ };
admin/bsf-analytics/assets/css/minified/style-rtl.min.css CHANGED
@@ -1 +1 @@
1
- #bsf-optin-notice{padding:1px 12px;border-right-color:#007cba}#bsf-optin-notice .notice-container{padding-top:10px;padding-bottom:12px}#bsf-optin-notice .notice-content{margin:0}#bsf-optin-notice .notice-heading{padding:0 0 12px 20px}#bsf-optin-notice .button-primary{margin-left:5px}
1
+ [ID*="-optin-notice"]{padding:1px 12px;border-right-color:#007cba}[ID*="-optin-notice"] .notice-container{padding-top:10px;padding-bottom:12px}[ID*="-optin-notice"] .notice-content{margin:0}[ID*="-optin-notice"] .notice-heading{padding:0 0 12px 20px}[ID*="-optin-notice"] .button-primary{margin-left:5px}
admin/bsf-analytics/assets/css/minified/style.min.css CHANGED
@@ -1 +1 @@
1
- #bsf-optin-notice{padding:1px 12px;border-left-color:#007cba}#bsf-optin-notice .notice-container{padding-top:10px;padding-bottom:12px}#bsf-optin-notice .notice-content{margin:0}#bsf-optin-notice .notice-heading{padding:0 20px 12px 0}#bsf-optin-notice .button-primary{margin-right:5px}
1
+ [ID*="-optin-notice"]{padding:1px 12px;border-left-color:#007cba}[ID*="-optin-notice"] .notice-container{padding-top:10px;padding-bottom:12px}[ID*="-optin-notice"] .notice-content{margin:0}[ID*="-optin-notice"] .notice-heading{padding:0 20px 12px 0}[ID*="-optin-notice"] .button-primary{margin-right:5px}
admin/bsf-analytics/assets/css/unminified/style-rtl.css CHANGED
@@ -1,21 +1,21 @@
1
- #bsf-optin-notice {
2
  padding: 1px 12px;
3
  border-right-color: #007cba;
4
  }
5
 
6
- #bsf-optin-notice .notice-container {
7
  padding-top: 10px;
8
  padding-bottom: 12px;
9
  }
10
 
11
- #bsf-optin-notice .notice-content {
12
  margin: 0;
13
  }
14
 
15
- #bsf-optin-notice .notice-heading {
16
  padding: 0 0 12px 20px;
17
  }
18
 
19
- #bsf-optin-notice .button-primary {
20
  margin-left: 5px;
21
  }
1
+ [ID*="-optin-notice"] {
2
  padding: 1px 12px;
3
  border-right-color: #007cba;
4
  }
5
 
6
+ [ID*="-optin-notice"] .notice-container {
7
  padding-top: 10px;
8
  padding-bottom: 12px;
9
  }
10
 
11
+ [ID*="-optin-notice"] .notice-content {
12
  margin: 0;
13
  }
14
 
15
+ [ID*="-optin-notice"] .notice-heading {
16
  padding: 0 0 12px 20px;
17
  }
18
 
19
+ [ID*="-optin-notice"] .button-primary {
20
  margin-left: 5px;
21
  }
admin/bsf-analytics/assets/css/unminified/style.css CHANGED
@@ -1,21 +1,21 @@
1
- #bsf-optin-notice {
2
  padding: 1px 12px;
3
  border-left-color: #007cba;
4
  }
5
 
6
- #bsf-optin-notice .notice-container {
7
  padding-top: 10px;
8
  padding-bottom: 12px;
9
  }
10
 
11
- #bsf-optin-notice .notice-content {
12
  margin: 0;
13
  }
14
 
15
- #bsf-optin-notice .notice-heading {
16
  padding: 0 20px 12px 0;
17
  }
18
 
19
- #bsf-optin-notice .button-primary {
20
  margin-right: 5px;
21
  }
1
+ [ID*="-optin-notice"] {
2
  padding: 1px 12px;
3
  border-left-color: #007cba;
4
  }
5
 
6
+ [ID*="-optin-notice"] .notice-container {
7
  padding-top: 10px;
8
  padding-bottom: 12px;
9
  }
10
 
11
+ [ID*="-optin-notice"] .notice-content {
12
  margin: 0;
13
  }
14
 
15
+ [ID*="-optin-notice"] .notice-heading {
16
  padding: 0 20px 12px 0;
17
  }
18
 
19
+ [ID*="-optin-notice"] .button-primary {
20
  margin-right: 5px;
21
  }
admin/bsf-analytics/class-bsf-analytics-loader.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BSF analytics loader file.
4
+ *
5
+ * @version 1.0.0
6
+ *
7
+ * @package bsf-analytics
8
+ */
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit();
12
+ }
13
+
14
+ /**
15
+ * Class BSF_Analytics_Loader.
16
+ */
17
+ class BSF_Analytics_Loader {
18
+
19
+ /**
20
+ * Analytics Entities.
21
+ *
22
+ * @access private
23
+ * @var array Entities array.
24
+ */
25
+ private $entities = array();
26
+
27
+ /**
28
+ * Analytics Version.
29
+ *
30
+ * @access private
31
+ * @var float analytics version.
32
+ */
33
+ private $analytics_version = '';
34
+
35
+ /**
36
+ * Analytics path.
37
+ *
38
+ * @access private
39
+ * @var string path array.
40
+ */
41
+ private $analytics_path = '';
42
+
43
+ /**
44
+ * Instance
45
+ *
46
+ * @access private
47
+ * @var object Class object.
48
+ */
49
+ private static $instance = null;
50
+
51
+ /**
52
+ * Get instace of class.
53
+ *
54
+ * @return object
55
+ */
56
+ public static function get_instance() {
57
+ if ( null === self::$instance ) {
58
+ self::$instance = new self();
59
+ }
60
+
61
+ return self::$instance;
62
+ }
63
+
64
+ /**
65
+ * Constructor
66
+ */
67
+ public function __construct() {
68
+ add_action( 'init', array( $this, 'load_analytics' ) );
69
+ }
70
+
71
+ /**
72
+ * Set entity for analytics.
73
+ *
74
+ * @param string $data Entity attributes data.
75
+ * @return void
76
+ */
77
+ public function set_entity( $data ) {
78
+ array_push( $this->entities, $data );
79
+ }
80
+
81
+ /**
82
+ * Load Analytics library.
83
+ *
84
+ * @return void
85
+ */
86
+ public function load_analytics() {
87
+ $unique_entities = array();
88
+
89
+ if ( ! empty( $this->entities ) ) {
90
+ foreach ( $this->entities as $entity ) {
91
+ foreach ( $entity as $key => $data ) {
92
+
93
+ if ( isset( $data['path'] ) ) {
94
+ if ( file_exists( $data['path'] . '/version.json' ) ) {
95
+ $file_contents = file_get_contents( $data['path'] . '/version.json' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
96
+ $analytics_version = json_decode( $file_contents, 1 );
97
+ $analytics_version = $analytics_version['bsf-analytics-ver'];
98
+
99
+ if ( version_compare( $analytics_version, $this->analytics_version, '>' ) ) {
100
+ $this->analytics_version = $analytics_version;
101
+ $this->analytics_path = $data['path'];
102
+ }
103
+ }
104
+ }
105
+
106
+ if ( ! isset( $unique_entities[ $key ] ) ) {
107
+ $unique_entities[ $key ] = $data;
108
+ }
109
+ }
110
+ }
111
+
112
+ if ( file_exists( $this->analytics_path ) && ! class_exists( 'BSF_Analytics' ) ) {
113
+ require_once $this->analytics_path . '/class-bsf-analytics.php';
114
+ new BSF_Analytics( $unique_entities, $this->analytics_path, $this->analytics_version );
115
+ }
116
+ }
117
+ }
118
+ }
admin/bsf-analytics/class-bsf-analytics-stats.php CHANGED
@@ -1,256 +1,256 @@
1
- <?php
2
- /**
3
- * BSF analytics stat class file.
4
- *
5
- * @package bsf-analytics
6
- */
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // Exit if accessed directly.
10
- }
11
-
12
- if ( ! class_exists( 'BSF_Analytics_Stats' ) ) {
13
- /**
14
- * BSF analytics stat class.
15
- */
16
- class BSF_Analytics_Stats {
17
-
18
- /**
19
- * Active plugins.
20
- *
21
- * Holds the sites active plugins list.
22
- *
23
- * @var array
24
- */
25
- private $plugins;
26
-
27
- /**
28
- * Instance of BSF_Analytics_Stats.
29
- *
30
- * Holds only the first object of class.
31
- *
32
- * @var object
33
- */
34
- private static $instance = null;
35
-
36
- /**
37
- * Create only once instance of a class.
38
- *
39
- * @return object
40
- * @since 1.0.0
41
- */
42
- public static function instance() {
43
- if ( null === self::$instance ) {
44
- self::$instance = new self();
45
- }
46
-
47
- return self::$instance;
48
- }
49
-
50
- /**
51
- * Get stats.
52
- *
53
- * @return array stats data.
54
- * @since 1.0.0
55
- */
56
- public function get_stats() {
57
- return apply_filters( 'bsf_core_stats', $this->get_default_stats() );
58
- }
59
-
60
- /**
61
- * Retrieve stats for site.
62
- *
63
- * @return array stats data.
64
- * @since 1.0.0
65
- */
66
- private function get_default_stats() {
67
- return array(
68
- 'graupi_version' => defined( 'BSF_UPDATER_VERSION' ) ? BSF_UPDATER_VERSION : false,
69
- 'domain_name' => get_site_url(),
70
- 'php_os' => PHP_OS,
71
- 'server_software' => isset( $_SERVER['SERVER_SOFTWARE'] ) ? filter_var( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ), FILTER_SANITIZE_STRING ) : '',
72
- 'mysql_version' => $this->get_mysql_version(),
73
- 'php_version' => $this->get_php_version(),
74
- 'php_max_input_vars' => ini_get( 'max_input_vars' ), // phpcs:ignore:PHPCompatibility.IniDirectives.NewIniDirectives.max_input_varsFound
75
- 'php_post_max_size' => ini_get( 'post_max_size' ),
76
- 'php_max_execution_time' => ini_get( 'max_execution_time' ),
77
- 'php_memory_limit' => ini_get( 'memory_limit' ),
78
- 'zip_installed' => extension_loaded( 'zip' ),
79
- 'imagick_availabile' => extension_loaded( 'imagick' ),
80
- 'xmlreader_exists' => class_exists( 'XMLReader' ),
81
- 'gd_available' => extension_loaded( 'gd' ),
82
- 'curl_version' => $this->get_curl_version(),
83
- 'curl_ssl_version' => $this->get_curl_ssl_version(),
84
- 'is_writable' => $this->is_content_writable(),
85
-
86
- 'wp_version' => get_bloginfo( 'version' ),
87
- 'user_count' => $this->get_user_count(),
88
- 'site_language' => get_locale(),
89
- 'timezone' => wp_timezone_string(),
90
- 'is_ssl' => is_ssl(),
91
- 'is_multisite' => is_multisite(),
92
- 'network_url' => network_site_url(),
93
- 'external_object_cache' => (bool) wp_using_ext_object_cache(),
94
- 'wp_debug' => WP_DEBUG,
95
- 'wp_debug_display' => WP_DEBUG_DISPLAY,
96
- 'script_debug' => SCRIPT_DEBUG,
97
-
98
- 'active_plugins' => $this->get_active_plugins(),
99
-
100
- 'active_theme' => get_template(),
101
- 'active_stylesheet' => get_stylesheet(),
102
- );
103
- }
104
-
105
- /**
106
- * Get installed PHP version.
107
- *
108
- * @return float PHP version.
109
- * @since 1.0.0
110
- */
111
- private function get_php_version() {
112
- if ( defined( 'PHP_MAJOR_VERSION' ) && defined( 'PHP_MINOR_VERSION' ) && defined( 'PHP_RELEASE_VERSION' ) ) { // phpcs:ignore
113
- return PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION;
114
- }
115
-
116
- return phpversion();
117
- }
118
-
119
- /**
120
- * User count on site.
121
- *
122
- * @return int User count.
123
- * @since 1.0.0
124
- */
125
- private function get_user_count() {
126
- if ( is_multisite() ) {
127
- $user_count = get_user_count();
128
- } else {
129
- $count = count_users();
130
- $user_count = $count['total_users'];
131
- }
132
-
133
- return $user_count;
134
- }
135
-
136
- /**
137
- * Get active plugin's data.
138
- *
139
- * @return array active plugin's list.
140
- * @since 1.0.0
141
- */
142
- private function get_active_plugins() {
143
- if ( ! $this->plugins ) {
144
- // Ensure get_plugin_data function is loaded.
145
- if ( ! function_exists( 'get_plugin_data' ) ) {
146
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
147
- }
148
-
149
- $plugins = wp_get_active_and_valid_plugins();
150
- $plugins = array_map( 'get_plugin_data', $plugins );
151
- $this->plugins = array_map( array( $this, 'format_plugin' ), $plugins );
152
- }
153
-
154
- return $this->plugins;
155
- }
156
-
157
- /**
158
- * Format plugin data.
159
- *
160
- * @param string $plugin plugin.
161
- * @return array formatted plugin data.
162
- * @since 1.0.0
163
- */
164
- public function format_plugin( $plugin ) {
165
- return array(
166
- 'name' => html_entity_decode( $plugin['Name'], ENT_COMPAT, 'UTF-8' ),
167
- 'url' => $plugin['PluginURI'],
168
- 'version' => $plugin['Version'],
169
- 'slug' => $plugin['TextDomain'],
170
- 'author_name' => html_entity_decode( wp_strip_all_tags( $plugin['Author'] ), ENT_COMPAT, 'UTF-8' ),
171
- 'author_url' => $plugin['AuthorURI'],
172
- );
173
- }
174
-
175
- /**
176
- * Curl SSL version.
177
- *
178
- * @return float SSL version.
179
- * @since 1.0.0
180
- */
181
- private function get_curl_ssl_version() {
182
- $curl = array();
183
- if ( function_exists( 'curl_version' ) ) {
184
- $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version
185
- }
186
-
187
- return isset( $curl['ssl_version'] ) ? $curl['ssl_version'] : false;
188
- }
189
-
190
- /**
191
- * Get cURL version.
192
- *
193
- * @return float cURL version.
194
- * @since 1.0.0
195
- */
196
- private function get_curl_version() {
197
- if ( function_exists( 'curl_version' ) ) {
198
- $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version
199
- }
200
-
201
- return isset( $curl['version'] ) ? $curl['version'] : false;
202
- }
203
-
204
- /**
205
- * Get MySQL version.
206
- *
207
- * @return float MySQL version.
208
- * @since 1.0.0
209
- */
210
- private function get_mysql_version() {
211
- global $wpdb;
212
- return $wpdb->db_version();
213
- }
214
-
215
- /**
216
- * Check if content directory is writable.
217
- *
218
- * @return bool
219
- * @since 1.0.0
220
- */
221
- private function is_content_writable() {
222
- $upload_dir = wp_upload_dir();
223
- return wp_is_writable( $upload_dir['basedir'] );
224
- }
225
- }
226
- }
227
-
228
- /**
229
- * Polyfill for sites using WP version less than 5.3
230
- */
231
- if ( ! function_exists( 'wp_timezone_string' ) ) {
232
- /**
233
- * Get timezone string.
234
- *
235
- * @return string timezone string.
236
- * @since 1.0.0
237
- */
238
- function wp_timezone_string() {
239
- $timezone_string = get_option( 'timezone_string' );
240
-
241
- if ( $timezone_string ) {
242
- return $timezone_string;
243
- }
244
-
245
- $offset = (float) get_option( 'gmt_offset' );
246
- $hours = (int) $offset;
247
- $minutes = ( $offset - $hours );
248
-
249
- $sign = ( $offset < 0 ) ? '-' : '+';
250
- $abs_hour = abs( $hours );
251
- $abs_mins = abs( $minutes * 60 );
252
- $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
253
-
254
- return $tz_offset;
255
- }
256
- }
1
+ <?php
2
+ /**
3
+ * BSF analytics stat class file.
4
+ *
5
+ * @package bsf-analytics
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly.
10
+ }
11
+
12
+ if ( ! class_exists( 'BSF_Analytics_Stats' ) ) {
13
+ /**
14
+ * BSF analytics stat class.
15
+ */
16
+ class BSF_Analytics_Stats {
17
+
18
+ /**
19
+ * Active plugins.
20
+ *
21
+ * Holds the sites active plugins list.
22
+ *
23
+ * @var array
24
+ */
25
+ private $plugins;
26
+
27
+ /**
28
+ * Instance of BSF_Analytics_Stats.
29
+ *
30
+ * Holds only the first object of class.
31
+ *
32
+ * @var object
33
+ */
34
+ private static $instance = null;
35
+
36
+ /**
37
+ * Create only once instance of a class.
38
+ *
39
+ * @return object
40
+ * @since 1.0.0
41
+ */
42
+ public static function instance() {
43
+ if ( null === self::$instance ) {
44
+ self::$instance = new self();
45
+ }
46
+
47
+ return self::$instance;
48
+ }
49
+
50
+ /**
51
+ * Get stats.
52
+ *
53
+ * @return array stats data.
54
+ * @since 1.0.0
55
+ */
56
+ public function get_stats() {
57
+ return apply_filters( 'bsf_core_stats', $this->get_default_stats() );
58
+ }
59
+
60
+ /**
61
+ * Retrieve stats for site.
62
+ *
63
+ * @return array stats data.
64
+ * @since 1.0.0
65
+ */
66
+ private function get_default_stats() {
67
+ return array(
68
+ 'graupi_version' => defined( 'BSF_UPDATER_VERSION' ) ? BSF_UPDATER_VERSION : false,
69
+ 'domain_name' => get_site_url(),
70
+ 'php_os' => PHP_OS,
71
+ 'server_software' => isset( $_SERVER['SERVER_SOFTWARE'] ) ? filter_var( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ), FILTER_SANITIZE_STRING ) : '',
72
+ 'mysql_version' => $this->get_mysql_version(),
73
+ 'php_version' => $this->get_php_version(),
74
+ 'php_max_input_vars' => ini_get( 'max_input_vars' ), // phpcs:ignore:PHPCompatibility.IniDirectives.NewIniDirectives.max_input_varsFound
75
+ 'php_post_max_size' => ini_get( 'post_max_size' ),
76
+ 'php_max_execution_time' => ini_get( 'max_execution_time' ),
77
+ 'php_memory_limit' => ini_get( 'memory_limit' ),
78
+ 'zip_installed' => extension_loaded( 'zip' ),
79
+ 'imagick_availabile' => extension_loaded( 'imagick' ),
80
+ 'xmlreader_exists' => class_exists( 'XMLReader' ),
81
+ 'gd_available' => extension_loaded( 'gd' ),
82
+ 'curl_version' => $this->get_curl_version(),
83
+ 'curl_ssl_version' => $this->get_curl_ssl_version(),
84
+ 'is_writable' => $this->is_content_writable(),
85
+
86
+ 'wp_version' => get_bloginfo( 'version' ),
87
+ 'user_count' => $this->get_user_count(),
88
+ 'site_language' => get_locale(),
89
+ 'timezone' => wp_timezone_string(),
90
+ 'is_ssl' => is_ssl(),
91
+ 'is_multisite' => is_multisite(),
92
+ 'network_url' => network_site_url(),
93
+ 'external_object_cache' => (bool) wp_using_ext_object_cache(),
94
+ 'wp_debug' => WP_DEBUG,
95
+ 'wp_debug_display' => WP_DEBUG_DISPLAY,
96
+ 'script_debug' => SCRIPT_DEBUG,
97
+
98
+ 'active_plugins' => $this->get_active_plugins(),
99
+
100
+ 'active_theme' => get_template(),
101
+ 'active_stylesheet' => get_stylesheet(),
102
+ );
103
+ }
104
+
105
+ /**
106
+ * Get installed PHP version.
107
+ *
108
+ * @return float PHP version.
109
+ * @since 1.0.0
110
+ */
111
+ private function get_php_version() {
112
+ if ( defined( 'PHP_MAJOR_VERSION' ) && defined( 'PHP_MINOR_VERSION' ) && defined( 'PHP_RELEASE_VERSION' ) ) { // phpcs:ignore
113
+ return PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION;
114
+ }
115
+
116
+ return phpversion();
117
+ }
118
+
119
+ /**
120
+ * User count on site.
121
+ *
122
+ * @return int User count.
123
+ * @since 1.0.0
124
+ */
125
+ private function get_user_count() {
126
+ if ( is_multisite() ) {
127
+ $user_count = get_user_count();
128
+ } else {
129
+ $count = count_users();
130
+ $user_count = $count['total_users'];
131
+ }
132
+
133
+ return $user_count;
134
+ }
135
+
136
+ /**
137
+ * Get active plugin's data.
138
+ *
139
+ * @return array active plugin's list.
140
+ * @since 1.0.0
141
+ */
142
+ private function get_active_plugins() {
143
+ if ( ! $this->plugins ) {
144
+ // Ensure get_plugin_data function is loaded.
145
+ if ( ! function_exists( 'get_plugin_data' ) ) {
146
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
147
+ }
148
+
149
+ $plugins = wp_get_active_and_valid_plugins();
150
+ $plugins = array_map( 'get_plugin_data', $plugins );
151
+ $this->plugins = array_map( array( $this, 'format_plugin' ), $plugins );
152
+ }
153
+
154
+ return $this->plugins;
155
+ }
156
+
157
+ /**
158
+ * Format plugin data.
159
+ *
160
+ * @param string $plugin plugin.
161
+ * @return array formatted plugin data.
162
+ * @since 1.0.0
163
+ */
164
+ public function format_plugin( $plugin ) {
165
+ return array(
166
+ 'name' => html_entity_decode( $plugin['Name'], ENT_COMPAT, 'UTF-8' ),
167
+ 'url' => $plugin['PluginURI'],
168
+ 'version' => $plugin['Version'],
169
+ 'slug' => $plugin['TextDomain'],
170
+ 'author_name' => html_entity_decode( wp_strip_all_tags( $plugin['Author'] ), ENT_COMPAT, 'UTF-8' ),
171
+ 'author_url' => $plugin['AuthorURI'],
172
+ );
173
+ }
174
+
175
+ /**
176
+ * Curl SSL version.
177
+ *
178
+ * @return float SSL version.
179
+ * @since 1.0.0
180
+ */
181
+ private function get_curl_ssl_version() {
182
+ $curl = array();
183
+ if ( function_exists( 'curl_version' ) ) {
184
+ $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version
185
+ }
186
+
187
+ return isset( $curl['ssl_version'] ) ? $curl['ssl_version'] : false;
188
+ }
189
+
190
+ /**
191
+ * Get cURL version.
192
+ *
193
+ * @return float cURL version.
194
+ * @since 1.0.0
195
+ */
196
+ private function get_curl_version() {
197
+ if ( function_exists( 'curl_version' ) ) {
198
+ $curl = curl_version(); // phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_version
199
+ }
200
+
201
+ return isset( $curl['version'] ) ? $curl['version'] : false;
202
+ }
203
+
204
+ /**
205
+ * Get MySQL version.
206
+ *
207
+ * @return float MySQL version.
208
+ * @since 1.0.0
209
+ */
210
+ private function get_mysql_version() {
211
+ global $wpdb;
212
+ return $wpdb->db_version();
213
+ }
214
+
215
+ /**
216
+ * Check if content directory is writable.
217
+ *
218
+ * @return bool
219
+ * @since 1.0.0
220
+ */
221
+ private function is_content_writable() {
222
+ $upload_dir = wp_upload_dir();
223
+ return wp_is_writable( $upload_dir['basedir'] );
224
+ }
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Polyfill for sites using WP version less than 5.3
230
+ */
231
+ if ( ! function_exists( 'wp_timezone_string' ) ) {
232
+ /**
233
+ * Get timezone string.
234
+ *
235
+ * @return string timezone string.
236
+ * @since 1.0.0
237
+ */
238
+ function wp_timezone_string() {
239
+ $timezone_string = get_option( 'timezone_string' );
240
+
241
+ if ( $timezone_string ) {
242
+ return $timezone_string;
243
+ }
244
+
245
+ $offset = (float) get_option( 'gmt_offset' );
246
+ $hours = (int) $offset;
247
+ $minutes = ( $offset - $hours );
248
+
249
+ $sign = ( $offset < 0 ) ? '-' : '+';
250
+ $abs_hour = abs( $hours );
251
+ $abs_mins = abs( $minutes * 60 );
252
+ $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
253
+
254
+ return $tz_offset;
255
+ }
256
+ }
admin/bsf-analytics/class-bsf-analytics.php CHANGED
@@ -18,60 +18,74 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
18
  */
19
  class BSF_Analytics {
20
 
 
 
 
 
 
 
 
21
  /**
22
  * Member Variable
23
  *
24
  * @var string Usage tracking document URL
25
  */
26
- private $usage_doc_link = 'https://store.brainstormforce.com/usage-tracking/?utm_source=wp_dashboard&utm_medium=general_settings&utm_campaign=usage_tracking';
27
 
28
  /**
29
  * Setup actions, load files.
30
  *
 
 
 
31
  * @since 1.0.0
32
  */
33
- public function __construct() {
 
 
 
 
 
 
 
34
 
35
- define( 'BSF_ANALYTICS_FILE', __FILE__ );
36
- define( 'BSF_ANALYTICS_VERSION', '1.0.2' );
37
- define( 'BSF_ANALYTICS_PATH', dirname( __FILE__ ) );
38
- define( 'BSF_ANALYTICS_URI', $this->bsf_analytics_url() );
39
 
40
  add_action( 'admin_init', array( $this, 'handle_optin_optout' ) );
41
- add_action( 'cron_schedules', array( $this, 'every_two_days_schedule' ) );
42
  add_action( 'admin_notices', array( $this, 'option_notice' ) );
43
- add_action( 'astra_notice_before_markup_bsf-optin-notice', array( $this, 'enqueue_assets' ) );
44
 
45
- add_action( 'init', array( $this, 'schedule_unschedule_event' ) );
46
-
47
- if ( ! has_action( 'bsf_analytics_send', array( $this, 'send' ) ) ) {
48
- add_action( 'bsf_analytics_send', array( $this, 'send' ) );
49
- }
50
 
51
  add_action( 'admin_init', array( $this, 'register_usage_tracking_setting' ) );
52
 
53
- add_action( 'update_option_bsf_analytics_optin', array( $this, 'update_analytics_option_callback' ), 10, 3 );
54
- add_action( 'add_option_bsf_analytics_optin', array( $this, 'add_analytics_option_callback' ), 10, 2 );
55
-
56
  $this->includes();
57
  }
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  /**
60
  * BSF Analytics URL
61
  *
 
62
  * @return String URL of bsf-analytics directory.
63
  * @since 1.0.0
64
  */
65
- public function bsf_analytics_url() {
66
-
67
- $path = wp_normalize_path( BSF_ANALYTICS_PATH );
68
- $theme_dir = wp_normalize_path( get_template_directory() );
69
-
70
- if ( strpos( $path, $theme_dir ) !== false ) {
71
- return rtrim( get_template_directory_uri() . '/admin/bsf-analytics/', '/' );
72
- } else {
73
- return rtrim( plugin_dir_url( BSF_ANALYTICS_FILE ), '/' );
74
- }
75
  }
76
 
77
  /**
@@ -129,21 +143,30 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
129
  * @since 1.0.0
130
  */
131
  public function is_tracking_enabled() {
132
- $is_enabled = get_site_option( 'bsf_analytics_optin' ) === 'yes' ? true : false;
133
- $is_enabled = $this->is_white_label_enabled() ? false : $is_enabled;
134
 
135
- return apply_filters( 'bsf_tracking_enabled', $is_enabled );
 
 
 
 
 
 
 
 
 
 
136
  }
137
 
138
  /**
139
  * Check if WHITE label is enabled for BSF products.
140
  *
 
141
  * @return bool
142
  * @since 1.0.0
143
  */
144
- public function is_white_label_enabled() {
145
 
146
- $options = apply_filters( 'bsf_white_label_options', array() );
147
  $is_enabled = false;
148
 
149
  if ( is_array( $options ) ) {
@@ -169,67 +192,75 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
169
  return;
170
  }
171
 
172
- // Don't display the notice if tracking is disabled or White Label is enabled for any of our plugins.
173
- if ( false !== get_site_option( 'bsf_analytics_optin', false ) || $this->is_white_label_enabled() ) {
174
- return;
175
- }
176
 
177
- // Show tracker consent notice after 24 hours from installed time.
178
- if ( strtotime( '+24 hours', $this->get_analytics_install_time() ) > time() ) {
179
- return;
180
- }
181
 
182
- /* translators: %s product name */
183
- $notice_string = __( 'Want to help make <strong>%1s</strong> even more awesome? Allow us to collect non-sensitive diagnostic data and usage information. ', 'woo-cart-abandonment-recovery' );
 
 
184
 
185
- if ( is_multisite() ) {
186
- $notice_string .= __( 'This will be applicable for all sites from the network.', 'woo-cart-abandonment-recovery' );
187
- }
 
188
 
189
- $language_dir = is_rtl() ? 'rtl' : 'ltr';
 
190
 
191
- Astra_Notices::add_notice(
192
- array(
193
- 'id' => 'bsf-optin-notice',
194
- 'type' => '',
195
- 'message' => sprintf(
196
- '<div class="notice-content">
197
- <div class="notice-heading">
198
- %1$s
199
- </div>
200
- <div class="astra-notices-container">
201
- <a href="%2$s" class="astra-notices button-primary">
202
- %3$s
203
- </a>
204
- <a href="%4$s" data-repeat-notice-after="%5$s" class="astra-notices button-secondary">
205
- %6$s
206
- </a>
207
- </div>
208
- </div>',
209
- /* translators: %s usage doc link */
210
- sprintf( $notice_string . '<span dir="%2s"><a href="%3s" target="_blank" rel="noreferrer noopener">%4s</a><span>', esc_html( $this->get_product_name() ), $language_dir, esc_url( $this->usage_doc_link ), __( ' Know More.', 'woo-cart-abandonment-recovery' ) ),
211
- add_query_arg(
212
- array(
213
- 'bsf_analytics_optin' => 'yes',
214
- 'bsf_analytics_nonce' => wp_create_nonce( 'bsf_analytics_optin' ),
215
- )
216
- ),
217
- __( 'Yes! Allow it', 'woo-cart-abandonment-recovery' ),
218
- add_query_arg(
219
- array(
220
- 'bsf_analytics_optin' => 'no',
221
- 'bsf_analytics_nonce' => wp_create_nonce( 'bsf_analytics_optin' ),
222
- )
 
 
 
 
 
 
 
 
 
 
 
223
  ),
224
- MONTH_IN_SECONDS,
225
- __( 'No Thanks', 'woo-cart-abandonment-recovery' )
226
- ),
227
- 'show_if' => true,
228
- 'repeat-notice-after' => false,
229
- 'priority' => 18,
230
- 'display-with-other-notices' => true,
231
- )
232
- );
233
  }
234
 
235
  /**
@@ -238,27 +269,35 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
238
  * @since 1.0.0
239
  */
240
  public function handle_optin_optout() {
241
- if ( ! isset( $_GET['bsf_analytics_nonce'] ) ) {
 
 
 
 
 
 
 
242
  return;
243
  }
244
 
245
- if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['bsf_analytics_nonce'] ) ), 'bsf_analytics_optin' ) ) {
246
  return;
247
  }
248
 
249
- $optin_status = isset( $_GET['bsf_analytics_optin'] ) ? sanitize_text_field( wp_unslash( $_GET['bsf_analytics_optin'] ) ) : '';
250
 
251
  if ( 'yes' === $optin_status ) {
252
- $this->optin();
253
  } elseif ( 'no' === $optin_status ) {
254
- $this->optout();
255
  }
256
 
257
  wp_safe_redirect(
258
  remove_query_arg(
259
  array(
260
- 'bsf_analytics_optin',
261
- 'bsf_analytics_nonce',
 
262
  )
263
  )
264
  );
@@ -267,54 +306,21 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
267
  /**
268
  * Opt in to usage tracking.
269
  *
 
270
  * @since 1.0.0
271
  */
272
- private function optin() {
273
- update_site_option( 'bsf_analytics_optin', 'yes' );
274
  }
275
 
276
  /**
277
  * Opt out to usage tracking.
278
  *
 
279
  * @since 1.0.0
280
  */
281
- private function optout() {
282
- update_site_option( 'bsf_analytics_optin', 'no' );
283
- }
284
-
285
- /**
286
- * Add two days event schedule variables.
287
- *
288
- * @param array $schedules scheduled array data.
289
- * @since 1.0.0
290
- */
291
- public function every_two_days_schedule( $schedules ) {
292
- $schedules['every_two_days'] = array(
293
- 'interval' => 2 * DAY_IN_SECONDS,
294
- 'display' => __( 'Every two days', 'woo-cart-abandonment-recovery' ),
295
- );
296
-
297
- return $schedules;
298
- }
299
-
300
- /**
301
- * Schedule usage tracking event.
302
- *
303
- * @since 1.0.0
304
- */
305
- private function schedule_event() {
306
- if ( ! wp_next_scheduled( 'bsf_analytics_send' ) && $this->is_tracking_enabled() ) {
307
- wp_schedule_event( time(), 'every_two_days', 'bsf_analytics_send' );
308
- }
309
- }
310
-
311
- /**
312
- * Unschedule usage tracking event.
313
- *
314
- * @since 1.0.0
315
- */
316
- private function unschedule_event() {
317
- wp_clear_scheduled_hook( 'bsf_analytics_send' );
318
  }
319
 
320
  /**
@@ -333,22 +339,37 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
333
  */
334
  public function register_usage_tracking_setting() {
335
 
336
- if ( ! apply_filters( 'bsf_tracking_enabled', true ) || $this->is_white_label_enabled() ) {
337
- return;
338
- }
339
 
340
- register_setting(
341
- 'general', // Options group.
342
- 'bsf_analytics_optin', // Option name/database.
343
- array( 'sanitize_callback' => array( $this, 'sanitize_option' ) ) // sanitize callback function.
344
- );
345
 
346
- add_settings_field(
347
- 'bsf-analytics-optin', // Field ID.
348
- __( 'Usage Tracking', 'woo-cart-abandonment-recovery' ), // Field title.
349
- array( $this, 'render_settings_field_html' ), // Field callback function.
350
- 'general' // Settings page slug.
351
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  }
353
 
354
  /**
@@ -369,15 +390,17 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
369
  /**
370
  * Print settings field HTML.
371
  *
 
372
  * @since 1.0.0
373
  */
374
- public function render_settings_field_html() {
375
  ?>
376
  <fieldset>
377
- <label for="bsf-analytics-optin">
378
- <input id="bsf-analytics-optin" type="checkbox" value="1" name="bsf_analytics_optin" <?php checked( get_site_option( 'bsf_analytics_optin', 'no' ), 'yes' ); ?>>
379
  <?php
380
- esc_html_e( 'Allow Brainstorm Force products to track non-sensitive usage tracking data.', 'woo-cart-abandonment-recovery' );
 
381
 
382
  if ( is_multisite() ) {
383
  esc_html_e( ' This will be applicable for all sites from the network.', 'woo-cart-abandonment-recovery' );
@@ -385,75 +408,26 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
385
  ?>
386
  </label>
387
  <?php
388
- echo wp_kses_post( sprintf( '<a href="%1s" target="_blank" rel="noreferrer noopener">%2s</a>', esc_url( $this->usage_doc_link ), __( 'Learn More.', 'woo-cart-abandonment-recovery' ) ) );
389
  ?>
390
  </fieldset>
391
  <?php
392
  }
393
 
394
- /**
395
- * Get current product name.
396
- *
397
- * @return string $plugin_data['Name] Name of plugin.
398
- * @since 1.0.0
399
- */
400
- private function get_product_name() {
401
-
402
- $base = wp_normalize_path( dirname( __FILE__ ) );
403
- $theme_dir = wp_normalize_path( get_template_directory() );
404
-
405
- if ( false !== strpos( $base, $theme_dir ) ) {
406
- $theme = wp_get_theme( get_template() );
407
- return $theme->get( 'Name' );
408
- }
409
-
410
- $base = plugin_basename( __FILE__ );
411
-
412
- $exploded_path = explode( '/', $base, 2 );
413
- $plugin_slug = $exploded_path[0];
414
-
415
- return $this->get_plugin_name( $plugin_slug );
416
- }
417
-
418
- /**
419
- * Get plugin name by plugin slug.
420
- *
421
- * @param string $plugin_slug Plugin slug.
422
- * @return string $plugin_info['Name'] Plugin name.
423
- */
424
- private function get_plugin_name( $plugin_slug ) {
425
-
426
- $plugins = get_option( 'active_plugins' );
427
-
428
- if ( ! function_exists( 'get_plugin_data' ) ) {
429
- require_once ABSPATH . 'wp-admin/includes/plugin.php';
430
- }
431
-
432
- foreach ( $plugins as $plugin_file ) {
433
-
434
- $plugin_folder = explode( "/", $plugin_file );
435
- $plugin_folder = $plugin_folder[0];
436
- if ( $plugin_folder === $plugin_slug ) {
437
- $plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file;
438
- $plugin_data = get_plugin_data( $plugin_path );
439
- return $plugin_data['Name'];
440
- }
441
- }
442
- }
443
-
444
  /**
445
  * Set analytics installed time in option.
446
  *
 
447
  * @return string $time analytics installed time.
448
  * @since 1.0.0
449
  */
450
- private function get_analytics_install_time() {
451
 
452
- $time = get_site_option( 'bsf_analytics_installed_time' );
453
 
454
  if ( ! $time ) {
455
  $time = time();
456
- update_site_option( 'bsf_analytics_installed_time', time() );
457
  }
458
 
459
  return $time;
@@ -468,7 +442,9 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
468
  * @since 1.0.0
469
  */
470
  public function update_analytics_option_callback( $old_value, $value, $option ) {
471
- $this->add_option_to_network( $value );
 
 
472
  }
473
 
474
  /**
@@ -479,50 +455,49 @@ if ( ! class_exists( 'BSF_Analytics' ) ) {
479
  * @since 1.0.0
480
  */
481
  public function add_analytics_option_callback( $option, $value ) {
482
- $this->add_option_to_network( $value );
 
 
483
  }
484
 
485
  /**
486
- * Schedule or unschedule event based on analytics option value.
487
  *
488
  * @since 1.0.0
489
  */
490
- public function schedule_unschedule_event() {
491
 
492
- if ( true === $this->is_white_label_enabled() ) {
493
- $this->unschedule_event();
494
  return;
495
  }
496
 
497
- $analytics_option = get_site_option( 'bsf_analytics_optin' );
498
 
499
- if ( 'no' === $analytics_option ) {
500
- $this->unschedule_event();
501
- } elseif ( 'yes' === $analytics_option ) {
502
- $this->schedule_event();
503
  }
504
  }
505
 
506
  /**
507
  * Save analytics option to network.
508
  *
 
509
  * @param string $value value of option.
510
  * @since 1.0.0
511
  */
512
- public function add_option_to_network( $value ) {
513
 
514
  // If action coming from general settings page.
515
  if ( isset( $_POST['option_page'] ) && 'general' === $_POST['option_page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
516
 
517
- if ( get_site_option( 'bsf_analytics_optin' ) ) {
518
- update_site_option( 'bsf_analytics_optin', $value );
519
  } else {
520
- add_site_option( 'bsf_analytics_optin', $value );
521
  }
522
  }
523
  }
524
  }
525
-
526
- new BSF_Analytics();
527
-
528
  }
18
  */
19
  class BSF_Analytics {
20
 
21
+ /**
22
+ * Member Variable
23
+ *
24
+ * @var array Entities data.
25
+ */
26
+ private $entities;
27
+
28
  /**
29
  * Member Variable
30
  *
31
  * @var string Usage tracking document URL
32
  */
33
+ public $usage_doc_link = 'https://store.brainstormforce.com/usage-tracking/?utm_source=wp_dashboard&utm_medium=general_settings&utm_campaign=usage_tracking';
34
 
35
  /**
36
  * Setup actions, load files.
37
  *
38
+ * @param array $args entity data for analytics.
39
+ * @param string $analytics_path directory path to analytics library.
40
+ * @param float $analytics_version analytics library version.
41
  * @since 1.0.0
42
  */
43
+ public function __construct( $args, $analytics_path, $analytics_version ) {
44
+
45
+ // Bail when no analytics entities are registered.
46
+ if ( empty( $args ) ) {
47
+ return;
48
+ }
49
+
50
+ $this->entities = $args;
51
 
52
+ define( 'BSF_ANALYTICS_VERSION', $analytics_version );
53
+ define( 'BSF_ANALYTICS_URI', $this->get_analytics_url( $analytics_path ) );
 
 
54
 
55
  add_action( 'admin_init', array( $this, 'handle_optin_optout' ) );
 
56
  add_action( 'admin_notices', array( $this, 'option_notice' ) );
57
+ add_action( 'init', array( $this, 'maybe_track_analytics' ), 99 );
58
 
59
+ $this->set_actions();
 
 
 
 
60
 
61
  add_action( 'admin_init', array( $this, 'register_usage_tracking_setting' ) );
62
 
 
 
 
63
  $this->includes();
64
  }
65
 
66
+ /**
67
+ * Setup actions for admin notice style and analytics cron event.
68
+ *
69
+ * @since 1.0.4
70
+ */
71
+ public function set_actions() {
72
+
73
+ foreach ( $this->entities as $key => $data ) {
74
+ add_action( 'astra_notice_before_markup_' . $key . '-optin-notice', array( $this, 'enqueue_assets' ) );
75
+ add_action( 'update_option_' . $key . '_analytics_optin', array( $this, 'update_analytics_option_callback' ), 10, 3 );
76
+ add_action( 'add_option_' . $key . '_analytics_optin', array( $this, 'add_analytics_option_callback' ), 10, 2 );
77
+ }
78
+ }
79
+
80
  /**
81
  * BSF Analytics URL
82
  *
83
+ * @param string $analytics_path directory path to analytics library.
84
  * @return String URL of bsf-analytics directory.
85
  * @since 1.0.0
86
  */
87
+ public function get_analytics_url( $analytics_path ) {
88
+ return str_replace( WP_CONTENT_DIR, content_url(), $analytics_path );
 
 
 
 
 
 
 
 
89
  }
90
 
91
  /**
143
  * @since 1.0.0
144
  */
145
  public function is_tracking_enabled() {
 
 
146
 
147
+ foreach ( $this->entities as $key => $data ) {
148
+
149
+ $is_enabled = get_site_option( $key . '_analytics_optin' ) === 'yes' ? true : false;
150
+ $is_enabled = $this->is_white_label_enabled( $key ) ? false : $is_enabled;
151
+
152
+ if ( apply_filters( $key . '_tracking_enabled', $is_enabled ) ) {
153
+ return true;
154
+ }
155
+ }
156
+
157
+ return false;
158
  }
159
 
160
  /**
161
  * Check if WHITE label is enabled for BSF products.
162
  *
163
+ * @param string $source source of analytics.
164
  * @return bool
165
  * @since 1.0.0
166
  */
167
+ public function is_white_label_enabled( $source ) {
168
 
169
+ $options = apply_filters( $source . '_white_label_options', array() );
170
  $is_enabled = false;
171
 
172
  if ( is_array( $options ) ) {
192
  return;
193
  }
194
 
195
+ foreach ( $this->entities as $key => $data ) {
 
 
 
196
 
197
+ $time_to_display = isset( $data['time_to_display'] ) ? $data['time_to_display'] : '+24 hours';
198
+ $usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->usage_doc_link;
 
 
199
 
200
+ // Don't display the notice if tracking is disabled or White Label is enabled for any of our plugins.
201
+ if ( false !== get_site_option( $key . '_analytics_optin', false ) || $this->is_white_label_enabled( $key ) ) {
202
+ continue;
203
+ }
204
 
205
+ // Show tracker consent notice after 24 hours from installed time.
206
+ if ( strtotime( $time_to_display, $this->get_analytics_install_time( $key ) ) > time() ) {
207
+ continue;
208
+ }
209
 
210
+ /* translators: %s product name */
211
+ $notice_string = __( 'Want to help make <strong>%1s</strong> even more awesome? Allow us to collect non-sensitive diagnostic data and usage information. ', 'woo-cart-abandonment-recovery' );
212
 
213
+ if ( is_multisite() ) {
214
+ $notice_string .= __( 'This will be applicable for all sites from the network.', 'woo-cart-abandonment-recovery' );
215
+ }
216
+
217
+ $language_dir = is_rtl() ? 'rtl' : 'ltr';
218
+
219
+ Astra_Notices::add_notice(
220
+ array(
221
+ 'id' => $key . '-optin-notice',
222
+ 'type' => '',
223
+ 'message' => sprintf(
224
+ '<div class="notice-content">
225
+ <div class="notice-heading">
226
+ %1$s
227
+ </div>
228
+ <div class="astra-notices-container">
229
+ <a href="%2$s" class="astra-notices button-primary">
230
+ %3$s
231
+ </a>
232
+ <a href="%4$s" data-repeat-notice-after="%5$s" class="astra-notices button-secondary">
233
+ %6$s
234
+ </a>
235
+ </div>
236
+ </div>',
237
+ /* translators: %s usage doc link */
238
+ sprintf( $notice_string . '<span dir="%2s"><a href="%3s" target="_blank" rel="noreferrer noopener">%4s</a><span>', esc_html( $data['product_name'] ), $language_dir, esc_url( $usage_doc_link ), __( ' Know More.', 'woo-cart-abandonment-recovery' ) ),
239
+ add_query_arg(
240
+ array(
241
+ $key . '_analytics_optin' => 'yes',
242
+ $key . '_analytics_nonce' => wp_create_nonce( $key . '_analytics_optin' ),
243
+ 'bsf_analytics_source' => $key,
244
+ )
245
+ ),
246
+ __( 'Yes! Allow it', 'woo-cart-abandonment-recovery' ),
247
+ add_query_arg(
248
+ array(
249
+ $key . '_analytics_optin' => 'no',
250
+ $key . '_analytics_nonce' => wp_create_nonce( $key . '_analytics_optin' ),
251
+ 'bsf_analytics_source' => $key,
252
+ )
253
+ ),
254
+ MONTH_IN_SECONDS,
255
+ __( 'No Thanks', 'woo-cart-abandonment-recovery' )
256
  ),
257
+ 'show_if' => true,
258
+ 'repeat-notice-after' => false,
259
+ 'priority' => 18,
260
+ 'display-with-other-notices' => true,
261
+ )
262
+ );
263
+ }
 
 
264
  }
265
 
266
  /**
269
  * @since 1.0.0
270
  */
271
  public function handle_optin_optout() {
272
+
273
+ if ( ! current_user_can( 'manage_options' ) ) {
274
+ return;
275
+ }
276
+
277
+ $source = isset( $_GET['bsf_analytics_source'] ) ? sanitize_text_field( wp_unslash( $_GET['bsf_analytics_source'] ) ) : '';
278
+
279
+ if ( ! isset( $_GET[ $source . '_analytics_nonce' ] ) ) {
280
  return;
281
  }
282
 
283
+ if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET[ $source . '_analytics_nonce' ] ) ), $source . '_analytics_optin' ) ) {
284
  return;
285
  }
286
 
287
+ $optin_status = isset( $_GET[ $source . '_analytics_optin' ] ) ? sanitize_text_field( wp_unslash( $_GET[ $source . '_analytics_optin' ] ) ) : '';
288
 
289
  if ( 'yes' === $optin_status ) {
290
+ $this->optin( $source );
291
  } elseif ( 'no' === $optin_status ) {
292
+ $this->optout( $source );
293
  }
294
 
295
  wp_safe_redirect(
296
  remove_query_arg(
297
  array(
298
+ $source . '_analytics_optin',
299
+ $source . '_analytics_nonce',
300
+ 'bsf_analytics_source',
301
  )
302
  )
303
  );
306
  /**
307
  * Opt in to usage tracking.
308
  *
309
+ * @param string $source source of analytics.
310
  * @since 1.0.0
311
  */
312
+ private function optin( $source ) {
313
+ update_site_option( $source . '_analytics_optin', 'yes' );
314
  }
315
 
316
  /**
317
  * Opt out to usage tracking.
318
  *
319
+ * @param string $source source of analytics.
320
  * @since 1.0.0
321
  */
322
+ private function optout( $source ) {
323
+ update_site_option( $source . '_analytics_optin', 'no' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  }
325
 
326
  /**
339
  */
340
  public function register_usage_tracking_setting() {
341
 
342
+ foreach ( $this->entities as $key => $data ) {
 
 
343
 
344
+ if ( ! apply_filters( $key . '_tracking_enabled', true ) || $this->is_white_label_enabled( $key ) ) {
345
+ return;
346
+ }
 
 
347
 
348
+ $usage_doc_link = isset( $data['usage_doc_link'] ) ? $data['usage_doc_link'] : $this->usage_doc_link;
349
+ $author = isset( $data['author'] ) ? $data['author'] : 'Brainstorm Force';
350
+
351
+ register_setting(
352
+ 'general', // Options group.
353
+ $key . '_analytics_optin', // Option name/database.
354
+ array( 'sanitize_callback' => array( $this, 'sanitize_option' ) ) // sanitize callback function.
355
+ );
356
+
357
+ add_settings_field(
358
+ $key . '-analytics-optin', // Field ID.
359
+ __( 'Usage Tracking', 'woo-cart-abandonment-recovery' ), // Field title.
360
+ array( $this, 'render_settings_field_html' ), // Field callback function.
361
+ 'general',
362
+ 'default', // Settings page slug.
363
+ array(
364
+ 'type' => 'checkbox',
365
+ 'title' => $author,
366
+ 'name' => $key . '_analytics_optin',
367
+ 'label_for' => $key . '-analytics-optin',
368
+ 'id' => $key . '-analytics-optin',
369
+ 'usage_doc_link' => $usage_doc_link,
370
+ )
371
+ );
372
+ }
373
  }
374
 
375
  /**
390
  /**
391
  * Print settings field HTML.
392
  *
393
+ * @param array $args arguments to field.
394
  * @since 1.0.0
395
  */
396
+ public function render_settings_field_html( $args ) {
397
  ?>
398
  <fieldset>
399
+ <label for="<?php echo esc_attr( $args['label_for'] ); ?>">
400
+ <input id="<?php echo esc_attr( $args['id'] ); ?>" type="checkbox" value="1" name="<?php echo esc_attr( $args['name'] ); ?>" <?php checked( get_site_option( $args['name'], 'no' ), 'yes' ); ?>>
401
  <?php
402
+ /* translators: %s Product title */
403
+ echo esc_html( sprintf( __( 'Allow %s products to track non-sensitive usage tracking data.', 'woo-cart-abandonment-recovery' ), $args['title'] ) );// phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
404
 
405
  if ( is_multisite() ) {
406
  esc_html_e( ' This will be applicable for all sites from the network.', 'woo-cart-abandonment-recovery' );
408
  ?>
409
  </label>
410
  <?php
411
+ echo wp_kses_post( sprintf( '<a href="%1s" target="_blank" rel="noreferrer noopener">%2s</a>', esc_url( $args['usage_doc_link'] ), __( 'Learn More.', 'woo-cart-abandonment-recovery' ) ) );
412
  ?>
413
  </fieldset>
414
  <?php
415
  }
416
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
  /**
418
  * Set analytics installed time in option.
419
  *
420
+ * @param string $source source of analytics.
421
  * @return string $time analytics installed time.
422
  * @since 1.0.0
423
  */
424
+ private function get_analytics_install_time( $source ) {
425
 
426
+ $time = get_site_option( $source . '_analytics_installed_time' );
427
 
428
  if ( ! $time ) {
429
  $time = time();
430
+ update_site_option( $source . '_analytics_installed_time', time() );
431
  }
432
 
433
  return $time;
442
  * @since 1.0.0
443
  */
444
  public function update_analytics_option_callback( $old_value, $value, $option ) {
445
+ if ( is_multisite() ) {
446
+ $this->add_option_to_network( $option, $value );
447
+ }
448
  }
449
 
450
  /**
455
  * @since 1.0.0
456
  */
457
  public function add_analytics_option_callback( $option, $value ) {
458
+ if ( is_multisite() ) {
459
+ $this->add_option_to_network( $option, $value );
460
+ }
461
  }
462
 
463
  /**
464
+ * Send analaytics track event if tracking is enabled.
465
  *
466
  * @since 1.0.0
467
  */
468
+ public function maybe_track_analytics() {
469
 
470
+ if ( ! $this->is_tracking_enabled() ) {
 
471
  return;
472
  }
473
 
474
+ $analytics_track = get_site_transient( 'bsf_analytics_track' );
475
 
476
+ // If the last data sent is 2 days old i.e. transient is expired.
477
+ if ( ! $analytics_track ) {
478
+ $this->send();
479
+ set_site_transient( 'bsf_analytics_track', true, 2 * DAY_IN_SECONDS );
480
  }
481
  }
482
 
483
  /**
484
  * Save analytics option to network.
485
  *
486
+ * @param string $option name of option.
487
  * @param string $value value of option.
488
  * @since 1.0.0
489
  */
490
+ public function add_option_to_network( $option, $value ) {
491
 
492
  // If action coming from general settings page.
493
  if ( isset( $_POST['option_page'] ) && 'general' === $_POST['option_page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
494
 
495
+ if ( get_site_option( $option ) ) {
496
+ update_site_option( $option, $value );
497
  } else {
498
+ add_site_option( $option, $value );
499
  }
500
  }
501
  }
502
  }
 
 
 
503
  }
admin/bsf-analytics/composer.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "require-dev": {
3
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4",
4
+ "wp-coding-standards/wpcs": "2.2.1",
5
+ "phpcompatibility/phpcompatibility-wp": "2.1.0",
6
+ "brainmaestro/composer-git-hooks": "^2.6"
7
+ },
8
+ "scripts": {
9
+ "format": "phpcbf --standard=phpcs.xml.dist --report-summary --report-source",
10
+ "lint": "phpcs --standard=phpcs.xml.dist --report-summary --report-source",
11
+ "post-install-cmd": "vendor/bin/cghooks add --ignore-lock",
12
+ "post-update-cmd": "vendor/bin/cghooks update"
13
+ },
14
+ "extra": {
15
+ "hooks": {
16
+ "pre-commit": [
17
+ "echo committing as $(git config user.name)",
18
+ "sh bin/block-commits-with-merge-conflict.sh"
19
+ ]
20
+ }
21
+ }
22
+ }
admin/bsf-analytics/composer.lock ADDED
@@ -0,0 +1,711 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_readme": [
3
+ "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
+ "This file is @generated automatically"
6
+ ],
7
+ "content-hash": "3fea1d501a95bbd7e1f1492dae0a3847",
8
+ "packages": [],
9
+ "packages-dev": [
10
+ {
11
+ "name": "brainmaestro/composer-git-hooks",
12
+ "version": "v2.8.3",
13
+ "source": {
14
+ "type": "git",
15
+ "url": "https://github.com/BrainMaestro/composer-git-hooks.git",
16
+ "reference": "97888dd34e900931117747cd34a42fdfcf271142"
17
+ },
18
+ "dist": {
19
+ "type": "zip",
20
+ "url": "https://api.github.com/repos/BrainMaestro/composer-git-hooks/zipball/97888dd34e900931117747cd34a42fdfcf271142",
21
+ "reference": "97888dd34e900931117747cd34a42fdfcf271142",
22
+ "shasum": ""
23
+ },
24
+ "require": {
25
+ "php": "^5.6 || >=7.0",
26
+ "symfony/console": "^3.2 || ^4.0 || ^5.0"
27
+ },
28
+ "require-dev": {
29
+ "ext-json": "*",
30
+ "friendsofphp/php-cs-fixer": "^2.9",
31
+ "phpunit/phpunit": "^5.7 || ^7.0"
32
+ },
33
+ "bin": [
34
+ "cghooks"
35
+ ],
36
+ "type": "library",
37
+ "extra": {
38
+ "hooks": {
39
+ "pre-commit": "composer check-style",
40
+ "pre-push": [
41
+ "composer test",
42
+ "appver=$(grep -o -E '\\d.\\d.\\d' cghooks)",
43
+ "tag=$(git describe --tags --abbrev=0)",
44
+ "if [ \"$tag\" != \"v$appver\" ]; then",
45
+ "echo \"The most recent tag $tag does not match the application version $appver\\n\"",
46
+ "tag=${tag#v}",
47
+ "sed -i -E \"s/$appver/$tag/\" cghooks",
48
+ "exit 1",
49
+ "fi"
50
+ ]
51
+ }
52
+ },
53
+ "autoload": {
54
+ "psr-4": {
55
+ "BrainMaestro\\GitHooks\\": "src/"
56
+ },
57
+ "files": [
58
+ "src/helpers.php"
59
+ ]
60
+ },
61
+ "notification-url": "https://packagist.org/downloads/",
62
+ "license": [
63
+ "MIT"
64
+ ],
65
+ "authors": [
66
+ {
67
+ "name": "Ezinwa Okpoechi",
68
+ "email": "brainmaestro@outlook.com"
69
+ }
70
+ ],
71
+ "description": "Easily manage git hooks in your composer config",
72
+ "keywords": [
73
+ "HOOK",
74
+ "composer",
75
+ "git"
76
+ ],
77
+ "time": "2019-12-09T09:49:20+00:00"
78
+ },
79
+ {
80
+ "name": "dealerdirect/phpcodesniffer-composer-installer",
81
+ "version": "v0.4.4",
82
+ "source": {
83
+ "type": "git",
84
+ "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git",
85
+ "reference": "2e41850d5f7797cbb1af7b030d245b3b24e63a08"
86
+ },
87
+ "dist": {
88
+ "type": "zip",
89
+ "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/2e41850d5f7797cbb1af7b030d245b3b24e63a08",
90
+ "reference": "2e41850d5f7797cbb1af7b030d245b3b24e63a08",
91
+ "shasum": ""
92
+ },
93
+ "require": {
94
+ "composer-plugin-api": "^1.0",
95
+ "php": "^5.3|^7",
96
+ "squizlabs/php_codesniffer": "*"
97
+ },
98
+ "require-dev": {
99
+ "composer/composer": "*",
100
+ "wimg/php-compatibility": "^8.0"
101
+ },
102
+ "suggest": {
103
+ "dealerdirect/qa-tools": "All the PHP QA tools you'll need"
104
+ },
105
+ "type": "composer-plugin",
106
+ "extra": {
107
+ "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin"
108
+ },
109
+ "autoload": {
110
+ "psr-4": {
111
+ "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/"
112
+ }
113
+ },
114
+ "notification-url": "https://packagist.org/downloads/",
115
+ "license": [
116
+ "MIT"
117
+ ],
118
+ "authors": [
119
+ {
120
+ "name": "Franck Nijhof",
121
+ "email": "f.nijhof@dealerdirect.nl",
122
+ "homepage": "http://workingatdealerdirect.eu",
123
+ "role": "Developer"
124
+ }
125
+ ],
126
+ "description": "PHP_CodeSniffer Standards Composer Installer Plugin",
127
+ "homepage": "http://workingatdealerdirect.eu",
128
+ "keywords": [
129
+ "PHPCodeSniffer",
130
+ "PHP_CodeSniffer",
131
+ "code quality",
132
+ "codesniffer",
133
+ "composer",
134
+ "installer",
135
+ "phpcs",
136
+ "plugin",
137
+ "qa",
138
+ "quality",
139
+ "standard",
140
+ "standards",
141
+ "style guide",
142
+ "stylecheck",
143
+ "tests"
144
+ ],
145
+ "time": "2017-12-06T16:27:17+00:00"
146
+ },
147
+ {
148
+ "name": "phpcompatibility/php-compatibility",
149
+ "version": "9.3.5",
150
+ "source": {
151
+ "type": "git",
152
+ "url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
153
+ "reference": "9fb324479acf6f39452e0655d2429cc0d3914243"
154
+ },
155
+ "dist": {
156
+ "type": "zip",
157
+ "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243",
158
+ "reference": "9fb324479acf6f39452e0655d2429cc0d3914243",
159
+ "shasum": ""
160
+ },
161
+ "require": {
162
+ "php": ">=5.3",
163
+ "squizlabs/php_codesniffer": "^2.3 || ^3.0.2"
164
+ },
165
+ "conflict": {
166
+ "squizlabs/php_codesniffer": "2.6.2"
167
+ },
168
+ "require-dev": {
169
+ "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0"
170
+ },
171
+ "suggest": {
172
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.",
173
+ "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
174
+ },
175
+ "type": "phpcodesniffer-standard",
176
+ "notification-url": "https://packagist.org/downloads/",
177
+ "license": [
178
+ "LGPL-3.0-or-later"
179
+ ],
180
+ "authors": [
181
+ {
182
+ "name": "Wim Godden",
183
+ "homepage": "https://github.com/wimg",
184
+ "role": "lead"
185
+ },
186
+ {
187
+ "name": "Juliette Reinders Folmer",
188
+ "homepage": "https://github.com/jrfnl",
189
+ "role": "lead"
190
+ },
191
+ {
192
+ "name": "Contributors",
193
+ "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors"
194
+ }
195
+ ],
196
+ "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.",
197
+ "homepage": "http://techblog.wimgodden.be/tag/codesniffer/",
198
+ "keywords": [
199
+ "compatibility",
200
+ "phpcs",
201
+ "standards"
202
+ ],
203
+ "time": "2019-12-27T09:44:58+00:00"
204
+ },
205
+ {
206
+ "name": "phpcompatibility/phpcompatibility-paragonie",
207
+ "version": "1.3.0",
208
+ "source": {
209
+ "type": "git",
210
+ "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
211
+ "reference": "b862bc32f7e860d0b164b199bd995e690b4b191c"
212
+ },
213
+ "dist": {
214
+ "type": "zip",
215
+ "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c",
216
+ "reference": "b862bc32f7e860d0b164b199bd995e690b4b191c",
217
+ "shasum": ""
218
+ },
219
+ "require": {
220
+ "phpcompatibility/php-compatibility": "^9.0"
221
+ },
222
+ "require-dev": {
223
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5",
224
+ "paragonie/random_compat": "dev-master",
225
+ "paragonie/sodium_compat": "dev-master"
226
+ },
227
+ "suggest": {
228
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
229
+ "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
230
+ },
231
+ "type": "phpcodesniffer-standard",
232
+ "notification-url": "https://packagist.org/downloads/",
233
+ "license": [
234
+ "LGPL-3.0-or-later"
235
+ ],
236
+ "authors": [
237
+ {
238
+ "name": "Wim Godden",
239
+ "role": "lead"
240
+ },
241
+ {
242
+ "name": "Juliette Reinders Folmer",
243
+ "role": "lead"
244
+ }
245
+ ],
246
+ "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.",
247
+ "homepage": "http://phpcompatibility.com/",
248
+ "keywords": [
249
+ "compatibility",
250
+ "paragonie",
251
+ "phpcs",
252
+ "polyfill",
253
+ "standards"
254
+ ],
255
+ "time": "2019-11-04T15:17:54+00:00"
256
+ },
257
+ {
258
+ "name": "phpcompatibility/phpcompatibility-wp",
259
+ "version": "2.1.0",
260
+ "source": {
261
+ "type": "git",
262
+ "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git",
263
+ "reference": "41bef18ba688af638b7310666db28e1ea9158b2f"
264
+ },
265
+ "dist": {
266
+ "type": "zip",
267
+ "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f",
268
+ "reference": "41bef18ba688af638b7310666db28e1ea9158b2f",
269
+ "shasum": ""
270
+ },
271
+ "require": {
272
+ "phpcompatibility/php-compatibility": "^9.0",
273
+ "phpcompatibility/phpcompatibility-paragonie": "^1.0"
274
+ },
275
+ "require-dev": {
276
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5"
277
+ },
278
+ "suggest": {
279
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.",
280
+ "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues."
281
+ },
282
+ "type": "phpcodesniffer-standard",
283
+ "notification-url": "https://packagist.org/downloads/",
284
+ "license": [
285
+ "LGPL-3.0-or-later"
286
+ ],
287
+ "authors": [
288
+ {
289
+ "name": "Wim Godden",
290
+ "role": "lead"
291
+ },
292
+ {
293
+ "name": "Juliette Reinders Folmer",
294
+ "role": "lead"
295
+ }
296
+ ],
297
+ "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.",
298
+ "homepage": "http://phpcompatibility.com/",
299
+ "keywords": [
300
+ "compatibility",
301
+ "phpcs",
302
+ "standards",
303
+ "wordpress"
304
+ ],
305
+ "time": "2019-08-28T14:22:28+00:00"
306
+ },
307
+ {
308
+ "name": "psr/container",
309
+ "version": "1.0.0",
310
+ "source": {
311
+ "type": "git",
312
+ "url": "https://github.com/php-fig/container.git",
313
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f"
314
+ },
315
+ "dist": {
316
+ "type": "zip",
317
+ "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
318
+ "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f",
319
+ "shasum": ""
320
+ },
321
+ "require": {
322
+ "php": ">=5.3.0"
323
+ },
324
+ "type": "library",
325
+ "extra": {
326
+ "branch-alias": {
327
+ "dev-master": "1.0.x-dev"
328
+ }
329
+ },
330
+ "autoload": {
331
+ "psr-4": {
332
+ "Psr\\Container\\": "src/"
333
+ }
334
+ },
335
+ "notification-url": "https://packagist.org/downloads/",
336
+ "license": [
337
+ "MIT"
338
+ ],
339
+ "authors": [
340
+ {
341
+ "name": "PHP-FIG",
342
+ "homepage": "http://www.php-fig.org/"
343
+ }
344
+ ],
345
+ "description": "Common Container Interface (PHP FIG PSR-11)",
346
+ "homepage": "https://github.com/php-fig/container",
347
+ "keywords": [
348
+ "PSR-11",
349
+ "container",
350
+ "container-interface",
351
+ "container-interop",
352
+ "psr"
353
+ ],
354
+ "time": "2017-02-14T16:28:37+00:00"
355
+ },
356
+ {
357
+ "name": "squizlabs/php_codesniffer",
358
+ "version": "3.5.4",
359
+ "source": {
360
+ "type": "git",
361
+ "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
362
+ "reference": "dceec07328401de6211037abbb18bda423677e26"
363
+ },
364
+ "dist": {
365
+ "type": "zip",
366
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dceec07328401de6211037abbb18bda423677e26",
367
+ "reference": "dceec07328401de6211037abbb18bda423677e26",
368
+ "shasum": ""
369
+ },
370
+ "require": {
371
+ "ext-simplexml": "*",
372
+ "ext-tokenizer": "*",
373
+ "ext-xmlwriter": "*",
374
+ "php": ">=5.4.0"
375
+ },
376
+ "require-dev": {
377
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
378
+ },
379
+ "bin": [
380
+ "bin/phpcs",
381
+ "bin/phpcbf"
382
+ ],
383
+ "type": "library",
384
+ "extra": {
385
+ "branch-alias": {
386
+ "dev-master": "3.x-dev"
387
+ }
388
+ },
389
+ "notification-url": "https://packagist.org/downloads/",
390
+ "license": [
391
+ "BSD-3-Clause"
392
+ ],
393
+ "authors": [
394
+ {
395
+ "name": "Greg Sherwood",
396
+ "role": "lead"
397
+ }
398
+ ],
399
+ "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
400
+ "homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
401
+ "keywords": [
402
+ "phpcs",
403
+ "standards"
404
+ ],
405
+ "time": "2020-01-30T22:20:29+00:00"
406
+ },
407
+ {
408
+ "name": "symfony/console",
409
+ "version": "v5.0.5",
410
+ "source": {
411
+ "type": "git",
412
+ "url": "https://github.com/symfony/console.git",
413
+ "reference": "d29e2d36941de13600c399e393a60b8cfe59ac49"
414
+ },
415
+ "dist": {
416
+ "type": "zip",
417
+ "url": "https://api.github.com/repos/symfony/console/zipball/d29e2d36941de13600c399e393a60b8cfe59ac49",
418
+ "reference": "d29e2d36941de13600c399e393a60b8cfe59ac49",
419
+ "shasum": ""
420
+ },
421
+ "require": {
422
+ "php": "^7.2.5",
423
+ "symfony/polyfill-mbstring": "~1.0",
424
+ "symfony/polyfill-php73": "^1.8",
425
+ "symfony/service-contracts": "^1.1|^2"
426
+ },
427
+ "conflict": {
428
+ "symfony/dependency-injection": "<4.4",
429
+ "symfony/event-dispatcher": "<4.4",
430
+ "symfony/lock": "<4.4",
431
+ "symfony/process": "<4.4"
432
+ },
433
+ "provide": {
434
+ "psr/log-implementation": "1.0"
435
+ },
436
+ "require-dev": {
437
+ "psr/log": "~1.0",
438
+ "symfony/config": "^4.4|^5.0",
439
+ "symfony/dependency-injection": "^4.4|^5.0",
440
+ "symfony/event-dispatcher": "^4.4|^5.0",
441
+ "symfony/lock": "^4.4|^5.0",
442
+ "symfony/process": "^4.4|^5.0",
443
+ "symfony/var-dumper": "^4.4|^5.0"
444
+ },
445
+ "suggest": {
446
+ "psr/log": "For using the console logger",
447
+ "symfony/event-dispatcher": "",
448
+ "symfony/lock": "",
449
+ "symfony/process": ""
450
+ },
451
+ "type": "library",
452
+ "extra": {
453
+ "branch-alias": {
454
+ "dev-master": "5.0-dev"
455
+ }
456
+ },
457
+ "autoload": {
458
+ "psr-4": {
459
+ "Symfony\\Component\\Console\\": ""
460
+ },
461
+ "exclude-from-classmap": [
462
+ "/Tests/"
463
+ ]
464
+ },
465
+ "notification-url": "https://packagist.org/downloads/",
466
+ "license": [
467
+ "MIT"
468
+ ],
469
+ "authors": [
470
+ {
471
+ "name": "Fabien Potencier",
472
+ "email": "fabien@symfony.com"
473
+ },
474
+ {
475
+ "name": "Symfony Community",
476
+ "homepage": "https://symfony.com/contributors"
477
+ }
478
+ ],
479
+ "description": "Symfony Console Component",
480
+ "homepage": "https://symfony.com",
481
+ "time": "2020-02-24T15:05:31+00:00"
482
+ },
483
+ {
484
+ "name": "symfony/polyfill-mbstring",
485
+ "version": "v1.14.0",
486
+ "source": {
487
+ "type": "git",
488
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
489
+ "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2"
490
+ },
491
+ "dist": {
492
+ "type": "zip",
493
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2",
494
+ "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2",
495
+ "shasum": ""
496
+ },
497
+ "require": {
498
+ "php": ">=5.3.3"
499
+ },
500
+ "suggest": {
501
+ "ext-mbstring": "For best performance"
502
+ },
503
+ "type": "library",
504
+ "extra": {
505
+ "branch-alias": {
506
+ "dev-master": "1.14-dev"
507
+ }
508
+ },
509
+ "autoload": {
510
+ "psr-4": {
511
+ "Symfony\\Polyfill\\Mbstring\\": ""
512
+ },
513
+ "files": [
514
+ "bootstrap.php"
515
+ ]
516
+ },
517
+ "notification-url": "https://packagist.org/downloads/",
518
+ "license": [
519
+ "MIT"
520
+ ],
521
+ "authors": [
522
+ {
523
+ "name": "Nicolas Grekas",
524
+ "email": "p@tchwork.com"
525
+ },
526
+ {
527
+ "name": "Symfony Community",
528
+ "homepage": "https://symfony.com/contributors"
529
+ }
530
+ ],
531
+ "description": "Symfony polyfill for the Mbstring extension",
532
+ "homepage": "https://symfony.com",
533
+ "keywords": [
534
+ "compatibility",
535
+ "mbstring",
536
+ "polyfill",
537
+ "portable",
538
+ "shim"
539
+ ],
540
+ "time": "2020-01-13T11:15:53+00:00"
541
+ },
542
+ {
543
+ "name": "symfony/polyfill-php73",
544
+ "version": "v1.14.0",
545
+ "source": {
546
+ "type": "git",
547
+ "url": "https://github.com/symfony/polyfill-php73.git",
548
+ "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675"
549
+ },
550
+ "dist": {
551
+ "type": "zip",
552
+ "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675",
553
+ "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675",
554
+ "shasum": ""
555
+ },
556
+ "require": {
557
+ "php": ">=5.3.3"
558
+ },
559
+ "type": "library",
560
+ "extra": {
561
+ "branch-alias": {
562
+ "dev-master": "1.14-dev"
563
+ }
564
+ },
565
+ "autoload": {
566
+ "psr-4": {
567
+ "Symfony\\Polyfill\\Php73\\": ""
568
+ },
569
+ "files": [
570
+ "bootstrap.php"
571
+ ],
572
+ "classmap": [
573
+ "Resources/stubs"
574
+ ]
575
+ },
576
+ "notification-url": "https://packagist.org/downloads/",
577
+ "license": [
578
+ "MIT"
579
+ ],
580
+ "authors": [
581
+ {
582
+ "name": "Nicolas Grekas",
583
+ "email": "p@tchwork.com"
584
+ },
585
+ {
586
+ "name": "Symfony Community",
587
+ "homepage": "https://symfony.com/contributors"
588
+ }
589
+ ],
590
+ "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
591
+ "homepage": "https://symfony.com",
592
+ "keywords": [
593
+ "compatibility",
594
+ "polyfill",
595
+ "portable",
596
+ "shim"
597
+ ],
598
+ "time": "2020-01-13T11:15:53+00:00"
599
+ },
600
+ {
601
+ "name": "symfony/service-contracts",
602
+ "version": "v2.0.1",
603
+ "source": {
604
+ "type": "git",
605
+ "url": "https://github.com/symfony/service-contracts.git",
606
+ "reference": "144c5e51266b281231e947b51223ba14acf1a749"
607
+ },
608
+ "dist": {
609
+ "type": "zip",
610
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749",
611
+ "reference": "144c5e51266b281231e947b51223ba14acf1a749",
612
+ "shasum": ""
613
+ },
614
+ "require": {
615
+ "php": "^7.2.5",
616
+ "psr/container": "^1.0"
617
+ },
618
+ "suggest": {
619
+ "symfony/service-implementation": ""
620
+ },
621
+ "type": "library",
622
+ "extra": {
623
+ "branch-alias": {
624
+ "dev-master": "2.0-dev"
625
+ }
626
+ },
627
+ "autoload": {
628
+ "psr-4": {
629
+ "Symfony\\Contracts\\Service\\": ""
630
+ }
631
+ },
632
+ "notification-url": "https://packagist.org/downloads/",
633
+ "license": [
634
+ "MIT"
635
+ ],
636
+ "authors": [
637
+ {
638
+ "name": "Nicolas Grekas",
639
+ "email": "p@tchwork.com"
640
+ },
641
+ {
642
+ "name": "Symfony Community",
643
+ "homepage": "https://symfony.com/contributors"
644
+ }
645
+ ],
646
+ "description": "Generic abstractions related to writing services",
647
+ "homepage": "https://symfony.com",
648
+ "keywords": [
649
+ "abstractions",
650
+ "contracts",
651
+ "decoupling",
652
+ "interfaces",
653
+ "interoperability",
654
+ "standards"
655
+ ],
656
+ "time": "2019-11-18T17:27:11+00:00"
657
+ },
658
+ {
659
+ "name": "wp-coding-standards/wpcs",
660
+ "version": "2.2.1",
661
+ "source": {
662
+ "type": "git",
663
+ "url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
664
+ "reference": "b5a453203114cc2284b1a614c4953456fbe4f546"
665
+ },
666
+ "dist": {
667
+ "type": "zip",
668
+ "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/b5a453203114cc2284b1a614c4953456fbe4f546",
669
+ "reference": "b5a453203114cc2284b1a614c4953456fbe4f546",
670
+ "shasum": ""
671
+ },
672
+ "require": {
673
+ "php": ">=5.4",
674
+ "squizlabs/php_codesniffer": "^3.3.1"
675
+ },
676
+ "require-dev": {
677
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
678
+ "phpcompatibility/php-compatibility": "^9.0",
679
+ "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
680
+ },
681
+ "suggest": {
682
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
683
+ },
684
+ "type": "phpcodesniffer-standard",
685
+ "notification-url": "https://packagist.org/downloads/",
686
+ "license": [
687
+ "MIT"
688
+ ],
689
+ "authors": [
690
+ {
691
+ "name": "Contributors",
692
+ "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
693
+ }
694
+ ],
695
+ "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
696
+ "keywords": [
697
+ "phpcs",
698
+ "standards",
699
+ "wordpress"
700
+ ],
701
+ "time": "2020-02-04T02:52:06+00:00"
702
+ }
703
+ ],
704
+ "aliases": [],
705
+ "minimum-stability": "stable",
706
+ "stability-flags": [],
707
+ "prefer-stable": false,
708
+ "prefer-lowest": false,
709
+ "platform": [],
710
+ "platform-dev": []
711
+ }
admin/bsf-analytics/package-lock.json ADDED
@@ -0,0 +1,3978 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "bsf-analytics",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 1,
5
+ "requires": true,
6
+ "dependencies": {
7
+ "abbrev": {
8
+ "version": "1.1.1",
9
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
10
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
11
+ },
12
+ "ajv": {
13
+ "version": "6.12.0",
14
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
15
+ "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
16
+ "dev": true,
17
+ "requires": {
18
+ "fast-deep-equal": "^3.1.1",
19
+ "fast-json-stable-stringify": "^2.0.0",
20
+ "json-schema-traverse": "^0.4.1",
21
+ "uri-js": "^4.2.2"
22
+ }
23
+ },
24
+ "amdefine": {
25
+ "version": "1.0.1",
26
+ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
27
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
28
+ "dev": true
29
+ },
30
+ "ansi-regex": {
31
+ "version": "2.1.1",
32
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
33
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
34
+ "dev": true
35
+ },
36
+ "ansi-styles": {
37
+ "version": "3.2.1",
38
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
39
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
40
+ "dev": true,
41
+ "requires": {
42
+ "color-convert": "^1.9.0"
43
+ }
44
+ },
45
+ "aproba": {
46
+ "version": "1.2.0",
47
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
48
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
49
+ "dev": true
50
+ },
51
+ "archiver": {
52
+ "version": "1.3.0",
53
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz",
54
+ "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=",
55
+ "dev": true,
56
+ "requires": {
57
+ "archiver-utils": "^1.3.0",
58
+ "async": "^2.0.0",
59
+ "buffer-crc32": "^0.2.1",
60
+ "glob": "^7.0.0",
61
+ "lodash": "^4.8.0",
62
+ "readable-stream": "^2.0.0",
63
+ "tar-stream": "^1.5.0",
64
+ "walkdir": "^0.0.11",
65
+ "zip-stream": "^1.1.0"
66
+ },
67
+ "dependencies": {
68
+ "async": {
69
+ "version": "2.6.3",
70
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
71
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
72
+ "dev": true,
73
+ "requires": {
74
+ "lodash": "^4.17.14"
75
+ }
76
+ }
77
+ }
78
+ },
79
+ "archiver-utils": {
80
+ "version": "1.3.0",
81
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz",
82
+ "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=",
83
+ "dev": true,
84
+ "requires": {
85
+ "glob": "^7.0.0",
86
+ "graceful-fs": "^4.1.0",
87
+ "lazystream": "^1.0.0",
88
+ "lodash": "^4.8.0",
89
+ "normalize-path": "^2.0.0",
90
+ "readable-stream": "^2.0.0"
91
+ }
92
+ },
93
+ "are-we-there-yet": {
94
+ "version": "1.1.5",
95
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
96
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
97
+ "dev": true,
98
+ "requires": {
99
+ "delegates": "^1.0.0",
100
+ "readable-stream": "^2.0.6"
101
+ }
102
+ },
103
+ "argparse": {
104
+ "version": "1.0.10",
105
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
106
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
107
+ "dev": true,
108
+ "requires": {
109
+ "sprintf-js": "~1.0.2"
110
+ },
111
+ "dependencies": {
112
+ "sprintf-js": {
113
+ "version": "1.0.3",
114
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
115
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
116
+ "dev": true
117
+ }
118
+ }
119
+ },
120
+ "arr-diff": {
121
+ "version": "4.0.0",
122
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
123
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
124
+ },
125
+ "arr-flatten": {
126
+ "version": "1.1.0",
127
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
128
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
129
+ },
130
+ "arr-union": {
131
+ "version": "3.1.0",
132
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
133
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
134
+ },
135
+ "array-each": {
136
+ "version": "1.0.1",
137
+ "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
138
+ "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8="
139
+ },
140
+ "array-find-index": {
141
+ "version": "1.0.2",
142
+ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
143
+ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
144
+ "dev": true
145
+ },
146
+ "array-slice": {
147
+ "version": "1.1.0",
148
+ "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
149
+ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w=="
150
+ },
151
+ "array-unique": {
152
+ "version": "0.3.2",
153
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
154
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
155
+ },
156
+ "asn1": {
157
+ "version": "0.2.4",
158
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
159
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
160
+ "dev": true,
161
+ "requires": {
162
+ "safer-buffer": "~2.1.0"
163
+ }
164
+ },
165
+ "assert-plus": {
166
+ "version": "1.0.0",
167
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
168
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
169
+ "dev": true
170
+ },
171
+ "assign-symbols": {
172
+ "version": "1.0.0",
173
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
174
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
175
+ },
176
+ "async": {
177
+ "version": "1.5.2",
178
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
179
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
180
+ "dev": true
181
+ },
182
+ "async-foreach": {
183
+ "version": "0.1.3",
184
+ "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
185
+ "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
186
+ "dev": true
187
+ },
188
+ "asynckit": {
189
+ "version": "0.4.0",
190
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
191
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
192
+ "dev": true
193
+ },
194
+ "atob": {
195
+ "version": "2.1.2",
196
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
197
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
198
+ },
199
+ "autoprefixer": {
200
+ "version": "9.7.6",
201
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.6.tgz",
202
+ "integrity": "sha512-F7cYpbN7uVVhACZTeeIeealwdGM6wMtfWARVLTy5xmKtgVdBNJvbDRoCK3YO1orcs7gv/KwYlb3iXwu9Ug9BkQ==",
203
+ "dev": true,
204
+ "requires": {
205
+ "browserslist": "^4.11.1",
206
+ "caniuse-lite": "^1.0.30001039",
207
+ "chalk": "^2.4.2",
208
+ "normalize-range": "^0.1.2",
209
+ "num2fraction": "^1.2.2",
210
+ "postcss": "^7.0.27",
211
+ "postcss-value-parser": "^4.0.3"
212
+ }
213
+ },
214
+ "aws-sign2": {
215
+ "version": "0.7.0",
216
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
217
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
218
+ "dev": true
219
+ },
220
+ "aws4": {
221
+ "version": "1.9.1",
222
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
223
+ "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==",
224
+ "dev": true
225
+ },
226
+ "balanced-match": {
227
+ "version": "1.0.0",
228
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
229
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
230
+ "dev": true
231
+ },
232
+ "base": {
233
+ "version": "0.11.2",
234
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
235
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
236
+ "requires": {
237
+ "cache-base": "^1.0.1",
238
+ "class-utils": "^0.3.5",
239
+ "component-emitter": "^1.2.1",
240
+ "define-property": "^1.0.0",
241
+ "isobject": "^3.0.1",
242
+ "mixin-deep": "^1.2.0",
243
+ "pascalcase": "^0.1.1"
244
+ },
245
+ "dependencies": {
246
+ "define-property": {
247
+ "version": "1.0.0",
248
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
249
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
250
+ "requires": {
251
+ "is-descriptor": "^1.0.0"
252
+ }
253
+ },
254
+ "is-accessor-descriptor": {
255
+ "version": "1.0.0",
256
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
257
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
258
+ "requires": {
259
+ "kind-of": "^6.0.0"
260
+ }
261
+ },
262
+ "is-data-descriptor": {
263
+ "version": "1.0.0",
264
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
265
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
266
+ "requires": {
267
+ "kind-of": "^6.0.0"
268
+ }
269
+ },
270
+ "is-descriptor": {
271
+ "version": "1.0.2",
272
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
273
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
274
+ "requires": {
275
+ "is-accessor-descriptor": "^1.0.0",
276
+ "is-data-descriptor": "^1.0.0",
277
+ "kind-of": "^6.0.2"
278
+ }
279
+ }
280
+ }
281
+ },
282
+ "base64-js": {
283
+ "version": "1.3.1",
284
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
285
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
286
+ "dev": true
287
+ },
288
+ "bcrypt-pbkdf": {
289
+ "version": "1.0.2",
290
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
291
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
292
+ "dev": true,
293
+ "requires": {
294
+ "tweetnacl": "^0.14.3"
295
+ }
296
+ },
297
+ "bl": {
298
+ "version": "1.2.2",
299
+ "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
300
+ "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
301
+ "dev": true,
302
+ "requires": {
303
+ "readable-stream": "^2.3.5",
304
+ "safe-buffer": "^5.1.1"
305
+ }
306
+ },
307
+ "block-stream": {
308
+ "version": "0.0.9",
309
+ "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
310
+ "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
311
+ "dev": true,
312
+ "requires": {
313
+ "inherits": "~2.0.0"
314
+ }
315
+ },
316
+ "brace-expansion": {
317
+ "version": "1.1.11",
318
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
319
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
320
+ "dev": true,
321
+ "requires": {
322
+ "balanced-match": "^1.0.0",
323
+ "concat-map": "0.0.1"
324
+ }
325
+ },
326
+ "braces": {
327
+ "version": "2.3.2",
328
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
329
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
330
+ "requires": {
331
+ "arr-flatten": "^1.1.0",
332
+ "array-unique": "^0.3.2",
333
+ "extend-shallow": "^2.0.1",
334
+ "fill-range": "^4.0.0",
335
+ "isobject": "^3.0.1",
336
+ "repeat-element": "^1.1.2",
337
+ "snapdragon": "^0.8.1",
338
+ "snapdragon-node": "^2.0.1",
339
+ "split-string": "^3.0.2",
340
+ "to-regex": "^3.0.1"
341
+ },
342
+ "dependencies": {
343
+ "extend-shallow": {
344
+ "version": "2.0.1",
345
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
346
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
347
+ "requires": {
348
+ "is-extendable": "^0.1.0"
349
+ }
350
+ }
351
+ }
352
+ },
353
+ "browserslist": {
354
+ "version": "4.11.1",
355
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.11.1.tgz",
356
+ "integrity": "sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g==",
357
+ "dev": true,
358
+ "requires": {
359
+ "caniuse-lite": "^1.0.30001038",
360
+ "electron-to-chromium": "^1.3.390",
361
+ "node-releases": "^1.1.53",
362
+ "pkg-up": "^2.0.0"
363
+ }
364
+ },
365
+ "buffer": {
366
+ "version": "5.6.0",
367
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
368
+ "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
369
+ "dev": true,
370
+ "requires": {
371
+ "base64-js": "^1.0.2",
372
+ "ieee754": "^1.1.4"
373
+ }
374
+ },
375
+ "buffer-alloc": {
376
+ "version": "1.2.0",
377
+ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
378
+ "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
379
+ "dev": true,
380
+ "requires": {
381
+ "buffer-alloc-unsafe": "^1.1.0",
382
+ "buffer-fill": "^1.0.0"
383
+ }
384
+ },
385
+ "buffer-alloc-unsafe": {
386
+ "version": "1.1.0",
387
+ "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
388
+ "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
389
+ "dev": true
390
+ },
391
+ "buffer-crc32": {
392
+ "version": "0.2.13",
393
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
394
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
395
+ "dev": true
396
+ },
397
+ "buffer-fill": {
398
+ "version": "1.0.0",
399
+ "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
400
+ "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
401
+ "dev": true
402
+ },
403
+ "cache-base": {
404
+ "version": "1.0.1",
405
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
406
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
407
+ "requires": {
408
+ "collection-visit": "^1.0.0",
409
+ "component-emitter": "^1.2.1",
410
+ "get-value": "^2.0.6",
411
+ "has-value": "^1.0.0",
412
+ "isobject": "^3.0.1",
413
+ "set-value": "^2.0.0",
414
+ "to-object-path": "^0.3.0",
415
+ "union-value": "^1.0.0",
416
+ "unset-value": "^1.0.0"
417
+ }
418
+ },
419
+ "camelcase": {
420
+ "version": "2.1.1",
421
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
422
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
423
+ "dev": true
424
+ },
425
+ "camelcase-keys": {
426
+ "version": "2.1.0",
427
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
428
+ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
429
+ "dev": true,
430
+ "requires": {
431
+ "camelcase": "^2.0.0",
432
+ "map-obj": "^1.0.0"
433
+ }
434
+ },
435
+ "caniuse-lite": {
436
+ "version": "1.0.30001042",
437
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001042.tgz",
438
+ "integrity": "sha512-igMQ4dlqnf4tWv0xjaaE02op9AJ2oQzXKjWf4EuAHFN694Uo9/EfPVIPJcmn2WkU9RqozCxx5e2KPcVClHDbDw==",
439
+ "dev": true
440
+ },
441
+ "caseless": {
442
+ "version": "0.12.0",
443
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
444
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
445
+ "dev": true
446
+ },
447
+ "chalk": {
448
+ "version": "2.4.2",
449
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
450
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
451
+ "dev": true,
452
+ "requires": {
453
+ "ansi-styles": "^3.2.1",
454
+ "escape-string-regexp": "^1.0.5",
455
+ "supports-color": "^5.3.0"
456
+ }
457
+ },
458
+ "chownr": {
459
+ "version": "1.1.4",
460
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
461
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
462
+ "dev": true,
463
+ "optional": true
464
+ },
465
+ "class-utils": {
466
+ "version": "0.3.6",
467
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
468
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
469
+ "requires": {
470
+ "arr-union": "^3.1.0",
471
+ "define-property": "^0.2.5",
472
+ "isobject": "^3.0.0",
473
+ "static-extend": "^0.1.1"
474
+ },
475
+ "dependencies": {
476
+ "define-property": {
477
+ "version": "0.2.5",
478
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
479
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
480
+ "requires": {
481
+ "is-descriptor": "^0.1.0"
482
+ }
483
+ }
484
+ }
485
+ },
486
+ "clean-css": {
487
+ "version": "4.2.3",
488
+ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
489
+ "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
490
+ "dev": true,
491
+ "requires": {
492
+ "source-map": "~0.6.0"
493
+ },
494
+ "dependencies": {
495
+ "source-map": {
496
+ "version": "0.6.1",
497
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
498
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
499
+ "dev": true
500
+ }
501
+ }
502
+ },
503
+ "cliui": {
504
+ "version": "3.2.0",
505
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
506
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
507
+ "dev": true,
508
+ "requires": {
509
+ "string-width": "^1.0.1",
510
+ "strip-ansi": "^3.0.1",
511
+ "wrap-ansi": "^2.0.0"
512
+ }
513
+ },
514
+ "code-point-at": {
515
+ "version": "1.1.0",
516
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
517
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
518
+ "dev": true
519
+ },
520
+ "coffeescript": {
521
+ "version": "1.10.0",
522
+ "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz",
523
+ "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=",
524
+ "dev": true
525
+ },
526
+ "collection-visit": {
527
+ "version": "1.0.0",
528
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
529
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
530
+ "requires": {
531
+ "map-visit": "^1.0.0",
532
+ "object-visit": "^1.0.0"
533
+ }
534
+ },
535
+ "color-convert": {
536
+ "version": "1.9.3",
537
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
538
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
539
+ "dev": true,
540
+ "requires": {
541
+ "color-name": "1.1.3"
542
+ }
543
+ },
544
+ "color-name": {
545
+ "version": "1.1.3",
546
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
547
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
548
+ "dev": true
549
+ },
550
+ "colors": {
551
+ "version": "1.1.2",
552
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
553
+ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
554
+ "dev": true
555
+ },
556
+ "combined-stream": {
557
+ "version": "1.0.8",
558
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
559
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
560
+ "dev": true,
561
+ "requires": {
562
+ "delayed-stream": "~1.0.0"
563
+ }
564
+ },
565
+ "commander": {
566
+ "version": "2.1.0",
567
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz",
568
+ "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=",
569
+ "dev": true
570
+ },
571
+ "component-emitter": {
572
+ "version": "1.3.0",
573
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
574
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
575
+ },
576
+ "compress-commons": {
577
+ "version": "1.2.2",
578
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz",
579
+ "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=",
580
+ "dev": true,
581
+ "requires": {
582
+ "buffer-crc32": "^0.2.1",
583
+ "crc32-stream": "^2.0.0",
584
+ "normalize-path": "^2.0.0",
585
+ "readable-stream": "^2.0.0"
586
+ }
587
+ },
588
+ "concat-map": {
589
+ "version": "0.0.1",
590
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
591
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
592
+ "dev": true
593
+ },
594
+ "console-control-strings": {
595
+ "version": "1.1.0",
596
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
597
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
598
+ "dev": true
599
+ },
600
+ "copy-descriptor": {
601
+ "version": "0.1.1",
602
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
603
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
604
+ },
605
+ "core-util-is": {
606
+ "version": "1.0.2",
607
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
608
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
609
+ "dev": true
610
+ },
611
+ "crc": {
612
+ "version": "3.8.0",
613
+ "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
614
+ "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
615
+ "dev": true,
616
+ "requires": {
617
+ "buffer": "^5.1.0"
618
+ }
619
+ },
620
+ "crc32-stream": {
621
+ "version": "2.0.0",
622
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz",
623
+ "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=",
624
+ "dev": true,
625
+ "requires": {
626
+ "crc": "^3.4.4",
627
+ "readable-stream": "^2.0.0"
628
+ }
629
+ },
630
+ "cross-spawn": {
631
+ "version": "3.0.1",
632
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
633
+ "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
634
+ "dev": true,
635
+ "requires": {
636
+ "lru-cache": "^4.0.1",
637
+ "which": "^1.2.9"
638
+ }
639
+ },
640
+ "currently-unhandled": {
641
+ "version": "0.4.1",
642
+ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
643
+ "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
644
+ "dev": true,
645
+ "requires": {
646
+ "array-find-index": "^1.0.1"
647
+ }
648
+ },
649
+ "dashdash": {
650
+ "version": "1.14.1",
651
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
652
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
653
+ "dev": true,
654
+ "requires": {
655
+ "assert-plus": "^1.0.0"
656
+ }
657
+ },
658
+ "dateformat": {
659
+ "version": "1.0.12",
660
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz",
661
+ "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=",
662
+ "dev": true,
663
+ "requires": {
664
+ "get-stdin": "^4.0.1",
665
+ "meow": "^3.3.0"
666
+ }
667
+ },
668
+ "debug": {
669
+ "version": "2.6.9",
670
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
671
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
672
+ "requires": {
673
+ "ms": "2.0.0"
674
+ }
675
+ },
676
+ "decamelize": {
677
+ "version": "1.2.0",
678
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
679
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
680
+ "dev": true
681
+ },
682
+ "decode-uri-component": {
683
+ "version": "0.2.0",
684
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
685
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
686
+ },
687
+ "decompress-response": {
688
+ "version": "4.2.1",
689
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
690
+ "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
691
+ "dev": true,
692
+ "optional": true,
693
+ "requires": {
694
+ "mimic-response": "^2.0.0"
695
+ }
696
+ },
697
+ "deep-extend": {
698
+ "version": "0.6.0",
699
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
700
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
701
+ "dev": true,
702
+ "optional": true
703
+ },
704
+ "define-property": {
705
+ "version": "2.0.2",
706
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
707
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
708
+ "requires": {
709
+ "is-descriptor": "^1.0.2",
710
+ "isobject": "^3.0.1"
711
+ },
712
+ "dependencies": {
713
+ "is-accessor-descriptor": {
714
+ "version": "1.0.0",
715
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
716
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
717
+ "requires": {
718
+ "kind-of": "^6.0.0"
719
+ }
720
+ },
721
+ "is-data-descriptor": {
722
+ "version": "1.0.0",
723
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
724
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
725
+ "requires": {
726
+ "kind-of": "^6.0.0"
727
+ }
728
+ },
729
+ "is-descriptor": {
730
+ "version": "1.0.2",
731
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
732
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
733
+ "requires": {
734
+ "is-accessor-descriptor": "^1.0.0",
735
+ "is-data-descriptor": "^1.0.0",
736
+ "kind-of": "^6.0.2"
737
+ }
738
+ }
739
+ }
740
+ },
741
+ "delayed-stream": {
742
+ "version": "1.0.0",
743
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
744
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
745
+ "dev": true
746
+ },
747
+ "delegates": {
748
+ "version": "1.0.0",
749
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
750
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
751
+ "dev": true
752
+ },
753
+ "detect-file": {
754
+ "version": "1.0.0",
755
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
756
+ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc="
757
+ },
758
+ "detect-libc": {
759
+ "version": "1.0.3",
760
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
761
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
762
+ "dev": true,
763
+ "optional": true
764
+ },
765
+ "diff": {
766
+ "version": "3.5.0",
767
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
768
+ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
769
+ "dev": true
770
+ },
771
+ "duplexer": {
772
+ "version": "0.1.1",
773
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
774
+ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
775
+ "dev": true
776
+ },
777
+ "ecc-jsbn": {
778
+ "version": "0.1.2",
779
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
780
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
781
+ "dev": true,
782
+ "requires": {
783
+ "jsbn": "~0.1.0",
784
+ "safer-buffer": "^2.1.0"
785
+ }
786
+ },
787
+ "electron-to-chromium": {
788
+ "version": "1.3.409",
789
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.409.tgz",
790
+ "integrity": "sha512-CB2HUXiMsaVYY5VvcpELhDShiTRhI2FfN7CuacEZ5mDmMFuSG/ZVm8HoSya0+S61RvUd3TjIjFSKywqHZpRPzQ==",
791
+ "dev": true
792
+ },
793
+ "end-of-stream": {
794
+ "version": "1.4.4",
795
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
796
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
797
+ "dev": true,
798
+ "requires": {
799
+ "once": "^1.4.0"
800
+ }
801
+ },
802
+ "error-ex": {
803
+ "version": "1.3.2",
804
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
805
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
806
+ "dev": true,
807
+ "requires": {
808
+ "is-arrayish": "^0.2.1"
809
+ }
810
+ },
811
+ "escape-string-regexp": {
812
+ "version": "1.0.5",
813
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
814
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
815
+ "dev": true
816
+ },
817
+ "esprima": {
818
+ "version": "4.0.1",
819
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
820
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
821
+ "dev": true
822
+ },
823
+ "eventemitter2": {
824
+ "version": "0.4.14",
825
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
826
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
827
+ "dev": true
828
+ },
829
+ "exit": {
830
+ "version": "0.1.2",
831
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
832
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
833
+ "dev": true
834
+ },
835
+ "expand-brackets": {
836
+ "version": "2.1.4",
837
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
838
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
839
+ "requires": {
840
+ "debug": "^2.3.3",
841
+ "define-property": "^0.2.5",
842
+ "extend-shallow": "^2.0.1",
843
+ "posix-character-classes": "^0.1.0",
844
+ "regex-not": "^1.0.0",
845
+ "snapdragon": "^0.8.1",
846
+ "to-regex": "^3.0.1"
847
+ },
848
+ "dependencies": {
849
+ "define-property": {
850
+ "version": "0.2.5",
851
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
852
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
853
+ "requires": {
854
+ "is-descriptor": "^0.1.0"
855
+ }
856
+ },
857
+ "extend-shallow": {
858
+ "version": "2.0.1",
859
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
860
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
861
+ "requires": {
862
+ "is-extendable": "^0.1.0"
863
+ }
864
+ }
865
+ }
866
+ },
867
+ "expand-template": {
868
+ "version": "2.0.3",
869
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
870
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
871
+ "dev": true,
872
+ "optional": true
873
+ },
874
+ "expand-tilde": {
875
+ "version": "2.0.2",
876
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
877
+ "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
878
+ "requires": {
879
+ "homedir-polyfill": "^1.0.1"
880
+ }
881
+ },
882
+ "extend": {
883
+ "version": "3.0.2",
884
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
885
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
886
+ },
887
+ "extend-shallow": {
888
+ "version": "3.0.2",
889
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
890
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
891
+ "requires": {
892
+ "assign-symbols": "^1.0.0",
893
+ "is-extendable": "^1.0.1"
894
+ },
895
+ "dependencies": {
896
+ "is-extendable": {
897
+ "version": "1.0.1",
898
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
899
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
900
+ "requires": {
901
+ "is-plain-object": "^2.0.4"
902
+ }
903
+ }
904
+ }
905
+ },
906
+ "extglob": {
907
+ "version": "2.0.4",
908
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
909
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
910
+ "requires": {
911
+ "array-unique": "^0.3.2",
912
+ "define-property": "^1.0.0",
913
+ "expand-brackets": "^2.1.4",
914
+ "extend-shallow": "^2.0.1",
915
+ "fragment-cache": "^0.2.1",
916
+ "regex-not": "^1.0.0",
917
+ "snapdragon": "^0.8.1",
918
+ "to-regex": "^3.0.1"
919
+ },
920
+ "dependencies": {
921
+ "define-property": {
922
+ "version": "1.0.0",
923
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
924
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
925
+ "requires": {
926
+ "is-descriptor": "^1.0.0"
927
+ }
928
+ },
929
+ "extend-shallow": {
930
+ "version": "2.0.1",
931
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
932
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
933
+ "requires": {
934
+ "is-extendable": "^0.1.0"
935
+ }
936
+ },
937
+ "is-accessor-descriptor": {
938
+ "version": "1.0.0",
939
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
940
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
941
+ "requires": {
942
+ "kind-of": "^6.0.0"
943
+ }
944
+ },
945
+ "is-data-descriptor": {
946
+ "version": "1.0.0",
947
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
948
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
949
+ "requires": {
950
+ "kind-of": "^6.0.0"
951
+ }
952
+ },
953
+ "is-descriptor": {
954
+ "version": "1.0.2",
955
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
956
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
957
+ "requires": {
958
+ "is-accessor-descriptor": "^1.0.0",
959
+ "is-data-descriptor": "^1.0.0",
960
+ "kind-of": "^6.0.2"
961
+ }
962
+ }
963
+ }
964
+ },
965
+ "extsprintf": {
966
+ "version": "1.3.0",
967
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
968
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
969
+ "dev": true
970
+ },
971
+ "fast-deep-equal": {
972
+ "version": "3.1.1",
973
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
974
+ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
975
+ "dev": true
976
+ },
977
+ "fast-json-stable-stringify": {
978
+ "version": "2.1.0",
979
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
980
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
981
+ "dev": true
982
+ },
983
+ "figures": {
984
+ "version": "1.7.0",
985
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
986
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
987
+ "dev": true,
988
+ "requires": {
989
+ "escape-string-regexp": "^1.0.5",
990
+ "object-assign": "^4.1.0"
991
+ }
992
+ },
993
+ "file-sync-cmp": {
994
+ "version": "0.1.1",
995
+ "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz",
996
+ "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=",
997
+ "dev": true
998
+ },
999
+ "fill-range": {
1000
+ "version": "4.0.0",
1001
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
1002
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
1003
+ "requires": {
1004
+ "extend-shallow": "^2.0.1",
1005
+ "is-number": "^3.0.0",
1006
+ "repeat-string": "^1.6.1",
1007
+ "to-regex-range": "^2.1.0"
1008
+ },
1009
+ "dependencies": {
1010
+ "extend-shallow": {
1011
+ "version": "2.0.1",
1012
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
1013
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
1014
+ "requires": {
1015
+ "is-extendable": "^0.1.0"
1016
+ }
1017
+ }
1018
+ }
1019
+ },
1020
+ "find-up": {
1021
+ "version": "2.1.0",
1022
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
1023
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
1024
+ "dev": true,
1025
+ "requires": {
1026
+ "locate-path": "^2.0.0"
1027
+ }
1028
+ },
1029
+ "findup": {
1030
+ "version": "0.1.5",
1031
+ "resolved": "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz",
1032
+ "integrity": "sha1-itkpozk7rGJ5V6fl3kYjsGsOLOs=",
1033
+ "dev": true,
1034
+ "requires": {
1035
+ "colors": "~0.6.0-1",
1036
+ "commander": "~2.1.0"
1037
+ },
1038
+ "dependencies": {
1039
+ "colors": {
1040
+ "version": "0.6.2",
1041
+ "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
1042
+ "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=",
1043
+ "dev": true
1044
+ }
1045
+ }
1046
+ },
1047
+ "findup-sync": {
1048
+ "version": "2.0.0",
1049
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
1050
+ "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
1051
+ "requires": {
1052
+ "detect-file": "^1.0.0",
1053
+ "is-glob": "^3.1.0",
1054
+ "micromatch": "^3.0.4",
1055
+ "resolve-dir": "^1.0.1"
1056
+ }
1057
+ },
1058
+ "fined": {
1059
+ "version": "1.2.0",
1060
+ "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
1061
+ "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
1062
+ "requires": {
1063
+ "expand-tilde": "^2.0.2",
1064
+ "is-plain-object": "^2.0.3",
1065
+ "object.defaults": "^1.1.0",
1066
+ "object.pick": "^1.2.0",
1067
+ "parse-filepath": "^1.0.1"
1068
+ }
1069
+ },
1070
+ "flagged-respawn": {
1071
+ "version": "1.0.1",
1072
+ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
1073
+ "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q=="
1074
+ },
1075
+ "for-in": {
1076
+ "version": "1.0.2",
1077
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
1078
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
1079
+ },
1080
+ "for-own": {
1081
+ "version": "1.0.0",
1082
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
1083
+ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
1084
+ "requires": {
1085
+ "for-in": "^1.0.1"
1086
+ }
1087
+ },
1088
+ "forever-agent": {
1089
+ "version": "0.6.1",
1090
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
1091
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
1092
+ "dev": true
1093
+ },
1094
+ "form-data": {
1095
+ "version": "2.3.3",
1096
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
1097
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
1098
+ "dev": true,
1099
+ "requires": {
1100
+ "asynckit": "^0.4.0",
1101
+ "combined-stream": "^1.0.6",
1102
+ "mime-types": "^2.1.12"
1103
+ }
1104
+ },
1105
+ "fragment-cache": {
1106
+ "version": "0.2.1",
1107
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
1108
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
1109
+ "requires": {
1110
+ "map-cache": "^0.2.2"
1111
+ }
1112
+ },
1113
+ "fs-constants": {
1114
+ "version": "1.0.0",
1115
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
1116
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
1117
+ "dev": true
1118
+ },
1119
+ "fs.realpath": {
1120
+ "version": "1.0.0",
1121
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
1122
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
1123
+ "dev": true
1124
+ },
1125
+ "fstream": {
1126
+ "version": "1.0.12",
1127
+ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
1128
+ "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
1129
+ "dev": true,
1130
+ "requires": {
1131
+ "graceful-fs": "^4.1.2",
1132
+ "inherits": "~2.0.0",
1133
+ "mkdirp": ">=0.5 0",
1134
+ "rimraf": "2"
1135
+ },
1136
+ "dependencies": {
1137
+ "mkdirp": {
1138
+ "version": "0.5.5",
1139
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
1140
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
1141
+ "dev": true,
1142
+ "requires": {
1143
+ "minimist": "^1.2.5"
1144
+ }
1145
+ }
1146
+ }
1147
+ },
1148
+ "gauge": {
1149
+ "version": "2.7.4",
1150
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
1151
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
1152
+ "dev": true,
1153
+ "requires": {
1154
+ "aproba": "^1.0.3",
1155
+ "console-control-strings": "^1.0.0",
1156
+ "has-unicode": "^2.0.0",
1157
+ "object-assign": "^4.1.0",
1158
+ "signal-exit": "^3.0.0",
1159
+ "string-width": "^1.0.1",
1160
+ "strip-ansi": "^3.0.1",
1161
+ "wide-align": "^1.1.0"
1162
+ }
1163
+ },
1164
+ "gaze": {
1165
+ "version": "1.1.3",
1166
+ "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
1167
+ "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
1168
+ "dev": true,
1169
+ "requires": {
1170
+ "globule": "^1.0.0"
1171
+ }
1172
+ },
1173
+ "get-caller-file": {
1174
+ "version": "1.0.3",
1175
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
1176
+ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
1177
+ "dev": true
1178
+ },
1179
+ "get-stdin": {
1180
+ "version": "4.0.1",
1181
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
1182
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
1183
+ "dev": true
1184
+ },
1185
+ "get-value": {
1186
+ "version": "2.0.6",
1187
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
1188
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
1189
+ },
1190
+ "getobject": {
1191
+ "version": "0.1.0",
1192
+ "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
1193
+ "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
1194
+ "dev": true
1195
+ },
1196
+ "getpass": {
1197
+ "version": "0.1.7",
1198
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
1199
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
1200
+ "dev": true,
1201
+ "requires": {
1202
+ "assert-plus": "^1.0.0"
1203
+ }
1204
+ },
1205
+ "github-from-package": {
1206
+ "version": "0.0.0",
1207
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
1208
+ "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=",
1209
+ "dev": true,
1210
+ "optional": true
1211
+ },
1212
+ "glob": {
1213
+ "version": "7.0.6",
1214
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
1215
+ "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
1216
+ "dev": true,
1217
+ "requires": {
1218
+ "fs.realpath": "^1.0.0",
1219
+ "inflight": "^1.0.4",
1220
+ "inherits": "2",
1221
+ "minimatch": "^3.0.2",
1222
+ "once": "^1.3.0",
1223
+ "path-is-absolute": "^1.0.0"
1224
+ }
1225
+ },
1226
+ "global-modules": {
1227
+ "version": "1.0.0",
1228
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
1229
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
1230
+ "requires": {
1231
+ "global-prefix": "^1.0.1",
1232
+ "is-windows": "^1.0.1",
1233
+ "resolve-dir": "^1.0.0"
1234
+ }
1235
+ },
1236
+ "global-prefix": {
1237
+ "version": "1.0.2",
1238
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
1239
+ "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
1240
+ "requires": {
1241
+ "expand-tilde": "^2.0.2",
1242
+ "homedir-polyfill": "^1.0.1",
1243
+ "ini": "^1.3.4",
1244
+ "is-windows": "^1.0.1",
1245
+ "which": "^1.2.14"
1246
+ }
1247
+ },
1248
+ "globule": {
1249
+ "version": "1.3.1",
1250
+ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz",
1251
+ "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==",
1252
+ "dev": true,
1253
+ "requires": {
1254
+ "glob": "~7.1.1",
1255
+ "lodash": "~4.17.12",
1256
+ "minimatch": "~3.0.2"
1257
+ },
1258
+ "dependencies": {
1259
+ "glob": {
1260
+ "version": "7.1.6",
1261
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
1262
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
1263
+ "dev": true,
1264
+ "requires": {
1265
+ "fs.realpath": "^1.0.0",
1266
+ "inflight": "^1.0.4",
1267
+ "inherits": "2",
1268
+ "minimatch": "^3.0.4",
1269
+ "once": "^1.3.0",
1270
+ "path-is-absolute": "^1.0.0"
1271
+ }
1272
+ }
1273
+ }
1274
+ },
1275
+ "graceful-fs": {
1276
+ "version": "4.2.3",
1277
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
1278
+ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
1279
+ "dev": true
1280
+ },
1281
+ "grunt": {
1282
+ "version": "1.1.0",
1283
+ "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.1.0.tgz",
1284
+ "integrity": "sha512-+NGod0grmviZ7Nzdi9am7vuRS/h76PcWDsV635mEXF0PEQMUV6Kb+OjTdsVxbi0PZmfQOjCMKb3w8CVZcqsn1g==",
1285
+ "dev": true,
1286
+ "requires": {
1287
+ "coffeescript": "~1.10.0",
1288
+ "dateformat": "~1.0.12",
1289
+ "eventemitter2": "~0.4.13",
1290
+ "exit": "~0.1.1",
1291
+ "findup-sync": "~0.3.0",
1292
+ "glob": "~7.0.0",
1293
+ "grunt-cli": "~1.2.0",
1294
+ "grunt-known-options": "~1.1.0",
1295
+ "grunt-legacy-log": "~2.0.0",
1296
+ "grunt-legacy-util": "~1.1.1",
1297
+ "iconv-lite": "~0.4.13",
1298
+ "js-yaml": "~3.13.1",
1299
+ "minimatch": "~3.0.2",
1300
+ "mkdirp": "~1.0.3",
1301
+ "nopt": "~3.0.6",
1302
+ "path-is-absolute": "~1.0.0",
1303
+ "rimraf": "~2.6.2"
1304
+ },
1305
+ "dependencies": {
1306
+ "findup-sync": {
1307
+ "version": "0.3.0",
1308
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
1309
+ "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
1310
+ "dev": true,
1311
+ "requires": {
1312
+ "glob": "~5.0.0"
1313
+ },
1314
+ "dependencies": {
1315
+ "glob": {
1316
+ "version": "5.0.15",
1317
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
1318
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
1319
+ "dev": true,
1320
+ "requires": {
1321
+ "inflight": "^1.0.4",
1322
+ "inherits": "2",
1323
+ "minimatch": "2 || 3",
1324
+ "once": "^1.3.0",
1325
+ "path-is-absolute": "^1.0.0"
1326
+ }
1327
+ }
1328
+ }
1329
+ },
1330
+ "grunt-cli": {
1331
+ "version": "1.2.0",
1332
+ "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz",
1333
+ "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=",
1334
+ "dev": true,
1335
+ "requires": {
1336
+ "findup-sync": "~0.3.0",
1337
+ "grunt-known-options": "~1.1.0",
1338
+ "nopt": "~3.0.6",
1339
+ "resolve": "~1.1.0"
1340
+ }
1341
+ },
1342
+ "nopt": {
1343
+ "version": "3.0.6",
1344
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
1345
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
1346
+ "dev": true,
1347
+ "requires": {
1348
+ "abbrev": "1"
1349
+ }
1350
+ },
1351
+ "resolve": {
1352
+ "version": "1.1.7",
1353
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
1354
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
1355
+ "dev": true
1356
+ }
1357
+ }
1358
+ },
1359
+ "grunt-cli": {
1360
+ "version": "1.3.2",
1361
+ "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.3.2.tgz",
1362
+ "integrity": "sha512-8OHDiZZkcptxVXtMfDxJvmN7MVJNE8L/yIcPb4HB7TlyFD1kDvjHrb62uhySsU14wJx9ORMnTuhRMQ40lH/orQ==",
1363
+ "requires": {
1364
+ "grunt-known-options": "~1.1.0",
1365
+ "interpret": "~1.1.0",
1366
+ "liftoff": "~2.5.0",
1367
+ "nopt": "~4.0.1",
1368
+ "v8flags": "~3.1.1"
1369
+ }
1370
+ },
1371
+ "grunt-contrib-clean": {
1372
+ "version": "2.0.0",
1373
+ "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-2.0.0.tgz",
1374
+ "integrity": "sha512-g5ZD3ORk6gMa5ugZosLDQl3dZO7cI3R14U75hTM+dVLVxdMNJCPVmwf9OUt4v4eWgpKKWWoVK9DZc1amJp4nQw==",
1375
+ "dev": true,
1376
+ "requires": {
1377
+ "async": "^2.6.1",
1378
+ "rimraf": "^2.6.2"
1379
+ },
1380
+ "dependencies": {
1381
+ "async": {
1382
+ "version": "2.6.3",
1383
+ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
1384
+ "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
1385
+ "dev": true,
1386
+ "requires": {
1387
+ "lodash": "^4.17.14"
1388
+ }
1389
+ }
1390
+ }
1391
+ },
1392
+ "grunt-contrib-compress": {
1393
+ "version": "1.6.0",
1394
+ "resolved": "https://registry.npmjs.org/grunt-contrib-compress/-/grunt-contrib-compress-1.6.0.tgz",
1395
+ "integrity": "sha512-wIFuvk+/Ny4E+OgEfJYFZgoH7KcU/nnNFbYasB7gRvrcRyW6vmTp3Pj8a4rFSR3tbFMjrGvTUszdO6fgLajgZQ==",
1396
+ "dev": true,
1397
+ "requires": {
1398
+ "archiver": "^1.3.0",
1399
+ "chalk": "^1.1.1",
1400
+ "iltorb": "^2.4.3",
1401
+ "lodash": "^4.7.0",
1402
+ "pretty-bytes": "^4.0.2",
1403
+ "stream-buffers": "^2.1.0"
1404
+ },
1405
+ "dependencies": {
1406
+ "ansi-styles": {
1407
+ "version": "2.2.1",
1408
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
1409
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
1410
+ "dev": true
1411
+ },
1412
+ "chalk": {
1413
+ "version": "1.1.3",
1414
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
1415
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
1416
+ "dev": true,
1417
+ "requires": {
1418
+ "ansi-styles": "^2.2.1",
1419
+ "escape-string-regexp": "^1.0.2",
1420
+ "has-ansi": "^2.0.0",
1421
+ "strip-ansi": "^3.0.0",
1422
+ "supports-color": "^2.0.0"
1423
+ }
1424
+ },
1425
+ "supports-color": {
1426
+ "version": "2.0.0",
1427
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
1428
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
1429
+ "dev": true
1430
+ }
1431
+ }
1432
+ },
1433
+ "grunt-contrib-copy": {
1434
+ "version": "1.0.0",
1435
+ "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz",
1436
+ "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=",
1437
+ "dev": true,
1438
+ "requires": {
1439
+ "chalk": "^1.1.1",
1440
+ "file-sync-cmp": "^0.1.0"
1441
+ },
1442
+ "dependencies": {
1443
+ "ansi-styles": {
1444
+ "version": "2.2.1",
1445
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
1446
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
1447
+ "dev": true
1448
+ },
1449
+ "chalk": {
1450
+ "version": "1.1.3",
1451
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
1452
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
1453
+ "dev": true,
1454
+ "requires": {
1455
+ "ansi-styles": "^2.2.1",
1456
+ "escape-string-regexp": "^1.0.2",
1457
+ "has-ansi": "^2.0.0",
1458
+ "strip-ansi": "^3.0.0",
1459
+ "supports-color": "^2.0.0"
1460
+ }
1461
+ },
1462
+ "supports-color": {
1463
+ "version": "2.0.0",
1464
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
1465
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
1466
+ "dev": true
1467
+ }
1468
+ }
1469
+ },
1470
+ "grunt-contrib-cssmin": {
1471
+ "version": "3.0.0",
1472
+ "resolved": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-3.0.0.tgz",
1473
+ "integrity": "sha512-eXpooYmVGKMs/xV7DzTLgJFPVOfMuawPD3x0JwhlH0mumq2NtH3xsxaHxp1Y3NKxp0j0tRhFS6kSBRsz6TuTGg==",
1474
+ "dev": true,
1475
+ "requires": {
1476
+ "chalk": "^2.4.1",
1477
+ "clean-css": "~4.2.1",
1478
+ "maxmin": "^2.1.0"
1479
+ }
1480
+ },
1481
+ "grunt-known-options": {
1482
+ "version": "1.1.1",
1483
+ "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz",
1484
+ "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ=="
1485
+ },
1486
+ "grunt-legacy-log": {
1487
+ "version": "2.0.0",
1488
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz",
1489
+ "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==",
1490
+ "dev": true,
1491
+ "requires": {
1492
+ "colors": "~1.1.2",
1493
+ "grunt-legacy-log-utils": "~2.0.0",
1494
+ "hooker": "~0.2.3",
1495
+ "lodash": "~4.17.5"
1496
+ }
1497
+ },
1498
+ "grunt-legacy-log-utils": {
1499
+ "version": "2.0.1",
1500
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz",
1501
+ "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==",
1502
+ "dev": true,
1503
+ "requires": {
1504
+ "chalk": "~2.4.1",
1505
+ "lodash": "~4.17.10"
1506
+ }
1507
+ },
1508
+ "grunt-legacy-util": {
1509
+ "version": "1.1.1",
1510
+ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz",
1511
+ "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==",
1512
+ "dev": true,
1513
+ "requires": {
1514
+ "async": "~1.5.2",
1515
+ "exit": "~0.1.1",
1516
+ "getobject": "~0.1.0",
1517
+ "hooker": "~0.2.3",
1518
+ "lodash": "~4.17.10",
1519
+ "underscore.string": "~3.3.4",
1520
+ "which": "~1.3.0"
1521
+ }
1522
+ },
1523
+ "grunt-postcss": {
1524
+ "version": "0.9.0",
1525
+ "resolved": "https://registry.npmjs.org/grunt-postcss/-/grunt-postcss-0.9.0.tgz",
1526
+ "integrity": "sha512-lglLcVaoOIqH0sFv7RqwUKkEFGQwnlqyAKbatxZderwZGV1nDyKHN7gZS9LUiTx1t5GOvRBx0BEalHMyVwFAIA==",
1527
+ "dev": true,
1528
+ "requires": {
1529
+ "chalk": "^2.1.0",
1530
+ "diff": "^3.0.0",
1531
+ "postcss": "^6.0.11"
1532
+ },
1533
+ "dependencies": {
1534
+ "postcss": {
1535
+ "version": "6.0.23",
1536
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
1537
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
1538
+ "dev": true,
1539
+ "requires": {
1540
+ "chalk": "^2.4.1",
1541
+ "source-map": "^0.6.1",
1542
+ "supports-color": "^5.4.0"
1543
+ }
1544
+ },
1545
+ "source-map": {
1546
+ "version": "0.6.1",
1547
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1548
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1549
+ "dev": true
1550
+ }
1551
+ }
1552
+ },
1553
+ "grunt-rtlcss": {
1554
+ "version": "2.0.2",
1555
+ "resolved": "https://registry.npmjs.org/grunt-rtlcss/-/grunt-rtlcss-2.0.2.tgz",
1556
+ "integrity": "sha512-WbI2thnwlF04N+xvJu+NxqEaCyPuLyar196SYhEQFZ2EJHkOS8YYE+Zkh+X9cWhwAtKp7ZEpR/IKXcyQggOIsQ==",
1557
+ "dev": true,
1558
+ "requires": {
1559
+ "chalk": "^1.0.0",
1560
+ "rtlcss": "^2.0.0"
1561
+ },
1562
+ "dependencies": {
1563
+ "ansi-styles": {
1564
+ "version": "2.2.1",
1565
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
1566
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
1567
+ "dev": true
1568
+ },
1569
+ "chalk": {
1570
+ "version": "1.1.3",
1571
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
1572
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
1573
+ "dev": true,
1574
+ "requires": {
1575
+ "ansi-styles": "^2.2.1",
1576
+ "escape-string-regexp": "^1.0.2",
1577
+ "has-ansi": "^2.0.0",
1578
+ "strip-ansi": "^3.0.0",
1579
+ "supports-color": "^2.0.0"
1580
+ }
1581
+ },
1582
+ "supports-color": {
1583
+ "version": "2.0.0",
1584
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
1585
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
1586
+ "dev": true
1587
+ }
1588
+ }
1589
+ },
1590
+ "grunt-text-replace": {
1591
+ "version": "0.4.0",
1592
+ "resolved": "https://registry.npmjs.org/grunt-text-replace/-/grunt-text-replace-0.4.0.tgz",
1593
+ "integrity": "sha1-252c5Z4v5J2id+nbwZXD4Rz7FsI=",
1594
+ "dev": true
1595
+ },
1596
+ "gzip-size": {
1597
+ "version": "3.0.0",
1598
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz",
1599
+ "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=",
1600
+ "dev": true,
1601
+ "requires": {
1602
+ "duplexer": "^0.1.1"
1603
+ }
1604
+ },
1605
+ "har-schema": {
1606
+ "version": "2.0.0",
1607
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
1608
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
1609
+ "dev": true
1610
+ },
1611
+ "har-validator": {
1612
+ "version": "5.1.3",
1613
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
1614
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
1615
+ "dev": true,
1616
+ "requires": {
1617
+ "ajv": "^6.5.5",
1618
+ "har-schema": "^2.0.0"
1619
+ }
1620
+ },
1621
+ "has-ansi": {
1622
+ "version": "2.0.0",
1623
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
1624
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
1625
+ "dev": true,
1626
+ "requires": {
1627
+ "ansi-regex": "^2.0.0"
1628
+ }
1629
+ },
1630
+ "has-flag": {
1631
+ "version": "3.0.0",
1632
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
1633
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
1634
+ "dev": true
1635
+ },
1636
+ "has-unicode": {
1637
+ "version": "2.0.1",
1638
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
1639
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
1640
+ "dev": true
1641
+ },
1642
+ "has-value": {
1643
+ "version": "1.0.0",
1644
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
1645
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
1646
+ "requires": {
1647
+ "get-value": "^2.0.6",
1648
+ "has-values": "^1.0.0",
1649
+ "isobject": "^3.0.0"
1650
+ }
1651
+ },
1652
+ "has-values": {
1653
+ "version": "1.0.0",
1654
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
1655
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
1656
+ "requires": {
1657
+ "is-number": "^3.0.0",
1658
+ "kind-of": "^4.0.0"
1659
+ },
1660
+ "dependencies": {
1661
+ "kind-of": {
1662
+ "version": "4.0.0",
1663
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
1664
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
1665
+ "requires": {
1666
+ "is-buffer": "^1.1.5"
1667
+ }
1668
+ }
1669
+ }
1670
+ },
1671
+ "homedir-polyfill": {
1672
+ "version": "1.0.3",
1673
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
1674
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
1675
+ "requires": {
1676
+ "parse-passwd": "^1.0.0"
1677
+ }
1678
+ },
1679
+ "hooker": {
1680
+ "version": "0.2.3",
1681
+ "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
1682
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
1683
+ "dev": true
1684
+ },
1685
+ "hosted-git-info": {
1686
+ "version": "2.8.8",
1687
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
1688
+ "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
1689
+ "dev": true
1690
+ },
1691
+ "http-signature": {
1692
+ "version": "1.2.0",
1693
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
1694
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
1695
+ "dev": true,
1696
+ "requires": {
1697
+ "assert-plus": "^1.0.0",
1698
+ "jsprim": "^1.2.2",
1699
+ "sshpk": "^1.7.0"
1700
+ }
1701
+ },
1702
+ "iconv-lite": {
1703
+ "version": "0.4.24",
1704
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1705
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1706
+ "dev": true,
1707
+ "requires": {
1708
+ "safer-buffer": ">= 2.1.2 < 3"
1709
+ }
1710
+ },
1711
+ "ieee754": {
1712
+ "version": "1.1.13",
1713
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
1714
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
1715
+ "dev": true
1716
+ },
1717
+ "iltorb": {
1718
+ "version": "2.4.5",
1719
+ "resolved": "https://registry.npmjs.org/iltorb/-/iltorb-2.4.5.tgz",
1720
+ "integrity": "sha512-EMCMl3LnnNSZJS5QrxyZmMTaAC4+TJkM5woD+xbpm9RB+mFYCr7C05GFE3TEGCsVQSVHmjX+3sf5AiwsylNInQ==",
1721
+ "dev": true,
1722
+ "optional": true,
1723
+ "requires": {
1724
+ "detect-libc": "^1.0.3",
1725
+ "nan": "^2.14.0",
1726
+ "npmlog": "^4.1.2",
1727
+ "prebuild-install": "^5.3.3",
1728
+ "which-pm-runs": "^1.0.0"
1729
+ }
1730
+ },
1731
+ "in-publish": {
1732
+ "version": "2.0.1",
1733
+ "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
1734
+ "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==",
1735
+ "dev": true
1736
+ },
1737
+ "indent-string": {
1738
+ "version": "2.1.0",
1739
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
1740
+ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
1741
+ "dev": true,
1742
+ "requires": {
1743
+ "repeating": "^2.0.0"
1744
+ }
1745
+ },
1746
+ "inflight": {
1747
+ "version": "1.0.6",
1748
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
1749
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
1750
+ "dev": true,
1751
+ "requires": {
1752
+ "once": "^1.3.0",
1753
+ "wrappy": "1"
1754
+ }
1755
+ },
1756
+ "inherits": {
1757
+ "version": "2.0.4",
1758
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1759
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1760
+ "dev": true
1761
+ },
1762
+ "ini": {
1763
+ "version": "1.3.5",
1764
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
1765
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
1766
+ },
1767
+ "interpret": {
1768
+ "version": "1.1.0",
1769
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
1770
+ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
1771
+ },
1772
+ "invert-kv": {
1773
+ "version": "1.0.0",
1774
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
1775
+ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
1776
+ "dev": true
1777
+ },
1778
+ "is-absolute": {
1779
+ "version": "1.0.0",
1780
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
1781
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
1782
+ "requires": {
1783
+ "is-relative": "^1.0.0",
1784
+ "is-windows": "^1.0.1"
1785
+ }
1786
+ },
1787
+ "is-accessor-descriptor": {
1788
+ "version": "0.1.6",
1789
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
1790
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
1791
+ "requires": {
1792
+ "kind-of": "^3.0.2"
1793
+ },
1794
+ "dependencies": {
1795
+ "kind-of": {
1796
+ "version": "3.2.2",
1797
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1798
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1799
+ "requires": {
1800
+ "is-buffer": "^1.1.5"
1801
+ }
1802
+ }
1803
+ }
1804
+ },
1805
+ "is-arrayish": {
1806
+ "version": "0.2.1",
1807
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
1808
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
1809
+ "dev": true
1810
+ },
1811
+ "is-buffer": {
1812
+ "version": "1.1.6",
1813
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
1814
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
1815
+ },
1816
+ "is-data-descriptor": {
1817
+ "version": "0.1.4",
1818
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
1819
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
1820
+ "requires": {
1821
+ "kind-of": "^3.0.2"
1822
+ },
1823
+ "dependencies": {
1824
+ "kind-of": {
1825
+ "version": "3.2.2",
1826
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1827
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1828
+ "requires": {
1829
+ "is-buffer": "^1.1.5"
1830
+ }
1831
+ }
1832
+ }
1833
+ },
1834
+ "is-descriptor": {
1835
+ "version": "0.1.6",
1836
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
1837
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
1838
+ "requires": {
1839
+ "is-accessor-descriptor": "^0.1.6",
1840
+ "is-data-descriptor": "^0.1.4",
1841
+ "kind-of": "^5.0.0"
1842
+ },
1843
+ "dependencies": {
1844
+ "kind-of": {
1845
+ "version": "5.1.0",
1846
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
1847
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
1848
+ }
1849
+ }
1850
+ },
1851
+ "is-extendable": {
1852
+ "version": "0.1.1",
1853
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
1854
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
1855
+ },
1856
+ "is-extglob": {
1857
+ "version": "2.1.1",
1858
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1859
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
1860
+ },
1861
+ "is-finite": {
1862
+ "version": "1.1.0",
1863
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
1864
+ "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
1865
+ "dev": true
1866
+ },
1867
+ "is-fullwidth-code-point": {
1868
+ "version": "1.0.0",
1869
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
1870
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
1871
+ "dev": true,
1872
+ "requires": {
1873
+ "number-is-nan": "^1.0.0"
1874
+ }
1875
+ },
1876
+ "is-glob": {
1877
+ "version": "3.1.0",
1878
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
1879
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
1880
+ "requires": {
1881
+ "is-extglob": "^2.1.0"
1882
+ }
1883
+ },
1884
+ "is-number": {
1885
+ "version": "3.0.0",
1886
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
1887
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
1888
+ "requires": {
1889
+ "kind-of": "^3.0.2"
1890
+ },
1891
+ "dependencies": {
1892
+ "kind-of": {
1893
+ "version": "3.2.2",
1894
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1895
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1896
+ "requires": {
1897
+ "is-buffer": "^1.1.5"
1898
+ }
1899
+ }
1900
+ }
1901
+ },
1902
+ "is-plain-object": {
1903
+ "version": "2.0.4",
1904
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
1905
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
1906
+ "requires": {
1907
+ "isobject": "^3.0.1"
1908
+ }
1909
+ },
1910
+ "is-relative": {
1911
+ "version": "1.0.0",
1912
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
1913
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
1914
+ "requires": {
1915
+ "is-unc-path": "^1.0.0"
1916
+ }
1917
+ },
1918
+ "is-typedarray": {
1919
+ "version": "1.0.0",
1920
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
1921
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
1922
+ "dev": true
1923
+ },
1924
+ "is-unc-path": {
1925
+ "version": "1.0.0",
1926
+ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
1927
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
1928
+ "requires": {
1929
+ "unc-path-regex": "^0.1.2"
1930
+ }
1931
+ },
1932
+ "is-utf8": {
1933
+ "version": "0.2.1",
1934
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
1935
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
1936
+ "dev": true
1937
+ },
1938
+ "is-windows": {
1939
+ "version": "1.0.2",
1940
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
1941
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
1942
+ },
1943
+ "isarray": {
1944
+ "version": "1.0.0",
1945
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
1946
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
1947
+ },
1948
+ "isexe": {
1949
+ "version": "2.0.0",
1950
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1951
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
1952
+ },
1953
+ "isobject": {
1954
+ "version": "3.0.1",
1955
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
1956
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
1957
+ },
1958
+ "isstream": {
1959
+ "version": "0.1.2",
1960
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
1961
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
1962
+ "dev": true
1963
+ },
1964
+ "js-base64": {
1965
+ "version": "2.5.2",
1966
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz",
1967
+ "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==",
1968
+ "dev": true
1969
+ },
1970
+ "js-yaml": {
1971
+ "version": "3.13.1",
1972
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
1973
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
1974
+ "dev": true,
1975
+ "requires": {
1976
+ "argparse": "^1.0.7",
1977
+ "esprima": "^4.0.0"
1978
+ }
1979
+ },
1980
+ "jsbn": {
1981
+ "version": "0.1.1",
1982
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
1983
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
1984
+ "dev": true
1985
+ },
1986
+ "json-schema": {
1987
+ "version": "0.2.3",
1988
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
1989
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
1990
+ "dev": true
1991
+ },
1992
+ "json-schema-traverse": {
1993
+ "version": "0.4.1",
1994
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
1995
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
1996
+ "dev": true
1997
+ },
1998
+ "json-stringify-safe": {
1999
+ "version": "5.0.1",
2000
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
2001
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
2002
+ "dev": true
2003
+ },
2004
+ "jsprim": {
2005
+ "version": "1.4.1",
2006
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
2007
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
2008
+ "dev": true,
2009
+ "requires": {
2010
+ "assert-plus": "1.0.0",
2011
+ "extsprintf": "1.3.0",
2012
+ "json-schema": "0.2.3",
2013
+ "verror": "1.10.0"
2014
+ }
2015
+ },
2016
+ "kind-of": {
2017
+ "version": "6.0.3",
2018
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
2019
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
2020
+ },
2021
+ "lazystream": {
2022
+ "version": "1.0.0",
2023
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
2024
+ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
2025
+ "dev": true,
2026
+ "requires": {
2027
+ "readable-stream": "^2.0.5"
2028
+ }
2029
+ },
2030
+ "lcid": {
2031
+ "version": "1.0.0",
2032
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
2033
+ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
2034
+ "dev": true,
2035
+ "requires": {
2036
+ "invert-kv": "^1.0.0"
2037
+ }
2038
+ },
2039
+ "liftoff": {
2040
+ "version": "2.5.0",
2041
+ "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
2042
+ "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=",
2043
+ "requires": {
2044
+ "extend": "^3.0.0",
2045
+ "findup-sync": "^2.0.0",
2046
+ "fined": "^1.0.1",
2047
+ "flagged-respawn": "^1.0.0",
2048
+ "is-plain-object": "^2.0.4",
2049
+ "object.map": "^1.0.0",
2050
+ "rechoir": "^0.6.2",
2051
+ "resolve": "^1.1.7"
2052
+ }
2053
+ },
2054
+ "load-json-file": {
2055
+ "version": "1.1.0",
2056
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
2057
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
2058
+ "dev": true,
2059
+ "requires": {
2060
+ "graceful-fs": "^4.1.2",
2061
+ "parse-json": "^2.2.0",
2062
+ "pify": "^2.0.0",
2063
+ "pinkie-promise": "^2.0.0",
2064
+ "strip-bom": "^2.0.0"
2065
+ }
2066
+ },
2067
+ "locate-path": {
2068
+ "version": "2.0.0",
2069
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
2070
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
2071
+ "dev": true,
2072
+ "requires": {
2073
+ "p-locate": "^2.0.0",
2074
+ "path-exists": "^3.0.0"
2075
+ }
2076
+ },
2077
+ "lodash": {
2078
+ "version": "4.17.15",
2079
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
2080
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
2081
+ "dev": true
2082
+ },
2083
+ "loud-rejection": {
2084
+ "version": "1.6.0",
2085
+ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
2086
+ "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
2087
+ "dev": true,
2088
+ "requires": {
2089
+ "currently-unhandled": "^0.4.1",
2090
+ "signal-exit": "^3.0.0"
2091
+ }
2092
+ },
2093
+ "lru-cache": {
2094
+ "version": "4.1.5",
2095
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
2096
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
2097
+ "dev": true,
2098
+ "requires": {
2099
+ "pseudomap": "^1.0.2",
2100
+ "yallist": "^2.1.2"
2101
+ }
2102
+ },
2103
+ "make-iterator": {
2104
+ "version": "1.0.1",
2105
+ "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
2106
+ "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
2107
+ "requires": {
2108
+ "kind-of": "^6.0.2"
2109
+ }
2110
+ },
2111
+ "map-cache": {
2112
+ "version": "0.2.2",
2113
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
2114
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
2115
+ },
2116
+ "map-obj": {
2117
+ "version": "1.0.1",
2118
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
2119
+ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
2120
+ "dev": true
2121
+ },
2122
+ "map-visit": {
2123
+ "version": "1.0.0",
2124
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
2125
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
2126
+ "requires": {
2127
+ "object-visit": "^1.0.0"
2128
+ }
2129
+ },
2130
+ "maxmin": {
2131
+ "version": "2.1.0",
2132
+ "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz",
2133
+ "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=",
2134
+ "dev": true,
2135
+ "requires": {
2136
+ "chalk": "^1.0.0",
2137
+ "figures": "^1.0.1",
2138
+ "gzip-size": "^3.0.0",
2139
+ "pretty-bytes": "^3.0.0"
2140
+ },
2141
+ "dependencies": {
2142
+ "ansi-styles": {
2143
+ "version": "2.2.1",
2144
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
2145
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
2146
+ "dev": true
2147
+ },
2148
+ "chalk": {
2149
+ "version": "1.1.3",
2150
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
2151
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
2152
+ "dev": true,
2153
+ "requires": {
2154
+ "ansi-styles": "^2.2.1",
2155
+ "escape-string-regexp": "^1.0.2",
2156
+ "has-ansi": "^2.0.0",
2157
+ "strip-ansi": "^3.0.0",
2158
+ "supports-color": "^2.0.0"
2159
+ }
2160
+ },
2161
+ "pretty-bytes": {
2162
+ "version": "3.0.1",
2163
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz",
2164
+ "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=",
2165
+ "dev": true,
2166
+ "requires": {
2167
+ "number-is-nan": "^1.0.0"
2168
+ }
2169
+ },
2170
+ "supports-color": {
2171
+ "version": "2.0.0",
2172
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
2173
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
2174
+ "dev": true
2175
+ }
2176
+ }
2177
+ },
2178
+ "meow": {
2179
+ "version": "3.7.0",
2180
+ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
2181
+ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
2182
+ "dev": true,
2183
+ "requires": {
2184
+ "camelcase-keys": "^2.0.0",
2185
+ "decamelize": "^1.1.2",
2186
+ "loud-rejection": "^1.0.0",
2187
+ "map-obj": "^1.0.1",
2188
+ "minimist": "^1.1.3",
2189
+ "normalize-package-data": "^2.3.4",
2190
+ "object-assign": "^4.0.1",
2191
+ "read-pkg-up": "^1.0.1",
2192
+ "redent": "^1.0.0",
2193
+ "trim-newlines": "^1.0.0"
2194
+ }
2195
+ },
2196
+ "micromatch": {
2197
+ "version": "3.1.10",
2198
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
2199
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
2200
+ "requires": {
2201
+ "arr-diff": "^4.0.0",
2202
+ "array-unique": "^0.3.2",
2203
+ "braces": "^2.3.1",
2204
+ "define-property": "^2.0.2",
2205
+ "extend-shallow": "^3.0.2",
2206
+ "extglob": "^2.0.4",
2207
+ "fragment-cache": "^0.2.1",
2208
+ "kind-of": "^6.0.2",
2209
+ "nanomatch": "^1.2.9",
2210
+ "object.pick": "^1.3.0",
2211
+ "regex-not": "^1.0.0",
2212
+ "snapdragon": "^0.8.1",
2213
+ "to-regex": "^3.0.2"
2214
+ }
2215
+ },
2216
+ "mime-db": {
2217
+ "version": "1.43.0",
2218
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
2219
+ "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
2220
+ "dev": true
2221
+ },
2222
+ "mime-types": {
2223
+ "version": "2.1.26",
2224
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
2225
+ "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
2226
+ "dev": true,
2227
+ "requires": {
2228
+ "mime-db": "1.43.0"
2229
+ }
2230
+ },
2231
+ "mimic-response": {
2232
+ "version": "2.1.0",
2233
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
2234
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
2235
+ "dev": true,
2236
+ "optional": true
2237
+ },
2238
+ "minimatch": {
2239
+ "version": "3.0.4",
2240
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
2241
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
2242
+ "dev": true,
2243
+ "requires": {
2244
+ "brace-expansion": "^1.1.7"
2245
+ }
2246
+ },
2247
+ "minimist": {
2248
+ "version": "1.2.5",
2249
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
2250
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
2251
+ "dev": true
2252
+ },
2253
+ "mixin-deep": {
2254
+ "version": "1.3.2",
2255
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
2256
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
2257
+ "requires": {
2258
+ "for-in": "^1.0.2",
2259
+ "is-extendable": "^1.0.1"
2260
+ },
2261
+ "dependencies": {
2262
+ "is-extendable": {
2263
+ "version": "1.0.1",
2264
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
2265
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
2266
+ "requires": {
2267
+ "is-plain-object": "^2.0.4"
2268
+ }
2269
+ }
2270
+ }
2271
+ },
2272
+ "mkdirp": {
2273
+ "version": "1.0.4",
2274
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
2275
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
2276
+ "dev": true
2277
+ },
2278
+ "mkdirp-classic": {
2279
+ "version": "0.5.2",
2280
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.2.tgz",
2281
+ "integrity": "sha512-ejdnDQcR75gwknmMw/tx02AuRs8jCtqFoFqDZMjiNxsu85sRIJVXDKHuLYvUUPRBUtV2FpSZa9bL1BUa3BdR2g==",
2282
+ "dev": true,
2283
+ "optional": true
2284
+ },
2285
+ "ms": {
2286
+ "version": "2.0.0",
2287
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
2288
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
2289
+ },
2290
+ "nan": {
2291
+ "version": "2.14.0",
2292
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
2293
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
2294
+ "dev": true
2295
+ },
2296
+ "nanomatch": {
2297
+ "version": "1.2.13",
2298
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
2299
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
2300
+ "requires": {
2301
+ "arr-diff": "^4.0.0",
2302
+ "array-unique": "^0.3.2",
2303
+ "define-property": "^2.0.2",
2304
+ "extend-shallow": "^3.0.2",
2305
+ "fragment-cache": "^0.2.1",
2306
+ "is-windows": "^1.0.2",
2307
+ "kind-of": "^6.0.2",
2308
+ "object.pick": "^1.3.0",
2309
+ "regex-not": "^1.0.0",
2310
+ "snapdragon": "^0.8.1",
2311
+ "to-regex": "^3.0.1"
2312
+ }
2313
+ },
2314
+ "napi-build-utils": {
2315
+ "version": "1.0.2",
2316
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
2317
+ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
2318
+ "dev": true,
2319
+ "optional": true
2320
+ },
2321
+ "node-abi": {
2322
+ "version": "2.15.0",
2323
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.15.0.tgz",
2324
+ "integrity": "sha512-FeLpTS0F39U7hHZU1srAK4Vx+5AHNVOTP+hxBNQknR/54laTHSFIJkDWDqiquY1LeLUgTfPN7sLPhMubx0PLAg==",
2325
+ "dev": true,
2326
+ "optional": true,
2327
+ "requires": {
2328
+ "semver": "^5.4.1"
2329
+ }
2330
+ },
2331
+ "node-gyp": {
2332
+ "version": "3.8.0",
2333
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
2334
+ "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
2335
+ "dev": true,
2336
+ "requires": {
2337
+ "fstream": "^1.0.0",
2338
+ "glob": "^7.0.3",
2339
+ "graceful-fs": "^4.1.2",
2340
+ "mkdirp": "^0.5.0",
2341
+ "nopt": "2 || 3",
2342
+ "npmlog": "0 || 1 || 2 || 3 || 4",
2343
+ "osenv": "0",
2344
+ "request": "^2.87.0",
2345
+ "rimraf": "2",
2346
+ "semver": "~5.3.0",
2347
+ "tar": "^2.0.0",
2348
+ "which": "1"
2349
+ },
2350
+ "dependencies": {
2351
+ "mkdirp": {
2352
+ "version": "0.5.5",
2353
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
2354
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
2355
+ "dev": true,
2356
+ "requires": {
2357
+ "minimist": "^1.2.5"
2358
+ }
2359
+ },
2360
+ "nopt": {
2361
+ "version": "3.0.6",
2362
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
2363
+ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
2364
+ "dev": true,
2365
+ "requires": {
2366
+ "abbrev": "1"
2367
+ }
2368
+ },
2369
+ "semver": {
2370
+ "version": "5.3.0",
2371
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
2372
+ "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
2373
+ "dev": true
2374
+ }
2375
+ }
2376
+ },
2377
+ "node-releases": {
2378
+ "version": "1.1.53",
2379
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz",
2380
+ "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==",
2381
+ "dev": true
2382
+ },
2383
+ "node-sass": {
2384
+ "version": "4.13.1",
2385
+ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz",
2386
+ "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==",
2387
+ "dev": true,
2388
+ "requires": {
2389
+ "async-foreach": "^0.1.3",
2390
+ "chalk": "^1.1.1",
2391
+ "cross-spawn": "^3.0.0",
2392
+ "gaze": "^1.0.0",
2393
+ "get-stdin": "^4.0.1",
2394
+ "glob": "^7.0.3",
2395
+ "in-publish": "^2.0.0",
2396
+ "lodash": "^4.17.15",
2397
+ "meow": "^3.7.0",
2398
+ "mkdirp": "^0.5.1",
2399
+ "nan": "^2.13.2",
2400
+ "node-gyp": "^3.8.0",
2401
+ "npmlog": "^4.0.0",
2402
+ "request": "^2.88.0",
2403
+ "sass-graph": "^2.2.4",
2404
+ "stdout-stream": "^1.4.0",
2405
+ "true-case-path": "^1.0.2"
2406
+ },
2407
+ "dependencies": {
2408
+ "ansi-styles": {
2409
+ "version": "2.2.1",
2410
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
2411
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
2412
+ "dev": true
2413
+ },
2414
+ "chalk": {
2415
+ "version": "1.1.3",
2416
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
2417
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
2418
+ "dev": true,
2419
+ "requires": {
2420
+ "ansi-styles": "^2.2.1",
2421
+ "escape-string-regexp": "^1.0.2",
2422
+ "has-ansi": "^2.0.0",
2423
+ "strip-ansi": "^3.0.0",
2424
+ "supports-color": "^2.0.0"
2425
+ }
2426
+ },
2427
+ "mkdirp": {
2428
+ "version": "0.5.5",
2429
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
2430
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
2431
+ "dev": true,
2432
+ "requires": {
2433
+ "minimist": "^1.2.5"
2434
+ }
2435
+ },
2436
+ "supports-color": {
2437
+ "version": "2.0.0",
2438
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
2439
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
2440
+ "dev": true
2441
+ }
2442
+ }
2443
+ },
2444
+ "noop-logger": {
2445
+ "version": "0.1.1",
2446
+ "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
2447
+ "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=",
2448
+ "dev": true,
2449
+ "optional": true
2450
+ },
2451
+ "nopt": {
2452
+ "version": "4.0.3",
2453
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
2454
+ "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
2455
+ "requires": {
2456
+ "abbrev": "1",
2457
+ "osenv": "^0.1.4"
2458
+ }
2459
+ },
2460
+ "normalize-package-data": {
2461
+ "version": "2.5.0",
2462
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
2463
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
2464
+ "dev": true,
2465
+ "requires": {
2466
+ "hosted-git-info": "^2.1.4",
2467
+ "resolve": "^1.10.0",
2468
+ "semver": "2 || 3 || 4 || 5",
2469
+ "validate-npm-package-license": "^3.0.1"
2470
+ }
2471
+ },
2472
+ "normalize-path": {
2473
+ "version": "2.1.1",
2474
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
2475
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
2476
+ "dev": true,
2477
+ "requires": {
2478
+ "remove-trailing-separator": "^1.0.1"
2479
+ }
2480
+ },
2481
+ "normalize-range": {
2482
+ "version": "0.1.2",
2483
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
2484
+ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
2485
+ "dev": true
2486
+ },
2487
+ "npmlog": {
2488
+ "version": "4.1.2",
2489
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
2490
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
2491
+ "dev": true,
2492
+ "requires": {
2493
+ "are-we-there-yet": "~1.1.2",
2494
+ "console-control-strings": "~1.1.0",
2495
+ "gauge": "~2.7.3",
2496
+ "set-blocking": "~2.0.0"
2497
+ }
2498
+ },
2499
+ "num2fraction": {
2500
+ "version": "1.2.2",
2501
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
2502
+ "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
2503
+ "dev": true
2504
+ },
2505
+ "number-is-nan": {
2506
+ "version": "1.0.1",
2507
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
2508
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
2509
+ "dev": true
2510
+ },
2511
+ "oauth-sign": {
2512
+ "version": "0.9.0",
2513
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
2514
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
2515
+ "dev": true
2516
+ },
2517
+ "object-assign": {
2518
+ "version": "4.1.1",
2519
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
2520
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
2521
+ "dev": true
2522
+ },
2523
+ "object-copy": {
2524
+ "version": "0.1.0",
2525
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
2526
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
2527
+ "requires": {
2528
+ "copy-descriptor": "^0.1.0",
2529
+ "define-property": "^0.2.5",
2530
+ "kind-of": "^3.0.3"
2531
+ },
2532
+ "dependencies": {
2533
+ "define-property": {
2534
+ "version": "0.2.5",
2535
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
2536
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
2537
+ "requires": {
2538
+ "is-descriptor": "^0.1.0"
2539
+ }
2540
+ },
2541
+ "kind-of": {
2542
+ "version": "3.2.2",
2543
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
2544
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
2545
+ "requires": {
2546
+ "is-buffer": "^1.1.5"
2547
+ }
2548
+ }
2549
+ }
2550
+ },
2551
+ "object-visit": {
2552
+ "version": "1.0.1",
2553
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
2554
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
2555
+ "requires": {
2556
+ "isobject": "^3.0.0"
2557
+ }
2558
+ },
2559
+ "object.defaults": {
2560
+ "version": "1.1.0",
2561
+ "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
2562
+ "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
2563
+ "requires": {
2564
+ "array-each": "^1.0.1",
2565
+ "array-slice": "^1.0.0",
2566
+ "for-own": "^1.0.0",
2567
+ "isobject": "^3.0.0"
2568
+ }
2569
+ },
2570
+ "object.map": {
2571
+ "version": "1.0.1",
2572
+ "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
2573
+ "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
2574
+ "requires": {
2575
+ "for-own": "^1.0.0",
2576
+ "make-iterator": "^1.0.0"
2577
+ }
2578
+ },
2579
+ "object.pick": {
2580
+ "version": "1.3.0",
2581
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
2582
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
2583
+ "requires": {
2584
+ "isobject": "^3.0.1"
2585
+ }
2586
+ },
2587
+ "once": {
2588
+ "version": "1.4.0",
2589
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
2590
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
2591
+ "dev": true,
2592
+ "requires": {
2593
+ "wrappy": "1"
2594
+ }
2595
+ },
2596
+ "os-homedir": {
2597
+ "version": "1.0.2",
2598
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
2599
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
2600
+ },
2601
+ "os-locale": {
2602
+ "version": "1.4.0",
2603
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
2604
+ "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
2605
+ "dev": true,
2606
+ "requires": {
2607
+ "lcid": "^1.0.0"
2608
+ }
2609
+ },
2610
+ "os-tmpdir": {
2611
+ "version": "1.0.2",
2612
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
2613
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
2614
+ },
2615
+ "osenv": {
2616
+ "version": "0.1.5",
2617
+ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
2618
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
2619
+ "requires": {
2620
+ "os-homedir": "^1.0.0",
2621
+ "os-tmpdir": "^1.0.0"
2622
+ }
2623
+ },
2624
+ "p-limit": {
2625
+ "version": "1.3.0",
2626
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
2627
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
2628
+ "dev": true,
2629
+ "requires": {
2630
+ "p-try": "^1.0.0"
2631
+ }
2632
+ },
2633
+ "p-locate": {
2634
+ "version": "2.0.0",
2635
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
2636
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
2637
+ "dev": true,
2638
+ "requires": {
2639
+ "p-limit": "^1.1.0"
2640
+ }
2641
+ },
2642
+ "p-try": {
2643
+ "version": "1.0.0",
2644
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
2645
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
2646
+ "dev": true
2647
+ },
2648
+ "parse-filepath": {
2649
+ "version": "1.0.2",
2650
+ "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
2651
+ "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
2652
+ "requires": {
2653
+ "is-absolute": "^1.0.0",
2654
+ "map-cache": "^0.2.0",
2655
+ "path-root": "^0.1.1"
2656
+ }
2657
+ },
2658
+ "parse-json": {
2659
+ "version": "2.2.0",
2660
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
2661
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
2662
+ "dev": true,
2663
+ "requires": {
2664
+ "error-ex": "^1.2.0"
2665
+ }
2666
+ },
2667
+ "parse-passwd": {
2668
+ "version": "1.0.0",
2669
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
2670
+ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY="
2671
+ },
2672
+ "pascalcase": {
2673
+ "version": "0.1.1",
2674
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
2675
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
2676
+ },
2677
+ "path-exists": {
2678
+ "version": "3.0.0",
2679
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
2680
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
2681
+ "dev": true
2682
+ },
2683
+ "path-is-absolute": {
2684
+ "version": "1.0.1",
2685
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
2686
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
2687
+ "dev": true
2688
+ },
2689
+ "path-parse": {
2690
+ "version": "1.0.6",
2691
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
2692
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
2693
+ },
2694
+ "path-root": {
2695
+ "version": "0.1.1",
2696
+ "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
2697
+ "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
2698
+ "requires": {
2699
+ "path-root-regex": "^0.1.0"
2700
+ }
2701
+ },
2702
+ "path-root-regex": {
2703
+ "version": "0.1.2",
2704
+ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
2705
+ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0="
2706
+ },
2707
+ "path-type": {
2708
+ "version": "1.1.0",
2709
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
2710
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
2711
+ "dev": true,
2712
+ "requires": {
2713
+ "graceful-fs": "^4.1.2",
2714
+ "pify": "^2.0.0",
2715
+ "pinkie-promise": "^2.0.0"
2716
+ }
2717
+ },
2718
+ "performance-now": {
2719
+ "version": "2.1.0",
2720
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
2721
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
2722
+ "dev": true
2723
+ },
2724
+ "pify": {
2725
+ "version": "2.3.0",
2726
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
2727
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
2728
+ "dev": true
2729
+ },
2730
+ "pinkie": {
2731
+ "version": "2.0.4",
2732
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
2733
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
2734
+ "dev": true
2735
+ },
2736
+ "pinkie-promise": {
2737
+ "version": "2.0.1",
2738
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
2739
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
2740
+ "dev": true,
2741
+ "requires": {
2742
+ "pinkie": "^2.0.0"
2743
+ }
2744
+ },
2745
+ "pkg-up": {
2746
+ "version": "2.0.0",
2747
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
2748
+ "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
2749
+ "dev": true,
2750
+ "requires": {
2751
+ "find-up": "^2.1.0"
2752
+ }
2753
+ },
2754
+ "posix-character-classes": {
2755
+ "version": "0.1.1",
2756
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
2757
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
2758
+ },
2759
+ "postcss": {
2760
+ "version": "7.0.27",
2761
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.27.tgz",
2762
+ "integrity": "sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==",
2763
+ "dev": true,
2764
+ "requires": {
2765
+ "chalk": "^2.4.2",
2766
+ "source-map": "^0.6.1",
2767
+ "supports-color": "^6.1.0"
2768
+ },
2769
+ "dependencies": {
2770
+ "source-map": {
2771
+ "version": "0.6.1",
2772
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
2773
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
2774
+ "dev": true
2775
+ },
2776
+ "supports-color": {
2777
+ "version": "6.1.0",
2778
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
2779
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
2780
+ "dev": true,
2781
+ "requires": {
2782
+ "has-flag": "^3.0.0"
2783
+ }
2784
+ }
2785
+ }
2786
+ },
2787
+ "postcss-flexibility": {
2788
+ "version": "2.0.0",
2789
+ "resolved": "https://registry.npmjs.org/postcss-flexibility/-/postcss-flexibility-2.0.0.tgz",
2790
+ "integrity": "sha1-VhLBuF1lle1ICWaDmSikFhemp2g=",
2791
+ "dev": true,
2792
+ "requires": {
2793
+ "postcss": "^6.0.1"
2794
+ },
2795
+ "dependencies": {
2796
+ "postcss": {
2797
+ "version": "6.0.23",
2798
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
2799
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
2800
+ "dev": true,
2801
+ "requires": {
2802
+ "chalk": "^2.4.1",
2803
+ "source-map": "^0.6.1",
2804
+ "supports-color": "^5.4.0"
2805
+ }
2806
+ },
2807
+ "source-map": {
2808
+ "version": "0.6.1",
2809
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
2810
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
2811
+ "dev": true
2812
+ }
2813
+ }
2814
+ },
2815
+ "postcss-value-parser": {
2816
+ "version": "4.0.3",
2817
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz",
2818
+ "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==",
2819
+ "dev": true
2820
+ },
2821
+ "prebuild-install": {
2822
+ "version": "5.3.3",
2823
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz",
2824
+ "integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==",
2825
+ "dev": true,
2826
+ "optional": true,
2827
+ "requires": {
2828
+ "detect-libc": "^1.0.3",
2829
+ "expand-template": "^2.0.3",
2830
+ "github-from-package": "0.0.0",
2831
+ "minimist": "^1.2.0",
2832
+ "mkdirp": "^0.5.1",
2833
+ "napi-build-utils": "^1.0.1",
2834
+ "node-abi": "^2.7.0",
2835
+ "noop-logger": "^0.1.1",
2836
+ "npmlog": "^4.0.1",
2837
+ "pump": "^3.0.0",
2838
+ "rc": "^1.2.7",
2839
+ "simple-get": "^3.0.3",
2840
+ "tar-fs": "^2.0.0",
2841
+ "tunnel-agent": "^0.6.0",
2842
+ "which-pm-runs": "^1.0.0"
2843
+ },
2844
+ "dependencies": {
2845
+ "mkdirp": {
2846
+ "version": "0.5.5",
2847
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
2848
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
2849
+ "dev": true,
2850
+ "optional": true,
2851
+ "requires": {
2852
+ "minimist": "^1.2.5"
2853
+ }
2854
+ }
2855
+ }
2856
+ },
2857
+ "pretty-bytes": {
2858
+ "version": "4.0.2",
2859
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz",
2860
+ "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=",
2861
+ "dev": true
2862
+ },
2863
+ "process-nextick-args": {
2864
+ "version": "2.0.1",
2865
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
2866
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
2867
+ "dev": true
2868
+ },
2869
+ "pseudomap": {
2870
+ "version": "1.0.2",
2871
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
2872
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
2873
+ "dev": true
2874
+ },
2875
+ "psl": {
2876
+ "version": "1.8.0",
2877
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
2878
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
2879
+ "dev": true
2880
+ },
2881
+ "pump": {
2882
+ "version": "3.0.0",
2883
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
2884
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
2885
+ "dev": true,
2886
+ "optional": true,
2887
+ "requires": {
2888
+ "end-of-stream": "^1.1.0",
2889
+ "once": "^1.3.1"
2890
+ }
2891
+ },
2892
+ "punycode": {
2893
+ "version": "2.1.1",
2894
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
2895
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
2896
+ "dev": true
2897
+ },
2898
+ "qs": {
2899
+ "version": "6.5.2",
2900
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
2901
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
2902
+ "dev": true
2903
+ },
2904
+ "rc": {
2905
+ "version": "1.2.8",
2906
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
2907
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
2908
+ "dev": true,
2909
+ "optional": true,
2910
+ "requires": {
2911
+ "deep-extend": "^0.6.0",
2912
+ "ini": "~1.3.0",
2913
+ "minimist": "^1.2.0",
2914
+ "strip-json-comments": "~2.0.1"
2915
+ }
2916
+ },
2917
+ "read-pkg": {
2918
+ "version": "1.1.0",
2919
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
2920
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
2921
+ "dev": true,
2922
+ "requires": {
2923
+ "load-json-file": "^1.0.0",
2924
+ "normalize-package-data": "^2.3.2",
2925
+ "path-type": "^1.0.0"
2926
+ }
2927
+ },
2928
+ "read-pkg-up": {
2929
+ "version": "1.0.1",
2930
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
2931
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
2932
+ "dev": true,
2933
+ "requires": {
2934
+ "find-up": "^1.0.0",
2935
+ "read-pkg": "^1.0.0"
2936
+ },
2937
+ "dependencies": {
2938
+ "find-up": {
2939
+ "version": "1.1.2",
2940
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
2941
+ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
2942
+ "dev": true,
2943
+ "requires": {
2944
+ "path-exists": "^2.0.0",
2945
+ "pinkie-promise": "^2.0.0"
2946
+ }
2947
+ },
2948
+ "path-exists": {
2949
+ "version": "2.1.0",
2950
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
2951
+ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
2952
+ "dev": true,
2953
+ "requires": {
2954
+ "pinkie-promise": "^2.0.0"
2955
+ }
2956
+ }
2957
+ }
2958
+ },
2959
+ "readable-stream": {
2960
+ "version": "2.3.7",
2961
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
2962
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
2963
+ "dev": true,
2964
+ "requires": {
2965
+ "core-util-is": "~1.0.0",
2966
+ "inherits": "~2.0.3",
2967
+ "isarray": "~1.0.0",
2968
+ "process-nextick-args": "~2.0.0",
2969
+ "safe-buffer": "~5.1.1",
2970
+ "string_decoder": "~1.1.1",
2971
+ "util-deprecate": "~1.0.1"
2972
+ }
2973
+ },
2974
+ "rechoir": {
2975
+ "version": "0.6.2",
2976
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
2977
+ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
2978
+ "requires": {
2979
+ "resolve": "^1.1.6"
2980
+ }
2981
+ },
2982
+ "redent": {
2983
+ "version": "1.0.0",
2984
+ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
2985
+ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
2986
+ "dev": true,
2987
+ "requires": {
2988
+ "indent-string": "^2.1.0",
2989
+ "strip-indent": "^1.0.1"
2990
+ }
2991
+ },
2992
+ "regex-not": {
2993
+ "version": "1.0.2",
2994
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
2995
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
2996
+ "requires": {
2997
+ "extend-shallow": "^3.0.2",
2998
+ "safe-regex": "^1.1.0"
2999
+ }
3000
+ },
3001
+ "remove-trailing-separator": {
3002
+ "version": "1.1.0",
3003
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
3004
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
3005
+ "dev": true
3006
+ },
3007
+ "repeat-element": {
3008
+ "version": "1.1.3",
3009
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
3010
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g=="
3011
+ },
3012
+ "repeat-string": {
3013
+ "version": "1.6.1",
3014
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
3015
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
3016
+ },
3017
+ "repeating": {
3018
+ "version": "2.0.1",
3019
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
3020
+ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
3021
+ "dev": true,
3022
+ "requires": {
3023
+ "is-finite": "^1.0.0"
3024
+ }
3025
+ },
3026
+ "request": {
3027
+ "version": "2.88.2",
3028
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
3029
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
3030
+ "dev": true,
3031
+ "requires": {
3032
+ "aws-sign2": "~0.7.0",
3033
+ "aws4": "^1.8.0",
3034
+ "caseless": "~0.12.0",
3035
+ "combined-stream": "~1.0.6",
3036
+ "extend": "~3.0.2",
3037
+ "forever-agent": "~0.6.1",
3038
+ "form-data": "~2.3.2",
3039
+ "har-validator": "~5.1.3",
3040
+ "http-signature": "~1.2.0",
3041
+ "is-typedarray": "~1.0.0",
3042
+ "isstream": "~0.1.2",
3043
+ "json-stringify-safe": "~5.0.1",
3044
+ "mime-types": "~2.1.19",
3045
+ "oauth-sign": "~0.9.0",
3046
+ "performance-now": "^2.1.0",
3047
+ "qs": "~6.5.2",
3048
+ "safe-buffer": "^5.1.2",
3049
+ "tough-cookie": "~2.5.0",
3050
+ "tunnel-agent": "^0.6.0",
3051
+ "uuid": "^3.3.2"
3052
+ }
3053
+ },
3054
+ "require-directory": {
3055
+ "version": "2.1.1",
3056
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
3057
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
3058
+ "dev": true
3059
+ },
3060
+ "require-main-filename": {
3061
+ "version": "1.0.1",
3062
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
3063
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
3064
+ "dev": true
3065
+ },
3066
+ "resolve": {
3067
+ "version": "1.16.0",
3068
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.0.tgz",
3069
+ "integrity": "sha512-LarL/PIKJvc09k1jaeT4kQb/8/7P+qV4qSnN2K80AES+OHdfZELAKVOBjxsvtToT/uLOfFbvYvKfZmV8cee7nA==",
3070
+ "requires": {
3071
+ "path-parse": "^1.0.6"
3072
+ }
3073
+ },
3074
+ "resolve-dir": {
3075
+ "version": "1.0.1",
3076
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
3077
+ "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
3078
+ "requires": {
3079
+ "expand-tilde": "^2.0.0",
3080
+ "global-modules": "^1.0.0"
3081
+ }
3082
+ },
3083
+ "resolve-url": {
3084
+ "version": "0.2.1",
3085
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
3086
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
3087
+ },
3088
+ "ret": {
3089
+ "version": "0.1.15",
3090
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
3091
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
3092
+ },
3093
+ "rimraf": {
3094
+ "version": "2.6.3",
3095
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
3096
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
3097
+ "dev": true,
3098
+ "requires": {
3099
+ "glob": "^7.1.3"
3100
+ },
3101
+ "dependencies": {
3102
+ "glob": {
3103
+ "version": "7.1.6",
3104
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
3105
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
3106
+ "dev": true,
3107
+ "requires": {
3108
+ "fs.realpath": "^1.0.0",
3109
+ "inflight": "^1.0.4",
3110
+ "inherits": "2",
3111
+ "minimatch": "^3.0.4",
3112
+ "once": "^1.3.0",
3113
+ "path-is-absolute": "^1.0.0"
3114
+ }
3115
+ }
3116
+ }
3117
+ },
3118
+ "rtlcss": {
3119
+ "version": "2.5.0",
3120
+ "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-2.5.0.tgz",
3121
+ "integrity": "sha512-NCVdF45w70/3CQeqVvQ84bu2HN8agNn+CDjw+RxXaiWb7mPOmEvltdd1z4qzm9kin4Jnu9ShFBIx28yvWerZ2g==",
3122
+ "dev": true,
3123
+ "requires": {
3124
+ "chalk": "^2.4.2",
3125
+ "findup": "^0.1.5",
3126
+ "mkdirp": "^0.5.1",
3127
+ "postcss": "^6.0.23",
3128
+ "strip-json-comments": "^2.0.0"
3129
+ },
3130
+ "dependencies": {
3131
+ "mkdirp": {
3132
+ "version": "0.5.5",
3133
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
3134
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
3135
+ "dev": true,
3136
+ "requires": {
3137
+ "minimist": "^1.2.5"
3138
+ }
3139
+ },
3140
+ "postcss": {
3141
+ "version": "6.0.23",
3142
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
3143
+ "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
3144
+ "dev": true,
3145
+ "requires": {
3146
+ "chalk": "^2.4.1",
3147
+ "source-map": "^0.6.1",
3148
+ "supports-color": "^5.4.0"
3149
+ }
3150
+ },
3151
+ "source-map": {
3152
+ "version": "0.6.1",
3153
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
3154
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
3155
+ "dev": true
3156
+ }
3157
+ }
3158
+ },
3159
+ "safe-buffer": {
3160
+ "version": "5.1.2",
3161
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
3162
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
3163
+ "dev": true
3164
+ },
3165
+ "safe-regex": {
3166
+ "version": "1.1.0",
3167
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
3168
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
3169
+ "requires": {
3170
+ "ret": "~0.1.10"
3171
+ }
3172
+ },
3173
+ "safer-buffer": {
3174
+ "version": "2.1.2",
3175
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
3176
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
3177
+ "dev": true
3178
+ },
3179
+ "sass-graph": {
3180
+ "version": "2.2.4",
3181
+ "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
3182
+ "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
3183
+ "dev": true,
3184
+ "requires": {
3185
+ "glob": "^7.0.0",
3186
+ "lodash": "^4.0.0",
3187
+ "scss-tokenizer": "^0.2.3",
3188
+ "yargs": "^7.0.0"
3189
+ }
3190
+ },
3191
+ "scss-tokenizer": {
3192
+ "version": "0.2.3",
3193
+ "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
3194
+ "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
3195
+ "dev": true,
3196
+ "requires": {
3197
+ "js-base64": "^2.1.8",
3198
+ "source-map": "^0.4.2"
3199
+ },
3200
+ "dependencies": {
3201
+ "source-map": {
3202
+ "version": "0.4.4",
3203
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
3204
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
3205
+ "dev": true,
3206
+ "requires": {
3207
+ "amdefine": ">=0.0.4"
3208
+ }
3209
+ }
3210
+ }
3211
+ },
3212
+ "semver": {
3213
+ "version": "5.7.1",
3214
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
3215
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
3216
+ "dev": true
3217
+ },
3218
+ "set-blocking": {
3219
+ "version": "2.0.0",
3220
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
3221
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
3222
+ "dev": true
3223
+ },
3224
+ "set-value": {
3225
+ "version": "2.0.1",
3226
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
3227
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
3228
+ "requires": {
3229
+ "extend-shallow": "^2.0.1",
3230
+ "is-extendable": "^0.1.1",
3231
+ "is-plain-object": "^2.0.3",
3232
+ "split-string": "^3.0.1"
3233
+ },
3234
+ "dependencies": {
3235
+ "extend-shallow": {
3236
+ "version": "2.0.1",
3237
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
3238
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
3239
+ "requires": {
3240
+ "is-extendable": "^0.1.0"
3241
+ }
3242
+ }
3243
+ }
3244
+ },
3245
+ "signal-exit": {
3246
+ "version": "3.0.3",
3247
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
3248
+ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
3249
+ "dev": true
3250
+ },
3251
+ "simple-concat": {
3252
+ "version": "1.0.0",
3253
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
3254
+ "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=",
3255
+ "dev": true,
3256
+ "optional": true
3257
+ },
3258
+ "simple-get": {
3259
+ "version": "3.1.0",
3260
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
3261
+ "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
3262
+ "dev": true,
3263
+ "optional": true,
3264
+ "requires": {
3265
+ "decompress-response": "^4.2.0",
3266
+ "once": "^1.3.1",
3267
+ "simple-concat": "^1.0.0"
3268
+ }
3269
+ },
3270
+ "snapdragon": {
3271
+ "version": "0.8.2",
3272
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
3273
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
3274
+ "requires": {
3275
+ "base": "^0.11.1",
3276
+ "debug": "^2.2.0",
3277
+ "define-property": "^0.2.5",
3278
+ "extend-shallow": "^2.0.1",
3279
+ "map-cache": "^0.2.2",
3280
+ "source-map": "^0.5.6",
3281
+ "source-map-resolve": "^0.5.0",
3282
+ "use": "^3.1.0"
3283
+ },
3284
+ "dependencies": {
3285
+ "define-property": {
3286
+ "version": "0.2.5",
3287
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
3288
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
3289
+ "requires": {
3290
+ "is-descriptor": "^0.1.0"
3291
+ }
3292
+ },
3293
+ "extend-shallow": {
3294
+ "version": "2.0.1",
3295
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
3296
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
3297
+ "requires": {
3298
+ "is-extendable": "^0.1.0"
3299
+ }
3300
+ }
3301
+ }
3302
+ },
3303
+ "snapdragon-node": {
3304
+ "version": "2.1.1",
3305
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
3306
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
3307
+ "requires": {
3308
+ "define-property": "^1.0.0",
3309
+ "isobject": "^3.0.0",
3310
+ "snapdragon-util": "^3.0.1"
3311
+ },
3312
+ "dependencies": {
3313
+ "define-property": {
3314
+ "version": "1.0.0",
3315
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
3316
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
3317
+ "requires": {
3318
+ "is-descriptor": "^1.0.0"
3319
+ }
3320
+ },
3321
+ "is-accessor-descriptor": {
3322
+ "version": "1.0.0",
3323
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
3324
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
3325
+ "requires": {
3326
+ "kind-of": "^6.0.0"
3327
+ }
3328
+ },
3329
+ "is-data-descriptor": {
3330
+ "version": "1.0.0",
3331
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
3332
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
3333
+ "requires": {
3334
+ "kind-of": "^6.0.0"
3335
+ }
3336
+ },
3337
+ "is-descriptor": {
3338
+ "version": "1.0.2",
3339
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
3340
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
3341
+ "requires": {
3342
+ "is-accessor-descriptor": "^1.0.0",
3343
+ "is-data-descriptor": "^1.0.0",
3344
+ "kind-of": "^6.0.2"
3345
+ }
3346
+ }
3347
+ }
3348
+ },
3349
+ "snapdragon-util": {
3350
+ "version": "3.0.1",
3351
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
3352
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
3353
+ "requires": {
3354
+ "kind-of": "^3.2.0"
3355
+ },
3356
+ "dependencies": {
3357
+ "kind-of": {
3358
+ "version": "3.2.2",
3359
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
3360
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
3361
+ "requires": {
3362
+ "is-buffer": "^1.1.5"
3363
+ }
3364
+ }
3365
+ }
3366
+ },
3367
+ "source-map": {
3368
+ "version": "0.5.7",
3369
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
3370
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
3371
+ },
3372
+ "source-map-resolve": {
3373
+ "version": "0.5.3",
3374
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
3375
+ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
3376
+ "requires": {
3377
+ "atob": "^2.1.2",
3378
+ "decode-uri-component": "^0.2.0",
3379
+ "resolve-url": "^0.2.1",
3380
+ "source-map-url": "^0.4.0",
3381
+ "urix": "^0.1.0"
3382
+ }
3383
+ },
3384
+ "source-map-url": {
3385
+ "version": "0.4.0",
3386
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
3387
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM="
3388
+ },
3389
+ "spdx-correct": {
3390
+ "version": "3.1.0",
3391
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
3392
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
3393
+ "dev": true,
3394
+ "requires": {
3395
+ "spdx-expression-parse": "^3.0.0",
3396
+ "spdx-license-ids": "^3.0.0"
3397
+ }
3398
+ },
3399
+ "spdx-exceptions": {
3400
+ "version": "2.2.0",
3401
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
3402
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
3403
+ "dev": true
3404
+ },
3405
+ "spdx-expression-parse": {
3406
+ "version": "3.0.0",
3407
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
3408
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
3409
+ "dev": true,
3410
+ "requires": {
3411
+ "spdx-exceptions": "^2.1.0",
3412
+ "spdx-license-ids": "^3.0.0"
3413
+ }
3414
+ },
3415
+ "spdx-license-ids": {
3416
+ "version": "3.0.5",
3417
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
3418
+ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
3419
+ "dev": true
3420
+ },
3421
+ "split-string": {
3422
+ "version": "3.1.0",
3423
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
3424
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
3425
+ "requires": {
3426
+ "extend-shallow": "^3.0.0"
3427
+ }
3428
+ },
3429
+ "sprintf-js": {
3430
+ "version": "1.1.2",
3431
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
3432
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
3433
+ "dev": true
3434
+ },
3435
+ "sshpk": {
3436
+ "version": "1.16.1",
3437
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
3438
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
3439
+ "dev": true,
3440
+ "requires": {
3441
+ "asn1": "~0.2.3",
3442
+ "assert-plus": "^1.0.0",
3443
+ "bcrypt-pbkdf": "^1.0.0",
3444
+ "dashdash": "^1.12.0",
3445
+ "ecc-jsbn": "~0.1.1",
3446
+ "getpass": "^0.1.1",
3447
+ "jsbn": "~0.1.0",
3448
+ "safer-buffer": "^2.0.2",
3449
+ "tweetnacl": "~0.14.0"
3450
+ }
3451
+ },
3452
+ "static-extend": {
3453
+ "version": "0.1.2",
3454
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
3455
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
3456
+ "requires": {
3457
+ "define-property": "^0.2.5",
3458
+ "object-copy": "^0.1.0"
3459
+ },
3460
+ "dependencies": {
3461
+ "define-property": {
3462
+ "version": "0.2.5",
3463
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
3464
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
3465
+ "requires": {
3466
+ "is-descriptor": "^0.1.0"
3467
+ }
3468
+ }
3469
+ }
3470
+ },
3471
+ "stdout-stream": {
3472
+ "version": "1.4.1",
3473
+ "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
3474
+ "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
3475
+ "dev": true,
3476
+ "requires": {
3477
+ "readable-stream": "^2.0.1"
3478
+ }
3479
+ },
3480
+ "stream-buffers": {
3481
+ "version": "2.2.0",
3482
+ "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
3483
+ "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=",
3484
+ "dev": true
3485
+ },
3486
+ "string-width": {
3487
+ "version": "1.0.2",
3488
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
3489
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
3490
+ "dev": true,
3491
+ "requires": {
3492
+ "code-point-at": "^1.0.0",
3493
+ "is-fullwidth-code-point": "^1.0.0",
3494
+ "strip-ansi": "^3.0.0"
3495
+ }
3496
+ },
3497
+ "string_decoder": {
3498
+ "version": "1.1.1",
3499
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
3500
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
3501
+ "dev": true,
3502
+ "requires": {
3503
+ "safe-buffer": "~5.1.0"
3504
+ }
3505
+ },
3506
+ "strip-ansi": {
3507
+ "version": "3.0.1",
3508
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
3509
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
3510
+ "dev": true,
3511
+ "requires": {
3512
+ "ansi-regex": "^2.0.0"
3513
+ }
3514
+ },
3515
+ "strip-bom": {
3516
+ "version": "2.0.0",
3517
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
3518
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
3519
+ "dev": true,
3520
+ "requires": {
3521
+ "is-utf8": "^0.2.0"
3522
+ }
3523
+ },
3524
+ "strip-indent": {
3525
+ "version": "1.0.1",
3526
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
3527
+ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
3528
+ "dev": true,
3529
+ "requires": {
3530
+ "get-stdin": "^4.0.1"
3531
+ }
3532
+ },
3533
+ "strip-json-comments": {
3534
+ "version": "2.0.1",
3535
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
3536
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
3537
+ "dev": true
3538
+ },
3539
+ "supports-color": {
3540
+ "version": "5.5.0",
3541
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
3542
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
3543
+ "dev": true,
3544
+ "requires": {
3545
+ "has-flag": "^3.0.0"
3546
+ }
3547
+ },
3548
+ "tar": {
3549
+ "version": "2.2.2",
3550
+ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
3551
+ "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
3552
+ "dev": true,
3553
+ "requires": {
3554
+ "block-stream": "*",
3555
+ "fstream": "^1.0.12",
3556
+ "inherits": "2"
3557
+ }
3558
+ },
3559
+ "tar-fs": {
3560
+ "version": "2.0.1",
3561
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz",
3562
+ "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==",
3563
+ "dev": true,
3564
+ "optional": true,
3565
+ "requires": {
3566
+ "chownr": "^1.1.1",
3567
+ "mkdirp-classic": "^0.5.2",
3568
+ "pump": "^3.0.0",
3569
+ "tar-stream": "^2.0.0"
3570
+ },
3571
+ "dependencies": {
3572
+ "bl": {
3573
+ "version": "4.0.2",
3574
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
3575
+ "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==",
3576
+ "dev": true,
3577
+ "optional": true,
3578
+ "requires": {
3579
+ "buffer": "^5.5.0",
3580
+ "inherits": "^2.0.4",
3581
+ "readable-stream": "^3.4.0"
3582
+ }
3583
+ },
3584
+ "readable-stream": {
3585
+ "version": "3.6.0",
3586
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
3587
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
3588
+ "dev": true,
3589
+ "optional": true,
3590
+ "requires": {
3591
+ "inherits": "^2.0.3",
3592
+ "string_decoder": "^1.1.1",
3593
+ "util-deprecate": "^1.0.1"
3594
+ }
3595
+ },
3596
+ "tar-stream": {
3597
+ "version": "2.1.2",
3598
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz",
3599
+ "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==",
3600
+ "dev": true,
3601
+ "optional": true,
3602
+ "requires": {
3603
+ "bl": "^4.0.1",
3604
+ "end-of-stream": "^1.4.1",
3605
+ "fs-constants": "^1.0.0",
3606
+ "inherits": "^2.0.3",
3607
+ "readable-stream": "^3.1.1"
3608
+ }
3609
+ }
3610
+ }
3611
+ },
3612
+ "tar-stream": {
3613
+ "version": "1.6.2",
3614
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
3615
+ "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
3616
+ "dev": true,
3617
+ "requires": {
3618
+ "bl": "^1.0.0",
3619
+ "buffer-alloc": "^1.2.0",
3620
+ "end-of-stream": "^1.0.0",
3621
+ "fs-constants": "^1.0.0",
3622
+ "readable-stream": "^2.3.0",
3623
+ "to-buffer": "^1.1.1",
3624
+ "xtend": "^4.0.0"
3625
+ }
3626
+ },
3627
+ "to-buffer": {
3628
+ "version": "1.1.1",
3629
+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
3630
+ "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
3631
+ "dev": true
3632
+ },
3633
+ "to-object-path": {
3634
+ "version": "0.3.0",
3635
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
3636
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
3637
+ "requires": {
3638
+ "kind-of": "^3.0.2"
3639
+ },
3640
+ "dependencies": {
3641
+ "kind-of": {
3642
+ "version": "3.2.2",
3643
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
3644
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
3645
+ "requires": {
3646
+ "is-buffer": "^1.1.5"
3647
+ }
3648
+ }
3649
+ }
3650
+ },
3651
+ "to-regex": {
3652
+ "version": "3.0.2",
3653
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
3654
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
3655
+ "requires": {
3656
+ "define-property": "^2.0.2",
3657
+ "extend-shallow": "^3.0.2",
3658
+ "regex-not": "^1.0.2",
3659
+ "safe-regex": "^1.1.0"
3660
+ }
3661
+ },
3662
+ "to-regex-range": {
3663
+ "version": "2.1.1",
3664
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
3665
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
3666
+ "requires": {
3667
+ "is-number": "^3.0.0",
3668
+ "repeat-string": "^1.6.1"
3669
+ }
3670
+ },
3671
+ "tough-cookie": {
3672
+ "version": "2.5.0",
3673
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
3674
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
3675
+ "dev": true,
3676
+ "requires": {
3677
+ "psl": "^1.1.28",
3678
+ "punycode": "^2.1.1"
3679
+ }
3680
+ },
3681
+ "trim-newlines": {
3682
+ "version": "1.0.0",
3683
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
3684
+ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
3685
+ "dev": true
3686
+ },
3687
+ "true-case-path": {
3688
+ "version": "1.0.3",
3689
+ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
3690
+ "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
3691
+ "dev": true,
3692
+ "requires": {
3693
+ "glob": "^7.1.2"
3694
+ },
3695
+ "dependencies": {
3696
+ "glob": {
3697
+ "version": "7.1.6",
3698
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
3699
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
3700
+ "dev": true,
3701
+ "requires": {
3702
+ "fs.realpath": "^1.0.0",
3703
+ "inflight": "^1.0.4",
3704
+ "inherits": "2",
3705
+ "minimatch": "^3.0.4",
3706
+ "once": "^1.3.0",
3707
+ "path-is-absolute": "^1.0.0"
3708
+ }
3709
+ }
3710
+ }
3711
+ },
3712
+ "tunnel-agent": {
3713
+ "version": "0.6.0",
3714
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
3715
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
3716
+ "dev": true,
3717
+ "requires": {
3718
+ "safe-buffer": "^5.0.1"
3719
+ }
3720
+ },
3721
+ "tweetnacl": {
3722
+ "version": "0.14.5",
3723
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
3724
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
3725
+ "dev": true
3726
+ },
3727
+ "unc-path-regex": {
3728
+ "version": "0.1.2",
3729
+ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
3730
+ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo="
3731
+ },
3732
+ "underscore.string": {
3733
+ "version": "3.3.5",
3734
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
3735
+ "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
3736
+ "dev": true,
3737
+ "requires": {
3738
+ "sprintf-js": "^1.0.3",
3739
+ "util-deprecate": "^1.0.2"
3740
+ }
3741
+ },
3742
+ "union-value": {
3743
+ "version": "1.0.1",
3744
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
3745
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
3746
+ "requires": {
3747
+ "arr-union": "^3.1.0",
3748
+ "get-value": "^2.0.6",
3749
+ "is-extendable": "^0.1.1",
3750
+ "set-value": "^2.0.1"
3751
+ }
3752
+ },
3753
+ "unset-value": {
3754
+ "version": "1.0.0",
3755
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
3756
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
3757
+ "requires": {
3758
+ "has-value": "^0.3.1",
3759
+ "isobject": "^3.0.0"
3760
+ },
3761
+ "dependencies": {
3762
+ "has-value": {
3763
+ "version": "0.3.1",
3764
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
3765
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
3766
+ "requires": {
3767
+ "get-value": "^2.0.3",
3768
+ "has-values": "^0.1.4",
3769
+ "isobject": "^2.0.0"
3770
+ },
3771
+ "dependencies": {
3772
+ "isobject": {
3773
+ "version": "2.1.0",
3774
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
3775
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
3776
+ "requires": {
3777
+ "isarray": "1.0.0"
3778
+ }
3779
+ }
3780
+ }
3781
+ },
3782
+ "has-values": {
3783
+ "version": "0.1.4",
3784
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
3785
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
3786
+ }
3787
+ }
3788
+ },
3789
+ "uri-js": {
3790
+ "version": "4.2.2",
3791
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
3792
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
3793
+ "dev": true,
3794
+ "requires": {
3795
+ "punycode": "^2.1.0"
3796
+ }
3797
+ },
3798
+ "urix": {
3799
+ "version": "0.1.0",
3800
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
3801
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
3802
+ },
3803
+ "use": {
3804
+ "version": "3.1.1",
3805
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
3806
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
3807
+ },
3808
+ "util-deprecate": {
3809
+ "version": "1.0.2",
3810
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
3811
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
3812
+ "dev": true
3813
+ },
3814
+ "uuid": {
3815
+ "version": "3.4.0",
3816
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
3817
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
3818
+ "dev": true
3819
+ },
3820
+ "v8flags": {
3821
+ "version": "3.1.3",
3822
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz",
3823
+ "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==",
3824
+ "requires": {
3825
+ "homedir-polyfill": "^1.0.1"
3826
+ }
3827
+ },
3828
+ "validate-npm-package-license": {
3829
+ "version": "3.0.4",
3830
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
3831
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
3832
+ "dev": true,
3833
+ "requires": {
3834
+ "spdx-correct": "^3.0.0",
3835
+ "spdx-expression-parse": "^3.0.0"
3836
+ }
3837
+ },
3838
+ "verror": {
3839
+ "version": "1.10.0",
3840
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
3841
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
3842
+ "dev": true,
3843
+ "requires": {
3844
+ "assert-plus": "^1.0.0",
3845
+ "core-util-is": "1.0.2",
3846
+ "extsprintf": "^1.2.0"
3847
+ }
3848
+ },
3849
+ "walkdir": {
3850
+ "version": "0.0.11",
3851
+ "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz",
3852
+ "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=",
3853
+ "dev": true
3854
+ },
3855
+ "which": {
3856
+ "version": "1.3.1",
3857
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
3858
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
3859
+ "requires": {
3860
+ "isexe": "^2.0.0"
3861
+ }
3862
+ },
3863
+ "which-module": {
3864
+ "version": "1.0.0",
3865
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
3866
+ "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
3867
+ "dev": true
3868
+ },
3869
+ "which-pm-runs": {
3870
+ "version": "1.0.0",
3871
+ "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
3872
+ "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
3873
+ "dev": true,
3874
+ "optional": true
3875
+ },
3876
+ "wide-align": {
3877
+ "version": "1.1.3",
3878
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
3879
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
3880
+ "dev": true,
3881
+ "requires": {
3882
+ "string-width": "^1.0.2 || 2"
3883
+ }
3884
+ },
3885
+ "wrap-ansi": {
3886
+ "version": "2.1.0",
3887
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
3888
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
3889
+ "dev": true,
3890
+ "requires": {
3891
+ "string-width": "^1.0.1",
3892
+ "strip-ansi": "^3.0.1"
3893
+ }
3894
+ },
3895
+ "wrappy": {
3896
+ "version": "1.0.2",
3897
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
3898
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
3899
+ "dev": true
3900
+ },
3901
+ "xtend": {
3902
+ "version": "4.0.2",
3903
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
3904
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
3905
+ "dev": true
3906
+ },
3907
+ "y18n": {
3908
+ "version": "3.2.1",
3909
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
3910
+ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
3911
+ "dev": true
3912
+ },
3913
+ "yallist": {
3914
+ "version": "2.1.2",
3915
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
3916
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
3917
+ "dev": true
3918
+ },
3919
+ "yargs": {
3920
+ "version": "7.1.0",
3921
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
3922
+ "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
3923
+ "dev": true,
3924
+ "requires": {
3925
+ "camelcase": "^3.0.0",
3926
+ "cliui": "^3.2.0",
3927
+ "decamelize": "^1.1.1",
3928
+ "get-caller-file": "^1.0.1",
3929
+ "os-locale": "^1.4.0",
3930
+ "read-pkg-up": "^1.0.1",
3931
+ "require-directory": "^2.1.1",
3932
+ "require-main-filename": "^1.0.1",
3933
+ "set-blocking": "^2.0.0",
3934
+ "string-width": "^1.0.2",
3935
+ "which-module": "^1.0.0",
3936
+ "y18n": "^3.2.1",
3937
+ "yargs-parser": "^5.0.0"
3938
+ },
3939
+ "dependencies": {
3940
+ "camelcase": {
3941
+ "version": "3.0.0",
3942
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
3943
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
3944
+ "dev": true
3945
+ }
3946
+ }
3947
+ },
3948
+ "yargs-parser": {
3949
+ "version": "5.0.0",
3950
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
3951
+ "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
3952
+ "dev": true,
3953
+ "requires": {
3954
+ "camelcase": "^3.0.0"
3955
+ },
3956
+ "dependencies": {
3957
+ "camelcase": {
3958
+ "version": "3.0.0",
3959
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
3960
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
3961
+ "dev": true
3962
+ }
3963
+ }
3964
+ },
3965
+ "zip-stream": {
3966
+ "version": "1.2.0",
3967
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz",
3968
+ "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=",
3969
+ "dev": true,
3970
+ "requires": {
3971
+ "archiver-utils": "^1.3.0",
3972
+ "compress-commons": "^1.2.0",
3973
+ "lodash": "^4.8.0",
3974
+ "readable-stream": "^2.0.0"
3975
+ }
3976
+ }
3977
+ }
3978
+ }
admin/bsf-analytics/package.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "bsf-analytics",
3
+ "version": "1.0.0",
4
+ "description": "BSF Analytics Project.",
5
+ "main": "Gruntfile.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git@git.brainstormforce.com:wp-sharks/bsf-analytics.git"
9
+ },
10
+ "author": "",
11
+ "license": "ISC",
12
+ "devDependencies": {
13
+ "autoprefixer": "^9.6.1",
14
+ "grunt": "^1.0.4",
15
+ "grunt-contrib-clean": "^2.0.0",
16
+ "grunt-contrib-compress": "^1.5.0",
17
+ "grunt-contrib-copy": "^1.0.0",
18
+ "grunt-contrib-cssmin": "^3.0.0",
19
+ "grunt-postcss": "^0.9.0",
20
+ "grunt-rtlcss": "^2.0.2",
21
+ "grunt-text-replace": "^0.4.0",
22
+ "kind-of": ">=6.0.3",
23
+ "minimist": ">=1.2.3",
24
+ "node-sass": "^4.13.1",
25
+ "postcss-flexibility": "^2.0.0"
26
+ },
27
+ "dependencies": {
28
+ "grunt-cli": "^1.3.2"
29
+ }
30
+ }
admin/bsf-analytics/phpcs.xml.dist ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <ruleset name="WordPress Coding Standards for Plugins">
3
+ <description>Generally-applicable sniffs for WordPress plugins</description>
4
+ <config name="testVersion" value="5.3-"/>
5
+
6
+ <rule ref="WordPress-Core" />
7
+ <rule ref="WordPress-Docs" />
8
+ <rule ref="WordPress-Extra" />
9
+
10
+ <!-- Check all PHP files in directory tree by default. -->
11
+ <arg name="extensions" value="php"/>
12
+ <file>.</file>
13
+
14
+ <!-- Show sniff codes in all reports -->
15
+ <arg value="s"/>
16
+
17
+ <exclude-pattern>*/node_modules/*</exclude-pattern>
18
+ <exclude-pattern>*/vendor/*</exclude-pattern>
19
+ </ruleset>
admin/bsf-analytics/version.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ {
2
+ "bsf-analytics-ver": "1.1.0"
3
+ }
4
+
changelog.txt CHANGED
@@ -1,6 +1,10 @@
 
 
 
 
1
  Version 1.2.7 - Tuesday, 16th June 2020
2
- - New: Users can now share [non-personal usage data] to help us test and develop better products.
3
- ( https://store.brainstormforce.com/usage-tracking/?utm_source=wp_repo&utm_medium=changelog&utm_campaign=usage_tracking )
4
 
5
  Version 1.2.6 - Thursday, 21st May 2020
6
  - New: Added option to send the email to admin after successfully cart recovery of the abandoned order.
1
+ Version 1.2.8 - Friday, 14th August 2020
2
+ - New: Added new option to prevent recovery emails for specific order status.
3
+ - Fix: Deprecated the 'woo_ca_exclude_on_hold_order_from_tracking' filter.
4
+
5
  Version 1.2.7 - Tuesday, 16th June 2020
6
+ - New: Users can now share [non-personal usage data] to help us test and develop better products.
7
+ (https://my.cartflows.com/usage-tracking/?utm_source=wp_repo&utm_medium=changelog&utm_campaign=usage_tracking)
8
 
9
  Version 1.2.6 - Thursday, 21st May 2020
10
  - New: Added option to send the email to admin after successfully cart recovery of the abandoned order.
classes/class-cartflows-ca-loader.php CHANGED
@@ -78,7 +78,7 @@ if ( ! class_exists( 'CARTFLOWS_CA_Loader' ) ) {
78
  define( 'CARTFLOWS_CA_BASE', plugin_basename( CARTFLOWS_CA_FILE ) );
79
  define( 'CARTFLOWS_CA_DIR', plugin_dir_path( CARTFLOWS_CA_FILE ) );
80
  define( 'CARTFLOWS_CA_URL', plugins_url( '/', CARTFLOWS_CA_FILE ) );
81
- define( 'CARTFLOWS_CA_VER', '1.2.7' );
82
  define( 'CARTFLOWS_CA_SLUG', 'cartflows_ca' );
83
 
84
  define( 'CARTFLOWS_CA_CART_ABANDONMENT_TABLE', 'cartflows_ca_cart_abandonment' );
@@ -115,6 +115,9 @@ if ( ! class_exists( 'CARTFLOWS_CA_Loader' ) ) {
115
  do_action( 'cartflows_ca_init' );
116
  }
117
 
 
 
 
118
  /**
119
  * Fires admin notice when Elementor is not installed and activated.
120
  *
@@ -215,7 +218,22 @@ if ( ! class_exists( 'CARTFLOWS_CA_Loader' ) ) {
215
  require_once CARTFLOWS_CA_DIR . 'lib/notices/class-astra-notices.php';
216
  }
217
 
218
- require_once CARTFLOWS_CA_DIR . 'admin/bsf-analytics/class-bsf-analytics.php';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  }
220
 
221
  /**
@@ -319,6 +337,8 @@ if ( ! class_exists( 'CARTFLOWS_CA_Loader' ) ) {
319
  'wcf_ca_gdpr_message' => 'Your email & cart are saved so we can send email reminders about this order.',
320
  'wcf_ca_coupon_expiry' => 0,
321
  'wcf_ca_coupon_expiry_unit' => 'hours',
 
 
322
  );
323
 
324
  foreach ( $default_settings as $option_key => $option_value ) {
78
  define( 'CARTFLOWS_CA_BASE', plugin_basename( CARTFLOWS_CA_FILE ) );
79
  define( 'CARTFLOWS_CA_DIR', plugin_dir_path( CARTFLOWS_CA_FILE ) );
80
  define( 'CARTFLOWS_CA_URL', plugins_url( '/', CARTFLOWS_CA_FILE ) );
81
+ define( 'CARTFLOWS_CA_VER', '1.2.8' );
82
  define( 'CARTFLOWS_CA_SLUG', 'cartflows_ca' );
83
 
84
  define( 'CARTFLOWS_CA_CART_ABANDONMENT_TABLE', 'cartflows_ca_cart_abandonment' );
115
  do_action( 'cartflows_ca_init' );
116
  }
117
 
118
+
119
+
120
+
121
  /**
122
  * Fires admin notice when Elementor is not installed and activated.
123
  *
218
  require_once CARTFLOWS_CA_DIR . 'lib/notices/class-astra-notices.php';
219
  }
220
 
221
+ if ( ! class_exists( 'BSF_Analytics_Loader' ) ) {
222
+ require_once CARTFLOWS_CA_DIR . '/admin/bsf-analytics/class-bsf-analytics-loader.php';
223
+ }
224
+
225
+ $bsf_analytics = BSF_Analytics_Loader::get_instance();
226
+
227
+ $bsf_analytics->set_entity(
228
+ array(
229
+ 'cf' => array(
230
+ 'product_name' => 'Woocommerce Cart Abandonment Recovery',
231
+ 'usage_doc_link' => 'https://my.cartflows.com/usage-tracking/',
232
+ 'path' => CARTFLOWS_CA_DIR . 'admin/bsf-analytics',
233
+ 'author' => 'CartFlows Inc',
234
+ ),
235
+ )
236
+ );
237
  }
238
 
239
  /**
337
  'wcf_ca_gdpr_message' => 'Your email & cart are saved so we can send email reminders about this order.',
338
  'wcf_ca_coupon_expiry' => 0,
339
  'wcf_ca_coupon_expiry_unit' => 'hours',
340
+ 'wcf_ca_excludes_orders' => array( 'processing', 'completed' ),
341
+
342
  );
343
 
344
  foreach ( $default_settings as $option_key => $option_value ) {
classes/class-cartflows-ca-settings.php CHANGED
@@ -84,6 +84,20 @@ class Cartflows_Ca_Settings {
84
  'wcf_ca_ignore_users'
85
  );
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  add_settings_field(
88
  'wcar_email_admin_on_recovery',
89
  __( 'Notify recovery to admin', 'woo-cart-abandonment-recovery' ),
@@ -573,6 +587,43 @@ class Cartflows_Ca_Settings {
573
  echo wp_kses_post( $html );
574
  }
575
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
576
  /**
577
  * Delete coupons.
578
  *
84
  'wcf_ca_ignore_users'
85
  );
86
 
87
+ add_settings_field(
88
+ 'wcf_ca_excludes_orders',
89
+ __( 'Exclude email sending For', 'woo-cart-abandonment-recovery' ),
90
+ array( $this, 'wcf_ca_exclude_orders_callback' ),
91
+ WCF_CA_PAGE_NAME,
92
+ WCF_CA_GENERAL_SETTINGS_SECTION,
93
+ array( '<br><span class="description"><strong>Note:</strong>' . __( ' It will not send future recovery emails to selected order status and will mark as recovered.', 'woo-cart-abandonment-recovery' ) . '</span>' )
94
+ );
95
+
96
+ register_setting(
97
+ WCF_CA_SETTINGS_OPTION_GROUP,
98
+ 'wcf_ca_excludes_orders'
99
+ );
100
+
101
  add_settings_field(
102
  'wcar_email_admin_on_recovery',
103
  __( 'Notify recovery to admin', 'woo-cart-abandonment-recovery' ),
587
  echo wp_kses_post( $html );
588
  }
589
 
590
+ /**
591
+ * Callback for ignore users from tracking cart.
592
+ *
593
+ * @param array $args args.
594
+ * @since 1.1.5
595
+ */
596
+ public function wcf_ca_exclude_orders_callback( $args ) {
597
+ $wcf_ca_excludes_orders = get_option( 'wcf_ca_excludes_orders' );
598
+
599
+ $html = '';
600
+ $order_status = wc_get_order_statuses();
601
+ $new_order_status = str_replace( 'wc-', '', array_keys( $order_status ) );
602
+ $order_status = array_combine( $new_order_status, $order_status );
603
+ $order_status = \array_diff( $order_status, array( 'Refunded', 'Draft', 'Cancelled' ) );
604
+ ?>
605
+ <p class="wcf-ca-excludes-orders" name="wcf-ca-excludes-orders">
606
+ <?php
607
+ foreach ( $order_status as $key => $value ) {
608
+ ?>
609
+ <input type="checkbox" name="wcf_ca_excludes_orders[]"
610
+ <?php
611
+ if ( ! empty( $wcf_ca_excludes_orders ) && in_array( $key, $wcf_ca_excludes_orders, true ) ) {
612
+ checked( true, true );
613
+ }
614
+ ?>
615
+ value="<?php echo esc_attr( $key ); ?>">
616
+ <?php
617
+ echo esc_attr( $value );
618
+ echo '<br> ';
619
+ }
620
+ ?>
621
+ </p>
622
+
623
+ <?php
624
+ $html .= '<span for="wcf_ca_excludes_orders"> ' . $args[0] . '</span>';
625
+ echo wp_kses_post( $html );
626
+ }
627
  /**
628
  * Delete coupons.
629
  *
classes/class-cartflows-ca-update.php CHANGED
@@ -1,92 +1,92 @@
1
- <?php
2
- /**
3
- * Update Compatibility
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! class_exists( 'Cartflows_Ca_Update' ) ) :
9
-
10
- /**
11
- * CartFlows CA Update initial setup
12
- *
13
- * @since 1.0.0
14
- */
15
- class Cartflows_Ca_Update {
16
-
17
- /**
18
- * Class instance.
19
- *
20
- * @access private
21
- * @var $instance Class instance.
22
- */
23
- private static $instance;
24
-
25
- /**
26
- * Initiator
27
- */
28
- public static function get_instance() {
29
- if ( ! isset( self::$instance ) ) {
30
- self::$instance = new self();
31
- }
32
- return self::$instance;
33
- }
34
-
35
- /**
36
- * Constructor
37
- */
38
- public function __construct() {
39
- add_action( 'admin_init', __CLASS__ . '::init' );
40
- }
41
-
42
- /**
43
- * Create tables if not exists and seed default settings.
44
- */
45
- public static function update_table_with_default_settings() {
46
-
47
- $cartflows_loader = CARTFLOWS_CA_Loader::get_instance();
48
- $cartflows_loader->initialize_cart_abandonment_tables();
49
- $cartflows_loader->update_default_settings();
50
- }
51
-
52
-
53
- /**
54
- * Init
55
- *
56
- * @since 1.0.0
57
- * @return void
58
- */
59
- public static function init() {
60
-
61
- do_action( 'cartflows_ca_update_before' );
62
-
63
- // Get auto saved version number.
64
- $saved_version = get_option( 'wcf_ca_version', false );
65
-
66
- // Update auto saved version number.
67
- if ( ! $saved_version ) {
68
- self::update_table_with_default_settings();
69
- update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
70
- return;
71
- }
72
-
73
- // If equals then return.
74
- if ( version_compare( $saved_version, CARTFLOWS_CA_VER, '=' ) ) {
75
- return;
76
- }
77
-
78
- // Update auto saved version number.
79
- update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
80
-
81
- self::update_table_with_default_settings();
82
-
83
- do_action( 'cartflows_ca_update_after' );
84
- }
85
- }
86
-
87
- /**
88
- * Kicking this off by calling 'get_instance()' method
89
- */
90
- Cartflows_Ca_Update::get_instance();
91
-
92
- endif;
1
+ <?php
2
+ /**
3
+ * Update Compatibility
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! class_exists( 'Cartflows_Ca_Update' ) ) :
9
+
10
+ /**
11
+ * CartFlows CA Update initial setup
12
+ *
13
+ * @since 1.0.0
14
+ */
15
+ class Cartflows_Ca_Update {
16
+
17
+ /**
18
+ * Class instance.
19
+ *
20
+ * @access private
21
+ * @var $instance Class instance.
22
+ */
23
+ private static $instance;
24
+
25
+ /**
26
+ * Initiator
27
+ */
28
+ public static function get_instance() {
29
+ if ( ! isset( self::$instance ) ) {
30
+ self::$instance = new self();
31
+ }
32
+ return self::$instance;
33
+ }
34
+
35
+ /**
36
+ * Constructor
37
+ */
38
+ public function __construct() {
39
+ add_action( 'admin_init', __CLASS__ . '::init' );
40
+ }
41
+
42
+ /**
43
+ * Create tables if not exists and seed default settings.
44
+ */
45
+ public static function update_table_with_default_settings() {
46
+
47
+ $cartflows_loader = CARTFLOWS_CA_Loader::get_instance();
48
+ $cartflows_loader->initialize_cart_abandonment_tables();
49
+ $cartflows_loader->update_default_settings();
50
+ }
51
+
52
+
53
+ /**
54
+ * Init
55
+ *
56
+ * @since 1.0.0
57
+ * @return void
58
+ */
59
+ public static function init() {
60
+
61
+ do_action( 'cartflows_ca_update_before' );
62
+
63
+ // Get auto saved version number.
64
+ $saved_version = get_option( 'wcf_ca_version', false );
65
+
66
+ // Update auto saved version number.
67
+ if ( ! $saved_version ) {
68
+ self::update_table_with_default_settings();
69
+ update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
70
+ return;
71
+ }
72
+
73
+ // If equals then return.
74
+ if ( version_compare( $saved_version, CARTFLOWS_CA_VER, '=' ) ) {
75
+ return;
76
+ }
77
+
78
+ // Update auto saved version number.
79
+ update_option( 'wcf_ca_version', CARTFLOWS_CA_VER );
80
+
81
+ self::update_table_with_default_settings();
82
+
83
+ do_action( 'cartflows_ca_update_after' );
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Kicking this off by calling 'get_instance()' method
89
+ */
90
+ Cartflows_Ca_Update::get_instance();
91
+
92
+ endif;
classes/class-cartflows-ca-utils.php CHANGED
@@ -1,115 +1,115 @@
1
- <?php
2
- /**
3
- * Utils.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- exit; // Exit if accessed directly.
10
- }
11
-
12
- /**
13
- * Class Cartflows_Ca_Utils.
14
- */
15
- class Cartflows_Ca_Utils {
16
-
17
-
18
- /**
19
- * Member Variable
20
- *
21
- * @var instance
22
- */
23
- private static $instance;
24
-
25
- /**
26
- * Common zapier data
27
- *
28
- * @var zapier
29
- */
30
- private static $zapier = null;
31
-
32
- /**
33
- * Common zapier data
34
- *
35
- * @var zapier
36
- */
37
- private static $cart_abandonment_settings = null;
38
-
39
-
40
- /**
41
- * Initiator
42
- */
43
- public static function get_instance() {
44
- if ( ! isset( self::$instance ) ) {
45
- self::$instance = new self();
46
- }
47
- return self::$instance;
48
- }
49
-
50
- /**
51
- * Check if cart abandonment tracking is enabled.
52
- *
53
- * @return bool
54
- */
55
- public function is_cart_abandonment_tracking_enabled() {
56
-
57
- $wcf_ca_status = get_option( 'wcf_ca_status' );
58
-
59
- // Check if abandonment cart tracking is disabled or zapier webhook is empty.
60
- if ( isset( $wcf_ca_status ) && 'on' === $wcf_ca_status ) {
61
- return true;
62
- }
63
-
64
- return false;
65
- }
66
-
67
- /**
68
- * Check if cart abandonment tracking is enabled.
69
- *
70
- * @return bool
71
- */
72
- public function is_zapier_trigger_enabled() {
73
-
74
- $wcf_ca_zapier_tracking_status = get_option( 'wcf_ca_zapier_tracking_status' );
75
-
76
- // Check if zapier tracking is disabled or zapier webhook is empty.
77
- if ( isset( $wcf_ca_zapier_tracking_status ) && 'on' === $wcf_ca_zapier_tracking_status ) {
78
- return true;
79
- }
80
-
81
- return false;
82
- }
83
-
84
- /**
85
- * Get cart abandonment tracking cutoff time.
86
- *
87
- * @param boolean $in_seconds get cutoff time in seconds if true.
88
- * @return bool
89
- */
90
- public function get_cart_abandonment_tracking_cut_off_time( $in_seconds = false ) {
91
-
92
- $cart_abandoned_time = apply_filters( 'cartflows_ca_cart_abandonment_cut_off_time', WCF_DEFAULT_CUT_OFF_TIME );
93
- return $in_seconds ? $cart_abandoned_time * MINUTE_IN_SECONDS : $cart_abandoned_time;
94
-
95
- }
96
-
97
- /**
98
- * Check if GDPR is enabled.
99
- *
100
- * @return bool
101
- */
102
- public function is_gdpr_enabled() {
103
-
104
- $wcf_ca_gdpr_status = get_option( 'wcf_ca_gdpr_status' );
105
-
106
- // Check if abandonment cart tracking is disabled or zapier webhook is empty.
107
- if ( isset( $wcf_ca_gdpr_status ) && 'on' === $wcf_ca_gdpr_status ) {
108
- return true;
109
- }
110
-
111
- return false;
112
- }
113
-
114
-
115
- }
1
+ <?php
2
+ /**
3
+ * Utils.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ exit; // Exit if accessed directly.
10
+ }
11
+
12
+ /**
13
+ * Class Cartflows_Ca_Utils.
14
+ */
15
+ class Cartflows_Ca_Utils {
16
+
17
+
18
+ /**
19
+ * Member Variable
20
+ *
21
+ * @var instance
22
+ */
23
+ private static $instance;
24
+
25
+ /**
26
+ * Common zapier data
27
+ *
28
+ * @var zapier
29
+ */
30
+ private static $zapier = null;
31
+
32
+ /**
33
+ * Common zapier data
34
+ *
35
+ * @var zapier
36
+ */
37
+ private static $cart_abandonment_settings = null;
38
+
39
+
40
+ /**
41
+ * Initiator
42
+ */
43
+ public static function get_instance() {
44
+ if ( ! isset( self::$instance ) ) {
45
+ self::$instance = new self();
46
+ }
47
+ return self::$instance;
48
+ }
49
+
50
+ /**
51
+ * Check if cart abandonment tracking is enabled.
52
+ *
53
+ * @return bool
54
+ */
55
+ public function is_cart_abandonment_tracking_enabled() {
56
+
57
+ $wcf_ca_status = get_option( 'wcf_ca_status' );
58
+
59
+ // Check if abandonment cart tracking is disabled or zapier webhook is empty.
60
+ if ( isset( $wcf_ca_status ) && 'on' === $wcf_ca_status ) {
61
+ return true;
62
+ }
63
+
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * Check if cart abandonment tracking is enabled.
69
+ *
70
+ * @return bool
71
+ */
72
+ public function is_zapier_trigger_enabled() {
73
+
74
+ $wcf_ca_zapier_tracking_status = get_option( 'wcf_ca_zapier_tracking_status' );
75
+
76
+ // Check if zapier tracking is disabled or zapier webhook is empty.
77
+ if ( isset( $wcf_ca_zapier_tracking_status ) && 'on' === $wcf_ca_zapier_tracking_status ) {
78
+ return true;
79
+ }
80
+
81
+ return false;
82
+ }
83
+
84
+ /**
85
+ * Get cart abandonment tracking cutoff time.
86
+ *
87
+ * @param boolean $in_seconds get cutoff time in seconds if true.
88
+ * @return bool
89
+ */
90
+ public function get_cart_abandonment_tracking_cut_off_time( $in_seconds = false ) {
91
+
92
+ $cart_abandoned_time = apply_filters( 'cartflows_ca_cart_abandonment_cut_off_time', WCF_DEFAULT_CUT_OFF_TIME );
93
+ return $in_seconds ? $cart_abandoned_time * MINUTE_IN_SECONDS : $cart_abandoned_time;
94
+
95
+ }
96
+
97
+ /**
98
+ * Check if GDPR is enabled.
99
+ *
100
+ * @return bool
101
+ */
102
+ public function is_gdpr_enabled() {
103
+
104
+ $wcf_ca_gdpr_status = get_option( 'wcf_ca_gdpr_status' );
105
+
106
+ // Check if abandonment cart tracking is disabled or zapier webhook is empty.
107
+ if ( isset( $wcf_ca_gdpr_status ) && 'on' === $wcf_ca_gdpr_status ) {
108
+ return true;
109
+ }
110
+
111
+ return false;
112
+ }
113
+
114
+
115
+ }
languages/woo-cart-abandonment-recovery.pot CHANGED
@@ -1,879 +1,885 @@
1
- # Copyright (C) 2020 CartFlows Inc
2
- # This file is distributed under the same license as the WooCommerce Cart Abandonment Recovery package.
3
- msgid ""
4
- msgstr ""
5
- "Project-Id-Version: WooCommerce Cart Abandonment Recovery 1.2.7\n"
6
- "Report-Msgid-Bugs-To: "
7
- "https://wordpress.org/support/plugin/woo-cart-abandonment-recovery\n"
8
- "POT-Creation-Date: 2020-06-16 08:57:12+00:00\n"
9
- "MIME-Version: 1.0\n"
10
- "Content-Type: text/plain; charset=utf-8\n"
11
- "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
13
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
- "Language-Team: LANGUAGE <LL@li.org>\n"
15
- "Language: en\n"
16
- "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
- "X-Poedit-Country: United States\n"
18
- "X-Poedit-SourceCharset: UTF-8\n"
19
- "X-Poedit-KeywordsList: "
20
- "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
21
- "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
22
- "X-Poedit-Basepath: ../\n"
23
- "X-Poedit-SearchPath-0: .\n"
24
- "X-Poedit-Bookmarks: \n"
25
- "X-Textdomain-Support: yes\n"
26
- "X-Generator: grunt-wp-i18n 1.0.3\n"
27
-
28
- #: admin/bsf-analytics/class-bsf-analytics.php:183
29
- #. translators: %s product name
30
- msgid ""
31
- "Want to help make <strong>%1s</strong> even more awesome? Allow us to "
32
- "collect non-sensitive diagnostic data and usage information. "
33
- msgstr ""
34
-
35
- #: admin/bsf-analytics/class-bsf-analytics.php:186
36
- msgid "This will be applicable for all sites from the network."
37
- msgstr ""
38
-
39
- #: admin/bsf-analytics/class-bsf-analytics.php:210
40
- #. translators: %s usage doc link
41
- msgid " Know More."
42
- msgstr ""
43
-
44
- #: admin/bsf-analytics/class-bsf-analytics.php:217
45
- msgid "Yes! Allow it"
46
- msgstr ""
47
-
48
- #: admin/bsf-analytics/class-bsf-analytics.php:225
49
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:536
50
- msgid "No Thanks"
51
- msgstr ""
52
-
53
- #: admin/bsf-analytics/class-bsf-analytics.php:294
54
- msgid "Every two days"
55
- msgstr ""
56
-
57
- #: admin/bsf-analytics/class-bsf-analytics.php:348
58
- msgid "Usage Tracking"
59
- msgstr ""
60
-
61
- #: admin/bsf-analytics/class-bsf-analytics.php:380
62
- msgid "Allow Brainstorm Force products to track non-sensitive usage tracking data."
63
- msgstr ""
64
-
65
- #: admin/bsf-analytics/class-bsf-analytics.php:383
66
- msgid " This will be applicable for all sites from the network."
67
- msgstr ""
68
-
69
- #: admin/bsf-analytics/class-bsf-analytics.php:388
70
- msgid "Learn More."
71
- msgstr ""
72
-
73
- #: classes/class-cartflows-ca-loader.php:135
74
- #. translators: %s: html tags
75
- msgid ""
76
- "The %1$sWooCommerce Cart Abandonment Recovery%2$s plugin requires "
77
- "%1$sWooCommerce%2$s plugin installed & activated."
78
- msgstr ""
79
-
80
- #: classes/class-cartflows-ca-loader.php:144
81
- msgid "Activate WooCommerce"
82
- msgstr ""
83
-
84
- #: classes/class-cartflows-ca-loader.php:152
85
- msgid "Install WooCommerce"
86
- msgstr ""
87
-
88
- #: classes/class-cartflows-ca-settings.php:54
89
- msgid "Cart Abandonment Settings"
90
- msgstr ""
91
-
92
- #: classes/class-cartflows-ca-settings.php:61
93
- msgid "Enable Tracking"
94
- msgstr ""
95
-
96
- #: classes/class-cartflows-ca-settings.php:65
97
- msgid ""
98
- "Start capturing abandoned carts. <br/><br/> <span "
99
- "class=\"description\"><strong>Note:</strong> Cart will be considered "
100
- "abandoned if order is not completed in <strong>15 minutes</strong>.</span>"
101
- msgstr ""
102
-
103
- #: classes/class-cartflows-ca-settings.php:75
104
- msgid "Disable Tracking For"
105
- msgstr ""
106
-
107
- #: classes/class-cartflows-ca-settings.php:79
108
- msgid ""
109
- " It will ignore selected users from abandonment process when they logged "
110
- "in, and hence they can not receive mail for cart abandoned by themselves."
111
- msgstr ""
112
-
113
- #: classes/class-cartflows-ca-settings.php:89
114
- msgid "Notify recovery to admin"
115
- msgstr ""
116
-
117
- #: classes/class-cartflows-ca-settings.php:93
118
- msgid "This option will send an email to admin on new order recovery."
119
- msgstr ""
120
-
121
- #: classes/class-cartflows-ca-settings.php:106
122
- msgid "Coupons Settings"
123
- msgstr ""
124
-
125
- #: classes/class-cartflows-ca-settings.php:113
126
- msgid "Delete Coupons Automatically"
127
- msgstr ""
128
-
129
- #: classes/class-cartflows-ca-settings.php:117
130
- msgid ""
131
- "Delete coupons automatically on weekly basis.<br><span "
132
- "class=\"description\"><br/><strong>Note:</strong> This option will set a "
133
- "weekly cron to delete all <strong>expired</strong> and "
134
- "<strong>used</strong> coupons automatically in the background.</p>"
135
- msgstr ""
136
-
137
- #: classes/class-cartflows-ca-settings.php:127
138
- msgid "Delete Coupons Manually"
139
- msgstr ""
140
-
141
- #: classes/class-cartflows-ca-settings.php:131
142
- msgid ""
143
- "<br><strong>Note:</strong> This will delete all <strong>expired</strong> "
144
- "and <strong>used</strong> coupons that were created by Woo Cart Abandonment "
145
- "Recovery.</p>"
146
- msgstr ""
147
-
148
- #: classes/class-cartflows-ca-settings.php:143
149
- msgid "Email Settings"
150
- msgstr ""
151
-
152
- #: classes/class-cartflows-ca-settings.php:150
153
- msgid "\"From\" Name"
154
- msgstr ""
155
-
156
- #: classes/class-cartflows-ca-settings.php:154
157
- msgid "Name will appear in email sent."
158
- msgstr ""
159
-
160
- #: classes/class-cartflows-ca-settings.php:159
161
- msgid "\"From\" Address"
162
- msgstr ""
163
-
164
- #: classes/class-cartflows-ca-settings.php:163
165
- msgid "Email which send from."
166
- msgstr ""
167
-
168
- #: classes/class-cartflows-ca-settings.php:168
169
- msgid "\"Reply To\" Address"
170
- msgstr ""
171
-
172
- #: classes/class-cartflows-ca-settings.php:172
173
- msgid "When a user clicks reply, which email address should that reply be sent to?"
174
- msgstr ""
175
-
176
- #: classes/class-cartflows-ca-settings.php:195
177
- msgid "Enable Webhook"
178
- msgstr ""
179
-
180
- #: classes/class-cartflows-ca-settings.php:199
181
- msgid ""
182
- "Allows you to trigger webhook automatically upon cart abandonment and "
183
- "recovery."
184
- msgstr ""
185
-
186
- #: classes/class-cartflows-ca-settings.php:204
187
- msgid "Webhook URL"
188
- msgstr ""
189
-
190
- #: classes/class-cartflows-ca-settings.php:223
191
- msgid "Coupon Code Settings"
192
- msgstr ""
193
-
194
- #: classes/class-cartflows-ca-settings.php:230
195
- msgid "Create Coupon Code"
196
- msgstr ""
197
-
198
- #: classes/class-cartflows-ca-settings.php:234
199
- msgid ""
200
- "Auto-create the special coupon for the abandoned cart to send over the "
201
- "emails."
202
- msgstr ""
203
-
204
- #: classes/class-cartflows-ca-settings.php:239
205
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:533
206
- msgid "Discount Type"
207
- msgstr ""
208
-
209
- #: classes/class-cartflows-ca-settings.php:248
210
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:565
211
- msgid "Coupon Amount"
212
- msgstr ""
213
-
214
- #: classes/class-cartflows-ca-settings.php:257
215
- msgid "Coupon Expires After"
216
- msgstr ""
217
-
218
- #: classes/class-cartflows-ca-settings.php:261
219
- msgid ""
220
- "<br/><br/> <span class=\"description\"><strong>Note: </strong>. Enter zero "
221
- "(0) to restrict coupon from expiring.</span>"
222
- msgstr ""
223
-
224
- #: classes/class-cartflows-ca-settings.php:292
225
- msgid "Webhook Settings"
226
- msgstr ""
227
-
228
- #: classes/class-cartflows-ca-settings.php:301
229
- msgid "GDPR Settings"
230
- msgstr ""
231
-
232
- #: classes/class-cartflows-ca-settings.php:308
233
- msgid "Enable GDPR Integration"
234
- msgstr ""
235
-
236
- #: classes/class-cartflows-ca-settings.php:312
237
- msgid ""
238
- "Ask confirmation from the user before tracking data. <br/><br/> <span "
239
- "class=\"description\"><strong>Note:</strong> By checking this, it will show "
240
- "up confirmation text below the email id on checkout page.</span>"
241
- msgstr ""
242
-
243
- #: classes/class-cartflows-ca-settings.php:317
244
- msgid "GDPR Message"
245
- msgstr ""
246
-
247
- #: classes/class-cartflows-ca-settings.php:436
248
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:603
249
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:699
250
- msgid "Hour(s)"
251
- msgstr ""
252
-
253
- #: classes/class-cartflows-ca-settings.php:437
254
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:604
255
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:700
256
- msgid "Day(s)"
257
- msgstr ""
258
-
259
- #: classes/class-cartflows-ca-settings.php:505
260
- msgid "Coupon code should be numeric and has to be greater than or equals to 1."
261
- msgstr ""
262
-
263
- #: classes/class-cartflows-ca-settings.php:600
264
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:82
265
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:134
266
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:84
267
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:118
268
- msgid "Delete"
269
- msgstr ""
270
-
271
- #: classes/class-cartflows-ca-settings.php:686
272
- msgid "Invalid email \"From\" address field"
273
- msgstr ""
274
-
275
- #: classes/class-cartflows-ca-settings.php:704
276
- msgid "Invalid email \"Reply\" address field"
277
- msgstr ""
278
-
279
- #: lib/notices/class-astra-notices.php:120
280
- msgid "WordPress Nonce not validated."
281
- msgstr ""
282
-
283
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:81
284
- msgid "View"
285
- msgstr ""
286
-
287
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:86
288
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:138
289
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1778
290
- msgid "Unsubscribe"
291
- msgstr ""
292
-
293
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:234
294
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1919
295
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1970
296
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:173
297
- msgid "Name"
298
- msgstr ""
299
-
300
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:235
301
- msgid "Email"
302
- msgstr ""
303
-
304
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:236
305
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1992
306
- msgid "Cart Total"
307
- msgstr ""
308
-
309
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:237
310
- msgid "Order Status"
311
- msgstr ""
312
-
313
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:238
314
- msgid "Time"
315
- msgstr ""
316
-
317
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:205
318
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1021
319
- msgid "This order was abandoned & subsequently recovered."
320
- msgstr ""
321
-
322
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:230
323
- msgid "Mail has been sent successfully!"
324
- msgstr ""
325
-
326
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:232
327
- msgid "Mail sending failed!"
328
- msgstr ""
329
-
330
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:271
331
- msgid "Every Fifteen Minutes"
332
- msgstr ""
333
-
334
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:343
335
- msgid "You have successfully unsubscribed from our email list."
336
- msgstr ""
337
-
338
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:343
339
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:164
340
- msgid "Unsubscribed"
341
- msgstr ""
342
-
343
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:494
344
- msgid ""
345
- "This checkout page is generated by WooCommerce Cart Abandonment Recovery "
346
- "plugin from test mail."
347
- msgstr ""
348
-
349
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:537
350
- msgid "You won't receive further emails from us, thank you!"
351
- msgstr ""
352
-
353
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1179
354
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1180
355
- msgid "Cart Abandonment"
356
- msgstr ""
357
-
358
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1205
359
- msgid "Items deleted: %d"
360
- msgstr ""
361
-
362
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1222
363
- msgid "User(s) unsubscribed successfully!"
364
- msgstr ""
365
-
366
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1283
367
- msgid ""
368
- "Do you really want to delete the used and expired coupons created by Cart "
369
- "Abandonment Plugin?"
370
- msgstr ""
371
-
372
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1284
373
- msgid "Do you really want to export orders?"
374
- msgstr ""
375
-
376
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1288
377
- msgid "No such order is found."
378
- msgstr ""
379
-
380
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1307
381
- msgid "View Report"
382
- msgstr ""
383
-
384
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1445
385
- msgid "Report"
386
- msgstr ""
387
-
388
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1461
389
- msgid "Follow-Up Emails"
390
- msgstr ""
391
-
392
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1477
393
- msgid "Settings"
394
- msgstr ""
395
-
396
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1739
397
- msgid "there"
398
- msgstr ""
399
-
400
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1911
401
- msgid "Cart Total ( Cart Total + Shipping + Tax )"
402
- msgstr ""
403
-
404
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1918
405
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1969
406
- msgid "Item"
407
- msgstr ""
408
-
409
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1920
410
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1971
411
- msgid "Quantity"
412
- msgstr ""
413
-
414
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1921
415
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1972
416
- msgid "Price"
417
- msgstr ""
418
-
419
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1922
420
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1973
421
- msgid "Line Subtotal"
422
- msgstr ""
423
-
424
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1979
425
- msgid "Discount"
426
- msgstr ""
427
-
428
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1983
429
- msgid "Other"
430
- msgstr ""
431
-
432
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1988
433
- msgid "Shipping"
434
- msgstr ""
435
-
436
- #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:2140
437
- #. translators: %1$s: Coupons Deleted, %2$s: Deleted coupons count'.
438
- msgid "%1$s: %2$d"
439
- msgstr ""
440
-
441
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:72
442
- msgid "Edit"
443
- msgstr ""
444
-
445
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:96
446
- msgid "Clone"
447
- msgstr ""
448
-
449
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:183
450
- msgid "Template Name"
451
- msgstr ""
452
-
453
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:184
454
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:83
455
- msgid "Email Subject"
456
- msgstr ""
457
-
458
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:185
459
- msgid "Trigger After"
460
- msgstr ""
461
-
462
- #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:186
463
- msgid "Activate Template"
464
- msgstr ""
465
-
466
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:128
467
- msgid "Admin Firstname"
468
- msgstr ""
469
-
470
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:129
471
- msgid "Admin Company"
472
- msgstr ""
473
-
474
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:130
475
- msgid "Abandoned Product Details Table"
476
- msgstr ""
477
-
478
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:131
479
- msgid "Abandoned Product Names"
480
- msgstr ""
481
-
482
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:132
483
- msgid "Cart Checkout URL"
484
- msgstr ""
485
-
486
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:133
487
- msgid "Coupon Code"
488
- msgstr ""
489
-
490
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:134
491
- msgid "Customer First Name"
492
- msgstr ""
493
-
494
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:135
495
- msgid "Customer Last Name"
496
- msgstr ""
497
-
498
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:136
499
- msgid "Customer Full Name"
500
- msgstr ""
501
-
502
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:137
503
- msgid "Cart Abandonment Date"
504
- msgstr ""
505
-
506
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:138
507
- msgid "Site URL"
508
- msgstr ""
509
-
510
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:139
511
- msgid "Unsubscribe Link"
512
- msgstr ""
513
-
514
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:159
515
- msgid "Something went wrong"
516
- msgstr ""
517
-
518
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:166
519
- msgid "Activated"
520
- msgstr ""
521
-
522
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:169
523
- msgid "Deactivated"
524
- msgstr ""
525
-
526
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:228
527
- msgid "The Email Template has been successfully added."
528
- msgstr ""
529
-
530
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:238
531
- msgid "The Email Template has been cloned successfully."
532
- msgstr ""
533
-
534
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:248
535
- msgid "The Email Template has been successfully deleted."
536
- msgstr ""
537
-
538
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:257
539
- msgid "The Email Template has been successfully updated."
540
- msgstr ""
541
-
542
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:267
543
- msgid "Default Email Templates has been restored successfully."
544
- msgstr ""
545
-
546
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:434
547
- msgid "Activate Template now?"
548
- msgstr ""
549
-
550
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:454
551
- msgid "Template Name:"
552
- msgstr ""
553
-
554
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:469
555
- msgid "Email Subject:"
556
- msgstr ""
557
-
558
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:484
559
- msgid "Email Body:"
560
- msgstr ""
561
-
562
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:513
563
- msgid "Create Coupon"
564
- msgstr ""
565
-
566
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:526
567
- msgid "Allows you to send new coupon only for this template."
568
- msgstr ""
569
-
570
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:583
571
- msgid "Coupon expiry date"
572
- msgstr ""
573
-
574
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:613
575
- msgid "Enter zero (0) to restrict coupon from expiring"
576
- msgstr ""
577
-
578
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:619
579
- msgid "Free Shipping"
580
- msgstr ""
581
-
582
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:632
583
- msgid ""
584
- "Allows you to grant free shipping. A free shipping method must be enabled "
585
- "in your shipping zone and be set to require \"a valid free shipping "
586
- "coupon\". "
587
- msgstr ""
588
-
589
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:639
590
- msgid "Individual use only"
591
- msgstr ""
592
-
593
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:653
594
- msgid ""
595
- "Check this box if the coupon cannot be used in conjunction with other "
596
- "coupons."
597
- msgstr ""
598
-
599
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:660
600
- msgid "Auto Apply Coupon"
601
- msgstr ""
602
-
603
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:674
604
- msgid " Automatically add the coupon to the cart at the checkout."
605
- msgstr ""
606
-
607
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:680
608
- msgid "Send This Email"
609
- msgstr ""
610
-
611
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:698
612
- msgid "Minute(s)"
613
- msgstr ""
614
-
615
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:713
616
- msgid "after cart is abandoned."
617
- msgstr ""
618
-
619
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:723
620
- msgid "Send Test Email To:"
621
- msgstr ""
622
-
623
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:727
624
- msgid "Send a test email"
625
- msgstr ""
626
-
627
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:740
628
- msgid "Save Changes"
629
- msgstr ""
630
-
631
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:742
632
- msgid "Update Changes"
633
- msgstr ""
634
-
635
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:1048
636
- msgid "Create New Template"
637
- msgstr ""
638
-
639
- #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:1051
640
- msgid " Restore Default Templates"
641
- msgstr ""
642
-
643
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:27
644
- msgid "Back to Reports"
645
- msgstr ""
646
-
647
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:38
648
- msgid "Email Details:"
649
- msgstr ""
650
-
651
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:48
652
- msgid ""
653
- "All new activated emails will be reschedule for this abandoned order.New "
654
- "emails will\r\n"
655
- "\t\t\t\t\t\t\t\t\t\t\tbe sent to user according to schedule time."
656
- msgstr ""
657
-
658
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:56
659
- msgid "Are your sure?"
660
- msgstr ""
661
-
662
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:60
663
- msgid "Reschedule"
664
- msgstr ""
665
-
666
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:64
667
- msgid "Close"
668
- msgstr ""
669
-
670
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:69
671
- msgid "Do you really want to reschedule emails?"
672
- msgstr ""
673
-
674
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:69
675
- msgid "Reschedule Emails"
676
- msgstr ""
677
-
678
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:75
679
- msgid " No Email Scheduled."
680
- msgstr ""
681
-
682
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:82
683
- msgid "Scheduled Template"
684
- msgstr ""
685
-
686
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:84
687
- msgid "Email Coupon"
688
- msgstr ""
689
-
690
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:85
691
- msgid "Email Sent"
692
- msgstr ""
693
-
694
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:86
695
- msgid "Scheduled At"
696
- msgstr ""
697
-
698
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:115
699
- msgid "The email has been unsubscribed and won't be sent further."
700
- msgstr ""
701
-
702
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:118
703
- msgid "Email is in the queue and will be sent at the scheduled time."
704
- msgstr ""
705
-
706
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:123
707
- msgid "The email has been sent."
708
- msgstr ""
709
-
710
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:127
711
- msgid ""
712
- "The email has been unscheduled due to the complete order and won't be sent "
713
- "further."
714
- msgstr ""
715
-
716
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:160
717
- msgid "User Address Details:"
718
- msgstr ""
719
-
720
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:172
721
- msgid "Billing Address"
722
- msgstr ""
723
-
724
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:176
725
- msgid "Email address"
726
- msgstr ""
727
-
728
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:181
729
- msgid "Phone"
730
- msgstr ""
731
-
732
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:186
733
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:206
734
- msgid "Address 1:"
735
- msgstr ""
736
-
737
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:189
738
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:209
739
- msgid "Address 2:"
740
- msgstr ""
741
-
742
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:192
743
- msgid "Country, City:"
744
- msgstr ""
745
-
746
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:195
747
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:215
748
- msgid "State:"
749
- msgstr ""
750
-
751
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:199
752
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:221
753
- msgid "Postcode:"
754
- msgstr ""
755
-
756
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:204
757
- msgid "Shipping Address"
758
- msgstr ""
759
-
760
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:212
761
- msgid "City:"
762
- msgstr ""
763
-
764
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:218
765
- msgid "Country:"
766
- msgstr ""
767
-
768
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:229
769
- msgid "Checkout Link"
770
- msgstr ""
771
-
772
- #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:244
773
- msgid "User Order Details:"
774
- msgstr ""
775
-
776
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:14
777
- msgid "Today"
778
- msgstr ""
779
-
780
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:18
781
- msgid "Yesterday"
782
- msgstr ""
783
-
784
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:22
785
- msgid "Last Week"
786
- msgstr ""
787
-
788
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:26
789
- msgid "Last Month"
790
- msgstr ""
791
-
792
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:35
793
- msgid "Custom Filter"
794
- msgstr ""
795
-
796
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:46
797
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:108
798
- msgid "Recoverable Orders"
799
- msgstr ""
800
-
801
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:50
802
- msgid "Total Recoverable Orders."
803
- msgstr ""
804
-
805
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:55
806
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:111
807
- msgid "Recovered Orders"
808
- msgstr ""
809
-
810
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:57
811
- msgid "Total Recovered Orders."
812
- msgstr ""
813
-
814
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:62
815
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:114
816
- msgid "Lost Orders"
817
- msgstr ""
818
-
819
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:65
820
- msgid "Total Lost Orders."
821
- msgstr ""
822
-
823
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:74
824
- msgid "Recoverable Revenue"
825
- msgstr ""
826
-
827
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:79
828
- msgid "Total Recoverable Revenue."
829
- msgstr ""
830
-
831
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:84
832
- msgid "Recovered Revenue"
833
- msgstr ""
834
-
835
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:90
836
- msgid "Total Recovered Revenue."
837
- msgstr ""
838
-
839
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:95
840
- msgid "Recovery Rate"
841
- msgstr ""
842
-
843
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:97
844
- msgid "Total Percentage Of Recovered Orders After Abandonment."
845
- msgstr ""
846
-
847
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:124
848
- msgid "Search by email"
849
- msgstr ""
850
-
851
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:125
852
- msgid "Search Orders"
853
- msgstr ""
854
-
855
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:152
856
- msgid "No Orders Found."
857
- msgstr ""
858
-
859
- #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-tabs.php:10
860
- msgid "WooCommerce Cart Abandonment Recovery "
861
- msgstr ""
862
-
863
- #. Plugin Name of the plugin/theme
864
- msgid "WooCommerce Cart Abandonment Recovery"
865
- msgstr ""
866
-
867
- #. Author URI of the plugin/theme
868
- msgid "https://cartflows.com/"
869
- msgstr ""
870
-
871
- #. Description of the plugin/theme
872
- msgid ""
873
- "Recover your lost revenue. Capture email address of users on the checkout "
874
- "page and send follow up emails if they don't complete the purchase."
875
- msgstr ""
876
-
877
- #. Author of the plugin/theme
878
- msgid "CartFlows Inc"
 
 
 
 
 
 
879
  msgstr ""
1
+ # Copyright (C) 2020 CartFlows Inc
2
+ # This file is distributed under the same license as the WooCommerce Cart Abandonment Recovery package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: WooCommerce Cart Abandonment Recovery 1.2.8\n"
6
+ "Report-Msgid-Bugs-To: "
7
+ "https://wordpress.org/support/plugin/woo-cart-abandonment-recovery\n"
8
+ "POT-Creation-Date: 2020-08-14 06:46:47+00:00\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=utf-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
13
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: en\n"
16
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
+ "X-Poedit-Country: United States\n"
18
+ "X-Poedit-SourceCharset: UTF-8\n"
19
+ "X-Poedit-KeywordsList: "
20
+ "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
21
+ "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
22
+ "X-Poedit-Basepath: ../\n"
23
+ "X-Poedit-SearchPath-0: .\n"
24
+ "X-Poedit-Bookmarks: \n"
25
+ "X-Textdomain-Support: yes\n"
26
+ "X-Generator: grunt-wp-i18n 1.0.3\n"
27
+
28
+ #: admin/bsf-analytics/class-bsf-analytics.php:211
29
+ #. translators: %s product name
30
+ msgid ""
31
+ "Want to help make <strong>%1s</strong> even more awesome? Allow us to "
32
+ "collect non-sensitive diagnostic data and usage information. "
33
+ msgstr ""
34
+
35
+ #: admin/bsf-analytics/class-bsf-analytics.php:214
36
+ msgid "This will be applicable for all sites from the network."
37
+ msgstr ""
38
+
39
+ #: admin/bsf-analytics/class-bsf-analytics.php:238
40
+ #. translators: %s usage doc link
41
+ msgid " Know More."
42
+ msgstr ""
43
+
44
+ #: admin/bsf-analytics/class-bsf-analytics.php:246
45
+ msgid "Yes! Allow it"
46
+ msgstr ""
47
+
48
+ #: admin/bsf-analytics/class-bsf-analytics.php:255
49
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:537
50
+ msgid "No Thanks"
51
+ msgstr ""
52
+
53
+ #: admin/bsf-analytics/class-bsf-analytics.php:359
54
+ msgid "Usage Tracking"
55
+ msgstr ""
56
+
57
+ #: admin/bsf-analytics/class-bsf-analytics.php:403
58
+ #. translators: %s Product title
59
+ msgid "Allow %s products to track non-sensitive usage tracking data."
60
+ msgstr ""
61
+
62
+ #: admin/bsf-analytics/class-bsf-analytics.php:406
63
+ msgid " This will be applicable for all sites from the network."
64
+ msgstr ""
65
+
66
+ #: admin/bsf-analytics/class-bsf-analytics.php:411
67
+ msgid "Learn More."
68
+ msgstr ""
69
+
70
+ #: classes/class-cartflows-ca-loader.php:138
71
+ #. translators: %s: html tags
72
+ msgid ""
73
+ "The %1$sWooCommerce Cart Abandonment Recovery%2$s plugin requires "
74
+ "%1$sWooCommerce%2$s plugin installed & activated."
75
+ msgstr ""
76
+
77
+ #: classes/class-cartflows-ca-loader.php:147
78
+ msgid "Activate WooCommerce"
79
+ msgstr ""
80
+
81
+ #: classes/class-cartflows-ca-loader.php:155
82
+ msgid "Install WooCommerce"
83
+ msgstr ""
84
+
85
+ #: classes/class-cartflows-ca-settings.php:54
86
+ msgid "Cart Abandonment Settings"
87
+ msgstr ""
88
+
89
+ #: classes/class-cartflows-ca-settings.php:61
90
+ msgid "Enable Tracking"
91
+ msgstr ""
92
+
93
+ #: classes/class-cartflows-ca-settings.php:65
94
+ msgid ""
95
+ "Start capturing abandoned carts. <br/><br/> <span "
96
+ "class=\"description\"><strong>Note:</strong> Cart will be considered "
97
+ "abandoned if order is not completed in <strong>15 minutes</strong>.</span>"
98
+ msgstr ""
99
+
100
+ #: classes/class-cartflows-ca-settings.php:75
101
+ msgid "Disable Tracking For"
102
+ msgstr ""
103
+
104
+ #: classes/class-cartflows-ca-settings.php:79
105
+ msgid ""
106
+ " It will ignore selected users from abandonment process when they logged "
107
+ "in, and hence they can not receive mail for cart abandoned by themselves."
108
+ msgstr ""
109
+
110
+ #: classes/class-cartflows-ca-settings.php:89
111
+ msgid "Exclude email sending For"
112
+ msgstr ""
113
+
114
+ #: classes/class-cartflows-ca-settings.php:93
115
+ msgid ""
116
+ " It will not send future recovery emails to selected order status and will "
117
+ "mark as recovered."
118
+ msgstr ""
119
+
120
+ #: classes/class-cartflows-ca-settings.php:103
121
+ msgid "Notify recovery to admin"
122
+ msgstr ""
123
+
124
+ #: classes/class-cartflows-ca-settings.php:107
125
+ msgid "This option will send an email to admin on new order recovery."
126
+ msgstr ""
127
+
128
+ #: classes/class-cartflows-ca-settings.php:120
129
+ msgid "Coupons Settings"
130
+ msgstr ""
131
+
132
+ #: classes/class-cartflows-ca-settings.php:127
133
+ msgid "Delete Coupons Automatically"
134
+ msgstr ""
135
+
136
+ #: classes/class-cartflows-ca-settings.php:131
137
+ msgid ""
138
+ "Delete coupons automatically on weekly basis.<br><span "
139
+ "class=\"description\"><br/><strong>Note:</strong> This option will set a "
140
+ "weekly cron to delete all <strong>expired</strong> and "
141
+ "<strong>used</strong> coupons automatically in the background.</p>"
142
+ msgstr ""
143
+
144
+ #: classes/class-cartflows-ca-settings.php:141
145
+ msgid "Delete Coupons Manually"
146
+ msgstr ""
147
+
148
+ #: classes/class-cartflows-ca-settings.php:145
149
+ msgid ""
150
+ "<br><strong>Note:</strong> This will delete all <strong>expired</strong> "
151
+ "and <strong>used</strong> coupons that were created by Woo Cart Abandonment "
152
+ "Recovery.</p>"
153
+ msgstr ""
154
+
155
+ #: classes/class-cartflows-ca-settings.php:157
156
+ msgid "Email Settings"
157
+ msgstr ""
158
+
159
+ #: classes/class-cartflows-ca-settings.php:164
160
+ msgid "\"From\" Name"
161
+ msgstr ""
162
+
163
+ #: classes/class-cartflows-ca-settings.php:168
164
+ msgid "Name will appear in email sent."
165
+ msgstr ""
166
+
167
+ #: classes/class-cartflows-ca-settings.php:173
168
+ msgid "\"From\" Address"
169
+ msgstr ""
170
+
171
+ #: classes/class-cartflows-ca-settings.php:177
172
+ msgid "Email which send from."
173
+ msgstr ""
174
+
175
+ #: classes/class-cartflows-ca-settings.php:182
176
+ msgid "\"Reply To\" Address"
177
+ msgstr ""
178
+
179
+ #: classes/class-cartflows-ca-settings.php:186
180
+ msgid "When a user clicks reply, which email address should that reply be sent to?"
181
+ msgstr ""
182
+
183
+ #: classes/class-cartflows-ca-settings.php:209
184
+ msgid "Enable Webhook"
185
+ msgstr ""
186
+
187
+ #: classes/class-cartflows-ca-settings.php:213
188
+ msgid ""
189
+ "Allows you to trigger webhook automatically upon cart abandonment and "
190
+ "recovery."
191
+ msgstr ""
192
+
193
+ #: classes/class-cartflows-ca-settings.php:218
194
+ msgid "Webhook URL"
195
+ msgstr ""
196
+
197
+ #: classes/class-cartflows-ca-settings.php:237
198
+ msgid "Coupon Code Settings"
199
+ msgstr ""
200
+
201
+ #: classes/class-cartflows-ca-settings.php:244
202
+ msgid "Create Coupon Code"
203
+ msgstr ""
204
+
205
+ #: classes/class-cartflows-ca-settings.php:248
206
+ msgid ""
207
+ "Auto-create the special coupon for the abandoned cart to send over the "
208
+ "emails."
209
+ msgstr ""
210
+
211
+ #: classes/class-cartflows-ca-settings.php:253
212
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:533
213
+ msgid "Discount Type"
214
+ msgstr ""
215
+
216
+ #: classes/class-cartflows-ca-settings.php:262
217
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:565
218
+ msgid "Coupon Amount"
219
+ msgstr ""
220
+
221
+ #: classes/class-cartflows-ca-settings.php:271
222
+ msgid "Coupon Expires After"
223
+ msgstr ""
224
+
225
+ #: classes/class-cartflows-ca-settings.php:275
226
+ msgid ""
227
+ "<br/><br/> <span class=\"description\"><strong>Note: </strong>. Enter zero "
228
+ "(0) to restrict coupon from expiring.</span>"
229
+ msgstr ""
230
+
231
+ #: classes/class-cartflows-ca-settings.php:306
232
+ msgid "Webhook Settings"
233
+ msgstr ""
234
+
235
+ #: classes/class-cartflows-ca-settings.php:315
236
+ msgid "GDPR Settings"
237
+ msgstr ""
238
+
239
+ #: classes/class-cartflows-ca-settings.php:322
240
+ msgid "Enable GDPR Integration"
241
+ msgstr ""
242
+
243
+ #: classes/class-cartflows-ca-settings.php:326
244
+ msgid ""
245
+ "Ask confirmation from the user before tracking data. <br/><br/> <span "
246
+ "class=\"description\"><strong>Note:</strong> By checking this, it will show "
247
+ "up confirmation text below the email id on checkout page.</span>"
248
+ msgstr ""
249
+
250
+ #: classes/class-cartflows-ca-settings.php:331
251
+ msgid "GDPR Message"
252
+ msgstr ""
253
+
254
+ #: classes/class-cartflows-ca-settings.php:450
255
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:603
256
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:699
257
+ msgid "Hour(s)"
258
+ msgstr ""
259
+
260
+ #: classes/class-cartflows-ca-settings.php:451
261
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:604
262
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:700
263
+ msgid "Day(s)"
264
+ msgstr ""
265
+
266
+ #: classes/class-cartflows-ca-settings.php:519
267
+ msgid "Coupon code should be numeric and has to be greater than or equals to 1."
268
+ msgstr ""
269
+
270
+ #: classes/class-cartflows-ca-settings.php:651
271
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:82
272
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:134
273
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:84
274
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:118
275
+ msgid "Delete"
276
+ msgstr ""
277
+
278
+ #: classes/class-cartflows-ca-settings.php:737
279
+ msgid "Invalid email \"From\" address field"
280
+ msgstr ""
281
+
282
+ #: classes/class-cartflows-ca-settings.php:755
283
+ msgid "Invalid email \"Reply\" address field"
284
+ msgstr ""
285
+
286
+ #: lib/notices/class-astra-notices.php:120
287
+ msgid "WordPress Nonce not validated."
288
+ msgstr ""
289
+
290
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:81
291
+ msgid "View"
292
+ msgstr ""
293
+
294
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:86
295
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:138
296
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1791
297
+ msgid "Unsubscribe"
298
+ msgstr ""
299
+
300
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:234
301
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1932
302
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1983
303
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:171
304
+ msgid "Name"
305
+ msgstr ""
306
+
307
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:235
308
+ msgid "Email"
309
+ msgstr ""
310
+
311
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:236
312
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:2005
313
+ msgid "Cart Total"
314
+ msgstr ""
315
+
316
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:237
317
+ msgid "Order Status"
318
+ msgstr ""
319
+
320
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php:238
321
+ msgid "Time"
322
+ msgstr ""
323
+
324
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:206
325
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1034
326
+ msgid "This order was abandoned & subsequently recovered."
327
+ msgstr ""
328
+
329
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:231
330
+ msgid "Mail has been sent successfully!"
331
+ msgstr ""
332
+
333
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:233
334
+ msgid "Mail sending failed!"
335
+ msgstr ""
336
+
337
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:272
338
+ msgid "Every Fifteen Minutes"
339
+ msgstr ""
340
+
341
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:344
342
+ msgid "You have successfully unsubscribed from our email list."
343
+ msgstr ""
344
+
345
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:344
346
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:162
347
+ msgid "Unsubscribed"
348
+ msgstr ""
349
+
350
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:495
351
+ msgid ""
352
+ "This checkout page is generated by WooCommerce Cart Abandonment Recovery "
353
+ "plugin from test mail."
354
+ msgstr ""
355
+
356
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:538
357
+ msgid "You won't receive further emails from us, thank you!"
358
+ msgstr ""
359
+
360
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1192
361
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1193
362
+ msgid "Cart Abandonment"
363
+ msgstr ""
364
+
365
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1218
366
+ msgid "Items deleted: %d"
367
+ msgstr ""
368
+
369
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1235
370
+ msgid "User(s) unsubscribed successfully!"
371
+ msgstr ""
372
+
373
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1296
374
+ msgid ""
375
+ "Do you really want to delete the used and expired coupons created by Cart "
376
+ "Abandonment Plugin?"
377
+ msgstr ""
378
+
379
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1297
380
+ msgid "Do you really want to export orders?"
381
+ msgstr ""
382
+
383
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1301
384
+ msgid "No such order is found."
385
+ msgstr ""
386
+
387
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1320
388
+ msgid "View Report"
389
+ msgstr ""
390
+
391
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1458
392
+ msgid "Report"
393
+ msgstr ""
394
+
395
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1474
396
+ msgid "Follow-Up Emails"
397
+ msgstr ""
398
+
399
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1490
400
+ msgid "Settings"
401
+ msgstr ""
402
+
403
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1752
404
+ msgid "there"
405
+ msgstr ""
406
+
407
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1924
408
+ msgid "Cart Total ( Cart Total + Shipping + Tax )"
409
+ msgstr ""
410
+
411
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1931
412
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1982
413
+ msgid "Item"
414
+ msgstr ""
415
+
416
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1933
417
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1984
418
+ msgid "Quantity"
419
+ msgstr ""
420
+
421
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1934
422
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1985
423
+ msgid "Price"
424
+ msgstr ""
425
+
426
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1935
427
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1986
428
+ msgid "Line Subtotal"
429
+ msgstr ""
430
+
431
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1992
432
+ msgid "Discount"
433
+ msgstr ""
434
+
435
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:1996
436
+ msgid "Other"
437
+ msgstr ""
438
+
439
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:2001
440
+ msgid "Shipping"
441
+ msgstr ""
442
+
443
+ #: modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php:2153
444
+ #. translators: %1$s: Coupons Deleted, %2$s: Deleted coupons count'.
445
+ msgid "%1$s: %2$d"
446
+ msgstr ""
447
+
448
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:72
449
+ msgid "Edit"
450
+ msgstr ""
451
+
452
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:96
453
+ msgid "Clone"
454
+ msgstr ""
455
+
456
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:183
457
+ msgid "Template Name"
458
+ msgstr ""
459
+
460
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:184
461
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:81
462
+ msgid "Email Subject"
463
+ msgstr ""
464
+
465
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:185
466
+ msgid "Trigger After"
467
+ msgstr ""
468
+
469
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates-table.php:186
470
+ msgid "Activate Template"
471
+ msgstr ""
472
+
473
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:128
474
+ msgid "Admin Firstname"
475
+ msgstr ""
476
+
477
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:129
478
+ msgid "Admin Company"
479
+ msgstr ""
480
+
481
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:130
482
+ msgid "Abandoned Product Details Table"
483
+ msgstr ""
484
+
485
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:131
486
+ msgid "Abandoned Product Names"
487
+ msgstr ""
488
+
489
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:132
490
+ msgid "Cart Checkout URL"
491
+ msgstr ""
492
+
493
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:133
494
+ msgid "Coupon Code"
495
+ msgstr ""
496
+
497
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:134
498
+ msgid "Customer First Name"
499
+ msgstr ""
500
+
501
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:135
502
+ msgid "Customer Last Name"
503
+ msgstr ""
504
+
505
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:136
506
+ msgid "Customer Full Name"
507
+ msgstr ""
508
+
509
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:137
510
+ msgid "Cart Abandonment Date"
511
+ msgstr ""
512
+
513
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:138
514
+ msgid "Site URL"
515
+ msgstr ""
516
+
517
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:139
518
+ msgid "Unsubscribe Link"
519
+ msgstr ""
520
+
521
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:159
522
+ msgid "Something went wrong"
523
+ msgstr ""
524
+
525
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:166
526
+ msgid "Activated"
527
+ msgstr ""
528
+
529
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:169
530
+ msgid "Deactivated"
531
+ msgstr ""
532
+
533
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:228
534
+ msgid "The Email Template has been successfully added."
535
+ msgstr ""
536
+
537
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:238
538
+ msgid "The Email Template has been cloned successfully."
539
+ msgstr ""
540
+
541
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:248
542
+ msgid "The Email Template has been successfully deleted."
543
+ msgstr ""
544
+
545
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:257
546
+ msgid "The Email Template has been successfully updated."
547
+ msgstr ""
548
+
549
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:267
550
+ msgid "Default Email Templates has been restored successfully."
551
+ msgstr ""
552
+
553
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:434
554
+ msgid "Activate Template now?"
555
+ msgstr ""
556
+
557
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:454
558
+ msgid "Template Name:"
559
+ msgstr ""
560
+
561
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:469
562
+ msgid "Email Subject:"
563
+ msgstr ""
564
+
565
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:484
566
+ msgid "Email Body:"
567
+ msgstr ""
568
+
569
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:513
570
+ msgid "Create Coupon"
571
+ msgstr ""
572
+
573
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:526
574
+ msgid "Allows you to send new coupon only for this template."
575
+ msgstr ""
576
+
577
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:583
578
+ msgid "Coupon expiry date"
579
+ msgstr ""
580
+
581
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:613
582
+ msgid "Enter zero (0) to restrict coupon from expiring"
583
+ msgstr ""
584
+
585
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:619
586
+ msgid "Free Shipping"
587
+ msgstr ""
588
+
589
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:632
590
+ msgid ""
591
+ "Allows you to grant free shipping. A free shipping method must be enabled "
592
+ "in your shipping zone and be set to require \"a valid free shipping "
593
+ "coupon\". "
594
+ msgstr ""
595
+
596
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:639
597
+ msgid "Individual use only"
598
+ msgstr ""
599
+
600
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:653
601
+ msgid ""
602
+ "Check this box if the coupon cannot be used in conjunction with other "
603
+ "coupons."
604
+ msgstr ""
605
+
606
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:660
607
+ msgid "Auto Apply Coupon"
608
+ msgstr ""
609
+
610
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:674
611
+ msgid " Automatically add the coupon to the cart at the checkout."
612
+ msgstr ""
613
+
614
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:680
615
+ msgid "Send This Email"
616
+ msgstr ""
617
+
618
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:698
619
+ msgid "Minute(s)"
620
+ msgstr ""
621
+
622
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:713
623
+ msgid "after cart is abandoned."
624
+ msgstr ""
625
+
626
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:723
627
+ msgid "Send Test Email To:"
628
+ msgstr ""
629
+
630
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:727
631
+ msgid "Send a test email"
632
+ msgstr ""
633
+
634
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:740
635
+ msgid "Save Changes"
636
+ msgstr ""
637
+
638
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:742
639
+ msgid "Update Changes"
640
+ msgstr ""
641
+
642
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:1048
643
+ msgid "Create New Template"
644
+ msgstr ""
645
+
646
+ #: modules/cart-abandonment/class-cartflows-ca-email-templates.php:1051
647
+ msgid " Restore Default Templates"
648
+ msgstr ""
649
+
650
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:27
651
+ msgid "Back to Reports"
652
+ msgstr ""
653
+
654
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:38
655
+ msgid "Email Details:"
656
+ msgstr ""
657
+
658
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:48
659
+ msgid ""
660
+ "All new activated emails will be reschedule for this abandoned order. New "
661
+ "emails will be sent to user according to schedule time."
662
+ msgstr ""
663
+
664
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:54
665
+ msgid "Are your sure?"
666
+ msgstr ""
667
+
668
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:58
669
+ msgid "Reschedule"
670
+ msgstr ""
671
+
672
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:62
673
+ msgid "Close"
674
+ msgstr ""
675
+
676
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:67
677
+ msgid "Do you really want to reschedule emails?"
678
+ msgstr ""
679
+
680
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:67
681
+ msgid "Reschedule Emails"
682
+ msgstr ""
683
+
684
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:73
685
+ msgid " No Email Scheduled."
686
+ msgstr ""
687
+
688
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:80
689
+ msgid "Scheduled Template"
690
+ msgstr ""
691
+
692
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:82
693
+ msgid "Email Coupon"
694
+ msgstr ""
695
+
696
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:83
697
+ msgid "Email Sent"
698
+ msgstr ""
699
+
700
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:84
701
+ msgid "Scheduled At"
702
+ msgstr ""
703
+
704
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:113
705
+ msgid "The email has been unsubscribed and won't be sent further."
706
+ msgstr ""
707
+
708
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:116
709
+ msgid "Email is in the queue and will be sent at the scheduled time."
710
+ msgstr ""
711
+
712
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:121
713
+ msgid "The email has been sent."
714
+ msgstr ""
715
+
716
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:125
717
+ msgid ""
718
+ "The email has been unscheduled due to the complete order and won't be sent "
719
+ "further."
720
+ msgstr ""
721
+
722
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:158
723
+ msgid "User Address Details:"
724
+ msgstr ""
725
+
726
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:170
727
+ msgid "Billing Address"
728
+ msgstr ""
729
+
730
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:174
731
+ msgid "Email address"
732
+ msgstr ""
733
+
734
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:179
735
+ msgid "Phone"
736
+ msgstr ""
737
+
738
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:184
739
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:204
740
+ msgid "Address 1:"
741
+ msgstr ""
742
+
743
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:187
744
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:207
745
+ msgid "Address 2:"
746
+ msgstr ""
747
+
748
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:190
749
+ msgid "Country, City:"
750
+ msgstr ""
751
+
752
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:193
753
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:213
754
+ msgid "State:"
755
+ msgstr ""
756
+
757
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:197
758
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:219
759
+ msgid "Postcode:"
760
+ msgstr ""
761
+
762
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:202
763
+ msgid "Shipping Address"
764
+ msgstr ""
765
+
766
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:210
767
+ msgid "City:"
768
+ msgstr ""
769
+
770
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:216
771
+ msgid "Country:"
772
+ msgstr ""
773
+
774
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:227
775
+ msgid "Checkout Link"
776
+ msgstr ""
777
+
778
+ #: modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php:242
779
+ msgid "User Order Details:"
780
+ msgstr ""
781
+
782
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:14
783
+ msgid "Today"
784
+ msgstr ""
785
+
786
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:18
787
+ msgid "Yesterday"
788
+ msgstr ""
789
+
790
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:22
791
+ msgid "Last Week"
792
+ msgstr ""
793
+
794
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:26
795
+ msgid "Last Month"
796
+ msgstr ""
797
+
798
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:35
799
+ msgid "Custom Filter"
800
+ msgstr ""
801
+
802
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:46
803
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:108
804
+ msgid "Recoverable Orders"
805
+ msgstr ""
806
+
807
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:50
808
+ msgid "Total Recoverable Orders."
809
+ msgstr ""
810
+
811
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:55
812
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:111
813
+ msgid "Recovered Orders"
814
+ msgstr ""
815
+
816
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:57
817
+ msgid "Total Recovered Orders."
818
+ msgstr ""
819
+
820
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:62
821
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:114
822
+ msgid "Lost Orders"
823
+ msgstr ""
824
+
825
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:65
826
+ msgid "Total Lost Orders."
827
+ msgstr ""
828
+
829
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:74
830
+ msgid "Recoverable Revenue"
831
+ msgstr ""
832
+
833
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:79
834
+ msgid "Total Recoverable Revenue."
835
+ msgstr ""
836
+
837
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:84
838
+ msgid "Recovered Revenue"
839
+ msgstr ""
840
+
841
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:90
842
+ msgid "Total Recovered Revenue."
843
+ msgstr ""
844
+
845
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:95
846
+ msgid "Recovery Rate"
847
+ msgstr ""
848
+
849
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:97
850
+ msgid "Total Percentage Of Recovered Orders After Abandonment."
851
+ msgstr ""
852
+
853
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:124
854
+ msgid "Search by email"
855
+ msgstr ""
856
+
857
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:125
858
+ msgid "Search Orders"
859
+ msgstr ""
860
+
861
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php:152
862
+ msgid "No Orders Found."
863
+ msgstr ""
864
+
865
+ #: modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-tabs.php:10
866
+ msgid "WooCommerce Cart Abandonment Recovery "
867
+ msgstr ""
868
+
869
+ #. Plugin Name of the plugin/theme
870
+ msgid "WooCommerce Cart Abandonment Recovery"
871
+ msgstr ""
872
+
873
+ #. Author URI of the plugin/theme
874
+ msgid "https://cartflows.com/"
875
+ msgstr ""
876
+
877
+ #. Description of the plugin/theme
878
+ msgid ""
879
+ "Recover your lost revenue. Capture email address of users on the checkout "
880
+ "page and send follow up emails if they don't complete the purchase."
881
+ msgstr ""
882
+
883
+ #. Author of the plugin/theme
884
+ msgid "CartFlows Inc"
885
  msgstr ""
modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php CHANGED
@@ -1,241 +1,241 @@
1
- <?php
2
- /**
3
- * Cart Abandonment DB
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- /**
9
- * Cart Abandonment DB class.
10
- */
11
- class Cartflows_Ca_Cart_Abandonment_Db {
12
-
13
-
14
-
15
- /**
16
- * Member Variable
17
- *
18
- * @var object instance
19
- */
20
- private static $instance;
21
-
22
- /**
23
- * Initiator
24
- */
25
- public static function get_instance() {
26
- if ( ! isset( self::$instance ) ) {
27
- self::$instance = new self();
28
- }
29
- return self::$instance;
30
- }
31
-
32
- /**
33
- * Create tables
34
- */
35
- public function create_tables() {
36
- $this->create_cart_abandonment_table();
37
- $this->create_cart_abandonment_template_table();
38
- $this->create_email_templates_meta_table();
39
- $this->create_email_history_table();
40
- }
41
-
42
- /**
43
- * Create Email templates meta table.
44
- */
45
- public function create_email_templates_meta_table() {
46
- global $wpdb;
47
-
48
- $email_template_meta_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
49
- $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
50
- $charset_collate = $wpdb->get_charset_collate();
51
-
52
- // Email templates meta table db sql command.
53
- $sql = "CREATE TABLE IF NOT EXISTS $email_template_meta_db (
54
- `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
55
- `email_template_id` BIGINT(20) NOT NULL,
56
- `meta_key` varchar(255) NOT NULL,
57
- `meta_value` longtext NOT NULL,
58
- PRIMARY KEY (`id`),
59
- FOREIGN KEY ( `email_template_id` ) REFERENCES $cart_abandonment_template_db(`id`) ON DELETE CASCADE
60
- ) $charset_collate;\n";
61
-
62
- include_once ABSPATH . 'wp-admin/includes/upgrade.php';
63
- dbDelta( $sql );
64
-
65
- }
66
-
67
- /**
68
- * Create tables for analytics.
69
- */
70
- public function create_cart_abandonment_table() {
71
-
72
- global $wpdb;
73
-
74
- $cart_abandonment_db = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
75
- $charset_collate = $wpdb->get_charset_collate();
76
-
77
- // Cart abandonment tracking db sql command.
78
- $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_db (
79
- id BIGINT(20) NOT NULL AUTO_INCREMENT,
80
- checkout_id int(11) NOT NULL,
81
- email VARCHAR(100),
82
- cart_contents LONGTEXT,
83
- cart_total DECIMAL(10,2),
84
- session_id VARCHAR(60) NOT NULL,
85
- other_fields LONGTEXT,
86
- order_status ENUM( 'normal','abandoned','completed','lost') NOT NULL DEFAULT 'normal',
87
- unsubscribed boolean DEFAULT 0,
88
- coupon_code VARCHAR(50),
89
- time DATETIME DEFAULT NULL,
90
- PRIMARY KEY (`id`, `session_id`),
91
- UNIQUE KEY `session_id_UNIQUE` (`session_id`)
92
- ) $charset_collate;\n";
93
-
94
- include_once ABSPATH . 'wp-admin/includes/upgrade.php';
95
- dbDelta( $sql );
96
-
97
- }
98
-
99
- /**
100
- * Create tables for analytics.
101
- */
102
- public function create_cart_abandonment_template_table() {
103
-
104
- global $wpdb;
105
-
106
- $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
107
-
108
- $charset_collate = $wpdb->get_charset_collate();
109
-
110
- // Cart abandonment tracking db sql command.
111
- $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_template_db (
112
- `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
113
- `template_name` text NOT NULL,
114
- `email_subject` text NOT NULL,
115
- `email_body` mediumtext NOT NULL,
116
- `is_activated` tinyint(1) NOT NULL DEFAULT '0',
117
- `frequency` int(11) NOT NULL,
118
- `frequency_unit` ENUM( 'MINUTE','HOUR','DAY') NOT NULL DEFAULT 'MINUTE',
119
- PRIMARY KEY (`id`)
120
- ) $charset_collate;\n";
121
-
122
- include_once ABSPATH . 'wp-admin/includes/upgrade.php';
123
- dbDelta( $sql );
124
-
125
- }
126
-
127
- /**
128
- * Create tables for analytics.
129
- */
130
- public function create_email_history_table() {
131
-
132
- global $wpdb;
133
-
134
- $cart_abandonment_history_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
135
- $cart_abandonment_db = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
136
- $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
137
-
138
- $charset_collate = $wpdb->get_charset_collate();
139
-
140
- $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_history_db (
141
- `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
142
- `template_id` BIGINT(20) NOT NULL,
143
- `ca_session_id` VARCHAR(60),
144
- `coupon_code` VARCHAR(50),
145
- `scheduled_time` DATETIME,
146
- `email_sent` boolean DEFAULT 0,
147
- PRIMARY KEY (`id`),
148
- FOREIGN KEY ( `template_id` ) REFERENCES $cart_abandonment_template_db(`id`) ON DELETE CASCADE,
149
- FOREIGN KEY ( `ca_session_id` ) REFERENCES $cart_abandonment_db(`session_id`) ON DELETE CASCADE
150
- ) $charset_collate;\n";
151
-
152
- include_once ABSPATH . 'wp-admin/includes/upgrade.php';
153
- dbDelta( $sql );
154
-
155
- }
156
-
157
- /**
158
- * Insert initial sample email templates.
159
- *
160
- * @param boolean $force_restore restore forcefully.
161
- */
162
- public function template_table_seeder( $force_restore = false ) {
163
- global $wpdb;
164
- $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
165
- $cart_abandonment_template_meta_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
166
-
167
- $email_template_count = $wpdb->get_var( "SELECT COUNT(*) FROM $cart_abandonment_template_db" ); // phpcs:ignore
168
-
169
- if ( ( ! $email_template_count ) || $force_restore ) {
170
-
171
- $email_templates = array(
172
- array(
173
- 'template_name' => 'Sample Email Template 1',
174
- 'subject' => 'Purchase issue?',
175
- 'body' => "<p>Hi {{customer.firstname}}!</p><p>We\'re having trouble processing your recent purchase. Would you mind completing it?</p><p>Here\'s a link to continue where you left off:</p><p><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'> Continue Your Purchase Now </a></p><p>Kindly,<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
176
- 'frequency' => 30,
177
- 'frequency_unit' => 'MINUTE',
178
- ),
179
- array(
180
- 'template_name' => 'Sample Email Template 2',
181
- 'subject' => 'Need help?',
182
- 'body' => "<p>Hi {{customer.firstname}}!</p><p>I'm {{admin.firstname}}, and I help handle customer issues at {{admin.company}}.</p><p>I just noticed that you tried to make a purchase, but unfortunately, there was some trouble. Is there anything I can do to help?</p><p>You should be able to complete your checkout in less than a minute:<br /><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'> Click here to continue your purchase </a><p><p>Thanks!<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
183
- 'frequency' => 1,
184
- 'frequency_unit' => 'DAY',
185
- ),
186
- array(
187
- 'template_name' => 'Sample Email Template 3',
188
- 'subject' => 'Exclusive discount for you. Let\'s get things started!',
189
- 'body' => "<p>Few days back you left {{cart.product.names}} in your cart.</p><p>To help make up your mind, we have added an exclusive 10% discount coupon {{cart.coupon_code}} to your cart.</p><p><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'>Complete Your Purchase Now &gt;&gt;</a></p><p>Hurry! This is a onetime offer and will expire in 24 Hours.</p><p>In case you couldn\'t finish your order due to technical difficulties or because you need some help, just reply to this email we will be happy to help.</p><p>Kind Regards,<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
190
- 'frequency' => 3,
191
- 'frequency_unit' => 'DAY',
192
- ),
193
- );
194
-
195
- // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
196
- $template_index = 1;
197
- $template_meta_index = 1;
198
- foreach ( $email_templates as $email_template ) {
199
- $wpdb->query(
200
- $wpdb->prepare(
201
- "INSERT INTO $cart_abandonment_template_db (`id`, `template_name`, `email_subject`, `email_body`, `frequency`, `frequency_unit`)
202
- VALUES ( %d, %s, %s, %s, %d, %s )",
203
- $force_restore ? null : $template_index++,
204
- $email_template['template_name'],
205
- $email_template['subject'],
206
- $email_template['body'],
207
- $email_template['frequency'],
208
- $email_template['frequency_unit']
209
- )
210
- );
211
-
212
- $meta_data = array(
213
- 'override_global_coupon' => false,
214
- 'discount_type' => 'percent',
215
- 'coupon_amount' => 10,
216
- 'coupon_expiry_date' => '',
217
- 'coupon_expiry_unit' => 'hours',
218
- );
219
-
220
- $email_tmpl_id = $wpdb->insert_id;
221
-
222
- foreach ( $meta_data as $meta_key => $meta_value ) {
223
- $wpdb->query(
224
- $wpdb->prepare(
225
- "INSERT INTO $cart_abandonment_template_meta_db ( `id`, `email_template_id`, `meta_key`, `meta_value` )
226
- VALUES ( %d, %d, %s, %s )",
227
- $force_restore ? null : $template_meta_index++,
228
- $email_tmpl_id,
229
- $meta_key,
230
- $meta_value
231
- )
232
- );
233
- }
234
- }
235
- // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
236
- }
237
-
238
- }
239
- }
240
-
241
- Cartflows_Ca_Cart_Abandonment_Db::get_instance();
1
+ <?php
2
+ /**
3
+ * Cart Abandonment DB
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ /**
9
+ * Cart Abandonment DB class.
10
+ */
11
+ class Cartflows_Ca_Cart_Abandonment_Db {
12
+
13
+
14
+
15
+ /**
16
+ * Member Variable
17
+ *
18
+ * @var object instance
19
+ */
20
+ private static $instance;
21
+
22
+ /**
23
+ * Initiator
24
+ */
25
+ public static function get_instance() {
26
+ if ( ! isset( self::$instance ) ) {
27
+ self::$instance = new self();
28
+ }
29
+ return self::$instance;
30
+ }
31
+
32
+ /**
33
+ * Create tables
34
+ */
35
+ public function create_tables() {
36
+ $this->create_cart_abandonment_table();
37
+ $this->create_cart_abandonment_template_table();
38
+ $this->create_email_templates_meta_table();
39
+ $this->create_email_history_table();
40
+ }
41
+
42
+ /**
43
+ * Create Email templates meta table.
44
+ */
45
+ public function create_email_templates_meta_table() {
46
+ global $wpdb;
47
+
48
+ $email_template_meta_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
49
+ $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
50
+ $charset_collate = $wpdb->get_charset_collate();
51
+
52
+ // Email templates meta table db sql command.
53
+ $sql = "CREATE TABLE IF NOT EXISTS $email_template_meta_db (
54
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
55
+ `email_template_id` BIGINT(20) NOT NULL,
56
+ `meta_key` varchar(255) NOT NULL,
57
+ `meta_value` longtext NOT NULL,
58
+ PRIMARY KEY (`id`),
59
+ FOREIGN KEY ( `email_template_id` ) REFERENCES $cart_abandonment_template_db(`id`) ON DELETE CASCADE
60
+ ) $charset_collate;\n";
61
+
62
+ include_once ABSPATH . 'wp-admin/includes/upgrade.php';
63
+ dbDelta( $sql );
64
+
65
+ }
66
+
67
+ /**
68
+ * Create tables for analytics.
69
+ */
70
+ public function create_cart_abandonment_table() {
71
+
72
+ global $wpdb;
73
+
74
+ $cart_abandonment_db = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
75
+ $charset_collate = $wpdb->get_charset_collate();
76
+
77
+ // Cart abandonment tracking db sql command.
78
+ $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_db (
79
+ id BIGINT(20) NOT NULL AUTO_INCREMENT,
80
+ checkout_id int(11) NOT NULL,
81
+ email VARCHAR(100),
82
+ cart_contents LONGTEXT,
83
+ cart_total DECIMAL(10,2),
84
+ session_id VARCHAR(60) NOT NULL,
85
+ other_fields LONGTEXT,
86
+ order_status ENUM( 'normal','abandoned','completed','lost') NOT NULL DEFAULT 'normal',
87
+ unsubscribed boolean DEFAULT 0,
88
+ coupon_code VARCHAR(50),
89
+ time DATETIME DEFAULT NULL,
90
+ PRIMARY KEY (`id`, `session_id`),
91
+ UNIQUE KEY `session_id_UNIQUE` (`session_id`)
92
+ ) $charset_collate;\n";
93
+
94
+ include_once ABSPATH . 'wp-admin/includes/upgrade.php';
95
+ dbDelta( $sql );
96
+
97
+ }
98
+
99
+ /**
100
+ * Create tables for analytics.
101
+ */
102
+ public function create_cart_abandonment_template_table() {
103
+
104
+ global $wpdb;
105
+
106
+ $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
107
+
108
+ $charset_collate = $wpdb->get_charset_collate();
109
+
110
+ // Cart abandonment tracking db sql command.
111
+ $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_template_db (
112
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
113
+ `template_name` text NOT NULL,
114
+ `email_subject` text NOT NULL,
115
+ `email_body` mediumtext NOT NULL,
116
+ `is_activated` tinyint(1) NOT NULL DEFAULT '0',
117
+ `frequency` int(11) NOT NULL,
118
+ `frequency_unit` ENUM( 'MINUTE','HOUR','DAY') NOT NULL DEFAULT 'MINUTE',
119
+ PRIMARY KEY (`id`)
120
+ ) $charset_collate;\n";
121
+
122
+ include_once ABSPATH . 'wp-admin/includes/upgrade.php';
123
+ dbDelta( $sql );
124
+
125
+ }
126
+
127
+ /**
128
+ * Create tables for analytics.
129
+ */
130
+ public function create_email_history_table() {
131
+
132
+ global $wpdb;
133
+
134
+ $cart_abandonment_history_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
135
+ $cart_abandonment_db = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
136
+ $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
137
+
138
+ $charset_collate = $wpdb->get_charset_collate();
139
+
140
+ $sql = "CREATE TABLE IF NOT EXISTS $cart_abandonment_history_db (
141
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
142
+ `template_id` BIGINT(20) NOT NULL,
143
+ `ca_session_id` VARCHAR(60),
144
+ `coupon_code` VARCHAR(50),
145
+ `scheduled_time` DATETIME,
146
+ `email_sent` boolean DEFAULT 0,
147
+ PRIMARY KEY (`id`),
148
+ FOREIGN KEY ( `template_id` ) REFERENCES $cart_abandonment_template_db(`id`) ON DELETE CASCADE,
149
+ FOREIGN KEY ( `ca_session_id` ) REFERENCES $cart_abandonment_db(`session_id`) ON DELETE CASCADE
150
+ ) $charset_collate;\n";
151
+
152
+ include_once ABSPATH . 'wp-admin/includes/upgrade.php';
153
+ dbDelta( $sql );
154
+
155
+ }
156
+
157
+ /**
158
+ * Insert initial sample email templates.
159
+ *
160
+ * @param boolean $force_restore restore forcefully.
161
+ */
162
+ public function template_table_seeder( $force_restore = false ) {
163
+ global $wpdb;
164
+ $cart_abandonment_template_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
165
+ $cart_abandonment_template_meta_db = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
166
+
167
+ $email_template_count = $wpdb->get_var( "SELECT COUNT(*) FROM $cart_abandonment_template_db" ); // phpcs:ignore
168
+
169
+ if ( ( ! $email_template_count ) || $force_restore ) {
170
+
171
+ $email_templates = array(
172
+ array(
173
+ 'template_name' => 'Sample Email Template 1',
174
+ 'subject' => 'Purchase issue?',
175
+ 'body' => "<p>Hi {{customer.firstname}}!</p><p>We\'re having trouble processing your recent purchase. Would you mind completing it?</p><p>Here\'s a link to continue where you left off:</p><p><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'> Continue Your Purchase Now </a></p><p>Kindly,<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
176
+ 'frequency' => 30,
177
+ 'frequency_unit' => 'MINUTE',
178
+ ),
179
+ array(
180
+ 'template_name' => 'Sample Email Template 2',
181
+ 'subject' => 'Need help?',
182
+ 'body' => "<p>Hi {{customer.firstname}}!</p><p>I'm {{admin.firstname}}, and I help handle customer issues at {{admin.company}}.</p><p>I just noticed that you tried to make a purchase, but unfortunately, there was some trouble. Is there anything I can do to help?</p><p>You should be able to complete your checkout in less than a minute:<br /><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'> Click here to continue your purchase </a><p><p>Thanks!<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
183
+ 'frequency' => 1,
184
+ 'frequency_unit' => 'DAY',
185
+ ),
186
+ array(
187
+ 'template_name' => 'Sample Email Template 3',
188
+ 'subject' => 'Exclusive discount for you. Let\'s get things started!',
189
+ 'body' => "<p>Few days back you left {{cart.product.names}} in your cart.</p><p>To help make up your mind, we have added an exclusive 10% discount coupon {{cart.coupon_code}} to your cart.</p><p><a href='{{cart.checkout_url}}' target='_blank' rel='noopener'>Complete Your Purchase Now &gt;&gt;</a></p><p>Hurry! This is a onetime offer and will expire in 24 Hours.</p><p>In case you couldn\'t finish your order due to technical difficulties or because you need some help, just reply to this email we will be happy to help.</p><p>Kind Regards,<br />{{admin.firstname}}<br />{{admin.company}}</p><p>{{cart.unsubscribe}}</p>",
190
+ 'frequency' => 3,
191
+ 'frequency_unit' => 'DAY',
192
+ ),
193
+ );
194
+
195
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
196
+ $template_index = 1;
197
+ $template_meta_index = 1;
198
+ foreach ( $email_templates as $email_template ) {
199
+ $wpdb->query(
200
+ $wpdb->prepare(
201
+ "INSERT INTO $cart_abandonment_template_db (`id`, `template_name`, `email_subject`, `email_body`, `frequency`, `frequency_unit`)
202
+ VALUES ( %d, %s, %s, %s, %d, %s )",
203
+ $force_restore ? null : $template_index++,
204
+ $email_template['template_name'],
205
+ $email_template['subject'],
206
+ $email_template['body'],
207
+ $email_template['frequency'],
208
+ $email_template['frequency_unit']
209
+ )
210
+ );
211
+
212
+ $meta_data = array(
213
+ 'override_global_coupon' => false,
214
+ 'discount_type' => 'percent',
215
+ 'coupon_amount' => 10,
216
+ 'coupon_expiry_date' => '',
217
+ 'coupon_expiry_unit' => 'hours',
218
+ );
219
+
220
+ $email_tmpl_id = $wpdb->insert_id;
221
+
222
+ foreach ( $meta_data as $meta_key => $meta_value ) {
223
+ $wpdb->query(
224
+ $wpdb->prepare(
225
+ "INSERT INTO $cart_abandonment_template_meta_db ( `id`, `email_template_id`, `meta_key`, `meta_value` )
226
+ VALUES ( %d, %d, %s, %s )",
227
+ $force_restore ? null : $template_meta_index++,
228
+ $email_tmpl_id,
229
+ $meta_key,
230
+ $meta_value
231
+ )
232
+ );
233
+ }
234
+ }
235
+ // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
236
+ }
237
+
238
+ }
239
+ }
240
+
241
+ Cartflows_Ca_Cart_Abandonment_Db::get_instance();
modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php CHANGED
@@ -1,291 +1,291 @@
1
- <?php
2
- /**
3
- * Cart Abandonment
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! class_exists( 'WP_List_Table' ) ) {
9
- include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
- }
11
- /**
12
- * Cart abandonment tracking table class.
13
- */
14
- class Cartflows_Ca_Cart_Abandonment_Table extends WP_List_Table {
15
-
16
-
17
- /**
18
- * Member Variable
19
- *
20
- * @var object instance
21
- */
22
- private static $instance;
23
-
24
- /**
25
- * Initiator
26
- */
27
- public static function get_instance() {
28
- if ( ! isset( self::$instance ) ) {
29
- self::$instance = new self();
30
- }
31
- return self::$instance;
32
- }
33
-
34
- /**
35
- * Constructor function.
36
- */
37
- public function __construct() {
38
- global $status, $page;
39
-
40
- parent::__construct(
41
- array(
42
- 'singular' => 'id',
43
- 'plural' => 'ids',
44
- )
45
- );
46
- }
47
-
48
- /**
49
- * Default columns.
50
- *
51
- * @param object $item item.
52
- * @param string $column_name column name.
53
- */
54
- public function column_default( $item, $column_name ) {
55
- return $item[ $column_name ];
56
- }
57
-
58
- /**
59
- * Column name surname.
60
- *
61
- * @param object $item item.
62
- * @return string
63
- */
64
- public function column_nameSurname( $item ) {
65
-
66
- $item_details = unserialize( $item['other_fields'] );
67
-
68
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
69
-
70
- $view_url = add_query_arg(
71
- array(
72
- 'page' => WCF_CA_PAGE_NAME,
73
- 'action' => WCF_ACTION_REPORTS,
74
- 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
75
- 'session_id' => sanitize_text_field( $item['session_id'] ),
76
- ),
77
- admin_url( '/admin.php' )
78
- );
79
-
80
- $actions = array(
81
- 'view' => sprintf( '<a href="%s">%s</a>', esc_url( $view_url ), __( 'View', 'woo-cart-abandonment-recovery' ) ),
82
- 'delete' => sprintf( '<a onclick="return confirm(\'Are you sure to delete this order?\');" href="?page=%s&action=delete&id=%s">%s</a>', esc_html( $page ), esc_html( $item['id'] ), __( 'Delete', 'woo-cart-abandonment-recovery' ) ),
83
- );
84
-
85
- if ( WCF_CART_ABANDONED_ORDER === $item['order_status'] && ! $item['unsubscribed'] ) {
86
- $actions['unsubscribe'] = sprintf( '<a onclick="return confirm(\'Are you sure to unsubscribe this user? \');" href="?page=%s&action=unsubscribe&id=%s">%s</a>', esc_html( $page ), esc_html( $item['id'] ), __( 'Unsubscribe', 'woo-cart-abandonment-recovery' ) );
87
-
88
- }
89
-
90
- return sprintf(
91
- '<a href="%s"><span class="dashicons dashicons-admin-users"></span> %s %s %s </a>',
92
- esc_url( $view_url ),
93
- esc_html( $item_details['wcf_first_name'] ),
94
- esc_html( $item_details['wcf_last_name'] ),
95
- $this->row_actions( $actions )
96
- );
97
- }
98
-
99
- /**
100
- * Render date column
101
- *
102
- * @param object $item - row (key, value array).
103
- * @return HTML
104
- */
105
- public function column_time( $item ) {
106
- $database_time = $item['time'];
107
- $date_time = new DateTime( $database_time );
108
- $date_time_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
109
- $date_time = $date_time->format( $date_time_format );
110
-
111
- return sprintf( '<span class="dashicons dashicons-clock"></span> %s', esc_html( $date_time ) );
112
- }
113
-
114
- /**
115
- * This is how checkbox column renders.
116
- *
117
- * @param object $item item.
118
- * @return HTML
119
- */
120
- public function column_cb( $item ) {
121
- return sprintf(
122
- '<input type="checkbox" name="id[]" value="%s" />',
123
- esc_html( $item['id'] )
124
- );
125
- }
126
-
127
- /**
128
- * [OPTIONAL] Return array of bult actions if has any
129
- *
130
- * @return array
131
- */
132
- public function get_bulk_actions() {
133
- $actions = array(
134
- 'delete' => __( 'Delete', 'woo-cart-abandonment-recovery' ),
135
- );
136
- $filter_table = isset( $_GET['filter_table'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_table'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
137
- if ( ! isset( $filter_table ) || ( isset( $filter_table ) && WCF_CART_ABANDONED_ORDER === $filter_table ) ) {
138
- $actions['unsubscribe'] = __( 'Unsubscribe', 'woo-cart-abandonment-recovery' );
139
- }
140
-
141
- return $actions;
142
- }
143
-
144
- /**
145
- * Whether the table has items to display or not
146
- *
147
- * @return bool
148
- */
149
- public function has_items() {
150
- return ! empty( $this->items );
151
- }
152
-
153
- /**
154
- * Fetch data from the database to render on view.
155
- *
156
- * @param string $cart_type abandoned|completed.
157
- * @param string $from_date from date.
158
- * @param string $to_date to date.
159
- */
160
- public function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER, $from_date = '', $to_date = '' ) {
161
- global $wpdb;
162
- $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
163
-
164
- $per_page = 10;
165
-
166
- $columns = $this->get_columns();
167
- $hidden = array();
168
- $sortable = $this->get_sortable_columns();
169
-
170
- $this->_column_headers = array( $columns, $hidden, $sortable );
171
-
172
- $this->process_bulk_action();
173
-
174
- $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
175
- $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
176
- $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
177
- $search_term = filter_input( INPUT_GET, 'search_term', FILTER_SANITIZE_STRING );
178
-
179
- $paged = $paged ? max( 0, $paged - 1 ) : 0;
180
- $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
181
- $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
182
-
183
- $this->items = $wpdb->get_results(
184
- $wpdb->prepare( "SELECT * FROM {$cart_abandonment_table_name} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s AND `email` LIKE '%%%s%%' ORDER BY %s %s LIMIT %d OFFSET %d", //phpcs:ignore
185
- $cart_type,
186
- $from_date,
187
- $to_date,
188
- $wpdb->esc_like( $search_term ),
189
- $orderby,
190
- $order,
191
- $per_page,
192
- $paged * $per_page
193
- ),
194
- ARRAY_A
195
- );
196
-
197
- $total_items = $wpdb->get_var($wpdb->prepare("SELECT count(*) FROM $cart_abandonment_table_name WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s", $cart_type, $from_date, $to_date)); // phpcs:ignore
198
-
199
- // [REQUIRED] configure pagination
200
- $this->set_pagination_args(
201
- array(
202
- 'total_items' => $total_items,
203
- 'per_page' => $per_page,
204
- 'total_pages' => ceil( $total_items / $per_page ),
205
- )
206
- );
207
-
208
- $export_data = filter_input( INPUT_GET, 'export_data', FILTER_VALIDATE_BOOLEAN );
209
- if ( $export_data ) {
210
-
211
- $this->items = $wpdb->get_results(
212
- $wpdb->prepare( "SELECT * FROM {$cart_abandonment_table_name} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s AND `email` LIKE '%%%s%%' ORDER BY %s %s", //phpcs:ignore
213
- $cart_type,
214
- $from_date,
215
- $to_date,
216
- $wpdb->esc_like( $search_term ),
217
- $orderby,
218
- $order
219
- ),
220
- ARRAY_A
221
- );
222
- return $this->items;
223
- }
224
- }
225
-
226
- /**
227
- * Table columns.
228
- *
229
- * @return array
230
- */
231
- public function get_columns() {
232
- $columns = array(
233
- 'cb' => '<input type="checkbox" />',
234
- 'nameSurname' => __( 'Name', 'woo-cart-abandonment-recovery' ),
235
- 'email' => __( 'Email', 'woo-cart-abandonment-recovery' ),
236
- 'cart_total' => __( 'Cart Total', 'woo-cart-abandonment-recovery' ),
237
- 'order_status' => __( 'Order Status', 'woo-cart-abandonment-recovery' ),
238
- 'time' => __( 'Time', 'woo-cart-abandonment-recovery' ),
239
- );
240
- return $columns;
241
- }
242
-
243
- /**
244
- * Table sortable columns.
245
- *
246
- * @return array
247
- */
248
- public function get_sortable_columns() {
249
- $sortable = array(
250
- 'nameSurname' => array( 'name', true ),
251
- 'cart_total' => array( 'cart_total', true ),
252
- 'cart_total' => array( 'Cart Total', true ),
253
- 'order_status' => array( 'Order Status', true ),
254
- 'time' => array( 'time', true ),
255
- );
256
- return $sortable;
257
- }
258
-
259
- /**
260
- * Processes bulk actions
261
- */
262
- public function process_bulk_action() {
263
- global $wpdb;
264
- $table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
265
-
266
- $ids = array();
267
- $request_id = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : ''; //phpcs:ignore
268
- if ( is_array( $request_id ) ) {
269
- $ids = array_map( 'intval', $request_id );
270
- } elseif ( isset( $request_id ) ) {
271
- $ids = array( intval( $request_id ) );
272
- }
273
- $ids = implode( ',', $ids );
274
- if ( ! empty( $ids ) ) {
275
-
276
- switch ( $this->current_action() ) {
277
-
278
- case 'delete':
279
- $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
280
- break;
281
- case 'unsubscribe':
282
- $wpdb->query( "UPDATE {$table_name} SET unsubscribed = 1 WHERE id IN($ids)" ); // phpcs:ignore
283
- break;
284
-
285
- }
286
- }
287
-
288
- }
289
-
290
-
291
- }
1
+ <?php
2
+ /**
3
+ * Cart Abandonment
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! class_exists( 'WP_List_Table' ) ) {
9
+ include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
+ }
11
+ /**
12
+ * Cart abandonment tracking table class.
13
+ */
14
+ class Cartflows_Ca_Cart_Abandonment_Table extends WP_List_Table {
15
+
16
+
17
+ /**
18
+ * Member Variable
19
+ *
20
+ * @var object instance
21
+ */
22
+ private static $instance;
23
+
24
+ /**
25
+ * Initiator
26
+ */
27
+ public static function get_instance() {
28
+ if ( ! isset( self::$instance ) ) {
29
+ self::$instance = new self();
30
+ }
31
+ return self::$instance;
32
+ }
33
+
34
+ /**
35
+ * Constructor function.
36
+ */
37
+ public function __construct() {
38
+ global $status, $page;
39
+
40
+ parent::__construct(
41
+ array(
42
+ 'singular' => 'id',
43
+ 'plural' => 'ids',
44
+ )
45
+ );
46
+ }
47
+
48
+ /**
49
+ * Default columns.
50
+ *
51
+ * @param object $item item.
52
+ * @param string $column_name column name.
53
+ */
54
+ public function column_default( $item, $column_name ) {
55
+ return $item[ $column_name ];
56
+ }
57
+
58
+ /**
59
+ * Column name surname.
60
+ *
61
+ * @param object $item item.
62
+ * @return string
63
+ */
64
+ public function column_nameSurname( $item ) {
65
+
66
+ $item_details = unserialize( $item['other_fields'] );
67
+
68
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
69
+
70
+ $view_url = add_query_arg(
71
+ array(
72
+ 'page' => WCF_CA_PAGE_NAME,
73
+ 'action' => WCF_ACTION_REPORTS,
74
+ 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
75
+ 'session_id' => sanitize_text_field( $item['session_id'] ),
76
+ ),
77
+ admin_url( '/admin.php' )
78
+ );
79
+
80
+ $actions = array(
81
+ 'view' => sprintf( '<a href="%s">%s</a>', esc_url( $view_url ), __( 'View', 'woo-cart-abandonment-recovery' ) ),
82
+ 'delete' => sprintf( '<a onclick="return confirm(\'Are you sure to delete this order?\');" href="?page=%s&action=delete&id=%s">%s</a>', esc_html( $page ), esc_html( $item['id'] ), __( 'Delete', 'woo-cart-abandonment-recovery' ) ),
83
+ );
84
+
85
+ if ( WCF_CART_ABANDONED_ORDER === $item['order_status'] && ! $item['unsubscribed'] ) {
86
+ $actions['unsubscribe'] = sprintf( '<a onclick="return confirm(\'Are you sure to unsubscribe this user? \');" href="?page=%s&action=unsubscribe&id=%s">%s</a>', esc_html( $page ), esc_html( $item['id'] ), __( 'Unsubscribe', 'woo-cart-abandonment-recovery' ) );
87
+
88
+ }
89
+
90
+ return sprintf(
91
+ '<a href="%s"><span class="dashicons dashicons-admin-users"></span> %s %s %s </a>',
92
+ esc_url( $view_url ),
93
+ esc_html( $item_details['wcf_first_name'] ),
94
+ esc_html( $item_details['wcf_last_name'] ),
95
+ $this->row_actions( $actions )
96
+ );
97
+ }
98
+
99
+ /**
100
+ * Render date column
101
+ *
102
+ * @param object $item - row (key, value array).
103
+ * @return HTML
104
+ */
105
+ public function column_time( $item ) {
106
+ $database_time = $item['time'];
107
+ $date_time = new DateTime( $database_time );
108
+ $date_time_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
109
+ $date_time = $date_time->format( $date_time_format );
110
+
111
+ return sprintf( '<span class="dashicons dashicons-clock"></span> %s', esc_html( $date_time ) );
112
+ }
113
+
114
+ /**
115
+ * This is how checkbox column renders.
116
+ *
117
+ * @param object $item item.
118
+ * @return HTML
119
+ */
120
+ public function column_cb( $item ) {
121
+ return sprintf(
122
+ '<input type="checkbox" name="id[]" value="%s" />',
123
+ esc_html( $item['id'] )
124
+ );
125
+ }
126
+
127
+ /**
128
+ * [OPTIONAL] Return array of bult actions if has any
129
+ *
130
+ * @return array
131
+ */
132
+ public function get_bulk_actions() {
133
+ $actions = array(
134
+ 'delete' => __( 'Delete', 'woo-cart-abandonment-recovery' ),
135
+ );
136
+ $filter_table = isset( $_GET['filter_table'] ) ? sanitize_text_field( wp_unslash( $_GET['filter_table'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
137
+ if ( ! isset( $filter_table ) || ( isset( $filter_table ) && WCF_CART_ABANDONED_ORDER === $filter_table ) ) {
138
+ $actions['unsubscribe'] = __( 'Unsubscribe', 'woo-cart-abandonment-recovery' );
139
+ }
140
+
141
+ return $actions;
142
+ }
143
+
144
+ /**
145
+ * Whether the table has items to display or not
146
+ *
147
+ * @return bool
148
+ */
149
+ public function has_items() {
150
+ return ! empty( $this->items );
151
+ }
152
+
153
+ /**
154
+ * Fetch data from the database to render on view.
155
+ *
156
+ * @param string $cart_type abandoned|completed.
157
+ * @param string $from_date from date.
158
+ * @param string $to_date to date.
159
+ */
160
+ public function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER, $from_date = '', $to_date = '' ) {
161
+ global $wpdb;
162
+ $cart_abandonment_table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
163
+
164
+ $per_page = 10;
165
+
166
+ $columns = $this->get_columns();
167
+ $hidden = array();
168
+ $sortable = $this->get_sortable_columns();
169
+
170
+ $this->_column_headers = array( $columns, $hidden, $sortable );
171
+
172
+ $this->process_bulk_action();
173
+
174
+ $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
175
+ $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
176
+ $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
177
+ $search_term = filter_input( INPUT_GET, 'search_term', FILTER_SANITIZE_STRING );
178
+
179
+ $paged = $paged ? max( 0, $paged - 1 ) : 0;
180
+ $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
181
+ $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
182
+
183
+ $this->items = $wpdb->get_results(
184
+ $wpdb->prepare( "SELECT * FROM {$cart_abandonment_table_name} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s AND `email` LIKE '%%%s%%' ORDER BY %s %s LIMIT %d OFFSET %d", //phpcs:ignore
185
+ $cart_type,
186
+ $from_date,
187
+ $to_date,
188
+ $wpdb->esc_like( $search_term ),
189
+ $orderby,
190
+ $order,
191
+ $per_page,
192
+ $paged * $per_page
193
+ ),
194
+ ARRAY_A
195
+ );
196
+
197
+ $total_items = $wpdb->get_var($wpdb->prepare("SELECT count(*) FROM $cart_abandonment_table_name WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s", $cart_type, $from_date, $to_date)); // phpcs:ignore
198
+
199
+ // [REQUIRED] configure pagination
200
+ $this->set_pagination_args(
201
+ array(
202
+ 'total_items' => $total_items,
203
+ 'per_page' => $per_page,
204
+ 'total_pages' => ceil( $total_items / $per_page ),
205
+ )
206
+ );
207
+
208
+ $export_data = filter_input( INPUT_GET, 'export_data', FILTER_VALIDATE_BOOLEAN );
209
+ if ( $export_data ) {
210
+
211
+ $this->items = $wpdb->get_results(
212
+ $wpdb->prepare( "SELECT * FROM {$cart_abandonment_table_name} WHERE `order_status` = %s AND DATE(`time`) >= %s AND DATE(`time`) <= %s AND `email` LIKE '%%%s%%' ORDER BY %s %s", //phpcs:ignore
213
+ $cart_type,
214
+ $from_date,
215
+ $to_date,
216
+ $wpdb->esc_like( $search_term ),
217
+ $orderby,
218
+ $order
219
+ ),
220
+ ARRAY_A
221
+ );
222
+ return $this->items;
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Table columns.
228
+ *
229
+ * @return array
230
+ */
231
+ public function get_columns() {
232
+ $columns = array(
233
+ 'cb' => '<input type="checkbox" />',
234
+ 'nameSurname' => __( 'Name', 'woo-cart-abandonment-recovery' ),
235
+ 'email' => __( 'Email', 'woo-cart-abandonment-recovery' ),
236
+ 'cart_total' => __( 'Cart Total', 'woo-cart-abandonment-recovery' ),
237
+ 'order_status' => __( 'Order Status', 'woo-cart-abandonment-recovery' ),
238
+ 'time' => __( 'Time', 'woo-cart-abandonment-recovery' ),
239
+ );
240
+ return $columns;
241
+ }
242
+
243
+ /**
244
+ * Table sortable columns.
245
+ *
246
+ * @return array
247
+ */
248
+ public function get_sortable_columns() {
249
+ $sortable = array(
250
+ 'nameSurname' => array( 'name', true ),
251
+ 'cart_total' => array( 'cart_total', true ),
252
+ 'cart_total' => array( 'Cart Total', true ),
253
+ 'order_status' => array( 'Order Status', true ),
254
+ 'time' => array( 'time', true ),
255
+ );
256
+ return $sortable;
257
+ }
258
+
259
+ /**
260
+ * Processes bulk actions
261
+ */
262
+ public function process_bulk_action() {
263
+ global $wpdb;
264
+ $table_name = $wpdb->prefix . CARTFLOWS_CA_CART_ABANDONMENT_TABLE;
265
+
266
+ $ids = array();
267
+ $request_id = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : ''; //phpcs:ignore
268
+ if ( is_array( $request_id ) ) {
269
+ $ids = array_map( 'intval', $request_id );
270
+ } elseif ( isset( $request_id ) ) {
271
+ $ids = array( intval( $request_id ) );
272
+ }
273
+ $ids = implode( ',', $ids );
274
+ if ( ! empty( $ids ) ) {
275
+
276
+ switch ( $this->current_action() ) {
277
+
278
+ case 'delete':
279
+ $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
280
+ break;
281
+ case 'unsubscribe':
282
+ $wpdb->query( "UPDATE {$table_name} SET unsubscribed = 1 WHERE id IN($ids)" ); // phpcs:ignore
283
+ break;
284
+
285
+ }
286
+ }
287
+
288
+ }
289
+
290
+
291
+ }
modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php CHANGED
@@ -172,13 +172,14 @@ class Cartflows_Ca_Cart_Abandonment {
172
  */
173
  public function wcf_ca_update_order_status( $order_id, $old_order_status, $new_order_status ) {
174
 
175
- $acceptable_order_statuses = array( 'completed', 'processing', 'failed' );
176
 
177
- $exclude_on_hold_order = apply_filters( 'woo_ca_exclude_on_hold_order_from_tracking', false );
178
 
179
- if ( $exclude_on_hold_order ) {
180
  array_push( $acceptable_order_statuses, 'on-hold' );
181
  }
 
182
  if ( ( WCF_CART_FAILED_ORDER === $new_order_status ) ) {
183
  return;
184
  }
@@ -980,6 +981,17 @@ class Cartflows_Ca_Cart_Abandonment {
980
  return $checkout_details;
981
  }
982
 
 
 
 
 
 
 
 
 
 
 
 
983
  /**
984
  * Deletes cart abandonment tracking and scheduled event.
985
  *
@@ -988,9 +1000,10 @@ class Cartflows_Ca_Cart_Abandonment {
988
  */
989
  public function delete_cart_abandonment_data( $order_id ) {
990
 
991
- $acceptable_order_statuses = array( 'completed', 'processing' );
992
- $order = wc_get_order( $order_id );
993
- $order_status = $order->get_status();
 
994
  if ( ! in_array( $order_status, $acceptable_order_statuses, true ) ) {
995
  // Proceed if order status in completed or processing.
996
  return;
172
  */
173
  public function wcf_ca_update_order_status( $order_id, $old_order_status, $new_order_status ) {
174
 
175
+ $acceptable_order_statuses = $this->get_acceptable_order_statuses();
176
 
177
+ $exclude_on_hold_order = apply_filters_deprecated( 'woo_ca_exclude_on_hold_order_from_tracking', array( false ), '1.2.8', 'New Option is introduced instead of this filter' );
178
 
179
+ if ( $exclude_on_hold_order & ! ( in_array( 'on-hold', $acceptable_order_statuses, true ) ) ) {
180
  array_push( $acceptable_order_statuses, 'on-hold' );
181
  }
182
+
183
  if ( ( WCF_CART_FAILED_ORDER === $new_order_status ) ) {
184
  return;
185
  }
981
  return $checkout_details;
982
  }
983
 
984
+ /**
985
+ * Get the acceptable order statuses.
986
+ */
987
+ public function get_acceptable_order_statuses() {
988
+
989
+ $acceptable_order_statuses = get_option( 'wcf_ca_excludes_orders' );
990
+ $acceptable_order_statuses = array_map( 'strtolower', $acceptable_order_statuses );
991
+
992
+ return $acceptable_order_statuses;
993
+ }
994
+
995
  /**
996
  * Deletes cart abandonment tracking and scheduled event.
997
  *
1000
  */
1001
  public function delete_cart_abandonment_data( $order_id ) {
1002
 
1003
+ $acceptable_order_statuses = $this->get_acceptable_order_statuses();
1004
+
1005
+ $order = wc_get_order( $order_id );
1006
+ $order_status = $order->get_status();
1007
  if ( ! in_array( $order_status, $acceptable_order_statuses, true ) ) {
1008
  // Proceed if order status in completed or processing.
1009
  return;
modules/cart-abandonment/class-cartflows-ca-email-templates-table.php CHANGED
@@ -1,268 +1,268 @@
1
- <?php
2
- /**
3
- * Cart Abandonment
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- if ( ! class_exists( 'WP_List_Table' ) ) {
9
- include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
- }
11
-
12
- /**
13
- * Cart abandonment templates table class.
14
- */
15
- class Cartflows_Ca_Email_Templates_Table extends WP_List_Table {
16
-
17
-
18
-
19
-
20
- /**
21
- * URL of this page
22
- *
23
- * @var string
24
- * @since 2.5.2
25
- */
26
- public $base_url;
27
-
28
- /**
29
- * Constructor function.
30
- */
31
- public function __construct() {
32
- global $status, $page;
33
-
34
- parent::__construct(
35
- array(
36
- 'singular' => 'id',
37
- 'plural' => 'ids',
38
- )
39
- );
40
-
41
- $this->base_url = admin_url( 'admin.php?page=' . WCF_CA_PAGE_NAME . '&action=' . WCF_ACTION_EMAIL_TEMPLATES );
42
- }
43
-
44
- /**
45
- * Default columns.
46
- *
47
- * @param object $item item.
48
- * @param string $column_name column name.
49
- */
50
- public function column_default( $item, $column_name ) {
51
- return $item[ $column_name ];
52
- }
53
-
54
- /**
55
- * This is how id column renders.
56
- *
57
- * @param object $item item.
58
- * @return HTML
59
- */
60
- public function column_template_name( $item ) {
61
-
62
- $row_actions['edit'] = '<a href="' . wp_nonce_url(
63
- add_query_arg(
64
- array(
65
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
66
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
67
- 'id' => $item['id'],
68
- ),
69
- $this->base_url
70
- ),
71
- WCF_EMAIL_TEMPLATES_NONCE
72
- ) . '">' . __( 'Edit', 'woo-cart-abandonment-recovery' ) . '</a>';
73
-
74
- $row_actions['delete'] = '<a onclick="return confirm(\'Are you sure to delete this email template?\');" href="' . wp_nonce_url(
75
- add_query_arg(
76
- array(
77
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
78
- 'sub_action' => WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES,
79
- 'id' => $item['id'],
80
- ),
81
- $this->base_url
82
- ),
83
- WCF_EMAIL_TEMPLATES_NONCE
84
- ) . '">' . __( 'Delete', 'woo-cart-abandonment-recovery' ) . '</a>';
85
-
86
- $row_actions['clone'] = '<a href="' . wp_nonce_url(
87
- add_query_arg(
88
- array(
89
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
90
- 'sub_action' => WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES,
91
- 'id' => $item['id'],
92
- ),
93
- $this->base_url
94
- ),
95
- WCF_EMAIL_TEMPLATES_NONCE
96
- ) . '">' . __( 'Clone', 'woo-cart-abandonment-recovery' ) . '</a>';
97
-
98
- return sprintf( '%s %s', esc_html( $item['template_name'] ), $this->row_actions( $row_actions ) );
99
- }
100
-
101
- /**
102
- * This is how checkbox column renders.
103
- *
104
- * @param object $item item.
105
- * @return HTML
106
- */
107
- public function column_cb( $item ) {
108
- return sprintf( '<input type="checkbox" name="id[]" value="%s" />', esc_html( $item['id'] ) );
109
- }
110
-
111
- /**
112
- * [OPTIONAL] Return array of bult actions if has any
113
- *
114
- * @return array
115
- */
116
- public function get_bulk_actions() {
117
- $actions = array(
118
- WCF_ACTION_EMAIL_TEMPLATES => __( 'Delete', 'woo-cart-abandonment-recovery' ),
119
- );
120
- return $actions;
121
- }
122
-
123
- /**
124
- * Whether the table has items to display or not
125
- *
126
- * @return bool
127
- */
128
- public function has_items() {
129
- return ! empty( $this->items );
130
- }
131
-
132
- /**
133
- * Fetch data from the database to render on view.
134
- *
135
- * @param string $cart_type abandoned|completed.
136
- */
137
- public function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER ) {
138
- global $wpdb;
139
- $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
140
-
141
- $per_page = 10;
142
-
143
- $columns = $this->get_columns();
144
- $hidden = array();
145
- $sortable = $this->get_sortable_columns();
146
-
147
- $this->_column_headers = array( $columns, $hidden, $sortable );
148
-
149
- $this->process_bulk_action();
150
-
151
- $total_items = $wpdb->get_var( "SELECT COUNT(id) FROM $cart_abandonment_template_table_name" ); // phpcs:ignore
152
-
153
- $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
154
- $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
155
- $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
156
-
157
- $paged = $paged ? max( 0, $paged - 1 ) : 0;
158
- $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
159
- $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
160
-
161
- // [REQUIRED] configure pagination
162
- $this->set_pagination_args(
163
- array(
164
- 'total_items' => $total_items,
165
- 'per_page' => $per_page,
166
- 'total_pages' => ceil( $total_items / $per_page ),
167
- )
168
- );
169
- $this->items = $wpdb->get_results(
170
- $wpdb->prepare( "SELECT * FROM {$cart_abandonment_template_table_name} ORDER BY $orderby $order LIMIT %d OFFSET %d", $per_page, $paged * $per_page ), // phpcs:ignore
171
- ARRAY_A
172
- );
173
- }
174
-
175
- /**
176
- * Table columns.
177
- *
178
- * @return array
179
- */
180
- public function get_columns() {
181
- $columns = array(
182
- 'cb' => '<input type="checkbox" />',
183
- 'template_name' => __( 'Template Name', 'woo-cart-abandonment-recovery' ),
184
- 'email_subject' => __( 'Email Subject', 'woo-cart-abandonment-recovery' ),
185
- 'trigger_time' => __( 'Trigger After', 'woo-cart-abandonment-recovery' ),
186
- 'is_activated' => __( 'Activate Template', 'woo-cart-abandonment-recovery' ),
187
-
188
- );
189
- return $columns;
190
- }
191
-
192
-
193
- /**
194
- * Column name trigger_time.
195
- *
196
- * @param object $item item.
197
- * @return string
198
- */
199
- protected function column_trigger_time( $item ) {
200
-
201
- return sprintf(
202
- '%d %s',
203
- esc_html( $item['frequency'] ),
204
- ' - ' . esc_html( $item['frequency_unit'] )
205
- );
206
- }
207
-
208
- /**
209
- * Column name trigger_time.
210
- *
211
- * @param object $item item.
212
- */
213
- protected function column_is_activated( $item ) {
214
- global $wpdb;
215
- if ( isset( $item['id'] ) ) {
216
- $id = $item['id'];
217
- }
218
- $is_activated = '';
219
- $active_status = 0;
220
- if ( $item && isset( $item['is_activated'] ) ) {
221
- $active_status = stripslashes( $item['is_activated'] );
222
- $is_activated = $active_status ? 'on' : 'off';
223
-
224
- }
225
- print '<button type="button" id="' . esc_attr( $id ) . '" class="wcf-ca-switch wcf-toggle-template-status wcar-switch-grid" wcf-ca-template-switch="' . esc_attr( $is_activated ) . '"> ' . esc_attr( $is_activated ) . ' </button>';
226
- print '<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . esc_attr( $active_status ) . '" />';
227
- }
228
-
229
- /**
230
- * Table sortable columns.
231
- *
232
- * @return array
233
- */
234
- public function get_sortable_columns() {
235
- $sortable = array(
236
- 'id' => array( 'id', true ),
237
- 'template_name' => array( 'Template Name', true ),
238
- 'email_subject' => array( 'Email Subject', true ),
239
- );
240
- return $sortable;
241
- }
242
-
243
- /**
244
- * Processes bulk actions
245
- */
246
- public function process_bulk_action() {
247
-
248
- global $wpdb;
249
- $table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
250
- $action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
251
-
252
- if ( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES === $action ) {
253
- $ids = array();
254
- $request_id = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : ''; //phpcs:ignore
255
- if ( is_array( $request_id ) ) {
256
- $ids = array_map( 'intval', $request_id );
257
- } else {
258
- $ids = array( intval( $request_id ) );
259
- }
260
- $ids = implode( ',', $ids );
261
-
262
- if ( ! empty( $ids ) ) {
263
- $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
264
- }
265
- }
266
-
267
- }
268
- }
1
+ <?php
2
+ /**
3
+ * Cart Abandonment
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ if ( ! class_exists( 'WP_List_Table' ) ) {
9
+ include_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10
+ }
11
+
12
+ /**
13
+ * Cart abandonment templates table class.
14
+ */
15
+ class Cartflows_Ca_Email_Templates_Table extends WP_List_Table {
16
+
17
+
18
+
19
+
20
+ /**
21
+ * URL of this page
22
+ *
23
+ * @var string
24
+ * @since 2.5.2
25
+ */
26
+ public $base_url;
27
+
28
+ /**
29
+ * Constructor function.
30
+ */
31
+ public function __construct() {
32
+ global $status, $page;
33
+
34
+ parent::__construct(
35
+ array(
36
+ 'singular' => 'id',
37
+ 'plural' => 'ids',
38
+ )
39
+ );
40
+
41
+ $this->base_url = admin_url( 'admin.php?page=' . WCF_CA_PAGE_NAME . '&action=' . WCF_ACTION_EMAIL_TEMPLATES );
42
+ }
43
+
44
+ /**
45
+ * Default columns.
46
+ *
47
+ * @param object $item item.
48
+ * @param string $column_name column name.
49
+ */
50
+ public function column_default( $item, $column_name ) {
51
+ return $item[ $column_name ];
52
+ }
53
+
54
+ /**
55
+ * This is how id column renders.
56
+ *
57
+ * @param object $item item.
58
+ * @return HTML
59
+ */
60
+ public function column_template_name( $item ) {
61
+
62
+ $row_actions['edit'] = '<a href="' . wp_nonce_url(
63
+ add_query_arg(
64
+ array(
65
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
66
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
67
+ 'id' => $item['id'],
68
+ ),
69
+ $this->base_url
70
+ ),
71
+ WCF_EMAIL_TEMPLATES_NONCE
72
+ ) . '">' . __( 'Edit', 'woo-cart-abandonment-recovery' ) . '</a>';
73
+
74
+ $row_actions['delete'] = '<a onclick="return confirm(\'Are you sure to delete this email template?\');" href="' . wp_nonce_url(
75
+ add_query_arg(
76
+ array(
77
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
78
+ 'sub_action' => WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES,
79
+ 'id' => $item['id'],
80
+ ),
81
+ $this->base_url
82
+ ),
83
+ WCF_EMAIL_TEMPLATES_NONCE
84
+ ) . '">' . __( 'Delete', 'woo-cart-abandonment-recovery' ) . '</a>';
85
+
86
+ $row_actions['clone'] = '<a href="' . wp_nonce_url(
87
+ add_query_arg(
88
+ array(
89
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
90
+ 'sub_action' => WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES,
91
+ 'id' => $item['id'],
92
+ ),
93
+ $this->base_url
94
+ ),
95
+ WCF_EMAIL_TEMPLATES_NONCE
96
+ ) . '">' . __( 'Clone', 'woo-cart-abandonment-recovery' ) . '</a>';
97
+
98
+ return sprintf( '%s %s', esc_html( $item['template_name'] ), $this->row_actions( $row_actions ) );
99
+ }
100
+
101
+ /**
102
+ * This is how checkbox column renders.
103
+ *
104
+ * @param object $item item.
105
+ * @return HTML
106
+ */
107
+ public function column_cb( $item ) {
108
+ return sprintf( '<input type="checkbox" name="id[]" value="%s" />', esc_html( $item['id'] ) );
109
+ }
110
+
111
+ /**
112
+ * [OPTIONAL] Return array of bult actions if has any
113
+ *
114
+ * @return array
115
+ */
116
+ public function get_bulk_actions() {
117
+ $actions = array(
118
+ WCF_ACTION_EMAIL_TEMPLATES => __( 'Delete', 'woo-cart-abandonment-recovery' ),
119
+ );
120
+ return $actions;
121
+ }
122
+
123
+ /**
124
+ * Whether the table has items to display or not
125
+ *
126
+ * @return bool
127
+ */
128
+ public function has_items() {
129
+ return ! empty( $this->items );
130
+ }
131
+
132
+ /**
133
+ * Fetch data from the database to render on view.
134
+ *
135
+ * @param string $cart_type abandoned|completed.
136
+ */
137
+ public function prepare_items( $cart_type = WCF_CART_ABANDONED_ORDER ) {
138
+ global $wpdb;
139
+ $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
140
+
141
+ $per_page = 10;
142
+
143
+ $columns = $this->get_columns();
144
+ $hidden = array();
145
+ $sortable = $this->get_sortable_columns();
146
+
147
+ $this->_column_headers = array( $columns, $hidden, $sortable );
148
+
149
+ $this->process_bulk_action();
150
+
151
+ $total_items = $wpdb->get_var( "SELECT COUNT(id) FROM $cart_abandonment_template_table_name" ); // phpcs:ignore
152
+
153
+ $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT );
154
+ $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_STRING );
155
+ $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_STRING );
156
+
157
+ $paged = $paged ? max( 0, $paged - 1 ) : 0;
158
+ $orderby = ( $orderby && in_array( $orderby, array_keys( $this->get_sortable_columns() ), true ) ) ? $orderby : 'id';
159
+ $order = ( $order && in_array( $order, array( 'asc', 'desc' ), true ) ) ? $order : 'desc';
160
+
161
+ // [REQUIRED] configure pagination
162
+ $this->set_pagination_args(
163
+ array(
164
+ 'total_items' => $total_items,
165
+ 'per_page' => $per_page,
166
+ 'total_pages' => ceil( $total_items / $per_page ),
167
+ )
168
+ );
169
+ $this->items = $wpdb->get_results(
170
+ $wpdb->prepare( "SELECT * FROM {$cart_abandonment_template_table_name} ORDER BY $orderby $order LIMIT %d OFFSET %d", $per_page, $paged * $per_page ), // phpcs:ignore
171
+ ARRAY_A
172
+ );
173
+ }
174
+
175
+ /**
176
+ * Table columns.
177
+ *
178
+ * @return array
179
+ */
180
+ public function get_columns() {
181
+ $columns = array(
182
+ 'cb' => '<input type="checkbox" />',
183
+ 'template_name' => __( 'Template Name', 'woo-cart-abandonment-recovery' ),
184
+ 'email_subject' => __( 'Email Subject', 'woo-cart-abandonment-recovery' ),
185
+ 'trigger_time' => __( 'Trigger After', 'woo-cart-abandonment-recovery' ),
186
+ 'is_activated' => __( 'Activate Template', 'woo-cart-abandonment-recovery' ),
187
+
188
+ );
189
+ return $columns;
190
+ }
191
+
192
+
193
+ /**
194
+ * Column name trigger_time.
195
+ *
196
+ * @param object $item item.
197
+ * @return string
198
+ */
199
+ protected function column_trigger_time( $item ) {
200
+
201
+ return sprintf(
202
+ '%d %s',
203
+ esc_html( $item['frequency'] ),
204
+ ' - ' . esc_html( $item['frequency_unit'] )
205
+ );
206
+ }
207
+
208
+ /**
209
+ * Column name trigger_time.
210
+ *
211
+ * @param object $item item.
212
+ */
213
+ protected function column_is_activated( $item ) {
214
+ global $wpdb;
215
+ if ( isset( $item['id'] ) ) {
216
+ $id = $item['id'];
217
+ }
218
+ $is_activated = '';
219
+ $active_status = 0;
220
+ if ( $item && isset( $item['is_activated'] ) ) {
221
+ $active_status = stripslashes( $item['is_activated'] );
222
+ $is_activated = $active_status ? 'on' : 'off';
223
+
224
+ }
225
+ print '<button type="button" id="' . esc_attr( $id ) . '" class="wcf-ca-switch wcf-toggle-template-status wcar-switch-grid" wcf-ca-template-switch="' . esc_attr( $is_activated ) . '"> ' . esc_attr( $is_activated ) . ' </button>';
226
+ print '<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . esc_attr( $active_status ) . '" />';
227
+ }
228
+
229
+ /**
230
+ * Table sortable columns.
231
+ *
232
+ * @return array
233
+ */
234
+ public function get_sortable_columns() {
235
+ $sortable = array(
236
+ 'id' => array( 'id', true ),
237
+ 'template_name' => array( 'Template Name', true ),
238
+ 'email_subject' => array( 'Email Subject', true ),
239
+ );
240
+ return $sortable;
241
+ }
242
+
243
+ /**
244
+ * Processes bulk actions
245
+ */
246
+ public function process_bulk_action() {
247
+
248
+ global $wpdb;
249
+ $table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
250
+ $action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
251
+
252
+ if ( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES === $action ) {
253
+ $ids = array();
254
+ $request_id = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : ''; //phpcs:ignore
255
+ if ( is_array( $request_id ) ) {
256
+ $ids = array_map( 'intval', $request_id );
257
+ } else {
258
+ $ids = array( intval( $request_id ) );
259
+ }
260
+ $ids = implode( ',', $ids );
261
+
262
+ if ( ! empty( $ids ) ) {
263
+ $wpdb->query("DELETE FROM $table_name WHERE id IN($ids)"); // phpcs:ignore
264
+ }
265
+ }
266
+
267
+ }
268
+ }
modules/cart-abandonment/class-cartflows-ca-email-templates.php CHANGED
@@ -1,1096 +1,1096 @@
1
- <?php
2
- /**
3
- * Cart Abandonment
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- define( 'CARTFLOWS_EMAIL_TEMPLATE_DIR', CARTFLOWS_CA_DIR . 'modules/cart-abandonment/' );
9
- define( 'CARTFLOWS_EMAIL_TEMPLATE_URL', CARTFLOWS_CA_URL . 'modules/cart-abandonment/' );
10
-
11
- /**
12
- * Class for analytics tracking.
13
- */
14
- class Cartflows_Ca_Email_Templates {
15
-
16
-
17
-
18
- /**
19
- * Member Variable
20
- *
21
- * @var object instance
22
- */
23
- private $wpdb;
24
-
25
- /**
26
- * Member Variable
27
- *
28
- * @var object instance
29
- */
30
- private static $instance;
31
-
32
- /**
33
- * Member Variable
34
- *
35
- * @var object instance
36
- */
37
- public $email_history_table;
38
-
39
- /**
40
- * Table name for email templates
41
- *
42
- * @var string
43
- */
44
- public $cart_abandonment_template_table_name;
45
-
46
- /**
47
- * Table name for email templates meta table
48
- *
49
- * @var string
50
- */
51
- public $email_templates_meta_table;
52
-
53
- /**
54
- * Initiator
55
- */
56
- public static function get_instance() {
57
- if ( ! isset( self::$instance ) ) {
58
- self::$instance = new self();
59
- }
60
- return self::$instance;
61
- }
62
-
63
-
64
-
65
-
66
-
67
- /**
68
- * Constructor function that initializes required actions and hooks
69
- */
70
- public function __construct() {
71
- $this->define_template_constants();
72
- global $wpdb;
73
- $this->cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
74
- $this->email_templates_meta_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
75
- $this->email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
76
- $this->wpdb = $wpdb;
77
-
78
- add_action( 'admin_enqueue_scripts', __class__ . '::load_email_templates_script', 15 );
79
- add_action( 'wp_ajax_activate_email_templates', array( $this, 'update_email_toggle_button' ) );
80
- }
81
-
82
-
83
-
84
-
85
- /**
86
- * Add email template JS script.
87
- */
88
- public static function load_email_templates_script() {
89
-
90
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
91
-
92
- if ( ! ( WCF_CA_PAGE_NAME === $page ) ) {
93
- return;
94
- }
95
-
96
- wp_enqueue_script( 'jquery-ui-datepicker' );
97
- wp_enqueue_style( 'jquery-ui-style' );
98
-
99
- wp_enqueue_script(
100
- 'cartflows-ca-email-tmpl-settings',
101
- CARTFLOWS_CA_URL . 'admin/assets/js/admin-email-templates.js',
102
- array( 'jquery' ),
103
- CARTFLOWS_CA_VER,
104
- false
105
- );
106
-
107
- $current_user = wp_get_current_user();
108
- $vars = array(
109
- 'email' => $current_user->user_email,
110
- 'name' => $current_user->user_firstname,
111
- 'surname' => $current_user->user_lastname,
112
- 'phone' => get_user_meta( $current_user->ID, 'billing_phone', true ),
113
- 'billing_company' => get_user_meta( $current_user->ID, 'billing_company', true ),
114
- 'billing_address_1' => get_user_meta( $current_user->ID, 'billing_address_1', true ),
115
- 'billing_address_2' => get_user_meta( $current_user->ID, 'billing_address_2', true ),
116
- 'billing_state' => get_user_meta( $current_user->ID, 'billing_state', true ),
117
- 'billing_postcode' => get_user_meta( $current_user->ID, 'billing_postcode', true ),
118
- 'shipping_first_name' => $current_user->user_firstname,
119
- 'shipping_last_name' => $current_user->user_lastname,
120
- 'shipping_company' => get_user_meta( $current_user->ID, 'shipping_company', true ),
121
- 'shipping_address_1' => get_user_meta( $current_user->ID, 'shipping_address_1', true ),
122
- 'shipping_address_2' => get_user_meta( $current_user->ID, 'shipping_address_2', true ),
123
- 'shipping_city' => get_user_meta( $current_user->ID, 'shipping_city', true ),
124
- 'shipping_state' => get_user_meta( $current_user->ID, 'shipping_state', true ),
125
- 'shipping_postcode' => get_user_meta( $current_user->ID, 'shipping_postcode', true ),
126
- 'woo_currency_symbol' => get_woocommerce_currency_symbol(),
127
- 'email_toggle_button_nonce' => wp_create_nonce( 'activate_email_templates' ),
128
- 'admin_firstname' => __( 'Admin Firstname', 'woo-cart-abandonment-recovery' ),
129
- 'admin_company' => __( 'Admin Company', 'woo-cart-abandonment-recovery' ),
130
- 'abandoned_product_details_table' => __( 'Abandoned Product Details Table', 'woo-cart-abandonment-recovery' ),
131
- 'abandoned_product_names' => __( 'Abandoned Product Names', 'woo-cart-abandonment-recovery' ),
132
- 'cart_checkout_url' => __( 'Cart Checkout URL', 'woo-cart-abandonment-recovery' ),
133
- 'coupon_code' => __( 'Coupon Code', 'woo-cart-abandonment-recovery' ),
134
- 'customer_firstname' => __( 'Customer First Name', 'woo-cart-abandonment-recovery' ),
135
- 'customer_lastname' => __( 'Customer Last Name', 'woo-cart-abandonment-recovery' ),
136
- 'customer_full_name' => __( 'Customer Full Name', 'woo-cart-abandonment-recovery' ),
137
- 'cart_abandonment_date' => __( 'Cart Abandonment Date', 'woo-cart-abandonment-recovery' ),
138
- 'site_url' => __( 'Site URL', 'woo-cart-abandonment-recovery' ),
139
- 'unsubscribe_link' => __( 'Unsubscribe Link', 'woo-cart-abandonment-recovery' ),
140
- );
141
- wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'wcf_ca_details', $vars );
142
-
143
- }
144
-
145
-
146
- /**
147
- * Update the activate email template toggle button.
148
- */
149
- public function update_email_toggle_button() {
150
-
151
- check_ajax_referer( 'activate_email_templates', 'security' );
152
- global $wpdb;
153
- $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
154
-
155
- $id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT );
156
-
157
- $is_activated = filter_input( INPUT_POST, 'state', FILTER_SANITIZE_STRING );
158
-
159
- $response = __( 'Something went wrong', 'woo-cart-abandonment-recovery' );
160
- if ( ! isset( $is_activated ) || ! isset( $id ) ) {
161
- wp_send_json_error( $response );
162
- }
163
-
164
- if ( $is_activated && 'on' === $is_activated ) {
165
- $is_activated = 1;
166
- $response = __( 'Activated', 'woo-cart-abandonment-recovery' );
167
- } else {
168
- $is_activated = 0;
169
- $response = __( 'Deactivated', 'woo-cart-abandonment-recovery' );
170
- }
171
-
172
- $wpdb->query( $wpdb->prepare( "UPDATE {$cart_abandonment_template_table_name} SET is_activated = %d WHERE id = %d ", $is_activated, $id ), ARRAY_A ); // phpcs:ignore
173
- wp_send_json_success( $response );
174
-
175
- }
176
-
177
- /**
178
- * Initialise all the constants
179
- */
180
- public function define_template_constants() {
181
- define( 'WCF_CA_PAGE_NAME', 'woo-cart-abandonment-recovery' );
182
-
183
- define( 'WCF_CA_GENERAL_SETTINGS_SECTION', 'cartflows_cart_abandonment_settings_section' );
184
- define( 'WCF_CA_COUPONS_SETTINGS_SECTION', 'cartflows_cart_abandonment_coupons_settings_section' );
185
- define( 'WCF_CA_EMAIL_SETTINGS_SECTION', 'cartflows_email_template_settings_section' );
186
- define( 'WCF_CA_COUPON_CODE_SECTION', 'cartflows_coupon_code_settings_section' );
187
- define( 'WCF_CA_ZAPIER_SETTINGS_SECTION', 'cartflows_zapier_settings_section' );
188
- define( 'WCF_CA_GDPR_SETTINGS_SECTION', 'cartflows_gdpr_settings_section' );
189
-
190
- define( 'WCF_CA_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-settings' );
191
- define( 'WCF_CA_EMAIL_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-email-settings' );
192
-
193
- define( 'WCF_ACTION_EMAIL_TEMPLATES', 'email_tmpl' );
194
-
195
- define( 'WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES', 'add_email_tmpl' );
196
- define( 'WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES', 'edit_email_tmpl' );
197
- define( 'WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES', 'delete_email_tmpl' );
198
- define( 'WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES', 'clone_email_tmpl' );
199
- define( 'WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES', 'delete_bulk_email_tmpl' );
200
- define( 'WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES', 'save_email_template' );
201
- define( 'WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES', 'restore_default_email_tmpl' );
202
-
203
- define( 'WCF_SUB_ACTION_CART_ABANDONMENT_SETTINGS', 'cart_abandonment_settings' );
204
- define( 'WCF_SUB_ACTION_EMAIL_SETTINGS', 'email_settings' );
205
- define( 'WCF_SUB_ACTION_COUPON_CODE_SETTINGS', 'coupon_code_settings' );
206
- define( 'WCF_SUB_ACTION_ZAPIER_SETTINGS', 'zapier_settings' );
207
-
208
- define( 'WCF_EMAIL_TEMPLATES_NONCE', 'email_template_nonce' );
209
-
210
- }
211
-
212
- /**
213
- * Show success messages for email templates.
214
- */
215
- public function show_messages() {
216
-
217
- $wcf_ca_template_created = filter_input( INPUT_GET, 'wcf_ca_template_created', FILTER_SANITIZE_STRING );
218
- $wcf_ca_template_cloned = filter_input( INPUT_GET, 'wcf_ca_template_cloned', FILTER_SANITIZE_STRING );
219
- $wcf_ca_template_deleted = filter_input( INPUT_GET, 'wcf_ca_template_deleted', FILTER_SANITIZE_STRING );
220
- $wcf_ca_template_updated = filter_input( INPUT_GET, 'wcf_ca_template_updated', FILTER_SANITIZE_STRING );
221
- $wcf_ca_template_restored = filter_input( INPUT_GET, 'wcf_ca_template_restored', FILTER_SANITIZE_STRING );
222
-
223
- ?>
224
- <?php if ( 'YES' === $wcf_ca_template_created ) { ?>
225
- <div id="message" class="notice notice-success is-dismissible">
226
- <p>
227
- <strong>
228
- <?php esc_html_e( 'The Email Template has been successfully added.', 'woo-cart-abandonment-recovery' ); ?>
229
- </strong>
230
- </p>
231
- </div>
232
- <?php } ?>
233
-
234
- <?php if ( 'YES' === $wcf_ca_template_cloned ) { ?>
235
- <div id="message" class="notice notice-success is-dismissible">
236
- <p>
237
- <strong>
238
- <?php esc_html_e( 'The Email Template has been cloned successfully.', 'woo-cart-abandonment-recovery' ); ?>
239
- </strong>
240
- </p>
241
- </div>
242
- <?php } ?>
243
-
244
- <?php if ( 'YES' === $wcf_ca_template_deleted ) { ?>
245
- <div id="message" class="notice notice-success is-dismissible">
246
- <p>
247
- <strong>
248
- <?php esc_html_e( 'The Email Template has been successfully deleted.', 'woo-cart-abandonment-recovery' ); ?>
249
- </strong>
250
- </p>
251
- </div>
252
- <?php } ?>
253
- <?php if ( 'YES' === $wcf_ca_template_updated ) { ?>
254
- <div id="message" class="notice notice-success is-dismissible">
255
- <p>
256
- <strong>
257
- <?php esc_html_e( 'The Email Template has been successfully updated.', 'woo-cart-abandonment-recovery' ); ?>
258
- </strong>
259
- </p>
260
- </div>
261
- <?php } ?>
262
-
263
- <?php if ( 'YES' === $wcf_ca_template_restored ) { ?>
264
- <div id="message" class="notice notice-success is-dismissible">
265
- <p>
266
- <strong>
267
- <?php esc_html_e( 'Default Email Templates has been restored successfully.', 'woo-cart-abandonment-recovery' ); ?>
268
- </strong>
269
- </p>
270
- </div>
271
- <?php } ?>
272
- <?php
273
-
274
- }
275
-
276
- /**
277
- * Delete bulk email templates.
278
- */
279
- public function delete_bulk_templates() {
280
- $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
281
- $wcf_template_list->process_bulk_action();
282
- $param = array(
283
- 'page' => WCF_CA_PAGE_NAME,
284
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
285
- 'wcf_ca_template_deleted' => 'YES',
286
- );
287
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
288
- wp_safe_redirect( $redirect_url );
289
- }
290
-
291
-
292
- /**
293
- * Delete email templates.
294
- */
295
- public function delete_single_template() {
296
-
297
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
298
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
299
-
300
- if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
301
-
302
- $this->wpdb->delete(
303
- $this->cart_abandonment_template_table_name,
304
- array( 'id' => $id ),
305
- '%d'
306
- );
307
- $param = array(
308
- 'page' => WCF_CA_PAGE_NAME,
309
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
310
- 'wcf_ca_template_deleted' => 'YES',
311
- );
312
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
313
- wp_safe_redirect( $redirect_url );
314
-
315
- }
316
- }
317
-
318
- /**
319
- * Delete email templates.
320
- */
321
- public function clone_email_template() {
322
-
323
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
324
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
325
-
326
- if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
327
-
328
- $email_template = $this->get_template_by_id( $id );
329
-
330
- $this->wpdb->insert(
331
- $this->cart_abandonment_template_table_name,
332
- array(
333
- 'template_name' => sanitize_text_field( $email_template->template_name ),
334
- 'email_subject' => sanitize_text_field( $email_template->email_subject ),
335
- 'email_body' => $email_template->email_body,
336
- 'frequency' => intval( sanitize_text_field( $email_template->frequency ) ),
337
- 'frequency_unit' => sanitize_text_field( $email_template->frequency_unit ),
338
-
339
- ),
340
- array( '%s', '%s', '%s', '%d', '%s' )
341
- );
342
-
343
- $email_template_id = $this->wpdb->insert_id;
344
- $meta_data = array(
345
- 'override_global_coupon' => false,
346
- 'discount_type' => 'percent',
347
- 'coupon_amount' => 10,
348
- 'coupon_expiry_date' => '',
349
- 'coupon_expiry_unit' => 'hours',
350
-
351
- );
352
-
353
- foreach ( $meta_data as $mera_key => $meta_value ) {
354
- $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
355
- }
356
-
357
- $param = array(
358
- 'page' => WCF_CA_PAGE_NAME,
359
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
360
- 'wcf_ca_template_cloned' => 'YES',
361
- );
362
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
363
- wp_safe_redirect( $redirect_url );
364
-
365
- }
366
- }
367
-
368
- /**
369
- * Get email template by id.
370
- *
371
- * @param int $email_tmpl_id template id.
372
- */
373
- public function get_email_template_by_id( $email_tmpl_id ) {
374
-
375
- $query = 'SELECT * FROM ' . $this->cart_abandonment_template_table_name . ' WHERE id = %d ';
376
- return $this->wpdb->get_row($this->wpdb->prepare($query, $email_tmpl_id)); // phpcs:ignore
377
-
378
- }
379
-
380
- /**
381
- * Render email template add/edit form.
382
- *
383
- * @param string $sub_action sub_action.
384
- */
385
- public function render_email_template_form( $sub_action = WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES ) {
386
-
387
- $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
388
-
389
- if ( $id ) {
390
- $results = $this->get_email_template_by_id( $id );
391
- }
392
-
393
- ?>
394
-
395
- <div id="content">
396
-
397
- <?php
398
- $param = array(
399
- 'page' => WCF_CA_PAGE_NAME,
400
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
401
- 'sub_action' => WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES,
402
- );
403
- $save_template_url = esc_url( add_query_arg( $param, admin_url( '/admin.php' ) ) );
404
- ?>
405
-
406
- <form method="post" action="<?php echo esc_attr( $save_template_url ); ?>" id="wcf_settings">
407
- <input type="hidden" name="sub_action" value="<?php echo esc_attr( $sub_action ); ?>"/>
408
- <?php
409
- $id_by = '';
410
- if ( isset( $id ) ) {
411
- $id_by = $id;
412
- }
413
- ?>
414
- <input type="hidden" name="id" value="<?php echo esc_attr( $id_by ); ?>"/>
415
- <?php
416
-
417
- $button_sub_action = 'save';
418
- $display_message = 'Add New Email Template:';
419
-
420
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
421
- $button_sub_action = 'update';
422
- $display_message = 'Edit Email Template:';
423
- }
424
- print '<input type="hidden" name="wcf_settings_frm" value="' . esc_attr( $button_sub_action ) . '">';
425
- ?>
426
- <div id="poststuff">
427
- <div> <!-- <div class="postbox" > -->
428
- <h3><?php esc_html_e($display_message, 'woo-cart-abandonment-recovery'); // phpcs:ignore ?></h3>
429
- <hr/>
430
- <div>
431
- <table class="form-table" id="addedit_template">
432
- <tr>
433
- <th>
434
- <label for="wcf_email_subject"><b><?php esc_html_e( 'Activate Template now?', 'woo-cart-abandonment-recovery' ); ?></b></label>
435
- </th>
436
- <td>
437
- <?php
438
- $is_activated = '';
439
- $active_status = 0;
440
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->is_activated ) ) {
441
- $active_status = stripslashes( $results->is_activated );
442
- $is_activated = $active_status ? 'on' : 'off';
443
-
444
- }
445
- print '<button type="button" class="wcf-ca-switch wcf-toggle-template-status" wcf-template-id="1" wcf-ca-template-switch="' . esc_attr( $is_activated ) . '"> ' . esc_attr( $is_activated ) . ' </button>';
446
- print '<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . esc_attr( $active_status ) . '" />';
447
- ?>
448
-
449
- </td>
450
- </tr>
451
-
452
- <tr>
453
- <th>
454
- <label for="wcf_template_name"><b><?php esc_html_e( 'Template Name:', 'woo-cart-abandonment-recovery' ); ?></b></label>
455
- </th>
456
- <td>
457
- <?php
458
- $template_name = '';
459
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->template_name ) ) {
460
- $template_name = $results->template_name;
461
- }
462
- print '<input type="text" name="wcf_template_name" id="wcf_template_name" class="wcf-ca-trigger-input" value="' . esc_attr( $template_name ) . '">';
463
- ?>
464
- </td>
465
- </tr>
466
-
467
- <tr>
468
- <th>
469
- <label for="wcf_email_subject"><b><?php esc_html_e( 'Email Subject:', 'woo-cart-abandonment-recovery' ); ?></b></label>
470
- </th>
471
- <td>
472
- <?php
473
- $subject_edit = '';
474
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_subject ) ) {
475
- $subject_edit = stripslashes( $results->email_subject );
476
- }
477
- print '<input type="text" name="wcf_email_subject" id="wcf_email_subject" class="wcf-ca-trigger-input" value="' . esc_attr( $subject_edit ) . '">';
478
- ?>
479
- </td>
480
- </tr>
481
-
482
- <tr>
483
- <th>
484
- <label for="wcf_email_body"><b><?php esc_html_e( 'Email Body:', 'woo-cart-abandonment-recovery' ); ?></b></label>
485
- </th>
486
- <td>
487
- <?php
488
- $initial_data = '';
489
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_body ) ) {
490
- $initial_data = stripslashes( $results->email_body );
491
- }
492
-
493
- wp_editor(
494
- $initial_data,
495
- 'wcf_email_body',
496
- array(
497
- 'media_buttons' => true,
498
- 'textarea_rows' => 15,
499
- 'tabindex' => 4,
500
- 'tinymce' => array(
501
- 'theme_advanced_buttons1' => 'bold,italic,underline,|,bullist,numlist,blockquote,|,link,unlink,|,spellchecker,fullscreen,|,formatselect,styleselect',
502
- ),
503
- )
504
- );
505
-
506
- ?>
507
- <?php echo stripslashes( get_option( 'wcf_email_body' ) ); //phpcs:ignore ?>
508
- </td>
509
- </tr>
510
-
511
- <tr>
512
- <th>
513
- <label for="wcf_override_global_coupon"><b><?php esc_html_e( 'Create Coupon', 'woo-cart-abandonment-recovery' ); ?></b></label>
514
- </th>
515
- <td>
516
- <?php
517
-
518
- $wcf_override_global_coupon = '';
519
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
520
- $wcf_override_global_coupon = $this->get_email_template_meta_by_key( $results->id, 'override_global_coupon' );
521
- if ( isset( $wcf_override_global_coupon->meta_value ) ) {
522
- $wcf_override_global_coupon = $wcf_override_global_coupon->meta_value ? 'checked' : '';
523
- }
524
- }
525
-
526
- print '<input ' . esc_attr( $wcf_override_global_coupon ) . ' id="wcf_override_global_coupon" name="wcf_override_global_coupon" type="checkbox" value="" /><span class="description">' . esc_html__( 'Allows you to send new coupon only for this template.', 'woo-cart-abandonment-recovery' ) . '</span>';
527
- ?>
528
- </td>
529
- </tr>
530
-
531
- <tr>
532
- <th>
533
- <label class="wcf-sub-heading" for="wcf_email_discount_type"> <?php esc_html_e( 'Discount Type', 'woo-cart-abandonment-recovery' ); ?> </label>
534
- </th>
535
- <td>
536
- <?php
537
-
538
- $wcf_email_discount_type = 'percent';
539
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
540
- $wcf_email_discount_type = $this->get_email_template_meta_by_key( $results->id, 'discount_type' );
541
- if ( isset( $wcf_email_discount_type->meta_value ) ) {
542
- $wcf_email_discount_type = $wcf_email_discount_type->meta_value;
543
- }
544
- }
545
-
546
- $dropdown_options = array(
547
- 'percent' => 'Percentage discount',
548
- 'fixed_cart' => 'Fixed cart discount',
549
- );
550
-
551
- echo '<select id="wcf_email_discount_type" name="wcf_email_discount_type">';
552
- foreach ( $dropdown_options as $key => $value ) {
553
- $is_selected = $key === $wcf_email_discount_type ? 'selected' : '';
554
- echo '<option ' . esc_attr( $is_selected ) . ' value=' . esc_attr( $key ) . '>' . esc_attr( $value ) . '</option>';
555
-
556
- }
557
- echo '</select>';
558
-
559
- ?>
560
- </td>
561
- </tr>
562
-
563
- <tr>
564
- <th>
565
- <label class="wcf-sub-heading" for="wcf_email_discount_amount"> <?php esc_html_e( 'Coupon Amount', 'woo-cart-abandonment-recovery' ); ?> </label>
566
- </th>
567
- <td>
568
- <?php
569
- $wcf_email_discount_amount = 10;
570
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
571
- $wcf_email_discount_amount = $this->get_email_template_meta_by_key( $results->id, 'coupon_amount' );
572
- if ( isset( $wcf_email_discount_amount->meta_value ) ) {
573
- $wcf_email_discount_amount = $wcf_email_discount_amount->meta_value;
574
- }
575
- }
576
- print '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="number" id="wcf_email_discount_amount" name="wcf_email_discount_amount" value="' . esc_attr( $wcf_email_discount_amount ) . '">';
577
- ?>
578
- </td>
579
- </tr>
580
-
581
- <tr>
582
- <th>
583
- <label class="wcf-sub-heading" for="wcf_email_coupon_expiry_date"> <?php esc_html_e( 'Coupon expiry date', 'woo-cart-abandonment-recovery' ); ?> </label>
584
- </th>
585
- <td>
586
- <?php
587
- $wcf_email_coupon_expiry_date = 0;
588
- $coupon_expiry_unit = 'hours';
589
-
590
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
591
- $wcf_email_coupon_expiry_date = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_date' );
592
- $wcf_email_coupon_expiry_unit = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_unit' );
593
-
594
- if ( isset( $wcf_email_coupon_expiry_date->meta_value ) ) {
595
- $wcf_email_coupon_expiry_date = $wcf_email_coupon_expiry_date->meta_value;
596
- }
597
- if ( isset( $wcf_email_coupon_expiry_unit->meta_value ) ) {
598
- $coupon_expiry_unit = $wcf_email_coupon_expiry_unit->meta_value;
599
- }
600
- }
601
- print '<input type="number" class="wcf-ca-trigger-input wcf-ca-coupon-inputs" id="wcf_email_coupon_expiry_date" name="wcf_email_coupon_expiry_date" value="' . intval( $wcf_email_coupon_expiry_date ) . '" autocomplete="off" />';
602
- $items = array(
603
- 'hours' => esc_html__( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
604
- 'days' => esc_html__( 'Day(s)', 'woo-cart-abandonment-recovery' ),
605
- );
606
- echo "<select id='wcf_coupon_expiry_unit' name='wcf_coupon_expiry_unit'>";
607
- foreach ( $items as $key => $item ) {
608
- $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
609
- echo "<option value='$key' $selected>$item</option>"; //phpcs:ignore
610
- }
611
- echo '</select>';
612
-
613
- echo " <span class='description'>" . esc_html__( 'Enter zero (0) to restrict coupon from expiring', 'woo-cart-abandonment-recovery' ) . ' </span>'
614
- ?>
615
- </td>
616
- </tr>
617
- <tr>
618
- <th>
619
- <label class="wcf-sub-heading" for="wcf_free_shipping_coupon"> <?php esc_html_e( 'Free Shipping', 'woo-cart-abandonment-recovery' ); ?> </label>
620
- </th>
621
- <td>
622
- <?php
623
-
624
- $wcf_free_shipping_coupon = '';
625
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
626
- $wcf_free_shipping_coupon = $this->get_email_template_meta_by_key( $results->id, 'free_shipping_coupon' );
627
- if ( isset( $wcf_free_shipping_coupon->meta_value ) ) {
628
- $wcf_free_shipping_coupon = $wcf_free_shipping_coupon->meta_value ? 'checked' : '';
629
- }
630
- }
631
-
632
- print '<input ' . esc_attr( $wcf_free_shipping_coupon ) . ' id="wcf_free_shipping_coupon" name="wcf_free_shipping_coupon" type="checkbox" value="" /><span class="description"> ' . esc_html__( 'Allows you to grant free shipping. A free shipping method must be enabled in your shipping zone and be set to require "a valid free shipping coupon". ', 'woo-cart-abandonment-recovery' ) . '</span>';
633
-
634
- ?>
635
- </td>
636
- </tr>
637
- <tr>
638
- <th>
639
- <label class="wcf-sub-heading" for="wcf_individual_use_only"><?php esc_html_e( 'Individual use only', 'woo-cart-abandonment-recovery' ); ?></label>
640
- </th>
641
- <td>
642
- <?php
643
-
644
- $wcf_individual_use_only = '';
645
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
646
- $wcf_individual_use_only = $this->get_email_template_meta_by_key( $results->id, 'individual_use_only' );
647
- if ( isset( $wcf_individual_use_only->meta_value ) ) {
648
- $wcf_individual_use_only = $wcf_individual_use_only->meta_value ? 'checked' : '';
649
- }
650
- }
651
-
652
- print '<input ' . esc_attr( $wcf_individual_use_only ) . ' id="wcf_individual_use_only" name="wcf_individual_use_only" type="checkbox" value="" />
653
- <span class="description">' . esc_html__( 'Check this box if the coupon cannot be used in conjunction with other coupons.', 'woo-cart-abandonment-recovery' ) . ' </span>';
654
-
655
- ?>
656
- </td>
657
- </tr>
658
- <tr>
659
- <th>
660
- <label class="wcf-sub-heading" for="wcf_apply_coupon_auto"> <?php esc_html_e( 'Auto Apply Coupon', 'woo-cart-abandonment-recovery' ); ?> </label>
661
- </th>
662
- <td>
663
- <?php
664
-
665
- $wcf_apply_coupon_auto = '';
666
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
667
- $wcf_apply_coupon_auto = $this->get_email_template_meta_by_key( $results->id, 'auto_coupon' );
668
-
669
- if ( isset( $wcf_apply_coupon_auto->meta_value ) ) {
670
- $wcf_apply_coupon_auto = $wcf_apply_coupon_auto->meta_value ? 'checked' : '';
671
- }
672
- }
673
-
674
- print '<input ' . esc_attr( $wcf_apply_coupon_auto ) . ' id="wcf_auto_coupon_apply" name="wcf_auto_coupon_apply" type="checkbox" value="" /><span class="description" > ' . esc_html__( ' Automatically add the coupon to the cart at the checkout.', 'woo-cart-abandonment-recovery' ) . ' </span>';
675
- ?>
676
- </td>
677
- </tr>
678
- <tr>
679
- <th>
680
- <label for="wcf_email_subject"><b><?php esc_html_e( 'Send This Email', 'woo-cart-abandonment-recovery' ); ?></b></label>
681
- </th>
682
- <td>
683
- <?php
684
- $frequency_edit = '';
685
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency ) ) {
686
- $frequency_edit = $results->frequency;
687
- }
688
- print '<input style="width:15%" type="number" name="wcf_email_frequency" id="wcf_email_frequency" class="wcf-ca-trigger-input" value="' . esc_attr( $frequency_edit ) . '">';
689
- ?>
690
-
691
- <select name="wcf_email_frequency_unit" id="wcf_email_frequency_unit">
692
- <?php
693
- $frequency_unit = '';
694
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency_unit ) ) {
695
- $frequency_unit = $results->frequency_unit;
696
- }
697
- $days_or_hours = array(
698
- 'MINUTE' => esc_html__( 'Minute(s)', 'woo-cart-abandonment-recovery' ),
699
- 'HOUR' => esc_html__( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
700
- 'DAY' => esc_html__( 'Day(s)', 'woo-cart-abandonment-recovery' ),
701
- );
702
- foreach ( $days_or_hours as $key => $value ) {
703
- printf(
704
- "<option %s value='%s'>%s</option>\n",
705
- selected( $key, $frequency_unit, false ),
706
- esc_attr( $key ),
707
- esc_attr( $value )
708
- );
709
- }
710
- ?>
711
- </select>
712
- <span class="description">
713
- <?php esc_html_e( 'after cart is abandoned.', 'woo-cart-abandonment-recovery' ); ?>
714
- </span>
715
-
716
-
717
- </td>
718
- </tr>
719
-
720
- <tr>
721
- <?php $current_user = wp_get_current_user(); ?>
722
- <th>
723
- <label for="wcf_email_preview"><b><?php esc_html_e( 'Send Test Email To:', 'woo-cart-abandonment-recovery' ); ?></b></label>
724
- </th>
725
- <td>
726
- <input class="wcf-ca-trigger-input" type="text" id="wcf_send_test_email" name="send_test_email" value="<?php echo esc_attr( $current_user->user_email ); ?>" class="wcf-ca-trigger-input">
727
- <input class="button" type="button" value=" <?php esc_html_e( 'Send a test email', 'woo-cart-abandonment-recovery' ); ?>" id="wcf_preview_email"/> <br/>
728
-
729
- <label id="mail_response_msg"> </label>
730
- </td>
731
- </tr>
732
-
733
- </table>
734
- </div>
735
- </div>
736
- </div>
737
- <?php wp_nonce_field( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' ); ?>
738
- <p class="submit">
739
- <?php
740
- $button_value = esc_html__( 'Save Changes', 'woo-cart-abandonment-recovery' );
741
- if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
742
- $button_value = esc_html__( 'Update Changes', 'woo-cart-abandonment-recovery' );
743
- }
744
- ?>
745
- <input type="submit" name="Submit" class="button-primary" value="<?php echo esc_attr( $button_value ); ?>"/>
746
- </p>
747
- </form>
748
- </div>
749
- <?php
750
-
751
- }
752
-
753
-
754
- /**
755
- * Sanitize email post data.
756
- *
757
- * @return array
758
- */
759
- public function sanitize_email_post_data() {
760
-
761
- $input_post_values = array(
762
- 'wcf_email_subject' => array(
763
- 'default' => '',
764
- 'sanitize' => FILTER_SANITIZE_STRING,
765
- ),
766
- 'wcf_email_body' => array(
767
- 'default' => '',
768
- 'sanitize' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
769
- ),
770
- 'wcf_template_name' => array(
771
- 'default' => '',
772
- 'sanitize' => FILTER_SANITIZE_STRING,
773
- ),
774
- 'wcf_email_frequency' => array(
775
- 'default' => 30,
776
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
777
- ),
778
- 'wcf_email_frequency_unit' => array(
779
- 'default' => 'MINUTE',
780
- 'sanitize' => FILTER_SANITIZE_STRING,
781
- ),
782
- 'wcf_activate_email_template' => array(
783
- 'default' => 0,
784
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
785
- ),
786
-
787
- 'wcf_email_discount_type' => array(
788
- 'default' => 'percent',
789
- 'sanitize' => FILTER_SANITIZE_STRING,
790
- ),
791
- 'wcf_email_discount_amount' => array(
792
- 'default' => 10,
793
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
794
- ),
795
- 'wcf_email_coupon_expiry_date' => array(
796
- 'default' => '',
797
- 'sanitize' => FILTER_SANITIZE_STRING,
798
- ),
799
- 'wcf_coupon_expiry_unit' => array(
800
- 'default' => 'hours',
801
- 'sanitize' => FILTER_SANITIZE_STRING,
802
- ),
803
- 'id' => array(
804
- 'default' => null,
805
- 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
806
- ),
807
- );
808
-
809
- $sanitized_post = array();
810
- foreach ( $input_post_values as $key => $input_post_value ) {
811
-
812
- if ( isset( $_POST[ $key ] ) ) { //phpcs:ignore
813
- $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
814
- } else {
815
- $sanitized_post[ $key ] = $input_post_value['default'];
816
- }
817
- }
818
-
819
- $sanitized_post['wcf_override_global_coupon'] = isset( $_POST['wcf_override_global_coupon'] ) ? true : false; //phpcs:ignore
820
- $sanitized_post['wcf_auto_coupon_apply'] = isset( $_POST['wcf_auto_coupon_apply'] ) ? true : false; //phpcs:ignore
821
- $sanitized_post['wcf_free_shipping_coupon'] = isset( $_POST['wcf_free_shipping_coupon'] ) ? true : false; //phpcs:ignore
822
- $sanitized_post['wcf_individual_use_only'] = isset( $_POST['wcf_individual_use_only'] ) ? true : false; //phpcs:ignore
823
- $sanitized_post['wcf_email_body'] = html_entity_decode( $sanitized_post['wcf_email_body'], ENT_COMPAT, 'UTF-8' );
824
-
825
- return $sanitized_post;
826
-
827
- }
828
-
829
-
830
- /**
831
- * Add email template callback ajax.
832
- */
833
- public function add_email_template() {
834
-
835
- $sanitized_post = $this->sanitize_email_post_data();
836
- $this->wpdb->insert(
837
- $this->cart_abandonment_template_table_name,
838
- array(
839
- 'template_name' => $sanitized_post['wcf_template_name'],
840
- 'email_subject' => $sanitized_post['wcf_email_subject'],
841
- 'email_body' => $sanitized_post['wcf_email_body'],
842
- 'frequency' => $sanitized_post['wcf_email_frequency'],
843
- 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
844
- 'is_activated' => $sanitized_post['wcf_activate_email_template'],
845
- ),
846
- array( '%s', '%s', '%s', '%d', '%s', '%d' )
847
- );
848
-
849
- $email_template_id = $this->wpdb->insert_id;
850
- $meta_data = array(
851
- 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
852
- 'discount_type' => $sanitized_post['wcf_email_discount_type'],
853
- 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
854
- 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
855
- 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
856
- 'auto_coupon' => $sanitized_post['wcf_auto_coupon_apply'],
857
- 'free_shipping_coupon' => $sanitized_post['wcf_free_shipping_coupon'],
858
- 'individual_use_only' => $sanitized_post['wcf_individual_use_only'],
859
-
860
- );
861
-
862
- foreach ( $meta_data as $mera_key => $meta_value ) {
863
- $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
864
- }
865
-
866
- $param = array(
867
- 'page' => WCF_CA_PAGE_NAME,
868
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
869
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
870
- 'id' => $email_template_id,
871
- 'wcf_ca_template_created' => 'YES',
872
- );
873
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
874
- wp_safe_redirect( $redirect_url );
875
-
876
- }
877
-
878
- /**
879
- * Edit email template callback ajax.
880
- */
881
- public function edit_email_template() {
882
- $sanitized_post = $this->sanitize_email_post_data();
883
- $email_template_id = $sanitized_post['id'];
884
-
885
- $this->wpdb->update(
886
- $this->cart_abandonment_template_table_name,
887
- array(
888
- 'template_name' => $sanitized_post['wcf_template_name'],
889
- 'email_subject' => $sanitized_post['wcf_email_subject'],
890
- 'email_body' => $sanitized_post['wcf_email_body'],
891
- 'frequency' => $sanitized_post['wcf_email_frequency'],
892
- 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
893
- 'is_activated' => $sanitized_post['wcf_activate_email_template'],
894
- ),
895
- array( 'id' => $email_template_id ),
896
- array( '%s', '%s', '%s', '%d', '%s', '%d' ),
897
- array( '%d' )
898
- );
899
-
900
- $meta_data = array(
901
- 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
902
- 'discount_type' => $sanitized_post['wcf_email_discount_type'],
903
- 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
904
- 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
905
- 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
906
- 'auto_coupon' => $sanitized_post['wcf_auto_coupon_apply'],
907
- 'free_shipping_coupon' => $sanitized_post['wcf_free_shipping_coupon'],
908
- 'individual_use_only' => $sanitized_post['wcf_individual_use_only'],
909
-
910
- );
911
- foreach ( $meta_data as $mera_key => $meta_value ) {
912
- $this->update_email_template_meta( $email_template_id, $mera_key, $meta_value );
913
- }
914
-
915
- $param = array(
916
- 'page' => WCF_CA_PAGE_NAME,
917
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
918
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
919
- 'id' => $email_template_id,
920
- 'wcf_ca_template_updated' => 'YES',
921
- );
922
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
923
-
924
- wp_safe_redirect( $redirect_url );
925
-
926
- }
927
-
928
- /**
929
- * Restore default email templates.
930
- */
931
- public function restore_email_templates() {
932
-
933
- $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
934
-
935
- if ( $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
936
-
937
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php';
938
- $db = Cartflows_Ca_Cart_Abandonment_Db::get_instance();
939
- $db->template_table_seeder( true );
940
-
941
- $param = array(
942
- 'page' => WCF_CA_PAGE_NAME,
943
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
944
- 'wcf_ca_template_restored' => 'YES',
945
- );
946
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
947
- wp_safe_redirect( $redirect_url );
948
- }
949
-
950
- }
951
-
952
- /**
953
- * Update the meta values.
954
- *
955
- * @param integer $email_template_id email template id.
956
- * @param string $meta_key meta key.
957
- * @param string $meta_value meta value.
958
- */
959
- public function update_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
960
-
961
- $template_meta = $this->get_email_template_meta_by_key( $email_template_id, $meta_key );
962
-
963
- if ( $template_meta ) {
964
- $this->wpdb->update(
965
- $this->email_templates_meta_table,
966
- array(
967
- 'meta_value' => sanitize_text_field( $meta_value ), // phpcs:ignore
968
- ),
969
- array(
970
- 'email_template_id' => $email_template_id,
971
- 'meta_key' => sanitize_text_field( $meta_key ), // phpcs:ignore
972
- )
973
- );
974
- } else {
975
- $this->add_email_template_meta( $email_template_id, $meta_key, $meta_value );
976
- }
977
-
978
- }
979
-
980
-
981
- /**
982
- * Add the meta values.
983
- *
984
- * @param integer $email_template_id email template id.
985
- * @param string $meta_key meta key.
986
- * @param string $meta_value meta value.
987
- */
988
- public function add_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
989
- $this->wpdb->insert(
990
- $this->email_templates_meta_table,
991
- array(
992
- 'email_template_id' => $email_template_id,
993
- 'meta_key' => sanitize_text_field( $meta_key ), // phpcs:ignore
994
- 'meta_value' => sanitize_text_field( $meta_value ), // phpcs:ignore
995
- )
996
- );
997
- }
998
-
999
- /**
1000
- * Get the meta values.
1001
- *
1002
- * @param integer $email_template_id email template id.
1003
- * @param string $meta_key meta key.
1004
- */
1005
- public function get_email_template_meta_by_key( $email_template_id, $meta_key ) {
1006
- return $this->wpdb->get_row(
1007
- $this->wpdb->prepare( "select * from $this->email_templates_meta_table where email_template_id = %d AND meta_key = %s", $email_template_id, $meta_key ) // phpcs:ignore
1008
- );
1009
- }
1010
-
1011
- /**
1012
- * Render email template grid.
1013
- */
1014
- public function show_email_template_data_table() {
1015
- $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
1016
- $wcf_template_list->prepare_items();
1017
- $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
1018
- ?>
1019
- <div class="wrap">
1020
- <form id="wcf-cart-abandonment-template-table" method="GET">
1021
- <input type="hidden" name="page" value="<?php echo esc_html( $page ); ?>"/>
1022
- <input type="hidden" name="action" value="<?php echo esc_html( WCF_ACTION_EMAIL_TEMPLATES ); ?>"/>
1023
- <input type="hidden" name="sub_action" value="<?php echo esc_html( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES ); ?>"/>
1024
- <?php $wcf_template_list->display(); ?>
1025
- </form>
1026
- </div>
1027
- <?php
1028
- }
1029
-
1030
- /**
1031
- * Render 'Add Email Template button'.
1032
- */
1033
- public function show_add_new_template_button() {
1034
- $param = array(
1035
- 'page' => WCF_CA_PAGE_NAME,
1036
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
1037
- 'sub_action' => WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES,
1038
- );
1039
-
1040
- $add_new_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
1041
-
1042
- $param['sub_action'] = WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES;
1043
- $restore_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
1044
-
1045
- ?>
1046
- <div class="wcf-ca-report-btn">
1047
- <div class="wcf-ca-left-report-field-group">
1048
- <a style="cursor: pointer" href="<?php echo esc_url( $add_new_template_url ); ?>" class="button-secondary"><?php esc_html_e( 'Create New Template', 'woo-cart-abandonment-recovery' ); ?></a>
1049
- </div>
1050
- <div class="wcf-ca-right-report-field-group">
1051
- <a onclick="return confirm('Are you sure to restore email templates?');" style="cursor: pointer" href="<?php echo esc_url( $restore_template_url ); ?>" class="button-secondary"><?php esc_html_e( ' Restore Default Templates', 'woo-cart-abandonment-recovery' ); ?></a>
1052
- </div>
1053
- </div>
1054
- <?php
1055
- }
1056
-
1057
- /**
1058
- * Get all active templates.
1059
- *
1060
- * @return array|object|null
1061
- */
1062
- public function fetch_all_active_templates() {
1063
- $result = $this->wpdb->get_results(
1064
- $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE is_activated = %s', true) // phpcs:ignore
1065
- );
1066
- return $result;
1067
- }
1068
-
1069
- /**
1070
- * Get specific template by id.
1071
- *
1072
- * @param integer $tmpl_id template id.
1073
- * @return array|object|void|null
1074
- */
1075
- public function get_template_by_id( $tmpl_id ) {
1076
- $result = $this->wpdb->get_row(
1077
- $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE id = %s', $tmpl_id) // phpcs:ignore
1078
- );
1079
- return $result;
1080
- }
1081
-
1082
- /**
1083
- * Get the email history.
1084
- *
1085
- * @param integer $email_history_id email history id.
1086
- * @return array|object|void|null
1087
- */
1088
- public function get_email_history_by_id( $email_history_id ) {
1089
- $result = $this->wpdb->get_row(
1090
- $this->wpdb->prepare('SELECT * FROM `' . $this->email_history_table . '` WHERE id = %s', $email_history_id) // phpcs:ignore
1091
- );
1092
- return $result;
1093
- }
1094
- }
1095
-
1096
- Cartflows_Ca_Email_Templates::get_instance();
1
+ <?php
2
+ /**
3
+ * Cart Abandonment
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ define( 'CARTFLOWS_EMAIL_TEMPLATE_DIR', CARTFLOWS_CA_DIR . 'modules/cart-abandonment/' );
9
+ define( 'CARTFLOWS_EMAIL_TEMPLATE_URL', CARTFLOWS_CA_URL . 'modules/cart-abandonment/' );
10
+
11
+ /**
12
+ * Class for analytics tracking.
13
+ */
14
+ class Cartflows_Ca_Email_Templates {
15
+
16
+
17
+
18
+ /**
19
+ * Member Variable
20
+ *
21
+ * @var object instance
22
+ */
23
+ private $wpdb;
24
+
25
+ /**
26
+ * Member Variable
27
+ *
28
+ * @var object instance
29
+ */
30
+ private static $instance;
31
+
32
+ /**
33
+ * Member Variable
34
+ *
35
+ * @var object instance
36
+ */
37
+ public $email_history_table;
38
+
39
+ /**
40
+ * Table name for email templates
41
+ *
42
+ * @var string
43
+ */
44
+ public $cart_abandonment_template_table_name;
45
+
46
+ /**
47
+ * Table name for email templates meta table
48
+ *
49
+ * @var string
50
+ */
51
+ public $email_templates_meta_table;
52
+
53
+ /**
54
+ * Initiator
55
+ */
56
+ public static function get_instance() {
57
+ if ( ! isset( self::$instance ) ) {
58
+ self::$instance = new self();
59
+ }
60
+ return self::$instance;
61
+ }
62
+
63
+
64
+
65
+
66
+
67
+ /**
68
+ * Constructor function that initializes required actions and hooks
69
+ */
70
+ public function __construct() {
71
+ $this->define_template_constants();
72
+ global $wpdb;
73
+ $this->cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
74
+ $this->email_templates_meta_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_META_TABLE;
75
+ $this->email_history_table = $wpdb->prefix . CARTFLOWS_CA_EMAIL_HISTORY_TABLE;
76
+ $this->wpdb = $wpdb;
77
+
78
+ add_action( 'admin_enqueue_scripts', __class__ . '::load_email_templates_script', 15 );
79
+ add_action( 'wp_ajax_activate_email_templates', array( $this, 'update_email_toggle_button' ) );
80
+ }
81
+
82
+
83
+
84
+
85
+ /**
86
+ * Add email template JS script.
87
+ */
88
+ public static function load_email_templates_script() {
89
+
90
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
91
+
92
+ if ( ! ( WCF_CA_PAGE_NAME === $page ) ) {
93
+ return;
94
+ }
95
+
96
+ wp_enqueue_script( 'jquery-ui-datepicker' );
97
+ wp_enqueue_style( 'jquery-ui-style' );
98
+
99
+ wp_enqueue_script(
100
+ 'cartflows-ca-email-tmpl-settings',
101
+ CARTFLOWS_CA_URL . 'admin/assets/js/admin-email-templates.js',
102
+ array( 'jquery' ),
103
+ CARTFLOWS_CA_VER,
104
+ false
105
+ );
106
+
107
+ $current_user = wp_get_current_user();
108
+ $vars = array(
109
+ 'email' => $current_user->user_email,
110
+ 'name' => $current_user->user_firstname,
111
+ 'surname' => $current_user->user_lastname,
112
+ 'phone' => get_user_meta( $current_user->ID, 'billing_phone', true ),
113
+ 'billing_company' => get_user_meta( $current_user->ID, 'billing_company', true ),
114
+ 'billing_address_1' => get_user_meta( $current_user->ID, 'billing_address_1', true ),
115
+ 'billing_address_2' => get_user_meta( $current_user->ID, 'billing_address_2', true ),
116
+ 'billing_state' => get_user_meta( $current_user->ID, 'billing_state', true ),
117
+ 'billing_postcode' => get_user_meta( $current_user->ID, 'billing_postcode', true ),
118
+ 'shipping_first_name' => $current_user->user_firstname,
119
+ 'shipping_last_name' => $current_user->user_lastname,
120
+ 'shipping_company' => get_user_meta( $current_user->ID, 'shipping_company', true ),
121
+ 'shipping_address_1' => get_user_meta( $current_user->ID, 'shipping_address_1', true ),
122
+ 'shipping_address_2' => get_user_meta( $current_user->ID, 'shipping_address_2', true ),
123
+ 'shipping_city' => get_user_meta( $current_user->ID, 'shipping_city', true ),
124
+ 'shipping_state' => get_user_meta( $current_user->ID, 'shipping_state', true ),
125
+ 'shipping_postcode' => get_user_meta( $current_user->ID, 'shipping_postcode', true ),
126
+ 'woo_currency_symbol' => get_woocommerce_currency_symbol(),
127
+ 'email_toggle_button_nonce' => wp_create_nonce( 'activate_email_templates' ),
128
+ 'admin_firstname' => __( 'Admin Firstname', 'woo-cart-abandonment-recovery' ),
129
+ 'admin_company' => __( 'Admin Company', 'woo-cart-abandonment-recovery' ),
130
+ 'abandoned_product_details_table' => __( 'Abandoned Product Details Table', 'woo-cart-abandonment-recovery' ),
131
+ 'abandoned_product_names' => __( 'Abandoned Product Names', 'woo-cart-abandonment-recovery' ),
132
+ 'cart_checkout_url' => __( 'Cart Checkout URL', 'woo-cart-abandonment-recovery' ),
133
+ 'coupon_code' => __( 'Coupon Code', 'woo-cart-abandonment-recovery' ),
134
+ 'customer_firstname' => __( 'Customer First Name', 'woo-cart-abandonment-recovery' ),
135
+ 'customer_lastname' => __( 'Customer Last Name', 'woo-cart-abandonment-recovery' ),
136
+ 'customer_full_name' => __( 'Customer Full Name', 'woo-cart-abandonment-recovery' ),
137
+ 'cart_abandonment_date' => __( 'Cart Abandonment Date', 'woo-cart-abandonment-recovery' ),
138
+ 'site_url' => __( 'Site URL', 'woo-cart-abandonment-recovery' ),
139
+ 'unsubscribe_link' => __( 'Unsubscribe Link', 'woo-cart-abandonment-recovery' ),
140
+ );
141
+ wp_localize_script( 'cartflows-ca-email-tmpl-settings', 'wcf_ca_details', $vars );
142
+
143
+ }
144
+
145
+
146
+ /**
147
+ * Update the activate email template toggle button.
148
+ */
149
+ public function update_email_toggle_button() {
150
+
151
+ check_ajax_referer( 'activate_email_templates', 'security' );
152
+ global $wpdb;
153
+ $cart_abandonment_template_table_name = $wpdb->prefix . CARTFLOWS_CA_EMAIL_TEMPLATE_TABLE;
154
+
155
+ $id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT );
156
+
157
+ $is_activated = filter_input( INPUT_POST, 'state', FILTER_SANITIZE_STRING );
158
+
159
+ $response = __( 'Something went wrong', 'woo-cart-abandonment-recovery' );
160
+ if ( ! isset( $is_activated ) || ! isset( $id ) ) {
161
+ wp_send_json_error( $response );
162
+ }
163
+
164
+ if ( $is_activated && 'on' === $is_activated ) {
165
+ $is_activated = 1;
166
+ $response = __( 'Activated', 'woo-cart-abandonment-recovery' );
167
+ } else {
168
+ $is_activated = 0;
169
+ $response = __( 'Deactivated', 'woo-cart-abandonment-recovery' );
170
+ }
171
+
172
+ $wpdb->query( $wpdb->prepare( "UPDATE {$cart_abandonment_template_table_name} SET is_activated = %d WHERE id = %d ", $is_activated, $id ), ARRAY_A ); // phpcs:ignore
173
+ wp_send_json_success( $response );
174
+
175
+ }
176
+
177
+ /**
178
+ * Initialise all the constants
179
+ */
180
+ public function define_template_constants() {
181
+ define( 'WCF_CA_PAGE_NAME', 'woo-cart-abandonment-recovery' );
182
+
183
+ define( 'WCF_CA_GENERAL_SETTINGS_SECTION', 'cartflows_cart_abandonment_settings_section' );
184
+ define( 'WCF_CA_COUPONS_SETTINGS_SECTION', 'cartflows_cart_abandonment_coupons_settings_section' );
185
+ define( 'WCF_CA_EMAIL_SETTINGS_SECTION', 'cartflows_email_template_settings_section' );
186
+ define( 'WCF_CA_COUPON_CODE_SECTION', 'cartflows_coupon_code_settings_section' );
187
+ define( 'WCF_CA_ZAPIER_SETTINGS_SECTION', 'cartflows_zapier_settings_section' );
188
+ define( 'WCF_CA_GDPR_SETTINGS_SECTION', 'cartflows_gdpr_settings_section' );
189
+
190
+ define( 'WCF_CA_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-settings' );
191
+ define( 'WCF_CA_EMAIL_SETTINGS_OPTION_GROUP', 'cartflows-cart-abandonment-email-settings' );
192
+
193
+ define( 'WCF_ACTION_EMAIL_TEMPLATES', 'email_tmpl' );
194
+
195
+ define( 'WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES', 'add_email_tmpl' );
196
+ define( 'WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES', 'edit_email_tmpl' );
197
+ define( 'WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES', 'delete_email_tmpl' );
198
+ define( 'WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES', 'clone_email_tmpl' );
199
+ define( 'WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES', 'delete_bulk_email_tmpl' );
200
+ define( 'WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES', 'save_email_template' );
201
+ define( 'WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES', 'restore_default_email_tmpl' );
202
+
203
+ define( 'WCF_SUB_ACTION_CART_ABANDONMENT_SETTINGS', 'cart_abandonment_settings' );
204
+ define( 'WCF_SUB_ACTION_EMAIL_SETTINGS', 'email_settings' );
205
+ define( 'WCF_SUB_ACTION_COUPON_CODE_SETTINGS', 'coupon_code_settings' );
206
+ define( 'WCF_SUB_ACTION_ZAPIER_SETTINGS', 'zapier_settings' );
207
+
208
+ define( 'WCF_EMAIL_TEMPLATES_NONCE', 'email_template_nonce' );
209
+
210
+ }
211
+
212
+ /**
213
+ * Show success messages for email templates.
214
+ */
215
+ public function show_messages() {
216
+
217
+ $wcf_ca_template_created = filter_input( INPUT_GET, 'wcf_ca_template_created', FILTER_SANITIZE_STRING );
218
+ $wcf_ca_template_cloned = filter_input( INPUT_GET, 'wcf_ca_template_cloned', FILTER_SANITIZE_STRING );
219
+ $wcf_ca_template_deleted = filter_input( INPUT_GET, 'wcf_ca_template_deleted', FILTER_SANITIZE_STRING );
220
+ $wcf_ca_template_updated = filter_input( INPUT_GET, 'wcf_ca_template_updated', FILTER_SANITIZE_STRING );
221
+ $wcf_ca_template_restored = filter_input( INPUT_GET, 'wcf_ca_template_restored', FILTER_SANITIZE_STRING );
222
+
223
+ ?>
224
+ <?php if ( 'YES' === $wcf_ca_template_created ) { ?>
225
+ <div id="message" class="notice notice-success is-dismissible">
226
+ <p>
227
+ <strong>
228
+ <?php esc_html_e( 'The Email Template has been successfully added.', 'woo-cart-abandonment-recovery' ); ?>
229
+ </strong>
230
+ </p>
231
+ </div>
232
+ <?php } ?>
233
+
234
+ <?php if ( 'YES' === $wcf_ca_template_cloned ) { ?>
235
+ <div id="message" class="notice notice-success is-dismissible">
236
+ <p>
237
+ <strong>
238
+ <?php esc_html_e( 'The Email Template has been cloned successfully.', 'woo-cart-abandonment-recovery' ); ?>
239
+ </strong>
240
+ </p>
241
+ </div>
242
+ <?php } ?>
243
+
244
+ <?php if ( 'YES' === $wcf_ca_template_deleted ) { ?>
245
+ <div id="message" class="notice notice-success is-dismissible">
246
+ <p>
247
+ <strong>
248
+ <?php esc_html_e( 'The Email Template has been successfully deleted.', 'woo-cart-abandonment-recovery' ); ?>
249
+ </strong>
250
+ </p>
251
+ </div>
252
+ <?php } ?>
253
+ <?php if ( 'YES' === $wcf_ca_template_updated ) { ?>
254
+ <div id="message" class="notice notice-success is-dismissible">
255
+ <p>
256
+ <strong>
257
+ <?php esc_html_e( 'The Email Template has been successfully updated.', 'woo-cart-abandonment-recovery' ); ?>
258
+ </strong>
259
+ </p>
260
+ </div>
261
+ <?php } ?>
262
+
263
+ <?php if ( 'YES' === $wcf_ca_template_restored ) { ?>
264
+ <div id="message" class="notice notice-success is-dismissible">
265
+ <p>
266
+ <strong>
267
+ <?php esc_html_e( 'Default Email Templates has been restored successfully.', 'woo-cart-abandonment-recovery' ); ?>
268
+ </strong>
269
+ </p>
270
+ </div>
271
+ <?php } ?>
272
+ <?php
273
+
274
+ }
275
+
276
+ /**
277
+ * Delete bulk email templates.
278
+ */
279
+ public function delete_bulk_templates() {
280
+ $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
281
+ $wcf_template_list->process_bulk_action();
282
+ $param = array(
283
+ 'page' => WCF_CA_PAGE_NAME,
284
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
285
+ 'wcf_ca_template_deleted' => 'YES',
286
+ );
287
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
288
+ wp_safe_redirect( $redirect_url );
289
+ }
290
+
291
+
292
+ /**
293
+ * Delete email templates.
294
+ */
295
+ public function delete_single_template() {
296
+
297
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
298
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
299
+
300
+ if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
301
+
302
+ $this->wpdb->delete(
303
+ $this->cart_abandonment_template_table_name,
304
+ array( 'id' => $id ),
305
+ '%d'
306
+ );
307
+ $param = array(
308
+ 'page' => WCF_CA_PAGE_NAME,
309
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
310
+ 'wcf_ca_template_deleted' => 'YES',
311
+ );
312
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
313
+ wp_safe_redirect( $redirect_url );
314
+
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Delete email templates.
320
+ */
321
+ public function clone_email_template() {
322
+
323
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
324
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
325
+
326
+ if ( $id && $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
327
+
328
+ $email_template = $this->get_template_by_id( $id );
329
+
330
+ $this->wpdb->insert(
331
+ $this->cart_abandonment_template_table_name,
332
+ array(
333
+ 'template_name' => sanitize_text_field( $email_template->template_name ),
334
+ 'email_subject' => sanitize_text_field( $email_template->email_subject ),
335
+ 'email_body' => $email_template->email_body,
336
+ 'frequency' => intval( sanitize_text_field( $email_template->frequency ) ),
337
+ 'frequency_unit' => sanitize_text_field( $email_template->frequency_unit ),
338
+
339
+ ),
340
+ array( '%s', '%s', '%s', '%d', '%s' )
341
+ );
342
+
343
+ $email_template_id = $this->wpdb->insert_id;
344
+ $meta_data = array(
345
+ 'override_global_coupon' => false,
346
+ 'discount_type' => 'percent',
347
+ 'coupon_amount' => 10,
348
+ 'coupon_expiry_date' => '',
349
+ 'coupon_expiry_unit' => 'hours',
350
+
351
+ );
352
+
353
+ foreach ( $meta_data as $mera_key => $meta_value ) {
354
+ $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
355
+ }
356
+
357
+ $param = array(
358
+ 'page' => WCF_CA_PAGE_NAME,
359
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
360
+ 'wcf_ca_template_cloned' => 'YES',
361
+ );
362
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
363
+ wp_safe_redirect( $redirect_url );
364
+
365
+ }
366
+ }
367
+
368
+ /**
369
+ * Get email template by id.
370
+ *
371
+ * @param int $email_tmpl_id template id.
372
+ */
373
+ public function get_email_template_by_id( $email_tmpl_id ) {
374
+
375
+ $query = 'SELECT * FROM ' . $this->cart_abandonment_template_table_name . ' WHERE id = %d ';
376
+ return $this->wpdb->get_row($this->wpdb->prepare($query, $email_tmpl_id)); // phpcs:ignore
377
+
378
+ }
379
+
380
+ /**
381
+ * Render email template add/edit form.
382
+ *
383
+ * @param string $sub_action sub_action.
384
+ */
385
+ public function render_email_template_form( $sub_action = WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES ) {
386
+
387
+ $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
388
+
389
+ if ( $id ) {
390
+ $results = $this->get_email_template_by_id( $id );
391
+ }
392
+
393
+ ?>
394
+
395
+ <div id="content">
396
+
397
+ <?php
398
+ $param = array(
399
+ 'page' => WCF_CA_PAGE_NAME,
400
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
401
+ 'sub_action' => WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES,
402
+ );
403
+ $save_template_url = esc_url( add_query_arg( $param, admin_url( '/admin.php' ) ) );
404
+ ?>
405
+
406
+ <form method="post" action="<?php echo esc_attr( $save_template_url ); ?>" id="wcf_settings">
407
+ <input type="hidden" name="sub_action" value="<?php echo esc_attr( $sub_action ); ?>"/>
408
+ <?php
409
+ $id_by = '';
410
+ if ( isset( $id ) ) {
411
+ $id_by = $id;
412
+ }
413
+ ?>
414
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id_by ); ?>"/>
415
+ <?php
416
+
417
+ $button_sub_action = 'save';
418
+ $display_message = 'Add New Email Template:';
419
+
420
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
421
+ $button_sub_action = 'update';
422
+ $display_message = 'Edit Email Template:';
423
+ }
424
+ print '<input type="hidden" name="wcf_settings_frm" value="' . esc_attr( $button_sub_action ) . '">';
425
+ ?>
426
+ <div id="poststuff">
427
+ <div> <!-- <div class="postbox" > -->
428
+ <h3><?php esc_html_e($display_message, 'woo-cart-abandonment-recovery'); // phpcs:ignore ?></h3>
429
+ <hr/>
430
+ <div>
431
+ <table class="form-table" id="addedit_template">
432
+ <tr>
433
+ <th>
434
+ <label for="wcf_email_subject"><b><?php esc_html_e( 'Activate Template now?', 'woo-cart-abandonment-recovery' ); ?></b></label>
435
+ </th>
436
+ <td>
437
+ <?php
438
+ $is_activated = '';
439
+ $active_status = 0;
440
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->is_activated ) ) {
441
+ $active_status = stripslashes( $results->is_activated );
442
+ $is_activated = $active_status ? 'on' : 'off';
443
+
444
+ }
445
+ print '<button type="button" class="wcf-ca-switch wcf-toggle-template-status" wcf-template-id="1" wcf-ca-template-switch="' . esc_attr( $is_activated ) . '"> ' . esc_attr( $is_activated ) . ' </button>';
446
+ print '<input type="hidden" name="wcf_activate_email_template" id="wcf_activate_email_template" value="' . esc_attr( $active_status ) . '" />';
447
+ ?>
448
+
449
+ </td>
450
+ </tr>
451
+
452
+ <tr>
453
+ <th>
454
+ <label for="wcf_template_name"><b><?php esc_html_e( 'Template Name:', 'woo-cart-abandonment-recovery' ); ?></b></label>
455
+ </th>
456
+ <td>
457
+ <?php
458
+ $template_name = '';
459
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->template_name ) ) {
460
+ $template_name = $results->template_name;
461
+ }
462
+ print '<input type="text" name="wcf_template_name" id="wcf_template_name" class="wcf-ca-trigger-input" value="' . esc_attr( $template_name ) . '">';
463
+ ?>
464
+ </td>
465
+ </tr>
466
+
467
+ <tr>
468
+ <th>
469
+ <label for="wcf_email_subject"><b><?php esc_html_e( 'Email Subject:', 'woo-cart-abandonment-recovery' ); ?></b></label>
470
+ </th>
471
+ <td>
472
+ <?php
473
+ $subject_edit = '';
474
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_subject ) ) {
475
+ $subject_edit = stripslashes( $results->email_subject );
476
+ }
477
+ print '<input type="text" name="wcf_email_subject" id="wcf_email_subject" class="wcf-ca-trigger-input" value="' . esc_attr( $subject_edit ) . '">';
478
+ ?>
479
+ </td>
480
+ </tr>
481
+
482
+ <tr>
483
+ <th>
484
+ <label for="wcf_email_body"><b><?php esc_html_e( 'Email Body:', 'woo-cart-abandonment-recovery' ); ?></b></label>
485
+ </th>
486
+ <td>
487
+ <?php
488
+ $initial_data = '';
489
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->email_body ) ) {
490
+ $initial_data = stripslashes( $results->email_body );
491
+ }
492
+
493
+ wp_editor(
494
+ $initial_data,
495
+ 'wcf_email_body',
496
+ array(
497
+ 'media_buttons' => true,
498
+ 'textarea_rows' => 15,
499
+ 'tabindex' => 4,
500
+ 'tinymce' => array(
501
+ 'theme_advanced_buttons1' => 'bold,italic,underline,|,bullist,numlist,blockquote,|,link,unlink,|,spellchecker,fullscreen,|,formatselect,styleselect',
502
+ ),
503
+ )
504
+ );
505
+
506
+ ?>
507
+ <?php echo stripslashes( get_option( 'wcf_email_body' ) ); //phpcs:ignore ?>
508
+ </td>
509
+ </tr>
510
+
511
+ <tr>
512
+ <th>
513
+ <label for="wcf_override_global_coupon"><b><?php esc_html_e( 'Create Coupon', 'woo-cart-abandonment-recovery' ); ?></b></label>
514
+ </th>
515
+ <td>
516
+ <?php
517
+
518
+ $wcf_override_global_coupon = '';
519
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
520
+ $wcf_override_global_coupon = $this->get_email_template_meta_by_key( $results->id, 'override_global_coupon' );
521
+ if ( isset( $wcf_override_global_coupon->meta_value ) ) {
522
+ $wcf_override_global_coupon = $wcf_override_global_coupon->meta_value ? 'checked' : '';
523
+ }
524
+ }
525
+
526
+ print '<input ' . esc_attr( $wcf_override_global_coupon ) . ' id="wcf_override_global_coupon" name="wcf_override_global_coupon" type="checkbox" value="" /><span class="description">' . esc_html__( 'Allows you to send new coupon only for this template.', 'woo-cart-abandonment-recovery' ) . '</span>';
527
+ ?>
528
+ </td>
529
+ </tr>
530
+
531
+ <tr>
532
+ <th>
533
+ <label class="wcf-sub-heading" for="wcf_email_discount_type"> <?php esc_html_e( 'Discount Type', 'woo-cart-abandonment-recovery' ); ?> </label>
534
+ </th>
535
+ <td>
536
+ <?php
537
+
538
+ $wcf_email_discount_type = 'percent';
539
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
540
+ $wcf_email_discount_type = $this->get_email_template_meta_by_key( $results->id, 'discount_type' );
541
+ if ( isset( $wcf_email_discount_type->meta_value ) ) {
542
+ $wcf_email_discount_type = $wcf_email_discount_type->meta_value;
543
+ }
544
+ }
545
+
546
+ $dropdown_options = array(
547
+ 'percent' => 'Percentage discount',
548
+ 'fixed_cart' => 'Fixed cart discount',
549
+ );
550
+
551
+ echo '<select id="wcf_email_discount_type" name="wcf_email_discount_type">';
552
+ foreach ( $dropdown_options as $key => $value ) {
553
+ $is_selected = $key === $wcf_email_discount_type ? 'selected' : '';
554
+ echo '<option ' . esc_attr( $is_selected ) . ' value=' . esc_attr( $key ) . '>' . esc_attr( $value ) . '</option>';
555
+
556
+ }
557
+ echo '</select>';
558
+
559
+ ?>
560
+ </td>
561
+ </tr>
562
+
563
+ <tr>
564
+ <th>
565
+ <label class="wcf-sub-heading" for="wcf_email_discount_amount"> <?php esc_html_e( 'Coupon Amount', 'woo-cart-abandonment-recovery' ); ?> </label>
566
+ </th>
567
+ <td>
568
+ <?php
569
+ $wcf_email_discount_amount = 10;
570
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
571
+ $wcf_email_discount_amount = $this->get_email_template_meta_by_key( $results->id, 'coupon_amount' );
572
+ if ( isset( $wcf_email_discount_amount->meta_value ) ) {
573
+ $wcf_email_discount_amount = $wcf_email_discount_amount->meta_value;
574
+ }
575
+ }
576
+ print '<input class="wcf-ca-trigger-input wcf-ca-email-inputs" type="number" id="wcf_email_discount_amount" name="wcf_email_discount_amount" value="' . esc_attr( $wcf_email_discount_amount ) . '">';
577
+ ?>
578
+ </td>
579
+ </tr>
580
+
581
+ <tr>
582
+ <th>
583
+ <label class="wcf-sub-heading" for="wcf_email_coupon_expiry_date"> <?php esc_html_e( 'Coupon expiry date', 'woo-cart-abandonment-recovery' ); ?> </label>
584
+ </th>
585
+ <td>
586
+ <?php
587
+ $wcf_email_coupon_expiry_date = 0;
588
+ $coupon_expiry_unit = 'hours';
589
+
590
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
591
+ $wcf_email_coupon_expiry_date = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_date' );
592
+ $wcf_email_coupon_expiry_unit = $this->get_email_template_meta_by_key( $results->id, 'coupon_expiry_unit' );
593
+
594
+ if ( isset( $wcf_email_coupon_expiry_date->meta_value ) ) {
595
+ $wcf_email_coupon_expiry_date = $wcf_email_coupon_expiry_date->meta_value;
596
+ }
597
+ if ( isset( $wcf_email_coupon_expiry_unit->meta_value ) ) {
598
+ $coupon_expiry_unit = $wcf_email_coupon_expiry_unit->meta_value;
599
+ }
600
+ }
601
+ print '<input type="number" class="wcf-ca-trigger-input wcf-ca-coupon-inputs" id="wcf_email_coupon_expiry_date" name="wcf_email_coupon_expiry_date" value="' . intval( $wcf_email_coupon_expiry_date ) . '" autocomplete="off" />';
602
+ $items = array(
603
+ 'hours' => esc_html__( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
604
+ 'days' => esc_html__( 'Day(s)', 'woo-cart-abandonment-recovery' ),
605
+ );
606
+ echo "<select id='wcf_coupon_expiry_unit' name='wcf_coupon_expiry_unit'>";
607
+ foreach ( $items as $key => $item ) {
608
+ $selected = ( $coupon_expiry_unit === $key ) ? 'selected="selected"' : '';
609
+ echo "<option value='$key' $selected>$item</option>"; //phpcs:ignore
610
+ }
611
+ echo '</select>';
612
+
613
+ echo " <span class='description'>" . esc_html__( 'Enter zero (0) to restrict coupon from expiring', 'woo-cart-abandonment-recovery' ) . ' </span>'
614
+ ?>
615
+ </td>
616
+ </tr>
617
+ <tr>
618
+ <th>
619
+ <label class="wcf-sub-heading" for="wcf_free_shipping_coupon"> <?php esc_html_e( 'Free Shipping', 'woo-cart-abandonment-recovery' ); ?> </label>
620
+ </th>
621
+ <td>
622
+ <?php
623
+
624
+ $wcf_free_shipping_coupon = '';
625
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
626
+ $wcf_free_shipping_coupon = $this->get_email_template_meta_by_key( $results->id, 'free_shipping_coupon' );
627
+ if ( isset( $wcf_free_shipping_coupon->meta_value ) ) {
628
+ $wcf_free_shipping_coupon = $wcf_free_shipping_coupon->meta_value ? 'checked' : '';
629
+ }
630
+ }
631
+
632
+ print '<input ' . esc_attr( $wcf_free_shipping_coupon ) . ' id="wcf_free_shipping_coupon" name="wcf_free_shipping_coupon" type="checkbox" value="" /><span class="description"> ' . esc_html__( 'Allows you to grant free shipping. A free shipping method must be enabled in your shipping zone and be set to require "a valid free shipping coupon". ', 'woo-cart-abandonment-recovery' ) . '</span>';
633
+
634
+ ?>
635
+ </td>
636
+ </tr>
637
+ <tr>
638
+ <th>
639
+ <label class="wcf-sub-heading" for="wcf_individual_use_only"><?php esc_html_e( 'Individual use only', 'woo-cart-abandonment-recovery' ); ?></label>
640
+ </th>
641
+ <td>
642
+ <?php
643
+
644
+ $wcf_individual_use_only = '';
645
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
646
+ $wcf_individual_use_only = $this->get_email_template_meta_by_key( $results->id, 'individual_use_only' );
647
+ if ( isset( $wcf_individual_use_only->meta_value ) ) {
648
+ $wcf_individual_use_only = $wcf_individual_use_only->meta_value ? 'checked' : '';
649
+ }
650
+ }
651
+
652
+ print '<input ' . esc_attr( $wcf_individual_use_only ) . ' id="wcf_individual_use_only" name="wcf_individual_use_only" type="checkbox" value="" />
653
+ <span class="description">' . esc_html__( 'Check this box if the coupon cannot be used in conjunction with other coupons.', 'woo-cart-abandonment-recovery' ) . ' </span>';
654
+
655
+ ?>
656
+ </td>
657
+ </tr>
658
+ <tr>
659
+ <th>
660
+ <label class="wcf-sub-heading" for="wcf_apply_coupon_auto"> <?php esc_html_e( 'Auto Apply Coupon', 'woo-cart-abandonment-recovery' ); ?> </label>
661
+ </th>
662
+ <td>
663
+ <?php
664
+
665
+ $wcf_apply_coupon_auto = '';
666
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results ) {
667
+ $wcf_apply_coupon_auto = $this->get_email_template_meta_by_key( $results->id, 'auto_coupon' );
668
+
669
+ if ( isset( $wcf_apply_coupon_auto->meta_value ) ) {
670
+ $wcf_apply_coupon_auto = $wcf_apply_coupon_auto->meta_value ? 'checked' : '';
671
+ }
672
+ }
673
+
674
+ print '<input ' . esc_attr( $wcf_apply_coupon_auto ) . ' id="wcf_auto_coupon_apply" name="wcf_auto_coupon_apply" type="checkbox" value="" /><span class="description" > ' . esc_html__( ' Automatically add the coupon to the cart at the checkout.', 'woo-cart-abandonment-recovery' ) . ' </span>';
675
+ ?>
676
+ </td>
677
+ </tr>
678
+ <tr>
679
+ <th>
680
+ <label for="wcf_email_subject"><b><?php esc_html_e( 'Send This Email', 'woo-cart-abandonment-recovery' ); ?></b></label>
681
+ </th>
682
+ <td>
683
+ <?php
684
+ $frequency_edit = '';
685
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency ) ) {
686
+ $frequency_edit = $results->frequency;
687
+ }
688
+ print '<input style="width:15%" type="number" name="wcf_email_frequency" id="wcf_email_frequency" class="wcf-ca-trigger-input" value="' . esc_attr( $frequency_edit ) . '">';
689
+ ?>
690
+
691
+ <select name="wcf_email_frequency_unit" id="wcf_email_frequency_unit">
692
+ <?php
693
+ $frequency_unit = '';
694
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action && $results && isset( $results->frequency_unit ) ) {
695
+ $frequency_unit = $results->frequency_unit;
696
+ }
697
+ $days_or_hours = array(
698
+ 'MINUTE' => esc_html__( 'Minute(s)', 'woo-cart-abandonment-recovery' ),
699
+ 'HOUR' => esc_html__( 'Hour(s)', 'woo-cart-abandonment-recovery' ),
700
+ 'DAY' => esc_html__( 'Day(s)', 'woo-cart-abandonment-recovery' ),
701
+ );
702
+ foreach ( $days_or_hours as $key => $value ) {
703
+ printf(
704
+ "<option %s value='%s'>%s</option>\n",
705
+ selected( $key, $frequency_unit, false ),
706
+ esc_attr( $key ),
707
+ esc_attr( $value )
708
+ );
709
+ }
710
+ ?>
711
+ </select>
712
+ <span class="description">
713
+ <?php esc_html_e( 'after cart is abandoned.', 'woo-cart-abandonment-recovery' ); ?>
714
+ </span>
715
+
716
+
717
+ </td>
718
+ </tr>
719
+
720
+ <tr>
721
+ <?php $current_user = wp_get_current_user(); ?>
722
+ <th>
723
+ <label for="wcf_email_preview"><b><?php esc_html_e( 'Send Test Email To:', 'woo-cart-abandonment-recovery' ); ?></b></label>
724
+ </th>
725
+ <td>
726
+ <input class="wcf-ca-trigger-input" type="text" id="wcf_send_test_email" name="send_test_email" value="<?php echo esc_attr( $current_user->user_email ); ?>" class="wcf-ca-trigger-input">
727
+ <input class="button" type="button" value=" <?php esc_html_e( 'Send a test email', 'woo-cart-abandonment-recovery' ); ?>" id="wcf_preview_email"/> <br/>
728
+
729
+ <label id="mail_response_msg"> </label>
730
+ </td>
731
+ </tr>
732
+
733
+ </table>
734
+ </div>
735
+ </div>
736
+ </div>
737
+ <?php wp_nonce_field( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' ); ?>
738
+ <p class="submit">
739
+ <?php
740
+ $button_value = esc_html__( 'Save Changes', 'woo-cart-abandonment-recovery' );
741
+ if ( WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES === $sub_action ) {
742
+ $button_value = esc_html__( 'Update Changes', 'woo-cart-abandonment-recovery' );
743
+ }
744
+ ?>
745
+ <input type="submit" name="Submit" class="button-primary" value="<?php echo esc_attr( $button_value ); ?>"/>
746
+ </p>
747
+ </form>
748
+ </div>
749
+ <?php
750
+
751
+ }
752
+
753
+
754
+ /**
755
+ * Sanitize email post data.
756
+ *
757
+ * @return array
758
+ */
759
+ public function sanitize_email_post_data() {
760
+
761
+ $input_post_values = array(
762
+ 'wcf_email_subject' => array(
763
+ 'default' => '',
764
+ 'sanitize' => FILTER_SANITIZE_STRING,
765
+ ),
766
+ 'wcf_email_body' => array(
767
+ 'default' => '',
768
+ 'sanitize' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
769
+ ),
770
+ 'wcf_template_name' => array(
771
+ 'default' => '',
772
+ 'sanitize' => FILTER_SANITIZE_STRING,
773
+ ),
774
+ 'wcf_email_frequency' => array(
775
+ 'default' => 30,
776
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
777
+ ),
778
+ 'wcf_email_frequency_unit' => array(
779
+ 'default' => 'MINUTE',
780
+ 'sanitize' => FILTER_SANITIZE_STRING,
781
+ ),
782
+ 'wcf_activate_email_template' => array(
783
+ 'default' => 0,
784
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
785
+ ),
786
+
787
+ 'wcf_email_discount_type' => array(
788
+ 'default' => 'percent',
789
+ 'sanitize' => FILTER_SANITIZE_STRING,
790
+ ),
791
+ 'wcf_email_discount_amount' => array(
792
+ 'default' => 10,
793
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
794
+ ),
795
+ 'wcf_email_coupon_expiry_date' => array(
796
+ 'default' => '',
797
+ 'sanitize' => FILTER_SANITIZE_STRING,
798
+ ),
799
+ 'wcf_coupon_expiry_unit' => array(
800
+ 'default' => 'hours',
801
+ 'sanitize' => FILTER_SANITIZE_STRING,
802
+ ),
803
+ 'id' => array(
804
+ 'default' => null,
805
+ 'sanitize' => FILTER_SANITIZE_NUMBER_INT,
806
+ ),
807
+ );
808
+
809
+ $sanitized_post = array();
810
+ foreach ( $input_post_values as $key => $input_post_value ) {
811
+
812
+ if ( isset( $_POST[ $key ] ) ) { //phpcs:ignore
813
+ $sanitized_post[ $key ] = filter_input( INPUT_POST, $key, $input_post_value['sanitize'] );
814
+ } else {
815
+ $sanitized_post[ $key ] = $input_post_value['default'];
816
+ }
817
+ }
818
+
819
+ $sanitized_post['wcf_override_global_coupon'] = isset( $_POST['wcf_override_global_coupon'] ) ? true : false; //phpcs:ignore
820
+ $sanitized_post['wcf_auto_coupon_apply'] = isset( $_POST['wcf_auto_coupon_apply'] ) ? true : false; //phpcs:ignore
821
+ $sanitized_post['wcf_free_shipping_coupon'] = isset( $_POST['wcf_free_shipping_coupon'] ) ? true : false; //phpcs:ignore
822
+ $sanitized_post['wcf_individual_use_only'] = isset( $_POST['wcf_individual_use_only'] ) ? true : false; //phpcs:ignore
823
+ $sanitized_post['wcf_email_body'] = html_entity_decode( $sanitized_post['wcf_email_body'], ENT_COMPAT, 'UTF-8' );
824
+
825
+ return $sanitized_post;
826
+
827
+ }
828
+
829
+
830
+ /**
831
+ * Add email template callback ajax.
832
+ */
833
+ public function add_email_template() {
834
+
835
+ $sanitized_post = $this->sanitize_email_post_data();
836
+ $this->wpdb->insert(
837
+ $this->cart_abandonment_template_table_name,
838
+ array(
839
+ 'template_name' => $sanitized_post['wcf_template_name'],
840
+ 'email_subject' => $sanitized_post['wcf_email_subject'],
841
+ 'email_body' => $sanitized_post['wcf_email_body'],
842
+ 'frequency' => $sanitized_post['wcf_email_frequency'],
843
+ 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
844
+ 'is_activated' => $sanitized_post['wcf_activate_email_template'],
845
+ ),
846
+ array( '%s', '%s', '%s', '%d', '%s', '%d' )
847
+ );
848
+
849
+ $email_template_id = $this->wpdb->insert_id;
850
+ $meta_data = array(
851
+ 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
852
+ 'discount_type' => $sanitized_post['wcf_email_discount_type'],
853
+ 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
854
+ 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
855
+ 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
856
+ 'auto_coupon' => $sanitized_post['wcf_auto_coupon_apply'],
857
+ 'free_shipping_coupon' => $sanitized_post['wcf_free_shipping_coupon'],
858
+ 'individual_use_only' => $sanitized_post['wcf_individual_use_only'],
859
+
860
+ );
861
+
862
+ foreach ( $meta_data as $mera_key => $meta_value ) {
863
+ $this->add_email_template_meta( $email_template_id, $mera_key, $meta_value );
864
+ }
865
+
866
+ $param = array(
867
+ 'page' => WCF_CA_PAGE_NAME,
868
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
869
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
870
+ 'id' => $email_template_id,
871
+ 'wcf_ca_template_created' => 'YES',
872
+ );
873
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
874
+ wp_safe_redirect( $redirect_url );
875
+
876
+ }
877
+
878
+ /**
879
+ * Edit email template callback ajax.
880
+ */
881
+ public function edit_email_template() {
882
+ $sanitized_post = $this->sanitize_email_post_data();
883
+ $email_template_id = $sanitized_post['id'];
884
+
885
+ $this->wpdb->update(
886
+ $this->cart_abandonment_template_table_name,
887
+ array(
888
+ 'template_name' => $sanitized_post['wcf_template_name'],
889
+ 'email_subject' => $sanitized_post['wcf_email_subject'],
890
+ 'email_body' => $sanitized_post['wcf_email_body'],
891
+ 'frequency' => $sanitized_post['wcf_email_frequency'],
892
+ 'frequency_unit' => $sanitized_post['wcf_email_frequency_unit'],
893
+ 'is_activated' => $sanitized_post['wcf_activate_email_template'],
894
+ ),
895
+ array( 'id' => $email_template_id ),
896
+ array( '%s', '%s', '%s', '%d', '%s', '%d' ),
897
+ array( '%d' )
898
+ );
899
+
900
+ $meta_data = array(
901
+ 'override_global_coupon' => $sanitized_post['wcf_override_global_coupon'],
902
+ 'discount_type' => $sanitized_post['wcf_email_discount_type'],
903
+ 'coupon_amount' => $sanitized_post['wcf_email_discount_amount'],
904
+ 'coupon_expiry_date' => $sanitized_post['wcf_email_coupon_expiry_date'],
905
+ 'coupon_expiry_unit' => $sanitized_post['wcf_coupon_expiry_unit'],
906
+ 'auto_coupon' => $sanitized_post['wcf_auto_coupon_apply'],
907
+ 'free_shipping_coupon' => $sanitized_post['wcf_free_shipping_coupon'],
908
+ 'individual_use_only' => $sanitized_post['wcf_individual_use_only'],
909
+
910
+ );
911
+ foreach ( $meta_data as $mera_key => $meta_value ) {
912
+ $this->update_email_template_meta( $email_template_id, $mera_key, $meta_value );
913
+ }
914
+
915
+ $param = array(
916
+ 'page' => WCF_CA_PAGE_NAME,
917
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
918
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
919
+ 'id' => $email_template_id,
920
+ 'wcf_ca_template_updated' => 'YES',
921
+ );
922
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
923
+
924
+ wp_safe_redirect( $redirect_url );
925
+
926
+ }
927
+
928
+ /**
929
+ * Restore default email templates.
930
+ */
931
+ public function restore_email_templates() {
932
+
933
+ $wpnonce = filter_input( INPUT_GET, '_wpnonce', FILTER_SANITIZE_STRING );
934
+
935
+ if ( $wpnonce && wp_verify_nonce( $wpnonce, WCF_EMAIL_TEMPLATES_NONCE ) ) {
936
+
937
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-db.php';
938
+ $db = Cartflows_Ca_Cart_Abandonment_Db::get_instance();
939
+ $db->template_table_seeder( true );
940
+
941
+ $param = array(
942
+ 'page' => WCF_CA_PAGE_NAME,
943
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
944
+ 'wcf_ca_template_restored' => 'YES',
945
+ );
946
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
947
+ wp_safe_redirect( $redirect_url );
948
+ }
949
+
950
+ }
951
+
952
+ /**
953
+ * Update the meta values.
954
+ *
955
+ * @param integer $email_template_id email template id.
956
+ * @param string $meta_key meta key.
957
+ * @param string $meta_value meta value.
958
+ */
959
+ public function update_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
960
+
961
+ $template_meta = $this->get_email_template_meta_by_key( $email_template_id, $meta_key );
962
+
963
+ if ( $template_meta ) {
964
+ $this->wpdb->update(
965
+ $this->email_templates_meta_table,
966
+ array(
967
+ 'meta_value' => sanitize_text_field( $meta_value ), // phpcs:ignore
968
+ ),
969
+ array(
970
+ 'email_template_id' => $email_template_id,
971
+ 'meta_key' => sanitize_text_field( $meta_key ), // phpcs:ignore
972
+ )
973
+ );
974
+ } else {
975
+ $this->add_email_template_meta( $email_template_id, $meta_key, $meta_value );
976
+ }
977
+
978
+ }
979
+
980
+
981
+ /**
982
+ * Add the meta values.
983
+ *
984
+ * @param integer $email_template_id email template id.
985
+ * @param string $meta_key meta key.
986
+ * @param string $meta_value meta value.
987
+ */
988
+ public function add_email_template_meta( $email_template_id, $meta_key, $meta_value ) {
989
+ $this->wpdb->insert(
990
+ $this->email_templates_meta_table,
991
+ array(
992
+ 'email_template_id' => $email_template_id,
993
+ 'meta_key' => sanitize_text_field( $meta_key ), // phpcs:ignore
994
+ 'meta_value' => sanitize_text_field( $meta_value ), // phpcs:ignore
995
+ )
996
+ );
997
+ }
998
+
999
+ /**
1000
+ * Get the meta values.
1001
+ *
1002
+ * @param integer $email_template_id email template id.
1003
+ * @param string $meta_key meta key.
1004
+ */
1005
+ public function get_email_template_meta_by_key( $email_template_id, $meta_key ) {
1006
+ return $this->wpdb->get_row(
1007
+ $this->wpdb->prepare( "select * from $this->email_templates_meta_table where email_template_id = %d AND meta_key = %s", $email_template_id, $meta_key ) // phpcs:ignore
1008
+ );
1009
+ }
1010
+
1011
+ /**
1012
+ * Render email template grid.
1013
+ */
1014
+ public function show_email_template_data_table() {
1015
+ $wcf_template_list = new Cartflows_Ca_Email_Templates_Table();
1016
+ $wcf_template_list->prepare_items();
1017
+ $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
1018
+ ?>
1019
+ <div class="wrap">
1020
+ <form id="wcf-cart-abandonment-template-table" method="GET">
1021
+ <input type="hidden" name="page" value="<?php echo esc_html( $page ); ?>"/>
1022
+ <input type="hidden" name="action" value="<?php echo esc_html( WCF_ACTION_EMAIL_TEMPLATES ); ?>"/>
1023
+ <input type="hidden" name="sub_action" value="<?php echo esc_html( WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES ); ?>"/>
1024
+ <?php $wcf_template_list->display(); ?>
1025
+ </form>
1026
+ </div>
1027
+ <?php
1028
+ }
1029
+
1030
+ /**
1031
+ * Render 'Add Email Template button'.
1032
+ */
1033
+ public function show_add_new_template_button() {
1034
+ $param = array(
1035
+ 'page' => WCF_CA_PAGE_NAME,
1036
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
1037
+ 'sub_action' => WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES,
1038
+ );
1039
+
1040
+ $add_new_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
1041
+
1042
+ $param['sub_action'] = WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES;
1043
+ $restore_template_url = wp_nonce_url( add_query_arg( $param, admin_url( '/admin.php' ) ), WCF_EMAIL_TEMPLATES_NONCE );
1044
+
1045
+ ?>
1046
+ <div class="wcf-ca-report-btn">
1047
+ <div class="wcf-ca-left-report-field-group">
1048
+ <a style="cursor: pointer" href="<?php echo esc_url( $add_new_template_url ); ?>" class="button-secondary"><?php esc_html_e( 'Create New Template', 'woo-cart-abandonment-recovery' ); ?></a>
1049
+ </div>
1050
+ <div class="wcf-ca-right-report-field-group">
1051
+ <a onclick="return confirm('Are you sure to restore email templates?');" style="cursor: pointer" href="<?php echo esc_url( $restore_template_url ); ?>" class="button-secondary"><?php esc_html_e( ' Restore Default Templates', 'woo-cart-abandonment-recovery' ); ?></a>
1052
+ </div>
1053
+ </div>
1054
+ <?php
1055
+ }
1056
+
1057
+ /**
1058
+ * Get all active templates.
1059
+ *
1060
+ * @return array|object|null
1061
+ */
1062
+ public function fetch_all_active_templates() {
1063
+ $result = $this->wpdb->get_results(
1064
+ $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE is_activated = %s', true) // phpcs:ignore
1065
+ );
1066
+ return $result;
1067
+ }
1068
+
1069
+ /**
1070
+ * Get specific template by id.
1071
+ *
1072
+ * @param integer $tmpl_id template id.
1073
+ * @return array|object|void|null
1074
+ */
1075
+ public function get_template_by_id( $tmpl_id ) {
1076
+ $result = $this->wpdb->get_row(
1077
+ $this->wpdb->prepare('SELECT * FROM `' . $this->cart_abandonment_template_table_name . '` WHERE id = %s', $tmpl_id) // phpcs:ignore
1078
+ );
1079
+ return $result;
1080
+ }
1081
+
1082
+ /**
1083
+ * Get the email history.
1084
+ *
1085
+ * @param integer $email_history_id email history id.
1086
+ * @return array|object|void|null
1087
+ */
1088
+ public function get_email_history_by_id( $email_history_id ) {
1089
+ $result = $this->wpdb->get_row(
1090
+ $this->wpdb->prepare('SELECT * FROM `' . $this->email_history_table . '` WHERE id = %s', $email_history_id) // phpcs:ignore
1091
+ );
1092
+ return $result;
1093
+ }
1094
+ }
1095
+
1096
+ Cartflows_Ca_Email_Templates::get_instance();
modules/cart-abandonment/class-cartflows-ca-module-loader.php CHANGED
@@ -1,62 +1,62 @@
1
- <?php
2
- /**
3
- * Cart Abandonment DB
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- /**
9
- * Cart Abandonment DB class.
10
- */
11
- class Cartflows_Ca_Module_Loader {
12
-
13
-
14
-
15
- /**
16
- * Member Variable
17
- *
18
- * @var object instance
19
- */
20
- private static $instance;
21
-
22
- /**
23
- * Initiator
24
- */
25
- public static function get_instance() {
26
- if ( ! isset( self::$instance ) ) {
27
- self::$instance = new self();
28
- }
29
- return self::$instance;
30
- }
31
-
32
- /**
33
- * Constructor
34
- */
35
- public function __construct() {
36
-
37
- $this->load_module_files();
38
- }
39
-
40
-
41
- /**
42
- * Load required files for module.
43
- */
44
- private function load_module_files() {
45
-
46
- /* Cart abandonment templates class */
47
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-email-templates.php';
48
-
49
- /* Cart abandonment templates table */
50
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-email-templates-table.php';
51
-
52
- /* Cart abandonment tracking */
53
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php';
54
-
55
- /* Cart abandonment tracking table */
56
- include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php';
57
-
58
- }
59
-
60
- }
61
-
62
- Cartflows_Ca_Module_Loader::get_instance();
1
+ <?php
2
+ /**
3
+ * Cart Abandonment DB
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ /**
9
+ * Cart Abandonment DB class.
10
+ */
11
+ class Cartflows_Ca_Module_Loader {
12
+
13
+
14
+
15
+ /**
16
+ * Member Variable
17
+ *
18
+ * @var object instance
19
+ */
20
+ private static $instance;
21
+
22
+ /**
23
+ * Initiator
24
+ */
25
+ public static function get_instance() {
26
+ if ( ! isset( self::$instance ) ) {
27
+ self::$instance = new self();
28
+ }
29
+ return self::$instance;
30
+ }
31
+
32
+ /**
33
+ * Constructor
34
+ */
35
+ public function __construct() {
36
+
37
+ $this->load_module_files();
38
+ }
39
+
40
+
41
+ /**
42
+ * Load required files for module.
43
+ */
44
+ private function load_module_files() {
45
+
46
+ /* Cart abandonment templates class */
47
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-email-templates.php';
48
+
49
+ /* Cart abandonment templates table */
50
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-email-templates-table.php';
51
+
52
+ /* Cart abandonment tracking */
53
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment.php';
54
+
55
+ /* Cart abandonment tracking table */
56
+ include_once CARTFLOWS_CA_DIR . 'modules/cart-abandonment/class-cartflows-ca-cart-abandonment-table.php';
57
+
58
+ }
59
+
60
+ }
61
+
62
+ Cartflows_Ca_Module_Loader::get_instance();
modules/cart-abandonment/includes/admin/cartflows-ca-single-report-details.php CHANGED
@@ -1,249 +1,247 @@
1
- <?php
2
- /**
3
- * Cartflows view for single cart abandonment report details.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- ?>
9
-
10
-
11
- <div class="wcf-ca-report-btn">
12
- <div class="wcf-ca-left-report-field-group">
13
- <?php
14
- if ( wp_get_referer() ) {
15
- $back_link = wp_get_referer();
16
- } else {
17
- $back_link = add_query_arg(
18
- array(
19
- 'page' => WCF_CA_PAGE_NAME,
20
- 'action' => WCF_ACTION_REPORTS,
21
- ),
22
- admin_url( '/admin.php' )
23
- );
24
- }
25
- ?>
26
- <a href="<?php echo esc_attr( $back_link ); ?>" class="button button-secondary back-button"><span
27
- class="dashicons dashicons-arrow-left"></span> <?php esc_html_e( 'Back to Reports', 'woo-cart-abandonment-recovery' ); ?> </a>
28
- </div>
29
- </div>
30
-
31
- <!-- First panel Start -->
32
- <div class="wcf-ca-panel">
33
- <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-right">
34
- <div class="wcf-ca-email-data">
35
-
36
- <div class="wcf-ca-report-btn" style="padding: 0px">
37
- <div class="wcf-ca-left-report-field-group">
38
- <h2> <?php esc_html_e( 'Email Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
39
- </div>
40
- <div class="wcf-ca-right-report-field-group">
41
-
42
- <?php if ( WCF_CART_ABANDONED_ORDER === $details->order_status && ! $details->unsubscribed ) : ?>
43
- <?php add_thickbox(); ?>
44
- <div id="wcf-ca-confirm-email-reschedule" style="display:none;">
45
- <div style="text-align:center;">
46
- <p>
47
- <?php
48
- esc_html_e(
49
- 'All new activated emails will be reschedule for this abandoned order.New emails will
50
- be sent to user according to schedule time.',
51
- 'woo-cart-abandonment-recovery'
52
- );
53
- ?>
54
- </p>
55
- <p>
56
- <strong><?php esc_html_e( 'Are your sure?', 'woo-cart-abandonment-recovery' ); ?></strong>
57
- </p>
58
- <p>
59
- <button onclick="window.location.search += '&sub_action=<?php echo esc_attr( WCF_SUB_ACTION_REPORTS_RESCHEDULE ); ?>';"
60
- class="button button-secondary"> <?php esc_html_e( 'Reschedule', 'woo-cart-abandonment-recovery' ); ?>
61
- </button>
62
- <button type="button"
63
- onclick='document.getElementById("TB_closeWindowButton").click()'
64
- class="button button-secondary"> <?php esc_html_e( 'Close', 'woo-cart-abandonment-recovery' ); ?>
65
- </button>
66
- </p>
67
- </div>
68
- </div>
69
- <a name="<?php esc_html_e( 'Do you really want to reschedule emails?', 'woo-cart-abandonment-recovery' ); ?>" href="#TB_inline?&width=500&height=200&inlineId=wcf-ca-confirm-email-reschedule" class="thickbox button button-secondary"> <?php esc_html_e( 'Reschedule Emails', 'woo-cart-abandonment-recovery' ); ?> </a>
70
- <?php endif; ?>
71
- </div>
72
- </div>
73
-
74
- <?php if ( empty( $scheduled_emails ) ) : ?>
75
- <div style="text-align: center;"><strong> <?php esc_html_e( ' No Email Scheduled.', 'woo-cart-abandonment-recovery' ); ?></strong>
76
- </div>
77
- <?php else : ?>
78
- <table cellpadding="15" cellspacing="0" class="wcf-table wcf-table-striped fixed posts">
79
- <thead>
80
- <tr>
81
-
82
- <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Scheduled Template', 'woo-cart-abandonment-recovery' ); ?></th>
83
- <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Subject', 'woo-cart-abandonment-recovery' ); ?></th>
84
- <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Coupon', 'woo-cart-abandonment-recovery' ); ?></th>
85
- <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Sent', 'woo-cart-abandonment-recovery' ); ?></th>
86
- <th class="wcf-ca-report-table-row"><span class="dashicons dashicons-clock"></span> <?php esc_html_e( 'Scheduled At', 'woo-cart-abandonment-recovery' ); ?>
87
- </th>
88
-
89
- </tr>
90
- </thead>
91
-
92
- <tbody>
93
- <?php foreach ( $scheduled_emails as $scheduled_email ) : ?>
94
-
95
- <?php
96
- $email_tmpl_url = wp_nonce_url(
97
- add_query_arg(
98
- array(
99
- 'page' => WCF_CA_PAGE_NAME,
100
- 'action' => WCF_ACTION_EMAIL_TEMPLATES,
101
- 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
102
- 'id' => $scheduled_email->template_id,
103
- ),
104
- admin_url( '/admin.php' )
105
- ),
106
- WCF_EMAIL_TEMPLATES_NONCE
107
- );
108
-
109
-
110
-
111
- switch ( $scheduled_email->email_sent ) {
112
- case 0:
113
- if ( $details->unsubscribed ) {
114
- $icon = '<span class="dashicons dashicons-minus"></span>';
115
- $title_text = esc_html__( 'The email has been unsubscribed and won\'t be sent further.', 'woo-cart-abandonment-recovery' );
116
- } else {
117
- $icon = '<span class="dashicons dashicons-no"></span>';
118
- $title_text = esc_html__( 'Email is in the queue and will be sent at the scheduled time.', 'woo-cart-abandonment-recovery' );
119
- }
120
- break;
121
- case 1:
122
- $icon = '<span class="dashicons dashicons-yes wp-ui-text-highlight" ></span>';
123
- $title_text = esc_html__( 'The email has been sent.', 'woo-cart-abandonment-recovery' );
124
- break;
125
- case -1:
126
- $icon = '<span class="dashicons dashicons-dismiss wp-ui-text-highlight" ></span>';
127
- $title_text = esc_html__( 'The email has been unscheduled due to the complete order and won\'t be sent further.', 'woo-cart-abandonment-recovery' );
128
- break;
129
- }
130
-
131
-
132
- $scheduled_time = gmdate( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $scheduled_email->scheduled_time ) );
133
- ?>
134
-
135
- <tr class="wcf-ca-report-table-row">
136
- <td class="wcf-ca-report-table-row"><a
137
- href="<?php echo esc_url( $email_tmpl_url ); ?>"
138
- class="wp-ui-text-highlight"> <?php echo esc_attr( $scheduled_email->template_name ); ?> </a>
139
- </td>
140
- <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_email->email_subject ); ?> </td>
141
- <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_email->coupon_code ? $scheduled_email->coupon_code : '--' ); ?> </td>
142
- <td class="wcf-ca-report-table-row wcf-ca-icon-row"> <?php echo( $icon ); //phpcs:ignore ?>
143
- <span class="wcf-ca-tooltip-text"><?php echo esc_attr( $title_text ); ?></span>
144
- </td>
145
- <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_time ); ?> </td>
146
- </tr>
147
- <?php endforeach; ?>
148
- </tbody>
149
- </table>
150
- <?php endif; ?>
151
-
152
- </div>
153
- </div>
154
-
155
- <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-left">
156
- <div class="wcf-ca-user-detail ">
157
-
158
- <div class="wcf-ca-report-btn" style="padding: 0px">
159
- <div class="wcf-ca-left-report-field-group">
160
- <h2> <?php esc_html_e( 'User Address Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
161
- </div>
162
- <div class="wcf-ca-right-report-field-group">
163
- <?php if ( $details->unsubscribed ) : ?>
164
- <span class="wcf-ca-tag"> <?php esc_html_e( 'Unsubscribed', 'woo-cart-abandonment-recovery' ); ?> </span>
165
- <?php endif; ?>
166
-
167
- <span class="wcf-ca-tag"> <?php echo esc_attr( ucfirst( $details->order_status ) ); ?> </span>
168
- </div>
169
- </div>
170
-
171
- <div class="wcf-ca-user-address wcf-pull-left">
172
- <h3> <?php esc_html_e( 'Billing Address', 'woo-cart-abandonment-recovery' ); ?> </h3>
173
- <p><strong> <?php esc_html_e( 'Name', 'woo-cart-abandonment-recovery' ); ?> </strong>
174
- <?php echo esc_attr( $user_details->wcf_first_name . ' ' . $user_details->wcf_last_name ); ?> </p>
175
- <p>
176
- <strong> <?php esc_html_e( 'Email address', 'woo-cart-abandonment-recovery' ); ?> </strong>
177
- <a href="mailto:<?php echo esc_attr( $details->email ); ?>"><?php echo esc_attr( $details->email ); ?></a>
178
- </p>
179
-
180
- <p>
181
- <strong> <?php esc_html_e( 'Phone', 'woo-cart-abandonment-recovery' ); ?> </strong>
182
- <a href="tel:<?php echo esc_attr( $user_details->wcf_phone_number ); ?>"><?php echo esc_attr( $user_details->wcf_phone_number ); ?></a>
183
- </p>
184
-
185
- <p>
186
- <strong> <?php esc_html_e( 'Address 1:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_address_1 ); ?>
187
- </p>
188
- <p>
189
- <strong> <?php esc_html_e( 'Address 2:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_address_2 ); ?>
190
- </p>
191
- <p>
192
- <strong> <?php esc_html_e( 'Country, City:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_location ); ?>
193
- </p>
194
- <p>
195
- <strong> <?php esc_html_e( 'State:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_state ); ?>
196
- </p>
197
-
198
- <p>
199
- <strong> <?php esc_html_e( 'Postcode:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_postcode ); ?>
200
- </p>
201
- </div>
202
-
203
- <div class="wcf-ca-user-address wcf-pull-left">
204
- <h3> <?php esc_html_e( 'Shipping Address', 'woo-cart-abandonment-recovery' ); ?> </h3>
205
- <p>
206
- <strong> <?php esc_html_e( 'Address 1:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_address_1 ); ?>
207
- </p>
208
- <p>
209
- <strong> <?php esc_html_e( 'Address 2:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_address_2 ); ?>
210
- </p>
211
- <p>
212
- <strong> <?php esc_html_e( 'City:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_city ); ?>
213
- </p>
214
- <p>
215
- <strong> <?php esc_html_e( 'State:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_state ); ?>
216
- </p>
217
- <p>
218
- <strong> <?php esc_html_e( 'Country:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_country ); ?>
219
- </p>
220
- <p>
221
- <strong> <?php esc_html_e( 'Postcode:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_postcode ); ?>
222
- </p>
223
- <p>
224
- <?php
225
- $cart_abandonment = Cartflows_Ca_Cart_Abandonment::get_instance();
226
- $token_data = array( 'wcf_session_id' => $details->session_id );
227
- ?>
228
- <strong> <a target="_blank" href=" <?php echo $cart_abandonment->get_checkout_url( $details->checkout_id, $token_data ); //phpcs:ignore?> ">
229
- <?php esc_html_e( 'Checkout Link', 'woo-cart-abandonment-recovery' ); ?>
230
- </a>
231
- </strong>
232
- </p>
233
- </div>
234
-
235
- </div>
236
- </div>
237
- </div>
238
- <!-- First panel closed -->
239
-
240
- <!-- Second panel Start -->
241
- <div class="wcf-ca-panel">
242
- <div class="wcf-ca-column wcf-ca-column-one">
243
- <div class="wcf-ca-user-order">
244
- <h2> <?php esc_html_e( 'User Order Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
245
- <?php echo( $this->get_admin_product_block( $details->cart_contents, $details->cart_total ) ); //phpcs:ignore ?>
246
- </div>
247
- </div>
248
- </div>
249
- <!-- Second panel closed -->
1
+ <?php
2
+ /**
3
+ * Cartflows view for single cart abandonment report details.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ ?>
9
+
10
+
11
+ <div class="wcf-ca-report-btn">
12
+ <div class="wcf-ca-left-report-field-group">
13
+ <?php
14
+ if ( wp_get_referer() ) {
15
+ $back_link = wp_get_referer();
16
+ } else {
17
+ $back_link = add_query_arg(
18
+ array(
19
+ 'page' => WCF_CA_PAGE_NAME,
20
+ 'action' => WCF_ACTION_REPORTS,
21
+ ),
22
+ admin_url( '/admin.php' )
23
+ );
24
+ }
25
+ ?>
26
+ <a href="<?php echo esc_attr( $back_link ); ?>" class="button button-secondary back-button"><span
27
+ class="dashicons dashicons-arrow-left"></span> <?php esc_html_e( 'Back to Reports', 'woo-cart-abandonment-recovery' ); ?> </a>
28
+ </div>
29
+ </div>
30
+
31
+ <!-- First panel Start -->
32
+ <div class="wcf-ca-panel">
33
+ <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-right">
34
+ <div class="wcf-ca-email-data">
35
+
36
+ <div class="wcf-ca-report-btn" style="padding: 0px">
37
+ <div class="wcf-ca-left-report-field-group">
38
+ <h2> <?php esc_html_e( 'Email Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
39
+ </div>
40
+ <div class="wcf-ca-right-report-field-group">
41
+
42
+ <?php if ( WCF_CART_ABANDONED_ORDER === $details->order_status && ! $details->unsubscribed ) : ?>
43
+ <?php add_thickbox(); ?>
44
+ <div id="wcf-ca-confirm-email-reschedule" style="display:none;">
45
+ <div style="text-align:center;">
46
+ <p>
47
+ <?php
48
+ esc_html_e(
49
+ 'All new activated emails will be reschedule for this abandoned order. New emails will be sent to user according to schedule time.', 'woo-cart-abandonment-recovery'
50
+ );
51
+ ?>
52
+ </p>
53
+ <p>
54
+ <strong><?php esc_html_e( 'Are your sure?', 'woo-cart-abandonment-recovery' ); ?></strong>
55
+ </p>
56
+ <p>
57
+ <button onclick="window.location.search += '&sub_action=<?php echo esc_attr( WCF_SUB_ACTION_REPORTS_RESCHEDULE ); ?>';"
58
+ class="button button-secondary"> <?php esc_html_e( 'Reschedule', 'woo-cart-abandonment-recovery' ); ?>
59
+ </button>
60
+ <button type="button"
61
+ onclick='document.getElementById("TB_closeWindowButton").click()'
62
+ class="button button-secondary"> <?php esc_html_e( 'Close', 'woo-cart-abandonment-recovery' ); ?>
63
+ </button>
64
+ </p>
65
+ </div>
66
+ </div>
67
+ <a name="<?php esc_html_e( 'Do you really want to reschedule emails?', 'woo-cart-abandonment-recovery' ); ?>" href="#TB_inline?&width=500&height=200&inlineId=wcf-ca-confirm-email-reschedule" class="thickbox button button-secondary"> <?php esc_html_e( 'Reschedule Emails', 'woo-cart-abandonment-recovery' ); ?> </a>
68
+ <?php endif; ?>
69
+ </div>
70
+ </div>
71
+
72
+ <?php if ( empty( $scheduled_emails ) ) : ?>
73
+ <div style="text-align: center;"><strong> <?php esc_html_e( ' No Email Scheduled.', 'woo-cart-abandonment-recovery' ); ?></strong>
74
+ </div>
75
+ <?php else : ?>
76
+ <table cellpadding="15" cellspacing="0" class="wcf-table wcf-table-striped fixed posts">
77
+ <thead>
78
+ <tr>
79
+
80
+ <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Scheduled Template', 'woo-cart-abandonment-recovery' ); ?></th>
81
+ <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Subject', 'woo-cart-abandonment-recovery' ); ?></th>
82
+ <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Coupon', 'woo-cart-abandonment-recovery' ); ?></th>
83
+ <th class="wcf-ca-report-table-row"> <?php esc_html_e( 'Email Sent', 'woo-cart-abandonment-recovery' ); ?></th>
84
+ <th class="wcf-ca-report-table-row"><span class="dashicons dashicons-clock"></span> <?php esc_html_e( 'Scheduled At', 'woo-cart-abandonment-recovery' ); ?>
85
+ </th>
86
+
87
+ </tr>
88
+ </thead>
89
+
90
+ <tbody>
91
+ <?php foreach ( $scheduled_emails as $scheduled_email ) : ?>
92
+
93
+ <?php
94
+ $email_tmpl_url = wp_nonce_url(
95
+ add_query_arg(
96
+ array(
97
+ 'page' => WCF_CA_PAGE_NAME,
98
+ 'action' => WCF_ACTION_EMAIL_TEMPLATES,
99
+ 'sub_action' => WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES,
100
+ 'id' => $scheduled_email->template_id,
101
+ ),
102
+ admin_url( '/admin.php' )
103
+ ),
104
+ WCF_EMAIL_TEMPLATES_NONCE
105
+ );
106
+
107
+
108
+
109
+ switch ( $scheduled_email->email_sent ) {
110
+ case 0:
111
+ if ( $details->unsubscribed ) {
112
+ $icon = '<span class="dashicons dashicons-minus"></span>';
113
+ $title_text = esc_html__( 'The email has been unsubscribed and won\'t be sent further.', 'woo-cart-abandonment-recovery' );
114
+ } else {
115
+ $icon = '<span class="dashicons dashicons-no"></span>';
116
+ $title_text = esc_html__( 'Email is in the queue and will be sent at the scheduled time.', 'woo-cart-abandonment-recovery' );
117
+ }
118
+ break;
119
+ case 1:
120
+ $icon = '<span class="dashicons dashicons-yes wp-ui-text-highlight" ></span>';
121
+ $title_text = esc_html__( 'The email has been sent.', 'woo-cart-abandonment-recovery' );
122
+ break;
123
+ case -1:
124
+ $icon = '<span class="dashicons dashicons-dismiss wp-ui-text-highlight" ></span>';
125
+ $title_text = esc_html__( 'The email has been unscheduled due to the complete order and won\'t be sent further.', 'woo-cart-abandonment-recovery' );
126
+ break;
127
+ }
128
+
129
+
130
+ $scheduled_time = gmdate( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $scheduled_email->scheduled_time ) );
131
+ ?>
132
+
133
+ <tr class="wcf-ca-report-table-row">
134
+ <td class="wcf-ca-report-table-row"><a
135
+ href="<?php echo esc_url( $email_tmpl_url ); ?>"
136
+ class="wp-ui-text-highlight"> <?php echo esc_attr( $scheduled_email->template_name ); ?> </a>
137
+ </td>
138
+ <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_email->email_subject ); ?> </td>
139
+ <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_email->coupon_code ? $scheduled_email->coupon_code : '--' ); ?> </td>
140
+ <td class="wcf-ca-report-table-row wcf-ca-icon-row"> <?php echo( $icon ); //phpcs:ignore ?>
141
+ <span class="wcf-ca-tooltip-text"><?php echo esc_attr( $title_text ); ?></span>
142
+ </td>
143
+ <td class="wcf-ca-report-table-row"> <?php echo esc_attr( $scheduled_time ); ?> </td>
144
+ </tr>
145
+ <?php endforeach; ?>
146
+ </tbody>
147
+ </table>
148
+ <?php endif; ?>
149
+
150
+ </div>
151
+ </div>
152
+
153
+ <div class="wcf-ca-column wcf-ca-column-two wcf-ca-margin-left">
154
+ <div class="wcf-ca-user-detail ">
155
+
156
+ <div class="wcf-ca-report-btn" style="padding: 0px">
157
+ <div class="wcf-ca-left-report-field-group">
158
+ <h2> <?php esc_html_e( 'User Address Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
159
+ </div>
160
+ <div class="wcf-ca-right-report-field-group">
161
+ <?php if ( $details->unsubscribed ) : ?>
162
+ <span class="wcf-ca-tag"> <?php esc_html_e( 'Unsubscribed', 'woo-cart-abandonment-recovery' ); ?> </span>
163
+ <?php endif; ?>
164
+
165
+ <span class="wcf-ca-tag"> <?php echo esc_attr( ucfirst( $details->order_status ) ); ?> </span>
166
+ </div>
167
+ </div>
168
+
169
+ <div class="wcf-ca-user-address wcf-pull-left">
170
+ <h3> <?php esc_html_e( 'Billing Address', 'woo-cart-abandonment-recovery' ); ?> </h3>
171
+ <p><strong> <?php esc_html_e( 'Name', 'woo-cart-abandonment-recovery' ); ?> </strong>
172
+ <?php echo esc_attr( $user_details->wcf_first_name . ' ' . $user_details->wcf_last_name ); ?> </p>
173
+ <p>
174
+ <strong> <?php esc_html_e( 'Email address', 'woo-cart-abandonment-recovery' ); ?> </strong>
175
+ <a href="mailto:<?php echo esc_attr( $details->email ); ?>"><?php echo esc_attr( $details->email ); ?></a>
176
+ </p>
177
+
178
+ <p>
179
+ <strong> <?php esc_html_e( 'Phone', 'woo-cart-abandonment-recovery' ); ?> </strong>
180
+ <a href="tel:<?php echo esc_attr( $user_details->wcf_phone_number ); ?>"><?php echo esc_attr( $user_details->wcf_phone_number ); ?></a>
181
+ </p>
182
+
183
+ <p>
184
+ <strong> <?php esc_html_e( 'Address 1:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_address_1 ); ?>
185
+ </p>
186
+ <p>
187
+ <strong> <?php esc_html_e( 'Address 2:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_address_2 ); ?>
188
+ </p>
189
+ <p>
190
+ <strong> <?php esc_html_e( 'Country, City:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_location ); ?>
191
+ </p>
192
+ <p>
193
+ <strong> <?php esc_html_e( 'State:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_state ); ?>
194
+ </p>
195
+
196
+ <p>
197
+ <strong> <?php esc_html_e( 'Postcode:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_billing_postcode ); ?>
198
+ </p>
199
+ </div>
200
+
201
+ <div class="wcf-ca-user-address wcf-pull-left">
202
+ <h3> <?php esc_html_e( 'Shipping Address', 'woo-cart-abandonment-recovery' ); ?> </h3>
203
+ <p>
204
+ <strong> <?php esc_html_e( 'Address 1:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_address_1 ); ?>
205
+ </p>
206
+ <p>
207
+ <strong> <?php esc_html_e( 'Address 2:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_address_2 ); ?>
208
+ </p>
209
+ <p>
210
+ <strong> <?php esc_html_e( 'City:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_city ); ?>
211
+ </p>
212
+ <p>
213
+ <strong> <?php esc_html_e( 'State:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_state ); ?>
214
+ </p>
215
+ <p>
216
+ <strong> <?php esc_html_e( 'Country:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_country ); ?>
217
+ </p>
218
+ <p>
219
+ <strong> <?php esc_html_e( 'Postcode:', 'woo-cart-abandonment-recovery' ); ?> </strong> <?php echo esc_attr( $user_details->wcf_shipping_postcode ); ?>
220
+ </p>
221
+ <p>
222
+ <?php
223
+ $cart_abandonment = Cartflows_Ca_Cart_Abandonment::get_instance();
224
+ $token_data = array( 'wcf_session_id' => $details->session_id );
225
+ ?>
226
+ <strong> <a target="_blank" href=" <?php echo $cart_abandonment->get_checkout_url( $details->checkout_id, $token_data ); //phpcs:ignore?> ">
227
+ <?php esc_html_e( 'Checkout Link', 'woo-cart-abandonment-recovery' ); ?>
228
+ </a>
229
+ </strong>
230
+ </p>
231
+ </div>
232
+
233
+ </div>
234
+ </div>
235
+ </div>
236
+ <!-- First panel closed -->
237
+
238
+ <!-- Second panel Start -->
239
+ <div class="wcf-ca-panel">
240
+ <div class="wcf-ca-column wcf-ca-column-one">
241
+ <div class="wcf-ca-user-order">
242
+ <h2> <?php esc_html_e( 'User Order Details:', 'woo-cart-abandonment-recovery' ); ?> </h2>
243
+ <?php echo( $this->get_admin_product_block( $details->cart_contents, $details->cart_total ) ); //phpcs:ignore ?>
244
+ </div>
245
+ </div>
246
+ </div>
247
+ <!-- Second panel closed -->
 
 
modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-reports.php CHANGED
@@ -1,156 +1,156 @@
1
- <?php
2
- /**
3
- * Cartflows view for cart abandonment reports.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- ?>
9
-
10
- <div class="wcf-ca-report-btn">
11
-
12
- <div class="wcf-ca-left-report-field-group">
13
- <button onclick="window.location.search += '&filter=today';"
14
- class="button <?php echo 'today' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Today', 'woo-cart-abandonment-recovery' ); ?>
15
- </button>
16
-
17
- <button onclick="window.location.search += '&filter=yesterday';"
18
- class="button <?php echo 'yesterday' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Yesterday', 'woo-cart-abandonment-recovery' ); ?>
19
- </button>
20
-
21
- <button onclick="window.location.search += '&filter=last_week';"
22
- class="button <?php echo 'last_week' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Last Week', 'woo-cart-abandonment-recovery' ); ?>
23
- </button>
24
-
25
- <button onclick="window.location.search += '&filter=last_month';"
26
- class="button <?php echo 'last_month' === $filter ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Last Month', 'woo-cart-abandonment-recovery' ); ?>
27
- </button>
28
- </div>
29
-
30
- <div class="wcf-ca-right-report-field-group">
31
-
32
- <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_from" placeholder="YYYY-MM-DD" value="<?php echo esc_attr( $from_date ); ?>"/>
33
- <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_to" placeholder="YYYY-MM-DD" value="<?php echo esc_attr( $to_date ); ?>" />
34
- <button id="wcf_ca_custom_filter"
35
- class="button <?php echo 'custom' === $filter ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Custom Filter', 'woo-cart-abandonment-recovery' ); ?>
36
- </button>
37
-
38
- </div>
39
-
40
- </div>
41
-
42
- <div class="wcf-ca-grid-container">
43
-
44
- <div class="wcf-ca-ibox">
45
- <div class="wcf-ca-ibox-title">
46
- <h3> <?php esc_html_e( 'Recoverable Orders', 'woo-cart-abandonment-recovery' ); ?> </h3>
47
- </div>
48
- <div class="wcf-ca-ibox-content">
49
- <h1> <?php echo esc_attr( $abandoned_report['no_of_orders'] ); ?> </h1>
50
- <small> <?php esc_html_e( 'Total Recoverable Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
51
- </div>
52
- </div>
53
-
54
- <div class="wcf-ca-ibox">
55
- <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Recovered Orders', 'woo-cart-abandonment-recovery' ); ?></h3></div>
56
- <div class="wcf-ca-ibox-content"><h1><?php echo esc_attr( $recovered_report['no_of_orders'] ); ?></h1>
57
- <small> <?php esc_html_e( 'Total Recovered Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
58
- </div>
59
- </div>
60
-
61
- <div class="wcf-ca-ibox">
62
- <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Lost Orders', 'woo-cart-abandonment-recovery' ); ?></h3></div>
63
- <div class="wcf-ca-ibox-content"><h1
64
- ><?php echo esc_attr( $lost_report['no_of_orders'] ); ?></h1>
65
- <small> <?php esc_html_e( 'Total Lost Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
66
- </div>
67
- </div>
68
-
69
- </div>
70
-
71
- <div class="wcf-ca-grid-container">
72
-
73
- <div class="wcf-ca-ibox">
74
- <div class="wcf-ca-ibox-title"><h3> <?php esc_html_e( 'Recoverable Revenue', 'woo-cart-abandonment-recovery' ); ?> </h3></div>
75
- <div class="wcf-ca-ibox-content">
76
- <h1>
77
- <?php echo esc_attr( $currency_symbol ) . esc_attr( number_format_i18n( $abandoned_report['revenue'], 2 ) ); ?>
78
- </h1>
79
- <small> <?php esc_html_e( 'Total Recoverable Revenue.', 'woo-cart-abandonment-recovery' ); ?> </small>
80
- </div>
81
- </div>
82
-
83
- <div class="wcf-ca-ibox">
84
- <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Recovered Revenue', 'woo-cart-abandonment-recovery' ); ?></h3></div>
85
- <div class="wcf-ca-ibox-content"><h1>
86
- <?php
87
- echo esc_attr( $currency_symbol ) . esc_attr( number_format_i18n( $recovered_report['revenue'], 2 ) );
88
- ?>
89
- </h1>
90
- <small> <?php esc_html_e( 'Total Recovered Revenue.', 'woo-cart-abandonment-recovery' ); ?> </small>
91
- </div>
92
- </div>
93
-
94
- <div class="wcf-ca-ibox">
95
- <div class="wcf-ca-ibox-title"><h3> <?php esc_html_e( 'Recovery Rate', 'woo-cart-abandonment-recovery' ); ?> </h3></div>
96
- <div class="wcf-ca-ibox-content"><h1><?php echo esc_attr( $conversion_rate ) . '%'; ?></h1>
97
- <small><?php esc_html_e( 'Total Percentage Of Recovered Orders After Abandonment.', 'woo-cart-abandonment-recovery' ); ?> </small>
98
- </div>
99
- </div>
100
-
101
- </div>
102
-
103
- <hr/>
104
-
105
- <div class="wcf-ca-report-btn">
106
- <div class="wcf-ca-left-report-field-group">
107
- <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_ABANDONED_ORDER ); ?>';"
108
- class="button <?php echo WCF_CART_ABANDONED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Recoverable Orders', 'woo-cart-abandonment-recovery' ); ?>
109
- </button>
110
- <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_COMPLETED_ORDER ); ?>';"
111
- class="button <?php echo WCF_CART_COMPLETED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"><?php esc_html_e( 'Recovered Orders', 'woo-cart-abandonment-recovery' ); ?>
112
- </button>
113
- <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_LOST_ORDER ); ?>';"
114
- class="button <?php echo WCF_CART_LOST_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"><?php esc_html_e( 'Lost Orders', 'woo-cart-abandonment-recovery' ); ?>
115
- </button>
116
- </div>
117
-
118
- <div class="wcf-ca-right-report-field-group">
119
- <div class="wcf-search-orders" id="wcf_search_wrapper" >
120
- <div class="search-box">
121
- <?php
122
- $search_term = filter_input( INPUT_GET, 'search_term', FILTER_SANITIZE_STRING );
123
- ?>
124
- <input type="search" id="wcf_search_id_search_input" name="s" placeholder="<?php echo esc_html__( 'Search by email', 'woo-cart-abandonment-recovery' ); ?>" value="<?php echo esc_attr( $search_term ); ?>">
125
- <input type="submit" id="wcf_search_id_submit" class="button" value="<?php esc_html_e( 'Search Orders', 'woo-cart-abandonment-recovery' ); ?>">
126
- </div>
127
- </div>
128
- <div class="wcf_export_orders">
129
- <?php
130
- if ( count( $wcf_list_table->items ) !== 0 ) {
131
- ?>
132
- <button id="wcf_ca_export_orders"
133
- class="button-primary " > Export Orders <span class="dashicons dashicons-download wcf-ca-export-icon" ></span>
134
- </button>
135
- <?php } ?>
136
- </div>
137
- </div>
138
- </div>
139
-
140
- <?php
141
- if ( count( $wcf_list_table->items ) ) {
142
- $wcar_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
143
- ?>
144
- <form id="wcf-cart-abandonment-table" method="GET">
145
- <input type="hidden" name="page" value="<?php echo esc_html( $wcar_page ); ?>"/>
146
- <?php $wcf_list_table->display(); ?>
147
- </form>
148
-
149
- <?php
150
- } else {
151
-
152
- echo '<div> <strong> ' . esc_html__( 'No Orders Found.', 'woo-cart-abandonment-recovery' ) . '</strong> </div>';
153
-
154
- }
155
-
156
- ?>
1
+ <?php
2
+ /**
3
+ * Cartflows view for cart abandonment reports.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ ?>
9
+
10
+ <div class="wcf-ca-report-btn">
11
+
12
+ <div class="wcf-ca-left-report-field-group">
13
+ <button onclick="window.location.search += '&filter=today';"
14
+ class="button <?php echo 'today' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Today', 'woo-cart-abandonment-recovery' ); ?>
15
+ </button>
16
+
17
+ <button onclick="window.location.search += '&filter=yesterday';"
18
+ class="button <?php echo 'yesterday' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Yesterday', 'woo-cart-abandonment-recovery' ); ?>
19
+ </button>
20
+
21
+ <button onclick="window.location.search += '&filter=last_week';"
22
+ class="button <?php echo 'last_week' === $filter ? 'button-primary' : 'button-secondary'; ?>"> <?php esc_html_e( 'Last Week', 'woo-cart-abandonment-recovery' ); ?>
23
+ </button>
24
+
25
+ <button onclick="window.location.search += '&filter=last_month';"
26
+ class="button <?php echo 'last_month' === $filter ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Last Month', 'woo-cart-abandonment-recovery' ); ?>
27
+ </button>
28
+ </div>
29
+
30
+ <div class="wcf-ca-right-report-field-group">
31
+
32
+ <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_from" placeholder="YYYY-MM-DD" value="<?php echo esc_attr( $from_date ); ?>"/>
33
+ <input class="wcf-ca-filter-input" type="text" id="wcf_ca_custom_filter_to" placeholder="YYYY-MM-DD" value="<?php echo esc_attr( $to_date ); ?>" />
34
+ <button id="wcf_ca_custom_filter"
35
+ class="button <?php echo 'custom' === $filter ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Custom Filter', 'woo-cart-abandonment-recovery' ); ?>
36
+ </button>
37
+
38
+ </div>
39
+
40
+ </div>
41
+
42
+ <div class="wcf-ca-grid-container">
43
+
44
+ <div class="wcf-ca-ibox">
45
+ <div class="wcf-ca-ibox-title">
46
+ <h3> <?php esc_html_e( 'Recoverable Orders', 'woo-cart-abandonment-recovery' ); ?> </h3>
47
+ </div>
48
+ <div class="wcf-ca-ibox-content">
49
+ <h1> <?php echo esc_attr( $abandoned_report['no_of_orders'] ); ?> </h1>
50
+ <small> <?php esc_html_e( 'Total Recoverable Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
51
+ </div>
52
+ </div>
53
+
54
+ <div class="wcf-ca-ibox">
55
+ <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Recovered Orders', 'woo-cart-abandonment-recovery' ); ?></h3></div>
56
+ <div class="wcf-ca-ibox-content"><h1><?php echo esc_attr( $recovered_report['no_of_orders'] ); ?></h1>
57
+ <small> <?php esc_html_e( 'Total Recovered Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="wcf-ca-ibox">
62
+ <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Lost Orders', 'woo-cart-abandonment-recovery' ); ?></h3></div>
63
+ <div class="wcf-ca-ibox-content"><h1
64
+ ><?php echo esc_attr( $lost_report['no_of_orders'] ); ?></h1>
65
+ <small> <?php esc_html_e( 'Total Lost Orders.', 'woo-cart-abandonment-recovery' ); ?> </small>
66
+ </div>
67
+ </div>
68
+
69
+ </div>
70
+
71
+ <div class="wcf-ca-grid-container">
72
+
73
+ <div class="wcf-ca-ibox">
74
+ <div class="wcf-ca-ibox-title"><h3> <?php esc_html_e( 'Recoverable Revenue', 'woo-cart-abandonment-recovery' ); ?> </h3></div>
75
+ <div class="wcf-ca-ibox-content">
76
+ <h1>
77
+ <?php echo esc_attr( $currency_symbol ) . esc_attr( number_format_i18n( $abandoned_report['revenue'], 2 ) ); ?>
78
+ </h1>
79
+ <small> <?php esc_html_e( 'Total Recoverable Revenue.', 'woo-cart-abandonment-recovery' ); ?> </small>
80
+ </div>
81
+ </div>
82
+
83
+ <div class="wcf-ca-ibox">
84
+ <div class="wcf-ca-ibox-title"><h3><?php esc_html_e( 'Recovered Revenue', 'woo-cart-abandonment-recovery' ); ?></h3></div>
85
+ <div class="wcf-ca-ibox-content"><h1>
86
+ <?php
87
+ echo esc_attr( $currency_symbol ) . esc_attr( number_format_i18n( $recovered_report['revenue'], 2 ) );
88
+ ?>
89
+ </h1>
90
+ <small> <?php esc_html_e( 'Total Recovered Revenue.', 'woo-cart-abandonment-recovery' ); ?> </small>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="wcf-ca-ibox">
95
+ <div class="wcf-ca-ibox-title"><h3> <?php esc_html_e( 'Recovery Rate', 'woo-cart-abandonment-recovery' ); ?> </h3></div>
96
+ <div class="wcf-ca-ibox-content"><h1><?php echo esc_attr( $conversion_rate ) . '%'; ?></h1>
97
+ <small><?php esc_html_e( 'Total Percentage Of Recovered Orders After Abandonment.', 'woo-cart-abandonment-recovery' ); ?> </small>
98
+ </div>
99
+ </div>
100
+
101
+ </div>
102
+
103
+ <hr/>
104
+
105
+ <div class="wcf-ca-report-btn">
106
+ <div class="wcf-ca-left-report-field-group">
107
+ <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_ABANDONED_ORDER ); ?>';"
108
+ class="button <?php echo WCF_CART_ABANDONED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?> "> <?php esc_html_e( 'Recoverable Orders', 'woo-cart-abandonment-recovery' ); ?>
109
+ </button>
110
+ <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_COMPLETED_ORDER ); ?>';"
111
+ class="button <?php echo WCF_CART_COMPLETED_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"><?php esc_html_e( 'Recovered Orders', 'woo-cart-abandonment-recovery' ); ?>
112
+ </button>
113
+ <button onclick="window.location.search += '&filter_table=<?php echo esc_attr( WCF_CART_LOST_ORDER ); ?>';"
114
+ class="button <?php echo WCF_CART_LOST_ORDER === $filter_table ? 'button-primary' : 'button-secondary'; ?>"><?php esc_html_e( 'Lost Orders', 'woo-cart-abandonment-recovery' ); ?>
115
+ </button>
116
+ </div>
117
+
118
+ <div class="wcf-ca-right-report-field-group">
119
+ <div class="wcf-search-orders" id="wcf_search_wrapper" >
120
+ <div class="search-box">
121
+ <?php
122
+ $search_term = filter_input( INPUT_GET, 'search_term', FILTER_SANITIZE_STRING );
123
+ ?>
124
+ <input type="search" id="wcf_search_id_search_input" name="s" placeholder="<?php echo esc_html__( 'Search by email', 'woo-cart-abandonment-recovery' ); ?>" value="<?php echo esc_attr( $search_term ); ?>">
125
+ <input type="submit" id="wcf_search_id_submit" class="button" value="<?php esc_html_e( 'Search Orders', 'woo-cart-abandonment-recovery' ); ?>">
126
+ </div>
127
+ </div>
128
+ <div class="wcf_export_orders">
129
+ <?php
130
+ if ( count( $wcf_list_table->items ) !== 0 ) {
131
+ ?>
132
+ <button id="wcf_ca_export_orders"
133
+ class="button-primary " > Export Orders <span class="dashicons dashicons-download wcf-ca-export-icon" ></span>
134
+ </button>
135
+ <?php } ?>
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ <?php
141
+ if ( count( $wcf_list_table->items ) ) {
142
+ $wcar_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
143
+ ?>
144
+ <form id="wcf-cart-abandonment-table" method="GET">
145
+ <input type="hidden" name="page" value="<?php echo esc_html( $wcar_page ); ?>"/>
146
+ <?php $wcf_list_table->display(); ?>
147
+ </form>
148
+
149
+ <?php
150
+ } else {
151
+
152
+ echo '<div> <strong> ' . esc_html__( 'No Orders Found.', 'woo-cart-abandonment-recovery' ) . '</strong> </div>';
153
+
154
+ }
155
+
156
+ ?>
modules/cart-abandonment/includes/admin/cartflows-cart-abandonment-tabs.php CHANGED
@@ -1,118 +1,118 @@
1
- <?php
2
- /**
3
- * Cartflows view for cart abandonment tabs.
4
- *
5
- * @package Woocommerce-Cart-Abandonment-Recovery
6
- */
7
-
8
- ?>
9
- <div class="wrap">
10
- <h1 id="wcf_cart_abandonment_tracking_table"><?php echo esc_html__( 'WooCommerce Cart Abandonment Recovery ', 'woo-cart-abandonment-recovery' ); ?></h1>
11
- <?php
12
-
13
- $wcar_action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
14
- $sub_action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
15
-
16
-
17
- if ( ! $wcar_action ) {
18
- $wcar_action = WCF_ACTION_REPORTS;
19
- }
20
-
21
- $this->wcf_display_tabs();
22
- $this->wcf_show_warning_ca();
23
- ?>
24
- <?php
25
- echo wp_kses_post( get_transient( 'wcf_ca_show_message' ) );
26
- ?>
27
-
28
- <?php if ( WCF_ACTION_SETTINGS === $wcar_action ) : ?>
29
- <?php
30
- $this->wcf_display_settings();
31
- ?>
32
- <?php endif; ?>
33
-
34
- <?php if ( WCF_ACTION_REPORTS === $wcar_action ) : ?>
35
-
36
- <?php
37
-
38
- switch ( $sub_action ) {
39
-
40
- case WCF_SUB_ACTION_REPORTS_VIEW:
41
- $this->wcf_display_report_details();
42
- break;
43
- case WCF_SUB_ACTION_REPORTS_RESCHEDULE:
44
- $ca_obj = Cartflows_Ca_Cart_Abandonment::get_instance();
45
-
46
- $session_id = filter_input( INPUT_GET, 'session_id', FILTER_SANITIZE_STRING );
47
- if ( $session_id ) {
48
- $ca_obj->schedule_emails( $session_id, true );
49
- }
50
-
51
- $param = array(
52
- 'page' => WCF_CA_PAGE_NAME,
53
- 'action' => WCF_ACTION_REPORTS,
54
- 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
55
- 'session_id' => $session_id,
56
- );
57
- $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
58
-
59
- wp_safe_redirect( $redirect_url );
60
-
61
- break;
62
- default:
63
- $this->wcf_display_reports();
64
- break;
65
-
66
- }
67
-
68
- ?>
69
-
70
- <?php endif; ?>
71
-
72
- <?php if ( WCF_ACTION_EMAIL_TEMPLATES === $wcar_action ) : ?>
73
-
74
- <?php
75
- $email_template_class_inst = Cartflows_Ca_Email_Templates::get_instance();
76
- $email_template_class_inst->show_messages();
77
- switch ( $sub_action ) {
78
- case WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES:
79
- $email_template_class_inst->delete_bulk_templates();
80
- break;
81
- case WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES:
82
- $email_template_class_inst->delete_single_template();
83
- break;
84
- case WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES:
85
- $email_template_class_inst->clone_email_template();
86
- break;
87
- case WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES:
88
- case WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES:
89
- $email_template_class_inst->render_email_template_form( $sub_action );
90
- break;
91
- case WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES:
92
- $email_template_class_inst->restore_email_templates();
93
- break;
94
-
95
- case WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES:
96
- check_ajax_referer( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' );
97
-
98
- $wcf_settings_frm = filter_input( INPUT_POST, 'wcf_settings_frm', FILTER_SANITIZE_STRING );
99
- $action_id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT );
100
-
101
- if ( 'save' === $wcf_settings_frm ) {
102
- $email_template_class_inst->add_email_template();
103
- } elseif ( 'update' === $wcf_settings_frm && $action_id ) {
104
- $email_template_class_inst->edit_email_template();
105
- }
106
- break;
107
- default:
108
- $email_template_class_inst->show_add_new_template_button();
109
- $email_template_class_inst->show_email_template_data_table();
110
- break;
111
- }
112
-
113
- ?>
114
-
115
-
116
- <?php endif; ?>
117
-
118
- </div>
1
+ <?php
2
+ /**
3
+ * Cartflows view for cart abandonment tabs.
4
+ *
5
+ * @package Woocommerce-Cart-Abandonment-Recovery
6
+ */
7
+
8
+ ?>
9
+ <div class="wrap">
10
+ <h1 id="wcf_cart_abandonment_tracking_table"><?php echo esc_html__( 'WooCommerce Cart Abandonment Recovery ', 'woo-cart-abandonment-recovery' ); ?></h1>
11
+ <?php
12
+
13
+ $wcar_action = filter_input( INPUT_GET, 'action', FILTER_SANITIZE_STRING );
14
+ $sub_action = filter_input( INPUT_GET, 'sub_action', FILTER_SANITIZE_STRING );
15
+
16
+
17
+ if ( ! $wcar_action ) {
18
+ $wcar_action = WCF_ACTION_REPORTS;
19
+ }
20
+
21
+ $this->wcf_display_tabs();
22
+ $this->wcf_show_warning_ca();
23
+ ?>
24
+ <?php
25
+ echo wp_kses_post( get_transient( 'wcf_ca_show_message' ) );
26
+ ?>
27
+
28
+ <?php if ( WCF_ACTION_SETTINGS === $wcar_action ) : ?>
29
+ <?php
30
+ $this->wcf_display_settings();
31
+ ?>
32
+ <?php endif; ?>
33
+
34
+ <?php if ( WCF_ACTION_REPORTS === $wcar_action ) : ?>
35
+
36
+ <?php
37
+
38
+ switch ( $sub_action ) {
39
+
40
+ case WCF_SUB_ACTION_REPORTS_VIEW:
41
+ $this->wcf_display_report_details();
42
+ break;
43
+ case WCF_SUB_ACTION_REPORTS_RESCHEDULE:
44
+ $ca_obj = Cartflows_Ca_Cart_Abandonment::get_instance();
45
+
46
+ $session_id = filter_input( INPUT_GET, 'session_id', FILTER_SANITIZE_STRING );
47
+ if ( $session_id ) {
48
+ $ca_obj->schedule_emails( $session_id, true );
49
+ }
50
+
51
+ $param = array(
52
+ 'page' => WCF_CA_PAGE_NAME,
53
+ 'action' => WCF_ACTION_REPORTS,
54
+ 'sub_action' => WCF_SUB_ACTION_REPORTS_VIEW,
55
+ 'session_id' => $session_id,
56
+ );
57
+ $redirect_url = add_query_arg( $param, admin_url( '/admin.php' ) );
58
+
59
+ wp_safe_redirect( $redirect_url );
60
+
61
+ break;
62
+ default:
63
+ $this->wcf_display_reports();
64
+ break;
65
+
66
+ }
67
+
68
+ ?>
69
+
70
+ <?php endif; ?>
71
+
72
+ <?php if ( WCF_ACTION_EMAIL_TEMPLATES === $wcar_action ) : ?>
73
+
74
+ <?php
75
+ $email_template_class_inst = Cartflows_Ca_Email_Templates::get_instance();
76
+ $email_template_class_inst->show_messages();
77
+ switch ( $sub_action ) {
78
+ case WCF_SUB_ACTION_DELETE_BULK_EMAIL_TEMPLATES:
79
+ $email_template_class_inst->delete_bulk_templates();
80
+ break;
81
+ case WCF_SUB_ACTION_DELETE_EMAIL_TEMPLATES:
82
+ $email_template_class_inst->delete_single_template();
83
+ break;
84
+ case WCF_SUB_ACTION_CLONE_EMAIL_TEMPLATES:
85
+ $email_template_class_inst->clone_email_template();
86
+ break;
87
+ case WCF_SUB_ACTION_ADD_EMAIL_TEMPLATES:
88
+ case WCF_SUB_ACTION_EDIT_EMAIL_TEMPLATES:
89
+ $email_template_class_inst->render_email_template_form( $sub_action );
90
+ break;
91
+ case WCF_SUB_ACTION_RESTORE_EMAIL_TEMPLATES:
92
+ $email_template_class_inst->restore_email_templates();
93
+ break;
94
+
95
+ case WCF_SUB_ACTION_SAVE_EMAIL_TEMPLATES:
96
+ check_ajax_referer( WCF_EMAIL_TEMPLATES_NONCE, '_wpnonce' );
97
+
98
+ $wcf_settings_frm = filter_input( INPUT_POST, 'wcf_settings_frm', FILTER_SANITIZE_STRING );
99
+ $action_id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT );
100
+
101
+ if ( 'save' === $wcf_settings_frm ) {
102
+ $email_template_class_inst->add_email_template();
103
+ } elseif ( 'update' === $wcf_settings_frm && $action_id ) {
104
+ $email_template_class_inst->edit_email_template();
105
+ }
106
+ break;
107
+ default:
108
+ $email_template_class_inst->show_add_new_template_button();
109
+ $email_template_class_inst->show_email_template_data_table();
110
+ break;
111
+ }
112
+
113
+ ?>
114
+
115
+
116
+ <?php endif; ?>
117
+
118
+ </div>
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: brainstormforce, wpcrafter
3
  Donate link: https://www.paypal.me/BrainstormForce
4
  Tags: woocommerce, cart abandonment, cart recovery
5
  Requires at least: 4.4
6
- Tested up to: 5.4.2
7
- Stable tag: 1.2.7
8
  Requires PHP: 5.6
9
  License: GPLv2 or later
10
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -129,9 +129,12 @@ Here are few thoughts behind making it available for free:
129
 
130
  == Changelog ==
131
 
 
 
 
 
132
  = Version 1.2.7 - Tuesday, 16th June 2020 =
133
- * New: Users can now share [non-personal usage data] to help us test and develop better products.
134
- ( https://store.brainstormforce.com/usage-tracking/?utm_source=wp_repo&utm_medium=changelog&utm_campaign=usage_tracking )
135
 
136
  = Version 1.2.6 - Thursday, 21st May 2020 =
137
  * New: Added option to send the email to admin after successfully cart recovery of the abandoned order.
3
  Donate link: https://www.paypal.me/BrainstormForce
4
  Tags: woocommerce, cart abandonment, cart recovery
5
  Requires at least: 4.4
6
+ Tested up to: 5.5
7
+ Stable tag: 1.2.8
8
  Requires PHP: 5.6
9
  License: GPLv2 or later
10
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
129
 
130
  == Changelog ==
131
 
132
+ = Version 1.2.8 - Friday, 14th August 2020 =
133
+ * New: Added new option to prevent recovery emails for specific order status.
134
+ * Fix: Deprecated the 'woo_ca_exclude_on_hold_order_from_tracking' filter.
135
+
136
  = Version 1.2.7 - Tuesday, 16th June 2020 =
137
+ * New: Users can now share [non-personal usage data](https://my.cartflows.com/usage-tracking/?utm_source=wp_repo&utm_medium=changelog&utm_campaign=usage_tracking) to help us test and develop better products.
 
138
 
139
  = Version 1.2.6 - Thursday, 21st May 2020 =
140
  * New: Added option to send the email to admin after successfully cart recovery of the abandoned order.
uninstall.php CHANGED
@@ -1,14 +1,14 @@
1
- <?php
2
- /**
3
- * Woocommerce Cart Abandonment Recovery
4
- * Unscheduling the events.
5
- *
6
- * @package Woocommerce-Cart-Abandonment-Recovery
7
- */
8
-
9
- if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
10
- exit;
11
- }
12
-
13
-
14
- wp_clear_scheduled_hook( 'cartflows_ca_update_order_status_action' );
1
+ <?php
2
+ /**
3
+ * Woocommerce Cart Abandonment Recovery
4
+ * Unscheduling the events.
5
+ *
6
+ * @package Woocommerce-Cart-Abandonment-Recovery
7
+ */
8
+
9
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
10
+ exit;
11
+ }
12
+
13
+
14
+ wp_clear_scheduled_hook( 'cartflows_ca_update_order_status_action' );
woo-cart-abandonment-recovery.php CHANGED
@@ -3,12 +3,12 @@
3
  * Plugin Name: WooCommerce Cart Abandonment Recovery
4
  * Plugin URI: https://cartflows.com/
5
  * Description: Recover your lost revenue. Capture email address of users on the checkout page and send follow up emails if they don't complete the purchase.
6
- * Version: 1.2.7
7
  * Author: CartFlows Inc
8
  * Author URI: https://cartflows.com/
9
  * Text Domain: woo-cart-abandonment-recovery
10
  * WC requires at least: 3.0
11
- * WC tested up to: 4.2.0
12
  *
13
  * @package Woocommerce-Cart-Abandonment-Recovery
14
  */
3
  * Plugin Name: WooCommerce Cart Abandonment Recovery
4
  * Plugin URI: https://cartflows.com/
5
  * Description: Recover your lost revenue. Capture email address of users on the checkout page and send follow up emails if they don't complete the purchase.
6
+ * Version: 1.2.8
7
  * Author: CartFlows Inc
8
  * Author URI: https://cartflows.com/
9
  * Text Domain: woo-cart-abandonment-recovery
10
  * WC requires at least: 3.0
11
+ * WC tested up to: 4.3.2
12
  *
13
  * @package Woocommerce-Cart-Abandonment-Recovery
14
  */