PluginProbe
WP Reset / 2.05
WP Reset v2.05
trunk 1.0 1.1 1.11 1.20 1.25 1.30 1.35 1.40 1.45 1.50 1.55 1.60 1.65 1.70 1.75 1.77 1.80 1.81 1.82 1.83 1.84 1.85 1.86 1.90 All 42 releases
← All changes | wp-reset.php +2643 -2436 1.902.05 View file →
@@ -2,17 +2,18 @@
2 2 /*
3 3 Plugin Name: WP Reset
4 4 Plugin URI: https://wpreset.com/
5 5 Description: Reset the entire site or just selected parts while reserving the option to undo by using snapshots.
6 - Version: 1.90
6 + Version: 2.05
7 7 Requires at least: 4.0
8 8 Requires PHP: 5.2
9 - Tested up to: 5.6
9 + Tested up to: 6.8
10 + License: GPLv2 or later
10 11 Author: WebFactory Ltd
11 12 Author URI: https://www.webfactoryltd.com/
12 13 Text Domain: wp-reset
13 14
14 - Copyright 2015 - 2021 WebFactory Ltd (email: wpreset@webfactoryltd.com)
15 + Copyright 2015 - 2025 WebFactory Ltd (email: wpreset@webfactoryltd.com)
15 16
16 17 This program is free software; you can redistribute it and/or modify
17 18 it under the terms of the GNU General Public License, version 2, as
18 19 published by the Free Software Foundation.
@@ -28,9 +29,9 @@
28 29 */
29 30
30 31 // include only file
31 32 if (!defined('ABSPATH')) {
32 - die('Do not open this file directly.');
33 + die('Do not open this file directly.');
33 34 }
34 35
35 36
36 37 define('WP_RESET_FILE', __FILE__);
@@ -42,1943 +43,2025 @@
42 43 new wf_flyout(__FILE__);
43 44
44 45 // load WP-CLI commands, if needed
45 46 if (defined('WP_CLI') && WP_CLI) {
46 - require_once dirname(__FILE__) . '/wp-reset-cli.php';
47 + require_once dirname(__FILE__) . '/wp-reset-cli.php';
47 48 }
48 49
49 50
50 51 class WP_Reset
51 52 {
52 - protected static $instance = null;
53 - public $version = 0;
54 - public $plugin_url = '';
55 - public $plugin_dir = '';
56 - public $snapshots_folder = 'wp-reset-snapshots-export';
57 - protected $options = array();
58 - private $delete_count = 0;
59 - private $licensing_servers = array('https://dashboard.wpreset.com/api/');
60 - public $core_tables = array('commentmeta', 'comments', 'links', 'options', 'postmeta', 'posts', 'term_relationships', 'term_taxonomy', 'termmeta', 'terms', 'usermeta', 'users');
61 - private $license = null;
53 + protected static $instance = null;
54 + public $version = 0;
55 + public $plugin_url = '';
56 + public $plugin_dir = '';
57 + public $snapshots_folder = 'wp-reset-snapshots-export';
58 + protected $options = array();
59 + private $delete_count = 0;
60 + private $licensing_servers = array('https://dashboard.wpreset.com/api/');
61 + public $core_tables = array('commentmeta', 'comments', 'links', 'options', 'postmeta', 'posts', 'term_relationships', 'term_taxonomy', 'termmeta', 'terms', 'usermeta', 'users');
62 + private $license = null;
63 + public $filesystem_initialized = false;
62 64
65 + /**
66 + * Creates a new WP_Reset object and implements singleton
67 + *
68 + * @return WP_Reset
69 + */
70 + static function getInstance()
71 + {
72 + if (!is_a(self::$instance, 'WP_Reset')) {
73 + self::$instance = new WP_Reset();
74 + }
63 75
64 - /**
65 - * Creates a new WP_Reset object and implements singleton
66 - *
67 - * @return WP_Reset
68 - */
69 - static function getInstance()
70 - {
71 - if (!is_a(self::$instance, 'WP_Reset')) {
72 - self::$instance = new WP_Reset();
73 - }
76 + return self::$instance;
77 + } // getInstance
74 78
75 - return self::$instance;
76 - } // getInstance
77 79
80 + /**
81 + * Initialize properties, hook to filters and actions
82 + *
83 + * @return null
84 + */
85 + private function __construct()
86 + {
87 + $this->version = $this->get_plugin_version();
88 + $this->plugin_dir = plugin_dir_path(__FILE__);
89 + $this->plugin_url = plugin_dir_url(__FILE__);
90 + $this->load_options();
78 91
79 - /**
80 - * Initialize properties, hook to filters and actions
81 - *
82 - * @return null
83 - */
84 - private function __construct()
85 - {
86 - $this->version = $this->get_plugin_version();
87 - $this->plugin_dir = plugin_dir_path(__FILE__);
88 - $this->plugin_url = plugin_dir_url(__FILE__);
89 - $this->load_options();
92 + $this->license = new WF_Licensing(array(
93 + 'prefix' => 'wpr',
94 + 'licensing_servers' => $this->licensing_servers,
95 + 'version' => $this->version,
96 + 'plugin_file' => __FILE__,
97 + 'plugin_page' => 'tools_page_wp-reset',
98 + 'skip_hooks' => false,
99 + 'debug' => true,
100 + 'js_folder' => plugin_dir_url(__FILE__) . '/js/'
101 + ));
90 102
91 - $this->license = new WF_Licensing(array(
92 - 'prefix' => 'wpr',
93 - 'licensing_servers' => $this->licensing_servers,
94 - 'version' => $this->version,
95 - 'plugin_file' => __FILE__,
96 - 'plugin_page' => 'tools_page_wp-reset',
97 - 'skip_hooks' => false,
98 - 'debug' => false,
99 - 'js_folder' => plugin_dir_url(__FILE__) . '/js/'
100 - ));
103 + add_action('admin_menu', array($this, 'admin_menu'));
104 + add_action('admin_init', array($this, 'do_all_actions'));
105 + add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
106 + add_action('admin_action_wpr_dismiss_notice', array($this, 'action_dismiss_notice'));
107 + add_action('wp_ajax_wp_reset_dismiss_notice', array($this, 'ajax_dismiss_notice'));
108 + add_action('wp_ajax_wp_reset_run_tool', array($this, 'ajax_run_tool'));
109 + add_action('admin_print_scripts', array($this, 'remove_admin_notices'));
110 + add_action('admin_action_wpr_install_wpfssl', array($this, 'install_wpfssl'));
101 111
102 - add_action('admin_menu', array($this, 'admin_menu'));
103 - add_action('admin_init', array($this, 'do_all_actions'));
104 - add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
105 - add_action('admin_action_wpr_dismiss_notice', array($this, 'action_dismiss_notice'));
106 - add_action('wp_ajax_wp_reset_dismiss_notice', array($this, 'ajax_dismiss_notice'));
107 - add_action('wp_ajax_wp_reset_run_tool', array($this, 'ajax_run_tool'));
108 - add_action('admin_print_scripts', array($this, 'remove_admin_notices'));
112 + add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'plugin_action_links'));
113 + add_filter('plugin_row_meta', array($this, 'plugin_meta_links'), 10, 2);
114 + add_filter('admin_footer_text', array($this, 'admin_footer_text'));
109 115
110 - add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'plugin_action_links'));
111 - add_filter('plugin_row_meta', array($this, 'plugin_meta_links'), 10, 2);
112 - add_filter('admin_footer_text', array($this, 'admin_footer_text'));
116 + $this->core_tables = array_map(function ($tbl) {
117 + global $wpdb;
118 + return $wpdb->prefix . $tbl;
119 + }, $this->core_tables);
120 + } // __construct
113 121
114 - $this->core_tables = array_map(function ($tbl) {
115 - global $wpdb;
116 - return $wpdb->prefix . $tbl;
117 - }, $this->core_tables);
118 - } // __construct
119 122
123 + /**
124 + * Get plugin version from file header
125 + *
126 + * @return string
127 + */
128 + function get_plugin_version()
129 + {
130 + $plugin_data = get_file_data(__FILE__, array('version' => 'Version'), 'plugin');
120 131
121 - /**
122 - * Get plugin version from file header
123 - *
124 - * @return string
125 - */
126 - function get_plugin_version()
127 - {
128 - $plugin_data = get_file_data(__FILE__, array('version' => 'Version'), 'plugin');
132 + return $plugin_data['version'];
133 + } // get_plugin_version
129 134
130 - return $plugin_data['version'];
131 - } // get_plugin_version
132 135
136 + /**
137 + * Load and prepare the options array
138 + * If needed create a new DB entry
139 + *
140 + * @return array
141 + */
142 + private function load_options()
143 + {
144 + $options = get_option('wp-reset', array());
145 + $change = false;
133 146
134 - /**
135 - * Load and prepare the options array
136 - * If needed create a new DB entry
137 - *
138 - * @return array
139 - */
140 - private function load_options()
141 - {
142 - $options = get_option('wp-reset', array());
143 - $change = false;
147 + if (!isset($options['meta'])) {
148 + $options['meta'] = array('first_version' => $this->version, 'first_install' => current_time('timestamp', true), 'reset_count' => 0);
149 + $change = true;
150 + }
151 + if (!isset($options['dismissed_notices'])) {
152 + $options['dismissed_notices'] = array();
153 + $change = true;
154 + }
155 + if (!isset($options['last_run'])) {
156 + $options['last_run'] = array();
157 + $change = true;
158 + }
159 + if (!isset($options['options'])) {
160 + $options['options'] = array();
161 + $change = true;
162 + }
163 + if ($change) {
164 + update_option('wp-reset', $options, true);
165 + }
144 166
145 - if (!isset($options['meta'])) {
146 - $options['meta'] = array('first_version' => $this->version, 'first_install' => current_time('timestamp', true), 'reset_count' => 0);
147 - $change = true;
148 - }
149 - if (!isset($options['dismissed_notices'])) {
150 - $options['dismissed_notices'] = array();
151 - $change = true;
152 - }
153 - if (!isset($options['last_run'])) {
154 - $options['last_run'] = array();
155 - $change = true;
156 - }
157 - if (!isset($options['options'])) {
158 - $options['options'] = array();
159 - $change = true;
160 - }
161 - if ($change) {
162 - update_option('wp-reset', $options, true);
163 - }
167 + $this->options = $options;
168 + return $options;
169 + } // load_options
164 170
165 - $this->options = $options;
166 - return $options;
167 - } // load_options
168 171
172 + /**
173 + * Get meta part of plugin options
174 + *
175 + * @return array
176 + */
177 + function get_meta()
178 + {
179 + return $this->options['meta'];
180 + } // get_meta
169 181
170 - /**
171 - * Get meta part of plugin options
172 - *
173 - * @return array
174 - */
175 - function get_meta()
176 - {
177 - return $this->options['meta'];
178 - } // get_meta
179 182
183 + /**
184 + * Get all dismissed notices, or check for one specific notice
185 + *
186 + * @param string $notice_name Optional. Check if specified notice is dismissed.
187 + *
188 + * @return bool|array
189 + */
190 + function get_dismissed_notices($notice_name = '')
191 + {
192 + $notices = $this->options['dismissed_notices'];
180 193
181 - /**
182 - * Get all dismissed notices, or check for one specific notice
183 - *
184 - * @param string $notice_name Optional. Check if specified notice is dismissed.
185 - *
186 - * @return bool|array
187 - */
188 - function get_dismissed_notices($notice_name = '')
189 - {
190 - $notices = $this->options['dismissed_notices'];
194 + if (empty($notice_name)) {
195 + return $notices;
196 + } else {
197 + if (empty($notices[$notice_name])) {
198 + return false;
199 + } else {
200 + return true;
201 + }
202 + }
203 + } // get_dismissed_notices
191 204
192 - if (empty($notice_name)) {
193 - return $notices;
194 - } else {
195 - if (empty($notices[$notice_name])) {
196 - return false;
197 - } else {
198 - return true;
199 - }
200 - }
201 - } // get_dismissed_notices
202 205
206 + /**
207 + * Get options part of plugin options
208 + *
209 + * @param string $key Optional.
210 + *
211 + * @return array
212 + */
213 + function get_options()
214 + {
215 + return $this->options['options'];
216 + } // get_options
203 217
204 - /**
205 - * Get options part of plugin options
206 - *
207 - * @param string $key Optional.
208 - *
209 - * @return array
210 - */
211 - function get_options()
212 - {
213 - return $this->options['options'];
214 - } // get_options
215 218
219 + /**
220 + * Update specified plugin options key
221 + *
222 + * @param string $key Data to save.
223 + * @param string $data Option key.
224 + *
225 + * @return bool
226 + */
227 + function update_options($key, $data)
228 + {
229 + if (false === in_array($key, array('meta', 'license', 'dismissed_notices', 'options'))) {
230 + user_error('Unknown options key.', E_USER_ERROR);
231 + return false;
232 + }
216 233
217 - /**
218 - * Update specified plugin options key
219 - *
220 - * @param string $key Data to save.
221 - * @param string $data Option key.
222 - *
223 - * @return bool
224 - */
225 - function update_options($key, $data)
226 - {
227 - if (false === in_array($key, array('meta', 'license', 'dismissed_notices', 'options'))) {
228 - user_error('Unknown options key.', E_USER_ERROR);
229 - return false;
230 - }
234 + $this->options[$key] = $data;
235 + $tmp = update_option('wp-reset', $this->options);
231 236
232 - $this->options[$key] = $data;
233 - $tmp = update_option('wp-reset', $this->options);
237 + return $tmp;
238 + } // update_options
234 239
235 - return $tmp;
236 - } // update_options
237 240
241 + /**
242 + * Add plugin menu entry under Tools menu
243 + *
244 + * @return null
245 + */
246 + function admin_menu()
247 + {
248 + add_management_page(__('WP Reset', 'wp-reset'), __('WP Reset', 'wp-reset'), 'administrator', 'wp-reset', array($this, 'plugin_page'));
249 + } // admin_menu
238 250
239 - /**
240 - * Add plugin menu entry under Tools menu
241 - *
242 - * @return null
243 - */
244 - function admin_menu()
245 - {
246 - add_management_page(__('WP Reset', 'wp-reset'), __('WP Reset', 'wp-reset'), 'administrator', 'wp-reset', array($this, 'plugin_page'));
247 - } // admin_menu
248 251
252 + /**
253 + * Dismiss notice via AJAX call
254 + *
255 + * @return null
256 + */
257 + function ajax_dismiss_notice()
258 + {
259 + check_ajax_referer('wp-reset_dismiss_notice');
249 260
250 - /**
251 - * Dismiss notice via AJAX call
252 - *
253 - * @return null
254 - */
255 - function ajax_dismiss_notice()
256 - {
257 - check_ajax_referer('wp-reset_dismiss_notice');
261 + if (!current_user_can('manage_options')) {
262 + wp_send_json_error(__('You are not allowed to run this action.', 'wp-reset'));
263 + }
258 264
259 - if (!current_user_can('administrator')) {
260 - wp_send_json_error(__('You are not allowed to run this action.', 'wp-reset'));
261 - }
265 + if (!isset($_GET['notice_name'])) {
266 + wp_send_json_error(__('Unknown Notice.', 'wp-reset'));
267 + }
262 268
263 - $notice_name = trim(sanitize_text_field(@$_GET['notice_name']));
264 - if (!$this->dismiss_notice($notice_name)) {
265 - wp_send_json_error(__('Notice is already dismissed.', 'wp-reset'));
266 - } else {
267 - wp_send_json_success();
268 - }
269 - } // ajax_dismiss_notice
269 + $notice_name = trim(sanitize_text_field(wp_unslash($_GET['notice_name'])));
270 + if (!$this->dismiss_notice($notice_name)) {
271 + wp_send_json_error(__('Notice is already dismissed.', 'wp-reset'));
272 + } else {
273 + wp_send_json_success();
274 + }
275 + } // ajax_dismiss_notice
270 276
271 277
272 - /**
273 - * Dismiss notice via admin action
274 - *
275 - * @return null
276 - */
277 - function action_dismiss_notice()
278 - {
279 - if (false == wp_verify_nonce(@$_GET['_wpnonce'], 'wpr_dismiss_notice')) {
280 - wp_die('Please reload the page and try again.');
281 - }
278 + /**
279 + * Dismiss notice via admin action
280 + *
281 + * @return null
282 + */
283 + function action_dismiss_notice()
284 + {
285 + if (!isset($_GET['notice']) || !isset($_GET['_wpnonce']) || false == wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'wpr_dismiss_notice')) {
286 + wp_die('Please reload the page and try again.');
287 + }
282 288
283 - if (empty($_GET['notice'])) {
284 - wp_safe_redirect(admin_url());
285 - exit;
286 - }
289 + if (empty($_GET['notice'])) {
290 + wp_safe_redirect(admin_url());
291 + exit;
292 + }
287 293
288 - $notice_name = trim(sanitize_text_field(@$_GET['notice']));
289 - $this->dismiss_notice($notice_name);
294 + $notice_name = trim(sanitize_text_field(wp_unslash($_GET['notice'])));
295 + $this->dismiss_notice($notice_name);
290 296
291 - if (!empty($_GET['redirect'])) {
292 - wp_safe_redirect($_GET['redirect']);
293 - } else {
294 - wp_safe_redirect(admin_url());
295 - }
297 + if (!empty($_GET['redirect'])) {
298 + wp_safe_redirect(sanitize_url(wp_unslash($_GET['redirect'])));
299 + } else {
300 + wp_safe_redirect(admin_url());
301 + }
296 302
297 - exit;
298 - } // action_dismiss_notice
303 + exit;
304 + } // action_dismiss_notice
299 305
300 306
301 - /**
302 - * Dismiss notice by adding it to dismissed_notices options array
303 - *
304 - * @param string $notice_name Notice to dismiss.
305 - *
306 - * @return bool
307 - */
308 - function dismiss_notice($notice_name)
309 - {
310 - if ($this->get_dismissed_notices($notice_name)) {
311 - return false;
312 - } else {
313 - $notices = $this->get_dismissed_notices();
314 - $notices[$notice_name] = true;
315 - $this->update_options('dismissed_notices', $notices);
316 - return true;
317 - }
318 - } // dismiss_notice
307 + /**
308 + * Dismiss notice by adding it to dismissed_notices options array
309 + *
310 + * @param string $notice_name Notice to dismiss.
311 + *
312 + * @return bool
313 + */
314 + function dismiss_notice($notice_name)
315 + {
316 + if ($this->get_dismissed_notices($notice_name)) {
317 + return false;
318 + } else {
319 + $notices = $this->get_dismissed_notices();
320 + $notices[$notice_name] = true;
321 + $this->update_options('dismissed_notices', $notices);
322 + return true;
323 + }
324 + } // dismiss_notice
319 325
320 326
321 - /**
322 - * Returns all WP pointers
323 - *
324 - * @return array
325 - */
326 - function get_pointers()
327 - {
328 - $pointers = array();
327 + /**
328 + * Returns all WP pointers
329 + *
330 + * @return array
331 + */
332 + function get_pointers()
333 + {
334 + $pointers = array();
329 335
330 - $pointers['welcome'] = array('target' => '#menu-tools', 'edge' => 'left', 'align' => 'right', 'content' => 'Thank you for installing the <b style="font-weight: 800;">WP Reset</b> plugin!<br>Open <a href="' . esc_url(admin_url('tools.php?page=wp-reset')) . '">Tools - WP Reset</a> to access resetting tools and start developing &amp; debugging faster.');
336 + $pointers['welcome'] = array('target' => '#menu-tools', 'edge' => 'left', 'align' => 'right', 'content' => 'Thank you for installing the <b style="font-weight: 800;">WP Reset</b> plugin!<br>Open <a href="' . esc_url(admin_url('tools.php?page=wp-reset')) . '">Tools - WP Reset</a> to access resetting tools and start developing &amp; debugging faster.');
331 337
332 - return $pointers;
333 - } // get_pointers
338 + return $pointers;
339 + } // get_pointers
334 340
335 341
336 - /**
337 - * Enqueue CSS and JS files
338 - *
339 - * @return null
340 - */
341 - function admin_enqueue_scripts($hook)
342 - {
343 - // welcome pointer is shown on all pages except WPR to admins, until dismissed
344 - $pointers = $this->get_pointers();
345 - $dismissed_notices = $this->get_dismissed_notices();
342 + /**
343 + * Enqueue CSS and JS files
344 + *
345 + * @return null
346 + */
347 + function admin_enqueue_scripts($hook)
348 + {
349 + // welcome pointer is shown on all pages except WPR to admins, until dismissed
350 + $pointers = $this->get_pointers();
351 + $dismissed_notices = $this->get_dismissed_notices();
346 352
347 - foreach ($dismissed_notices as $notice_name => $tmp) {
348 - if ($tmp) {
349 - unset($pointers[$notice_name]);
350 - }
351 - } // foreach
353 + foreach ($dismissed_notices as $notice_name => $tmp) {
354 + if ($tmp) {
355 + unset($pointers[$notice_name]);
356 + }
357 + } // foreach
352 358
353 - if (!empty($pointers) && !$this->is_plugin_page() && current_user_can('administrator')) {
354 - $pointers['_nonce_dismiss_pointer'] = wp_create_nonce('wp-reset_dismiss_notice');
359 + if (!empty($pointers) && !$this->is_plugin_page() && current_user_can('manage_options')) {
360 + $pointers['_nonce_dismiss_pointer'] = wp_create_nonce('wp-reset_dismiss_notice');
355 361
356 - wp_enqueue_style('wp-pointer');
362 + wp_enqueue_style('wp-pointer');
357 363
358 - wp_enqueue_script('wp-reset-pointers', $this->plugin_url . 'js/wp-reset-pointers.js', array('jquery'), $this->version, true);
359 - wp_enqueue_script('wp-pointer');
360 - wp_localize_script('wp-pointer', 'wp_reset_pointers', $pointers);
361 - }
364 + wp_enqueue_script('wp-reset-pointers', $this->plugin_url . 'js/wp-reset-pointers.js', array('jquery'), $this->version, true);
365 + wp_enqueue_script('wp-pointer');
366 + wp_localize_script('wp-pointer', 'wp_reset_pointers', $pointers);
367 + }
362 368
363 - // exit early if not on WP Reset page
364 - if (!$this->is_plugin_page()) {
365 - return;
366 - }
369 + // exit early if not on WP Reset page
370 + if (!$this->is_plugin_page()) {
371 + return;
372 + }
367 373
368 - $js_localize = array(
369 - 'undocumented_error' => __('An undocumented error has occurred. Please refresh the page and try again.', 'wp-reset'),
370 - 'documented_error' => __('An error has occurred.', 'wp-reset'),
371 - 'plugin_name' => __('WP Reset', 'wp-reset'),
372 - 'settings_url' => admin_url('tools.php?page=wp-reset'),
373 - 'icon_url' => $this->plugin_url . 'img/wp-reset-icon.png',
374 - 'invalid_confirmation' => __('Please type "reset" in the confirmation field.', 'wp-reset'),
375 - 'invalid_confirmation_title' => __('Invalid confirmation', 'wp-reset'),
376 - 'cancel_button' => __('Cancel', 'wp-reset'),
377 - 'ok_button' => __('OK', 'wp-reset'),
378 - 'confirm_button' => __('Reset WordPress', 'wp-reset'),
379 - 'confirm_title' => __('Are you sure you want to proceed?', 'wp-reset'),
380 - 'confirm_title_reset' => __('Are you sure you want to reset the site?', 'wp-reset'),
381 - 'confirm1' => __('Clicking "Reset WordPress" will reset your site to default values. All content will be lost. Always <a href="#" class="create-new-snapshot" data-description="Before resetting the site">create a snapshot</a> if you want to be able to undo.</b>', 'wp-reset'),
382 - 'confirm2' => __('Click "Cancel" to abort.', 'wp-reset'),
383 - 'doing_reset' => __('Resetting in progress. Please wait.', 'wp-reset'),
384 - 'snapshot_success' => __('Snapshot created', 'wp-reset'),
385 - 'snapshot_wait' => __('Creating snapshot. Please wait.', 'wp-reset'),
386 - 'snapshot_confirm' => __('Create snapshot', 'wp-reset'),
387 - 'snapshot_placeholder' => __('Snapshot name or brief description, ie: before plugin install', 'wp-reset'),
388 - 'snapshot_text' => __('Enter snapshot name or brief description', 'wp-reset'),
389 - 'snapshot_title' => __('Create a new snapshot', 'wp-reset'),
390 - 'nonce_dismiss_notice' => wp_create_nonce('wp-reset_dismiss_notice'),
391 - 'activating' => __('Activating', 'wp-reset'),
392 - 'deactivating' => __('Deactivating', 'wp-reset'),
393 - 'deleting' => __('Deleting', 'wp-reset'),
394 - 'installing' => __('Installing', 'wp-reset'),
395 - 'activate_failed' => __('Could not activate', 'wp-reset'),
396 - 'deactivate_failed' => __('Could not deactivate', 'wp-reset'),
397 - 'delete_failed' => __('Could not delete', 'wp-reset'),
398 - 'install_failed' => __('Could not install', 'wp-reset'),
399 - 'install_failed_existing' => __('is already installed', 'wp-reset'),
400 - 'nonce_run_tool' => wp_create_nonce('wp-reset_run_tool'),
401 - 'nonce_do_reset' => wp_create_nonce('wp-reset_do_reset'),
402 - );
374 + $js_localize = array(
375 + 'undocumented_error' => __('An undocumented error has occurred. Please refresh the page and try again.', 'wp-reset'),
376 + 'documented_error' => __('An error has occurred.', 'wp-reset'),
377 + 'plugin_name' => __('WP Reset', 'wp-reset'),
378 + 'settings_url' => admin_url('tools.php?page=wp-reset'),
379 + 'wpfssl_install_url' => add_query_arg(array('action' => 'wpr_install_wpfssl', '_wpnonce' => wp_create_nonce('install_wpfssl'), 'rnd' => wp_rand()), admin_url('admin.php')),
380 + 'icon_url' => $this->plugin_url . 'img/wp-reset-icon.png',
381 + 'invalid_confirmation' => __('Please type "reset" in the confirmation field.', 'wp-reset'),
382 + 'invalid_confirmation_title' => __('Invalid confirmation', 'wp-reset'),
383 + 'cancel_button' => __('Cancel', 'wp-reset'),
384 + 'ok_button' => __('OK', 'wp-reset'),
385 + 'confirm_button' => __('Reset WordPress', 'wp-reset'),
386 + 'confirm_title' => __('Are you sure you want to proceed?', 'wp-reset'),
387 + 'confirm_title_reset' => __('Are you sure you want to reset the site?', 'wp-reset'),
388 + 'confirm1' => __('Clicking "Reset WordPress" will reset your site to default values. All content will be lost. Always <a href="#" class="create-new-snapshot" data-description="Before resetting the site">create a snapshot</a> if you want to be able to undo.</b>', 'wp-reset'),
389 + 'confirm2' => __('Click "Cancel" to abort.', 'wp-reset'),
390 + 'doing_reset' => __('Resetting in progress. Please wait.', 'wp-reset'),
391 + 'snapshot_success' => __('Snapshot created', 'wp-reset'),
392 + 'snapshot_wait' => __('Creating snapshot. Please wait.', 'wp-reset'),
393 + 'snapshot_confirm' => __('Create snapshot', 'wp-reset'),
394 + 'snapshot_placeholder' => __('Snapshot name or brief description, ie: before plugin install', 'wp-reset'),
395 + 'snapshot_text' => __('Enter snapshot name or brief description', 'wp-reset'),
396 + 'snapshot_title' => __('Create a new snapshot', 'wp-reset'),
397 + 'nonce_dismiss_notice' => wp_create_nonce('wp-reset_dismiss_notice'),
398 + 'activating' => __('Activating', 'wp-reset'),
399 + 'deactivating' => __('Deactivating', 'wp-reset'),
400 + 'deleting' => __('Deleting', 'wp-reset'),
401 + 'installing' => __('Installing', 'wp-reset'),
402 + 'activate_failed' => __('Could not activate', 'wp-reset'),
403 + 'deactivate_failed' => __('Could not deactivate', 'wp-reset'),
404 + 'delete_failed' => __('Could not delete', 'wp-reset'),
405 + 'install_failed' => __('Could not install', 'wp-reset'),
406 + 'install_failed_existing' => __('is already installed', 'wp-reset'),
407 + 'nonce_run_tool' => wp_create_nonce('wp-reset_run_tool'),
408 + 'nonce_do_reset' => wp_create_nonce('wp-reset_do_reset'),
409 + );
403 410
404 - wp_enqueue_style('plugin-install');
405 - wp_enqueue_style('wp-reset', $this->plugin_url . 'css/wp-reset.css', array(), $this->version);
406 - wp_enqueue_style('wp-reset-sweetalert2', $this->plugin_url . 'css/sweetalert2.min.css', array(), $this->version);
407 - wp_enqueue_style('wp-reset-tooltipster', $this->plugin_url . 'css/tooltipster.bundle.min.css', array(), $this->version);
411 + wp_enqueue_style('plugin-install');
412 + wp_enqueue_style('wp-jquery-ui-dialog');
413 + wp_enqueue_style('wp-reset', $this->plugin_url . 'css/wp-reset.css', array(), $this->version);
414 + wp_enqueue_style('wp-reset-sweetalert2', $this->plugin_url . 'css/sweetalert2.min.css', array(), $this->version);
415 + wp_enqueue_style('wp-reset-tooltipster', $this->plugin_url . 'css/tooltipster.bundle.min.css', array(), $this->version);
408 416
409 - wp_enqueue_script('plugin-install');
410 - wp_enqueue_script('jquery-ui-tabs');
411 - wp_enqueue_script('wp-reset-sweetalert2', $this->plugin_url . 'js/wp-reset-libs.min.js', array('jquery'), $this->version, true);
412 - wp_enqueue_script('wp-reset', $this->plugin_url . 'js/wp-reset.js', array('jquery'), $this->version, true);
413 - wp_localize_script('wp-reset', 'wp_reset', $js_localize);
417 + wp_enqueue_script('plugin-install');
418 + wp_enqueue_script('jquery-ui-tabs');
419 + wp_enqueue_script('jquery-ui-dialog');
420 + wp_enqueue_script('wp-reset-sweetalert2', $this->plugin_url . 'js/wp-reset-libs.min.js', array('jquery'), $this->version, true);
421 + wp_enqueue_script('wp-reset', $this->plugin_url . 'js/wp-reset.js', array('jquery'), $this->version, true);
422 + wp_localize_script('wp-reset', 'wp_reset', $js_localize);
414 423
415 - add_thickbox();
424 + add_thickbox();
416 425
417 - // fix for aggressive plugins that include their CSS on all pages
418 - wp_dequeue_style('uiStyleSheet');
419 - wp_dequeue_style('wpcufpnAdmin');
420 - wp_dequeue_style('unifStyleSheet');
421 - wp_dequeue_style('wpcufpn_codemirror');
422 - wp_dequeue_style('wpcufpn_codemirrorTheme');
423 - wp_dequeue_style('collapse-admin-css');
424 - wp_dequeue_style('jquery-ui-css');
425 - wp_dequeue_style('tribe-common-admin');
426 - wp_dequeue_style('file-manager__jquery-ui-css');
427 - wp_dequeue_style('file-manager__jquery-ui-css-theme');
428 - wp_dequeue_style('wpmegmaps-jqueryui');
429 - wp_dequeue_style('wp-botwatch-css');
430 - } // admin_enqueue_scripts
426 + // fix for aggressive plugins that include their CSS on all pages
427 + wp_dequeue_style('uiStyleSheet');
428 + wp_dequeue_style('wpcufpnAdmin');
429 + wp_dequeue_style('unifStyleSheet');
430 + wp_dequeue_style('wpcufpn_codemirror');
431 + wp_dequeue_style('wpcufpn_codemirrorTheme');
432 + wp_dequeue_style('collapse-admin-css');
433 + wp_dequeue_style('jquery-ui-css');
434 + wp_dequeue_style('tribe-common-admin');
435 + wp_dequeue_style('file-manager__jquery-ui-css');
436 + wp_dequeue_style('file-manager__jquery-ui-css-theme');
437 + wp_dequeue_style('wpmegmaps-jqueryui');
438 + wp_dequeue_style('wp-botwatch-css');
439 + wp_dequeue_style('uap_main_admin_style');
440 + wp_dequeue_style('uap_font_awesome');
441 + wp_dequeue_style('uap_jquery-ui.min.css');
442 + } // admin_enqueue_scripts
431 443
432 444
433 - /**
434 - * Remove all WP notices on WPR page
435 - *
436 - * @return null
437 - */
438 - function remove_admin_notices()
439 - {
440 - if (!$this->is_plugin_page()) {
441 - return false;
442 - }
445 + /**
446 + * Remove all WP notices on WPR page
447 + *
448 + * @return null
449 + */
450 + function remove_admin_notices()
451 + {
452 + if (!$this->is_plugin_page()) {
453 + return false;
454 + }
443 455
444 - global $wp_filter;
445 - unset($wp_filter['user_admin_notices'], $wp_filter['admin_notices']);
446 - } // remove_admin_notices
456 + global $wp_filter;
457 + unset($wp_filter['user_admin_notices'], $wp_filter['admin_notices']);
458 + } // remove_admin_notices
447 459
448 460
449 - /**
450 - * Check if WP-CLI is available and running
451 - *
452 - * @return bool
453 - */
454 - static function is_cli_running()
455 - {
456 - if (!is_null($value = apply_filters('wp-reset-override-is-cli-running', null))) {
457 - return (bool) $value;
458 - }
461 + /**
462 + * Check if WP-CLI is available and running
463 + *
464 + * @return bool
465 + */
466 + static function is_cli_running()
467 + {
468 + if (!is_null($value = apply_filters('wp-reset-override-is-cli-running', null))) {
469 + return (bool) $value;
470 + }
459 471
460 - if (defined('WP_CLI') && WP_CLI) {
461 - return true;
462 - } else {
463 - return false;
464 - }
465 - } // is_cli_running
472 + if (defined('WP_CLI') && WP_CLI) {
473 + return true;
474 + } else {
475 + return false;
476 + }
477 + } // is_cli_running
466 478
467 479
468 - /**
469 - * Check if given plugin is installed
470 - *
471 - * @param [string] $slug Plugin slug
472 - * @return boolean
473 - */
474 - function is_plugin_installed($slug)
475 - {
476 - if (!function_exists('get_plugins')) {
477 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
478 - }
479 - $all_plugins = get_plugins();
480 + /**
481 + * Check if given plugin is installed
482 + *
483 + * @param [string] $slug Plugin slug
484 + * @return boolean
485 + */
486 + function is_plugin_installed($slug)
487 + {
488 + if (!function_exists('get_plugins')) {
489 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
490 + }
491 + $all_plugins = get_plugins();
480 492
481 - if (!empty($all_plugins[$slug])) {
482 - return true;
483 - } else {
484 - return false;
485 - }
486 - } // is_plugin_installed
493 + if (!empty($all_plugins[$slug])) {
494 + return true;
495 + } else {
496 + return false;
497 + }
498 + } // is_plugin_installed
487 499
488 500
489 - /**
490 - * Deletes all transients.
491 - *
492 - * @return int Number of deleted transient DB entries
493 - */
494 - function do_delete_transients()
495 - {
496 - global $wpdb;
501 + /**
502 + * Deletes all transients.
503 + *
504 + * @return int Number of deleted transient DB entries
505 + */
506 + function do_delete_transients()
507 + {
508 + global $wpdb;
497 509
498 - $count = $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '\_transient\_%' OR option_name LIKE '\_site\_transient\_%'");
510 + // phpcs:ignore db call warning as we are using uncommon queries
511 + $count = $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE '\_transient\_%' OR option_name LIKE '\_site\_transient\_%'"); // phpcs:ignore
499 512
500 - wp_cache_flush();
513 + wp_cache_flush();
501 514
502 - do_action('wp_reset_delete_transients', $count);
515 + do_action('wp_reset_delete_transients', $count);
503 516
504 - return $count;
505 - } // do_delete_transients
517 + return $count;
518 + } // do_delete_transients
506 519
507 520
508 - /**
509 - * Purge all cache for popular caching plugins
510 - *
511 - * @return bool true
512 - */
513 - function do_purge_cache()
514 - {
515 - global $wp_reset;
521 + /**
522 + * Purge all cache for popular caching plugins
523 + *
524 + * @return bool true
525 + */
526 + function do_purge_cache()
527 + {
528 + global $wp_reset;
516 529
517 - wp_cache_flush();
518 - $wp_reset->do_delete_transients();
530 + wp_cache_flush();
531 + $wp_reset->do_delete_transients();
519 532
520 - if (function_exists('w3tc_flush_all')) {
521 - w3tc_flush_all();
522 - }
523 - if (function_exists('wp_cache_clear_cache')) {
524 - wp_cache_clear_cache();
525 - }
526 - if (method_exists('LiteSpeed_Cache_API', 'purge_all')) {
527 - LiteSpeed_Cache_API::purge_all();
528 - }
529 - if (class_exists('Endurance_Page_Cache')) {
530 - $epc = new Endurance_Page_Cache;
531 - $epc->purge_all();
532 - }
533 - if (class_exists('SG_CachePress_Supercacher') && method_exists('SG_CachePress_Supercacher', 'purge_cache')) {
534 - SG_CachePress_Supercacher::purge_cache(true);
535 - }
536 - if (class_exists('SiteGround_Optimizer\Supercacher\Supercacher')) {
537 - SiteGround_Optimizer\Supercacher\Supercacher::purge_cache();
538 - }
539 - if (isset($GLOBALS['wp_fastest_cache']) && method_exists($GLOBALS['wp_fastest_cache'], 'deleteCache')) {
540 - $GLOBALS['wp_fastest_cache']->deleteCache(true);
541 - }
542 - if (is_callable(array('Swift_Performance_Cache', 'clear_all_cache'))) {
543 - Swift_Performance_Cache::clear_all_cache();
544 - }
545 - if (is_callable(array('Hummingbird\WP_Hummingbird', 'flush_cache'))) {
546 - Hummingbird\WP_Hummingbird::flush_cache(true, false);
547 - }
533 + if (function_exists('w3tc_flush_all')) {
534 + w3tc_flush_all();
535 + }
536 + if (function_exists('wp_cache_clear_cache')) {
537 + wp_cache_clear_cache();
538 + }
539 + if (method_exists('LiteSpeed_Cache_API', 'purge_all')) {
540 + LiteSpeed_Cache_API::purge_all();
541 + }
542 + if (class_exists('Endurance_Page_Cache')) {
543 + $epc = new Endurance_Page_Cache;
544 + $epc->purge_all();
545 + }
546 + if (class_exists('SG_CachePress_Supercacher') && method_exists('SG_CachePress_Supercacher', 'purge_cache')) {
547 + SG_CachePress_Supercacher::purge_cache(true);
548 + }
549 + if (class_exists('SiteGround_Optimizer\Supercacher\Supercacher')) {
550 + SiteGround_Optimizer\Supercacher\Supercacher::purge_cache();
551 + }
552 + if (isset($GLOBALS['wp_fastest_cache']) && method_exists($GLOBALS['wp_fastest_cache'], 'deleteCache')) {
553 + $GLOBALS['wp_fastest_cache']->deleteCache(true);
554 + }
555 + if (is_callable(array('Swift_Performance_Cache', 'clear_all_cache'))) {
556 + Swift_Performance_Cache::clear_all_cache();
557 + }
558 + if (is_callable(array('Hummingbird\WP_Hummingbird', 'flush_cache'))) {
559 + Hummingbird\WP_Hummingbird::flush_cache(true, false);
560 + }
548 561
549 - do_action('wp_reset_purge_cache');
562 + do_action('wp_reset_purge_cache');
550 563
551 - return true;
552 - } // do_purge_cache
564 + return true;
565 + } // do_purge_cache
553 566
554 567
555 - /**
556 - * Resets all theme options (mods).
557 - *
558 - * @param bool $all_themes Delete mods for all themes or just the current one
559 - *
560 - * @return int Number of deleted mod DB entries
561 - */
562 - function do_reset_theme_options($all_themes = true)
563 - {
564 - global $wpdb;
568 + /**
569 + * Resets all theme options (mods).
570 + *
571 + * @param bool $all_themes Delete mods for all themes or just the current one
572 + *
573 + * @return int Number of deleted mod DB entries
574 + */
575 + function do_reset_theme_options($all_themes = true)
576 + {
577 + global $wpdb;
565 578
566 - $query = $wpdb->prepare("DELETE FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s", array('mods\_%', 'theme_mods\_%'));
567 - $count = $wpdb->query($query);
579 + // phpcs:ignore db call warning as we are using uncommon queries
580 + $count = $wpdb->query($wpdb->prepare("DELETE FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s", array('mods\_%', 'theme_mods\_%'))); // phpcs:ignore
568 581
569 - do_action('wp_reset_reset_theme_options', $count);
582 + do_action('wp_reset_reset_theme_options', $count);
570 583
571 - return $count;
572 - } // do_reset_theme_options
584 + return $count;
585 + } // do_reset_theme_options
573 586
574 587
575 - /**
576 - * Deletes all files in uploads folder.
577 - *
578 - * @return int Number of deleted files and folders.
579 - */
580 - function do_delete_uploads()
581 - {
582 - $upload_dir = wp_get_upload_dir();
583 - $this->delete_count = 0;
588 + /**
589 + * Deletes all files in uploads folder.
590 + *
591 + * @return int Number of deleted files and folders.
592 + */
593 + function do_delete_uploads()
594 + {
595 + global $wp_filesystem;
596 + $this->wp_init_filesystem();
597 +
598 + $upload_dir = wp_get_upload_dir();
599 + $this->delete_count = 0;
584 600
585 - $this->delete_folder($upload_dir['basedir'], $upload_dir['basedir']);
601 + if ( $wp_filesystem->is_dir( $upload_dir['basedir'] ) ) {
586 602
587 - do_action('wp_reset_delete_uploads', $this->delete_count);
603 + // Get all files and directories in the folder.
604 + $files = $wp_filesystem->dirlist( $upload_dir['basedir'] );
605 +
606 + // Loop through the files and delete them.
607 + foreach ( $files as $file => $details ) {
608 + $file_path = trailingslashit( $upload_dir['basedir'] ) . $file;
609 + $wp_filesystem->delete( $file_path, true );
610 + $this->delete_count++;
611 + }
612 + }
588 613
589 - return $this->delete_count;
590 - } // do_delete_uploads
614 + do_action('wp_reset_delete_uploads', $this->delete_count);
591 615
616 + return $this->delete_count;
617 + } // do_delete_uploads
592 618
593 - /**
594 - * Recursively deletes a folder
595 - *
596 - * @param string $folder Recursive param.
597 - * @param string $base_folder Base folder.
598 - *
599 - * @return bool
600 - */
601 - private function delete_folder($folder, $base_folder)
602 - {
603 - $files = array_diff(scandir($folder), array('.', '..'));
619 + /**
620 + * Deactivate all plugins
621 + *
622 + * @param array keep_wp_reset - Keep WP Reset active and installed, silent_deactivate - Skip individual plugin deactivation functions when deactivating
623 + *
624 + * @return int Number of deactivated plugins.
625 + */
626 + function do_deactivate_plugins($params = array())
627 + {
628 + if (!function_exists('get_plugins')) {
629 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
630 + }
631 + if (!function_exists('request_filesystem_credentials')) {
632 + require_once ABSPATH . 'wp-admin/includes/file.php';
633 + }
604 634
605 - foreach ($files as $file) {
606 - if (is_dir($folder . DIRECTORY_SEPARATOR . $file)) {
607 - $this->delete_folder($folder . DIRECTORY_SEPARATOR . $file, $base_folder);
608 - } else {
609 - $tmp = @unlink($folder . DIRECTORY_SEPARATOR . $file);
610 - $this->delete_count = $this->delete_count + (int) $tmp;
611 - }
612 - } // foreach
635 + $wp_reset_basename = plugin_basename(WP_RESET_FILE);
636 + $params = shortcode_atts(array('keep_wp_reset' => true, 'silent_deactivate' => false), (array) $params);
613 637
614 - if ($folder != $base_folder) {
615 - $tmp = @rmdir($folder);
616 - $this->delete_count = $this->delete_count + (int) $tmp;
617 - return $tmp;
618 - } else {
619 - return true;
620 - }
621 - } // delete_folder
638 + $active_plugins = (array) get_option('active_plugins', array());
639 + if ($params['keep_wp_reset']) {
640 + if (($key = array_search($wp_reset_basename, $active_plugins)) !== false) {
641 + unset($active_plugins[$key]);
642 + }
643 + }
622 644
645 + if (!empty($active_plugins)) {
646 + deactivate_plugins($active_plugins, $params['silent_deactivate'], false);
647 + }
623 648
624 - /**
625 - * Deactivate all plugins
626 - *
627 - * @param array keep_wp_reset - Keep WP Reset active and installed, silent_deactivate - Skip individual plugin deactivation functions when deactivating
628 - *
629 - * @return int Number of deactivated plugins.
630 - */
631 - function do_deactivate_plugins($params = array())
632 - {
633 - if (!function_exists('get_plugins')) {
634 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
635 - }
636 - if (!function_exists('request_filesystem_credentials')) {
637 - require_once ABSPATH . 'wp-admin/includes/file.php';
638 - }
649 + do_action('wp_reset_deactivate_plugins', $active_plugins, $params);
639 650
640 - $wp_reset_basename = plugin_basename(WP_RESET_FILE);
641 - $params = shortcode_atts(array('keep_wp_reset' => true, 'silent_deactivate' => false), (array) $params);
651 + return sizeof($active_plugins);
652 + } // do_deactivate_plugins
642 653
643 - $active_plugins = (array) get_option('active_plugins', array());
644 - if ($params['keep_wp_reset']) {
645 - if (($key = array_search($wp_reset_basename, $active_plugins)) !== false) {
646 - unset($active_plugins[$key]);
647 - }
648 - }
649 654
650 - if (!empty($active_plugins)) {
651 - deactivate_plugins($active_plugins, $params['silent_deactivate'], false);
652 - }
655 + /**
656 + * Delete all plugins
657 + *
658 + * @param array keep_wp_reset - Keep WP Reset active and installed
659 + *
660 + * @return int Number of deleted plugins.
661 + */
662 + function do_delete_plugins($params = array())
663 + {
664 + if (!function_exists('get_plugins')) {
665 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
666 + }
667 + if (!function_exists('request_filesystem_credentials')) {
668 + require_once ABSPATH . 'wp-admin/includes/file.php';
669 + }
653 670
654 - do_action('wp_reset_deactivate_plugins', $active_plugins, $params);
671 + $wp_reset_basename = plugin_basename(WP_RESET_FILE);
672 + $params = shortcode_atts(array('keep_wp_reset' => true), (array) $params);
655 673
656 - return sizeof($active_plugins);
657 - } // do_deactivate_plugins
674 + $all_plugins = get_plugins();
675 + if ($params['keep_wp_reset']) {
676 + unset($all_plugins[$wp_reset_basename]);
677 + }
658 678
679 + if (!empty($all_plugins)) {
680 + delete_plugins(array_keys($all_plugins));
681 + }
659 682
660 - /**
661 - * Delete all plugins
662 - *
663 - * @param array keep_wp_reset - Keep WP Reset active and installed
664 - *
665 - * @return int Number of deleted plugins.
666 - */
667 - function do_delete_plugins($params = array())
668 - {
669 - if (!function_exists('get_plugins')) {
670 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
671 - }
672 - if (!function_exists('request_filesystem_credentials')) {
673 - require_once ABSPATH . 'wp-admin/includes/file.php';
674 - }
683 + do_action('wp_reset_delete_plugins', $all_plugins, $params);
675 684
676 - $wp_reset_basename = plugin_basename(WP_RESET_FILE);
677 - $params = shortcode_atts(array('keep_wp_reset' => true), (array) $params);
685 + return sizeof($all_plugins);
686 + } // do_delete_plugins
678 687
679 - $all_plugins = get_plugins();
680 - if ($params['keep_wp_reset']) {
681 - unset($all_plugins[$wp_reset_basename]);
682 - }
683 688
684 - if (!empty($all_plugins)) {
685 - delete_plugins(array_keys($all_plugins));
686 - }
689 + /**
690 + * Delete all themes
691 + *
692 + * @param bool $keep_default_theme Keep default theme
693 + *
694 + * @return int Number of deleted themes.
695 + */
696 + function do_delete_themes($keep_default_theme = true)
697 + {
698 + global $wp_version;
687 699
688 - do_action('wp_reset_delete_plugins', $all_plugins, $params);
700 + if (!function_exists('delete_theme')) {
701 + require_once ABSPATH . 'wp-admin/includes/theme.php';
702 + }
689 703
690 - return sizeof($all_plugins);
691 - } // do_delete_plugins
704 + if (!function_exists('request_filesystem_credentials')) {
705 + require_once ABSPATH . 'wp-admin/includes/file.php';
706 + }
692 707
708 + if (version_compare($wp_version, '5.0', '<') === true) {
709 + $default_theme = 'twentyseventeen';
710 + } else {
711 + $default_theme = 'twentytwentyone';
712 + }
693 713
694 - /**
695 - * Delete all themes
696 - *
697 - * @param bool $keep_default_theme Keep default theme
698 - *
699 - * @return int Number of deleted themes.
700 - */
701 - function do_delete_themes($keep_default_theme = true)
702 - {
703 - global $wp_version;
714 + $all_themes = wp_get_themes(array('errors' => null));
704 715
705 - if (!function_exists('delete_theme')) {
706 - require_once ABSPATH . 'wp-admin/includes/theme.php';
707 - }
716 + if (true == $keep_default_theme) {
717 + unset($all_themes[$default_theme]);
718 + }
708 719
709 - if (!function_exists('request_filesystem_credentials')) {
710 - require_once ABSPATH . 'wp-admin/includes/file.php';
711 - }
720 + foreach ($all_themes as $theme_slug => $theme_details) {
721 + $res = delete_theme($theme_slug);
722 + }
712 723
713 - if (version_compare($wp_version, '5.0', '<') === true) {
714 - $default_theme = 'twentyseventeen';
715 - } else {
716 - $default_theme = 'twentytwentyone';
717 - }
724 + if (false == $keep_default_theme) {
725 + update_option('template', '');
726 + update_option('stylesheet', '');
727 + update_option('current_theme', '');
728 + }
718 729
719 - $all_themes = wp_get_themes(array('errors' => null));
730 + do_action('wp_reset_delete_themes', $all_themes);
720 731
721 - if (true == $keep_default_theme) {
722 - unset($all_themes[$default_theme]);
723 - }
732 + return sizeof($all_themes);
733 + } // do_delete_themes
724 734
725 - foreach ($all_themes as $theme_slug => $theme_details) {
726 - $res = delete_theme($theme_slug);
727 - }
728 735
729 - if (false == $keep_default_theme) {
730 - update_option('template', '');
731 - update_option('stylesheet', '');
732 - update_option('current_theme', '');
733 - }
736 + /**
737 + * Truncate custom tables
738 + *
739 + * @return int Number of truncated tables.
740 + */
741 + function do_truncate_custom_tables()
742 + {
743 + global $wpdb;
744 + $custom_tables = $this->get_custom_tables();
734 745
735 - do_action('wp_reset_delete_themes', $all_themes);
746 + foreach ($custom_tables as $tbl) {
747 + $wpdb->wpreset_custom_table = $tbl['name'];
748 + // phpcs:ignore db call warning as we are using uncommon queries
749 + $wpdb->query('SET foreign_key_checks = 0'); // phpcs:ignore
750 + $wpdb->query("TRUNCATE TABLE " . $wpdb->wpreset_custom_table); // phpcs:ignore
751 + } // foreach
736 752
737 - return sizeof($all_themes);
738 - } // do_delete_themes
753 + do_action('wp_reset_truncate_custom_tables', $custom_tables);
739 754
755 + return sizeof($custom_tables);
756 + } // do_truncate_custom_tables
740 757
741 - /**
742 - * Truncate custom tables
743 - *
744 - * @return int Number of truncated tables.
745 - */
746 - function do_truncate_custom_tables()
747 - {
748 - global $wpdb;
749 - $custom_tables = $this->get_custom_tables();
750 758
751 - foreach ($custom_tables as $tbl) {
752 - $wpdb->query('SET foreign_key_checks = 0');
753 - $wpdb->query("TRUNCATE TABLE {$tbl['name']}");
754 - } // foreach
759 + /**
760 + * Drop custom tables
761 + *
762 + * @return int Number of dropped tables.
763 + */
764 + function do_drop_custom_tables()
765 + {
766 + global $wpdb;
767 + $custom_tables = $this->get_custom_tables();
755 768
756 - do_action('wp_reset_truncate_custom_tables', $custom_tables);
769 + foreach ($custom_tables as $tbl) {
770 + $wpdb->wpreset_custom_table = $tbl['name'];
771 + // phpcs:ignore db call warning as we are using uncommon queries
772 + $wpdb->query('SET foreign_key_checks = 0'); // phpcs:ignore
773 + $wpdb->query("DROP TABLE IF EXISTS " . $wpdb->wpreset_custom_table); // phpcs:ignore
774 + } // foreach
757 775
758 - return sizeof($custom_tables);
759 - } // do_truncate_custom_tables
776 + do_action('wp_reset_drop_custom_tables', $custom_tables);
760 777
778 + return sizeof($custom_tables);
779 + } // do_drop_custom_tables
761 780
762 - /**
763 - * Drop custom tables
764 - *
765 - * @return int Number of dropped tables.
766 - */
767 - function do_drop_custom_tables()
768 - {
769 - global $wpdb;
770 - $custom_tables = $this->get_custom_tables();
771 781
772 - foreach ($custom_tables as $tbl) {
773 - $wpdb->query('SET foreign_key_checks = 0');
774 - $wpdb->query("DROP TABLE IF EXISTS {$tbl['name']}");
775 - } // foreach
782 + /**
783 + * Delete .htaccess file
784 + *
785 + * @return bool|WP_Error Action status.
786 + */
787 + function do_delete_htaccess()
788 + {
789 + global $wp_filesystem;
776 790
777 - do_action('wp_reset_drop_custom_tables', $custom_tables);
791 + if (empty($wp_filesystem)) {
792 + require_once ABSPATH . '/wp-admin/includes/file.php';
793 + WP_Filesystem();
794 + }
778 795
779 - return sizeof($custom_tables);
780 - } // do_drop_custom_tables
796 + $htaccess_path = $this->get_htaccess_path();
797 + clearstatcache();
781 798
799 + do_action('wp_reset_delete_htaccess', $htaccess_path);
782 800
783 - /**
784 - * Delete .htaccess file
785 - *
786 - * @return bool|WP_Error Action status.
787 - */
788 - function do_delete_htaccess()
789 - {
790 - global $wp_filesystem;
801 + if (!$wp_filesystem->is_readable($htaccess_path)) {
802 + return new WP_Error(1, 'Htaccess file does not exist; there\'s nothing to delete.');
803 + }
791 804
792 - if (empty($wp_filesystem)) {
793 - require_once ABSPATH . '/wp-admin/includes/file.php';
794 - WP_Filesystem();
795 - }
805 + if (!$wp_filesystem->is_writable($htaccess_path)) {
806 + return new WP_Error(1, 'Htaccess file is not writable.');
807 + }
796 808
797 - $htaccess_path = $this->get_htaccess_path();
798 - clearstatcache();
809 + if ($wp_filesystem->delete($htaccess_path, false, 'f')) {
810 + return true;
811 + } else {
812 + return new WP_Error(1, 'Unknown error. Unable to delete htaccess file.');
813 + }
814 + } // do_delete_htaccess
799 815
800 - do_action('wp_reset_delete_htaccess', $htaccess_path);
801 816
802 - if (!$wp_filesystem->is_readable($htaccess_path)) {
803 - return new WP_Error(1, 'Htaccess file does not exist; there\'s nothing to delete.');
804 - }
817 + /**
818 + * Get .htaccess file path.
819 + *
820 + * @return string
821 + */
822 + function get_htaccess_path()
823 + {
824 + if (!function_exists('get_home_path')) {
825 + require_once ABSPATH . 'wp-admin/includes/file.php';
826 + }
805 827
806 - if (!$wp_filesystem->is_writable($htaccess_path)) {
807 - return new WP_Error(1, 'Htaccess file is not writable.');
808 - }
828 + if ($this->is_cli_running()) {
829 + $_SERVER['SCRIPT_FILENAME'] = ABSPATH;
830 + }
809 831
810 - if ($wp_filesystem->delete($htaccess_path, false, 'f')) {
811 - return true;
812 - } else {
813 - return new WP_Error(1, 'Unknown error. Unable to delete htaccess file.');
814 - }
815 - } // do_delete_htaccess
832 + $filepath = get_home_path() . '.htaccess';
816 833
834 + return $filepath;
835 + } // get_htaccess_path
817 836
818 - /**
819 - * Get .htaccess file path.
820 - *
821 - * @return string
822 - */
823 - function get_htaccess_path()
824 - {
825 - if (!function_exists('get_home_path')) {
826 - require_once ABSPATH . 'wp-admin/includes/file.php';
827 - }
828 837
829 - if ($this->is_cli_running()) {
830 - $_SERVER['SCRIPT_FILENAME'] = ABSPATH;
831 - }
838 + /**
839 + * Run one tool via AJAX call
840 + *
841 + * @return null
842 + */
843 + function ajax_run_tool()
844 + {
845 + check_ajax_referer('wp-reset_run_tool');
832 846
833 - $filepath = get_home_path() . '.htaccess';
847 + if (!current_user_can('manage_options')) {
848 + wp_send_json_error(__('You are not allowed to run this action.', 'wp-reset'));
849 + }
834 850
835 - return $filepath;
836 - } // get_htaccess_path
851 + if(!isset($_GET['tool'])){
852 + wp_send_json_error(__('Unknown tool.', 'wp-reset'));
853 + }
837 854
855 + $tool = trim(sanitize_text_field(wp_unslash($_GET['tool'])));
838 856
839 - /**
840 - * Run one tool via AJAX call
841 - *
842 - * @return null
843 - */
844 - function ajax_run_tool()
845 - {
846 - check_ajax_referer('wp-reset_run_tool');
857 + if(isset($_GET['extra_data'])){
858 + $extra_data = trim(sanitize_text_field(wp_unslash($_GET['extra_data'])));
859 + } else {
860 + $extra_data = '';
861 + }
847 862
848 - if (!current_user_can('administrator')) {
849 - wp_send_json_error(__('You are not allowed to run this action.', 'wp-reset'));
850 - }
863 + if ($tool == 'delete_transients') {
864 + $cnt = $this->do_delete_transients();
865 + wp_send_json_success($cnt);
866 + } elseif ($tool == 'reset_theme_options') {
867 + $cnt = $this->do_reset_theme_options(true);
868 + wp_send_json_success($cnt);
869 + } elseif ($tool == 'purge_cache') {
870 + $this->do_purge_cache();
871 + wp_send_json_success();
872 + } elseif ($tool == 'delete_wp_cookies') {
873 + wp_clear_auth_cookie();
874 + wp_send_json_success();
875 + } elseif ($tool == 'delete_themes') {
876 + $cnt = $this->do_delete_themes(false);
877 + wp_send_json_success($cnt);
878 + } elseif ($tool == 'deactivate_plugins') {
879 + $cnt = $this->do_deactivate_plugins($extra_data);
880 + wp_send_json_success($cnt);
881 + } elseif ($tool == 'delete_plugins') {
882 + $cnt = $this->do_delete_plugins($extra_data);
883 + wp_send_json_success($cnt);
884 + } elseif ($tool == 'delete_uploads') {
885 + $cnt = $this->do_delete_uploads();
886 + wp_send_json_success($cnt);
887 + } elseif ($tool == 'delete_htaccess') {
888 + $tmp = $this->do_delete_htaccess();
889 + if (is_wp_error($tmp)) {
890 + wp_send_json_error($tmp->get_error_message());
891 + } else {
892 + wp_send_json_success($tmp);
893 + }
894 + } elseif ($tool == 'drop_custom_tables') {
895 + $cnt = $this->do_drop_custom_tables();
896 + wp_send_json_success($cnt);
897 + } elseif ($tool == 'truncate_custom_tables') {
898 + $cnt = $this->do_truncate_custom_tables();
899 + wp_send_json_success($cnt);
900 + } elseif ($tool == 'delete_snapshot') {
901 + $res = $this->do_delete_snapshot($extra_data);
902 + if (is_wp_error($res)) {
903 + wp_send_json_error($res->get_error_message());
904 + } else {
905 + wp_send_json_success();
906 + }
907 + } elseif ($tool == 'download_snapshot') {
908 + $res = $this->do_export_snapshot($extra_data);
909 + if (is_wp_error($res)) {
910 + wp_send_json_error($res->get_error_message());
911 + } else {
912 + $url = content_url() . '/' . $this->snapshots_folder . '/' . $res;
913 + wp_send_json_success($url);
914 + }
915 + } elseif ($tool == 'restore_snapshot') {
916 + $res = $this->do_restore_snapshot($extra_data);
917 + if (is_wp_error($res)) {
918 + wp_send_json_error($res->get_error_message());
919 + } else {
920 + wp_send_json_success();
921 + }
922 + } elseif ($tool == 'compare_snapshots') {
923 + $res = $this->do_compare_snapshots($extra_data);
924 + if (is_wp_error($res)) {
925 + wp_send_json_error($res->get_error_message());
926 + } else {
927 + wp_send_json_success($res);
928 + }
929 + } elseif ($tool == 'create_snapshot') {
930 + $res = $this->do_create_snapshot($extra_data);
931 + if (is_wp_error($res)) {
932 + wp_send_json_error($res->get_error_message());
933 + } else {
934 + wp_send_json_success();
935 + }
936 + } elseif ($tool == 'get_table_details') {
937 + $res = WP_Reset_Utility::get_table_details();
938 + wp_send_json_success($res);
939 + } elseif (
940 + $tool == 'check_deactivate_plugin' ||
941 + $tool == 'check_delete_plugin' ||
942 + $tool == 'check_install_plugin' ||
943 + $tool == 'check_activate_plugin'
944 + ) {
945 + if(!isset($_GET['slug'])){
946 + wp_send_json_success('unknown plugin');
947 + }
948 +
949 + $slug = sanitize_text_field(wp_unslash($_GET['slug']));
950 + $path = $this->get_plugin_path($slug);
851 951
852 - $tool = trim(sanitize_text_field(@$_GET['tool']));
853 - $extra_data = trim(sanitize_text_field(@$_GET['extra_data']));
952 + if (false !== ($error = get_transient('wf_install_error_' . $slug))) {
953 + delete_transient('wf_install_error_' . $slug);
954 + wp_send_json_success($error);
955 + }
854 956
855 - if ($tool == 'delete_transients') {
856 - $cnt = $this->do_delete_transients();
857 - wp_send_json_success($cnt);
858 - } elseif ($tool == 'reset_theme_options') {
859 - $cnt = $this->do_reset_theme_options(true);
860 - wp_send_json_success($cnt);
861 - } elseif ($tool == 'purge_cache') {
862 - $this->do_purge_cache();
863 - wp_send_json_success();
864 - } elseif ($tool == 'delete_wp_cookies') {
865 - wp_clear_auth_cookie();
866 - wp_send_json_success();
867 - } elseif ($tool == 'delete_themes') {
868 - $cnt = $this->do_delete_themes(false);
869 - wp_send_json_success($cnt);
870 - } elseif ($tool == 'deactivate_plugins') {
871 - $cnt = $this->do_deactivate_plugins($extra_data);
872 - wp_send_json_success($cnt);
873 - } elseif ($tool == 'delete_plugins') {
874 - $cnt = $this->do_delete_plugins($extra_data);
875 - wp_send_json_success($cnt);
876 - } elseif ($tool == 'delete_uploads') {
877 - $cnt = $this->do_delete_uploads();
878 - wp_send_json_success($cnt);
879 - } elseif ($tool == 'delete_htaccess') {
880 - $tmp = $this->do_delete_htaccess();
881 - if (is_wp_error($tmp)) {
882 - wp_send_json_error($tmp->get_error_message());
883 - } else {
884 - wp_send_json_success($tmp);
885 - }
886 - } elseif ($tool == 'drop_custom_tables') {
887 - $cnt = $this->do_drop_custom_tables();
888 - wp_send_json_success($cnt);
889 - } elseif ($tool == 'truncate_custom_tables') {
890 - $cnt = $this->do_truncate_custom_tables();
891 - wp_send_json_success($cnt);
892 - } elseif ($tool == 'delete_snapshot') {
893 - $res = $this->do_delete_snapshot($extra_data);
894 - if (is_wp_error($res)) {
895 - wp_send_json_error($res->get_error_message());
896 - } else {
897 - wp_send_json_success();
898 - }
899 - } elseif ($tool == 'download_snapshot') {
900 - $res = $this->do_export_snapshot($extra_data);
901 - if (is_wp_error($res)) {
902 - wp_send_json_error($res->get_error_message());
903 - } else {
904 - $url = content_url() . '/' . $this->snapshots_folder . '/' . $res;
905 - wp_send_json_success($url);
906 - }
907 - } elseif ($tool == 'restore_snapshot') {
908 - $res = $this->do_restore_snapshot($extra_data);
909 - if (is_wp_error($res)) {
910 - wp_send_json_error($res->get_error_message());
911 - } else {
912 - wp_send_json_success();
913 - }
914 - } elseif ($tool == 'compare_snapshots') {
915 - $res = $this->do_compare_snapshots($extra_data);
916 - if (is_wp_error($res)) {
917 - wp_send_json_error($res->get_error_message());
918 - } else {
919 - wp_send_json_success($res);
920 - }
921 - } elseif ($tool == 'create_snapshot') {
922 - $res = $this->do_create_snapshot($extra_data);
923 - if (is_wp_error($res)) {
924 - wp_send_json_error($res->get_error_message());
925 - } else {
926 - wp_send_json_success();
927 - }
928 - } elseif ($tool == 'get_table_details') {
929 - $res = WP_Reset_Utility::get_table_details();
930 - wp_send_json_success($res);
931 - } elseif (
932 - $tool == 'check_deactivate_plugin' ||
933 - $tool == 'check_delete_plugin' ||
934 - $tool == 'check_install_plugin' ||
935 - $tool == 'check_activate_plugin'
936 - ) {
937 - $path = $this->get_plugin_path(sanitize_text_field($_GET['slug']));
957 + if (false !== $path) {
958 + $active_plugins = (array) get_option('active_plugins', array());
959 + if (false !== array_search($path, $active_plugins)) {
960 + wp_send_json_success('active');
961 + } else {
962 + wp_send_json_success('inactive');
963 + }
964 + } else {
965 + wp_send_json_success('deleted');
966 + }
967 + } elseif ($tool == 'install_plugin') {
968 + if(!isset($_GET['slug'])){
969 + wp_send_json_success('unknown plugin');
970 + }
971 +
972 + $slug = sanitize_text_field(wp_unslash($_GET['slug']));
938 973
939 - if (false !== ($error = get_transient('wf_install_error_' . sanitize_text_field($_GET['slug'])))) {
940 - delete_transient('wf_install_error_' . sanitize_text_field($_GET['slug']));
941 - wp_send_json_success($error);
942 - }
974 + @include_once ABSPATH . 'wp-admin/includes/plugin.php';
975 + @include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
976 + @include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
977 + @include_once ABSPATH . 'wp-admin/includes/file.php';
978 + @include_once ABSPATH . 'wp-admin/includes/misc.php';
943 979
944 - if (false !== $path) {
945 - $active_plugins = (array) get_option('active_plugins', array());
946 - if (false !== array_search($path, $active_plugins)) {
947 - wp_send_json_success('active');
980 + wp_cache_flush();
981 +
982 + $path = $this->get_plugin_path($slug);
983 +
984 + if (false !== $path) {
985 + // Plugin is already installed
986 + wp_send_json_success();
987 + } else {
988 + // Install Plugin
989 + $skin = new WP_Ajax_Upgrader_Skin();
990 + $upgrader = new Plugin_Upgrader($skin);
991 + $upgrader->install('https://downloads.wordpress.org/plugin/' . $slug . '.latest-stable.zip');
992 + wp_send_json_success();
993 + }
994 + } elseif ($tool == 'activate_plugin') {
995 + if(!isset($_GET['slug'])){
996 + wp_send_json_success('unknown plugin');
997 + }
998 +
999 + $slug = sanitize_text_field(wp_unslash($_GET['slug']));
1000 +
1001 + $path = $this->get_plugin_path($slug);
1002 + activate_plugin($path);
1003 + wp_send_json_success();
1004 + } elseif ($tool == 'before_reset') {
1005 + $active_plugins = get_option('active_plugins');
1006 + set_transient('wpr_active_plugins', $active_plugins, 100);
1007 + remove_all_actions('update_option_active_plugins');
1008 + update_option('active_plugins', array(plugin_basename(__FILE__)));
1009 + wp_send_json_success();
948 1010 } else {
949 - wp_send_json_success('inactive');
1011 + wp_send_json_error(__('Unknown tool.', 'wp-reset'));
950 1012 }
951 - } else {
952 - wp_send_json_success('deleted');
953 - }
954 - } elseif ($tool == 'install_plugin') {
955 - $slug = sanitize_text_field($_GET['slug']);
1013 + } // ajax_run_tool
956 1014
957 - @include_once ABSPATH . 'wp-admin/includes/plugin.php';
958 - @include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
959 - @include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
960 - @include_once ABSPATH . 'wp-admin/includes/file.php';
961 - @include_once ABSPATH . 'wp-admin/includes/misc.php';
962 1015
963 - wp_cache_flush();
1016 + /**
1017 + * Get plugin path from slug
1018 + *
1019 + * @return string path
1020 + */
1021 + function get_plugin_path($slug)
1022 + {
1023 + $all_plugins = get_plugins();
1024 + foreach ($all_plugins as $plugin_path => $plugin) {
1025 + if (strpos($plugin_path, $slug . '/') === 0) {
1026 + return $plugin_path;
1027 + }
1028 + }
1029 + return false;
1030 + } // get_plugin_path
964 1031
965 - $path = $this->get_plugin_path($slug);
966 1032
967 - if (false !== $path) {
968 - // Plugin is already installed
969 - wp_send_json_success();
970 - } else {
971 - // Install Plugin
972 - $skin = new WP_Ajax_Upgrader_Skin();
973 - $upgrader = new Plugin_Upgrader($skin);
974 - $upgrader->install('https://downloads.wordpress.org/plugin/' . $slug . '.latest-stable.zip');
975 - wp_send_json_success();
976 - }
977 - } elseif ($tool == 'activate_plugin') {
978 - $path = $this->get_plugin_path(sanitize_text_field($_GET['slug']));
979 - activate_plugin($path);
980 - wp_send_json_success();
981 - } else {
982 - wp_send_json_error(__('Unknown tool.', 'wp-reset'));
983 - }
984 - } // ajax_run_tool
1033 + /**
1034 + * Reinstall / reset the WP site
1035 + * There are no failsafes in the function - it reinstalls when called
1036 + * Redirects when done
1037 + *
1038 + * @param array $params Optional.
1039 + *
1040 + * @return null
1041 + */
1042 + function do_reinstall($params = array())
1043 + {
1044 + global $current_user, $wpdb;
985 1045
1046 + // only admins can reset; double-check
1047 + if (!$this->is_cli_running() && !current_user_can('manage_options')) {
1048 + return false;
1049 + }
986 1050
987 - /**
988 - * Get plugin path from slug
989 - *
990 - * @return string path
991 - */
992 - function get_plugin_path($slug)
993 - {
994 - $all_plugins = get_plugins();
995 - foreach ($all_plugins as $plugin_path => $plugin) {
996 - if (strpos($plugin_path, $slug . '/') === 0) {
997 - return $plugin_path;
998 - }
999 - }
1000 - return false;
1001 - } // get_plugin_path
1051 + // make sure the function is available to us
1052 + if (!function_exists('wp_install')) {
1053 + require ABSPATH . '/wp-admin/includes/upgrade.php';
1054 + }
1002 1055
1056 + // save values that need to be restored after reset
1057 + $blogname = get_option('blogname');
1058 + $blog_public = get_option('blog_public');
1059 + $wplang = get_option('wplang');
1060 + $siteurl = get_option('siteurl');
1061 + $home = get_option('home');
1062 + $snapshots = $this->get_snapshots();
1003 1063
1004 - /**
1005 - * Reinstall / reset the WP site
1006 - * There are no failsafes in the function - it reinstalls when called
1007 - * Redirects when done
1008 - *
1009 - * @param array $params Optional.
1010 - *
1011 - * @return null
1012 - */
1013 - function do_reinstall($params = array())
1014 - {
1015 - global $current_user, $wpdb;
1064 + $active_plugins = get_transient('wpr_active_plugins');
1065 + $active_theme = wp_get_theme();
1016 1066
1017 - // only admins can reset; double-check
1018 - if (!$this->is_cli_running() && !current_user_can('administrator')) {
1019 - return false;
1020 - }
1067 + // for WP-CLI
1068 + if (!$current_user->ID) {
1069 + $tmp = get_users(array('role' => 'administrator', 'order' => 'ASC', 'order_by' => 'ID'));
1070 + if (empty($tmp[0]->user_login)) {
1071 + return new WP_Error(1, 'Reset failed. Unable to find any admin users in database.');
1072 + }
1073 + $current_user = $tmp[0];
1074 + }
1021 1075
1022 - // make sure the function is available to us
1023 - if (!function_exists('wp_install')) {
1024 - require ABSPATH . '/wp-admin/includes/upgrade.php';
1025 - }
1076 + // delete custom tables with WP's prefix
1077 + $prefix = str_replace('_', '\_', $wpdb->prefix);
1026 1078
1027 - // save values that need to be restored after reset
1028 - $blogname = get_option('blogname');
1029 - $blog_public = get_option('blog_public');
1030 - $wplang = get_option('wplang');
1031 - $siteurl = get_option('siteurl');
1032 - $home = get_option('home');
1033 - $snapshots = $this->get_snapshots();
1079 + // phpcs:ignore db call warning as we are using uncommon queries
1080 + $tables = $wpdb->get_col($wpdb->prepare("SHOW TABLES LIKE %s", array($prefix . '%'))); // phpcs:ignore
1034 1081
1035 - $active_plugins = get_option('active_plugins');
1036 - $active_theme = wp_get_theme();
1082 + foreach ($tables as $table) {
1083 + $wpdb->wpreset_table = $table;
1084 + $wpdb->query("DROP TABLE " . $wpdb->wpreset_table); // phpcs:ignore
1085 + }
1037 1086
1038 - // for WP-CLI
1039 - if (!$current_user->ID) {
1040 - $tmp = get_users(array('role' => 'administrator', 'order' => 'ASC', 'order_by' => 'ID'));
1041 - if (empty($tmp[0]->user_login)) {
1042 - return new WP_Error(1, 'Reset failed. Unable to find any admin users in database.');
1043 - }
1044 - $current_user = $tmp[0];
1045 - }
1087 + $old_user_pass = $current_user->user_pass;
1046 1088
1047 - // delete custom tables with WP's prefix
1048 - $prefix = str_replace('_', '\_', $wpdb->prefix);
1049 - $tables = $wpdb->get_col("SHOW TABLES LIKE '{$prefix}%'");
1050 - foreach ($tables as $table) {
1051 - $wpdb->query("DROP TABLE $table");
1052 - }
1089 + // suppress errors for WP_CLI
1090 + $result = @wp_install($blogname, $current_user->user_login, $current_user->user_email, $blog_public, '', md5(wp_rand()), $wplang);
1091 + $user_id = $result['user_id'];
1053 1092
1054 - // supress errors for WP_CLI
1055 - $result = @wp_install($blogname, $current_user->user_login, $current_user->user_email, $blog_public, '', md5(rand()), $wplang);
1056 - $user_id = $result['user_id'];
1093 + // restore user pass
1094 + // phpcs:ignore db call warning as we are using uncommon queries
1095 + $wpdb->query($wpdb->prepare("UPDATE {$wpdb->users} SET user_pass = %s, user_activation_key = %s WHERE ID = %d LIMIT 1", array($old_user_pass, '', $user_id))); // phpcs:ignore
1096 + $current_user->user_pass = $old_user_pass;
1057 1097
1058 - // restore user pass
1059 - $query = $wpdb->prepare("UPDATE {$wpdb->users} SET user_pass = %s, user_activation_key = '' WHERE ID = %d LIMIT 1", array($current_user->user_pass, $user_id));
1060 - $wpdb->query($query);
1098 + // restore rest of the settings including WP Reset's
1099 + update_option('siteurl', $siteurl);
1100 + update_option('home', $home);
1101 + update_option('wp-reset', $this->options);
1102 + update_option('wp-reset-snapshots', $snapshots);
1061 1103
1062 - // restore rest of the settings including WP Reset's
1063 - update_option('siteurl', $siteurl);
1064 - update_option('home', $home);
1065 - update_option('wp-reset', $this->options);
1066 - update_option('wp-reset-snapshots', $snapshots);
1104 + // remove password nag
1105 + if (get_user_meta($user_id, 'default_password_nag')) {
1106 + update_user_meta($user_id, 'default_password_nag', false);
1107 + }
1108 + if (get_user_meta($user_id, $wpdb->prefix . 'default_password_nag')) {
1109 + update_user_meta($user_id, $wpdb->prefix . 'default_password_nag', false);
1110 + }
1067 1111
1068 - // remove password nag
1069 - if (get_user_meta($user_id, 'default_password_nag')) {
1070 - update_user_meta($user_id, 'default_password_nag', false);
1071 - }
1072 - if (get_user_meta($user_id, $wpdb->prefix . 'default_password_nag')) {
1073 - update_user_meta($user_id, $wpdb->prefix . 'default_password_nag', false);
1074 - }
1112 + $meta = $this->get_meta();
1113 + $meta['reset_count']++;
1114 + $this->update_options('meta', $meta);
1075 1115
1076 - $meta = $this->get_meta();
1077 - $meta['reset_count']++;
1078 - $this->update_options('meta', $meta);
1116 + // reactivate theme
1117 + if (!empty($params['reactivate_theme'])) {
1118 + switch_theme($active_theme->get_stylesheet());
1119 + }
1079 1120
1080 - // reactivate theme
1081 - if (!empty($params['reactivate_theme'])) {
1082 - switch_theme($active_theme->get_stylesheet());
1083 - }
1121 + // reactivate WP Reset
1122 + if (!empty($params['reactivate_wpreset'])) {
1123 + activate_plugin(plugin_basename(__FILE__));
1124 + }
1084 1125
1085 - // reactivate WP Reset
1086 - if (!empty($params['reactivate_wpreset'])) {
1087 - activate_plugin(plugin_basename(__FILE__));
1088 - }
1126 + // reactivate all plugins
1127 + if (!empty($params['reactivate_plugins'])) {
1128 + foreach ($active_plugins as $plugin_file) {
1129 + activate_plugin($plugin_file);
1130 + }
1131 + }
1089 1132
1090 - // reactivate all plugins
1091 - if (!empty($params['reactivate_plugins'])) {
1092 - foreach ($active_plugins as $plugin_file) {
1093 - activate_plugin($plugin_file);
1094 - }
1095 - }
1133 + if (!$this->is_cli_running()) {
1134 + // log out and log in the old/new user
1135 + // since the password doesn't change this is potentially unnecessary
1136 + wp_clear_auth_cookie();
1137 + wp_set_auth_cookie($user_id);
1096 1138
1097 - if (!$this->is_cli_running()) {
1098 - // log out and log in the old/new user
1099 - // since the password doesn't change this is potentially unnecessary
1100 - wp_clear_auth_cookie();
1101 - wp_set_auth_cookie($user_id);
1139 + wp_safe_redirect(admin_url() . '?wp-reset=success');
1140 + exit;
1141 + }
1142 + } // do_reinstall
1102 1143
1103 - wp_redirect(admin_url() . '?wp-reset=success');
1104 - exit;
1105 - }
1106 - } // do_reinstall
1107 1144
1145 + /**
1146 + * Checks wp_reset post value and performs all actions
1147 + *
1148 + * @return null|bool
1149 + */
1150 + function do_all_actions()
1151 + {
1152 + // only admins can perform actions
1153 + if (!current_user_can('manage_options')) {
1154 + return;
1155 + }
1108 1156
1109 - /**
1110 - * Checks wp_reset post value and performs all actions
1111 - *
1112 - * @return null|bool
1113 - */
1114 - function do_all_actions()
1115 - {
1116 - // only admins can perform actions
1117 - if (!current_user_can('administrator')) {
1118 - return;
1119 - }
1157 + if (!empty($_GET['wp-reset']) && sanitize_text_field(wp_unslash($_GET['wp-reset'])) == 'success') {
1158 + add_action('admin_notices', array($this, 'notice_successful_reset'));
1159 + }
1120 1160
1121 - if (!empty($_GET['wp-reset']) && sanitize_text_field($_GET['wp-reset']) == 'success') {
1122 - add_action('admin_notices', array($this, 'notice_successful_reset'));
1123 - }
1161 + // check nonce
1162 + if (true === isset($_POST['wp_reset_confirm']) && (!isset($_POST['_wpnonce']) || false === wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_wpnonce'])), 'wp-reset'))) {
1163 + add_settings_error('wp-reset', 'bad-nonce', __('Something went wrong. Please refresh the page and try again.', 'wp-reset'), 'error');
1164 + return false;
1165 + }
1124 1166
1125 - // check nonce
1126 - if (true === isset($_POST['wp_reset_confirm']) && false === wp_verify_nonce(@$_POST['_wpnonce'], 'wp-reset')) {
1127 - add_settings_error('wp-reset', 'bad-nonce', __('Something went wrong. Please refresh the page and try again.', 'wp-reset'), 'error');
1128 - return false;
1129 - }
1167 + // check confirmation code
1168 + if (true === isset($_POST['wp_reset_confirm']) && 'reset' !== sanitize_text_field(wp_unslash($_POST['wp_reset_confirm']))) {
1169 + add_settings_error('wp-reset', 'bad-confirm', __('<b>Invalid confirmation code.</b> Please type "reset" in the confirmation field.', 'wp-reset'), 'error');
1170 + return false;
1171 + }
1130 1172
1131 - // check confirmation code
1132 - if (true === isset($_POST['wp_reset_confirm']) && 'reset' !== sanitize_text_field($_POST['wp_reset_confirm'])) {
1133 - add_settings_error('wp-reset', 'bad-confirm', __('<b>Invalid confirmation code.</b> Please type "reset" in the confirmation field.', 'wp-reset'), 'error');
1134 - return false;
1135 - }
1173 + // only one action at the moment
1174 + if (true === isset($_POST['wp_reset_confirm']) && 'reset' === sanitize_text_field(wp_unslash($_POST['wp_reset_confirm']))) {
1175 + $params = array(
1176 + 'reactivate_theme' => '0',
1177 + 'reactivate_plugins' => '0',
1178 + 'reactivate_wpreset' => '0',
1179 + );
1180 + if (isset($_POST['wpr-post-reset']['reactivate_theme'])) {
1181 + $params['reactivate_theme'] = true;
1182 + }
1183 + if (isset($_POST['wpr-post-reset']['reactivate_plugins'])) {
1184 + $params['reactivate_plugins'] = true;
1185 + }
1186 + if (isset($_POST['wpr-post-reset']['reactivate_wpreset'])) {
1187 + $params['reactivate_wpreset'] = true;
1188 + }
1136 1189
1137 - // only one action at the moment
1138 - if (true === isset($_POST['wp_reset_confirm']) && 'reset' === sanitize_text_field($_POST['wp_reset_confirm'])) {
1139 - $params = array(
1140 - 'reactivate_theme' => '0',
1141 - 'reactivate_plugins' => '0',
1142 - 'reactivate_wpreset' => '0',
1143 - );
1144 - if (isset($_POST['wpr-post-reset']['reactivate_theme'])) {
1145 - $params['reactivate_theme'] = true;
1146 - }
1147 - if (isset($_POST['wpr-post-reset']['reactivate_plugins'])) {
1148 - $params['reactivate_plugins'] = true;
1149 - }
1150 - if (isset($_POST['wpr-post-reset']['reactivate_wpreset'])) {
1151 - $params['reactivate_wpreset'] = true;
1152 - }
1190 + $this->do_reinstall($params);
1191 + }
1192 + } // do_all_actions
1153 1193
1154 - $this->do_reinstall($params);
1155 - }
1156 - } // do_all_actions
1157 1194
1195 + /**
1196 + * Add "Open WP Reset Tools" action link to plugins table, left part
1197 + *
1198 + * @param array $links Initial list of links.
1199 + *
1200 + * @return array
1201 + */
1202 + function plugin_action_links($links)
1203 + {
1204 + $settings_link = '<a href="' . esc_url(admin_url('tools.php?page=wp-reset')) . '" title="' . esc_attr(__('Open WP Reset Tools', 'wp-reset')) . '">' . esc_html(__('Open WP Reset Tools', 'wp-reset')) . '</a>';
1158 1205
1159 - /**
1160 - * Add "Open WP Reset Tools" action link to plugins table, left part
1161 - *
1162 - * @param array $links Initial list of links.
1163 - *
1164 - * @return array
1165 - */
1166 - function plugin_action_links($links)
1167 - {
1168 - $settings_link = '<a href="' . esc_url(admin_url('tools.php?page=wp-reset')) . '" title="' . esc_attr(__('Open WP Reset Tools', 'wp-reset')) . '">' . esc_html(__('Open WP Reset Tools', 'wp-reset')) . '</a>';
1206 + array_unshift($links, $settings_link);
1169 1207
1170 - array_unshift($links, $settings_link);
1208 + return $links;
1209 + } // plugin_action_links
1171 1210
1172 - return $links;
1173 - } // plugin_action_links
1174 1211
1212 + /**
1213 + * Add links to plugin's description in plugins table
1214 + *
1215 + * @param array $links Initial list of links.
1216 + * @param string $file Basename of current plugin.
1217 + *
1218 + * @return array
1219 + */
1220 + function plugin_meta_links($links, $file)
1221 + {
1222 + if ($file !== plugin_basename(__FILE__)) {
1223 + return $links;
1224 + }
1175 1225
1176 - /**
1177 - * Add links to plugin's description in plugins table
1178 - *
1179 - * @param array $links Initial list of links.
1180 - * @param string $file Basename of current plugin.
1181 - *
1182 - * @return array
1183 - */
1184 - function plugin_meta_links($links, $file)
1185 - {
1186 - if ($file !== plugin_basename(__FILE__)) {
1187 - return $links;
1188 - }
1226 + $support_link = '<a target="_blank" href="https://wordpress.org/support/plugin/wp-reset" title="' . __('Get help', 'wp-reset') . '">' . __('Support', 'wp-reset') . '</a>';
1227 + $home_link = '<a target="_blank" href="' . esc_url($this->generate_web_link('plugins-table-right')) . '" title="' . __('Plugin Homepage', 'wp-reset') . '">' . __('Plugin Homepage', 'wp-reset') . '</a>';
1228 + $rate_link = '<a target="_blank" href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" title="' . __('Rate the plugin', 'wp-reset') . '">' . __('Rate the plugin ★★★★★', 'wp-reset') . '</a>';
1189 1229
1190 - $support_link = '<a target="_blank" href="https://wordpress.org/support/plugin/wp-reset" title="' . __('Get help', 'wp-reset') . '">' . __('Support', 'wp-reset') . '</a>';
1191 - $home_link = '<a target="_blank" href="' . esc_url($this->generate_web_link('plugins-table-right')) . '" title="' . __('Plugin Homepage', 'wp-reset') . '">' . __('Plugin Homepage', 'wp-reset') . '</a>';
1192 - $rate_link = '<a target="_blank" href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" title="' . __('Rate the plugin', 'wp-reset') . '">' . __('Rate the plugin ★★★★★', 'wp-reset') . '</a>';
1230 + $links[] = $support_link;
1231 + $links[] = $home_link;
1232 + $links[] = $rate_link;
1193 1233
1194 - $links[] = $support_link;
1195 - $links[] = $home_link;
1196 - $links[] = $rate_link;
1234 + return $links;
1235 + } // plugin_meta_links
1197 1236
1198 - return $links;
1199 - } // plugin_meta_links
1200 1237
1238 + /**
1239 + * Test if we're on WPR's admin page
1240 + *
1241 + * @return bool
1242 + */
1243 + function is_plugin_page()
1244 + {
1245 + $current_screen = get_current_screen();
1201 1246
1202 - /**
1203 - * Test if we're on WPR's admin page
1204 - *
1205 - * @return bool
1206 - */
1207 - function is_plugin_page()
1208 - {
1209 - $current_screen = get_current_screen();
1247 + if (!empty($current_screen->id) && $current_screen->id == 'tools_page_wp-reset') {
1248 + return true;
1249 + } else {
1250 + return false;
1251 + }
1252 + } // is_plugin_page
1210 1253
1211 - if (!empty($current_screen->id) && $current_screen->id == 'tools_page_wp-reset') {
1212 - return true;
1213 - } else {
1214 - return false;
1215 - }
1216 - } // is_plugin_page
1217 1254
1255 + /**
1256 + * Add powered by text in admin footer
1257 + *
1258 + * @param string $text Default footer text.
1259 + *
1260 + * @return string
1261 + */
1262 + function admin_footer_text($text)
1263 + {
1264 + if (!$this->is_plugin_page()) {
1265 + return $text;
1266 + }
1218 1267
1219 - /**
1220 - * Add powered by text in admin footer
1221 - *
1222 - * @param string $text Default footer text.
1223 - *
1224 - * @return string
1225 - */
1226 - function admin_footer_text($text)
1227 - {
1228 - if (!$this->is_plugin_page()) {
1229 - return $text;
1230 - }
1268 + $text = '<i><a href="' . esc_url($this->generate_web_link('admin_footer')) . '" title="' . esc_attr(__('Visit WP Reset page for more info', 'wp-reset')) . '" target="_blank">WP Reset</a> v' . $this->version . '. Please <a target="_blank" href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" title="Rate the plugin">rate the plugin <span>★★★★★</span></a> to help us spread the word. Thank you from the WP Reset team!</i>';
1231 1269
1232 - $text = '<i><a href="' . esc_url($this->generate_web_link('admin_footer')) . '" title="' . esc_attr(__('Visit WP Reset page for more info', 'wp-reset')) . '" target="_blank">WP Reset</a> v' . $this->version . '. Please <a target="_blank" href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" title="Rate the plugin">rate the plugin <span>★★★★★</span></a> to help us spread the word. Thank you from the WP Reset team!</i>';
1270 + return $text;
1271 + } // admin_footer_text
1233 1272
1234 - return $text;
1235 - } // admin_footer_text
1236 1273
1274 + /**
1275 + * Loads plugin's translated strings
1276 + *
1277 + * @return null
1278 + */
1279 + function load_textdomain()
1280 + {
1281 + load_plugin_textdomain('wp-reset');
1282 + } // load_textdomain
1237 1283
1238 - /**
1239 - * Loads plugin's translated strings
1240 - *
1241 - * @return null
1242 - */
1243 - function load_textdomain()
1244 - {
1245 - load_plugin_textdomain('wp-reset');
1246 - } // load_textdomain
1247 1284
1285 + /**
1286 + * Inform the user that WordPress has been successfully reset
1287 + *
1288 + * @return null
1289 + */
1290 + function notice_successful_reset()
1291 + {
1292 + global $current_user;
1293 + /* translators: %1$s is replaced with the current user's username, %2$s is replaced with the URL to WP Reset settings page */
1294 + WP_Reset_Utility::wp_kses_wf('<div style="padding: 15px; display: inline-block; font-size: 14px;" id="message" class="updated"><p style="font-size: 14px;">' . sprintf(__('<b>Site has been successfully reset to default settings.</b><br>User "%1$s" was restored with the password unchanged. Open <a href="%2$s">WP Reset</a> to do another reset.', 'wp-reset'), esc_html($current_user->user_login), esc_url(admin_url('tools.php?page=wp-reset'))) . '</p>');
1248 1295
1249 - /**
1250 - * Inform the user that WordPress has been successfully reset
1251 - *
1252 - * @return null
1253 - */
1254 - function notice_successful_reset()
1255 - {
1256 - global $current_user;
1257 1296
1258 - echo '<div style="padding: 15px; display: inline-block; font-size: 14px;" id="message" class="updated"><p style="font-size: 14px;">' . sprintf(__('<b>Site has been successfully reset to default settings.</b><br>User "%s" was restored with the password unchanged. Open <a href="%s">WP Reset</a> to do another reset.', 'wp-reset'), esc_html($current_user->user_login), esc_url(admin_url('tools.php?page=wp-reset'))) . '</p>';
1297 + if (false == $this->get_dismissed_notices('rate')) {
1298 + $request_url = isset($_SERVER['REQUEST_URI'])?sanitize_url(wp_unslash($_SERVER['REQUEST_URI'])):'';
1299 + $dismiss_url = add_query_arg(array('action' => 'wpr_dismiss_notice', 'notice' => 'rate', 'redirect' => urlencode($request_url)), admin_url('admin.php'));
1300 + $dismiss_url = wp_nonce_url($dismiss_url, 'wpr_dismiss_notice');
1259 1301
1260 - if (false == $this->get_dismissed_notices('rate')) {
1261 - $dismiss_url = add_query_arg(array('action' => 'wpr_dismiss_notice', 'notice' => 'rate', 'redirect' => urlencode($_SERVER['REQUEST_URI'])), admin_url('admin.php'));
1262 - $dismiss_url = wp_nonce_url($dismiss_url, 'wpr_dismiss_notice');
1302 + echo '<p style="font-size: 14px;">';
1303 + echo 'If WP Reset helped you please rate it so we can continue supporting it and helping others. Thank you!<br>';
1304 + echo '<a style="margin-top: 5px;" class="button button-secondary" href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" target="_blank">You deserve it, I\'ll rate it!</a> &nbsp; &nbsp; <a href="' . esc_url($dismiss_url) . '">I already rated it</a>';
1305 + echo '</p>';
1306 + }
1263 1307
1264 - echo '<p style="font-size: 14px;">';
1265 - echo 'If WP Reset helped you please rate it so we can continue supporting it and helping others. Thank you!<br>';
1266 - echo '<a style="margin-top: 5px;" class="button button-secondary" href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" target="_blank">You deserve it, I\'ll rate it!</a> &nbsp; &nbsp; <a href="' . esc_url($dismiss_url) . '">I already rated it</a>';
1267 - echo '</p>';
1268 - }
1308 + echo '</div>';
1309 + } // notice_successful_reset
1269 1310
1270 - echo '</div>';
1271 - } // notice_successful_reset
1272 1311
1312 + /**
1313 + * Generate a button that initiates snapshot creation
1314 + *
1315 + * @param string $tool_id Tool ID.
1316 + * @param string $description Snapshot description.
1317 + *
1318 + * @return string
1319 + */
1320 + function get_snapshot_button($tool_id = '', $description = '')
1321 + {
1322 + $out = '';
1323 + $out .= '<a data-tool-id="' . esc_attr($tool_id) . '" data-description="' . esc_attr($description) . '" class="button create-new-snapshot" href="#">Create snapshot</a>';
1273 1324
1274 - /**
1275 - * Generate a button that initiates snapshot creation
1276 - *
1277 - * @param string $tool_id Tool ID.
1278 - * @param string $description Snapshot description.
1279 - *
1280 - * @return string
1281 - */
1282 - function get_snapshot_button($tool_id = '', $description = '')
1283 - {
1284 - $out = '';
1285 - $out .= '<a data-tool-id="' . esc_attr($tool_id) . '" data-description="' . esc_attr($description) . '" class="button create-new-snapshot" href="#">Create snapshot</a>';
1325 + return $out;
1326 + } // get_snapshot_button
1286 1327
1287 - return $out;
1288 - } // get_snapshot_button
1289 1328
1329 + /**
1330 + * Generate card header including title and action buttons
1331 + *
1332 + * @param string $title Card title.
1333 + * @param string $card_id Card element #ID.
1334 + * @param array $params Individual icons arguments
1335 + *
1336 + * @return string
1337 + */
1338 + function get_card_header($title, $card_id, $params = array())
1339 + {
1340 + $params = shortcode_atts(array(
1341 + 'documentation_link' => false,
1342 + 'iot_button' => false,
1343 + 'collapse_button' => false,
1344 + 'create_snapshot' => false,
1345 + 'pro' => false
1346 + ), (array) $params);
1290 1347
1291 - /**
1292 - * Generate card header including title and action buttons
1293 - *
1294 - * @param string $title Card title.
1295 - * @param string $card_id Card element #ID.
1296 - * @param array $params Individual icons arguments
1297 - *
1298 - * @return string
1299 - */
1300 - function get_card_header($title, $card_id, $params = array())
1301 - {
1302 - $params = shortcode_atts(array(
1303 - 'documentation_link' => false,
1304 - 'iot_button' => false,
1305 - 'collapse_button' => false,
1306 - 'create_snapshot' => false,
1307 - 'pro' => false
1308 - ), (array) $params);
1348 + if ($params['documentation_link'] === true) {
1349 + $params['documentation_link'] = $card_id;
1350 + }
1309 1351
1310 - if ($params['documentation_link'] === true) {
1311 - $params['documentation_link'] = $card_id;
1312 - }
1352 + $out = '';
1353 + $out .= '<h4 id="' . esc_attr($card_id) . '"><span class="card-name">' . esc_html($title);
1354 + if ($params['pro']) {
1355 + $out .= ' - <a data-feature="' . esc_attr($card_id) . '" class="pro-feature tooltip" title="WP Reset PRO tool" href="#"><span class="pro">PRO</span> tool</a>';
1356 + }
1357 + $out .= '</span>';
1358 + $out .= '<div class="card-header-right">';
1359 + if ($params['documentation_link']) {
1360 + $out .= '<a class="documentation-link tooltip" href="' . esc_url($this->generate_web_link('documentation_link', '/documentation/')) . '" title="' . __('Open documentation for this tool', 'wp-reset') . '" target="blank"><span class="dashicons dashicons-editor-help"></span></a>';
1361 + }
1362 + if ($params['iot_button']) {
1363 + $out .= '<a class="scrollto tooltip" href="#iot" title="Jump to Index of Tools"><span class="dashicons dashicons-screenoptions"></span></a>';
1364 + }
1365 + if ($params['create_snapshot']) {
1366 + $out .= '<a id="create-new-snapshot-primary" title="Create a new snapshot" href="#" class="button button-primary create-new-snapshot tooltip">' . __('Create Snapshot', 'wp-reset') . '</a>';
1367 + }
1368 + if ($params['collapse_button']) {
1369 + $out .= '<a class="toggle-card tooltip" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a>';
1370 + }
1371 + $out .= '</div></h4>';
1313 1372
1314 - $out = '';
1315 - $out .= '<h4 id="' . esc_attr($card_id) . '"><span class="card-name">' . esc_html($title);
1316 - if ($params['pro']) {
1317 - $out .= ' - <a data-feature="' . esc_attr($card_id) . '" class="pro-feature tooltip" title="WP Reset PRO tool" href="#"><span class="pro">PRO</span> tool</a>';
1318 - }
1319 - $out .= '</span>';
1320 - $out .= '<div class="card-header-right">';
1321 - if ($params['documentation_link']) {
1322 - $out .= '<a class="documentation-link tooltip" href="' . esc_url($this->generate_web_link('documentation_link', '/documentation/')) . '" title="' . __('Open documentation for this tool', 'wp-reset') . '" target="blank"><span class="dashicons dashicons-editor-help"></span></a>';
1323 - }
1324 - if ($params['iot_button']) {
1325 - $out .= '<a class="scrollto tooltip" href="#iot" title="Jump to Index of Tools"><span class="dashicons dashicons-screenoptions"></span></a>';
1326 - }
1327 - if ($params['create_snapshot']) {
1328 - $out .= '<a id="create-new-snapshot-primary" title="Create a new snapshot" href="#" class="button button-primary create-new-snapshot tooltip">' . __('Create Snapshot', 'wp-reset') . '</a>';
1329 - }
1330 - if ($params['collapse_button']) {
1331 - $out .= '<a class="toggle-card tooltip" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a>';
1332 - }
1333 - $out .= '</div></h4>';
1373 + return $out;
1374 + } // get_card_header
1334 1375
1335 - return $out;
1336 - } // get_card_header
1337 1376
1377 + /**
1378 + * Generate tool icons and description detailing what it modifies
1379 + *
1380 + * @param bool $modify_files Does the tool modify files?
1381 + * @param bool $modify_db Does the tool modify the database?
1382 + * @param bool $plural Is there more than one tool in the set?
1383 + *
1384 + * @return string
1385 + */
1386 + function get_tool_icons($modify_files = false, $modify_db = false, $plural = false)
1387 + {
1388 + $out = '';
1389 + $modify_files = (bool) $modify_files;
1390 + $modify_db = (bool) $modify_db;
1391 + $plural = (bool) $plural;
1338 1392
1339 - /**
1340 - * Generate tool icons and description detailing what it modifies
1341 - *
1342 - * @param bool $modify_files Does the tool modify files?
1343 - * @param bool $modify_db Does the tool modify the database?
1344 - * @param bool $plural Is there more than one tool in the set?
1345 - *
1346 - * @return string
1347 - */
1348 - function get_tool_icons($modify_files = false, $modify_db = false, $plural = false)
1349 - {
1350 - $out = '';
1351 - $modify_files = (bool) $modify_files;
1352 - $modify_db = (bool) $modify_db;
1353 - $plural = (bool) $plural;
1393 + $out .= '<p class="tool-icons">';
1394 + $out .= '<i class="icon-doc-text-inv' . ($modify_files ? ' red' : '') . '"></i> ';
1395 + $out .= '<i class="icon-database' . ($modify_db ? ' red' : '') . '"></i> ';
1354 1396
1355 - $out .= '<p class="tool-icons">';
1356 - $out .= '<i class="icon-doc-text-inv' . ($modify_files ? ' red' : '') . '"></i> ';
1357 - $out .= '<i class="icon-database' . ($modify_db ? ' red' : '') . '"></i> ';
1397 + if ($plural) {
1398 + if ($modify_files && $modify_db) {
1399 + $out .= 'these tools <b>modify files &amp; the database</b>';
1400 + } elseif (!$modify_files && $modify_db) {
1401 + $out .= 'these tools <b>modify the database</b> but they don\'t modify any files</b>';
1402 + } elseif ($modify_files && !$modify_db) {
1403 + $out .= 'these tools <b>modify files</b> but they don\'t modify the database</b>';
1404 + }
1405 + } else {
1406 + if ($modify_files && $modify_db) {
1407 + $out .= 'this tool <b>modifies files &amp; the database</b>';
1408 + } elseif (!$modify_files && $modify_db) {
1409 + $out .= 'this tool <b>modifies the database</b> but it doesn\'t modify any files</b>';
1410 + } elseif ($modify_files && !$modify_db) {
1411 + $out .= 'this tool <b>modifies files</b> but it doesn\'t modify the database</b>';
1412 + } else {
1413 + $out .= 'this tool doesn\'t modify files or the database';
1414 + }
1415 + }
1416 + $out .= '</p>';
1358 1417
1359 - if ($plural) {
1360 - if ($modify_files && $modify_db) {
1361 - $out .= 'these tools <b>modify files &amp; the database</b>';
1362 - } elseif (!$modify_files && $modify_db) {
1363 - $out .= 'these tools <b>modify the database</b> but they don\'t modify any files</b>';
1364 - } elseif ($modify_files && !$modify_db) {
1365 - $out .= 'these tools <b>modify files</b> but they don\'t modify the database</b>';
1366 - }
1367 - } else {
1368 - if ($modify_files && $modify_db) {
1369 - $out .= 'this tool <b>modifies files &amp; the database</b>';
1370 - } elseif (!$modify_files && $modify_db) {
1371 - $out .= 'this tool <b>modifies the database</b> but it doesn\'t modify any files</b>';
1372 - } elseif ($modify_files && !$modify_db) {
1373 - $out .= 'this tool <b>modifies files</b> but it doesn\'t modify the database</b>';
1374 - } else {
1375 - $out .= 'this tool doesn\'t modify files or the database';
1376 - }
1377 - }
1378 - $out .= '</p>';
1418 + return $out;
1419 + } // get_tool_icons
1379 1420
1380 - return $out;
1381 - } // get_tool_icons
1382 1421
1422 + /**
1423 + * Outputs complete plugin's admin page
1424 + *
1425 + * @return null
1426 + */
1427 + function plugin_page()
1428 + {
1429 + // double check for admin privileges
1430 + if (!current_user_can('manage_options')) {
1431 + wp_die(esc_html__('Sorry, you are not allowed to access this page.', 'wp-reset'));
1432 + }
1383 1433
1384 - /**
1385 - * Outputs complete plugin's admin page
1386 - *
1387 - * @return null
1388 - */
1389 - function plugin_page()
1390 - {
1391 - // double check for admin privileges
1392 - if (!current_user_can('administrator')) {
1393 - wp_die(__('Sorry, you are not allowed to access this page.', 'wp-reset'));
1394 - }
1434 + echo '<div class="wrap">';
1435 + echo '<form id="wp_reset_form" action="' . esc_url(admin_url('tools.php?page=wp-reset')) . '" method="post" autocomplete="off">';
1395 1436
1396 - echo '<div class="wrap">';
1397 - echo '<form id="wp_reset_form" action="' . esc_url(admin_url('tools.php?page=wp-reset')) . '" method="post" autocomplete="off">';
1437 + echo '<header>';
1438 + echo '<div class="wpr-container">';
1439 + echo '<img id="logo-icon" src="' . esc_url($this->plugin_url) . 'img/wp-reset-logo.png" title="' . esc_html__('WP Reset', 'wp-reset') . '" alt="' . esc_html__('WP Reset', 'wp-reset') . '">';
1440 + echo '</div>';
1441 + echo '</header>';
1398 1442
1399 - echo '<header>';
1400 - echo '<div class="wpr-container">';
1401 - echo '<img id="logo-icon" src="' . esc_url($this->plugin_url) . 'img/wp-reset-logo.png" title="' . __('WP Reset', 'wp-reset') . '" alt="' . __('WP Reset', 'wp-reset') . '">';
1402 - echo '</div>';
1403 - echo '</header>';
1443 + echo '<div id="loading-tabs"><img class="rotating" src="' . esc_url($this->plugin_url) . 'img/wp-reset-icon.png' . '" alt="Loading. Please wait." title="Loading. Please wait."></div>';
1404 1444
1405 - echo '<div id="loading-tabs"><img class="rotating" src="' . esc_url($this->plugin_url) . 'img/wp-reset-icon.png' . '" alt="Loading. Please wait." title="Loading. Please wait."></div>';
1445 + echo '<div id="wp-reset-tabs" class="ui-tabs" style="display: none;">';
1406 1446
1407 - echo '<div id="wp-reset-tabs" class="ui-tabs" style="display: none;">';
1447 + echo '<nav>';
1448 + echo '<div class="wpr-container">';
1449 + echo '<ul class="wpr-main-tab">';
1450 + echo '<li><a href="#tab-reset">' . esc_html(__('Reset', 'wp-reset')) . '</a></li>';
1451 + echo '<li><a href="#tab-tools">' . esc_html(__('Tools', 'wp-reset')) . '</a></li>';
1452 + echo '<li><a href="#tab-snapshots">' . esc_html(__('Snapshots', 'wp-reset')) . '</a></li>';
1453 + echo '<li><a href="#tab-collections">' . esc_html(__('Collections', 'wp-reset')) . '</a></li>';
1454 + echo '<li><a href="#tab-support">' . esc_html(__('Support', 'wp-reset')) . '</a></li>';
1455 + echo '<li class="tab-pro"><a href="#tab-pro">' . esc_html(__('PRO', 'wp-reset')) . '</a></li>';
1456 + echo '</ul>';
1457 + echo '</div>'; // container
1458 + echo '</nav>';
1408 1459
1409 - echo '<nav>';
1410 - echo '<div class="wpr-container">';
1411 - echo '<ul class="wpr-main-tab">';
1412 - echo '<li><a href="#tab-reset">' . esc_html(__('Reset', 'wp-reset')) . '</a></li>';
1413 - echo '<li><a href="#tab-tools">' . esc_html(__('Tools', 'wp-reset')) . '</a></li>';
1414 - echo '<li><a href="#tab-snapshots">' . esc_html(__('Snapshots', 'wp-reset')) . '</a></li>';
1415 - echo '<li><a href="#tab-collections">' . esc_html(__('Collections', 'wp-reset')) . '</a></li>';
1416 - echo '<li><a href="#tab-support">' . esc_html(__('Support', 'wp-reset')) . '</a></li>';
1417 - echo '<li><a href="#tab-pro">' . esc_html(__('PRO', 'wp-reset')) . '</a></li>';
1418 - echo '</ul>';
1419 - echo '</div>'; // container
1420 - echo '</nav>';
1460 + echo '<div id="wpr-notifications">';
1461 + echo '<div class="wpr-container">';
1462 + $this->custom_notifications();
1463 + echo '</div>';
1464 + echo '</div>'; // wpr-notifications
1421 1465
1422 - echo '<div id="wpr-notifications">';
1423 - echo '<div class="wpr-container">';
1424 - $this->custom_notifications();
1425 - echo '</div>';
1426 - echo '</div>'; // wpr-notifications
1466 + // tabs
1467 + echo '<div class="wpr-container">';
1468 + echo '<div id="wpr-content">';
1427 1469
1428 - // tabs
1429 - echo '<div class="wpr-container">';
1430 - echo '<div id="wpr-content">';
1470 + echo '<div style="display: none;" id="tab-reset">';
1471 + $this->tab_reset();
1472 + echo '</div>';
1431 1473
1432 - echo '<div style="display: none;" id="tab-reset">';
1433 - $this->tab_reset();
1434 - echo '</div>';
1474 + echo '<div style="display: none;" id="tab-tools">';
1475 + $this->tab_tools();
1476 + echo '</div>';
1435 1477
1436 - echo '<div style="display: none;" id="tab-tools">';
1437 - $this->tab_tools();
1438 - echo '</div>';
1478 + echo '<div style="display: none;" id="tab-snapshots">';
1479 + $this->tab_snapshots();
1480 + echo '</div>';
1439 1481
1440 - echo '<div style="display: none;" id="tab-snapshots">';
1441 - $this->tab_snapshots();
1442 - echo '</div>';
1482 + echo '<div style="display: none;" id="tab-collections">';
1483 + $this->tab_collections();
1484 + echo '</div>';
1443 1485
1444 - echo '<div style="display: none;" id="tab-collections">';
1445 - $this->tab_collections();
1446 - echo '</div>';
1486 + echo '<div style="display: none;" id="tab-support">';
1487 + $this->tab_support();
1488 + echo '</div>';
1447 1489
1448 - echo '<div style="display: none;" id="tab-support">';
1449 - $this->tab_support();
1450 - echo '</div>';
1490 + echo '<div style="display: none;" id="tab-pro">';
1491 + $this->tab_pro();
1492 + echo '</div>';
1451 1493
1452 - echo '<div style="display: none;" id="tab-pro">';
1453 - $this->tab_pro();
1454 - echo '</div>';
1494 + echo '</div>'; // content
1495 + echo '</div>'; // container
1496 + echo '</div>'; // wp-reset-tabs
1455 1497
1456 - echo '</div>'; // content
1457 - echo '</div>'; // container
1458 - echo '</div>'; // wp-reset-tabs
1498 + echo '</form>';
1459 1499
1460 - echo '</form>';
1461 - echo '</div>'; // wrap
1462 - } // plugin_page
1500 + echo '<div id="wpr-sidebar-ads">';
1501 + echo '<div id="wpr-ad">';
1502 + echo '<h3 class="textcenter"><b>Save time &amp; money with WP Reset PRO! First WP dev tool for non-devs.</b></h3>';
1503 + echo '<p class="textcenter"><a href="#" data-feature="sidebar-logo" class="button-pro-feature textcenter"><img style="max-width: 90%;" src="' . esc_url($this->plugin_url) . '/img/wp-reset-logo.png" alt="WP Reset PRO" title="WP Reset PRO"></a></p>';
1504 + echo '<ul class="plain-list">
1505 + <li>25+ Reset Tools</li>
1506 + <li>Plugins &amp; Themes Collections</li>
1507 + <li>Automatic Snapshots</li>
1508 + <li>WP Reset Cloud, Dropbox &amp; Google Drive support</li>
1509 + <li>Emergency Recovery Script</li>
1510 + <li>White-label Mode + Complete Plugin Rebranding</li>
1511 + <li>Licenses &amp; Sites Manager (remote SaaS dashboard)</li>
1512 + <li>Friendly email support from plugin developers</li>
1513 + </ul>';
1514 + echo '<p class="textcenter"><a href="#" data-feature="sidebar-button" class="button-pro-feature button button-primary">Get PRO now</a></p>';
1515 + echo '</div>';
1463 1516
1517 + if (!defined('WPFSSL_OPTIONS_KEY')) {
1518 + echo '<div id="wpfssl-ad">';
1519 + echo '<h3 class="textcenter"><b>Problems with SSL certificate?<br>Moving a site from HTTP to HTTPS?<br>Mixed content giving you troubles?<br><br><u>Fix all SSL problems with one plugin!</u></b></h3>';
1520 + echo '<p class="textcenter"><a href="#" class="textcenter install-wpfssl"><img style="max-width: 90%;" src="' . esc_url($this->plugin_url) . '/img/wp-force-ssl-logo.png" alt="WP Force SSL" title="WP Force SSL"></a></p>';
1521 + echo '<p class="textcenter"><br><a href="#" class="install-wpfssl button button-primary">Install &amp; activate the free WP Force SSL plugin</a></p><p><a href="https://wordpress.org/plugins/wp-force-ssl/" target="_blank">WP Force SSL</a> is a free WP plugin maintained by the same team as this Maintenance plugin. It has <b>+150,000 users, 5-star rating</b>, and is hosted on the official WP repository.</p>';
1522 + echo '</div>';
1523 + }
1524 + echo '</div>';
1464 1525
1465 - /**
1466 - * Echoes all custom plugin notitications
1467 - *
1468 - * @return null
1469 - */
1470 - private function custom_notifications()
1471 - {
1472 - $notice_shown = false;
1473 - $meta = $this->get_meta();
1474 - $snapshots = $this->get_snapshots();
1526 + echo '</div>'; // wrap
1527 + } // plugin_page
1475 1528
1476 - // update to PRO after activating the license
1477 - if ($this->license->is_active()) {
1478 - echo '<div class="card notice-wrapper notice-info">';
1479 - echo '<h2>' . esc_html(__('Thank you for purchasing WP Reset PRO!', 'wp-reset')) . '</h2>';
1480 - echo '<p>Your license has been verified &amp; activated.</b><br>To start using the PRO version, please follow these steps:';
1481 - echo '<ol>';
1482 - echo '<li><a href="https://dashboard.wpreset.com/pro-download/" target="_blank">Download</a> the latest version of the PRO plugin.</li>';
1483 - echo '<li>Go to <a href="' . esc_url(admin_url('plugin-install.php')) . '">Plugins - Add New - Upload Plugin</a> and upload the ZIP you just downloaded.</li>';
1484 - echo '<li>If asked to replace (overwrite) the free version - confirm it.</li>';
1485 - echo '<li>Activate the plugin.</li>';
1486 - echo '<li>That\'s it, no more steps.</li>';
1487 - echo '</ol>';
1488 - echo '</div>';
1489 - $notice_shown = true;
1490 - }
1491 1529
1492 - // warn that WPR is not WPMU compatible
1493 - if (false === $notice_shown && is_multisite()) {
1494 - echo '<div class="card notice-wrapper notice-error">';
1495 - echo '<h2>' . __('WP Reset is not compatible with multisite!', 'wp-reset') . '</h2>';
1496 - echo '<p>' . __('Please be careful when using WP Reset with multisite enabled. It\'s not recommended to reset the main site. Sub-sites should be OK. We\'re working on making it fully compatible with WP-MU. <b>Till then please be careful.</b> Thank you for understanding.', 'wp-reset') . '</p>';
1497 - echo '</div>';
1498 - $notice_shown = true;
1499 - }
1530 + /**
1531 + * Echoes all custom plugin notitications
1532 + *
1533 + * @return null
1534 + */
1535 + private function custom_notifications()
1536 + {
1537 + $notice_shown = false;
1538 + $meta = $this->get_meta();
1539 + $snapshots = $this->get_snapshots();
1500 1540
1501 - // ask for review
1502 - if ((!empty($meta['reset_count']) || !empty($snapshots) || current_time('timestamp', true) - $meta['first_install'] > DAY_IN_SECONDS)
1503 - && false === $notice_shown
1504 - && false == $this->get_dismissed_notices('rate')
1505 - ) {
1506 - echo '<div class="card notice-wrapper notice-info">';
1507 - echo '<h2>' . __('Please help us spread the word &amp; keep the plugin up-to-date', 'wp-reset') . '</h2>';
1508 - echo '<p>' . __('If you use &amp; enjoy WP Reset, <b>please rate it on WordPress.org</b>. It only takes a second and helps us keep the plugin maintained. Thank you!', 'wp-reset') . '</p>';
1509 - echo '<p><a class="button-primary button" title="' . __('Rate WP Reset', 'wp-reset') . '" target="_blank" href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post">' . __('Rate the plugin ★★★★★', 'wp-reset') . '</a> <a href="#" class="wpr-dismiss-notice dismiss-notice-rate" data-notice="rate">' . __('I\'ve already rated it', 'wp-reset') . '</a></p>';
1510 - echo '</div>';
1511 - $notice_shown = true;
1512 - }
1513 - } // custom_notifications
1541 + // update to PRO after activating the license
1542 + if ($this->license->is_active()) {
1543 + echo '<div class="card notice-wrapper notice-info">';
1544 + echo '<h2>' . esc_html(__('Thank you for purchasing WP Reset PRO!', 'wp-reset')) . '</h2>';
1545 + echo '<p>Your license has been verified &amp; activated.</b><br>To start using the PRO version, please follow these steps:';
1546 + echo '<ol>';
1547 + echo '<li><a href="https://dashboard.wpreset.com/pro-download/" target="_blank">Download</a> the latest version of the PRO plugin.</li>';
1548 + echo '<li>Go to <a href="' . esc_url(admin_url('plugin-install.php')) . '">Plugins - Add New - Upload Plugin</a> and upload the ZIP you just downloaded.</li>';
1549 + echo '<li>If asked to replace (overwrite) the free version - confirm it.</li>';
1550 + echo '<li>Activate the plugin.</li>';
1551 + echo '<li>That\'s it, no more steps.</li>';
1552 + echo '</ol>';
1553 + echo '</div>';
1554 + $notice_shown = true;
1555 + }
1514 1556
1557 + // warn that WPR is not WPMU compatible
1558 + if (false === $notice_shown && is_multisite()) {
1559 + echo '<div class="card notice-wrapper notice-error">';
1560 + echo '<h2>' . esc_html__('WP Reset is not compatible with multisite!', 'wp-reset') . '</h2>';
1561 + WP_Reset_Utility::wp_kses_wf('<p>' . __('Please be careful when using WP Reset with multisite enabled. It\'s not recommended to reset the main site. Sub-sites should be OK. We\'re working on making it fully compatible with WP-MU. <b>Till then please be careful.</b> Thank you for understanding.', 'wp-reset') . '</p>');
1562 + echo '</div>';
1563 + $notice_shown = true;
1564 + }
1515 1565
1516 - /**
1517 - * Echoes content for reset tab
1518 - *
1519 - * @return null
1520 - */
1521 - private function tab_reset()
1522 - {
1523 - global $current_user, $wpdb;
1566 + // ask for review
1567 + if ((!empty($meta['reset_count']) || !empty($snapshots) || current_time('timestamp', true) - $meta['first_install'] > DAY_IN_SECONDS)
1568 + && false === $notice_shown
1569 + && false == $this->get_dismissed_notices('rate')
1570 + ) {
1571 + echo '<div class="card notice-wrapper notice-info">';
1572 + echo '<h2>' . esc_html__('Please help us spread the word &amp; keep the plugin up-to-date', 'wp-reset') . '</h2>';
1573 + WP_Reset_Utility::wp_kses_wf('<p>' . __('If you use &amp; enjoy WP Reset, <b>please rate it on WordPress.org</b>. It only takes a second and helps us keep the plugin maintained. Thank you!', 'wp-reset') . '</p>');
1574 + echo '<p><a class="button-primary button" title="' . esc_html__('Rate WP Reset', 'wp-reset') . '" target="_blank" href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post">' . esc_html__('Rate the plugin ★★★★★', 'wp-reset') . '</a> <a href="#" class="wpr-dismiss-notice dismiss-notice-rate" data-notice="rate">' . esc_html__('I\'ve already rated it', 'wp-reset') . '</a></p>';
1575 + echo '</div>';
1576 + $notice_shown = true;
1577 + }
1578 + } // custom_notifications
1524 1579
1525 - echo '<div class="card">';
1526 - echo $this->get_card_header(__('Please read carefully before proceeding', 'wp-reset'), 'reset-description', array('collapse_button' => true));
1527 - echo '<div class="card-body">';
1528 - echo '<p>The following table details what data will be deleted (reset or destroyed) when a selected reset tool is run. Please read it! ';
1529 - echo 'If something is not clear <a href="#" class="change-tab" data-tab="4">contact support</a> before running any tools. It\'s better to ask than to be sorry!';
1530 - echo '</p>';
1531 - echo '<p><i class="dashicons dashicons-trash red tooltip" title="Tool WILL delete, reset or destroy the noted data" style="vertical-align: bottom;"></i> - tool WILL delete, reset or destroy the noted data<br>';
1532 - echo '<i class="dashicons dashicons-yes tooltip" title="Tool will NOT touch the noted data in any way" style="vertical-align: bottom;"></i> - tool will NOT touch the noted data in any way</p>';
1533 1580
1534 - echo '<table id="reset-details" class="">';
1535 - echo '<tr>';
1536 - echo '<th>&nbsp;</th>';
1537 - echo '<th>Options Reset<br><a data-feature="tool-options-reset" class="pro-feature" href="#"><span class="pro">PRO</span> tool</a></th>';
1538 - echo '<th nowrap>Site Reset</th>';
1539 - echo '<th>Nuclear Reset<br><a data-feature="tool-nuclear-reset" class="pro-feature" href="#"><span class="pro">PRO</span> tool</a></th>';
1540 - echo '</tr>';
1581 + /**
1582 + * Echoes content for reset tab
1583 + *
1584 + * @return null
1585 + */
1586 + private function tab_reset()
1587 + {
1588 + global $current_user, $wpdb;
1541 1589
1542 - $rows = array();
1543 - $rows['Posts, pages & custom post types'] = array(0, 1, 1);
1544 - $rows['Comments'] = array(0, 1, 1);
1545 - $rows['Media'] = array(0, 1, 1);
1546 - $rows['Media files'] = array(0, 0, 1);
1547 - $rows['Users'] = array(0, 1, 1);
1548 - $rows['User roles'] = array(1, 1, 1);
1549 - $rows['Current user - ' . $current_user->user_login] = array(0, 0, 0);
1550 - $rows['Widgets'] = array(1, 1, 1);
1551 - $rows['Transients'] = array(1, 1, 1);
1552 - $rows['Settings &amp; options (from WP, plugins & themes)'] = array(1, 1, 1);
1553 - $rows['Site title, WP address, site address,' . PHP_EOL . 'search engine visibility, timezone'] = array(0, 0, 0);
1554 - $rows['Site language'] = array(0, 0, 1);
1555 - $rows['Data in all default WP tables'] = array(0, 1, 1);
1556 - $rows['Custom database tables with prefix ' . $wpdb->prefix] = array(0, 1, 1);
1557 - $rows['Other database tables'] = array(0, 0, 0);
1558 - $rows['Plugin files'] = array(0, 0, 1);
1559 - $rows['MU plugin files'] = array(0, 0, 1);
1560 - $rows['Drop-in files'] = array(0, 0, 1);
1561 - $rows['Theme files'] = array(0, 0, 1);
1562 - $rows['All files in uploads'] = array(0, 0, 1);
1563 - $rows['Custom folders in wp-content'] = array(0, 0, 1);
1590 + echo '<div class="card">';
1591 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Please read carefully before proceeding', 'wp-reset'), 'reset-description', array('collapse_button' => true)));
1592 + echo '<div class="card-body">';
1593 + echo '<p>The following table details what data will be deleted (reset or destroyed) when a selected reset tool is run. Please read it! ';
1594 + echo 'If something is not clear <a href="#" class="change-tab" data-tab="4">contact support</a> before running any tools. It\'s better to ask than to be sorry!';
1595 + echo '</p>';
1596 + echo '<p><i class="dashicons dashicons-trash red tooltip" title="Tool WILL delete, reset or destroy the noted data" style="vertical-align: bottom;"></i> - tool WILL delete, reset or destroy the noted data<br>';
1597 + echo '<i class="dashicons dashicons-yes tooltip" title="Tool will NOT touch the noted data in any way" style="vertical-align: bottom;"></i> - tool will NOT touch the noted data in any way</p>';
1564 1598
1565 - foreach ($rows as $tool => $opt) {
1566 - echo '<tr>';
1567 - echo '<td>' . nl2br(esc_html($tool)) . '</td>';
1568 - if (empty($opt[0])) {
1569 - echo '<td><i class="dashicons dashicons-yes tooltip" title="Data will NOT be deleted, reset or modified"></i></td>';
1570 - } else {
1571 - echo '<td><i class="dashicons dashicons-trash red tooltip" title="Data WILL BE deleted, reset or modified"></i></td>';
1572 - }
1573 - if (empty($opt[1])) {
1574 - echo '<td><i class="dashicons dashicons-yes tooltip" title="Data will NOT be deleted, reset or modified"></i></td>';
1575 - } else {
1576 - echo '<td><i class="dashicons dashicons-trash red tooltip" title="Data WILL BE deleted, reset or modified"></i></td>';
1577 - }
1578 - if (empty($opt[2])) {
1579 - echo '<td><i class="dashicons dashicons-yes tooltip" title="Data will NOT be deleted, reset or modified"></i></td>';
1580 - } else {
1581 - echo '<td><i class="dashicons dashicons-trash red tooltip" title="Data WILL BE deleted, reset or modified"></i></td>';
1582 - }
1583 - echo '</tr>';
1584 - } // foreach $rows
1585 - echo '<tfoot>';
1586 - echo '<tr>';
1587 - echo '<th>&nbsp;</th>';
1588 - echo '<th>Options Reset<br><a data-feature="tool-options-reset" class="pro-feature" href="#"><span class="pro">PRO</span> tool</a></th>';
1589 - echo '<th nowrap>Site Reset</th>';
1590 - echo '<th>Nuclear Reset<br><a data-feature="tool-nuclear-reset" class="pro-feature" href="#"><span class="pro">PRO</span> tool</a></th>';
1591 - echo '</tr>';
1592 - echo '</tfoot>';
1593 - echo '</table>';
1599 + echo '<table id="reset-details" class="">';
1600 + echo '<tr>';
1601 + echo '<th>&nbsp;</th>';
1602 + echo '<th>Options Reset<br><a data-feature="tool-options-reset" class="pro-feature" href="#"><span class="pro">PRO</span> tool</a></th>';
1603 + echo '<th nowrap>Site Reset</th>';
1604 + echo '<th>Nuclear Reset<br><a data-feature="tool-nuclear-reset" class="pro-feature" href="#"><span class="pro">PRO</span> tool</a></th>';
1605 + echo '</tr>';
1594 1606
1595 - echo '<p><b>' . __('What happens when I run any Reset tool?', 'wp-reset') . '</b></p>';
1596 - echo '<ul class="plain-list">';
1597 - echo '<li>' . __('remember, always <b>make a backup first</b> or use <a href="#" class="change-tab" data-tab="2">snapshots</a>', 'wp-reset') . '</li>';
1598 - echo '<li>' . __('you will have to confirm the action one more time', 'wp-reset') . '</li>';
1599 - echo '<li>' . __('see the table above to find out what exactly will be reset or deleted', 'wp-reset') . '</li>';
1600 - echo '<li>' . __('site title, WordPress URL, site URL, site language, search engine visibility and current user will always be restored', 'wp-reset') . '</li>';
1601 - echo '<li>' . __('you will be logged out, automatically logged back in and taken to the admin dashboard', 'wp-reset') . '</li>';
1602 - echo '<li>' . __('WP Reset plugin will be reactivated if that option is chosen', 'wp-reset') . '</li>';
1603 - echo '</ul>';
1607 + $rows = array();
1608 + $rows['Posts, pages & custom post types'] = array(0, 1, 1);
1609 + $rows['Comments'] = array(0, 1, 1);
1610 + $rows['Media'] = array(0, 1, 1);
1611 + $rows['Media files'] = array(0, 0, 1);
1612 + $rows['Users'] = array(0, 1, 1);
1613 + $rows['User roles'] = array(1, 1, 1);
1614 + $rows['Current user - ' . $current_user->user_login] = array(0, 0, 0);
1615 + $rows['Widgets'] = array(1, 1, 1);
1616 + $rows['Transients'] = array(1, 1, 1);
1617 + $rows['Settings &amp; options (from WP, plugins & themes)'] = array(1, 1, 1);
1618 + $rows['Site title, WP address, site address,' . PHP_EOL . 'search engine visibility, timezone'] = array(0, 0, 0);
1619 + $rows['Site language'] = array(0, 0, 1);
1620 + $rows['Data in all default WP tables'] = array(0, 1, 1);
1621 + $rows['Custom database tables with prefix ' . $wpdb->prefix] = array(0, 1, 1);
1622 + $rows['Other database tables'] = array(0, 0, 0);
1623 + $rows['Plugin files'] = array(0, 0, 1);
1624 + $rows['MU plugin files'] = array(0, 0, 1);
1625 + $rows['Drop-in files'] = array(0, 0, 1);
1626 + $rows['Theme files'] = array(0, 0, 1);
1627 + $rows['All files in uploads'] = array(0, 0, 1);
1628 + $rows['Custom folders in wp-content'] = array(0, 0, 1);
1604 1629
1605 - echo '<p><b>' . __('WP-CLI Support', 'wp-reset') . '</b><br>';
1606 - echo '' . sprintf(__('All tools available via GUI are available in WP-CLI as well. To get the list of commands run %s. Instead of the active user, the first user with admin privileges found in the database will be restored. ', 'wp-reset'), '<code>wp help reset</code>');
1607 - echo sprintf(__('All actions have to be confirmed. If you want to skip confirmation use the standard %s option. Please be careful and backup first.', 'wp-reset'), '<code>--yes</code>') . '</p>';
1630 + foreach ($rows as $tool => $opt) {
1631 + echo '<tr>';
1632 + echo '<td>';
1633 + WP_Reset_Utility::wp_kses_wf(nl2br(esc_html($tool)));
1634 + echo '</td>';
1635 + if (empty($opt[0])) {
1636 + echo '<td><i class="dashicons dashicons-yes tooltip" title="Data will NOT be deleted, reset or modified"></i></td>';
1637 + } else {
1638 + echo '<td><i class="dashicons dashicons-trash red tooltip" title="Data WILL BE deleted, reset or modified"></i></td>';
1639 + }
1640 + if (empty($opt[1])) {
1641 + echo '<td><i class="dashicons dashicons-yes tooltip" title="Data will NOT be deleted, reset or modified"></i></td>';
1642 + } else {
1643 + echo '<td><i class="dashicons dashicons-trash red tooltip" title="Data WILL BE deleted, reset or modified"></i></td>';
1644 + }
1645 + if (empty($opt[2])) {
1646 + echo '<td><i class="dashicons dashicons-yes tooltip" title="Data will NOT be deleted, reset or modified"></i></td>';
1647 + } else {
1648 + echo '<td><i class="dashicons dashicons-trash red tooltip" title="Data WILL BE deleted, reset or modified"></i></td>';
1649 + }
1650 + echo '</tr>';
1651 + } // foreach $rows
1652 + echo '<tfoot>';
1653 + echo '<tr>';
1654 + echo '<th>&nbsp;</th>';
1655 + echo '<th>Options Reset<br><a data-feature="tool-options-reset" class="pro-feature" href="#"><span class="pro">PRO</span> tool</a></th>';
1656 + echo '<th nowrap>Site Reset</th>';
1657 + echo '<th>Nuclear Reset<br><a data-feature="tool-nuclear-reset" class="pro-feature" href="#"><span class="pro">PRO</span> tool</a></th>';
1658 + echo '</tr>';
1659 + echo '</tfoot>';
1660 + echo '</table>';
1608 1661
1609 - echo '</div></div>'; // card description
1662 + echo '<p><b>' . esc_html__('What happens when I run any Reset tool?', 'wp-reset') . '</b></p>';
1663 + echo '<ul class="plain-list">';
1664 + WP_Reset_Utility::wp_kses_wf('<li>' . __('remember, always <b>make a backup first</b> or use <a href="#" class="change-tab" data-tab="2">snapshots</a>', 'wp-reset') . '</li>');
1665 + echo '<li>' . esc_html__('you will have to confirm the action one more time', 'wp-reset') . '</li>';
1666 + echo '<li>' . esc_html__('see the table above to find out what exactly will be reset or deleted', 'wp-reset') . '</li>';
1667 + echo '<li>' . esc_html__('site title, WordPress URL, site URL, site language, search engine visibility and current user will always be restored', 'wp-reset') . '</li>';
1668 + echo '<li>' . esc_html__('you will be logged out, automatically logged back in and taken to the admin dashboard', 'wp-reset') . '</li>';
1669 + echo '<li>' . esc_html__('WP Reset plugin will be reactivated if that option is chosen', 'wp-reset') . '</li>';
1670 + echo '</ul>';
1610 1671
1611 - $theme = wp_get_theme();
1612 - $theme_name = $theme->get('Name');
1613 - if (empty($theme_name)) {
1614 - $theme_name = '<i>no active theme</i>';
1615 - }
1616 - $active_plugins = get_option('active_plugins');
1672 + echo '<p><b>' . esc_html__('WP-CLI Support', 'wp-reset') . '</b><br>';
1673 + /* translators: %s is replaced with the literal html "<code>wp help reset</code>" */
1674 + echo '' . sprintf(esc_html__('All tools available via GUI are available in WP-CLI as well. To get the list of commands run %s. Instead of the active user, the first user with admin privileges found in the database will be restored. ', 'wp-reset'), '<code>wp help reset</code>');
1675 + /* translators: %s is replaced with the literal html "<code>--yes</code>" */
1676 + echo sprintf(esc_html__('All actions have to be confirmed. If you want to skip confirmation use the standard %s option. Please be careful and backup first.', 'wp-reset'), '<code>--yes</code>') . '</p>';
1617 1677
1618 - // options reset
1619 - echo '<div class="card">';
1620 - echo $this->get_card_header(__('Options Reset', 'wp-reset'), 'tool-options-reset', array('collapse_button' => true, 'pro' => true));
1621 - echo '<div class="card-body">';
1622 - echo '<p>Options table will be reset to default values meaning all WP core settings, widgets, theme settings and customizations, and plugin settings will be gone. Other content and files will not be touched including posts, pages, custom post types, comments and other data stored in separate tables. Site URL and name will be kept as well. Please see the <a href="#reset-details" class="scrollto">table above</a> for details.</p>';
1678 + echo '</div></div>'; // card description
1623 1679
1624 - echo $this->get_tool_icons(false, true);
1680 + $theme = wp_get_theme();
1681 + $theme_name = $theme->get('Name');
1682 + if (empty($theme_name)) {
1683 + $theme_name = '<i>no active theme</i>';
1684 + }
1685 + $active_plugins = get_option('active_plugins');
1625 1686
1626 - echo '<p><br><label for="reset-options-reactivate-theme"><input type="checkbox" id="reset-options-reactivate-theme" value="1"> ' . __('Reactivate current theme', 'wp-reset') . ' - ' . esc_html($theme_name) . '</label></p>';
1627 - echo '<p><label for="reset-options-reactivate-plugins"><input type="checkbox" id="reset-options-reactivate-plugins" value="1"> Reactivate ' . sizeof($active_plugins) . ' currently active plugin' . (sizeof($active_plugins) != 1 ? 's' : '') . ' (WP Reset will reactivate by default)</label></p>';
1687 + // options reset
1688 + echo '<div class="card">';
1689 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Options Reset', 'wp-reset'), 'tool-options-reset', array('collapse_button' => true, 'pro' => true)));
1690 + echo '<div class="card-body">';
1691 + echo '<p>Options table will be reset to default values meaning all WP core settings, widgets, theme settings and customizations, and plugin settings will be gone. Other content and files will not be touched including posts, pages, custom post types, comments and other data stored in separate tables. Site URL and name will be kept as well. Please see the <a href="#reset-details" class="scrollto">table above</a> for details.</p>';
1628 1692
1629 - echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Reset all options - <span data-feature="tool-options-reset" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1630 - echo '</div>';
1631 - echo '</div>'; // options reset
1693 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(false, true));
1632 1694
1633 - echo '<div class="card">';
1634 - echo $this->get_card_header(__('Site Reset', 'wp-reset'), 'tool-site-reset', array('collapse_button' => true));
1635 - echo '<div class="card-body">';
1636 - echo '<p><label for="reactivate-theme"><input name="wpr-post-reset[reactivate_theme]" type="checkbox" id="reactivate-theme" value="1"> ' . __('Reactivate current theme', 'wp-reset') . ' - ' . esc_html($theme->get('Name')) . '</label></p>';
1637 - echo '<p><label for="reactivate-wpreset"><input name="wpr-post-reset[reactivate_wpreset]" type="checkbox" id="reactivate-wpreset" value="1" checked> ' . __('Reactivate WP Reset plugin', 'wp-reset') . '</label></p>';
1695 + echo '<p><br><label for="reset-options-reactivate-theme"><input type="checkbox" id="reset-options-reactivate-theme" value="1"> ' . esc_html__('Reactivate current theme', 'wp-reset') . ' - ' . esc_html($theme_name) . '</label></p>';
1696 + echo '<p><label for="reset-options-reactivate-plugins"><input type="checkbox" id="reset-options-reactivate-plugins" value="1"> Reactivate ' . esc_attr(sizeof($active_plugins)) . ' currently active plugin' . (sizeof($active_plugins) != 1 ? 's' : '') . ' (WP Reset will reactivate by default)</label></p>';
1638 1697
1639 - echo '<p><label for="reactivate-plugins"><input name="wpr-post-reset[reactivate_plugins]" type="checkbox" id="reactivate-plugins" value="1"> ' . __('Reactivate all currently active plugins', 'wp-reset') . '</label></p>';
1640 - echo '<p>' . __('Type <b>reset</b> in the confirmation field to confirm the reset and then click the "Reset WordPress" button.<br>Always <a href="#" class="create-new-snapshot" data-description="Before resetting the site">create a snapshot</a> before resetting if you want to be able to undo.', 'wp-reset') . '</p>';
1698 + echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Reset all options - <span data-feature="tool-options-reset" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1699 + echo '</div>';
1700 + echo '</div>'; // options reset
1641 1701
1642 - wp_nonce_field('wp-reset');
1643 - echo '<p class="mb0"><input id="wp_reset_confirm" type="text" name="wp_reset_confirm" placeholder="' . esc_attr(sprintf(__('Type in: %s', 'wp-reset'), '"reset"')) . '" value="" autocomplete="off"> &nbsp;';
1644 - echo '<a id="wp_reset_submit" class="button button-delete">' . __('Reset Site', 'wp-reset') . '</a>' . $this->get_snapshot_button('reset-wordpress', 'Before resetting the site') . '</p>';
1645 - echo '</div>';
1646 - echo '</div>'; // card reset
1702 + echo '<div class="card">';
1703 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Site Reset', 'wp-reset'), 'tool-site-reset', array('collapse_button' => true)));
1704 + echo '<div class="card-body">';
1705 + echo '<p><label for="reactivate-theme"><input name="wpr-post-reset[reactivate_theme]" type="checkbox" id="reactivate-theme" value="1"> ' . esc_html__('Reactivate current theme', 'wp-reset') . ' - ' . esc_html($theme->get('Name')) . '</label></p>';
1706 + echo '<p><label for="reactivate-wpreset"><input name="wpr-post-reset[reactivate_wpreset]" type="checkbox" id="reactivate-wpreset" value="1" checked> ' . esc_html__('Reactivate WP Reset plugin', 'wp-reset') . '</label></p>';
1647 1707
1648 - // nuclear reset
1649 - echo '<div class="card">';
1650 - echo $this->get_card_header(__('Nuclear Site Reset', 'wp-reset'), 'tool-nuclear-reset', array('collapse_button' => true, 'pro' => true));
1651 - echo '<div class="card-body">';
1652 - echo '<p>All data will be deleted or reset (see the <a href="#reset-details" class="scrollto">explanation table</a> for details). All data stored in the database including custom tables with <code>' . esc_html($wpdb->prefix) . '</code> prefix, as well as all files in wp-content, themes and plugins folders. The only thing restored after reset will be your user account so you can log in again, and the basic WP settings like site URL. Please see the <a href="#reset-details" class="scrollto">table above</a> for details.</p>';
1708 + echo '<p><label for="reactivate-plugins"><input name="wpr-post-reset[reactivate_plugins]" type="checkbox" id="reactivate-plugins" value="1"> ' . esc_html__('Reactivate all currently active plugins', 'wp-reset') . '</label></p>';
1709 + WP_Reset_Utility::wp_kses_wf('<p>' . __('Type <b>reset</b> in the confirmation field to confirm the reset and then click the "Reset WordPress" button.<br>Always <a href="#" class="create-new-snapshot" data-description="Before resetting the site">create a snapshot</a> before resetting if you want to be able to undo.', 'wp-reset') . '</p>');
1653 1710
1654 - echo $this->get_tool_icons(true, true);
1711 + wp_nonce_field('wp-reset');
1712 + /* translators: %s is replaced with "reset"*/
1713 + echo '<p class="mb0"><input id="wp_reset_confirm" type="text" name="wp_reset_confirm" placeholder="' . esc_attr(sprintf(__('Type in: %s', 'wp-reset'), '"reset"')) . '" value="" autocomplete="off"> &nbsp;';
1714 + echo '<a id="wp_reset_submit" class="button button-delete">' . esc_html__('Reset Site', 'wp-reset') . '</a>';
1715 + WP_Reset_Utility::wp_kses_wf($this->get_snapshot_button('reset-wordpress', 'Before resetting the site'));
1716 + echo '</p>';
1717 + echo '</div>';
1718 + echo '</div>'; // card reset
1655 1719
1656 - if (is_multisite()) {
1657 - echo '<p class="mb0 wpmu-error">This tool is <b>not compatible</b> with WP multisite (WPMU). Using it would delete files shared by multiple sites in the WP network.</p>';
1658 - } else {
1659 - echo '<p><br><label for="nuclear-reset-reactivate-wpreset"><input type="checkbox" id="nuclear-reset-reactivate-wpreset" value="1" checked> ' . __('Reactivate WP Reset plugin', 'wp-reset') . '</label></p>';
1720 + // nuclear reset
1721 + echo '<div class="card">';
1722 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Nuclear Site Reset', 'wp-reset'), 'tool-nuclear-reset', array('collapse_button' => true, 'pro' => true)));
1723 + echo '<div class="card-body">';
1724 + echo '<p>All data will be deleted or reset (see the <a href="#reset-details" class="scrollto">explanation table</a> for details). All data stored in the database including custom tables with <code>' . esc_html($wpdb->prefix) . '</code> prefix, as well as all files in wp-content, themes and plugins folders. The only thing restored after reset will be your user account so you can log in again, and the basic WP settings like site URL. Please see the <a href="#reset-details" class="scrollto">table above</a> for details.</p>';
1660 1725
1661 - echo '<p>' . __('Type <b>reset</b> in the confirmation field to confirm the reset and then click the "Reset WordPress &amp; Delete All Custom Files &amp; Data" button. <b>There is NO UNDO.', 'wp-reset') . '</b></p>';
1726 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, true));
1662 1727
1663 - echo '<p class="mb0"><input id="nuclear_reset_confirm" type="text" placeholder="' . esc_attr__('Type in "reset"', 'wp-reset') . '" value="" autocomplete="off"> &nbsp;';
1664 - echo '<a class="button button-delete button-pro-feature" href="#">' . __('Reset WordPress &amp; Delete All Custom Files &amp; Data', 'wp-reset') . ' - <span data-feature="tool-nuclear-reset" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1665 - }
1666 - echo '</div>';
1667 - echo '</div>'; // nuclear reset
1668 - } // tab_reset
1728 + if (is_multisite()) {
1729 + echo '<p class="mb0 wpmu-error">This tool is <b>not compatible</b> with WP multisite (WPMU). Using it would delete files shared by multiple sites in the WP network.</p>';
1730 + } else {
1731 + echo '<p><br><label for="nuclear-reset-reactivate-wpreset"><input type="checkbox" id="nuclear-reset-reactivate-wpreset" value="1" checked> ' . esc_html__('Reactivate WP Reset plugin', 'wp-reset') . '</label></p>';
1669 1732
1733 + WP_Reset_Utility::wp_kses_wf('<p>' . __('Type <b>reset</b> in the confirmation field to confirm the reset and then click the "Reset WordPress &amp; Delete All Custom Files &amp; Data" button. <b>There is NO UNDO.', 'wp-reset') . '</b></p>');
1670 1734
1671 - /**
1672 - * Echoes content for tools tab
1673 - *
1674 - * @return null
1675 - */
1676 - private function tab_tools()
1677 - {
1678 - global $wpdb, $wp_version;
1735 + echo '<p class="mb0"><input id="nuclear_reset_confirm" type="text" placeholder="' . esc_html__('Type in "reset"', 'wp-reset') . '" value="" autocomplete="off"> &nbsp;';
1736 + echo '<a class="button button-delete button-pro-feature" href="#">' . esc_html__('Reset WordPress &amp; Delete All Custom Files &amp; Data', 'wp-reset') . ' - <span data-feature="tool-nuclear-reset" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1737 + }
1738 + echo '</div>';
1739 + echo '</div>'; // nuclear reset
1740 + } // tab_reset
1679 1741
1680 - $tools = array(
1681 - 'tool-reset-theme-options' => 'Reset Theme Options',
1682 - '_tool-reset-user-roles' => 'Reset User Roles',
1683 - 'tool-delete-transients' => 'Delete Transients',
1684 - 'tool-purge-cache' => 'Purge Cache',
1685 - 'tool-delete-local-data' => 'Delete Local Data',
1686 - '_tool-delete-content' => 'Delete Content',
1687 - '_tool-delete-widgets' => 'Delete Widgets',
1688 - 'tool-delete-themes' => 'Delete Themes',
1689 - 'tool-delete-plugins' => 'Delete Plugins',
1690 - '_tool-delete-mu-plugins-dropins' => 'Delete MU Plugins & Drop-ins',
1691 - 'tool-delete-uploads' => 'Clean uploads Folder',
1692 - '_tool-delete-wp-content' => 'Clean wp-content Folder',
1693 - 'tool-empty-delete-custom-tables' => 'Empty or Delete Custom Tables',
1694 - '_tool-switch-wp-version' => 'Switch WP Version',
1695 - 'tool-delete-htaccess' => 'Delete .htaccess File'
1696 - );
1697 1742
1698 - echo '<div class="card">';
1699 - echo $this->get_card_header(__('Index of Tools', 'wp-reset'), 'iot', array('collapse_button' => true));
1700 - echo '<div class="card-body">';
1701 - $i = 0;
1702 - $tools_nb = sizeof($tools);
1703 - foreach ($tools as $tool_id => $tool_name) {
1704 - if ($i == 0) {
1705 - echo '<div class="third">';
1706 - echo '<ul class="mb0 plain-list">';
1707 - }
1708 - if ($i == 5 || $i == 10) {
1709 - echo '</div>';
1710 - echo '<div class="third">';
1711 - echo '<ul class="mb0 plain-list">';
1712 - }
1743 + /**
1744 + * Echoes content for tools tab
1745 + *
1746 + * @return null
1747 + */
1748 + private function tab_tools()
1749 + {
1750 + global $wpdb, $wp_version, $wp_filesystem;
1751 + $this->wp_init_filesystem();
1713 1752
1714 - if ($tool_id[0] == '_') {
1715 - $tool_id = ltrim($tool_id, '_');
1716 - echo '<li><a title="Jump to ' . esc_attr($tool_name) . ' tool" class="scrollto" href="#' . esc_attr($tool_id) . '">' . esc_html($tool_name) . '</a> <a class="pro-feature" href="#" data-feature="' . esc_attr($tool_id) . '"><span class="pro">PRO</span> tool</a></li>';
1717 - } else {
1718 - echo '<li><a title="Jump to ' . esc_attr($tool_name) . ' tool" class="scrollto" href="#' . esc_attr($tool_id) . '">' . esc_html($tool_name) . '</a></li>';
1719 - }
1753 + $tools = array(
1754 + 'tool-reset-theme-options' => 'Reset Theme Options',
1755 + '_tool-reset-user-roles' => 'Reset User Roles',
1756 + 'tool-delete-transients' => 'Delete Transients',
1757 + 'tool-purge-cache' => 'Purge Cache',
1758 + 'tool-delete-local-data' => 'Delete Local Data',
1759 + '_tool-delete-content' => 'Delete Content',
1760 + '_tool-delete-widgets' => 'Delete Widgets',
1761 + 'tool-delete-themes' => 'Delete Themes',
1762 + 'tool-delete-plugins' => 'Delete Plugins',
1763 + '_tool-delete-mu-plugins-dropins' => 'Delete MU Plugins & Drop-ins',
1764 + 'tool-delete-uploads' => 'Clean uploads Folder',
1765 + '_tool-delete-wp-content' => 'Clean wp-content Folder',
1766 + 'tool-empty-delete-custom-tables' => 'Empty or Delete Custom Tables',
1767 + '_tool-switch-wp-version' => 'Switch WP Version',
1768 + 'tool-delete-htaccess' => 'Delete .htaccess File'
1769 + );
1720 1770
1721 - if ($i == $tools_nb - 1) {
1722 - echo '</ul>';
1723 - echo '</div>'; // third
1724 - }
1725 - $i++;
1726 - } // foreach tools
1727 - echo '</div>';
1728 - echo '</div>';
1771 + echo '<div class="card">';
1772 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Index of Tools', 'wp-reset'), 'iot', array('collapse_button' => true)));
1773 + echo '<div class="card-body">';
1774 + $i = 0;
1775 + $tools_nb = sizeof($tools);
1776 + foreach ($tools as $tool_id => $tool_name) {
1777 + if ($i == 0) {
1778 + echo '<div class="third">';
1779 + echo '<ul class="mb0 plain-list">';
1780 + }
1781 + if ($i == 5 || $i == 10) {
1782 + echo '</div>';
1783 + echo '<div class="third">';
1784 + echo '<ul class="mb0 plain-list">';
1785 + }
1729 1786
1730 - echo '<div class="card">';
1731 - echo $this->get_card_header(__('Reset Theme Options', 'wp-reset'), 'tool-reset-theme-options', array('iot_button' => true, 'collapse_button' => true));
1732 - echo '<div class="card-body">';
1733 - echo '<p>' . __('All options (mods) for all themes will be reset; not just for the active theme. The tool works only for themes that use the <a href="https://codex.wordpress.org/Theme_Modification_API" target="_blank">WordPress theme modification API</a>. If options are saved in some other, custom way they won\'t be reset.<br> Always <a href="#" class="create-new-snapshot" data-description="Before resetting theme options">create a snapshot</a> before using this tool if you want to be able to undo its actions.', 'wp-reset') . '</p>';
1734 - echo $this->get_tool_icons(false, true);
1735 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to reset all theme options?" data-btn-confirm="Reset theme options" data-text-wait="Resetting theme options. Please wait." data-text-confirm="All options (mods) for all themes will be reset. Always ' . esc_attr('<a data-description="Before resetting theme options" href="#" class="create-new-snapshot">create a snapshot</a> if you want to be able to undo') . '." data-text-done="Options for %n themes have been reset." data-text-done-singular="Options for one theme have been reset." class="button button-delete" href="#" id="reset-theme-options">Reset theme options</a>' . $this->get_snapshot_button('reset-theme-options', 'Before resetting theme options') . '</p>';
1736 - echo '</div>';
1737 - echo '</div>'; // reset theme options
1787 + if ($tool_id[0] == '_') {
1788 + $tool_id = ltrim($tool_id, '_');
1789 + echo '<li><a title="Jump to ' . esc_attr($tool_name) . ' tool" class="scrollto" href="#' . esc_attr($tool_id) . '">' . esc_html($tool_name) . '</a> <a class="pro-feature" href="#" data-feature="' . esc_attr($tool_id) . '"><span class="pro">PRO</span> tool</a></li>';
1790 + } else {
1791 + echo '<li><a title="Jump to ' . esc_attr($tool_name) . ' tool" class="scrollto" href="#' . esc_attr($tool_id) . '">' . esc_html($tool_name) . '</a></li>';
1792 + }
1738 1793
1739 - echo '<div class="card default-collapsed">';
1740 - echo $this->get_card_header(__('Reset User Roles', 'wp-reset'), 'tool-reset-user-roles', array('collapse_button' => true, 'iot_button' => true, 'pro' => true));
1741 - echo '<div class="card-body">';
1742 - echo '<p>Default user roles\' capatibilities will be reset to their default values. All custom roles will be deleted.<br>Users that had custom roles will not be assigned any default ones and might not be able to log in. Roles have to be (re)assigned to them manually.</p>';
1743 - echo $this->get_tool_icons(false, true);
1744 - echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Reset user roles - <span data-feature="tool-reset-user-roles" class="pro-feature"><span class="pro">PRO</span> tool</span></a>';
1745 - echo $this->get_snapshot_button('reset-user-roles', 'Before resetting user roles') . '</p>';
1746 - echo '</div>';
1747 - echo '</div>'; // reset user roles
1794 + if ($i == $tools_nb - 1) {
1795 + echo '</ul>';
1796 + echo '</div>'; // third
1797 + }
1798 + $i++;
1799 + } // foreach tools
1800 + echo '</div>';
1801 + echo '</div>';
1748 1802
1749 - echo '<div class="card">';
1750 - echo $this->get_card_header(__('Delete Transients', 'wp-reset'), 'tool-delete-transients', array('iot_button' => true, 'collapse_button' => true));
1751 - echo '<div class="card-body">';
1752 - echo '<p>All transient related database entries will be deleted. Including expired and non-expired transients, and orphaned transient timeout entries.<br>Always <a href="#" data-description="Before deleting transients" class="create-new-snapshot">create a snapshot</a> before using this tool if you want to be able to undo its actions.</p>';
1753 - echo $this->get_tool_icons(false, true);
1754 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all transients?" data-btn-confirm="Delete all transients" data-text-wait="Deleting transients. Please wait." data-text-confirm="All database entries related to transients will be deleted. Always ' . esc_attr('<a data-description="Before deleting transients" href="#" class="create-new-snapshot">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n transient database entries have been deleted." data-text-done-singular="One transient database entry has been deleted." class="button button-delete" href="#" id="delete-transients">Delete all transients</a>' . $this->get_snapshot_button('delete-transients', 'Before deleting transients') . '</p>';
1755 - echo '</div>';
1756 - echo '</div>'; // delete transients
1803 + echo '<div class="card">';
1804 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Reset Theme Options', 'wp-reset'), 'tool-reset-theme-options', array('iot_button' => true, 'collapse_button' => true)));
1805 + echo '<div class="card-body">';
1806 + WP_Reset_Utility::wp_kses_wf('<p>' . __('All options (mods) for all themes will be reset; not just for the active theme. The tool works only for themes that use the <a href="https://codex.wordpress.org/Theme_Modification_API" target="_blank">WordPress theme modification API</a>. If options are saved in some other, custom way they won\'t be reset.<br> Always <a href="#" class="create-new-snapshot" data-description="Before resetting theme options">create a snapshot</a> before using this tool if you want to be able to undo its actions.', 'wp-reset') . '</p>');
1807 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(false, true));
1808 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to reset all theme options?" data-btn-confirm="Reset theme options" data-text-wait="Resetting theme options. Please wait." data-text-confirm="All options (mods) for all themes will be reset. Always ' . esc_attr('<a data-description="Before resetting theme options" href="#" class="create-new-snapshot">create a snapshot</a> if you want to be able to undo') . '." data-text-done="Options for %n themes have been reset." data-text-done-singular="Options for one theme have been reset." class="button button-delete" href="#" id="reset-theme-options">Reset theme options</a>';
1809 + WP_Reset_Utility::wp_kses_wf($this->get_snapshot_button('reset-theme-options', 'Before resetting theme options') . '</p>');
1810 + echo '</div>';
1811 + echo '</div>'; // reset theme options
1757 1812
1758 - echo '<div class="card">';
1759 - echo $this->get_card_header(__('Purge Cache', 'wp-reset'), 'tool-purge-cache', array('collapse_button' => true, 'iot_button' => true));
1760 - echo '<div class="card-body">';
1761 - echo '<p>All cache objects stored in both files and the database will be deleted. Along with WP object cache and transients, cache from the following plugins will be purged: W3 Total Cache, WP Cache, LiteSpeed Cache, Endurance Page Cache, SiteGround Optimizer, WP Fastest Cache and Swift Performance.</p>';
1762 - echo $this->get_tool_icons(true, true);
1763 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to purge all cache?" data-btn-confirm="Purge cache" data-text-wait="Purging cache. Please wait." data-text-confirm="All cache objects will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="Cache has been purged." data-text-done-singular="Cache has been purged." class="button button-delete" href="#" id="purge-cache">Purge cache</a></p>';
1764 - echo '</div>';
1765 - echo '</div>'; // purge cache
1813 + echo '<div class="card default-collapsed">';
1814 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Reset User Roles', 'wp-reset'), 'tool-reset-user-roles', array('collapse_button' => true, 'iot_button' => true, 'pro' => true)));
1815 + echo '<div class="card-body">';
1816 + echo '<p>Default user roles\' capatibilities will be reset to their default values. All custom roles will be deleted.<br>Users that had custom roles will not be assigned any default ones and might not be able to log in. Roles have to be (re)assigned to them manually.</p>';
1817 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(false, true));
1818 + echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Reset user roles - <span data-feature="tool-reset-user-roles" class="pro-feature"><span class="pro">PRO</span> tool</span></a>';
1819 + WP_Reset_Utility::wp_kses_wf($this->get_snapshot_button('reset-user-roles', 'Before resetting user roles') . '</p>');
1820 + echo '</div>';
1821 + echo '</div>'; // reset user roles
1766 1822
1767 - echo '<div class="card">';
1768 - echo $this->get_card_header(__('Delete Local Data', 'wp-reset'), 'tool-delete-local-data', array('collapse_button' => true, 'iot_button' => true));
1769 - echo '<div class="card-body">';
1770 - echo '<p>All local storage and session storage data will be deleted. Cookies without a custom set path will be deleted as well. WP cookies are not touched, with Delete Local Data button.<br>Deleting all WordPress cookies (including authentication cookies) will delete all WP related cookies and user (you) will be logged out on the next page reload.
1771 - </p>';
1772 - echo $this->get_tool_icons(false, false);
1773 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all local data?" data-btn-confirm="Delete local data" data-text-wait="Deleting local data. Please wait." data-text-confirm="All local data; cookies, local storage and local session will be deleted. There is NO UNDO. WP Reset does not make backups of local data." data-text-done="%n local data objects have been deleted." data-text-done-singular="One local data object has been deleted." class="button button-delete" href="#" id="delete-local-data">Delete local data</a><a data-confirm-title="Are you sure you want to delete all WP related cookies?" data-btn-confirm="Delete all WordPress cookies" data-text-wait="Deleting WP cookies. Please wait." data-text-confirm="All WP cookies including authentication ones will be deleted. You will have to log in again. There is NO UNDO. WP Reset does not make backups of cookies." data-text-done="All WP cookies have been deleted. Reload the page to login again." data-text-done-singular="All WP cookies have been deleted. Reload the page to login again." class="button button-delete" href="#" id="delete-wp-cookies">Delete all WordPress cookies</a></p>';
1774 - echo '</div>';
1775 - echo '</div>'; // delete local data
1823 + echo '<div class="card">';
1824 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Delete Transients', 'wp-reset'), 'tool-delete-transients', array('iot_button' => true, 'collapse_button' => true)));
1825 + echo '<div class="card-body">';
1826 + echo '<p>All transient related database entries will be deleted. Including expired and non-expired transients, and orphaned transient timeout entries.<br>Always <a href="#" data-description="Before deleting transients" class="create-new-snapshot">create a snapshot</a> before using this tool if you want to be able to undo its actions.</p>';
1827 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(false, true));
1828 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all transients?" data-btn-confirm="Delete all transients" data-text-wait="Deleting transients. Please wait." data-text-confirm="All database entries related to transients will be deleted. Always ' . esc_attr('<a data-description="Before deleting transients" href="#" class="create-new-snapshot">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n transient database entries have been deleted." data-text-done-singular="One transient database entry has been deleted." class="button button-delete" href="#" id="delete-transients">Delete all transients</a>';
1829 + WP_Reset_Utility::wp_kses_wf($this->get_snapshot_button('delete-transients', 'Before deleting transients') . '</p>');
1830 + echo '</div>';
1831 + echo '</div>'; // delete transients
1776 1832
1777 - echo '<div class="card default-collapsed">';
1778 - echo $this->get_card_header(__('Delete Content', 'wp-reset'), 'tool-delete-content', array('collapse_button' => true, 'iot_button' => true, 'pro' => true));
1779 - echo '<div class="card-body">';
1780 - echo '<p>Besides content, all linked or child records (for selected content) will be deleted to prevent creating orphaned rows in the database. For instance, for posts that\'s posts, post meta, and comments related to posts. Delete process does not call any WP hooks such as <i>before_delete_post</i>. Choosing a post type or taxonomy does not delete that parent object it deletes the child objects. Parent objects are defined in code. If you want to remove them, remove their code definition. When media is deleted, files are left in the uploads folder. To delete files use the <a class="scrollto" href="#tool-delete-uploads">Clean uploads Folder</a> tool. Deleting users does not affect the current, logged in user account. All orphaned objects will be reassigned to him.</p>';
1833 + echo '<div class="card">';
1834 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Purge Cache', 'wp-reset'), 'tool-purge-cache', array('collapse_button' => true, 'iot_button' => true)));
1835 + echo '<div class="card-body">';
1836 + echo '<p>All cache objects stored in both files and the database will be deleted. Along with WP object cache and transients, cache from the following plugins will be purged: W3 Total Cache, WP Cache, LiteSpeed Cache, Endurance Page Cache, SiteGround Optimizer, WP Fastest Cache and Swift Performance.</p>';
1837 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, true));
1838 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to purge all cache?" data-btn-confirm="Purge cache" data-text-wait="Purging cache. Please wait." data-text-confirm="All cache objects will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="Cache has been purged." data-text-done-singular="Cache has been purged." class="button button-delete" href="#" id="purge-cache">Purge cache</a></p>';
1839 + echo '</div>';
1840 + echo '</div>'; // purge cache
1781 1841
1782 - echo $this->get_tool_icons(false, true);
1842 + echo '<div class="card">';
1843 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Delete Local Data', 'wp-reset'), 'tool-delete-local-data', array('collapse_button' => true, 'iot_button' => true)));
1844 + echo '<div class="card-body">';
1845 + echo '<p>All local storage and session storage data will be deleted. Cookies without a custom set path will be deleted as well. WP cookies are not touched, with Delete Local Data button.<br>Deleting all WordPress cookies (including authentication cookies) will delete all WP related cookies and user (you) will be logged out on the next page reload.
1846 + </p>';
1847 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(false, false));
1848 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all local data?" data-btn-confirm="Delete local data" data-text-wait="Deleting local data. Please wait." data-text-confirm="All local data; cookies, local storage and local session will be deleted. There is NO UNDO. WP Reset does not make backups of local data." data-text-done="%n local data objects have been deleted." data-text-done-singular="One local data object has been deleted." class="button button-delete" href="#" id="delete-local-data">Delete local data</a><a data-confirm-title="Are you sure you want to delete all WP related cookies?" data-btn-confirm="Delete all WordPress cookies" data-text-wait="Deleting WP cookies. Please wait." data-text-confirm="All WP cookies including authentication ones will be deleted. You will have to log in again. There is NO UNDO. WP Reset does not make backups of cookies." data-text-done="All WP cookies have been deleted. Reload the page to login again." data-text-done-singular="All WP cookies have been deleted. Reload the page to login again." class="button button-delete" href="#" id="delete-wp-cookies">Delete all WordPress cookies</a></p>';
1849 + echo '</div>';
1850 + echo '</div>'; // delete local data
1783 1851
1784 - $post_types = get_post_types('', false, 'and');
1785 - $taxonomies = get_taxonomies('', false, 'and');
1852 + echo '<div class="card default-collapsed">';
1853 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Delete Content', 'wp-reset'), 'tool-delete-content', array('collapse_button' => true, 'iot_button' => true, 'pro' => true)));
1854 + echo '<div class="card-body">';
1855 + echo '<p>Besides content, all linked or child records (for selected content) will be deleted to prevent creating orphaned rows in the database. For instance, for posts that\'s posts, post meta, and comments related to posts. Delete process does not call any WP hooks such as <i>before_delete_post</i>. Choosing a post type or taxonomy does not delete that parent object it deletes the child objects. Parent objects are defined in code. If you want to remove them, remove their code definition. When media is deleted, files are left in the uploads folder. To delete files use the <a class="scrollto" href="#tool-delete-uploads">Clean uploads Folder</a> tool. Deleting users does not affect the current, logged in user account. All orphaned objects will be reassigned to him.</p>';
1786 1856
1787 - echo '<p><select size="6" multiple id="delete-content-types">';
1788 - echo '<option value="_comments">Comments (' . ((int) $wpdb->get_var("SELECT COUNT(comment_id) FROM $wpdb->comments")) . ')</option>';
1789 - echo '<option value="_users">Users (' . ((int) $wpdb->get_var("SELECT COUNT(id) FROM $wpdb->users")) . ')</option>';
1790 - foreach ($post_types as $type) {
1791 - $count = wp_count_posts($type->name, 'readable');
1792 - $tmp = 0;
1793 - foreach ($count as $cnt) {
1794 - $tmp += (int) $cnt;
1795 - }
1796 - echo '<option value="' . esc_attr($type->name) . '">Post type - ' . esc_html($type->label . ' (' . $tmp) . ')</option>';
1797 - } // foreach post types
1798 - foreach ($taxonomies as $tax) {
1799 - echo '<option value="_tax_' . esc_attr($tax->name) . '">Taxonomy - ' . esc_html($tax->label . ' (' . wp_count_terms($tax->name)) . ')</option>';
1800 - } // foreach post types
1857 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(false, true));
1801 1858
1802 - echo '</select><br>';
1803 - echo 'Select content object(s) you want to delete. Use ctrl + click to select multiple objects.</p>';
1859 + $post_types = get_post_types('', false, 'and');
1860 + $taxonomies = get_taxonomies('', false, 'and');
1804 1861
1805 - echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Delete content - <span data-feature="tool-delete-content" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1806 - echo '</div>';
1807 - echo '</div>'; // delete content
1862 + echo '<p><select size="6" multiple id="delete-content-types">';
1863 + // phpcs:ignore db call warning as we are using uncommon queries
1864 + echo '<option value="_comments">Comments (' . ((int) $wpdb->get_var("SELECT COUNT(comment_id) FROM $wpdb->comments")) . ')</option>'; // phpcs:ignore
1865 + echo '<option value="_users">Users (' . ((int) $wpdb->get_var("SELECT COUNT(id) FROM $wpdb->users")) . ')</option>'; // phpcs:ignore
1866 + foreach ($post_types as $type) {
1867 + $count = wp_count_posts($type->name, 'readable');
1868 + $tmp = 0;
1869 + foreach ($count as $cnt) {
1870 + $tmp += (int) $cnt;
1871 + }
1872 + echo '<option value="' . esc_attr($type->name) . '">Post type - ' . esc_html($type->label . ' (' . $tmp) . ')</option>';
1873 + } // foreach post types
1874 + foreach ($taxonomies as $tax) {
1875 + echo '<option value="_tax_' . esc_attr($tax->name) . '">Taxonomy - ' . esc_html($tax->label . ' (' . wp_count_terms($tax->name)) . ')</option>';
1876 + } // foreach post types
1808 1877
1809 - echo '<div class="card default-collapsed">';
1810 - echo $this->get_card_header(__('Delete Widgets', 'wp-reset'), 'tool-delete-widgets', array('collapse_button' => true, 'iot_button' => true, 'pro' => true));
1811 - echo '<div class="card-body">';
1812 - echo '<p>All widgets, orphaned, active and inactive ones, as well as widgets in active and inactive sidebars will be deleted including their settings. After deleting, WordPress will automatically recreate default, empty database entries related to widgets. So, no matter how many times users run the tool it will never return "no data deleted". That\'s expected and normal.</p>';
1878 + echo '</select><br>';
1879 + echo 'Select content object(s) you want to delete. Use ctrl + click to select multiple objects.</p>';
1813 1880
1814 - echo $this->get_tool_icons(false, true);
1881 + echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Delete content - <span data-feature="tool-delete-content" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1882 + echo '</div>';
1883 + echo '</div>'; // delete content
1815 1884
1816 - echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Delete widgets - <span data-feature="tool-delete-widgets" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1817 - echo '</div>';
1818 - echo '</div>'; // delete widgets
1885 + echo '<div class="card default-collapsed">';
1886 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Delete Widgets', 'wp-reset'), 'tool-delete-widgets', array('collapse_button' => true, 'iot_button' => true, 'pro' => true)));
1887 + echo '<div class="card-body">';
1888 + echo '<p>All widgets, orphaned, active and inactive ones, as well as widgets in active and inactive sidebars will be deleted including their settings. After deleting, WordPress will automatically recreate default, empty database entries related to widgets. So, no matter how many times users run the tool it will never return "no data deleted". That\'s expected and normal.</p>';
1819 1889
1820 - $theme = wp_get_theme();
1890 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(false, true));
1821 1891
1822 - echo '<div class="card">';
1823 - echo $this->get_card_header(__('Delete Themes', 'wp-reset'), 'tool-delete-themes', array('iot_button' => true, 'collapse_button' => true));
1824 - echo '<div class="card-body">';
1825 - echo '<p>' . __('All themes will be deleted. Including the currently active theme - ' . esc_html($theme->get('Name')) . '.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
1826 - echo $this->get_tool_icons(true, true);
1827 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all themes?" data-btn-confirm="Delete all themes" data-text-wait="Deleting all themes. Please wait." data-text-confirm="All themes will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n themes have been deleted." data-text-done-singular="One theme has been deleted." class="button button-delete" href="#" id="delete-themes">Delete all themes</a></p>';
1828 - echo '</div>';
1829 - echo '</div>'; // delete themes
1892 + echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Delete widgets - <span data-feature="tool-delete-widgets" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1893 + echo '</div>';
1894 + echo '</div>'; // delete widgets
1830 1895
1831 - echo '<div class="card">';
1832 - echo $this->get_card_header(__('Delete Plugins', 'wp-reset'), 'tool-delete-plugins', array('iot_button' => true, 'collapse_button' => true));
1833 - echo '<div class="card-body">';
1834 - echo '<p>' . __('All plugins will be deleted except for WP Reset which will remain active.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
1835 - echo $this->get_tool_icons(true, true);
1836 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all plugins?" data-btn-confirm="Delete plugins" data-text-wait="Deleting plugins. Please wait." data-text-confirm="All plugins except WP Reset will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n plugins have been deleted." data-text-done-singular="One plugin has been deleted." class="button button-delete" href="#" id="delete-plugins">Delete plugins</a></p>';
1837 - echo '</div>';
1838 - echo '</div>'; // delete plugins
1896 + $theme = wp_get_theme();
1839 1897
1840 - echo '<div class="card default-collapsed">';
1841 - echo $this->get_card_header(__('Delete MU Plugins & Drop-ins', 'wp-reset'), 'tool-delete-mu-plugins-dropins', array('collapse_button' => true, 'iot_button' => true, 'pro' => true));
1842 - echo '<div class="card-body">';
1843 - echo '<p>MU Plugins are located in <code>/wp-content/mu-plugins/</code> and are, as the name suggests, must-use plugins that are automatically activated by WP and can\'t be deactiavated via the <a href="' . esc_url(admin_url('plugins.php?plugin_status=mustuse')) . '" target="_blank">plugins interface</a>, although if any are used, they are listed in the "Must Use" tab.<br>';
1844 - echo 'Drop-ins are pieces of code found in <code>/wp-content/</code> that replace default, built-in WordPress functionality. Most often used are <code>db.php</code> and <code>advanced-cache.php</code> that implement custom DB and cache functionality. They can\'t be deactivated via the <a href="' . esc_url(admin_url('plugins.php?plugin_status=dropins')) . '" target="_blank">plugins interface</a> but if any are present are listed in the "Drop-in" tab.</p>';
1898 + echo '<div class="card">';
1899 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Delete Themes', 'wp-reset'), 'tool-delete-themes', array('iot_button' => true, 'collapse_button' => true)));
1900 + echo '<div class="card-body">';
1901 + /* translators: %s is replaced with the currently active theme name */
1902 + WP_Reset_Utility::wp_kses_wf('<p>' . sprintf(__('All themes will be deleted. Including the currently active theme - %s.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset'), esc_html($theme->get('Name'))) . '</p>');
1903 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, true));
1904 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all themes?" data-btn-confirm="Delete all themes" data-text-wait="Deleting all themes. Please wait." data-text-confirm="All themes will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n themes have been deleted." data-text-done-singular="One theme has been deleted." class="button button-delete" href="#" id="delete-themes">Delete all themes</a></p>';
1905 + echo '</div>';
1906 + echo '</div>'; // delete themes
1845 1907
1846 - if (is_multisite()) {
1847 - echo '<p class="mb0 wpmu-error">This tool is <b>not compatible</b> with WP multisite (WPMU). Using it would delete plugins for all sites in the network since they all share the same plugin files.</p>';
1848 - } else {
1849 - echo $this->get_tool_icons(true, false, true);
1850 - echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Delete must use plugins - <span data-feature="tool-delete-mu-plugins" class="pro-feature"><span class="pro">PRO</span> tool</span></a><a class="button button-delete button-pro-feature" href="#">Delete drop-ins - <span data-feature="tool-delete-dropins" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1851 - }
1852 - echo '</div>';
1853 - echo '</div>'; // delete MU plugins and dropins
1908 + echo '<div class="card">';
1909 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Delete Plugins', 'wp-reset'), 'tool-delete-plugins', array('iot_button' => true, 'collapse_button' => true)));
1910 + echo '<div class="card-body">';
1911 + WP_Reset_Utility::wp_kses_wf('<p>' . __('All plugins will be deleted except for WP Reset which will remain active.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>');
1912 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, true));
1913 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all plugins?" data-btn-confirm="Delete plugins" data-text-wait="Deleting plugins. Please wait." data-text-confirm="All plugins except WP Reset will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n plugins have been deleted." data-text-done-singular="One plugin has been deleted." class="button button-delete" href="#" id="delete-plugins">Delete plugins</a></p>';
1914 + echo '</div>';
1915 + echo '</div>'; // delete plugins
1854 1916
1855 - $upload_dir = wp_upload_dir(date('Y/m'), true);
1856 - $upload_dir['basedir'] = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $upload_dir['basedir']);
1917 + echo '<div class="card default-collapsed">';
1918 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Delete MU Plugins & Drop-ins', 'wp-reset'), 'tool-delete-mu-plugins-dropins', array('collapse_button' => true, 'iot_button' => true, 'pro' => true)));
1919 + echo '<div class="card-body">';
1920 + echo '<p>MU Plugins are located in <code>/wp-content/mu-plugins/</code> and are, as the name suggests, must-use plugins that are automatically activated by WP and can\'t be deactiavated via the <a href="' . esc_url(admin_url('plugins.php?plugin_status=mustuse')) . '" target="_blank">plugins interface</a>, although if any are used, they are listed in the "Must Use" tab.<br>';
1921 + echo 'Drop-ins are pieces of code found in <code>/wp-content/</code> that replace default, built-in WordPress functionality. Most often used are <code>db.php</code> and <code>advanced-cache.php</code> that implement custom DB and cache functionality. They can\'t be deactivated via the <a href="' . esc_url(admin_url('plugins.php?plugin_status=dropins')) . '" target="_blank">plugins interface</a> but if any are present are listed in the "Drop-in" tab.</p>';
1857 1922
1858 - echo '<div class="card">';
1859 - echo $this->get_card_header(__('Clean uploads Folder', 'wp-reset'), 'tool-delete-uploads', array('iot_button' => true, 'collapse_button' => true));
1860 - echo '<div class="card-body">';
1861 - echo '<p>' . __('All files in <code>' . esc_html($upload_dir['basedir']) . '</code> folder will be deleted. Including folders and subfolders, and files in subfolders. Files associated with <a href="' . esc_url(admin_url('upload.php')) . '">media</a> entries will be deleted too.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
1862 - echo $this->get_tool_icons(true, false);
1863 - if (false != $upload_dir['error']) {
1864 - echo '<p class="mb0"><span style="color:#dd3036;"><b>Tool is not available.</b></span> Folder is not writeable by WordPress. Please check file and folder access rights.</p>';
1865 - } else {
1866 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all files &amp; folders in uploads folder?" data-btn-confirm="Delete everything in uploads folder" data-text-wait="Deleting uploads. Please wait." data-text-confirm="All files and folders in uploads will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n files &amp; folders have been deleted." data-text-done-singular="One file or folder has been deleted." class="button button-delete" href="#" id="delete-uploads">Delete all files &amp; folders in uploads folder</a></p>';
1867 - }
1868 - echo '</div>';
1869 - echo '</div>'; // clean uploads folder
1923 + if (is_multisite()) {
1924 + echo '<p class="mb0 wpmu-error">This tool is <b>not compatible</b> with WP multisite (WPMU). Using it would delete plugins for all sites in the network since they all share the same plugin files.</p>';
1925 + } else {
1926 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, false, true));
1927 + echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Delete must use plugins - <span data-feature="tool-delete-mu-plugins" class="pro-feature"><span class="pro">PRO</span> tool</span></a><a class="button button-delete button-pro-feature" href="#">Delete drop-ins - <span data-feature="tool-delete-dropins" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1928 + }
1929 + echo '</div>';
1930 + echo '</div>'; // delete MU plugins and dropins
1870 1931
1871 - echo '<div class="card default-collapsed">';
1872 - echo $this->get_card_header(__('Clean wp-content Folder', 'wp-reset'), 'tool-delete-wp-content', array('collapse_button' => true, 'iot_button' => true, 'pro' => true));
1873 - echo '<div class="card-body">';
1874 - echo '<p>All folders and their content in <code>wp-content</code> folder except the following ones will be deleted: <code>mu-plugins</code>, <code>plugins</code>, <code>themes</code>, <code>uploads</code>, <code>wp-reset-autosnapshots</code>, <code>wp-reset-snapshots-export</code>.</p>';
1875 - echo $this->get_tool_icons(true, false);
1876 - if (false === is_writable(trailingslashit(WP_CONTENT_DIR))) {
1877 - echo '<p class="mb0"><span style="color:#dd3036;"><b>Tool is not available.</b></span> Folder is not writeable by WordPress. Please check file and folder access rights.</p>';
1878 - } else {
1879 - echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Clean wp-content folder - <span data-feature="tool-delete-wp-content" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1880 - }
1881 - echo '</div>';
1882 - echo '</div>'; // clean wp-content
1932 + $upload_dir = wp_upload_dir(gmdate('Y/m'), true);
1933 + $upload_dir['basedir'] = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $upload_dir['basedir']);
1883 1934
1884 - $custom_tables = $this->get_custom_tables();
1935 + echo '<div class="card">';
1936 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Clean uploads Folder', 'wp-reset'), 'tool-delete-uploads', array('iot_button' => true, 'collapse_button' => true)));
1937 + echo '<div class="card-body">';
1938 + /* translators: %1$s is replaced with the uploads folder path, %2$s is replaced with the URL to WordPress Media upload page */
1939 + WP_Reset_Utility::wp_kses_wf('<p>' . sprintf(__('All files in <code>%1$s</code> folder will be deleted. Including folders and subfolders, and files in subfolders. Files associated with <a href="%2$s">media</a> entries will be deleted too.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset'), esc_html($upload_dir['basedir']), esc_url(admin_url('upload.php'))) . '</p>');
1940 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, false));
1941 + if (false != $upload_dir['error']) {
1942 + echo '<p class="mb0"><span style="color:#dd3036;"><b>Tool is not available.</b></span> Folder is not writeable by WordPress. Please check file and folder access rights.</p>';
1943 + } else {
1944 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all files &amp; folders in uploads folder?" data-btn-confirm="Delete everything in uploads folder" data-text-wait="Deleting uploads. Please wait." data-text-confirm="All files and folders in uploads will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n files &amp; folders have been deleted." data-text-done-singular="One file or folder has been deleted." class="button button-delete" href="#" id="delete-uploads">Delete all files &amp; folders in uploads folder</a></p>';
1945 + }
1946 + echo '</div>';
1947 + echo '</div>'; // clean uploads folder
1885 1948
1886 - echo '<div class="card">';
1887 - echo $this->get_card_header(__('Empty or Delete Custom Tables', 'wp-reset'), 'tool-empty-delete-custom-tables', array('iot_button' => true, 'collapse_button' => true));
1888 - echo '<div class="card-body">';
1889 - echo '<p>' . __('This action affects only custom tables with <code>' . esc_html($wpdb->prefix) . '</code> prefix. Core WP tables and other tables in the database that do not have that prefix will not be deleted/emptied. Deleting (dropping) tables completely removes them from the database. Emptying (truncating) removes all content from them, but keeps the structure intact.<br>Always <a href="#" class="create-new-snapshot" data-description="Before deleting custom tables">create a snapshot</a> before using this tool if you want to be able to undo its actions.</p>', 'wp-reset');
1890 - if ($custom_tables) {
1891 - echo '<p>' . __('The following ' . esc_html(sizeof($custom_tables)) . ' custom tables are affected by this tool: ');
1892 - foreach ($custom_tables as $tbl) {
1893 - echo '<code>' . esc_html($tbl['name']) . '</code>';
1894 - if (next($custom_tables)) {
1895 - echo ', ';
1949 + echo '<div class="card default-collapsed">';
1950 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Clean wp-content Folder', 'wp-reset'), 'tool-delete-wp-content', array('collapse_button' => true, 'iot_button' => true, 'pro' => true)));
1951 + echo '<div class="card-body">';
1952 + echo '<p>All folders and their content in <code>wp-content</code> folder except the following ones will be deleted: <code>mu-plugins</code>, <code>plugins</code>, <code>themes</code>, <code>uploads</code>, <code>wp-reset-autosnapshots</code>, <code>wp-reset-snapshots-export</code>.</p>';
1953 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, false));
1954 + if (false === $wp_filesystem->is_writable(trailingslashit(WP_CONTENT_DIR))) {
1955 + echo '<p class="mb0"><span style="color:#dd3036;"><b>Tool is not available.</b></span> Folder is not writeable by WordPress. Please check file and folder access rights.</p>';
1956 + } else {
1957 + echo '<p class="mb0"><a class="button button-delete button-pro-feature" href="#">Clean wp-content folder - <span data-feature="tool-delete-wp-content" class="pro-feature"><span class="pro">PRO</span> tool</span></a></p>';
1896 1958 }
1897 - } // foreach
1898 - echo '.</p>';
1899 - $custom_tables_btns = '';
1900 - } else {
1901 - echo '<p>' . __('There are no custom tables. There\'s nothing for this tool to empty or delete.', 'wp-reset') . '</p>';
1902 - $custom_tables_btns = ' disabled';
1903 - }
1904 - echo $this->get_tool_icons(false, true, true);
1905 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to empty all custom tables?" data-btn-confirm="Empty custom tables" data-text-wait="Emptying custom tables. Please wait." data-text-confirm="All custom tables with prefix <code>' . esc_attr($wpdb->prefix) . '</code> will be emptied. Always ' . esc_attr('<a href="#" class="create-new-snapshot" data-description="Before emptying custom tables">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n custom tables have been emptied." data-text-done-singular="One custom table has been emptied." class="button button-delete' . esc_attr($custom_tables_btns) . '" href="#" id="truncate-custom-tables">Empty (truncate) custom tables</a>';
1906 - echo '<a data-confirm-title="Are you sure you want to delete all custom tables?" data-btn-confirm="Delete custom tables" data-text-wait="Deleting custom tables. Please wait." data-text-confirm="All custom tables with prefix <code>' . esc_attr($wpdb->prefix) . '</code> will be deleted. Always ' . esc_attr('<a href="#" class="create-new-snapshot" data-description="Before deleting custom tables">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n custom tables have been deleted." data-text-done-singular="One custom table has been deleted." class="button button-delete' . esc_attr($custom_tables_btns) . '" href="#" id="drop-custom-tables">Delete (drop) custom tables</a>' . $this->get_snapshot_button('drop-custom-tables', 'Before deleting custom tables') . '</p>';
1907 - echo '</div>';
1908 - echo '</div>'; // empty custom tables
1959 + echo '</div>';
1960 + echo '</div>'; // clean wp-content
1909 1961
1910 - echo '<div class="card default-collapsed">';
1911 - echo $this->get_card_header(__('Switch WP Version', 'wp-reset'), 'tool-switch-wp-version', array('collapse_button' => true, 'iot_button' => true, 'pro' => true));
1912 - echo '<div class="card-body">';
1913 - if (is_multisite()) {
1914 - echo '<p class="mb0 wpmu-error">This tool is <b>not compatible</b> with WP multisite (WPMU). Using it would change the WP version for all sites in the network since they all share the same core files.</p>';
1915 - } else {
1916 - echo '<p>Replace current WordPress version with the selected new version. Switching from a previous version, to a newer version is mostly supported and properly handled by the WP installer. Reverting WordPress, rolling back WordPress to a previous version is not supported. Results may vary!</p>';
1917 - echo $this->get_tool_icons(true, true);
1962 + $custom_tables = $this->get_custom_tables();
1918 1963
1919 - $wp_versions = WP_Reset_Utility::get_wordpress_versions();
1920 - echo '<p><label for="select-wp-version">Select the WordPress version to switch to:</label> ';
1921 - echo '<select id="select-wp-version">';
1922 - echo '<option value="">select WordPress version</option>';
1923 - foreach ($wp_versions as $version => $release_date) {
1924 - if ($release_date == 'bleeding') {
1925 - echo '<option value="bleeding">WordPress v' . esc_html($version) . ' (Bleeding edge nightly)' . ($wp_version == $version ? ' - installed' : '') . '</option>';
1926 - } elseif ($release_date == 'point') {
1927 - echo '<option value="point-' . esc_attr(substr($version, 0, 3)) . '">WordPress v' . esc_html($version) . ' (Point release nightly)' . ($wp_version == $version ? ' - installed' : '') . '</option>';
1964 + echo '<div class="card">';
1965 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Empty or Delete Custom Tables', 'wp-reset'), 'tool-empty-delete-custom-tables', array('iot_button' => true, 'collapse_button' => true)));
1966 + echo '<div class="card-body">';
1967 + /* translators: %s is replaced with the table prefix */
1968 + WP_Reset_Utility::wp_kses_wf('<p>' . sprintf(__('This action affects only custom tables with <code>%s</code> prefix. Core WP tables and other tables in the database that do not have that prefix will not be deleted/emptied. Deleting (dropping) tables completely removes them from the database. Emptying (truncating) removes all content from them, but keeps the structure intact.<br>Always <a href="#" class="create-new-snapshot" data-description="Before deleting custom tables">create a snapshot</a> before using this tool if you want to be able to undo its actions.</p>', 'wp-reset'), esc_html($wpdb->prefix)));
1969 + if ($custom_tables) {
1970 + /* translators: %d is replaced with the number of custom tables */
1971 + WP_Reset_Utility::wp_kses_wf('<p>' . sprintf(__('The following %d custom tables are affected by this tool: ', 'wp-reset'), sizeof($custom_tables)));
1972 + foreach ($custom_tables as $tbl) {
1973 + echo '<code>' . esc_html($tbl['name']) . '</code>';
1974 + if (next($custom_tables)) {
1975 + echo ', ';
1976 + }
1977 + } // foreach
1978 + echo '.</p>';
1979 + $custom_tables_btns = '';
1928 1980 } else {
1929 - echo '<option value="' . esc_attr($version) . '">WordPress v' . esc_html($version) . ' (' . date('Y-m-d', $release_date) . ')' . ($wp_version == $version ? ' - installed' : '') . '</option>';
1981 + echo '<p>' . esc_html__('There are no custom tables. There\'s nothing for this tool to empty or delete.', 'wp-reset') . '</p>';
1982 + $custom_tables_btns = ' disabled';
1930 1983 }
1931 - }
1932 - echo '</select></p>';
1984 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(false, true, true));
1985 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to empty all custom tables?" data-btn-confirm="Empty custom tables" data-text-wait="Emptying custom tables. Please wait." data-text-confirm="All custom tables with prefix <code>' . esc_attr($wpdb->prefix) . '</code> will be emptied. Always ' . esc_attr('<a href="#" class="create-new-snapshot" data-description="Before emptying custom tables">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n custom tables have been emptied." data-text-done-singular="One custom table has been emptied." class="button button-delete' . esc_attr($custom_tables_btns) . '" href="#" id="truncate-custom-tables">Empty (truncate) custom tables</a>';
1986 + echo '<a data-confirm-title="Are you sure you want to delete all custom tables?" data-btn-confirm="Delete custom tables" data-text-wait="Deleting custom tables. Please wait." data-text-confirm="All custom tables with prefix <code>' . esc_attr($wpdb->prefix) . '</code> will be deleted. Always ' . esc_attr('<a href="#" class="create-new-snapshot" data-description="Before deleting custom tables">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n custom tables have been deleted." data-text-done-singular="One custom table has been deleted." class="button button-delete' . esc_attr($custom_tables_btns) . '" href="#" id="drop-custom-tables">Delete (drop) custom tables</a>';
1987 + WP_Reset_Utility::wp_kses_wf($this->get_snapshot_button('drop-custom-tables', 'Before deleting custom tables'));
1988 + echo '</p>';
1989 + echo '</div>';
1990 + echo '</div>'; // empty custom tables
1933 1991
1934 - echo '<p class="mb0">';
1935 - echo '<a class="button button-delete button-pro-feature" href="#">Switch WordPress version - <span data-feature="tool-switch-wp-version" class="pro-feature"><span class="pro">PRO</span> tool</span></a>';
1936 - echo '</p>';
1937 - }
1938 - echo '</div>';
1939 - echo '</div>'; // switch WP version
1992 + echo '<div class="card default-collapsed">';
1993 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Switch WP Version', 'wp-reset'), 'tool-switch-wp-version', array('collapse_button' => true, 'iot_button' => true, 'pro' => true)));
1994 + echo '<div class="card-body">';
1995 + if (is_multisite()) {
1996 + echo '<p class="mb0 wpmu-error">This tool is <b>not compatible</b> with WP multisite (WPMU). Using it would change the WP version for all sites in the network since they all share the same core files.</p>';
1997 + } else {
1998 + echo '<p>Replace current WordPress version with the selected new version. Switching from a previous version, to a newer version is mostly supported and properly handled by the WP installer. Reverting WordPress, rolling back WordPress to a previous version is not supported. Results may vary!</p>';
1999 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, true));
1940 2000
1941 - echo '<div class="card">';
1942 - echo $this->get_card_header(__('Delete .htaccess File', 'wp-reset'), 'tool-delete-htaccess', array('iot_button' => true, 'collapse_button' => true));
1943 - echo '<div class="card-body">';
1944 - echo '<p>' . __('This action deletes the .htaccess file located in <code>' . esc_html($this->get_htaccess_path()) . '</code><br><b>There is NO UNDO. WP Reset does not make any file backups.</b></p>', 'wp-reset');
2001 + $wp_versions = WP_Reset_Utility::get_wordpress_versions();
2002 + echo '<p><label for="select-wp-version">Select the WordPress version to switch to:</label> ';
2003 + echo '<select id="select-wp-version">';
2004 + echo '<option value="">select WordPress version</option>';
2005 + foreach ($wp_versions as $version => $release_date) {
2006 + if ($release_date == 'bleeding') {
2007 + echo '<option value="bleeding">WordPress v' . esc_html($version) . ' (Bleeding edge nightly)' . ($wp_version == $version ? ' - installed' : '') . '</option>';
2008 + } elseif ($release_date == 'point') {
2009 + echo '<option value="point-' . esc_attr(substr($version, 0, 3)) . '">WordPress v' . esc_html($version) . ' (Point release nightly)' . ($wp_version == $version ? ' - installed' : '') . '</option>';
2010 + } else {
2011 + echo '<option value="' . esc_attr($version) . '">WordPress v' . esc_html($version) . ' (' . esc_attr(gmdate('Y-m-d', $release_date)) . ')' . ($wp_version == $version ? ' - installed' : '') . '</option>';
2012 + }
2013 + }
2014 + echo '</select></p>';
1945 2015
1946 - echo '<p>If you need to edit .htaccess, install our free <a href="' . esc_url(admin_url('plugin-install.php?tab=plugin-information&plugin=wp-htaccess-editor&TB_iframe=true&width=600&height=550')) . '" class="thickbox open-plugin-details-modal">WP Htaccess Editor</a> plugin. It automatically creates backups when you edit .htaccess as well as checks for syntax errors. To create the default .htaccess file open <a href="' . esc_url(admin_url('options-permalink.php')) . '">Settings - Permalinks</a> and re-save settings. WordPress will recreate the file.</p>';
1947 - echo $this->get_tool_icons(true, false);
1948 - echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete the .htaccess file?" data-btn-confirm="Delete .htaccess file" data-text-wait="Deleting .htaccess file. Please wait." data-text-confirm="Htaccess file will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="Htaccess file has been deleted." data-text-done-singular="Htaccess file has been deleted." class="button button-delete" href="#" id="delete-htaccess">Delete .htaccess file</a></p>';
2016 + echo '<p class="mb0">';
2017 + echo '<a class="button button-delete button-pro-feature" href="#">Switch WordPress version - <span data-feature="tool-switch-wp-version" class="pro-feature"><span class="pro">PRO</span> tool</span></a>';
2018 + echo '</p>';
2019 + }
2020 + echo '</div>';
2021 + echo '</div>'; // switch WP version
1949 2022
1950 - echo '</div>';
1951 - echo '</div>'; // delete htaccess
1952 - } // tab_tools
2023 + echo '<div class="card">';
2024 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Delete .htaccess File', 'wp-reset'), 'tool-delete-htaccess', array('iot_button' => true, 'collapse_button' => true)));
2025 + echo '<div class="card-body">';
2026 + /* translators: %s is replaced with the .htaccess file path */
2027 + WP_Reset_Utility::wp_kses_wf('<p>' . sprintf(__('This action deletes the .htaccess file located in <code>%s</code><br><b>There is NO UNDO. WP Reset does not make any file backups.</b></p>', 'wp-reset'), esc_html($this->get_htaccess_path())));
1953 2028
2029 + echo '<p>If you need to edit .htaccess, install our free <a href="' . esc_url(admin_url('plugin-install.php?tab=plugin-information&plugin=wp-htaccess-editor&TB_iframe=true&width=600&height=550')) . '" class="thickbox open-plugin-details-modal">WP Htaccess Editor</a> plugin. It automatically creates backups when you edit .htaccess as well as checks for syntax errors. To create the default .htaccess file open <a href="' . esc_url(admin_url('options-permalink.php')) . '">Settings - Permalinks</a> and re-save settings. WordPress will recreate the file.</p>';
2030 + WP_Reset_Utility::wp_kses_wf($this->get_tool_icons(true, false));
2031 + echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete the .htaccess file?" data-btn-confirm="Delete .htaccess file" data-text-wait="Deleting .htaccess file. Please wait." data-text-confirm="Htaccess file will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="Htaccess file has been deleted." data-text-done-singular="Htaccess file has been deleted." class="button button-delete" href="#" id="delete-htaccess">Delete .htaccess file</a></p>';
1954 2032
1955 - /**
1956 - * Echoes content for collections tab
1957 - *
1958 - * @return null
1959 - */
1960 - private function tab_collections()
1961 - {
1962 - echo '<div class="card">';
1963 - echo $this->get_card_header('What are Plugin & Theme Collections?', 'collections-info', array('collapse_button' => false));
1964 - echo '<div class="card-body">';
1965 - echo '<p>' . __('Have a set of plugins (and themes) that you install and activate after every reset? Or on every fresh WordPress installation? Well, no more clicking install &amp; active for ten minutes! Build the collection once and install it with one click as many times as needed.</p><p>WP Reset stores collections in the cloud so they\'re accessible on every site you build. You can use free plugins and themes from the official repo, and PRO ones by uploading a ZIP file. We\'ll safely store your license keys too, so you have everything in one place.', 'wp-reset') . '</p>';
1966 - echo '<p><a class="button button-secondary button-pro-feature" href="#">Add a new collection - <span data-feature="collections" class="pro-feature"><span class="pro">PRO</span> feature</span></a> &nbsp; <a class="button button-secondary button-pro-feature" href="#">Reload my saved collections from the cloud - <span data-feature="collections" class="pro-feature"><span class="pro">PRO</span> feature</span></a></p>';
1967 - echo '</div>';
1968 - echo '</div>'; // collections-info
2033 + echo '</div>';
2034 + echo '</div>'; // delete htaccess
2035 + } // tab_tools
1969 2036
1970 - $plugins = array();
1971 - $plugins['eps-301-redirects'] = array('name' => '301 Redirects', 'desc' => 'Easiest way to manage redirects');
1972 - $plugins['classic-editor'] = array('name' => 'Classic Editor', 'desc' => 'Any easy fix for all your Gutenberg caused troubles');
1973 - $plugins['simple-author-box'] = array('name' => 'Simple Author Box', 'desc' => 'Simplest way to add responsive, great looking author boxes');
1974 - $plugins['sticky-menu-or-anything-on-scroll'] = array('name' => 'Sticky Menu (or Anything!) on Scroll', 'desc' => 'Make any element on the page sticky.');
1975 - $plugins['under-construction-page'] = array('name' => 'UnderConstructionPage', 'desc' => 'Working on your site? Put it in the under construction mode.');
1976 - $plugins['wp-external-links'] = array('name' => 'WP External Links', 'desc' => 'Manage all external & internal links. Control icons, nofollow, noopener, UGC, sponsored and if links open in new window or new tab.');
1977 2037
1978 - echo '<div class="card" data-collection-id="1">';
1979 - echo $this->get_card_header('Must Have WordPress Plugins', 'collection-id-1', array('collapse_button' => false));
1980 - echo '<div class="card-body"><div class="thirdx2"><p class="_mb0"></p><div class="dropdown dropdown-right">
2038 + /**
2039 + * Echoes content for collections tab
2040 + *
2041 + * @return null
2042 + */
2043 + private function tab_collections()
2044 + {
2045 + echo '<div class="card">';
2046 + WP_Reset_Utility::wp_kses_wf($this->get_card_header('What are Plugin & Theme Collections?', 'collections-info', array('collapse_button' => false)));
2047 + echo '<div class="card-body">';
2048 + WP_Reset_Utility::wp_kses_wf('<p>' . __('Have a set of plugins (and themes) that you install and activate after every reset? Or on every fresh WordPress installation? Well, no more clicking install &amp; active for ten minutes! Build the collection once and install it with one click as many times as needed.</p><p>WP Reset stores collections in the cloud so they\'re accessible on every site you build. You can use free plugins and themes from the official repo, and PRO ones by uploading a ZIP file. We\'ll safely store your license keys too, so you have everything in one place.', 'wp-reset') . '</p>');
2049 + echo '<p><a class="button button-secondary button-pro-feature" href="#">Add a new collection - <span data-feature="collections" class="pro-feature"><span class="pro">PRO</span> feature</span></a> &nbsp; <a class="button button-secondary button-pro-feature" href="#">Reload my saved collections from the cloud - <span data-feature="collections" class="pro-feature"><span class="pro">PRO</span> feature</span></a></p>';
2050 + echo '</div>';
2051 + echo '</div>'; // collections-info
2052 +
2053 + $plugins = array();
2054 + $plugins['eps-301-redirects'] = array('name' => '301 Redirects', 'desc' => 'Easiest way to manage redirects');
2055 + $plugins['classic-editor'] = array('name' => 'Classic Editor', 'desc' => 'Any easy fix for all your Gutenberg caused troubles');
2056 + $plugins['simple-author-box'] = array('name' => 'Simple Author Box', 'desc' => 'Simplest way to add responsive, great looking author boxes');
2057 + $plugins['sticky-menu-or-anything-on-scroll'] = array('name' => 'Sticky Menu (or Anything!) on Scroll', 'desc' => 'Make any element on the page sticky.');
2058 + $plugins['under-construction-page'] = array('name' => 'UnderConstructionPage', 'desc' => 'Working on your site? Put it in the under construction mode.');
2059 + $plugins['wp-external-links'] = array('name' => 'WP External Links', 'desc' => 'Manage all external & internal links. Control icons, nofollow, noopener, UGC, sponsored and if links open in new window or new tab.');
2060 +
2061 + echo '<div class="card" data-collection-id="1">';
2062 + WP_Reset_Utility::wp_kses_wf($this->get_card_header('Must Have WordPress Plugins', 'collection-id-1', array('collapse_button' => false)));
2063 + echo '<div class="card-body"><div class="thirdx2"><p class="_mb0"></p><div class="dropdown dropdown-right">
1981 2064 <a class="button dropdown-toggle" href="#">Install collection</a>
1982 2065 <div class="dropdown-menu">
1983 2066 <a class="dropdown-item install-collection" data-activate="true" href="#">Install &amp; activate collection</a>
1984 2067 <a class="dropdown-item install-collection" href="#">Install collection</a>
@@ -1992,10 +2075,10 @@
1992 2075 <a class="dropdown-item button-pro-feature" href="#">Rename collection - <span class="pro-feature" data-feature="collections"><span class="pro">PRO</span> Feature</span></a>
1993 2076 <a class="dropdown-item button-delete button-pro-feature" href="#">Delete collection - <span class="pro-feature" data-feature="collections"><span class="pro">PRO</span> Feature</span></a>
1994 2077 </div>
1995 2078 </div><p></p></div><table class="collection-table"><tbody><tr><th>Type</th><th>Name &amp; Note</th><th class="actions">Actions</th></tr>';
1996 - foreach ($plugins as $slug => $plugin) {
1997 - echo '<tr data-slug="' . esc_attr($slug) . '"><td><span class="dashicons dashicons-admin-plugins tooltip" title="Plugin"></span><span class="dashicons dashicons-wordpress tooltip" title="Comes from the WordPress repository"></span></td><td class="collection-item-details"><span>' . esc_html($plugin['name']) . '</span><i>' . esc_html($plugin['desc']) . '</i></td><td class="textcenter"><div class="dropdown">
2079 + foreach ($plugins as $slug => $plugin) {
2080 + echo '<tr data-slug="' . esc_attr($slug) . '"><td><span class="dashicons dashicons-admin-plugins tooltip" title="Plugin"></span><span class="dashicons dashicons-wordpress tooltip" title="Comes from the WordPress repository"></span></td><td class="collection-item-details"><span>' . esc_html($plugin['name']) . '</span><i>' . esc_html($plugin['desc']) . '</i></td><td class="textcenter"><div class="dropdown">
1998 2081 <a class="button dropdown-toggle" href="#">Actions</a>
1999 2082 <div class="dropdown-menu">
2000 2083 <a href="#" class="dropdown-item install-collection-item button-pro-feature">Install - <span class="pro-feature" data-feature="collections"><span class="pro">PRO</span> Feature</span></a>
2001 2084 <a href="#" class="dropdown-item install-collection-item button-pro-feature">Install &amp; Activate - <span class="pro-feature" data-feature="collections"><span class="pro">PRO</span> Feature</span></a>
@@ -2002,963 +2085,1087 @@
2002 2085 <a href="#" class="dropdown-item edit-collection-item button-pro-feature">Edit - <span class="pro-feature" data-feature="collections"><span class="pro">PRO</span> Feature</span></a>
2003 2086 <a href="#" class="dropdown-item button-delete button-link-delete delete-collection-item button-pro-feature">Delete - <span class="pro-feature" data-feature="collections"><span class="pro">PRO</span> Feature</span></a>
2004 2087 </div>
2005 2088 </div></td></tr>';
2006 - } // foreach plugin
2007 - echo '</tbody></table></div></div>';
2008 - } // tab_collections
2089 + } // foreach plugin
2090 + echo '</tbody></table></div></div>';
2091 + } // tab_collections
2009 2092
2010 2093
2011 - /**
2012 - * Echoes content for support tab
2013 - *
2014 - * @return null
2015 - */
2016 - private function tab_support()
2017 - {
2018 - echo '<div class="card">';
2019 - echo $this->get_card_header(__('Documentation', 'wp-reset'), 'support-documentation', array('collapse_button' => false));
2020 - echo '<div class="card-body">';
2021 - echo '<p class="mb0">' . __('All tools and features are explained in detail in <a href="' . esc_url($this->generate_web_link('support-tab', '/documentation/')) . '" target="_blank">the documentation</a>. We did our best to describe how things work on both the code level and an "average user" level.', 'wp-reset') . '</p>';
2022 - echo '</div>';
2023 - echo '</div>'; // documentation
2094 + /**
2095 + * Echoes content for support tab
2096 + *
2097 + * @return null
2098 + */
2099 + private function tab_support()
2100 + {
2101 + echo '<div class="card">';
2102 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Documentation', 'wp-reset'), 'support-documentation', array('collapse_button' => false)));
2103 + echo '<div class="card-body">';
2104 + /* translators: %s is replaced with the link to the documentation page */
2105 + WP_Reset_Utility::wp_kses_wf('<p class="mb0">' . sprintf(__('All tools and features are explained in detail in <a href="%s" target="_blank">the documentation</a>. We did our best to describe how things work on both the code level and an "average user" level.', 'wp-reset'), esc_url($this->generate_web_link('support-tab', '/documentation/'))) . '</p>');
2106 + echo '</div>';
2107 + echo '</div>'; // documentation
2024 2108
2025 - echo '<div class="card">';
2026 - echo $this->get_card_header('Emergency Recovery Script', 'support-ers', array('collapse_button' => false, 'pro' => true));
2027 - echo '<div class="card-body">';
2028 - echo '<p>Emergency Recovery Script is a standalone, single-file, WordPress independent PHP script created to <b>recover WordPress sites from the most difficult situations</b>. When access to the admin is not possible when core files are compromised (accidental delete or malware related situations), when you get the white screen of death, can\'t log in for whatever reason or a plugin has killed your site - emergency recovery script can fix the problem! Some of the things ERS can do;</p>';
2029 - echo '<ul class="plain-list">';
2030 - echo '<li>Test the integrity of all WP core files and reinstall them if needed</li>';
2031 - echo '<li>Detect and remove all files in core folders that are not a part of WP</li>';
2032 - echo '<li>Deactivate and activate plugins without logging in to WP admin</li>';
2033 - echo '<li>Deactivate and activate themes without logging in to WP admin</li>';
2034 - echo '<li>Reset user privileges and roles</li>';
2035 - echo '<li>Create new WP admin accounts without logging in to WP admin or knowing the admin username/password</li>';
2036 - echo '<li>Modify WordPress address and site address</li>';
2037 - echo '</ul>';
2038 - echo '<p class="mb0">You can install the script as a preventive measure, so it\'s always available in case of an emergency (don\'t worry, it\'s password protected), or upload it only when needed. On production sites, when big and potentially dangerous changes rarely happen, we suggest uploading it only when needed. On test sites, have it ready in advance because there\'s a higher probability that you\'ll need it. Emergency Recovery Script is a <span class="pro-feature pro-feature-text" data-feature="support-ers">WP Reset <span>PRO</span></span> tool.</p>';
2039 - echo '</div>';
2040 - echo '</div>'; // emergency recovery script
2109 + echo '<div class="card">';
2110 + WP_Reset_Utility::wp_kses_wf($this->get_card_header('Emergency Recovery Script', 'support-ers', array('collapse_button' => false, 'pro' => true)));
2111 + echo '<div class="card-body">';
2112 + echo '<p>Emergency Recovery Script is a standalone, single-file, WordPress independent PHP script created to <b>recover WordPress sites from the most difficult situations</b>. When access to the admin is not possible when core files are compromised (accidental delete or malware related situations), when you get the white screen of death, can\'t log in for whatever reason or a plugin has killed your site - emergency recovery script can fix the problem! Some of the things ERS can do;</p>';
2113 + echo '<ul class="plain-list">';
2114 + echo '<li>Test the integrity of all WP core files and reinstall them if needed</li>';
2115 + echo '<li>Detect and remove all files in core folders that are not a part of WP</li>';
2116 + echo '<li>Deactivate and activate plugins without logging in to WP admin</li>';
2117 + echo '<li>Deactivate and activate themes without logging in to WP admin</li>';
2118 + echo '<li>Reset user privileges and roles</li>';
2119 + echo '<li>Create new WP admin accounts without logging in to WP admin or knowing the admin username/password</li>';
2120 + echo '<li>Modify WordPress address and site address</li>';
2121 + echo '</ul>';
2122 + echo '<p class="mb0">You can install the script as a preventive measure, so it\'s always available in case of an emergency (don\'t worry, it\'s password protected), or upload it only when needed. On production sites, when big and potentially dangerous changes rarely happen, we suggest uploading it only when needed. On test sites, have it ready in advance because there\'s a higher probability that you\'ll need it. Emergency Recovery Script is a <span class="pro-feature pro-feature-text" data-feature="support-ers">WP Reset <span>PRO</span></span> tool.</p>';
2123 + echo '</div>';
2124 + echo '</div>'; // emergency recovery script
2041 2125
2042 - echo '<div class="card">';
2043 - echo $this->get_card_header(__('Public Support Forum', 'wp-reset'), 'support-forum', array('collapse_button' => false));
2044 - echo '<div class="card-body">';
2045 - echo '<p>' . __('We are very active on the <a href="https://wordpress.org/support/plugin/wp-reset" target="_blank">official WP Reset support forum</a>. If you found a bug, have a feature idea or just want to say hi - please drop by. We love to hear back from our users.', 'wp-reset') . '</p>';
2046 - echo '</div>';
2047 - echo '</div>'; // forum
2126 + echo '<div class="card">';
2127 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Public Support Forum', 'wp-reset'), 'support-forum', array('collapse_button' => false)));
2128 + echo '<div class="card-body">';
2129 + WP_Reset_Utility::wp_kses_wf('<p>' . __('We are very active on the <a href="https://wordpress.org/support/plugin/wp-reset" target="_blank">official WP Reset support forum</a>. If you found a bug, have a feature idea or just want to say hi - please drop by. We love to hear back from our users.', 'wp-reset') . '</p>');
2130 + echo '</div>';
2131 + echo '</div>'; // forum
2048 2132
2049 - echo '<div class="card">';
2050 - echo $this->get_card_header(__('Premium Email Support', 'wp-reset'), 'support-email', array('collapse_button' => false, 'pro' => true));
2051 - echo '<div class="card-body">';
2052 - echo '<p class="mb0">Need urgent support? Have one of our devs personally help you with your issue. All PRO license holders have access to premium email support. Get <span class="pro-feature pro-feature-text" data-feature="support-email">WP Reset <span>PRO</span></span> now.</p>';
2053 - echo '</div>';
2054 - echo '</div>'; // email support
2133 + echo '<div class="card">';
2134 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Premium Email Support', 'wp-reset'), 'support-email', array('collapse_button' => false, 'pro' => true)));
2135 + echo '<div class="card-body">';
2136 + echo '<p class="mb0">Need urgent support? Have one of our devs personally help you with your issue. All PRO license holders have access to premium email support. Get <span class="pro-feature pro-feature-text" data-feature="support-email">WP Reset <span>PRO</span></span> now.</p>';
2137 + echo '</div>';
2138 + echo '</div>'; // email support
2055 2139
2056 - echo '<div class="card">';
2057 - echo $this->get_card_header(__('Care to Help Out?', 'wp-reset'), 'support-help-out', array('collapse_button' => false));
2058 - echo '<div class="card-body">';
2059 - echo '<p class="mb0">' . __('No need for donations :) If you can give us a <a href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" target="_blank">five star rating</a> you\'ll help out more than you can imagine. A public mention <a href="https://twitter.com/webfactoryltd" target="_blank">@webfactoryltd</a> also does wonders. Thank you!', 'wp-reset') . '</p>';
2060 - echo '</div>';
2061 - echo '</div>'; // help out
2062 - } // tab_support
2140 + echo '<div class="card">';
2141 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Care to Help Out?', 'wp-reset'), 'support-help-out', array('collapse_button' => false)));
2142 + echo '<div class="card-body">';
2143 + WP_Reset_Utility::wp_kses_wf('<p class="mb0">' . __('No need for donations :) If you can give us a <a href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" target="_blank">five star rating</a> you\'ll help out more than you can imagine. A public mention <a href="https://twitter.com/webfactoryltd" target="_blank">@webfactoryltd</a> also does wonders. Thank you!', 'wp-reset') . '</p>');
2144 + echo '</div>';
2145 + echo '</div>'; // help out
2146 + } // tab_support
2063 2147
2064 2148
2065 - /**
2066 - * Echoes content for pro tab
2067 - *
2068 - * @return null
2069 - */
2070 - private function tab_pro()
2071 - {
2072 - echo '<div class="card">';
2073 - echo $this->get_card_header(__('WP Reset PRO', 'wp-reset'), 'pro-features', array('collapse_button' => false));
2074 - echo '<div class="card-body">';
2075 - echo '<p>More ways to reset your site, more tools, automatic snapshots, collections, email support and the emergency recover script - that\'s WP Reset PRO in a nutshell. The same <b>quality and easy-of-use</b> you experienced in the free version is very much a part of the PRO one, but extended and upgraded with more tools that will save you even more time.</p>';
2076 - echo '<p>WP Reset PRO is aimed towards <b>webmasters, agencies, and everyone who buildsa a lot of WordPress sites</b>. It\'s much, much more than a "reset" tool. It\'s an easy way to start a new site, to test changes and to get out of the thickest jams. And thanks to its cloud features and the Dashboard it\'ll give you access to collections and snapshots on all the sites you\'re working on - instantly, without dragging any files along.</p>';
2077 - echo '<p>Give WP Reset PRO a go. <b>It\'ll pay itself out in hours saved within the first few days!</b></p>';
2078 - echo '<p>If you already have a PRO license - <a href="#pro-activate" class="scrollto">activate it</a>.</p>';
2079 - echo '</div>';
2080 - echo '</div>';
2149 + /**
2150 + * Echoes content for pro tab
2151 + *
2152 + * @return null
2153 + */
2154 + private function tab_pro()
2155 + {
2156 + $agency_lifetime = $this->generate_web_link('pricing-table', '/buy/', array('p' => 'wp-reset-pro-agency-ltd-launch'));
2157 + $team_lifetime = $this->generate_web_link('pricing-table', '/', array(), 'pricing');
2158 + $personal_lifetime = $this->generate_web_link('pricing-table', '/buy/', array('p' => 'wp-reset-pro-personal-ltd-launch'));
2081 2159
2082 - echo '<div class="card">';
2083 - echo $this->get_card_header(__('Pricing', 'wp-reset'), 'pro-pricing', array('collapse_button' => false));
2084 - echo '<div class="card-body">';
2160 + echo '<div class="card">';
2161 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('WP Reset PRO', 'wp-reset'), 'pro-features', array('collapse_button' => false)));
2162 + echo '<div class="card-body">';
2163 + echo '<p>More ways to reset your site, more tools, automatic snapshots, collections, email support and the emergency recover script - that\'s WP Reset PRO in a nutshell. The same <b>quality and easy-of-use</b> you experienced in the free version is very much a part of the PRO one, but extended and upgraded with more tools that will save you even more time.</p>';
2164 + echo '<p>WP Reset PRO is aimed towards <b>webmasters, agencies, and everyone who buildsa a lot of WordPress sites</b>. It\'s much, much more than a "reset" tool. It\'s an easy way to start a new site, to test changes and to get out of the thickest jams. And thanks to its cloud features and the Dashboard it\'ll give you access to collections and snapshots on all the sites you\'re working on - instantly, without dragging any files along.</p>';
2165 + echo '<p>Give WP Reset PRO a go. <b>It\'ll pay itself out in hours saved within the first few days!</b></p>';
2166 + echo '<p>If you already have a PRO license, activate it below.</p>';
2167 + echo '<p class="textcenter"><a href="#" data-feature="purchase-pro" class="button-pro-feature button button-delete">Get PRO now</a></p>';
2168 + echo '</div>';
2169 + echo '</div>';
2085 2170
2086 - echo '<table id="pricing-table" class="mb0">';
2087 - echo '<tr>';
2088 - echo '<th>&nbsp;</th>';
2089 - echo '<th nowrap>WP Reset <span>PRO</span><br><b>Agency</b></th>';
2090 - echo '<th nowrap>WP Reset <span>PRO</span><br><b>Team</b></th>';
2091 - echo '<th nowrap>WP Reset <span>PRO</span><br><b>Personal</b></th>';
2092 - echo '<th nowrap>WP Reset<br>Free</th>';
2093 - echo '</tr>';
2171 + echo '<div class="card">';
2172 + WP_Reset_Utility::wp_kses_wf($this->get_card_header(__('Activate PRO License', 'wp-reset'), 'pro-activate', array('collapse_button' => false)));
2173 + echo '<div class="card-body">';
2094 2174
2095 - $rows = array();
2096 - $rows['Options & Nuclear Reset'] = array(false, true, true, true);
2097 - $rows['Site Reset'] = array(true, true, true, true);
2098 - $rows['9 Basic Reset Tools'] = array(true, true, true, true);
2099 - $rows['17+ PRO Reset Tools'] = array(false, true, true, true);
2100 - $rows['Granular Content Reset Tools'] = array(false, true, true, true);
2101 - $rows['User Snapshots'] = array(true, true, true, true);
2102 - $rows['Automatic Snapshots'] = array(false, true, true, true);
2103 - $rows['Automatically Offload Snapshots to WP Reset Cloud, 2GB storage per site'] = array(false, true, true, true);
2104 - $rows['Automatically Offload Snapshots to Dropbox, Google Drive & pCloud'] = array(false, true, true, true);
2105 - $rows['Plugins & Themes Collections'] = array(false, true, true, true);
2106 - $rows['Emergency Recovery Script'] = array(false, true, true, true);
2107 - $rows['Email Support'] = array(false, true, true, true);
2108 - $rows['WP Reset Dashboard'] = array(false, true, true, true);
2109 - $rows['License Manager'] = array(false, true, true, true);
2110 - $rows['White-Label'] = array(false, false, false, true);
2111 - $rows['Manage Snapshots for all sites in Dashboard'] = array(false, true, true, true);
2112 - $rows['Manage Collections for all sites in Dashboard'] = array(false, true, true, true);
2113 - $rows['Number of sites included in the license (localhosts are not counted & you can change sites)'] = array('&infin;', 1, 5, 100);
2114 - $rows['Number of WP Reset Cloud site licenses with 2GB storage per site (localhosts are not counted & you can change sites)'] = array(0, 1, 5, 20);
2175 + echo '<p>License key is visible on the confirmation screen, right after purchasing. You can also find it in the confirmation email sent to the email address provided on purchase. Or use keys created with the <a href="https://dashboard.wpreset.com/licenses/" target="_blank">license manager</a>.</p>
2176 + <p>If you don\'t have a license - <a class="button-pro-feature" href="#" data-feature="purchase-pro2">purchase one now</a>. In case of problems with the license please <a href="' . esc_url($this->generate_web_link('pro-tab-license', '/contact/')) . '" target="_blank">contact support</a>.</p>';
2115 2177
2116 - foreach ($rows as $feature => $details) {
2117 - echo '<tr>';
2118 - echo '<td>' . esc_html($feature) . '</td>';
2119 - $details = array_reverse($details);
2120 - foreach ($details as $tmp) {
2121 - echo '<td>';
2122 - if ($tmp === true) {
2123 - echo '<i class="dashicons dashicons-yes green tooltip" title="Feature is available"></i>';
2124 - } elseif ($tmp === false) {
2125 - echo '<i class="dashicons dashicons-no red tooltip" title="Feature is not available"></i>';
2178 + echo '<hr>';
2179 + echo '<p><label for="wpr-license-key">License Key: </label><input class="regular-text" type="text" id="wpr-license-key" value="' . ($this->license->get_license('license_key') != 'keyless' ? esc_attr($this->license->get_license('license_key')) : '') . '" placeholder="12345678-12345678-12345678-12345678">';
2180 +
2181 + echo '<br><label>Status: </label>';
2182 + if ($this->license->is_active()) {
2183 + $license_formatted = $this->license->get_license_formatted();
2184 + echo '<b style="color: #66b317;">Active</b><br>
2185 + <label>Type: </label>' . esc_html($license_formatted['name_long']);
2186 + echo '<br><label>Valid: </label>' . esc_html($license_formatted['valid_until']);
2187 +
2188 + echo '<p>Thank you for purchasing WP Reset PRO! <b>Your license has been verified and activated.</b>';
2189 + echo '<br>To start using the PRO version, please follow these steps:</p>';
2190 + echo '<ol>';
2191 + echo '<li><a href="https://dashboard.wpreset.com/pro-download/" target="_blank">Download</a> the latest version of the PRO plugin.</li>';
2192 + echo '<li>Go to <a href="' . esc_url(admin_url('plugin-install.php')) . '">Plugins - Add New - Upload Plugin</a> and upload the ZIP you just downloaded.</li>';
2193 + echo '<li>If asked to replace (overwrite) the free version - confirm it.</li>';
2194 + echo '<li>Activate the plugin.</li>';
2195 + echo '<li>That\'s it, no more steps.</li>';
2196 + echo '</ol>';
2197 + } else { // not active
2198 + echo '<strong style="color: #ea1919;">Inactive</strong>';
2199 + if (!empty($this->license->get_license('error'))) {
2200 + echo '<br><label>Error: </label>' . esc_html($this->license->get_license('error'));
2201 + }
2202 + }
2203 + echo '</p>';
2204 +
2205 + echo '<p>';
2206 + if ($this->license->is_active()) {
2207 + echo '<a href="#" id="wpr-save-license" data-text-wait="Validating. Please wait." class="button button-secondary">Save &amp; Revalidate License</a>';
2208 + echo '&nbsp; &nbsp;<a href="#" id="wpr-deactivate-license" data-text-wait="Deactivating. Please wait." class="button button-delete">Deactivate License</a>';
2126 2209 } else {
2127 - echo $tmp;
2210 + echo '<a href="#" id="wpr-save-license" data-text-wait="Activating. Please wait." class="button button-primary">Save &amp; Activate License</a>';
2211 + echo '&nbsp; &nbsp;<a href="#" data-text-wait="Activating. Please wait." class="button button-secondary" id="wpr-keyless-activation">Keyless Activation</a>';
2128 2212 }
2129 - echo '</td>';
2130 - } // foreach column
2131 - echo '</tr>';
2132 - } // foreach $rows
2213 + echo '</p>';
2214 + echo '<p class="mb0"><i>By attempting to activate a license you agree to share the following data with <a target="_blank" href="https://www.webfactoryltd.com/">WebFactory Ltd</a>: license key, site URL, site title, site WP version, site IP, and WP Reset plugin (free) version.</i>';
2215 + echo '</p>';
2133 2216
2134 - $agency = $this->generate_web_link('pricing-table', '/buy/', array('p' => 'wp-reset-pro-agency-launch'));
2135 - $team = $this->generate_web_link('pricing-table', '/buy/', array('p' => 'wp-reset-pro-team-launch'));
2136 - $team_lifetime = $this->generate_web_link('pricing-table', '/buy/', array('p' => 'wp-reset-pro-team-lifetime-launch'));
2137 - $personal = $this->generate_web_link('pricing-table', '/buy/', array('p' => 'wp-reset-pro-personal-launch'));
2138 - echo '<tr class="pricing"><td>Yearly Price</td>';
2139 - echo '<td><del>&nbsp;$299/y&nbsp;</del><br><b>50% OFF</b><br>$149 <small>/y</small><br><a href="' . esc_url($agency) . '" class="button" target="_blank">BUY NOW</a></td>';
2140 - echo '<td><del>&nbsp;$158/y&nbsp;</del><br><b>50% OFF</b><br>$79 <small>/y</small><br><a href="' . esc_url($team) . '" class="button" target="_blank">BUY NOW</a></td>';
2141 - echo '<td><del>&nbsp;$79 <small>/y</small>&nbsp;</del><br><b>50% OFF</b><br>$39 <small>/y</small><br><a href="' . esc_url($personal) . '" class="button" target="_blank">BUY NOW</a></td>';
2142 - echo '<td>free</td>';
2143 - echo '</tr>';
2144 - echo '<tr class="pricing"><td>Lifetime Price</td>';
2145 - echo '<td><i>n/a</i></td>';
2146 - echo '<td><del>&nbsp;$319&nbsp;</del><br><b>one-time payment<br>50% OFF</b><br>$159<br><a href="' . esc_url($team_lifetime) . '" class="button button-primary" target="_blank">BUY NOW</a></td>';
2147 - echo '<td><i>n/a</i></td>';
2148 - echo '<td>free</td>';
2149 - echo '</tr>';
2150 - echo '</table>';
2217 + echo '</div>';
2218 + echo '</div>'; // activate PRO
2151 2219
2152 - echo '</div>';
2153 - echo '</div>';
2220 + WP_Reset_Utility::wp_kses_wf($this->pro_dialog());
2221 + } // tab_pro
2154 2222
2155 - echo '<div class="card">';
2156 - echo $this->get_card_header(__('Activate PRO License', 'wp-reset'), 'pro-activate', array('collapse_button' => false));
2157 - echo '<div class="card-body">';
2158 2223
2159 - echo '<p>License key is visible on the confirmation screen, right after purchasing. You can also find it in the confirmation email sent to the email address provided on purchase. Or use keys created with the <a href="https://dashboard.wpreset.com/licenses/" target="_blank">license manager</a>.</p>
2160 - <p>If you don\'t have a license - <a class="scrollto" href="#pro-pricing">purchase one now</a>. In case of problems with the license please <a href="' . esc_url($this->generate_web_link('pro-tab-license', '/contact/')) . '" target="_blank">contact support</a>.</p>';
2224 + function pro_dialog()
2225 + {
2226 + $out = '';
2161 2227
2162 - echo '<hr>';
2163 - echo '<p><label for="wpr-license-key">License Key: </label><input class="regular-text" type="text" id="wpr-license-key" value="' . ($this->license->get_license('license_key') != 'keyless' ? esc_attr($this->license->get_license('license_key')) : '') . '" placeholder="12345678-12345678-12345678-12345678">';
2228 + $out .= '<div id="wpreset-pro-dialog" style="display: none;" title="WP Reset PRO"><span class="ui-helper-hidden-accessible"><input type="text"/></span>';
2164 2229
2165 - echo '<br><label>Status: </label>';
2166 - if ($this->license->is_active()) {
2167 - $license_formatted = $this->license->get_license_formatted();
2168 - echo '<b style="color: #66b317;">Active</b><br>
2169 - <label>Type: </label>' . esc_html($license_formatted['name_long']);
2170 - echo '<br><label>Valid: </label>' . esc_html($license_formatted['valid_until']);
2230 + $out .= '<div class="center logo"><a href="https://wpreset.com/?ref=wpreset-free-pricing-table" target="_blank"><img src="' . $this->plugin_url . 'img/wp-reset-logo.png' . '" alt="WP Reset PRO" title="WP Reset PRO"></a><br>';
2171 2231
2172 - echo '<p>Thank you for purchasing WP Reset PRO! <b>Your license has been verified and activated.</b>';
2173 - echo '<br>To start using the PRO version, please follow these steps:</p>';
2174 - echo '<ol>';
2175 - echo '<li><a href="https://dashboard.wpreset.com/pro-download/" target="_blank">Download</a> the latest version of the PRO plugin.</li>';
2176 - echo '<li>Go to <a href="' . esc_url(admin_url('plugin-install.php')) . '">Plugins - Add New - Upload Plugin</a> and upload the ZIP you just downloaded.</li>';
2177 - echo '<li>If asked to replace (overwrite) the free version - confirm it.</li>';
2178 - echo '<li>Activate the plugin.</li>';
2179 - echo '<li>That\'s it, no more steps.</li>';
2180 - echo '</ol>';
2181 - } else { // not active
2182 - echo '<strong style="color: #ea1919;">Inactive</strong>';
2183 - if (!empty($this->license->get_license('error'))) {
2184 - echo '<br><label>Error: </label>' . esc_html($this->license->get_license('error'));
2185 - }
2186 - }
2187 - echo '</p>';
2232 + $out .= '<span>Limited PRO Offer - <b>all prices are LIFETIME</b>! Pay once &amp; use forever!</span>';
2233 + $out .= '</div>';
2188 2234
2189 - echo '<p>';
2190 - if ($this->license->is_active()) {
2191 - echo '<a href="#" id="wpr-save-license" data-text-wait="Validating. Please wait." class="button button-secondary">Save &amp; Revalidate License</a>';
2192 - echo '&nbsp; &nbsp;<a href="#" id="wpr-deactivate-license" data-text-wait="Deactivating. Please wait." class="button button-delete">Deactivate License</a>';
2193 - } else {
2194 - echo '<a href="#" id="wpr-save-license" data-text-wait="Activating. Please wait." class="button button-primary">Save &amp; Activate License</a>';
2195 - echo '&nbsp; &nbsp;<a href="#" data-text-wait="Activating. Please wait." class="button button-secondary" id="wpr-keyless-activation">Keyless Activation</a>';
2196 - }
2197 - echo '</p>';
2198 - echo '<p class="mb0"><small><i>By attempting to activate a license you agree to share the following data with <a target="_blank" href="https://www.webfactoryltd.com/">WebFactory Ltd</a>: license key, site URL, site title, site WP version, and WP Reset (free) version.</i></small>';
2199 - echo '</p>';
2235 + $out .= '<table id="wpreset-pro-table">';
2236 + $out .= '<tr>';
2237 + $out .= '<td class="center">Lifetime Personal License</td>';
2238 + $out .= '<td class="center">Lifetime Team License</td>';
2239 + $out .= '<td class="center">Lifetime Agency License</td>';
2240 + $out .= '</tr>';
2200 2241
2201 - echo '</div>';
2202 - echo '</div>'; // activate PRO
2242 + $out .= '<tr class="prices">';
2243 + $out .= '<td class="center"><del>$39 /year</del><br><span>$59</span> <b>/lifetime</b></td>';
2244 + $out .= '<td class="center"><del>$79 /year</del><br><span>$69</span> <b>/lifetime</b></td>';
2245 + $out .= '<td class="center"><del>$119 /year</del><br><span>$149</span> <b>/lifetime</b></td>';
2246 + $out .= '</tr>';
2203 2247
2204 - // todo: not done
2205 - echo '<div style="display: none;">';
2248 + $out .= '<tr>';
2249 + $out .= '<td><span class="dashicons dashicons-yes"></span><b>1 Site License</b></td>';
2250 + $out .= '<td><span class="dashicons dashicons-yes"></span><b>5 Sites License</b></td>';
2251 + $out .= '<td><span class="dashicons dashicons-yes"></span><b>100 Sites License</b></td>';
2252 + $out .= '</tr>';
2206 2253
2207 - echo '<div id="pro-feature-details-tool-nuclear-reset-example">';
2208 - echo '<span class="title">this is a title</span>';
2209 - echo '<span class="description">this is a description</span>';
2210 - echo '<span class="button">button</span>';
2211 - echo '<span class="footer">footer</span>';
2212 - echo '</div>';
2254 + $out .= '<tr>';
2255 + $out .= '<td><span class="dashicons dashicons-yes"></span>All Plugin Features &amp; Tools</td>';
2256 + $out .= '<td><span class="dashicons dashicons-yes"></span>All Plugin Features &amp; Tools</td>';
2257 + $out .= '<td><span class="dashicons dashicons-yes"></span>All Plugin Features &amp; Tools</td>';
2258 + $out .= '</tr>';
2213 2259
2214 - echo '</div>';
2215 - } // tab_pro
2260 + $out .= '<tr>';
2261 + $out .= '<td><span class="dashicons dashicons-yes"></span>Lifetime Updates &amp; Support</td>';
2262 + $out .= '<td><span class="dashicons dashicons-yes"></span>Lifetime Updates &amp; Support</td>';
2263 + $out .= '<td><span class="dashicons dashicons-yes"></span>Lifetime Updates &amp; Support</td>';
2264 + $out .= '</tr>';
2216 2265
2266 + $out .= '<tr>';
2267 + $out .= '<td><span class="dashicons dashicons-yes"></span>2 GB WP Reset Cloud Storage</td>';
2268 + $out .= '<td><span class="dashicons dashicons-yes"></span>10 GB WP Reset Cloud Storage</td>';
2269 + $out .= '<td><span class="dashicons dashicons-yes"></span>100 GB WP Reset Cloud Storage</td>';
2270 + $out .= '</tr>';
2217 2271
2218 - /**
2219 - * Echoes content for snapshots tab
2220 - *
2221 - * @return null
2222 - */
2223 - private function tab_snapshots()
2224 - {
2225 - global $wpdb;
2226 - $tbl_core = $tbl_custom = $tbl_size = $tbl_rows = 0;
2272 + $out .= '<tr>';
2273 + $out .= '<td><span class="dashicons dashicons-yes"></span>Dropbox &amp; Google Drive support</td>';
2274 + $out .= '<td><span class="dashicons dashicons-yes"></span>Dropbox &amp; Google Drive support</td>';
2275 + $out .= '<td><span class="dashicons dashicons-yes"></span>Dropbox &amp; Google Drive support</td>';
2276 + $out .= '</tr>';
2227 2277
2228 - echo '<div class="card" id="card-snapshots">';
2229 - echo '<h4>';
2230 - echo __('Snapshots', 'wp-reset');
2231 - echo '<div class="card-header-right"><a class="toggle-card tooltip" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a></div>';
2232 - echo '</h4>';
2233 - echo '<div class="card-body">';
2234 - echo '<p>A snapshot is a copy of all WP database tables, standard and custom ones, saved in the site\'s database. <a href="https://www.youtube.com/watch?v=xBfMmS12vMY" target="_blank">Watch a short video</a> overview and tutorial about Snapshots.</p>';
2278 + $out .= '<tr>';
2279 + $out .= '<td><span class="dashicons dashicons-yes"></span>Plugins & Themes Collections</td>';
2280 + $out .= '<td><span class="dashicons dashicons-yes"></span>Plugins & Themes Collections</td>';
2281 + $out .= '<td><span class="dashicons dashicons-yes"></span>Plugins & Themes Collections</td>';
2282 + $out .= '</tr>';
2235 2283
2236 - echo '<p>Snapshots are primarily a development tool. When using various reset tools we advise using our 1-click snapshot tool available in every tool\'s confirmation dialog. If a full backup that includes files is needed, use one of the <a href="' . esc_url(admin_url('plugin-install.php?s=backup&tab=search&type=term')) . '" target="_blank">backup plugins</a> from the repo.</p>';
2284 + $out .= '<tr>';
2285 + $out .= '<td><span class="dashicons dashicons-yes"></span>Automatic Snapshots</td>';
2286 + $out .= '<td><span class="dashicons dashicons-yes"></span>Automatic Snapshots</td>';
2287 + $out .= '<td><span class="dashicons dashicons-yes"></span>Automatic Snapshots</td>';
2288 + $out .= '</tr>';
2237 2289
2238 - echo '<p>Use snapshots to find out what changes a plugin made to your database or to quickly restore the dev environment after testing database related changes. Restoring a snapshot does not affect other snapshots, or WP Reset settings.</p>';
2290 + $out .= '<tr>';
2291 + $out .= '<td><span class="dashicons dashicons-yes"></span>Emergency Recovery Script</td>';
2292 + $out .= '<td><span class="dashicons dashicons-yes"></span>Emergency Recovery Script</td>';
2293 + $out .= '<td><span class="dashicons dashicons-yes"></span>Emergency Recovery Script</td>';
2294 + $out .= '</tr>';
2239 2295
2240 - echo '<p>To automatically generate snapshots on plugin, theme, and core update, activate, deactivate and similar events enable automatic snapshots available in <span class="pro-feature pro-feature-text" data-feature="snapshots-auto">WP Reset <span>PRO</span></span>.</p>';
2296 + $out .= '<tr>';
2297 + $out .= '<td><span class="dashicons dashicons-no"></span>Licenses &amp; Sites Manager</td>';
2298 + $out .= '<td><span class="dashicons dashicons-yes"></span>Licenses &amp; Sites Manager</td>';
2299 + $out .= '<td><span class="dashicons dashicons-yes"></span>Licenses &amp; Sites Manager</td>';
2300 + $out .= '</tr>';
2241 2301
2242 - $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N);
2243 - if (is_array($tables)) {
2244 - foreach ($tables as $table) {
2245 - if (0 !== stripos($table[0], $wpdb->prefix)) {
2246 - continue;
2247 - }
2302 + $out .= '<tr>';
2303 + $out .= '<td><span class="dashicons dashicons-no"></span>White-label Mode</td>';
2304 + $out .= '<td><span class="dashicons dashicons-yes"></span>White-label Mode</td>';
2305 + $out .= '<td><span class="dashicons dashicons-yes"></span>White-label Mode</td>';
2306 + $out .= '</tr>';
2248 2307
2249 - if (in_array($table[0], $this->core_tables)) {
2250 - $tbl_core++;
2308 + $out .= '<tr>';
2309 + $out .= '<td><span class="dashicons dashicons-no"></span>Full Plugin Rebranding</td>';
2310 + $out .= '<td><span class="dashicons dashicons-no"></span>Full Plugin Rebranding</td>';
2311 + $out .= '<td><span class="dashicons dashicons-yes"></span>Full Plugin Rebranding</td>';
2312 + $out .= '</tr>';
2313 +
2314 + $out .= '<tr>';
2315 + $out .= '<td><a class="button button-buy" data-href-org="https://wpreset.com/buy2/?product=personal-free&ref=pricing-table" href="https://wpreset.com/buy2/?product=personal-free&ref=pricing-table" target="_blank">Lifetime License<br>$59 -&gt; BUY NOW</a>
2316 + <br>or <a class="button-buy" data-href-org="https://wpreset.com/buy2/?product=personal-monthly&ref=pricing-table" href="https://wpreset.com/buy2/?product=personal-monthly&ref=pricing-table" target="_blank">only $6.99 <small>/month</small></a></td>';
2317 + $out .= '<td><a class="button button-buy" data-href-org="https://wpreset.com/buy2/?product=team-free&ref=pricing-table" href="https://wpreset.com/buy2/?product=team-free&ref=pricing-table" target="_blank">Lifetime License<br>$69 -&gt; BUY NOW</a></td>';
2318 + $out .= '<td><a class="button button-buy" data-href-org="https://wpreset.com/buy2/?product=agency-free&ref=pricing-table" href="https://wpreset.com/buy2/?product=agency-free&ref=pricing-table" target="_blank">Lifetime License<br>$149 -&gt; BUY NOW</a></td>';
2319 + $out .= '</tr>';
2320 +
2321 + $out .= '</table>';
2322 +
2323 + $out .= '<div class="center footer"><b>100% No-Risk Money Back Guarantee!</b> If you don\'t like the plugin over the next 7 days, we will happily refund 100% of your money. No questions asked! Payments are processed by our merchant of records - <a href="https://paddle.com/" target="_blank">Paddle</a>.</div></div>';
2324 +
2325 + return $out;
2326 + } // pro_dialog
2327 +
2328 +
2329 + /**
2330 + * Echoes content for snapshots tab
2331 + *
2332 + * @return null
2333 + */
2334 + private function tab_snapshots()
2335 + {
2336 + global $wpdb;
2337 + $tbl_core = $tbl_custom = $tbl_size = $tbl_rows = 0;
2338 +
2339 + echo '<div class="card" id="card-snapshots">';
2340 + echo '<h4>';
2341 + echo esc_html__('Snapshots', 'wp-reset');
2342 + echo '<div class="card-header-right"><a class="toggle-card tooltip" href="#" title="' . esc_html__('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a></div>';
2343 + echo '</h4>';
2344 + echo '<div class="card-body">';
2345 + echo '<p>A snapshot is a copy of all WP database tables, standard and custom ones, saved in the site\'s database. <a href="https://www.youtube.com/watch?v=xBfMmS12vMY" target="_blank">Watch a short video</a> overview and tutorial about Snapshots.</p>';
2346 +
2347 + echo '<p>Snapshots are primarily a development tool. When using various reset tools we advise using our 1-click snapshot tool available in every tool\'s confirmation dialog. If a full backup that includes files is needed, use one of the <a href="' . esc_url(admin_url('plugin-install.php?s=backup&tab=search&type=term')) . '" target="_blank">backup plugins</a> from the repo.</p>';
2348 +
2349 + echo '<p>Use snapshots to find out what changes a plugin made to your database or to quickly restore the dev environment after testing database related changes. Restoring a snapshot does not affect other snapshots, or WP Reset settings.</p>';
2350 +
2351 + echo '<p>To automatically generate snapshots on plugin, theme, and core update, activate, deactivate and similar events enable automatic snapshots available in <span class="pro-feature pro-feature-text" data-feature="snapshots-auto">WP Reset <span>PRO</span></span>.</p>';
2352 +
2353 + // phpcs:ignore db call warning as we are using uncommon queries
2354 + $tables = $wpdb->get_results('SHOW TABLES', ARRAY_N); // phpcs:ignore
2355 + if (is_array($tables)) {
2356 + foreach ($tables as $table) {
2357 + if (0 !== stripos($table[0], $wpdb->prefix)) {
2358 + continue;
2359 + }
2360 +
2361 + if (in_array($table[0], $this->core_tables)) {
2362 + $tbl_core++;
2363 + } else {
2364 + $tbl_custom++;
2365 + }
2366 + } // foreach
2367 +
2368 + echo '<p class="mb0"><b>Currently used WordPress tables</b>, prefixed with <i>' . esc_html($wpdb->prefix) . '</i>, consist of ' . esc_html($tbl_core) . ' standard and ';
2369 + if ($tbl_custom) {
2370 + echo esc_attr($tbl_custom) . ' custom table' . ($tbl_custom == 1 ? '' : 's');
2371 + } else {
2372 + echo 'no custom tables';
2373 + }
2374 + echo ' <span id="wpr-table-details"><a href="#" id="show-table-details">(show details)</a></span>';
2251 2375 } else {
2252 - $tbl_custom++;
2376 + echo '<b>Tables information is not available.</b> Something is not working properly on your site. Snapshots won\'t work.';
2253 2377 }
2254 - } // foreach
2255 2378
2256 - echo '<p class="mb0"><b>Currently used WordPress tables</b>, prefixed with <i>' . esc_html($wpdb->prefix) . '</i>, consist of ' . esc_html($tbl_core) . ' standard and ';
2257 - if ($tbl_custom) {
2258 - echo $tbl_custom . ' custom table' . ($tbl_custom == 1 ? '' : 's');
2259 - } else {
2260 - echo 'no custom tables';
2261 - }
2262 - echo ' <span id="wpr-table-details"><a href="#" id="show-table-details">(show details)</a></span>';
2263 - } else {
2264 - echo '<b>Tables information is not available.</b> Something is not working properly on your site. Snapshots won\'t work.';
2265 - }
2379 + echo '</div>';
2380 + echo '</div>';
2266 2381
2267 - echo '</div>';
2268 - echo '</div>';
2382 + echo '<div class="card">';
2383 + WP_Reset_Utility::wp_kses_wf($this->get_card_header('User Created Snapshots', 'snapshots-user', array('collapse_button' => 1, 'create_snapshot' => true, 'snapshot_actions' => true)));
2384 + echo '<div class="card-body">';
2385 + if ($snapshots = $this->get_snapshots()) {
2386 + $snapshots = array_reverse($snapshots);
2387 + echo '<table id="wpr-snapshots">';
2388 + echo '<tr><th>Date</th><th>Description</th><th class="ss-size">Size</th><th class="ss-actions">
2389 + <div class="dropdown" style="font-weight:normal; margin-left: 4px;"><a class="button dropdown-toggle" href="#">Actions</a>
2390 + <div class="dropdown-menu">
2391 + <a class="dropdown-item button-pro-feature" href="#">Import a snapshot - <span class="pro-feature" data-feature="snapshots"><span class="pro">PRO</span> Feature</span></a>
2392 + <a class="dropdown-item button-pro-feature" href="#">Cloud snapshots - <span class="pro-feature" data-feature="snapshots"><span class="pro">PRO</span> Feature</span></a>
2393 + </div>
2394 + </div></th></tr>';
2395 + foreach ($snapshots as $ss) {
2396 + echo '<tr id="wpr-ss-' . esc_attr($ss['uid']) . '">';
2397 + if (!empty($ss['name'])) {
2398 + $name = $ss['name'];
2399 + } else {
2400 + $name = 'created on ' . gmdate(get_option('date_format'), strtotime($ss['timestamp'])) . ' @ ' . gmdate(get_option('time_format'), strtotime($ss['timestamp']));
2401 + }
2269 2402
2270 - echo '<div class="card">';
2271 - echo $this->get_card_header('User Created Snapshots', 'snapshots-user', array('collapse_button' => 1, 'create_snapshot' => true, 'snapshot_actions' => true));
2272 - echo '<div class="card-body">';
2273 - if ($snapshots = $this->get_snapshots()) {
2274 - $snapshots = array_reverse($snapshots);
2275 - echo '<table id="wpr-snapshots">';
2276 - echo '<tr><th>Date</th><th>Description</th><th class="ss-size">Size</th><th class="ss-actions">&nbsp;</th></tr>';
2277 - foreach ($snapshots as $ss) {
2278 - echo '<tr id="wpr-ss-' . esc_attr($ss['uid']) . '">';
2279 - if (!empty($ss['name'])) {
2280 - $name = $ss['name'];
2403 + echo '<td>';
2404 + if (current_time('timestamp') - strtotime($ss['timestamp']) > 12 * HOUR_IN_SECONDS) {
2405 + echo esc_attr(gmdate(get_option('date_format'), strtotime($ss['timestamp']))) . '<br>@ ' . esc_attr(gmdate(get_option('time_format'), strtotime($ss['timestamp'])));
2406 + } else {
2407 + echo esc_attr(human_time_diff(strtotime($ss['timestamp']), current_time('timestamp'))) . ' ago';
2408 + }
2409 + echo '</td>';
2410 +
2411 + echo '<td>';
2412 + if (!empty($ss['name'])) {
2413 + echo '<b>' . esc_html($ss['name']) . '</b><br>';
2414 + }
2415 + echo esc_attr($ss['tbl_core']) . ' standard &amp; ';
2416 + if ($ss['tbl_custom']) {
2417 + echo esc_attr($ss['tbl_custom']) . ' custom table' . ($ss['tbl_custom'] == 1 ? '' : 's');
2418 + } else {
2419 + echo 'no custom tables';
2420 + }
2421 + echo ' totaling ' . esc_attr(number_format($ss['tbl_rows'])) . ' rows</td>';
2422 + echo '<td class="ss-size">' . esc_attr(WP_Reset_Utility::format_size($ss['tbl_size'])) . '</td>';
2423 + echo '<td>';
2424 + echo '<div class="dropdown">
2425 + <a class="button dropdown-toggle" href="#">Actions</a>
2426 + <div class="dropdown-menu">';
2427 + echo '<a data-title="Current DB tables compared to snapshot %s" data-wait-msg="Comparing. Please wait." data-name="' . esc_attr($name) . '" title="Compare snapshot to current database tables" href="#" class="ss-action compare-snapshot dropdown-item tooltip" data-ss-uid="' . esc_attr($ss['uid']) . '">Compare snapshot to current data</a>';
2428 + echo '<a data-btn-confirm="Restore snapshot" data-text-wait="Restoring snapshot. Please wait." data-text-confirm="Are you sure you want to restore the selected snapshot? There is NO UNDO.<br>Restoring the snapshot will delete all current standard and custom tables and replace them with tables from the snapshot." data-text-done="Snapshot has been restored. Click OK to reload the page with new data." title="Restore snapshot by overwriting current database tables" href="#" class="ss-action restore-snapshot dropdown-item tooltip" data-ss-uid="' . esc_attr($ss['uid']) . '">Restore snapshot</a>';
2429 + echo '<a data-success-msg="Snapshot export created!<br><a href=\'%s\'>Download it</a>" data-wait-msg="Exporting snapshot. Please wait." title="Download snapshot as gzipped SQL dump" href="#" class="ss-action download-snapshot dropdown-item tooltip" data-ss-uid="' . esc_attr($ss['uid']) . '">Download snapshot</a>';
2430 + echo '<a data-btn-confirm="Delete snapshot" data-text-wait="Deleting snapshot. Please wait." data-text-confirm="Are you sure you want to delete the selected snapshot and all its data? There is NO UNDO.<br>Deleting the snapshot will not affect the active database tables in any way." data-text-done="Snapshot has been deleted." title="Permanently delete snapshot" href="#" class="ss-action delete-snapshot dropdown-item tooltip" data-ss-uid="' . esc_attr($ss['uid']) . '">Delete snapshot</a>';
2431 + echo '<a href="#" title="WP Reset PRO feature" data-feature="cloud-wpr" class="ss-action dropdown-item button-pro-feature tooltip">Upload to WP Reset Cloud - <span class="pro-feature" data-feature="cloud-wpr"><span class="pro">PRO</span> Feature</span></a>';
2432 + echo '<a href="#" title="WP Reset PRO feature" class="ss-action dropdown-item button-pro-feature tooltip" data-feature="cloud-general">Upload to Dropbox, Google Drive, or pCloud - <span class="pro-feature" data-feature="cloud-general"><span class="pro">PRO</span> Feature</span></a>';
2433 + echo '</div></div></td>';
2434 + echo '</tr>';
2435 + } // foreach
2436 + echo '</table>';
2437 + echo '<p id="ss-no-snapshots" class="mb0 textcenter hidden">There are no user created snapshots. <a href="#" class="create-new-snapshot">Create a new snapshot.</a></p>';
2281 2438 } else {
2282 - $name = 'created on ' . date(get_option('date_format'), strtotime($ss['timestamp'])) . ' @ ' . date(get_option('time_format'), strtotime($ss['timestamp']));
2439 + echo '<p id="ss-no-snapshots" class="mb0 textcenter">There are no user created snapshots. <a href="#" class="create-new-snapshot">Create a new snapshot.</a></p>';
2283 2440 }
2441 + echo '</div>';
2442 + echo '</div>';
2284 2443
2285 - echo '<td>';
2286 - if (current_time('timestamp') - strtotime($ss['timestamp']) > 12 * HOUR_IN_SECONDS) {
2287 - echo date(get_option('date_format'), strtotime($ss['timestamp'])) . '<br>@ ' . date(get_option('time_format'), strtotime($ss['timestamp']));
2288 - } else {
2289 - echo human_time_diff(strtotime($ss['timestamp']), current_time('timestamp')) . ' ago';
2444 + echo '<div class="card">';
2445 + WP_Reset_Utility::wp_kses_wf($this->get_card_header('Automatic Snapshots', 'snapshots-auto', array('collapse_button' => false, 'pro' => true)));
2446 + echo '<div class="card-body">';
2447 + echo '<p><span class="pro-feature pro-feature-text" data-feature="snapshots-auto">WP Reset <span>PRO</span></span> creates automatic snapshots before significant events occur on your site that can cause it to stop working correctly. Plugin, theme and core updates, plugin and theme activations and deactivations all of those can happen in the background without your knowledge. With automatic snapshots, you can roll back any update with a single click. Snapshots can be uploaded to the WP Reset Cloud, Dropbox, Google Drive or pCloud, giving you an extra layer of security.<br>
2448 + Upgrade to <span class="pro-feature pro-feature-text" data-feature="snapshots-auto">WP Reset <span>PRO</span></span> to enable automatic snapshots and give your site an extra layer of safety.</p>';
2449 + echo '</div>';
2450 + echo '</div>';
2451 + } // tab_snapshots
2452 +
2453 +
2454 + /**
2455 + * Helper function for generating links
2456 + *
2457 + * @param string $placement Optional. UTM content param.
2458 + * @param string $page Optional. Page to link to.
2459 + * @param array $params Optional. Extra URL params.
2460 + * @param string $anchor Optional. URL anchor part.
2461 + *
2462 + * @return string
2463 + */
2464 + function generate_web_link($placement = '', $page = '/', $params = array(), $anchor = '')
2465 + {
2466 + $base_url = 'https://wpreset.com';
2467 +
2468 + if ('/' != $page) {
2469 + $page = '/' . trim($page, '/') . '/';
2290 2470 }
2291 - echo '</td>';
2471 + if ($page == '//') {
2472 + $page = '/';
2473 + }
2292 2474
2293 - echo '<td>';
2294 - if (!empty($ss['name'])) {
2295 - echo '<b>' . esc_html($ss['name']) . '</b><br>';
2475 + if ($placement) {
2476 + $placement = trim($placement);
2477 + $placement = '-' . $placement;
2296 2478 }
2297 - echo $ss['tbl_core'] . ' standard &amp; ';
2298 - if ($ss['tbl_custom']) {
2299 - echo $ss['tbl_custom'] . ' custom table' . ($ss['tbl_custom'] == 1 ? '' : 's');
2300 - } else {
2301 - echo 'no custom tables';
2302 - }
2303 - echo ' totaling ' . number_format($ss['tbl_rows']) . ' rows</td>';
2304 - echo '<td class="ss-size">' . WP_Reset_Utility::format_size($ss['tbl_size']) . '</td>';
2305 - echo '<td>';
2306 - echo '<div class="dropdown">
2307 - <a class="button dropdown-toggle" href="#">Actions</a>
2308 - <div class="dropdown-menu">';
2309 - echo '<a data-title="Current DB tables compared to snapshot %s" data-wait-msg="Comparing. Please wait." data-name="' . esc_attr($name) . '" title="Compare snapshot to current database tables" href="#" class="ss-action compare-snapshot dropdown-item tooltip" data-ss-uid="' . esc_attr($ss['uid']) . '">Compare snapshot to current data</a>';
2310 - echo '<a data-btn-confirm="Restore snapshot" data-text-wait="Restoring snapshot. Please wait." data-text-confirm="Are you sure you want to restore the selected snapshot? There is NO UNDO.<br>Restoring the snapshot will delete all current standard and custom tables and replace them with tables from the snapshot." data-text-done="Snapshot has been restored. Click OK to reload the page with new data." title="Restore snapshot by overwriting current database tables" href="#" class="ss-action restore-snapshot dropdown-item tooltip" data-ss-uid="' . esc_attr($ss['uid']) . '">Restore snapshot</a>';
2311 - echo '<a data-success-msg="Snapshot export created!<br><a href=\'%s\'>Download it</a>" data-wait-msg="Exporting snapshot. Please wait." title="Download snapshot as gzipped SQL dump" href="#" class="ss-action download-snapshot dropdown-item tooltip" data-ss-uid="' . esc_attr($ss['uid']) . '">Download snapshot</a>';
2312 - echo '<a data-btn-confirm="Delete snapshot" data-text-wait="Deleting snapshot. Please wait." data-text-confirm="Are you sure you want to delete the selected snapshot and all its data? There is NO UNDO.<br>Deleting the snapshot will not affect the active database tables in any way." data-text-done="Snapshot has been deleted." title="Permanently delete snapshot" href="#" class="ss-action delete-snapshot dropdown-item tooltip" data-ss-uid="' . esc_attr($ss['uid']) . '">Delete snapshot</a>';
2313 - echo '<a href="#" title="WP Reset PRO feature" data-feature="cloud-wpr" class="ss-action dropdown-item button-pro-feature tooltip">Upload to WP Reset Cloud - <span class="pro-feature" data-feature="cloud-wpr"><span class="pro">PRO</span> Feature</span></a>';
2314 - echo '<a href="#" title="WP Reset PRO feature" class="ss-action dropdown-item button-pro-feature tooltip" data-feature="cloud-general">Upload to Dropbox, Google Drive, or pCloud - <span class="pro-feature" data-feature="cloud-general"><span class="pro">PRO</span> Feature</span></a>';
2315 - echo '</div></div></td>';
2316 - echo '</tr>';
2317 - } // foreach
2318 - echo '</table>';
2319 - echo '<p id="ss-no-snapshots" class="mb0 textcenter hidden">There are no user created snapshots. <a href="#" class="create-new-snapshot">Create a new snapshot.</a></p>';
2320 - } else {
2321 - echo '<p id="ss-no-snapshots" class="mb0 textcenter">There are no user created snapshots. <a href="#" class="create-new-snapshot">Create a new snapshot.</a></p>';
2322 - }
2323 - echo '</div>';
2324 - echo '</div>';
2325 2479
2326 - echo '<div class="card">';
2327 - echo $this->get_card_header('Automatic Snapshots', 'snapshots-auto', array('collapse_button' => false, 'pro' => true));
2328 - echo '<div class="card-body">';
2329 - echo '<p><span class="pro-feature pro-feature-text" data-feature="snapshots-auto">WP Reset <span>PRO</span></span> creates automatic snapshots before significant events occur on your site that can cause it to stop working correctly. Plugin, theme and core updates, plugin and theme activations and deactivations all of those can happen in the background without your knowledge. With automatic snapshots, you can roll back any update with a single click. Snapshots can be uploaded to the WP Reset Cloud, Dropbox, Google Drive or pCloud, giving you an extra layer of security.<br>
2330 - Upgrade to <span class="pro-feature pro-feature-text" data-feature="snapshots-auto">WP Reset <span>PRO</span></span> to enable automatic snapshots and give your site an extra layer of safety.</p>';
2331 - echo '</div>';
2332 - echo '</div>';
2333 - } // tab_snapshots
2480 + $parts = array_merge(array('ref' => 'wp-reset-free' . $placement), $params);
2334 2481
2482 + if (!empty($anchor)) {
2483 + $anchor = '#' . trim($anchor, '#');
2484 + }
2335 2485
2336 - /**
2337 - * Helper function for generating links
2338 - *
2339 - * @param string $placement Optional. UTM content param.
2340 - * @param string $page Optional. Page to link to.
2341 - * @param array $params Optional. Extra URL params.
2342 - * @param string $anchor Optional. URL anchor part.
2343 - *
2344 - * @return string
2345 - */
2346 - function generate_web_link($placement = '', $page = '/', $params = array(), $anchor = '')
2347 - {
2348 - $base_url = 'https://wpreset.com';
2486 + $out = $base_url . $page . '?' . http_build_query($parts, '', '&amp;') . $anchor;
2349 2487
2350 - if ('/' != $page) {
2351 - $page = '/' . trim($page, '/') . '/';
2352 - }
2353 - if ($page == '//') {
2354 - $page = '/';
2355 - }
2488 + return $out;
2489 + } // generate_web_link
2356 2490
2357 - if ($placement) {
2358 - $placement = trim($placement);
2359 - $placement = '-' . $placement;
2360 - }
2361 2491
2362 - $parts = array_merge(array('ref' => 'wp-reset-free'. $placement), $params);
2492 + /**
2493 + * Returns all saved snapshots from DB
2494 + *
2495 + * @return array
2496 + */
2497 + function get_snapshots()
2498 + {
2499 + $snapshots = get_option('wp-reset-snapshots', array());
2363 2500
2364 - if (!empty($anchor)) {
2365 - $anchor = '#' . trim($anchor, '#');
2366 - }
2501 + return $snapshots;
2502 + } // get_snapshots
2367 2503
2368 - $out = $base_url . $page . '?' . http_build_query($parts, '', '&amp;') . $anchor;
2369 2504
2370 - return $out;
2371 - } // generate_web_link
2505 + /**
2506 + * Returns all custom table names, with prefix
2507 + *
2508 + * @return array
2509 + */
2510 + function get_custom_tables()
2511 + {
2512 + global $wpdb;
2513 + $custom_tables = array();
2372 2514
2515 + // phpcs:ignore db call warning as we are using uncommon queries
2516 + $table_status = $wpdb->get_results('SHOW TABLE STATUS'); // phpcs:ignore
2517 + if (is_array($table_status)) {
2518 + foreach ($table_status as $index => $table) {
2519 + if (0 !== stripos($table->Name, $wpdb->prefix)) {
2520 + continue;
2521 + }
2522 + if (empty($table->Engine)) {
2523 + continue;
2524 + }
2373 2525
2374 - /**
2375 - * Returns all saved snapshots from DB
2376 - *
2377 - * @return array
2378 - */
2379 - function get_snapshots()
2380 - {
2381 - $snapshots = get_option('wp-reset-snapshots', array());
2526 + if (false === in_array($table->Name, $this->core_tables)) {
2527 + $custom_tables[] = array('name' => $table->Name, 'rows' => $table->Rows, 'data_length' => $table->Data_length, 'index_length' => $table->Index_length);
2528 + }
2529 + } // foreach
2530 + }
2382 2531
2383 - return $snapshots;
2384 - } // get_snapshots
2532 + return $custom_tables;
2533 + } // get_custom tables
2385 2534
2386 2535
2387 - /**
2388 - * Returns all custom table names, with prefix
2389 - *
2390 - * @return array
2391 - */
2392 - function get_custom_tables()
2393 - {
2394 - global $wpdb;
2395 - $custom_tables = array();
2536 + /**
2537 + * Creates snapshot of current tables by copying them in the DB and saving metadata.
2538 + *
2539 + * @param int $name Optional. Name for the new snapshot.
2540 + *
2541 + * @return array|WP_Error Snapshot details in array on success, or error object on fail.
2542 + */
2543 + function do_create_snapshot($name = '')
2544 + {
2545 + global $wpdb;
2546 + $snapshots = $this->get_snapshots();
2547 + $snapshot = array();
2548 + $uid = $this->generate_snapshot_uid();
2549 + $tbl_core = $tbl_custom = $tbl_size = $tbl_rows = 0;
2396 2550
2397 - $table_status = $wpdb->get_results('SHOW TABLE STATUS');
2398 - if (is_array($table_status)) {
2399 - foreach ($table_status as $index => $table) {
2400 - if (0 !== stripos($table->Name, $wpdb->prefix)) {
2401 - continue;
2551 + if (!$uid) {
2552 + return new WP_Error(1, 'Unable to generate a valid snapshot UID.');
2402 2553 }
2403 - if (empty($table->Engine)) {
2404 - continue;
2554 +
2555 + if ($name) {
2556 + $snapshot['name'] = substr(trim($name), 0, 64);
2557 + } else {
2558 + $snapshot['name'] = '';
2405 2559 }
2560 + $snapshot['uid'] = $uid;
2561 + $snapshot['timestamp'] = current_time('mysql');
2406 2562
2407 - if (false === in_array($table->Name, $this->core_tables)) {
2408 - $custom_tables[] = array('name' => $table->Name, 'rows' => $table->Rows, 'data_length' => $table->Data_length, 'index_length' => $table->Index_length);
2563 + // phpcs:ignore db call warning as we are using uncommon queries
2564 + $table_status = $wpdb->get_results('SHOW TABLE STATUS'); // phpcs:ignore
2565 + if (is_array($table_status)) {
2566 + foreach ($table_status as $index => $table) {
2567 + if (0 !== stripos($table->Name, $wpdb->prefix)) {
2568 + continue;
2569 + }
2570 + if (empty($table->Engine)) {
2571 + continue;
2572 + }
2573 +
2574 + $tbl_rows += $table->Rows;
2575 + $tbl_size += $table->Data_length + $table->Index_length;
2576 + if (in_array($table->Name, $this->core_tables)) {
2577 + $tbl_core++;
2578 + } else {
2579 + $tbl_custom++;
2580 + }
2581 +
2582 + $wpdb->wpreset_snapshot_table_name = $table->Name;
2583 + $wpdb->wpreset_snapshot_table_copy_name = $uid . '_' . $table->Name;
2584 +
2585 + // phpcs:ignore db call warning as we are using uncommon queries
2586 + $wpdb->query("OPTIMIZE TABLE " . $wpdb->wpreset_snapshot_table_name); // phpcs:ignore
2587 + $wpdb->query("CREATE TABLE " . $wpdb->wpreset_snapshot_table_copy_name . " LIKE " . $wpdb->wpreset_snapshot_table_name); // phpcs:ignore
2588 + $wpdb->query("INSERT " . $wpdb->wpreset_snapshot_table_copy_name . " SELECT * FROM " . $wpdb->wpreset_snapshot_table_name); // phpcs:ignore
2589 + } // foreach
2590 + } else {
2591 + return new WP_Error(1, 'Can\'t get table status data.');
2409 2592 }
2410 - } // foreach
2411 - }
2412 2593
2413 - return $custom_tables;
2414 - } // get_custom tables
2594 + $snapshot['tbl_core'] = $tbl_core;
2595 + $snapshot['tbl_custom'] = $tbl_custom;
2596 + $snapshot['tbl_rows'] = $tbl_rows;
2597 + $snapshot['tbl_size'] = $tbl_size;
2415 2598
2416 2599
2417 - /**
2418 - * Creates snapshot of current tables by copying them in the DB and saving metadata.
2419 - *
2420 - * @param int $name Optional. Name for the new snapshot.
2421 - *
2422 - * @return array|WP_Error Snapshot details in array on success, or error object on fail.
2423 - */
2424 - function do_create_snapshot($name = '')
2425 - {
2426 - global $wpdb;
2427 - $snapshots = $this->get_snapshots();
2428 - $snapshot = array();
2429 - $uid = $this->generate_snapshot_uid();
2430 - $tbl_core = $tbl_custom = $tbl_size = $tbl_rows = 0;
2600 + $snapshots[$uid] = $snapshot;
2601 + update_option('wp-reset-snapshots', $snapshots);
2431 2602
2432 - if (!$uid) {
2433 - return new WP_Error(1, 'Unable to generate a valid snapshot UID.');
2434 - }
2603 + do_action('wp_reset_create_snapshot', $uid, $snapshot);
2435 2604
2436 - if ($name) {
2437 - $snapshot['name'] = substr(trim($name), 0, 64);
2438 - } else {
2439 - $snapshot['name'] = '';
2440 - }
2441 - $snapshot['uid'] = $uid;
2442 - $snapshot['timestamp'] = current_time('mysql');
2605 + return $snapshot;
2606 + } // create_snapshot
2443 2607
2444 - $table_status = $wpdb->get_results('SHOW TABLE STATUS');
2445 - if (is_array($table_status)) {
2446 - foreach ($table_status as $index => $table) {
2447 - if (0 !== stripos($table->Name, $wpdb->prefix)) {
2448 - continue;
2608 +
2609 + /**
2610 + * Delete snapshot metadata and tables from DB
2611 + *
2612 + * @param string $uid Snapshot unique 6-char ID.
2613 + *
2614 + * @return bool|WP_Error True on success, or error object on fail.
2615 + */
2616 + function do_delete_snapshot($uid = '')
2617 + {
2618 + global $wpdb;
2619 + $snapshots = $this->get_snapshots();
2620 +
2621 + if (strlen($uid) != 6) {
2622 + return new WP_Error(1, 'Invalid UID format.');
2449 2623 }
2450 - if (empty($table->Engine)) {
2451 - continue;
2624 +
2625 + if (!isset($snapshots[$uid])) {
2626 + return new WP_Error(1, 'Unknown snapshot ID.');
2452 2627 }
2453 2628
2454 - $tbl_rows += $table->Rows;
2455 - $tbl_size += $table->Data_length + $table->Index_length;
2456 - if (in_array($table->Name, $this->core_tables)) {
2457 - $tbl_core++;
2458 - } else {
2459 - $tbl_custom++;
2629 + // phpcs:ignore db call warning as we are using uncommon queries
2630 + $tables = $wpdb->get_col($wpdb->prepare('SHOW TABLES LIKE %s', array($uid . '\_%'))); // phpcs:ignore
2631 + foreach ($tables as $table) {
2632 + $wpdb->wpreset_snapshot_table = $table;
2633 + $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->wpreset_snapshot_table); // phpcs:ignore
2460 2634 }
2461 2635
2462 - $wpdb->query("OPTIMIZE TABLE {$table->Name}");
2463 - $wpdb->query("CREATE TABLE {$uid}_{$table->Name} LIKE {$table->Name}");
2464 - $wpdb->query("INSERT {$uid}_{$table->Name} SELECT * FROM {$table->Name}");
2465 - } // foreach
2466 - } else {
2467 - return new WP_Error(1, 'Can\'t get table status data.');
2468 - }
2636 + $snapshot_copy = $snapshots[$uid];
2637 + unset($snapshots[$uid]);
2638 + update_option('wp-reset-snapshots', $snapshots);
2469 2639
2470 - $snapshot['tbl_core'] = $tbl_core;
2471 - $snapshot['tbl_custom'] = $tbl_custom;
2472 - $snapshot['tbl_rows'] = $tbl_rows;
2473 - $snapshot['tbl_size'] = $tbl_size;
2640 + do_action('wp_reset_delete_snapshot', $uid, $snapshot_copy);
2474 2641
2642 + return true;
2643 + } // delete_snapshot
2475 2644
2476 - $snapshots[$uid] = $snapshot;
2477 - update_option('wp-reset-snapshots', $snapshots);
2478 2645
2479 - do_action('wp_reset_create_snapshot', $uid, $snapshot);
2646 + /**
2647 + * Exports snapshot as SQL dump; saved in gzipped file in WP_CONTENT folder.
2648 + *
2649 + * @param string $uid Snapshot unique 6-char ID.
2650 + *
2651 + * @return string|WP_Error Export base filename, or error object on fail.
2652 + */
2653 + function do_export_snapshot($uid = '')
2654 + {
2655 + global $wp_filesystem;
2656 + $this->wp_init_filesystem();
2657 +
2658 + $snapshots = $this->get_snapshots();
2480 2659
2481 - return $snapshot;
2482 - } // create_snapshot
2660 + if (strlen($uid) != 6) {
2661 + return new WP_Error(1, 'Invalid snapshot ID format.');
2662 + }
2483 2663
2664 + if (!isset($snapshots[$uid])) {
2665 + return new WP_Error(1, 'Unknown snapshot ID.');
2666 + }
2484 2667
2485 - /**
2486 - * Delete snapshot metadata and tables from DB
2487 - *
2488 - * @param string $uid Snapshot unique 6-char ID.
2489 - *
2490 - * @return bool|WP_Error True on success, or error object on fail.
2491 - */
2492 - function do_delete_snapshot($uid = '')
2493 - {
2494 - global $wpdb;
2495 - $snapshots = $this->get_snapshots();
2668 + require_once $this->plugin_dir . 'libs/dumper.php';
2496 2669
2497 - if (strlen($uid) != 6) {
2498 - return new WP_Error(1, 'Invalid UID format.');
2499 - }
2670 + $snapshot_file_uid = md5($this->generate_snapshot_uid(10));
2671 + try {
2672 + $world_dumper = WPR_Shuttle_Dumper::create(array(
2673 + 'host' => DB_HOST,
2674 + 'username' => DB_USER,
2675 + 'password' => DB_PASSWORD,
2676 + 'db_name' => DB_NAME,
2677 + ));
2500 2678
2501 - if (!isset($snapshots[$uid])) {
2502 - return new WP_Error(1, 'Unknown snapshot ID.');
2503 - }
2679 + $folder = wp_mkdir_p(trailingslashit(WP_CONTENT_DIR) . $this->snapshots_folder);
2680 + if (!$folder) {
2681 + return new WP_Error(1, 'Unable to create wp-content/' . $this->snapshots_folder . '/ folder.');
2682 + }
2504 2683
2505 - $tables = $wpdb->get_col($wpdb->prepare('SHOW TABLES LIKE %s', array($uid . '\_%')));
2506 - foreach ($tables as $table) {
2507 - $wpdb->query('DROP TABLE IF EXISTS ' . $table);
2508 - }
2684 + $htaccess_content = 'AddType application/octet-stream .gz' . PHP_EOL;
2685 + $htaccess_content .= 'Options -Indexes' . PHP_EOL;
2509 2686
2510 - $snapshot_copy = $snapshots[$uid];
2511 - unset($snapshots[$uid]);
2512 - update_option('wp-reset-snapshots', $snapshots);
2687 + $wp_filesystem->put_contents(trailingslashit(WP_CONTENT_DIR) . $this->snapshots_folder . '/.htaccess', $htaccess_content);
2513 2688
2514 - do_action('wp_reset_delete_snapshot', $uid, $snapshot_copy);
2689 + $world_dumper->dump(trailingslashit(WP_CONTENT_DIR) . $this->snapshots_folder . '/wp-reset-snapshot-' . $snapshot_file_uid . '.sql.gz', $uid . '_');
2690 + } catch (Shuttle_Exception $e) {
2691 + return new WP_Error(1, 'Couldn\'t create snapshot: ' . $e->getMessage());
2692 + }
2515 2693
2516 - return true;
2517 - } // delete_snapshot
2694 + do_action('wp_reset_export_snapshot', 'wp-reset-snapshot-' . $snapshot_file_uid . '.sql.gz');
2518 2695
2696 + return 'wp-reset-snapshot-' . $snapshot_file_uid . '.sql.gz';
2697 + } // export_snapshot
2519 2698
2520 - /**
2521 - * Exports snapshot as SQL dump; saved in gzipped file in WP_CONTENT folder.
2522 - *
2523 - * @param string $uid Snapshot unique 6-char ID.
2524 - *
2525 - * @return string|WP_Error Export base filename, or error object on fail.
2526 - */
2527 - function do_export_snapshot($uid = '')
2528 - {
2529 - $snapshots = $this->get_snapshots();
2530 2699
2531 - if (strlen($uid) != 6) {
2532 - return new WP_Error(1, 'Invalid snapshot ID format.');
2533 - }
2700 + /**
2701 + * Replace current tables with ones in snapshot.
2702 + *
2703 + * @param string $uid Snapshot unique 6-char ID.
2704 + *
2705 + * @return bool|WP_Error True on success, or error object on fail.
2706 + */
2707 + function do_restore_snapshot($uid = '')
2708 + {
2709 + // phpcs:ignore db call warning as we are using uncommon queries
2710 + global $wpdb;
2711 + $new_tables = array();
2712 + $snapshots = $this->get_snapshots();
2534 2713
2535 - if (!isset($snapshots[$uid])) {
2536 - return new WP_Error(1, 'Unknown snapshot ID.');
2537 - }
2714 + if (($res = $this->verify_snapshot_integrity($uid)) !== true) {
2715 + return $res;
2716 + }
2538 2717
2539 - require_once $this->plugin_dir . 'libs/dumper.php';
2718 + $table_status = $wpdb->get_results('SHOW TABLE STATUS'); // phpcs:ignore
2719 + if (is_array($table_status)) {
2720 + foreach ($table_status as $index => $table) {
2721 + if (0 !== stripos($table->Name, $uid . '_')) {
2722 + continue;
2723 + }
2724 + if (empty($table->Engine)) {
2725 + continue;
2726 + }
2540 2727
2541 - try {
2542 - $world_dumper = WPR_Shuttle_Dumper::create(array(
2543 - 'host' => DB_HOST,
2544 - 'username' => DB_USER,
2545 - 'password' => DB_PASSWORD,
2546 - 'db_name' => DB_NAME,
2547 - ));
2728 + $new_tables[] = $table->Name;
2729 + } // foreach
2730 + } else {
2731 + return new WP_Error(1, 'Can\'t get table status data.');
2732 + }
2548 2733
2549 - $folder = wp_mkdir_p(trailingslashit(WP_CONTENT_DIR) . $this->snapshots_folder);
2550 - if (!$folder) {
2551 - return new WP_Error(1, 'Unable to create wp-content/' . $this->snapshots_folder . '/ folder.');
2552 - }
2734 + foreach ($table_status as $index => $table) {
2735 + if (0 !== stripos($table->Name, $wpdb->prefix)) {
2736 + continue;
2737 + }
2738 + if (empty($table->Engine)) {
2739 + continue;
2740 + }
2553 2741
2554 - $htaccess_content = 'AddType application/octet-stream .gz' . PHP_EOL;
2555 - $htaccess_content .= 'Options -Indexes' . PHP_EOL;
2556 - $htaccess_file = @fopen(trailingslashit(WP_CONTENT_DIR) . $this->snapshots_folder . '/.htaccess', 'w');
2557 - if ($htaccess_file) {
2558 - fputs($htaccess_file, $htaccess_content);
2559 - fclose($htaccess_file);
2560 - }
2742 + $wpdb->wpreset_snapshot_table = $table->Name;
2743 + $wpdb->query('DROP TABLE ' . $wpdb->wpreset_snapshot_table); // phpcs:ignore
2744 + } // foreach
2561 2745
2562 - $world_dumper->dump(trailingslashit(WP_CONTENT_DIR) . $this->snapshots_folder . '/wp-reset-snapshot-' . $uid . '.sql.gz', $uid . '_');
2563 - } catch (Shuttle_Exception $e) {
2564 - return new WP_Error(1, 'Couldn\'t create snapshot: ' . $e->getMessage());
2565 - }
2746 + // copy snapshot tables to original name
2747 + foreach ($new_tables as $table) {
2748 + $wpdb->wpreset_snapshot_table = $table;
2749 + $wpdb->wpreset_snapshot_table_new = str_replace($uid . '_', '', $table);
2566 2750
2567 - do_action('wp_reset_export_snapshot', 'wp-reset-snapshot-' . $uid . '.sql.gz');
2751 + $wpdb->query("CREATE TABLE " . $wpdb->wpreset_snapshot_table_new . " LIKE " . $wpdb->wpreset_snapshot_table); // phpcs:ignore
2752 + $wpdb->query("INSERT " . $wpdb->wpreset_snapshot_table_new . " SELECT * FROM " . $wpdb->wpreset_snapshot_table); // phpcs:ignore
2753 + }
2568 2754
2569 - return 'wp-reset-snapshot-' . $uid . '.sql.gz';
2570 - } // export_snapshot
2755 + wp_cache_flush();
2756 + update_option('wp-reset', $this->options);
2757 + update_option('wp-reset-snapshots', $snapshots);
2571 2758
2759 + do_action('wp_reset_restore_snapshot', $uid);
2572 2760
2573 - /**
2574 - * Replace current tables with ones in snapshot.
2575 - *
2576 - * @param string $uid Snapshot unique 6-char ID.
2577 - *
2578 - * @return bool|WP_Error True on success, or error object on fail.
2579 - */
2580 - function do_restore_snapshot($uid = '')
2581 - {
2582 - global $wpdb;
2583 - $new_tables = array();
2584 - $snapshots = $this->get_snapshots();
2761 + return true;
2762 + } // restore_snapshot
2585 2763
2586 - if (($res = $this->verify_snapshot_integrity($uid)) !== true) {
2587 - return $res;
2588 - }
2589 2764
2590 - $table_status = $wpdb->get_results('SHOW TABLE STATUS');
2591 - if (is_array($table_status)) {
2592 - foreach ($table_status as $index => $table) {
2593 - if (0 !== stripos($table->Name, $uid . '_')) {
2594 - continue;
2765 + /**
2766 + * Verifies snapshot integrity by comparing metadata and data in DB
2767 + *
2768 + * @param string $uid Snapshot unique 6-char ID.
2769 + *
2770 + * @return bool|WP_Error True on success, or error object on fail.
2771 + */
2772 + function verify_snapshot_integrity($uid)
2773 + {
2774 + // phpcs:ignore db call warning as we are using uncommon queries
2775 + global $wpdb;
2776 + $tbl_core = $tbl_custom = 0;
2777 + $snapshots = $this->get_snapshots();
2778 +
2779 + if (strlen($uid) != 6) {
2780 + return new WP_Error(1, 'Invalid snapshot ID format.');
2595 2781 }
2596 - if (empty($table->Engine)) {
2597 - continue;
2782 +
2783 + if (!isset($snapshots[$uid])) {
2784 + return new WP_Error(1, 'Unknown snapshot ID.');
2598 2785 }
2599 2786
2600 - $new_tables[] = $table->Name;
2601 - } // foreach
2602 - } else {
2603 - return new WP_Error(1, 'Can\'t get table status data.');
2604 - }
2787 + $snapshot = $snapshots[$uid];
2605 2788
2606 - foreach ($table_status as $index => $table) {
2607 - if (0 !== stripos($table->Name, $wpdb->prefix)) {
2608 - continue;
2609 - }
2610 - if (empty($table->Engine)) {
2611 - continue;
2612 - }
2789 + $table_status = $wpdb->get_results('SHOW TABLE STATUS'); // phpcs:ignore
2790 + if (is_array($table_status)) {
2791 + foreach ($table_status as $index => $table) {
2792 + if (0 !== stripos($table->Name, $uid . '_')) {
2793 + continue;
2794 + }
2795 + if (empty($table->Engine)) {
2796 + continue;
2797 + }
2613 2798
2614 - $wpdb->query('DROP TABLE ' . $table->Name);
2615 - } // foreach
2799 + if (in_array(str_replace($uid . '_', '', $table->Name), $this->core_tables)) {
2800 + $tbl_core++;
2801 + } else {
2802 + $tbl_custom++;
2803 + }
2804 + } // foreach
2616 2805
2617 - // copy snapshot tables to original name
2618 - foreach ($new_tables as $table) {
2619 - $new_name = str_replace($uid . '_', '', $table);
2806 + if ($tbl_core != $snapshot['tbl_core'] || $tbl_custom != $snapshot['tbl_custom']) {
2807 + return new WP_Error(1, 'Snapshot data has been compromised. Saved metadata does not match data in the DB. Contact WP Reset support if data is critical, or restore it via a MySQL GUI.');
2808 + }
2809 + } else {
2810 + return new WP_Error(1, 'Can\'t get table status data.');
2811 + }
2620 2812
2621 - $wpdb->query("CREATE TABLE {$new_name} LIKE {$table}");
2622 - $wpdb->query("INSERT {$new_name} SELECT * FROM {$table}");
2623 - }
2813 + return true;
2814 + } // verify_snapshot_integrity
2624 2815
2625 - wp_cache_flush();
2626 - update_option('wp-reset', $this->options);
2627 - update_option('wp-reset-snapshots', $snapshots);
2628 2816
2629 - do_action('wp_reset_restore_snapshot', $uid);
2817 + /**
2818 + * Compares a selected snapshot with the current table set in DB
2819 + *
2820 + * @param string $uid Snapshot unique 6-char ID.
2821 + *
2822 + * @return string|WP_Error Formatted table with details on success, or error object on fail.
2823 + */
2824 + function do_compare_snapshots($uid)
2825 + {
2826 + // phpcs:ignore db call warning as we are using uncommon queries
2827 + global $wpdb;
2828 + $current = $snapshot = array();
2829 + $out = $out2 = $out3 = '';
2630 2830
2631 - return true;
2632 - } // restore_snapshot
2831 + if (($res = $this->verify_snapshot_integrity($uid)) !== true) {
2832 + return $res;
2833 + }
2633 2834
2835 + $table_status = $wpdb->get_results('SHOW TABLE STATUS'); // phpcs:ignore
2836 + foreach ($table_status as $index => $table) {
2837 + if (empty($table->Engine)) {
2838 + continue;
2839 + }
2634 2840
2635 - /**
2636 - * Verifies snapshot integrity by comparing metadata and data in DB
2637 - *
2638 - * @param string $uid Snapshot unique 6-char ID.
2639 - *
2640 - * @return bool|WP_Error True on success, or error object on fail.
2641 - */
2642 - function verify_snapshot_integrity($uid)
2643 - {
2644 - global $wpdb;
2645 - $tbl_core = $tbl_custom = 0;
2646 - $snapshots = $this->get_snapshots();
2841 + if (0 !== stripos($table->Name, $uid . '_') && 0 !== stripos($table->Name, $wpdb->prefix)) {
2842 + continue;
2843 + }
2647 2844
2648 - if (strlen($uid) != 6) {
2649 - return new WP_Error(1, 'Invalid snapshot ID format.');
2650 - }
2845 + $info = array();
2846 + $info['rows'] = $table->Rows;
2847 + $info['size_data'] = $table->Data_length;
2848 + $info['size_index'] = $table->Index_length;
2849 + $wpdb->wpreset_table_name = $table->Name;
2850 + $schema = $wpdb->get_row('SHOW CREATE TABLE ' . $wpdb->wpreset_table_name, ARRAY_N); // phpcs:ignore
2851 + $info['schema'] = $schema[1];
2852 + $info['engine'] = $table->Engine;
2853 + $info['fullname'] = $table->Name;
2854 + $basename = str_replace(array($uid . '_'), array(''), $table->Name);
2855 + $info['basename'] = $basename;
2856 + $info['corename'] = str_replace(array($wpdb->prefix), array(''), $basename);
2857 + $info['uid'] = $uid;
2651 2858
2652 - if (!isset($snapshots[$uid])) {
2653 - return new WP_Error(1, 'Unknown snapshot ID.');
2654 - }
2859 + if (0 === stripos($table->Name, $uid . '_')) {
2860 + $snapshot[$basename] = $info;
2861 + }
2655 2862
2656 - $snapshot = $snapshots[$uid];
2863 + if (0 === stripos($table->Name, $wpdb->prefix)) {
2864 + $info['uid'] = '';
2865 + $current[$basename] = $info;
2866 + }
2867 + } // foreach
2657 2868
2658 - $table_status = $wpdb->get_results('SHOW TABLE STATUS');
2659 - if (is_array($table_status)) {
2660 - foreach ($table_status as $index => $table) {
2661 - if (0 !== stripos($table->Name, $uid . '_')) {
2662 - continue;
2663 - }
2664 - if (empty($table->Engine)) {
2665 - continue;
2666 - }
2869 + $in_both = array_keys(array_intersect_key($current, $snapshot));
2870 + $in_current_only = array_diff_key($current, $snapshot);
2871 + $in_snapshot_only = array_diff_key($snapshot, $current);
2667 2872
2668 - if (in_array(str_replace($uid . '_', '', $table->Name), $this->core_tables)) {
2669 - $tbl_core++;
2670 - } else {
2671 - $tbl_custom++;
2672 - }
2673 - } // foreach
2873 + $out .= '<br><br>';
2874 + foreach ($in_current_only as $table) {
2875 + $out .= '<div class="wpr-table-container in-current-only" data-table="' . esc_attr($table['basename']) . '">';
2876 + $out .= '<table>';
2877 + $out .= '<tr title="Click to show/hide more info" class="wpr-table-missing header-row">';
2878 + $out .= '<td><b>' . $table['fullname'] . '</b></td>';
2879 + $out .= '<td>table is not present in snapshot<span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2880 + $out .= '</tr>';
2881 + $out .= '<tr class="hidden">';
2882 + $out .= '<td>';
2883 + $out .= '<p>' . number_format($table['rows']) . ' row' . ($table['rows'] == 1 ? '' : 's') . ' totaling ' . WP_Reset_Utility::format_size($table['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($table['size_index']) . ' in index.</p>';
2884 + $out .= '<pre>' . $table['schema'] . '</pre>';
2885 + $out .= '</td>';
2886 + $out .= '<td>&nbsp;</td>';
2887 + $out .= '</tr>';
2888 + $out .= '</table>';
2889 + $out .= '</div>';
2890 + } // foreach in current only
2674 2891
2675 - if ($tbl_core != $snapshot['tbl_core'] || $tbl_custom != $snapshot['tbl_custom']) {
2676 - return new WP_Error(1, 'Snapshot data has been compromised. Saved metadata does not match data in the DB. Contact WP Reset support if data is critical, or restore it via a MySQL GUI.');
2677 - }
2678 - } else {
2679 - return new WP_Error(1, 'Can\'t get table status data.');
2680 - }
2892 + foreach ($in_snapshot_only as $table) {
2893 + $out .= '<div class="wpr-table-container in-snapshot-only" data-table="' . esc_attr($table['basename']) . '">';
2894 + $out .= '<table>';
2895 + $out .= '<tr title="Click to show/hide more info" class="wpr-table-missing header-row">';
2896 + $out .= '<td>table is not present in current tables</td>';
2897 + $out .= '<td><b>' . esc_html($table['fullname']) . '</b><span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2898 + $out .= '</tr>';
2899 + $out .= '<tr class="hidden">';
2900 + $out .= '<td>&nbsp;</td>';
2901 + $out .= '<td>';
2902 + $out .= '<p>' . number_format($table['rows']) . ' row' . ($table['rows'] == 1 ? '' : 's') . ' totaling ' . WP_Reset_Utility::format_size($table['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($table['size_index']) . ' in index.</p>';
2903 + $out .= '<pre>' . $table['schema'] . '</pre>';
2904 + $out .= '</td>';
2905 + $out .= '</tr>';
2906 + $out .= '</table>';
2907 + $out .= '</div>';
2908 + } // foreach in snapshot only
2681 2909
2682 - return true;
2683 - } // verify_snapshot_integrity
2910 + foreach ($in_both as $tablename) {
2911 + $tbl_current = $current[$tablename];
2912 + $tbl_snapshot = $snapshot[$tablename];
2684 2913
2914 + $schema1 = preg_replace('/(auto_increment=)([0-9]*) /i', '${1}1 ', $tbl_current['schema'], 1);
2915 + $schema2 = preg_replace('/(auto_increment=)([0-9]*) /i', '${1}1 ', $tbl_snapshot['schema'], 1);
2916 + $tbl_snapshot['tmp_schema'] = str_replace($tbl_snapshot['uid'] . '_' . $tablename, $tablename, $tbl_snapshot['schema']);
2917 + $schema2 = str_replace($tbl_snapshot['uid'] . '_' . $tablename, $tablename, $schema2);
2685 2918
2686 - /**
2687 - * Compares a selected snapshot with the current table set in DB
2688 - *
2689 - * @param string $uid Snapshot unique 6-char ID.
2690 - *
2691 - * @return string|WP_Error Formatted table with details on success, or error object on fail.
2692 - */
2693 - function do_compare_snapshots($uid)
2694 - {
2695 - global $wpdb;
2696 - $current = $snapshot = array();
2697 - $out = $out2 = $out3 = '';
2919 + if ($tbl_current['rows'] == $tbl_snapshot['rows'] && $tbl_current['schema'] == $tbl_snapshot['tmp_schema']) {
2920 + $out3 .= '<div class="wpr-table-container identical" data-table="' . esc_attr($tablename) . '">';
2921 + $out3 .= '<table>';
2922 + $out3 .= '<tr title="Click to show/hide more info" class="wpr-table-match header-row">';
2923 + $out3 .= '<td><b>' . $tbl_current['fullname'] . '</b></td>';
2924 + $out3 .= '<td><b>' . $tbl_snapshot['fullname'] . '</b><span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2925 + $out3 .= '</tr>';
2926 + $out3 .= '<tr class="hidden">';
2927 + $out3 .= '<td>';
2928 + $out3 .= '<p>' . number_format($tbl_current['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_current['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_current['size_index']) . ' in index.</p>';
2929 + $out3 .= '<pre>' . $tbl_current['schema'] . '</pre>';
2930 + $out3 .= '</td>';
2931 + $out3 .= '<td>';
2932 + $out3 .= '<p>' . number_format($tbl_snapshot['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_snapshot['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_snapshot['size_index']) . ' in index.</p>';
2933 + $out3 .= '<pre>' . $tbl_snapshot['schema'] . '</pre>';
2934 + $out3 .= '</td>';
2935 + $out3 .= '</tr>';
2936 + $out3 .= '</table>';
2937 + $out3 .= '</div>';
2938 + } elseif ($schema1 != $schema2) {
2939 + require_once $this->plugin_dir . 'libs/diff.php';
2940 + require_once $this->plugin_dir . 'libs/diff/Renderer/Html/SideBySide.php';
2941 + $diff = new WPR_Diff(explode("\n", $tbl_current['schema']), explode("\n", $tbl_snapshot['schema']), array('ignoreWhitespace' => false));
2942 + $renderer = new WPR_Diff_Renderer_Html_SideBySide;
2698 2943
2699 - if (($res = $this->verify_snapshot_integrity($uid)) !== true) {
2700 - return $res;
2701 - }
2944 + $out2 .= '<div class="wpr-table-container" data-table="' . $tbl_current['basename'] . '">';
2945 + $out2 .= '<table>';
2946 + $out2 .= '<tr title="Click to show/hide more info" class="wpr-table-difference header-row">';
2947 + $out2 .= '<td><b>' . $tbl_current['fullname'] . '</b> table schemas do not match</td>';
2948 + $out2 .= '<td><b>' . $tbl_snapshot['fullname'] . '</b> table schemas do not match<span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2949 + $out2 .= '</tr>';
2950 + $out2 .= '<tr class="hidden">';
2951 + $out2 .= '<td>';
2952 + $out2 .= '<p>' . number_format($tbl_current['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_current['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_current['size_index']) . ' in index.</p>';
2953 + $out2 .= '</td>';
2954 + $out2 .= '<td>';
2955 + $out2 .= '<p>' . number_format($tbl_snapshot['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_snapshot['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_snapshot['size_index']) . ' in index.</p>';
2956 + $out2 .= '</td>';
2957 + $out2 .= '</tr>';
2958 + $out2 .= '<tr class="hidden">';
2959 + $out2 .= '<td colspan="2" class="no-padding">';
2960 + $out2 .= $diff->Render($renderer);
2961 + $out2 .= '</td>';
2962 + $out2 .= '</tr>';
2963 + $out2 .= '</table>';
2964 + $out2 .= '</div>';
2965 + } else {
2966 + $out2 .= '<div class="wpr-table-container" data-table="' . $tbl_current['basename'] . '">';
2967 + $out2 .= '<table>';
2968 + $out2 .= '<tr title="Click to show/hide more info" class="wpr-table-difference header-row">';
2969 + $out2 .= '<td><b>' . $tbl_current['fullname'] . '</b> data in tables does not match</td>';
2970 + $out2 .= '<td><b>' . $tbl_snapshot['fullname'] . '</b> data in tables does not match<span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2971 + $out2 .= '</tr>';
2972 + $out2 .= '<tr class="hidden">';
2973 + $out2 .= '<td>';
2974 + $out2 .= '<p>' . number_format($tbl_current['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_current['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_current['size_index']) . ' in index.</p>';
2975 + $out2 .= '</td>';
2976 + $out2 .= '<td>';
2977 + $out2 .= '<p>' . number_format($tbl_snapshot['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_snapshot['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_snapshot['size_index']) . ' in index.</p>';
2978 + $out2 .= '</td>';
2979 + $out2 .= '</tr>';
2702 2980
2703 - $table_status = $wpdb->get_results('SHOW TABLE STATUS');
2704 - foreach ($table_status as $index => $table) {
2705 - if (empty($table->Engine)) {
2706 - continue;
2707 - }
2981 + $out2 .= '<tr class="hidden">';
2982 + $out2 .= '<td colspan="2">';
2983 + if ($tbl_current['corename'] == 'options') {
2984 + $ss_prefix = $tbl_snapshot['uid'] . '_' . $wpdb->prefix;
2985 + //Due to the working with various table sets, not always prefixed with the WordPress Database Table prefix we need to use custom unprepared queries
2986 + $diff_rows = $wpdb->get_results("SELECT {$wpdb->prefix}options.option_name, {$wpdb->prefix}options.option_value AS current_value, {$ss_prefix}options.option_value AS snapshot_value FROM {$wpdb->prefix}options LEFT JOIN {$ss_prefix}options ON {$ss_prefix}options.option_name = {$wpdb->prefix}options.option_name WHERE {$wpdb->prefix}options.option_value != {$ss_prefix}options.option_value LIMIT 100;"); //phpcs:ignore
2987 + $only_current = $wpdb->get_results("SELECT {$wpdb->prefix}options.option_name, {$wpdb->prefix}options.option_value AS current_value, {$ss_prefix}options.option_value AS snapshot_value FROM {$wpdb->prefix}options LEFT JOIN {$ss_prefix}options ON {$ss_prefix}options.option_name = {$wpdb->prefix}options.option_name WHERE {$ss_prefix}options.option_value IS NULL LIMIT 100;"); //phpcs:ignore
2988 + $only_snapshot = $wpdb->get_results("SELECT {$wpdb->prefix}options.option_name, {$wpdb->prefix}options.option_value AS current_value, {$ss_prefix}options.option_value AS snapshot_value FROM {$wpdb->prefix}options LEFT JOIN {$ss_prefix}options ON {$ss_prefix}options.option_name = {$wpdb->prefix}options.option_name WHERE {$wpdb->prefix}options.option_value IS NULL LIMIT 100;"); //phpcs:ignore
2989 + $out2 .= '<table class="table_diff">';
2990 + $out2 .= '<tr><td style="width: 100px;"><b>Option Name</b></td><td><b>Current Value</b></td><td><b>Snapshot Value</b></td></tr>';
2991 + foreach ($diff_rows as $row) {
2992 + $out2 .= '<tr>';
2993 + $out2 .= '<td style="width: 100px;">' . $row->option_name . '</td>';
2994 + $out2 .= '<td>' . (empty($row->current_value) ? '<i>empty</i>' : $row->current_value) . '</td>';
2995 + $out2 .= '<td>' . (empty($row->snapshot_value) ? '<i>empty</i>' : $row->snapshot_value) . '</td>';
2996 + $out2 .= '</tr>';
2997 + } // foreach
2998 + foreach ($only_current as $row) {
2999 + $out2 .= '<tr>';
3000 + $out2 .= '<td style="width: 100px;">' . $row->option_name . '</td>';
3001 + $out2 .= '<td>' . (empty($row->current_value) ? '<i>empty</i>' : $row->current_value) . '</td>';
3002 + $out2 .= '<td><i>not found in snapshot</i></td>';
3003 + $out2 .= '</tr>';
3004 + } // foreach
3005 + foreach ($only_current as $row) {
3006 + $out2 .= '<tr>';
3007 + $out2 .= '<td style="width: 100px;">' . $row->option_name . '</td>';
3008 + $out2 .= '<td><i>not found in current tables</i></td>';
3009 + $out2 .= '<td>' . (empty($row->snapshot_value) ? '<i>empty</i>' : $row->snapshot_value) . '</td>';
3010 + $out2 .= '</tr>';
3011 + } // foreach
3012 + $out2 .= '</table>';
3013 + } else {
3014 + $out2 .= '<p class="textcenter">Detailed data diff is not available for this table.</p>';
3015 + }
3016 + $out2 .= '</td>';
3017 + $out2 .= '</tr>';
2708 3018
2709 - if (0 !== stripos($table->Name, $uid . '_') && 0 !== stripos($table->Name, $wpdb->prefix)) {
2710 - continue;
2711 - }
3019 + $out2 .= '</table>';
3020 + $out2 .= '</div>';
3021 + }
3022 + } // foreach in both
2712 3023
2713 - $info = array();
2714 - $info['rows'] = $table->Rows;
2715 - $info['size_data'] = $table->Data_length;
2716 - $info['size_index'] = $table->Index_length;
2717 - $schema = $wpdb->get_row('SHOW CREATE TABLE ' . $table->Name, ARRAY_N);
2718 - $info['schema'] = $schema[1];
2719 - $info['engine'] = $table->Engine;
2720 - $info['fullname'] = $table->Name;
2721 - $basename = str_replace(array($uid . '_'), array(''), $table->Name);
2722 - $info['basename'] = $basename;
2723 - $info['corename'] = str_replace(array($wpdb->prefix), array(''), $basename);
2724 - $info['uid'] = $uid;
3024 + return $out . $out2 . $out3;
3025 + } // do_compare_snapshots
2725 3026
2726 - if (0 === stripos($table->Name, $uid . '_')) {
2727 - $snapshot[$basename] = $info;
2728 - }
2729 3027
2730 - if (0 === stripos($table->Name, $wpdb->prefix)) {
2731 - $info['uid'] = '';
2732 - $current[$basename] = $info;
2733 - }
2734 - } // foreach
3028 + /**
3029 + * Generates a unique snapshot ID; verified non-existing
3030 + *
3031 + * @return string
3032 + */
3033 + function generate_snapshot_uid($length = 6)
3034 + {
3035 + global $wpdb;
3036 + $snapshots = $this->get_snapshots();
3037 + $cnt = 0;
3038 + $uid = false;
2735 3039
2736 - $in_both = array_keys(array_intersect_key($current, $snapshot));
2737 - $in_current_only = array_diff_key($current, $snapshot);
2738 - $in_snapshot_only = array_diff_key($snapshot, $current);
3040 + do {
3041 + $cnt++;
3042 + $uid = substr(str_shuffle(str_repeat('abcdefghijklmnopqrstuvwxyz', $length)), 0, $length);
3043 + // phpcs:ignore db call warning as we are using uncommon queries
3044 + $verify_db = $wpdb->get_col($wpdb->prepare('SHOW TABLES LIKE %s', array('%' . $uid . '%'))); // phpcs:ignore
3045 + } while (!empty($verify_db) && isset($snapshots[$uid]) && $cnt < 30);
2739 3046
2740 - $out .= '<br><br>';
2741 - foreach ($in_current_only as $table) {
2742 - $out .= '<div class="wpr-table-container in-current-only" data-table="' . esc_attr($table['basename']) . '">';
2743 - $out .= '<table>';
2744 - $out .= '<tr title="Click to show/hide more info" class="wpr-table-missing header-row">';
2745 - $out .= '<td><b>' . $table['fullname'] . '</b></td>';
2746 - $out .= '<td>table is not present in snapshot<span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2747 - $out .= '</tr>';
2748 - $out .= '<tr class="hidden">';
2749 - $out .= '<td>';
2750 - $out .= '<p>' . number_format($table['rows']) . ' row' . ($table['rows'] == 1 ? '' : 's') . ' totaling ' . WP_Reset_Utility::format_size($table['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($table['size_index']) . ' in index.</p>';
2751 - $out .= '<pre>' . $table['schema'] . '</pre>';
2752 - $out .= '</td>';
2753 - $out .= '<td>&nbsp;</td>';
2754 - $out .= '</tr>';
2755 - $out .= '</table>';
2756 - $out .= '</div>';
2757 - } // foreach in current only
3047 + if ($cnt == 30) {
3048 + $uid = false;
3049 + }
2758 3050
2759 - foreach ($in_snapshot_only as $table) {
2760 - $out .= '<div class="wpr-table-container in-snapshot-only" data-table="' . esc_attr($table['basename']) . '">';
2761 - $out .= '<table>';
2762 - $out .= '<tr title="Click to show/hide more info" class="wpr-table-missing header-row">';
2763 - $out .= '<td>table is not present in current tables</td>';
2764 - $out .= '<td><b>' . esc_html($table['fullname']) . '</b><span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2765 - $out .= '</tr>';
2766 - $out .= '<tr class="hidden">';
2767 - $out .= '<td>&nbsp;</td>';
2768 - $out .= '<td>';
2769 - $out .= '<p>' . number_format($table['rows']) . ' row' . ($table['rows'] == 1 ? '' : 's') . ' totaling ' . WP_Reset_Utility::format_size($table['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($table['size_index']) . ' in index.</p>';
2770 - $out .= '<pre>' . $table['schema'] . '</pre>';
2771 - $out .= '</td>';
2772 - $out .= '</tr>';
2773 - $out .= '</table>';
2774 - $out .= '</div>';
2775 - } // foreach in snapshot only
3051 + return $uid;
3052 + } // generate_snapshot_uid
2776 3053
2777 - foreach ($in_both as $tablename) {
2778 - $tbl_current = $current[$tablename];
2779 - $tbl_snapshot = $snapshot[$tablename];
2780 3054
2781 - $schema1 = preg_replace('/(auto_increment=)([0-9]*) /i', '${1}1 ', $tbl_current['schema'], 1);
2782 - $schema2 = preg_replace('/(auto_increment=)([0-9]*) /i', '${1}1 ', $tbl_snapshot['schema'], 1);
2783 - $tbl_snapshot['tmp_schema'] = str_replace($tbl_snapshot['uid'] . '_' . $tablename, $tablename, $tbl_snapshot['schema']);
2784 - $schema2 = str_replace($tbl_snapshot['uid'] . '_' . $tablename, $tablename, $schema2);
3055 + // auto download / install / activate WP Force SSL plugin
3056 + function install_wpfssl()
3057 + {
3058 + check_ajax_referer('install_wpfssl');
2785 3059
2786 - if ($tbl_current['rows'] == $tbl_snapshot['rows'] && $tbl_current['schema'] == $tbl_snapshot['tmp_schema']) {
2787 - $out3 .= '<div class="wpr-table-container identical" data-table="' . esc_attr($tablename) . '">';
2788 - $out3 .= '<table>';
2789 - $out3 .= '<tr title="Click to show/hide more info" class="wpr-table-match header-row">';
2790 - $out3 .= '<td><b>' . $tbl_current['fullname'] . '</b></td>';
2791 - $out3 .= '<td><b>' . $tbl_snapshot['fullname'] . '</b><span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2792 - $out3 .= '</tr>';
2793 - $out3 .= '<tr class="hidden">';
2794 - $out3 .= '<td>';
2795 - $out3 .= '<p>' . number_format($tbl_current['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_current['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_current['size_index']) . ' in index.</p>';
2796 - $out3 .= '<pre>' . $tbl_current['schema'] . '</pre>';
2797 - $out3 .= '</td>';
2798 - $out3 .= '<td>';
2799 - $out3 .= '<p>' . number_format($tbl_snapshot['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_snapshot['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_snapshot['size_index']) . ' in index.</p>';
2800 - $out3 .= '<pre>' . $tbl_snapshot['schema'] . '</pre>';
2801 - $out3 .= '</td>';
2802 - $out3 .= '</tr>';
2803 - $out3 .= '</table>';
2804 - $out3 .= '</div>';
2805 - } elseif ($schema1 != $schema2) {
2806 - require_once $this->plugin_dir . 'libs/diff.php';
2807 - require_once $this->plugin_dir . 'libs/diff/Renderer/Html/SideBySide.php';
2808 - $diff = new WPR_Diff(explode("\n", $tbl_current['schema']), explode("\n", $tbl_snapshot['schema']), array('ignoreWhitespace' => false));
2809 - $renderer = new WPR_Diff_Renderer_Html_SideBySide;
3060 + if (false === current_user_can('manage_options')) {
3061 + wp_die('Sorry, you have to be an admin to run this action.');
3062 + }
2810 3063
2811 - $out2 .= '<div class="wpr-table-container" data-table="' . $tbl_current['basename'] . '">';
2812 - $out2 .= '<table>';
2813 - $out2 .= '<tr title="Click to show/hide more info" class="wpr-table-difference header-row">';
2814 - $out2 .= '<td><b>' . $tbl_current['fullname'] . '</b> table schemas do not match</td>';
2815 - $out2 .= '<td><b>' . $tbl_snapshot['fullname'] . '</b> table schemas do not match<span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2816 - $out2 .= '</tr>';
2817 - $out2 .= '<tr class="hidden">';
2818 - $out2 .= '<td>';
2819 - $out2 .= '<p>' . number_format($tbl_current['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_current['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_current['size_index']) . ' in index.</p>';
2820 - $out2 .= '</td>';
2821 - $out2 .= '<td>';
2822 - $out2 .= '<p>' . number_format($tbl_snapshot['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_snapshot['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_snapshot['size_index']) . ' in index.</p>';
2823 - $out2 .= '</td>';
2824 - $out2 .= '</tr>';
2825 - $out2 .= '<tr class="hidden">';
2826 - $out2 .= '<td colspan="2" class="no-padding">';
2827 - $out2 .= $diff->Render($renderer);
2828 - $out2 .= '</td>';
2829 - $out2 .= '</tr>';
2830 - $out2 .= '</table>';
2831 - $out2 .= '</div>';
2832 - } else {
2833 - $out2 .= '<div class="wpr-table-container" data-table="' . $tbl_current['basename'] . '">';
2834 - $out2 .= '<table>';
2835 - $out2 .= '<tr title="Click to show/hide more info" class="wpr-table-difference header-row">';
2836 - $out2 .= '<td><b>' . $tbl_current['fullname'] . '</b> data in tables does not match</td>';
2837 - $out2 .= '<td><b>' . $tbl_snapshot['fullname'] . '</b> data in tables does not match<span class="dashicons dashicons-arrow-down-alt2"></span></td>';
2838 - $out2 .= '</tr>';
2839 - $out2 .= '<tr class="hidden">';
2840 - $out2 .= '<td>';
2841 - $out2 .= '<p>' . number_format($tbl_current['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_current['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_current['size_index']) . ' in index.</p>';
2842 - $out2 .= '</td>';
2843 - $out2 .= '<td>';
2844 - $out2 .= '<p>' . number_format($tbl_snapshot['rows']) . ' rows totaling ' . WP_Reset_Utility::format_size($tbl_snapshot['size_data']) . ' in data and ' . WP_Reset_Utility::format_size($tbl_snapshot['size_index']) . ' in index.</p>';
2845 - $out2 .= '</td>';
2846 - $out2 .= '</tr>';
3064 + $plugin_slug = 'wp-force-ssl/wp-force-ssl.php';
3065 + $plugin_zip = 'https://downloads.wordpress.org/plugin/wp-force-ssl.latest-stable.zip';
2847 3066
2848 - $out2 .= '<tr class="hidden">';
2849 - $out2 .= '<td colspan="2">';
2850 - if ($tbl_current['corename'] == 'options') {
2851 - $ss_prefix = $tbl_snapshot['uid'] . '_' . $wpdb->prefix;
2852 - $diff_rows = $wpdb->get_results("SELECT {$wpdb->prefix}options.option_name, {$wpdb->prefix}options.option_value AS current_value, {$ss_prefix}options.option_value AS snapshot_value FROM {$wpdb->prefix}options LEFT JOIN {$ss_prefix}options ON {$ss_prefix}options.option_name = {$wpdb->prefix}options.option_name WHERE {$wpdb->prefix}options.option_value != {$ss_prefix}options.option_value LIMIT 100;");
2853 - $only_current = $wpdb->get_results("SELECT {$wpdb->prefix}options.option_name, {$wpdb->prefix}options.option_value AS current_value, {$ss_prefix}options.option_value AS snapshot_value FROM {$wpdb->prefix}options LEFT JOIN {$ss_prefix}options ON {$ss_prefix}options.option_name = {$wpdb->prefix}options.option_name WHERE {$ss_prefix}options.option_value IS NULL LIMIT 100;");
2854 - $only_snapshot = $wpdb->get_results("SELECT {$wpdb->prefix}options.option_name, {$wpdb->prefix}options.option_value AS current_value, {$ss_prefix}options.option_value AS snapshot_value FROM {$wpdb->prefix}options LEFT JOIN {$ss_prefix}options ON {$ss_prefix}options.option_name = {$wpdb->prefix}options.option_name WHERE {$wpdb->prefix}options.option_value IS NULL LIMIT 100;");
2855 - $out2 .= '<table class="table_diff">';
2856 - $out2 .= '<tr><td style="width: 100px;"><b>Option Name</b></td><td><b>Current Value</b></td><td><b>Snapshot Value</b></td></tr>';
2857 - foreach ($diff_rows as $row) {
2858 - $out2 .= '<tr>';
2859 - $out2 .= '<td style="width: 100px;">' . $row->option_name . '</td>';
2860 - $out2 .= '<td>' . (empty($row->current_value) ? '<i>empty</i>' : $row->current_value) . '</td>';
2861 - $out2 .= '<td>' . (empty($row->snapshot_value) ? '<i>empty</i>' : $row->snapshot_value) . '</td>';
2862 - $out2 .= '</tr>';
2863 - } // foreach
2864 - foreach ($only_current as $row) {
2865 - $out2 .= '<tr>';
2866 - $out2 .= '<td style="width: 100px;">' . $row->option_name . '</td>';
2867 - $out2 .= '<td>' . (empty($row->current_value) ? '<i>empty</i>' : $row->current_value) . '</td>';
2868 - $out2 .= '<td><i>not found in snapshot</i></td>';
2869 - $out2 .= '</tr>';
2870 - } // foreach
2871 - foreach ($only_current as $row) {
2872 - $out2 .= '<tr>';
2873 - $out2 .= '<td style="width: 100px;">' . $row->option_name . '</td>';
2874 - $out2 .= '<td><i>not found in current tables</i></td>';
2875 - $out2 .= '<td>' . (empty($row->snapshot_value) ? '<i>empty</i>' : $row->snapshot_value) . '</td>';
2876 - $out2 .= '</tr>';
2877 - } // foreach
2878 - $out2 .= '</table>';
3067 + @include_once ABSPATH . 'wp-admin/includes/plugin.php';
3068 + @include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
3069 + @include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
3070 + @include_once ABSPATH . 'wp-admin/includes/file.php';
3071 + @include_once ABSPATH . 'wp-admin/includes/misc.php';
3072 + echo '<style>
3073 + body{
3074 + font-family: sans-serif;
3075 + font-size: 14px;
3076 + line-height: 1.5;
3077 + color: #444;
3078 + }
3079 + </style>';
3080 +
3081 + echo '<div style="margin: 20px; color:#444;">';
3082 + echo 'If things are not done in a minute <a target="_parent" href="' . esc_url(admin_url('plugin-install.php?s=force%20ssl%20webfactory&tab=search&type=term')) . '">install the plugin manually via Plugins page</a><br><br>';
3083 + echo 'Starting ...<br><br>';
3084 +
3085 + wp_cache_flush();
3086 + $upgrader = new Plugin_Upgrader();
3087 + echo 'Check if WP Force SSL is already installed ... <br />';
3088 + if ($this->is_plugin_installed($plugin_slug)) {
3089 + echo 'WP Force SSL is already installed! <br /><br />Making sure it\'s the latest version.<br />';
3090 + $upgrader->upgrade($plugin_slug);
3091 + $installed = true;
2879 3092 } else {
2880 - $out2 .= '<p class="textcenter">Detailed data diff is not available for this table.</p>';
3093 + echo 'Installing WP Force SSL.<br />';
3094 + $installed = $upgrader->install($plugin_zip);
2881 3095 }
2882 - $out2 .= '</td>';
2883 - $out2 .= '</tr>';
3096 + wp_cache_flush();
2884 3097
2885 - $out2 .= '</table>';
2886 - $out2 .= '</div>';
2887 - }
2888 - } // foreach in both
3098 + if (!is_wp_error($installed) && $installed) {
3099 + echo 'Activating WP Force SSL.<br />';
3100 + $activate = activate_plugin($plugin_slug);
2889 3101
2890 - return $out . $out2 . $out3;
2891 - } // do_compare_snapshots
3102 + if (is_null($activate)) {
3103 + echo 'WP Force SSL Activated.<br />';
2892 3104
3105 + echo '<script>setTimeout(function() { top.location = "tools.php?page=wp-reset"; }, 1000);</script>';
3106 + echo '<br>If you are not redirected in a few seconds - <a href="tools.php?page=wp-reset" target="_parent">click here</a>.';
3107 + }
3108 + } else {
3109 + echo 'Could not install WP Force SSL. You\'ll have to <a target="_parent" href="' . esc_url(admin_url('plugin-install.php?s=force%20ssl%20webfactory&tab=search&type=term')) . '">download and install manually</a>.';
3110 + }
2893 3111
2894 - /**
2895 - * Generates a unique 6-char snapshot ID; verified non-existing
2896 - *
2897 - * @return string
2898 - */
2899 - function generate_snapshot_uid()
2900 - {
2901 - global $wpdb;
2902 - $snapshots = $this->get_snapshots();
2903 - $cnt = 0;
2904 - $uid = false;
3112 + echo '</div>';
3113 + } // install_wpfssl
2905 3114
2906 - do {
2907 - $cnt++;
2908 - $uid = sprintf('%06x', mt_rand(0, 0xFFFFFF));
3115 + /**
3116 + * Initializes the WordPress filesystem.
3117 + *
3118 + * @return bool
3119 + */
3120 + function wp_init_filesystem()
3121 + {
3122 + if (! $this->filesystem_initialized) {
3123 + if (! class_exists('WP_Filesystem')) {
3124 + require_once ABSPATH . 'wp-admin/includes/file.php';
3125 + }
2909 3126
2910 - $verify_db = $wpdb->get_col($wpdb->prepare('SHOW TABLES LIKE %s', array('%' . $uid . '%')));
2911 - } while (!empty($verify_db) && isset($snapshots[$uid]) && $cnt < 30);
3127 + WP_Filesystem();
3128 + $this->filesystem_initialized = true;
3129 + }
2912 3130
2913 - if ($cnt == 30) {
2914 - $uid = false;
3131 + return true;
2915 3132 }
2916 3133
2917 - return $uid;
2918 - } // generate_snapshot_uid
3134 + /**
3135 + * Clean up on uninstall; no action on deactive at the moment
3136 + *
3137 + * @return null
3138 + */
3139 + static function uninstall()
3140 + {
3141 + delete_option('wp-reset');
3142 + delete_option('wp-reset-snapshots');
3143 + } // uninstall
2919 3144
2920 3145
2921 - /**
2922 - * Clean up on uninstall; no action on deactive at the moment
2923 - *
2924 - * @return null
2925 - */
2926 - static function uninstall()
2927 - {
2928 - delete_option('wp-reset');
2929 - delete_option('wp-reset-snapshots');
2930 - } // uninstall
3146 + /**
3147 + * Disabled; we use singleton pattern so magic functions need to be disabled
3148 + *
3149 + * @return null
3150 + */
3151 + function __clone() {}
2931 3152
2932 3153
2933 - /**
2934 - * Disabled; we use singleton pattern so magic functions need to be disabled
2935 - *
2936 - * @return null
2937 - */
2938 - function __clone()
2939 - {
2940 - }
3154 + /**
3155 + * Disabled; we use singleton pattern so magic functions need to be disabled
3156 + *
3157 + * @return null
3158 + */
3159 + function __sleep() {}
2941 3160
2942 3161
2943 - /**
2944 - * Disabled; we use singleton pattern so magic functions need to be disabled
2945 - *
2946 - * @return null
2947 - */
2948 - function __sleep()
2949 - {
2950 - }
2951 -
2952 -
2953 - /**
2954 - * Disabled; we use singleton pattern so magic functions need to be disabled
2955 - *
2956 - * @return null
2957 - */
2958 - function __wakeup()
2959 - {
2960 - }
3162 + /**
3163 + * Disabled; we use singleton pattern so magic functions need to be disabled
3164 + *
3165 + * @return null
3166 + */
3167 + function __wakeup() {}
2961 3168 } // WP_Reset class
2962 3169
2963 3170
2964 3171 // Create plugin instance and hook things up
@@ -2963,9 +3170,9 @@
2963 3170
2964 3171 // Create plugin instance and hook things up
2965 3172 // Only if in admin - plugin has no frontend functionality
2966 3173 if (is_admin() || WP_Reset::is_cli_running()) {
2967 - global $wp_reset;
2968 - $wp_reset = WP_Reset::getInstance();
2969 - add_action('plugins_loaded', array($wp_reset, 'load_textdomain'));
2970 - register_uninstall_hook(__FILE__, array('WP_Reset', 'uninstall'));
3174 + global $wp_reset;
3175 + $wp_reset = WP_Reset::getInstance();
3176 + add_action('plugins_loaded', array($wp_reset, 'load_textdomain'));
3177 + register_uninstall_hook(__FILE__, array('WP_Reset', 'uninstall'));
2971 3178 }