add wp-rocket
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Activation;
|
||||
|
||||
use WP_Rocket\Engine\Container\Container;
|
||||
use WP_Rocket\ThirdParty\Hostings\HostResolver;
|
||||
|
||||
/**
|
||||
* Plugin activation controller
|
||||
*
|
||||
* @since 3.6.3
|
||||
*/
|
||||
class Activation {
|
||||
/**
|
||||
* Aliases in the container for each class that needs to call its activate method
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $activators = [
|
||||
'advanced_cache',
|
||||
'capabilities_manager',
|
||||
'wp_cache',
|
||||
];
|
||||
|
||||
/**
|
||||
* Performs these actions during the plugin activation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function activate_plugin() {
|
||||
$container = new Container();
|
||||
|
||||
$container->add( 'template_path', WP_ROCKET_PATH . 'views' );
|
||||
$container->addServiceProvider( 'WP_Rocket\Engine\Activation\ServiceProvider' );
|
||||
$container->addServiceProvider( 'WP_Rocket\ThirdParty\Hostings\ServiceProvider' );
|
||||
|
||||
$host_type = HostResolver::get_host_service();
|
||||
|
||||
if ( ! empty( $host_type ) ) {
|
||||
array_unshift( self::$activators, $host_type );
|
||||
}
|
||||
|
||||
foreach ( self::$activators as $activator ) {
|
||||
$container->get( $activator );
|
||||
}
|
||||
|
||||
// Last constants.
|
||||
define( 'WP_ROCKET_PLUGIN_NAME', 'WP Rocket' );
|
||||
define( 'WP_ROCKET_PLUGIN_SLUG', sanitize_key( WP_ROCKET_PLUGIN_NAME ) );
|
||||
|
||||
if ( defined( 'SUNRISE' ) && SUNRISE === 'on' && function_exists( 'domain_mapping_siteurl' ) ) {
|
||||
require WP_ROCKET_INC_PATH . 'domain-mapping.php';
|
||||
}
|
||||
|
||||
require WP_ROCKET_FUNCTIONS_PATH . 'options.php';
|
||||
require WP_ROCKET_FUNCTIONS_PATH . 'formatting.php';
|
||||
require WP_ROCKET_FUNCTIONS_PATH . 'i18n.php';
|
||||
require WP_ROCKET_FUNCTIONS_PATH . 'htaccess.php';
|
||||
|
||||
if ( class_exists( 'WPaaS\Plugin' ) ) {
|
||||
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/godaddy.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* WP Rocket activation.
|
||||
*
|
||||
* @since 3.1.5
|
||||
*/
|
||||
do_action( 'rocket_activation' );
|
||||
|
||||
if ( rocket_valid_key() ) {
|
||||
// Add All WP Rocket rules of the .htaccess file.
|
||||
flush_rocket_htaccess();
|
||||
}
|
||||
|
||||
// Create the cache folders (wp-rocket & min).
|
||||
rocket_init_cache_dir();
|
||||
|
||||
// Create the config folder (wp-rocket-config).
|
||||
rocket_init_config_dir();
|
||||
|
||||
// Update customer key & licence.
|
||||
wp_remote_get(
|
||||
WP_ROCKET_WEB_API . 'activate-licence.php',
|
||||
[
|
||||
'blocking' => false,
|
||||
]
|
||||
);
|
||||
|
||||
wp_remote_get(
|
||||
home_url(),
|
||||
[
|
||||
'timeout' => 0.01,
|
||||
'blocking' => false,
|
||||
'user-agent' => 'WP Rocket/Homepage Preload',
|
||||
'sslverify' => apply_filters( 'https_local_ssl_verify', false ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Activation;
|
||||
|
||||
interface ActivationInterface {
|
||||
/**
|
||||
* Executes this method on plugin activation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function activate();
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Activation;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\BootableServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* Service Provider for the activation process.
|
||||
*
|
||||
* @since 3.6.3
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider implements BootableServiceProviderInterface {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'advanced_cache',
|
||||
'capabilities_manager',
|
||||
'wp_cache',
|
||||
];
|
||||
|
||||
/**
|
||||
* Executes this method when the service provider is registered
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot() {
|
||||
$this->getContainer()
|
||||
->inflector( 'WP_Rocket\Engine\Activation\ActivationInterface' )
|
||||
->invokeMethod( 'activate', [] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the option array in the container.
|
||||
*/
|
||||
public function register() {
|
||||
$filesystem = rocket_direct_filesystem();
|
||||
|
||||
$this->getContainer()->add( 'advanced_cache', 'WP_Rocket\Engine\Cache\AdvancedCache' )
|
||||
->withArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' )
|
||||
->withArgument( $filesystem );
|
||||
$this->getContainer()->add( 'capabilities_manager', 'WP_Rocket\Engine\Capabilities\Manager' );
|
||||
$this->getContainer()->add( 'wp_cache', 'WP_Rocket\Engine\Cache\WPCache' )
|
||||
->withArgument( $filesystem );
|
||||
}
|
||||
}
|
630
wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/Beacon.php
Normal file
630
wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/Beacon.php
Normal file
@@ -0,0 +1,630 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Admin\Beacon;
|
||||
|
||||
use WP_Rocket\Abstract_Render;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Engine\Support\Data;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Helpscout Beacon integration
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class Beacon extends Abstract_Render implements Subscriber_Interface {
|
||||
/**
|
||||
* Options_Data instance
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @var Options_Data $options
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Current user locale
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @var string $locale
|
||||
*/
|
||||
private $locale;
|
||||
|
||||
/**
|
||||
* Support data instance
|
||||
*
|
||||
* @var Data
|
||||
*/
|
||||
private $support_data;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @param Options_Data $options Options instance.
|
||||
* @param string $template_path Absolute path to the views/settings.
|
||||
* @param Data $support_data Support data instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options, $template_path, Data $support_data ) {
|
||||
parent::__construct( $template_path );
|
||||
|
||||
$this->options = $options;
|
||||
$this->support_data = $support_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'admin_print_footer_scripts-settings_page_wprocket' => 'insert_script',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures and returns beacon javascript
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function insert_script() {
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( $this->get_user_locale() ) {
|
||||
case 'fr':
|
||||
$form_id = '9db9417a-5e2f-41dd-8857-1421d5112aea';
|
||||
break;
|
||||
default:
|
||||
$form_id = '44cc73fb-7636-4206-b115-c7b33823551b';
|
||||
break;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'form_id' => $form_id,
|
||||
'identify' => wp_json_encode( $this->identify_data() ),
|
||||
'session' => wp_json_encode( $this->support_data->get_support_data() ),
|
||||
'prefill' => wp_json_encode( $this->prefill_data() ),
|
||||
];
|
||||
|
||||
echo $this->generate( 'beacon', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the locale property with the current user locale if not set yet
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_user_locale() {
|
||||
if ( ! isset( $this->locale ) ) {
|
||||
$this->locale = current( array_slice( explode( '_', get_user_locale() ), 0, 1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the locale ID for Beacon
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $locale The locale ID.
|
||||
*/
|
||||
return apply_filters( 'rocket_beacon_locale', $this->locale );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Identify data to pass to Beacon
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function identify_data() {
|
||||
$identify_data = [
|
||||
'email' => $this->options->get( 'consumer_email' ),
|
||||
'Website' => home_url(),
|
||||
];
|
||||
$customer_data = get_transient( 'wp_rocket_customer_data' );
|
||||
|
||||
if ( false !== $customer_data && isset( $customer_data->status ) ) {
|
||||
$identify_data['status'] = $customer_data->status;
|
||||
}
|
||||
|
||||
return $identify_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns prefill data to pass to Beacon
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function prefill_data() {
|
||||
$prefill_data = [
|
||||
'fields' => [
|
||||
[
|
||||
'id' => 21728,
|
||||
'value' => 108003, // default to nulled.
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$customer_data = get_transient( 'wp_rocket_customer_data' );
|
||||
|
||||
if ( false === $customer_data || ! isset( $customer_data->licence_account ) ) {
|
||||
return $prefill_data;
|
||||
}
|
||||
|
||||
$licenses = [
|
||||
'Single' => 108000,
|
||||
'Plus' => 108001,
|
||||
'Infinite' => 108002,
|
||||
'Unavailable' => 108003,
|
||||
];
|
||||
|
||||
if ( isset( $licenses[ $customer_data->licence_account ] ) ) {
|
||||
$prefill_data['fields'][0]['value'] = $licenses[ $customer_data->licence_account ];
|
||||
}
|
||||
|
||||
return $prefill_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IDs for the HelpScout docs for the corresponding section and language.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $doc_id Section identifier.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function get_suggest( $doc_id ) {
|
||||
$suggest = [
|
||||
'faq' => [
|
||||
'en' => [
|
||||
[
|
||||
'id' => '5569b671e4b027e1978e3c51',
|
||||
'url' => 'https://docs.wp-rocket.me/article/99-pages-are-not-cached-or-css-and-js-minification-are-not-working/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
'title' => 'Pages Are Not Cached or CSS and JS Minification Are Not Working',
|
||||
],
|
||||
[
|
||||
'id' => '556778c8e4b01a224b426fad',
|
||||
'url' => 'https://docs.wp-rocket.me/article/85-google-page-speed-grade-does-not-improve/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
'title' => 'Google PageSpeed Grade does not Improve',
|
||||
],
|
||||
[
|
||||
'id' => '556ef48ce4b01a224b428691',
|
||||
'url' => 'https://docs.wp-rocket.me/article/106-my-site-is-broken/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
'title' => 'My Site Is Broken',
|
||||
],
|
||||
[
|
||||
'id' => '54205957e4b099def9b55df0',
|
||||
'url' => 'https://docs.wp-rocket.me/article/19-resolving-issues-with-file-optimization/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
'title' => 'Resolving Issues with File Optimization',
|
||||
],
|
||||
],
|
||||
'fr' => [
|
||||
[
|
||||
'id' => '5697d2dc9033603f7da31041',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/264-les-pages-ne-sont-pas-mises-en-cache-ou-la-minification-css-et-js-ne-fonctionne-pas/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
'title' => 'Les pages ne sont pas mises en cache, ou la minification CSS et JS ne fonctionne pas',
|
||||
],
|
||||
[
|
||||
'id' => '569564dfc69791436155e0b0',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/218-la-note-google-page-speed-ne-sameliore-pas/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
'title' => "La note Google Page Speed ne s'améliore pas",
|
||||
],
|
||||
[
|
||||
'id' => '5697d03bc69791436155ed69',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/263-site-casse/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
'title' => 'Mon site est cassé',
|
||||
],
|
||||
[
|
||||
'id' => '56967d73c69791436155e637',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/241-problemes-minification/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
'title' => "Résoudre les problèmes avec l'optimisation des fichiers",
|
||||
],
|
||||
],
|
||||
],
|
||||
'user_cache_section' => [
|
||||
'en' => '56b55ba49033600da1c0b687,587920b5c697915403a0e1f4,560c66b0c697917e72165a6d',
|
||||
'fr' => '56cb9ba990336008e9e9e3d9,5879230cc697915403a0e211,569410999033603f7da2fa94',
|
||||
],
|
||||
'user_cache' => [
|
||||
'en' => [
|
||||
'id' => '56b55ba49033600da1c0b687',
|
||||
'url' => 'https://docs.wp-rocket.me/article/313-user-cache/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '56cb9ba990336008e9e9e3d9',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/333-cache-utilisateurs-connectes/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'mobile_cache_section' => [
|
||||
'en' => '577a5f1f903360258a10e52a,5678aa76c697914361558e92,5745b9a6c697917290ddc715',
|
||||
'fr' => '589b17a02c7d3a784630b249,5a6b32830428632faf6233dc,58a480e5dd8c8e56bfa7b85c',
|
||||
],
|
||||
'mobile_cache' => [
|
||||
'en' => [
|
||||
'id' => '577a5f1f903360258a10e52a',
|
||||
'url' => 'https://docs.wp-rocket.me/article/708-mobile-caching/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '589b17a02c7d3a784630b249',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/934-mise-en-cache-pour-mobile/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cache_ssl' => [
|
||||
'en' => [
|
||||
'id' => '56c24fd3903360436857f1ed',
|
||||
'url' => 'https://docs.wp-rocket.me/article/314-using-ssl-with-wp-rocket/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '56cb9d24c6979102ccfc801c',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/335-utiliser-ssl-wp-rocket/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cache_lifespan' => [
|
||||
'en' => [
|
||||
'id' => '555c7e9ee4b027e1978e17a5',
|
||||
'url' => 'https://docs.wp-rocket.me/article/78-how-often-is-the-cache-updated/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '568f7df49033603f7da2ec72',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/171-intervalle-cache/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cache_lifespan_section' => [
|
||||
'en' => '555c7e9ee4b027e1978e17a5,5922fd0e0428634b4a33552c',
|
||||
'fr' => '568f7df49033603f7da2ec72,598080e1042863033a1b890e',
|
||||
],
|
||||
'nonce' => [
|
||||
'en' => [
|
||||
'id' => '5922fd0e0428634b4a33552c',
|
||||
'url' => 'https://docs.wp-rocket.me/article/975-nonces-and-cache-lifespan/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '598080e1042863033a1b890e',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1015-nonces-delai-nettoyage-cache/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'basic_section' => [
|
||||
'en' => '55231415e4b0221aadf25676,588286b32c7d3a4a60b95b6c,58869c492c7d3a7846303a3d',
|
||||
'fr' => '569568269033603f7da30334,58e3be72dd8c8e5c57311c6e,59b7f049042863033a1cc5d0',
|
||||
],
|
||||
'css_section' => [
|
||||
'en' => '54205957e4b099def9b55df0,5419ec47e4b099def9b5565f,5578cfbbe4b027e1978e6bb1,5569b671e4b027e1978e3c51,5923772c2c7d3a074e8ab8b9',
|
||||
'fr' => '56967d73c69791436155e637,56967e80c69791436155e646,56957209c69791436155e0f6,5697d2dc9033603f7da31041593fec6d2c7d3a0747cddb93',
|
||||
],
|
||||
'js_section' => [
|
||||
'en' => '54205957e4b099def9b55df0,5419ec47e4b099def9b5565f,5578cfbbe4b027e1978e6bb1,587904cf90336009736c678e,54b9509de4b07997ea3f27c7,59236dfb0428634b4a3358f9',
|
||||
'fr' => '56967d73c69791436155e637,56967e80c69791436155e646,56957209c69791436155e0f6,58a337c12c7d3a576d352cde,56967eebc69791436155e649,593fe9882c7d3a0747cddb77',
|
||||
],
|
||||
'file_optimization' => [
|
||||
'en' => [
|
||||
'id' => '54205957e4b099def9b55df0',
|
||||
'url' => 'https://docs.wp-rocket.me/article/19-resolving-issues-with-file-optimization/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '56967d73c69791436155e637',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/241-problemes-minification/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'combine' => [
|
||||
'en' => [
|
||||
'id' => '596eaf7d2c7d3a73488b3661',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1009-configuration-for-http-2/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '59a418ad042863033a1c572e',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1018-configuration-http-2/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'exclude_inline_js' => [
|
||||
'en' => [
|
||||
'id' => '5b4879100428630abc0c0713',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1104-excluding-inline-js-from-combine/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'exclude_js' => [
|
||||
'en' => [
|
||||
'id' => '54b9509de4b07997ea3f27c7',
|
||||
'url' => 'https://docs.wp-rocket.me/article/39-excluding-external-js-from-concatenation/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'defer_js' => [
|
||||
'en' => [
|
||||
'id' => '5d52138d2c7d3a68825e8faa',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1265-load-javascript-deferred/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5d5ac08b2c7d3a7920be3649',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1270-chargement-differe-des-fichiers-js/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'jquery_migrate' => [
|
||||
'en' => [
|
||||
'id' => '5e1d27de2c7d3a7e9ae627e8',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1304-remove-jquery-migrate/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5e5e5bfe04286364bc962504',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1309-supprimer-jquery-migrate/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'delay_js' => [
|
||||
'en' => [
|
||||
'id' => '5f359695042863444aa04e26',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1349-delay-javascript-execution/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'async' => [
|
||||
'en' => [
|
||||
'id' => '5d52144c0428631e94f94ae2',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1266-optimize-css-delivery/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5d5abada0428634552d85bff',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1268-optimiser-le-chargement-du-css/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'lazyload' => [
|
||||
'en' => [
|
||||
'id' => '5c884cf80428633d2cf38314',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1141-using-lazyload-in-wp-rocket/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5c98ff532c7d3a1544614cf4',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1146-utiliser-lazyload-images-wp-rocket/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'webp' => [
|
||||
'en' => [
|
||||
'id' => '5d72919704286364bc8ed49d',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1282-webp',
|
||||
],
|
||||
],
|
||||
'lazyload_section' => [
|
||||
'en' => '5c884cf80428633d2cf38314,54b85754e4b0512429883a86,5418c792e4b0e7b8127bed99,569ec4a69033603f7da32c93,5419e246e4b099def9b5561e,5a299b332c7d3a1a640cb402',
|
||||
'fr' => '56967a859033603f7da30858,56967952c69791436155e60a,56cb9c9d90336008e9e9e3dc,569676ea9033603f7da3083d,5a3a66f52c7d3a1943676524',
|
||||
],
|
||||
'sitemap_preload' => [
|
||||
'en' => '541780fde4b005ed2d11784c,5a71c8ab2c7d3a4a4198a9b3,55b282ede4b0b0593824f852',
|
||||
'fr' => '5693d582c69791436155d645',
|
||||
],
|
||||
'preload_bot' => [
|
||||
'en' => '541780fde4b005ed2d11784c,55b282ede4b0b0593824f852,559113eae4b027e1978eba11',
|
||||
'fr' => '5693d582c69791436155d645,569433d1c69791436155d99c',
|
||||
],
|
||||
'bot' => [
|
||||
'en' => [
|
||||
'id' => '541780fde4b005ed2d11784c',
|
||||
'url' => 'https://docs.wp-rocket.me/article/8-how-the-cache-is-preloaded/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5693d582c69791436155d645',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/188-comment-est-pre-charge-le-cache/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'dns_prefetch' => [
|
||||
'en' => '541780fde4b005ed2d11784c',
|
||||
'fr' => '5693d582c69791436155d645',
|
||||
],
|
||||
'fonts_preload' => [
|
||||
'en' => [
|
||||
'id' => '5eab7729042863474d19f647',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1317-preload-fonts/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5eb3add02c7d3a5ea54aa66d',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1319-precharger-polices/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'preload_links' => [
|
||||
'en' => [
|
||||
'id' => '5f35939b042863444aa04df9',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1348-preload-links/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'never_cache' => [
|
||||
'en' => '5519ab03e4b061031402119f,559110d0e4b027e1978eba09,56b55ba49033600da1c0b687,553ac7bfe4b0eb143c62af44,587920b5c697915403a0e1f4,5569b671e4b027e1978e3c51',
|
||||
'fr' => '56941c0cc69791436155d8ab,56943395c69791436155d99a,56cb9ba990336008e9e9e3d9,56942fc3c69791436155d987,5879230cc697915403a0e211,5697d2dc9033603f7da31041',
|
||||
],
|
||||
'always_purge_section' => [
|
||||
'en' => '555c7e9ee4b027e1978e17a,55151406e4b0610314020a3f,5632858890336002f86d903e,5792c0c1903360293603896b',
|
||||
'fr' => '568f7df49033603f7da2ec72,5694194d9033603f7da2fb00,56951208c69791436155de2a,57a4a0c3c697910783242008',
|
||||
],
|
||||
'query_strings' => [
|
||||
'en' => '590a83610428634b4a32d52c',
|
||||
'fr' => '597a04fd042863033a1b6da4',
|
||||
],
|
||||
'ecommerce' => [
|
||||
'en' => [
|
||||
'id' => '555c619ce4b027e1978e1767',
|
||||
'url' => 'https://docs.wp-rocket.me/article/75-is-wp-rocket-compatible-with-e-commerce-plugins/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '568f8291c69791436155caea',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/176-compatibilite-extensions-e-commerce/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cache_query_strings' => [
|
||||
'en' => [
|
||||
'id' => '590a83610428634b4a32d52c',
|
||||
'url' => 'https://docs.wp-rocket.me/article/971-caching-query-strings/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '597a04fd042863033a1b6da4',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1014-cache-query-strings/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'exclude_cache' => [
|
||||
'en' => [
|
||||
'id' => '5519ab03e4b061031402119f',
|
||||
'url' => 'https://docs.wp-rocket.me/article/54-exclude-pages-from-the-cache/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '56941c0cc69791436155d8ab',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/196-exclure-pages-cache/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'always_purge' => [
|
||||
'en' => [
|
||||
'id' => '555c7e9ee4b027e1978e17a5',
|
||||
'url' => 'https://docs.wp-rocket.me/article/78-how-often-is-the-cache-updated/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '568f7df49033603f7da2ec72',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/171-intervalle-cache/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cleanup' => [
|
||||
'en' => '55dcaa28e4b01d7a6a9bd373,578cd762c6979160ca1441cd,5569d11ae4b01a224b427725',
|
||||
'fr' => '5697cebbc69791436155ed5e,58b6e7a0dd8c8e56bfa819f5,5697cd85c69791436155ed50',
|
||||
],
|
||||
'slow_admin' => [
|
||||
'en' => [
|
||||
'id' => '55dcaa28e4b01d7a6a9bd373',
|
||||
'url' => 'https://docs.wp-rocket.me/article/121-wp-admin-area-is-slow/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5697cebbc69791436155ed5e',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/260-la-zone-d-administration-wp-est-lente/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cdn_section' => [
|
||||
'en' => '54c7fa3de4b0512429885b5c,54205619e4b0e7b8127bf849,54a6d578e4b047ebb774a687,56b2b4459033603f7da37acf,566f749f9033603f7da28459,5434667fe4b0310ce5ee867a',
|
||||
'fr' => '5696830b9033603f7da308ac,5696837e9033603f7da308ae,569685749033603f7da308c0,57a4961190336059d4edc9d8,5697d5f8c69791436155ed8e,569684d29033603f7da308b9',
|
||||
],
|
||||
'cdn' => [
|
||||
'en' => [
|
||||
'id' => '54c7fa3de4b0512429885b5c',
|
||||
'url' => 'https://docs.wp-rocket.me/article/42-using-wp-rocket-with-a-cdn/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5696830b9033603f7da308ac',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/246-utiliser-wp-rocket-avec-un-cdn/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'rocketcdn' => [
|
||||
'en' => [
|
||||
'id' => '5e4c84bd04286364bc958833',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1307-rocketcdn/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5e5e36712c7d3a7e9ae89555',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1308-rocketcdn/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'exclude_cdn' => [
|
||||
'en' => [
|
||||
'id' => '5434667fe4b0310ce5ee867a',
|
||||
'url' => 'https://docs.wp-rocket.me/article/24-resolving-issues-with-cdn-and-fonts-icons/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '569684d29033603f7da308b9',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/248-resoudre-des-problemes-avec-cdn-et-les-polices-icones/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cloudflare_credentials' => [
|
||||
'en' => [
|
||||
'id' => '54205619e4b0e7b8127bf849',
|
||||
'url' => 'https://docs.wp-rocket.me/article/18-using-wp-rocket-with-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5696837e9033603f7da308ae',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/247-utiliser-wp-rocket-avec-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cloudflare_settings' => [
|
||||
'en' => [
|
||||
'id' => '54205619e4b0e7b8127bf849',
|
||||
'url' => 'https://docs.wp-rocket.me/article/18-using-wp-rocket-with-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5696837e9033603f7da308ae',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/247-utiliser-wp-rocket-avec-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'cloudflare_credentials_api' => [
|
||||
'en' => [
|
||||
'id' => '54205619e4b0e7b8127bf849',
|
||||
'url' => 'https://docs.wp-rocket.me/article/18-using-wp-rocket-with-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket#add-on',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5696837e9033603f7da308ae',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/247-utiliser-wp-rocket-avec-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket#add-on',
|
||||
],
|
||||
],
|
||||
'sucuri_credentials' => [
|
||||
'en' => [
|
||||
'id' => '5bce07be2c7d3a04dd5bf94d',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1120-sucuri-add-on/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5bcf39c72c7d3a4db66085b9',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1122-sucuri-add-on/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'varnish' => [
|
||||
'en' => [
|
||||
'id' => '56f48132c6979115a34095bd',
|
||||
'url' => 'https://docs.wp-rocket.me/article/493-using-varnish-with-wp-rocket/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '56fd2f789033601d6683e574',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/512-varnish-wp-rocket-2-7/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'heartbeat_settings' => [
|
||||
'en' => [
|
||||
'id' => '5bcdfecd042863158cc7b672',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1119-control-wordpress-heartbeat-api/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5bcf4378042863215a46bc00',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1124-controler-api-wordpress-heartbeat/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'google_tracking' => [
|
||||
'en' => [
|
||||
'id' => '5b4693220428630abc0bf97b',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1103-google-tracking-add-on/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'facebook_tracking' => [
|
||||
'en' => [
|
||||
'id' => '5bc904e7042863158cc79d57',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1117-facebook-pixel-add-on/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5bcf3d35042863215a46bb7f',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1123-add-on-facebook-pixel/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
'google_fonts' => [
|
||||
'en' => [
|
||||
'id' => '5e8687c22c7d3a7e9aea4c4a',
|
||||
'url' => 'https://docs.wp-rocket.me/article/1312-optimize-google-fonts',
|
||||
],
|
||||
'fr' => [
|
||||
'id' => '5e970f512c7d3a7e9aeaf9fb',
|
||||
'url' => 'https://fr.docs.wp-rocket.me/article/1314-optimiser-les-google-fonts/?utm_source=wp_plugin&utm_medium=wp_rocket',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return isset( $suggest[ $doc_id ][ $this->get_user_locale() ] )
|
||||
? $suggest[ $doc_id ][ $this->get_user_locale() ]
|
||||
: $suggest[ $doc_id ]['en'];
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Admin\Beacon;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service Provider for Beacon
|
||||
*
|
||||
* @since 3.3
|
||||
* @author Remy Perona
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'beacon',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the option array in the container
|
||||
*
|
||||
* @since 3.3
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->add( 'beacon', 'WP_Rocket\Engine\Admin\Beacon\Beacon' )
|
||||
->withArgument( $this->getContainer()->get( 'options' ) )
|
||||
->withArgument( $this->getContainer()->get( 'template_path' ) . '/settings' )
|
||||
->withArgument( $this->getContainer()->get( 'support_data' ) );
|
||||
}
|
||||
}
|
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Admin\Deactivation;
|
||||
|
||||
use WP_Rocket\Admin\Options;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
use WP_Rocket\Interfaces\Render_Interface;
|
||||
|
||||
/**
|
||||
* Deactivation intent form on plugins page
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
class DeactivationIntent implements Subscriber_Interface {
|
||||
/**
|
||||
* Render Interface
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @var Render_Interface
|
||||
*/
|
||||
private $render;
|
||||
|
||||
/**
|
||||
* Options instance.
|
||||
*
|
||||
* @var Options
|
||||
*/
|
||||
private $options_api;
|
||||
|
||||
/**
|
||||
* Options_Data instance.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param Render_Interface $render Render interface.
|
||||
* @param Options $options_api Options instance.
|
||||
* @param Options_Data $options Options_Data instance.
|
||||
*/
|
||||
public function __construct( Render_Interface $render, Options $options_api, Options_Data $options ) {
|
||||
$this->render = $render;
|
||||
$this->options_api = $options_api;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'admin_print_footer_scripts-plugins.php' => 'insert_mixpanel_tracking',
|
||||
'admin_footer' => 'insert_deactivation_intent_form',
|
||||
'wp_ajax_rocket_safe_mode' => 'activate_safe_mode',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts mixpanel tracking on plugins page to send deactivation data
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function insert_mixpanel_tracking() {
|
||||
?>
|
||||
<!-- start Mixpanel --><script type="text/javascript">(function(e,a){if(!a.__SV){var b=window;try{var c,l,i,j=b.location,g=j.hash;c=function(a,b){return(l=a.match(RegExp(b+"=([^&]*)")))?l[1]:null};g&&c(g,"state")&&(i=JSON.parse(decodeURIComponent(c(g,"state"))),"mpeditor"===i.action&&(b.sessionStorage.setItem("_mpcehash",g),history.replaceState(i.desiredHash||"",e.title,j.pathname+j.search)))}catch(m){}var k,h;window.mixpanel=a;a._i=[];a.init=function(b,c,f){function e(b,a){var c=a.split(".");2==c.length&&(b=b[c[0]],a=c[1]);b[a]=function(){b.push([a].concat(Array.prototype.slice.call(arguments,
|
||||
0)))}}var d=a;"undefined"!==typeof f?d=a[f]=[]:f="mixpanel";d.people=d.people||[];d.toString=function(b){var a="mixpanel";"mixpanel"!==f&&(a+="."+f);b||(a+=" (stub)");return a};d.people.toString=function(){return d.toString(1)+".people (stub)"};k="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
|
||||
for(h=0;h<k.length;h++)e(d,k[h]);a._i.push([b,c,f])};a.__SV=1.2;b=e.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";c=e.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c)}})(document,window.mixpanel||[]);
|
||||
|
||||
mixpanel.init("a36067b00a263cce0299cfd960e26ecf", {
|
||||
'ip':false,
|
||||
property_blacklist: ['$initial_referrer', '$current_url', '$initial_referring_domain', '$referrer', '$referring_domain']
|
||||
} );
|
||||
|
||||
mixpanel.track_links( '#mixpanel-send-deactivation', 'Deactivation Intent', function(ele) {
|
||||
return {
|
||||
'Reason': document.getElementById('wpr-reason').value,
|
||||
'Details': document.getElementById('wpr-details').value,
|
||||
}
|
||||
} );
|
||||
</script><!-- end Mixpanel -->
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the deactivation intent form on plugins page
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function insert_deactivation_intent_form() {
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( 'plugins' !== $current_screen->id && 'plugins-network' !== $current_screen->id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->render->render_form();
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates WP Rocket safe mode by deactivating possibly layout breaking options
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function activate_safe_mode() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce' );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
wp_send_json_error();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the array of options to reset when activating safe mode
|
||||
*
|
||||
* @since 3.7
|
||||
*
|
||||
* @param array $options Array of options to reset.
|
||||
*/
|
||||
$reset_options = apply_filters(
|
||||
'rocket_safe_mode_reset_options',
|
||||
[
|
||||
'embeds' => 0,
|
||||
'defer_all_js' => 0,
|
||||
'async_css' => 0,
|
||||
'lazyload' => 0,
|
||||
'lazyload_iframes' => 0,
|
||||
'lazyload_youtube' => 0,
|
||||
'minify_css' => 0,
|
||||
'minify_concatenate_css' => 0,
|
||||
'minify_js' => 0,
|
||||
'minify_concatenate_js' => 0,
|
||||
'minify_google_fonts' => 0,
|
||||
'cdn' => 0,
|
||||
]
|
||||
);
|
||||
|
||||
$this->options->set_values( $reset_options );
|
||||
$this->options_api->set( 'settings', $this->options->get_options() );
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Admin;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service Provider for admin subscribers.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'deactivation_intent_render',
|
||||
'deactivation_intent_subscriber',
|
||||
'hummingbird_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the option array in the container.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public function register() {
|
||||
$options = $this->getContainer()->get( 'options' );
|
||||
|
||||
$this->getContainer()->add( 'deactivation_intent_render', 'WP_Rocket\Admin\Deactivation\Render' )
|
||||
->withArgument( $this->getContainer()->get( 'template_path' ) . '/deactivation-intent' );
|
||||
$this->getContainer()->share( 'deactivation_intent_subscriber', 'WP_Rocket\Engine\Admin\Deactivation\DeactivationIntent' )
|
||||
->withArgument( $this->getContainer()->get( 'deactivation_intent_render' ) )
|
||||
->withArgument( $this->getContainer()->get( 'options_api' ) )
|
||||
->withArgument( $options );
|
||||
$this->getContainer()->share( 'hummingbird_subscriber', 'WP_Rocket\ThirdParty\Plugins\Optimization\Hummingbird' )
|
||||
->withArgument( $options );
|
||||
}
|
||||
}
|
2141
wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Page.php
Normal file
2141
wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Page.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,476 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Admin\Settings;
|
||||
|
||||
use WP_Rocket\Abstract_Render;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Handle rendering of HTML content for the settings page.
|
||||
*
|
||||
* @since 3.5.5 Moves into the new architecture.
|
||||
* @since 3.0
|
||||
*/
|
||||
class Render extends Abstract_render {
|
||||
/**
|
||||
* Settings array.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $settings = [];
|
||||
|
||||
/**
|
||||
* Hidden settings array.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $hidden_settings;
|
||||
|
||||
/**
|
||||
* Sets the settings value.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $settings Array of settings.
|
||||
* @return void
|
||||
*/
|
||||
public function set_settings( $settings ) {
|
||||
$this->settings = (array) $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hidden settings value.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $hidden_settings Array of hidden settings.
|
||||
*/
|
||||
public function set_hidden_settings( $hidden_settings ) {
|
||||
$this->hidden_settings = $hidden_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the page sections navigation.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function render_navigation() {
|
||||
/**
|
||||
* Filters WP Rocket settings page navigation items.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $navigation {
|
||||
* Items to populate the navigation.
|
||||
*
|
||||
* @type string $id Page section identifier.
|
||||
* @type string $title Menu item title.
|
||||
* @type string $menu_description Menu item description.
|
||||
* @type string $class Menu item classes
|
||||
* }
|
||||
*/
|
||||
$navigation = (array) apply_filters( 'rocket_settings_menu_navigation', $this->settings );
|
||||
|
||||
$default = [
|
||||
'id' => '',
|
||||
'title' => '',
|
||||
'menu_description' => '',
|
||||
'class' => '',
|
||||
];
|
||||
|
||||
$navigation = array_map(
|
||||
function( array $item ) use ( $default ) {
|
||||
$item = wp_parse_args( $item, $default );
|
||||
|
||||
if ( ! empty( $item['class'] ) ) {
|
||||
$item['class'] = implode( ' ', array_map( 'sanitize_html_class', $item['class'] ) );
|
||||
}
|
||||
|
||||
unset( $item['sections'] );
|
||||
return $item;
|
||||
},
|
||||
$navigation
|
||||
);
|
||||
|
||||
echo $this->generate( 'navigation', $navigation ); // phpcs:ignore WordPress.Security.EscapeOutput -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the page sections.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function render_form_sections() {
|
||||
if ( ! isset( $this->settings ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->settings as $id => $args ) {
|
||||
$default = [
|
||||
'title' => '',
|
||||
'menu_description' => '',
|
||||
'class' => '',
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $default );
|
||||
$id = str_replace( '_', '-', $id );
|
||||
|
||||
echo $this->generate( 'page-sections/' . $id, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Imagify page section.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public function render_imagify_section() {
|
||||
echo $this->generate( 'page-sections/imagify' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the Tutorials page section.
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public function render_tutorials_section() {
|
||||
echo $this->generate( 'page-sections/tutorials' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the tools page section.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function render_tools_section() {
|
||||
echo $this->generate( 'page-sections/tools' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the settings sections for a page section.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $page Page section identifier.
|
||||
* @return void
|
||||
*/
|
||||
public function render_settings_sections( $page ) {
|
||||
if ( ! isset( $this->settings[ $page ]['sections'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->settings[ $page ]['sections'] as $args ) {
|
||||
$default = [
|
||||
'type' => 'fields_container',
|
||||
'title' => '',
|
||||
'description' => '',
|
||||
'class' => '',
|
||||
'help' => '',
|
||||
'helper' => '',
|
||||
'page' => '',
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $default );
|
||||
|
||||
if ( ! empty( $args['class'] ) ) {
|
||||
$args['class'] = implode( ' ', array_map( 'sanitize_html_class', $args['class'] ) );
|
||||
}
|
||||
|
||||
call_user_func_array( [ $this, $args['type'] ], [ $args ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the settings fields for a setting section and page.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $page Page section identifier.
|
||||
* @param string $section Settings section identifier.
|
||||
* @return void
|
||||
*/
|
||||
public function render_settings_fields( $page, $section ) {
|
||||
if ( ! isset( $this->settings[ $page ]['sections'][ $section ]['fields'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->settings[ $page ]['sections'][ $section ]['fields'] as $args ) {
|
||||
$default = [
|
||||
'type' => 'text',
|
||||
'label' => '',
|
||||
'description' => '',
|
||||
'class' => '',
|
||||
'container_class' => '',
|
||||
'default' => '',
|
||||
'helper' => '',
|
||||
'placeholder' => '',
|
||||
'parent' => '',
|
||||
'section' => '',
|
||||
'page' => '',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'input_attr' => '',
|
||||
'warning' => [],
|
||||
];
|
||||
|
||||
$args = wp_parse_args( $args, $default );
|
||||
|
||||
if ( ! empty( $args['input_attr'] ) ) {
|
||||
$input_attr = '';
|
||||
|
||||
foreach ( $args['input_attr'] as $key => $value ) {
|
||||
if ( 'disabled' === $key ) {
|
||||
if ( 1 === $value ) {
|
||||
$input_attr .= ' disabled';
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$input_attr .= ' ' . sanitize_key( $key ) . '="' . esc_attr( $value ) . '"';
|
||||
}
|
||||
|
||||
$args['input_attr'] = $input_attr;
|
||||
}
|
||||
|
||||
if ( ! empty( $args['parent'] ) ) {
|
||||
$args['parent'] = ' data-parent="' . esc_attr( $args['parent'] ) . '"';
|
||||
}
|
||||
|
||||
if ( ! empty( $args['class'] ) ) {
|
||||
$args['class'] = implode( ' ', array_map( 'sanitize_html_class', $args['class'] ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $args['container_class'] ) ) {
|
||||
$args['container_class'] = implode( ' ', array_map( 'sanitize_html_class', $args['container_class'] ) );
|
||||
}
|
||||
|
||||
call_user_func_array( [ $this, $args['type'] ], [ $args ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders hidden fields in the form.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function render_hidden_fields() {
|
||||
foreach ( $this->hidden_settings as $setting ) {
|
||||
call_user_func_array( [ $this, 'hidden' ], [ $setting ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the fields container section template.
|
||||
*
|
||||
* @since 3.0
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function fields_container( $args ) {
|
||||
echo $this->generate( 'sections/fields-container', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the no container section template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function nocontainer( $args ) {
|
||||
echo $this->generate( 'sections/nocontainer', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the add-ons container section template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function addons_container( $args ) {
|
||||
echo $this->generate( 'sections/addons-container', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the text field template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function text( $args ) {
|
||||
echo $this->generate( 'fields/text', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the checkbox field template.
|
||||
*
|
||||
* @since 3.0
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
* @return void
|
||||
*/
|
||||
public function checkbox( $args ) {
|
||||
echo $this->generate( 'fields/checkbox', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the textarea field template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function textarea( $args ) {
|
||||
if ( is_array( $args['value'] ) ) {
|
||||
$args['value'] = implode( "\n", $args['value'] );
|
||||
}
|
||||
|
||||
$args['value'] = empty( $args['value'] ) ? '' : $args['value'];
|
||||
|
||||
echo $this->generate( 'fields/textarea', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the sliding checkbox field template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function sliding_checkbox( $args ) {
|
||||
echo $this->generate( 'fields/sliding-checkbox', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the number input field template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function number( $args ) {
|
||||
echo $this->generate( 'fields/number', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the select field template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function select( $args ) {
|
||||
echo $this->generate( 'fields/select', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the clear cache lifespan block template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function cache_lifespan( $args ) {
|
||||
echo $this->generate( 'fields/cache-lifespan', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the hidden field template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function hidden( $args ) {
|
||||
echo $this->generate( 'fields/hidden', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the CDN CNAMES template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function cnames( $args ) {
|
||||
echo $this->generate( 'fields/cnames', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the RocketCDN template.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function rocket_cdn( $args ) {
|
||||
echo $this->generate( 'fields/rocket-cdn', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the one-click add-on field template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function one_click_addon( $args ) {
|
||||
echo $this->generate( 'fields/one-click-addon', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the Rocket add-on field template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $args Array of arguments to populate the template.
|
||||
*/
|
||||
public function rocket_addon( $args ) {
|
||||
echo $this->generate( 'fields/rocket-addon', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the import form template.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function render_import_form() {
|
||||
$args = [];
|
||||
|
||||
/**
|
||||
* Filter the maximum allowed upload size for import files.
|
||||
*
|
||||
* @since (WordPress) 2.3.0
|
||||
*
|
||||
* @see wp_max_upload_size()
|
||||
*
|
||||
* @param int $max_upload_size Allowed upload size. Default 1 MB.
|
||||
*/
|
||||
$args['bytes'] = apply_filters( 'import_upload_size_limit', wp_max_upload_size() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
|
||||
$args['size'] = size_format( $args['bytes'] );
|
||||
$args['upload_dir'] = wp_upload_dir();
|
||||
$args['action'] = 'rocket_import_settings';
|
||||
$args['submit_text'] = __( 'Upload file and import settings', 'rocket' );
|
||||
|
||||
echo $this->generate( 'fields/import-form', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a partial template.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $part Partial template name.
|
||||
*/
|
||||
public function render_part( $part ) {
|
||||
echo $this->generate( 'partials/' . $part ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Admin\Settings;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service provider for the WP Rocket settings.
|
||||
*
|
||||
* @since 3.5.5 Moves into the new architecture.
|
||||
* @since 3.3
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'settings',
|
||||
'settings_render',
|
||||
'settings_page',
|
||||
'settings_page_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the option array in the container.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->add( 'settings', 'WP_Rocket\Engine\Admin\Settings\Settings' )
|
||||
->withArgument( $this->getContainer()->get( 'options' ) );
|
||||
$this->getContainer()->add( 'settings_render', 'WP_Rocket\Engine\Admin\Settings\Render' )
|
||||
->withArgument( $this->getContainer()->get( 'template_path' ) . '/settings' );
|
||||
$this->getContainer()->add( 'settings_page', 'WP_Rocket\Engine\Admin\Settings\Page' )
|
||||
->withArgument( $this->getContainer()->get( 'settings_page_config' ) )
|
||||
->withArgument( $this->getContainer()->get( 'settings' ) )
|
||||
->withArgument( $this->getContainer()->get( 'settings_render' ) )
|
||||
->withArgument( $this->getContainer()->get( 'beacon' ) )
|
||||
->withArgument( $this->getContainer()->get( 'db_optimization' ) )
|
||||
->withArgument( $this->getContainer()->get( 'user_client' ) );
|
||||
$this->getContainer()->share( 'settings_page_subscriber', 'WP_Rocket\Engine\Admin\Settings\Subscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'settings_page' ) );
|
||||
}
|
||||
}
|
@@ -0,0 +1,667 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Admin\Settings;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Subscriber\Third_Party\Plugins\Security\Sucuri_Subscriber;
|
||||
|
||||
/**
|
||||
* Settings class.
|
||||
*
|
||||
* @since 3.5.5 Moves into the new architecture.
|
||||
*/
|
||||
class Settings {
|
||||
/**
|
||||
* Options_Data instance.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Array of settings to build the settings page.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* Hidden settings on the settings page.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $hidden_settings;
|
||||
|
||||
/**
|
||||
* Font formats allowed to be preloaded.
|
||||
*
|
||||
* @since 3.6
|
||||
* @see $this->sanitize_font()
|
||||
*
|
||||
* @var string|bool
|
||||
*/
|
||||
private $font_formats = [
|
||||
'otf',
|
||||
'ttf',
|
||||
'svg',
|
||||
'woff',
|
||||
'woff2',
|
||||
];
|
||||
|
||||
/**
|
||||
* Array of valid hosts.
|
||||
*
|
||||
* @since 3.6
|
||||
* @see $this->get_hosts()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $hosts;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param Options_Data $options Options_Data instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a page section to the settings.
|
||||
*
|
||||
* A page section is a top-level block containing settings sections.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param string $id Page section identifier.
|
||||
* @param array $args {
|
||||
* Data to build the section.
|
||||
*
|
||||
* @type string $title Section title.
|
||||
* @type string $menu_description Description displayed in the navigation.
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
public function add_page_section( $id, $args ) {
|
||||
$args['id'] = $id;
|
||||
|
||||
$this->settings[ $id ] = $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds settings sections to the settings.
|
||||
*
|
||||
* A setting section is a block containing settings fields.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $settings_sections {
|
||||
* Data to build the section.
|
||||
*
|
||||
* @type string $title Section title.
|
||||
* @type string $type Type of section.
|
||||
* @type string $page Page section identifier it belongs to.
|
||||
* @type string $description Section description.
|
||||
* @type string $help Helper IDs for beacon.
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
public function add_settings_sections( $settings_sections ) {
|
||||
foreach ( $settings_sections as $id => $args ) {
|
||||
$args['id'] = $id;
|
||||
|
||||
$this->settings[ $args['page'] ]['sections'][ $id ] = $args;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds settings fields to the settings.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $settings_fields {
|
||||
* Data to build the section.
|
||||
*
|
||||
* @type string $id Identifier.
|
||||
* @type string $title Field title.
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
public function add_settings_fields( $settings_fields ) {
|
||||
foreach ( $settings_fields as $id => $args ) {
|
||||
$args['id'] = $id;
|
||||
$args['value'] = $this->options->get( $id, $args['default'] );
|
||||
$page = $args['page'];
|
||||
$section = $args['section'];
|
||||
unset( $args['page'], $args['section'] );
|
||||
|
||||
$this->settings[ $page ]['sections'][ $section ]['fields'][ $id ] = $args;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds hidden settings fields to the settings.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $hidden_settings_fields {
|
||||
* Data to build the section.
|
||||
*
|
||||
* @type string $id Identifier.
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
public function add_hidden_settings_fields( $hidden_settings_fields ) {
|
||||
foreach ( $hidden_settings_fields as $id ) {
|
||||
$value = $this->options->get( $id );
|
||||
|
||||
$this->hidden_settings[] = [
|
||||
'id' => $id,
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin settings
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_settings() {
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plugin hidden settings
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_hidden_settings() {
|
||||
return $this->hidden_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the submitted values.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $input Array of values submitted by the form.
|
||||
* @return array
|
||||
*/
|
||||
public function sanitize_callback( $input ) {
|
||||
global $wp_settings_errors;
|
||||
|
||||
$input['do_beta'] = ! empty( $input['do_beta'] ) ? 1 : 0;
|
||||
|
||||
$input['cache_logged_user'] = ! empty( $input['cache_logged_user'] ) ? 1 : 0;
|
||||
|
||||
$input['cache_ssl'] = ! empty( $input['cache_ssl'] ) ? 1 : 0;
|
||||
|
||||
$input['cache_mobile'] = ! empty( $input['cache_mobile'] ) ? 1 : 0;
|
||||
$input['do_caching_mobile_files'] = ! empty( $input['do_caching_mobile_files'] ) ? 1 : 0;
|
||||
|
||||
$input['minify_google_fonts'] = ! empty( $input['minify_google_fonts'] ) ? 1 : 0;
|
||||
|
||||
// Option : Minification CSS & JS.
|
||||
$input['minify_css'] = ! empty( $input['minify_css'] ) ? 1 : 0;
|
||||
$input['minify_js'] = ! empty( $input['minify_js'] ) ? 1 : 0;
|
||||
|
||||
$input['minify_concatenate_css'] = ! empty( $input['minify_concatenate_css'] ) ? 1 : 0;
|
||||
$input['minify_concatenate_js'] = ! empty( $input['minify_concatenate_js'] ) ? 1 : 0;
|
||||
|
||||
$input['defer_all_js'] = ! empty( $input['defer_all_js'] ) ? 1 : 0;
|
||||
$input['defer_all_js_safe'] = ! empty( $input['defer_all_js_safe'] ) ? 1 : 0;
|
||||
$input['delay_js'] = $this->sanitize_checkbox( $input, 'delay_js' );
|
||||
$input['delay_js_scripts'] = ! empty( $input['delay_js_scripts'] ) ? rocket_sanitize_textarea_field( 'delay_js_scripts', $input['delay_js_scripts'] ) : [];
|
||||
|
||||
// If Defer JS is deactivated, set Safe Mode for Jquery to active.
|
||||
if ( 0 === $input['defer_all_js'] ) {
|
||||
$input['defer_all_js_safe'] = 1;
|
||||
}
|
||||
|
||||
$input['embeds'] = ! empty( $input['embeds'] ) ? 1 : 0;
|
||||
$input['emoji'] = ! empty( $input['emoji'] ) ? 1 : 0;
|
||||
|
||||
$input['lazyload'] = ! empty( $input['lazyload'] ) ? 1 : 0;
|
||||
$input['lazyload_iframes'] = ! empty( $input['lazyload_iframes'] ) ? 1 : 0;
|
||||
$input['lazyload_youtube'] = ! empty( $input['lazyload_youtube'] ) ? 1 : 0;
|
||||
|
||||
// If iframes lazyload is not checked, uncheck youtube thumbnail option too.
|
||||
if ( 0 === $input['lazyload_iframes'] ) {
|
||||
$input['lazyload_youtube'] = 0;
|
||||
}
|
||||
|
||||
// Option : Purge interval.
|
||||
$input['purge_cron_interval'] = isset( $input['purge_cron_interval'] ) ? (int) $input['purge_cron_interval'] : $this->options->get( 'purge_cron_interval' );
|
||||
|
||||
$allowed_cron_units = [
|
||||
'MINUTE_IN_SECONDS' => 1,
|
||||
'HOUR_IN_SECONDS' => 1,
|
||||
'DAY_IN_SECONDS' => 1,
|
||||
];
|
||||
|
||||
$input['purge_cron_unit'] = isset( $input['purge_cron_unit'], $allowed_cron_units[ $input['purge_cron_unit'] ] ) ? $input['purge_cron_unit'] : $this->options->get( 'purge_cron_unit' );
|
||||
|
||||
// Force a minimum 10 minutes value for the purge interval.
|
||||
if ( $input['purge_cron_interval'] < 10 && 'MINUTE_IN_SECONDS' === $input['purge_cron_unit'] ) {
|
||||
$input['purge_cron_interval'] = 10;
|
||||
}
|
||||
|
||||
// Option : Prefetch DNS requests.
|
||||
$input['dns_prefetch'] = $this->sanitize_dns_prefetch( $input );
|
||||
|
||||
// Option : Empty the cache of the following pages when updating a post.
|
||||
if ( ! empty( $input['cache_purge_pages'] ) ) {
|
||||
$input['cache_purge_pages'] = rocket_sanitize_textarea_field( 'cache_purge_pages', $input['cache_purge_pages'] );
|
||||
} else {
|
||||
$input['cache_purge_pages'] = [];
|
||||
}
|
||||
|
||||
// Option : Never cache the following pages.
|
||||
if ( ! empty( $input['cache_reject_uri'] ) ) {
|
||||
$input['cache_reject_uri'] = rocket_sanitize_textarea_field( 'cache_reject_uri', $input['cache_reject_uri'] );
|
||||
} else {
|
||||
$input['cache_reject_uri'] = [];
|
||||
}
|
||||
|
||||
// Option : Don't cache pages that use the following cookies.
|
||||
if ( ! empty( $input['cache_reject_cookies'] ) ) {
|
||||
$input['cache_reject_cookies'] = rocket_sanitize_textarea_field( 'cache_reject_cookies', $input['cache_reject_cookies'] );
|
||||
} else {
|
||||
$input['cache_reject_cookies'] = [];
|
||||
}
|
||||
|
||||
// Option : Cache pages that use the following query strings (GET parameters).
|
||||
if ( ! empty( $input['cache_query_strings'] ) ) {
|
||||
$input['cache_query_strings'] = rocket_sanitize_textarea_field( 'cache_query_strings', $input['cache_query_strings'] );
|
||||
} else {
|
||||
$input['cache_query_strings'] = [];
|
||||
}
|
||||
|
||||
// Option : Never send cache pages for these user agents.
|
||||
if ( ! empty( $input['cache_reject_ua'] ) ) {
|
||||
$input['cache_reject_ua'] = rocket_sanitize_textarea_field( 'cache_reject_ua', $input['cache_reject_ua'] );
|
||||
} else {
|
||||
$input['cache_reject_ua'] = [];
|
||||
}
|
||||
|
||||
// Option : CSS files to exclude from the minification.
|
||||
if ( ! empty( $input['exclude_css'] ) ) {
|
||||
$input['exclude_css'] = rocket_sanitize_textarea_field( 'exclude_css', $input['exclude_css'] );
|
||||
} else {
|
||||
$input['exclude_css'] = [];
|
||||
}
|
||||
|
||||
// Option : JS files to exclude from the minification.
|
||||
if ( ! empty( $input['exclude_js'] ) ) {
|
||||
$input['exclude_js'] = rocket_sanitize_textarea_field( 'exclude_js', $input['exclude_js'] );
|
||||
} else {
|
||||
$input['exclude_js'] = [];
|
||||
}
|
||||
|
||||
// Option: inline JS patterns to exclude from combine JS.
|
||||
if ( ! empty( $input['exclude_inline_js'] ) ) {
|
||||
$input['exclude_inline_js'] = rocket_sanitize_textarea_field( 'exclude_inline_js', $input['exclude_inline_js'] );
|
||||
} else {
|
||||
$input['exclude_inline_js'] = [];
|
||||
}
|
||||
|
||||
// Option: Async CSS.
|
||||
$input['async_css'] = ! empty( $input['async_css'] ) ? 1 : 0;
|
||||
|
||||
// Option: Critical CSS.
|
||||
$input['critical_css'] = ! empty( $input['critical_css'] ) ? wp_strip_all_tags( str_replace( [ '<style>', '</style>' ], '', $input['critical_css'] ), [ "\'", '\"' ] ) : '';
|
||||
|
||||
// Database options.
|
||||
$input['database_revisions'] = ! empty( $input['database_revisions'] ) ? 1 : 0;
|
||||
$input['database_auto_drafts'] = ! empty( $input['database_auto_drafts'] ) ? 1 : 0;
|
||||
$input['database_trashed_posts'] = ! empty( $input['database_trashed_posts'] ) ? 1 : 0;
|
||||
$input['database_spam_comments'] = ! empty( $input['database_spam_comments'] ) ? 1 : 0;
|
||||
$input['database_trashed_comments'] = ! empty( $input['database_trashed_comments'] ) ? 1 : 0;
|
||||
$input['database_expired_transients'] = ! empty( $input['database_expired_transients'] ) ? 1 : 0;
|
||||
$input['database_all_transients'] = ! empty( $input['database_all_transients'] ) ? 1 : 0;
|
||||
$input['database_optimize_tables'] = ! empty( $input['database_optimize_tables'] ) ? 1 : 0;
|
||||
$input['schedule_automatic_cleanup'] = ! empty( $input['schedule_automatic_cleanup'] ) ? 1 : 0;
|
||||
|
||||
$cleanup_frequencies = [
|
||||
'daily' => 1,
|
||||
'weekly' => 1,
|
||||
'monthly' => 1,
|
||||
];
|
||||
|
||||
$input['automatic_cleanup_frequency'] = isset( $input['automatic_cleanup_frequency'], $cleanup_frequencies[ $input['automatic_cleanup_frequency'] ] ) ? $input['automatic_cleanup_frequency'] : $this->options->get( 'automatic_cleanup_frequency' );
|
||||
|
||||
if ( 1 !== $input['schedule_automatic_cleanup'] && ( 'daily' !== $input['automatic_cleanup_frequency'] || 'weekly' !== $input['automatic_cleanup_frequency'] || 'monthly' !== $input['automatic_cleanup_frequency'] ) ) {
|
||||
$input['automatic_cleanup_frequency'] = $this->options->get( 'automatic_cleanup_frequency' );
|
||||
}
|
||||
|
||||
// Options: Activate bot preload.
|
||||
$input['manual_preload'] = ! empty( $input['manual_preload'] ) ? 1 : 0;
|
||||
|
||||
// Option: activate sitemap preload.
|
||||
$input['sitemap_preload'] = ! empty( $input['sitemap_preload'] ) ? 1 : 0;
|
||||
|
||||
// Option : XML sitemaps URLs.
|
||||
if ( ! empty( $input['sitemaps'] ) ) {
|
||||
if ( ! is_array( $input['sitemaps'] ) ) {
|
||||
$input['sitemaps'] = explode( "\n", $input['sitemaps'] );
|
||||
}
|
||||
$input['sitemaps'] = array_map( 'trim', $input['sitemaps'] );
|
||||
$input['sitemaps'] = array_map( 'rocket_sanitize_xml', $input['sitemaps'] );
|
||||
$input['sitemaps'] = array_filter( $input['sitemaps'] );
|
||||
$input['sitemaps'] = array_unique( $input['sitemaps'] );
|
||||
} else {
|
||||
$input['sitemaps'] = [];
|
||||
}
|
||||
|
||||
// Option : fonts to preload.
|
||||
$input['preload_fonts'] = ! empty( $input['preload_fonts'] ) ? $this->sanitize_fonts( $input['preload_fonts'] ) : [];
|
||||
|
||||
// Options : CloudFlare.
|
||||
$input['do_cloudflare'] = ! empty( $input['do_cloudflare'] ) ? 1 : 0;
|
||||
$input['cloudflare_email'] = isset( $input['cloudflare_email'] ) ? sanitize_email( $input['cloudflare_email'] ) : '';
|
||||
$input['cloudflare_api_key'] = isset( $input['cloudflare_api_key'] ) ? sanitize_text_field( $input['cloudflare_api_key'] ) : '';
|
||||
$input['cloudflare_zone_id'] = isset( $input['cloudflare_zone_id'] ) ? sanitize_text_field( $input['cloudflare_zone_id'] ) : '';
|
||||
$input['cloudflare_devmode'] = isset( $input['cloudflare_devmode'] ) && is_numeric( $input['cloudflare_devmode'] ) ? (int) $input['cloudflare_devmode'] : 0;
|
||||
$input['cloudflare_auto_settings'] = ( isset( $input['cloudflare_auto_settings'] ) && is_numeric( $input['cloudflare_auto_settings'] ) ) ? (int) $input['cloudflare_auto_settings'] : 0;
|
||||
$input['cloudflare_protocol_rewrite'] = ! empty( $input['cloudflare_protocol_rewrite'] ) ? 1 : 0;
|
||||
|
||||
if ( defined( 'WP_ROCKET_CF_API_KEY' ) ) {
|
||||
$input['cloudflare_api_key'] = WP_ROCKET_CF_API_KEY;
|
||||
}
|
||||
|
||||
// Options: Sucuri cache. And yeah, there's a typo, but now it's too late to fix ^^'.
|
||||
$input['sucury_waf_cache_sync'] = ! empty( $input['sucury_waf_cache_sync'] ) ? 1 : 0;
|
||||
|
||||
if ( defined( 'WP_ROCKET_SUCURI_API_KEY' ) ) {
|
||||
$input['sucury_waf_api_key'] = WP_ROCKET_SUCURI_API_KEY;
|
||||
} else {
|
||||
$input['sucury_waf_api_key'] = isset( $input['sucury_waf_api_key'] ) ? sanitize_text_field( $input['sucury_waf_api_key'] ) : '';
|
||||
}
|
||||
|
||||
$input['sucury_waf_api_key'] = trim( $input['sucury_waf_api_key'] );
|
||||
|
||||
if ( ! Sucuri_Subscriber::is_api_key_valid( $input['sucury_waf_api_key'] ) ) {
|
||||
$input['sucury_waf_api_key'] = '';
|
||||
|
||||
if ( $input['sucury_waf_cache_sync'] && empty( $input['ignore'] ) ) {
|
||||
add_settings_error( 'general', 'sucuri_waf_api_key_invalid', __( 'Sucuri Add-on: The API key for the Sucuri firewall must be in format <code>{32 characters}/{32 characters}</code>.', 'rocket' ), 'error' );
|
||||
}
|
||||
}
|
||||
|
||||
// Options : Heartbeat.
|
||||
$choices = [
|
||||
'' => 1,
|
||||
'reduce_periodicity' => 1,
|
||||
'disable' => 1,
|
||||
];
|
||||
|
||||
$input['control_heartbeat'] = ! empty( $input['control_heartbeat'] ) ? 1 : 0;
|
||||
$input['heartbeat_site_behavior'] = isset( $input['heartbeat_site_behavior'], $choices[ $input['heartbeat_site_behavior'] ] ) ? $input['heartbeat_site_behavior'] : '';
|
||||
$input['heartbeat_admin_behavior'] = isset( $input['heartbeat_admin_behavior'], $choices[ $input['heartbeat_admin_behavior'] ] ) ? $input['heartbeat_admin_behavior'] : '';
|
||||
$input['heartbeat_editor_behavior'] = isset( $input['heartbeat_editor_behavior'], $choices[ $input['heartbeat_editor_behavior'] ] ) ? $input['heartbeat_editor_behavior'] : '';
|
||||
|
||||
// Option : CDN.
|
||||
$input['cdn'] = ! empty( $input['cdn'] ) ? 1 : 0;
|
||||
|
||||
// Option : CDN Cnames.
|
||||
if ( isset( $input['cdn_cnames'] ) ) {
|
||||
$input['cdn_cnames'] = array_map( 'sanitize_text_field', $input['cdn_cnames'] );
|
||||
$input['cdn_cnames'] = array_filter( $input['cdn_cnames'] );
|
||||
} else {
|
||||
$input['cdn_cnames'] = [];
|
||||
}
|
||||
|
||||
if ( ! $input['cdn_cnames'] ) {
|
||||
$input['cdn_zone'] = [];
|
||||
} else {
|
||||
$total_cdn_cnames = max( array_keys( $input['cdn_cnames'] ) );
|
||||
for ( $i = 0; $i <= $total_cdn_cnames; $i++ ) {
|
||||
if ( ! isset( $input['cdn_cnames'][ $i ] ) ) {
|
||||
unset( $input['cdn_zone'][ $i ] );
|
||||
} else {
|
||||
$allowed_cdn_zones = [
|
||||
'all' => 1,
|
||||
'images' => 1,
|
||||
'css_and_js' => 1,
|
||||
'css' => 1,
|
||||
'js' => 1,
|
||||
];
|
||||
|
||||
$input['cdn_zone'][ $i ] = isset( $allowed_cdn_zones[ $input['cdn_zone'][ $i ] ] ) ? $input['cdn_zone'][ $i ] : 'all';
|
||||
}
|
||||
}
|
||||
|
||||
$input['cdn_cnames'] = array_values( $input['cdn_cnames'] );
|
||||
$input['cdn_cnames'] = array_map( 'untrailingslashit', $input['cdn_cnames'] );
|
||||
|
||||
ksort( $input['cdn_zone'] );
|
||||
|
||||
$input['cdn_zone'] = array_values( $input['cdn_zone'] );
|
||||
}
|
||||
|
||||
// Option : Files to exclude from the CDN process.
|
||||
if ( ! empty( $input['cdn_reject_files'] ) ) {
|
||||
$input['cdn_reject_files'] = rocket_sanitize_textarea_field( 'cdn_reject_files', $input['cdn_reject_files'] );
|
||||
} else {
|
||||
$input['cdn_reject_files'] = [];
|
||||
}
|
||||
|
||||
$input['varnish_auto_purge'] = ! empty( $input['varnish_auto_purge'] ) ? 1 : 0;
|
||||
|
||||
if ( ! rocket_valid_key() ) {
|
||||
$checked = rocket_check_key();
|
||||
}
|
||||
|
||||
if ( isset( $checked ) && is_array( $checked ) ) {
|
||||
$input['consumer_key'] = $checked['consumer_key'];
|
||||
$input['consumer_email'] = $checked['consumer_email'];
|
||||
$input['secret_key'] = $checked['secret_key'];
|
||||
}
|
||||
|
||||
if ( ! empty( $input['secret_key'] ) && empty( $input['ignore'] ) && rocket_valid_key() ) {
|
||||
// Add a "Settings saved." admin notice only if not already added.
|
||||
$notices = array_merge( (array) $wp_settings_errors, (array) get_transient( 'settings_errors' ) );
|
||||
$notices = array_filter(
|
||||
$notices,
|
||||
function( $error ) {
|
||||
if ( ! $error || ! is_array( $error ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! isset( $error['setting'], $error['code'], $error['type'] ) ) {
|
||||
return false;
|
||||
}
|
||||
return 'general' === $error['setting'] && 'settings_updated' === $error['code'] && 'updated' === $error['type'];
|
||||
}
|
||||
);
|
||||
|
||||
if ( ! $notices ) {
|
||||
add_settings_error( 'general', 'settings_updated', __( 'Settings saved.', 'rocket' ), 'updated' );
|
||||
}
|
||||
}
|
||||
|
||||
unset( $input['ignore'] );
|
||||
|
||||
return apply_filters( 'rocket_input_sanitize', $input );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the returned value of a checkbox
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $array Options array.
|
||||
* @param string $key Array key to check.
|
||||
* @return int
|
||||
*/
|
||||
public function sanitize_checkbox( $array, $key ) {
|
||||
return isset( $array[ $key ] ) && ! empty( $array[ $key ] ) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the DNS Prefetch sub-option value
|
||||
*
|
||||
* @since 3.5.1
|
||||
*
|
||||
* @param array $input Array of values for the WP Rocket settings option.
|
||||
* @return array Sanitized array for the DNS Prefetch sub-option
|
||||
*/
|
||||
private function sanitize_dns_prefetch( array $input ) {
|
||||
if ( empty( $input['dns_prefetch'] ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$value = $input['dns_prefetch'];
|
||||
|
||||
if ( ! is_array( $value ) ) {
|
||||
$value = explode( "\n", $value );
|
||||
}
|
||||
|
||||
$urls = [];
|
||||
|
||||
foreach ( $value as $url ) {
|
||||
$url = trim( $url );
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = preg_replace( '/^(?:https?)?:?\/{3,}/i', 'http://', $url );
|
||||
$url = esc_url_raw( $url );
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$urls[] = $url;
|
||||
}
|
||||
|
||||
if ( empty( $urls ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_unique(
|
||||
array_map(
|
||||
function( $url ) {
|
||||
return '//' . wp_parse_url( $url, PHP_URL_HOST );
|
||||
},
|
||||
$urls
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a list of font file paths.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array|string $files List of filepaths to sanitize. Can be an array of strings or a string listing paths separated by "\n".
|
||||
* @return array Sanitized filepaths.
|
||||
*/
|
||||
private function sanitize_fonts( $files ) {
|
||||
if ( ! is_array( $files ) ) {
|
||||
$files = explode( "\n", trim( $files ) );
|
||||
}
|
||||
|
||||
$files = array_map( [ $this, 'sanitize_font' ], $files );
|
||||
|
||||
return array_unique( array_filter( $files ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize an entry for the preload fonts option.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $file URL or path to a font file.
|
||||
* @return string|bool
|
||||
*/
|
||||
private function sanitize_font( $file ) {
|
||||
if ( ! is_string( $file ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = trim( $file );
|
||||
|
||||
if ( empty( $file ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$parsed_url = wp_parse_url( $file );
|
||||
$hosts = $this->get_hosts();
|
||||
|
||||
if ( ! empty( $parsed_url['host'] ) ) {
|
||||
$match = false;
|
||||
|
||||
foreach ( $hosts as $host ) {
|
||||
if ( false !== strpos( $file, $host ) ) {
|
||||
$match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $match ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$file = str_replace( [ 'http:', 'https:' ], '', $file );
|
||||
$file = str_replace( $hosts, '', $file );
|
||||
$file = '/' . ltrim( $file, '/' );
|
||||
|
||||
$ext = strtolower( pathinfo( $parsed_url['path'], PATHINFO_EXTENSION ) );
|
||||
|
||||
if ( ! in_array( $ext, $this->font_formats, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of valid hosts.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_hosts() {
|
||||
if ( isset( $this->hosts ) ) {
|
||||
return $this->hosts;
|
||||
}
|
||||
|
||||
$urls = (array) $this->options->get( 'cdn_cnames', [] );
|
||||
$urls[] = home_url();
|
||||
$urls = array_map( 'rocket_add_url_protocol', $urls );
|
||||
|
||||
foreach ( $urls as $url ) {
|
||||
$parsed_url = get_rocket_parse_url( $url );
|
||||
|
||||
if ( empty( $parsed_url['host'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parsed_url['path'] = ( '/' === $parsed_url['path'] ) ? '' : $parsed_url['path'];
|
||||
|
||||
$this->hosts[] = "//{$parsed_url['host']}{$parsed_url['path']}";
|
||||
}
|
||||
|
||||
if ( empty( $this->hosts ) ) {
|
||||
$this->hosts = [];
|
||||
}
|
||||
|
||||
return $this->hosts;
|
||||
}
|
||||
}
|
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Admin\Settings;
|
||||
|
||||
use Imagify_Partner;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* WP Rocket settings page subscriber.
|
||||
*
|
||||
* @since 3.5.5 Moves into the new architecture.
|
||||
* @since 3.3
|
||||
*/
|
||||
class Subscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* Page instance
|
||||
*
|
||||
* @var Page
|
||||
*/
|
||||
private $page;
|
||||
|
||||
/**
|
||||
* Creates an instance of the object.
|
||||
*
|
||||
* @param Page $page Page instance.
|
||||
*/
|
||||
public function __construct( Page $page ) {
|
||||
$this->page = $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.3
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'admin_menu' => 'add_admin_page',
|
||||
'admin_init' => 'configure',
|
||||
'wp_ajax_rocket_refresh_customer_data' => 'refresh_customer_data',
|
||||
'wp_ajax_rocket_toggle_option' => 'toggle_option',
|
||||
'rocket_settings_menu_navigation' => [
|
||||
[ 'add_menu_tools_page' ],
|
||||
[ 'add_imagify_page', 9 ],
|
||||
[ 'add_tutorials_page', 11 ],
|
||||
],
|
||||
'admin_enqueue_scripts' => 'enqueue_rocket_scripts',
|
||||
'script_loader_tag' => [ 'async_wistia_script', 10, 2 ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues WP Rocket scripts on the settings page
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $hook The current admin page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_rocket_scripts( $hook ) {
|
||||
$this->page->enqueue_rocket_scripts( $hook );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the async attribute to the Wistia script
|
||||
*
|
||||
* @param string $tag The <script> tag for the enqueued script.
|
||||
* @param string $handle The script's registered handle.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function async_wistia_script( $tag, $handle ) {
|
||||
return $this->page->async_wistia_script( $tag, $handle );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds plugin page to the Settings menu.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function add_admin_page() {
|
||||
add_options_page(
|
||||
$this->page->get_title(),
|
||||
/**
|
||||
* Filters the menu title to display in the Settings sub-menu
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @param string $menu_title The text to be used for the menu.
|
||||
*/
|
||||
apply_filters( 'rocket_menu_title', $this->page->get_title() ),
|
||||
$this->page->get_capability(),
|
||||
$this->page->get_slug(),
|
||||
[ $this->page, 'render_page' ]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the settings, page sections, fields sections and fields.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function configure() {
|
||||
$this->page->configure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets customer data to refresh it on the dashboard with AJAX.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function refresh_customer_data() {
|
||||
check_ajax_referer( 'rocket-ajax' );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
wp_die();
|
||||
}
|
||||
|
||||
delete_transient( 'wp_rocket_customer_data' );
|
||||
|
||||
return wp_send_json_success( $this->page->customer_data() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle sliding checkboxes option value.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public function toggle_option() {
|
||||
$this->page->toggle_option();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Tools section to navigation.
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
* @param array $navigation Array of menu items.
|
||||
* @return array
|
||||
*/
|
||||
public function add_menu_tools_page( $navigation ) {
|
||||
$navigation['tools'] = [
|
||||
'id' => 'tools',
|
||||
'title' => __( 'Tools', 'rocket' ),
|
||||
'menu_description' => __( 'Import, Export, Rollback', 'rocket' ),
|
||||
];
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Imagify section to navigation.
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @param array $navigation Array of menu items.
|
||||
* @return array
|
||||
*/
|
||||
public function add_imagify_page( $navigation ) {
|
||||
if ( Imagify_Partner::has_imagify_api_key() ) {
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
$navigation['imagify'] = [
|
||||
'id' => 'imagify',
|
||||
'title' => __( 'Image Optimization', 'rocket' ),
|
||||
'menu_description' => __( 'Compress your images', 'rocket' ),
|
||||
];
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Tutorials section to navigation.
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param array $navigation Array of menu items.
|
||||
* @return array
|
||||
*/
|
||||
public function add_tutorials_page( $navigation ) {
|
||||
$navigation['tutorials'] = [
|
||||
'id' => 'tutorials',
|
||||
'title' => __( 'Tutorials', 'rocket' ),
|
||||
'menu_description' => __( 'Getting started and how to videos', 'rocket' ),
|
||||
];
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
}
|
371
wp-content/plugins/wp-rocket/inc/Engine/CDN/CDN.php
Normal file
371
wp-content/plugins/wp-rocket/inc/Engine/CDN/CDN.php
Normal file
@@ -0,0 +1,371 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
|
||||
/**
|
||||
* CDN class
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
class CDN {
|
||||
/**
|
||||
* WP Rocket Options instance
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Home URL host
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $home_host;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Options_Data $options WP Rocket Options instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search & Replace URLs with the CDN URLs in the provided content
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
public function rewrite( $html ) {
|
||||
$pattern = '#[("\']\s*(?<url>(?:(?:https?:|)' . preg_quote( $this->get_base_url(), '#' ) . ')\/(?:(?:(?:' . $this->get_allowed_paths() . ')[^"\',)]+))|\/[^/](?:[^"\')\s>]+\.[[:alnum:]]+))\s*["\')]#i';
|
||||
return preg_replace_callback(
|
||||
$pattern,
|
||||
function( $matches ) {
|
||||
return str_replace( $matches['url'], $this->rewrite_url( $matches['url'] ), $matches[0] );
|
||||
},
|
||||
$html
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites URLs in a srcset attribute using the CDN URL
|
||||
*
|
||||
* @since 3.4.0.4
|
||||
*
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
public function rewrite_srcset( $html ) {
|
||||
$pattern = '#\s+(?:data-lazy-|data-)?srcset\s*=\s*["\']\s*(?<sources>[^"\',\s]+\.[^"\',\s]+(?:\s+\d+[wx])?(?:\s*,\s*[^"\',\s]+\.[^"\',\s]+\s+\d+[wx])*)\s*["\']#i';
|
||||
|
||||
if ( ! preg_match_all( $pattern, $html, $srcsets, PREG_SET_ORDER ) ) {
|
||||
return $html;
|
||||
}
|
||||
foreach ( $srcsets as $srcset ) {
|
||||
$sources = explode( ',', $srcset['sources'] );
|
||||
$sources = array_unique( array_map( 'trim', $sources ) );
|
||||
$cdn_srcset = $srcset['sources'];
|
||||
foreach ( $sources as $source ) {
|
||||
$url = preg_split( '#\s+#', trim( $source ) );
|
||||
$cdn_srcset = str_replace( $url[0], $this->rewrite_url( $url[0] ), $cdn_srcset );
|
||||
}
|
||||
|
||||
$cdn_srcsets = str_replace( $srcset['sources'], $cdn_srcset, $srcset[0] );
|
||||
$html = str_replace( $srcset[0], $cdn_srcsets, $html );
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites an URL with the CDN URL
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param string $url Original URL.
|
||||
* @return string
|
||||
*/
|
||||
public function rewrite_url( $url ) {
|
||||
if ( ! $this->options->get( 'cdn', 0 ) ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
if ( $this->is_excluded( $url ) ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$cdn_urls = $this->get_cdn_urls( $this->get_zones_for_url( $url ) );
|
||||
|
||||
if ( ! $cdn_urls ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$parsed_url = wp_parse_url( $url );
|
||||
$cdn_url = untrailingslashit( $cdn_urls[ ( abs( crc32( $parsed_url['path'] ) ) % count( $cdn_urls ) ) ] );
|
||||
|
||||
if ( ! isset( $parsed_url['host'] ) ) {
|
||||
return rocket_add_url_protocol( $cdn_url . '/' . ltrim( $url, '/' ) );
|
||||
}
|
||||
|
||||
$home_host = $this->get_home_host();
|
||||
|
||||
if ( ! isset( $parsed_url['scheme'] ) ) {
|
||||
return str_replace( $home_host, rocket_remove_url_protocol( $cdn_url ), $url );
|
||||
}
|
||||
|
||||
$home_url = [
|
||||
'http://' . $home_host,
|
||||
'https://' . $home_host,
|
||||
];
|
||||
|
||||
return str_replace( $home_url, rocket_add_url_protocol( $cdn_url ), $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites URLs to CDN URLs in CSS content
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param string $content CSS content.
|
||||
* @return string
|
||||
*/
|
||||
public function rewrite_css_properties( $content ) {
|
||||
if ( ! preg_match_all( '#url\(\s*(\'|")?\s*(?![\'"]?data)(?<url>(?:https?:|)' . preg_quote( $this->get_base_url(), '#' ) . '\/[^"|\'|\)|\s]+)\s*#i', $content, $matches, PREG_SET_ORDER ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
foreach ( $matches as $property ) {
|
||||
/**
|
||||
* Filters the URL of the CSS property
|
||||
*
|
||||
* @since 2.8
|
||||
*
|
||||
* @param string $url URL of the CSS property.
|
||||
*/
|
||||
$cdn_url = $this->rewrite_url( apply_filters( 'rocket_cdn_css_properties_url', $property['url'] ) );
|
||||
$replacement = str_replace( $property['url'], $cdn_url, $property[0] );
|
||||
$content = str_replace( $property[0], $replacement, $content );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all CDN URLs for one or more zones.
|
||||
*
|
||||
* @since 2.1
|
||||
* @since 3.0 Don't check for WP Rocket CDN option activated to be able to use the function on Hosting with CDN auto-enabled.
|
||||
*
|
||||
* @param array $zones List of zones. Default is [ 'all' ].
|
||||
* @return array
|
||||
*/
|
||||
public function get_cdn_urls( $zones = [ 'all' ] ) {
|
||||
$hosts = [];
|
||||
$zones = (array) $zones;
|
||||
$cdn_urls = $this->options->get( 'cdn_cnames', [] );
|
||||
|
||||
if ( $cdn_urls ) {
|
||||
$cdn_zones = $this->options->get( 'cdn_zone', [] );
|
||||
|
||||
foreach ( $cdn_urls as $k => $urls ) {
|
||||
if ( ! in_array( $cdn_zones[ $k ], $zones, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$urls = explode( ',', $urls );
|
||||
$urls = array_map( 'trim', $urls );
|
||||
|
||||
foreach ( $urls as $url ) {
|
||||
$hosts[] = $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter all CDN URLs.
|
||||
*
|
||||
* @since 2.7
|
||||
* @since 3.4 Added $zone parameter.
|
||||
*
|
||||
* @param array $hosts List of CDN URLs.
|
||||
* @param array $zones List of zones. Default is [ 'all' ].
|
||||
*/
|
||||
$hosts = (array) apply_filters( 'rocket_cdn_cnames', $hosts, $zones );
|
||||
$hosts = array_filter( $hosts );
|
||||
$hosts = array_flip( array_flip( $hosts ) );
|
||||
$hosts = array_values( $hosts );
|
||||
|
||||
return $hosts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base URL for the website
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_base_url() {
|
||||
return '//' . $this->get_home_host();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the allowed paths as a regex pattern for the CDN rewrite
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_allowed_paths() {
|
||||
$wp_content_dirname = ltrim( trailingslashit( wp_parse_url( content_url(), PHP_URL_PATH ) ), '/' );
|
||||
$wp_includes_dirname = ltrim( trailingslashit( wp_parse_url( includes_url(), PHP_URL_PATH ) ), '/' );
|
||||
|
||||
$upload_dirname = '';
|
||||
$uploads_info = wp_upload_dir();
|
||||
|
||||
if ( ! empty( $uploads_info['baseurl'] ) ) {
|
||||
$upload_dirname = '|' . ltrim( trailingslashit( wp_parse_url( $uploads_info['baseurl'], PHP_URL_PATH ) ), '/' );
|
||||
}
|
||||
|
||||
return $wp_content_dirname . $upload_dirname . '|' . $wp_includes_dirname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided URL can be rewritten with the CDN URL
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param string $url URL to check.
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_excluded( $url ) {
|
||||
$path = wp_parse_url( $url, PHP_URL_PATH );
|
||||
|
||||
$excluded_extensions = [
|
||||
'php',
|
||||
'html',
|
||||
'htm',
|
||||
];
|
||||
|
||||
if ( in_array( pathinfo( $path, PATHINFO_EXTENSION ), $excluded_extensions, true ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! $path ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( '/' === $path ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( preg_match( '#^(' . $this->get_excluded_files( '#' ) . ')$#', $path ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the home URL host
|
||||
*
|
||||
* @since 3.5.5
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_home_host() {
|
||||
if ( empty( $this->home_host ) ) {
|
||||
$this->home_host = wp_parse_url( home_url(), PHP_URL_HOST );
|
||||
}
|
||||
|
||||
return $this->home_host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CDN zones for the provided URL
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param string $url URL to check.
|
||||
* @return array
|
||||
*/
|
||||
private function get_zones_for_url( $url ) {
|
||||
$zones = [ 'all' ];
|
||||
|
||||
$ext = pathinfo( wp_parse_url( $url, PHP_URL_PATH ), PATHINFO_EXTENSION );
|
||||
|
||||
$image_types = [
|
||||
'jpg',
|
||||
'jpeg',
|
||||
'jpe',
|
||||
'png',
|
||||
'gif',
|
||||
'webp',
|
||||
'bmp',
|
||||
'tiff',
|
||||
'svg',
|
||||
];
|
||||
|
||||
if ( 'css' === $ext || 'js' === $ext ) {
|
||||
$zones[] = 'css_and_js';
|
||||
}
|
||||
|
||||
if ( 'css' === $ext ) {
|
||||
$zones[] = 'css';
|
||||
}
|
||||
|
||||
if ( 'js' === $ext ) {
|
||||
$zones[] = 'js';
|
||||
}
|
||||
|
||||
if ( in_array( $ext, $image_types, true ) ) {
|
||||
$zones[] = 'images';
|
||||
}
|
||||
|
||||
return $zones;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all files we don't allow to get in CDN.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @param string $delimiter RegEx delimiter.
|
||||
* @return string A pipe-separated list of excluded files.
|
||||
*/
|
||||
private function get_excluded_files( $delimiter ) {
|
||||
$files = $this->options->get( 'cdn_reject_files', [] );
|
||||
|
||||
/**
|
||||
* Filter the excluded files.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @param array $files List of excluded files.
|
||||
*/
|
||||
$files = (array) apply_filters( 'rocket_cdn_reject_files', $files );
|
||||
$files = array_filter( $files );
|
||||
|
||||
if ( ! $files ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$files = array_flip( array_flip( $files ) );
|
||||
$files = array_map(
|
||||
function ( $file ) use ( $delimiter ) {
|
||||
return str_replace( $delimiter, '\\' . $delimiter, $file );
|
||||
},
|
||||
$files
|
||||
);
|
||||
|
||||
return implode( '|', $files );
|
||||
}
|
||||
}
|
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN\RocketCDN;
|
||||
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class to Interact with the RocketCDN API
|
||||
*/
|
||||
class APIClient {
|
||||
const ROCKETCDN_API = 'https://rocketcdn.me/api/';
|
||||
|
||||
/**
|
||||
* Gets current RocketCDN subscription data from cache if it exists
|
||||
*
|
||||
* Else do a request to the API to get fresh data
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_subscription_data() {
|
||||
$status = get_transient( 'rocketcdn_status' );
|
||||
|
||||
if ( false !== $status ) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
return $this->get_remote_subscription_data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets fresh RocketCDN subscription data from the API
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_remote_subscription_data() {
|
||||
$default = [
|
||||
'id' => 0,
|
||||
'is_active' => false,
|
||||
'cdn_url' => '',
|
||||
'subscription_next_date_update' => 0,
|
||||
'subscription_status' => 'cancelled',
|
||||
];
|
||||
|
||||
$token = get_option( 'rocketcdn_user_token' );
|
||||
|
||||
if ( empty( $token ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$args = [
|
||||
'headers' => [
|
||||
'Authorization' => 'Token ' . $token,
|
||||
],
|
||||
];
|
||||
|
||||
$response = wp_remote_get(
|
||||
self::ROCKETCDN_API . 'website/search/?url=' . home_url(),
|
||||
$args
|
||||
);
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
$this->set_status_transient( $default, 3 * MINUTE_IN_SECONDS );
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
$data = wp_remote_retrieve_body( $response );
|
||||
|
||||
if ( empty( $data ) ) {
|
||||
$this->set_status_transient( $default, 3 * MINUTE_IN_SECONDS );
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
$data = json_decode( $data, true );
|
||||
$data = array_intersect_key( (array) $data, $default );
|
||||
$data = array_merge( $default, $data );
|
||||
|
||||
$this->set_status_transient( $data, WEEK_IN_SECONDS );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the RocketCDN status transient with the provided value
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $value Transient value.
|
||||
* @param int $duration Transient duration.
|
||||
* @return void
|
||||
*/
|
||||
private function set_status_transient( $value, $duration ) {
|
||||
set_transient( 'rocketcdn_status', $value, $duration );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets pricing & promotion data for RocketCDN from cache if it exists
|
||||
*
|
||||
* Else do a request to the API to get fresh data
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_pricing_data() {
|
||||
$pricing = get_transient( 'rocketcdn_pricing' );
|
||||
|
||||
if ( false !== $pricing ) {
|
||||
return $pricing;
|
||||
}
|
||||
|
||||
return $this->get_remote_pricing_data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets fresh pricing & promotion data for RocketCDN
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
private function get_remote_pricing_data() {
|
||||
$response = wp_remote_get( self::ROCKETCDN_API . 'pricing' );
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return $this->get_wp_error();
|
||||
}
|
||||
|
||||
$data = wp_remote_retrieve_body( $response );
|
||||
|
||||
if ( empty( $data ) ) {
|
||||
return $this->get_wp_error();
|
||||
}
|
||||
|
||||
$data = json_decode( $data, true );
|
||||
|
||||
set_transient( 'rocketcdn_pricing', $data, 6 * HOUR_IN_SECONDS );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a new WP_Error instance
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return WP_Error
|
||||
*/
|
||||
private function get_wp_error() {
|
||||
return new WP_Error( 'rocketcdn_error', __( 'RocketCDN is not available at the moment. Please retry later', 'rocket' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to the API to purge the CDN cache
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function purge_cache_request() {
|
||||
$subscription = $this->get_subscription_data();
|
||||
$status = 'error';
|
||||
|
||||
if ( ! isset( $subscription['id'] ) || 0 === $subscription['id'] ) {
|
||||
return [
|
||||
'status' => $status,
|
||||
'message' => __( 'RocketCDN cache purge failed: Missing identifier parameter.', 'rocket' ),
|
||||
];
|
||||
}
|
||||
|
||||
$token = get_option( 'rocketcdn_user_token' );
|
||||
|
||||
if ( empty( $token ) ) {
|
||||
return [
|
||||
'status' => $status,
|
||||
'message' => __( 'RocketCDN cache purge failed: Missing user token.', 'rocket' ),
|
||||
];
|
||||
}
|
||||
|
||||
$args = [
|
||||
'method' => 'DELETE',
|
||||
'headers' => [
|
||||
'Authorization' => 'Token ' . $token,
|
||||
],
|
||||
];
|
||||
|
||||
$response = wp_remote_request(
|
||||
self::ROCKETCDN_API . 'website/' . $subscription['id'] . '/purge/',
|
||||
$args
|
||||
);
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return [
|
||||
'status' => $status,
|
||||
'message' => __( 'RocketCDN cache purge failed: The API returned an unexpected response code.', 'rocket' ),
|
||||
];
|
||||
}
|
||||
|
||||
$data = wp_remote_retrieve_body( $response );
|
||||
|
||||
if ( empty( $data ) ) {
|
||||
return [
|
||||
'status' => $status,
|
||||
'message' => __( 'RocketCDN cache purge failed: The API returned an empty response.', 'rocket' ),
|
||||
];
|
||||
}
|
||||
|
||||
$data = json_decode( $data );
|
||||
|
||||
if ( ! isset( $data->success ) ) {
|
||||
return [
|
||||
'status' => $status,
|
||||
'message' => __( 'RocketCDN cache purge failed: The API returned an unexpected response.', 'rocket' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( ! $data->success ) {
|
||||
return [
|
||||
'status' => $status,
|
||||
'message' => sprintf(
|
||||
// translators: %s = message returned by the API.
|
||||
__( 'RocketCDN cache purge failed: %s.', 'rocket' ),
|
||||
$data->message
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'message' => __( 'RocketCDN cache purge successful.', 'rocket' ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the arguments used in an HTTP request, to make sure our user token has not been overwritten
|
||||
* by some other plugin.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $args An array of HTTP request arguments.
|
||||
* @param string $url The request URL.
|
||||
* @return array
|
||||
*/
|
||||
public function preserve_authorization_token( $args, $url ) {
|
||||
if ( strpos( $url, self::ROCKETCDN_API ) === false ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
if ( empty( $args['headers']['Authorization'] ) && self::ROCKETCDN_API . 'pricing' === $url ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$token = get_option( 'rocketcdn_user_token' );
|
||||
|
||||
if ( empty( $token ) ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$value = 'token ' . $token;
|
||||
|
||||
if ( isset( $args['headers']['Authorization'] ) && $value === $args['headers']['Authorization'] ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$args['headers']['Authorization'] = $value;
|
||||
|
||||
return $args;
|
||||
}
|
||||
}
|
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CDN\RocketCDN;
|
||||
|
||||
use WP_Rocket\Abstract_Render;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Engine\Admin\Beacon\Beacon;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the RocketCDN integration in WP Rocket settings page
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class AdminPageSubscriber extends Abstract_Render implements Subscriber_Interface {
|
||||
/**
|
||||
* RocketCDN API Client instance.
|
||||
*
|
||||
* @var APIClient
|
||||
*/
|
||||
private $api_client;
|
||||
|
||||
/**
|
||||
* WP Rocket options instance
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Beacon instance
|
||||
*
|
||||
* @var Beacon
|
||||
*/
|
||||
private $beacon;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param APIClient $api_client RocketCDN API Client instance.
|
||||
* @param Options_Data $options WP Rocket options instance.
|
||||
* @param Beacon $beacon Beacon instance.
|
||||
* @param string $template_path Path to the templates.
|
||||
*/
|
||||
public function __construct( APIClient $api_client, Options_Data $options, Beacon $beacon, $template_path ) {
|
||||
parent::__construct( $template_path );
|
||||
|
||||
$this->api_client = $api_client;
|
||||
$this->options = $options;
|
||||
$this->beacon = $beacon;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rocket_dashboard_after_account_data' => 'display_rocketcdn_status',
|
||||
'rocket_after_cdn_sections' => 'display_manage_subscription',
|
||||
'rocket_cdn_settings_fields' => 'rocketcdn_field',
|
||||
'admin_post_rocket_purge_rocketcdn' => 'purge_cdn_cache',
|
||||
'rocket_settings_page_footer' => 'add_subscription_modal',
|
||||
'http_request_args' => [ 'preserve_authorization_token', PHP_INT_MAX, 2 ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the RocketCDN section on the dashboard tab
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_rocketcdn_status() {
|
||||
if ( $this->is_white_label_account() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subscription_data = $this->api_client->get_subscription_data();
|
||||
|
||||
if ( 'running' === $subscription_data['subscription_status'] ) {
|
||||
$label = __( 'Next Billing Date', 'rocket' );
|
||||
$status_class = ' wpr-isValid';
|
||||
$container_class = '';
|
||||
$status_text = date_i18n( get_option( 'date_format' ), strtotime( $subscription_data['subscription_next_date_update'] ) );
|
||||
$is_active = true;
|
||||
} elseif ( 'cancelled' === $subscription_data['subscription_status'] ) {
|
||||
$label = '';
|
||||
$status_class = ' wpr-isInvalid';
|
||||
$container_class = ' wpr-flex--egal';
|
||||
$status_text = __( 'No Subscription', 'rocket' );
|
||||
$is_active = false;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'is_live_site' => rocket_is_live_site(),
|
||||
'container_class' => $container_class,
|
||||
'label' => $label,
|
||||
'status_class' => $status_class,
|
||||
'status_text' => $status_text,
|
||||
'is_active' => $is_active,
|
||||
];
|
||||
|
||||
echo $this->generate( 'dashboard-status', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the RocketCDN fields to the CDN section
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $fields CDN settings fields.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rocketcdn_field( $fields ) {
|
||||
if ( $this->is_white_label_account() ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$subscription_data = $this->api_client->get_subscription_data();
|
||||
|
||||
if ( 'running' !== $subscription_data['subscription_status'] ) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$helper_text = __( 'Your RocketCDN subscription is currently active.', 'rocket' );
|
||||
$cdn_cnames = $this->options->get( 'cdn_cnames', [] );
|
||||
|
||||
if ( empty( $cdn_cnames ) || $cdn_cnames[0] !== $subscription_data['cdn_url'] ) {
|
||||
$helper_text = sprintf(
|
||||
// translators: %1$s = opening <code> tag, %2$s = CDN URL, %3$s = closing </code> tag.
|
||||
__( 'To use RocketCDN, replace your CNAME with %1$s%2$s%3$s.', 'rocket' ),
|
||||
'<code>',
|
||||
$subscription_data['cdn_url'],
|
||||
'</code>'
|
||||
);
|
||||
}
|
||||
|
||||
$beacon = $this->beacon->get_suggest( 'rocketcdn' );
|
||||
|
||||
$more_info = sprintf(
|
||||
// translators: %1$is = opening link tag, %2$s = closing link tag.
|
||||
__( '%1$sMore Info%2$s', 'rocket' ),
|
||||
'<a href="' . esc_url( $beacon['url'] ) . '" data-beacon-article="' . esc_attr( $beacon['id'] ) . '" rel="noopener noreferrer" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
|
||||
$fields['cdn_cnames'] = [
|
||||
'type' => 'rocket_cdn',
|
||||
'label' => __( 'CDN CNAME(s)', 'rocket' ),
|
||||
'description' => __( 'Specify the CNAME(s) below', 'rocket' ),
|
||||
'helper' => $helper_text . ' ' . $more_info,
|
||||
'default' => '',
|
||||
'section' => 'cnames_section',
|
||||
'page' => 'page_cdn',
|
||||
'beacon' => [
|
||||
'url' => $beacon['url'],
|
||||
'id' => $beacon['id'],
|
||||
],
|
||||
];
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the button to open the subscription modal
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_manage_subscription() {
|
||||
if ( $this->is_white_label_account() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! rocket_is_live_site() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subscription_data = $this->api_client->get_subscription_data();
|
||||
|
||||
if ( 'running' !== $subscription_data['subscription_status'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<p class="wpr-rocketcdn-subscription">
|
||||
<button class="wpr-rocketcdn-open" data-micromodal-trigger="wpr-rocketcdn-modal"><?php esc_html_e( 'Manage Subscription', 'rocket' ); ?></button>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the CDN cache and store the response in a transient.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function purge_cdn_cache() {
|
||||
if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'rocket_purge_rocketcdn' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
wp_nonce_ays( '' );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
wp_die();
|
||||
}
|
||||
|
||||
set_transient( 'rocketcdn_purge_cache_response', $this->api_client->purge_cache_request(), HOUR_IN_SECONDS );
|
||||
|
||||
wp_safe_redirect( esc_url_raw( wp_get_referer() ) );
|
||||
rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ? wp_die() : exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the subscription modal on the WP Rocket settings page
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_subscription_modal() {
|
||||
if ( $this->is_white_label_account() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! rocket_is_live_site() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$iframe_src = add_query_arg(
|
||||
[
|
||||
'website' => home_url(),
|
||||
'callback' => rest_url( 'wp-rocket/v1/rocketcdn/' ),
|
||||
],
|
||||
rocket_get_constant( 'WP_ROCKET_WEB_MAIN' ) . 'cdn/iframe'
|
||||
);
|
||||
?>
|
||||
<div class="wpr-rocketcdn-modal" id="wpr-rocketcdn-modal" aria-hidden="true">
|
||||
<div class="wpr-rocketcdn-modal__overlay" tabindex="-1">
|
||||
<div class="wpr-rocketcdn-modal__container" role="dialog" aria-modal="true" aria-labelledby="wpr-rocketcdn-modal-title">
|
||||
<div id="wpr-rocketcdn-modal-content">
|
||||
<iframe id="rocketcdn-iframe" src="<?php echo esc_url( $iframe_src ); ?>" width="674" height="425"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the arguments used in an HTTP request, to make sure our user token has not been overwritten
|
||||
* by some other plugin.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $args An array of HTTP request arguments.
|
||||
* @param string $url The request URL.
|
||||
* @return array
|
||||
*/
|
||||
public function preserve_authorization_token( $args, $url ) {
|
||||
return $this->api_client->preserve_authorization_token( $args, $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if white label is enabled
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_white_label_account() {
|
||||
return (bool) rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT' );
|
||||
}
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN\RocketCDN;
|
||||
|
||||
use WP_Rocket\Admin\Options;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
|
||||
/**
|
||||
* Manager for WP Rocket CDN options
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class CDNOptionsManager {
|
||||
/**
|
||||
* WP Options API instance
|
||||
*
|
||||
* @var Options
|
||||
*/
|
||||
private $options_api;
|
||||
|
||||
/**
|
||||
* WP Rocket Options instance
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Options $options_api WP Options API instance.
|
||||
* @param Options_Data $options WP Rocket Options instance.
|
||||
*/
|
||||
public function __construct( Options $options_api, Options_Data $options ) {
|
||||
$this->options_api = $options_api;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable CDN option, save CDN URL & delete RocketCDN status transient
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param string $cdn_url CDN URL.
|
||||
* @return void
|
||||
*/
|
||||
public function enable( $cdn_url ) {
|
||||
$this->options->set( 'cdn', 1 );
|
||||
$this->options->set( 'cdn_cnames', [ $cdn_url ] );
|
||||
$this->options->set( 'cdn_zone', [ 'all' ] );
|
||||
|
||||
$this->options_api->set( 'settings', $this->options->get_options() );
|
||||
|
||||
delete_transient( 'rocketcdn_status' );
|
||||
rocket_clean_domain();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable CDN option, remove CDN URL & user token, delete RocketCDN status transient
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disable() {
|
||||
$this->options->set( 'cdn', 0 );
|
||||
$this->options->set( 'cdn_cnames', [] );
|
||||
$this->options->set( 'cdn_zone', [] );
|
||||
|
||||
$this->options_api->set( 'settings', $this->options->get_options() );
|
||||
|
||||
delete_option( 'rocketcdn_user_token' );
|
||||
delete_transient( 'rocketcdn_status' );
|
||||
rocket_clean_domain();
|
||||
}
|
||||
}
|
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN\RocketCDN;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the RocketCDN integration in WP Rocket settings page
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class DataManagerSubscriber implements Subscriber_Interface {
|
||||
const CRON_EVENT = 'rocketcdn_check_subscription_status_event';
|
||||
|
||||
/**
|
||||
* RocketCDN API Client instance.
|
||||
*
|
||||
* @var APIClient
|
||||
*/
|
||||
private $api_client;
|
||||
|
||||
/**
|
||||
* CDNOptionsManager instance.
|
||||
*
|
||||
* @var CDNOptionsManager
|
||||
*/
|
||||
private $cdn_options;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param APIClient $api_client RocketCDN API Client instance.
|
||||
* @param CDNOptionsManager $cdn_options CDNOptionsManager instance.
|
||||
*/
|
||||
public function __construct( APIClient $api_client, CDNOptionsManager $cdn_options ) {
|
||||
$this->api_client = $api_client;
|
||||
$this->cdn_options = $cdn_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'wp_ajax_save_rocketcdn_token' => 'update_user_token',
|
||||
'wp_ajax_rocketcdn_enable' => 'enable',
|
||||
'wp_ajax_rocketcdn_disable' => 'disable',
|
||||
'wp_ajax_rocketcdn_process_set' => 'set_process_status',
|
||||
'wp_ajax_rocketcdn_process_status' => 'get_process_status',
|
||||
self::CRON_EVENT => 'maybe_disable_cdn',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the RocketCDN user token value
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_user_token() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
wp_send_json_error( 'unauthorized_user' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( empty( $_POST['value'] ) ) {
|
||||
delete_option( 'rocketcdn_user_token' );
|
||||
|
||||
wp_send_json_success( 'user_token_deleted' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_string( $_POST['value'] ) ) {
|
||||
wp_send_json_error( 'invalid_token' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$token = sanitize_key( $_POST['value'] );
|
||||
|
||||
if ( 40 !== strlen( $token ) ) {
|
||||
wp_send_json_error( 'invalid_token_length' );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
update_option( 'rocketcdn_user_token', $token );
|
||||
|
||||
wp_send_json_success( 'user_token_saved' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback to enable RocketCDN
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enable() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
$data = [
|
||||
'process' => 'subscribe',
|
||||
];
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
$data['message'] = 'unauthorized_user';
|
||||
|
||||
wp_send_json_error( $data );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( empty( $_POST['cdn_url'] ) ) {
|
||||
$data['message'] = 'cdn_url_empty';
|
||||
|
||||
wp_send_json_error( $data );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$cdn_url = filter_var( wp_unslash( $_POST['cdn_url'] ), FILTER_VALIDATE_URL );
|
||||
|
||||
if ( ! $cdn_url ) {
|
||||
$data['message'] = 'cdn_url_invalid_format';
|
||||
|
||||
wp_send_json_error( $data );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cdn_options->enable( esc_url_raw( $cdn_url ) );
|
||||
|
||||
$subscription = $this->api_client->get_subscription_data();
|
||||
|
||||
$this->schedule_subscription_check( $subscription );
|
||||
$this->delete_process();
|
||||
|
||||
$data['message'] = 'rocketcdn_enabled';
|
||||
|
||||
wp_send_json_success( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback to disable RocketCDN
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disable() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
$data = [
|
||||
'process' => 'unsubscribe',
|
||||
];
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
$data['message'] = 'unauthorized_user';
|
||||
|
||||
wp_send_json_error( $data );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cdn_options->disable();
|
||||
|
||||
$timestamp = wp_next_scheduled( self::CRON_EVENT );
|
||||
|
||||
if ( $timestamp ) {
|
||||
wp_unschedule_event( $timestamp, self::CRON_EVENT );
|
||||
}
|
||||
|
||||
$this->delete_process();
|
||||
|
||||
$data['message'] = 'rocketcdn_disabled';
|
||||
|
||||
wp_send_json_success( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the option tracking the RocketCDN process state
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function delete_process() {
|
||||
delete_option( 'rocketcdn_process' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the RocketCDN subscription process status
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_process_status() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( empty( $_POST['status'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$status = filter_var( $_POST['status'], FILTER_VALIDATE_BOOLEAN ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Used as a boolean.
|
||||
|
||||
if ( false === $status ) {
|
||||
delete_option( 'rocketcdn_process' );
|
||||
return;
|
||||
}
|
||||
|
||||
update_option( 'rocketcdn_process', $status );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for RocketCDN subscription process status
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function get_process_status() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
wp_send_json_error();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( get_option( 'rocketcdn_process' ) ) {
|
||||
wp_send_json_success();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cron job to disable CDN if the subscription expired
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_disable_cdn() {
|
||||
delete_transient( 'rocketcdn_status' );
|
||||
|
||||
$subscription = $this->api_client->get_subscription_data();
|
||||
|
||||
if ( rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ) {
|
||||
$subscription = apply_filters( 'rocket_pre_get_subscription_data', $subscription );
|
||||
}
|
||||
|
||||
if ( 'running' === $subscription['subscription_status'] ) {
|
||||
$this->schedule_subscription_check( $subscription );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cdn_options->disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the next cron subscription check
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $subscription Array containing the subscription data.
|
||||
* @return void
|
||||
*/
|
||||
private function schedule_subscription_check( $subscription ) {
|
||||
$timestamp = strtotime( $subscription['subscription_next_date_update'] ) + strtotime( '+2 days' );
|
||||
|
||||
if ( ! wp_next_scheduled( self::CRON_EVENT ) ) {
|
||||
wp_schedule_single_event( $timestamp, self::CRON_EVENT );
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,300 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN\RocketCDN;
|
||||
|
||||
use WP_Rocket\Abstract_Render;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the RocketCDN notices on WP Rocket settings page
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class NoticesSubscriber extends Abstract_Render implements Subscriber_Interface {
|
||||
/**
|
||||
* RocketCDN API Client instance.
|
||||
*
|
||||
* @var APIClient
|
||||
*/
|
||||
private $api_client;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param APIClient $api_client RocketCDN API Client instance.
|
||||
* @param string $template_path Path to the templates.
|
||||
*/
|
||||
public function __construct( APIClient $api_client, $template_path ) {
|
||||
parent::__construct( $template_path );
|
||||
|
||||
$this->api_client = $api_client;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'admin_notices' => [
|
||||
[ 'promote_rocketcdn_notice' ],
|
||||
[ 'purge_cache_notice' ],
|
||||
],
|
||||
'rocket_before_cdn_sections' => 'display_rocketcdn_cta',
|
||||
'wp_ajax_toggle_rocketcdn_cta' => 'toggle_cta',
|
||||
'wp_ajax_rocketcdn_dismiss_notice' => 'dismiss_notice',
|
||||
'admin_footer' => 'add_dismiss_script',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds notice to promote RocketCDN on settings page
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function promote_rocketcdn_notice() {
|
||||
if ( $this->is_white_label_account() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! rocket_is_live_site() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->should_display_notice() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo $this->generate( 'promote-notice' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds inline script to permanently dismissing the RocketCDN promotion notice
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_dismiss_script() {
|
||||
if ( $this->is_white_label_account() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! rocket_is_live_site() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->should_display_notice() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$nonce = wp_create_nonce( 'rocketcdn_dismiss_notice' );
|
||||
?>
|
||||
<script>
|
||||
window.addEventListener( 'load', function() {
|
||||
var dismissBtn = document.querySelectorAll( '#rocketcdn-promote-notice .notice-dismiss, #rocketcdn-promote-notice #rocketcdn-learn-more-dismiss' );
|
||||
|
||||
dismissBtn.forEach(function(element) {
|
||||
element.addEventListener( 'click', function( event ) {
|
||||
var httpRequest = new XMLHttpRequest(),
|
||||
postData = '';
|
||||
|
||||
postData += 'action=rocketcdn_dismiss_notice';
|
||||
postData += '&nonce=<?php echo esc_attr( $nonce ); ?>';
|
||||
httpRequest.open( 'POST', '<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>' );
|
||||
httpRequest.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' )
|
||||
httpRequest.send( postData );
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the promotion notice should be displayed
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function should_display_notice() {
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( 'settings_page_wprocket' !== get_current_screen()->id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( get_user_meta( get_current_user_id(), 'rocketcdn_dismiss_notice', true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$subscription_data = $this->api_client->get_subscription_data();
|
||||
|
||||
return 'running' !== $subscription_data['subscription_status'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback to save the dismiss as a user meta
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dismiss_notice() {
|
||||
check_ajax_referer( 'rocketcdn_dismiss_notice', 'nonce', true );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_user_meta( get_current_user_id(), 'rocketcdn_dismiss_notice', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the RocketCDN Call to Action on the CDN tab of WP Rocket settings page
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_rocketcdn_cta() {
|
||||
if ( $this->is_white_label_account() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! rocket_is_live_site() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subscription_data = $this->api_client->get_subscription_data();
|
||||
|
||||
if ( 'running' === $subscription_data['subscription_status'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pricing = $this->api_client->get_pricing_data();
|
||||
|
||||
$regular_price = '';
|
||||
$nopromo_variant = '--no-promo';
|
||||
$cta_small_class = 'wpr-isHidden';
|
||||
$cta_big_class = '';
|
||||
|
||||
if ( get_user_meta( get_current_user_id(), 'rocket_rocketcdn_cta_hidden', true ) ) {
|
||||
$cta_small_class = '';
|
||||
$cta_big_class = 'wpr-isHidden';
|
||||
}
|
||||
|
||||
$small_cta_data = [
|
||||
'container_class' => $cta_small_class,
|
||||
];
|
||||
|
||||
if ( is_wp_error( $pricing ) ) {
|
||||
$big_cta_data = [
|
||||
'container_class' => $cta_big_class,
|
||||
'nopromo_variant' => $nopromo_variant,
|
||||
'error' => true,
|
||||
'message' => $pricing->get_error_message(),
|
||||
];
|
||||
} else {
|
||||
$current_price = number_format_i18n( $pricing['monthly_price'], 2 );
|
||||
$promotion_campaign = '';
|
||||
$end_date = strtotime( $pricing['end_date'] );
|
||||
$promotion_end_date = '';
|
||||
|
||||
if (
|
||||
$pricing['is_discount_active']
|
||||
&&
|
||||
$end_date > time()
|
||||
) {
|
||||
$promotion_campaign = $pricing['discount_campaign_name'];
|
||||
$regular_price = $current_price;
|
||||
$current_price = number_format_i18n( $pricing['discounted_price_monthly'], 2 ) . '*';
|
||||
$nopromo_variant = '';
|
||||
$promotion_end_date = date_i18n( get_option( 'date_format' ), $end_date );
|
||||
}
|
||||
|
||||
$big_cta_data = [
|
||||
'container_class' => $cta_big_class,
|
||||
'promotion_campaign' => $promotion_campaign,
|
||||
'promotion_end_date' => $promotion_end_date,
|
||||
'nopromo_variant' => $nopromo_variant,
|
||||
'regular_price' => $regular_price,
|
||||
'current_price' => $current_price,
|
||||
];
|
||||
}
|
||||
|
||||
echo $this->generate( 'cta-small', $small_cta_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
echo $this->generate( 'cta-big', $big_cta_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view.
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles display of the RocketCDN CTAs on the settings page
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function toggle_cta() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! isset( $_POST['status'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'big' === $_POST['status'] ) {
|
||||
delete_user_meta( get_current_user_id(), 'rocket_rocketcdn_cta_hidden' );
|
||||
} elseif ( 'small' === $_POST['status'] ) {
|
||||
update_user_meta( get_current_user_id(), 'rocket_rocketcdn_cta_hidden', true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a notice after purging the RocketCDN cache.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function purge_cache_notice() {
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'settings_page_wprocket' !== get_current_screen()->id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$purge_response = get_transient( 'rocketcdn_purge_cache_response' );
|
||||
|
||||
if ( false === $purge_response ) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete_transient( 'rocketcdn_purge_cache_response' );
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => $purge_response['status'],
|
||||
'message' => $purge_response['message'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if white label is enabled
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_white_label_account() {
|
||||
return (bool) rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT' );
|
||||
}
|
||||
}
|
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN\RocketCDN;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
|
||||
/**
|
||||
* Subscriber for RocketCDN REST API Integration
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class RESTSubscriber implements Subscriber_Interface {
|
||||
const ROUTE_NAMESPACE = 'wp-rocket/v1';
|
||||
|
||||
/**
|
||||
* CDNOptionsManager instance
|
||||
*
|
||||
* @var CDNOptionsManager
|
||||
*/
|
||||
private $cdn_options;
|
||||
|
||||
/**
|
||||
* WP Rocket Options instance
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param CDNOptionsManager $cdn_options CDNOptionsManager instance.
|
||||
* @param Options_Data $options WP Rocket Options instance.
|
||||
*/
|
||||
public function __construct( CDNOptionsManager $cdn_options, Options_Data $options ) {
|
||||
$this->cdn_options = $cdn_options;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rest_api_init' => [
|
||||
[ 'register_enable_route' ],
|
||||
[ 'register_disable_route' ],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Enable route in the WP REST API
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_enable_route() {
|
||||
register_rest_route(
|
||||
self::ROUTE_NAMESPACE,
|
||||
'rocketcdn/enable',
|
||||
[
|
||||
'methods' => 'PUT',
|
||||
'callback' => [ $this, 'enable' ],
|
||||
'args' => [
|
||||
'email' => [
|
||||
'required' => true,
|
||||
'validate_callback' => [ $this, 'validate_email' ],
|
||||
],
|
||||
'key' => [
|
||||
'required' => true,
|
||||
'validate_callback' => [ $this, 'validate_key' ],
|
||||
],
|
||||
'url' => [
|
||||
'required' => true,
|
||||
'validate_callback' => function ( $param ) {
|
||||
$url = esc_url_raw( $param );
|
||||
|
||||
return ! empty( $url );
|
||||
},
|
||||
'sanitize_callback' => function ( $param ) {
|
||||
return esc_url_raw( $param );
|
||||
},
|
||||
],
|
||||
],
|
||||
'permission_callback' => '__return_true',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Disable route in the WP REST API
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_disable_route() {
|
||||
register_rest_route(
|
||||
self::ROUTE_NAMESPACE,
|
||||
'rocketcdn/disable',
|
||||
[
|
||||
'methods' => 'PUT',
|
||||
'callback' => [ $this, 'disable' ],
|
||||
'args' => [
|
||||
'email' => [
|
||||
'required' => true,
|
||||
'validate_callback' => [ $this, 'validate_email' ],
|
||||
],
|
||||
'key' => [
|
||||
'required' => true,
|
||||
'validate_callback' => [ $this, 'validate_key' ],
|
||||
],
|
||||
],
|
||||
'permission_callback' => '__return_true',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable CDN and add RocketCDN URL to WP Rocket options
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param \WP_REST_Request $request the WP REST Request object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function enable( \WP_REST_Request $request ) {
|
||||
$params = $request->get_body_params();
|
||||
|
||||
$this->cdn_options->enable( $params['url'] );
|
||||
|
||||
$response = [
|
||||
'code' => 'success',
|
||||
'message' => __( 'RocketCDN enabled', 'rocket' ),
|
||||
'data' => [
|
||||
'status' => 200,
|
||||
],
|
||||
];
|
||||
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the CDN and remove the RocketCDN URL from WP Rocket options
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param \WP_REST_Request $request the WP Rest Request object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function disable( \WP_REST_Request $request ) {
|
||||
$this->cdn_options->disable();
|
||||
|
||||
$response = [
|
||||
'code' => 'success',
|
||||
'message' => __( 'RocketCDN disabled', 'rocket' ),
|
||||
'data' => [
|
||||
'status' => 200,
|
||||
],
|
||||
];
|
||||
|
||||
return rest_ensure_response( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the email sent along the request corresponds to the one saved in the DB
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param string $param Parameter value to validate.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validate_email( $param ) {
|
||||
return $param === $this->options->get( 'consumer_email' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the key sent along the request corresponds to the one saved in the DB
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param string $param Parameter value to validate.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validate_key( $param ) {
|
||||
return $param === $this->options->get( 'consumer_key' );
|
||||
}
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN\RocketCDN;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service provider for RocketCDN
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'rocketcdn_api_client',
|
||||
'rocketcdn_options_manager',
|
||||
'rocketcdn_data_manager_subscriber',
|
||||
'rocketcdn_rest_subscriber',
|
||||
'rocketcdn_admin_subscriber',
|
||||
'rocketcdn_notices_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the RocketCDN classes in the container
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$options = $this->getContainer()->get( 'options' );
|
||||
// RocketCDN API Client.
|
||||
$this->getContainer()->add( 'rocketcdn_api_client', 'WP_Rocket\Engine\CDN\RocketCDN\APIClient' );
|
||||
// RocketCDN CDN options manager.
|
||||
$this->getContainer()->add( 'rocketcdn_options_manager', 'WP_Rocket\Engine\CDN\RocketCDN\CDNOptionsManager' )
|
||||
->withArgument( $this->getContainer()->get( 'options_api' ) )
|
||||
->withArgument( $options );
|
||||
// RocketCDN Data manager subscriber.
|
||||
$this->getContainer()->share( 'rocketcdn_data_manager_subscriber', 'WP_Rocket\Engine\CDN\RocketCDN\DataManagerSubscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) )
|
||||
->withArgument( $this->getContainer()->get( 'rocketcdn_options_manager' ) );
|
||||
// RocketCDN REST API Subscriber.
|
||||
$this->getContainer()->share( 'rocketcdn_rest_subscriber', 'WP_Rocket\Engine\CDN\RocketCDN\RESTSubscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'rocketcdn_options_manager' ) )
|
||||
->withArgument( $options );
|
||||
// RocketCDN Notices Subscriber.
|
||||
$this->getContainer()->share( 'rocketcdn_notices_subscriber', 'WP_Rocket\Engine\CDN\RocketCDN\NoticesSubscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) )
|
||||
->withArgument( __DIR__ . '/views' );
|
||||
// RocketCDN settings page subscriber.
|
||||
$this->getContainer()->share( 'rocketcdn_admin_subscriber', 'WP_Rocket\Engine\CDN\RocketCDN\AdminPageSubscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) )
|
||||
->withArgument( $options )
|
||||
->withArgument( $this->getContainer()->get( 'beacon' ) )
|
||||
->withArgument( __DIR__ . '/views' );
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "wp-media/module-rocketcdn",
|
||||
"description": "Module for RocketCDN integration",
|
||||
"homepage": "https://github.com/wp-media/module-rocketcdn",
|
||||
"license": "GPL-2.0+",
|
||||
"authors": [
|
||||
{
|
||||
"name": "WP Media",
|
||||
"email": "contact@wp-media.me",
|
||||
"homepage": "https://wp-media.me"
|
||||
}
|
||||
],
|
||||
"type": "library",
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"support": {
|
||||
"issues": "https://github.com/wp-media/module-rocketcdn/issues",
|
||||
"source": "https://github.com/wp-media/module-rocketcdn"
|
||||
},
|
||||
"require-dev": {
|
||||
"php": "^5.6 || ^7",
|
||||
"brain/monkey": "^2.0",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
|
||||
"phpcompatibility/phpcompatibility-wp": "^2.0",
|
||||
"phpunit/phpunit": "^5.7 || ^7",
|
||||
"roave/security-advisories": "dev-master",
|
||||
"wp-coding-standards/wpcs": "^2",
|
||||
"wp-media/event-manager": "^3.1",
|
||||
"wp-media/options": "^3.0",
|
||||
"wp-media/module-container": "^2.4",
|
||||
"wp-media/phpunit": "^1.0",
|
||||
"wp-media/phpunit-wp-rocket": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "WP_Rocket\\Engine\\CDN\\RocketCDN\\": "." }
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": { "WP_Rocket\\Tests\\": "Tests/" }
|
||||
},
|
||||
"scripts": {
|
||||
"test-unit": "\"vendor/bin/phpunit\" --testsuite unit --colors=always --configuration Tests/Unit/phpunit.xml.dist",
|
||||
"test-integration": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration Tests/Integration/phpunit.xml.dist --exclude-group AdminOnly",
|
||||
"test-integration-adminonly": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration Tests/Integration/phpunit.xml.dist --group AdminOnly",
|
||||
"run-tests": [
|
||||
"@test-unit",
|
||||
"@test-integration",
|
||||
"@test-integration-adminonly"
|
||||
],
|
||||
"install-codestandards": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run",
|
||||
"phpcs": "phpcs --basepath=.",
|
||||
"phpcs-changed": "./bin/phpcs-changed.sh",
|
||||
"phpcs:fix": "phpcbf"
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* RocketCDN small CTA template.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $data {
|
||||
* @type string $container_class container CSS class.
|
||||
* @type string $promotion_campaign Promotion campaign title.
|
||||
* @type string $promotion_end_date Promotion end date.
|
||||
* @type string $nopromo_variant CSS modifier for the no promotion display.
|
||||
* @type string $regular_price RocketCDN regular price.
|
||||
* @type string $current_price RocketCDN current price.
|
||||
* }
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
?>
|
||||
<div class="wpr-rocketcdn-cta <?php echo esc_attr( $data['container_class'] ); ?>" id="wpr-rocketcdn-cta">
|
||||
<?php if ( ! empty( $data['promotion_campaign'] ) ) : ?>
|
||||
<div class="wpr-flex wpr-rocketcdn-promo">
|
||||
<h3 class="wpr-title1"><?php echo esc_html( $data['promotion_campaign'] ); ?></h3>
|
||||
<p class="wpr-title2 wpr-rocketcdn-promo-date">
|
||||
<?php
|
||||
printf(
|
||||
// Translators: %s = date formatted using date_i18n() and get_option( 'date_format' ).
|
||||
esc_html__( 'Valid until %s only!', 'rocket' ),
|
||||
esc_html( $data['promotion_end_date'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<section class="wpr-rocketcdn-cta-content<?php echo esc_attr( $data['nopromo_variant'] ); ?>">
|
||||
<h3 class="wpr-title2">RocketCDN</h3>
|
||||
<p class="wpr-rocketcdn-cta-subtitle"><?php esc_html_e( 'Speed up your website thanks to:', 'rocket' ); ?></p>
|
||||
<div class="wpr-flex">
|
||||
<ul class="wpr-rocketcdn-features">
|
||||
<li class="wpr-rocketcdn-feature wpr-rocketcdn-bandwidth">
|
||||
<?php
|
||||
// translators: %1$s = opening strong tag, %2$s = closing strong tag.
|
||||
printf( esc_html__( 'High performance Content Delivery Network (CDN) with %1$sunlimited bandwith%2$s', 'rocket' ), '<strong>', '</strong>' );
|
||||
?>
|
||||
</li>
|
||||
<li class="wpr-rocketcdn-feature wpr-rocketcdn-configuration">
|
||||
<?php
|
||||
// translators: %1$s = opening strong tag, %2$s = closing strong tag.
|
||||
printf( esc_html__( 'Easy configuration: the %1$sbest CDN settings%2$s are automatically applied', 'rocket' ), '<strong>', '</strong>' );
|
||||
?>
|
||||
</li>
|
||||
<li class="wpr-rocketcdn-feature wpr-rocketcdn-automatic">
|
||||
<?php
|
||||
// translators: %1$s = opening strong tag, %2$s = closing strong tag.
|
||||
printf( esc_html__( 'WP Rocket integration: the CDN option is %1$sautomatically configured%2$s in our plugin', 'rocket' ), '<strong>', '</strong>' );
|
||||
?>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="wpr-rocketcdn-pricing">
|
||||
<?php if ( ! empty( $data['error'] ) ) : ?>
|
||||
<p><?php echo esc_html( $data['message'] ); ?></p>
|
||||
<?php else : ?>
|
||||
<?php if ( ! empty( $data['regular_price'] ) ) : ?>
|
||||
<h4 class="wpr-title2 wpr-rocketcdn-pricing-regular"><del>$<?php echo esc_html( $data['regular_price'] ); ?></del></h4>
|
||||
<?php endif; ?>
|
||||
<h4 class="wpr-rocketcdn-pricing-current">
|
||||
<?php
|
||||
printf(
|
||||
// translators: %s = price of RocketCDN subscription.
|
||||
esc_html__( '%s / month', 'rocket' ),
|
||||
'<span class="wpr-title1">$' . esc_html( $data['current_price'] ) . '</span>'
|
||||
);
|
||||
?>
|
||||
</h4>
|
||||
<button class="wpr-button wpr-rocketcdn-open" data-micromodal-trigger="wpr-rocketcdn-modal"><?php esc_html_e( 'Get Started', 'rocket' ); ?></button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div class="wpr-rocketcdn-cta-footer">
|
||||
<a href="https://go.wp-rocket.me/rocket-cdn" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Learn more about RocketCDN', 'rocket' ); ?></a>
|
||||
</div>
|
||||
<button class="wpr-rocketcdn-cta-close<?php echo esc_attr( $data['nopromo_variant'] ); ?>" id="wpr-rocketcdn-close-cta"><span class="screen-reader-text"><?php esc_html_e( 'Reduce this banner', 'rocket' ); ?></span></button>
|
||||
<?php if ( ! empty( $data['promotion_campaign'] ) ) : ?>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
// translators: %1$s = discounted price, %2$s = regular price.
|
||||
esc_html__( '* $%1$s/month for 12 months then $%2$s/month. You can cancel your subscription at any time.', 'rocket' ),
|
||||
esc_html( str_replace( '*', '', $data['current_price'] ) ),
|
||||
esc_html( $data['regular_price'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* RocketCDN small CTA template.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $data {
|
||||
* @type string $container_class container CSS class.
|
||||
* }
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
?>
|
||||
<div class="wpr-rocketcdn-cta-small notice-alt notice-warning <?php echo esc_attr( $data['container_class'] ); ?>" id="wpr-rocketcdn-cta-small">
|
||||
<div class="wpr-flex">
|
||||
<section>
|
||||
<h3 class="notice-title"><?php esc_html_e( 'Speed up your website with RocketCDN, WP Rocket’s Content Delivery Network.', 'rocket' ); ?></strong></h3>
|
||||
</section>
|
||||
<div>
|
||||
<button class="wpr-button" id="wpr-rocketcdn-open-cta"><?php esc_html_e( 'Learn More', 'rocket' ); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* RocketCDN status on dashboard tab template.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param array $data {
|
||||
* @type bool $is_live_site Identifies if the current website is a live or local/staging one
|
||||
* @type string $container_class Flex container CSS class.
|
||||
* @type string $label Content label.
|
||||
* @type string $status_class CSS Class to display the status.
|
||||
* @type string $status_text Text to display the subscription status.
|
||||
* @type bool $is_active Boolean identifying the activation status.
|
||||
* }
|
||||
*/
|
||||
|
||||
?>
|
||||
<div class="wpr-optionHeader">
|
||||
<h3 class="wpr-title2">RocketCDN</h3>
|
||||
</div>
|
||||
<div class="wpr-field wpr-field-account">
|
||||
<?php if ( ! $data['is_live_site'] ) : ?>
|
||||
<span class="wpr-infoAccount wpr-isInvalid"><?php esc_html_e( 'RocketCDN is unavailable on local domains and staging sites.', 'rocket' ); ?></span>
|
||||
<?php else : ?>
|
||||
<div class="wpr-flex<?php echo esc_attr( $data['container_class'] ); ?>">
|
||||
<div>
|
||||
<span class="wpr-title3"><?php echo esc_html( $data['label'] ); ?></span>
|
||||
<span class="wpr-infoAccount<?php echo esc_attr( $data['status_class'] ); ?>"><?php echo esc_html( $data['status_text'] ); ?></span>
|
||||
</div>
|
||||
<?php if ( ! $data['is_active'] ) : ?>
|
||||
<div>
|
||||
<a href="#page_cdn" class="wpr-button"><?php esc_html_e( 'Get RocketCDN', 'rocket' ); ?></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Promote RocketCDN notice template.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
?>
|
||||
<div class="notice notice-alt notice-warning is-dismissible" id="rocketcdn-promote-notice">
|
||||
<h2 class="notice-title"><?php esc_html_e( 'New!', 'rocket' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Speed up your website with RocketCDN, WP Rocket’s Content Delivery Network!', 'rocket' ); ?></p>
|
||||
<p><a href="#page_cdn" class="wpr-button" id="rocketcdn-learn-more-dismiss"><?php esc_html_e( 'Learn More', 'rocket' ); ?></a></p>
|
||||
</div>
|
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service provider for WP Rocket CDN
|
||||
*
|
||||
* @since 3.5.5
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'cdn',
|
||||
'cdn_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the services in the container
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$options = $this->getContainer()->get( 'options' );
|
||||
|
||||
$this->getContainer()->share( 'cdn', 'WP_Rocket\Engine\CDN\CDN' )
|
||||
->withArgument( $options );
|
||||
$this->getContainer()->share( 'cdn_subscriber', 'WP_Rocket\Engine\CDN\Subscriber' )
|
||||
->withArgument( $options )
|
||||
->withArgument( $this->getContainer()->get( 'cdn' ) );
|
||||
}
|
||||
}
|
277
wp-content/plugins/wp-rocket/inc/Engine/CDN/Subscriber.php
Normal file
277
wp-content/plugins/wp-rocket/inc/Engine/CDN/Subscriber.php
Normal file
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\CDN;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the CDN feature
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
class Subscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* WP Rocket Options instance
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* CDN instance
|
||||
*
|
||||
* @var CDN
|
||||
*/
|
||||
private $cdn;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Options_Data $options WP Rocket Options instance.
|
||||
* @param CDN $cdn CDN instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options, CDN $cdn ) {
|
||||
$this->options = $options;
|
||||
$this->cdn = $cdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rocket_buffer' => [
|
||||
[ 'rewrite', 20 ],
|
||||
[ 'rewrite_srcset', 21 ],
|
||||
],
|
||||
'rocket_css_content' => 'rewrite_css_properties',
|
||||
'rocket_cdn_hosts' => [ 'get_cdn_hosts', 10, 2 ],
|
||||
'rocket_dns_prefetch' => 'add_dns_prefetch_cdn',
|
||||
'rocket_facebook_sdk_url' => 'add_cdn_url',
|
||||
'rocket_css_url' => [ 'add_cdn_url', 10, 2 ],
|
||||
'rocket_js_url' => [ 'add_cdn_url', 10, 2 ],
|
||||
'rocket_asset_url' => [ 'maybe_replace_url', 10, 2 ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites URLs to the CDN URLs if allowed
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
public function rewrite( $html ) {
|
||||
if ( ! $this->is_allowed() ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
return $this->cdn->rewrite( $html );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites URLs in srcset attributes to the CDN URLs if allowed
|
||||
*
|
||||
* @since 3.4.0.4
|
||||
*
|
||||
* @param string $html HTML content.
|
||||
* @return string
|
||||
*/
|
||||
public function rewrite_srcset( $html ) {
|
||||
if ( ! $this->is_allowed() ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
return $this->cdn->rewrite_srcset( $html );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites URLs to the CDN URLs in CSS files
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param string $content CSS content.
|
||||
* @return string
|
||||
*/
|
||||
public function rewrite_css_properties( $content ) {
|
||||
/**
|
||||
* Filters the application of the CDN on CSS properties
|
||||
*
|
||||
* @since 2.6
|
||||
*
|
||||
* @param bool true to apply CDN to properties, false otherwise
|
||||
*/
|
||||
$do_rewrite = apply_filters( 'do_rocket_cdn_css_properties', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
|
||||
|
||||
if ( ! $do_rewrite ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if ( ! $this->is_cdn_enabled() ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return $this->cdn->rewrite_css_properties( $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the host value for each CDN URLs
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param array $hosts Base hosts.
|
||||
* @param array $zones Zones to get the CND URLs associated with.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_cdn_hosts( array $hosts = [], array $zones = [ 'all' ] ) {
|
||||
$cdn_urls = $this->cdn->get_cdn_urls( $zones );
|
||||
|
||||
if ( empty( $cdn_urls ) ) {
|
||||
return $hosts;
|
||||
}
|
||||
|
||||
foreach ( $cdn_urls as $cdn_url ) {
|
||||
$parsed = get_rocket_parse_url( rocket_add_url_protocol( $cdn_url ) );
|
||||
|
||||
if ( empty( $parsed['host'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hosts[] = untrailingslashit( $parsed['host'] . $parsed['path'] );
|
||||
}
|
||||
|
||||
return array_unique( $hosts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds CDN URLs to the DNS prefetch links
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param array $domains Domain names to DNS prefetch.
|
||||
* @return array
|
||||
*/
|
||||
public function add_dns_prefetch_cdn( $domains ) {
|
||||
if ( ! $this->is_allowed() ) {
|
||||
return $domains;
|
||||
}
|
||||
|
||||
$cdn_urls = $this->cdn->get_cdn_urls( [ 'all', 'images', 'css_and_js', 'css', 'js' ] );
|
||||
|
||||
if ( ! $cdn_urls ) {
|
||||
return $domains;
|
||||
}
|
||||
|
||||
return array_merge( $domains, $cdn_urls );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the CDN URL on the provided URL
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param string $url URL to rewrite.
|
||||
* @param string $original_url Original URL for this URL. Optional.
|
||||
* @return string
|
||||
*/
|
||||
public function add_cdn_url( $url, $original_url = '' ) {
|
||||
if ( ! empty( $original_url ) ) {
|
||||
if ( $this->cdn->is_excluded( $original_url ) ) {
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cdn->rewrite_url( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace CDN URL with site URL on the provided asset URL.
|
||||
*
|
||||
* @since 3.5.3
|
||||
*
|
||||
* @param string $url URL of the asset.
|
||||
* @param array $zones Array of corresponding zones for the asset.
|
||||
* @return string
|
||||
*/
|
||||
public function maybe_replace_url( $url, array $zones = [ 'all' ] ) {
|
||||
if ( ! $this->is_allowed() ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$url_parts = get_rocket_parse_url( $url );
|
||||
|
||||
if ( empty( $url_parts['host'] ) ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$site_url_parts = get_rocket_parse_url( site_url() );
|
||||
|
||||
if ( empty( $site_url_parts['host'] ) ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
if ( $url_parts['host'] === $site_url_parts['host'] ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$cdn_urls = $this->cdn->get_cdn_urls( $zones );
|
||||
|
||||
if ( empty( $cdn_urls ) ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$cdn_urls = array_map( 'rocket_add_url_protocol', $cdn_urls );
|
||||
|
||||
$site_url = $site_url_parts['scheme'] . '://' . $site_url_parts['host'];
|
||||
|
||||
foreach ( $cdn_urls as $cdn_url ) {
|
||||
if ( false === strpos( $url, $cdn_url ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return str_replace( $cdn_url, $site_url, $url );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if CDN can be applied
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_allowed() {
|
||||
if ( rocket_get_constant( 'DONOTROCKETOPTIMIZE' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->is_cdn_enabled() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_rocket_post_excluded_option( 'cdn' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the CDN option is enabled
|
||||
*
|
||||
* @since 3.5.5
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_cdn_enabled() {
|
||||
return (bool) $this->options->get( 'cdn', 0 );
|
||||
}
|
||||
}
|
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Cache;
|
||||
|
||||
use WP_Rocket\Event_Management\Event_Manager;
|
||||
use WP_Rocket\Event_Management\Event_Manager_Aware_Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the cache admin events
|
||||
*
|
||||
* @since 3.5.5
|
||||
*/
|
||||
class AdminSubscriber implements Event_Manager_Aware_Subscriber_Interface {
|
||||
/**
|
||||
* Event Manager instance
|
||||
*
|
||||
* @var Event_Manager;
|
||||
*/
|
||||
protected $event_manager;
|
||||
|
||||
/**
|
||||
* AdvancedCache instance
|
||||
*
|
||||
* @var AdvancedCache
|
||||
*/
|
||||
private $advanced_cache;
|
||||
|
||||
/**
|
||||
* WPCache instance
|
||||
*
|
||||
* @var WPCache
|
||||
*/
|
||||
private $wp_cache;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param AdvancedCache $advanced_cache AdvancedCache instance.
|
||||
* @param WPCache $wp_cache WPCache instance.
|
||||
*/
|
||||
public function __construct( AdvancedCache $advanced_cache, WPCache $wp_cache ) {
|
||||
$this->advanced_cache = $advanced_cache;
|
||||
$this->wp_cache = $wp_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
$slug = rocket_get_constant( 'WP_ROCKET_SLUG' );
|
||||
|
||||
return [
|
||||
'admin_init' => [
|
||||
[ 'register_terms_row_action' ],
|
||||
[ 'maybe_set_wp_cache' ],
|
||||
],
|
||||
'admin_notices' => [
|
||||
[ 'notice_advanced_cache_permissions' ],
|
||||
[ 'notice_wp_config_permissions' ],
|
||||
],
|
||||
"update_option_{$slug}" => [ 'maybe_set_wp_cache', 12 ],
|
||||
'site_status_tests' => 'add_wp_cache_status_test',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event manager for the subscriber.
|
||||
*
|
||||
* @param Event_Manager $event_manager Event Manager instance.
|
||||
*/
|
||||
public function set_event_manager( Event_Manager $event_manager ) {
|
||||
$this->event_manager = $event_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the action for each public taxonomy
|
||||
*
|
||||
* @since 3.5.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_terms_row_action() {
|
||||
$taxonomies = get_taxonomies(
|
||||
[
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
]
|
||||
);
|
||||
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
$this->event_manager->add_callback( "{$taxonomy}_row_actions", [ $this, 'add_purge_term_link' ], 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a link "Purge this cache" in the terms list table
|
||||
*
|
||||
* @param array $actions An array of action links to be displayed.
|
||||
* @param WP_Term $term Term object.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_purge_term_link( $actions, $term ) {
|
||||
if ( ! current_user_can( 'rocket_purge_terms' ) ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
$url = wp_nonce_url(
|
||||
admin_url( "admin-post.php?action=purge_cache&type=term-{$term->term_id}&taxonomy={$term->taxonomy}" ),
|
||||
"purge_cache_term-{$term->term_id}"
|
||||
);
|
||||
|
||||
$actions['rocket_purge'] = sprintf(
|
||||
'<a href="%1$s">%2$s</a>',
|
||||
$url,
|
||||
__( 'Clear this cache', 'rocket' )
|
||||
);
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the notice for advanced-cache.php permissions
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function notice_advanced_cache_permissions() {
|
||||
$this->advanced_cache->notice_permissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set WP_CACHE constant to true if needed
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_set_wp_cache() {
|
||||
$this->wp_cache->maybe_set_wp_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the notice for wp-config.php permissions
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function notice_wp_config_permissions() {
|
||||
$this->wp_cache->notice_wp_config_permissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Site Health check for the WP_CACHE constant value
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param array $tests An array of tests to perform.
|
||||
* @return array
|
||||
*/
|
||||
public function add_wp_cache_status_test( $tests ) {
|
||||
return $this->wp_cache->add_wp_cache_status_test( $tests );
|
||||
}
|
||||
}
|
206
wp-content/plugins/wp-rocket/inc/Engine/Cache/AdvancedCache.php
Normal file
206
wp-content/plugins/wp-rocket/inc/Engine/Cache/AdvancedCache.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Cache;
|
||||
|
||||
use WP_Filesystem_Direct;
|
||||
use WP_Rocket\Engine\Activation\ActivationInterface;
|
||||
use WP_Rocket\Engine\Deactivation\DeactivationInterface;
|
||||
|
||||
class AdvancedCache implements ActivationInterface, DeactivationInterface {
|
||||
|
||||
/**
|
||||
* Absolute path to template files
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $template_path;
|
||||
|
||||
/**
|
||||
* WP Content directory path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $content_dir;
|
||||
|
||||
/**
|
||||
* Instance of the filesystem handler.
|
||||
*
|
||||
* @var WP_Filesystem_Direct
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* Instantiate of the class.
|
||||
*
|
||||
* @param string $template_path Absolute path to template files.
|
||||
* @param WP_Filesystem_Direct $filesystem Instance of the filesystem handler.
|
||||
*/
|
||||
public function __construct( $template_path, $filesystem ) {
|
||||
$this->template_path = $template_path;
|
||||
$this->content_dir = rocket_get_constant( 'WP_CONTENT_DIR' );
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions to perform on plugin activation
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function activate() {
|
||||
add_action( 'rocket_activation', [ $this, 'update_advanced_cache' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions to perform on plugin deactivation
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deactivate() {
|
||||
add_action( 'rocket_deactivation', [ $this, 'update_advanced_cache' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the advanced-cache.php file with its content
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @param int $sites_number Number of WP Rocket config files found.
|
||||
* @return void
|
||||
*/
|
||||
public function update_advanced_cache( $sites_number = 0 ) {
|
||||
/**
|
||||
* Filters whether to generate the advanced-cache.php file.
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @param bool True (default) to go ahead with advanced cache file generation; false to stop generation.
|
||||
*/
|
||||
if ( ! (bool) apply_filters( 'rocket_generate_advanced_cache_file', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = $this->get_advanced_cache_content();
|
||||
|
||||
if ( 'rocket_deactivation' === current_filter() ) {
|
||||
if ( is_multisite() && 0 !== $sites_number ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = '';
|
||||
}
|
||||
|
||||
$this->filesystem->put_contents(
|
||||
"{$this->content_dir}/advanced-cache.php",
|
||||
$content,
|
||||
rocket_get_filesystem_perms( 'file' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content for the advanced-cache.php file
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_advanced_cache_content() {
|
||||
$content = $this->filesystem->get_contents( $this->template_path . 'advanced-cache.php' );
|
||||
$mobile = is_rocket_generate_caching_mobile_files() ? '$1' : '';
|
||||
$content = preg_replace( "/'{{MOBILE_CACHE}}';(\X*)'{{\/MOBILE_CACHE}}';/", $mobile, $content );
|
||||
|
||||
$replacements = [
|
||||
'{{WP_ROCKET_PHP_VERSION}}' => rocket_get_constant( 'WP_ROCKET_PHP_VERSION' ),
|
||||
'{{WP_ROCKET_PATH}}' => rocket_get_constant( 'WP_ROCKET_PATH' ),
|
||||
'{{WP_ROCKET_CONFIG_PATH}}' => rocket_get_constant( 'WP_ROCKET_CONFIG_PATH' ),
|
||||
'{{WP_ROCKET_CACHE_PATH}}' => rocket_get_constant( 'WP_ROCKET_CACHE_PATH' ),
|
||||
];
|
||||
|
||||
foreach ( $replacements as $key => $value ) {
|
||||
$content = str_replace( $key, $value, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the content of advanced-cache.php file.
|
||||
*
|
||||
* @since 2.1
|
||||
*
|
||||
* @param string $content The content that will be printed in advanced-cache.php.
|
||||
*/
|
||||
return (string) apply_filters( 'rocket_advanced_cache_file', $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* This warning is displayed when the advanced-cache.php file isn't writeable
|
||||
*
|
||||
* @since 3.6 Moved to a method in AdvancedCache
|
||||
* @since 2.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function notice_permissions() {
|
||||
if ( ! $this->is_user_allowed() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This filter is documented in inc/functions/files.php.
|
||||
if ( ! (bool) apply_filters( 'rocket_generate_advanced_cache_file', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
$this->filesystem->is_writable( "{$this->content_dir}/advanced-cache.php" )
|
||||
||
|
||||
rocket_get_constant( 'WP_ROCKET_ADVANCED_CACHE' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$notice_name = 'rocket_warning_advanced_cache_permissions';
|
||||
|
||||
if (
|
||||
in_array(
|
||||
$notice_name,
|
||||
(array) get_user_meta( get_current_user_id(), 'rocket_boxes', true ),
|
||||
true
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => 'error',
|
||||
'dismissible' => '',
|
||||
'message' => $this->get_notice_message(),
|
||||
'dismiss_button' => $notice_name,
|
||||
'readonly_content' => $this->get_advanced_cache_content(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current user can see the notices
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_user_allowed() {
|
||||
return current_user_can( 'rocket_manage_options' ) && rocket_valid_key();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the message to display in the notice
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_notice_message() {
|
||||
return rocket_notice_writing_permissions( basename( $this->content_dir ) . '/advanced-cache.php' );
|
||||
}
|
||||
}
|
223
wp-content/plugins/wp-rocket/inc/Engine/Cache/Purge.php
Normal file
223
wp-content/plugins/wp-rocket/inc/Engine/Cache/Purge.php
Normal file
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Cache;
|
||||
|
||||
use DirectoryIterator;
|
||||
use Exception;
|
||||
use WP_Term;
|
||||
use WP_Post;
|
||||
|
||||
/**
|
||||
* Cache Purge handling class
|
||||
*/
|
||||
class Purge {
|
||||
/**
|
||||
* Filesystem instance
|
||||
*
|
||||
* @var WP_Filesystem_Direct
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* Initialize the class
|
||||
*
|
||||
* @param WP_Filesystem_Direct $filesystem Filesystem instance.
|
||||
*/
|
||||
public function __construct( $filesystem ) {
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges cache for the dates archives of a post
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
* @return void
|
||||
*/
|
||||
public function purge_dates_archives( $post ) {
|
||||
foreach ( $this->get_dates_archives( $post ) as $url ) {
|
||||
$this->purge_url( $url, true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge URL cache.
|
||||
*
|
||||
* @param string $url URL to be purged.
|
||||
* @param boolean $pagination Purge also pagination.
|
||||
* @return void
|
||||
*/
|
||||
private function purge_url( $url, $pagination = false ) {
|
||||
global $wp_rewrite;
|
||||
|
||||
$parsed_url = $this->parse_url( $url );
|
||||
|
||||
foreach ( _rocket_get_cache_dirs( $parsed_url['host'] ) as $dir ) {
|
||||
$path = $dir . $parsed_url['path'];
|
||||
|
||||
if ( ! $this->filesystem->exists( $path ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $this->get_iterator( $path ) as $item ) {
|
||||
if ( $item->isFile() ) {
|
||||
$this->filesystem->delete( $item->getPathname() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $pagination ) {
|
||||
$this->maybe_remove_dir( $path . DIRECTORY_SEPARATOR . $wp_rewrite->pagination_base );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dates archives URLs for the provided post
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
* @return array
|
||||
*/
|
||||
private function get_dates_archives( $post ) {
|
||||
$time = get_the_time( 'Y-m-d', $post );
|
||||
|
||||
if ( empty( $time ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$date = explode( '-', $time );
|
||||
$urls = [
|
||||
get_year_link( $date[0] ),
|
||||
get_month_link( $date[0], $date[1] ),
|
||||
get_day_link( $date[0], $date[1], $date[2] ),
|
||||
];
|
||||
|
||||
/**
|
||||
* Filter the list of dates URLs.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @param array $urls List of dates URLs.
|
||||
*/
|
||||
return (array) apply_filters( 'rocket_post_dates_urls', $urls );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses URL and return the parts array
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param string $url URL to parse.
|
||||
* @return array
|
||||
*/
|
||||
private function parse_url( $url ) {
|
||||
$parsed_url = get_rocket_parse_url( $url );
|
||||
|
||||
/** This filter is documented in inc/front/htaccess.php */
|
||||
if ( apply_filters( 'rocket_url_no_dots', false ) ) {
|
||||
$parsed_url['host'] = str_replace( '.', '_', $parsed_url['host'] );
|
||||
}
|
||||
|
||||
return $parsed_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the iterator for the given path
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param string $path Absolute path.
|
||||
* @return DirectoryIterator|array
|
||||
*/
|
||||
private function get_iterator( $path ) {
|
||||
try {
|
||||
$iterator = new DirectoryIterator( $path );
|
||||
} catch ( Exception $e ) {
|
||||
// No action required, as logging not enabled.
|
||||
$iterator = [];
|
||||
}
|
||||
|
||||
return $iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively remove the provided directory and its content
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param string $dir Absolute path for the directory.
|
||||
* @return void
|
||||
*/
|
||||
private function maybe_remove_dir( $dir ) {
|
||||
if ( $this->filesystem->is_dir( $dir ) ) {
|
||||
rocket_rrmdir( $dir, [], $this->filesystem );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge all terms archives urls associated to a specific post.
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
*/
|
||||
public function purge_post_terms_urls( WP_Post $post ) {
|
||||
foreach ( $this->get_post_terms_urls( $post ) as $url ) {
|
||||
$this->purge_url( $url );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all terms archives urls associated to a specific post.
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
*
|
||||
* @return array $urls List of taxonomies URLs
|
||||
*/
|
||||
private function get_post_terms_urls( WP_Post $post ) {
|
||||
$urls = [];
|
||||
$taxonomies = get_object_taxonomies( get_post_type( $post->ID ), 'objects' );
|
||||
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
if ( ! $taxonomy->public || 'product_shipping_class' === $taxonomy->name ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the terms related to post.
|
||||
$terms = get_the_terms( $post->ID, $taxonomy->name );
|
||||
|
||||
if ( empty( $terms ) || is_wp_error( $terms ) ) {
|
||||
continue;
|
||||
}
|
||||
foreach ( $terms as $term ) {
|
||||
$term_url = get_term_link( $term->slug, $taxonomy->name );
|
||||
if ( ! is_wp_error( $term_url ) ) {
|
||||
$urls[] = $term_url;
|
||||
}
|
||||
if ( ! is_taxonomy_hierarchical( $taxonomy->name ) ) {
|
||||
continue;
|
||||
}
|
||||
$ancestors = (array) get_ancestors( $term->term_id, $taxonomy->name );
|
||||
foreach ( $ancestors as $ancestor ) {
|
||||
$ancestor_object = get_term( $ancestor, $taxonomy->name );
|
||||
if ( ! $ancestor_object instanceof WP_Term ) {
|
||||
continue;
|
||||
}
|
||||
$ancestor_term_url = get_term_link( $ancestor_object->slug, $taxonomy->name );
|
||||
if ( ! is_wp_error( $ancestor_term_url ) ) {
|
||||
$urls[] = $ancestor_term_url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Filter the list of taxonomies URLs
|
||||
*
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @param array $urls List of taxonomies URLs
|
||||
*/
|
||||
return apply_filters( 'rocket_post_terms_urls', $urls );
|
||||
}
|
||||
}
|
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Cache;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
|
||||
/**
|
||||
* Subscriber for the cache purge actions
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
class PurgeActionsSubscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* WP Rocket options instance
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Purge instance
|
||||
*
|
||||
* @var Purge
|
||||
*/
|
||||
private $purge;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Options_Data $options WP Rocket options instance.
|
||||
* @param Purge $purge Purge instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options, Purge $purge ) {
|
||||
$this->options = $options;
|
||||
$this->purge = $purge;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'profile_update' => 'purge_user_cache',
|
||||
'delete_user' => 'purge_user_cache',
|
||||
'create_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ],
|
||||
'edit_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ],
|
||||
'delete_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ],
|
||||
'after_rocket_clean_post' => [
|
||||
[ 'purge_dates_archives' ],
|
||||
[ 'purge_post_terms_urls' ],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the cache of the corresponding user
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
* @return void
|
||||
*/
|
||||
public function purge_user_cache( $user_id ) {
|
||||
if ( ! $this->should_purge_user_cache() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
rocket_clean_user( $user_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the cache when a public term is created|updated|deleted
|
||||
*
|
||||
* @since 3.5.5
|
||||
*
|
||||
* @param int $term_id Term ID.
|
||||
* @param int $tt_id Term taxonomy ID.
|
||||
* @param string $taxonomy Taxonomy slug.
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_purge_cache_on_term_change( $term_id, $tt_id, $taxonomy ) {
|
||||
if ( ! $this->is_taxonomy_public( $taxonomy ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
rocket_clean_domain();
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges cache for the dates archives of a post after cleaning the post
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
* @return void
|
||||
*/
|
||||
public function purge_dates_archives( $post ) {
|
||||
$this->purge->purge_dates_archives( $post );
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge all terms archives urls associated to a specific post.
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
* @return void
|
||||
*/
|
||||
public function purge_post_terms_urls( $post ) {
|
||||
$this->purge->purge_post_terms_urls( $post );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given taxonomy is public
|
||||
*
|
||||
* @param string $name Taxonomy name.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_taxonomy_public( $name ) {
|
||||
$taxonomy = get_taxonomy( $name );
|
||||
|
||||
if ( false === $taxonomy ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ( $taxonomy->public && $taxonomy->publicly_queryable );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user cache should be purged
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function should_purge_user_cache() {
|
||||
if ( ! $this->options->get( 'cache_logged_user', 0 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This filter is documented in /inc/functions/files.php.
|
||||
return ! (bool) apply_filters( 'rocket_common_cache_logged_users', false );
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Cache;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service Provider for cache subscribers
|
||||
*
|
||||
* @since 3.5.5
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'advanced_cache',
|
||||
'wp_cache',
|
||||
'purge',
|
||||
'purge_actions_subscriber',
|
||||
'admin_cache_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the option array in the container
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$filesystem = rocket_direct_filesystem();
|
||||
|
||||
$this->getContainer()->add( 'advanced_cache', 'WP_Rocket\Engine\Cache\AdvancedCache' )
|
||||
->withArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' )
|
||||
->withArgument( $filesystem );
|
||||
$this->getContainer()->add( 'wp_cache', 'WP_Rocket\Engine\Cache\WPCache' )
|
||||
->withArgument( $filesystem );
|
||||
$this->getContainer()->add( 'purge', 'WP_Rocket\Engine\Cache\Purge' )
|
||||
->withArgument( $filesystem );
|
||||
$this->getContainer()->share( 'purge_actions_subscriber', 'WP_Rocket\Engine\Cache\PurgeActionsSubscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'options' ) )
|
||||
->withArgument( $this->getContainer()->get( 'purge' ) );
|
||||
$this->getContainer()->share( 'admin_cache_subscriber', 'WP_Rocket\Engine\Cache\AdminSubscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'advanced_cache' ) )
|
||||
->withArgument( $this->getContainer()->get( 'wp_cache' ) );
|
||||
}
|
||||
}
|
385
wp-content/plugins/wp-rocket/inc/Engine/Cache/WPCache.php
Normal file
385
wp-content/plugins/wp-rocket/inc/Engine/Cache/WPCache.php
Normal file
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Cache;
|
||||
|
||||
use WP_Rocket\Engine\Activation\ActivationInterface;
|
||||
use WP_Rocket\Engine\Deactivation\DeactivationInterface;
|
||||
|
||||
class WPCache implements ActivationInterface, DeactivationInterface {
|
||||
/**
|
||||
* Filesystem instance.
|
||||
*
|
||||
* @var WP_Filesystem_Direct
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param WP_Filesystem_Direct $filesystem Filesystem instance.
|
||||
*/
|
||||
public function __construct( $filesystem ) {
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs these actions during the plugin activation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function activate() {
|
||||
add_action( 'rocket_activation', [ $this, 'update_wp_cache' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs these actions during the plugin deactivation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deactivate() {
|
||||
add_action( 'rocket_deactivation', [ $this, 'update_wp_cache' ] );
|
||||
add_filter( 'rocket_prevent_deactivation', [ $this, 'maybe_prevent_deactivation' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the WP_CACHE constant on (de)activation
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @param int $sites_number Number of WP Rocket config files found.
|
||||
* @return void
|
||||
*/
|
||||
public function update_wp_cache( $sites_number = 0 ) {
|
||||
if ( ! rocket_valid_key() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$value = true;
|
||||
|
||||
if ( 'rocket_deactivation' === current_filter() ) {
|
||||
if ( is_multisite() && 0 !== $sites_number ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$value = false;
|
||||
}
|
||||
|
||||
$this->set_wp_cache_constant( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the causes array on deactivation if needed
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @param array $causes Array of causes to pass to the notice.
|
||||
*/
|
||||
public function maybe_prevent_deactivation( $causes ) {
|
||||
if (
|
||||
$this->find_wpconfig_path()
|
||||
||
|
||||
// This filter is documented in inc/Engine/Cache/WPCache.php.
|
||||
! (bool) apply_filters( 'rocket_set_wp_cache_constant', true )
|
||||
) {
|
||||
return $causes;
|
||||
}
|
||||
|
||||
$causes[] = 'wpconfig';
|
||||
|
||||
return $causes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set WP_CACHE constant to true if needed
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_set_wp_cache() {
|
||||
if (
|
||||
rocket_get_constant( 'DOING_AJAX' )
|
||||
||
|
||||
rocket_get_constant( 'DOING_AUTOSAVE' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( rocket_get_constant( 'WP_CACHE' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->set_wp_cache_constant( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the WP_CACHE constant in wp-config.php
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param bool $value The value to set for WP_CACHE constant.
|
||||
* @return void
|
||||
*/
|
||||
public function set_wp_cache_constant( $value ) {
|
||||
if ( ! $this->should_set_wp_cache_constant( $value ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config_file_path = $this->find_wpconfig_path();
|
||||
|
||||
if ( ! $config_file_path ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config_file_contents = $this->filesystem->get_contents( $config_file_path );
|
||||
$value = $value ? 'true' : 'false';
|
||||
|
||||
/**
|
||||
* Filter allow to change the value of WP_CACHE constant
|
||||
*
|
||||
* @since 2.1
|
||||
*
|
||||
* @param string $value The value of WP_CACHE constant.
|
||||
*/
|
||||
$value = apply_filters( 'set_rocket_wp_cache_define', $value ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
|
||||
|
||||
$wp_cache_found = preg_match( '/^\s*define\(\s*\'WP_CACHE\'\s*,\s*(?<value>[^\s\)]*)\s*\)/m', $config_file_contents, $matches );
|
||||
|
||||
if (
|
||||
! empty( $matches['value'] )
|
||||
&&
|
||||
$matches['value'] === $value
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$constant = $this->get_wp_cache_content( $value );
|
||||
|
||||
if ( ! $wp_cache_found ) {
|
||||
$config_file_contents = preg_replace( '/(<\?php)/i', "<?php\r\n{$constant}\r\n", $config_file_contents );
|
||||
} elseif ( ! empty( $matches['value'] ) && $matches['value'] !== $value ) {
|
||||
$config_file_contents = preg_replace( '/^\s*define\(\s*\'WP_CACHE\'\s*,\s*([^\s\)]*)\s*\).+/m', $constant, $config_file_contents );
|
||||
}
|
||||
|
||||
$this->filesystem->put_contents( $config_file_path, $config_file_contents, rocket_get_filesystem_perms( 'file' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we should set the WP_CACHE constant
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param bool $value The value to set for WP_CACHE constant.
|
||||
* @return bool
|
||||
*/
|
||||
private function should_set_wp_cache_constant( $value ) {
|
||||
if ( ! $this->is_user_allowed() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
true === $value
|
||||
&&
|
||||
rocket_get_constant( 'WP_CACHE' )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the writing of the WP_CACHE constant in wp-config.php
|
||||
*
|
||||
* @since 3.6.1
|
||||
* @param bool $set True to allow writing, false otherwise.
|
||||
*/
|
||||
return (bool) apply_filters( 'rocket_set_wp_cache_constant', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find the correct wp-config.php file, support one level up in file tree.
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @return string|bool The path of wp-config.php file or false if not found.
|
||||
*/
|
||||
private function find_wpconfig_path() {
|
||||
/**
|
||||
* Filter the wp-config's filename.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param string $filename The WP Config filename, without the extension.
|
||||
*/
|
||||
$config_file_name = apply_filters( 'rocket_wp_config_name', 'wp-config' );
|
||||
$abspath = rocket_get_constant( 'ABSPATH' );
|
||||
$config_file = "{$abspath}{$config_file_name}.php";
|
||||
|
||||
if ( $this->filesystem->is_writable( $config_file ) ) {
|
||||
return $config_file;
|
||||
}
|
||||
|
||||
$abspath_parent = dirname( $abspath ) . DIRECTORY_SEPARATOR;
|
||||
$config_file_alt = "{$abspath_parent}{$config_file_name}.php";
|
||||
|
||||
if (
|
||||
$this->filesystem->exists( $config_file_alt )
|
||||
&&
|
||||
$this->filesystem->is_writable( $config_file_alt )
|
||||
&&
|
||||
! $this->filesystem->exists( "{$abspath_parent}wp-settings.php" )
|
||||
) {
|
||||
return $config_file_alt;
|
||||
}
|
||||
|
||||
// No writable file found.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This warning is displayed when the wp-config.php file isn't writable
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function notice_wp_config_permissions() {
|
||||
global $pagenow;
|
||||
|
||||
if (
|
||||
'plugins.php' === $pagenow
|
||||
||
|
||||
isset( $_GET['activate'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->is_user_allowed() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( rocket_get_constant( 'WP_CACHE' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This filter is documented in inc/Engine/Cache/WPCache.php.
|
||||
if ( ! (bool) apply_filters( 'rocket_set_wp_cache_constant', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->find_wpconfig_path() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$notice_name = 'rocket_warning_wp_config_permissions';
|
||||
|
||||
if (
|
||||
in_array(
|
||||
$notice_name,
|
||||
(array) get_user_meta( get_current_user_id(), 'rocket_boxes', true ),
|
||||
true
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => 'error',
|
||||
'dismissible' => '',
|
||||
'message' => rocket_notice_writing_permissions( 'wp-config.php' ),
|
||||
'dismiss_button' => $notice_name,
|
||||
'readonly_content' => $this->get_wp_cache_content(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current user can perform the action
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_user_allowed() {
|
||||
return current_user_can( 'rocket_manage_options' ) && rocket_valid_key();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content to add to the wp-config.php file
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param string $value Value for the WP_CACHE constant.
|
||||
* @return string
|
||||
*/
|
||||
private function get_wp_cache_content( $value = 'true' ) {
|
||||
$plugin_name = rocket_get_constant( 'WP_ROCKET_PLUGIN_NAME' );
|
||||
|
||||
return "define( 'WP_CACHE', {$value} ); // Added by {$plugin_name}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Site Health check for the WP_CACHE constant value
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param array $tests An array of tests to perform.
|
||||
* @return array
|
||||
*/
|
||||
public function add_wp_cache_status_test( $tests ) {
|
||||
$tests['direct']['wp_cache_status'] = [
|
||||
'label' => __( 'WP_CACHE value', 'rocket' ),
|
||||
'test' => [ $this, 'check_wp_cache_value' ],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the WP_CACHE constant value and return the result for Site Health
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function check_wp_cache_value() {
|
||||
$result = [
|
||||
'badge' => [
|
||||
'label' => __( 'Cache', 'rocket' ),
|
||||
],
|
||||
'description' => sprintf(
|
||||
'<p>%s</p>',
|
||||
__( 'The WP_CACHE constant needs to be set to true for WP Rocket cache to work properly', 'rocket' )
|
||||
),
|
||||
'actions' => '',
|
||||
'test' => 'wp_cache_status',
|
||||
];
|
||||
|
||||
$value = rocket_get_constant( 'WP_CACHE' );
|
||||
|
||||
if ( true === $value ) {
|
||||
$result['label'] = __( 'WP_CACHE is set to true', 'rocket' );
|
||||
$result['status'] = 'good';
|
||||
$result['badge']['color'] = 'green';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( null === $value ) {
|
||||
$result['label'] = __( 'WP_CACHE is not set', 'rocket' );
|
||||
$result['status'] = 'critical';
|
||||
$result['badge']['color'] = 'red';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( false === $value ) {
|
||||
$result['label'] = __( 'WP_CACHE is set to false', 'rocket' );
|
||||
$result['status'] = 'critical';
|
||||
$result['badge']['color'] = 'red';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
168
wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Manager.php
Normal file
168
wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Manager.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Capabilities;
|
||||
|
||||
use WP_Rocket\Engine\Activation\ActivationInterface;
|
||||
use WP_Rocket\Engine\Deactivation\DeactivationInterface;
|
||||
|
||||
class Manager implements ActivationInterface, DeactivationInterface {
|
||||
/**
|
||||
* List of WP Rocket capabilities
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $capabilities = [
|
||||
'rocket_manage_options',
|
||||
'rocket_purge_cache',
|
||||
'rocket_purge_posts',
|
||||
'rocket_purge_terms',
|
||||
'rocket_purge_users',
|
||||
'rocket_purge_opcache',
|
||||
'rocket_purge_cloudflare_cache',
|
||||
'rocket_purge_sucuri_cache',
|
||||
'rocket_preload_cache',
|
||||
'rocket_regenerate_critical_css',
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets the WP Rocket capabilities
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_capabilities() {
|
||||
return $this->capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs these actions during the plugin activation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function activate() {
|
||||
add_action( 'rocket_activation', [ $this, 'add_rocket_capabilities' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs these actions during the plugin deactivation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deactivate() {
|
||||
add_action( 'rocket_deactivation', [ $this, 'remove_rocket_capabilities' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add WP Rocket capabilities to the administrator role
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_rocket_capabilities() {
|
||||
$role = $this->get_administrator_role_object();
|
||||
|
||||
if ( is_null( $role ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->get_capabilities() as $cap ) {
|
||||
$role->add_cap( $cap );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove WP Rocket capabilities from the administrator role
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function remove_rocket_capabilities() {
|
||||
$role = $this->get_administrator_role_object();
|
||||
|
||||
if ( is_null( $role ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->get_capabilities() as $cap ) {
|
||||
$role->remove_cap( $cap );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the capability for the options page.
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param string $capability The capability used for the page, which is manage_options by default.
|
||||
* @return string
|
||||
*/
|
||||
public function required_capability( $capability ) {
|
||||
return 'rocket_manage_options';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add WP Rocket capabilities to User Role Editor
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param array $caps Array of existing capabilities.
|
||||
* @return array
|
||||
*/
|
||||
public function add_caps_to_ure( $caps ) {
|
||||
foreach ( $this->get_capabilities() as $cap ) {
|
||||
$caps[ $cap ] = [
|
||||
'custom',
|
||||
'wp_rocket',
|
||||
];
|
||||
}
|
||||
|
||||
return $caps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add WP Rocket as a group in User Role Editor
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param array $groups Array of existing groups.
|
||||
* @return array
|
||||
*/
|
||||
public function add_group_to_ure( $groups ) {
|
||||
$groups['wp_rocket'] = [
|
||||
'caption' => esc_html( 'WP Rocket' ),
|
||||
'parent' => 'custom',
|
||||
'level' => 2,
|
||||
];
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds WP Rocket capabilities on plugin upgrade
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @param string $wp_rocket_version Latest WP Rocket version.
|
||||
* @param string $actual_version Installed WP Rocket version.
|
||||
* @return void
|
||||
*/
|
||||
public function add_capabilities_on_upgrade( $wp_rocket_version, $actual_version ) {
|
||||
if ( version_compare( $actual_version, '3.4.0.1', '<' ) ) {
|
||||
$this->add_rocket_capabilities();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object for the administrator roll
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @return WP_Role|null
|
||||
*/
|
||||
private function get_administrator_role_object() {
|
||||
return get_role( 'administrator' );
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Capabilities;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service Provider for capabilities
|
||||
*
|
||||
* @since 3.6.3
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'capabilities_manager',
|
||||
'capabilities_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the option array in the container
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->add( 'capabilities_manager', 'WP_Rocket\Engine\Capabilities\Manager' );
|
||||
$this->getContainer()->share( 'capabilities_subscriber', 'WP_Rocket\Engine\Capabilities\Subscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'capabilities_manager' ) );
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Capabilities;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Manage WP Rocket custom capabilities
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
class Subscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* Capabilities manager instance
|
||||
*
|
||||
* @var Manager
|
||||
*/
|
||||
private $capabilities;
|
||||
|
||||
/**
|
||||
* Instantiate the subscriber
|
||||
*
|
||||
* @param Manager $capabilities Capabilities manager instance.
|
||||
*/
|
||||
public function __construct( Manager $capabilities ) {
|
||||
$this->capabilities = $capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
$slug = rocket_get_constant( 'WP_ROCKET_PLUGIN_SLUG' );
|
||||
|
||||
return [
|
||||
"option_page_capability_{$slug}" => 'required_capability',
|
||||
'ure_built_in_wp_caps' => 'add_caps_to_ure',
|
||||
'ure_capabilities_groups_tree' => 'add_group_to_ure',
|
||||
'wp_rocket_upgrade' => [ 'add_capabilities_on_upgrade', 12, 2 ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the capability for the options page.
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param string $capability The capability used for the page, which is manage_options by default.
|
||||
* @return string
|
||||
*/
|
||||
public function required_capability( $capability ) {
|
||||
return $this->capabilities->required_capability( $capability );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds WP Rocket capabilities to User Role Editor
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param array $caps Array of existing capabilities.
|
||||
* @return array
|
||||
*/
|
||||
public function add_caps_to_ure( $caps ) {
|
||||
return $this->capabilities->add_caps_to_ure( $caps );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds WP Rocket as a group in User Role Editor
|
||||
*
|
||||
* @since 3.4
|
||||
*
|
||||
* @param array $groups Array of existing groups.
|
||||
* @return array
|
||||
*/
|
||||
public function add_group_to_ure( $groups ) {
|
||||
return $this->capabilities->add_group_to_ure( $groups );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds WP Rocket capabilities on plugin upgrade
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @param string $wp_rocket_version Latest WP Rocket version.
|
||||
* @param string $actual_version Installed WP Rocket version.
|
||||
* @return void
|
||||
*/
|
||||
public function add_capabilities_on_upgrade( $wp_rocket_version, $actual_version ) {
|
||||
$this->capabilities->add_capabilities_on_upgrade( $wp_rocket_version, $actual_version );
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Argument;
|
||||
|
||||
use WP_Rocket\Engine\Container\ImmutableContainerAwareInterface;
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
interface ArgumentResolverInterface extends ImmutableContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Resolve an array of arguments to their concrete implementations.
|
||||
*
|
||||
* @param array $arguments
|
||||
* @return array
|
||||
*/
|
||||
public function resolveArguments(array $arguments);
|
||||
|
||||
/**
|
||||
* Resolves the correct arguments to be passed to a method.
|
||||
*
|
||||
* @param \ReflectionFunctionAbstract $method
|
||||
* @param array $args
|
||||
* @return array
|
||||
*/
|
||||
public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []);
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Argument;
|
||||
|
||||
use WP_Rocket\Engine\Container\Exception\NotFoundException;
|
||||
use WP_Rocket\Engine\Container\ReflectionContainer;
|
||||
use ReflectionFunctionAbstract;
|
||||
use ReflectionParameter;
|
||||
|
||||
trait ArgumentResolverTrait
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolveArguments(array $arguments)
|
||||
{
|
||||
foreach ($arguments as &$arg) {
|
||||
if ($arg instanceof RawArgumentInterface) {
|
||||
$arg = $arg->getValue();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! is_string($arg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$container = $this->getContainer();
|
||||
|
||||
if (is_null($container) && $this instanceof ReflectionContainer) {
|
||||
$container = $this;
|
||||
}
|
||||
|
||||
if (! is_null($container) && $container->has($arg)) {
|
||||
$arg = $container->get($arg);
|
||||
|
||||
if ($arg instanceof RawArgumentInterface) {
|
||||
$arg = $arg->getValue();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function reflectArguments(ReflectionFunctionAbstract $method, array $args = [])
|
||||
{
|
||||
$arguments = array_map(function (ReflectionParameter $param) use ($method, $args) {
|
||||
$name = $param->getName();
|
||||
$class = $param->getClass();
|
||||
|
||||
if (array_key_exists($name, $args)) {
|
||||
return $args[$name];
|
||||
}
|
||||
|
||||
if (! is_null($class)) {
|
||||
return $class->getName();
|
||||
}
|
||||
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
return $param->getDefaultValue();
|
||||
}
|
||||
|
||||
throw new NotFoundException(sprintf(
|
||||
'Unable to resolve a value for parameter (%s) in the function/method (%s)',
|
||||
$name,
|
||||
$method->getName()
|
||||
));
|
||||
}, $method->getParameters());
|
||||
|
||||
return $this->resolveArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WP_Rocket\Engine\Container\ContainerInterface
|
||||
*/
|
||||
abstract public function getContainer();
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Argument;
|
||||
|
||||
class RawArgument implements RawArgumentInterface
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Argument;
|
||||
|
||||
interface RawArgumentInterface
|
||||
{
|
||||
/**
|
||||
* Return the value of the raw argument.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue();
|
||||
}
|
305
wp-content/plugins/wp-rocket/inc/Engine/Container/Container.php
Normal file
305
wp-content/plugins/wp-rocket/inc/Engine/Container/Container.php
Normal file
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container;
|
||||
|
||||
use Psr\Container\ContainerInterface as InteropContainerInterface;
|
||||
use WP_Rocket\Engine\Container\Argument\RawArgumentInterface;
|
||||
use WP_Rocket\Engine\Container\Definition\DefinitionFactory;
|
||||
use WP_Rocket\Engine\Container\Definition\DefinitionFactoryInterface;
|
||||
use WP_Rocket\Engine\Container\Definition\DefinitionInterface;
|
||||
use WP_Rocket\Engine\Container\Exception\NotFoundException;
|
||||
use WP_Rocket\Engine\Container\Inflector\InflectorAggregate;
|
||||
use WP_Rocket\Engine\Container\Inflector\InflectorAggregateInterface;
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderAggregate;
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderAggregateInterface;
|
||||
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
/**
|
||||
* @var \WP_Rocket\Engine\Container\Definition\DefinitionFactoryInterface
|
||||
*/
|
||||
protected $definitionFactory;
|
||||
|
||||
/**
|
||||
* @var \WP_Rocket\Engine\Container\Definition\DefinitionInterface[]
|
||||
*/
|
||||
protected $definitions = [];
|
||||
|
||||
/**
|
||||
* @var \WP_Rocket\Engine\Container\Definition\DefinitionInterface[]
|
||||
*/
|
||||
protected $sharedDefinitions = [];
|
||||
|
||||
/**
|
||||
* @var \WP_Rocket\Engine\Container\Inflector\InflectorAggregateInterface
|
||||
*/
|
||||
protected $inflectors;
|
||||
|
||||
/**
|
||||
* @var \WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderAggregateInterface
|
||||
*/
|
||||
protected $providers;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $shared = [];
|
||||
|
||||
/**
|
||||
* @var \Psr\Container\ContainerInterface[]
|
||||
*/
|
||||
protected $delegates = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderAggregateInterface|null $providers
|
||||
* @param \WP_Rocket\Engine\Container\Inflector\InflectorAggregateInterface|null $inflectors
|
||||
* @param \WP_Rocket\Engine\Container\Definition\DefinitionFactoryInterface|null $definitionFactory
|
||||
*/
|
||||
public function __construct(
|
||||
ServiceProviderAggregateInterface $providers = null,
|
||||
InflectorAggregateInterface $inflectors = null,
|
||||
DefinitionFactoryInterface $definitionFactory = null
|
||||
) {
|
||||
// set required dependencies
|
||||
$this->providers = (is_null($providers))
|
||||
? (new ServiceProviderAggregate)->setContainer($this)
|
||||
: $providers->setContainer($this);
|
||||
|
||||
$this->inflectors = (is_null($inflectors))
|
||||
? (new InflectorAggregate)->setContainer($this)
|
||||
: $inflectors->setContainer($this);
|
||||
|
||||
$this->definitionFactory = (is_null($definitionFactory))
|
||||
? (new DefinitionFactory)->setContainer($this)
|
||||
: $definitionFactory->setContainer($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($alias, array $args = [])
|
||||
{
|
||||
try {
|
||||
return $this->getFromThisContainer($alias, $args);
|
||||
} catch (NotFoundException $exception) {
|
||||
if ($this->providers->provides($alias)) {
|
||||
$this->providers->register($alias);
|
||||
|
||||
return $this->getFromThisContainer($alias, $args);
|
||||
}
|
||||
|
||||
$resolved = $this->getFromDelegate($alias, $args);
|
||||
|
||||
return $this->inflectors->inflect($resolved);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($alias)
|
||||
{
|
||||
if (array_key_exists($alias, $this->definitions) || $this->hasShared($alias)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->providers->provides($alias)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->hasInDelegate($alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean to determine if the container has a shared instance of an alias.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param boolean $resolved
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasShared($alias, $resolved = false)
|
||||
{
|
||||
$shared = ($resolved === false) ? array_merge($this->shared, $this->sharedDefinitions) : $this->shared;
|
||||
|
||||
return (array_key_exists($alias, $shared));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add($alias, $concrete = null, $share = false)
|
||||
{
|
||||
unset($this->shared[$alias]);
|
||||
unset($this->definitions[$alias]);
|
||||
unset($this->sharedDefinitions[$alias]);
|
||||
|
||||
if (is_null($concrete)) {
|
||||
$concrete = $alias;
|
||||
}
|
||||
|
||||
$definition = $this->definitionFactory->getDefinition($alias, $concrete);
|
||||
|
||||
if ($definition instanceof DefinitionInterface) {
|
||||
if ($share === false) {
|
||||
$this->definitions[$alias] = $definition;
|
||||
} else {
|
||||
$this->sharedDefinitions[$alias] = $definition;
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// dealing with a value that cannot build a definition
|
||||
$this->shared[$alias] = $concrete;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function share($alias, $concrete = null)
|
||||
{
|
||||
return $this->add($alias, $concrete, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addServiceProvider($provider)
|
||||
{
|
||||
$this->providers->add($provider);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extend($alias)
|
||||
{
|
||||
if ($this->providers->provides($alias)) {
|
||||
$this->providers->register($alias);
|
||||
}
|
||||
|
||||
if (array_key_exists($alias, $this->definitions)) {
|
||||
return $this->definitions[$alias];
|
||||
}
|
||||
|
||||
if (array_key_exists($alias, $this->sharedDefinitions)) {
|
||||
return $this->sharedDefinitions[$alias];
|
||||
}
|
||||
|
||||
throw new NotFoundException(
|
||||
sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $alias)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function inflector($type, callable $callback = null)
|
||||
{
|
||||
return $this->inflectors->add($type, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function call(callable $callable, array $args = [])
|
||||
{
|
||||
return (new ReflectionContainer)->setContainer($this)->call($callable, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate a backup container to be checked for services if it
|
||||
* cannot be resolved via this container.
|
||||
*
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
* @return $this
|
||||
*/
|
||||
public function delegate(InteropContainerInterface $container)
|
||||
{
|
||||
$this->delegates[] = $container;
|
||||
|
||||
if ($container instanceof ImmutableContainerAwareInterface) {
|
||||
$container->setContainer($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if service is registered in one of the delegated backup containers.
|
||||
*
|
||||
* @param string $alias
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasInDelegate($alias)
|
||||
{
|
||||
foreach ($this->delegates as $container) {
|
||||
if ($container->has($alias)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get a service from the stack of delegated backup containers.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getFromDelegate($alias, array $args = [])
|
||||
{
|
||||
foreach ($this->delegates as $container) {
|
||||
if ($container->has($alias)) {
|
||||
return $container->get($alias, $args);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new NotFoundException(
|
||||
sprintf('Alias (%s) is not being managed by the container', $alias)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a service that has been registered in this container.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getFromThisContainer($alias, array $args = [])
|
||||
{
|
||||
if ($this->hasShared($alias, true)) {
|
||||
$shared = $this->inflectors->inflect($this->shared[$alias]);
|
||||
if ($shared instanceof RawArgumentInterface) {
|
||||
return $shared->getValue();
|
||||
}
|
||||
return $shared;
|
||||
}
|
||||
|
||||
if (array_key_exists($alias, $this->sharedDefinitions)) {
|
||||
$shared = $this->inflectors->inflect($this->sharedDefinitions[$alias]->build());
|
||||
$this->shared[$alias] = $shared;
|
||||
return $shared;
|
||||
}
|
||||
|
||||
if (array_key_exists($alias, $this->definitions)) {
|
||||
return $this->inflectors->inflect(
|
||||
$this->definitions[$alias]->build($args)
|
||||
);
|
||||
}
|
||||
|
||||
throw new NotFoundException(
|
||||
sprintf('Alias (%s) is not being managed by the container', $alias)
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container;
|
||||
|
||||
interface ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Set a container
|
||||
*
|
||||
* @param \WP_Rocket\Engine\Container\ContainerInterface $container
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container);
|
||||
|
||||
/**
|
||||
* Get the container
|
||||
*
|
||||
* @return \WP_Rocket\Engine\Container\ContainerInterface
|
||||
*/
|
||||
public function getContainer();
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container;
|
||||
|
||||
trait ContainerAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var \WP_Rocket\Engine\Container\ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Set a container.
|
||||
*
|
||||
* @param \WP_Rocket\Engine\Container\ContainerInterface $container
|
||||
* @return $this
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container.
|
||||
*
|
||||
* @return \WP_Rocket\Engine\Container\ContainerInterface
|
||||
*/
|
||||
public function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container;
|
||||
|
||||
interface ContainerInterface extends ImmutableContainerInterface
|
||||
{
|
||||
/**
|
||||
* Add an item to the container.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param mixed|null $concrete
|
||||
* @param boolean $share
|
||||
* @return \WP_Rocket\Engine\Container\Definition\DefinitionInterface
|
||||
*/
|
||||
public function add($alias, $concrete = null, $share = false);
|
||||
|
||||
/**
|
||||
* Convenience method to add an item to the container as a shared item.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param mixed|null $concrete
|
||||
* @return \WP_Rocket\Engine\Container\Definition\DefinitionInterface
|
||||
*/
|
||||
public function share($alias, $concrete = null);
|
||||
|
||||
/**
|
||||
* Add a service provider to the container.
|
||||
*
|
||||
* @param string|\WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderInterface $provider
|
||||
* @return void
|
||||
*/
|
||||
public function addServiceProvider($provider);
|
||||
|
||||
/**
|
||||
* Returns a definition of an item to be extended.
|
||||
*
|
||||
* @param string $alias
|
||||
* @return \WP_Rocket\Engine\Container\Definition\DefinitionInterface
|
||||
*/
|
||||
public function extend($alias);
|
||||
|
||||
/**
|
||||
* Allows for manipulation of specific types on resolution.
|
||||
*
|
||||
* @param string $type
|
||||
* @param callable|null $callback
|
||||
* @return \WP_Rocket\Engine\Container\Inflector\Inflector|void
|
||||
*/
|
||||
public function inflector($type, callable $callback = null);
|
||||
|
||||
/**
|
||||
* Invoke a callable via the container.
|
||||
*
|
||||
* @param callable $callable
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
public function call(callable $callable, array $args = []);
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Definition;
|
||||
|
||||
use WP_Rocket\Engine\Container\Argument\ArgumentResolverInterface;
|
||||
use WP_Rocket\Engine\Container\Argument\ArgumentResolverTrait;
|
||||
use WP_Rocket\Engine\Container\ImmutableContainerAwareTrait;
|
||||
|
||||
abstract class AbstractDefinition implements ArgumentResolverInterface, DefinitionInterface
|
||||
{
|
||||
use ArgumentResolverTrait;
|
||||
use ImmutableContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $alias;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $concrete;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $arguments = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param mixed $concrete
|
||||
*/
|
||||
public function __construct($alias, $concrete)
|
||||
{
|
||||
$this->alias = $alias;
|
||||
$this->concrete = $concrete;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withArgument($arg)
|
||||
{
|
||||
$this->arguments[] = $arg;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withArguments(array $args)
|
||||
{
|
||||
foreach ($args as $arg) {
|
||||
$this->withArgument($arg);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Definition;
|
||||
|
||||
class CallableDefinition extends AbstractDefinition
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build(array $args = [])
|
||||
{
|
||||
$args = (empty($args)) ? $this->arguments : $args;
|
||||
$resolved = $this->resolveArguments($args);
|
||||
|
||||
if (is_array($this->concrete) && is_string($this->concrete[0])) {
|
||||
$this->concrete[0] = ($this->getContainer()->has($this->concrete[0]))
|
||||
? $this->getContainer()->get($this->concrete[0])
|
||||
: $this->concrete[0];
|
||||
}
|
||||
|
||||
return call_user_func_array($this->concrete, $resolved);
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Definition;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
class ClassDefinition extends AbstractDefinition implements ClassDefinitionInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $methods = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withMethodCall($method, array $args = [])
|
||||
{
|
||||
$this->methods[] = [
|
||||
'method' => $method,
|
||||
'arguments' => $args
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withMethodCalls(array $methods = [])
|
||||
{
|
||||
foreach ($methods as $method => $args) {
|
||||
$this->withMethodCall($method, $args);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build(array $args = [])
|
||||
{
|
||||
$args = (empty($args)) ? $this->arguments : $args;
|
||||
$resolved = $this->resolveArguments($args);
|
||||
$reflection = new ReflectionClass($this->concrete);
|
||||
$instance = $reflection->newInstanceArgs($resolved);
|
||||
|
||||
return $this->invokeMethods($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke methods on resolved instance.
|
||||
*
|
||||
* @param object $instance
|
||||
* @return object
|
||||
*/
|
||||
protected function invokeMethods($instance)
|
||||
{
|
||||
foreach ($this->methods as $method) {
|
||||
$args = $this->resolveArguments($method['arguments']);
|
||||
call_user_func_array([$instance, $method['method']], $args);
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Definition;
|
||||
|
||||
interface ClassDefinitionInterface extends DefinitionInterface
|
||||
{
|
||||
/**
|
||||
* Add a method to be invoked
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @return $this
|
||||
*/
|
||||
public function withMethodCall($method, array $args = []);
|
||||
|
||||
/**
|
||||
* Add multiple methods to be invoked
|
||||
*
|
||||
* @param array $methods
|
||||
* @return $this
|
||||
*/
|
||||
public function withMethodCalls(array $methods = []);
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Definition;
|
||||
|
||||
use WP_Rocket\Engine\Container\ImmutableContainerAwareTrait;
|
||||
|
||||
class DefinitionFactory implements DefinitionFactoryInterface
|
||||
{
|
||||
use ImmutableContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefinition($alias, $concrete)
|
||||
{
|
||||
if (is_callable($concrete)) {
|
||||
return (new CallableDefinition($alias, $concrete))->setContainer($this->getContainer());
|
||||
}
|
||||
|
||||
if (is_string($concrete) && class_exists($concrete)) {
|
||||
return (new ClassDefinition($alias, $concrete))->setContainer($this->getContainer());
|
||||
}
|
||||
|
||||
// if the item is not definable we just return the value to be stored
|
||||
// in the container as an arbitrary value/instance
|
||||
return $concrete;
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Definition;
|
||||
|
||||
use WP_Rocket\Engine\Container\ImmutableContainerAwareInterface;
|
||||
|
||||
interface DefinitionFactoryInterface extends ImmutableContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Return a definition based on type of concrete.
|
||||
*
|
||||
* @param string $alias
|
||||
* @param mixed $concrete
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefinition($alias, $concrete);
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Definition;
|
||||
|
||||
interface DefinitionInterface
|
||||
{
|
||||
/**
|
||||
* Handle instantiation and manipulation of value and return.
|
||||
*
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
public function build(array $args = []);
|
||||
|
||||
/**
|
||||
* Add an argument to be injected.
|
||||
*
|
||||
* @param mixed $arg
|
||||
* @return $this
|
||||
*/
|
||||
public function withArgument($arg);
|
||||
|
||||
/**
|
||||
* Add multiple arguments to be injected.
|
||||
*
|
||||
* @param array $args
|
||||
* @return $this
|
||||
*/
|
||||
public function withArguments(array $args);
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Exception;
|
||||
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class NotFoundException extends InvalidArgumentException implements NotFoundExceptionInterface
|
||||
{
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container;
|
||||
|
||||
use Psr\Container\ContainerInterface as InteropContainerInterface;
|
||||
|
||||
interface ImmutableContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Set a container
|
||||
*
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
*/
|
||||
public function setContainer(InteropContainerInterface $container);
|
||||
|
||||
/**
|
||||
* Get the container
|
||||
*
|
||||
* @return \WP_Rocket\Engine\Container\ImmutableContainerInterface
|
||||
*/
|
||||
public function getContainer();
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container;
|
||||
|
||||
use Psr\Container\ContainerInterface as InteropContainerInterface;
|
||||
|
||||
trait ImmutableContainerAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var \Psr\Container\ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Set a container.
|
||||
*
|
||||
* @param \Psr\Container\ContainerInterface $container
|
||||
* @return $this
|
||||
*/
|
||||
public function setContainer(InteropContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container.
|
||||
*
|
||||
* @return \WP_Rocket\Engine\Container\ImmutableContainerInterface
|
||||
*/
|
||||
public function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container;
|
||||
|
||||
use Psr\Container\ContainerInterface as InteropContainerInterface;
|
||||
|
||||
interface ImmutableContainerInterface extends InteropContainerInterface
|
||||
{
|
||||
|
||||
}
|
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Inflector;
|
||||
|
||||
use WP_Rocket\Engine\Container\ImmutableContainerAwareTrait;
|
||||
use WP_Rocket\Engine\Container\Argument\ArgumentResolverInterface;
|
||||
use WP_Rocket\Engine\Container\Argument\ArgumentResolverTrait;
|
||||
|
||||
class Inflector implements ArgumentResolverInterface
|
||||
{
|
||||
use ArgumentResolverTrait;
|
||||
use ImmutableContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $methods = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = [];
|
||||
|
||||
/**
|
||||
* Defines a method to be invoked on the subject object.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $args
|
||||
* @return $this
|
||||
*/
|
||||
public function invokeMethod($name, array $args)
|
||||
{
|
||||
$this->methods[$name] = $args;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines multiple methods to be invoked on the subject object.
|
||||
*
|
||||
* @param array $methods
|
||||
* @return $this
|
||||
*/
|
||||
public function invokeMethods(array $methods)
|
||||
{
|
||||
foreach ($methods as $name => $args) {
|
||||
$this->invokeMethod($name, $args);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a property to be set on the subject object.
|
||||
*
|
||||
* @param string $property
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
*/
|
||||
public function setProperty($property, $value)
|
||||
{
|
||||
$this->properties[$property] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines multiple properties to be set on the subject object.
|
||||
*
|
||||
* @param array $properties
|
||||
* @return $this
|
||||
*/
|
||||
public function setProperties(array $properties)
|
||||
{
|
||||
foreach ($properties as $property => $value) {
|
||||
$this->setProperty($property, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply inflections to an object.
|
||||
*
|
||||
* @param object $object
|
||||
* @return void
|
||||
*/
|
||||
public function inflect($object)
|
||||
{
|
||||
$properties = $this->resolveArguments(array_values($this->properties));
|
||||
$properties = array_combine(array_keys($this->properties), $properties);
|
||||
|
||||
foreach ($properties as $property => $value) {
|
||||
$object->{$property} = $value;
|
||||
}
|
||||
|
||||
foreach ($this->methods as $method => $args) {
|
||||
$args = $this->resolveArguments($args);
|
||||
|
||||
call_user_func_array([$object, $method], $args);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Inflector;
|
||||
|
||||
use WP_Rocket\Engine\Container\ImmutableContainerAwareTrait;
|
||||
|
||||
class InflectorAggregate implements InflectorAggregateInterface
|
||||
{
|
||||
use ImmutableContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $inflectors = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add($type, callable $callback = null)
|
||||
{
|
||||
if (is_null($callback)) {
|
||||
$inflector = new Inflector;
|
||||
$this->inflectors[$type] = $inflector;
|
||||
|
||||
return $inflector;
|
||||
}
|
||||
|
||||
$this->inflectors[$type] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function inflect($object)
|
||||
{
|
||||
foreach ($this->inflectors as $type => $inflector) {
|
||||
if (! $object instanceof $type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($inflector instanceof Inflector) {
|
||||
$inflector->setContainer($this->getContainer());
|
||||
$inflector->inflect($object);
|
||||
continue;
|
||||
}
|
||||
|
||||
// must be dealing with a callable as the inflector
|
||||
call_user_func_array($inflector, [$object]);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\Inflector;
|
||||
|
||||
use WP_Rocket\Engine\Container\ImmutableContainerAwareInterface;
|
||||
|
||||
interface InflectorAggregateInterface extends ImmutableContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Add an inflector to the aggregate.
|
||||
*
|
||||
* @param string $type
|
||||
* @param callable $callback
|
||||
* @return \WP_Rocket\Engine\Container\Inflector\Inflector
|
||||
*/
|
||||
public function add($type, callable $callback = null);
|
||||
|
||||
/**
|
||||
* Applies all inflectors to an object.
|
||||
*
|
||||
* @param object $object
|
||||
* @return object
|
||||
*/
|
||||
public function inflect($object);
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container;
|
||||
|
||||
use WP_Rocket\Engine\Container\Argument\ArgumentResolverInterface;
|
||||
use WP_Rocket\Engine\Container\Argument\ArgumentResolverTrait;
|
||||
use WP_Rocket\Engine\Container\Exception\NotFoundException;
|
||||
use ReflectionClass;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
|
||||
class ReflectionContainer implements
|
||||
ArgumentResolverInterface,
|
||||
ImmutableContainerInterface
|
||||
{
|
||||
use ArgumentResolverTrait;
|
||||
use ImmutableContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($alias, array $args = [])
|
||||
{
|
||||
if (! $this->has($alias)) {
|
||||
throw new NotFoundException(
|
||||
sprintf('Alias (%s) is not an existing class and therefore cannot be resolved', $alias)
|
||||
);
|
||||
}
|
||||
|
||||
$reflector = new ReflectionClass($alias);
|
||||
$construct = $reflector->getConstructor();
|
||||
|
||||
if ($construct === null) {
|
||||
return new $alias;
|
||||
}
|
||||
|
||||
return $reflector->newInstanceArgs(
|
||||
$this->reflectArguments($construct, $args)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($alias)
|
||||
{
|
||||
return class_exists($alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a callable via the container.
|
||||
*
|
||||
* @param callable $callable
|
||||
* @param array $args
|
||||
* @return mixed
|
||||
*/
|
||||
public function call(callable $callable, array $args = [])
|
||||
{
|
||||
if (is_string($callable) && strpos($callable, '::') !== false) {
|
||||
$callable = explode('::', $callable);
|
||||
}
|
||||
|
||||
if (is_array($callable)) {
|
||||
if (is_string($callable[0])) {
|
||||
$callable[0] = $this->getContainer()->get($callable[0]);
|
||||
}
|
||||
|
||||
$reflection = new ReflectionMethod($callable[0], $callable[1]);
|
||||
|
||||
if ($reflection->isStatic()) {
|
||||
$callable[0] = null;
|
||||
}
|
||||
|
||||
return $reflection->invokeArgs($callable[0], $this->reflectArguments($reflection, $args));
|
||||
}
|
||||
|
||||
if (is_object($callable)) {
|
||||
$reflection = new ReflectionMethod($callable, '__invoke');
|
||||
|
||||
return $reflection->invokeArgs($callable, $this->reflectArguments($reflection, $args));
|
||||
}
|
||||
|
||||
$reflection = new ReflectionFunction($callable);
|
||||
|
||||
return $reflection->invokeArgs($this->reflectArguments($reflection, $args));
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\ServiceProvider;
|
||||
|
||||
use WP_Rocket\Engine\Container\ContainerAwareTrait;
|
||||
|
||||
abstract class AbstractServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function provides($alias = null)
|
||||
{
|
||||
if (! is_null($alias)) {
|
||||
return (in_array($alias, $this->provides));
|
||||
}
|
||||
|
||||
return $this->provides;
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\ServiceProvider;
|
||||
|
||||
abstract class AbstractSignatureServiceProvider
|
||||
extends AbstractServiceProvider
|
||||
implements SignatureServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function withSignature($signature)
|
||||
{
|
||||
$this->signature = $signature;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSignature()
|
||||
{
|
||||
return (is_null($this->signature)) ? get_class($this) : $this->signature;
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\ServiceProvider;
|
||||
|
||||
interface BootableServiceProviderInterface extends ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Method will be invoked on registration of a service provider implementing
|
||||
* this interface. Provides ability for eager loading of Service Providers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot();
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\ServiceProvider;
|
||||
|
||||
use WP_Rocket\Engine\Container\ContainerAwareInterface;
|
||||
use WP_Rocket\Engine\Container\ContainerAwareTrait;
|
||||
|
||||
class ServiceProviderAggregate implements ServiceProviderAggregateInterface
|
||||
{
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $providers = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $registered = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add($provider)
|
||||
{
|
||||
if (is_string($provider) && class_exists($provider)) {
|
||||
$provider = new $provider;
|
||||
}
|
||||
|
||||
if ($provider instanceof ContainerAwareInterface) {
|
||||
$provider->setContainer($this->getContainer());
|
||||
}
|
||||
|
||||
if ($provider instanceof BootableServiceProviderInterface) {
|
||||
$provider->boot();
|
||||
}
|
||||
|
||||
if ($provider instanceof ServiceProviderInterface) {
|
||||
foreach ($provider->provides() as $service) {
|
||||
$this->providers[$service] = $provider;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(
|
||||
'A service provider must be a fully qualified class name or instance ' .
|
||||
'of (\WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderInterface)'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function provides($service)
|
||||
{
|
||||
return array_key_exists($service, $this->providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function register($service)
|
||||
{
|
||||
if (! array_key_exists($service, $this->providers)) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('(%s) is not provided by a service provider', $service)
|
||||
);
|
||||
}
|
||||
|
||||
$provider = $this->providers[$service];
|
||||
$signature = get_class($provider);
|
||||
|
||||
if ($provider instanceof SignatureServiceProviderInterface) {
|
||||
$signature = $provider->getSignature();
|
||||
}
|
||||
|
||||
// ensure that the provider hasn't already been invoked by any other service request
|
||||
if (in_array($signature, $this->registered)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$provider->register();
|
||||
|
||||
$this->registered[] = $signature;
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\ServiceProvider;
|
||||
|
||||
use WP_Rocket\Engine\Container\ContainerAwareInterface;
|
||||
|
||||
interface ServiceProviderAggregateInterface extends ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Add a service provider to the aggregate.
|
||||
*
|
||||
* @param string|\WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderInterface $provider
|
||||
* @return $this
|
||||
*/
|
||||
public function add($provider);
|
||||
|
||||
/**
|
||||
* Determines whether a service is provided by the aggregate.
|
||||
*
|
||||
* @param string $service
|
||||
* @return boolean
|
||||
*/
|
||||
public function provides($service);
|
||||
|
||||
/**
|
||||
* Invokes the register method of a provider that provides a specific service.
|
||||
*
|
||||
* @param string $service
|
||||
* @return void
|
||||
*/
|
||||
public function register($service);
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\ServiceProvider;
|
||||
|
||||
use WP_Rocket\Engine\Container\ContainerAwareInterface;
|
||||
|
||||
interface ServiceProviderInterface extends ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Returns a boolean if checking whether this provider provides a specific
|
||||
* service or returns an array of provided services if no argument passed.
|
||||
*
|
||||
* @param string $service
|
||||
* @return boolean|array
|
||||
*/
|
||||
public function provides($service = null);
|
||||
|
||||
/**
|
||||
* Use the register method to register items with the container via the
|
||||
* protected $this->container property or the `getContainer` method
|
||||
* from the ContainerAwareTrait.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register();
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Container\ServiceProvider;
|
||||
|
||||
interface SignatureServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Set a custom signature for the service provider. This enables
|
||||
* registering the same service provider multiple times.
|
||||
*
|
||||
* @param string $signature
|
||||
* @return self
|
||||
*/
|
||||
public function withSignature($signature);
|
||||
|
||||
/**
|
||||
* The signature of the service provider uniquely identifies it, so
|
||||
* that we can quickly determine if it has already been registered.
|
||||
* Defaults to get_class($provider).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSignature();
|
||||
}
|
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use stdClass;
|
||||
use WP_Error;
|
||||
|
||||
class APIClient {
|
||||
|
||||
/**
|
||||
* Constant url for Critical Path API job.
|
||||
*/
|
||||
const API_URL = 'https://cpcss.wp-rocket.me/api/job/';
|
||||
|
||||
/**
|
||||
* Sends a generation request to the Critical Path API.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $url The URL to send a CPCSS generation request for.
|
||||
* @param array $params Optional. Parameters needed to be sent in the body. Default: [].
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
* @return array
|
||||
*/
|
||||
public function send_generation_request( $url, $params = [], $item_type = 'custom' ) {
|
||||
$params['url'] = $url;
|
||||
$is_mobile = isset( $params['mobile'] ) && $params['mobile'];
|
||||
$response = wp_remote_post(
|
||||
self::API_URL,
|
||||
[
|
||||
/**
|
||||
* Filters the parameters sent to the Critical CSS generator API.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param array $params An array of parameters to send to the API.
|
||||
*/
|
||||
'body' => apply_filters( 'rocket_cpcss_job_request', $params ),
|
||||
]
|
||||
);
|
||||
|
||||
return $this->prepare_response( $response, $url, $is_mobile, $item_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the response to be returned.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array|WP_Error $response The response or WP_Error on failure.
|
||||
* @param string $url Url to be checked.
|
||||
* @param bool $is_mobile Optional. Flag for if this is cpcss for mobile or not. Default: false.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
private function prepare_response( $response, $url, $is_mobile = false, $item_type = 'custom' ) {
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return new WP_Error(
|
||||
$this->get_response_code( $response ),
|
||||
sprintf(
|
||||
// translators: %1$s = type of content, %2$s = error message.
|
||||
__( 'Critical CSS for %1$s not generated. Error: %2$s', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $url : $item_type,
|
||||
$response->get_error_message()
|
||||
),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$response_data = $this->get_response_data( $response );
|
||||
$response_status_code = $this->get_response_status( $response, ( isset( $response_data->status ) ) ? $response_data->status : null );
|
||||
$succeeded = $this->get_response_success( $response_status_code, $response_data );
|
||||
|
||||
if ( $succeeded ) {
|
||||
return $response_data;
|
||||
}
|
||||
|
||||
$response_message = $this->get_response_message( $response_status_code, $response_data, $url, $is_mobile, $item_type );
|
||||
|
||||
if ( 200 === $response_status_code ) {
|
||||
$response_status_code = 400;
|
||||
}
|
||||
|
||||
return new WP_Error(
|
||||
$this->get_response_code( $response ),
|
||||
$response_message,
|
||||
[
|
||||
'status' => $response_status_code,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of response.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $response_code Response code to check success or failure.
|
||||
* @param stdClass $response_data Object of data returned from request.
|
||||
*
|
||||
* @return bool success or failed.
|
||||
*/
|
||||
private function get_response_success( $response_code, $response_data ) {
|
||||
return (
|
||||
200 === $response_code
|
||||
&&
|
||||
! empty( $response_data )
|
||||
&&
|
||||
(
|
||||
(
|
||||
isset( $response_data->status )
|
||||
&&
|
||||
200 === $response_data->status
|
||||
)
|
||||
||
|
||||
(
|
||||
isset( $response_data->data )
|
||||
&&
|
||||
isset( $response_data->data->id )
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response status code/number.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array|WP_Error $response The response or WP_Error on failure.
|
||||
* @param null|int $status Optional. Status code to overwrite the response status. Default: null.
|
||||
*
|
||||
* @return int status code|number of response.
|
||||
*/
|
||||
private function get_response_status( $response, $status = null ) {
|
||||
if ( ! is_null( $status ) ) {
|
||||
return (int) $status;
|
||||
}
|
||||
|
||||
return (int) wp_remote_retrieve_response_code( $response );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response message.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $response_status_code Response status code.
|
||||
* @param stdClass $response_data Object of data returned from request.
|
||||
* @param string $url Url for the web page to be checked.
|
||||
* @param bool $is_mobile Optional. Flag for if this is cpcss for mobile or not. Default: false.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_response_message( $response_status_code, $response_data, $url, $is_mobile = false, $item_type = 'custom' ) {
|
||||
$message = '';
|
||||
|
||||
switch ( $response_status_code ) {
|
||||
case 200:
|
||||
if ( ! isset( $response_data->data->id ) ) {
|
||||
$message .= sprintf(
|
||||
$is_mobile
|
||||
?
|
||||
// translators: %s = item URL.
|
||||
__( 'Critical CSS for %1$s on mobile not generated. Error: The API returned an empty response.', 'rocket' )
|
||||
:
|
||||
// translators: %s = item URL.
|
||||
__( 'Critical CSS for %1$s not generated. Error: The API returned an empty response.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $url : $item_type
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 400:
|
||||
case 440:
|
||||
case 404:
|
||||
// translators: %s = item URL.
|
||||
$message .= sprintf(
|
||||
$is_mobile
|
||||
// translators: %s = item URL.
|
||||
? __( 'Critical CSS for %1$s on mobile not generated.', 'rocket' )
|
||||
// translators: %s = item URL.
|
||||
: __( 'Critical CSS for %1$s not generated.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $url : $item_type
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$message .= sprintf(
|
||||
$is_mobile
|
||||
// translators: %s = URL.
|
||||
? __( 'Critical CSS for %1$s on mobile not generated. Error: The API returned an invalid response code.', 'rocket' )
|
||||
// translators: %s = URL.
|
||||
: __( 'Critical CSS for %1$s not generated. Error: The API returned an invalid response code.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $url : $item_type
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( isset( $response_data->message ) ) {
|
||||
// translators: %1$s = error message.
|
||||
$message .= ' ' . sprintf( __( 'Error: %1$s', 'rocket' ), $response_data->message );
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response data from the API.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array|WP_Error $response The response or WP_Error on failure.
|
||||
*
|
||||
* @return mixed response of API.
|
||||
*/
|
||||
private function get_response_data( $response ) {
|
||||
return json_decode( wp_remote_retrieve_body( $response ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get our internal response code [Not the standard HTTP codes].
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array|WP_Error $response The response or WP_Error on failure.
|
||||
*
|
||||
* @return string response code.
|
||||
*/
|
||||
private function get_response_code( $response ) {
|
||||
// Todo: we can return code based on the response status number, for example 404 not_found.
|
||||
return 'cpcss_generation_failed';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job details by calling API with job ID.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $job_id ID for the job to get details.
|
||||
* @param string $url URL to be used in error messages.
|
||||
* @param bool $is_mobile Optional. Flag for if this is cpcss for mobile or not. Default: false.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return mixed|WP_Error Details for job.
|
||||
*/
|
||||
public function get_job_details( $job_id, $url, $is_mobile = false, $item_type = 'custom' ) {
|
||||
$response = wp_remote_get(
|
||||
self::API_URL . "{$job_id}/"
|
||||
);
|
||||
|
||||
return $this->prepare_response( $response, $url, $is_mobile, $item_type );
|
||||
}
|
||||
}
|
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath\Admin;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Engine\CriticalPath\ProcessorService;
|
||||
use WP_Rocket\Engine\CriticalPath\TransientTrait;
|
||||
|
||||
class Admin {
|
||||
use TransientTrait;
|
||||
|
||||
/**
|
||||
* Instance of options handler.
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Instance of ProcessorService.
|
||||
*
|
||||
* @var ProcessorService
|
||||
*/
|
||||
private $processor;
|
||||
|
||||
/**
|
||||
* Creates an instance of the class.
|
||||
*
|
||||
* @param Options_Data $options Options instance.
|
||||
* @param ProcessorService $processor ProcessorService instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options, ProcessorService $processor ) {
|
||||
$this->options = $options;
|
||||
$this->processor = $processor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the CPCSS heartbeat.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
public function cpcss_heartbeat() {
|
||||
check_ajax_referer( 'cpcss_heartbeat_nonce', '_nonce', true );
|
||||
|
||||
if (
|
||||
! $this->is_async_css_enabled()
|
||||
||
|
||||
! current_user_can( 'rocket_manage_options' )
|
||||
||
|
||||
! current_user_can( 'rocket_regenerate_critical_css' )
|
||||
) {
|
||||
wp_send_json_error();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$cpcss_pending = get_transient( 'rocket_cpcss_generation_pending' );
|
||||
|
||||
if ( ! empty( $cpcss_pending ) ) {
|
||||
$cpcss_pending = $this->process_cpcss_pending_queue( (array) $cpcss_pending );
|
||||
}
|
||||
|
||||
if ( false !== $cpcss_pending && empty( $cpcss_pending ) ) {
|
||||
delete_transient( 'rocket_cpcss_generation_pending' );
|
||||
}
|
||||
|
||||
if ( empty( $cpcss_pending ) ) {
|
||||
$this->generation_complete();
|
||||
wp_send_json_success( [ 'status' => 'cpcss_complete' ] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
set_transient( 'rocket_cpcss_generation_pending', $cpcss_pending, HOUR_IN_SECONDS );
|
||||
wp_send_json_success( [ 'status' => 'cpcss_running' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull one item off of the CPCSS Pending Queue and process it.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $cpcss_pending CPCSS Pending Queue.
|
||||
*
|
||||
* @return array remaining queue.
|
||||
*/
|
||||
private function process_cpcss_pending_queue( array $cpcss_pending ) {
|
||||
$cpcss_item = reset( $cpcss_pending );
|
||||
if ( empty( $cpcss_item ) ) {
|
||||
return $cpcss_pending;
|
||||
}
|
||||
|
||||
// Threshold 'check' > 10 = timed out.
|
||||
$timeout = ( $cpcss_item['check'] > 10 );
|
||||
$additional_params = [
|
||||
'timeout' => $timeout,
|
||||
'is_mobile' => ! empty( $cpcss_item['mobile'] ) ? (bool) $cpcss_item['mobile'] : false,
|
||||
'item_type' => $cpcss_item['type'],
|
||||
];
|
||||
$cpcss_generation = $this->processor->process_generate(
|
||||
$cpcss_item['url'],
|
||||
$cpcss_item['path'],
|
||||
$additional_params
|
||||
);
|
||||
|
||||
// Increment this item's threshold count.
|
||||
$cpcss_pending[ $cpcss_item['path'] ]['check']++;
|
||||
|
||||
$this->cpcss_heartbeat_notices( $cpcss_generation, $cpcss_item );
|
||||
|
||||
// Remove the item from the queue when (a) the CPCSS API returns success or error or (b) timeouts.
|
||||
if (
|
||||
is_wp_error( $cpcss_generation )
|
||||
||
|
||||
'cpcss_generation_successful' === $cpcss_generation['code']
|
||||
||
|
||||
'cpcss_generation_failed' === $cpcss_generation['code']
|
||||
||
|
||||
$timeout
|
||||
) {
|
||||
unset( $cpcss_pending[ $cpcss_item['path'] ] );
|
||||
}
|
||||
|
||||
return $cpcss_pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* CPCSS heartbeat update notices transients.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array|WP_Error $cpcss_generation CPCSS regeneration reply.
|
||||
* @param array $cpcss_item Item processed.
|
||||
*/
|
||||
private function cpcss_heartbeat_notices( $cpcss_generation, $cpcss_item ) {
|
||||
$mobile = isset( $cpcss_item['mobile'] ) ? $cpcss_item['mobile'] : 0;
|
||||
$transient = (array) get_transient( 'rocket_critical_css_generation_process_running' );
|
||||
|
||||
// Initializes the transient.
|
||||
if ( ! isset( $transient['items'] ) ) {
|
||||
$transient['items'] = [];
|
||||
}
|
||||
|
||||
if ( is_wp_error( $cpcss_generation ) ) {
|
||||
$this->update_running_transient( $transient, $cpcss_item['path'], $mobile, $cpcss_generation->get_error_message(), false );
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isset( $cpcss_generation['code'] )
|
||||
&&
|
||||
(
|
||||
'cpcss_generation_successful' === $cpcss_generation['code']
|
||||
||
|
||||
'cpcss_generation_failed' === $cpcss_generation['code']
|
||||
)
|
||||
) {
|
||||
$this->update_running_transient( $transient, $cpcss_item['path'], $mobile, $cpcss_generation['message'], ( 'cpcss_generation_successful' === $cpcss_generation['code'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches when the CPCSS generation is complete.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
private function generation_complete() {
|
||||
$running = get_transient( 'rocket_critical_css_generation_process_running' );
|
||||
|
||||
if ( false === $running ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! isset( $running['total'], $running['items'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $running['total'] > count( $running['items'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when the critical CSS generation process is complete.
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
do_action( 'rocket_critical_css_generation_process_complete' );
|
||||
|
||||
rocket_clean_domain();
|
||||
set_transient( 'rocket_critical_css_generation_process_complete', get_transient( 'rocket_critical_css_generation_process_running' ), HOUR_IN_SECONDS );
|
||||
delete_transient( 'rocket_critical_css_generation_process_running' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue CPCSS heartbeat script on all admin pages.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
public function enqueue_admin_cpcss_heartbeat_script() {
|
||||
if ( ! $this->is_async_css_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_script(
|
||||
'wpr-heartbeat-cpcss-script',
|
||||
rocket_get_constant( 'WP_ROCKET_ASSETS_JS_URL' ) . 'wpr-cpcss-heartbeat.js',
|
||||
[],
|
||||
rocket_get_constant( 'WP_ROCKET_VERSION' ),
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'wpr-heartbeat-cpcss-script',
|
||||
'rocket_cpcss_heartbeat',
|
||||
[
|
||||
'nonce' => wp_create_nonce( 'cpcss_heartbeat_nonce' ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Regenerate Critical CSS link to WP Rocket admin bar item
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance, passed by reference.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_regenerate_menu_item( $wp_admin_bar ) {
|
||||
if ( ! current_user_can( 'rocket_regenerate_critical_css' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->is_async_css_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This filter is documented in inc/Engine/CriticalPath/CriticalCSS.php.
|
||||
if ( ! apply_filters( 'do_rocket_critical_css_generation', true ) ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
|
||||
return;
|
||||
}
|
||||
|
||||
$referer = '';
|
||||
$action = 'rocket_generate_critical_css';
|
||||
|
||||
if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
|
||||
$referer_url = filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ), FILTER_SANITIZE_URL );
|
||||
$referer = '&_wp_http_referer=' . rawurlencode( remove_query_arg( 'fl_builder', $referer_url ) );
|
||||
}
|
||||
|
||||
$wp_admin_bar->add_menu(
|
||||
[
|
||||
'parent' => 'wp-rocket',
|
||||
'id' => 'regenerate-critical-path',
|
||||
'title' => __( 'Regenerate Critical Path CSS', 'rocket' ),
|
||||
'href' => wp_nonce_url( admin_url( "admin-post.php?action={$action}{$referer}" ), $action ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the "async_css" option is enabled.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool true when "async_css" option is enabled.
|
||||
*/
|
||||
private function is_async_css_enabled() {
|
||||
return (bool) $this->options->get( 'async_css', 0 );
|
||||
}
|
||||
}
|
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath\Admin;
|
||||
|
||||
use WP_Rocket\Abstract_Render;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Engine\Admin\Beacon\Beacon;
|
||||
|
||||
class Post extends Abstract_Render {
|
||||
/**
|
||||
* Instance of the Beacon handler.
|
||||
*
|
||||
* @var Beacon
|
||||
*/
|
||||
private $beacon;
|
||||
|
||||
/**
|
||||
* Instance of options handler.
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Path to the critical-css directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $critical_css_path;
|
||||
|
||||
/**
|
||||
* Array of reasons to disable actions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $disabled_data;
|
||||
|
||||
/**
|
||||
* Creates an instance of the subscriber.
|
||||
*
|
||||
* @param Options_Data $options WP Rocket Options instance.
|
||||
* @param Beacon $beacon Beacon instance.
|
||||
* @param string $critical_path Path to the critical CSS base folder.
|
||||
* @param string $template_path Path to the templates folder.
|
||||
*/
|
||||
public function __construct( Options_Data $options, Beacon $beacon, $critical_path, $template_path ) {
|
||||
parent::__construct( $template_path );
|
||||
|
||||
$this->beacon = $beacon;
|
||||
$this->options = $options;
|
||||
$this->critical_css_path = $critical_path . get_current_blog_id() . '/posts/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the critical CSS block in WP Rocket options metabox.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cpcss_section() {
|
||||
$data = [
|
||||
'disabled_description' => $this->get_disabled_description(),
|
||||
];
|
||||
|
||||
echo $this->generate( 'metabox/container', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the content inside the critical CSS block.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cpcss_actions() {
|
||||
$data = [
|
||||
'disabled' => $this->is_enabled(),
|
||||
'beacon' => $this->beacon->get_suggest( 'async' ),
|
||||
'cpcss_exists' => $this->cpcss_exists(),
|
||||
];
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $this->generate(
|
||||
'metabox/generate',
|
||||
$data // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue CPCSS generation / deletion script on edit.php page.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $page The current admin page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_admin_edit_script( $page ) {
|
||||
global $post, $pagenow;
|
||||
|
||||
// Bailout if the page is not Post / Page.
|
||||
if ( ! in_array( $page, [ 'edit.php', 'post.php' ], true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! in_array( $pagenow, [ 'post-new.php', 'post.php' ], true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bailout if the CPCSS is not enabled for this Post / Page.
|
||||
if ( $this->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post_id = ( 'post-new.php' === $pagenow ) ? '' : $post->ID;
|
||||
|
||||
wp_enqueue_script(
|
||||
'wpr-edit-cpcss-script',
|
||||
rocket_get_constant( 'WP_ROCKET_ASSETS_JS_URL' ) . 'wpr-cpcss.js',
|
||||
[],
|
||||
rocket_get_constant( 'WP_ROCKET_VERSION' ),
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'wpr-edit-cpcss-script',
|
||||
'rocket_cpcss',
|
||||
[
|
||||
'rest_url' => rest_url( "wp-rocket/v1/cpcss/post/{$post_id}" ),
|
||||
'rest_nonce' => wp_create_nonce( 'wp_rest' ),
|
||||
'generate_btn' => __( 'Generate Specific CPCSS', 'rocket' ),
|
||||
'regenerate_btn' => __( 'Regenerate specific CPCSS', 'rocket' ),
|
||||
'wprMobileCpcssEnabled' => $this->options->get( 'async_css_mobile', 0 ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data for the disabled checks.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_disabled_data() {
|
||||
global $post;
|
||||
|
||||
if ( rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ) {
|
||||
$this->disabled_data = null;
|
||||
}
|
||||
|
||||
if ( isset( $this->disabled_data ) ) {
|
||||
return $this->disabled_data;
|
||||
}
|
||||
|
||||
if ( 'publish' !== $post->post_status ) {
|
||||
$this->disabled_data['not_published'] = 1;
|
||||
}
|
||||
|
||||
if ( ! $this->options->get( 'async_css', 0 ) ) {
|
||||
$this->disabled_data['option_disabled'] = 1;
|
||||
}
|
||||
|
||||
if ( get_post_meta( $post->ID, '_rocket_exclude_async_css', true ) ) {
|
||||
$this->disabled_data['option_excluded'] = 1;
|
||||
}
|
||||
|
||||
return $this->disabled_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if critical CSS generation is enabled for the current post.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_enabled() {
|
||||
return ! empty( $this->get_disabled_data() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reason why actions are disabled.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_disabled_description() {
|
||||
global $post;
|
||||
|
||||
$disabled_data = $this->get_disabled_data();
|
||||
|
||||
if ( empty( $disabled_data ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$notice = __( '%l to use this feature.', 'rocket' );
|
||||
$list = [
|
||||
// translators: %s = post type.
|
||||
'not_published' => sprintf( __( 'Publish the %s', 'rocket' ), $post->post_type ),
|
||||
'option_disabled' => __( 'Enable Optimize CSS delivery in WP Rocket settings', 'rocket' ),
|
||||
'option_excluded' => __( 'Enable Optimize CSS delivery in the options above', 'rocket' ),
|
||||
];
|
||||
|
||||
return wp_sprintf_l( $notice, array_intersect_key( $list, $disabled_data ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a specific critical css file exists for the current post.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function cpcss_exists() {
|
||||
global $post;
|
||||
|
||||
$post_cpcss = "{$this->critical_css_path}{$post->post_type}-{$post->ID}.css";
|
||||
|
||||
return rocket_direct_filesystem()->exists( $post_cpcss );
|
||||
}
|
||||
}
|
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath\Admin;
|
||||
|
||||
use WP_Rocket\Abstract_Render;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Engine\Admin\Beacon\Beacon;
|
||||
use WP_Rocket\Engine\CriticalPath\CriticalCSS;
|
||||
|
||||
class Settings extends Abstract_Render {
|
||||
/**
|
||||
* Instance of the Beacon handler.
|
||||
*
|
||||
* @var Beacon
|
||||
*/
|
||||
private $beacon;
|
||||
|
||||
/**
|
||||
* Instance of options handler.
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Instance of CriticalCSS.
|
||||
*
|
||||
* @var CriticalCSS
|
||||
*/
|
||||
private $critical_css;
|
||||
|
||||
/**
|
||||
* Creates an instance of the subscriber.
|
||||
*
|
||||
* @param Options_Data $options WP Rocket Options instance.
|
||||
* @param Beacon $beacon Beacon instance.
|
||||
* @param CriticalCSS $critical_css CriticalCSS instance.
|
||||
* @param string $template_path Path to the templates folder.
|
||||
*/
|
||||
public function __construct( Options_Data $options, Beacon $beacon, CriticalCSS $critical_css, $template_path ) {
|
||||
parent::__construct( $template_path );
|
||||
|
||||
$this->beacon = $beacon;
|
||||
$this->options = $options;
|
||||
$this->critical_css = $critical_css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display CPCSS mobile section tool admin view.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_cpcss_mobile_section() {
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bailout if CPCSS is not enabled & separate cache for mobiles is not enabled.
|
||||
// Or bailout if CPCSS mobile option is false.
|
||||
if (
|
||||
! (
|
||||
$this->options->get( 'async_css', 0 )
|
||||
&&
|
||||
$this->options->get( 'cache_mobile', 0 )
|
||||
&&
|
||||
$this->options->get( 'do_caching_mobile_files', 0 )
|
||||
)
|
||||
||
|
||||
$this->options->get( 'async_css_mobile', 0 )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'beacon' => $this->beacon->get_suggest( 'async' ),
|
||||
];
|
||||
|
||||
echo $this->generate( 'activate-cpcss-mobile', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable CPCSS mobile.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enable_mobile_cpcss() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) || ! current_user_can( 'rocket_regenerate_critical_css' ) ) {
|
||||
wp_send_json_error();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->options->set( 'async_css_mobile', 1 );
|
||||
update_option( rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' ), $this->options->get_options() );
|
||||
|
||||
// Start Mobile CPCSS process.
|
||||
$this->critical_css->process_handler( 'mobile' );
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds async_css_mobile option to WP Rocket options.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $options WP Rocket options array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_async_css_mobile_option( $options ) {
|
||||
$options = (array) $options;
|
||||
|
||||
$options['async_css_mobile'] = 1;
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value of async_css_mobile to 0 when upgrading from < 3.6.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $new_version New WP Rocket version.
|
||||
* @param string $old_version Previous WP Rocket version.
|
||||
*/
|
||||
public function set_async_css_mobile_default_value( $new_version, $old_version ) {
|
||||
if ( version_compare( $old_version, '3.6', '>' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$options = get_option( 'wp_rocket_settings', [] );
|
||||
|
||||
$options['async_css_mobile'] = 0;
|
||||
|
||||
update_option( 'wp_rocket_settings', $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds async_css_mobile to the hidden settings fields.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $hidden_settings_fields An array of hidden settings fields ID.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_hidden_async_css_mobile( $hidden_settings_fields ) {
|
||||
$hidden_settings_fields = (array) $hidden_settings_fields;
|
||||
|
||||
$hidden_settings_fields[] = 'async_css_mobile';
|
||||
|
||||
return $hidden_settings_fields;
|
||||
}
|
||||
}
|
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath\Admin;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
class Subscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* Instance of the CPCSS Settings handler.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* Instance of the Post handler
|
||||
*
|
||||
* @var Post
|
||||
*/
|
||||
private $post;
|
||||
|
||||
/**
|
||||
* Instance of the Admin handler
|
||||
*
|
||||
* @var Admin
|
||||
*/
|
||||
private $admin;
|
||||
|
||||
/**
|
||||
* Creates an instance of the subscriber.
|
||||
*
|
||||
* @param Post $post Post instance.
|
||||
* @param Settings $settings CPCSS Settings instance.
|
||||
* @param Admin $admin Admin instance.
|
||||
*/
|
||||
public function __construct( Post $post, Settings $settings, Admin $admin ) {
|
||||
$this->post = $post;
|
||||
$this->settings = $settings;
|
||||
$this->admin = $admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Events this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rocket_after_options_metabox' => 'cpcss_section',
|
||||
'rocket_metabox_cpcss_content' => 'cpcss_actions',
|
||||
'rocket_first_install_options' => 'add_async_css_mobile_option',
|
||||
'wp_rocket_upgrade' => [ 'set_async_css_mobile_default_value', 12, 2 ],
|
||||
'rocket_hidden_settings_fields' => 'add_hidden_async_css_mobile',
|
||||
'rocket_settings_tools_content' => 'display_cpcss_mobile_section',
|
||||
'wp_ajax_rocket_enable_mobile_cpcss' => 'enable_mobile_cpcss',
|
||||
'wp_ajax_rocket_cpcss_heartbeat' => 'cpcss_heartbeat',
|
||||
'admin_enqueue_scripts' => [
|
||||
[ 'enqueue_admin_edit_script' ],
|
||||
[ 'enqueue_admin_cpcss_heartbeat_script' ],
|
||||
],
|
||||
'rocket_admin_bar_items' => 'add_regenerate_menu_item',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable CPCSS mobile.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enable_mobile_cpcss() {
|
||||
$this->settings->enable_mobile_cpcss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display CPCSS mobile section tool admin view.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_cpcss_mobile_section() {
|
||||
$this->settings->display_cpcss_mobile_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue CPCSS generation / deletion script on edit.php page.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $page The current admin page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_admin_edit_script( $page ) {
|
||||
$this->post->enqueue_admin_edit_script( $page );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the critical CSS block in WP Rocket options metabox.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cpcss_section() {
|
||||
$this->post->cpcss_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the content inside the critical CSS block.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cpcss_actions() {
|
||||
$this->post->cpcss_actions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds async_css_mobile option to WP Rocket options.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $options WP Rocket options array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_async_css_mobile_option( $options ) {
|
||||
return $this->settings->add_async_css_mobile_option( $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default value of async_css_mobile to 0 when upgrading from < 3.6.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $new_version New WP Rocket version.
|
||||
* @param string $old_version Previous WP Rocket version.
|
||||
*/
|
||||
public function set_async_css_mobile_default_value( $new_version, $old_version ) {
|
||||
$this->settings->set_async_css_mobile_default_value( $new_version, $old_version );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds async_css_mobile to the hidden settings fields.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $hidden_settings_fields An array of hidden settings fields ID.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_hidden_async_css_mobile( $hidden_settings_fields ) {
|
||||
return $this->settings->add_hidden_async_css_mobile( $hidden_settings_fields );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the CPCSS heartbeat.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
public function cpcss_heartbeat() {
|
||||
$this->admin->cpcss_heartbeat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue CPCSS heartbeat script on all admin pages.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
public function enqueue_admin_cpcss_heartbeat_script() {
|
||||
$this->admin->enqueue_admin_cpcss_heartbeat_script();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Regenerate Critical CSS link to WP Rocket admin bar item
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance, passed by reference.
|
||||
* @return void
|
||||
*/
|
||||
public function add_regenerate_menu_item( $wp_admin_bar ) {
|
||||
$this->admin->add_regenerate_menu_item( $wp_admin_bar );
|
||||
}
|
||||
}
|
@@ -0,0 +1,578 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use FilesystemIterator;
|
||||
use UnexpectedValueException;
|
||||
use WP_Filesystem_Direct;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
|
||||
/**
|
||||
* Handles the critical CSS generation process.
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
class CriticalCSS {
|
||||
/**
|
||||
* Background Process instance.
|
||||
*
|
||||
* @var CriticalCSSGeneration
|
||||
*/
|
||||
public $process;
|
||||
|
||||
/**
|
||||
* WP Rocket options instance.
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Items for which we generate a critical CSS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $items = [];
|
||||
|
||||
/**
|
||||
* Path to the critical CSS directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $critical_css_path;
|
||||
|
||||
/**
|
||||
* Instance of the filesystem handler.
|
||||
*
|
||||
* @var WP_Filesystem_Direct
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* Creates an instance of CriticalCSS.
|
||||
*
|
||||
* @param CriticalCSSGeneration $process Background process instance.
|
||||
* @param Options_Data $options Instance of options data handler.
|
||||
* @param WP_Filesystem_Direct $filesystem Instance of the filesystem handler.
|
||||
*/
|
||||
public function __construct( CriticalCSSGeneration $process, Options_Data $options, $filesystem ) {
|
||||
$this->process = $process;
|
||||
$this->options = $options;
|
||||
$this->critical_css_path = rocket_get_constant( 'WP_ROCKET_CRITICAL_CSS_PATH' ) . get_current_blog_id() . '/';
|
||||
$this->filesystem = $filesystem;
|
||||
$this->items['front_page'] = [
|
||||
'type' => 'front_page',
|
||||
'url' => home_url( '/' ),
|
||||
'path' => 'front_page.css',
|
||||
'check' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current site critical CSS path.
|
||||
*
|
||||
* @since 3.3.5
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_critical_css_path() {
|
||||
return $this->critical_css_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the critical CSS generation.
|
||||
*
|
||||
* @since 3.6 Added the $version parameter.
|
||||
* @since 2.11
|
||||
*
|
||||
* @param string $version Optional. Version of the CPCSS files to generate. Possible values: default, mobile, all.
|
||||
*/
|
||||
public function process_handler( $version = 'default' ) {
|
||||
/**
|
||||
* Filters the critical CSS generation process.
|
||||
*
|
||||
* Use this filter to prevent the automatic critical CSS generation.
|
||||
*
|
||||
* @since 2.11.5
|
||||
*
|
||||
* @param bool $do_rocket_critical_css_generation True to activate the automatic generation, false to prevent it.
|
||||
*/
|
||||
if ( ! apply_filters( 'do_rocket_critical_css_generation', true ) ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
|
||||
return;
|
||||
}
|
||||
|
||||
if ( get_transient( 'rocket_critical_css_generation_process_running' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->clean_critical_css( $version );
|
||||
|
||||
$this->stop_generation();
|
||||
|
||||
$this->set_items( $version );
|
||||
|
||||
array_map( [ $this->process, 'push_to_queue' ], $this->items );
|
||||
|
||||
$this->update_process_running_transient();
|
||||
|
||||
$this->process->save()->dispatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the critical CSS generation process.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public function stop_generation() {
|
||||
if ( method_exists( $this->process, 'cancel_process' ) ) {
|
||||
$this->process->cancel_process();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches when the CPCSS generation is complete.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
protected function generation_complete() {
|
||||
/**
|
||||
* Fires when the critical CSS generation process is complete.
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
do_action( 'rocket_critical_css_generation_process_complete' );
|
||||
|
||||
set_transient( 'rocket_critical_css_generation_process_complete', get_transient( 'rocket_critical_css_generation_process_running' ), HOUR_IN_SECONDS );
|
||||
delete_transient( 'rocket_critical_css_generation_process_running' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes critical CSS files.
|
||||
*
|
||||
* @since 3.6 Replaced glob().
|
||||
* @since 3.6 Added $version parameter.
|
||||
* @since 2.11
|
||||
*
|
||||
* @param string $version Optional. Version of the CPCSS files to delete. Possible values: default, mobile, all.
|
||||
*/
|
||||
public function clean_critical_css( $version = 'default' ) {
|
||||
foreach ( $this->get_critical_css_iterator() as $file ) {
|
||||
if ( ! $this->filesystem->is_file( $file ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
'mobile' === $version
|
||||
&&
|
||||
false === strpos( $file, '-mobile' )
|
||||
) {
|
||||
continue;
|
||||
} elseif (
|
||||
'default' === $version
|
||||
&&
|
||||
false !== strpos( $file, '-mobile' )
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->filesystem->delete( $file );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Critical CSS Filesystem Iterator.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return FilesystemIterator|array Returns iterator on success; else an empty array.
|
||||
*/
|
||||
private function get_critical_css_iterator() {
|
||||
try {
|
||||
return new FilesystemIterator( $this->critical_css_path );
|
||||
} catch ( UnexpectedValueException $e ) {
|
||||
// No logging yet.
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all public post types.
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
private function get_public_post_types() {
|
||||
global $wpdb;
|
||||
|
||||
$post_types = get_post_types(
|
||||
[
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$post_types[] = 'page';
|
||||
|
||||
/**
|
||||
* Filters the post types excluded from critical CSS generation.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param array $excluded_post_types An array of post types names.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
$excluded_post_types = (array) apply_filters(
|
||||
'rocket_cpcss_excluded_post_types',
|
||||
[
|
||||
'elementor_library',
|
||||
'oceanwp_library',
|
||||
'tbuilder_layout',
|
||||
'tbuilder_layout_part',
|
||||
'slider',
|
||||
'karma-slider',
|
||||
'tt-gallery',
|
||||
'xlwcty_thankyou',
|
||||
'fusion_template',
|
||||
'blocks',
|
||||
'jet-woo-builder',
|
||||
'fl-builder-template',
|
||||
]
|
||||
);
|
||||
|
||||
$post_types = array_diff( $post_types, $excluded_post_types );
|
||||
$post_types = esc_sql( $post_types );
|
||||
$post_types = "'" . implode( "','", $post_types ) . "'";
|
||||
|
||||
return $wpdb->get_results(
|
||||
"SELECT MAX(ID) as ID, post_type
|
||||
FROM (
|
||||
SELECT ID, post_type
|
||||
FROM $wpdb->posts
|
||||
WHERE post_type IN ( $post_types )
|
||||
AND post_status = 'publish'
|
||||
ORDER BY post_date DESC
|
||||
) AS posts
|
||||
GROUP BY post_type"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all public taxonomies.
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
private function get_public_taxonomies() {
|
||||
global $wpdb;
|
||||
|
||||
$taxonomies = get_taxonomies(
|
||||
[
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
]
|
||||
);
|
||||
|
||||
/**
|
||||
* Filters the taxonomies excluded from critical CSS generation.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param array $excluded_taxonomies An array of taxonomies names.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
$excluded_taxonomies = (array) apply_filters(
|
||||
'rocket_cpcss_excluded_taxonomies',
|
||||
[
|
||||
'post_format',
|
||||
'product_shipping_class',
|
||||
'karma-slider-category',
|
||||
'truethemes-gallery-category',
|
||||
'coupon_campaign',
|
||||
'element_category',
|
||||
'mediamatic_wpfolder',
|
||||
'attachment_category',
|
||||
]
|
||||
);
|
||||
|
||||
$taxonomies = array_diff( $taxonomies, $excluded_taxonomies );
|
||||
$taxonomies = esc_sql( $taxonomies );
|
||||
$taxonomies = "'" . implode( "','", $taxonomies ) . "'";
|
||||
|
||||
return $wpdb->get_results(
|
||||
"SELECT MAX( term_id ) AS ID, taxonomy
|
||||
FROM (
|
||||
SELECT term_id, taxonomy
|
||||
FROM $wpdb->term_taxonomy
|
||||
WHERE taxonomy IN ( $taxonomies )
|
||||
AND count > 0
|
||||
) AS taxonomies
|
||||
GROUP BY taxonomy"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the items for which we generate critical CSS.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param string $version Optional. Version of the CPCSS files to generate. Possible values: default, mobile, all.
|
||||
*/
|
||||
private function set_items( $version = 'default' ) {
|
||||
$page_for_posts = get_option( 'page_for_posts' );
|
||||
|
||||
if ( 'page' === get_option( 'show_on_front' ) && ! empty( $page_for_posts ) ) {
|
||||
$this->items['home'] = [
|
||||
'type' => 'home',
|
||||
'url' => get_permalink( get_option( 'page_for_posts' ) ),
|
||||
'path' => 'home.css',
|
||||
'check' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
$post_types = $this->get_public_post_types();
|
||||
|
||||
foreach ( $post_types as $post_type ) {
|
||||
$this->items[ $post_type->post_type ] = [
|
||||
'type' => $post_type->post_type,
|
||||
'url' => get_permalink( $post_type->ID ),
|
||||
'path' => "{$post_type->post_type}.css",
|
||||
'check' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
$taxonomies = $this->get_public_taxonomies();
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
|
||||
$this->items[ $taxonomy->taxonomy ] = [
|
||||
'type' => $taxonomy->taxonomy,
|
||||
'url' => get_term_link( (int) $taxonomy->ID, $taxonomy->taxonomy ),
|
||||
'path' => "{$taxonomy->taxonomy}.css",
|
||||
'check' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
if ( in_array( $version, [ 'all', 'mobile' ], true ) ) {
|
||||
$mobile_items = [];
|
||||
|
||||
foreach ( $this->items as $key => $value ) {
|
||||
$value['mobile'] = 1;
|
||||
$value['path'] = str_replace( '.css', '-mobile.css', $value['path'] );
|
||||
$mobile_items[ "{$key}-mobile" ] = $value;
|
||||
}
|
||||
|
||||
if ( 'mobile' === $version ) {
|
||||
$this->items = $mobile_items;
|
||||
} elseif ( 'all' === $version ) {
|
||||
$this->items = array_merge( $this->items, $mobile_items );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the array containing the items to send to the critical CSS generator.
|
||||
*
|
||||
* @since 2.11.4
|
||||
*
|
||||
* @param array $items Array containing the type/url pair for each item to send.
|
||||
*/
|
||||
$this->items = (array) apply_filters( 'rocket_cpcss_items', $this->items );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the "rocket_critical_css_generation_process_running" transient.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
private function update_process_running_transient() {
|
||||
$total = 0;
|
||||
|
||||
foreach ( $this->items as $item ) {
|
||||
if ( ! isset( $item['mobile'] ) ) {
|
||||
$total ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 1 === $item['mobile'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$total ++;
|
||||
}
|
||||
|
||||
$transient = [
|
||||
'total' => $total,
|
||||
'items' => [],
|
||||
];
|
||||
|
||||
set_transient( 'rocket_critical_css_generation_process_running', $transient, HOUR_IN_SECONDS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CPCSS content to use on the current page.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function get_critical_css_content() {
|
||||
$filename = $this->get_current_page_critical_css();
|
||||
|
||||
if ( empty( $filename ) ) {
|
||||
return $this->options->get( 'critical_css', '' );
|
||||
}
|
||||
|
||||
return $this->filesystem->get_contents( $filename );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CPCSS filepath for the current page.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @return string Filepath if the file exists, empty string otherwise.
|
||||
*/
|
||||
public function get_current_page_critical_css() {
|
||||
$files = $this->get_critical_css_filenames();
|
||||
|
||||
if (
|
||||
$this->is_async_css_mobile()
|
||||
&&
|
||||
wp_is_mobile()
|
||||
&&
|
||||
$this->filesystem->is_readable( $this->critical_css_path . $files['mobile'] )
|
||||
) {
|
||||
return $this->critical_css_path . $files['mobile'];
|
||||
}
|
||||
|
||||
if ( $this->filesystem->is_readable( $this->critical_css_path . $files['default'] ) ) {
|
||||
return $this->critical_css_path . $files['default'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CPCSS filenames for the current URL type.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_critical_css_filenames() {
|
||||
$default = [
|
||||
'default' => 'front_page.css',
|
||||
'mobile' => 'front_page-mobile.css',
|
||||
];
|
||||
|
||||
if ( is_home() && 'page' === get_option( 'show_on_front' ) ) {
|
||||
return [
|
||||
'default' => 'home.css',
|
||||
'mobile' => 'home-mobile.css',
|
||||
];
|
||||
}
|
||||
|
||||
if ( is_front_page() ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ( is_category() ) {
|
||||
return [
|
||||
'default' => 'category.css',
|
||||
'mobile' => 'category-mobile.css',
|
||||
];
|
||||
}
|
||||
|
||||
if ( is_tag() ) {
|
||||
return [
|
||||
'default' => 'post_tag.css',
|
||||
'mobile' => 'post_tag-mobile.css',
|
||||
];
|
||||
}
|
||||
|
||||
if ( is_tax() ) {
|
||||
$taxonomy = get_queried_object()->taxonomy;
|
||||
|
||||
return [
|
||||
'default' => "{$taxonomy}.css",
|
||||
'mobile' => "{$taxonomy}-mobile.css",
|
||||
];
|
||||
}
|
||||
|
||||
if ( is_singular() ) {
|
||||
return $this->get_singular_cpcss_filenames();
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the filenames for a singular content.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_singular_cpcss_filenames() {
|
||||
$post_type = get_post_type();
|
||||
$post_id = get_the_ID();
|
||||
$post_cpcss = [
|
||||
'default' => "posts/{$post_type}-{$post_id}.css",
|
||||
'mobile' => "posts/{$post_type}-{$post_id}-mobile.css",
|
||||
];
|
||||
|
||||
if (
|
||||
$this->is_async_css_mobile()
|
||||
&&
|
||||
! $this->filesystem->exists( $this->critical_css_path . $post_cpcss['mobile'] )
|
||||
) {
|
||||
$post_cpcss['mobile'] = $post_cpcss['default'];
|
||||
}
|
||||
|
||||
if ( $this->filesystem->exists( $this->critical_css_path . $post_cpcss['default'] ) ) {
|
||||
return $post_cpcss;
|
||||
}
|
||||
|
||||
return [
|
||||
'default' => "{$post_type}.css",
|
||||
'mobile' => "{$post_type}-mobile.css",
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we are in a situation where we need the mobile CPCSS.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_async_css_mobile() {
|
||||
if ( ! (bool) $this->options->get( 'do_caching_mobile_files', 0 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $this->options->get( 'async_css_mobile', 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of CSS files to be excluded from async CSS.
|
||||
*
|
||||
* @since 3.6.2
|
||||
*
|
||||
* @return array An array of URLs for the CSS files to be excluded.
|
||||
*/
|
||||
public function get_exclude_async_css() {
|
||||
/**
|
||||
* Filter list of async CSS files
|
||||
*
|
||||
* @since 2.10
|
||||
*
|
||||
* @param array $exclude_async_css An array of URLs for the CSS files to be excluded.
|
||||
*/
|
||||
$exclude_async_css = (array) apply_filters( 'rocket_exclude_async_css', [] );
|
||||
if ( empty( $exclude_async_css ) ) {
|
||||
return $exclude_async_css;
|
||||
}
|
||||
$exclude_async_css = array_filter( $exclude_async_css );
|
||||
|
||||
return array_flip( array_flip( $exclude_async_css ) );
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_Rocket_WP_Background_Process;
|
||||
|
||||
/**
|
||||
* Extends the background process class for the critical CSS generation process.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @see WP_Background_Process
|
||||
*/
|
||||
class CriticalCSSGeneration extends WP_Rocket_WP_Background_Process {
|
||||
use TransientTrait;
|
||||
|
||||
/**
|
||||
* Process prefix.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = 'rocket';
|
||||
|
||||
/**
|
||||
* Specific action identifier for sitemap preload.
|
||||
*
|
||||
* @var string Action identifier
|
||||
*/
|
||||
protected $action = 'critical_css_generation';
|
||||
|
||||
/**
|
||||
* ProcessorService instance.
|
||||
*
|
||||
* @var ProcessorService
|
||||
*/
|
||||
protected $processor;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param ProcessorService $processor ProcessorService instance.
|
||||
*/
|
||||
public function __construct( ProcessorService $processor ) {
|
||||
parent::__construct();
|
||||
|
||||
$this->processor = $processor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the optimization corresponding to $item.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param mixed $item Queue item to iterate over.
|
||||
*
|
||||
* @return bool false if task performed successfully, true otherwise to re-queue the item.
|
||||
*/
|
||||
protected function task( $item ) {
|
||||
if ( ! is_array( $item ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$transient = get_transient( 'rocket_critical_css_generation_process_running' );
|
||||
$mobile = isset( $item['mobile'] ) ? $item['mobile'] : 0;
|
||||
|
||||
$generation_params = [
|
||||
'is_mobile' => $mobile,
|
||||
'item_type' => $item['type'],
|
||||
];
|
||||
$generated = $this->processor->process_generate( $item['url'], $item['path'], $generation_params );
|
||||
|
||||
if ( is_wp_error( $generated ) ) {
|
||||
$this->update_running_transient( $transient, $item['path'], $mobile, $generated->get_error_message(), false );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isset( $generated['code'] ) && 'cpcss_generation_pending' === $generated['code'] ) {
|
||||
$pending = get_transient( 'rocket_cpcss_generation_pending' );
|
||||
|
||||
if ( false === $pending ) {
|
||||
$pending = [];
|
||||
}
|
||||
|
||||
$pending[ $item['path'] ] = $item;
|
||||
|
||||
set_transient( 'rocket_cpcss_generation_pending', $pending, HOUR_IN_SECONDS );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->update_running_transient( $transient, $item['path'], $mobile, $generated['message'], ( 'cpcss_generation_successful' === $generated['code'] ) );
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,728 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
use WP_Filesystem_Direct;
|
||||
|
||||
/**
|
||||
* Critical CSS Subscriber.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
class CriticalCSSSubscriber implements Subscriber_Interface {
|
||||
|
||||
/**
|
||||
* Instance of Critical CSS.
|
||||
*
|
||||
* @var Critical_CSS
|
||||
*/
|
||||
protected $critical_css;
|
||||
|
||||
/**
|
||||
* Instance of options.
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* Instance of the filesystem handler.
|
||||
*
|
||||
* @var WP_Filesystem_Direct
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* CPCSS generation and deletion service.
|
||||
*
|
||||
* @var ProcessorService instance for this service.
|
||||
*/
|
||||
private $cpcss_service;
|
||||
|
||||
/**
|
||||
* Creates an instance of the Critical CSS Subscriber.
|
||||
*
|
||||
* @param CriticalCSS $critical_css Critical CSS instance.
|
||||
* @param ProcessorService $cpcss_service Has the logic for cpcss generation and deletion.
|
||||
* @param Options_Data $options WP Rocket options.
|
||||
* @param WP_Filesystem_Direct $filesystem Instance of the filesystem handler.
|
||||
*/
|
||||
public function __construct( CriticalCSS $critical_css, ProcessorService $cpcss_service, Options_Data $options, $filesystem ) {
|
||||
$this->critical_css = $critical_css;
|
||||
$this->cpcss_service = $cpcss_service;
|
||||
$this->options = $options;
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.3
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
// phpcs:disable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
|
||||
return [
|
||||
'admin_post_rocket_generate_critical_css' => 'init_critical_css_generation',
|
||||
|
||||
'update_option_' . rocket_get_constant( 'WP_ROCKET_SLUG' ) => [
|
||||
[ 'generate_critical_css_on_activation', 11, 2 ],
|
||||
[ 'stop_process_on_deactivation', 11, 2 ],
|
||||
[ 'maybe_generate_cpcss_mobile', 12, 2 ],
|
||||
],
|
||||
|
||||
'admin_notices' => [
|
||||
[ 'notice_critical_css_generation_triggered' ],
|
||||
[ 'critical_css_generation_running_notice' ],
|
||||
[ 'critical_css_generation_complete_notice' ],
|
||||
[ 'warning_critical_css_dir_permissions' ],
|
||||
],
|
||||
|
||||
'wp_head' => [ 'insert_load_css', PHP_INT_MAX ],
|
||||
|
||||
'rocket_buffer' => [
|
||||
[ 'insert_critical_css_buffer', 19 ],
|
||||
[ 'async_css', 32 ],
|
||||
],
|
||||
|
||||
'switch_theme' => 'maybe_regenerate_cpcss',
|
||||
'rocket_excluded_inline_js_content' => 'exclude_inline_js',
|
||||
'before_delete_post' => 'delete_cpcss',
|
||||
];
|
||||
// phpcs:enable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the custom CPCSS files from /posts/ folder.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $post_id Deleted post id.
|
||||
*/
|
||||
public function delete_cpcss( $post_id ) {
|
||||
if ( ! current_user_can( 'rocket_regenerate_critical_css' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->options->get( 'async_css', 0 ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post_type = get_post_type( $post_id );
|
||||
$item_path = 'posts' . DIRECTORY_SEPARATOR . "{$post_type}-{$post_id}.css";
|
||||
$this->cpcss_service->process_delete( $item_path );
|
||||
|
||||
if ( $this->options->get( 'async_css_mobile', 0 ) ) {
|
||||
$mobile_item_path = 'posts' . DIRECTORY_SEPARATOR . "{$post_type}-{$post_id}-mobile.css";
|
||||
$this->cpcss_service->process_delete( $mobile_item_path );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This notice is displayed when the Critical CSS Generation is triggered from a different page than
|
||||
* WP Rocket settings page.
|
||||
*
|
||||
* @since 3.4.1
|
||||
*/
|
||||
public function notice_critical_css_generation_triggered() {
|
||||
if ( ! current_user_can( 'rocket_regenerate_critical_css' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
|
||||
if ( 'settings_page_wprocket' === $screen->id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( false === get_transient( 'rocket_critical_css_generation_triggered' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete_transient( 'rocket_critical_css_generation_triggered' );
|
||||
|
||||
$message = __( 'Critical CSS generation is currently running.', 'rocket' );
|
||||
|
||||
if ( current_user_can( 'rocket_manage_options' ) ) {
|
||||
$message .= ' ' . sprintf(
|
||||
// Translators: %1$s = opening link tag, %2$s = closing link tag.
|
||||
__( 'Go to the %1$sWP Rocket settings%2$s page to track progress.', 'rocket' ),
|
||||
'<a href="' . esc_url( admin_url( 'options-general.php?page=' . WP_ROCKET_PLUGIN_SLUG ) ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
}
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => 'info',
|
||||
'message' => $message,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the critical CSS generation from admin.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @see CriticalCSS::process_handler()
|
||||
*/
|
||||
public function init_critical_css_generation() {
|
||||
if (
|
||||
! isset( $_GET['_wpnonce'] )
|
||||
||
|
||||
! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'rocket_generate_critical_css' )
|
||||
) {
|
||||
wp_nonce_ays( '' );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'rocket_regenerate_critical_css' ) ) {
|
||||
wp_die();
|
||||
}
|
||||
|
||||
$version = 'default';
|
||||
|
||||
if ( $this->critical_css->is_async_css_mobile() ) {
|
||||
$version = 'all';
|
||||
}
|
||||
|
||||
$this->critical_css->process_handler( $version );
|
||||
|
||||
if ( ! strpos( wp_get_referer(), 'wprocket' ) ) {
|
||||
set_transient( 'rocket_critical_css_generation_triggered', 1 );
|
||||
}
|
||||
|
||||
wp_safe_redirect( esc_url_raw( wp_get_referer() ) );
|
||||
rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ? wp_die() : exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the critical CSS generation when activating the async CSS option.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param array $old_value Previous values for WP Rocket settings.
|
||||
* @param array $value New values for WP Rocket settings.
|
||||
*
|
||||
* @see CriticalCSS::process_handler()
|
||||
*/
|
||||
public function generate_critical_css_on_activation( $old_value, $value ) {
|
||||
if (
|
||||
! isset( $old_value['async_css'], $value['async_css'] )
|
||||
||
|
||||
( $old_value['async_css'] === $value['async_css'] )
|
||||
|| 1 !== (int) $value['async_css']
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$critical_css_path = $this->critical_css->get_critical_css_path();
|
||||
|
||||
// Check if the CPCSS path exists and create it.
|
||||
if ( ! $this->filesystem->is_dir( $critical_css_path ) ) {
|
||||
rocket_mkdir_p( $critical_css_path );
|
||||
}
|
||||
|
||||
$version = 'default';
|
||||
|
||||
if (
|
||||
isset( $value['do_caching_mobile_files'], $value['async_css_mobile'] )
|
||||
&&
|
||||
(
|
||||
1 === (int) $value['do_caching_mobile_files']
|
||||
&&
|
||||
1 === (int) $value['async_css_mobile']
|
||||
)
|
||||
) {
|
||||
$version = 'all';
|
||||
}
|
||||
|
||||
// Generate the CPCSS files.
|
||||
$this->critical_css->process_handler( $version );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe generate the CPCSS for Mobile.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $old_value Array of original values.
|
||||
* @param array $value Array of new values.
|
||||
*/
|
||||
public function maybe_generate_cpcss_mobile( $old_value, $value ) {
|
||||
if (
|
||||
! isset( $value['async_css_mobile'] )
|
||||
||
|
||||
1 !== (int) $value['async_css_mobile']
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
! isset( $value['do_caching_mobile_files'] )
|
||||
||
|
||||
1 !== (int) $value['do_caching_mobile_files']
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
! isset( $old_value['async_css'], $value['async_css'] )
|
||||
||
|
||||
( ( $old_value['async_css'] !== $value['async_css'] ) && 1 === (int) $value['async_css'] )
|
||||
||
|
||||
1 !== (int) $value['async_css']
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->critical_css->process_handler( 'mobile' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the critical CSS generation when deactivating the async CSS option and remove the notices.
|
||||
*
|
||||
* @since 2.11
|
||||
*
|
||||
* @param array $old_value Previous values for WP Rocket settings.
|
||||
* @param array $value New values for WP Rocket settings.
|
||||
*/
|
||||
public function stop_process_on_deactivation( $old_value, $value ) {
|
||||
if (
|
||||
! empty( $_POST[ WP_ROCKET_SLUG ] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
&&
|
||||
isset( $old_value['async_css'], $value['async_css'] )
|
||||
&&
|
||||
( $old_value['async_css'] !== $value['async_css'] )
|
||||
&&
|
||||
0 === (int) $value['async_css']
|
||||
) {
|
||||
$this->critical_css->stop_generation();
|
||||
|
||||
delete_transient( 'rocket_critical_css_generation_process_running' );
|
||||
delete_transient( 'rocket_critical_css_generation_process_complete' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This notice is displayed when the critical CSS generation is running.
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
public function critical_css_generation_running_notice() {
|
||||
if ( ! current_user_can( 'rocket_regenerate_critical_css' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
|
||||
if ( 'settings_page_wprocket' !== $screen->id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transient = get_transient( 'rocket_critical_css_generation_process_running' );
|
||||
|
||||
if ( ! $transient ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$success_counter = 0;
|
||||
$items_message = '';
|
||||
|
||||
if ( ! empty( $transient['items'] ) ) {
|
||||
$items_message .= '<ul>';
|
||||
|
||||
foreach ( $transient['items'] as $item ) {
|
||||
$status_nonmobile = isset( $item['status']['nonmobile'] );
|
||||
$status_mobile = $this->is_mobile_cpcss_active() ? isset( $item['status']['mobile'] ) : true;
|
||||
if ( $status_nonmobile && $status_mobile ) {
|
||||
$items_message .= '<li>' . $item['status']['nonmobile']['message'] . '</li>';
|
||||
if ( $item['status']['nonmobile']['success'] ) {
|
||||
$success_counter ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$items_message .= '</ul>';
|
||||
}
|
||||
|
||||
if ( ! isset( $transient['total'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
0 === $success_counter
|
||||
&&
|
||||
0 === $transient['total']
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = '<p>' . sprintf(
|
||||
// Translators: %1$d = number of critical CSS generated, %2$d = total number of critical CSS to generate.
|
||||
__( 'Critical CSS generation is currently running: %1$d of %2$d page types completed. (Refresh this page to view progress)', 'rocket' ),
|
||||
$success_counter,
|
||||
$transient['total']
|
||||
) . '</p>' . $items_message;
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => 'info',
|
||||
'message' => $message,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This notice is displayed when the critical CSS generation is complete.
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
public function critical_css_generation_complete_notice() {
|
||||
if ( ! current_user_can( 'rocket_regenerate_critical_css' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
|
||||
if ( 'settings_page_wprocket' !== $screen->id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transient = get_transient( 'rocket_critical_css_generation_process_complete' );
|
||||
if ( ! $transient ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$status = 'success';
|
||||
$success_counter = 0;
|
||||
$items_message = '';
|
||||
$desktop = false;
|
||||
|
||||
if ( ! empty( $transient['items'] ) ) {
|
||||
$items_message .= '<ul>';
|
||||
|
||||
foreach ( $transient['items'] as $item ) {
|
||||
$status_nonmobile = isset( $item['status']['nonmobile'] );
|
||||
$status_mobile = $this->is_mobile_cpcss_active() ? isset( $item['status']['mobile'] ) : true;
|
||||
if ( ! $status_nonmobile || ! $status_mobile ) {
|
||||
continue;
|
||||
}
|
||||
if ( isset( $item['status']['nonmobile']['message'] ) ) {
|
||||
$desktop = true;
|
||||
}
|
||||
$items_message .= '<li>' . $item['status']['nonmobile']['message'] . '</li>';
|
||||
if ( $item['status']['nonmobile']['success'] ) {
|
||||
$success_counter ++;
|
||||
}
|
||||
}
|
||||
|
||||
$items_message .= '</ul>';
|
||||
}
|
||||
|
||||
if ( ! $desktop || ( 0 === $success_counter && 0 === $transient['total'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 0 === $success_counter ) {
|
||||
$status = 'error';
|
||||
} elseif ( $success_counter < $transient['total'] ) {
|
||||
$status = 'warning';
|
||||
}
|
||||
|
||||
$message = '<p>' . sprintf(
|
||||
// Translators: %1$d = number of critical CSS generated, %2$d = total number of critical CSS to generate.
|
||||
__( 'Critical CSS generation finished for %1$d of %2$d page types.', 'rocket' ),
|
||||
$success_counter,
|
||||
$transient['total']
|
||||
);
|
||||
$message .= ' <em> (' . date_i18n( get_option( 'date_format' ) ) . ' @ ' . date_i18n( get_option( 'time_format' ) ) . ') </em></p>' . $items_message;
|
||||
|
||||
if ( 'error' === $status || 'warning' === $status ) {
|
||||
$message .= '<p>' . __( 'Critical CSS generation encountered one or more errors.', 'rocket' ) . ' <a href="https://docs.wp-rocket.me/article/1267-troubleshooting-critical-css-generation-issues" data-beacon-article="5d5214d10428631e94f94ae6" target="_blank" rel="noreferer noopener">' . __( 'Learn more.', 'rocket' ) . '</a>';
|
||||
}
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => $status,
|
||||
'message' => $message,
|
||||
]
|
||||
);
|
||||
|
||||
delete_transient( 'rocket_critical_css_generation_process_complete' );
|
||||
}
|
||||
|
||||
/**
|
||||
* This warning is displayed when the critical CSS dir isn't writeable.
|
||||
*
|
||||
* @since 2.11
|
||||
*/
|
||||
public function warning_critical_css_dir_permissions() {
|
||||
if (
|
||||
current_user_can( 'rocket_manage_options' )
|
||||
&&
|
||||
( ! $this->filesystem->is_writable( WP_ROCKET_CRITICAL_CSS_PATH ) )
|
||||
&&
|
||||
( $this->options->get( 'async_css', false ) )
|
||||
&&
|
||||
rocket_valid_key()
|
||||
) {
|
||||
|
||||
$boxes = get_user_meta( get_current_user_id(), 'rocket_boxes', true );
|
||||
|
||||
if ( in_array( __FUNCTION__, (array) $boxes, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = rocket_notice_writing_permissions(
|
||||
trim( str_replace( ABSPATH, '', WP_ROCKET_CRITICAL_CSS_PATH ), '/' )
|
||||
);
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => 'error',
|
||||
'dismissible' => '',
|
||||
'message' => $message,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert loadCSS script in <head>.
|
||||
*
|
||||
* @since 2.11.2 Updated loadCSS rel=preload polyfill to version 2.0.1
|
||||
* @since 2.10
|
||||
*/
|
||||
public function insert_load_css() {
|
||||
if ( ! $this->should_async_css() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This filter is documented in inc/classes/Buffer/class-tests.php.
|
||||
$rocket_cache_search = apply_filters( 'rocket_cache_search', false );
|
||||
|
||||
// Don't apply on search page.
|
||||
if ( is_search() && ! $rocket_cache_search ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't apply on 404 page.
|
||||
if ( is_404() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
empty( $this->critical_css->get_current_page_critical_css() )
|
||||
&&
|
||||
empty( $this->options->get( 'critical_css', '' ) )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. */ <<<JS
|
||||
<script>
|
||||
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
|
||||
(function(w){"use strict";if(!w.loadCSS){w.loadCSS=function(){}}
|
||||
var rp=loadCSS.relpreload={};rp.support=(function(){var ret;try{ret=w.document.createElement("link").relList.supports("preload")}catch(e){ret=!1}
|
||||
return function(){return ret}})();rp.bindMediaToggle=function(link){var finalMedia=link.media||"all";function enableStylesheet(){link.media=finalMedia}
|
||||
if(link.addEventListener){link.addEventListener("load",enableStylesheet)}else if(link.attachEvent){link.attachEvent("onload",enableStylesheet)}
|
||||
setTimeout(function(){link.rel="stylesheet";link.media="only x"});setTimeout(enableStylesheet,3000)};rp.poly=function(){if(rp.support()){return}
|
||||
var links=w.document.getElementsByTagName("link");for(var i=0;i<links.length;i++){var link=links[i];if(link.rel==="preload"&&link.getAttribute("as")==="style"&&!link.getAttribute("data-loadcss")){link.setAttribute("data-loadcss",!0);rp.bindMediaToggle(link)}}};if(!rp.support()){rp.poly();var run=w.setInterval(rp.poly,500);if(w.addEventListener){w.addEventListener("load",function(){rp.poly();w.clearInterval(run)})}else if(w.attachEvent){w.attachEvent("onload",function(){rp.poly();w.clearInterval(run)})}}
|
||||
if(typeof exports!=="undefined"){exports.loadCSS=loadCSS}
|
||||
else{w.loadCSS=loadCSS}}(typeof global!=="undefined"?global:this))
|
||||
</script>
|
||||
JS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert critical CSS before combined CSS when option is active.
|
||||
*
|
||||
* @since 2.11.5
|
||||
*
|
||||
* @param string $buffer HTML output of the page.
|
||||
*
|
||||
* @return string Updated HTML output
|
||||
*/
|
||||
public function insert_critical_css_buffer( $buffer ) {
|
||||
if ( ! $this->should_async_css() ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$critical_css_content = $this->critical_css->get_critical_css_content();
|
||||
|
||||
if ( empty( $critical_css_content ) ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$critical_css_content = str_replace( '\\', '\\\\', $critical_css_content );
|
||||
|
||||
$buffer = preg_replace(
|
||||
'#</title>#iU',
|
||||
'</title><style id="rocket-critical-css">' . wp_strip_all_tags( $critical_css_content ) . '</style>',
|
||||
$buffer,
|
||||
1
|
||||
);
|
||||
|
||||
return preg_replace( '#</body>#iU', $this->return_remove_cpcss_script() . '</body>', $buffer, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JS script to remove the critical css style from frontend.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function return_remove_cpcss_script() {
|
||||
$filename = rocket_get_constant( 'SCRIPT_DEBUG' ) ? 'cpcss-removal.js' : 'cpcss-removal.min.js';
|
||||
$script = rocket_get_constant( 'WP_ROCKET_PATH' ) . "assets/js/{$filename}";
|
||||
|
||||
if ( ! is_readable( $script ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<script>%s</script>',
|
||||
$this->filesystem->get_contents( $script )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds wprRemoveCPCSS to excluded inline JS array.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $excluded_inline Array of inline JS excluded from being combined.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function exclude_inline_js( array $excluded_inline ) {
|
||||
$excluded_inline[] = 'wprRemoveCPCSS';
|
||||
|
||||
return $excluded_inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defer loading of CSS files.
|
||||
*
|
||||
* @since 2.10
|
||||
*
|
||||
* @param string $buffer HTML code.
|
||||
*
|
||||
* @return string Updated HTML code
|
||||
*/
|
||||
public function async_css( $buffer ) {
|
||||
if ( ! $this->should_async_css() ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
if (
|
||||
empty( $this->critical_css->get_current_page_critical_css() )
|
||||
&&
|
||||
empty( $this->options->get( 'critical_css', '' ) )
|
||||
) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$excluded_css = array_flip( $this->critical_css->get_exclude_async_css() );
|
||||
|
||||
/**
|
||||
* Filters the pattern used to get all stylesheets in the HTML.
|
||||
*
|
||||
* @since 2.10
|
||||
*
|
||||
* @param string $css_pattern Regex pattern to get all stylesheets in the HTML.
|
||||
*/
|
||||
$css_pattern = apply_filters(
|
||||
'rocket_async_css_regex_pattern',
|
||||
'/(?=<link[^>]*\s(rel\s*=\s*[\'"]stylesheet["\']))<link[^>]*\shref\s*=\s*[\'"]([^\'"]+)[\'"](.*)>/iU'
|
||||
);
|
||||
|
||||
// Get all css files with this regex.
|
||||
preg_match_all( $css_pattern, $buffer, $tags_match );
|
||||
if ( ! isset( $tags_match[0] ) ) {
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$noscripts = '<noscript>';
|
||||
|
||||
foreach ( $tags_match[0] as $i => $tag ) {
|
||||
// Strip query args.
|
||||
$path = wp_parse_url( $tags_match[2][ $i ], PHP_URL_PATH );
|
||||
|
||||
// Check if this file should be deferred.
|
||||
if ( isset( $excluded_css[ $path ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$preload = str_replace( 'stylesheet', 'preload', $tags_match[1][ $i ] );
|
||||
$onload = preg_replace( '~' . preg_quote( $tags_match[3][ $i ], '~' ) . '~iU', ' data-rocket-async="style" as="style" onload=""' . $tags_match[3][ $i ] . '>', $tags_match[3][ $i ] );
|
||||
$tag = str_replace( $tags_match[3][ $i ] . '>', $onload, $tag );
|
||||
$tag = str_replace( $tags_match[1][ $i ], $preload, $tag );
|
||||
$tag = str_replace( 'onload=""', 'onload="this.onload=null;this.rel=\'stylesheet\'"', $tag );
|
||||
$tag = preg_replace( '/(id\s*=\s*[\"\'](?:[^\"\']*)*[\"\'])/i', '', $tag );
|
||||
$buffer = str_replace( $tags_match[0][ $i ], $tag, $buffer );
|
||||
|
||||
$noscripts .= $tags_match[0][ $i ];
|
||||
}
|
||||
|
||||
$noscripts .= '</noscript>';
|
||||
|
||||
return str_replace( '</body>', $noscripts . '</body>', $buffer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerates the CPCSS when switching theme if the option is active.
|
||||
*
|
||||
* @since 3.3
|
||||
*/
|
||||
public function maybe_regenerate_cpcss() {
|
||||
if ( ! $this->options->get( 'async_css' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->critical_css->process_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if mobile CPCSS is active.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return boolean CPCSS active or not.
|
||||
*/
|
||||
private function is_mobile_cpcss_active() {
|
||||
return (
|
||||
$this->options->get( 'async_css', 0 )
|
||||
&&
|
||||
$this->options->get( 'cache_mobile', 0 )
|
||||
&&
|
||||
$this->options->get( 'do_caching_mobile_files', 0 )
|
||||
)
|
||||
&&
|
||||
$this->options->get( 'async_css_mobile', 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if we should async CSS
|
||||
*
|
||||
* @since 3.6.2.1
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function should_async_css() {
|
||||
if ( rocket_get_constant( 'DONOTROCKETOPTIMIZE' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->options->get( 'async_css', 0 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! is_rocket_post_excluded_option( 'async_css' );
|
||||
}
|
||||
}
|
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_Error;
|
||||
use WP_Filesystem_Direct;
|
||||
|
||||
/**
|
||||
* Class DataManager
|
||||
*
|
||||
* @package WP_Rocket\Engine\CriticalPath
|
||||
*/
|
||||
class DataManager {
|
||||
|
||||
/**
|
||||
* Base critical CSS path for posts.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $critical_css_path;
|
||||
|
||||
/**
|
||||
* Instance of the filesystem handler.
|
||||
*
|
||||
* @var WP_Filesystem_Direct
|
||||
*/
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* DataManager constructor, adjust the critical css path for posts.
|
||||
*
|
||||
* @param string $critical_css_path path for main critical css folder.
|
||||
* @param WP_Filesystem_Direct $filesystem Instance of the filesystem handler.
|
||||
*/
|
||||
public function __construct( $critical_css_path, $filesystem ) {
|
||||
$this->critical_css_path = $critical_css_path . get_current_blog_id() . DIRECTORY_SEPARATOR;
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save CPCSS into file.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $path Path for cpcss file related to this web page.
|
||||
* @param string $cpcss CPCSS code to be saved.
|
||||
* @param string $url URL for item to be used in error messages.
|
||||
* @param bool $is_mobile If this is cpcss for mobile or not.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function save_cpcss( $path, $cpcss, $url, $is_mobile = false, $item_type = 'custom' ) {
|
||||
$file_path_directory = dirname( $this->critical_css_path . $path );
|
||||
|
||||
if ( ! $this->filesystem->is_dir( $file_path_directory ) ) {
|
||||
if ( ! rocket_mkdir_p( $file_path_directory ) ) {
|
||||
|
||||
return new WP_Error(
|
||||
'cpcss_generation_failed',
|
||||
// translators: %s = item URL.
|
||||
sprintf(
|
||||
$is_mobile
|
||||
?
|
||||
// translators: %s = item URL.
|
||||
__( 'Critical CSS for %1$s on mobile not generated. Error: The API returned an empty response.', 'rocket' )
|
||||
:
|
||||
// translators: %s = item URL.
|
||||
__( 'Critical CSS for %1$s not generated. Error: The API returned an empty response.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $url : $item_type
|
||||
),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return rocket_put_content(
|
||||
$this->critical_css_path . $path,
|
||||
wp_strip_all_tags( $cpcss, true )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete critical css file by path.
|
||||
*
|
||||
* @param string $path Critical css file path to be deleted.
|
||||
* @param bool $is_mobile If this is cpcss for mobile or not.
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function delete_cpcss( $path, $is_mobile = false ) {
|
||||
$full_path = $this->critical_css_path . $path;
|
||||
|
||||
if ( ! $this->filesystem->exists( $full_path ) ) {
|
||||
return new WP_Error(
|
||||
'cpcss_not_exists',
|
||||
$is_mobile
|
||||
?
|
||||
__( 'Critical CSS file for mobile does not exist', 'rocket' )
|
||||
:
|
||||
__( 'Critical CSS file does not exist', 'rocket' ),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! $this->filesystem->delete( $full_path ) ) {
|
||||
return new WP_Error(
|
||||
'cpcss_deleted_failed',
|
||||
$is_mobile
|
||||
?
|
||||
__( 'Critical CSS file for mobile cannot be deleted', 'rocket' )
|
||||
:
|
||||
__( 'Critical CSS file cannot be deleted', 'rocket' ),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job_id from cache based on item_url.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_url URL for item to be used in error messages.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_cache_job_id( $item_url, $is_mobile = false ) {
|
||||
$cache_key = $this->get_cache_key_from_url( $item_url, $is_mobile );
|
||||
|
||||
return get_transient( $cache_key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Job_id for Item_url into cache.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_url URL for item to be used in error messages.
|
||||
* @param string $job_id ID for the job to get details.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function set_cache_job_id( $item_url, $job_id, $is_mobile = false ) {
|
||||
$cache_key = $this->get_cache_key_from_url( $item_url, $is_mobile );
|
||||
|
||||
return set_transient( $cache_key, $job_id, HOUR_IN_SECONDS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete job_id from cache based on item_url.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_url URL for item to be used in error messages.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_cache_job_id( $item_url, $is_mobile = false ) {
|
||||
$cache_key = $this->get_cache_key_from_url( $item_url, $is_mobile );
|
||||
|
||||
return delete_transient( $cache_key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key from url to be used in caching job_id.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_url URL for item to be used in error messages.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_cache_key_from_url( $item_url, $is_mobile = false ) {
|
||||
$encoded_url = md5( $item_url );
|
||||
|
||||
if ( $is_mobile ) {
|
||||
$encoded_url .= '_mobile';
|
||||
}
|
||||
|
||||
return 'rocket_specific_cpcss_job_' . $encoded_url;
|
||||
}
|
||||
}
|
@@ -0,0 +1,338 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_Error;
|
||||
|
||||
class ProcessorService {
|
||||
|
||||
/**
|
||||
* Responsible for dealing with data/database.
|
||||
*
|
||||
* @var DataManager datamanager instance.
|
||||
*/
|
||||
private $data_manager;
|
||||
|
||||
/**
|
||||
* Responsible for dealing with CPCSS APIs.
|
||||
*
|
||||
* @var APIClient api_client instance.
|
||||
*/
|
||||
private $api_client;
|
||||
|
||||
/**
|
||||
* RESTWP constructor.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param DataManager $data_manager Data manager instance, responsible for dealing with data/database.
|
||||
* @param APIClient $api_client API Client instance to deal with CPCSS APIs.
|
||||
*/
|
||||
public function __construct( DataManager $data_manager, APIClient $api_client ) {
|
||||
$this->data_manager = $data_manager;
|
||||
$this->api_client = $api_client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process CPCSS generation, Check timeout and send the generation request.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_url URL for item to be used in error messages.
|
||||
* @param string $item_path Path for item to be processed.
|
||||
* @param array $additional_parameters additional parameters for generation.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function process_generate( $item_url, $item_path, $additional_parameters = [] ) {
|
||||
$defaults = [
|
||||
'timeout' => false,
|
||||
'is_mobile' => false,
|
||||
'item_type' => 'custom',
|
||||
];
|
||||
$args = array_merge( $defaults, $additional_parameters );
|
||||
|
||||
// Ajax call requested a timeout.
|
||||
if ( $args['timeout'] ) {
|
||||
return $this->process_timeout( $item_url, $args['is_mobile'], $args['item_type'] );
|
||||
}
|
||||
|
||||
$cpcss_job_id = $this->data_manager->get_cache_job_id( $item_url, $args['is_mobile'] );
|
||||
if ( false === $cpcss_job_id ) {
|
||||
return $this->send_generation_request( $item_url, $item_path, $args['is_mobile'], $args['item_type'] );
|
||||
}
|
||||
|
||||
// job_id is found and we need to check status for it.
|
||||
return $this->check_cpcss_job_status( $cpcss_job_id, $item_path, $item_url, $args['is_mobile'], $args['item_type'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Generation first request.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_url Url for item to send the generation request for.
|
||||
* @param string $item_path Path for item to send the generation request for.
|
||||
* @param bool $is_mobile If this request is for mobile cpcss.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function send_generation_request( $item_url, $item_path, $is_mobile = false, $item_type = 'custom' ) {
|
||||
// call send generation request from APIClient for the first time.
|
||||
$params = [
|
||||
'mobile' => (int) $is_mobile,
|
||||
];
|
||||
$generated_job = $this->api_client->send_generation_request( $item_url, $params, $item_type );
|
||||
|
||||
// validate generate response.
|
||||
if ( is_wp_error( $generated_job ) ) {
|
||||
// Failed so return back the data.
|
||||
return $generated_job;
|
||||
}
|
||||
|
||||
// Send generation request succeeded.
|
||||
// Save job_id into cache.
|
||||
$this->data_manager->set_cache_job_id( $item_url, $generated_job->data->id, $is_mobile );
|
||||
|
||||
return $this->check_cpcss_job_status( $generated_job->data->id, $item_path, $item_url, $is_mobile, $item_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get job details by job_id.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $job_id ID for the job to get details.
|
||||
* @param string $item_url URL for item to be used in error messages.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return array|mixed|WP_Error
|
||||
*/
|
||||
private function get_cpcss_job_details( $job_id, $item_url, $item_type = 'custom' ) {
|
||||
$job_details = $this->api_client->get_job_details( $job_id, $item_url, $item_type );
|
||||
|
||||
if ( is_wp_error( $job_details ) ) {
|
||||
return $job_details;
|
||||
}
|
||||
|
||||
return $job_details;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check status and process the output for a job.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $job_id ID for the job to get details.
|
||||
* @param string $item_path Path for this item to be validated.
|
||||
* @param string $item_url URL for item to be used in error messages.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return array|WP_Error Response in case of success, failure or pending.
|
||||
*/
|
||||
private function check_cpcss_job_status( $job_id, $item_path, $item_url, $is_mobile = false, $item_type = 'custom' ) {
|
||||
$job_details = $this->api_client->get_job_details( $job_id, $item_url, $is_mobile, $item_type );
|
||||
|
||||
if ( is_wp_error( $job_details ) ) {
|
||||
$this->data_manager->delete_cache_job_id( $item_url, $is_mobile );
|
||||
|
||||
return $job_details;
|
||||
}
|
||||
|
||||
if ( 200 !== $job_details->status ) {
|
||||
// On job error.
|
||||
return $this->on_job_error( $job_details, $item_url, $is_mobile, $item_type );
|
||||
}
|
||||
|
||||
// On job status 200.
|
||||
$job_state = $job_details->data->state;
|
||||
|
||||
// For pending job status.
|
||||
if ( isset( $job_state ) && 'complete' !== $job_state ) {
|
||||
return $this->on_job_pending( $item_url, $item_type );
|
||||
}
|
||||
|
||||
// For successful job status.
|
||||
if (
|
||||
isset( $job_state, $job_details->data->critical_path )
|
||||
&&
|
||||
'complete' === $job_state
|
||||
) {
|
||||
return $this->on_job_success( $item_path, $item_url, $job_details->data->critical_path, $is_mobile, $item_type );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process logic for job error.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $job_details Job details array.
|
||||
* @param string $item_url Url for web page to be processed, used for error messages.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return WP_Error
|
||||
*/
|
||||
private function on_job_error( $job_details, $item_url, $is_mobile = false, $item_type = 'custom' ) {
|
||||
$this->data_manager->delete_cache_job_id( $item_url, $is_mobile );
|
||||
|
||||
if ( $is_mobile ) {
|
||||
|
||||
$error = sprintf(
|
||||
// translators: %1$s = item URL or item type.
|
||||
__( 'Mobile Critical CSS for %1$s not generated.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $item_url : $item_type
|
||||
);
|
||||
} else {
|
||||
|
||||
$error = sprintf(
|
||||
// translators: %1$s = item URL or item type.
|
||||
__( 'Critical CSS for %1$s not generated.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $item_url : $item_type
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $job_details->message ) ) {
|
||||
// translators: %1$s = error message.
|
||||
$error .= ' ' . sprintf( __( 'Error: %1$s', 'rocket' ), $job_details->message );
|
||||
}
|
||||
|
||||
return new WP_Error(
|
||||
'cpcss_generation_failed',
|
||||
$error,
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process logic for job pending status.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_url Url for web page to be processed, used for error messages.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function on_job_pending( $item_url, $item_type = 'custom' ) {
|
||||
return [
|
||||
'code' => 'cpcss_generation_pending',
|
||||
'message' => sprintf(
|
||||
// translators: %1$s = Item URL or item type.
|
||||
__( 'Critical CSS for %s in progress.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $item_url : $item_type
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process logic for job success status.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_path Item Path for web page to be processed.
|
||||
* @param string $item_url Item Url for web page to be processed.
|
||||
* @param string $cpcss_code CPCSS Code to be saved.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
private function on_job_success( $item_path, $item_url, $cpcss_code, $is_mobile = false, $item_type = 'custom' ) {
|
||||
// delete cache job_id for this item.
|
||||
$this->data_manager->delete_cache_job_id( $item_url, $is_mobile );
|
||||
|
||||
// save the generated CPCSS code into file.
|
||||
$saved = $this->data_manager->save_cpcss( $item_path, $cpcss_code, $item_url, $is_mobile, $item_type );
|
||||
if ( is_wp_error( $saved ) ) {
|
||||
return $saved;
|
||||
}
|
||||
|
||||
if ( $is_mobile ) {
|
||||
return [
|
||||
'code' => 'cpcss_generation_successful',
|
||||
'message' => sprintf(
|
||||
// translators: %1$s = Item URL or item type.
|
||||
__( 'Mobile Critical CSS for %s generated.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $item_url : $item_type
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
// Send the current status of job.
|
||||
return [
|
||||
'code' => 'cpcss_generation_successful',
|
||||
'message' => sprintf(
|
||||
// translators: %1$s = Item URL or item type.
|
||||
__( 'Critical CSS for %s generated.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $item_url : $item_type
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the login for CPCSS deletion.
|
||||
*
|
||||
* @param string $item_path Path for item to delete CPCSS code.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function process_delete( $item_path ) {
|
||||
$deleted = $this->data_manager->delete_cpcss( $item_path );
|
||||
|
||||
if ( is_wp_error( $deleted ) ) {
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
return [
|
||||
'code' => 'success',
|
||||
'message' => __( 'Critical CSS file deleted successfully.', 'rocket' ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process timeout action for CPCSS generation.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $item_url URL for item to be used in error messages.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
* @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom.
|
||||
* @return WP_Error
|
||||
*/
|
||||
private function process_timeout( $item_url, $is_mobile = false, $item_type = 'custom' ) {
|
||||
$this->data_manager->delete_cache_job_id( $item_url, $is_mobile );
|
||||
|
||||
if ( $is_mobile ) {
|
||||
return new WP_Error(
|
||||
'cpcss_generation_timeout',
|
||||
sprintf(
|
||||
// translators: %1$s = Item URL or item type.
|
||||
__( 'Mobile Critical CSS for %1$s timeout. Please retry a little later.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $item_url : $item_type
|
||||
),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return new WP_Error(
|
||||
'cpcss_generation_timeout',
|
||||
sprintf(
|
||||
// translators: %1$s = Item URL or item type.
|
||||
__( 'Critical CSS for %1$s timeout. Please retry a little later.', 'rocket' ),
|
||||
( 'custom' === $item_type ) ? $item_url : $item_type
|
||||
),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Class RESTCSSSubscriber
|
||||
*
|
||||
* @package WP_Rocket\Engine\CriticalPath
|
||||
*/
|
||||
class RESTCSSSubscriber implements Subscriber_Interface {
|
||||
|
||||
/**
|
||||
* REST manager that has generate and delete methods.
|
||||
*
|
||||
* @var RESTWPInterface
|
||||
*/
|
||||
private $rest_manager;
|
||||
|
||||
/**
|
||||
* RESTCSSSubscriber constructor.
|
||||
*
|
||||
* @param RESTWPInterface $rest_manager REST manager instance.
|
||||
*/
|
||||
public function __construct( RESTWPInterface $rest_manager ) {
|
||||
$this->rest_manager = $rest_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rest_api_init' => [ 'register_routes' ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers generate/delete routes in the API.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_routes() {
|
||||
$this->rest_manager->register_generate_route();
|
||||
$this->rest_manager->register_delete_route();
|
||||
}
|
||||
|
||||
}
|
322
wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWP.php
Normal file
322
wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWP.php
Normal file
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
use WP_Error;
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
|
||||
/**
|
||||
* Class RESTWP
|
||||
*
|
||||
* @package WP_Rocket\Engine\CriticalPath
|
||||
*/
|
||||
abstract class RESTWP implements RESTWPInterface {
|
||||
|
||||
/**
|
||||
* Namespace for REST Route.
|
||||
*/
|
||||
const ROUTE_NAMESPACE = 'wp-rocket/v1';
|
||||
|
||||
/**
|
||||
* Part of route namespace for this inherited class item type.
|
||||
*
|
||||
* @var string $route_namespace to be set with like post, term.
|
||||
*/
|
||||
protected $route_namespace;
|
||||
|
||||
/**
|
||||
* CPCSS generation and deletion service.
|
||||
*
|
||||
* @var ProcessorService instance for this service.
|
||||
*/
|
||||
private $cpcss_service;
|
||||
|
||||
/**
|
||||
* WP Rocket options instance.
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* RESTWP constructor.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param ProcessorService $cpcss_service Has the logic for cpcss generation and deletion.
|
||||
* @param Options_Data $options Instance of options data handler.
|
||||
*/
|
||||
public function __construct( ProcessorService $cpcss_service, Options_Data $options ) {
|
||||
$this->cpcss_service = $cpcss_service;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the generate route in the WP REST API
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_generate_route() {
|
||||
register_rest_route(
|
||||
self::ROUTE_NAMESPACE,
|
||||
'cpcss/' . $this->route_namespace . '/(?P<id>[\d]+)',
|
||||
[
|
||||
'methods' => 'POST',
|
||||
'callback' => [ $this, 'generate' ],
|
||||
'permission_callback' => [ $this, 'check_permissions' ],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Delete CPCSS route in the WP REST API.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
public function register_delete_route() {
|
||||
register_rest_route(
|
||||
self::ROUTE_NAMESPACE,
|
||||
'cpcss/' . $this->route_namespace . '/(?P<id>[\d]+)',
|
||||
[
|
||||
'methods' => 'DELETE',
|
||||
'callback' => [ $this, 'delete' ],
|
||||
'permission_callback' => [ $this, 'check_permissions' ],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks user's permissions. This is a callback registered to REST route's "permission_callback" parameter.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool true if the user has permission; else false.
|
||||
*/
|
||||
public function check_permissions() {
|
||||
return current_user_can( 'rocket_regenerate_critical_css' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean post cache files on CPCSS generation or deletion.
|
||||
*
|
||||
* @since 3.6.1
|
||||
*
|
||||
* @param int $item_id ID for this item to get Url for.
|
||||
*/
|
||||
private function clean_post_cache( $item_id ) {
|
||||
rocket_clean_files( $this->get_url( $item_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the CPCSS for the requested post ID.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param WP_REST_Request $request WP REST request response.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function generate( WP_REST_Request $request ) {
|
||||
$item_id = (int) $request->get_param( 'id' );
|
||||
$is_mobile = (bool) $request->get_param( 'is_mobile' );
|
||||
|
||||
// Bailout in case mobile CPCSS generation is called but this option is disabled.
|
||||
if (
|
||||
$is_mobile
|
||||
&&
|
||||
(
|
||||
! $this->options->get( 'async_css_mobile', 0 )
|
||||
||
|
||||
! $this->options->get( 'do_caching_mobile_files', 0 )
|
||||
)
|
||||
) {
|
||||
return rest_ensure_response(
|
||||
$this->return_error(
|
||||
new WP_Error(
|
||||
'mobile_cpcss_not_enabled',
|
||||
__( 'Mobile CPCSS generation not enabled.', 'rocket' ),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// validate item.
|
||||
$validated = $this->validate_item_for_generate( $item_id );
|
||||
if ( is_wp_error( $validated ) ) {
|
||||
return rest_ensure_response( $this->return_error( $validated ) );
|
||||
}
|
||||
|
||||
// get item url.
|
||||
$item_url = $this->get_url( $item_id );
|
||||
$timeout = ( isset( $request['timeout'] ) && ! empty( $request['timeout'] ) );
|
||||
$item_path = $this->get_path( $item_id, $is_mobile );
|
||||
|
||||
$additional_params = [
|
||||
'timeout' => $timeout,
|
||||
'is_mobile' => $is_mobile,
|
||||
'item_type' => 'custom',
|
||||
];
|
||||
$generated = $this->cpcss_service->process_generate( $item_url, $item_path, $additional_params );
|
||||
|
||||
if ( is_wp_error( $generated ) ) {
|
||||
return rest_ensure_response(
|
||||
$this->return_error( $generated )
|
||||
);
|
||||
}
|
||||
|
||||
$this->clean_post_cache( $item_id );
|
||||
|
||||
return rest_ensure_response(
|
||||
$this->return_success( $generated )
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the item to be sent to generate CPCSS.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $item_id ID for this item to be validated.
|
||||
*
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
abstract protected function validate_item_for_generate( $item_id );
|
||||
|
||||
/**
|
||||
* Validate the item to be sent to Delete CPCSS.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $item_id ID for this item to be validated.
|
||||
*
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
abstract protected function validate_item_for_delete( $item_id );
|
||||
|
||||
/**
|
||||
* Get url for this item.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $item_id ID for this item to get Url for.
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
abstract protected function get_url( $item_id );
|
||||
|
||||
/**
|
||||
* Get CPCSS file path to save CPCSS code into.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $item_id ID for this item to get the path for.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_path( $item_id, $is_mobile = false );
|
||||
|
||||
/**
|
||||
* Delete Post ID CPCSS file.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param WP_REST_Request $request the WP Rest Request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function delete( WP_REST_Request $request ) {
|
||||
$item_id = (int) $request->get_param( 'id' );
|
||||
|
||||
// validate item.
|
||||
$validated = $this->validate_item_for_delete( $item_id );
|
||||
if ( is_wp_error( $validated ) ) {
|
||||
return rest_ensure_response( $this->return_error( $validated ) );
|
||||
}
|
||||
|
||||
if ( $this->options->get( 'async_css_mobile', 0 ) ) {
|
||||
$mobile_item_path = $this->get_path( $item_id, true );
|
||||
$this->cpcss_service->process_delete( $mobile_item_path );
|
||||
}
|
||||
|
||||
$item_path = $this->get_path( $item_id );
|
||||
$deleted = $this->cpcss_service->process_delete( $item_path );
|
||||
if ( is_wp_error( $deleted ) ) {
|
||||
return rest_ensure_response( $this->return_error( $deleted ) );
|
||||
}
|
||||
|
||||
$this->clean_post_cache( $item_id );
|
||||
|
||||
return rest_ensure_response( $this->return_success( $deleted ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatted array response
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param bool $success True for success, false otherwise.
|
||||
* @param string $code The code to use for the response.
|
||||
* @param string $message The message to send in the response.
|
||||
* @param int $status The status code to send for the response.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function return_array_response( $success = false, $code = '', $message = '', $status = 200 ) {
|
||||
return [
|
||||
'success' => $success,
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
'data' => [
|
||||
'status' => $status,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert WP_Error into array to be used in response.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param WP_Error $error Error that will be converted to array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function return_error( $error ) {
|
||||
$error_data = $error->get_error_data();
|
||||
|
||||
return $this->return_array_response(
|
||||
false,
|
||||
$error->get_error_code(),
|
||||
$error->get_error_message(),
|
||||
isset( $error_data['status'] ) ? $error_data['status'] : 400
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return success to be used in response.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $data which has success parameters with two keys: code and message.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function return_success( $data ) {
|
||||
return $this->return_array_response(
|
||||
true,
|
||||
$data['code'],
|
||||
$data['message'],
|
||||
200
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
interface RESTWPInterface {
|
||||
/**
|
||||
* Registers the generate route in the WP REST API
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_generate_route();
|
||||
|
||||
/**
|
||||
* Register Delete CPCSS route in the WP REST API.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_delete_route();
|
||||
|
||||
/**
|
||||
* Checks user's permissions. This is a callback registered to REST route's "permission_callback" parameter.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return bool true if the user has permission; else false.
|
||||
*/
|
||||
public function check_permissions();
|
||||
|
||||
/**
|
||||
* Generates the CPCSS for the requested post ID.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param WP_REST_Request $request WP REST request response.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function generate( WP_REST_Request $request );
|
||||
|
||||
/**
|
||||
* Delete Post ID CPCSS file.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param WP_REST_Request $request the WP Rest Request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function delete( WP_REST_Request $request );
|
||||
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class RESTWPPost
|
||||
*
|
||||
* @package WP_Rocket\Engine\CriticalPath
|
||||
*/
|
||||
class RESTWPPost extends RESTWP {
|
||||
|
||||
/**
|
||||
* Part of route namespace for this inherited class item type.
|
||||
*
|
||||
* @var string $route_namespace to be set with like post, term.
|
||||
*/
|
||||
protected $route_namespace = 'post';
|
||||
|
||||
/**
|
||||
* Validate the item to be sent to generate CPCSS.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $post_id ID for this post to be validated.
|
||||
*
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
protected function validate_item_for_generate( $post_id ) {
|
||||
$status = get_post_status( $post_id );
|
||||
|
||||
if ( ! $status ) {
|
||||
return new WP_Error(
|
||||
'post_not_exists',
|
||||
__( 'Requested post does not exist.', 'rocket' ),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'publish' !== $status ) {
|
||||
return new WP_Error(
|
||||
'post_not_published',
|
||||
__( 'Cannot generate CPCSS for unpublished post.', 'rocket' ),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the item to be sent to delete CPCSS.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $post_id ID for this post to be validated.
|
||||
*
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
protected function validate_item_for_delete( $post_id ) {
|
||||
if ( empty( get_permalink( $post_id ) ) ) {
|
||||
return new WP_Error(
|
||||
'post_not_exists',
|
||||
__( 'Requested post does not exist.', 'rocket' ),
|
||||
[
|
||||
'status' => 400,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get url for this item.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $post_id ID for this post to be validated.
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
protected function get_url( $post_id ) {
|
||||
return get_permalink( $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CPCSS file path to save CPCSS code into.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param int $post_id ID for this post to be validated.
|
||||
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_path( $post_id, $is_mobile = false ) {
|
||||
$post_type = get_post_type( $post_id );
|
||||
|
||||
return 'posts' . DIRECTORY_SEPARATOR . "{$post_type}-{$post_id}" . ( $is_mobile ? '-mobile' : '' ) . '.css';
|
||||
}
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service provider for the Critical CSS classes
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'critical_css_generation',
|
||||
'critical_css',
|
||||
'critical_css_subscriber',
|
||||
'cpcss_api_client',
|
||||
'cpcss_data_manager',
|
||||
'cpcss_service',
|
||||
'rest_cpcss_wp_post',
|
||||
'rest_cpcss_subscriber',
|
||||
'cpcss_settings',
|
||||
'cpcss_post',
|
||||
'cpcss_admin',
|
||||
'critical_css_admin_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the subscribers in the container.
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
public function register() {
|
||||
$filesystem = rocket_direct_filesystem();
|
||||
$critical_css_path = rocket_get_constant( 'WP_ROCKET_CRITICAL_CSS_PATH' );
|
||||
$options = $this->getContainer()->get( 'options' );
|
||||
$beacon = $this->getContainer()->get( 'beacon' );
|
||||
$template_path = $this->getContainer()->get( 'template_path' ) . '/cpcss';
|
||||
|
||||
$this->getContainer()->share( 'cpcss_api_client', 'WP_Rocket\Engine\CriticalPath\APIClient' );
|
||||
$this->getContainer()->share( 'cpcss_data_manager', 'WP_Rocket\Engine\CriticalPath\DataManager' )
|
||||
->withArgument( $critical_css_path )
|
||||
->withArgument( $filesystem );
|
||||
$this->getContainer()->share( 'cpcss_service', 'WP_Rocket\Engine\CriticalPath\ProcessorService' )
|
||||
->withArgument( $this->getContainer()->get( 'cpcss_data_manager' ) )
|
||||
->withArgument( $this->getContainer()->get( 'cpcss_api_client' ) );
|
||||
|
||||
$processor_service = $this->getContainer()->get( 'cpcss_service' );
|
||||
|
||||
// REST CPCSS START.
|
||||
$this->getContainer()->share( 'rest_cpcss_wp_post', 'WP_Rocket\Engine\CriticalPath\RESTWPPost' )
|
||||
->withArgument( $processor_service )
|
||||
->withArgument( $options );
|
||||
$this->getContainer()->share( 'rest_cpcss_subscriber', 'WP_Rocket\Engine\CriticalPath\RESTCSSSubscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'rest_cpcss_wp_post' ) );
|
||||
// REST CPCSS END.
|
||||
|
||||
$this->getContainer()->add( 'critical_css_generation', 'WP_Rocket\Engine\CriticalPath\CriticalCSSGeneration' )
|
||||
->withArgument( $processor_service );
|
||||
$this->getContainer()->add( 'critical_css', 'WP_Rocket\Engine\CriticalPath\CriticalCSS' )
|
||||
->withArgument( $this->getContainer()->get( 'critical_css_generation' ) )
|
||||
->withArgument( $options )
|
||||
->withArgument( $filesystem );
|
||||
|
||||
$critical_css = $this->getContainer()->get( 'critical_css' );
|
||||
|
||||
$this->getContainer()->share( 'critical_css_subscriber', 'WP_Rocket\Engine\CriticalPath\CriticalCSSSubscriber' )
|
||||
->withArgument( $critical_css )
|
||||
->withArgument( $processor_service )
|
||||
->withArgument( $options )
|
||||
->withArgument( $filesystem );
|
||||
|
||||
$this->getContainer()->add( 'cpcss_post', 'WP_Rocket\Engine\CriticalPath\Admin\Post' )
|
||||
->withArgument( $options )
|
||||
->withArgument( $beacon )
|
||||
->withArgument( $critical_css_path )
|
||||
->withArgument( $template_path );
|
||||
$this->getContainer()->add( 'cpcss_settings', 'WP_Rocket\Engine\CriticalPath\Admin\Settings' )
|
||||
->withArgument( $options )
|
||||
->withArgument( $beacon )
|
||||
->withArgument( $critical_css )
|
||||
->withArgument( $template_path );
|
||||
$this->getContainer()->add( 'cpcss_admin', 'WP_Rocket\Engine\CriticalPath\Admin\Admin' )
|
||||
->withArgument( $options )
|
||||
->withArgument( $processor_service );
|
||||
$this->getContainer()->share( 'critical_css_admin_subscriber', 'WP_Rocket\Engine\CriticalPath\Admin\Subscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'cpcss_post' ) )
|
||||
->withArgument( $this->getContainer()->get( 'cpcss_settings' ) )
|
||||
->withArgument( $this->getContainer()->get( 'cpcss_admin' ) );
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\CriticalPath;
|
||||
|
||||
trait TransientTrait {
|
||||
/**
|
||||
* Updates CPCSS running transient with status notices.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $transient Transient to be updated.
|
||||
* @param string $item_path Path for processed item.
|
||||
* @param bool $mobile If this request is for mobile cpcss.
|
||||
* @param string $message CPCSS reply message.
|
||||
* @param bool/string $success CPCSS success or failure.
|
||||
* @return void
|
||||
*/
|
||||
private function update_running_transient( $transient, $item_path, $mobile, $message, $success ) {
|
||||
$path = ! (bool) $mobile ? $item_path : str_replace( '-mobile.css', '.css', $item_path );
|
||||
|
||||
$transient['items'][ $path ]['status'][ ! (bool) $mobile ? 'nonmobile' : 'mobile' ]['message'] = $message;
|
||||
$transient['items'][ $path ]['status'][ ! (bool) $mobile ? 'nonmobile' : 'mobile' ]['success'] = $success;
|
||||
set_transient( 'rocket_critical_css_generation_process_running', $transient, HOUR_IN_SECONDS );
|
||||
}
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Deactivation;
|
||||
|
||||
use WP_Rocket\Engine\Container\Container;
|
||||
use WP_Rocket\ThirdParty\Hostings\HostResolver;
|
||||
|
||||
class Deactivation {
|
||||
/**
|
||||
* Aliases in the container for each class that needs to call its deactivate method
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $deactivators = [
|
||||
'advanced_cache',
|
||||
'capabilities_manager',
|
||||
'wp_cache',
|
||||
];
|
||||
|
||||
/**
|
||||
* Performs these actions during the plugin deactivation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function deactivate_plugin() {
|
||||
global $is_apache;
|
||||
|
||||
$container = new Container();
|
||||
|
||||
$container->add( 'template_path', WP_ROCKET_PATH . 'views' );
|
||||
$container->addServiceProvider( 'WP_Rocket\Engine\Deactivation\ServiceProvider' );
|
||||
$container->addServiceProvider( 'WP_Rocket\ThirdParty\Hostings\ServiceProvider' );
|
||||
|
||||
$host_type = HostResolver::get_host_service();
|
||||
|
||||
if ( ! empty( $host_type ) ) {
|
||||
array_unshift( self::$deactivators, $host_type );
|
||||
}
|
||||
|
||||
foreach ( self::$deactivators as $deactivator ) {
|
||||
$container->get( $deactivator );
|
||||
}
|
||||
|
||||
if ( ! isset( $_GET['rocket_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['rocket_nonce'] ), 'force_deactivation' ) ) {
|
||||
$causes = [];
|
||||
|
||||
// .htaccess problem.
|
||||
if ( $is_apache && ! rocket_direct_filesystem()->is_writable( get_home_path() . '.htaccess' ) ) {
|
||||
$causes[] = 'htaccess';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the causes which can prevent the deactivation of the plugin
|
||||
*
|
||||
* @since 3.6.3
|
||||
*
|
||||
* @param array $causes An array of causes to pass to the notice.
|
||||
*/
|
||||
$causes = (array) apply_filters( 'rocket_prevent_deactivation', $causes );
|
||||
|
||||
if ( count( $causes ) ) {
|
||||
set_transient( get_current_user_id() . '_donotdeactivaterocket', $causes );
|
||||
wp_safe_redirect( wp_get_referer() );
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete config files.
|
||||
rocket_delete_config_file();
|
||||
|
||||
$sites_number = count( _rocket_get_php_files_in_dir( rocket_get_constant( 'WP_ROCKET_CONFIG_PATH' ) ) );
|
||||
|
||||
if ( ! $sites_number ) {
|
||||
// Delete All WP Rocket rules of the .htaccess file.
|
||||
flush_rocket_htaccess( true );
|
||||
}
|
||||
|
||||
// Update customer key & licence.
|
||||
wp_remote_get(
|
||||
WP_ROCKET_WEB_API . 'pause-licence.php',
|
||||
[
|
||||
'blocking' => false,
|
||||
]
|
||||
);
|
||||
|
||||
// Delete transients.
|
||||
delete_transient( 'rocket_check_licence_30' );
|
||||
delete_transient( 'rocket_check_licence_1' );
|
||||
delete_site_transient( 'update_wprocket_response' );
|
||||
|
||||
// Unschedule WP Cron events.
|
||||
wp_clear_scheduled_hook( 'rocket_facebook_tracking_cache_update' );
|
||||
wp_clear_scheduled_hook( 'rocket_google_tracking_cache_update' );
|
||||
wp_clear_scheduled_hook( 'rocket_cache_dir_size_check' );
|
||||
|
||||
/**
|
||||
* WP Rocket deactivation.
|
||||
*
|
||||
* @since 3.6.3 add $sites_count parameter.
|
||||
* @since 3.1.5
|
||||
*
|
||||
* @param int $sites_number Number of WP Rocket config files found.
|
||||
*/
|
||||
do_action( 'rocket_deactivation', $sites_number );
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\Deactivation;
|
||||
|
||||
interface DeactivationInterface {
|
||||
/**
|
||||
* Executes this method on plugin deactivation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deactivate();
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Deactivation;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\BootableServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* Service Provider for the activation process.
|
||||
*
|
||||
* @since 3.6.3
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider implements BootableServiceProviderInterface {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'advanced_cache',
|
||||
'capabilities_manager',
|
||||
'wp_cache',
|
||||
];
|
||||
|
||||
/**
|
||||
* Executes this method when the service provider is registered
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot() {
|
||||
$this->getContainer()
|
||||
->inflector( 'WP_Rocket\Engine\Deactivation\DeactivationInterface' )
|
||||
->invokeMethod( 'deactivate', [] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the option array in the container.
|
||||
*/
|
||||
public function register() {
|
||||
$filesystem = rocket_direct_filesystem();
|
||||
|
||||
$this->getContainer()->add( 'advanced_cache', 'WP_Rocket\Engine\Cache\AdvancedCache' )
|
||||
->withArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' )
|
||||
->withArgument( $filesystem );
|
||||
$this->getContainer()->add( 'capabilities_manager', 'WP_Rocket\Engine\Capabilities\Manager' );
|
||||
$this->getContainer()->add( 'wp_cache', 'WP_Rocket\Engine\Cache\WPCache' )
|
||||
->withArgument( $filesystem );
|
||||
}
|
||||
}
|
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\HealthCheck;
|
||||
|
||||
use FilesystemIterator;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use UnexpectedValueException;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Add a weekly event to check for the cache directories sizes
|
||||
* and send a notification if it's bigger thant the defined maximum size
|
||||
*
|
||||
* @since 3.3.5
|
||||
*/
|
||||
class CacheDirSizeCheck implements Subscriber_Interface {
|
||||
/**
|
||||
* Event name
|
||||
*/
|
||||
const CRON_NAME = 'rocket_cache_dir_size_check';
|
||||
|
||||
/**
|
||||
* Maximum allowed size
|
||||
*/
|
||||
const MAX_SIZE = 10737418240;
|
||||
|
||||
/**
|
||||
* ROUTE endpoint to request
|
||||
*/
|
||||
const ROUTE = 'api/wp-rocket/cache-dir-check.php';
|
||||
|
||||
/**
|
||||
* Absolute path to the minify directory
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $minify_path;
|
||||
|
||||
/**
|
||||
* Full URL to the API endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $api_endpoint;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param string $minify_path Absolute path to the minify directory.
|
||||
* @param string $rocket_url WP Rocket website URL.
|
||||
*/
|
||||
public function __construct( $minify_path, $rocket_url ) {
|
||||
$this->minify_path = $minify_path . get_current_blog_id();
|
||||
$this->api_endpoint = $rocket_url . self::ROUTE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.3.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'cron_schedules' => 'add_schedule',
|
||||
'init' => 'schedule_cache_dir_size_check',
|
||||
self::CRON_NAME => 'cache_dir_size_check',
|
||||
'wp_rocket_upgrade' => [ 'delete_option_after_upgrade', 11, 2 ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the weekly interval if it doesn't already exist
|
||||
*
|
||||
* @since 3.3.5
|
||||
*
|
||||
* @param array $schedules Array of intervals.
|
||||
* @return array
|
||||
*/
|
||||
public function add_schedule( $schedules ) {
|
||||
if ( isset( $schedules['weekly'] ) ) {
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
$schedules['weekly'] = [
|
||||
'interval' => 604800,
|
||||
'display' => __( 'weekly', 'rocket' ),
|
||||
];
|
||||
|
||||
return $schedules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules the cron event if not yet scheduled.
|
||||
*
|
||||
* @since 3.3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function schedule_cache_dir_size_check() {
|
||||
if ( ! wp_next_scheduled( self::CRON_NAME ) ) {
|
||||
wp_schedule_event( time(), 'weekly', self::CRON_NAME );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the cache dir size when the event is triggered
|
||||
* and send a notification if the directory size is above the defined maximum size
|
||||
*
|
||||
* @since 3.3.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cache_dir_size_check() {
|
||||
if ( 1 === (int) get_option( self::CRON_NAME ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$checks = [
|
||||
'min' => $this->minify_path,
|
||||
];
|
||||
|
||||
foreach ( $checks as $type => $path ) {
|
||||
$size = $this->get_dir_size( $path );
|
||||
|
||||
if ( $size > self::MAX_SIZE ) {
|
||||
$this->send_notification( $type );
|
||||
}
|
||||
}
|
||||
|
||||
update_option( self::CRON_NAME, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the check size option when updating the plugin
|
||||
*
|
||||
* @since 3.3.6
|
||||
*
|
||||
* @param string $new_version Latest WP Rocket version.
|
||||
* @param string $current_version Installed WP Rocket version.
|
||||
*/
|
||||
public function delete_option_after_upgrade( $new_version, $current_version ) {
|
||||
if ( version_compare( $current_version, $new_version, '<' ) ) {
|
||||
delete_option( self::CRON_NAME );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the provided directory
|
||||
*
|
||||
* @since 3.3.5
|
||||
*
|
||||
* @param string $dir Absolute path to the directory.
|
||||
* @return int
|
||||
*/
|
||||
private function get_dir_size( $dir ) {
|
||||
$size = 0;
|
||||
|
||||
try {
|
||||
foreach ( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ) ) as $file ) {
|
||||
$size += $file->getSize();
|
||||
}
|
||||
|
||||
return $size;
|
||||
} catch ( UnexpectedValueException $e ) {
|
||||
return $size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a notification to our endpoint with the type of directory
|
||||
*
|
||||
* @since 3.3.5
|
||||
*
|
||||
* @param string $dir_type Type of directory.
|
||||
* @return void
|
||||
*/
|
||||
private function send_notification( $dir_type ) {
|
||||
wp_safe_remote_post(
|
||||
$this->api_endpoint,
|
||||
[
|
||||
'body' => 'cache_dir_type=' . $dir_type,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\HealthCheck;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
class HealthCheck implements Subscriber_Interface {
|
||||
/**
|
||||
* Instance of options.
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Array of events with their descriptions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $events;
|
||||
|
||||
/**
|
||||
* Creates an instance of the health checker.
|
||||
*
|
||||
* @param Options_Data $options Options_Data instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options ) {
|
||||
$this->options = $options;
|
||||
$this->events = $this->get_events();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'admin_notices' => 'missed_cron',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a warning notice if WP Rocket scheduled events are not running properly.
|
||||
*
|
||||
* @since 3.5.4
|
||||
*/
|
||||
public function missed_cron() {
|
||||
if ( ! $this->should_check() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$delay = rocket_get_constant( 'DISABLE_WP_CRON' ) ? HOUR_IN_SECONDS : 5 * MINUTE_IN_SECONDS;
|
||||
$list = '';
|
||||
$events = $this->events;
|
||||
|
||||
foreach ( $this->events as $event => $description ) {
|
||||
$timestamp = wp_next_scheduled( $event );
|
||||
|
||||
if (
|
||||
false === $timestamp
|
||||
||
|
||||
( $timestamp + $delay - time() ) > 0
|
||||
) {
|
||||
unset( $events[ $event ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
$list .= "<li>{$description}</li>";
|
||||
}
|
||||
|
||||
if ( empty( $events ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
'<p>%1$s</p>
|
||||
<ul>%2$s</ul>
|
||||
<p>%3$s</p>',
|
||||
_n(
|
||||
'The following scheduled event failed to run. This may indicate the CRON system is not running properly, which can prevent some WP Rocket features from working as intended:',
|
||||
'The following scheduled events failed to run. This may indicate the CRON system is not running properly, which can prevent some WP Rocket features from working as intended:',
|
||||
count( $events ),
|
||||
'rocket'
|
||||
),
|
||||
$list,
|
||||
__( 'Please contact your host to check if CRON is working.', 'rocket' )
|
||||
);
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => 'warning',
|
||||
'dismissible' => '',
|
||||
'message' => $message,
|
||||
'dismiss_button' => 'rocket_warning_cron',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if health check should run.
|
||||
*
|
||||
* @since 3.5.4
|
||||
*
|
||||
* @return bool true when should do health check; else, false.
|
||||
*/
|
||||
protected function should_check() {
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( 'settings_page_wprocket' !== get_current_screen()->id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$dismissed = (array) get_user_meta( get_current_user_id(), 'rocket_boxes', true );
|
||||
if ( in_array( 'rocket_warning_cron', $dismissed, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! (
|
||||
0 === (int) $this->options->get( 'purge_cron_interval', 0 )
|
||||
&&
|
||||
0 === (int) $this->options->get( 'async_css', 0 )
|
||||
&&
|
||||
0 === (int) $this->options->get( 'manual_preload', 0 )
|
||||
&&
|
||||
0 === (int) $this->options->get( 'schedule_automatic_cleanup', 0 )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of events with their descriptions.
|
||||
*
|
||||
* @since 3.5.4
|
||||
*
|
||||
* @return array array of events => descriptions.
|
||||
*/
|
||||
protected function get_events() {
|
||||
return [
|
||||
'rocket_purge_time_event' => __( 'Scheduled Cache Purge', 'rocket' ),
|
||||
'rocket_database_optimization_time_event' => __( 'Scheduled Database Optimization', 'rocket' ),
|
||||
'rocket_database_optimization_cron_interval' => __( 'Database Optimization Process', 'rocket' ),
|
||||
'rocket_preload_cron_interval' => _x( 'Preload', 'noun', 'rocket' ),
|
||||
'rocket_critical_css_generation_cron_interval' => __( 'Critical Path CSS Generation Process', 'rocket' ),
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\HealthCheck;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service Provider for health check subscribers
|
||||
*
|
||||
* @since 3.6
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'health_check',
|
||||
'cache_dir_size_check',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the option array in the container
|
||||
*
|
||||
* @since 3.6
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->share( 'health_check', 'WP_Rocket\Engine\HealthCheck\HealthCheck' )
|
||||
->withArgument( $this->getContainer()->get( 'options' ) );
|
||||
$this->getContainer()->share( 'cache_dir_size_check', 'WP_Rocket\Engine\HealthCheck\CacheDirSizeCheck' )
|
||||
->withArgument( rocket_get_constant( 'WP_ROCKET_MINIFY_CACHE_PATH' ) )
|
||||
->withArgument( rocket_get_constant( 'WP_ROCKET_WEB_MAIN' ) );
|
||||
}
|
||||
}
|
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Heartbeat;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
use WP_Rocket\Admin\Options_Data as Options;
|
||||
|
||||
/**
|
||||
* Event subscriber to control Heartbeat behavior.
|
||||
*
|
||||
* @since 3.7 Moved to new architecture.
|
||||
* @since 3.2
|
||||
*/
|
||||
class HeartbeatSubscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* Instance of the Option_Data class.
|
||||
*
|
||||
* @var Options
|
||||
* @since 3.2
|
||||
* @access private
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
|
||||
* @param Options $options Instance of the Option_Data class.
|
||||
*/
|
||||
public function __construct( Options $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
$priority = PHP_INT_MAX - 60;
|
||||
return [
|
||||
'admin_enqueue_scripts' => [ 'maybe_disable', $priority ],
|
||||
'wp_enqueue_scripts' => [ 'maybe_disable', $priority ],
|
||||
'heartbeat_settings' => [ 'maybe_modify_period', $priority ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe disable Heartbeat.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
*/
|
||||
public function maybe_disable() {
|
||||
if ( ! $this->behavior_match_context( 'disable' ) || rocket_bypass() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_deregister_script( 'heartbeat' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe modify Heartbeat periodicity.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
*
|
||||
* @param array $settings The Heartbeat settings.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function maybe_modify_period( $settings ) {
|
||||
if ( ! $this->behavior_match_context( 'reduce_periodicity' ) ) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
$settings['interval'] = 120;
|
||||
$settings['minimalInterval'] = 120;
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if we're in frontend, backend, or a post edition page.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access private
|
||||
*
|
||||
* @return string Either 'site' (frontend), 'admin' (backend), or 'editor'.
|
||||
*/
|
||||
private function get_current_context() {
|
||||
$request_uri = ! empty( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
$request_uri = explode( '?', $request_uri, 2 );
|
||||
$request_uri = reset( $request_uri );
|
||||
|
||||
if ( $request_uri && preg_match( '@/wp-admin/post(-new)?\.php$@', $request_uri ) ) {
|
||||
$context = 'editor';
|
||||
} elseif ( is_admin() ) {
|
||||
$context = 'admin';
|
||||
|
||||
if ( wp_doing_ajax() && ! empty( $_POST['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
if ( 'wp-remove-post-lock' === sanitize_key( wp_unslash( $_POST['action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$context = 'editor';
|
||||
} elseif ( ! empty( $_POST['screen_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
switch ( $_POST['screen_id'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
case 'post':
|
||||
$context = 'editor';
|
||||
break;
|
||||
case 'front':
|
||||
$context = 'site';
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$context = 'site';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the current context.
|
||||
* This can be useful for ajax requests or requests to admin-post.php, as there is no easy way to tell where those requests come from.
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @param $context string Either 'site' (frontend), 'admin' (backend), or 'editor'.
|
||||
*/
|
||||
$filtered_context = apply_filters( 'rocket_heartbeat_context', $context );
|
||||
|
||||
$contexts = [
|
||||
'editor' => 1,
|
||||
'admin' => 1,
|
||||
'site' => 1,
|
||||
];
|
||||
|
||||
return isset( $contexts[ $filtered_context ] ) ? $filtered_context : $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the given behavior is what is set in the addon settings, accordingly to the current context.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access private
|
||||
*
|
||||
* @param string $behavior Either '', 'disable', or 'reduce_periodicity'.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function behavior_match_context( $behavior ) {
|
||||
if ( ! $this->options->get( 'control_heartbeat', 0 ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$context = $this->get_current_context();
|
||||
|
||||
return $behavior === $this->options->get( 'heartbeat_' . $context . '_behavior', '' );
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Engine\Heartbeat;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service provider for Media module
|
||||
*
|
||||
* @since 3.7
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
|
||||
/**
|
||||
* The provides array is a way to let the container
|
||||
* know that a service is provided by this service
|
||||
* provider. Every service that is registered via
|
||||
* this service provider must have an alias added
|
||||
* to this array or it will be ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'heartbeat_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the services in the container
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$options = $this->getContainer()->get( 'options' );
|
||||
|
||||
$this->getContainer()->share( 'heartbeat_subscriber', 'WP_Rocket\Engine\Heartbeat\HeartbeatSubscriber' )
|
||||
->withArgument( $this->getContainer()->get( 'options' ) );
|
||||
}
|
||||
}
|
324
wp-content/plugins/wp-rocket/inc/Engine/License/API/Pricing.php
Normal file
324
wp-content/plugins/wp-rocket/inc/Engine/License/API/Pricing.php
Normal file
@@ -0,0 +1,324 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\License\API;
|
||||
|
||||
class Pricing {
|
||||
/**
|
||||
* The pricing data object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
private $pricing;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param object $pricing The pricing object.
|
||||
*/
|
||||
public function __construct( $pricing ) {
|
||||
$this->pricing = $pricing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the single license pricing data
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
public function get_single_pricing() {
|
||||
if (
|
||||
! isset( $this->pricing->licenses->single )
|
||||
||
|
||||
! is_object( $this->pricing->licenses->single )
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->pricing->licenses->single;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plus license pricing data
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
public function get_plus_pricing() {
|
||||
if (
|
||||
! isset( $this->pricing->licenses->plus )
|
||||
||
|
||||
! is_object( $this->pricing->licenses->plus )
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->pricing->licenses->plus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the infinite license pricing data
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
public function get_infinite_pricing() {
|
||||
if (
|
||||
! isset( $this->pricing->licenses->infinite )
|
||||
||
|
||||
! is_object( $this->pricing->licenses->infinite )
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->pricing->licenses->infinite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the license renewal pricing data
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
public function get_renewals_data() {
|
||||
if (
|
||||
! isset( $this->pricing->renewals )
|
||||
||
|
||||
! is_object( $this->pricing->renewals )
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->pricing->renewals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the promotion data
|
||||
*
|
||||
* @return null|object
|
||||
*/
|
||||
public function get_promo_data() {
|
||||
if (
|
||||
! isset( $this->pricing->promo )
|
||||
||
|
||||
! is_object( $this->pricing->promo )
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->pricing->promo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a promotion is currently active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_promo_active() {
|
||||
$promo_data = $this->get_promo_data();
|
||||
|
||||
if ( is_null( $promo_data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $promo_data->start_date, $promo_data->end_date ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$current_time = time();
|
||||
|
||||
return (
|
||||
absint( $promo_data->start_date ) < $current_time
|
||||
&&
|
||||
absint( $promo_data->end_date ) > $current_time
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets promotion end date
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_promo_end() {
|
||||
$promo = $this->get_promo_data();
|
||||
|
||||
if (
|
||||
is_null( $promo )
|
||||
||
|
||||
! isset( $promo->end_date )
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return absint( $promo->end_date );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the regular upgrade price from single to plus
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_regular_single_to_plus_price() {
|
||||
$plus_pricing = $this->get_plus_pricing();
|
||||
|
||||
if (
|
||||
is_null( $plus_pricing )
|
||||
||
|
||||
! isset( $plus_pricing->prices->from_single->regular )
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $plus_pricing->prices->from_single->regular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current upgrade price from single to plus
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_single_to_plus_price() {
|
||||
$plus_pricing = $this->get_plus_pricing();
|
||||
$regular = $this->get_regular_single_to_plus_price();
|
||||
|
||||
if (
|
||||
is_null( $plus_pricing )
|
||||
||
|
||||
! isset( $plus_pricing->prices->from_single->sale )
|
||||
) {
|
||||
return $regular;
|
||||
}
|
||||
|
||||
return $this->is_promo_active() ? $plus_pricing->prices->from_single->sale : $regular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the regular upgrade price from single to infinite
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_regular_single_to_infinite_price() {
|
||||
$infinite_pricing = $this->get_infinite_pricing();
|
||||
|
||||
if (
|
||||
is_null( $infinite_pricing )
|
||||
||
|
||||
! isset( $infinite_pricing->prices->from_single->regular )
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $infinite_pricing->prices->from_single->regular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current upgrade price from single to plus
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_single_to_infinite_price() {
|
||||
$infinite_pricing = $this->get_infinite_pricing();
|
||||
$regular = $this->get_regular_single_to_infinite_price();
|
||||
|
||||
if (
|
||||
is_null( $infinite_pricing )
|
||||
||
|
||||
! isset( $infinite_pricing->prices->from_single->sale )
|
||||
) {
|
||||
return $regular;
|
||||
}
|
||||
|
||||
return $this->is_promo_active() ? $infinite_pricing->prices->from_single->sale : $regular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the regular upgrade price from plus to infinite
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_regular_plus_to_infinite_price() {
|
||||
$infinite_pricing = $this->get_infinite_pricing();
|
||||
|
||||
if (
|
||||
is_null( $infinite_pricing )
|
||||
||
|
||||
! isset( $infinite_pricing->prices->from_plus->regular )
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $infinite_pricing->prices->from_plus->regular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current upgrade price from plus to infinite
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_plus_to_infinite_price() {
|
||||
$infinite_pricing = $this->get_infinite_pricing();
|
||||
$regular = $this->get_regular_plus_to_infinite_price();
|
||||
|
||||
if (
|
||||
is_null( $infinite_pricing )
|
||||
||
|
||||
! isset( $infinite_pricing->prices->from_plus->sale )
|
||||
) {
|
||||
return $regular;
|
||||
}
|
||||
|
||||
return $this->is_promo_active() ? $infinite_pricing->prices->from_plus->sale : $regular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of websites allowed for the single license
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_single_websites_count() {
|
||||
$single_pricing = $this->get_single_pricing();
|
||||
|
||||
if (
|
||||
is_null( $single_pricing )
|
||||
||
|
||||
! isset( $single_pricing->websites )
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $single_pricing->websites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of websites allowed for the plus license
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_plus_websites_count() {
|
||||
$plus_pricing = $this->get_plus_pricing();
|
||||
|
||||
if (
|
||||
is_null( $plus_pricing )
|
||||
||
|
||||
! isset( $plus_pricing->websites )
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $plus_pricing->websites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of websites allowed for the infinite license
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_infinite_websites_count() {
|
||||
$infinite_pricing = $this->get_infinite_pricing();
|
||||
|
||||
if (
|
||||
is_null( $infinite_pricing )
|
||||
||
|
||||
! isset( $infinite_pricing->websites )
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $infinite_pricing->websites;
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\License\API;
|
||||
|
||||
class PricingClient {
|
||||
const PRICING_ENDPOINT = 'https://wp-rocket.me/stat/1.0/wp-rocket/pricing.php';
|
||||
|
||||
/**
|
||||
* Gets pricing data from cache if it exists, else gets it from the pricing endpoint
|
||||
*
|
||||
* Cache the pricing data for 6 hours in a transient
|
||||
*
|
||||
* @since 3.7.3
|
||||
*
|
||||
* @return bool|object
|
||||
*/
|
||||
public function get_pricing_data() {
|
||||
$cached_data = get_transient( 'wp_rocket_pricing' );
|
||||
|
||||
if ( false !== $cached_data ) {
|
||||
return $cached_data;
|
||||
}
|
||||
|
||||
$data = $this->get_raw_pricing_data();
|
||||
|
||||
if ( false === $data ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_transient( 'wp_rocket_pricing', $data, 6 * HOUR_IN_SECONDS );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pricing data from the pricing endpoint
|
||||
*
|
||||
* @since 3.7.3
|
||||
*
|
||||
* @return bool|object
|
||||
*/
|
||||
private function get_raw_pricing_data() {
|
||||
$response = wp_safe_remote_get(
|
||||
self::PRICING_ENDPOINT
|
||||
);
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
|
||||
if ( empty( $body ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return json_decode( $body );
|
||||
}
|
||||
}
|
121
wp-content/plugins/wp-rocket/inc/Engine/License/API/User.php
Normal file
121
wp-content/plugins/wp-rocket/inc/Engine/License/API/User.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\License\API;
|
||||
|
||||
class User {
|
||||
/**
|
||||
* The user object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param object $user The user object.
|
||||
*/
|
||||
public function __construct( $user ) {
|
||||
$this->user = is_object( $user ) ? $user : new \stdClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user license type
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_license_type() {
|
||||
if ( ! isset( $this->user->licence_account ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $this->user->licence_account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user license expiration timestamp
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_license_expiration() {
|
||||
if ( ! isset( $this->user->licence_expiration ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $this->user->licence_expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user license is expired
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_license_expired() {
|
||||
return time() > $this->get_license_expiration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user license creation date
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_creation_date() {
|
||||
if ( ! isset( $this->user->date_created ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $this->user->date_created;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if user has auto-renew enabled
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_auto_renew() {
|
||||
if ( ! isset( $this->user->has_auto_renew ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $this->user->has_auto_renew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the upgrade to plus URL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_upgrade_plus_url() {
|
||||
if ( ! isset( $this->user->upgrade_plus_url ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->user->upgrade_plus_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the upgrade to infinite url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_upgrade_infinite_url() {
|
||||
if ( ! isset( $this->user->upgrade_infinite_url ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->user->upgrade_infinite_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the renewal url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_renewal_url() {
|
||||
if ( ! isset( $this->user->renewal_url ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->user->renewal_url;
|
||||
}
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\License\API;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
|
||||
class UserClient {
|
||||
const USER_ENDPOINT = 'https://wp-rocket.me/stat/1.0/wp-rocket/user.php';
|
||||
|
||||
/**
|
||||
* WP Rocket options instance
|
||||
*
|
||||
* @var Options_Data
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param Options_Data $options WP Rocket options instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user data from cache if it exists, else gets it from the user endpoint
|
||||
*
|
||||
* Cache the user data for 24 hours in a transient
|
||||
*
|
||||
* @since 3.7.3
|
||||
*
|
||||
* @return bool|object
|
||||
*/
|
||||
public function get_user_data() {
|
||||
$cached_data = get_transient( 'wp_rocket_customer_data' );
|
||||
|
||||
if ( false !== $cached_data ) {
|
||||
return $cached_data;
|
||||
}
|
||||
|
||||
$data = $this->get_raw_user_data();
|
||||
|
||||
if ( false === $data ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_transient( 'wp_rocket_customer_data', $data, DAY_IN_SECONDS );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user data from the user endpoint
|
||||
*
|
||||
* @since 3.7.3
|
||||
*
|
||||
* @return bool|object
|
||||
*/
|
||||
private function get_raw_user_data() {
|
||||
$customer_key = ! empty( $this->options->get( 'consumer_key', '' ) )
|
||||
? $this->options->get( 'consumer_key', '' )
|
||||
: rocket_get_constant( 'WP_ROCKET_KEY', '' );
|
||||
$customer_email = ! empty( $this->options->get( 'consumer_email', '' ) )
|
||||
? $this->options->get( 'consumer_email', '' )
|
||||
: rocket_get_constant( 'WP_ROCKET_EMAIL', '' );
|
||||
|
||||
$response = wp_safe_remote_post(
|
||||
self::USER_ENDPOINT,
|
||||
[
|
||||
'body' => 'user_id=' . rawurlencode( $customer_email ) . '&consumer_key=' . sanitize_key( $customer_key ),
|
||||
]
|
||||
);
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
|
||||
if ( empty( $body ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return json_decode( $body );
|
||||
}
|
||||
}
|
313
wp-content/plugins/wp-rocket/inc/Engine/License/Renewal.php
Normal file
313
wp-content/plugins/wp-rocket/inc/Engine/License/Renewal.php
Normal file
@@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\License;
|
||||
|
||||
use WP_Rocket\Abstract_Render;
|
||||
use WP_Rocket\Engine\License\API\Pricing;
|
||||
use WP_Rocket\Engine\License\API\User;
|
||||
|
||||
class Renewal extends Abstract_Render {
|
||||
/**
|
||||
* Pricing instance
|
||||
*
|
||||
* @var Pricing
|
||||
*/
|
||||
private $pricing;
|
||||
|
||||
/**
|
||||
* User instance
|
||||
*
|
||||
* @var User
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param Pricing $pricing Pricing instance.
|
||||
* @param User $user User instance.
|
||||
* @param string $template_path Path to the views.
|
||||
*/
|
||||
public function __construct( Pricing $pricing, User $user, $template_path ) {
|
||||
parent::__construct( $template_path );
|
||||
|
||||
$this->pricing = $pricing;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the renewal banner for users expiring in less than 30 days
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_renewal_soon_banner() {
|
||||
if ( rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->user->is_license_expired() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->is_expired_soon() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->get_banner_data();
|
||||
$data['countdown'] = $this->get_countdown_data();
|
||||
|
||||
echo $this->generate( 'renewal-soon-banner', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the renewal banner for expired users
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_renewal_expired_banner() {
|
||||
if ( rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 0 === $this->user->get_license_expiration() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->user->is_license_expired() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( false !== get_transient( 'rocket_renewal_banner_' . get_current_user_id() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo $this->generate( 'renewal-expired-banner', $this->get_banner_data() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base data to display in the banners
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_banner_data() {
|
||||
return [
|
||||
'discount_percent' => $this->get_discount_percent(),
|
||||
'discount_price' => number_format_i18n( $this->get_discount_price(), 2 ),
|
||||
'renewal_url' => $this->user->get_renewal_url(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback to dismiss the renewal banner for expired users
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dismiss_renewal_expired_banner() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transient = 'rocket_renewal_banner_' . get_current_user_id();
|
||||
|
||||
if ( false !== get_transient( $transient ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_transient( $transient, 1, MONTH_IN_SECONDS );
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the license expiration time to WP Rocket localize script data
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @param array $data Localize script data.
|
||||
* @return array
|
||||
*/
|
||||
public function add_localize_script_data( $data ) {
|
||||
if ( ! is_array( $data ) ) {
|
||||
$data = (array) $data;
|
||||
}
|
||||
|
||||
if ( $this->user->is_license_expired() ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ( ! $this->is_expired_soon() ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data['license_expiration'] = $this->user->get_license_expiration();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the license expires in less than 30 days
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_expired_soon() {
|
||||
if ( $this->user->is_auto_renew() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$expiration_delay = $this->user->get_license_expiration() - time();
|
||||
|
||||
return 30 * DAY_IN_SECONDS > $expiration_delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the discount percentage corresponding to the current user status
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function get_discount_percent() {
|
||||
$renewals = $this->get_user_renewal_status();
|
||||
|
||||
if ( false === $renewals ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( $renewals['is_expired'] ) {
|
||||
return isset( $renewals['discount_percent']->is_expired ) ? $renewals['discount_percent']->is_expired : 0;
|
||||
}
|
||||
|
||||
if ( $renewals['is_grandfather'] ) {
|
||||
return isset( $renewals['discount_percent']->is_grandfather ) ? $renewals['discount_percent']->is_grandfather : 0;
|
||||
}
|
||||
|
||||
return isset( $renewals['discount_percent']->not_grandfather ) ? $renewals['discount_percent']->not_grandfather : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the discount price corresponding to the current user status
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function get_discount_price() {
|
||||
$renewals = $this->get_user_renewal_status();
|
||||
|
||||
if ( false === $renewals ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$license = $this->get_license_pricing_data();
|
||||
|
||||
if ( $renewals['is_expired'] ) {
|
||||
return isset( $license->prices->renewal->is_expired ) ? $license->prices->renewal->is_expired : 0;
|
||||
}
|
||||
|
||||
if ( $renewals['is_grandfather'] ) {
|
||||
return isset( $license->prices->renewal->is_grandfather ) ? $license->prices->renewal->is_grandfather : 0;
|
||||
}
|
||||
|
||||
return isset( $license->prices->renewal->not_grandfather ) ? $license->prices->renewal->not_grandfather : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user renewal status
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_user_renewal_status() {
|
||||
$renewals = $this->pricing->get_renewals_data();
|
||||
|
||||
if ( ! isset( $renewals->extra_days, $renewals->grandfather_date, $renewals->discount_percent ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return [
|
||||
'discount_percent' => $renewals->discount_percent,
|
||||
'is_expired' => time() > ( $this->user->get_license_expiration() + ( $renewals->extra_days * DAY_IN_SECONDS ) ),
|
||||
'is_grandfather' => $renewals->grandfather_date > $this->user->get_creation_date(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the license pricing data corresponding to the user license
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return object|null
|
||||
*/
|
||||
private function get_license_pricing_data() {
|
||||
$license = $this->user->get_license_type();
|
||||
$plus_websites = $this->pricing->get_plus_websites_count();
|
||||
|
||||
if ( $license === $plus_websites ) {
|
||||
return $this->pricing->get_plus_pricing();
|
||||
} elseif (
|
||||
$license >= $this->pricing->get_single_websites_count()
|
||||
&&
|
||||
$license < $plus_websites
|
||||
) {
|
||||
return $this->pricing->get_single_pricing();
|
||||
}
|
||||
|
||||
return $this->pricing->get_infinite_pricing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the countdown data to display for the renewal soon banner
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_countdown_data() {
|
||||
$data = [
|
||||
'days' => 0,
|
||||
'hours' => 0,
|
||||
'minutes' => 0,
|
||||
'seconds' => 0,
|
||||
];
|
||||
|
||||
if ( rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$expiration = $this->user->get_license_expiration();
|
||||
|
||||
if ( 0 === $expiration ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$now = date_create();
|
||||
$end = date_timestamp_set( date_create(), $expiration );
|
||||
|
||||
if ( $now > $end ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$remaining = date_diff( $now, $end );
|
||||
$format = explode( ' ', $remaining->format( '%d %H %i %s' ) );
|
||||
|
||||
$data['days'] = $format[0];
|
||||
$data['hours'] = $format[1];
|
||||
$data['minutes'] = $format[2];
|
||||
$data['seconds'] = $format[3];
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\License;
|
||||
|
||||
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
|
||||
use WP_Rocket\Engine\License\API\PricingClient;
|
||||
use WP_Rocket\Engine\License\API\Pricing;
|
||||
use WP_Rocket\Engine\License\API\UserClient;
|
||||
use WP_Rocket\Engine\License\API\User;
|
||||
use WP_Rocket\Engine\License\Renewal;
|
||||
use WP_Rocket\Engine\License\Subscriber;
|
||||
use WP_Rocket\Engine\License\Upgrade;
|
||||
|
||||
/**
|
||||
* Service Provider for the License module
|
||||
*
|
||||
* @since 3.7.3
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
/**
|
||||
* Aliases the service provider provides
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'pricing_client',
|
||||
'user_client',
|
||||
'pricing',
|
||||
'user',
|
||||
'upgrade',
|
||||
'renewal',
|
||||
'license_subscriber',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers items with the container
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$views = __DIR__ . '/views';
|
||||
|
||||
$this->getContainer()->add( 'pricing_client', PricingClient::class );
|
||||
$this->getContainer()->add( 'user_client', UserClient::class )
|
||||
->withArgument( $this->getContainer()->get( 'options' ) );
|
||||
$this->getContainer()->share( 'pricing', Pricing::class )
|
||||
->withArgument( $this->getContainer()->get( 'pricing_client' )->get_pricing_data() );
|
||||
$this->getContainer()->share( 'user', User::class )
|
||||
->withArgument( $this->getContainer()->get( 'user_client' )->get_user_data() );
|
||||
$this->getContainer()->add( 'upgrade', Upgrade::class )
|
||||
->withArgument( $this->getContainer()->get( 'pricing' ) )
|
||||
->withArgument( $this->getContainer()->get( 'user' ) )
|
||||
->withArgument( $views );
|
||||
$this->getContainer()->add( 'renewal', Renewal::class )
|
||||
->withArgument( $this->getContainer()->get( 'pricing' ) )
|
||||
->withArgument( $this->getContainer()->get( 'user' ) )
|
||||
->withArgument( $views );
|
||||
$this->getContainer()->share( 'license_subscriber', Subscriber::class )
|
||||
->withArgument( $this->getContainer()->get( 'upgrade' ) )
|
||||
->withArgument( $this->getContainer()->get( 'renewal' ) );
|
||||
}
|
||||
}
|
187
wp-content/plugins/wp-rocket/inc/Engine/License/Subscriber.php
Normal file
187
wp-content/plugins/wp-rocket/inc/Engine/License/Subscriber.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\License;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
class Subscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* Upgrade instance
|
||||
*
|
||||
* @var Upgrade
|
||||
*/
|
||||
private $upgrade;
|
||||
|
||||
/**
|
||||
* Renewal instance
|
||||
*
|
||||
* @var Renewal
|
||||
*/
|
||||
private $renewal;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param Upgrade $upgrade Upgrade instance.
|
||||
* @param Renewal $renewal Renewal instance.
|
||||
*/
|
||||
public function __construct( Upgrade $upgrade, Renewal $renewal ) {
|
||||
$this->upgrade = $upgrade;
|
||||
$this->renewal = $renewal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Events this subscriber listens to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rocket_dashboard_license_info' => 'display_upgrade_section',
|
||||
'rocket_settings_page_footer' => 'display_upgrade_popin',
|
||||
'rocket_menu_title' => 'add_notification_bubble',
|
||||
'admin_footer-settings_page_wprocket' => 'dismiss_notification_bubble',
|
||||
'rocket_before_dashboard_content' => [
|
||||
[ 'display_promo_banner' ],
|
||||
[ 'display_renewal_soon_banner', 11 ],
|
||||
[ 'display_renewal_expired_banner', 12 ],
|
||||
],
|
||||
'wp_ajax_rocket_dismiss_promo' => 'dismiss_promo_banner',
|
||||
'wp_ajax_rocket_dismiss_renewal' => 'dismiss_renewal_banner',
|
||||
'rocket_localize_admin_script' => 'add_localize_script_data',
|
||||
'wp_rocket_upgrade' => [ 'clean_user_transient', 15, 2 ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the upgrade section in the license info block
|
||||
*
|
||||
* @since 3.7.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_upgrade_section() {
|
||||
$this->upgrade->display_upgrade_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the upgrade popin
|
||||
*
|
||||
* @since 3.7.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_upgrade_popin() {
|
||||
$this->upgrade->display_upgrade_popin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the notification bubble to the menu title if a promotion is active
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @param string $menu_title The text to be used for the menu.
|
||||
* @return string
|
||||
*/
|
||||
public function add_notification_bubble( $menu_title ) {
|
||||
return $this->upgrade->add_notification_bubble( $menu_title );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the notification bubble from showing once the user accessed the dashboard once
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dismiss_notification_bubble() {
|
||||
$this->upgrade->dismiss_notification_bubble();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the promotions banner when a promotion is active
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_promo_banner() {
|
||||
$this->upgrade->display_promo_banner();
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback to dismiss the promotion banner
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dismiss_promo_banner() {
|
||||
$this->upgrade->dismiss_promo_banner();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the current time and promotion end time to WP Rocket localize script data
|
||||
*
|
||||
* @since 3.7.5 Add the renewal localize data
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @param array $data Localize script data.
|
||||
* @return array
|
||||
*/
|
||||
public function add_localize_script_data( $data ) {
|
||||
$data = $this->upgrade->add_localize_script_data( $data );
|
||||
|
||||
return $this->renewal->add_localize_script_data( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the user data transient on 3.7.4 update
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @param string $new_version New version of the plugin.
|
||||
* @param string $old_version Installed version of the plugin.
|
||||
* @return void
|
||||
*/
|
||||
public function clean_user_transient( $new_version, $old_version ) {
|
||||
if ( version_compare( $old_version, '3.7.4', '>' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete_transient( 'wp_rocket_customer_data' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the renewal banner for users expiring in less than 30 days
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_renewal_soon_banner() {
|
||||
$this->renewal->display_renewal_soon_banner();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the renewal banner for expired users
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_renewal_expired_banner() {
|
||||
$this->renewal->display_renewal_expired_banner();
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback to dismiss the renewal banner
|
||||
*
|
||||
* @since 3.7.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dismiss_renewal_banner() {
|
||||
$this->renewal->dismiss_renewal_expired_banner();
|
||||
}
|
||||
}
|
404
wp-content/plugins/wp-rocket/inc/Engine/License/Upgrade.php
Normal file
404
wp-content/plugins/wp-rocket/inc/Engine/License/Upgrade.php
Normal file
@@ -0,0 +1,404 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Rocket\Engine\License;
|
||||
|
||||
use WP_Rocket\Abstract_Render;
|
||||
use WP_Rocket\Engine\License\API\Pricing;
|
||||
use WP_Rocket\Engine\License\API\User;
|
||||
|
||||
class Upgrade extends Abstract_Render {
|
||||
/**
|
||||
* Pricing instance
|
||||
*
|
||||
* @var Pricing
|
||||
*/
|
||||
private $pricing;
|
||||
|
||||
/**
|
||||
* User instance
|
||||
*
|
||||
* @var User
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Instantiate the class
|
||||
*
|
||||
* @param Pricing $pricing Pricing instance.
|
||||
* @param User $user User instance.
|
||||
* @param string $template_path Path to the views.
|
||||
*/
|
||||
public function __construct( Pricing $pricing, User $user, $template_path ) {
|
||||
parent::__construct( $template_path );
|
||||
|
||||
$this->pricing = $pricing;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the upgrade section in the license block on the dashboard
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_upgrade_section() {
|
||||
if ( ! $this->can_upgrade() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo $this->generate( 'upgrade-section' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the upgrade pop on the dashboard
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_upgrade_popin() {
|
||||
if ( rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->can_upgrade() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'is_promo_active' => $this->pricing->is_promo_active(),
|
||||
'upgrades' => $this->get_upgrade_choices(),
|
||||
];
|
||||
|
||||
echo $this->generate( 'upgrade-popin', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the notification bubble to WP Rocket menu item when a promo is active
|
||||
*
|
||||
* @param string $menu_title Menu title.
|
||||
* @return string
|
||||
*/
|
||||
public function add_notification_bubble( $menu_title ) {
|
||||
if ( ! $this->can_use_promo() ) {
|
||||
return $menu_title;
|
||||
}
|
||||
|
||||
if ( false !== get_transient( 'rocket_promo_seen_' . get_current_user_id() ) ) {
|
||||
return $menu_title;
|
||||
}
|
||||
|
||||
return $menu_title . ' <span class="rocket-promo-bubble">!</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the notification bubble from showing once the user accessed the dashboard once
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dismiss_notification_bubble() {
|
||||
if ( ! $this->can_use_promo() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
|
||||
if ( false !== get_transient( "rocket_promo_seen_{$user_id}" ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_transient( "rocket_promo_seen_{$user_id}", 1, 2 * WEEK_IN_SECONDS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the promotion banner
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function display_promo_banner() {
|
||||
if ( ! $this->can_use_promo() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( false !== get_transient( 'rocket_promo_banner_' . get_current_user_id() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$promo = $this->pricing->get_promo_data();
|
||||
$promo_name = isset( $promo->name ) ? $promo->name : '';
|
||||
$promo_discount = isset( $promo->discount_percent ) ? $promo->discount_percent : 0;
|
||||
|
||||
$data = [
|
||||
'name' => $promo_name,
|
||||
'discount_percent' => $promo_discount,
|
||||
'countdown' => $this->get_countdown_data(),
|
||||
'message' => $this->get_promo_message( $promo_name, $promo_discount ),
|
||||
];
|
||||
|
||||
echo $this->generate( 'promo-banner', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback to dismiss the promotion banner
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dismiss_promo_banner() {
|
||||
check_ajax_referer( 'rocket-ajax', 'nonce', true );
|
||||
|
||||
if ( ! current_user_can( 'rocket_manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = get_current_user_id();
|
||||
|
||||
if ( false !== get_transient( "rocket_promo_banner_{$user}" ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_transient( "rocket_promo_banner_{$user}", 1, 2 * WEEK_IN_SECONDS );
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the promotion end time to WP Rocket localize script data
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @param array $data Localize script data.
|
||||
* @return array
|
||||
*/
|
||||
public function add_localize_script_data( $data ) {
|
||||
if ( ! is_array( $data ) ) {
|
||||
$data = (array) $data;
|
||||
}
|
||||
|
||||
if ( ! $this->can_use_promo() ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$data['promo_end'] = $this->pricing->get_promo_end();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing the remaining days, hours, minutes & seconds for the promotion
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_countdown_data() {
|
||||
$data = [
|
||||
'days' => 0,
|
||||
'hours' => 0,
|
||||
'minutes' => 0,
|
||||
'seconds' => 0,
|
||||
];
|
||||
|
||||
if ( rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$promo_end = $this->pricing->get_promo_end();
|
||||
|
||||
if ( 0 === $promo_end ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$now = date_create();
|
||||
$end = date_timestamp_set( date_create(), $promo_end );
|
||||
|
||||
if ( $now > $end ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$remaining = date_diff( $now, $end );
|
||||
$format = explode( ' ', $remaining->format( '%d %H %i %s' ) );
|
||||
|
||||
$data['days'] = $format[0];
|
||||
$data['hours'] = $format[1];
|
||||
$data['minutes'] = $format[2];
|
||||
$data['seconds'] = $format[3];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the promotion message to display in the banner
|
||||
*
|
||||
* @param string $promo_name Name of the promotion.
|
||||
* @param int $promo_discount Discount percentage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_promo_message( $promo_name = '', $promo_discount = 0 ) {
|
||||
$choices = 0;
|
||||
$license = $this->user->get_license_type();
|
||||
$plus_websites = $this->pricing->get_plus_websites_count();
|
||||
|
||||
if ( $license === $plus_websites ) {
|
||||
$choices = 2;
|
||||
} elseif (
|
||||
$license >= $this->pricing->get_single_websites_count()
|
||||
&&
|
||||
$license < $plus_websites
|
||||
) {
|
||||
$choices = 1;
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
// translators: %1$s = promotion name, %2$s = <br>, %3$s = <strong>, %4$s = promotion discount percentage, %5$s = </strong>.
|
||||
_n(
|
||||
'Take advantage of %1$s to speed up more websites:%2$s get a %3$s%4$s off%5$s for %3$supgrading your license to Plus or Infinite!%5$s',
|
||||
'Take advantage of %1$s to speed up more websites:%2$s get a %3$s%4$s off%5$s for %3$supgrading your license to Infinite!%5$s',
|
||||
$choices,
|
||||
'rocket'
|
||||
),
|
||||
$promo_name,
|
||||
'<br>',
|
||||
'<strong>',
|
||||
$promo_discount . '%',
|
||||
'</strong>'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current user can use the promotion
|
||||
*
|
||||
* @since 3.7.4
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function can_use_promo() {
|
||||
if ( rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $this->can_upgrade() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->is_expired_soon() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->pricing->is_promo_active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the license expires in less than 30 days
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_expired_soon() {
|
||||
$expiration_delay = $this->user->get_license_expiration() - time();
|
||||
|
||||
return 30 * DAY_IN_SECONDS > $expiration_delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current license can upgrade
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function can_upgrade() {
|
||||
return (
|
||||
-1 !== $this->user->get_license_type()
|
||||
&&
|
||||
! $this->user->is_license_expired()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the upgrade choices depending on the current license level
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_upgrade_choices() {
|
||||
$choices = [];
|
||||
$license = $this->user->get_license_type();
|
||||
$plus_websites = $this->pricing->get_plus_websites_count();
|
||||
|
||||
if ( $license === $plus_websites ) {
|
||||
$choices['infinite'] = $this->get_upgrade_from_plus_to_infinite_data();
|
||||
} elseif (
|
||||
$license >= $this->pricing->get_single_websites_count()
|
||||
&&
|
||||
$license < $plus_websites
|
||||
) {
|
||||
$choices['plus'] = $this->get_upgrade_from_single_to_plus_data();
|
||||
$choices['infinite'] = $this->get_upgrade_from_single_to_infinite_data();
|
||||
}
|
||||
|
||||
return $choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data to upgrade from single to plus
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_upgrade_from_single_to_plus_data() {
|
||||
$price = $this->pricing->get_single_to_plus_price();
|
||||
$data = [
|
||||
'name' => 'Plus',
|
||||
'price' => $price,
|
||||
'websites' => $this->pricing->get_plus_websites_count(),
|
||||
'upgrade_url' => $this->user->get_upgrade_plus_url(),
|
||||
];
|
||||
|
||||
if ( $this->pricing->is_promo_active() ) {
|
||||
$regular_price = $this->pricing->get_regular_single_to_plus_price();
|
||||
$data['saving'] = $regular_price - $price;
|
||||
$data['regular_price'] = $regular_price;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data to upgrade from single to infinite
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_upgrade_from_single_to_infinite_data() {
|
||||
$price = $this->pricing->get_single_to_infinite_price();
|
||||
$data = [
|
||||
'name' => 'Infinite',
|
||||
'price' => $price,
|
||||
'websites' => __( 'Unlimited', 'rocket' ),
|
||||
'upgrade_url' => $this->user->get_upgrade_infinite_url(),
|
||||
];
|
||||
|
||||
if ( $this->pricing->is_promo_active() ) {
|
||||
$regular_price = $this->pricing->get_regular_single_to_infinite_price();
|
||||
$data['saving'] = $regular_price - $price;
|
||||
$data['regular_price'] = $regular_price;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data to upgrade from plus to infinite
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_upgrade_from_plus_to_infinite_data() {
|
||||
$price = $this->pricing->get_plus_to_infinite_price();
|
||||
$data = [
|
||||
'name' => 'Infinite',
|
||||
'price' => $price,
|
||||
'websites' => __( 'Unlimited', 'rocket' ),
|
||||
'upgrade_url' => $this->user->get_upgrade_infinite_url(),
|
||||
];
|
||||
|
||||
if ( $this->pricing->is_promo_active() ) {
|
||||
$regular_price = $this->pricing->get_regular_plus_to_infinite_price();
|
||||
$data['saving'] = $regular_price - $price;
|
||||
$data['regular_price'] = $regular_price;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* Promo banner.
|
||||
*
|
||||
* @since 3.7.4
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
?>
|
||||
<div class="rocket-promo-banner" id="rocket-promo-banner">
|
||||
<div>
|
||||
<h3 class="rocket-promo-title">
|
||||
<span class="rocket-promo-discount">
|
||||
<?php
|
||||
// translators: %s = promotion discount percentage.
|
||||
printf( esc_html__( '%s off', 'rocket' ), esc_html( $data['discount_percent'] . '%' ) );
|
||||
?>
|
||||
</span>
|
||||
<?php
|
||||
// translators: %s = promotion name.
|
||||
printf( esc_html__( '%s promotion is live!', 'rocket' ), esc_html( $data['name'] ) );
|
||||
?>
|
||||
</h3>
|
||||
<p class="rocket-promo-message"><?php echo wp_kses_post( $data['message'] ); ?></p>
|
||||
</div>
|
||||
<div class="rocket-promo-cta-block">
|
||||
<p class="rocket-promo-deal"><?php esc_html_e( 'Hurry Up! Deal ends in:', 'rocket' ); ?></p>
|
||||
<ul class="rocket-promo-countdown" id="rocket-promo-countdown">
|
||||
<li class="rocket-countdown-item"><span class="rocket-countdown-value rocket-countdown-days"><?php echo esc_html( $data['countdown']['days'] ); ?></span> <?php esc_html_e( 'Days', 'rocket' ); ?></li>
|
||||
<li class="rocket-countdown-item"><span class="rocket-countdown-value rocket-countdown-hours"><?php echo esc_html( $data['countdown']['hours'] ); ?></span> <?php esc_html_e( 'Hours', 'rocket' ); ?></li>
|
||||
<li class="rocket-countdown-item"><span class="rocket-countdown-value rocket-countdown-minutes"><?php echo esc_html( $data['countdown']['minutes'] ); ?></span> <?php esc_html_e( 'Minutes', 'rocket' ); ?></li>
|
||||
<li class="rocket-countdown-item"><span class="rocket-countdown-value rocket-countdown-seconds"><?php echo esc_html( $data['countdown']['seconds'] ); ?></span> <?php esc_html_e( 'Seconds', 'rocket' ); ?></li>
|
||||
</ul>
|
||||
<button class="rocket-promo-cta wpr-popin-upgrade-toggle"><?php esc_html_e( 'Upgrade now', 'rocket' ); ?></button>
|
||||
</div>
|
||||
<button class="wpr-notice-close wpr-icon-close" id="rocket-dismiss-promotion"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'rocket' ); ?></span></button>
|
||||
</div>
|
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Renewal soon banner.
|
||||
*
|
||||
* @since 3.7.5
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
?>
|
||||
<div class="rocket-promo-banner" id="rocket-renewal-banner">
|
||||
<div class="rocket-expired-message">
|
||||
<h3 class="rocket-expired-title"><?php esc_html_e( 'Your WP Rocket license is expired!', 'rocket' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
// translators: %1$s = <strong>, %2$s = </strong>.
|
||||
esc_html__( 'Your website could be much faster if it could take advantage of our %1$snew features and enhancements.%2$s', 'rocket' ),
|
||||
'<strong>',
|
||||
'</strong>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
// translators: %1$s = <strong>, %2$s = discount percentage, %3$s = </strong>, %4$s = discount price.
|
||||
esc_html__( 'Renew your license for 1 year and get an immediate %1$s%2$s off%3$s on your renewal rate: you will only pay %1$s%4$s%3$s!', 'rocket' ),
|
||||
'<strong>',
|
||||
esc_html( $data['discount_percent'] . '%' ),
|
||||
'</strong>',
|
||||
esc_html( '$' . $data['discount_price'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<div class="rocket-expired-cta-container">
|
||||
<a href="<?php echo esc_url( $data['renewal_url'] ); ?>" class="rocket-renew-cta" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Renew now', 'rocket' ); ?></a>
|
||||
</div>
|
||||
<button class="wpr-notice-close wpr-icon-close" id="rocket-dismiss-renewal"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'rocket' ); ?></span></button>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user