add wp-rocket

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

View File

@@ -0,0 +1,89 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'FlywheelNginxCompat' ) ) {
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/flywheel.php';
}
if ( defined( 'DB_HOST' ) && strpos( DB_HOST, '.wpserveur.net' ) !== false ) {
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/wp-serveur.php';
}
if ( rocket_is_plugin_active( 'sg-cachepress/sg-cachepress.php' ) ) {
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/siteground.php';
}
if ( class_exists( 'WPaaS\Plugin' ) ) {
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/godaddy.php';
}
if ( isset( $_SERVER['KINSTA_CACHE_ZONE'] ) ) {
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/kinsta.php';
}
if ( defined( 'PL_INSTANCE_REF' ) && class_exists( '\Presslabs\Cache\CacheHandler' ) && file_exists( WP_CONTENT_DIR . '/advanced-cache.php' ) ) {
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/presslabs.php';
}
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/pagely.php';
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/nginx.php';
require WP_ROCKET_3RD_PARTY_PATH . 'hosting/pressidium.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/geotargetingwp.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/slider/layerslider.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/slider/meta-slider.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/slider/soliloquy.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/i18n/wpml.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/i18n/polylang.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/aelia-currencyswitcher.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/aelia-prices-by-country.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/aelia-tax-display-by-country.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/woocommerce-multilingual.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/woocommerce-currency-converter-widget.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/edd-software-licencing.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/easy-digital-downloads.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/ithemes-exchange.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/jigoshop.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/wpshop.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/give.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/age-verify.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/autoptimize.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/envira-gallery.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/cookies/cookie-notice.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/cookies/uk-cookie-consent.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/cookies/eu-cookie-law.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/cookies/weepie-cookie-allow.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/cookies/gdpr.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/rating/kk-star-ratings.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/rating/wp-postratings.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/wp-print.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/buddypress.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/disqus.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/custom-login.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/mobile/wp-appkit.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/seopress.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/rank-math-seo.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/yoast-seo.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/the-seo-framework.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/all-in-one-seo-pack.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/premium-seo-pack.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/wp-rest-api.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/page-builder/thrive-visual-editor.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/page-builder/visual-composer.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/security/secupress.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/security/sf-move-login.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/security/wps-hide-login.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/varnish-http-purge.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/thrive-leads.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/mailchimp.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/advanced-custom-fields.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/wp-offload-s3.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/wp-offload-s3-assets.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/s2member.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/sumome.php';
require WP_ROCKET_3RD_PARTY_PATH . 'plugins/nginx-helper.php';
require WP_ROCKET_3RD_PARTY_PATH . 'themes/avada.php';
require WP_ROCKET_3RD_PARTY_PATH . 'themes/studiopress.php';
require WP_ROCKET_3RD_PARTY_PATH . 'themes/uncode.php';

View File

@@ -0,0 +1,80 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Changes the text on the Varnish one-click block.
*
* @since 3.0
* @author Remy Perona
*
* @param array $settings Field settings data.
*
* @return array modified field settings data.
*/
function rocket_flywheel_varnish_field( $settings ) {
$settings['varnish_auto_purge']['title'] = sprintf(
// Translators: %s = Hosting name.
__( 'Your site is hosted on %s, we have enabled Varnish auto-purge for compatibility.', 'rocket' ),
'Flywheel'
);
return $settings;
}
add_filter( 'rocket_varnish_field_settings', 'rocket_flywheel_varnish_field' );
add_filter( 'rocket_display_input_varnish_auto_purge', '__return_false' );
/**
* Allow to purge Varnish on Flywheel websites
*
* @since 2.6.8
*/
add_filter( 'do_rocket_varnish_http_purge', '__return_true' );
add_filter( 'do_rocket_generate_caching_files', '__return_false' );
// Prevent mandatory cookies on hosting with server cache.
add_filter( 'rocket_cache_mandatory_cookies', '__return_empty_array', PHP_INT_MAX );
/**
* Set up the right Varnish IP for Flywheel
*
* @since 2.6.8
* @param array $varnish_ip Varnish IP.
*/
function rocket_varnish_ip_on_flywheel( $varnish_ip ) {
$varnish_ip[] = '127.0.0.1';
return $varnish_ip;
}
add_filter( 'rocket_varnish_ip', 'rocket_varnish_ip_on_flywheel' );
/**
* Remove WP Rocket functions on WP core action hooks to prevent triggering a double cache clear.
*
* @since 3.3.1
* @author Remy Perona
*
* @return void
*/
function rocket_flywheel_remove_partial_purge_hooks() {
// WP core action hooks rocket_clean_post() gets hooked into.
$clean_post_hooks = [
// Disables the refreshing of partial cache when content is edited.
'wp_trash_post',
'delete_post',
'clean_post_cache',
'wp_update_comment_count',
];
// Remove rocket_clean_post() from core action hooks.
array_map(
function( $hook ) {
remove_action( $hook, 'rocket_clean_post' );
},
$clean_post_hooks
);
remove_filter( 'rocket_clean_files', 'rocket_clean_files_users' );
}
add_action( 'wp_rocket_loaded', 'rocket_flywheel_remove_partial_purge_hooks' );

View File

@@ -0,0 +1,130 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Changes the text on the Varnish one-click block.
*
* @since 3.0
* @author Remy Perona
*
* @param array $settings Field settings data.
*
* @return array modified field settings data.
*/
function rocket_godaddy_varnish_field( $settings ) {
$settings['varnish_auto_purge']['title'] = sprintf(
// Translators: %s = Hosting name.
__( 'Your site is hosted on %s, we have enabled Varnish auto-purge for compatibility.', 'rocket' ),
'GoDaddy'
);
return $settings;
}
add_filter( 'rocket_varnish_field_settings', 'rocket_godaddy_varnish_field' );
add_filter( 'rocket_display_input_varnish_auto_purge', '__return_false' );
add_filter( 'set_rocket_wp_cache_define', '__return_true' );
// Prevent mandatory cookies on hosting with server cache.
add_filter( 'rocket_cache_mandatory_cookies', '__return_empty_array', PHP_INT_MAX );
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false' );
/**
* Remove expiration on HTML to prevent issue with Varnish cache.
*
* @since 2.9.5
* @author Remy Perona
*
* @param string $rules htaccess rules.
* @return string Updated htaccess rules.
*/
function rocket_remove_html_expire_goddady( $rules ) {
$rules = preg_replace( '@\s*#\s*Your document html@', '', $rules );
$rules = preg_replace( '@\s*ExpiresByType text/html\s*"access plus \d+ (seconds|minutes|hour|week|month|year)"@', '', $rules );
return $rules;
}
add_filter( 'rocket_htaccess_mod_expires', 'rocket_remove_html_expire_goddady', 5 );
/**
* Call the Varnish server to purge the cache with GoDaddy.
*
* @since 2.9.5
*
* @return void
*/
function rocket_clean_domain_godaddy() {
rocket_godaddy_request( 'BAN' );
}
add_action( 'before_rocket_clean_domain', 'rocket_clean_domain_godaddy' );
/**
* Call the Varnish server to purge a specific URL with GoDaddy.
*
* @since 2.9.5
*
* @param string $url URL to purge.
* @return void
*/
function rocket_clean_file_godaddy( $url ) {
rocket_godaddy_request( 'PURGE', home_url( $url ) );
}
add_action( 'before_rocket_clean_file', 'rocket_clean_file_godaddy' );
/**
* Call the Varnish server to purge the home with GoDaddy.
*
* @since 2.9.5
*
* @param string $root root URL.
* @param string $lang language code.
* @return void
*/
function rocket_clean_home_godaddy( $root, $lang ) {
$home_url = trailingslashit( get_rocket_i18n_home_url( $lang ) );
$home_pagination_url = $home_url . trailingslashit( $GLOBALS['wp_rewrite']->pagination_base );
rocket_godaddy_request( 'PURGE', $home_url );
rocket_godaddy_request( 'PURGE', $home_pagination_url );
}
add_action( 'before_rocket_clean_home', 'rocket_clean_home_godaddy', 10, 2 );
/**
* Perform the call to the Varnish server to purge
*
* @since 2.9.5
* @source WPaaS\Cache
*
* @param string $method can be BAN or PURGE.
* @param string $url URL to purge.
* @return void
*/
function rocket_godaddy_request( $method, $url = null ) {
if ( ! method_exists( 'WPass\Plugin', 'vip' ) ) {
return;
}
if ( empty( $url ) ) {
$url = home_url();
}
$host = rocket_extract_url_component( $url, PHP_URL_HOST );
$url = set_url_scheme( str_replace( $host, WPaas\Plugin::vip(), $url ), 'http' );
wp_cache_flush();
// This forces the APC cache to flush across the server.
update_option( 'gd_system_last_cache_flush', time() );
wp_remote_request(
esc_url_raw( $url ),
[
'method' => $method,
'blocking' => false,
'headers' => [
'Host' => $host,
],
]
);
}

View File

@@ -0,0 +1,166 @@
<?php
defined( 'ABSPATH' ) || exit;
add_filter( 'do_rocket_generate_caching_files', '__return_false', PHP_INT_MAX );
add_filter( 'rocket_display_varnish_options_tab', '__return_false' );
// Prevent mandatory cookies on hosting with server cache.
add_filter( 'rocket_cache_mandatory_cookies', '__return_empty_array', PHP_INT_MAX );
global $kinsta_cache;
if ( isset( $kinsta_cache ) && class_exists( '\\Kinsta\\CDN_Enabler' ) ) {
/**
* Clear Kinsta cache when clearing WP Rocket cache
*
* @since 3.0
* @author Remy Perona
*
* @return void
*/
function rocket_clean_kinsta_cache() {
global $kinsta_cache;
if ( ! empty( $kinsta_cache->kinsta_cache_purge ) ) {
$kinsta_cache->kinsta_cache_purge->purge_complete_caches();
}
}
add_action( 'after_rocket_clean_domain', 'rocket_clean_kinsta_cache' );
/**
* Partially clear Kinsta cache when partially clearing WP Rocket cache
*
* @since 3.0
* @author Remy Perona
*
* @param object $post Post object.
* @return void
*/
function rocket_clean_kinsta_post_cache( $post ) {
global $kinsta_cache;
$kinsta_cache->kinsta_cache_purge->initiate_purge( $post->ID, 'post' );
}
add_action( 'after_rocket_clean_post', 'rocket_clean_kinsta_post_cache' );
/**
* Clears Kinsta cache for the homepage URL when using "Purge this URL" from the admin bar on the front end
*
* @since 3.0.4
* @author Remy Perona
*
* @param string $root WP Rocket root cache path.
* @param string $lang Current language.
* @return void
*/
function rocket_clean_kinsta_cache_home( $root = '', $lang = '' ) {
$url = get_rocket_i18n_home_url( $lang );
$url = trailingslashit( $url ) . 'kinsta-clear-cache/';
wp_remote_get(
$url,
[
'blocking' => false,
'timeout' => 0.01,
]
);
}
add_action( 'after_rocket_clean_home', 'rocket_clean_kinsta_cache_home', 10, 2 );
/**
* Clears Kinsta cache for a specific URL when using "Purge this URL" from the admin bar on the front end
*
* @since 3.0.4
* @author Remy Perona
*
* @param string $url URL to purge.
* @return void
*/
function rocket_clean_kinsta_cache_url( $url ) {
$url = trailingslashit( $url ) . 'kinsta-clear-cache/';
wp_remote_get(
$url,
[
'blocking' => false,
'timeout' => 0.01,
]
);
}
add_action( 'after_rocket_clean_file', 'rocket_clean_kinsta_cache_url' );
/**
* Remove WP Rocket functions on WP core action hooks to prevent triggering a double cache clear.
*
* @since 3.0
* @author Remy Perona
*
* @return void
*/
function rocket_remove_partial_purge_hooks() {
// WP core action hooks rocket_clean_post() gets hooked into.
$clean_post_hooks = [
// Disables the refreshing of partial cache when content is edited.
'wp_trash_post',
'delete_post',
'clean_post_cache',
'wp_update_comment_count',
];
// Remove rocket_clean_post() from core action hooks.
array_map(
function( $hook ) {
remove_action( $hook, 'rocket_clean_post' );
},
$clean_post_hooks
);
remove_filter( 'rocket_clean_files', 'rocket_clean_files_users' );
}
add_action( 'wp_rocket_loaded', 'rocket_remove_partial_purge_hooks' );
if ( \Kinsta\CDN_Enabler::cdn_is_enabled() ) {
/**
* Add Kinsta CDN to WP Rocket CDN hosts list if enabled
*
* @since 3.0
* @author Remy Perona
*
* @param Array $hosts Array of CDN hosts.
* @return Array Updated array of CDN hosts
*/
function rocket_add_kinsta_cdn_cname( $hosts ) {
if ( ! isset( $_SERVER['KINSTA_CDN_DOMAIN'] ) ) {
return $hosts;
}
$hosts[] = sanitize_text_field( wp_unslash( $_SERVER['KINSTA_CDN_DOMAIN'] ) );
return $hosts;
}
add_filter( 'rocket_cdn_cnames', 'rocket_add_kinsta_cdn_cname', 1 );
}
} else {
add_action(
'admin_notices',
function() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$screen = get_current_screen();
if ( 'settings_page_wprocket' !== $screen->id ) {
return;
}
rocket_notice_html(
[
'status' => 'error',
'dismissible' => '',
// translators: %1$s = opening link tag, %2$s = closing link tag.
'message' => sprintf( __( 'Your installation seems to be missing core Kinsta files managing Cache clearing and CDN, which will prevent your Kinsta installation and WP Rocket from working correctly. Please get in touch with Kinsta support through your %1$sMyKinsta%2$s account to resolve this issue.', 'rocket' ), '<a href="https://my.kinsta.com/login/" target="_blank">', '</a>' ),
]
);
}
);
}

View File

@@ -0,0 +1,24 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with an usual NGINX configuration which include:
* try_files $uri $uri/ /index.php?q=$uri&$args
*
* @since 2.3.9
*
* @param array $query_strings Array of query strings to cache.
*
* @return array Updated array of query strings.
*/
function rocket_better_nginx_compatibility( $query_strings ) {
global $is_nginx;
if ( $is_nginx ) {
$query_strings[] = 'q';
}
return $query_strings;
}
add_filter( 'rocket_cache_query_strings', 'rocket_better_nginx_compatibility' );

View File

@@ -0,0 +1,31 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Clear WP Rocket cache after purged the Varnish cache via Pagely hosting.
*
* @since 2.5.7
*
* @return void
*/
function rocket_clear_cache_after_pagely() {
// Clear all caching files.
rocket_clean_domain();
}
add_action( 'pagely_cache_purge_after', 'rocket_clear_cache_after_pagely' );
/**
* Call the cache server to purge the cache with Pagely hosting.
*
* @since 2.5.7
*
* @return void
*/
function rocket_clean_pagely() {
if ( class_exists( 'PagelyCachePurge' ) ) {
$purger = new PagelyCachePurge();
$purger->purgeAll();
}
}
add_action( 'after_rocket_clean_domain', 'rocket_clean_pagely' );

View File

@@ -0,0 +1,61 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'WP_NINUKIS_WP_NAME' ) ) {
/**
* Changes the text on the Varnish one-click block.
*
* @since 3.0
* @author Remy Perona
*
* @param array $settings Field settings data.
*
* @return array modified field settings data.
*/
function rocket_pressidium_varnish_field( $settings ) {
// Translators: %s = Hosting name.
$settings['varnish_auto_purge']['title'] = sprintf( __( 'Your site is hosted on %s, we have enabled Varnish auto-purge for compatibility.', 'rocket' ), 'Pressidium' );
return $settings;
}
add_filter( 'rocket_varnish_field_settings', 'rocket_pressidium_varnish_field' );
add_filter( 'rocket_display_input_varnish_auto_purge', '__return_false' );
// Prevent mandatory cookies on hosting with server cache.
add_filter( 'rocket_cache_mandatory_cookies', '__return_empty_array', PHP_INT_MAX );
/**
* Clear WP Rocket cache after purged the Varnish cache via Pressidium Hosting
*
* @since 2.5.11
*
* @return void
*/
function rocket_clear_cache_after_pressidium() {
if ( isset( $_POST['purge-all'] ) && current_user_can( 'manage_options' ) && check_admin_referer( WP_NINUKIS_WP_NAME . '-caching' ) ) {
// Clear all caching files.
rocket_clean_domain();
// Preload cache.
run_rocket_bot();
run_rocket_sitemap_preload();
}
}
add_action( 'admin_init', 'rocket_clear_cache_after_pressidium' );
}
if ( class_exists( 'Ninukis_Plugin' ) ) {
/**
* Call the cache server to purge the cache with Pressidium hosting.
*
* @since 2.6
*
* @return void
*/
function rocket_clean_pressidium() {
$plugin = Ninukis_Plugin::get_instance();
$plugin->purgeAllCaches();
}
add_action( 'after_rocket_clean_domain', 'rocket_clean_pressidium' );
}

View File

@@ -0,0 +1,98 @@
<?php
defined( 'ABSPATH' ) || exit;
require_once WP_CONTENT_DIR . '/advanced-cache.php';
add_action( 'pl_pre_cache_refresh', 'rocket_clean_files', 0 );
add_filter( 'rocket_display_varnish_options_tab', '__return_false' );
add_filter( 'do_rocket_generate_caching_files', '__return_false', PHP_INT_MAX );
add_filter( 'rocket_cache_mandatory_cookies', '__return_empty_array', PHP_INT_MAX );
add_action( 'after_rocket_clean_home', 'rocket_pl_clean_home', 10, 2 );
add_action( 'after_rocket_clean_file', 'rocket_pl_clean_post', 2 );
add_action( 'pl_pre_url_button_cache_refresh', 'rocket_clean_files' );
add_action( 'wp_rocket_loaded', 'rocket_remove_partial_purge_hooks' );
/**
* We clear the cache only on the post, homepage and listings when creating/updating/deleting posts.
*
* @since 3.3
*
* @param object $post The Post object itself for which the action occured.
* @param array $permalink A list of permalinks to be flushed from cache.
*
* @return void
*/
function rocket_pl_clean_post( $post = false, $permalink = false ) {
if ( ! $post || ! $permalink ) {
return;
}
$cache_handler = new \Presslabs\Cache\CacheHandler();
$cache_handler->invalidate_url( $permalink[0], true );
$cache_handler->invalidate_url( home_url( '/' ), true );
$cache_handler->purge_cache( 'listing' );
}
/**
* We clear the cache for the homepage URL when using "Purge this URL" from the admin bar on the front end.
*
* @since 3.3
*
* @param string $root WP Rocket root cache path.
* @param string $lang Current language.
*
* @return void
*/
function rocket_pl_clean_home( $root = false, $lang = false ) {
if ( ! $post || ! $permalink ) {
return;
}
$cache_handler = new \Presslabs\Cache\CacheHandler();
$cache_handler->invalidate_url( home_url( '/' ), true );
}
/**
* Remove WP Rocket functions on WP core action hooks to prevent triggering a double cache clear.
*
* @since 3.3
*
* @return void
*/
function rocket_remove_partial_purge_hooks() {
// WP core action hooks rocket_clean_post() gets hooked into.
$clean_post_hooks = [
// Disables the refreshing of partial cache when content is edited.
'wp_trash_post',
'delete_post',
'clean_post_cache',
'wp_update_comment_count',
];
// Remove rocket_clean_post() from core action hooks.
array_map(
function( $hook ) {
remove_action( $hook, 'rocket_clean_post' );
},
$clean_post_hooks
);
remove_filter( 'rocket_clean_files', 'rocket_clean_files_users' );
}
if ( ! defined( 'DISABLE_CDN_OFFLOAD' ) && defined( 'PL_CDN_HOST' ) ) {
/**
* If we have CDN enabled we'll add our HOST to the list.
*
* @since 3.3
*
* @param array $hosts Array of CDN hosts.
*
* @return array Updated array of CDN hosts
*/
function rocket_add_pl_cdn( $hosts ) {
$hosts[] = constant( 'PL_CDN_HOST' );
return $hosts;
}
add_filter( 'rocket_cdn_cnames', 'rocket_add_pl_cdn', 1 );
}

View File

@@ -0,0 +1,87 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Returns the current version of the SG Optimizer plugin.
*
* @since 3.2.3.1
* @author Remy Perona
*
* @return string version number.
*/
function rocket_get_sg_optimizer_version() {
static $version;
if ( isset( $version ) ) {
return $version;
}
$sg_optimizer = get_file_data( WP_PLUGIN_DIR . '/sg-cachepress/sg-cachepress.php', [ 'Version' => 'Version' ] );
$version = $sg_optimizer['Version'];
return $version;
}
/**
* Checks if SG Optimizer Supercache is active.
*
* @since 3.2.3.1
* @author Remy Perona
*
* @return bool
*/
function rocket_is_supercacher_active() {
if ( ! version_compare( rocket_get_sg_optimizer_version(), '5.0' ) < 0 ) {
global $sg_cachepress_environment;
return isset( $sg_cachepress_environment ) && $sg_cachepress_environment instanceof SG_CachePress_Environment && $sg_cachepress_environment->cache_is_enabled();
}
return (bool) get_option( 'siteground_optimizer_enable_cache', 0 );
}
/**
* Call the cache server to purge the cache with SuperCacher (SiteGround).
*
* @since 2.3
*
* @return void
*/
function rocket_clean_supercacher() {
if ( ! rocket_is_supercacher_active() ) {
return;
}
if ( ! version_compare( rocket_get_sg_optimizer_version(), '5.0' ) < 0 ) {
SiteGround_Optimizer\Supercacher\Supercacher::purge_cache();
} elseif ( isset( $sg_cachepress_supercacher ) && $sg_cachepress_supercacher instanceof SG_CachePress_Supercacher ) {
$sg_cachepress_supercacher->purge_cache();
}
}
if ( rocket_is_supercacher_active() ) {
add_action( 'admin_post_sg-cachepress-purge', 'rocket_clean_domain', 0 );
add_action( 'after_rocket_clean_domain', 'rocket_clean_supercacher' );
add_filter( 'rocket_display_varnish_options_tab', '__return_false' );
// Prevent mandatory cookies on hosting with server cache.
add_filter( 'rocket_cache_mandatory_cookies', '__return_empty_array', PHP_INT_MAX );
/**
* Force WP Rocket caching on SG Optimizer versions before 4.0.5.
*
* @since 3.0.4
* @author Arun Basil Lal
*
* @link https://github.com/wp-media/wp-rocket/issues/925
*/
if ( version_compare( rocket_get_sg_optimizer_version(), '4.0.5' ) < 0 ) {
add_filter( 'do_rocket_generate_caching_files', '__return_true', 11 );
}
if ( version_compare( rocket_get_sg_optimizer_version(), '5.0' ) < 0 ) {
add_action( 'wp_ajax_sg-cachepress-purge', 'rocket_clean_domain', 0 );
} else {
add_action( 'wp_ajax_admin_bar_purge_cache', 'rocket_clean_domain', 0 );
}
}

View File

@@ -0,0 +1,35 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Allow to purge Varnish on WP Serveur websites.
*
* @since 2.6.11
*/
add_filter( 'do_rocket_varnish_http_purge', '__return_true' );
// Prevent mandatory cookies on hosting with server cache.
add_filter( 'rocket_cache_mandatory_cookies', '__return_empty_array', PHP_INT_MAX );
/**
* Changes the text on the Varnish one-click block.
*
* @since 3.0
* @author Remy Perona
*
* @param array $settings Field settings data.
*
* @return array modified field settings data.
*/
function rocket_wpserveur_varnish_field( $settings ) {
$settings['varnish_auto_purge']['title'] = sprintf(
// Translators: %s = Hosting name.
__( 'Your site is hosted on %s, we have enabled Varnish auto-purge for compatibility.', 'rocket' ),
'WP Serveur'
);
return $settings;
}
add_filter( 'rocket_varnish_field_settings', 'rocket_wpserveur_varnish_field' );
add_filter( 'rocket_display_input_varnish_auto_purge', '__return_false' );

View File

@@ -0,0 +1,18 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Clear cache when ACF options page is updated.
*
* @since 2.10.7
* @author Remy Perona
*
* @param string $post_id ACF options page ID is 'options'.
*/
function rocket_clear_cache_on_acf_options_save( $post_id ) {
if ( 'options' === $post_id ) {
rocket_clean_domain();
}
}
add_action( 'acf/save_post', 'rocket_clear_cache_on_acf_options_save' );

View File

@@ -0,0 +1,59 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Conflict with Age Verify: don't cache pages until the age-verified cookie is set
*
* @since 2.7
*/
if ( class_exists( 'Age_Verify' ) && defined( 'Age_Verify::SLUG' ) ) :
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 18 );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_cache_mandatory_cookie_for_age_verify' );
endif;
/**
* Add age-verified to the list of mandatory cookies
*
* @since 2.7
*
* @param Array $cookies Array of mandatory cookies.
* @return Array Updated array of mandatory cookies
*/
function rocket_add_cache_mandatory_cookie_for_age_verify( $cookies ) {
$cookies[] = 'age-verified';
return $cookies;
}
/**
* Add age-verified cookie when we activate the plugin
*
* @since 2.7
*/
function rocket_activate_age_verify() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 18 );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_cache_mandatory_cookie_for_age_verify' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_age-verify/age-verify.php', 'rocket_activate_age_verify', 11 );
/**
* Remove age-verified cookie when we deactivate the plugin
*
* @since 2.7
*/
function rocket_deactivate_age_verify() {
remove_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_cache_mandatory_cookie_for_age_verify' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_age-verify/age-verify.php', 'rocket_deactivate_age_verify', 11 );

View File

@@ -0,0 +1,175 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'autoptimizeCache' ) ) :
/**
* Improvement with Autoptimize: clear the cache when Autoptimize's cache is cleared
*
* @since 2.7
*/
add_action( 'autoptimize_action_cachepurged', 'rocket_clean_domain' );
endif;
if ( class_exists( 'autoptimizeConfig' ) ) :
/**
* Deactivate WP Rocket lazyload if Autoptimize lazyload is enabled
*
* @since 3.3.4
* @author Remy Perona
*
* @param string $old_value Previous autoptimize option value.
* @param string $value New autoptimize option value.
* @return void
*/
function rocket_maybe_deactivate_lazyload( $old_value, $value ) {
if ( empty( $old_value['autoptimize_imgopt_checkbox_field_3'] ) && ! empty( $value['autoptimize_imgopt_checkbox_field_3'] ) ) {
update_rocket_option( 'lazyload', 0 );
update_rocket_option( 'lazyload_iframes', 0 );
update_rocket_option( 'lazyload_youtube', 0 );
}
}
add_action( 'update_option_autoptimize_imgopt_settings', 'rocket_maybe_deactivate_lazyload', 10, 2 );
/**
* Deactivate WP Rocket CSS Minification if Autoptimize CSS minification is enabled
*
* @since 2.9.5
* @author Remy Perona
*
* @param string $old_value Previous autoptimize option value.
* @param string $value New autoptimize option value.
*/
function rocket_maybe_deactivate_minify_css( $old_value, $value ) {
if ( $value !== $old_value && 'on' === $value ) {
update_rocket_option( 'minify_css', 0 );
update_rocket_option( 'minify_concatenate_css', 0 );
}
}
add_action( 'update_option_autoptimize_css', 'rocket_maybe_deactivate_minify_css', 10, 2 );
/**
* Deactivate WP Rocket JS Minification if Autoptimize JS minification is enabled
*
* @since 2.9.5
* @author Remy Perona
*
* @param string $old_value Previous autoptimize option value.
* @param string $value New autoptimize option value.
*/
function rocket_maybe_deactivate_minify_js( $old_value, $value ) {
if ( $value !== $old_value && 'on' === $value ) {
update_rocket_option( 'minify_js', 0 );
update_rocket_option( 'minify_concatenate_js', 0 );
}
}
add_action( 'update_option_autoptimize_js', 'rocket_maybe_deactivate_minify_js', 10, 2 );
/**
* Deactivate WP Rocket async CSS if Autoptimize async CSS is enabled
*
* @since 2.10
* @author Remy Perona
*
* @param string $old_value Previous autoptimize option value.
* @param string $value New autoptimize option value.
*/
function rocket_maybe_deactivate_css_defer( $old_value, $value ) {
if ( $value !== $old_value && 'on' === $value ) {
update_rocket_option( 'autoptimize_css_defer', 0 );
}
}
add_action( 'update_option_autoptimize_css_defer', 'rocket_maybe_deactivate_css_defer', 10, 2 );
endif;
/**
* Disable WP Rocket minification options when activating Autoptimize and values are already in the database.
*
* @since 2.9.5
* @author Remy Perona
*/
function rocket_activate_autoptimize() {
if ( 'on' === get_option( 'autoptimize_css' ) ) {
update_rocket_option( 'minify_css', 0 );
update_rocket_option( 'minify_concatenate_css', 0 );
}
if ( 'on' === get_option( 'autoptimize_js' ) ) {
update_rocket_option( 'minify_js', 0 );
update_rocket_option( 'minify_concatenate_js', 0 );
}
if ( 'on' === get_option( 'autoptimize_css_defer' ) ) {
update_rocket_option( 'async_css', 0 );
}
$lazyload = get_option( 'autoptimize_imgopt_settings' );
if ( ! empty( $lazyload['autoptimize_imgopt_checkbox_field_3'] ) ) {
update_rocket_option( 'lazyload', 0 );
update_rocket_option( 'lazyload_iframes', 0 );
update_rocket_option( 'lazyload_youtube', 0 );
}
}
add_action( 'activate_autoptimize/autoptimize.php', 'rocket_activate_autoptimize', 11 );
/**
* Disable WP Rocket lazyload fields if Autoptimize lazyload is enabled
*
* @since 3.3.4
* @author Remy Perona
*
* @return bool
*/
function rocket_maybe_disable_lazyload() {
$lazyload = get_option( 'autoptimize_imgopt_settings' );
if ( is_plugin_active( 'autoptimize/autoptimize.php' ) && ! empty( $lazyload['autoptimize_imgopt_checkbox_field_3'] ) ) {
return true;
}
return false;
}
/**
* Disable WP Rocket CSS minification field if Autoptimize CSS minification is enabled
*
* @since 2.9.5
* @author Remy Perona
*
* @return bool|null True if it is active
*/
function rocket_maybe_disable_minify_css() {
if ( is_plugin_active( 'autoptimize/autoptimize.php' ) && 'on' === get_option( 'autoptimize_css' ) ) {
return true;
}
}
/**
* Disable WP Rocket JS minification field if Autoptimize JS minification is enabled
*
* @since 2.9.5
* @author Remy Perona
*
* @return bool|null True if it is active
*/
function rocket_maybe_disable_minify_js() {
if ( is_plugin_active( 'autoptimize/autoptimize.php' ) && 'on' === get_option( 'autoptimize_js' ) ) {
return true;
}
}
/**
* Disable WP Rocket async CSS field if Autoptimize async CSS is enabled
*
* @since 2.10
* @author Remy Perona
*
* @return bool|null True if it is active
*/
function rocket_maybe_disable_async_css() {
if ( is_plugin_active( 'autoptimize/autoptimize.php' ) && 'on' === get_option( 'autoptimize_css_defer' ) ) {
return true;
}
}

View File

@@ -0,0 +1,47 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'BuddyPress' ) ) :
/**
* Conflict with BuddyPress: don't apply LazyLoad on BuddyPress profil pages & group creation
*
* @since 2.8.15 Improve checks for user profile & disable for cover images
* @since 2.6.9
*/
if ( function_exists( 'bp_is_user_profile' ) ) :
/**
* Prevent lazyload if on a BuddyPress profil page
*
* @param Bool $run_filter Do lazyload value.
* @return Bool False if on a BuddyPress profil page, initial value otherwise
*/
function rocket_deactivate_lazyload_on_buddypress_profil_pages( $run_filter ) {
if ( bp_is_user_profile() ) {
return false;
}
return $run_filter;
}
add_filter( 'do_rocket_lazyload', 'rocket_deactivate_lazyload_on_buddypress_profil_pages' );
add_filter( 'do_rocket_lazyload_iframes', 'rocket_deactivate_lazyload_on_buddypress_profil_pages' );
endif;
if ( function_exists( 'bp_is_group_creation_step' ) && function_exists( 'bp_is_group_admin_screen' ) ) :
/**
* Prevent lazyload if on a BuddyPress group creation page
*
* @param Bool $run_filter Do lazyload value.
* @return Bool False if on a BuddyPress profil page, initial value otherwise
*/
function rocket_deactivate_lazyload_on_buddypress_group_pages( $run_filter ) {
if ( bp_is_group_creation_step( 'group-avatar' ) || bp_is_group_creation_step( 'group-cover-image' ) || bp_is_group_admin_screen( 'group-avatar' ) || bp_is_group_admin_screen( 'group-cover-image' ) ) {
return false;
}
return $run_filter;
}
add_filter( 'do_rocket_lazyload', 'rocket_deactivate_lazyload_on_buddypress_group_pages' );
add_filter( 'do_rocket_lazyload_iframes', 'rocket_deactivate_lazyload_on_buddypress_group_pages' );
endif;
endif;

View File

@@ -0,0 +1,81 @@
<?php
/**
* Compatibility with Cookie Notice by dFactory.
*
* @since 2.11.6
* @author Arun Basil Lal
* @link https://wordpress.org/plugins/cookie-notice/
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'Cookie_Notice' ) ) {
// Don't add the WP Rocket rewrite rules to avoid issues.
if ( ! class_exists( 'CC4R_options' ) || ! CC4R_options::rewrite_enabled() ) {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 56 );
}
// Create cache version based on value set in cookie_notice_accepted cookie.
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_cookie_notice_cookie' );
}
/**
* Return the cookie name set by Cookie Notice plugin.
*
* @since 2.11.6
* @author Arun Basil Lal
*
* @param array $cookies List of dynamic cookies.
* @return array List of dynamic cookies with the Cookie Notice cookie appended.
*/
function rocket_get_cookie_notice_cookie( $cookies ) {
$cookies[] = 'cookie_notice_accepted';
return $cookies;
}
/**
* Add dynamic cookie and mandatory cookie when Cookie Notice plugin is activated.
*
* @since 2.11.6
* @author Arun Basil Lal
*/
function rocket_add_cookie_notice_dynamic_cookie() {
// Don't add the WP Rocket rewrite rules to avoid issues.
if ( ! class_exists( 'CC4R_options' ) || ! CC4R_options::rewrite_enabled() ) {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 56 );
}
// Create cache version based on value set in cookie_notice_accepted cookie.
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_cookie_notice_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
// Clear WP Rocket cache.
rocket_clean_domain();
}
add_action( 'activate_cookie-notice/cookie-notice.php', 'rocket_add_cookie_notice_dynamic_cookie', 11 );
/**
* Remove dynamic cookie when Cookie Notice plugin is deactivated.
*
* @since 2.11.6
* @author Arun Basil Lal
*/
function rocket_remove_cookie_notice_dynamic_cookie() {
if ( ! class_exists( 'CC4R_options' ) || ! CC4R_options::rewrite_enabled() ) {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 56 );
}
remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_cookie_notice_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
// Clear WP Rocket cache.
rocket_clean_domain();
}
add_action( 'deactivate_cookie-notice/cookie-notice.php', 'rocket_remove_cookie_notice_dynamic_cookie', 11 );

View File

@@ -0,0 +1,89 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with EU Cookie Law
* https://wordpress.org/plugins/eu-cookie-law/
*
* @since 2.7
*/
if ( function_exists( 'eucookie_start' ) ) :
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_eu_cookie_law_mandatory_cookie' );
/**
* Update .htaccess & config files when the "Activate" and "Autoblock" options are turned on
*
* @since 2.7
*
* @param Array $old_value Array of previous values.
* @param Array $value Array of submitted values.
*/
function rocket_after_update_eu_cookie_law_options( $old_value, $value ) {
if ( ( isset( $old_value['enabled'], $value['enabled'] ) && ( $old_value['enabled'] === $value['enabled'] ) ) && isset( $old_value['autoblock'], $value['autoblock'] ) && $old_value['autoblock'] === $value['autoblock'] ) {
return;
}
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Update the config file.
rocket_generate_config_file();
}
add_action( 'update_option_peadig_eucookie', 'rocket_after_update_eu_cookie_law_options', 10, 2 );
// Don't add the WP Rocket rewrite rules to avoid issues.
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 58 );
endif;
/**
* Add mandatory cookie when we activate the plugin
*
* @since 2.7
*/
function rocket_activate_eu_cookie_law() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 58 );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_eu_cookie_law_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_eu-cookie-law/eu-cookie-law.php', 'rocket_activate_eu_cookie_law', 11 );
/**
* Remove mandatory cookie when we deactivate the plugin
*
* @since 2.7
*/
function rocket_deactivate_eu_cookie_law() {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 58 );
remove_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_eu_cookie_law_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_eu-cookie-law/eu-cookie-law.php', 'rocket_deactivate_eu_cookie_law', 11 );
/**
* Add the EU Cookie Law to the list of mandatory cookies before generating caching files.
*
* @since 2.7
*
* @param Array $cookies Array of mandatory cookies.
* @return Array Updated array of mandatory cookies
*/
function rocket_add_eu_cookie_law_mandatory_cookie( $cookies ) {
$options = get_option( 'peadig_eucookie' );
if ( ! empty( $options['enabled'] ) && ! empty( $options['autoblock'] ) ) {
$cookies['eu-cookie-law'] = 'euCookie';
}
return $cookies;
}

View File

@@ -0,0 +1,87 @@
<?php
/**
* Compatibility with GDPR by Trew Knowledge
*
* @link https://github.com/trewknowledge/GDPR/
* @link https://wordpress.org/plugins/gdpr/
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'GDPR' ) ) {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 60 );
// Create cache version based on value set in gdpr[] cookies.
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_gdpr_dynamic_cookies' );
}
/**
* Return the cookie names set by GDPR plugin
*
* @since 3.1.4
* @author jorditarrida
*
* @param array $cookies array List of dynamic cookies.
* @return array List of dynamic cookies with the GDPR cookie appended
*/
function rocket_get_gdpr_mandatory_cookies( $cookies ) {
$cookies[] = 'allowed_cookies';
$cookies[] = 'consent_types';
return $cookies;
}
/**
* Return the cookie names set by GDPR plugin
*
* @since 3.1.4
* @author jorditarrida
*
* @param array $cookies array List of dynamic cookies.
* @return array List of dynamic cookies with the GDPR cookie appended
*/
function rocket_get_gdpr_dynamic_cookies( $cookies ) {
$cookies['gdpr'] = [
'allowed_cookies',
'consent_types',
];
return $cookies;
}
/**
* Add dynamic cookie when GDPR plugin is activated
*
* @since 3.1.4
* @author jorditarrida
*/
function rocket_add_gdpr_mandatory_cookies() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 60 );
// Create cache version based on value set in GDPR cookies.
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_gdpr_dynamic_cookies' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
// Clear WP Rocket cache.
rocket_clean_domain();
}
add_action( 'activate_gdpr/gdpr.php', 'rocket_add_gdpr_mandatory_cookies', 11 );
/**
* Remove dynamic cookie when GDPR plugin is deactivated.
*
* @since 3.1.4
* @author jorditarrida
*/
function rocket_remove_gdpr_mandatory_cookies() {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 60 );
// Delete the dynamic cookie filter.
remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_gdpr_dynamic_cookies' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
// Clear WP Rocket cache.
rocket_clean_domain();
}
add_action( 'deactivate_gdpr/gdpr.php', 'rocket_remove_gdpr_mandatory_cookies', 11 );

View File

@@ -0,0 +1,73 @@
<?php
/**
* Compatibility with UK Cookie Consent.
*
* @since 3.2
* @author TheZoker
* @link https://wordpress.org/plugins/uk-cookie-consent/
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'CTCC_Public' ) ) {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 62 );
// Create cache version based on value set in cookie_consent_accepted cookie.
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_cookie_uk_consent_cookie' );
}
/**
* Return the cookie name set by UK Cookie Consent plugin.
*
* @since 3.2
* @author TheZoker
*
* @param array $cookies List of dynamic cookies.
* @return array List of dynamic cookies with the UK Cookie Consent cookie appended.
*/
function rocket_get_cookie_uk_consent_cookie( $cookies ) {
$cookies[] = 'catAccCookies';
return $cookies;
}
/**
* Add dynamic cookie and mandatory cookie when UK Cookie Consent plugin is activated.
*
* @since 3.2
* @author TheZoker
*/
function rocket_add_uk_cookie_consent_dynamic_cookie() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 62 );
// Create cache version based on value set in cookie_consent_accepted cookie.
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_cookie_uk_consent_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
// Clear WP Rocket cache.
rocket_clean_domain();
}
add_action( 'activate_uk-cookie-consent/uk-cookie-consent.php', 'rocket_add_uk_cookie_consent_dynamic_cookie', 11 );
/**
* Remove dynamic cookie when Cookie Consent plugin is deactivated.
*
* @since 3.2
* @author TheZoker
*/
function rocket_remove_uk_cookie_consent_dynamic_cookie() {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 62 );
remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_get_cookie_uk_consent_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
// Clear WP Rocket cache.
rocket_clean_domain();
}
add_action( 'deactivate_uk-cookie-consent/uk-cookie-consent.php', 'rocket_remove_uk_cookie_consent_dynamic_cookie', 11 );

View File

@@ -0,0 +1,53 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with WeePie Cookie Allow
*
* @since 2.9
*/
if ( class_exists( 'WpieCookieAllow' ) ) :
add_action( 'update_option_wpca_settings_general', 'rocket_after_update_wp_cookie_allow_options', 10, 2 );
add_action( 'update_option_wpca_settings_style', 'rocket_after_update_wp_cookie_allow_options', 10, 2 );
add_action( 'update_option_wpca_settings_content', 'rocket_after_update_wp_cookie_allow_options', 10, 2 );
add_action( 'update_option_wpca_settings_consent_log', 'rocket_after_update_wp_cookie_allow_options', 10, 2 );
endif;
/**
* Update .htaccess & config files when the "Enabled" and "Autoblock" options are turned on.
*
* @since 2.9
* @author Remy Perona
*
* @param array $old_value Previous values for the plugin options.
* @param array $value New values for the plugin options.
*/
function rocket_after_update_wp_cookie_allow_options( $old_value, $value ) {
// clear the cache because WeePie Cookie Allow plugin settings might have been changed.
rocket_clean_domain();
}
/**
* Add cookies when we activate the plugin.
*
* @since 2.9
* @author Remy Perona
*/
function rocket_activate_wp_cookie_allow() {
// clear the cache because plugin might be enabled already before.
rocket_clean_domain();
}
add_action( 'activate_wp-cookie-allow/wp-cookie-allow.php', 'rocket_activate_wp_cookie_allow', 11 );
/**
* Remove cookies when we deactivate the plugin
*
* @since 2.9
* @author Remy Perona
*/
function rocket_deactivate_wp_cookie_allow() {
// clear the cache because the bar/box and other WeePie Cookie Allow plugin frontend HTML is not needed anymore.
rocket_clean_domain();
}
add_action( 'deactivate_wp-cookie-allow/wp-cookie-allow.php', 'rocket_deactivate_wp_cookie_allow', 11 );

View File

@@ -0,0 +1,63 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Exclude plugin custom login page template from cache.
*
* @since 2.7
*/
if ( class_exists( 'Custom_Login_Page_Template' ) ) {
add_filter( 'rocket_cache_reject_uri', 'rocket_add_custom_login_exclude_pages' );
add_action( 'update_option_custom_login_page_template', 'rocket_after_update_single_options', 10, 2 );
}
/**
* Add custom login page to excluded urls array
*
* @since 2.7
* @author Remy Perona
*
* @param Array $urls Array of pages to exclude.
* @return Array Updated array of pages to exclude
*/
function rocket_add_custom_login_exclude_pages( $urls ) {
$clpt_options = get_option( 'custom_login_page_template' );
$urls = array_merge( $urls, get_rocket_i18n_translated_post_urls( $clpt_options['login_page_id'], 'page' ) );
return $urls;
}
/**
* Add custom login page to excluded urls array on plugin activation
*
* @since 2.7
* @author Remy Perona
*/
function rocket_activate_custom_login_page_template() {
add_filter( 'rocket_cache_reject_uri', 'rocket_add_custom_login_exclude_pages' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_custom-login-page-template/custom-login-page-template.php', 'rocket_activate_custom_login_page_template', 11 );
/**
* Remove custom login page from excluded urls array on plugin activation
*
* @since 2.7
* @author Remy Perona
*/
function rocket_remove_custom_login_exclude_pages() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_add_custom_login_exclude_pages' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_custom-login-page-template/custom-login-page-template.php', 'rocket_remove_custom_login_exclude_pages', 11 );

View File

@@ -0,0 +1,22 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'DISQUS_VERSION' ) ) :
/**
* Excludes Disqus scripts from JS minification
*
* @since 2.9
* @author Remy Perona
*
* @param Array $excluded_js An array of JS handles enqueued in WordPress.
* @return Array the updated array of handles
*/
function rocket_exclude_js_disqus( $excluded_js ) {
$excluded_js[] = str_replace( home_url(), '', plugins_url( '/disqus-comment-system/media/js/disqus.js' ) );
$excluded_js[] = str_replace( home_url(), '', plugins_url( '/disqus-comment-system/media/js/count.js' ) );
return $excluded_js;
}
add_filter( 'rocket_exclude_js', 'rocket_exclude_js_disqus' );
endif;

View File

@@ -0,0 +1,106 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with Aelia Currency Switcher.
*
* @since 2.7
*/
if ( class_exists( 'WC_Aelia_CurrencySwitcher' ) ) :
/**
* Update .htaccess & config files when the Geolocation option is updated
*
* @since 2.7
*
* @param array $old_value Previous setting values.
* @param array $value Submitted settings values.
*/
function rocket_after_update_aelia_currencyswitcher_options( $old_value, $value ) {
if ( ( ! isset( $old_value['ipgeolocation_enabled'] ) && isset( $value['ipgeolocation_enabled'] ) ) || ( isset( $old_value['ipgeolocation_enabled'], $value['ipgeolocation_enabled'] ) && $old_value['ipgeolocation_enabled'] !== $value['ipgeolocation_enabled'] )
) {
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Update the config file.
rocket_generate_config_file();
}
}
add_action( 'update_option_wc_aelia_currency_switcher', 'rocket_after_update_aelia_currencyswitcher_options', 10, 2 );
/**
* Generate a caching file depending on the currency cookie value
*/
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 64 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_currencyswitcher_dynamic_cookies' );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_aelia_currencyswitcher_mandatory_cookie' );
endif;
/**
* Add the Aelia Currency Switcher cookies when activating the plugin
*
* @since 2.7
*/
function rocket_activate_aelia_currencyswitcher() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 64 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_currencyswitcher_dynamic_cookies' );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_aelia_currencyswitcher_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_woocommerce-aelia-currencyswitcher/woocommerce-aelia-currencyswitcher.php', 'rocket_activate_aelia_currencyswitcher', 11 );
/**
* Remove the Aelia Currency Switcher cookies when deactivating the plugin
*
* @since 2.7
*/
function rocket_deactivate_aelia_currencyswitcher() {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 64 );
remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_currencyswitcher_dynamic_cookies' );
remove_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_aelia_currencyswitcher_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_woocommerce-aelia-currencyswitcher/woocommerce-aelia-currencyswitcher.php', 'rocket_deactivate_aelia_currencyswitcher', 11 );
/**
* Add the Aelia Currency Switcher cookies to the dynamic cookies list
*
* @since 2.7
*
* @param array $cookies Cookies to use for dynamic caching.
* @return array Updated cookies list
*/
function rocket_add_aelia_currencyswitcher_dynamic_cookies( $cookies ) {
$cookies[] = 'aelia_cs_recalculate_cart_totals';
$cookies[] = 'aelia_cs_selected_currency';
$cookies[] = 'aelia_customer_country';
return $cookies;
}
/**
* Add the Aelia Currency Switcher to the list of mandatory cookies before generating caching files
*
* @since 2.7
*
* @param array $cookies Mandatory cookies to serve the cache.
* @return array Updated cookies list
*/
function rocket_add_aelia_currencyswitcher_mandatory_cookie( $cookies ) {
$acs_options = get_option( 'wc_aelia_currency_switcher' );
if ( ! empty( $acs_options['ipgeolocation_enabled'] ) ) {
$cookies[] = 'aelia_cs_selected_currency';
}
return $cookies;
}

View File

@@ -0,0 +1,66 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with Aelia Prices by Country.
*
* @since 2.8.15
*/
if ( class_exists( 'Aelia\WC\PricesByCountry\WC_Aelia_Prices_By_Country' ) ) :
/**
* Generate a caching file depending on the country cookie value
*/
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 66 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_prices_by_country_dynamic_cookies' );
endif;
/**
* Add cookie when we activate the plugin
*
* @since 2.8.15
* @author Remy Perona
*/
function rocket_activate_aelia_prices_by_country() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 66 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_prices_by_country_dynamic_cookies' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_woocommerce-prices-by-country/woocommerce-prices-by-country.php', 'rocket_activate_aelia_prices_by_country', 11 );
/**
* Remove cookies when we deactivate the plugin
*
* @since 2.8.15
* @author Remy Perona
*/
function rocket_deactivate_aelia_prices_by_country() {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 66 );
remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_prices_by_country_dynamic_cookies' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_woocommerce-prices-by-country/woocommerce-prices-by-country.php', 'rocket_deactivate_aelia_prices_by_country', 11 );
/**
* Add the Aelia Prices by Country cookie to generate caching files depending on its value
*
* @since 2.8.15
* @author Remy Perona
*
* @param array $cookies Cookies list to use for dynamic caching.
* @return array Updated cookies list
*/
function rocket_add_aelia_prices_by_country_dynamic_cookies( $cookies ) {
$cookies[] = 'aelia_customer_country';
return $cookies;
}

View File

@@ -0,0 +1,69 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with Aelia Tax Display by Country.
*
* @since 2.8.15
*/
if ( class_exists( 'Aelia\WC\TaxDisplayByCountry\WC_Aelia_Tax_Display_By_Country' ) ) :
/**
* Generate a caching file depending to the tax display cookie values
*/
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 68 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_tax_display_by_country_dynamic_cookies' );
endif;
/**
* Add cookies when we activate the plugin
*
* @since 2.8.15
* @author Remy Perona
*/
function rocket_activate_aelia_tax_display_by_country() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 68 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_tax_display_by_country_dynamic_cookies' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_woocommerce-tax-display-by-country/woocommerce-tax-display-by-country.php', 'rocket_activate_aelia_tax_display_by_country', 11 );
/**
* Remove cookies when we deactivate the plugin
*
* @since 2.8.15
* @author Remy Perona
*/
function rocket_deactivate_aelia_tax_display_by_country() {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 68 );
remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_aelia_tax_display_by_country_dynamic_cookies' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_woocommerce-tax-display-by-country/woocommerce-tax-display-by-country.php', 'rocket_deactivate_aelia_tax_display_by_country', 11 );
/**
* Add the Aelia Tax Display by Country cookies to generate caching files depending on their values
*
* @since 2.8.15
* @author Remy Perona
*
* @param array $cookies Cookies list to use for dynamic caching.
* @return array Updated cookies list
*/
function rocket_add_aelia_tax_display_by_country_dynamic_cookies( $cookies ) {
$cookies[] = 'aelia_customer_country';
$cookies[] = 'aelia_customer_state';
$cookies[] = 'aelia_tax_exempt';
return $cookies;
}

View File

@@ -0,0 +1,52 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( function_exists( 'EDD' ) ) :
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_edd_pages' );
add_action( 'update_option_edd_settings', 'rocket_after_update_array_options', 10, 2 );
endif;
/**
* Exclude EDD pages from cache
*
* @param array $urls Array of URLs to exclude from cache.
* @return array Updated array of URLs
*/
function rocket_exclude_edd_pages( $urls ) {
$edd_settings = get_option( 'edd_settings' );
if ( isset( $edd_settings['purchase_page'] ) ) {
$checkout_urls = get_rocket_i18n_translated_post_urls( $edd_settings['purchase_page'], 'page', '(.*)' );
$urls = array_merge( $urls, $checkout_urls );
}
return $urls;
}
/**
* Exclude EDD pages from cache on EDD activation.
*/
function rocket_activate_edd() {
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_edd_pages' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_easy-digital-downloads/easy-digital-downloads.php', 'rocket_activate_edd', 11 );
/**
* Remove EDD pages from cache exclusion on EDD deactivation.
*/
function rocket_deactivate_edd() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_exclude_edd_pages' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_easy-digital-downloads/easy-digital-downloads.php', 'rocket_deactivate_edd', 11 );

View File

@@ -0,0 +1,58 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with Easy Digital Downloads Software Licensing addon.
*
* @since 2.7
*/
if ( class_exists( 'EDD_Software_Licensing' ) && defined( 'EDD_SL_VERSION' ) ) :
// Exclude EDD SL endpoint from cache on WP Rocket activation.
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_edd_sl_endpoint' );
endif;
/**
* Exclude EDD SL endpoint from cache when activating the plugin
*
* @since 2.7
*/
function rocket_activate_edd_software_licensing() {
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_edd_sl_endpoint' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_edd-software-licensing/edd-software-licenses.php', 'rocket_activate_edd_software_licensing', 11 );
/**
* Remove exclusion of EDD SL endpoint from cache when deactivating the plugin
*
* @since 2.7
*/
function rocket_deactivate_edd_software_licensing() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_exclude_edd_sl_endpoint' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_edd-software-licensing/edd-software-licenses.php', 'rocket_deactivate_edd_software_licensing', 11 );
/**
* Exclude EDD SL endpoint from caching
*
* @since 2.7
*
* @param array $uri URLs to exclude from caching.
* @return array Updated list of URLs to exclude
*/
function rocket_exclude_edd_sl_endpoint( $uri ) {
$uri[] = '/edd-sl/(.*)';
return $uri;
}

View File

@@ -0,0 +1,65 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Exclude pages of Give plugin from cache.
*
* @since 2.7
*/
if ( defined( 'GIVE_VERSION' ) && function_exists( 'give_get_settings' ) ) {
add_filter( 'rocket_cache_reject_uri', 'rocket_add_give_exclude_pages' );
if ( is_admin() ) {
add_action( 'update_option_give_settings', 'rocket_after_update_single_options', 10, 2 );
}
}
/**
* Add give pages to the excluded pages
*
* @since 2.7
*
* @param Array $urls Array of excluded pages.
* @return Array Updated array of excluded pages
*/
function rocket_add_give_exclude_pages( $urls ) {
$give_options = give_get_settings();
$urls = array_merge( $urls, get_rocket_i18n_translated_post_urls( $give_options['success_page'], 'page' ) );
$urls = array_merge( $urls, get_rocket_i18n_translated_post_urls( $give_options['history_page'], 'page' ) );
$urls = array_merge( $urls, get_rocket_i18n_translated_post_urls( $give_options['failure_page'], 'page' ) );
return $urls;
}
/**
* Add give pages to the excluded pages when activating the plugin
*
* @since 2.7
*/
function rocket_activate_give() {
add_filter( 'rocket_cache_reject_uri', 'rocket_add_give_exclude_pages' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_give/give.php', 'rocket_activate_give', 11 );
/**
* Remove give pages from the excluded pages when activating the plugin
*
* @since 2.7
*/
function rocket_remove_give_exclude_pages() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_add_give_exclude_pages' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_give/give.php', 'rocket_remove_give_exclude_pages', 11 );

View File

@@ -0,0 +1,69 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( function_exists( 'it_exchange_get_page_type' ) && function_exists( 'it_exchange_get_page_url' ) ) :
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_ithemes_exchange_pages' );
add_action( 'update_option_it-storage-exchange_settings_pages', 'rocket_after_update_single_options', 10, 2 );
endif;
/**
* Exclude iThemes Exchange pages from cache.
*
* @param array $urls Array of URLs to exclude from cache.
* @return array Updated array of URLs to exclude from cache
*/
function rocket_exclude_ithemes_exchange_pages( $urls ) {
$pages = [
'purchases',
'confirmation',
'account',
'profile',
'downloads',
'purchases',
'log-in',
'log-out',
];
foreach ( $pages as $page ) {
if ( it_exchange_get_page_type( $page ) === 'WordPress' ) {
$exchange_urls = get_rocket_i18n_translated_post_urls( it_exchange_get_page_wpid( $page ) );
} else {
$exchange_urls = [ rocket_extract_url_component( it_exchange_get_page_url( $page ), PHP_URL_PATH ) ];
}
$urls = array_merge( $urls, $exchange_urls );
}
return $urls;
}
/**
* Exclude iThemes Exchanges pages from cache on plugin activation.
*/
function rocket_activate_ithemes_exchange() {
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_ithemes_exchange_pages' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_ithemes-exchange/ithemes-exchange.php', 'rocket_activate_ithemes_exchange', 11 );
/**
* Remove iThemes Exchanges pages from cache exclusion on plugin deactivation.
*/
function rocket_deactivate_ithemes_exchange() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_exclude_ithemes_exchange_pages' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_ithemes-exchange/ithemes-exchange.php', 'rocket_deactivate_ithemes_exchange', 11 );

View File

@@ -0,0 +1,61 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'JIGOSHOP_VERSION' ) && function_exists( 'jigoshop_get_page_id' ) ) :
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_jigoshop_pages' );
add_action( 'update_option_jigoshop_options', 'rocket_after_update_array_options', 10, 2 );
endif;
/**
* Exclude Jigoshop pages from cache.
*
* @param array $urls Array of URLs to exclude from cache.
* @return array Updated array of URLs to exclude from cache
*/
function rocket_exclude_jigoshop_pages( $urls ) {
if ( jigoshop_get_page_id( 'checkout' ) && jigoshop_get_page_id( 'checkout' ) !== '-1' ) {
$checkout_urls = get_rocket_i18n_translated_post_urls( jigoshop_get_page_id( 'checkout' ), 'page', '(.*)' );
$urls = array_merge( $urls, $checkout_urls );
}
if ( jigoshop_get_page_id( 'cart' ) && jigoshop_get_page_id( 'cart' ) !== '-1' ) {
$cart_urls = get_rocket_i18n_translated_post_urls( jigoshop_get_page_id( 'cart' ) );
$urls = array_merge( $urls, $cart_urls );
}
if ( jigoshop_get_page_id( 'myaccount' ) && jigoshop_get_page_id( 'myaccount' ) !== '-1' ) {
$cart_urls = get_rocket_i18n_translated_post_urls( jigoshop_get_page_id( 'myaccount' ), 'page', '(.*)' );
$urls = array_merge( $urls, $cart_urls );
}
return $urls;
}
/**
* Exclude Jigoshop pages from cache on plugin activation.
*/
function rocket_activate_jigoshop() {
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_jigoshop_pages' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_jigoshop/jigoshop.php', 'rocket_activate_jigoshop', 11 );
/**
* Remove Jigoshop pages from cache exclusion on plugin deactivation.
*/
function rocket_deactivate_jigoshop() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_exclude_jigoshop_pages' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_jigoshop/jigoshop.php', 'rocket_deactivate_jigoshop', 11 );

View File

@@ -0,0 +1,83 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with WooCommerce Currency Converter Widget.
*
* @since 2.7
*/
if ( class_exists( 'WC_Currency_Converter' ) ) :
// Add cookie to config file when WP Rocket is activated and WooCommerce Currency Converter Widget is already active.
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 70 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_woocommerce_currency_converter_dynamic_cookies', 11 );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_woocommerce_currency_converter_mandatory_cookie', 11 );
add_action( 'update_option_woocommerce_default_customer_address', 'rocket_after_update_single_options', 10, 2 );
endif;
/**
* Add cookies when we activating the plugin
*
* @since 2.7
*/
function rocket_activate_woocommerce_currency_converter() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 70 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_woocommerce_currency_converter_dynamic_cookies' );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_woocommerce_currency_converter_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_woocommerce-currency-converter-widget/currency-converter.php', 'rocket_activate_woocommerce_currency_converter', 11 );
/**
* Remove cookies when deactivating the plugin
*
* @since 2.7
*/
function rocket_deactivate_woocommerce_currency_converter() {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 70 );
remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_woocommerce_currency_converter_dynamic_cookies' );
remove_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_woocommerce_currency_converter_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_woocommerce-currency-converter-widget/currency-converter.php', 'rocket_deactivate_woocommerce_currency_converter', 11 );
/**
* Add the WC Currency Converter Widget cookie to generate caching files depending on its value
*
* @since 2.7
*
* @param array $cookies Cookies list to use for dynamic caching.
* @return array Updated cookies list
*/
function rocket_add_woocommerce_currency_converter_dynamic_cookies( $cookies ) {
$cookies[] = 'woocommerce_current_currency';
return $cookies;
}
/**
* Add the WC Currency Converter Widget cookie to the list of mandatory cookies before generating the caching files
*
* @since 2.7
*
* @param array $cookies Mandatory cookies list.
* @return array Updated cookies list
*/
function rocket_add_woocommerce_currency_converter_mandatory_cookie( $cookies ) {
$widget_woocommerce_currency_converter = get_option( 'widget_woocommerce_currency_converter' );
if ( ! empty( $widget_woocommerce_currency_converter ) && 'geolocation_ajax' === get_option( 'woocommerce_default_customer_address' ) ) {
$cookies[] = 'woocommerce_current_currency';
}
return $cookies;
}

View File

@@ -0,0 +1,8 @@
<?php
defined( 'ABSPATH' ) || exit;
// Compatibility with the currency switcher in WooCommerce Multilingual plugin.
if ( defined( 'WCML_VERSION' ) ) :
add_action( 'wcml_switch_currency', 'rocket_clean_domain' );
endif;

View File

@@ -0,0 +1,66 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'WPSHOP_VERSION' ) && class_exists( 'wpshop_tools' ) && method_exists( 'wpshop_tools', 'get_page_id' ) ) :
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_wpshop_pages' );
add_action( 'update_option_wpshop_cart_page_id', 'rocket_after_update_single_options', 10, 2 );
add_action( 'update_option_wpshop_checkout_page_id', 'rocket_after_update_single_options', 10, 2 );
add_action( 'update_option_wpshop_payment_return_page_id', 'rocket_after_update_single_options', 10, 2 );
add_action( 'update_option_wpshop_payment_return_nok_page_id', 'rocket_after_update_single_options', 10, 2 );
add_action( 'update_option_wpshop_myaccount_page_id', 'rocket_after_update_single_options', 10, 2 );
endif;
/**
* Exclude WP Shop pages from cache.
*
* @param array $urls Array of URLs to exclude from cache.
* @return array Updated array of URLs to exclude from cache
*/
function rocket_exclude_wpshop_pages( $urls ) {
$pages = [
'wpshop_cart_page_id',
'wpshop_checkout_page_id',
'wpshop_payment_return_page_id',
'wpshop_payment_return_nok_page_id',
'wpshop_myaccount_page_id',
];
foreach ( $pages as $page ) {
$page_id = wpshop_tools::get_page_id( get_option( $page ) );
if ( $page_id ) {
$urls = array_merge( $urls, get_rocket_i18n_translated_post_urls( $page_id ) );
}
}
return $urls;
}
/**
* Exclude WP Shop pages from cache on plugin activation.
*/
function rocket_activate_wpshop() {
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_wpshop_pages' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_wpshop/wpshop.php', 'rocket_activate_wpshop', 11 );
/**
* Remove WP Shop pages from cache exclusion on plugin deactivation.
*/
function rocket_deactivate_wpshop() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_exclude_wpshop_pages' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_wpshop/wpshop.php', 'rocket_deactivate_wpshop', 11 );

View File

@@ -0,0 +1,33 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Conflict with Envira Gallery: don't apply LazyLoad on all images
*
* @since 2.3.10
*
* @param string $attr Envira gallery image attributes.
* @return string Updated attributes
*/
function rocket_deactivate_lazyload_on_envira_gallery( $attr ) {
return $attr . ' data-no-lazy="1" ';
}
add_filter( 'envira_gallery_output_image_attr', 'rocket_deactivate_lazyload_on_envira_gallery', PHP_INT_MAX );
/**
* Conflict with Envira Gallery: don't apply LazyLoad on all images
*
* @since 2.3.10
*
* @param string $images Envira gallery images HTML code.
* @return string Updated HTML code
*/
function rocket_deactivate_lazyload_on_envira_gallery_indexable_images( $images ) {
$images = str_replace( '<img', '<img data-no-lazy="1" ', $images );
return $images;
}
add_filter( 'envira_gallery_indexable_images', 'rocket_deactivate_lazyload_on_envira_gallery_indexable_images', PHP_INT_MAX );

View File

@@ -0,0 +1,115 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Compatibility with GeotargetingWP Plugins
*
* @author Damian Logghe <info@timersys.com>
*/
if ( class_exists( 'GeotWP\GeotargetingWP' ) ) :
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 72 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_geotargetingwp_dynamic_cookies' );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_geotargetingwp_mandatory_cookie' );
/**
* If we recently deactivated a plugin of the family but
* we still see the class it means another plugin is still active,
* so flush rules once more to be safe
*/
if ( get_option( 'geotWP-deactivated' ) ) {
// Update the WP Rocket rules on the .htaccess file.
add_action( 'admin_init', 'flush_rocket_htaccess' );
// Regenerate the config file.
add_action( 'admin_init', 'rocket_generate_config_file' );
delete_option( 'geotWP-deactivated' );
}
endif;
/**
* Add cookies when we activate any goetargetingWP plugin.
*
* @since 2.10.3
* @author Damian Logghe
*/
function rocket_activate_geotargetingwp() {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 72 );
add_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_geotargetingwp_dynamic_cookies' );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_geotargetingwp_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'geotWP/activated', 'rocket_activate_geotargetingwp', 11 );
/**
* Remove cookies when we deactivate the plugin.
*
* @since 2.10.3
* @author Damian Logghe
*/
function rocket_deactivate_geotargetingwp() {
// add into db a record saying we deactivated one of the family plugins.
update_option( 'geotWP-deactivated', true );
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 72 );
remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_add_geotargetingwp_dynamic_cookies' );
remove_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_geotargetingwp_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'geotWP/deactivated', 'rocket_deactivate_geotargetingwp', 11 );
/**
* Add the GeotargetingWP cookies to generate caching files depending on their values.
*
* @since 2.10.3
* @author Damian Logghe
*
* @param Array $cookies An array of cookies.
* @return Array Updated array of cookies
*/
function rocket_add_geotargetingwp_dynamic_cookies( $cookies ) {
return rocket_add_geot_cookies( $cookies );
}
/**
* Add the GeotargetingWP cookies to the list of mandatory cookies before to generate caching files.
*
* @since 2.10.3
* @author Damian Logghe
*
* @param Array $cookies An array of cookies.
* @return Array Updated array of cookies
*/
function rocket_add_geotargetingwp_mandatory_cookie( $cookies ) {
return rocket_add_geot_cookies( $cookies );
}
/**
* Let users modify cache level by default set to country.
*
* @since 2.10.3
* @author Damian Logghe
*
* @param Array $cookies An array of cookies.
* @return Array Updated array of cookies
*/
function rocket_add_geot_cookies( $cookies ) {
// valid options are country, state, city.
$enabled_cookies = apply_filters( 'rocket_geotargetingwp_enabled_cookies', [ 'country' ] );
foreach ( $enabled_cookies as $enabled_cookie ) {
if ( ! in_array( 'geot_rocket_' . $enabled_cookie, $cookies, true ) ) {
$cookies[] = 'geot_rocket_' . $enabled_cookie;
}
}
return $cookies;
}

View File

@@ -0,0 +1,145 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'POLYLANG_VERSION' ) && POLYLANG_VERSION ) :
/**
* Conflict with Polylang: Clear the whole cache when the "The language is set from content" option is activated.
*
* @since 2.6.8
*/
function rocket_force_clean_domain_on_polylang() {
$pll = function_exists( 'PLL' ) ? PLL() : $GLOBALS['polylang'];
if ( isset( $pll ) && 0 === $pll->options['force_lang'] ) {
rocket_clean_cache_dir();
}
}
add_action( 'after_rocket_clean_domain', 'rocket_force_clean_domain_on_polylang' );
// Filter mandatory cookies and WP Rocket rewrite rules if Polylang module 'Detect browser language' is enabled.
if ( function_exists( 'PLL' ) && PLL()->options['browser'] ) {
// Add Polylang's language cookie as a mandatory cookie.
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_polylang_mandatory_cookie' );
// Remove WP Rocket rewrite rules from .htaccess file.
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 74 );
}
endif;
/**
* Add Polylang's language cookie to the mandatory cookies of WP Rocket.
*
* Polylang saves the users preferred language in this cookie by detecting browser language or by user choice
* Adding this as a mandatory cookie prevents WP Rocket from serving the cache when the cookie is not set.
*
* @param array $cookies Array with mandatory cookies.
* @return (array) Array of mandatory cookies with the Polylang cookie appended
*
* @author Arun Basil Lal
* @since 3.0.5
*/
function rocket_add_polylang_mandatory_cookie( $cookies ) {
$cookies[] = defined( 'PLL_COOKIE' ) ? PLL_COOKIE : 'pll_language';
return $cookies;
}
/**
* Add mandatory cookie to WP Rocket config and remove rewrite rules from .htaccess on Polylang activation.
*
* Add mandatory cookie only if the Polylang module 'Detect browser language' is active.
* Also purge the homepage cache.
*
* @author Arun Basil Lal
* @since 3.0.5
*/
function rocket_activate_polylang() {
// Read Polylang settings from db.
$polylang_settings = get_option( 'polylang' );
if ( isset( $polylang_settings['browser'] ) && ( 1 === (int) $polylang_settings['browser'] ) ) {
// Add Polylang's language cookie as a mandatory cookie.
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_polylang_mandatory_cookie' );
// Remove WP Rocket rewrite rules from .htaccess file.
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 74 );
// Regenerate the config file.
rocket_generate_config_file();
// Regenerate .htaccess file.
flush_rocket_htaccess();
// Purge homepage cache.
rocket_clean_home();
}
}
add_action( 'activate_polylang/polylang.php', 'rocket_activate_polylang', 11 );
/**
* Remove mandatory cookie and add rewrite rules back to .htaccess when Polylang is deactivated.
*
* @author Arun Basil Lal
* @since 3.0.5
*/
function rocket_deactivate_polylang() {
// Remove Polylang's language cookie as a mandatory cookie.
remove_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_polylang_mandatory_cookie' );
// Add back WP Rocket rewrite rules from .htaccess file.
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 74 );
// Regenerate the config file.
rocket_generate_config_file();
// Regenerate .htaccess file.
flush_rocket_htaccess();
}
add_action( 'deactivate_polylang/polylang.php', 'rocket_deactivate_polylang', 11 );
/**
* Update mandatory cookie in WP Rocket config file and remove rewrite rules from .htaccess
* when Detect browser language module is enabled / disabled.
*
* @param array $value Array containing Polylang settings before its written to db.
* @return array
*
* @author Arun Basil Lal
* @since 3.0.5
*/
function rocket_detect_browser_language_status_change( $value ) {
if ( function_exists( 'PLL' ) && PLL()->options['browser'] ) {
// Add Polylang's language cookie as a mandatory cookie.
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_polylang_mandatory_cookie' );
// Remove WP Rocket rewrite rules from .htaccess file.
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 74 );
// Regenerate the config file.
rocket_generate_config_file();
// Regenerate .htaccess file.
flush_rocket_htaccess();
// Purge homepage cache.
rocket_clean_home();
} else {
// Remove Polylang's language cookie as a mandatory cookie.
remove_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_polylang_mandatory_cookie' );
// Add back WP Rocket rewrite rules from .htaccess file.
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 74 );
// Regenerate the config file.
rocket_generate_config_file();
// Regenerate .htaccess file.
flush_rocket_htaccess();
}
return $value;
}
add_filter( 'pre_update_option_polylang', 'rocket_detect_browser_language_status_change' );

View File

@@ -0,0 +1,11 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'ICL_SITEPRESS_VERSION' ) && ICL_SITEPRESS_VERSION ) :
/**
* Tell WooCommerce Multilingual that we are caching.
* This will add a URL param when switching currency to get the correct response.
*/
add_filter( 'wcml_is_cache_enabled_for_switching_currency', '__return_true' );
endif;

View File

@@ -0,0 +1,187 @@
<?php
/**
* Compatibility file with the Jetpack plugin.
* https://wordpress.org/plugins/jetpack/
*
* @package WP Rocket
*/
defined( 'ABSPATH' ) || exit;
// Is Jetpack installed and active?
if ( class_exists( 'Jetpack' ) ) :
/**
* Improvement with Jetpack: auto-detect the XML sitemaps for the preload option
*
* @since 2.8
* @author Remy Perona
*/
if (
Jetpack::is_module_active( 'sitemaps' )
&& function_exists( 'jetpack_sitemap_uri' )
) {
/**
* Add Jetpack option to WP Rocket options
*
* @since 2.8
* @author Remy Perona
*
* @param Array $options WP Rocket options array.
* @return Array Updated WP Rocket options array
*/
function rocket_add_jetpack_sitemap_option( $options ) {
$options['jetpack_xml_sitemap'] = 0;
return $options;
}
add_filter( 'rocket_first_install_options', 'rocket_add_jetpack_sitemap_option' );
/**
* Sanitize jetpack option value
*
* @since 2.8
* @author Remy Perona
*
* @param Array $inputs Array of inputs values.
* @return Array Array of inputs values
*/
function rocket_jetpack_sitemap_option_sanitize( $inputs ) {
$inputs['jetpack_xml_sitemap'] = ! empty( $inputs['jetpack_xml_sitemap'] ) ? 1 : 0;
return $inputs;
}
add_filter( 'rocket_inputs_sanitize', 'rocket_jetpack_sitemap_option_sanitize' );
/**
* Add Jetpack sitemap to preload list
*
* @since 2.8
* @author Remy Perona
*
* @param Array $sitemaps Array of sitemaps to preload.
* @return Array Updated Array of sitemaps to preload
*/
function rocket_add_jetpack_sitemap( $sitemaps ) {
if ( get_rocket_option( 'jetpack_xml_sitemap', false ) ) {
$sitemaps['jetpack'] = jetpack_sitemap_uri();
}
return $sitemaps;
}
add_filter( 'rocket_sitemap_preload_list', 'rocket_add_jetpack_sitemap' );
/**
* Add Jetpack sub-option to WP Rocket settings page
*
* @since 2.8
* @author Remy Perona
*
* @param Array $options WP Rocket options array.
* @return Array Updated WP Rocket options array
*/
function rocket_sitemap_preload_jetpack_option( $options ) {
$options[] = [
'parent' => 'sitemap_preload',
'type' => 'checkbox',
'label' => __( 'Jetpack XML Sitemaps', 'rocket' ),
'label_for' => 'jetpack_xml_sitemap',
'label_screen' => sprintf( __( 'Preload the sitemap from the Jetpack plugin', 'rocket' ), 'Jetpack' ),
'default' => 0,
];
$options[] = [
'parent' => 'sitemap_preload',
'type' => 'helper_description',
'name' => 'jetpack_xml_sitemap_desc',
// translators: %s = plugin name, e.g. Yoast SEO.
'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'Jetpack' ),
];
return $options;
}
add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_preload_jetpack_option' );
} // End if().
/**
* Support Jetpack's EU Cookie Law Widget.
*
* @see https://jetpack.com/support/extra-sidebar-widgets/eu-cookie-law-widget/
*
* @since 2.10.1
* @author Jeremy Herve
*/
if ( Jetpack::is_module_active( 'widgets' ) ) :
/**
* Add the EU Cookie Law to the list of mandatory cookies before generating caching files.
*
* @since 2.10.1
* @author Jeremy Herve
*
* @param array $cookies List of mandatory cookies.
*/
function rocket_add_jetpack_cookie_law_mandatory_cookie( $cookies ) {
$cookies['jetpack-eu-cookie-law'] = 'eucookielaw';
return $cookies;
}
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_jetpack_cookie_law_mandatory_cookie' );
// Don't add the WP Rocket rewrite rules to avoid issues.
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 76 );
/**
* Add Jetpack cookie when:
* - Jetpack is active.
* - Jetpack's Extra Sidebar Widgets module is active.
* - The widget is active.
* - the rocket_jetpack_eu_cookie_widget option is empty or not set.
*
* @since 2.10.1
* @author Jeremy Herve
*/
function rocket_activate_jetpack_cookie_law() {
$rocket_jp_eu_cookie_widget = get_option( 'rocket_jetpack_eu_cookie_widget' );
if (
is_active_widget( false, false, 'eu_cookie_law_widget' )
&& empty( $rocket_jp_eu_cookie_widget )
) {
add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 76 );
add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_jetpack_cookie_law_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
// Set the option, so this is not triggered again.
update_option( 'rocket_jetpack_eu_cookie_widget', 1, true );
}
}
add_action( 'admin_init', 'rocket_activate_jetpack_cookie_law' );
endif; // End if Widgets module is active check.
endif; // End if Jetpack is active check.
/**
* Remove cookies if Jetpack gets deactivated.
*
* @since 2.10.1
* @author Jeremy Herve
*/
function rocket_remove_jetpack_cookie_law_mandatory_cookie() {
remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 76 );
remove_filter( 'rocket_cache_mandatory_cookies', '_rocket_add_eu_cookie_law_mandatory_cookie' );
// Update the WP Rocket rules on the .htaccess file.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
// Delete our option.
delete_option( 'rocket_jetpack_eu_cookie_widget' );
}
add_action( 'deactivate_jetpack/jetpack.php', 'rocket_remove_jetpack_cookie_law_mandatory_cookie', 11 );

View File

@@ -0,0 +1,36 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Conflict with MailChimp List Subscribe Form: Enqueue style without lack of performance, grrrr!!!
*
* @since 2.6
*/
function rocket_fix_mailchimp_main_css() {
if ( ! defined( 'MCSF_VER' ) || ! function_exists( 'mailchimpSF_main_css' ) ) {
return;
}
$blog_id = get_current_blog_id();
$cache_path = WP_ROCKET_MINIFY_CACHE_PATH . $blog_id . '/';
$cache_url = WP_ROCKET_MINIFY_CACHE_URL . $blog_id . '/';
$css_path = $cache_path . 'mailchimpSF_main_css.css';
if ( ! rocket_direct_filesystem()->is_dir( $cache_path ) ) {
rocket_mkdir_p( $cache_path );
}
if ( ! rocket_direct_filesystem()->exists( $css_path ) ) {
ob_start();
mailchimpSF_main_css();
$content = ob_get_contents();
ob_end_clean();
rocket_put_content( $css_path, $content );
}
wp_deregister_style( 'mailchimpSF_main_css' );
wp_register_style( 'mailchimpSF_main_css', $cache_url . 'mailchimpSF_main_css.css', null, MCSF_VER );
}
add_action( 'init', 'rocket_fix_mailchimp_main_css', PHP_INT_MAX );

View File

@@ -0,0 +1,56 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WpAppKit' ) ) :
add_filter( 'rocket_cache_reject_uri', 'rocket_add_appkit_exclude_pages' );
endif;
/**
* Add WP Appkit path to cache exclusion
*
* @since 2.9
* @author Remy Perona
*
* @param array $urls URLs to exclude from cache.
* @return array Updated URLs array
*/
function rocket_add_appkit_exclude_pages( $urls ) {
$urls[] = '/wp-appkit-api/(.*)';
return $urls;
}
/**
* Add WP Appkit path to cache exclusion when activating the plugin
*
* @since 2.9
* @author Remy Perona
*/
function rocket_activate_wp_appkit() {
add_filter( 'rocket_cache_reject_uri', 'rocket_add_appkit_exclude_pages' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'activate_wp-appkit/wp-appkit.php', 'rocket_activate_wp_appkit', 11 );
/**
* Remove Appkit path from cache exclusion when deactivating the plugin
*
* @since 2.9
* @author Remy Perona
*/
function rocket_deactivate_wp_appkit() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_add_appkit_exclude_pages' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'deactivate_wp-appkit/wp-appkit.php', 'rocket_deactivate_wp_appkit', 11 );

View File

@@ -0,0 +1,149 @@
<?php
defined( 'ABSPATH' ) || exit;
global $nginx_helper;
if ( isset( $nginx_helper ) ) :
global $nginx_purger;
/**
* Clear WP Rocket cache after the NGINX cache is purged from Nginx Helper.
*
* @since 3.3.0.1
*
* @return void
*/
function rocket_clear_cache_after_nginx_helper_purge() {
if ( ! isset( $_GET['nginx_helper_action'] ) ) {
return;
}
if ( ! check_admin_referer( 'nginx_helper-purge_all' ) ) {
return;
}
if ( 'done' !== sanitize_text_field( wp_unslash( $_GET['nginx_helper_action'] ) ) ) {
return;
}
if ( ! current_user_can( 'rocket_purge_cache' ) ) {
return;
}
// Clear all caching files.
rocket_clean_domain();
}
add_action( 'admin_init', 'rocket_clear_cache_after_nginx_helper_purge' );
/**
* Clear WP Rocket cache for the current page after the NGINX cache is purged from Nginx Helper.
*
* @since 3.3.0.1
*
* @return void
*/
function rocket_clear_current_page_after_nginx_helper_purge() {
if ( ! isset( $_GET['nginx_helper_action'], $_GET['_wpnonce'] ) ) {
return;
}
if ( ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'nginx_helper-purge_all' ) ) {
return;
}
if ( is_admin() ) {
return;
}
if ( ! current_user_can( 'rocket_purge_posts' ) ) {
return;
}
$referer = wp_get_referer();
if ( 0 !== strpos( $referer, 'http' ) ) {
$parse_url = get_rocket_parse_url( untrailingslashit( home_url() ) );
$referer = $parse_url['scheme'] . '://' . $parse_url['host'] . $referer;
}
if ( home_url( '/' ) === $referer ) {
rocket_clean_home();
return;
}
rocket_clean_files( $referer );
}
add_action( 'init', 'rocket_clear_current_page_after_nginx_helper_purge' );
/**
* Clears NGINX cache for the homepage URL when using "Purge this URL" from the admin bar on the front end
*
* @since 3.3.0.1
* @author Remy Perona
*
* @param string $root WP Rocket root cache path.
* @param string $lang Current language.
* @return void
*/
function rocket_clean_nginx_cache_home( $root = '', $lang = '' ) {
global $nginx_purger;
if ( ! isset( $nginx_purger ) ) {
return;
}
$url = get_rocket_i18n_home_url( $lang );
$nginx_purger->purge_url( $url );
}
add_action( 'after_rocket_clean_home', 'rocket_clean_nginx_cache_home', 10, 2 );
/**
* Clears NGINX cache for a specific URL when using "Purge this URL" from the admin bar on the front end
*
* @since 3.3.0.1
* @author Remy Perona
*
* @param string $url URL to purge.
* @return void
*/
function rocket_clean_nginx_cache_url( $url ) {
global $nginx_purger;
if ( ! isset( $nginx_purger ) ) {
return;
}
if ( ! isset( $_GET['type'], $_GET['_wpnonce'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
if ( false !== strpos( $url, 'index.html' ) ) {
return;
}
if ( 'page' === substr( $url, -4 ) ) {
return;
}
$url = str_replace( '*', '', $url );
$nginx_purger->purge_url( $url );
}
add_action( 'after_rocket_clean_file', 'rocket_clean_nginx_cache_url' );
/**
* Clean the NGINX cache using Nginx Helper after WP Rocket's cache is purged.
*
* @since 3.3.0.1
*/
function rocket_clean_nginx_helper_cache() {
if ( isset( $_GET['nginx_helper_action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
do_action( 'rt_nginx_helper_purge_all' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
}
add_action( 'after_rocket_clean_domain', 'rocket_clean_nginx_helper_cache' );
endif;

View File

@@ -0,0 +1,16 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( function_exists( 'tve_editor_url' ) ) {
/**
* Forces Thrive Visual Editors bot detection to assume a human visitor.
*
* @since 2.8.11
* @author Remy Perona
*
* @param boolean|integer $bot_detection 1|0 when crawler has|not been detected, FALSE when user agent string is unavailable
* @return integer
*/
add_filter( 'tve_dash_is_crawler', '__return_zero', PHP_INT_MAX );
}

View File

@@ -0,0 +1,10 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'WPB_VC_VERSION' ) && class_exists( 'Vc_Manager' ) ) :
/**
* Disable nonce checking for Visual Composer grid
*/
add_filter( 'vc_grid_get_grid_data_access', '__return_true' );
endif;

View File

@@ -0,0 +1,17 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'BhittaniPlugin_kkStarRatings' ) ) :
/**
* Conflict with kk Star Ratings: Clear the cache when a post gets rated.
*
* @since 2.5.3
*
* @param int $post_id Post ID.
*/
function rocket_clear_cache_on_kksr_rate( $post_id ) {
rocket_clean_post( $post_id );
}
add_action( 'kksr_rate', 'rocket_clear_cache_on_kksr_rate' );
endif;

View File

@@ -0,0 +1,18 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'WP_POSTRATINGS_VERSION' ) ) :
/**
* Conflict with WP-PostRatings: Clear the cache when a post gets rated.
*
* @since 2.6.6
*
* @param int $user_id user ID.
* @param int $post_id post ID.
*/
function rocket_clear_cache_on_wp_postratings_rate( $user_id, $post_id ) {
rocket_clean_post( $post_id );
}
add_action( 'rate_post', 'rocket_clear_cache_on_wp_postratings_rate', 10, 2 );
endif;

View File

@@ -0,0 +1,18 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Excludes s2 Member dynamic file from saving as static resource
*
* @since 2.11.4
* @author Remy Perona
*
* @param array $excluded_files Array of excluded files.
*/
function rocket_exclude_s2member_dynamic_files( $excluded_files ) {
$excluded_files[] = rocket_clean_exclude_file( plugins_url( '/s2member/s2member-o.php' ) );
return $excluded_files;
}
add_action( 'rocket_exclude_static_dynamic_resources', 'rocket_exclude_s2member_dynamic_files' );

View File

@@ -0,0 +1,90 @@
<?php
defined( 'ABSPATH' ) || exit;
add_action( 'update_option_secupress_users-login_settings', 'rocket_after_update_single_options', 10, 2 );
/**
* Add SecuPress move login pages to cache exclusion
*
* @since 2.9
* @author Remy Perona
*
* @param array $urls URLs to exclude from cache.
* @return array Updated URLs to exclude
*/
function rocket_exclude_secupress_move_login( $urls ) {
if ( ! function_exists( 'secupress_move_login_get_slugs' ) ) {
return $urls;
}
$bases = secupress_get_rewrite_bases();
$slugs = secupress_move_login_get_slugs();
foreach ( $slugs as $slug ) {
$urls[] = $bases['base'] . ltrim( $bases['site_from'], '/' ) . $slug . '/?';
}
return $urls;
}
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_secupress_move_login' );
/**
* Add SecuPress move login pages to cache exclusion when activating the plugin
*
* @since 2.9
* @author Remy Perona
*/
function rocket_maybe_activate_secupress() {
if ( function_exists( 'secupress_move_login_get_slugs' ) ) {
rocket_activate_secupress();
}
}
add_action( 'secupress.plugins.activation', 'rocket_maybe_activate_secupress', 10001 );
/**
* Add SecuPress move login pages to cache exclusion when activating the move login module
*
* @since 2.9
* @author Remy Perona
*/
function rocket_activate_secupress() {
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_secupress_move_login' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'secupress.plugin.move_login.activate', 'rocket_activate_secupress' );
/**
* Remove SecuPress move login pages from cache exclusion when deactivating the plugin
*
* @since 2.9
* @author Remy Perona
*/
function rocket_maybe_deactivate_secupress() {
if ( function_exists( 'secupress_move_login_get_slugs' ) ) {
rocket_deactivate_secupress();
}
}
add_action( 'secupress.deactivation', 'rocket_maybe_deactivate_secupress', 10001 );
/**
* Remove SecuPress move login pages from cache exclusion when deactivating the move login module
*
* @since 2.9
* @author Remy Perona
*/
function rocket_deactivate_secupress() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_exclude_secupress_move_login' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
add_action( 'secupress.plugin.move_login.deactivate', 'rocket_deactivate_secupress' );

View File

@@ -0,0 +1,82 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'SFML_VERSION' ) ) :
add_filter( 'rocket_cache_reject_uri', 'rocket_add_sfml_exclude_pages' );
add_action( 'update_option_sfml', 'rocket_after_update_single_options', 10, 2 );
endif;
/**
* Exclude SF Move Login custom urls from caching
*
* @since 2.9.3 Moved to 3rd party file and improved
* @since 2.6
*
* @param array $urls An array of URLs to exclude from cache.
* @return array Updated array of URLs
*/
function rocket_add_sfml_exclude_pages( $urls ) {
if ( ! function_exists( 'sfml_get_slugs' ) ) {
if ( file_exists( SFML_PLUGIN_DIR . 'inc/utilities.php' ) ) {
include SFML_PLUGIN_DIR . 'inc/utilities.php';
} else {
return $urls;
}
}
if ( ! class_exists( 'SFML_Options' ) && ! defined( 'SFML_NOOP_VERSION' ) ) {
if ( file_exists( SFML_PLUGIN_DIR . 'inc/class-sfml-options.php' ) ) {
include SFML_PLUGIN_DIR . 'inc/class-sfml-options.php';
} else {
return $urls;
}
}
$sfml_slugs = sfml_get_slugs();
$sfml_slugs = array_map( 'home_url', $sfml_slugs );
$sfml_slugs = array_map( 'trailingslashit', $sfml_slugs );
$sfml_slugs = array_map( 'rocket_clean_exclude_file', $sfml_slugs );
foreach ( $sfml_slugs as $key => $slug ) {
$sfml_slugs[ $key ] = $slug . '?';
}
return array_merge( $urls, $sfml_slugs );
}
/**
* Add SFML custom urls to caching exclusion when activating the plugin
*
* @since 2.9.3
*/
function rocket_activate_sfml() {
if ( defined( 'SFML_VERSION' ) ) {
add_filter( 'rocket_cache_reject_uri', 'rocket_add_sfml_exclude_pages' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
}
add_action( 'activate_sf-move-login/sf-move-login.php', 'rocket_activate_sfml', 11 );
/**
* Remove SFML custom urls from caching exclusion when deactivating the plugin
*
* @since 2.9.3
*/
function rocket_deactivate_sfml() {
if ( defined( 'SFML_VERSION' ) ) {
remove_filter( 'rocket_cache_reject_uri', 'rocket_add_sfml_exclude_pages' );
// Update the WP Rocket rules on the .htaccess.
flush_rocket_htaccess();
// Regenerate the config file.
rocket_generate_config_file();
}
}
add_action( 'deactivate_sf-move-login/sf-move-login.php', 'rocket_deactivate_sfml', 11 );

View File

@@ -0,0 +1,62 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WPS_Hide_Login' ) || defined( 'WPS_HIDE_LOGIN_VERSION' ) ) :
add_action( 'update_option_whl_page', 'rocket_after_update_single_options', 10, 2 );
add_filter( 'rocket_cache_reject_uri', 'rocket_exlude_wps_hide_login_page' );
endif;
/**
* Exclude WPS Hide Login custom url from caching
*
* @since 3.1 Switch implementation depending on the WPS Hide Login version
* @since 2.11.7 Login url is retrieved using new_login_url() method of WPS_Hide_Login() class.
* @since 2.11 Moved to 3rd party file
* @since 2.6
*
* @param array $urls An array of URLs to exclude from cache.
* @return array Updated array of URLs
*/
function rocket_exlude_wps_hide_login_page( $urls ) {
if ( class_exists( 'WPS_Hide_Login' ) ) {
$wps_hide_login = new WPS_Hide_Login();
$urls[] = rocket_clean_exclude_file( $wps_hide_login->new_login_url() );
} elseif ( class_exists( '\WPS\WPS_Hide_Login\Plugin' ) ) {
$urls[] = rocket_clean_exclude_file( \WPS\WPS_Hide_Login\Plugin::get_instance()->new_login_url() );
}
return $urls;
}
/**
* Add WPS Hide Login custom url to caching exclusion when activating the plugin
*
* @since 2.11
*/
function rocket_activate_wps_hide_login() {
add_filter( 'rocket_cache_reject_uri', 'rocket_exlude_wps_hide_login_page' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Update config file.
rocket_generate_config_file();
}
add_action( 'activate_wps-hide-login/wps-hide-login.php', 'rocket_activate_wps_hide_login', 11 );
/**
* Remove WPS Hide Login custom url from caching exclusion when deactivating the plugin
*
* @since 2.11
*/
function rocket_deactivate_wps_hide_login() {
remove_filter( 'rocket_cache_reject_uri', 'rocket_exlude_wps_hide_login_page' );
// Update .htaccess file rules.
flush_rocket_htaccess();
// Update config file.
rocket_generate_config_file();
}
add_action( 'deactivate_wps-hide-login/wps-hide-login.php', 'rocket_deactivate_wps_hide_login', 11 );

View File

@@ -0,0 +1,101 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'AIOSEOP_VERSION' ) ) :
$aioseosp_options = get_option( 'aioseop_options' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
/**
* Improvement with All in One SEO Pack: auto-detect the XML sitemaps for the preload option
*
* @since 2.8
* @author Remy Perona
*/
if ( isset( $aioseosp_options['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_sitemap'] ) && 'on' === $aioseosp_options['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_sitemap'] ) {
/**
* Add All in One SEO Sitemap option to WP Rocket options
*
* @since 2.8
* @author Remy Perona
*
* @param Array $options Array of WP Rocket options.
* @return Array Updated array of WP Rocket options
*/
function rocket_add_all_in_one_seo_sitemap_option( $options ) {
$options['all_in_one_seo_xml_sitemap'] = 0;
return $options;
}
add_filter( 'rocket_first_install_options', 'rocket_add_all_in_one_seo_sitemap_option' );
/**
* Sanitize the AIO SEO option value
*
* @since 2.8
* @author Remy Perona
*
* @param Array $inputs Array of inputs values.
* @return Array Updated array of inputs $values
*/
function rocket_all_in_one_seo_sitemap_option_sanitize( $inputs ) {
$inputs['all_in_one_seo_xml_sitemap'] = ! empty( $inputs['all_in_one_seo_xml_sitemap'] ) ? 1 : 0;
return $inputs;
}
add_filter( 'rocket_inputs_sanitize', 'rocket_all_in_one_seo_sitemap_option_sanitize' );
/**
* Add All in One SEO Sitemap to the preload list
*
* @since 2.8
* @author Remy Perona
*
* @param Array $sitemaps Array of sitemaps to preload.
* @return Array Updated array of sitemaps to preload
*/
function rocket_add_all_in_one_seo_sitemap( $sitemaps ) {
if ( ! get_rocket_option( 'all_in_one_seo_xml_sitemap', false ) ) {
return $sitemaps;
}
$aioseosp_options = get_option( 'aioseop_options' );
if ( ! isset( $aioseosp_options['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_sitemap'] ) || 'on' !== $aioseosp_options['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_sitemap'] ) {
return $sitemaps;
}
$sitemaps[] = trailingslashit( home_url() ) . apply_filters( 'aiosp_sitemap_filename', 'sitemap' ) . '.xml'; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
return $sitemaps;
}
add_filter( 'rocket_sitemap_preload_list', 'rocket_add_all_in_one_seo_sitemap' );
/**
* Add All in One SEO Sitemap sub-option on WP Rocket settings page
*
* @since 2.8
* @author Remy Perona
*
* @param Array $options Array of WP Rocket options.
* @return Array Updated array of WP Rocket options
*/
function rocket_sitemap_preload_all_in_one_seo_option( $options ) {
$options['all_in_one_seo_xml_sitemap'] = [
'type' => 'checkbox',
'container_class' => [
'wpr-field--children',
],
'label' => __( 'All in One SEO XML sitemap', 'rocket' ),
// translators: %s = Name of the plugin.
'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'All in One SEO' ),
'parent' => 'sitemap_preload',
'section' => 'preload_section',
'page' => 'preload',
'default' => 0,
'sanitize_callback' => 'sanitize_checkbox',
];
return $options;
}
add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_preload_all_in_one_seo_option' );
}
endif;

View File

@@ -0,0 +1,30 @@
<?php
/**
* Compatibility with Premium SEO Pack
*
* @link http://premiumseopack.com
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'psp' ) ) {
/**
* Dequeue the stylesheet of Premium SEO Pack on WP Rocket settings page.
*
* @since 2.11.6
* @author Arun Basil Lal
*/
function rocket_dequeue_premium_seo_pack_stylesheet() {
// Retun on all pages but WP Rocket settings page.
$screen = get_current_screen();
if ( 'settings_page_wprocket' !== $screen->id ) {
return;
}
// Dequeueing this stylesheet unfreezes WP Rocket.
wp_dequeue_style( 'psp-main-style' );
}
add_action( 'admin_print_styles', 'rocket_dequeue_premium_seo_pack_stylesheet', 11 );
}

View File

@@ -0,0 +1,91 @@
<?php
/**
* The wp-rocket compatibility functionality.
*
* @since 3.2.3
* @package Rank Math
* @subpackage RankMath\Compatibility
* @author MyThemeShop <admin@mythemeshop.com>
*/
defined( 'ABSPATH' ) || exit;
// Ealry Bail!!
if ( ! defined( 'RANK_MATH_FILE' ) || ! \RankMath\Helper::is_module_active( 'sitemap' ) ) {
return;
}
/**
* Add sitemap option to WP Rocket settings
*
* @since 3.2.3
*
* @param array $options WP Rocket settings array.
* @return array Updated WP Rocket settings array
*/
function rank_math_rocket_sitemap_preload_option( $options ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
$options['rank_math_xml_sitemap'] = [
'type' => 'checkbox',
'container_class' => [
'wpr-field--children',
],
'label' => __( 'Rank Math XML sitemap', 'rocket' ),
// translators: %s = Name of the plugin.
'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'Rank Math SEO' ),
'parent' => 'sitemap_preload',
'section' => 'preload_section',
'page' => 'preload',
'default' => 0,
'sanitize_callback' => 'sanitize_checkbox',
];
return $options;
}
add_filter( 'rocket_sitemap_preload_options', 'rank_math_rocket_sitemap_preload_option' );
/**
* Add sitemap option to WP Rocket default options
*
* @since 3.2.3
*
* @param array $options WP Rocket options array.
* @return array Updated WP Rocket options array
*/
function rank_math_rocket_add_sitemap_option( $options ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
$options['rank_math_xml_sitemap'] = 0;
return $options;
}
add_filter( 'rocket_first_install_options', 'rank_math_rocket_add_sitemap_option' );
/**
* Sanitize SEO sitemap option value
*
* @since 3.2.3
*
* @param array $inputs WP Rocket inputs array.
* @return array Sanitized WP Rocket inputs array
*/
function rank_math_rocket_sitemap_option_sanitize( $inputs ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
$inputs['rank_math_xml_sitemap'] = ! empty( $inputs['rank_math_xml_sitemap'] ) ? 1 : 0;
return $inputs;
}
add_filter( 'rocket_inputs_sanitize', 'rank_math_rocket_sitemap_option_sanitize' );
/**
* Add SEO sitemap URL to the sitemaps to preload
*
* @since 3.2.3
*
* @param array $sitemaps Sitemaps to preload.
* @return array Updated Sitemaps to preload
*/
function rank_math_rocket_sitemap( $sitemaps ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
if ( get_rocket_option( 'rank_math_xml_sitemap', false ) ) {
$sitemaps[] = \RankMath\Sitemap\Router::get_base_url( 'sitemap_index.xml' );
}
return $sitemaps;
}
add_filter( 'rocket_sitemap_preload_list', 'rank_math_rocket_sitemap' );

View File

@@ -0,0 +1,98 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( function_exists( 'seopress_get_toggle_xml_sitemap_option' ) && 1 === (int) seopress_get_toggle_xml_sitemap_option() ) :
/**
* Improvement with SEOPress: auto-detect the XML sitemaps for the preload option
*
* @since 3.3.6
* @author Benjamin Denis
* @source ./yoast-seo.php (Remy Perona)
*/
if ( function_exists( 'seopress_xml_sitemap_general_enable_option' ) && 1 === (int) seopress_xml_sitemap_general_enable_option() ) {
/**
* Add SEOPress sitemap option to WP Rocket default options
*
* @since 3.3.6
* @author Benjamin Denis
* @source ./yoast-seo.php (Remy Perona)
*
* @param array $options WP Rocket options array.
* @return array Updated WP Rocket options array
*/
function rocket_add_seopress_sitemap_option( $options ) {
$options['seopress_xml_sitemap'] = 0;
return $options;
}
add_filter( 'rocket_first_install_options', 'rocket_add_seopress_sitemap_option' );
/**
* Sanitize SEOPress sitemap option value
*
* @since 3.3.6
* @author Benjamin Denis
* @source ./yoast-seo.php (Remy Perona)
*
* @param array $inputs WP Rocket inputs array.
* @return array Sanitized WP Rocket inputs array
*/
function rocket_seopress_sitemap_option_sanitize( $inputs ) {
$inputs['seopress_xml_sitemap'] = ! empty( $inputs['seopress_xml_sitemap'] ) ? 1 : 0;
return $inputs;
}
add_filter( 'rocket_inputs_sanitize', 'rocket_seopress_sitemap_option_sanitize' );
/**
* Add SEOPress sitemap URL to the sitemaps to preload
*
* @since 3.3.6
* @author Benjamin Denis
* @source ./yoast-seo.php (Remy Perona)
*
* @param array $sitemaps Sitemaps to preload.
* @return array Updated Sitemaps to preload
*/
function rocket_add_seopress_sitemap( $sitemaps ) {
if ( get_rocket_option( 'seopress_xml_sitemap', false ) ) {
$sitemaps[] = get_home_url() . '/sitemaps.xml';
}
return $sitemaps;
}
add_filter( 'rocket_sitemap_preload_list', 'rocket_add_seopress_sitemap' );
/**
* Add SEOPress option to WP Rocket settings
*
* @since 3.3.6
* @author Benjamin Denis
* @source ./yoast-seo.php (Remy Perona)
*
* @param array $options WP Rocket settings array.
* @return array Updated WP Rocket settings array
*/
function rocket_sitemap_preload_seopress_option( $options ) {
$options['seopress_xml_sitemap'] = [
'type' => 'checkbox',
'container_class' => [
'wpr-field--children',
],
'label' => __( 'SEOPress XML sitemap', 'rocket' ),
// translators: %s = Name of the plugin.
'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'SEOPress' ),
'parent' => 'sitemap_preload',
'section' => 'preload_section',
'page' => 'preload',
'default' => 0,
'sanitize_callback' => 'sanitize_checkbox',
];
return $options;
}
add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_preload_seopress_option' );
}
endif;

View File

@@ -0,0 +1,153 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* This file is loaded at plugins_loaded, priority 10.
* This function is available at plugins_loaded, priority 5:
*/
if ( ! function_exists( 'the_seo_framework' ) ) {
return;
}
rocket_add_tsf_compat();
/**
* Runs detection and adds extra compatibility for The SEO Framework plugin.
*
* @since 3.2.1
* @since TODO Removed "conflicting sitemap detection" (detect_sitemap_plugin) call.
* TSF always tries to output it now while trying to give WP Rewrite priority for display.
* @author Sybre Waaijer
*/
function rocket_add_tsf_compat() {
$tsf = the_seo_framework();
// Either TSF < 3.1, or the plugin's silenced (soft-disabled) via a drop-in.
if ( empty( $tsf->loaded ) ) {
return;
}
/**
* 1. Performs option & other checks.
* 2. Checks for conflicting sitemap plugins that might prevent loading.
*
* These methods cache their output at runtime.
*
* @link https://github.com/wp-media/wp-rocket/issues/899
*/
if ( $tsf->can_run_sitemap() ) {
rocket_add_tsf_sitemap_compat();
}
}
/**
* Adds compatibility for the sitemap functionality in The SEO Framework plugin.
*
* @since 3.2.1
* @author Sybre Waaijer
*/
function rocket_add_tsf_sitemap_compat() {
add_filter( 'rocket_first_install_options', 'rocket_add_tsf_seo_sitemap_option' );
add_filter( 'rocket_inputs_sanitize', 'rocket_tsf_seo_sitemap_option_sanitize' );
add_filter( 'rocket_sitemap_preload_list', 'rocket_add_tsf_sitemap_to_preload' );
add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_add_tsf_sitemap_to_preload_option' );
}
/**
* Adds a sitemap option in WP Rocket for The SEO Framework.
*
* @since 3.2.1
* @author Sybre Waaijer
* @source ./yoast-seo.php (Remy Perona)
*
* @param array $options WP Rocket options array.
* @return array Updated WP Rocket options array
*/
function rocket_add_tsf_seo_sitemap_option( $options ) {
$options['tsf_xml_sitemap'] = 0;
return $options;
}
/**
* Sanitizes the added sitemap option for The SEO Framework.
*
* @since 3.2.1
* @author Sybre Waaijer
* @source ./yoast-seo.php (Remy Perona)
*
* @param array $inputs WP Rocket inputs array.
* @return array Sanitized WP Rocket inputs array
*/
function rocket_tsf_seo_sitemap_option_sanitize( $inputs ) {
$inputs['tsf_xml_sitemap'] = ! empty( $inputs['tsf_xml_sitemap'] ) ? 1 : 0;
return $inputs;
}
/**
* Adds TSF sitemap URLs to preload.
*
* @since 3.2.1
* @since TODO Added compatibility support for The SEO Framework v4.0+
* @author Sybre Waaijer
* @source ./yoast-seo.php (Remy Perona)
*
* @param array $sitemaps Sitemaps to preload.
* @return array Updated Sitemaps to preload
*/
function rocket_add_tsf_sitemap_to_preload( $sitemaps ) {
if ( get_rocket_option( 'tsf_xml_sitemap', false ) ) {
// The autoloader in TSF doesn't check for file_exists(). So, use version compare instead to prevent fatal errors.
if ( version_compare( THE_SEO_FRAMEWORK_VERSION, '4.0', '>=' ) ) {
// TSF 4.0+. Expect the class to exist indefinitely.
$sitemap_bridge = The_SEO_Framework\Bridges\Sitemap::get_instance();
foreach ( $sitemap_bridge->get_sitemap_endpoint_list() as $id => $data ) {
// When the sitemap is good enough for a robots display, we determine it as valid for precaching.
// Non-robots display types are among the stylesheet endpoint, or the Yoast SEO-compatible endpoint.
// In other words, this enables support for ALL current and future public sitemap endpoints.
if ( ! empty( $data['robots'] ) ) {
$sitemaps[] = $sitemap_bridge->get_expected_sitemap_endpoint_url( $id );
}
}
} else {
// Deprecated. TSF <4.0.
$sitemaps[] = the_seo_framework()->get_sitemap_xml_url();
}
}
return $sitemaps;
}
/**
* Add The SEO Framework SEO option to WP Rocket settings
*
* @since 3.2.1
* @author Sybre Waaijer
* @source ./yoast-seo.php (Remy Perona)
*
* @param array $options WP Rocket settings array.
* @return array Updated WP Rocket settings array
*/
function rocket_sitemap_add_tsf_sitemap_to_preload_option( $options ) {
$options['tsf_xml_sitemap'] = [
'type' => 'checkbox',
'container_class' => [
'wpr-field--children',
],
'label' => __( 'The SEO Framework XML sitemap', 'rocket' ),
// translators: %s = Name of the plugin.
'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'The SEO Framework' ),
'parent' => 'sitemap_preload',
'section' => 'preload_section',
'page' => 'preload',
'default' => 0,
'sanitize_callback' => 'sanitize_checkbox',
];
return $options;
}

View File

@@ -0,0 +1,99 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( defined( 'WPSEO_VERSION' ) && class_exists( 'WPSEO_Sitemaps_Router' ) ) :
$yoast_seo_xml = get_option( 'wpseo_xml' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
if ( version_compare( WPSEO_VERSION, '7.0' ) >= 0 ) {
$yoast_seo = get_option( 'wpseo' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
$yoast_seo_xml['enablexmlsitemap'] = isset( $yoast_seo['enable_xml_sitemap'] ) && $yoast_seo['enable_xml_sitemap']; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
}
/**
* Improvement with Yoast SEO: auto-detect the XML sitemaps for the preload option
*
* @since 2.8
* @author Remy Perona
*/
if ( true === $yoast_seo_xml['enablexmlsitemap'] ) {
/**
* Add Yoast SEO sitemap option to WP Rocket default options
*
* @since 2.8
* @author Remy Perona
*
* @param array $options WP Rocket options array.
* @return array Updated WP Rocket options array
*/
function rocket_add_yoast_seo_sitemap_option( $options ) {
$options['yoast_xml_sitemap'] = 0;
return $options;
}
add_filter( 'rocket_first_install_options', 'rocket_add_yoast_seo_sitemap_option' );
/**
* Sanitize Yoast SEO sitemap option value
*
* @since 2.8
* @author Remy Perona
*
* @param array $inputs WP Rocket inputs array.
* @return array Sanitized WP Rocket inputs array
*/
function rocket_yoast_seo_sitemap_option_sanitize( $inputs ) {
$inputs['yoast_xml_sitemap'] = ! empty( $inputs['yoast_xml_sitemap'] ) ? 1 : 0;
return $inputs;
}
add_filter( 'rocket_inputs_sanitize', 'rocket_yoast_seo_sitemap_option_sanitize' );
/**
* Add Yoast SEO sitemap URL to the sitemaps to preload
*
* @since 2.8
* @author Remy Perona
*
* @param array $sitemaps Sitemaps to preload.
* @return array Updated Sitemaps to preload
*/
function rocket_add_yoast_seo_sitemap( $sitemaps ) {
if ( get_rocket_option( 'yoast_xml_sitemap', false ) ) {
$sitemaps[] = WPSEO_Sitemaps_Router::get_base_url( 'sitemap_index.xml' );
}
return $sitemaps;
}
add_filter( 'rocket_sitemap_preload_list', 'rocket_add_yoast_seo_sitemap' );
/**
* Add Yoast SEO option to WP Rocket settings
*
* @since 2.8
* @author Remy Perona
*
* @param array $options WP Rocket settings array.
* @return array Updated WP Rocket settings array
*/
function rocket_sitemap_preload_yoast_seo_option( $options ) {
$options['yoast_xml_sitemap'] = [
'type' => 'checkbox',
'container_class' => [
'wpr-field--children',
],
'label' => __( 'Yoast SEO XML sitemap', 'rocket' ),
// translators: %s = Name of the plugin.
'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'Yoast SEO' ),
'parent' => 'sitemap_preload',
'section' => 'preload_section',
'page' => 'preload',
'default' => 0,
'sanitize_callback' => 'sanitize_checkbox',
];
return $options;
}
add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_preload_yoast_seo_option' );
}
endif;

View File

@@ -0,0 +1,13 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Conflict with LayerSlider: don't add width and height attributes on all images
*
* @since 2.1
*/
function rocket_deactivate_specify_image_dimensions_with_layerslider() {
remove_filter( 'rocket_buffer', 'rocket_specify_image_dimensions' );
}
add_action( 'layerslider_ready', 'rocket_deactivate_specify_image_dimensions_with_layerslider' );

View File

@@ -0,0 +1,17 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Conflict with Meta Slider (Nivo Slider): don't apply LazyLoad on all images
*
* @since 2.4
*
* @param array $slide Slide attributes.
* @return array Updated slide attributes
*/
function rocket_deactivate_lazyload_on_metaslider( $slide ) {
$slide['data-no-lazy'] = 1;
return $slide;
}
add_filter( 'metaslider_nivo_slider_image_attributes', 'rocket_deactivate_lazyload_on_metaslider' );

View File

@@ -0,0 +1,31 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Conflict with Soliloquy: don't apply LazyLoad on all images
*
* @since 2.4.2
*
* @param string $attr Image attributes.
* @return string Updated attributes
*/
function rocket_deactivate_lazyload_on_soliloquy( $attr ) {
return $attr . ' data-no-lazy="1" ';
}
add_filter( 'soliloquy_output_image_attr', 'rocket_deactivate_lazyload_on_soliloquy', PHP_INT_MAX );
/**
* Conflict with Soliloquy: don't apply LazyLoad on all images
*
* @since 2.4.2
*
* @param string $images Image HTML code.
* @return string Updated image HTML code
*/
function rocket_deactivate_lazyload_on_soliloquy_indexable_images( $images ) {
$images = str_replace( '<img', '<img data-no-lazy="1" ', $images );
return $images;
}
add_filter( 'soliloquy_indexable_images', 'rocket_deactivate_lazyload_on_soliloquy_indexable_images', PHP_INT_MAX );

View File

@@ -0,0 +1,53 @@
<?php
/**
* Compatibility with SumoMe
*
* Prevents conflict with SumoMe and the WP Rocket UI by removing SumoMe
* styles and scripts on WP Rocket admin pages.
*
* @link https://wordpress.org/plugins/sumome/
* @since 3.0.4
*/
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'WP_Plugin_SumoMe' ) ) {
/**
* Dequeue SumoMe styles
*
* @since 3.0.4
* @author Arun Basil Lal
*/
function rocket_dequeue_sumo_me_css() {
// Retun on all pages but WP Rocket settings page.
$screen = get_current_screen();
if ( 'settings_page_wprocket' !== $screen->id ) {
return;
}
wp_dequeue_style( 'sumome-admin-styles' );
wp_dequeue_style( 'sumome-admin-media' );
}
add_action( 'admin_enqueue_scripts', 'rocket_dequeue_sumo_me_css', PHP_INT_MAX );
/**
* Dequeue SumoMe inline script
*
* @since 3.0.4
* @author Arun Basil Lal
*/
function rocket_dequeue_sumo_me_js() {
// Retun on all pages but WP Rocket settings page.
$screen = get_current_screen();
if ( 'settings_page_wprocket' !== $screen->id ) {
return;
}
global $wp_plugin_sumome;
remove_action( 'admin_footer', [ $wp_plugin_sumome, 'append_admin_script_code' ] );
}
add_action( 'admin_head', 'rocket_dequeue_sumo_me_js' );
}

View File

@@ -0,0 +1,13 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Conflict with Thrive Leads: override the DONOTCACHEPAGE behavior because this plugin add this constant!
*
* @since 2.5
*/
function rocket_override_donotcachepage_on_thrive_leads() {
return defined( 'TVE_LEADS_VERSION' ) && TVE_LEADS_VERSION > 0;
}
add_filter( 'rocket_override_donotcachepage', 'rocket_override_donotcachepage_on_thrive_leads' );

View File

@@ -0,0 +1,75 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( class_exists( 'VarnishPurger' ) ) :
add_action( 'admin_init', 'rocket_clear_cache_after_varnish_http_purge' );
/**
* Clear WP Rocket cache after purged the Varnish cache via Varnish HTTP Purge plugin
*
* @since 2.5.5
*
* @return void
*/
function rocket_clear_cache_after_varnish_http_purge() {
if ( isset( $_GET['vhp_flush_all'] ) && current_user_can( 'manage_options' ) && check_admin_referer( 'varnish-http-purge' ) ) {
// Clear all caching files.
rocket_clean_domain();
// Preload cache.
run_rocket_bot();
run_rocket_sitemap_preload();
}
}
endif;
add_action( 'after_rocket_clean_domain', 'rocket_clean_varnish_http_purge' );
/**
* Call the cache server to purge the cache with Varnish HTTP Purge.
*
* @since 2.5.5
*
* @return void
*/
function rocket_clean_varnish_http_purge() {
if ( class_exists( 'VarnishPurger' ) ) {
$url = home_url( '/?vhp-regex' );
$p = wp_parse_url( $url );
$path = '';
$pregex = '.*';
// Build a varniship.
if ( defined( 'VHP_VARNISH_IP' ) && VHP_VARNISH_IP ) {
$varniship = VHP_VARNISH_IP;
} else {
$varniship = get_option( 'vhp_varnish_ip' );
}
if ( isset( $p['path'] ) ) {
$path = $p['path'];
}
$schema = apply_filters( 'varnish_http_purge_schema', 'http://' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
// If we made varniship, let it sail.
if ( ! empty( $varniship ) ) {
$purgeme = $schema . $varniship . $path . $pregex;
} else {
$purgeme = $schema . $p['host'] . $path . $pregex;
}
wp_remote_request(
$purgeme,
[
'method' => 'PURGE',
'blocking' => false,
'headers' => [
'host' => $p['host'],
'X-Purge-Method' => 'regex',
],
]
);
do_action( 'after_purge_url', $url, $purgeme ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
}
}

View File

@@ -0,0 +1,38 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( is_admin() && function_exists( 'as3cf_assets_init' ) ) :
add_action( 'aws_init', 'rocket_as3cf_assets_compatibility', 13 );
add_action( 'update_option_as3cf_assets', 'rocket_maybe_deactivate_cdn', 10, 2 );
endif;
/**
* Compatibility with WP Offload S3 assets addon.
*
* @since 2.10.7
* @author Remy Perona
*/
function rocket_as3cf_assets_compatibility() {
global $as3cf_assets;
if ( isset( $as3cf_assets ) && $as3cf_assets->is_plugin_setup() && 1 === (int) $as3cf_assets->get_setting( 'enable-addon' ) ) {
// Disable WP Rocket CDN option.
add_filter( 'rocket_readonly_cdn_option', '__return_true' );
}
}
/**
* Deactivate WP Rocket CDN if WP Offload S3 assets addon copy & serve is active.
*
* @since 2.10.7
* @author Remy Perona
*
* @param string $old_value Previous assets option value.
* @param string $new_value New assets option value.
*/
function rocket_maybe_deactivate_cdn( $old_value, $new_value ) {
if ( $old_value['enable-addon'] !== $new_value['enable-addon'] && 1 === (int) $new_value['enable-addon'] ) {
update_rocket_option( 'cdn', 0 );
}
}

View File

@@ -0,0 +1,23 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( is_admin() && ( function_exists( 'as3cf_init' ) || function_exists( 'as3cf_pro_init' ) ) ) :
add_action( 'aws_init', 'rocket_as3cf_compatibility', 12 );
endif;
/**
* Compatibility with WP Offload S3.
*
* @since 2.10.7
* @author Remy Perona
*/
function rocket_as3cf_compatibility() {
global $as3cf;
if ( isset( $as3cf ) && $as3cf->is_plugin_setup() && 1 === (int) $as3cf->get_setting( 'serve-from-s3' ) ) {
// Remove images option from WP Rocket CDN dropdown settings.
add_filter( 'rocket_allow_cdn_images', '__return_false' );
}
}

View File

@@ -0,0 +1,19 @@
<?php
defined( 'ABSPATH' ) || exit;
if ( function_exists( 'print_link' ) ) :
/**
* Conflict with WP-Print: don't apply LazyLoad on print pages
*
* @since 2.6.8
*/
function rocket_deactivate_lazyload_on_print_pages() {
global $wp_query;
if ( isset( $wp_query->query_vars['print'] ) ) {
add_filter( 'do_rocket_lazyload', '__return_false' );
}
}
add_action( 'wp', 'rocket_deactivate_lazyload_on_print_pages' );
endif;

View File

@@ -0,0 +1,48 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Add WP REST API path to cache exclusion
*
* @since 2.5.12
*
* @param array $uri URLs to exclude from cache.
* @return array Updated URLs
*/
function rocket_exclude_wp_rest_api( $uri ) {
global $wp_rewrite;
/**
* By default, don't cache the WP REST API.
*
* @since 2.5.12
*
* @param bool false will force to cache the WP REST API
*/
$reject_wp_rest_api = apply_filters( 'rocket_cache_reject_wp_rest_api', true );
if ( ! $reject_wp_rest_api ) {
return $uri;
}
/**
* `(/[^/]+)?` is used instead of `(/.+)?` to match only one level.
* This prevents to match a taxonomy term named `wp-json` (on multisite, the main site's posts and taxonomy archives are prefixed with `blog` => example.com/blog/category/wp-json/).
*/
$prefix = rocket_is_subfolder_install() ? '(/[^/]+)?' : '';
$index = ! empty( $wp_rewrite->index ) ? $wp_rewrite->index : 'index.php';
$index = preg_quote( $index, '/' );
$suffix = rest_get_url_prefix();
$suffix = preg_quote( trim( $suffix, '/' ), '/' );
/**
* Results in:
* - Single site: (/index\.php)?/wp\-json(/.*|$)
* - Multisite: (/[^/]+)?(/index\.php)?/wp\-json(/.*|$)
*/
$uri[] = $prefix . '/(' . $index . '/)?' . $suffix . '(/.*|$)';
return $uri;
}
add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_wp_rest_api' );

View File

@@ -0,0 +1,68 @@
<?php
defined( 'ABSPATH' ) || exit;
$current_theme = wp_get_theme(); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
if ( 'Avada' === $current_theme->get( 'Name' ) ) {
// When Avada theme purge its own cache.
add_action( 'avada_clear_dynamic_css_cache', 'rocket_clean_domain' );
/**
* Deactivate WP Rocket lazyload if Avada lazyload is enabled
*
* @since 3.3.4
*
* @param string $old_value Previous Avada option value.
* @param string $value New Avada option value.
* @return void
*/
function rocket_avada_maybe_deactivate_lazyload( $old_value, $value ) {
if (
empty( $old_value['lazy_load'] )
||
( ! empty( $value['lazy_load'] ) && 'avada' === $value['lazy_load'] )
) {
update_rocket_option( 'lazyload', 0 );
}
}
add_action( 'update_option_fusion_options', 'rocket_avada_maybe_deactivate_lazyload', 10, 2 );
}
/**
* Disable WP Rocket lazyload field if Avada lazyload is enabled
*
* @since 3.3.4
*
* @return bool
*/
function rocket_avada_maybe_disable_lazyload() {
$avada_options = get_option( 'fusion_options' );
$current_theme = wp_get_theme();
if ( 'Avada' !== $current_theme->get( 'Name' ) ) {
return false;
}
if ( empty( $avada_options['lazy_load'] ) ) {
return false;
}
if ( ! empty( $avada_options['lazy_load'] && 'avada' !== $avada_options['lazy_load'] ) ) {
return false;
}
return true;
}
/**
* Clears WP Rocket's cache after Avada's Fusion Patcher flushes their caches
*
* @since 3.3.5
*
* @return void
*/
function rocket_avada_clear_cache_fusion_patcher() {
rocket_clean_domain();
}
add_action( 'fusion_cache_reset_after', 'rocket_avada_clear_cache_fusion_patcher' );

View File

@@ -0,0 +1,44 @@
<?php
defined( 'ABSPATH' ) || exit;
add_action( 'admin_init', 'rocket_clear_cache_after_studiopress_accelerator' );
/**
* Clear WP Rocket cache after purged the StudioPress Accelerator cache
*
* @since 2.5.5
*
* @return void
*/
function rocket_clear_cache_after_studiopress_accelerator() {
if ( isset( $GLOBALS['sp_accel_nginx_proxy_cache_purge'] ) && is_a( $GLOBALS['sp_accel_nginx_proxy_cache_purge'], 'SP_Accel_Nginx_Proxy_Cache_Purge' ) && isset( $_REQUEST['_wpnonce'] ) ) {
$nonce = $_REQUEST['_wpnonce']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Recommended
if ( wp_verify_nonce( $nonce, 'sp-accel-purge-url' ) && ! empty( $_REQUEST['cache-purge-url'] ) ) {
$submitted_url = sanitize_text_field( wp_unslash( $_REQUEST['cache-purge-url'] ) );
// Clear the URL.
rocket_clean_files( [ $submitted_url ] );
} elseif ( wp_verify_nonce( $nonce, 'sp-accel-purge-theme' ) ) {
// Clear all caching files.
rocket_clean_domain();
// Preload cache.
run_rocket_bot();
run_rocket_sitemap_preload();
}
}
}
add_action( 'after_rocket_clean_domain', 'rocket_clean_studiopress_accelerator' );
/**
* Call the cache server to purge the cache with StudioPress Accelerator.
*
* @since 2.5.5
*
* @return void
*/
function rocket_clean_studiopress_accelerator() {
if ( isset( $GLOBALS['sp_accel_nginx_proxy_cache_purge'] ) && is_a( $GLOBALS['sp_accel_nginx_proxy_cache_purge'], 'SP_Accel_Nginx_Proxy_Cache_Purge' ) ) {
$GLOBALS['sp_accel_nginx_proxy_cache_purge']->cache_flush_theme();
}
}

View File

@@ -0,0 +1,64 @@
<?php
defined( 'ABSPATH' ) || exit;
$current_theme = wp_get_theme(); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
if ( 'uncode' === strtolower( $current_theme->get( 'Name' ) ) || 'uncode' === strtolower( $current_theme->get( 'Template' ) ) ) {
/**
* Excludes Uncode init and ai-uncode JS files from minification/combine
*
* @since 3.1
* @author Remy Perona
*
* @param array $excluded_js Array of JS filepaths to be excluded.
* @return array
*/
function rocket_exclude_js_uncode( $excluded_js ) {
$excluded_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/init.js' );
$excluded_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/min/init.min.js' );
$excluded_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/ai-uncode.js' );
$excluded_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/min/ai-uncode.min.js' );
return $excluded_js;
}
add_filter( 'rocket_exclude_js', 'rocket_exclude_js_uncode' );
/**
* Excludes some Uncode inline scripts from combine JS
*
* @since 3.1
* @author Remy Perona
*
* @param array $inline_js Array of patterns to match for exclusion.
* @return array
*/
function rocket_exclude_inline_js_uncode( $inline_js ) {
$inline_js[] = 'SiteParameters';
$inline_js[] = 'script-';
$inline_js[] = 'initBox';
$inline_js[] = 'initHeader';
$inline_js[] = 'fixMenuHeight';
return $inline_js;
}
add_filter( 'rocket_excluded_inline_js_content', 'rocket_exclude_inline_js_uncode' );
if ( version_compare( $current_theme->get( 'Version' ), '2.1', '<' ) ) {
/**
* Excludes Uncode JS files from defer JS
*
* @since 3.2.5
* @author Remy Perona
*
* @param array $exclude_defer_js Array of JS filepaths to be excluded.
* @return array
*/
function rocket_exclude_defer_js_uncode( $exclude_defer_js ) {
$exclude_defer_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/init.js' );
$exclude_defer_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/min/init.min.js' );
return $exclude_defer_js;
}
add_filter( 'rocket_exclude_defer_js', 'rocket_exclude_defer_js_uncode' );
}
}

View File

@@ -0,0 +1,31 @@
<?php
defined( 'ABSPATH' ) || exit;
/**
* Indicate to bypass rocket optimizations.
*
* Checks for "nowprocket" query string in the url to bypass rocket processes.
*
* @since 3.7
*
* @return bool True to indicate should bypass; false otherwise.
*/
function rocket_bypass() {
global $wp;
static $bypass = null;
if ( rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ) {
$bypass = null;
}
if ( ! is_null( $bypass ) ) {
return $bypass;
}
$url = wp_parse_url( add_query_arg( $wp->query_vars, home_url( $wp->request ) ) );
$bypass = isset( $url['query'] ) && false !== strpos( $url['query'], 'nowprocket' );
return $bypass;
}

View File

@@ -0,0 +1,112 @@
<?php
defined( 'ABSPATH' ) || exit;
use WP_Rocket\Engine\Preload\FullProcess;
use WP_Rocket\Engine\Preload\Homepage;
use WP_Rocket\Engine\Preload\Sitemap;
/**
* Launches the Homepage preload (helper function for backward compatibility)
*
* @since 2.6.4 Don't preload localhost & .dev domains
* @since 1.0
*
* @param string $spider (default: 'cache-preload') The spider name: cache-preload or cache-json.
* @param string $lang (default: '') The language code to preload.
* @return false
*/
function run_rocket_bot( $spider = 'cache-preload', $lang = '' ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
if ( ! get_rocket_option( 'manual_preload' ) ) {
return;
}
$urls = [];
if ( ! $lang ) {
$urls = get_rocket_i18n_uri();
} else {
$urls[] = get_rocket_i18n_home_url( $lang );
}
$homepage_preload = new Homepage( new FullProcess() );
$homepage_preload->preload( $urls );
}
/**
* Launches the sitemap preload (helper function for backward compatibility)
*
* @since 2.8
* @author Remy Perona
*
* @return void
*/
function run_rocket_sitemap_preload() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
if ( ! get_rocket_option( 'sitemap_preload' ) || ! get_rocket_option( 'manual_preload' ) ) {
return;
}
/**
* Filters the sitemaps list to preload
*
* @since 2.8
*
* @param array Array of sitemaps URL
*/
$sitemaps = apply_filters( 'rocket_sitemap_preload_list', get_rocket_option( 'sitemaps', false ) );
$sitemaps = array_flip( array_flip( $sitemaps ) );
if ( ! $sitemaps ) {
return;
}
$sitemap_preload = new Sitemap( new FullProcess() );
$sitemap_preload->run_preload( $sitemaps );
}
/**
* Launches the preload cache from the admin bar or the dashboard button
*
* @since 1.3.0 Compatibility with WPML
* @since 1.0 (delete in 1.1.6 and re-add in 1.1.9)
* @deprecated 3.2
*/
function do_admin_post_rocket_preload_cache() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
if ( empty( $_GET['_wpnonce'] ) ) {
wp_safe_redirect( wp_get_referer() );
die();
}
if ( ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'preload' ) ) {
wp_nonce_ays( '' );
}
if ( ! current_user_can( 'rocket_preload_cache' ) ) {
wp_safe_redirect( wp_get_referer() );
die();
}
$preload_process = new FullProcess();
if ( $preload_process->is_process_running() ) {
wp_safe_redirect( wp_get_referer() );
die();
}
delete_transient( 'rocket_preload_errors' );
$lang = isset( $_GET['lang'] ) && 'all' !== $_GET['lang'] ? sanitize_key( $_GET['lang'] ) : '';
run_rocket_bot( 'cache-preload', $lang );
run_rocket_sitemap_preload();
if ( ! strpos( wp_get_referer(), 'wprocket' ) ) {
set_transient( 'rocket_preload_triggered', 1 );
}
wp_safe_redirect( wp_get_referer() );
die();
}
add_action( 'admin_post_nopriv_preload', 'do_admin_post_rocket_preload_cache' );
add_action( 'admin_post_preload', 'do_admin_post_rocket_preload_cache' );

View File

@@ -0,0 +1,58 @@
<?php
namespace WP_Rocket\Addon\Busting;
use WP_Rocket\Addon\GoogleTracking\GoogleAnalytics;
use WP_Rocket\Addon\GoogleTracking\GoogleTagManager;
use WP_Rocket\Busting\Facebook_Pickles;
use WP_Rocket\Busting\Facebook_SDK;
/**
* Busting classes Factory
*
* @since 3.6.2
*/
class BustingFactory {
/**
* Base cache busting filepath.
*
* @var string
*/
private $busting_path;
/**
* Base cache busting URL.
*
* @var string
*/
private $busting_url;
/**
* Constructor
*
* @param string $busting_path Base cache busting filepath.
* @param string $busting_url Base cache busting URL.
*/
public function __construct( $busting_path, $busting_url ) {
$this->busting_path = $busting_path;
$this->busting_url = $busting_url;
}
/**
* Creator method
*
* @param string $type Type of busting class to create.
* @return Busting_Interface
*/
public function type( $type ) {
switch ( $type ) {
case 'fbpix':
return new Facebook_Pickles( $this->busting_path, $this->busting_url );
case 'fbsdk':
return new Facebook_SDK( $this->busting_path, $this->busting_url );
case 'ga':
return new GoogleAnalytics( $this->busting_path, $this->busting_url );
case 'gtm':
return new GoogleTagManager( $this->busting_path, $this->busting_url, new GoogleAnalytics( $this->busting_path, $this->busting_url ) );
}
}
}

View File

@@ -0,0 +1,478 @@
<?php
namespace WP_Rocket\Addon\Busting;
use WP_Rocket\Logger\Logger;
trait FileBustingTrait {
/**
* Saves the content of the URL to bust to the busting file if it doesn't exist yet.
*
* @since 3.2.4
* @access public
*
* @param string $url URL to get the content from.
* @return bool
*/
public function save( $url ) {
if ( $this->get_busting_version() ) {
// We have a local copy.
Logger::debug(
'Found local file.',
[
self::LOGGER_CONTEXT,
'path' => $this->get_busting_path(),
]
);
return true;
}
if ( $this->refresh_save( $url ) ) {
// We downloaded a fresh copy.
Logger::debug(
'New copy downloaded.',
[
self::LOGGER_CONTEXT,
'path' => $this->get_busting_path(),
]
);
return true;
}
return false;
}
/**
* Deletes the busting file.
*
* @since 3.1
* @since 3.2.4 Handle versioning.
* @access public
* @author Remy Perona
* @author Grégory Viguier
*
* @return bool True on success. False on failure.
*/
public function delete() {
$files = $this->get_all_files();
if ( false === $files ) {
// Error.
return false;
}
$this->file_version = null;
if ( ! $files ) {
// No local files yet.
return true;
}
return $this->delete_files( array_keys( $files ) );
}
/** ----------------------------------------------------------------------------------------- */
/** LOCAL FILE ============================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the version of the current busting file.
*
* @since 3.2.4
* @access protected
* @author Grégory Viguier
*
* @return string|bool Version of the file. False if the file does not exist.
*/
protected function get_busting_version() {
if ( ! empty( $this->file_version ) ) {
return $this->file_version;
}
$files = $this->get_all_files();
if ( ! $files ) {
// Error or no local files yet.
return false;
}
// Since we're not supposed to have several files, return the first one.
$this->file_version = reset( $files );
return $this->file_version;
}
/**
* Get all cached files in the directory.
* In a perfect world, there should be only one.
*
* @since 3.2.4
* @access private
*
* @return bool|array A list of file names (as array keys) and versions (as array values). False on failure.
*/
private function get_all_files() {
$dir_path = rtrim( $this->busting_path, '\\/' );
if ( ! $this->filesystem->exists( $dir_path ) ) {
return [];
}
if ( ! $this->filesystem->is_readable( $dir_path ) ) {
Logger::error(
'Directory is not readable.',
[
self::LOGGER_CONTEXT,
'path' => $dir_path,
]
);
return false;
}
$pattern = '/' . sprintf(
$this->escape_file_name( $this->filename_pattern ),
'([a-f0-9]{32}|local)'
) . '/';
$entries = _rocket_get_dir_files_by_regex( $dir_path, $pattern );
$list = [];
foreach ( $entries as $entry ) {
$filename = $entry->getFilename();
preg_match( $pattern, $filename, $file_details_match );
if ( ! empty( $file_details_match[1] ) ) {
$list[ $filename ] = $file_details_match[1];
}
}
return $list;
}
/**
* Get the final URL for the current cache busting file.
*
* @since 3.2.4
* @access protected
*
* @return string|bool URL of the file. False if the file does not exist.
*/
public function get_busting_url() {
return $this->get_busting_file_url( $this->get_busting_version() );
}
/**
* Get the path to the current cache busting file.
*
* @since 3.2.4
* @access protected
* @author Grégory Viguier
*
* @return string|bool URL of the file. False if the file does not exist.
*/
protected function get_busting_path() {
return $this->get_busting_file_path( $this->get_busting_version() );
}
/**
* Get the final URL for a cache busting file.
*
* @since 3.2.4
* @access private
* @author Grégory Viguier
*
* @param string $version The file version.
* @return string|bool URL of the file with this version. False if no versions are provided.
*/
private function get_busting_file_url( $version ) {
if ( ! $version ) {
return false;
}
$filename = $this->get_busting_file_name( $version );
// This filter is documented in inc/functions/minify.php.
return apply_filters( 'rocket_js_url', $this->busting_url . $filename );
}
/**
* Get the local file name.
*
* @since 3.2.4
* @access private
* @author Grégory Viguier
*
* @param string $version The file version.
* @return string|bool The name of the file with this version. False if no versions are provided.
*/
private function get_busting_file_name( $version ) {
if ( ! $version ) {
return false;
}
return sprintf( $this->filename_pattern, $version );
}
/**
* Get the local file path.
*
* @since 3.2.4
* @access private
* @author Grégory Viguier
*
* @param string $version The file version.
* @return string|bool Path to the file with this version. False if no versions are provided.
*/
private function get_busting_file_path( $version ) {
if ( ! $version ) {
return false;
}
return $this->busting_path . $this->get_busting_file_name( $version );
}
/**
* Escape a file name, to be used in a regex pattern (delimiter is `/`).
* `%s` conversion specifications are protected.
*
* @since 3.2.4
* @access private
*
* @param string $filename_pattern The file name.
* @return string
*/
private function escape_file_name( $filename_pattern ) {
return preg_quote( $filename_pattern, '/' );
}
/**
* Delete busting files.
*
* @since 3.2.4
* @access private
* @author Grégory Viguier
*
* @param array $files A list of file names.
* @return bool True if files have been deleted (or no files have been provided). False on failure.
*/
private function delete_files( $files ) {
if ( ! $files ) {
// ¯\_(ツ)_/¯
return true;
}
$has_deleted = false;
$error_paths = [];
foreach ( $files as $file_name ) {
if ( ! $this->filesystem->delete( $this->busting_path . $file_name, false, 'f' ) ) {
$error_paths[] = $this->busting_path . $file_name;
} else {
$has_deleted = true;
}
}
if ( $error_paths ) {
// Group all deletion errors into one log.
Logger::error(
'Local file(s) could not be deleted.',
[
self::LOGGER_CONTEXT,
'paths' => $error_paths,
]
);
}
return $has_deleted;
}
/** ----------------------------------------------------------------------------------------- */
/** UPDATE THE LOCAL FILE =================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Add new contents to a file. If the file doesn't exist, it is created.
*
* @since 3.2.4
* @access private
* @author Grégory Viguier
*
* @param string $file_path Path to the file to update.
* @param string $file_contents New contents.
* @return string|bool The file contents on success. False on failure.
*/
private function update_file_contents( $file_path, $file_contents ) {
if ( ! $this->is_busting_dir_writable() ) {
return false;
}
if ( ! rocket_put_content( $file_path, $file_contents ) ) {
Logger::error(
'Contents could not be written into file.',
[
self::LOGGER_CONTEXT,
'path' => $file_path,
]
);
return false;
}
return $file_contents;
}
/**
* Tell if the directory containing the busting file is writable.
*
* @since 3.2
* @access private
* @author Grégory Viguier
*
* @return bool
*/
private function is_busting_dir_writable() {
if ( ! $this->filesystem->exists( $this->busting_path ) ) {
rocket_mkdir_p( $this->busting_path );
}
if ( ! $this->filesystem->is_writable( $this->busting_path ) ) {
Logger::error(
'Directory is not writable.',
[
self::LOGGER_CONTEXT,
'paths' => $this->busting_path,
]
);
return false;
}
return true;
}
/** ----------------------------------------------------------------------------------------- */
/** GET LOCAL/REMOTE CONTENTS =============================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Get a file contents. If the file doesn't exist, new contents are fetched remotely.
*
* @since 3.2.4
* @access private
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @param string $file_url URL to the remote file.
* @return string|bool The contents on success, false on failure.
*/
private function get_file_or_remote_contents( $file_path, $file_url ) {
$content = $this->get_file_contents( $file_path );
if ( $content ) {
// We have a local file.
return $content;
}
return $this->get_remote_contents( $file_url );
}
/**
* Get a file contents.
*
* @since 3.2.4
* @access private
* @author Grégory Viguier
*
* @param string $file_path Path to the file.
* @return string|bool The contents on success, false on failure.
*/
private function get_file_contents( $file_path ) {
if ( ! $this->filesystem->exists( $file_path ) ) {
Logger::error(
'Local file does not exist.',
[
self::LOGGER_CONTEXT,
'path' => $file_path,
]
);
return false;
}
if ( ! $this->filesystem->is_readable( $file_path ) ) {
Logger::error(
'Local file is not readable.',
[
self::LOGGER_CONTEXT,
'path' => $file_path,
]
);
return false;
}
$content = $this->filesystem->get_contents( $file_path );
if ( ! $content ) {
Logger::error(
'Local file is empty.',
[
self::LOGGER_CONTEXT,
'path' => $file_path,
]
);
return false;
}
return $content;
}
/**
* Get the contents of a URL.
*
* @since 3.2.4
* @access private
* @author Grégory Viguier
*
* @param string $url The URL to request.
* @return string|bool The contents on success. False on failure.
*/
private function get_remote_contents( $url ) {
try {
$response = wp_remote_get( $url );
} catch ( Exception $e ) {
Logger::error(
'Remote file could not be fetched.',
[
self::LOGGER_CONTEXT,
'url' => $url,
'response' => $e->getMessage(),
]
);
return false;
}
if ( is_wp_error( $response ) ) {
Logger::error(
'Remote file could not be fetched.',
[
self::LOGGER_CONTEXT,
'url' => $url,
'response' => $response->get_error_message(),
]
);
return false;
}
$contents = wp_remote_retrieve_body( $response );
if ( ! $contents ) {
Logger::error(
'Remote file could not be fetched.',
[
self::LOGGER_CONTEXT,
'url' => $url,
'response' => $response,
]
);
return false;
}
return $contents;
}
}

View File

@@ -0,0 +1,394 @@
<?php
namespace WPMedia\Cloudflare;
use stdClass;
use Exception;
/**
* Cloudflare API Client.
*
* @since 1.0
*/
class APIClient {
const CLOUDFLARE_API = 'https://api.cloudflare.com/client/v4/';
/**
* Email address for API authentication.
*
* @var string
*/
protected $email;
/**
* API key for API authentication.
*
* @var string
*/
protected $api_key;
/**
* Zone ID.
*
* @var string
*/
protected $zone_id;
/**
* An array of arguments for wp_remote_get.
*
* @var array
*/
protected $args = [];
/**
* HTTP headers.
*
* @var array
*/
protected $headers = [];
/**
* APIClient constructor.
*
* @since 1.0
*
* @param string $useragent The user agent for this plugin or package. For example, "wp-rocket/3.5".
*/
public function __construct( $useragent ) {
$this->args = [
'timeout' => 30, // Increase from default of 5 to give extra time for the plugin to process story for exporting.
'sslverify' => true,
'body' => [],
];
$this->headers = [
'X-Auth-Email' => '',
'X-Auth-Key' => '',
'User-Agent' => $useragent,
'Content-type' => 'application/json',
];
}
/**
* Sets up the API credentials.
*
* @since 1.0
*
* @param string $email The email associated with the Cloudflare account.
* @param string $api_key The API key for the associated Cloudflare account.
* @param string $zone_id The zone ID.
*/
public function set_api_credentials( $email, $api_key, $zone_id ) {
$this->email = $email;
$this->api_key = $api_key;
$this->zone_id = $zone_id;
$this->headers['X-Auth-Email'] = $email;
$this->headers['X-Auth-Key'] = $api_key;
}
/**
* Get zone data.
*
* @since 1.0
*
* @return stdClass Cloudflare response packet.
*/
public function get_zones() {
return $this->get( "zones/{$this->zone_id}" );
}
/**
* Get the zone's page rules.
*
* @since 1.0
*
* @return stdClass Cloudflare response packet.
*/
public function list_pagerules() {
return $this->get( "zones/{$this->zone_id}/pagerules?status=active" );
}
/**
* Purges the cache.
*
* @since 1.0
*
* @return stdClass Cloudflare response packet.
*/
public function purge() {
return $this->delete( "zones/{$this->zone_id}/purge_cache", [ 'purge_everything' => true ] );
}
/**
* Purges the given URLs.
*
* @since 1.0
*
* @param array|null $urls An array of URLs that should be removed from cache.
*
* @return stdClass Cloudflare response packet.
*/
public function purge_files( array $urls ) {
return $this->delete( "zones/{$this->zone_id}/purge_cache", [ 'files' => $urls ] );
}
/**
* Changes the zone's browser cache TTL setting.
*
* @since 1.0
*
* @param string $value New setting's value.
*
* @return stdClass Cloudflare response packet.
*/
public function change_browser_cache_ttl( $value ) {
return $this->change_setting( 'browser_cache_ttl', $value );
}
/**
* Changes the zone's rocket loader setting.
*
* @since 1.0
*
* @param string $value New setting's value.
*
* @return stdClass Cloudflare response packet.
*/
public function change_rocket_loader( $value ) {
return $this->change_setting( 'rocket_loader', $value );
}
/**
* Changes the zone's minify setting.
*
* @since 1.0
*
* @param string $value New setting's value.
*
* @return stdClass Cloudflare response packet.
*/
public function change_minify( $value ) {
return $this->change_setting( 'minify', $value );
}
/**
* Changes the zone's cache level.
*
* @since 1.0
*
* @param string $value New setting's value.
*
* @return stdClass Cloudflare response packet.
*/
public function change_cache_level( $value ) {
return $this->change_setting( 'cache_level', $value );
}
/**
* Changes the zone's development mode.
*
* @since 1.0
*
* @param string $value New setting's value.
*
* @return stdClass Cloudflare response packet.
*/
public function change_development_mode( $value ) {
return $this->change_setting( 'development_mode', $value );
}
/**
* Changes the given setting.
*
* @since 1.0
*
* @param string $setting Name of the setting to change.
* @param string $value New setting's value.
*
* @return stdClass Cloudflare response packet.
*/
protected function change_setting( $setting, $value ) {
return $this->patch( "zones/{$this->zone_id}/settings/{$setting}", [ 'value' => $value ] );
}
/**
* Gets all of the Cloudflare settings.
*
* @since 1.0
*
* @return stdClass Cloudflare response packet.
*/
public function get_settings() {
return $this->get( "zones/{$this->zone_id}/settings" );
}
/**
* Gets Cloudflare's IPs.
*
* @since 1.0
*
* @return stdClass Cloudflare response packet.
*/
public function get_ips() {
return $this->get( '/ips' );
}
/**
* API call method for sending requests using GET.
*
* @since 1.0
*
* @param string $path Path of the endpoint.
* @param array $data Data to be sent along with the request.
*
* @return stdClass Cloudflare response packet.
*/
protected function get( $path, array $data = [] ) {
return $this->request( $path, $data, 'get' );
}
/**
* API call method for sending requests using DELETE.
*
* @since 1.0
*
* @param string $path Path of the endpoint.
* @param array $data Data to be sent along with the request.
*
* @return stdClass Cloudflare response packet.
*/
protected function delete( $path, array $data = [] ) {
return $this->request( $path, $data, 'delete' );
}
/**
* API call method for sending requests using PATCH.
*
* @since 1.0
*
* @param string $path Path of the endpoint.
* @param array $data Data to be sent along with the request.
*
* @return stdClass Cloudflare response packet.
*/
protected function patch( $path, array $data = [] ) {
return $this->request( $path, $data, 'patch' );
}
/**
* API call method for sending requests using GET, POST, PUT, DELETE OR PATCH.
*
* @since 1.0
*
* @author James Bell <james@james-bell.co.uk> - credit for original code adapted for version 1.0.
* @author WP Media
*
* @param string $path Path of the endpoint.
* @param array $data Data to be sent along with the request.
* @param string $method Type of method that should be used ('GET', 'DELETE', 'PATCH').
*
* @return stdClass response object.
* @throws AuthenticationException When email or api key are not set.
* @throws UnauthorizedException When Cloudflare's API returns a 401 or 403.
*/
protected function request( $path, array $data = [], $method = 'get' ) {
if ( '/ips' !== $path && ! $this->is_authorized() ) {
throw new AuthenticationException( 'Authentication information must be provided.' );
}
$response = $this->do_remote_request( $path, $data, $method );
if ( is_wp_error( $response ) ) {
throw new Exception( $response->get_error_message() );
}
$data = wp_remote_retrieve_body( $response );
if ( empty( $data ) ) {
throw new Exception( __( 'Cloudflare did not provide any reply. Please try again later.', 'rocket' ) );
}
$data = json_decode( $data );
if ( empty( $data->success ) ) {
$errors = [];
foreach ( $data->errors as $error ) {
if ( 6003 === $error->code || 9103 === $error->code ) {
$msg = __( 'Incorrect Cloudflare email address or API key.', 'rocket' );
$msg .= ' ' . sprintf(
/* translators: %1$s = opening link; %2$s = closing link */
__( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ),
// translators: Documentation exists in EN, FR; use localized URL if applicable.
'<a href="' . esc_url( __( 'https://docs.wp-rocket.me/article/18-using-wp-rocket-with-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket#add-on', 'rocket' ) ) . '" rel="noopener noreferrer" target="_blank">',
'</a>'
);
throw new Exception( $msg );
}
if ( 7003 === $error->code ) {
$msg = __( 'Incorrect Cloudflare Zone ID.', 'rocket' );
$msg .= ' ' . sprintf(
/* translators: %1$s = opening link; %2$s = closing link */
__( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ),
// translators: Documentation exists in EN, FR; use localized URL if applicable.
'<a href="' . esc_url( __( 'https://docs.wp-rocket.me/article/18-using-wp-rocket-with-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket#add-on', 'rocket' ) ) . '" rel="noopener noreferrer" target="_blank">',
'</a>'
);
throw new Exception( $msg );
}
$errors[] = $error->message;
}
throw new Exception( wp_sprintf_l( '%l ', $errors ) );
}
return $data;
}
/**
* Checks if the email and API key for the API credentials are set.
*
* @since 1.0
*
* @return bool true if authorized; else false.
*/
private function is_authorized() {
return (
isset( $this->email, $this->api_key )
&&
false !== filter_var( $this->email, FILTER_VALIDATE_EMAIL )
);
}
/**
* Does the request remote cURL request.
*
* @since 1.0
*
* @param string $path Path of the endpoint.
* @param array $data Data to be sent along with the request.
* @param string $method Type of method that should be used ('GET', 'DELETE', 'PATCH').
*
* @return array curl response packet.
*/
private function do_remote_request( $path, array $data, $method ) {
$this->args['method'] = isset( $method ) ? strtoupper( $method ) : 'GET';
if ( '/ips' !== $path ) {
$this->args['headers'] = $this->headers;
}
$this->args['body'] = [];
if ( ! empty( $data ) ) {
$this->args['body'] = wp_json_encode( $data );
}
$response = wp_remote_request( self::CLOUDFLARE_API . $path, $this->args );
return $response;
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace WPMedia\Cloudflare;
use RuntimeException;
class AuthenticationException extends RuntimeException {}

View File

@@ -0,0 +1,481 @@
<?php
namespace WPMedia\Cloudflare;
use Exception;
use stdClass;
use WP_Error;
use WP_Rocket\Admin\Options_Data;
/**
* Cloudflare
*
* @since 1.0
*/
class Cloudflare {
/**
* Options Data instance.
*
* @var Options_Data
*/
private $options;
/**
* Cloudflare API instance.
*
* @var APIClient
*/
private $api;
/**
* WP_Error if Cloudflare Credentials are not valid.
*
* @var WP_Error
*/
private $cloudflare_api_error;
/**
* Creates an instance of Cloudflare Addon.
*
* @param Options_Data $options WP Rocket options instance.
* @param APIClient $api Cloudflare API instance.
*/
public function __construct( Options_Data $options, APIClient $api ) {
$this->options = $options;
$this->cloudflare_api_error = null;
$this->api = $api;
// Update api_error with WP_Error if credentials are not valid.
// Update API with Cloudflare instance with correct auth data.
$this->get_cloudflare_instance();
}
/**
* Get a Cloudflare\Api instance & the zone_id corresponding to the domain.
*
* @since 1.0
*
* @return Object Cloudflare instance & zone_id if credentials are correct, WP_Error otherwise.
*/
public function get_cloudflare_instance() {
$cf_email = $this->options->get( 'cloudflare_email', null );
$cf_api_key = defined( 'WP_ROCKET_CF_API_KEY' ) ? WP_ROCKET_CF_API_KEY : $this->options->get( 'cloudflare_api_key', null );
$cf_zone_id = $this->options->get( 'cloudflare_zone_id', null );
$is_api_keys_valid_cf = get_transient( 'rocket_cloudflare_is_api_keys_valid' );
if ( false === $is_api_keys_valid_cf ) {
$is_api_keys_valid_cf = $this->is_api_keys_valid( $cf_email, $cf_api_key, $cf_zone_id );
set_transient( 'rocket_cloudflare_is_api_keys_valid', $is_api_keys_valid_cf, 2 * WEEK_IN_SECONDS );
}
if ( is_wp_error( $is_api_keys_valid_cf ) ) {
// Sets Cloudflare API as WP_Error if credentials are not valid.
$this->cloudflare_api_error = $is_api_keys_valid_cf;
return;
}
// Sets Cloudflare Valid Credentials and User Agent.
$this->api->set_api_credentials( $cf_email, $cf_api_key, $cf_zone_id );
}
/**
* Validate Cloudflare input data.
*
* @since 1.0
*
* @param string $cf_email Cloudflare email.
* @param string $cf_api_key Cloudflare API key.
* @param string $cf_zone_id Cloudflare zone ID.
*
* @return stdClass true if credentials are ok, WP_Error otherwise.
*/
public function is_api_keys_valid( $cf_email, $cf_api_key, $cf_zone_id ) {
if ( empty( $cf_email ) || empty( $cf_api_key ) ) {
return new WP_Error(
'cloudflare_credentials_empty',
sprintf(
/* translators: %1$s = opening link; %2$s = closing link */
__( 'Cloudflare email and/or API key are not set. Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ),
// translators: Documentation exists in EN, FR; use localized URL if applicable.
'<a href="' . esc_url( __( 'https://docs.wp-rocket.me/article/18-using-wp-rocket-with-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket#add-on', 'rocket' ) ) . '" rel="noopener noreferrer" target="_blank">',
'</a>'
)
);
}
if ( empty( $cf_zone_id ) ) {
$msg = __( 'Missing Cloudflare Zone ID.', 'rocket' );
$msg .= ' ' . sprintf(
/* translators: %1$s = opening link; %2$s = closing link */
__( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ),
// translators: Documentation exists in EN, FR; use localized URL if applicable.
'<a href="' . esc_url( __( 'https://docs.wp-rocket.me/article/18-using-wp-rocket-with-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket#add-on', 'rocket' ) ) . '" rel="noopener noreferrer" target="_blank">',
'</a>'
);
return new WP_Error( 'cloudflare_no_zone_id', $msg );
}
try {
$this->api->set_api_credentials( $cf_email, $cf_api_key, $cf_zone_id );
$cf_zone = $this->api->get_zones();
$zone_found = false;
$site_url = get_site_url();
if ( function_exists( 'domain_mapping_siteurl' ) ) {
$site_url = domain_mapping_siteurl( $site_url );
}
if ( ! empty( $cf_zone->result ) ) {
$parsed_url = wp_parse_url( $site_url );
if ( false !== strpos( strtolower( $parsed_url['host'] ), $cf_zone->result->name ) ) {
$zone_found = true;
}
}
if ( ! $zone_found ) {
$msg = __( 'It looks like your domain is not set up on Cloudflare.', 'rocket' );
$msg .= ' ' . sprintf(
/* translators: %1$s = opening link; %2$s = closing link */
__( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ),
// translators: Documentation exists in EN, FR; use localized URL if applicable.
'<a href="' . esc_url( __( 'https://docs.wp-rocket.me/article/18-using-wp-rocket-with-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket#add-on', 'rocket' ) ) . '" rel="noopener noreferrer" target="_blank">',
'</a>'
);
return new WP_Error( 'cloudflare_wrong_zone_id', $msg );
}
$this->cloudflare_api_error = null;
return true;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_invalid_auth', $e->getMessage() );
}
}
/**
* Checks if CF has the $action_value set as a Page Rule.
*
* @since 1.0
*
* @param string $action_value Cache_everything.
*
* @return mixed Object|bool true / false if $action_value was found or not, WP_Error otherwise.
*/
public function has_page_rule( $action_value ) {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
try {
$cf_page_rule = $this->api->list_pagerules();
$cf_page_rule_arr = wp_json_encode( $cf_page_rule );
return preg_match( '/' . $action_value . '/', $cf_page_rule_arr );
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_page_rule_failed', $e->getMessage() );
}
}
/**
* Purge Cloudflare cache.
*
* @since 1.0
*
* @return mixed Object|bool true if the purge is successful, WP_Error otherwise.
*/
public function purge_cloudflare() {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
try {
$cf_purge = $this->api->purge();
return true;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_purge_failed', $e->getMessage() );
}
}
/**
* Purge Cloudflare Cache by URL
*
* @since 1.0
*
* @param WP_Post $post The post object.
* @param array $purge_urls URLs cache files to remove.
* @param string $lang The post language.
*
* @return mixed Object|bool true if the purge is successful, WP_Error otherwise
*/
public function purge_by_url( $post, $purge_urls, $lang ) {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
try {
$cf_purge = $this->api->purge_files( $purge_urls );
return true;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_purge_failed', $e->getMessage() );
}
}
/**
* Set the Browser Cache TTL in Cloudflare.
*
* @since 1.0
*
* @param string $mode Value for Cloudflare browser cache TTL.
*
* @return mixed Object|String Mode value if the update is successful, WP_Error otherwise.
*/
public function set_browser_cache_ttl( $mode ) {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
try {
$cf_return = $this->api->change_browser_cache_ttl( (int) $mode );
return $mode;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_browser_cache', $e->getMessage() );
}
}
/**
* Set the Cloudflare Rocket Loader.
*
* @since 1.0
*
* @param string $mode Value for Cloudflare Rocket Loader.
*
* @return mixed Object|String Mode value if the update is successful, WP_Error otherwise.
*/
public function set_rocket_loader( $mode ) {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
try {
$cf_return = $this->api->change_rocket_loader( $mode );
return $mode;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_rocket_loader', $e->getMessage() );
}
}
/**
* Set the Cloudflare Minification.
*
* @since 1.0
*
* @param string $mode Value for Cloudflare minification.
*
* @return mixed Object|String Mode value if the update is successful, WP_Error otherwise.
*/
public function set_minify( $mode ) {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
$cf_minify_settings = [
'css' => $mode,
'html' => $mode,
'js' => $mode,
];
try {
$cf_return = $this->api->change_minify( $cf_minify_settings );
return $mode;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_minification', $e->getMessage() );
}
}
/**
* Set the Cloudflare Caching level.
*
* @since 1.0
*
* @param string $mode Value for Cloudflare caching level.
*
* @return mixed Object|String Mode value if the update is successful, WP_Error otherwise.
*/
public function set_cache_level( $mode ) {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
try {
$cf_return = $this->api->change_cache_level( $mode );
return $mode;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_cache_level', $e->getMessage() );
}
}
/**
* Set the Cloudflare Development mode.
*
* @since 1.0
*
* @param string $mode Value for Cloudflare development mode.
*
* @return mixed Object|String Mode value if the update is successful, WP_Error otherwise.
*/
public function set_devmode( $mode ) {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
if ( 0 === (int) $mode ) {
$value = 'off';
} else {
$value = 'on';
}
try {
$cf_return = $this->api->change_development_mode( $value );
if ( 'on' === $value ) {
wp_schedule_single_event( time() + 3 * HOUR_IN_SECONDS, 'rocket_cron_deactivate_cloudflare_devmode' );
}
return $value;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_dev_mode', $e->getMessage() );
}
}
/**
* Get all the current Cloudflare settings for a given domain.
*
* @since 1.0
*
* @return mixed bool|Array Array of Cloudflare settings, false if any error connection to Cloudflare.
*/
public function get_settings() {
if ( is_wp_error( $this->cloudflare_api_error ) ) {
return $this->cloudflare_api_error;
}
try {
$cf_settings = $this->api->get_settings();
foreach ( $cf_settings->result as $cloudflare_option ) {
switch ( $cloudflare_option->id ) {
case 'browser_cache_ttl':
$browser_cache_ttl = $cloudflare_option->value;
break;
case 'cache_level':
$cache_level = $cloudflare_option->value;
break;
case 'rocket_loader':
$rocket_loader = $cloudflare_option->value;
break;
case 'minify':
$cf_minify = $cloudflare_option->value;
break;
}
}
$cf_minify_value = 'on';
if ( 'off' === $cf_minify->js || 'off' === $cf_minify->css || 'off' === $cf_minify->html ) {
$cf_minify_value = 'off';
}
$cf_settings_array = [
'cache_level' => $cache_level,
'minify' => $cf_minify_value,
'rocket_loader' => $rocket_loader,
'browser_cache_ttl' => $browser_cache_ttl,
];
return $cf_settings_array;
} catch ( Exception $e ) {
return new WP_Error( 'cloudflare_current_settings', $e->getMessage() );
}
}
/**
* Get Cloudflare IPs. No API validation needed, all exceptions returns the default CF IPs array.
*
* @since 1.0
*
* @return Object Result of API request if successful, default CF IPs otherwise.
*/
public function get_cloudflare_ips() {
$cf_ips = get_transient( 'rocket_cloudflare_ips' );
if ( false !== $cf_ips ) {
return $cf_ips;
}
try {
$cf_ips = $this->api->get_ips();
if ( empty( $cf_ips->success ) ) {
// Set default IPs from Cloudflare if call to Cloudflare /ips API does not contain a success.
// Prevents from making API calls on each page load.
$cf_ips = $this->get_default_ips();
}
} catch ( Exception $e ) {
// Set default IPs from Cloudflare if call to Cloudflare /ips API fails.
// Prevents from making API calls on each page load.
$cf_ips = $this->get_default_ips();
}
set_transient( 'rocket_cloudflare_ips', $cf_ips, 2 * WEEK_IN_SECONDS );
return $cf_ips;
}
/**
* Get default Cloudflare IPs.
*
* @since 1.0
*
* @return stdClass Default Cloudflare connecting IPs.
*/
private function get_default_ips() {
$cf_ips = (object) [
'result' => (object) [],
'success' => true,
'errors' => [],
'messages' => [],
];
$cf_ips->result->ipv4_cidrs = [
'173.245.48.0/20',
'103.21.244.0/22',
'103.22.200.0/22',
'103.31.4.0/22',
'141.101.64.0/18',
'108.162.192.0/18',
'190.93.240.0/20',
'188.114.96.0/20',
'197.234.240.0/22',
'198.41.128.0/17',
'162.158.0.0/15',
'104.16.0.0/12',
'172.64.0.0/13',
'131.0.72.0/22',
];
$cf_ips->result->ipv6_cidrs = [
'2400:cb00::/32',
'2606:4700::/32',
'2803:f800::/32',
'2405:b500::/32',
'2405:8100::/32',
'2a06:98c0::/29',
'2c0f:f248::/32',
];
return $cf_ips;
}
}

View File

@@ -0,0 +1,608 @@
<?php
namespace WPMedia\Cloudflare;
use WP_Rocket\Event_Management\Subscriber_Interface;
use WP_Rocket\Admin\Options_Data;
use WP_Rocket\Admin\Options;
/**
* Cloudflare Subscriber.
*
* @since 1.0
*/
class Subscriber implements Subscriber_Interface {
/**
* Cloudflare instance.
*
* @var Cloudflare
*/
private $cloudflare;
/**
* Options Data instance.
*
* @var Options_Data
*/
private $options;
/**
* Options instance.
*
* @var Options
*/
private $options_api;
/**
* Creates an instance of the Cloudflare Subscriber.
*
* @param Cloudflare $cloudflare Cloudflare instance.
* @param Options_Data $options WP Rocket options instance.
* @param Options $options_api Options instance.
*/
public function __construct( Cloudflare $cloudflare, Options_Data $options, Options $options_api ) {
$this->options = $options;
$this->options_api = $options_api;
$this->cloudflare = $cloudflare;
}
/**
* Gets the subscribed events.
*
* @since 1.0
*
* @return array subscribed events => callbacks.
*/
public static function get_subscribed_events() {
$slug = rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' );
return [
'rocket_varnish_ip' => 'set_varnish_localhost',
'rocket_varnish_purge_request_host' => 'set_varnish_purge_request_host',
'rocket_cron_deactivate_cloudflare_devmode' => 'deactivate_devmode',
'after_rocket_clean_domain' => 'auto_purge',
'after_rocket_clean_post' => [ 'auto_purge_by_url', 10, 3 ],
'admin_post_rocket_purge_cloudflare' => 'purge_cache',
'init' => [ 'set_real_ip', 1 ],
'update_option_' . $slug => [ 'save_cloudflare_options', 10, 2 ],
'pre_update_option_' . $slug => [ 'save_cloudflare_old_settings', 10, 2 ],
'admin_notices' => [
[ 'maybe_display_purge_notice' ],
[ 'maybe_print_update_settings_notice' ],
],
];
}
/**
* Sets the Varnish IP to localhost if Cloudflare is active.
*
* @since 1.0
*
* @param string|array $varnish_ip Varnish IP.
*
* @return array
*/
public function set_varnish_localhost( $varnish_ip ) {
if ( ! $this->should_filter_varnish() ) {
return $varnish_ip;
}
if ( is_string( $varnish_ip ) ) {
$varnish_ip = (array) $varnish_ip;
}
$varnish_ip[] = 'localhost';
return $varnish_ip;
}
/**
* Sets the Host header to the website domain if Cloudflare is active.
*
* @since 1.0
*
* @param string $host the host header value.
*
* @return string
*/
public function set_varnish_purge_request_host( $host ) {
if ( ! $this->should_filter_varnish() ) {
return $host;
}
return wp_parse_url( home_url(), PHP_URL_HOST );
}
/**
* Checks if we should filter the value for the Varnish purge.
*
* @since 1.0
*
* @return bool
*/
private function should_filter_varnish() {
// This filter is documented in inc/classes/subscriber/Addons/Varnish/VarnishSubscriber.php.
if ( ! apply_filters( 'do_rocket_varnish_http_purge', false ) && ! $this->options->get( 'varnish_auto_purge', 0 ) ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
return false;
}
return true;
}
/**
* Automatically set Cloudflare development mode value to off after 3 hours to reflect Cloudflare behaviour.
*
* @since 1.0
*/
public function deactivate_devmode() {
$this->options->set( 'cloudflare_devmode', 'off' );
$this->options_api->set( 'settings', $this->options->get_options() );
}
/**
* Purge Cloudflare cache automatically if Cache Everything is set as a Page Rule.
*
* @since 1.0
*/
public function auto_purge() {
if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) {
return;
}
$cf_cache_everything = $this->cloudflare->has_page_rule( 'cache_everything' );
if ( is_wp_error( $cf_cache_everything ) || ! $cf_cache_everything ) {
return;
}
// Purge CloudFlare.
$this->cloudflare->purge_cloudflare();
}
/**
* Purge Cloudflare cache URLs automatically if Cache Everything is set as a Page Rule.
*
* @since 1.0
*
* @param WP_Post $post The post object.
* @param array $purge_urls URLs cache files to remove.
* @param string $lang The post language.
*/
public function auto_purge_by_url( $post, $purge_urls, $lang ) {
if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) {
return;
}
$cf_cache_everything = $this->cloudflare->has_page_rule( 'cache_everything' );
if ( is_wp_error( $cf_cache_everything ) || ! $cf_cache_everything ) {
return;
}
// Add home URL and feeds URLs to Cloudflare clean cache URLs list.
$purge_urls[] = get_rocket_i18n_home_url( $lang );
$feed_urls = [];
$feed_urls[] = get_feed_link();
$feed_urls[] = get_feed_link( 'comments_' );
// this filter is documented in inc/functions/files.php.
$feed_urls = apply_filters( 'rocket_clean_home_feeds', $feed_urls );
$purge_urls = array_unique( array_merge( $purge_urls, $feed_urls ) );
// Purge CloudFlare.
$this->cloudflare->purge_by_url( $post, $purge_urls, $lang );
}
/**
* Purge CloudFlare cache.
*
* @since 1.0
*/
public function purge_cache_no_die() {
if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) {
return;
}
// Purge CloudFlare.
$cf_purge = $this->cloudflare->purge_cloudflare();
if ( is_wp_error( $cf_purge ) ) {
$cf_purge_result = [
'result' => 'error',
// translators: %s = CloudFare API return message.
'message' => sprintf( __( '<strong>WP Rocket:</strong> %s', 'rocket' ), $cf_purge->get_error_message() ),
];
} else {
$cf_purge_result = [
'result' => 'success',
'message' => __( '<strong>WP Rocket:</strong> Cloudflare cache successfully purged.', 'rocket' ),
];
}
set_transient( get_current_user_id() . '_cloudflare_purge_result', $cf_purge_result );
}
/**
* Purge CloudFlare cache.
*
* @since 1.0
*/
public function purge_cache() {
if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'rocket_purge_cloudflare' ) ) {
wp_nonce_ays( '' );
}
$this->purge_cache_no_die();
wp_safe_redirect( esc_url_raw( wp_get_referer() ) );
defined( 'WPMEDIA_IS_TESTING' ) ? wp_die() : exit;
}
/**
* Set Real IP from CloudFlare.
*
* @since 1.0
* @source cloudflare.php - https://wordpress.org/plugins/cloudflare/
*/
public function set_real_ip() {
// only run this logic if the REMOTE_ADDR is populated, to avoid causing notices in CLI mode.
if ( ! isset( $_SERVER['HTTP_CF_CONNECTING_IP'], $_SERVER['REMOTE_ADDR'] ) ) {
return;
}
$cf_ips_values = $this->cloudflare->get_cloudflare_ips();
$cf_ip_ranges = $cf_ips_values->result->ipv6_cidrs;
$ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
$ipv6 = get_rocket_ipv6_full( $ip );
if ( false === strpos( $ip, ':' ) ) {
// IPV4: Update the REMOTE_ADDR value if the current REMOTE_ADDR value is in the specified range.
$cf_ip_ranges = $cf_ips_values->result->ipv4_cidrs;
}
foreach ( $cf_ip_ranges as $range ) {
if (
( strpos( $ip, ':' ) && rocket_ipv6_in_range( $ipv6, $range ) )
||
( false === strpos( $ip, ':' ) && rocket_ipv4_in_range( $ip, $range ) )
) {
$_SERVER['REMOTE_ADDR'] = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CF_CONNECTING_IP'] ) );
break;
}
}
}
/**
* This notice is displayed after purging the CloudFlare cache.
*
* @since 1.0
*/
public function maybe_display_purge_notice() {
if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) {
return;
}
$user_id = get_current_user_id();
$notice = get_transient( $user_id . '_cloudflare_purge_result' );
if ( ! $notice ) {
return;
}
delete_transient( $user_id . '_cloudflare_purge_result' );
rocket_notice_html(
[
'status' => $notice['result'],
'message' => $notice['message'],
]
);
}
/**
* This notice is displayed after modifying the CloudFlare settings.
*
* @since 1.0
*/
public function maybe_print_update_settings_notice() {
$screen = get_current_screen();
if ( ! current_user_can( 'rocket_manage_options' ) || 'settings_page_wprocket' !== $screen->id ) {
return;
}
$user_id = get_current_user_id();
$notices = get_transient( $user_id . '_cloudflare_update_settings' );
if ( ! $notices ) {
return;
}
$errors = '';
$success = '';
delete_transient( $user_id . '_cloudflare_update_settings' );
foreach ( $notices as $notice ) {
if ( 'error' === $notice['result'] ) {
$errors .= $notice['message'] . '<br>';
} elseif ( 'success' === $notice['result'] ) {
$success .= $notice['message'] . '<br>';
}
}
if ( ! empty( $success ) ) {
rocket_notice_html(
[
'message' => $success,
]
);
}
if ( ! empty( $errors ) ) {
rocket_notice_html(
[
'status' => 'error',
'message' => $errors,
]
);
}
}
/**
* Save Cloudflare dev mode admin option.
*
* @since 3.5.2
* @author Soponar Cristina
*
* @param string $devmode New value for Cloudflare dev mode.
*/
private function save_cloudflare_devmode( $devmode ) {
$cloudflare_dev_mode_return = $this->cloudflare->set_devmode( $devmode );
if ( is_wp_error( $cloudflare_dev_mode_return ) ) {
return [
'result' => 'error',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare development mode error: %s', 'rocket' ), $cloudflare_dev_mode_return->get_error_message() ),
];
}
return [
'result' => 'success',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare development mode %s', 'rocket' ), $cloudflare_dev_mode_return ),
];
}
/**
* Save Cloudflare cache_level admin option.
*
* @since 3.5.2
* @author Soponar Cristina
*
* @param string $cache_level New value for Cloudflare cache_level.
*/
private function save_cache_level( $cache_level ) {
// Set Cache Level to Aggressive.
$cf_cache_level_return = $this->cloudflare->set_cache_level( $cache_level );
if ( is_wp_error( $cf_cache_level_return ) ) {
return [
'result' => 'error',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare cache level error: %s', 'rocket' ), $cf_cache_level_return->get_error_message() ),
];
}
if ( 'aggressive' === $cf_cache_level_return ) {
$cf_cache_level_return = _x( 'Standard', 'Cloudflare caching level', 'rocket' );
}
return [
'result' => 'success',
// translators: %s is the caching level returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare cache level set to %s', 'rocket' ), $cf_cache_level_return ),
];
}
/**
* Save Cloudflare minify admin option.
*
* @since 3.5.2
* @author Soponar Cristina
*
* @param string $minify New value for Cloudflare minify.
*/
private function save_minify( $minify ) {
$cf_minify_return = $this->cloudflare->set_minify( $minify );
if ( is_wp_error( $cf_minify_return ) ) {
return [
'result' => 'error',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare minification error: %s', 'rocket' ), $cf_minify_return->get_error_message() ),
];
}
return [
'result' => 'success',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare minification %s', 'rocket' ), $cf_minify_return ),
];
}
/**
* Save Cloudflare rocket loader admin option.
*
* @since 3.5.2
* @author Soponar Cristina
*
* @param string $rocket_loader New value for Cloudflare rocket loader.
*/
private function save_rocket_loader( $rocket_loader ) {
$cf_rocket_loader_return = $this->cloudflare->set_rocket_loader( $rocket_loader );
if ( is_wp_error( $cf_rocket_loader_return ) ) {
return [
'result' => 'error',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare rocket loader error: %s', 'rocket' ), $cf_rocket_loader_return->get_error_message() ),
];
}
return [
'result' => 'success',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare rocket loader %s', 'rocket' ), $cf_rocket_loader_return ),
];
}
/**
* Save Cloudflare browser cache ttl admin option.
*
* @since 3.5.2
* @author Soponar Cristina
*
* @param int $browser_cache_ttl New value for Cloudflare browser cache ttl.
*/
private function save_browser_cache_ttl( $browser_cache_ttl ) {
$cf_browser_cache_return = $this->cloudflare->set_browser_cache_ttl( $browser_cache_ttl );
if ( is_wp_error( $cf_browser_cache_return ) ) {
return [
'result' => 'error',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare browser cache error: %s', 'rocket' ), $cf_browser_cache_return->get_error_message() ),
];
}
return [
'result' => 'success',
// translators: %s is the message returned by the CloudFlare API.
'message' => '<strong>' . __( 'WP Rocket: ', 'rocket' ) . '</strong>' . sprintf( __( 'Cloudflare browser cache set to %s seconds', 'rocket' ), $cf_browser_cache_return ),
];
}
/**
* Save Cloudflare auto settings admin option.
*
* @since 3.5.2
* @author Soponar Cristina
*
* @param array $auto_settings New value for Cloudflare auto_settings.
* @param array $old_settings Cloudflare cloudflare_old_settings.
*/
private function save_cloudflare_auto_settings( $auto_settings, $old_settings ) {
$cf_old_settings = explode( ',', $old_settings );
$cloudflare_update_result = [];
// Set Cache Level to Aggressive.
$cf_cache_level = isset( $cf_old_settings[0] ) && 0 === $auto_settings ? 'basic' : 'aggressive';
$cloudflare_update_result[] = $this->save_cache_level( $cf_cache_level );
// Active Minification for HTML, CSS & JS.
$cf_minify = isset( $cf_old_settings[1] ) && 0 === $auto_settings ? $cf_old_settings[1] : 'on';
$cloudflare_update_result[] = $this->save_minify( $cf_minify );
// Deactivate Rocket Loader to prevent conflicts.
$cf_rocket_loader = isset( $cf_old_settings[2] ) && 0 === $auto_settings ? $cf_old_settings[2] : 'off';
$cloudflare_update_result[] = $this->save_rocket_loader( $cf_rocket_loader );
// Set Browser cache to 1 year.
$cf_browser_cache_ttl = isset( $cf_old_settings[3] ) && 0 === $auto_settings ? $cf_old_settings[3] : '31536000';
$cloudflare_update_result[] = $this->save_browser_cache_ttl( $cf_browser_cache_ttl );
return $cloudflare_update_result;
}
/**
* Save Cloudflare admin options.
*
* @since 1.0
*
* @param array $old_value An array of previous values for the settings.
* @param array $value An array of submitted values for the settings.
*/
public function save_cloudflare_options( $old_value, $value ) {
if ( ! current_user_can( 'rocket_manage_options' ) ) {
return;
}
$is_api_keys_valid_cloudflare = get_transient( 'rocket_cloudflare_is_api_keys_valid' );
$submit_cloudflare_view = false;
if (
( isset( $old_value['cloudflare_email'], $value['cloudflare_email'] ) && $old_value['cloudflare_email'] !== $value['cloudflare_email'] )
||
( isset( $old_value['cloudflare_api_key'], $value['cloudflare_api_key'] ) && $old_value['cloudflare_api_key'] !== $value['cloudflare_api_key'] )
||
( isset( $old_value['cloudflare_zone_id'], $value['cloudflare_zone_id'] ) && $old_value['cloudflare_zone_id'] !== $value['cloudflare_zone_id'] )
) {
delete_transient( 'rocket_cloudflare_is_api_keys_valid' );
$is_api_keys_valid_cloudflare = $this->cloudflare->is_api_keys_valid( $value['cloudflare_email'], $value['cloudflare_api_key'], $value['cloudflare_zone_id'], true );
set_transient( 'rocket_cloudflare_is_api_keys_valid', $is_api_keys_valid_cloudflare, 2 * WEEK_IN_SECONDS );
$submit_cloudflare_view = true;
}
if ( ( isset( $old_value['cloudflare_devmode'], $value['cloudflare_devmode'] ) && (int) $old_value['cloudflare_devmode'] !== (int) $value['cloudflare_devmode'] ) ||
( isset( $old_value['cloudflare_auto_settings'], $value['cloudflare_auto_settings'] ) && (int) $old_value['cloudflare_auto_settings'] !== (int) $value['cloudflare_auto_settings'] ) ) {
$submit_cloudflare_view = true;
}
// Revalidate Cloudflare credentials if transient is false.
if ( false === $is_api_keys_valid_cloudflare ) {
if ( isset( $value['cloudflare_email'], $value['cloudflare_api_key'], $value['cloudflare_zone_id'] ) ) {
$is_api_keys_valid_cloudflare = $this->cloudflare->is_api_keys_valid( $value['cloudflare_email'], $value['cloudflare_api_key'], $value['cloudflare_zone_id'] );
} else {
$is_api_keys_valid_cloudflare = false;
}
set_transient( 'rocket_cloudflare_is_api_keys_valid', $is_api_keys_valid_cloudflare, 2 * WEEK_IN_SECONDS );
}
// If is submit CF view & CF Credentials are invalid, display error and bail out.
if ( is_wp_error( $is_api_keys_valid_cloudflare ) && $submit_cloudflare_view ) {
$cloudflare_error_message = $is_api_keys_valid_cloudflare->get_error_message();
add_settings_error( 'general', 'cloudflare_api_key_invalid', __( 'WP Rocket: ', 'rocket' ) . '</strong>' . $cloudflare_error_message . '<strong>', 'error' );
set_transient( get_current_user_id() . '_cloudflare_update_settings', [] );
return;
}
// Update CloudFlare Development Mode.
$cloudflare_update_result = [];
if ( isset( $old_value['cloudflare_devmode'], $value['cloudflare_devmode'] ) && (int) $old_value['cloudflare_devmode'] !== (int) $value['cloudflare_devmode'] ) {
$cloudflare_update_result[] = $this->save_cloudflare_devmode( $value['cloudflare_devmode'] );
}
// Update CloudFlare settings.
if ( isset( $old_value['cloudflare_auto_settings'], $value['cloudflare_auto_settings'] ) && (int) $old_value['cloudflare_auto_settings'] !== (int) $value['cloudflare_auto_settings'] ) {
$cloudflare_update_result = array_merge( $cloudflare_update_result, $this->save_cloudflare_auto_settings( $value['cloudflare_auto_settings'], $value['cloudflare_old_settings'] ) );
}
set_transient( get_current_user_id() . '_cloudflare_update_settings', $cloudflare_update_result );
}
/**
* Save Cloudflare old settings when the auto settings option is enabled.
*
* @since 1.0
*
* @param array $value An array of previous values for the settings.
* @param array $old_value An array of submitted values for the settings.
*
* @return array settings with old settings.
*/
public function save_cloudflare_old_settings( $value, $old_value ) {
if ( ! current_user_can( 'rocket_manage_options' ) ) {
return $value;
}
// Save old CloudFlare settings.
if (
isset( $value['cloudflare_auto_settings'], $old_value ['cloudflare_auto_settings'] )
&&
$value['cloudflare_auto_settings'] !== $old_value ['cloudflare_auto_settings']
&&
1 === $value['cloudflare_auto_settings']
) {
$cf_settings = $this->cloudflare->get_settings();
$value['cloudflare_old_settings'] = ! is_wp_error( $cf_settings )
? implode( ',', array_filter( $cf_settings ) )
: '';
}
return $value;
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace WPMedia\Cloudflare;
use RuntimeException;
class UnauthorizedException extends RuntimeException {}

View File

@@ -0,0 +1,51 @@
{
"name": "wp-media/cloudflare",
"description": "Cloudflare Addon",
"homepage": "https://github.com/wp-media/cloudflare",
"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/cloudflare/issues",
"source": "https://github.com/wp-media/cloudflare"
},
"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",
"wp-coding-standards/wpcs": "^2",
"wp-media/event-manager": "^3.1",
"wp-media/options": "^3.0",
"wp-media/phpunit": "^1.0"
},
"autoload": {
"psr-4": { "WPMedia\\Cloudflare\\": "." },
"exclude-from-classmap": [ "/Tests/" ]
},
"autoload-dev": {
"psr-4": { "WPMedia\\Cloudflare\\Tests\\": "Tests/" }
},
"scripts": {
"test-unit": "\"vendor/bin/wpmedia-phpunit\" unit path=Tests/Unit",
"test-integration": "\"vendor/bin/wpmedia-phpunit\" integration path=Tests/Integration/",
"run-tests": [
"@test-unit",
"@test-integration"
],
"install-codestandards": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run",
"phpcs": "phpcs --basepath=.",
"phpcs-changed": "./bin/phpcs-changed.sh",
"phpcs:fix": "phpcbf"
}
}

View File

@@ -0,0 +1,192 @@
<?php
namespace WP_Rocket\Addon\FacebookTracking;
use WP_Rocket\Addon\Busting\BustingFactory;
use WP_Rocket\Event_Management\Subscriber_Interface;
use WP_Rocket\Admin\Options_Data as Options;
/**
* Event subscriber for Facebook tracking cache busting.
*
* @since 3.2
*/
class Subscriber implements Subscriber_Interface {
/**
* Name of the cron.
*
* @var string
* @since 3.2
*/
const CRON_NAME = 'rocket_facebook_tracking_cache_update';
/**
* Instance of the Busting Factory class.
*
* @var BustingFactory
* @since 3.2
*/
private $busting_factory;
/**
* Instance of the Option_Data class.
*
* @var Options
* @since 3.2
*/
private $options;
/**
* Constructor.
*
* @since 3.2
*
* @param BustingFactory $busting_factory Instance of the Busting Factory class.
* @param Options $options Instance of the Options_Data class.
*/
public function __construct( BustingFactory $busting_factory, Options $options ) {
$this->busting_factory = $busting_factory;
$this->options = $options;
}
/**
* Return an array of events that this subscriber wants to listen to.
*
* @since 3.2
*
* @return array
*/
public static function get_subscribed_events() {
$events = [
'cron_schedules' => 'add_schedule',
'init' => 'schedule_cache_update',
self::CRON_NAME => 'update_cache',
'rocket_purge_cache' => 'delete_cache',
'rocket_buffer' => 'cache_busting_facebook_tracking',
];
return $events;
}
/**
* Add weekly interval to cron schedules.
*
* @since 3.2
*
* @param array $schedules An array of intervals used by cron jobs.
* @return array
*/
public function add_schedule( $schedules ) {
if ( ! $this->is_busting_active() ) {
return $schedules;
}
$schedules['weekly'] = [
'interval' => 604800,
'display' => __( 'weekly', 'rocket' ),
];
return $schedules;
}
/**
* (Un)Schedule the auto-update of the cache busting files.
*
* @since 3.2
*/
public function schedule_cache_update() {
$scheduled = wp_next_scheduled( self::CRON_NAME );
if ( ! $this->is_busting_active() ) {
if ( $scheduled ) {
wp_clear_scheduled_hook( self::CRON_NAME );
}
return;
}
if ( ! $scheduled ) {
wp_schedule_event( time(), 'weekly', self::CRON_NAME );
}
}
/**
* Update the Facebook Pixel cache busting files.
*
* @since 3.2
*
* @return bool
*/
public function update_cache() {
if ( ! $this->is_busting_active() ) {
return false;
}
$html = $this->busting_factory->type( 'fbsdk' )->refresh();
return $this->busting_factory->type( 'fbpix' )->refresh_all();
}
/**
* Delete Facebook Pixel cache busting files.
*
* @since 3.2
* @since 3.6 Argument replacement.
*
* @param string $type Type of cache clearance: 'all', 'post', 'term', 'user', 'url'.
* @return bool
*/
public function delete_cache( $type ) {
if ( 'all' !== $type || ! $this->is_busting_active() ) {
return false;
}
$html = $this->busting_factory->type( 'fbsdk' )->delete();
return $this->busting_factory->type( 'fbpix' )->delete_all();
}
/**
* Process the cache busting on the HTML contents.
*
* @since 3.2
*
* @param string $html HTML contents.
* @return string
*/
public function cache_busting_facebook_tracking( $html ) {
if ( ! $this->is_allowed() ) {
return $html;
}
$html = $this->busting_factory->type( 'fbsdk' )->replace_url( $html );
return $this->busting_factory->type( 'fbpix' )->replace_url( $html );
}
/**
* Tell if the cache busting should happen.
*
* @since 3.2
*
* @return bool
*/
private function is_allowed() {
if ( defined( 'DONOTROCKETOPTIMIZE' ) && DONOTROCKETOPTIMIZE ) {
return false;
}
return $this->is_busting_active();
}
/**
* Tell if the cache busting option is active.
*
* @since 3.2
*
* @return bool
*/
private function is_busting_active() {
return (bool) $this->options->get( 'facebook_pixel_cache', 0 );
}
}

View File

@@ -0,0 +1,245 @@
<?php
namespace WP_Rocket\Addon\GoogleTracking;
use WP_Rocket\Addon\Busting\FileBustingTrait;
use WP_Rocket\Busting\Abstract_Busting;
use WP_Rocket\Logger\Logger;
/**
* Manages the cache busting of the Google Analytics file.
*
* @since 3.1
*/
class GoogleAnalytics extends Abstract_Busting {
use FileBustingTrait;
/**
* Context used for the logger.
*
* @var string
* @since 3.2.4
* @author Grégory Viguier
*/
const LOGGER_CONTEXT = 'gg analytics';
/**
* Google Analytics URL.
*
* @var string
* @since 3.1
* @access protected
* @author Remy Perona
*/
protected $url = 'https://www.google-analytics.com/analytics.js';
/**
* File name (local).
* %s is a "version": a md5 hash of the file contents.
*
* @var string
* @since 3.2.4
* @access protected
* @author Grégory Viguier
*/
protected $filename_pattern = 'ga-%s.js';
/**
* Current file version (local): a md5 hash of the file contents.
*
* @var string
* @since 3.2.4
* @access protected
* @author Grégory Viguier
*/
protected $file_version;
/**
* Flag to track the replacement.
*
* @var bool
* @since 3.1
* @access protected
* @author Remy Perona
*/
protected $is_replaced = false;
/**
* Filesystem object.
*
* @var object
* @since 3.2.4
* @access protected
* @author Grégory Viguier
*/
protected $filesystem = false;
/**
* Constructor.
*
* @since 3.1
* @access public
* @author Remy Perona
*
* @param string $busting_path Path to the busting directory.
* @param string $busting_url URL of the busting directory.
*/
public function __construct( $busting_path, $busting_url ) {
$this->busting_path = $busting_path . 'google-tracking/';
$this->busting_url = $busting_url . 'google-tracking/';
$this->filesystem = rocket_direct_filesystem();
}
/** ----------------------------------------------------------------------------------------- */
/** PUBLIC METHODS ========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Performs the replacement process.
*
* @since 3.1
* @access public
* @author Remy Perona
*
* @param string $html HTML content.
* @return string
*/
public function replace_url( $html ) {
$this->is_replaced = false;
$tag = $this->find( '<script\s*(?<attr>[^>]*)?>(?<content>.*)?<\/script>', $html );
if ( ! $tag ) {
return $html;
}
Logger::info(
'GOOGLE ANALYTICS CACHING PROCESS STARTED.',
[
self::LOGGER_CONTEXT,
'tag' => $tag,
]
);
if ( ! $this->save( $this->url ) ) {
return $html;
}
$replace_tag = preg_replace( '/(?:https?:)?\/\/www\.google-analytics\.com\/analytics\.js/i', $this->get_busting_url(), $tag );
$html = str_replace( $tag, $replace_tag, $html );
$this->is_replaced = true;
Logger::info(
'Google Analytics caching process succeeded.',
[
self::LOGGER_CONTEXT,
'file' => $this->get_busting_path(),
]
);
return $html;
}
/**
* Tell if the replacement was sucessful or not.
*
* @since 3.1
* @access public
* @author Remy Perona
*
* @return bool
*/
public function is_replaced() {
return $this->is_replaced;
}
/**
* Saves the content of the URL to cache to the busting file.
*
* @since 3.2.4
* @access public
* @author Grégory Viguier
*
* @param string $url URL to get the content from.
* @return bool
*/
public function refresh_save( $url ) {
// Before doing anything, make sure the busting file can be created.
if ( ! $this->is_busting_dir_writable() ) {
return false;
}
// Get remote content.
$content = $this->get_remote_contents( $url );
if ( ! $content ) {
// Could not get the remote contents.
return false;
}
$version = md5( $content );
$path = $this->get_busting_file_path( $version );
return $this->update_file_contents( $path, $content );
}
/** ----------------------------------------------------------------------------------------- */
/** REMOTE FILE ============================================================================= */
/** ----------------------------------------------------------------------------------------- */
/**
* Get the Google Analytics URL.
*
* @since 3.1
* @access public
* @author Remy Perona
*
* @return string
*/
public function get_url() {
return $this->url;
}
/** ----------------------------------------------------------------------------------------- */
/** VARIOUS INTERNAL TOOLS ================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Searches for element(s) in the DOM.
*
* @since 3.1
* @access public
* @author Remy Perona
*
* @param string $pattern Pattern to match.
* @param string $html HTML content.
* @return string
*/
protected function find( $pattern, $html ) {
preg_match_all( '/' . $pattern . '/si', $html, $all_matches, PREG_SET_ORDER );
$matches = array_map(
function( $match ) {
if (
! preg_match( '/src\s*=\s*[\'"]\s*(?:https?:)?\/\/www\.google-analytics\.com\/analytics\.js\s*[\'"]/i', $match['attr'] . $match['content'] )
&&
false === strpos( $match['content'], 'GoogleAnalyticsObject' )
) {
return;
}
return $match[0];
},
$all_matches
);
$matches = array_values( array_filter( $matches ) );
if ( ! $matches ) {
return false;
}
return $matches[0];
}
}

View File

@@ -0,0 +1,200 @@
<?php
namespace WP_Rocket\Addon\GoogleTracking;
use WP_Rocket\Addon\Busting\FileBustingTrait;
use WP_Rocket\Logger\Logger;
use WP_Rocket\Busting\Abstract_Busting;
use WP_Filesystem_Direct;
/**
* Manages the cache busting of the Google Tag Manager file
*
* @since 3.1
*/
class GoogleTagManager extends Abstract_Busting {
use FileBustingTrait;
/**
* Context used for the logger.
*
* @var string
* @since 3.2.4
*/
const LOGGER_CONTEXT = 'gg tag manager';
/**
* File name (local).
* %s is a "version": a md5 hash of the file contents.
*
* @var string
* @since 3.2.4
* @access protected
*/
protected $filename_pattern = 'gtm-%s.js';
/**
* Current file version (local): a md5 hash of the file contents.
*
* @var string
* @since 3.2.4
* @access protected
*/
protected $file_version;
/**
* Filesystem object.
*
* @var object
* @since 3.2.4
* @access protected
*/
protected $filesystem = false;
/**
* Google Analytics object.
*
* @var object
* @since 3.2.4
* @access protected
*/
protected $ga_busting = false;
/**
* Constructor.
*
* @since 3.1
* @access public
*
* @param string $busting_path Path to the busting directory.
* @param string $busting_url URL of the busting directory.
* @param GoogleAnalytics $ga_busting A GoogleAnalytics instance.
* @param WP_Filesystem_Direct $filesystem Instance of the filesystem handler.
*/
public function __construct( $busting_path, $busting_url, GoogleAnalytics $ga_busting, $filesystem = null ) {
$blog_id = get_current_blog_id();
$this->busting_path = $busting_path . $blog_id . '/';
$this->busting_url = $busting_url . $blog_id . '/';
$this->ga_busting = $ga_busting;
$this->filesystem = is_null( $filesystem ) ? rocket_direct_filesystem() : $filesystem;
}
/** ----------------------------------------------------------------------------------------- */
/** PUBLIC METHODS ========================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Performs the replacement process.
*
* @since 3.1
* @access public
*
* @param string $html HTML content.
* @return string
*/
public function replace_url( $html ) {
$script = $this->find( '<script(\s+[^>]+)?\s+src\s*=\s*[\'"]\s*?((?:https?:)?\/\/www\.googletagmanager\.com(?:.+)?)\s*?[\'"]([^>]+)?\/?>', $html );
if ( ! $script ) {
return $html;
}
// replace relative protocol // with full https://.
$gtm_url = preg_replace( '/^\/\//', 'https://', $script[2] );
Logger::info(
'GOOGLE TAG MANAGER CACHING PROCESS STARTED.',
[
self::LOGGER_CONTEXT,
'tag' => $script,
]
);
if ( ! $this->save( $gtm_url ) ) {
return $html;
}
$replace_script = str_replace( $script[2], $this->get_busting_url(), $script[0] );
$replace_script = str_replace( '<script', '<script data-no-minify="1"', $replace_script );
$html = str_replace( $script[0], $replace_script, $html );
Logger::info(
'Google Tag Manager caching process succeeded.',
[
self::LOGGER_CONTEXT,
'file' => $this->get_busting_path(),
]
);
return $html;
}
/**
* Saves the content of the URL to cache to the busting file.
*
* @since 3.2
* @access public
*
* @param string $url URL to get the content from.
* @return bool
*/
public function refresh_save( $url ) {
// Before doing anything, make sure the busting file can be created.
if ( ! $this->is_busting_dir_writable() ) {
return false;
}
// Get remote content.
$content = $this->get_remote_contents( $url );
if ( ! $content ) {
// Could not get the remote contents.
return false;
}
$version = md5( $content );
$path = $this->get_busting_file_path( $version );
$content = $this->replace_ga_url( $content );
return $this->update_file_contents( $path, $content );
}
/** ----------------------------------------------------------------------------------------- */
/** VARIOUS INTERNAL TOOLS ================================================================== */
/** ----------------------------------------------------------------------------------------- */
/**
* Searches for element(s) in the DOM.
*
* @since 3.1
* @access public
*
* @param string $pattern Pattern to match.
* @param string $html HTML content.
* @return string
*/
protected function find( $pattern, $html ) {
preg_match_all( '/' . $pattern . '/Umsi', $html, $matches, PREG_SET_ORDER );
if ( empty( $matches ) ) {
return false;
}
return $matches[0];
}
/**
* Replaces the Google Analytics URL by the local copy inside the gtm-local.js file content
*
* @since 3.1
*
* @param string $content JavaScript content.
* @return string
*/
protected function replace_ga_url( $content ) {
if ( ! $this->ga_busting->save( $this->ga_busting->get_url() ) ) {
return $content;
}
return str_replace( $this->ga_busting->get_url(), $this->ga_busting->get_busting_url(), $content );
}
}

View File

@@ -0,0 +1,182 @@
<?php
namespace WP_Rocket\Addon\GoogleTracking;
use WP_Rocket\Event_Management\Subscriber_Interface;
use WP_Rocket\Addon\Busting\BustingFactory;
use WP_Rocket\Admin\Options_Data as Options;
/**
* Event subscriber for Google tracking cache busting
*
* @since 3.1
*/
class Subscriber implements Subscriber_Interface {
/**
* Instance of the Busting Factory class
*
* @var BustingFactory
*/
private $busting_factory;
/**
* Instance of the Option_Data class
*
* @var Options
*/
private $options;
/**
* Constructor
*
* @param BustingFactory $busting_factory Instance of the Busting Factory class.
* @param Options $options Instance of the Option_Data class.
*/
public function __construct( BustingFactory $busting_factory, Options $options ) {
$this->busting_factory = $busting_factory;
$this->options = $options;
}
/**
* Return an array of events that this subscriber wants to listen to.
*
* @since 3.1
*
* @return array
*/
public static function get_subscribed_events() {
$events = [
'cron_schedules' => 'add_schedule',
'init' => 'schedule_tracking_cache_update',
'rocket_google_tracking_cache_update' => 'update_tracking_cache',
'rocket_purge_cache' => 'delete_tracking_cache',
'rocket_buffer' => 'cache_busting_google_tracking',
];
return $events;
}
/**
* Processes the cache busting on the HTML content
*
* Google Analytics replacement is performed first, and if no replacement occured, Google Tag Manager replacement is performed.
*
* @since 3.1
*
* @param string $html HTML content.
* @return string
*/
public function cache_busting_google_tracking( $html ) {
if ( ! $this->is_allowed() ) {
return $html;
}
$processor = $this->busting_factory->type( 'ga' );
$html = $processor->replace_url( $html );
$processor = $this->busting_factory->type( 'gtm' );
$html = $processor->replace_url( $html );
return $html;
}
/**
* Schedules the auto-update of Google Analytics cache busting file
*
* @since 3.1
*
* @return void
*/
public function schedule_tracking_cache_update() {
if ( ! $this->is_busting_active() ) {
return;
}
if ( ! wp_next_scheduled( 'rocket_google_tracking_cache_update' ) ) {
wp_schedule_event( time(), 'weekly', 'rocket_google_tracking_cache_update' );
}
}
/**
* Updates Google Analytics cache busting file
*
* @since 3.1
*
* @return bool
*/
public function update_tracking_cache() {
if ( ! $this->is_busting_active() ) {
return false;
}
$processor = $this->busting_factory->type( 'ga' );
return $processor->refresh_save( $processor->get_url() );
}
/**
* Adds weekly interval to cron schedules
*
* @since 3.1
*
* @param Array $schedules An array of intervals used by cron jobs.
* @return Array
*/
public function add_schedule( $schedules ) {
if ( ! $this->is_busting_active() ) {
return $schedules;
}
$schedules['weekly'] = [
'interval' => 604800,
'display' => __( 'weekly', 'rocket' ),
];
return $schedules;
}
/**
* Deletes the GA busting file.
*
* @since 3.1
* @since 3.6 Argument replacement.
*
* @param string $type Type of cache clearance: 'all', 'post', 'term', 'user', 'url'.
* @return bool
*/
public function delete_tracking_cache( $type ) {
if ( 'all' !== $type || ! $this->is_busting_active() ) {
return false;
}
$this->busting_factory->type( 'gtm' )->delete();
return $this->busting_factory->type( 'ga' )->delete();
}
/**
* Checks if the cache busting should happen
*
* @since 3.1
*
* @return boolean
*/
private function is_allowed() {
if ( rocket_get_constant( 'DONOTROCKETOPTIMIZE' ) ) {
return false;
}
return $this->is_busting_active();
}
/**
* Tell if the cache busting option is active.
*
* @since 3.6
*
* @return bool
*/
private function is_busting_active() {
return (bool) $this->options->get( 'google_analytics_cache', 0 );
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace WP_Rocket\Addon;
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
use WP_Rocket\Admin\Options_Data;
/**
* Service provider for WP Rocket addons.
*
* @since 3.3
* @since 3.5 - renamed and moved into this module.
*/
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 = [
'busting_factory',
'facebook_tracking',
'google_tracking',
'sucuri_subscriber',
];
/**
* Registers the subscribers in the container.
*
* @since 3.3
*/
public function register() {
$options = $this->getContainer()->get( 'options' );
// Busting Factory.
$this->getContainer()->add( 'busting_factory', 'WP_Rocket\Addon\Busting\BustingFactory' )
->withArgument( rocket_get_constant( 'WP_ROCKET_CACHE_BUSTING_PATH' ) )
->withArgument( rocket_get_constant( 'WP_ROCKET_CACHE_BUSTING_URL' ) );
// Facebook Tracking Subscriber.
$this->getContainer()->share( 'facebook_tracking', 'WP_Rocket\Addon\FacebookTracking\Subscriber' )
->withArgument( $this->getContainer()->get( 'busting_factory' ) )
->withArgument( $options );
// Google Tracking Subscriber.
$this->getContainer()->share( 'google_tracking', 'WP_Rocket\Addon\GoogleTracking\Subscriber' )
->withArgument( $this->getContainer()->get( 'busting_factory' ) )
->withArgument( $options );
// Sucuri Addon.
$this->getContainer()->share( 'sucuri_subscriber', 'WP_Rocket\Subscriber\Third_Party\Plugins\Security\Sucuri_Subscriber' )
->withArgument( $options );
// Cloudflare Addon.
$this->addon_cloudflare( $options );
}
/**
* Adds Cloudflare Addon into the Container when the addon is enabled.
*
* @since 3.5
*
* @param Options_Data $options Instance of options.
*/
protected function addon_cloudflare( Options_Data $options ) {
// If the addon is not enabled, delete the transient and bail out. Don't load the addon.
if ( ! (bool) $options->get( 'do_cloudflare', false ) ) {
delete_transient( 'rocket_cloudflare_is_api_keys_valid' );
return;
}
$this->provides[] = 'cloudflare_subscriber';
$this->getContainer()->add( 'cloudflare_api', 'WPMedia\Cloudflare\APIClient' )
->withArgument( rocket_get_constant( 'WP_ROCKET_VERSION' ) );
$this->getContainer()->add( 'cloudflare', 'WPMedia\Cloudflare\Cloudflare' )
->withArgument( $options )
->withArgument( $this->getContainer()->get( 'cloudflare_api' ) );
$this->getContainer()->share( 'cloudflare_subscriber', 'WPMedia\Cloudflare\Subscriber' )
->withArgument( $this->getContainer()->get( 'cloudflare' ) )
->withArgument( $options )
->withArgument( $this->getContainer()->get( 'options_api' ) );
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace WP_Rocket\Addon\Varnish;
use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider;
/**
* Service provider for Varnish Addon.
*/
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 = [
'varnish',
'varnish_subscriber',
];
/**
* Registers the subscribers in the container.
*
* @since 3.3
*/
public function register() {
$this->getContainer()->add( 'varnish', 'WP_Rocket\Addon\Varnish\Varnish' );
$this->getContainer()->share( 'varnish_subscriber', 'WP_Rocket\Addon\Varnish\Subscriber' )
->withArgument( $this->getContainer()->get( 'varnish' ) )
->withArgument( $this->getContainer()->get( 'options' ) );
}
}

View File

@@ -0,0 +1,117 @@
<?php
namespace WP_Rocket\Addon\Varnish;
use WP_Rocket\Admin\Options_Data;
use WP_Rocket\Event_Management\Subscriber_Interface;
/**
* Subscriber for the Varnish Purge.
*
* @since 3.5
*/
class Subscriber implements Subscriber_Interface {
/**
* Varnish instance
*
* @var Varnish
*/
private $varnish;
/**
* WP Rocket options instance
*
* @var Options_Data
*/
private $options;
/**
* Constructor
*
* @param Varnish $varnish Varnish instance.
* @param Options_Data $options WP Rocket options instance.
*/
public function __construct( Varnish $varnish, Options_Data $options ) {
$this->varnish = $varnish;
$this->options = $options;
}
/**
* {@inheritdoc}
*/
public static function get_subscribed_events() {
return [
'before_rocket_clean_domain' => [ 'clean_domain', 10, 3 ],
'before_rocket_clean_file' => [ 'clean_file' ],
'before_rocket_clean_home' => [ 'clean_home', 10, 2 ],
];
}
/**
* Checks if Varnish cache should be purged
*
* @since 3.5
*
* @return bool
*/
private function should_purge() {
return (
/**
* Filters the use of the Varnish compatibility add-on
*
* @param bool $varnish_purge True to use, false otherwise.
*/
apply_filters( 'do_rocket_varnish_http_purge', false ) // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
||
(bool) $this->options->get( 'varnish_auto_purge', 0 )
);
}
/**
* Clears Varnish cache for the whole domain
*
* @param string $root The path of home cache file.
* @param string $lang The current lang to purge.
* @param string $url The home url.
* @return void
*/
public function clean_domain( $root, $lang, $url ) {
if ( ! $this->should_purge() ) {
return;
}
$this->varnish->purge( trailingslashit( $url ) . '?regex' );
}
/**
* Clears a specific page in Varnish cache
*
* @param string $url The url to purge.
* @return void
*/
public function clean_file( $url ) {
if ( ! $this->should_purge() ) {
return;
}
$this->varnish->purge( trailingslashit( $url ) . '?regex' );
}
/**
* Clears the homepage in Varnish cache
*
* @param string $root The path of home cache file.
* @param string $lang The current lang to purge.
* @return void
*/
public function clean_home( $root, $lang ) {
if ( ! $this->should_purge() ) {
return;
}
$home_url = trailingslashit( get_rocket_i18n_home_url( $lang ) );
$home_pagination_url = $home_url . trailingslashit( $GLOBALS['wp_rewrite']->pagination_base ) . '?regex';
$this->varnish->purge( $home_url );
$this->varnish->purge( $home_pagination_url );
}
}

View File

@@ -0,0 +1,129 @@
<?php
namespace WP_Rocket\Addon\Varnish;
/**
* Varnish cache purge
*
* @since 3.5
*/
class Varnish {
/**
* Send purge request to Varnish
*
* @since 3.5
*
* @param string $url The URL to purge.
* @return void
*/
public function purge( $url ) {
$parse_url = get_rocket_parse_url( $url );
$x_purge_method = 'default';
$regex = '';
if ( 'regex' === $parse_url['query'] ) {
$x_purge_method = 'regex';
$regex = '.*';
}
/**
* Filter the HTTP protocol (scheme)
*
* @since 2.7.3
* @param string $scheme The HTTP protocol
*/
$scheme = apply_filters( 'rocket_varnish_http_purge_scheme', 'http' );
/**
* Filters the headers to send with the Varnish purge request
*
* @since 3.1
*
* @param array $headers Headers to send.
*/
$headers = apply_filters(
'rocket_varnish_purge_headers',
[
/**
* Filters the host value passed in the request headers
*
* @since 2.8.15
* @param string $host The host value.
*/
'host' => apply_filters( 'rocket_varnish_purge_request_host', $parse_url['host'] ),
'X-Purge-Method' => $x_purge_method,
]
);
/**
* Filters the arguments passed to the Varnish purge request
*
* @since 3.5
*
* @param array $args Array of arguments for the request.
*/
$args = apply_filters(
'rocket_varnish_purge_request_args',
[
'method' => 'PURGE',
'blocking' => false,
'redirection' => 0,
'headers' => $headers,
]
);
foreach ( $this->get_varnish_ips() as $ip ) {
$host = ! empty( $ip ) ? $ip : str_replace( '*', '', $parse_url['host'] );
$purge_url_main = $scheme . '://' . $host . $parse_url['path'];
/**
* Filters the purge url.
*
* @since 3.6.3
*
* @param string $purge_url_full Full url contains the main url plus regex pattern.
* @param string $purge_url_main Main purge url without any additions params.
* @param string $regex Regex string.
*/
$purge_url = apply_filters(
'rocket_varnish_purge_url',
$purge_url_main . $regex,
$purge_url_main,
$regex
);
wp_remote_request( $purge_url, $args );
}
}
/**
* Gets an array of Varnish IPs to send the purge request to
*
* @return array
*/
private function get_varnish_ips() {
/**
* Filter the Varnish IP to call
*
* @since 2.6.8
* @param string|array $varnish_ip The Varnish IP
*/
$varnish_ip = apply_filters( 'rocket_varnish_ip', [] );
$constant = rocket_get_constant( 'WP_ROCKET_VARNISH_IP' );
if (
! empty( $constant )
&&
empty( $varnish_ip )
) {
$varnish_ip = $constant;
}
if ( empty( $varnish_ip ) ) {
$varnish_ip = [ '' ];
} elseif ( is_string( $varnish_ip ) ) {
$varnish_ip = (array) $varnish_ip;
}
return $varnish_ip;
}
}

View File

@@ -0,0 +1,54 @@
{
"name": "wp-media/module-varnish",
"description": "Varnish Addon for WP Rocket",
"homepage": "https://github.com/wp-media/module-varnish",
"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-varnish/issues",
"source": "https://github.com/wp-media/module-varnish"
},
"require-dev": {
"php": "^5.6 || ^7",
"brain/monkey": "^2.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
"phpcompatibility/phpcompatibility-wp": "^2.0",
"phpstan/phpstan": "^0.12.3",
"phpunit/phpunit": "^5.7 || ^7",
"roave/security-advisories": "dev-master",
"szepeviktor/phpstan-wordpress": "^0.6",
"wp-coding-standards/wpcs": "^2",
"wp-media/event-manager": "^3.1",
"wp-media/module-container": "^2.4",
"wp-media/options": "^3.0",
"wp-media/phpunit": "^1.0"
},
"autoload": {
"psr-4": { "WP_Rocket\\Addon\\Varnish\\": "." }
},
"autoload-dev": {
"psr-4": { "WP_Rocket\\Tests\\": "Tests/" }
},
"scripts": {
"test-unit": "\"vendor/bin/wpmedia-phpunit\" unit path=Tests/Unit",
"test-integration": "\"vendor/bin/wpmedia-phpunit\" integration path=Tests/Integration/",
"run-tests": [
"@test-unit",
"@test-integration"
],
"install-codestandards": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run",
"phpcs": "phpcs --basepath=.",
"phpcs-changed": "./bin/phpcs-changed.sh",
"phpcs:fix": "phpcbf"
}
}

View File

@@ -0,0 +1,752 @@
<?php
/**
* CSS Minifier
*
* Please report bugs on https://github.com/matthiasmullie/minify/issues
*
* @author Matthias Mullie <minify@mullie.eu>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
namespace WP_Rocket\Dependencies\Minify;
use WP_Rocket\Dependencies\Minify\Exceptions\FileImportException;
use WP_Rocket\Dependencies\PathConverter\ConverterInterface;
use WP_Rocket\Dependencies\PathConverter\Converter;
/**
* CSS minifier
*
* Please report bugs on https://github.com/matthiasmullie/minify/issues
*
* @package Minify
* @author Matthias Mullie <minify@mullie.eu>
* @author Tijs Verkoyen <minify@verkoyen.eu>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
class CSS extends Minify
{
/**
* @var int maximum inport size in kB
*/
protected $maxImportSize = 5;
/**
* @var string[] valid import extensions
*/
protected $importExtensions = array(
'gif' => 'data:image/gif',
'png' => 'data:image/png',
'jpe' => 'data:image/jpeg',
'jpg' => 'data:image/jpeg',
'jpeg' => 'data:image/jpeg',
'svg' => 'data:image/svg+xml',
'woff' => 'data:application/x-font-woff',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'xbm' => 'image/x-xbitmap',
);
/**
* Set the maximum size if files to be imported.
*
* Files larger than this size (in kB) will not be imported into the CSS.
* Importing files into the CSS as data-uri will save you some connections,
* but we should only import relatively small decorative images so that our
* CSS file doesn't get too bulky.
*
* @param int $size Size in kB
*/
public function setMaxImportSize($size)
{
$this->maxImportSize = $size;
}
/**
* Set the type of extensions to be imported into the CSS (to save network
* connections).
* Keys of the array should be the file extensions & respective values
* should be the data type.
*
* @param string[] $extensions Array of file extensions
*/
public function setImportExtensions(array $extensions)
{
$this->importExtensions = $extensions;
}
/**
* Move any import statements to the top.
*
* @param string $content Nearly finished CSS content
*
* @return string
*/
protected function moveImportsToTop($content)
{
if (preg_match_all('/(;?)(@import (?<url>url\()?(?P<quotes>["\']?).+?(?P=quotes)(?(url)\)));?/', $content, $matches)) {
// remove from content
foreach ($matches[0] as $import) {
$content = str_replace($import, '', $content);
}
// add to top
$content = implode(';', $matches[2]).';'.trim($content, ';');
}
return $content;
}
/**
* Combine CSS from import statements.
*
* @import's will be loaded and their content merged into the original file,
* to save HTTP requests.
*
* @param string $source The file to combine imports for
* @param string $content The CSS content to combine imports for
* @param string[] $parents Parent paths, for circular reference checks
*
* @return string
*
* @throws FileImportException
*/
protected function combineImports($source, $content, $parents)
{
$importRegexes = array(
// @import url(xxx)
'/
# import statement
@import
# whitespace
\s+
# open url()
url\(
# (optional) open path enclosure
(?P<quotes>["\']?)
# fetch path
(?P<path>.+?)
# (optional) close path enclosure
(?P=quotes)
# close url()
\)
# (optional) trailing whitespace
\s*
# (optional) media statement(s)
(?P<media>[^;]*)
# (optional) trailing whitespace
\s*
# (optional) closing semi-colon
;?
/ix',
// @import 'xxx'
'/
# import statement
@import
# whitespace
\s+
# open path enclosure
(?P<quotes>["\'])
# fetch path
(?P<path>.+?)
# close path enclosure
(?P=quotes)
# (optional) trailing whitespace
\s*
# (optional) media statement(s)
(?P<media>[^;]*)
# (optional) trailing whitespace
\s*
# (optional) closing semi-colon
;?
/ix',
);
// find all relative imports in css
$matches = array();
foreach ($importRegexes as $importRegex) {
if (preg_match_all($importRegex, $content, $regexMatches, PREG_SET_ORDER)) {
$matches = array_merge($matches, $regexMatches);
}
}
$search = array();
$replace = array();
// loop the matches
foreach ($matches as $match) {
// get the path for the file that will be imported
$importPath = dirname($source).'/'.$match['path'];
// only replace the import with the content if we can grab the
// content of the file
if (!$this->canImportByPath($match['path']) || !$this->canImportFile($importPath)) {
continue;
}
// check if current file was not imported previously in the same
// import chain.
if (in_array($importPath, $parents)) {
throw new FileImportException('Failed to import file "'.$importPath.'": circular reference detected.');
}
// grab referenced file & minify it (which may include importing
// yet other @import statements recursively)
$minifier = new static($importPath);
$minifier->setMaxImportSize($this->maxImportSize);
$minifier->setImportExtensions($this->importExtensions);
$importContent = $minifier->execute($source, $parents);
// check if this is only valid for certain media
if (!empty($match['media'])) {
$importContent = '@media '.$match['media'].'{'.$importContent.'}';
}
// add to replacement array
$search[] = $match[0];
$replace[] = $importContent;
}
// replace the import statements
return str_replace($search, $replace, $content);
}
/**
* Import files into the CSS, base64-ized.
*
* @url(image.jpg) images will be loaded and their content merged into the
* original file, to save HTTP requests.
*
* @param string $source The file to import files for
* @param string $content The CSS content to import files for
*
* @return string
*/
protected function importFiles($source, $content)
{
$regex = '/url\((["\']?)(.+?)\\1\)/i';
if ($this->importExtensions && preg_match_all($regex, $content, $matches, PREG_SET_ORDER)) {
$search = array();
$replace = array();
// loop the matches
foreach ($matches as $match) {
$extension = substr(strrchr($match[2], '.'), 1);
if ($extension && !array_key_exists($extension, $this->importExtensions)) {
continue;
}
// get the path for the file that will be imported
$path = $match[2];
$path = dirname($source).'/'.$path;
// only replace the import with the content if we're able to get
// the content of the file, and it's relatively small
if ($this->canImportFile($path) && $this->canImportBySize($path)) {
// grab content && base64-ize
$importContent = $this->load($path);
$importContent = base64_encode($importContent);
// build replacement
$search[] = $match[0];
$replace[] = 'url('.$this->importExtensions[$extension].';base64,'.$importContent.')';
}
}
// replace the import statements
$content = str_replace($search, $replace, $content);
}
return $content;
}
/**
* Minify the data.
* Perform CSS optimizations.
*
* @param string[optional] $path Path to write the data to
* @param string[] $parents Parent paths, for circular reference checks
*
* @return string The minified data
*/
public function execute($path = null, $parents = array())
{
$content = '';
// loop CSS data (raw data and files)
foreach ($this->data as $source => $css) {
/*
* Let's first take out strings & comments, since we can't just
* remove whitespace anywhere. If whitespace occurs inside a string,
* we should leave it alone. E.g.:
* p { content: "a test" }
*/
$this->extractStrings();
$this->stripComments();
$this->extractCalcs();
$css = $this->replace($css);
$css = $this->stripWhitespace($css);
$css = $this->shortenColors($css);
$css = $this->shortenZeroes($css);
$css = $this->shortenFontWeights($css);
$css = $this->stripEmptyTags($css);
// restore the string we've extracted earlier
$css = $this->restoreExtractedData($css);
$source = is_int($source) ? '' : $source;
$parents = $source ? array_merge($parents, array($source)) : $parents;
$css = $this->combineImports($source, $css, $parents);
$css = $this->importFiles($source, $css);
/*
* If we'll save to a new path, we'll have to fix the relative paths
* to be relative no longer to the source file, but to the new path.
* If we don't write to a file, fall back to same path so no
* conversion happens (because we still want it to go through most
* of the move code, which also addresses url() & @import syntax...)
*/
$converter = $this->getPathConverter($source, $path ?: $source);
$css = $this->move($converter, $css);
// combine css
$content .= $css;
}
$content = $this->moveImportsToTop($content);
return $content;
}
/**
* Moving a css file should update all relative urls.
* Relative references (e.g. ../images/image.gif) in a certain css file,
* will have to be updated when a file is being saved at another location
* (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
*
* @param ConverterInterface $converter Relative path converter
* @param string $content The CSS content to update relative urls for
*
* @return string
*/
protected function move(ConverterInterface $converter, $content)
{
/*
* Relative path references will usually be enclosed by url(). @import
* is an exception, where url() is not necessary around the path (but is
* allowed).
* This *could* be 1 regular expression, where both regular expressions
* in this array are on different sides of a |. But we're using named
* patterns in both regexes, the same name on both regexes. This is only
* possible with a (?J) modifier, but that only works after a fairly
* recent PCRE version. That's why I'm doing 2 separate regular
* expressions & combining the matches after executing of both.
*/
$relativeRegexes = array(
// url(xxx)
'/
# open url()
url\(
\s*
# open path enclosure
(?P<quotes>["\'])?
# fetch path
(?P<path>.+?)
# close path enclosure
(?(quotes)(?P=quotes))
\s*
# close url()
\)
/ix',
// @import "xxx"
'/
# import statement
@import
# whitespace
\s+
# we don\'t have to check for @import url(), because the
# condition above will already catch these
# open path enclosure
(?P<quotes>["\'])
# fetch path
(?P<path>.+?)
# close path enclosure
(?P=quotes)
/ix',
);
// find all relative urls in css
$matches = array();
foreach ($relativeRegexes as $relativeRegex) {
if (preg_match_all($relativeRegex, $content, $regexMatches, PREG_SET_ORDER)) {
$matches = array_merge($matches, $regexMatches);
}
}
$search = array();
$replace = array();
// loop all urls
foreach ($matches as $match) {
// determine if it's a url() or an @import match
$type = (strpos($match[0], '@import') === 0 ? 'import' : 'url');
$url = $match['path'];
if ($this->canImportByPath($url)) {
// attempting to interpret GET-params makes no sense, so let's discard them for awhile
$params = strrchr($url, '?');
$url = $params ? substr($url, 0, -strlen($params)) : $url;
// fix relative url
$url = $converter->convert($url);
// now that the path has been converted, re-apply GET-params
$url .= $params;
}
/*
* Urls with control characters above 0x7e should be quoted.
* According to Mozilla's parser, whitespace is only allowed at the
* end of unquoted urls.
* Urls with `)` (as could happen with data: uris) should also be
* quoted to avoid being confused for the url() closing parentheses.
* And urls with a # have also been reported to cause issues.
* Urls with quotes inside should also remain escaped.
*
* @see https://developer.mozilla.org/nl/docs/Web/CSS/url#The_url()_functional_notation
* @see https://hg.mozilla.org/mozilla-central/rev/14abca4e7378
* @see https://github.com/matthiasmullie/minify/issues/193
*/
$url = trim($url);
if (preg_match('/[\s\)\'"#\x{7f}-\x{9f}]/u', $url)) {
$url = $match['quotes'] . $url . $match['quotes'];
}
// build replacement
$search[] = $match[0];
if ($type === 'url') {
$replace[] = 'url('.$url.')';
} elseif ($type === 'import') {
$replace[] = '@import "'.$url.'"';
}
}
// replace urls
return str_replace($search, $replace, $content);
}
/**
* Shorthand hex color codes.
* #FF0000 -> #F00.
*
* @param string $content The CSS content to shorten the hex color codes for
*
* @return string
*/
protected function shortenColors($content)
{
$content = preg_replace('/(?<=[: ])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?:([0-9a-z])\\4)?(?=[; }])/i', '#$1$2$3$4', $content);
// remove alpha channel if it's pointless...
$content = preg_replace('/(?<=[: ])#([0-9a-z]{6})ff?(?=[; }])/i', '#$1', $content);
$content = preg_replace('/(?<=[: ])#([0-9a-z]{3})f?(?=[; }])/i', '#$1', $content);
$colors = array(
// we can shorten some even more by replacing them with their color name
'#F0FFFF' => 'azure',
'#F5F5DC' => 'beige',
'#A52A2A' => 'brown',
'#FF7F50' => 'coral',
'#FFD700' => 'gold',
'#808080' => 'gray',
'#008000' => 'green',
'#4B0082' => 'indigo',
'#FFFFF0' => 'ivory',
'#F0E68C' => 'khaki',
'#FAF0E6' => 'linen',
'#800000' => 'maroon',
'#000080' => 'navy',
'#808000' => 'olive',
'#CD853F' => 'peru',
'#FFC0CB' => 'pink',
'#DDA0DD' => 'plum',
'#800080' => 'purple',
'#F00' => 'red',
'#FA8072' => 'salmon',
'#A0522D' => 'sienna',
'#C0C0C0' => 'silver',
'#FFFAFA' => 'snow',
'#D2B48C' => 'tan',
'#FF6347' => 'tomato',
'#EE82EE' => 'violet',
'#F5DEB3' => 'wheat',
// or the other way around
'WHITE' => '#fff',
'BLACK' => '#000',
);
return preg_replace_callback(
'/(?<=[: ])('.implode('|', array_keys($colors)).')(?=[; }])/i',
function ($match) use ($colors) {
return $colors[strtoupper($match[0])];
},
$content
);
}
/**
* Shorten CSS font weights.
*
* @param string $content The CSS content to shorten the font weights for
*
* @return string
*/
protected function shortenFontWeights($content)
{
$weights = array(
'normal' => 400,
'bold' => 700,
);
$callback = function ($match) use ($weights) {
return $match[1].$weights[$match[2]];
};
return preg_replace_callback('/(font-weight\s*:\s*)('.implode('|', array_keys($weights)).')(?=[;}])/', $callback, $content);
}
/**
* Shorthand 0 values to plain 0, instead of e.g. -0em.
*
* @param string $content The CSS content to shorten the zero values for
*
* @return string
*/
protected function shortenZeroes($content)
{
// we don't want to strip units in `calc()` expressions:
// `5px - 0px` is valid, but `5px - 0` is not
// `10px * 0` is valid (equates to 0), and so is `10 * 0px`, but
// `10 * 0` is invalid
// we've extracted calcs earlier, so we don't need to worry about this
// reusable bits of code throughout these regexes:
// before & after are used to make sure we don't match lose unintended
// 0-like values (e.g. in #000, or in http://url/1.0)
// units can be stripped from 0 values, or used to recognize non 0
// values (where wa may be able to strip a .0 suffix)
$before = '(?<=[:(, ])';
$after = '(?=[ ,);}])';
$units = '(em|ex|%|px|cm|mm|in|pt|pc|ch|rem|vh|vw|vmin|vmax|vm)';
// strip units after zeroes (0px -> 0)
// NOTE: it should be safe to remove all units for a 0 value, but in
// practice, Webkit (especially Safari) seems to stumble over at least
// 0%, potentially other units as well. Only stripping 'px' for now.
// @see https://github.com/matthiasmullie/minify/issues/60
$content = preg_replace('/'.$before.'(-?0*(\.0+)?)(?<=0)px'.$after.'/', '\\1', $content);
// strip 0-digits (.0 -> 0)
$content = preg_replace('/'.$before.'\.0+'.$units.'?'.$after.'/', '0\\1', $content);
// strip trailing 0: 50.10 -> 50.1, 50.10px -> 50.1px
$content = preg_replace('/'.$before.'(-?[0-9]+\.[0-9]+)0+'.$units.'?'.$after.'/', '\\1\\2', $content);
// strip trailing 0: 50.00 -> 50, 50.00px -> 50px
$content = preg_replace('/'.$before.'(-?[0-9]+)\.0+'.$units.'?'.$after.'/', '\\1\\2', $content);
// strip leading 0: 0.1 -> .1, 01.1 -> 1.1
$content = preg_replace('/'.$before.'(-?)0+([0-9]*\.[0-9]+)'.$units.'?'.$after.'/', '\\1\\2\\3', $content);
// strip negative zeroes (-0 -> 0) & truncate zeroes (00 -> 0)
$content = preg_replace('/'.$before.'-?0+'.$units.'?'.$after.'/', '0\\1', $content);
// IE doesn't seem to understand a unitless flex-basis value (correct -
// it goes against the spec), so let's add it in again (make it `%`,
// which is only 1 char: 0%, 0px, 0 anything, it's all just the same)
// @see https://developer.mozilla.org/nl/docs/Web/CSS/flex
$content = preg_replace('/flex:([0-9]+\s[0-9]+\s)0([;\}])/', 'flex:${1}0%${2}', $content);
$content = preg_replace('/flex-basis:0([;\}])/', 'flex-basis:0%${1}', $content);
return $content;
}
/**
* Strip empty tags from source code.
*
* @param string $content
*
* @return string
*/
protected function stripEmptyTags($content)
{
$content = preg_replace('/(?<=^)[^\{\};]+\{\s*\}/', '', $content);
$content = preg_replace('/(?<=(\}|;))[^\{\};]+\{\s*\}/', '', $content);
return $content;
}
/**
* Strip comments from source code.
*/
protected function stripComments()
{
// PHP only supports $this inside anonymous functions since 5.4
$minifier = $this;
$callback = function ($match) use ($minifier) {
$count = count($minifier->extracted);
$placeholder = '/*'.$count.'*/';
$minifier->extracted[$placeholder] = $match[0];
return $placeholder;
};
$this->registerPattern('/\n?\/\*(!|.*?@license|.*?@preserve).*?\*\/\n?/s', $callback);
$this->registerPattern('/\/\*.*?\*\//s', '');
}
/**
* Strip whitespace.
*
* @param string $content The CSS content to strip the whitespace for
*
* @return string
*/
protected function stripWhitespace($content)
{
// remove leading & trailing whitespace
$content = preg_replace('/^\s*/m', '', $content);
$content = preg_replace('/\s*$/m', '', $content);
// replace newlines with a single space
$content = preg_replace('/\s+/', ' ', $content);
// remove whitespace around meta characters
// inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
$content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
$content = preg_replace('/([\[(:>\+])\s+/', '$1', $content);
$content = preg_replace('/\s+([\]\)>\+])/', '$1', $content);
$content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
// whitespace around + and - can only be stripped inside some pseudo-
// classes, like `:nth-child(3+2n)`
// not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
// selectors like `div.weird- p`
$pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type');
$content = preg_replace('/:('.implode('|', $pseudos).')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
// remove semicolon/whitespace followed by closing bracket
$content = str_replace(';}', '}', $content);
return trim($content);
}
/**
* Replace all `calc()` occurrences.
*/
protected function extractCalcs()
{
// PHP only supports $this inside anonymous functions since 5.4
$minifier = $this;
$callback = function ($match) use ($minifier) {
$length = strlen($match[1]);
$expr = '';
$opened = 0;
for ($i = 0; $i < $length; $i++) {
$char = $match[1][$i];
$expr .= $char;
if ($char === '(') {
$opened++;
} elseif ($char === ')' && --$opened === 0) {
break;
}
}
$rest = str_replace($expr, '', $match[1]);
$expr = trim(substr($expr, 1, -1));
$count = count($minifier->extracted);
$placeholder = 'calc('.$count.')';
$minifier->extracted[$placeholder] = 'calc('.$expr.')';
return $placeholder.$rest;
};
$this->registerPattern('/calc(\(.+?)(?=$|;|}|calc\()/', $callback);
$this->registerPattern('/calc(\(.+?)(?=$|;|}|calc\()/m', $callback);
}
/**
* Check if file is small enough to be imported.
*
* @param string $path The path to the file
*
* @return bool
*/
protected function canImportBySize($path)
{
return ($size = @filesize($path)) && $size <= $this->maxImportSize * 1024;
}
/**
* Check if file a file can be imported, going by the path.
*
* @param string $path
*
* @return bool
*/
protected function canImportByPath($path)
{
return preg_match('/^(data:|https?:|\\/)/', $path) === 0;
}
/**
* Return a converter to update relative paths to be relative to the new
* destination.
*
* @param string $source
* @param string $target
*
* @return ConverterInterface
*/
protected function getPathConverter($source, $target)
{
return new Converter($source, $target);
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* Base Exception
*
* @deprecated Use Exceptions\BasicException instead
*
* @author Matthias Mullie <minify@mullie.eu>
*/
namespace WP_Rocket\Dependencies\Minify;
/**
* Base Exception Class
* @deprecated Use Exceptions\BasicException instead
*
* @package Minify
* @author Matthias Mullie <minify@mullie.eu>
*/
abstract class Exception extends \Exception
{
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Basic exception
*
* Please report bugs on https://github.com/matthiasmullie/minify/issues
*
* @author Matthias Mullie <minify@mullie.eu>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
namespace WP_Rocket\Dependencies\Minify\Exceptions;
use WP_Rocket\Dependencies\Minify\Exception;
/**
* Basic Exception Class
*
* @package Minify\Exception
* @author Matthias Mullie <minify@mullie.eu>
*/
abstract class BasicException extends Exception
{
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* File Import Exception
*
* Please report bugs on https://github.com/matthiasmullie/minify/issues
*
* @author Matthias Mullie <minify@mullie.eu>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
namespace WP_Rocket\Dependencies\Minify\Exceptions;
/**
* File Import Exception Class
*
* @package Minify\Exception
* @author Matthias Mullie <minify@mullie.eu>
*/
class FileImportException extends BasicException
{
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* IO Exception
*
* Please report bugs on https://github.com/matthiasmullie/minify/issues
*
* @author Matthias Mullie <minify@mullie.eu>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
namespace WP_Rocket\Dependencies\Minify\Exceptions;
/**
* IO Exception Class
*
* @package Minify\Exception
* @author Matthias Mullie <minify@mullie.eu>
*/
class IOException extends BasicException
{
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,497 @@
<?php
/**
* Abstract minifier class
*
* Please report bugs on https://github.com/matthiasmullie/minify/issues
*
* @author Matthias Mullie <minify@mullie.eu>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
namespace WP_Rocket\Dependencies\Minify;
use WP_Rocket\Dependencies\Minify\Exceptions\IOException;
use Psr\Cache\CacheItemInterface;
/**
* Abstract minifier class.
*
* Please report bugs on https://github.com/matthiasmullie/minify/issues
*
* @package Minify
* @author Matthias Mullie <minify@mullie.eu>
* @copyright Copyright (c) 2012, Matthias Mullie. All rights reserved
* @license MIT License
*/
abstract class Minify
{
/**
* The data to be minified.
*
* @var string[]
*/
protected $data = array();
/**
* Array of patterns to match.
*
* @var string[]
*/
protected $patterns = array();
/**
* This array will hold content of strings and regular expressions that have
* been extracted from the JS source code, so we can reliably match "code",
* without having to worry about potential "code-like" characters inside.
*
* @var string[]
*/
public $extracted = array();
/**
* Init the minify class - optionally, code may be passed along already.
*/
public function __construct(/* $data = null, ... */)
{
// it's possible to add the source through the constructor as well ;)
if (func_num_args()) {
call_user_func_array(array($this, 'add'), func_get_args());
}
}
/**
* Add a file or straight-up code to be minified.
*
* @param string|string[] $data
*
* @return static
*/
public function add($data /* $data = null, ... */)
{
// bogus "usage" of parameter $data: scrutinizer warns this variable is
// not used (we're using func_get_args instead to support overloading),
// but it still needs to be defined because it makes no sense to have
// this function without argument :)
$args = array($data) + func_get_args();
// this method can be overloaded
foreach ($args as $data) {
if (is_array($data)) {
call_user_func_array(array($this, 'add'), $data);
continue;
}
// redefine var
$data = (string) $data;
// load data
$value = $this->load($data);
$key = ($data != $value) ? $data : count($this->data);
// replace CR linefeeds etc.
// @see https://github.com/matthiasmullie/minify/pull/139
$value = str_replace(array("\r\n", "\r"), "\n", $value);
// store data
$this->data[$key] = $value;
}
return $this;
}
/**
* Add a file to be minified.
*
* @param string|string[] $data
*
* @return static
*
* @throws IOException
*/
public function addFile($data /* $data = null, ... */)
{
// bogus "usage" of parameter $data: scrutinizer warns this variable is
// not used (we're using func_get_args instead to support overloading),
// but it still needs to be defined because it makes no sense to have
// this function without argument :)
$args = array($data) + func_get_args();
// this method can be overloaded
foreach ($args as $path) {
if (is_array($path)) {
call_user_func_array(array($this, 'addFile'), $path);
continue;
}
// redefine var
$path = (string) $path;
// check if we can read the file
if (!$this->canImportFile($path)) {
throw new IOException('The file "'.$path.'" could not be opened for reading. Check if PHP has enough permissions.');
}
$this->add($path);
}
return $this;
}
/**
* Minify the data & (optionally) saves it to a file.
*
* @param string[optional] $path Path to write the data to
*
* @return string The minified data
*/
public function minify($path = null)
{
$content = $this->execute($path);
// save to path
if ($path !== null) {
$this->save($content, $path);
}
return $content;
}
/**
* Minify & gzip the data & (optionally) saves it to a file.
*
* @param string[optional] $path Path to write the data to
* @param int[optional] $level Compression level, from 0 to 9
*
* @return string The minified & gzipped data
*/
public function gzip($path = null, $level = 9)
{
$content = $this->execute($path);
$content = gzencode($content, $level, FORCE_GZIP);
// save to path
if ($path !== null) {
$this->save($content, $path);
}
return $content;
}
/**
* Minify the data & write it to a CacheItemInterface object.
*
* @param CacheItemInterface $item Cache item to write the data to
*
* @return CacheItemInterface Cache item with the minifier data
*/
public function cache(CacheItemInterface $item)
{
$content = $this->execute();
$item->set($content);
return $item;
}
/**
* Minify the data.
*
* @param string[optional] $path Path to write the data to
*
* @return string The minified data
*/
abstract public function execute($path = null);
/**
* Load data.
*
* @param string $data Either a path to a file or the content itself
*
* @return string
*/
protected function load($data)
{
// check if the data is a file
if ($this->canImportFile($data)) {
$data = file_get_contents($data);
// strip BOM, if any
if (substr($data, 0, 3) == "\xef\xbb\xbf") {
$data = substr($data, 3);
}
}
return $data;
}
/**
* Save to file.
*
* @param string $content The minified data
* @param string $path The path to save the minified data to
*
* @throws IOException
*/
protected function save($content, $path)
{
$handler = $this->openFileForWriting($path);
$this->writeToFile($handler, $content);
@fclose($handler);
}
/**
* Register a pattern to execute against the source content.
*
* @param string $pattern PCRE pattern
* @param string|callable $replacement Replacement value for matched pattern
*/
protected function registerPattern($pattern, $replacement = '')
{
// study the pattern, we'll execute it more than once
$pattern .= 'S';
$this->patterns[] = array($pattern, $replacement);
}
/**
* We can't "just" run some regular expressions against JavaScript: it's a
* complex language. E.g. having an occurrence of // xyz would be a comment,
* unless it's used within a string. Of you could have something that looks
* like a 'string', but inside a comment.
* The only way to accurately replace these pieces is to traverse the JS one
* character at a time and try to find whatever starts first.
*
* @param string $content The content to replace patterns in
*
* @return string The (manipulated) content
*/
protected function replace($content)
{
$processed = '';
$positions = array_fill(0, count($this->patterns), -1);
$matches = array();
while ($content) {
// find first match for all patterns
foreach ($this->patterns as $i => $pattern) {
list($pattern, $replacement) = $pattern;
// we can safely ignore patterns for positions we've unset earlier,
// because we know these won't show up anymore
if (array_key_exists($i, $positions) == false) {
continue;
}
// no need to re-run matches that are still in the part of the
// content that hasn't been processed
if ($positions[$i] >= 0) {
continue;
}
$match = null;
if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE)) {
$matches[$i] = $match;
// we'll store the match position as well; that way, we
// don't have to redo all preg_matches after changing only
// the first (we'll still know where those others are)
$positions[$i] = $match[0][1];
} else {
// if the pattern couldn't be matched, there's no point in
// executing it again in later runs on this same content;
// ignore this one until we reach end of content
unset($matches[$i], $positions[$i]);
}
}
// no more matches to find: everything's been processed, break out
if (!$matches) {
$processed .= $content;
break;
}
// see which of the patterns actually found the first thing (we'll
// only want to execute that one, since we're unsure if what the
// other found was not inside what the first found)
$discardLength = min($positions);
$firstPattern = array_search($discardLength, $positions);
$match = $matches[$firstPattern][0][0];
// execute the pattern that matches earliest in the content string
list($pattern, $replacement) = $this->patterns[$firstPattern];
$replacement = $this->replacePattern($pattern, $replacement, $content);
// figure out which part of the string was unmatched; that's the
// part we'll execute the patterns on again next
$content = (string) substr($content, $discardLength);
$unmatched = (string) substr($content, strpos($content, $match) + strlen($match));
// move the replaced part to $processed and prepare $content to
// again match batch of patterns against
$processed .= substr($replacement, 0, strlen($replacement) - strlen($unmatched));
$content = $unmatched;
// first match has been replaced & that content is to be left alone,
// the next matches will start after this replacement, so we should
// fix their offsets
foreach ($positions as $i => $position) {
$positions[$i] -= $discardLength + strlen($match);
}
}
return $processed;
}
/**
* This is where a pattern is matched against $content and the matches
* are replaced by their respective value.
* This function will be called plenty of times, where $content will always
* move up 1 character.
*
* @param string $pattern Pattern to match
* @param string|callable $replacement Replacement value
* @param string $content Content to match pattern against
*
* @return string
*/
protected function replacePattern($pattern, $replacement, $content)
{
if (is_callable($replacement)) {
return preg_replace_callback($pattern, $replacement, $content, 1, $count);
} else {
return preg_replace($pattern, $replacement, $content, 1, $count);
}
}
/**
* Strings are a pattern we need to match, in order to ignore potential
* code-like content inside them, but we just want all of the string
* content to remain untouched.
*
* This method will replace all string content with simple STRING#
* placeholder text, so we've rid all strings from characters that may be
* misinterpreted. Original string content will be saved in $this->extracted
* and after doing all other minifying, we can restore the original content
* via restoreStrings().
*
* @param string[optional] $chars
* @param string[optional] $placeholderPrefix
*/
protected function extractStrings($chars = '\'"', $placeholderPrefix = '')
{
// PHP only supports $this inside anonymous functions since 5.4
$minifier = $this;
$callback = function ($match) use ($minifier, $placeholderPrefix) {
// check the second index here, because the first always contains a quote
if ($match[2] === '') {
/*
* Empty strings need no placeholder; they can't be confused for
* anything else anyway.
* But we still needed to match them, for the extraction routine
* to skip over this particular string.
*/
return $match[0];
}
$count = count($minifier->extracted);
$placeholder = $match[1].$placeholderPrefix.$count.$match[1];
$minifier->extracted[$placeholder] = $match[1].$match[2].$match[1];
return $placeholder;
};
/*
* The \\ messiness explained:
* * Don't count ' or " as end-of-string if it's escaped (has backslash
* in front of it)
* * Unless... that backslash itself is escaped (another leading slash),
* in which case it's no longer escaping the ' or "
* * So there can be either no backslash, or an even number
* * multiply all of that times 4, to account for the escaping that has
* to be done to pass the backslash into the PHP string without it being
* considered as escape-char (times 2) and to get it in the regex,
* escaped (times 2)
*/
$this->registerPattern('/(['.$chars.'])(.*?(?<!\\\\)(\\\\\\\\)*+)\\1/s', $callback);
}
/**
* This method will restore all extracted data (strings, regexes) that were
* replaced with placeholder text in extract*(). The original content was
* saved in $this->extracted.
*
* @param string $content
*
* @return string
*/
protected function restoreExtractedData($content)
{
if (!$this->extracted) {
// nothing was extracted, nothing to restore
return $content;
}
$content = strtr($content, $this->extracted);
$this->extracted = array();
return $content;
}
/**
* Check if the path is a regular file and can be read.
*
* @param string $path
*
* @return bool
*/
protected function canImportFile($path)
{
$parsed = parse_url($path);
if (
// file is elsewhere
isset($parsed['host']) ||
// file responds to queries (may change, or need to bypass cache)
isset($parsed['query'])
) {
return false;
}
return strlen($path) < PHP_MAXPATHLEN && @is_file($path) && is_readable($path);
}
/**
* Attempts to open file specified by $path for writing.
*
* @param string $path The path to the file
*
* @return resource Specifier for the target file
*
* @throws IOException
*/
protected function openFileForWriting($path)
{
if (($handler = @fopen($path, 'w')) === false) {
throw new IOException('The file "'.$path.'" could not be opened for writing. Check if PHP has enough permissions.');
}
return $handler;
}
/**
* Attempts to write $content to the file specified by $handler. $path is used for printing exceptions.
*
* @param resource $handler The resource to write to
* @param string $content The content to write
* @param string $path The path to the file (for exception printing only)
*
* @throws IOException
*/
protected function writeToFile($handler, $content, $path = '')
{
if (($result = @fwrite($handler, $content)) === false || ($result < strlen($content))) {
throw new IOException('The file "'.$path.'" could not be written to. Check your disk space and file permissions.');
}
}
}

View File

@@ -0,0 +1,7 @@
in
public
extends
private
protected
implements
instanceof

View File

@@ -0,0 +1,26 @@
do
in
let
new
var
case
else
enum
void
with
class
const
yield
delete
export
import
public
static
typeof
extends
package
private
function
protected
implements
instanceof

View File

@@ -0,0 +1,63 @@
do
if
in
for
let
new
try
var
case
else
enum
eval
null
this
true
void
with
break
catch
class
const
false
super
throw
while
yield
delete
export
import
public
return
static
switch
typeof
default
extends
finally
package
private
continue
debugger
function
arguments
interface
protected
implements
instanceof
abstract
boolean
byte
char
double
final
float
goto
int
long
native
short
synchronized
throws
transient
volatile

View File

@@ -0,0 +1,46 @@
+
-
*
/
%
=
+=
-=
*=
/=
%=
<<=
>>=
>>>=
&=
^=
|=
&
|
^
~
<<
>>
>>>
==
===
!=
!==
>
<
>=
<=
&&
||
!
.
[
]
?
:
,
;
(
)
{
}

View File

@@ -0,0 +1,43 @@
+
-
*
/
%
=
+=
-=
*=
/=
%=
<<=
>>=
>>>=
&=
^=
|=
&
|
^
<<
>>
>>>
==
===
!=
!==
>
<
>=
<=
&&
||
.
[
]
?
:
,
;
(
)
}

View File

@@ -0,0 +1,43 @@
+
-
*
/
%
=
+=
-=
*=
/=
%=
<<=
>>=
>>>=
&=
^=
|=
&
|
^
~
<<
>>
>>>
==
===
!=
!==
>
<
>=
<=
&&
||
!
.
[
?
:
,
;
(
{

View File

@@ -0,0 +1,204 @@
<?php
namespace WP_Rocket\Dependencies\PathConverter;
/**
* Convert paths relative from 1 file to another.
*
* E.g.
* ../../images/icon.jpg relative to /css/imports/icons.css
* becomes
* ../images/icon.jpg relative to /css/minified.css
*
* Please report bugs on https://github.com/matthiasmullie/path-converter/issues
*
* @author Matthias Mullie <pathconverter@mullie.eu>
* @copyright Copyright (c) 2015, Matthias Mullie. All rights reserved
* @license MIT License
*/
class Converter implements ConverterInterface
{
/**
* @var string
*/
protected $from;
/**
* @var string
*/
protected $to;
/**
* @param string $from The original base path (directory, not file!)
* @param string $to The new base path (directory, not file!)
* @param string $root Root directory (defaults to `getcwd`)
*/
public function __construct($from, $to, $root = '')
{
$shared = $this->shared($from, $to);
if ($shared === '') {
// when both paths have nothing in common, one of them is probably
// absolute while the other is relative
$root = $root ?: getcwd();
$from = strpos($from, $root) === 0 ? $from : preg_replace('/\/+/', '/', $root.'/'.$from);
$to = strpos($to, $root) === 0 ? $to : preg_replace('/\/+/', '/', $root.'/'.$to);
// or traveling the tree via `..`
// attempt to resolve path, or assume it's fine if it doesn't exist
$from = @realpath($from) ?: $from;
$to = @realpath($to) ?: $to;
}
$from = $this->dirname($from);
$to = $this->dirname($to);
$from = $this->normalize($from);
$to = $this->normalize($to);
$this->from = $from;
$this->to = $to;
}
/**
* Normalize path.
*
* @param string $path
*
* @return string
*/
protected function normalize($path)
{
// deal with different operating systems' directory structure
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $path), '/');
// remove leading current directory.
if (substr($path, 0, 2) === './') {
$path = substr($path, 2);
}
// remove references to current directory in the path.
$path = str_replace('/./', '/', $path);
/*
* Example:
* /home/forkcms/frontend/cache/compiled_templates/../../core/layout/css/../images/img.gif
* to
* /home/forkcms/frontend/core/layout/images/img.gif
*/
do {
$path = preg_replace('/[^\/]+(?<!\.\.)\/\.\.\//', '', $path, -1, $count);
} while ($count);
return $path;
}
/**
* Figure out the shared path of 2 locations.
*
* Example:
* /home/forkcms/frontend/core/layout/images/img.gif
* and
* /home/forkcms/frontend/cache/minified_css
* share
* /home/forkcms/frontend
*
* @param string $path1
* @param string $path2
*
* @return string
*/
protected function shared($path1, $path2)
{
// $path could theoretically be empty (e.g. no path is given), in which
// case it shouldn't expand to array(''), which would compare to one's
// root /
$path1 = $path1 ? explode('/', $path1) : array();
$path2 = $path2 ? explode('/', $path2) : array();
$shared = array();
// compare paths & strip identical ancestors
foreach ($path1 as $i => $chunk) {
if (isset($path2[$i]) && $path1[$i] == $path2[$i]) {
$shared[] = $chunk;
} else {
break;
}
}
return implode('/', $shared);
}
/**
* Convert paths relative from 1 file to another.
*
* E.g.
* ../images/img.gif relative to /home/forkcms/frontend/core/layout/css
* should become:
* ../../core/layout/images/img.gif relative to
* /home/forkcms/frontend/cache/minified_css
*
* @param string $path The relative path that needs to be converted
*
* @return string The new relative path
*/
public function convert($path)
{
// quit early if conversion makes no sense
if ($this->from === $this->to) {
return $path;
}
$path = $this->normalize($path);
// if we're not dealing with a relative path, just return absolute
if (strpos($path, '/') === 0) {
return $path;
}
// normalize paths
$path = $this->normalize($this->from.'/'.$path);
// strip shared ancestor paths
$shared = $this->shared($path, $this->to);
$path = mb_substr($path, mb_strlen($shared));
$to = mb_substr($this->to, mb_strlen($shared));
// add .. for every directory that needs to be traversed to new path
$to = str_repeat('../', count(array_filter(explode('/', $to))));
return $to.ltrim($path, '/');
}
/**
* Attempt to get the directory name from a path.
*
* @param string $path
*
* @return string
*/
protected function dirname($path)
{
if (@is_file($path)) {
return dirname($path);
}
if (@is_dir($path)) {
return rtrim($path, '/');
}
// no known file/dir, start making assumptions
// ends in / = dir
if (mb_substr($path, -1) === '/') {
return rtrim($path, '/');
}
// has a dot in the name, likely a file
if (preg_match('/.*\..*$/', basename($path)) !== 0) {
return dirname($path);
}
// you're on your own here!
return $path;
}
}

Some files were not shown because too many files have changed in this diff Show More