page_title = __( 'Tools', 'insert-headers-and-footers' );
parent::__construct();
}
/**
* Register hook on admin init just for this page.
*
* @return void
*/
public function page_hooks() {
$this->process_message();
add_action( 'admin_init', array( $this, 'submit_listener' ) );
add_action( 'admin_print_scripts', array( $this, 'importer_templates' ) );
add_filter( 'wpcode_admin_js_data', array( $this, 'add_tools_data' ) );
// Listen for log delete requests.
add_action( 'admin_init', array( $this, 'maybe_delete_log' ) );
// Localize script data.
add_filter( 'wpcode_admin_js_data', array( $this, 'add_tools_strings' ) );
}
/**
* Process messages specific to this page.
*
* @return void
*/
public function process_message() {
// phpcs:disable WordPress.Security.NonceVerification
if ( ! isset( $_GET['message'] ) ) {
return;
}
$messages = array(
1 => sprintf(
// Translators: Adds a link to the snippets list in the admin.
__( 'Import was successfully finished. You can go and check %1$syour snippets%2$s.', 'insert-headers-and-footers' ),
'',
''
),
);
$message = absint( $_GET['message'] );
// phpcs:enable WordPress.Security.NonceVerification
if ( ! isset( $messages[ $message ] ) ) {
return;
}
$this->set_success_message( $messages[ $message ] );
}
/**
* @return WPCode_Importer_Type[]
*/
public function get_importers() {
if ( empty( $this->importers ) ) {
$this->importers = wpcode()->importers->get_importers();
}
return $this->importers;
}
/**
* The Tools page output.
*
* @return void
*/
public function output_content() {
if ( method_exists( $this, 'output_view_' . $this->view ) ) {
call_user_func( array( $this, 'output_view_' . $this->view ) );
}
}
/**
* The Import view.
*
* @return void
*/
public function output_view_import() {
?>
importers->importers;
$snippets = array();
$provider_name = '';
if ( isset( $importers[ $provider ] ) ) {
$snippets = $importers[ $provider ]->get_snippets();
$provider_name = $importers[ $provider ]->name;
}
?>
array(
'class' => array(),
),
)
),
'1',
'0',
esc_html( $provider_name )
);
?>
array(
'class' => array(),
),
)
),
''
);
?>
__( 'All', 'insert-headers-and-footers' ),
'publish' => __( 'Active', 'insert-headers-and-footers' ),
'draft' => __( 'Inactive', 'insert-headers-and-footers' ),
);
$select = '';
return $select;
}
/**
* Get all the tags in a checkbox list.
*
* @return string
*/
public function get_code_type_checkboxes() {
$labels = wpcode()->execute->get_options();
$tags = get_terms(
array(
'taxonomy' => 'wpcode_type',
'count' => true,
)
);
$options = array();
if ( empty( $tags ) ) {
return __( 'No snippets available to export.', 'insert-headers-and-footers' );
}
foreach ( $tags as $tag ) {
$label = isset( $labels[ $tag->slug ] ) ? $labels[ $tag->slug ] : $tag->name;
$options[ $tag->term_id ] = $label . ' (' . $tag->count . ')';
}
return $this->get_checkboxes_list( $options, 'wpcode_export_code_type' );
}
/**
* Get all the tags in a checkbox list.
*
* @return string
*/
public function get_tags_checkboxes() {
$tags = get_terms(
array(
'taxonomy' => 'wpcode_tags',
'count' => true,
)
);
if ( empty( $tags ) ) {
return __( 'No tags available.', 'insert-headers-and-footers' );
}
$options = array();
foreach ( $tags as $tag ) {
$options[ $tag->term_id ] = $tag->name . ' (' . $tag->count . ')';
}
return $this->get_checkboxes_list( $options, 'wpcode_export_tags' );
}
/**
* Get a list of checkboxes from a key=>value array.
*
* @param array $options The options to display as checkboxes.
* @param string $name The name used for the input name attribute.
*
* @return string
*/
public function get_checkboxes_list( $options, $name ) {
$checkboxes = '';
foreach ( $options as $value => $label ) {
$checkboxes .= sprintf(
'',
$name,
$value,
$label
);
}
$checkboxes .= '
';
return $checkboxes;
}
/**
* For this page we output a menu.
*
* @return void
*/
public function output_header_bottom() {
?>
views as $slug => $label ) {
if ( 'importer' === $slug ) {
continue;
}
$class = $this->view === $slug ? 'active' : '';
?>
-
views = array(
'import' => __( 'Import', 'insert-headers-and-footers' ),
'export' => __( 'Export', 'insert-headers-and-footers' ),
'info' => __( 'System Info', 'insert-headers-and-footers' ),
'importer' => __( 'Importer', 'insert-headers-and-footers' ),
'logs' => __( 'Logs', 'insert-headers-and-footers' ),
);
}
/**
* If the form is submitted attempt to save the values.
*
* @return void
*/
public function submit_listener() {
if ( ! isset( $_REQUEST[ $this->nonce_name ] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST[ $this->nonce_name ] ), $this->action ) ) {
// Nonce is missing, so we're not even going to try.
return;
}
if ( isset( $_REQUEST['wpcode-export-snippets'] ) ) {
$this->handle_export();
}
if ( ! isset( $_REQUEST['action'] ) ) {
return;
}
$action = sanitize_text_field( wp_unslash( $_REQUEST['action'] ) );
if ( 'import_snippets' === $action ) {
$this->handle_import_file();
}
}
/**
* Process export form and download a JSON file.
*
* @return void
*/
public function handle_export() {
// Already verified nonce in parent method @see submit_listener.
// phpcs:disable WordPress.Security.NonceVerification
$status = isset( $_POST['wpcode_export_status'] ) ? sanitize_text_field( wp_unslash( $_POST['wpcode_export_status'] ) ) : 'all';
$code_types = isset( $_POST['wpcode_export_code_type'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['wpcode_export_code_type'] ) ) : array();
$tags = isset( $_POST['wpcode_export_tags'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['wpcode_export_tags'] ) ) : array();
if ( 'all' === $status ) {
$status = array(
'publish',
'draft',
);
}
$tax_query = array();
if ( ! empty( $code_types ) ) {
$tax_query[] = array(
'taxonomy' => 'wpcode_type',
'terms' => $code_types,
);
}
if ( ! empty( $tags ) ) {
$tax_query[] = array(
'taxonomy' => 'wpcode_tags',
'terms' => $tags,
);
}
$query_args = array(
'post_type' => 'wpcode',
'post_status' => $status,
'nopaging' => true,
);
if ( ! empty( $tax_query ) ) {
$query_args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
}
$export = array();
$snippets = get_posts( $query_args );
foreach ( $snippets as $snippet ) {
$snippet = new WPCode_Snippet( $snippet );
$snippet_data = $snippet->get_data_for_caching();
$snippet_data['tags'] = $snippet->get_tags();
$snippet_data['note'] = $snippet->get_note();
$snippet_data['cloud_id'] = $snippet->get_cloud_id();
$snippet_data['custom_shortcode'] = $snippet->get_custom_shortcode();
$export[] = apply_filters( 'wpcode_export_snippet_data', $snippet_data, $snippet );
}
$export = array_reverse( $export );
ignore_user_abort( true );
nocache_headers();
header( 'Content-Type: application/json; charset=utf-8' );
header( 'Content-Disposition: attachment; filename=wpcode-snippets-export-' . current_time( 'Y-m-d' ) . '.json' );
header( 'Expires: 0' );
echo wp_json_encode( $export );
exit;
}
/**
* Process import file.
*
* @return void
*/
public function handle_import_file() {
$ext = '';
if ( isset( $_FILES['file']['name'] ) ) {
$ext = strtolower( pathinfo( sanitize_text_field( wp_unslash( $_FILES['file']['name'] ) ), PATHINFO_EXTENSION ) );
}
if ( 'json' !== $ext ) {
wp_die(
esc_html__( 'Please upload a valid .json snippets export file.', 'insert-headers-and-footers' ),
esc_html__( 'Error', 'insert-headers-and-footers' ),
array(
'response' => 400,
)
);
}
$tmp_name = isset( $_FILES['file']['tmp_name'] ) ? sanitize_text_field( $_FILES['file']['tmp_name'] ) : ''; //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- wp_unslash() breaks upload on Windows.
$snippets = json_decode( $this->remove_utf8_bom( file_get_contents( $tmp_name ) ), true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
if ( empty( $snippets ) || ! is_array( $snippets ) ) {
wp_die(
esc_html__( 'Snippets data cannot be imported.', 'insert-headers-and-footers' ),
esc_html__( 'Error', 'insert-headers-and-footers' ),
array(
'response' => 400,
)
);
}
foreach ( $snippets as $snippet ) {
if ( empty( $snippet['code_type'] ) ) {
// Just a minimal check that we have some required fields.
continue;
}
if ( isset( $snippet['id'] ) ) {
// We don't want to update existing snippets/posts.
unset( $snippet['id'] );
}
$snippet = apply_filters( 'wpcode_import_snippet_data', $snippet );
$snippet['code'] = isset( $snippet['code'] ) ? wp_slash( $snippet['code'] ) : '';
$new_snippet = new WPCode_Snippet( $snippet );
$new_snippet->save();
}
wp_safe_redirect(
add_query_arg( 'message', 1, $this->get_page_action_url() )
);
exit;
}
/**
* Remove UTF-8 BOM signature if it is present.
*
* @param string $string String to process.
*
* @return string
*/
public function remove_utf8_bom( $string ) {
if ( strpos( bin2hex( $string ), 'efbbbf' ) === 0 ) {
$string = substr( $string, 3 );
}
return $string;
}
/**
* Templates used by the importer in JS.
*
* @return void
*/
public function importer_templates() {
?>
site_info();
$data .= $this->wp_info();
$data .= $this->uploads_info();
$data .= $this->plugins_info();
$data .= $this->server_info();
$data .= "\n" . '### End System Info ###';
return $data;
}
/**
* Get Site info.
*
* @return string
*/
private function site_info() {
$data = "\n" . '-- Site Info' . "\n\n";
$data .= 'Site URL: ' . site_url() . "\n";
$data .= 'Home URL: ' . home_url() . "\n";
$data .= 'Multisite: ' . ( is_multisite() ? 'Yes' : 'No' ) . "\n";
return $data;
}
/**
* Get WordPress Configuration info.
*
* @return string
*/
private function wp_info() {
global $wpdb;
$theme_data = wp_get_theme();
$theme = $theme_data->name . ' ' . $theme_data->version;
$data = "\n" . '-- WordPress Configuration' . "\n\n";
$data .= 'Version: ' . get_bloginfo( 'version' ) . "\n";
$data .= 'Language: ' . get_locale() . "\n";
$data .= 'User Language: ' . get_user_locale() . "\n";
$data .= 'Permalink Structure: ' . ( get_option( 'permalink_structure' ) ? get_option( 'permalink_structure' ) : 'Default' ) . "\n";
$data .= 'Active Theme: ' . $theme . "\n";
$data .= 'Show On Front: ' . get_option( 'show_on_front' ) . "\n";
// Only show page specs if front page is set to 'page'.
if ( get_option( 'show_on_front' ) === 'page' ) {
$front_page_id = get_option( 'page_on_front' );
$blog_page_id = get_option( 'page_for_posts' );
$data .= 'Page On Front: ' . ( $front_page_id ? get_the_title( $front_page_id ) . ' (#' . $front_page_id . ')' : 'Unset' ) . "\n";
$data .= 'Page For Posts: ' . ( $blog_page_id ? get_the_title( $blog_page_id ) . ' (#' . $blog_page_id . ')' : 'Unset' ) . "\n";
}
$data .= 'ABSPATH: ' . ABSPATH . "\n";
$data .= 'Table Prefix: ' . 'Length: ' . strlen( $wpdb->prefix ) . ' Status: ' . ( strlen( $wpdb->prefix ) > 16 ? 'ERROR: Too long' : 'Acceptable' ) . "\n"; //phpcs:ignore
$data .= 'WP_DEBUG: ' . ( defined( 'WP_DEBUG' ) ? WP_DEBUG ? 'Enabled' : 'Disabled' : 'Not set' ) . "\n";
$data .= 'Memory Limit: ' . WP_MEMORY_LIMIT . "\n";
$data .= 'Registered Post Stati: ' . implode( ', ', get_post_stati() ) . "\n";
$data .= 'Revisions: ' . ( WP_POST_REVISIONS ? WP_POST_REVISIONS > 1 ? 'Limited to ' . WP_POST_REVISIONS : 'Enabled' : 'Disabled' ) . "\n";
return $data;
}
/**
* Get Uploads/Constants info.
*
* @return string
*/
private function uploads_info() {
$data = "\n" . '-- WordPress Uploads/Constants' . "\n\n";
$data .= 'WP_CONTENT_DIR: ' . ( defined( 'WP_CONTENT_DIR' ) ? WP_CONTENT_DIR ? WP_CONTENT_DIR : 'Disabled' : 'Not set' ) . "\n";
$data .= 'WP_CONTENT_URL: ' . ( defined( 'WP_CONTENT_URL' ) ? WP_CONTENT_URL ? WP_CONTENT_URL : 'Disabled' : 'Not set' ) . "\n";
$data .= 'UPLOADS: ' . ( defined( 'UPLOADS' ) ? UPLOADS ? UPLOADS : 'Disabled' : 'Not set' ) . "\n";
$uploads_dir = wp_upload_dir();
$data .= 'wp_uploads_dir() path: ' . $uploads_dir['path'] . "\n";
$data .= 'wp_uploads_dir() url: ' . $uploads_dir['url'] . "\n";
$data .= 'wp_uploads_dir() basedir: ' . $uploads_dir['basedir'] . "\n";
$data .= 'wp_uploads_dir() baseurl: ' . $uploads_dir['baseurl'] . "\n";
return $data;
}
/**
* Get Plugins info.
*
* @return string
*/
private function plugins_info() {
// Get plugins that have an update.
$data = $this->mu_plugins();
$data .= $this->installed_plugins();
$data .= $this->multisite_plugins();
return $data;
}
/**
* Get MU Plugins info.
*
* @return string
*/
private function mu_plugins() {
$data = '';
// Must-use plugins.
// NOTE: MU plugins can't show updates!
$muplugins = get_mu_plugins();
if ( ! empty( $muplugins ) && count( $muplugins ) > 0 ) {
$data = "\n" . '-- Must-Use Plugins' . "\n\n";
foreach ( $muplugins as $plugin => $plugin_data ) {
$data .= $plugin_data['Name'] . ': ' . $plugin_data['Version'] . "\n";
}
}
return $data;
}
/**
* Get Installed Plugins info.
*
* @return string
*/
private function installed_plugins() {
$updates = get_plugin_updates();
// WordPress active plugins.
$data = "\n" . '-- WordPress Active Plugins' . "\n\n";
$plugins = get_plugins();
$active_plugins = get_option( 'active_plugins', array() );
foreach ( $plugins as $plugin_path => $plugin ) {
if ( ! in_array( $plugin_path, $active_plugins, true ) ) {
continue;
}
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
$data .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
}
// WordPress inactive plugins.
$data .= "\n" . '-- WordPress Inactive Plugins' . "\n\n";
foreach ( $plugins as $plugin_path => $plugin ) {
if ( in_array( $plugin_path, $active_plugins, true ) ) {
continue;
}
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
$data .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
}
return $data;
}
/**
* Get Multisite Plugins info.
*
* @return string
*/
private function multisite_plugins() {
$data = '';
if ( ! is_multisite() ) {
return $data;
}
$updates = get_plugin_updates();
// WordPress Multisite active plugins.
$data = "\n" . '-- Network Active Plugins' . "\n\n";
$plugins = wp_get_active_network_plugins();
$active_plugins = get_site_option( 'active_sitewide_plugins', array() );
foreach ( $plugins as $plugin_path ) {
$plugin_base = plugin_basename( $plugin_path );
if ( ! array_key_exists( $plugin_base, $active_plugins ) ) {
continue;
}
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
$plugin = get_plugin_data( $plugin_path );
$data .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
}
return $data;
}
/**
* Get Server info.
*
* @return string
*/
private function server_info() {
global $wpdb;
// Server configuration (really just versions).
$data = "\n" . '-- Webserver Configuration' . "\n\n";
$data .= 'PHP Version: ' . PHP_VERSION . "\n";
$data .= 'MySQL Version: ' . $wpdb->db_version() . "\n";
$data .= 'Webserver Info: ' . ( isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '' ) . "\n";
// PHP configs... now we're getting to the important stuff.
$data .= "\n" . '-- PHP Configuration' . "\n\n";
$data .= 'Memory Limit: ' . ini_get( 'memory_limit' ) . "\n";
$data .= 'Upload Max Size: ' . ini_get( 'upload_max_filesize' ) . "\n";
$data .= 'Post Max Size: ' . ini_get( 'post_max_size' ) . "\n";
$data .= 'Upload Max Filesize: ' . ini_get( 'upload_max_filesize' ) . "\n";
$data .= 'Time Limit: ' . ini_get( 'max_execution_time' ) . "\n";
$data .= 'Max Input Vars: ' . ini_get( 'max_input_vars' ) . "\n";
$data .= 'Display Errors: ' . ( ini_get( 'display_errors' ) ? 'On (' . ini_get( 'display_errors' ) . ')' : 'N/A' ) . "\n";
// PHP extensions and such.
$data .= "\n" . '-- PHP Extensions' . "\n\n";
$data .= 'cURL: ' . ( function_exists( 'curl_init' ) ? 'Supported' : 'Not Supported' ) . "\n";
$data .= 'fsockopen: ' . ( function_exists( 'fsockopen' ) ? 'Supported' : 'Not Supported' ) . "\n";
$data .= 'SOAP Client: ' . ( class_exists( 'SoapClient', false ) ? 'Installed' : 'Not Installed' ) . "\n";
$data .= 'Suhosin: ' . ( extension_loaded( 'suhosin' ) ? 'Installed' : 'Not Installed' ) . "\n";
// Session stuff.
$data .= "\n" . '-- Session Configuration' . "\n\n";
$data .= 'Session: ' . ( isset( $_SESSION ) ? 'Enabled' : 'Disabled' ) . "\n";
// The rest of this is only relevant if session is enabled.
if ( isset( $_SESSION ) ) {
$data .= 'Session Name: ' . esc_html( ini_get( 'session.name' ) ) . "\n";
$data .= 'Cookie Path: ' . esc_html( ini_get( 'session.cookie_path' ) ) . "\n";
$data .= 'Save Path: ' . esc_html( ini_get( 'session.save_path' ) ) . "\n";
$data .= 'Use Cookies: ' . ( ini_get( 'session.use_cookies' ) ? 'On' : 'Off' ) . "\n";
$data .= 'Use Only Cookies: ' . ( ini_get( 'session.use_only_cookies' ) ? 'On' : 'Off' ) . "\n";
}
return $data;
}
/**
* Output the log viewer.
*
* @return void
*/
public function output_view_logs() {
if ( ! current_user_can( 'wpcode_edit_php_snippets' ) ) {
echo '' . esc_html__( 'You do not have sufficient permissions to view logs.', 'insert-headers-and-footers' ) . '
';
return;
}
$logs = wpcode()->logger->get_logs();
if ( empty( $logs ) ) {
echo '';
printf(
// translators: %1$s: opening anchor tag, %2$s: closing anchor tag.
esc_html__( 'No logs found. You can enable logging from the %1$ssettings panel%2$s.', 'insert-headers-and-footers' ),
'',
''
);
echo '
';
return;
}
$selected_log = $logs[0]['path'];
$selected_log_name = $logs[0]['filename'];
if ( isset( $_POST['log'] ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_POST['_wpnonce'] ), 'wpcode_view_log' ) ) {
$selected_log_name = sanitize_text_field( wp_unslash( $_POST['log'] ) );
// Find the log file path.
foreach ( $logs as $log ) {
if ( $log['filename'] === $selected_log_name ) {
$selected_log = $log['path'];
break;
}
}
}
// Load the selected log.
$log_content = file_get_contents( $selected_log ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
$delete_log_url = wp_nonce_url(
add_query_arg(
array(
'wpcode_action' => 'delete_log',
'log' => str_replace( '.log', '', $selected_log_name ),
),
$this->get_page_action_url()
),
'wpcode_delete_log'
);
// Log picker form.
?>
' . esc_html__( 'You do not have sufficient permissions to delete logs.', 'insert-headers-and-footers' ) . '';
return;
}
wpcode()->logger->delete_log( sanitize_key( wp_unslash( $_GET['log'] ) ) );
wp_safe_redirect( $this->get_page_action_url() );
exit;
}
/**
* Add tools-specific strings to the JS strings object.
*
* @param array $data The strings object.
*
* @return array
*/
public function add_tools_strings( $data ) {
$data['confirm_delete_log'] = __( 'Are you sure you want to delete this log?', 'insert-headers-and-footers' );
return $data;
}
}