add wp-rocket
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Hostings;
|
||||
|
||||
use WP_Rocket\Logger\Logger;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for compatibility with Litespeed
|
||||
*
|
||||
* @since 3.4.1
|
||||
* @author Soponar Cristina
|
||||
*/
|
||||
class Litespeed_Subscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* Subscribed events for Litespeed.
|
||||
*
|
||||
* @since 3.4.1
|
||||
* @author Soponar Cristina
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
if ( ! isset( $_SERVER['HTTP_X_LSCACHE'] ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'before_rocket_clean_domain' => 'litespeed_clean_domain',
|
||||
'before_rocket_clean_file' => 'litespeed_clean_file',
|
||||
'before_rocket_clean_home' => [ 'litespeed_clean_home', 10, 2 ],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge Litespeed all domain.
|
||||
*
|
||||
* @since 3.4.1
|
||||
* @author Soponar Cristina
|
||||
*/
|
||||
public function litespeed_clean_domain() {
|
||||
$this->litespeed_header_purge_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge a specific page
|
||||
*
|
||||
* @since 3.4.1
|
||||
* @author Soponar Cristina
|
||||
*
|
||||
* @param string $url The url to purge.
|
||||
*/
|
||||
public function litespeed_clean_file( $url ) {
|
||||
$this->litespeed_header_purge_url( trailingslashit( $url ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge the homepage and its pagination
|
||||
*
|
||||
* @since 3.4.1
|
||||
* @author Soponar Cristina
|
||||
*
|
||||
* @param string $root The path of home cache file.
|
||||
* @param string $lang The current lang to purge.
|
||||
*/
|
||||
public function litespeed_clean_home( $root, $lang ) {
|
||||
$home_url = trailingslashit( get_rocket_i18n_home_url( $lang ) );
|
||||
$home_pagination_url = $home_url . trailingslashit( $GLOBALS['wp_rewrite']->pagination_base );
|
||||
|
||||
$this->litespeed_header_purge_url( $home_url );
|
||||
$this->litespeed_header_purge_url( $home_pagination_url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge Litespeed URL
|
||||
*
|
||||
* @since 3.4.1
|
||||
* @author Soponar Cristina
|
||||
*
|
||||
* @param string $url The URL to purge.
|
||||
* @return void
|
||||
*/
|
||||
public function litespeed_header_purge_url( $url ) {
|
||||
if ( headers_sent() ) {
|
||||
Logger::debug(
|
||||
'X-LiteSpeed Headers already sent',
|
||||
[ 'headers_sent' ]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$parse_url = get_rocket_parse_url( $url );
|
||||
$path = rtrim( $parse_url['path'], '/' );
|
||||
$private_prefix = 'X-LiteSpeed-Purge: ' . $path;
|
||||
|
||||
Logger::debug(
|
||||
'X-LiteSpeed',
|
||||
[
|
||||
'litespeed_header_purge_url',
|
||||
'path' => $private_prefix,
|
||||
]
|
||||
);
|
||||
|
||||
@header( $private_prefix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge Litespeed Cache
|
||||
*
|
||||
* @since 3.4.1
|
||||
* @author Soponar Cristina
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function litespeed_header_purge_all() {
|
||||
if ( headers_sent() ) {
|
||||
return;
|
||||
}
|
||||
$private_prefix = 'X-LiteSpeed-Purge: *';
|
||||
@header( $private_prefix );
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins\Images\Webp;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the WebP support with EWWW.
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class EWWW_Subscriber implements Webp_Interface, Subscriber_Interface {
|
||||
use Webp_Common;
|
||||
|
||||
/**
|
||||
* Options_Data instance.
|
||||
*
|
||||
* @var Options_Data
|
||||
* @access private
|
||||
* @author Remy Perona
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* EWWW basename.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $plugin_basename;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param Options_Data $options Options instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rocket_webp_plugins' => 'register',
|
||||
'wp_rocket_loaded' => 'load_hooks',
|
||||
];
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOKS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Launch filters.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function load_hooks() {
|
||||
if ( ! $this->options->get( 'cache_webp' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Every time EWWW is (de)activated, we must "sync" our webp cache option.
|
||||
*/
|
||||
if ( did_action( 'activate_' . $this->get_basename() ) ) {
|
||||
$this->plugin_activation();
|
||||
}
|
||||
if ( did_action( 'deactivate_' . $this->get_basename() ) ) {
|
||||
$this->plugin_deactivation();
|
||||
}
|
||||
add_action( 'activate_' . $this->get_basename(), [ $this, 'plugin_activation' ], 20 );
|
||||
add_action( 'deactivate_' . $this->get_basename(), [ $this, 'plugin_deactivation' ], 20 );
|
||||
|
||||
if ( ! function_exists( 'ewww_image_optimizer_get_option' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since Rocket already updates the config file after updating its options, there is no need to do it again if the CDN or zone options change.
|
||||
* Sadly, we can’t monitor EWWW options accurately to update our config file.
|
||||
*/
|
||||
|
||||
add_filter( 'rocket_cdn_cnames', [ $this, 'maybe_remove_images_cnames' ], 1000, 2 );
|
||||
add_filter( 'rocket_allow_cdn_images', [ $this, 'maybe_remove_images_from_cdn_dropdown' ] );
|
||||
|
||||
$option_names = [
|
||||
'ewww_image_optimizer_exactdn',
|
||||
'ewww_image_optimizer_webp_for_cdn',
|
||||
];
|
||||
|
||||
foreach ( $option_names as $option_name ) {
|
||||
if ( $this->is_active_for_network() ) {
|
||||
add_filter( 'add_site_option_' . $option_name, [ $this, 'trigger_webp_change' ] );
|
||||
add_filter( 'update_site_option_' . $option_name, [ $this, 'trigger_webp_change' ] );
|
||||
add_filter( 'delete_site_option_' . $option_name, [ $this, 'trigger_webp_change' ] );
|
||||
} else {
|
||||
add_filter( 'add_option_' . $option_name, [ $this, 'trigger_webp_change' ] );
|
||||
add_filter( 'update_option_' . $option_name, [ $this, 'trigger_webp_change' ] );
|
||||
add_filter( 'delete_option_' . $option_name, [ $this, 'trigger_webp_change' ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove CDN hosts for images if EWWW uses ExactDN.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param array $hosts List of CDN URLs.
|
||||
* @param array $zones List of zones. Default is [ 'all' ].
|
||||
* @return array
|
||||
*/
|
||||
public function maybe_remove_images_cnames( $hosts, $zones ) {
|
||||
if ( ! $hosts ) {
|
||||
return $hosts;
|
||||
}
|
||||
if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
|
||||
return $hosts;
|
||||
}
|
||||
// EWWW uses ExactDN: WPR CDN should be disabled for images.
|
||||
if ( ! in_array( 'images', $zones, true ) ) {
|
||||
// Not asking for images.
|
||||
return $hosts;
|
||||
}
|
||||
if ( ! array_diff( $zones, [ 'all', 'images' ] ) ) {
|
||||
// This is clearly for images: return an empty list of hosts.
|
||||
return [];
|
||||
}
|
||||
|
||||
// We also want other things, like js and css: let's only remove the hosts for 'images'.
|
||||
$cdn_urls = $this->options->get( 'cdn_cnames', [] );
|
||||
|
||||
if ( ! $cdn_urls ) {
|
||||
return $hosts;
|
||||
}
|
||||
|
||||
// Separate image hosts from the other ones.
|
||||
$image_hosts = [];
|
||||
$other_hosts = [];
|
||||
$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 );
|
||||
|
||||
if ( 'images' === $cdn_zones[ $k ] ) {
|
||||
foreach ( $urls as $url ) {
|
||||
$image_hosts[] = $url;
|
||||
}
|
||||
} else {
|
||||
foreach ( $urls as $url ) {
|
||||
$other_hosts[] = $url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the image hosts are not also used for other things (duplicate).
|
||||
$image_hosts = array_diff( $image_hosts, $other_hosts );
|
||||
|
||||
// Then remove the remaining from the final list.
|
||||
return array_diff( $hosts, $image_hosts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe remove the images option from the CDN dropdown.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param bool $allow true to add the option, false otherwise.
|
||||
* @return bool
|
||||
*/
|
||||
public function maybe_remove_images_from_cdn_dropdown( $allow ) {
|
||||
if ( ! $allow ) {
|
||||
return $allow;
|
||||
}
|
||||
if ( ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
|
||||
return $allow;
|
||||
}
|
||||
|
||||
// EWWW uses ExactDN: WPR CDN should be disabled for images.
|
||||
return false;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PUBLIC TOOLS ============================================================================ */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the plugin name.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'EWWW';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin identifier.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_id() {
|
||||
return 'ewww';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin converts images to webp.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_converting_to_webp() {
|
||||
if ( ! function_exists( 'ewww_image_optimizer_get_option' ) ) {
|
||||
// No EWWW, no webp.
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin serves webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp() {
|
||||
if ( ! function_exists( 'ewww_image_optimizer_get_option' ) ) {
|
||||
// No EWWW, no webp.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
|
||||
// EWWW uses ExactDN (WPR CDN should be disabled for images).
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) ) {
|
||||
// EWWW uses JS to rewrite file extensions.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Decide if rewrite rules are used.
|
||||
if ( ! function_exists( 'ewww_image_optimizer_webp_rewrite_verify' ) ) {
|
||||
// Uh?
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'get_home_path' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'extract_from_markers' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/misc.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns null if rules are present and valid. Otherwise it returns rules to be inserted.
|
||||
* Note: this also returns null if WP Fastest Cache rules for webp are found in the file.
|
||||
*
|
||||
* @see ewww_image_optimizer_wpfc_webp_enabled()
|
||||
*/
|
||||
$use_rewrite_rules = ! ewww_image_optimizer_webp_rewrite_verify();
|
||||
|
||||
/**
|
||||
* Filter wether EWW is using rewrite rules for webp.
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param bool $use_rewrite_rules True when EWWW uses rewrite rules. False otherwise.
|
||||
*/
|
||||
return (bool) apply_filters( 'rocket_webp_ewww_use_rewrite_rules', $use_rewrite_rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin uses a CDN-compatible technique to serve webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp_compatible_with_cdn() {
|
||||
if ( ! function_exists( 'ewww_image_optimizer_get_option' ) ) {
|
||||
// No EWWW, no webp.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_exactdn' ) ) {
|
||||
// EWWW uses ExactDN.
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ewww_image_optimizer_get_option( 'ewww_image_optimizer_webp_for_cdn' ) ) {
|
||||
// EWWW uses JS to rewrite file extensions.
|
||||
return true;
|
||||
}
|
||||
|
||||
// At this point, the plugin is using rewrite rules or nothing.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin basename.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_basename() {
|
||||
if ( empty( $this->plugin_basename ) ) {
|
||||
$this->plugin_basename = rocket_has_constant( 'EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE' )
|
||||
? plugin_basename( rocket_get_constant( 'EWWW_IMAGE_OPTIMIZER_PLUGIN_FILE' ) )
|
||||
: 'ewww-image-optimizer/ewww-image-optimizer.php';
|
||||
}
|
||||
|
||||
return $this->plugin_basename;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PRIVATE TOOLS =========================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Tell if EWWW is active for network.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_active_for_network() {
|
||||
static $is;
|
||||
|
||||
if ( isset( $is ) ) {
|
||||
return $is;
|
||||
}
|
||||
|
||||
if ( ! is_multisite() ) {
|
||||
$is = false;
|
||||
return $is;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
$is = is_plugin_active_for_network( $this->get_basename() ) && ! get_site_option( 'ewww_image_optimizer_allow_multisite_override' );
|
||||
|
||||
return $is;
|
||||
}
|
||||
}
|
@@ -0,0 +1,435 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins\Images\Webp;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the WebP support with Imagify.
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class Imagify_Subscriber implements Webp_Interface, Subscriber_Interface {
|
||||
use Webp_Common;
|
||||
|
||||
/**
|
||||
* Options_Data instance.
|
||||
*
|
||||
* @var Options_Data
|
||||
* @access private
|
||||
* @author Remy Perona
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Imagify basename.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $plugin_basename;
|
||||
|
||||
/**
|
||||
* Imagify’s "serve webp" option name.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $plugin_option_name_to_serve_webp;
|
||||
|
||||
/**
|
||||
* Temporarily store the result of $this->is_serving_webp().
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $tmp_is_serving_webp;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param Options_Data $options Options instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rocket_webp_plugins' => 'register',
|
||||
'wp_rocket_loaded' => 'load_hooks',
|
||||
];
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOKS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Launch filters.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function load_hooks() {
|
||||
if ( ! $this->options->get( 'cache_webp' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Every time Imagify is (de)activated, we must "sync" our webp cache option.
|
||||
*/
|
||||
add_action( 'imagify_activation', [ $this, 'plugin_activation' ], 20 );
|
||||
add_action( 'imagify_deactivation', [ $this, 'plugin_deactivation' ], 20 );
|
||||
|
||||
if ( ! rocket_has_constant( 'IMAGIFY_VERSION' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since Rocket already updates the config file after updating its options, there is no need to do it again if the CDN or zone options change.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Every time Imagify’s option changes, we must "sync" our webp cache option.
|
||||
*/
|
||||
$option_name = $this->get_option_name_to_serve_webp();
|
||||
|
||||
if ( $this->is_active_for_network() ) {
|
||||
add_filter( 'add_site_option_' . $option_name, [ $this, 'sync_on_network_option_add' ], 10, 3 );
|
||||
add_filter( 'update_site_option_' . $option_name, [ $this, 'sync_on_network_option_update' ], 10, 4 );
|
||||
add_filter( 'pre_delete_site_option_' . $option_name, [ $this, 'store_option_value_before_network_delete' ], 10, 2 );
|
||||
add_filter( 'delete_site_option_' . $option_name, [ $this, 'sync_on_network_option_delete' ], 10, 2 );
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter( 'add_option_' . $option_name, [ $this, 'sync_on_option_add' ], 10, 2 );
|
||||
add_filter( 'update_option_' . $option_name, [ $this, 'sync_on_option_update' ], 10, 2 );
|
||||
add_filter( 'delete_option', [ $this, 'store_option_value_before_delete' ] );
|
||||
add_filter( 'delete_option_' . $option_name, [ $this, 'sync_on_option_delete' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe deactivate webp cache after Imagify network option has been successfully added.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the network option.
|
||||
* @param mixed $value Value of the network option.
|
||||
* @param int $network_id ID of the network.
|
||||
*/
|
||||
public function sync_on_network_option_add( $option, $value, $network_id ) {
|
||||
if ( get_current_network_id() === $network_id && ! empty( $value['display_webp'] ) ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe activate or deactivate webp cache after Imagify network option has been modified.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the network option.
|
||||
* @param mixed $value Current value of the network option.
|
||||
* @param mixed $old_value Old value of the network option.
|
||||
* @param int $network_id ID of the network.
|
||||
*/
|
||||
public function sync_on_network_option_update( $option, $value, $old_value, $network_id ) {
|
||||
if ( get_current_network_id() === $network_id ) {
|
||||
$this->sync_on_option_update( $old_value, $value );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the Imagify network option value before it is deleted.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Option name.
|
||||
* @param int $network_id ID of the network.
|
||||
*/
|
||||
public function store_option_value_before_network_delete( $option, $network_id ) {
|
||||
if ( get_current_network_id() === $network_id ) {
|
||||
$this->tmp_is_serving_webp = $this->is_serving_webp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe activate webp cache after Imagify network option has been deleted.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the network option.
|
||||
* @param int $network_id ID of the network.
|
||||
*/
|
||||
public function sync_on_network_option_delete( $option, $network_id ) {
|
||||
if ( get_current_network_id() === $network_id && false !== $this->tmp_is_serving_webp ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe deactivate webp cache after Imagify option has been successfully added.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the option to add.
|
||||
* @param mixed $value Value of the option.
|
||||
*/
|
||||
public function sync_on_option_add( $option, $value ) {
|
||||
if ( ! empty( $value['display_webp'] ) ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe activate or deactivate webp cache after Imagify option has been modified.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param mixed $old_value The old option value.
|
||||
* @param mixed $value The new option value.
|
||||
*/
|
||||
public function sync_on_option_update( $old_value, $value ) {
|
||||
$old_display = ! empty( $old_value['display_webp'] );
|
||||
$display = ! empty( $value['display_webp'] );
|
||||
|
||||
if ( $old_display !== $display || $old_value['display_webp_method'] !== $value['display_webp_method'] ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the Imagify option value before it is deleted.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the option to delete.
|
||||
*/
|
||||
public function store_option_value_before_delete( $option ) {
|
||||
if ( $this->get_option_name_to_serve_webp() === $option ) {
|
||||
$this->tmp_is_serving_webp = $this->is_serving_webp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe activate webp cache after Imagify option has been deleted.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the deleted option.
|
||||
*/
|
||||
public function sync_on_option_delete( $option ) {
|
||||
if ( false !== $this->tmp_is_serving_webp ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PUBLIC TOOLS ============================================================================ */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the plugin name.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'Imagify';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin identifier.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_id() {
|
||||
return 'imagify';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin converts images to webp.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_converting_to_webp() {
|
||||
if ( ! function_exists( 'get_imagify_option' ) ) {
|
||||
// No Imagify, no webp.
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) get_imagify_option( 'convert_to_webp' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin serves webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp() {
|
||||
if ( ! function_exists( 'get_imagify_option' ) ) {
|
||||
// No Imagify, no webp.
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) get_imagify_option( 'display_webp' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin uses a CDN-compatible technique to serve webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp_compatible_with_cdn() {
|
||||
if ( ! $this->is_serving_webp() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 'rewrite' !== get_imagify_option( 'display_webp_method' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin basename.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_basename() {
|
||||
if ( empty( $this->plugin_basename ) ) {
|
||||
$this->plugin_basename = rocket_has_constant( 'IMAGIFY_FILE' )
|
||||
? plugin_basename( rocket_get_constant( 'IMAGIFY_FILE' ) )
|
||||
: 'imagify/imagify.php';
|
||||
}
|
||||
|
||||
return $this->plugin_basename;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PRIVATE TOOLS =========================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the name of the Imagify’s "serve webp" option.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_option_name_to_serve_webp() {
|
||||
if ( ! empty( $this->plugin_option_name_to_serve_webp ) ) {
|
||||
return $this->plugin_option_name_to_serve_webp;
|
||||
}
|
||||
|
||||
$default = 'imagify_settings';
|
||||
|
||||
if ( ! class_exists( '\Imagify_Options' ) || ! method_exists( '\Imagify_Options', 'get_instance' ) ) {
|
||||
$this->plugin_option_name_to_serve_webp = $default;
|
||||
return $this->plugin_option_name_to_serve_webp;
|
||||
}
|
||||
|
||||
$instance = \Imagify_Options::get_instance();
|
||||
|
||||
if ( ! method_exists( $instance, 'get_option_name' ) ) {
|
||||
$this->plugin_option_name_to_serve_webp = $default;
|
||||
return $this->plugin_option_name_to_serve_webp;
|
||||
}
|
||||
|
||||
$this->plugin_option_name_to_serve_webp = $instance->get_option_name();
|
||||
|
||||
return $this->plugin_option_name_to_serve_webp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if Imagify is active for network.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_active_for_network() {
|
||||
static $is;
|
||||
|
||||
if ( isset( $is ) ) {
|
||||
return $is;
|
||||
}
|
||||
|
||||
if ( function_exists( 'imagify_is_active_for_network' ) ) {
|
||||
$is = imagify_is_active_for_network();
|
||||
return $is;
|
||||
}
|
||||
|
||||
if ( ! is_multisite() ) {
|
||||
$is = false;
|
||||
return $is;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
$is = is_plugin_active_for_network( $this->get_basename() );
|
||||
|
||||
return $is;
|
||||
}
|
||||
}
|
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins\Images\Webp;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the WebP support with Optimus.
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class Optimus_Subscriber implements Webp_Interface, Subscriber_Interface {
|
||||
|
||||
/**
|
||||
* Optimus basename.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $plugin_basename;
|
||||
|
||||
/**
|
||||
* Returns an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
if ( ! defined( 'OPTIMUS_FILE' ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'rocket_webp_plugins' => 'register',
|
||||
];
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOKS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Register the plugin.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param array $webp_plugins An array of Webp_Interface objects.
|
||||
* @return array
|
||||
*/
|
||||
public function register( $webp_plugins ) {
|
||||
$webp_plugins[] = $this;
|
||||
return $webp_plugins;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PUBLIC TOOLS ============================================================================ */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the plugin name.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'Optimus';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin identifier.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_id() {
|
||||
return 'optimus';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin converts images to webp.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_converting_to_webp() {
|
||||
if ( class_exists( '\Optimus' ) && method_exists( '\Optimus', 'get_options' ) ) {
|
||||
$options = \Optimus::get_options();
|
||||
} else {
|
||||
$options = get_option( 'optimus' );
|
||||
}
|
||||
|
||||
return ! empty( $options['webp_convert'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin serves webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin uses a CDN-compatible technique to serve webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp_compatible_with_cdn() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin basename.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_basename() {
|
||||
if ( empty( $this->plugin_basename ) ) {
|
||||
$this->plugin_basename = defined( 'OPTIMUS_FILE' ) ? plugin_basename( OPTIMUS_FILE ) : 'optimus/optimus.php';
|
||||
}
|
||||
|
||||
return $this->plugin_basename;
|
||||
}
|
||||
}
|
@@ -0,0 +1,294 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins\Images\Webp;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Subscriber for the WebP support with ShortPixel.
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class ShortPixel_Subscriber implements Webp_Interface, Subscriber_Interface {
|
||||
use Webp_Common;
|
||||
|
||||
/**
|
||||
* Options_Data instance.
|
||||
*
|
||||
* @var Options_Data
|
||||
* @access private
|
||||
* @author Remy Perona
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* ShortPixel basename.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $plugin_basename;
|
||||
|
||||
/**
|
||||
* ShortPixel’s "serve webp" option name.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $plugin_option_name_to_serve_webp = 'wp-short-pixel-create-webp-markup';
|
||||
|
||||
/**
|
||||
* Temporarily store the result of $this->is_serving_webp().
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $tmp_is_serving_webp;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param Options_Data $options Options instance.
|
||||
*/
|
||||
public function __construct( Options_Data $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'rocket_webp_plugins' => 'register',
|
||||
'wp_rocket_loaded' => 'load_hooks',
|
||||
];
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOKS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Launch filters.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function load_hooks() {
|
||||
if ( ! $this->options->get( 'cache_webp' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Every time ShortPixel is (de)activated, we must "sync" our webp cache option.
|
||||
*/
|
||||
if ( did_action( 'activate_' . $this->get_basename() ) ) {
|
||||
$this->plugin_activation();
|
||||
}
|
||||
if ( did_action( 'deactivate_' . $this->get_basename() ) ) {
|
||||
$this->plugin_deactivation();
|
||||
}
|
||||
add_action( 'activate_' . $this->get_basename(), [ $this, 'plugin_activation' ], 20 );
|
||||
add_action( 'deactivate_' . $this->get_basename(), [ $this, 'plugin_deactivation' ], 20 );
|
||||
|
||||
if ( ! defined( 'SHORTPIXEL_IMAGE_OPTIMISER_VERSION' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since Rocket already updates the config file after updating its options, there is no need to do it again if the CDN or zone options change.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Every time ShortPixel’s option changes, we must "sync" our webp cache option.
|
||||
*/
|
||||
$option_name = $this->plugin_option_name_to_serve_webp;
|
||||
|
||||
add_filter( 'add_option_' . $option_name, [ $this, 'sync_on_option_add' ], 10, 2 );
|
||||
add_filter( 'update_option_' . $option_name, [ $this, 'sync_on_option_update' ], 10, 2 );
|
||||
add_filter( 'delete_option', [ $this, 'store_option_value_before_delete' ] );
|
||||
add_filter( 'delete_option_' . $option_name, [ $this, 'sync_on_option_delete' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe deactivate webp cache after ShortPixel option has been successfully added.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the option to add.
|
||||
* @param mixed $value Value of the option.
|
||||
*/
|
||||
public function sync_on_option_add( $option, $value ) {
|
||||
if ( $value ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe activate or deactivate webp cache after ShortPixel option has been modified.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param mixed $old_value The old option value.
|
||||
* @param mixed $value The new option value.
|
||||
*/
|
||||
public function sync_on_option_update( $old_value, $value ) {
|
||||
/**
|
||||
* 0 = Don’t serve webp.
|
||||
* 1 = <picture> + buffer
|
||||
* 2 = <picture> + hooks
|
||||
* 3 = .htaccess
|
||||
*/
|
||||
$old_value = $old_value > 0;
|
||||
$value = $value > 0;
|
||||
|
||||
if ( $old_value !== $value ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the ShortPixel option value before it is deleted.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the option to delete.
|
||||
*/
|
||||
public function store_option_value_before_delete( $option ) {
|
||||
if ( $this->plugin_option_name_to_serve_webp === $option ) {
|
||||
$this->tmp_is_serving_webp = $this->is_serving_webp();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe activate webp cache after ShortPixel option has been deleted.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function sync_on_option_delete() {
|
||||
if ( false !== $this->tmp_is_serving_webp ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PUBLIC TOOLS ============================================================================ */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the plugin name.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'ShortPixel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin identifier.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_id() {
|
||||
return 'shortpixel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin converts images to webp.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_converting_to_webp() {
|
||||
return (bool) get_option( 'wp-short-create-webp' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin serves webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp() {
|
||||
return (bool) get_option( $this->plugin_option_name_to_serve_webp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the plugin uses a CDN-compatible technique to serve webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp_compatible_with_cdn() {
|
||||
$display = (int) get_option( $this->plugin_option_name_to_serve_webp );
|
||||
|
||||
if ( ! $display ) {
|
||||
// The option is not enabled, no webp.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( 3 === $display ) {
|
||||
// The option is set to "rewrite rules".
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin basename.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_basename() {
|
||||
if ( empty( $this->plugin_basename ) ) {
|
||||
$this->plugin_basename = defined( 'SHORTPIXEL_PLUGIN_FILE' ) ? plugin_basename( SHORTPIXEL_PLUGIN_FILE ) : 'shortpixel-image-optimiser/wp-shortpixel.php';
|
||||
}
|
||||
|
||||
return $this->plugin_basename;
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins\Images\Webp;
|
||||
|
||||
/**
|
||||
* Trait for webp subscribers, focussed on plugins that serve webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
trait Webp_Common {
|
||||
|
||||
/**
|
||||
* Register the plugin.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param array $webp_plugins An array of Webp_Interface objects.
|
||||
* @return array
|
||||
*/
|
||||
public function register( $webp_plugins ) {
|
||||
$webp_plugins[] = $this;
|
||||
return $webp_plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* On plugin activation, deactivate Rocket webp cache if the plugin is serving webp.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function plugin_activation() {
|
||||
if ( $this->is_serving_webp() ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* On plugin deactivation, activate Rocket webp cache if the plugin is serving webp.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function plugin_deactivation() {
|
||||
if ( $this->is_serving_webp() ) {
|
||||
$this->trigger_webp_change();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an action when the webp feature is enabled/disabled in a third party plugin.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function trigger_webp_change() {
|
||||
/**
|
||||
* Trigger an action when the webp feature is enabled/disabled in a third party plugin.
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
do_action( 'rocket_third_party_webp_change' );
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins\Images\Webp;
|
||||
|
||||
/**
|
||||
* Interface to use for webp subscribers.
|
||||
*
|
||||
* @since 3.4
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
interface Webp_Interface {
|
||||
|
||||
/**
|
||||
* Get the plugin name.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name();
|
||||
|
||||
/**
|
||||
* Get the plugin identifier.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_id();
|
||||
|
||||
/**
|
||||
* Tell if the plugin converts images to webp.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_converting_to_webp();
|
||||
|
||||
/**
|
||||
* Tell if the plugin serves webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp();
|
||||
|
||||
/**
|
||||
* Tell if the plugin uses a CDN-compatible technique to serve webp images on frontend.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_serving_webp_compatible_with_cdn();
|
||||
|
||||
/**
|
||||
* Get the plugin basename.
|
||||
*
|
||||
* @since 3.4
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_basename();
|
||||
}
|
396
wp-content/plugins/wp-rocket/inc/classes/subscriber/third-party/plugins/class-mobile-subscriber.php
vendored
Normal file
396
wp-content/plugins/wp-rocket/inc/classes/subscriber/third-party/plugins/class-mobile-subscriber.php
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class that handles events related to plugins that add mobile themes.
|
||||
*
|
||||
* @since 3.2
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class Mobile_Subscriber implements Subscriber_Interface {
|
||||
|
||||
/**
|
||||
* Options to activate when a mobile plugin is active.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $options = [
|
||||
'cache_mobile' => 1,
|
||||
'do_caching_mobile_files' => 1,
|
||||
];
|
||||
|
||||
/**
|
||||
* Cache the value of self::is_mobile_plugin_active().
|
||||
*
|
||||
* @since 3.2
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @var array An array of arrays of booleans.
|
||||
* First level of keys corresponds to the network ID. Second level of keys corresponds to the blog ID.
|
||||
*/
|
||||
protected static $is_mobile_active = [];
|
||||
|
||||
/**
|
||||
* Returns an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
// In case a mobile plugin has already been activated.
|
||||
$do = [];
|
||||
$undo = [];
|
||||
$plugin_events = [];
|
||||
|
||||
if ( ! function_exists( '\is_plugin_active' ) ) {
|
||||
include_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
foreach ( static::get_mobile_plugins() as $plugin => $plugin_data ) {
|
||||
if ( \did_action( 'activate_' . $plugin ) &&
|
||||
! isset( $plugin_data['is_active_callback'] ) ) {
|
||||
$do[] = $plugin;
|
||||
}
|
||||
|
||||
if ( \did_action( 'activate_' . $plugin ) &&
|
||||
isset( $plugin_data['is_active_callback'] ) &&
|
||||
call_user_func( $plugin_data['is_active_callback'] ) ) {
|
||||
$do[] = $plugin;
|
||||
}
|
||||
|
||||
if ( \did_action( 'deactivate_' . $plugin ) ) {
|
||||
$undo[] = $plugin;
|
||||
}
|
||||
|
||||
if ( \is_plugin_active( $plugin ) ) {
|
||||
if ( isset( $plugin_data['activation_hook'] ) ) {
|
||||
$plugin_events[ $plugin_data['activation_hook'] ] = 'maybe_update_mobile_cache_activation_plugin_hook';
|
||||
}
|
||||
if ( isset( $plugin_data['deactivation_hook'] ) ) {
|
||||
$plugin_events[ $plugin_data['deactivation_hook'] ] = 'maybe_update_mobile_cache_activation_plugin_hook';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( array_diff( $do, $undo ) || array_diff( $undo, $do ) ) {
|
||||
static::update_mobile_cache_activation();
|
||||
}
|
||||
|
||||
// Register events.
|
||||
$events = [
|
||||
// Plugin activation/deactivation.
|
||||
'add_option_active_plugins' => [ 'add_option_callback', 10, 2 ],
|
||||
'update_option_active_plugins' => [ 'update_option_callback', 10, 2 ],
|
||||
'delete_option_active_plugins' => 'delete_option_callback',
|
||||
'add_site_option_active_sitewide_plugins' => [ 'add_site_option_callback', 10, 3 ],
|
||||
'update_site_option_active_sitewide_plugins' => [ 'update_site_option_callback', 10, 4 ],
|
||||
'delete_site_option_active_sitewide_plugins' => [ 'delete_site_option_callback', 10, 2 ],
|
||||
// WPR settings (`get_option()`).
|
||||
'option_' . WP_ROCKET_SLUG => 'mobile_options_filter',
|
||||
];
|
||||
|
||||
foreach ( static::$options as $option => $value ) {
|
||||
// WPR settings (`get_rocket_option()`).
|
||||
$events[ 'pre_get_rocket_option_' . $option ] = 'is_mobile_plugin_active_callback';
|
||||
}
|
||||
|
||||
$events = array_merge( $events, $plugin_events );
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOK CALLBACKS ========================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Callback triggered after the option `active_plugins` is created.
|
||||
* This should normally never be triggered.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the option to add.
|
||||
* @param mixed $value Value of the option.
|
||||
*/
|
||||
public function add_option_callback( $option, $value ) {
|
||||
$this->maybe_update_mobile_cache_activation( $value, [] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback triggered after the option `active_plugins` is updated.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param mixed $old_value The old option value.
|
||||
* @param mixed $value Value of the option.
|
||||
*/
|
||||
public function update_option_callback( $old_value, $value ) {
|
||||
$this->maybe_update_mobile_cache_activation( $value, $old_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback triggered after the option `active_plugins` is deleted.
|
||||
* Very low probability to be triggered.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function delete_option_callback() {
|
||||
static::update_mobile_cache_activation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback triggered after the option `active_sitewide_plugins` is created.
|
||||
* This should normally never be triggered.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the option to add.
|
||||
* @param mixed $value Value of the option.
|
||||
* @param int $network_id ID of the network.
|
||||
*/
|
||||
public function add_site_option_callback( $option, $value, $network_id ) {
|
||||
if ( get_current_network_id() === $network_id ) {
|
||||
$this->maybe_update_mobile_cache_activation( $value, [] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback triggered after the option `active_sitewide_plugins` is updated.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the option to add.
|
||||
* @param mixed $value Value of the option.
|
||||
* @param mixed $old_value The old option value.
|
||||
* @param int $network_id ID of the network.
|
||||
*/
|
||||
public function update_site_option_callback( $option, $value, $old_value, $network_id ) {
|
||||
if ( get_current_network_id() === $network_id ) {
|
||||
$this->maybe_update_mobile_cache_activation( $value, $old_value );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback triggered after the option `active_sitewide_plugins` is deleted.
|
||||
* Very low probability to be triggered.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option Name of the option to add.
|
||||
* @param int $network_id ID of the network.
|
||||
*/
|
||||
public function delete_site_option_callback( $option, $network_id ) {
|
||||
if ( get_current_network_id() === $network_id ) {
|
||||
static::update_mobile_cache_activation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable mobile caching when a mobile plugin is activated, or revert it back to its previous state when a mobile plugin is deactivated.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param mixed $value The new option value.
|
||||
* @param mixed $old_value The old option value.
|
||||
*/
|
||||
public function maybe_update_mobile_cache_activation( $value, $old_value ) {
|
||||
$plugins = static::get_mobile_plugins();
|
||||
$plugins = array_keys( $plugins );
|
||||
$value = array_intersect( $plugins, (array) $value );
|
||||
$old_value = array_intersect( $plugins, (array) $old_value );
|
||||
|
||||
if ( $value !== $old_value ) {
|
||||
static::update_mobile_cache_activation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables mobile caching when a mobile plugin option is activated, or reverts it back to its previous state when a mobile plugin option is deactivated.
|
||||
*
|
||||
* @since 3.4.2
|
||||
* @access public
|
||||
* @author Soponar Cristina
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_update_mobile_cache_activation_plugin_hook() {
|
||||
$is_mobile_plugin_active = static::is_mobile_plugin_active();
|
||||
static::reset_class_cache();
|
||||
$is_new_mobile_plugin_active = static::is_mobile_plugin_active();
|
||||
if ( $is_mobile_plugin_active !== $is_new_mobile_plugin_active ) {
|
||||
static::update_mobile_cache_activation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the values for the mobile options if a mobile plugin is active.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param array $values Option values.
|
||||
* @return array
|
||||
*/
|
||||
public function mobile_options_filter( $values ) {
|
||||
if ( static::is_mobile_plugin_active() ) {
|
||||
return array_merge( (array) $values, static::$options );
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the value for a mobile option if a mobile plugin is active.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param int|null $value Option value.
|
||||
* @return int|null
|
||||
*/
|
||||
public function is_mobile_plugin_active_callback( $value ) {
|
||||
if ( static::is_mobile_plugin_active() ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** MAIN HELPERS ============================================================================ */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Update the config file and the advanced cache file.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public static function update_mobile_cache_activation() {
|
||||
// Reset class cache.
|
||||
static::reset_class_cache();
|
||||
|
||||
// Update the config file.
|
||||
rocket_generate_config_file();
|
||||
// Update the advanced cache file.
|
||||
rocket_generate_advanced_cache_file();
|
||||
// Flush htaccess file.
|
||||
flush_rocket_htaccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset `is_mobile_plugin_active()` cache.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public static function reset_class_cache() {
|
||||
// Reset class cache.
|
||||
unset( static::$is_mobile_active[ get_current_network_id() ][ get_current_blog_id() ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the concerned plugins.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_mobile_plugins() {
|
||||
return [
|
||||
'jetpack/jetpack.php' => [
|
||||
'is_active_callback' => function() {
|
||||
if ( ! class_exists( 'Jetpack' ) ) {
|
||||
return false;
|
||||
}
|
||||
return \Jetpack::is_active() && \Jetpack::is_module_active( 'minileven' );
|
||||
},
|
||||
'activation_hook' => 'jetpack_activate_module_minileven',
|
||||
'deactivation_hook' => 'jetpack_deactivate_module_minileven',
|
||||
],
|
||||
'wptouch/wptouch.php' => [],
|
||||
'wiziapp-create-your-own-native-iphone-app/wiziapp.php' => [],
|
||||
'wordpress-mobile-pack/wordpress-mobile-pack.php' => [],
|
||||
'wp-mobilizer/wp-mobilizer.php' => [],
|
||||
'wp-mobile-edition/wp-mobile-edition.php' => [],
|
||||
'device-theme-switcher/dts_controller.php' => [],
|
||||
'wp-mobile-detect/wp-mobile-detect.php' => [],
|
||||
'easy-social-share-buttons3/easy-social-share-buttons3.php' => [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if a mobile plugin is active.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool True if a mobile plugin in the list is active, false otherwise.
|
||||
*/
|
||||
public static function is_mobile_plugin_active() {
|
||||
$network_id = get_current_network_id();
|
||||
$blog_id = get_current_blog_id();
|
||||
|
||||
if ( isset( static::$is_mobile_active[ $network_id ][ $blog_id ] ) ) {
|
||||
return static::$is_mobile_active[ $network_id ][ $blog_id ];
|
||||
}
|
||||
|
||||
if ( ! function_exists( '\is_plugin_active' ) ) {
|
||||
include_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
if ( ! isset( static::$is_mobile_active[ $network_id ] ) ) {
|
||||
static::$is_mobile_active[ $network_id ] = [];
|
||||
}
|
||||
|
||||
foreach ( static::get_mobile_plugins() as $mobile_plugin => $mobile_plugin_data ) {
|
||||
if ( \is_plugin_active( $mobile_plugin ) &&
|
||||
isset( $mobile_plugin_data['is_active_callback'] ) &&
|
||||
call_user_func( $mobile_plugin_data['is_active_callback'] ) ) {
|
||||
static::$is_mobile_active[ $network_id ][ $blog_id ] = true;
|
||||
return true;
|
||||
}
|
||||
if ( \is_plugin_active( $mobile_plugin ) &&
|
||||
! isset( $mobile_plugin_data['is_active_callback'] ) ) {
|
||||
static::$is_mobile_active[ $network_id ][ $blog_id ] = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static::$is_mobile_active[ $network_id ][ $blog_id ] = false;
|
||||
return false;
|
||||
}
|
||||
}
|
44
wp-content/plugins/wp-rocket/inc/classes/subscriber/third-party/plugins/class-ngg-subscriber.php
vendored
Normal file
44
wp-content/plugins/wp-rocket/inc/classes/subscriber/third-party/plugins/class-ngg-subscriber.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class that handles events related to Next Gen Gallery.
|
||||
*
|
||||
* @since 3.3.1
|
||||
* @author Remy Perona
|
||||
*/
|
||||
class NGG_Subscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.3.1
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
if ( ! class_exists( 'C_NextGEN_Bootstrap' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return [
|
||||
'run_ngg_resource_manager' => 'deactivate_resource_manager',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate NGG Resource Manager to prevent conflict with WP Rocket output buffering
|
||||
*
|
||||
* @since 3.3.1
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deactivate_resource_manager() {
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins;
|
||||
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* Compatibility class for SyntaxHighlighter plugin
|
||||
*
|
||||
* @since 3.3.1
|
||||
* @author Remy Perona
|
||||
*/
|
||||
class SyntaxHighlighter_Subscriber implements Subscriber_Interface {
|
||||
/**
|
||||
* Return an array of events that this subscriber wants to listen to.
|
||||
*
|
||||
* @since 3.3.1
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
if ( ! class_exists( 'SyntaxHighlighter' ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'rocket_exclude_defer_js' => 'exclude_defer_js_syntaxhighlighter_scripts',
|
||||
'rocket_exclude_js' => 'exclude_minify_js_syntaxhighlighter_scripts',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds SyntaxHighlighter scripts to defer JS exclusion
|
||||
*
|
||||
* @since 3.3.1
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param array $excluded_scripts Array of scripts to exclude.
|
||||
* @return array
|
||||
*/
|
||||
public function exclude_defer_js_syntaxhighlighter_scripts( $excluded_scripts ) {
|
||||
return array_merge(
|
||||
$excluded_scripts,
|
||||
[
|
||||
'syntaxhighlighter/syntaxhighlighter3/scripts/(.*).js',
|
||||
'syntaxhighlighter/syntaxhighlighter2/scripts/(.*).js',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds SyntaxHighlighter scripts to minify/combine JS exclusion
|
||||
*
|
||||
* @since 3.3.1
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param array $excluded_scripts Array of scripts to exclude.
|
||||
* @return array
|
||||
*/
|
||||
public function exclude_minify_js_syntaxhighlighter_scripts( $excluded_scripts ) {
|
||||
return array_merge(
|
||||
$excluded_scripts,
|
||||
[
|
||||
rocket_clean_exclude_file( plugins_url( 'syntaxhighlighter/syntaxhighlighter3/scripts/(.*).js' ) ),
|
||||
rocket_clean_exclude_file( plugins_url( 'syntaxhighlighter/syntaxhighlighter2/scripts/(.*).js' ) ),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins\Ecommerce;
|
||||
|
||||
use WP_Rocket\Event_Management\Event_Manager;
|
||||
use WP_Rocket\Event_Management\Event_Manager_Aware_Subscriber_Interface;
|
||||
|
||||
/**
|
||||
* BigCommerce compatibility subscriber
|
||||
*
|
||||
* @since 3.3.7
|
||||
* @author Remy Perona
|
||||
*/
|
||||
class BigCommerce_Subscriber implements Event_Manager_Aware_Subscriber_Interface {
|
||||
use \WP_Rocket\Traits\Config_Updater;
|
||||
|
||||
/**
|
||||
* The WordPress Event Manager
|
||||
*
|
||||
* @var Event_Manager;
|
||||
*/
|
||||
protected $event_manager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param Event_Manager $event_manager The WordPress Event Manager.
|
||||
*/
|
||||
public function set_event_manager( Event_Manager $event_manager ) {
|
||||
$this->event_manager = $event_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
$events = [
|
||||
'activate_bigcommerce/bigcommerce.php' => [ 'activate_bigcommerce', 11 ],
|
||||
'deactivate_bigcommerce/bigcommerce.php' => [ 'deactivate_bigcommerce', 11 ],
|
||||
];
|
||||
|
||||
if ( function_exists( 'bigcommerce_init' ) ) {
|
||||
$events['update_option_bigcommerce_login_page_id'] = [ 'after_update_single_option', 10, 2 ];
|
||||
$events['update_option_bigcommerce_account_page_id'] = [ 'after_update_single_option', 10, 2 ];
|
||||
$events['update_option_bigcommerce_address_page_id'] = [ 'after_update_single_option', 10, 2 ];
|
||||
$events['update_option_bigcommerce_orders_page_id'] = [ 'after_update_single_option', 10, 2 ];
|
||||
$events['update_option_bigcommerce_cart_page_id'] = [ 'after_update_single_option', 10, 2 ];
|
||||
$events['update_option_bigcommerce_checkout_page_id'] = [ 'after_update_single_option', 10, 2 ];
|
||||
|
||||
$events['shutdown'] = 'maybe_update_config';
|
||||
$events['transition_post_status'] = [ 'maybe_exclude_page', 10, 3 ];
|
||||
$events['rocket_cache_reject_uri'] = [
|
||||
[ 'exclude_pages' ],
|
||||
];
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add exclusions when activating the BigCommerce plugin
|
||||
*
|
||||
* @since 3.3.7
|
||||
* @author Rémy Perona
|
||||
*/
|
||||
public function activate_bigcommerce() {
|
||||
$this->event_manager->add_callback( 'rocket_cache_reject_uri', [ $this, 'exclude_pages' ] );
|
||||
|
||||
// Update .htaccess file rules.
|
||||
flush_rocket_htaccess();
|
||||
|
||||
// Regenerate the config file.
|
||||
rocket_generate_config_file();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove exclusions when deactivating the BigCommerce plugin
|
||||
*
|
||||
* @since 3.3.7
|
||||
* @author Rémy Perona
|
||||
*/
|
||||
public function deactivate_woocommerce() {
|
||||
$this->event_manager->remove_callback( 'rocket_cache_reject_uri', [ $this, 'exclude_pages' ] );
|
||||
|
||||
// Update .htaccess file rules.
|
||||
flush_rocket_htaccess();
|
||||
|
||||
// Regenerate the config file.
|
||||
rocket_generate_config_file();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe regenerate the htaccess & config file if a BigCommerce page is published
|
||||
*
|
||||
* @since 3.3.7
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param string $new_status New post status.
|
||||
* @param string $old_status Old post status.
|
||||
* @param WP_Post $post Post object.
|
||||
* @return bool
|
||||
*/
|
||||
public function maybe_exclude_page( $new_status, $old_status, $post ) {
|
||||
if ( 'publish' === $old_status || 'publish' !== $new_status ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( get_option( 'bigcommerce_login_page_id' ) !== $post->ID && get_option( 'bigcommerce_account_page_id' ) !== $post->ID && get_option( 'bigcommerce_address_page_id' ) !== $post->ID && get_option( 'bigcommerce_orders_page_id' ) !== $post->ID && get_option( 'bigcommerce_cart_page_id' ) !== $post->ID && get_option( 'bigcommerce_checkout_page_id' ) !== $post->ID ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update .htaccess file rules.
|
||||
flush_rocket_htaccess();
|
||||
|
||||
// Regenerate the config file.
|
||||
rocket_generate_config_file();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude BigCommerce login, cart, checkout, account, address and orders pages from caching
|
||||
*
|
||||
* @since 3.3.7
|
||||
*
|
||||
* @param array $urls An array of excluded pages.
|
||||
* @return array
|
||||
*/
|
||||
public function exclude_pages( $urls ) {
|
||||
$checkout_urls = $this->exclude_page( get_option( 'bigcommerce_checkout_page_id' ) );
|
||||
$cart_urls = $this->exclude_page( get_option( 'bigcommerce_cart_page_id' ) );
|
||||
$account_urls = $this->exclude_page( get_option( 'bigcommerce_account_page_id' ) );
|
||||
$login_urls = $this->exclude_page( get_option( 'bigcommerce_login_page_id' ) );
|
||||
$address_urls = $this->exclude_page( get_option( 'bigcommerce_address_page_id' ) );
|
||||
$orders_urls = $this->exclude_page( get_option( 'bigcommerce_orders_page_id' ) );
|
||||
|
||||
return array_merge( $urls, $checkout_urls, $cart_urls, $account_urls, $login_urls, $address_urls, $orders_urls );
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes BigCommerce checkout page from cache
|
||||
*
|
||||
* @since 3.3.7
|
||||
* @author Remy Perona
|
||||
*
|
||||
* @param int $page_id ID of page to exclude.
|
||||
* @param string $post_type Post type of the page.
|
||||
* @param string $pattern Pattern to use for the exclusion.
|
||||
* @return array
|
||||
*/
|
||||
private function exclude_page( $page_id, $post_type = 'page', $pattern = '' ) {
|
||||
$urls = [];
|
||||
|
||||
if ( ! $page_id ) {
|
||||
return $urls;
|
||||
}
|
||||
|
||||
if ( $page_id <= 0 || (int) get_option( 'page_on_front' ) === $page_id ) {
|
||||
return $urls;
|
||||
}
|
||||
|
||||
if ( 'publish' !== get_post_status( $page_id ) ) {
|
||||
return $urls;
|
||||
}
|
||||
|
||||
$urls = get_rocket_i18n_translated_post_urls( $page_id, $post_type, $pattern );
|
||||
|
||||
return $urls;
|
||||
}
|
||||
}
|
@@ -0,0 +1,395 @@
|
||||
<?php
|
||||
namespace WP_Rocket\Subscriber\Third_Party\Plugins\Security;
|
||||
|
||||
use WP_Rocket\Admin\Options_Data as Options;
|
||||
use WP_Rocket\Event_Management\Subscriber_Interface;
|
||||
use WP_Rocket\Logger\Logger;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Sucuri Security compatibility.
|
||||
* %s is here for the other query args.
|
||||
*
|
||||
* @since 3.2
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class Sucuri_Subscriber implements Subscriber_Interface {
|
||||
|
||||
/**
|
||||
* URL of the API.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
const API_URL = 'https://waf.sucuri.net/api?v2&%s';
|
||||
|
||||
/**
|
||||
* Instance of the Option_Data class.
|
||||
*
|
||||
* @var Options
|
||||
* @since 3.2
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param Options $options Instance of the Option_Data class.
|
||||
*/
|
||||
public function __construct( Options $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'after_rocket_clean_domain' => 'maybe_clean_firewall_cache',
|
||||
'after_rocket_clean_post' => 'maybe_clean_firewall_cache',
|
||||
'after_rocket_clean_term' => 'maybe_clean_firewall_cache',
|
||||
'after_rocket_clean_user' => 'maybe_clean_firewall_cache',
|
||||
'after_rocket_clean_home' => 'maybe_clean_firewall_cache',
|
||||
'after_rocket_clean_files' => 'maybe_clean_firewall_cache',
|
||||
'admin_post_rocket_purge_sucuri' => 'do_admin_post_rocket_purge_sucuri',
|
||||
'admin_notices' => 'maybe_print_notice',
|
||||
];
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOK CALLBACKS ========================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Clear Sucuri firewall cache.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function maybe_clean_firewall_cache() {
|
||||
static $done = false;
|
||||
|
||||
if ( $done ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$done = true;
|
||||
|
||||
if ( ! $this->options->get( 'sucury_waf_cache_sync', 0 ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->clean_firewall_cache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback to empty Sucury cache.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function do_admin_post_rocket_purge_sucuri() {
|
||||
if ( empty( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'rocket_purge_sucuri' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
wp_nonce_ays( '' );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'rocket_purge_sucuri_cache' ) ) {
|
||||
wp_nonce_ays( '' );
|
||||
}
|
||||
|
||||
$purged = $this->clean_firewall_cache();
|
||||
|
||||
if ( is_wp_error( $purged ) ) {
|
||||
$purged_result = [
|
||||
'result' => 'error',
|
||||
/* translators: %s is the error message returned by the API. */
|
||||
'message' => sprintf( __( 'Sucuri cache purge error: %s', 'rocket' ), $purged->get_error_message() ),
|
||||
];
|
||||
} else {
|
||||
$purged_result = [
|
||||
'result' => 'success',
|
||||
'message' => __( 'The Sucuri cache is being cleared. Note that it may take up to two minutes for it to be fully flushed.', 'rocket' ),
|
||||
];
|
||||
}
|
||||
|
||||
set_transient( get_current_user_id() . '_sucuri_purge_result', $purged_result );
|
||||
|
||||
wp_safe_redirect( esc_url_raw( wp_get_referer() ) );
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an admin notice if the cache failed to be cleared.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
public function maybe_print_notice() {
|
||||
if ( ! current_user_can( 'rocket_purge_sucuri_cache' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
|
||||
$notice = get_transient( $user_id . '_sucuri_purge_result' );
|
||||
|
||||
if ( ! $notice ) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete_transient( $user_id . '_sucuri_purge_result' );
|
||||
|
||||
rocket_notice_html(
|
||||
[
|
||||
'status' => $notice['result'],
|
||||
'message' => $notice['message'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** TOOLS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Tell if a API key is well formatted.
|
||||
*
|
||||
* @since 3.2.3
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $api_key An API kay.
|
||||
* @return array|bool An array with the keys 'k' and 's' (required by the API) if valid. False otherwise.
|
||||
*/
|
||||
public static function is_api_key_valid( $api_key ) {
|
||||
if ( '' !== $api_key && preg_match( '@^(?<k>[a-z0-9]{32})/(?<s>[a-z0-9]{32})$@', $api_key, $matches ) ) {
|
||||
return $matches;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Sucuri firewall cache.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return bool|object True on success. A WP_Error object on failure.
|
||||
*/
|
||||
private function clean_firewall_cache() {
|
||||
$api_key = $this->get_api_key();
|
||||
|
||||
if ( is_wp_error( $api_key ) ) {
|
||||
return $api_key;
|
||||
}
|
||||
|
||||
$response = $this->request_api(
|
||||
[
|
||||
'a' => 'clear_cache',
|
||||
'k' => $api_key['k'],
|
||||
's' => $api_key['s'],
|
||||
]
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
Logger::info(
|
||||
'Sucuri firewall cache cleared.',
|
||||
[
|
||||
'sucuri firewall cache',
|
||||
]
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API key.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return array|object An array with the keys 'k' and 's', required by the API. A WP_Error object if no key or invalid key.
|
||||
*/
|
||||
private function get_api_key() {
|
||||
$api_key = trim( $this->options->get( 'sucury_waf_api_key', '' ) );
|
||||
|
||||
if ( ! $api_key ) {
|
||||
Logger::error(
|
||||
'API key was not found.',
|
||||
[
|
||||
'sucuri firewall cache',
|
||||
]
|
||||
);
|
||||
return new \WP_Error( 'no_sucuri_api_key', __( 'Sucuri firewall API key was not found.', 'rocket' ) );
|
||||
}
|
||||
|
||||
$matches = self::is_api_key_valid( $api_key );
|
||||
|
||||
if ( ! $matches ) {
|
||||
Logger::error(
|
||||
'API key is invalid.',
|
||||
[
|
||||
'sucuri firewall cache',
|
||||
]
|
||||
);
|
||||
return new \WP_Error( 'invalid_sucuri_api_key', __( 'Sucuri firewall API key is invalid.', 'rocket' ) );
|
||||
}
|
||||
|
||||
return [
|
||||
'k' => $matches['k'],
|
||||
's' => $matches['s'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Request against the API.
|
||||
*
|
||||
* @since 3.2
|
||||
* @access private
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param array $params Parameters to send.
|
||||
* @return array|object The response data on success. A WP_Error object on failure.
|
||||
*/
|
||||
private function request_api( $params = [] ) {
|
||||
$params['time'] = time();
|
||||
$params = $this->build_query( $params );
|
||||
$url = sprintf( static::API_URL, $params );
|
||||
|
||||
try {
|
||||
/**
|
||||
* Filters the arguments for the Sucuri API request
|
||||
*
|
||||
* @since 3.3.4
|
||||
* @author Soponar Cristina
|
||||
*
|
||||
* @param array $args Arguments for the request.
|
||||
*/
|
||||
$args = apply_filters(
|
||||
'rocket_sucuri_api_request_args',
|
||||
[
|
||||
'timeout' => 5,
|
||||
'redirection' => 5,
|
||||
'httpversion' => '1.1',
|
||||
'blocking' => true,
|
||||
/** This filter is documented in wp-includes/class-wp-http-streams.php */
|
||||
'sslverify' => apply_filters( 'https_ssl_verify', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
|
||||
]
|
||||
);
|
||||
|
||||
$response = wp_remote_get( $url, $args );
|
||||
} catch ( \Exception $e ) {
|
||||
Logger::error(
|
||||
'Error when contacting the API.',
|
||||
[
|
||||
'sucuri firewall cache',
|
||||
'url' => $url,
|
||||
'response' => $e->getMessage(),
|
||||
]
|
||||
);
|
||||
return new \WP_Error( 'error_sucuri_api', __( 'Error when contacting Sucuri firewall API.', 'rocket' ) );
|
||||
}
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
Logger::error(
|
||||
'Error when contacting the API.',
|
||||
[
|
||||
'sucuri firewall cache',
|
||||
'url' => $url,
|
||||
'response' => $response->get_error_message(),
|
||||
]
|
||||
);
|
||||
/* translators: %s is an error message. */
|
||||
return new \WP_Error( 'wp_error_sucuri_api', sprintf( __( 'Error when contacting Sucuri firewall API. Error message was: %s', 'rocket' ), $response->get_error_message() ) );
|
||||
}
|
||||
|
||||
$contents = wp_remote_retrieve_body( $response );
|
||||
|
||||
if ( ! $contents ) {
|
||||
Logger::error(
|
||||
'Could not get a response from the API.',
|
||||
[
|
||||
'sucuri firewall cache',
|
||||
'url' => $url,
|
||||
'response' => $response,
|
||||
]
|
||||
);
|
||||
return new \WP_Error( 'sucuri_api_no_response', __( 'Could not get a response from the Sucuri firewall API.', 'rocket' ) );
|
||||
}
|
||||
|
||||
$data = @json_decode( $contents, true );
|
||||
|
||||
if ( ! $data || ! is_array( $data ) ) {
|
||||
Logger::error(
|
||||
'Invalid response from the API.',
|
||||
[
|
||||
'sucuri firewall cache',
|
||||
'url' => $url,
|
||||
'response_body' => $contents,
|
||||
]
|
||||
);
|
||||
return new \WP_Error( 'sucuri_api_invalid_response', __( 'Got an invalid response from the Sucuri firewall API.', 'rocket' ) );
|
||||
}
|
||||
|
||||
if ( empty( $data['status'] ) ) {
|
||||
Logger::error(
|
||||
'The action failed.',
|
||||
[
|
||||
'sucuri firewall cache',
|
||||
'url' => $url,
|
||||
'response_data' => $data,
|
||||
]
|
||||
);
|
||||
if ( empty( $data['messages'] ) || ! is_array( $data['messages'] ) ) {
|
||||
return new \WP_Error( 'sucuri_api_error_status', __( 'The Sucuri firewall API returned an unknown error.', 'rocket' ) );
|
||||
}
|
||||
/* translators: %s is an error message. */
|
||||
$message = _n( 'The Sucuri firewall API returned the following error: %s', 'The Sucuri firewall API returned the following errors: %s', count( $data['messages'] ), 'rocket' );
|
||||
$message = sprintf( $message, '<br/>' . implode( '<br/>', $data['messages'] ) );
|
||||
return new \WP_Error( 'sucuri_api_error_status', $message );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* An i18n-firendly alternative to the built-in PHP method `http_build_query()`.
|
||||
*
|
||||
* @param array|object $params An array or object containing properties.
|
||||
* @return string A URL-encoded string.
|
||||
*/
|
||||
private function build_query( $params ) {
|
||||
if ( ! $params ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$params = (array) $params;
|
||||
|
||||
foreach ( $params as $param => $value ) {
|
||||
$params[ $param ] = $param . '=' . rawurlencode( (string) $value );
|
||||
}
|
||||
|
||||
return implode( '&', $params );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user