add wp-rocket

This commit is contained in:
nguyen dung
2022-02-18 19:09:35 +07:00
parent 39b8cb3612
commit 3110d00ee7
927 changed files with 271703 additions and 2 deletions

View File

@@ -0,0 +1,172 @@
<?php
namespace WP_Rocket\Admin\Database;
use WP_Rocket_WP_Background_Process;
/**
* Extends the background process class for the database optimization background process.
*
* @since 2.11
*
* @see WP_Background_Process
*/
class Optimization_Process extends WP_Rocket_WP_Background_Process {
/**
* Prefix
*
* @var string
* @access protected
*/
protected $prefix = 'rocket';
/**
* Specific action identifier for sitemap preload.
*
* @access protected
* @var string Action identifier
*/
protected $action = 'database_optimization';
/**
* Count the number of optimized items.
*
* @access protected
* @var array $count An array of indexed number of optimized items.
*/
protected $count = [];
/**
* Dispatch
*
* @access public
* @return array|WP_Error
*/
public function dispatch() {
set_transient( 'rocket_database_optimization_process', 'running', HOUR_IN_SECONDS );
// Perform remote post.
return parent::dispatch();
}
/**
* Perform the optimization corresponding to $item
*
* @param mixed $item Queue item to iterate over.
*
* @return bool false
*/
protected function task( $item ) {
global $wpdb;
switch ( $item ) {
case 'database_revisions':
$query = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type = 'revision'" );
if ( $query ) {
$number = 0;
foreach ( $query as $id ) {
$number += wp_delete_post_revision( intval( $id ) ) instanceof \WP_Post ? 1 : 0;
}
$this->count[ $item ] = $number;
}
break;
case 'database_auto_drafts':
$query = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft'" );
if ( $query ) {
$number = 0;
foreach ( $query as $id ) {
$number += wp_delete_post( intval( $id ), true ) instanceof \WP_Post ? 1 : 0;
}
$this->count[ $item ] = $number;
}
break;
case 'database_trashed_posts':
$query = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'trash'" );
if ( $query ) {
$number = 0;
foreach ( $query as $id ) {
$number += wp_delete_post( $id, true ) instanceof \WP_Post ? 1 : 0;
}
$this->count[ $item ] = $number;
}
break;
case 'database_spam_comments':
$query = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments WHERE comment_approved = 'spam'" );
if ( $query ) {
$number = 0;
foreach ( $query as $id ) {
$number += (int) wp_delete_comment( intval( $id ), true );
}
$this->count[ $item ] = $number;
}
break;
case 'database_trashed_comments':
$query = $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments WHERE (comment_approved = 'trash' OR comment_approved = 'post-trashed')" );
if ( $query ) {
$number = 0;
foreach ( $query as $id ) {
$number += (int) wp_delete_comment( intval( $id ), true );
}
$this->count[ $item ] = $number;
}
break;
case 'database_expired_transients':
$time = isset( $_SERVER['REQUEST_TIME'] ) ? (int) $_SERVER['REQUEST_TIME'] : time();
$query = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s AND option_value < %d", $wpdb->esc_like( '_transient_timeout' ) . '%', $time ) );
if ( $query ) {
$number = 0;
foreach ( $query as $transient ) {
$key = str_replace( '_transient_timeout_', '', $transient );
$number += (int) delete_transient( $key );
}
$this->count[ $item ] = $number;
}
break;
case 'database_all_transients':
$query = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s", $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_site_transient_' ) . '%' ) );
if ( $query ) {
$number = 0;
foreach ( $query as $transient ) {
if ( strpos( $transient, '_site_transient_' ) !== false ) {
$number += (int) delete_site_transient( str_replace( '_site_transient_', '', $transient ) );
} else {
$number += (int) delete_transient( str_replace( '_transient_', '', $transient ) );
}
}
$this->count[ $item ] = $number;
}
break;
case 'database_optimize_tables':
$query = $wpdb->get_results( "SELECT table_name, data_free FROM information_schema.tables WHERE table_schema = '" . DB_NAME . "' and Engine <> 'InnoDB' and data_free > 0" );
if ( $query ) {
$number = 0;
foreach ( $query as $table ) {
$number += (int) $wpdb->query( "OPTIMIZE TABLE $table->table_name" );
}
$this->count[ $item ] = $number;
}
break;
}
return false;
}
/**
* Complete
*/
protected function complete() {
delete_transient( 'rocket_database_optimization_process' );
set_transient( 'rocket_database_optimization_process_complete', $this->count );
parent::complete();
}
}

View File

@@ -0,0 +1,126 @@
<?php
namespace WP_Rocket\Admin\Database;
defined( 'ABSPATH' ) || exit;
/**
* Handles the database optimization process.
*
* @since 2.11
* @author Remy Perona
*/
class Optimization {
/**
* Background process instance
*
* @since 2.11
* @var Optimization_Process $process Background Process instance.
* @access protected
*/
protected $process;
/**
* Array of option name/label pairs.
*
* @var array
* @access private
*/
private $options;
/**
* Class constructor.
*
* @since 2.11
* @author Remy Perona
*
* @param Optimization_Process $process Background process instance.
*/
public function __construct( Optimization_Process $process ) {
$this->process = $process;
$this->options = [
'database_revisions' => __( 'Revisions', 'rocket' ),
'database_auto_drafts' => __( 'Auto Drafts', 'rocket' ),
'database_trashed_posts' => __( 'Trashed Posts', 'rocket' ),
'database_spam_comments' => __( 'Spam Comments', 'rocket' ),
'database_trashed_comments' => __( 'Trashed Comments', 'rocket' ),
'database_expired_transients' => __( 'Expired transients', 'rocket' ),
'database_all_transients' => __( 'Transients', 'rocket' ),
'database_optimize_tables' => __( 'Tables', 'rocket' ),
];
}
/**
* Get Database options
*
* @since 3.0.4
* @author Remy Perona
*
* @return array
*/
public function get_options() {
return $this->options;
}
/**
* Performs the database optimization
*
* @since 2.11
* @author Remy Perona
*
* @param array $options WP Rocket Database options.
*/
public function process_handler( $options ) {
if ( method_exists( $this->process, 'cancel_process' ) ) {
$this->process->cancel_process();
}
array_map( [ $this->process, 'push_to_queue' ], $options );
$this->process->save()->dispatch();
}
/**
* Count the number of items concerned by the database cleanup
*
* @since 2.8
* @author Remy Perona
*
* @param string $type Item type to count.
* @return int Number of items for this type
*/
public function count_cleanup_items( $type ) {
global $wpdb;
$count = 0;
switch ( $type ) {
case 'database_revisions':
$count = $wpdb->get_var( "SELECT COUNT(ID) FROM $wpdb->posts WHERE post_type = 'revision'" );
break;
case 'database_auto_drafts':
$count = $wpdb->get_var( "SELECT COUNT(ID) FROM $wpdb->posts WHERE post_status = 'auto-draft'" );
break;
case 'database_trashed_posts':
$count = $wpdb->get_var( "SELECT COUNT(ID) FROM $wpdb->posts WHERE post_status = 'trash'" );
break;
case 'database_spam_comments':
$count = $wpdb->get_var( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = 'spam'" );
break;
case 'database_trashed_comments':
$count = $wpdb->get_var( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE (comment_approved = 'trash' OR comment_approved = 'post-trashed')" );
break;
case 'database_expired_transients':
$time = isset( $_SERVER['REQUEST_TIME'] ) ? (int) $_SERVER['REQUEST_TIME'] : time();
$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(option_name) FROM $wpdb->options WHERE option_name LIKE %s AND option_value < %d", $wpdb->esc_like( '_transient_timeout' ) . '%', $time ) );
break;
case 'database_all_transients':
$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(option_id) FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s", $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_site_transient_' ) . '%' ) );
break;
case 'database_optimize_tables':
$count = $wpdb->get_var( "SELECT COUNT(table_name) FROM information_schema.tables WHERE table_schema = '" . DB_NAME . "' and Engine <> 'InnoDB' and data_free > 0" );
break;
}
return $count;
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace WP_Rocket\Admin;
defined( 'ABSPATH' ) || exit;
/**
* Manages options using the WordPress options API.
*
* @since 3.0
* @author Remy Perona
*/
abstract class Abstract_Options {
/**
* Gets the option for the given name. Returns the default value if the value does not exist.
*
* @since 3.0
* @author Remy Perona
*
* @param string $name Name of the option to get.
* @param mixed $default Default value to return if the value does not exist.
*
* @return mixed
*/
abstract public function get( $name, $default = null );
/**
* Sets the value of an option. Update the value if the option for the given name already exists.
*
* @since 3.0
* @author Remy Perona
* @param string $name Name of the option to set.
* @param mixed $value Value to set for the option.
*
* @return void
*/
abstract public function set( $name, $value );
/**
* Deletes the option with the given name.
*
* @since 3.0
* @author Remy Perona
*
* @param string $name Name of the option to delete.
*
* @return void
*/
abstract public function delete( $name );
/**
* Checks if the option with the given name exists.
*
* @since 3.0
* @author Remy Perona
*
* @param string $name Name of the option to check.
*
* @return boolean True if the option exists, false otherwise
*/
public function has( $name ) {
return null !== $this->get( $name );
}
}

View File

@@ -0,0 +1,183 @@
<?php
namespace WP_Rocket\Admin;
use WP_Rocket\Logger\Logger;
use WP_Rocket\Event_Management\Subscriber_Interface;
defined( 'ABSPATH' ) || exit;
/**
* Class that handles few things about the logs.
*
* @since 3.1.4
* @author Grégory Viguier
*/
class Logs implements Subscriber_Interface {
/**
* Returns an array of events that this subscriber wants to listen to.
*
* @since 3.1.4
* @access public
* @author Grégory Viguier
*
* @return array
*/
public static function get_subscribed_events() {
return [
'pre_update_option_' . WP_ROCKET_SLUG => [ 'enable_debug', 10, 2 ],
'admin_post_rocket_download_debug_file' => 'download_debug_file',
'admin_post_rocket_delete_debug_file' => 'delete_debug_file',
];
}
/** ----------------------------------------------------------------------------------------- */
/** DEBUG ACTIVATION ======================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Enable or disable the debug mode when settings are saved.
*
* @since 3.1.4
* @access public
* @author Grégory Viguier
*
* @param array $newvalue An array of submitted options values.
* @param array $oldvalue An array of previous options values.
* @return array Updated submitted options values.
*/
public function enable_debug( $newvalue, $oldvalue ) {
if ( empty( $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
return $newvalue;
}
if ( ! empty( $newvalue['debug_enabled'] ) ) {
Logger::enable_debug();
} else {
Logger::disable_debug();
}
unset( $newvalue['debug_enabled'] );
return $newvalue;
}
/** ----------------------------------------------------------------------------------------- */
/** ADMIN POST CALLBACKS ==================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Download the log file.
*
* @since 3.1.4
* @access public
* @author Grégory Viguier
*/
public function download_debug_file() {
if ( ! $this->verify_nonce( 'download_debug_file' ) ) {
wp_nonce_ays( '' );
}
if ( ! $this->current_user_can() ) {
$this->redirect();
}
$contents = Logger::get_log_file_contents();
if ( is_wp_error( $contents ) ) {
add_settings_error( 'general', $contents->get_error_code(), $contents->get_error_message(), 'error' );
set_transient( 'settings_errors', get_settings_errors(), 30 );
$this->redirect( add_query_arg( 'settings-updated', 1, wp_get_referer() ) );
}
$file_name = Logger::get_log_file_path();
$file_name = basename( $file_name, '.log' ) . Logger::get_log_file_extension();
nocache_headers();
@header( 'Content-Type: text/x-log' );
@header( 'Content-Disposition: attachment; filename="' . $file_name . '"' );
@header( 'Content-Transfer-Encoding: binary' );
@header( 'Content-Length: ' . strlen( $contents ) );
@header( 'Connection: close' );
echo $contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
exit();
}
/**
* Delete the log file.
*
* @since 3.1.4
* @access public
* @author Grégory Viguier
*/
public function delete_debug_file() {
if ( ! $this->verify_nonce( 'delete_debug_file' ) ) {
wp_nonce_ays( '' );
}
if ( ! $this->current_user_can() ) {
$this->redirect();
}
if ( ! Logger::delete_log_file() ) {
add_settings_error( 'general', 'debug_file_not_deleted', __( 'The debug file could not be deleted.', 'rocket' ), 'error' );
set_transient( 'settings_errors', get_settings_errors(), 30 );
$this->redirect( add_query_arg( 'settings-updated', 1, wp_get_referer() ) );
}
// Done.
$this->redirect();
}
/** ----------------------------------------------------------------------------------------- */
/** TOOLS =================================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Verify the nonce sent in $_GET['_wpnonce'].
*
* @since 3.1.4
* @access protected
* @author Grégory Viguier
*
* @param string $nonce_name The nonce name.
* @return bool
*/
protected function verify_nonce( $nonce_name ) {
return isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], $nonce_name ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
}
/**
* Tell if the current user can operate.
*
* @since 3.1.4
* @access protected
* @author Grégory Viguier
*
* @return bool
*/
protected function current_user_can() {
return current_user_can( 'rocket_manage_options' );
}
/**
* Redirect the user.
*
* @since 3.1.4
* @access protected
* @author Grégory Viguier
*
* @param string $redirect URL to redirect the user to.
*/
protected function redirect( $redirect = null ) {
if ( empty( $redirect ) ) {
$redirect = wp_get_referer();
}
wp_safe_redirect( esc_url_raw( $redirect ) );
die();
}
}

View File

@@ -0,0 +1,124 @@
<?php
namespace WP_Rocket\Admin;
/**
* Manages the data inside an option.
*
* @since 3.0
* @author Remy Perona
*/
class Options_Data {
/**
* Option data
*
* @var Array Array of data inside the option
*/
private $options;
/**
* Constructor
*
* @param Array $options Array of data coming from an option.
*/
public function __construct( $options ) {
$this->options = $options;
}
/**
* Checks if the provided key exists in the option data array.
*
* @since 3.0
* @author Remy Perona
*
* @param string $key key name.
* @return boolean true if it exists, false otherwise
*/
public function has( $key ) {
return isset( $this->options[ $key ] );
}
/**
* Gets the value associated with a specific key.
*
* @since 3.0
* @author Remy Perona
*
* @param string $key key name.
* @param mixed $default default value to return if key doesn't exist.
* @return mixed
*/
public function get( $key, $default = '' ) {
/**
* Pre-filter any WP Rocket option before read
*
* @since 2.5
*
* @param mixed $default The default value.
*/
$value = apply_filters( 'pre_get_rocket_option_' . $key, null, $default ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
if ( null !== $value ) {
return $value;
}
if ( 'consumer_key' === $key && rocket_has_constant( 'WP_ROCKET_KEY' ) ) {
return WP_ROCKET_KEY;
} elseif ( 'consumer_email' === $key && rocket_has_constant( 'WP_ROCKET_EMAIL' ) ) {
return WP_ROCKET_EMAIL;
}
if ( ! $this->has( $key ) ) {
return $default;
}
/**
* Filter any WP Rocket option after read
*
* @since 2.5
*
* @param mixed $default The default value.
*/
return apply_filters( 'get_rocket_option_' . $key, $this->options[ $key ], $default ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
}
/**
* Sets the value associated with a specific key.
*
* @since 3.0
* @author Remy Perona
*
* @param string $key key name.
* @param mixed $value to set.
* @return void
*/
public function set( $key, $value ) {
$this->options[ $key ] = $value;
}
/**
* Sets multiple values.
*
* @since 3.0
* @author Remy Perona
*
* @param array $options An array of key/value pairs to set.
* @return void
*/
public function set_values( $options ) {
foreach ( $options as $key => $value ) {
$this->set( $key, $value );
}
}
/**
* Gets the option array.
*
* @since 3.0
* @author Remy Perona
*
* @return array
*/
public function get_options() {
return $this->options;
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace WP_Rocket\Admin;
/**
* Manages options using the WordPress options API.
*
* @since 3.0
* @author Remy Perona
*/
class Options extends Abstract_Options {
/**
* The prefix used by WP Rocket options.
*
* @since 3.0
* @author Remy Perona
*
* @var string
*/
private $prefix;
/**
* Constructor
*
* @since 3.0
* @author Remy Perona
*
* @param string $prefix WP Rocket options prefix.
*/
public function __construct( $prefix = '' ) {
$this->prefix = $prefix;
}
/**
* Gets the option name used to store the option in the WordPress database.
*
* @since 3.0
* @author Remy Perona
*
* @param string $name Unprefixed name of the option.
*
* @return string Option name used to store it
*/
public function get_option_name( $name ) {
return $this->prefix . $name;
}
/**
* Gets the option for the given name. Returns the default value if the value does not exist.
*
* @since 3.0
* @author Remy Perona
*
* @param string $name Name of the option to get.
* @param mixed $default Default value to return if the value does not exist.
*
* @return mixed
*/
public function get( $name, $default = null ) {
$option = get_option( $this->get_option_name( $name ), $default );
if ( is_array( $default ) && ! is_array( $option ) ) {
$option = (array) $option;
}
return $option;
}
/**
* Sets the value of an option. Update the value if the option for the given name already exists.
*
* @since 3.0
* @author Remy Perona
* @param string $name Name of the option to set.
* @param mixed $value Value to set for the option.
*
* @return void
*/
public function set( $name, $value ) {
update_option( $this->get_option_name( $name ), $value );
}
/**
* Deletes the option with the given name.
*
* @since 3.0
* @author Remy Perona
*
* @param string $name Name of the option to delete.
*
* @return void
*/
public function delete( $name ) {
delete_option( $this->get_option_name( $name ) );
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace WP_Rocket\Admin\Deactivation;
use WP_Rocket\Abstract_Render;
defined( 'ABSPATH' ) || exit;
/**
* Handles rendering of deactivation intent form on plugins page
*
* @since 3.0
* @author Remy Perona
*/
class Render extends Abstract_Render {
/**
* Renders Deactivation intent form
*
* @since 3.0
* @author Remy Perona
*
* @return void
*/
public function render_form() {
$args = [
'deactivation_url' => wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . rawurlencode( 'wp-rocket/wp-rocket.php' ), 'deactivate-plugin_wp-rocket/wp-rocket.php' ),
];
echo $this->generate( 'form', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
}
}