WC_Admin_Status::output()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Debug/Status page
4
 *
5
 * @author      WooThemes
6
 * @category    Admin
7
 * @package     WooCommerce/Admin/System Status
8
 * @version     2.2.0
9
 */
10
11
if ( ! defined( 'ABSPATH' ) ) {
12
	exit;
13
}
14
15
/**
16
 * WC_Admin_Status Class.
17
 */
18
class WC_Admin_Status {
19
20
	/**
21
	 * Handles output of the reports page in admin.
22
	 */
23
	public static function output() {
24
		include_once( 'views/html-admin-page-status.php' );
25
	}
26
27
	/**
28
	 * Handles output of report.
29
	 */
30
	public static function status_report() {
31
		include_once( 'views/html-admin-page-status-report.php' );
32
	}
33
34
	/**
35
	 * Handles output of tools.
36
	 */
37
	public static function status_tools() {
38
		global $wpdb;
39
40
		$tools = self::get_tools();
41
42
		if ( ! empty( $_GET['action'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'debug_action' ) ) {
43
44
			switch ( $_GET['action'] ) {
45
				case 'clear_transients' :
46
					wc_delete_product_transients();
47
					wc_delete_shop_order_transients();
48
					WC_Cache_Helper::get_transient_version( 'shipping', true );
49
50
					echo '<div class="updated inline"><p>' . __( 'Product Transients Cleared', 'woocommerce' ) . '</p></div>';
51
				break;
52
				case 'clear_expired_transients' :
53
54
					/*
55
					 * Deletes all expired transients. The multi-table delete syntax is used.
56
					 * to delete the transient record from table a, and the corresponding.
57
					 * transient_timeout record from table b.
58
					 *
59
					 * Based on code inside core's upgrade_network() function.
60
					 */
61
					$sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
62
						WHERE a.option_name LIKE %s
63
						AND a.option_name NOT LIKE %s
64
						AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
65
						AND b.option_value < %d";
66
					$rows = $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', time() ) );
67
68
					$sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
69
						WHERE a.option_name LIKE %s
70
						AND a.option_name NOT LIKE %s
71
						AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )
72
						AND b.option_value < %d";
73
					$rows2 = $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_site_transient_' ) . '%', $wpdb->esc_like( '_site_transient_timeout_' ) . '%', time() ) );
74
75
					echo '<div class="updated inline"><p>' . sprintf( __( '%d Transients Rows Cleared', 'woocommerce' ), $rows + $rows2 ) . '</p></div>';
76
				break;
77
				case 'reset_roles' :
78
					// Remove then re-add caps and roles
79
					WC_Install::remove_roles();
80
					WC_Install::create_roles();
81
82
					echo '<div class="updated inline"><p>' . __( 'Roles successfully reset', 'woocommerce' ) . '</p></div>';
83
				break;
84
				case 'recount_terms' :
85
86
					$product_cats = get_terms( 'product_cat', array( 'hide_empty' => false, 'fields' => 'id=>parent' ) );
87
88
					_wc_term_recount( $product_cats, get_taxonomy( 'product_cat' ), true, false );
89
90
					$product_tags = get_terms( 'product_tag', array( 'hide_empty' => false, 'fields' => 'id=>parent' ) );
91
92
					_wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), true, false );
93
94
					echo '<div class="updated inline"><p>' . __( 'Terms successfully recounted', 'woocommerce' ) . '</p></div>';
95
				break;
96
				case 'clear_sessions' :
97
98
					$wpdb->query( "TRUNCATE {$wpdb->prefix}woocommerce_sessions" );
99
100
					wp_cache_flush();
101
102
					echo '<div class="updated inline"><p>' . __( 'Sessions successfully cleared', 'woocommerce' ) . '</p></div>';
103
				break;
104
				case 'install_pages' :
105
					WC_Install::create_pages();
106
					echo '<div class="updated inline"><p>' . __( 'All missing WooCommerce pages was installed successfully.', 'woocommerce' ) . '</p></div>';
107
				break;
108
				case 'delete_taxes' :
109
110
					$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rates;" );
111
					$wpdb->query( "TRUNCATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations;" );
112
					WC_Cache_Helper::incr_cache_prefix( 'taxes' );
113
114
					echo '<div class="updated inline"><p>' . __( 'Tax rates successfully deleted', 'woocommerce' ) . '</p></div>';
115
				break;
116
				case 'reset_tracking' :
117
					delete_option( 'woocommerce_allow_tracking' );
118
					WC_Admin_Notices::add_notice( 'tracking' );
119
120
					echo '<div class="updated inline"><p>' . __( 'Usage tracking settings successfully reset.', 'woocommerce' ) . '</p></div>';
121
				break;
122
				default :
123
					$action = esc_attr( $_GET['action'] );
124
					if ( isset( $tools[ $action ]['callback'] ) ) {
125
						$callback = $tools[ $action ]['callback'];
126
						$return = call_user_func( $callback );
127
						if ( $return === false ) {
128
							$callback_string = is_array( $callback ) ? get_class( $callback[0] ) . '::' . $callback[1] : $callback;
129
							echo '<div class="error inline"><p>' . sprintf( __( 'There was an error calling %s', 'woocommerce' ), $callback_string ) . '</p></div>';
130
						}
131
					}
132
				break;
133
			}
134
		}
135
136
		// Display message if settings settings have been saved
137
		if ( isset( $_REQUEST['settings-updated'] ) ) {
138
			echo '<div class="updated inline"><p>' . __( 'Your changes have been saved.', 'woocommerce' ) . '</p></div>';
139
		}
140
141
		include_once( 'views/html-admin-page-status-tools.php' );
142
	}
143
144
	/**
145
	 * Get tools.
146
	 * @return array of tools
147
	 */
148
	public static function get_tools() {
149
		$tools = array(
150
			'clear_transients' => array(
151
				'name'    => __( 'WC Transients', 'woocommerce' ),
152
				'button'  => __( 'Clear transients', 'woocommerce' ),
153
				'desc'    => __( 'This tool will clear the product/shop transients cache.', 'woocommerce' ),
154
			),
155
			'clear_expired_transients' => array(
156
				'name'    => __( 'Expired Transients', 'woocommerce' ),
157
				'button'  => __( 'Clear expired transients', 'woocommerce' ),
158
				'desc'    => __( 'This tool will clear ALL expired transients from WordPress.', 'woocommerce' ),
159
			),
160
			'recount_terms' => array(
161
				'name'    => __( 'Term counts', 'woocommerce' ),
162
				'button'  => __( 'Recount terms', 'woocommerce' ),
163
				'desc'    => __( 'This tool will recount product terms - useful when changing your settings in a way which hides products from the catalog.', 'woocommerce' ),
164
			),
165
			'reset_roles' => array(
166
				'name'    => __( 'Capabilities', 'woocommerce' ),
167
				'button'  => __( 'Reset capabilities', 'woocommerce' ),
168
				'desc'    => __( 'This tool will reset the admin, customer and shop_manager roles to default. Use this if your users cannot access all of the WooCommerce admin pages.', 'woocommerce' ),
169
			),
170
			'clear_sessions' => array(
171
				'name'    => __( 'Customer Sessions', 'woocommerce' ),
172
				'button'  => __( 'Clear all sessions', 'woocommerce' ),
173
				'desc'    => __( '<strong class="red">Warning:</strong> This tool will delete all customer session data from the database, including any current live carts.', 'woocommerce' ),
174
			),
175
			'install_pages' => array(
176
				'name'    => __( 'Install WooCommerce Pages', 'woocommerce' ),
177
				'button'  => __( 'Install pages', 'woocommerce' ),
178
				'desc'    => __( '<strong class="red">Note:</strong> This tool will install all the missing WooCommerce pages. Pages already defined and set up will not be replaced.', 'woocommerce' ),
179
			),
180
			'delete_taxes' => array(
181
				'name'    => __( 'Delete all WooCommerce tax rates', 'woocommerce' ),
182
				'button'  => __( 'Delete ALL tax rates', 'woocommerce' ),
183
				'desc'    => __( '<strong class="red">Note:</strong> This option will delete ALL of your tax rates, use with caution.', 'woocommerce' ),
184
			),
185
			'reset_tracking' => array(
186
				'name'    => __( 'Reset Usage Tracking Settings', 'woocommerce' ),
187
				'button'  => __( 'Reset usage tracking settings', 'woocommerce' ),
188
				'desc'    => __( 'This will reset your usage tracking settings, causing it to show the opt-in banner again and not sending any data.', 'woocommerce' ),
189
			)
190
		);
191
192
		return apply_filters( 'woocommerce_debug_tools', $tools );
193
	}
194
195
	/**
196
	 * Show the logs page.
197
	 */
198
	public static function status_logs() {
199
200
		$logs = self::scan_log_files();
201
202
		if ( ! empty( $_REQUEST['log_file'] ) && isset( $logs[ sanitize_title( $_REQUEST['log_file'] ) ] ) ) {
203
			$viewed_log = $logs[ sanitize_title( $_REQUEST['log_file'] ) ];
204
		} elseif ( ! empty( $logs ) ) {
205
			$viewed_log = current( $logs );
206
		}
207
208
		include_once( 'views/html-admin-page-status-logs.php' );
209
	}
210
211
	/**
212
	 * Retrieve metadata from a file. Based on WP Core's get_file_data function.
213
	 * @since  2.1.1
214
	 * @param  string $file Path to the file
215
	 * @return string
216
	 */
217
	public static function get_file_version( $file ) {
218
219
		// Avoid notices if file does not exist
220
		if ( ! file_exists( $file ) ) {
221
			return '';
222
		}
223
224
		// We don't need to write to the file, so just open for reading.
225
		$fp = fopen( $file, 'r' );
226
227
		// Pull only the first 8kiB of the file in.
228
		$file_data = fread( $fp, 8192 );
229
230
		// PHP will close file handle, but we are good citizens.
231
		fclose( $fp );
232
233
		// Make sure we catch CR-only line endings.
234
		$file_data = str_replace( "\r", "\n", $file_data );
235
		$version   = '';
236
237
		if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( '@version', '/' ) . '(.*)$/mi', $file_data, $match ) && $match[1] )
238
			$version = _cleanup_header_comment( $match[1] );
239
240
		return $version ;
241
	}
242
243
	/**
244
	 * Scan the template files.
245
	 * @param  string $template_path
246
	 * @return array
247
	 */
248
	public static function scan_template_files( $template_path ) {
249
250
		$files  = @scandir( $template_path );
251
		$result = array();
252
253
		if ( ! empty( $files ) ) {
254
255
			foreach ( $files as $key => $value ) {
256
257
				if ( ! in_array( $value, array( ".",".." ) ) ) {
258
259
					if ( is_dir( $template_path . DIRECTORY_SEPARATOR . $value ) ) {
260
						$sub_files = self::scan_template_files( $template_path . DIRECTORY_SEPARATOR . $value );
261
						foreach ( $sub_files as $sub_file ) {
262
							$result[] = $value . DIRECTORY_SEPARATOR . $sub_file;
263
						}
264
					} else {
265
						$result[] = $value;
266
					}
267
				}
268
			}
269
		}
270
		return $result;
271
	}
272
273
	/**
274
	 * Scan the log files.
275
	 * @return array
276
	 */
277
	public static function scan_log_files() {
278
		$files  = @scandir( WC_LOG_DIR );
279
		$result = array();
280
281
		if ( $files ) {
282
283
			foreach ( $files as $key => $value ) {
284
285
				if ( ! in_array( $value, array( '.', '..' ) ) ) {
286
					if ( ! is_dir( $value ) && strstr( $value, '.log' ) ) {
287
						$result[ sanitize_title( $value ) ] = $value;
288
					}
289
				}
290
			}
291
292
		}
293
294
		return $result;
295
	}
296
297
	/**
298
	 * Get latest version of a theme by slug.
299
	 * @param  object $theme WP_Theme object.
300
	 * @return string Version number if found.
301
	 */
302
	public static function get_latest_theme_version( $theme ) {
303
		$api = themes_api( 'theme_information', array(
304
			'slug'     => $theme->get_stylesheet(),
305
			'fields'   => array(
306
				'sections' => false,
307
				'tags'     => false,
308
			)
309
		) );
310
311
		$update_theme_version = 0;
312
313
		// Check .org for updates.
314
		if ( is_object( $api ) && ! is_wp_error( $api ) ) {
315
			$update_theme_version = $api->version;
316
317
		// Check WooThemes Theme Version.
318
		} elseif ( strstr( $theme->{'Author URI'}, 'woothemes' ) ) {
319
			$theme_dir = substr( strtolower( str_replace( ' ','', $theme->Name ) ), 0, 45 );
320
321 View Code Duplication
			if ( false === ( $theme_version_data = get_transient( $theme_dir . '_version_data' ) ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
322
				$theme_changelog = wp_safe_remote_get( 'http://dzv365zjfbd8v.cloudfront.net/changelogs/' . $theme_dir . '/changelog.txt' );
323
				$cl_lines  = explode( "\n", wp_remote_retrieve_body( $theme_changelog ) );
324
				if ( ! empty( $cl_lines ) ) {
325
					foreach ( $cl_lines as $line_num => $cl_line ) {
326
						if ( preg_match( '/^[0-9]/', $cl_line ) ) {
327
							$theme_date         = str_replace( '.' , '-' , trim( substr( $cl_line , 0 , strpos( $cl_line , '-' ) ) ) );
328
							$theme_version      = preg_replace( '~[^0-9,.]~' , '' ,stristr( $cl_line , "version" ) );
329
							$theme_update       = trim( str_replace( "*" , "" , $cl_lines[ $line_num + 1 ] ) );
330
							$theme_version_data = array( 'date' => $theme_date , 'version' => $theme_version , 'update' => $theme_update , 'changelog' => $theme_changelog );
331
							set_transient( $theme_dir . '_version_data', $theme_version_data , DAY_IN_SECONDS );
332
							break;
333
						}
334
					}
335
				}
336
			}
337
338
			if ( ! empty( $theme_version_data['version'] ) ) {
339
				$update_theme_version = $theme_version_data['version'];
340
			}
341
		}
342
343
		return $update_theme_version;
344
	}
345
}
346