You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

195 lines
5.7 KiB
PHP

<?php
/**
* Prevent Page/Post from being cached.
*
* @package Builder
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Class to prevent Page/Post from being cached.
*/
class ET_Builder_Do_Not_Cache_Page {
/**
* Instance of `ET_Builder_Do_Not_Cache_Page`.
*
* @var ET_Builder_Do_Not_Cache_Page
*/
private static $_instance;
/**
* Instance of `ET_Builder_Do_Not_Cache_Page`.
*
* @var bool
*/
protected $_processed = false;
/**
* ET_Builder_Do_Not_Cache_Page constructor.
*/
public function __construct() {
add_action( 'template_redirect', [ $this, 'maybe_prevent_cache' ] );
}
/**
* When a page loads for the first time, Builder CSS is generated during the request and then
* printed inline in the footer which causes CLS issues because the CSS is loading late.
*
* @since 4.11.0
*
* @return void
*/
public function prevent_cache() {
// Ensure this only runs once.
if ( $this->_processed ) {
return;
}
$this->_processed = true;
// Disable several plugins which do not honor `DONOTCACHEPAGE` (set in `PageResource.php`).
if ( ! headers_sent() ) {
// Sending `no-cache` header should prevent CDNs from caching the first request.
header( 'Cache-Control: no-store, no-cache' );
// Disable SiteGround Optimizer Dynamic Cache.
header( 'X-Cache-Enabled: False' );
}
// Disable LiteSpeed Cache.
$reason = esc_html__( 'Generating CSS', 'et_builder' );
do_action( 'litespeed_control_set_nocache', $reason );
// Disable WP Fastest Cache.
if ( class_exists( 'WpFastestCacheCreateCache' ) ) {
// This Plugin has no hook/API to disable cache programmatically....
// The only way we can do this is by setting the `exclude_current_page_text` public property
// to a non empty value... except the class instance is not made available anywhere in the code....
// However, the instance also adds itself to the `wp` hook so we can find it by scanning the list
// of all registered actions.
$hooks = et_()->array_get( $GLOBALS, 'wp_filter.wp.10', [] );
if ( is_array( $hooks ) ) {
foreach ( $hooks as $key => $hook ) {
if (
isset( $hook['function'] ) &&
is_array( $hook['function'] ) &&
is_a( $hook['function'][0], 'WpFastestCacheCreateCache' )
) {
$wp_fastest_cache = $hook['function'][0];
$wp_fastest_cache->exclude_current_page_text = "<!-- $reason -->";
break;
}
}
}
}
// Disable Breeze Cache.
if ( function_exists( 'breeze_cache' ) ) {
// This Plugin has no hook/API to disable cache programmatically....
// The only way we can do this is by overwriting its configuration
// which is exposed as global variable.
global $breeze_config;
if ( isset( $breeze_config['cache_options'] ) ) {
$cache_options =& $breeze_config['cache_options'];
if ( is_array( $cache_options ) ) {
$cache_options['breeze-browser-cache'] = 0;
$cache_options['breeze-desktop-cache'] = 0;
$cache_options['breeze-mobile-cache'] = 0;
}
}
}
// Disable Hyper Cache.
if ( function_exists( 'hyper_cache_callback' ) ) {
global $hyper_cache_stop;
$hyper_cache_stop = true;
}
}
/**
* Disable Cache on first page request.
*
* @see prevent_cache()
*
* @since 4.11.0
*
* @return void
*/
public function maybe_prevent_cache() {
global $shortname;
// Bail if the magic already happened.
if ( $this->_processed ) {
return;
}
// Disable in the Visual Builder
if ( et_fb_is_enabled() ) {
return;
}
$product = in_array( $shortname, [ 'divi', 'extra' ], true ) ? $shortname : 'divi-builder';
$post_id = et_core_page_resource_get_the_ID();
$is_preview = is_preview() || is_et_pb_preview() || isset( $_GET['et_pb_preview_nonce'] ) || is_customize_preview(); // phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification -- Only checks if the parameter exists, and is therefore not susceptible to CSRF.
$is_singular = et_core_page_resource_is_singular();
$is_cpt = et_builder_should_wrap_styles();
$forced_in_footer = $post_id && et_builder_setting_is_on( 'et_pb_css_in_footer', $post_id );
$forced_inline = (
! $post_id ||
$is_preview ||
$forced_in_footer ||
et_builder_setting_is_off( 'et_pb_static_css_file', $post_id ) ||
et_core_is_safe_mode_active() ||
ET_GB_Block_Layout::is_layout_block_preview()
);
// If the post is password protected and a password has not been provided yet,
// no content (including any custom style) will be printed.
// When static css file option is enabled this will result in missing styles.
if ( ! $forced_inline && post_password_required( $post_id ? $post_id : null ) ) {
$forced_inline = true;
}
// Bail if using inline styles, page content won't be changing between requests anyway.
if ( $forced_inline ) {
return;
}
$unified = $is_singular && ! $forced_inline && ! $forced_in_footer && et_core_is_builder_used_on_current_request();
$post_id = $unified ? $post_id : 'global';
$owner = $unified ? 'core' : $product;
$slug = $unified ? 'unified' : 'customizer';
$slug .= $is_cpt ? '-cpt' : '';
$slug = et_theme_builder_decorate_page_resource_slug( $post_id, $slug );
$resource = et_core_page_resource_get( $owner, $slug, $post_id );
// Bail if Builder CSS already exists in external file, this is the request we want to cache.
if ( $resource->has_file() ) {
return;
}
$this->prevent_cache();
}
/**
* Get the class instance.
*
* @since 4.11.0
*
* @return ET_Builder_Do_Not_Cache_Page
*/
public static function instance() {
if ( ! self::$_instance ) {
self::$_instance = new self();
}
return self::$_instance;
}
}
ET_Builder_Do_Not_Cache_Page::instance();