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