Current File : /home3/z1b8p1s5/segurocelular.uy/wp-content/mu-plugins/endurance-page-cache.php
<?php

/**
 * Plugin Name: Endurance Page Cache
 * Description: This cache plugin is primarily for cache purging of the additional layers of cache that may be available on your hosting account.
 * Version: 2.2.2
 * Author: Mike Hansen
 * Author URI: https://www.mikehansen.me/
 * License: GPLv2 or later
 * License URI: http://www.gnu.org/licenses/gpl-2.0.html
 *
 * @package EndurancePageCache
 */

/**
 * Endurance Page Cache is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * Endurance Page Cache is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with Endurance Page Cache; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * @license GPL-v2-or-later
 * @link    https://github.com/bluehost/endurance-page-cache/LICENSE
 * (If this plugin was installed as a single file, a copy of the license is available in the distribution repository in the link above)
 */

// Do not access file directly!
if ( ! defined( 'WPINC' ) ) {
	die;
}

define('EPC_VERSION', '2.2.2');

if ( ! class_exists( 'Endurance_Page_Cache' ) ) {

	/**
	 * Class Endurance_Page_Cache
	 */
	class Endurance_Page_Cache {

		/**
		 * The directory where cached files are stored.
		 *
		 * @var string
		 */
		public $cache_dir;

		/**
		 * A collection of tokens which, if contained in a URI, will prevent caching.
		 *
		 * @var array
		 */
		public $cache_exempt = array( 'checkout', 'cart', 'wp-admin' );

		/**
		 * Cache level.
		 *
		 * @var int
		 */
		public $cache_level = 2;

		/**
		 * Cloudflare enabled
		 *
		 * @var bool
		 */
		public $cloudflare_enabled = false;

		/**
		 * Cloudflare tier
		 *
		 * @var string
		 */
		public $cloudflare_tier = 'basic';

		/**
		 * File Based enabled
		 *
		 * @var bool
		 */
		public $file_based_enabled = false;

		/**
		 * Whether or not to force a purge.
		 *
		 * @var bool
		 */
		public $force_purge = false;

		/**
		 * A collection of throttled items grouped by type where the key is a hash of the URI and the value is the expiration timestamp.
		 *
		 * @var array
		 */
		public $throttled = array();

		/**
		 * Whether or not to update list of throttled items (transient: epc_throttled).
		 *
		 * @var bool
		 */
		public $should_update_throttled_items = false;

		/**
		 * Record keeping for which triggers have fired
		 *
		 * @var array
		 */
		public $triggers = array();

		/**
		 * UDEV Purge Buffer
		 *
		 * This parameter determines whether to hit the UDEV Cache Purge API.
		 *
		 * Set to false, no request is made.
		 * Set to true or an empty array all cached resources are purged.
		 * Set to array of relative paths to purge specified resources only.
		 *
		 * @var boolean|array
		 */
		protected $udev_purge_buffer = false;

		/**
		 * UDEV Cache Purge API Root URL.
		 *
		 * @var string
		 */
		protected static $udev_api_root = 'https://cachepurge.bluehost.com';

		/**
		 * UDEV Cache Purge API version string. First tag v0.
		 *
		 * @var string
		 */
		protected static $udev_api_version = 'v0';

		/**
		 * UDEV Cache Purge API endpoint
		 *
		 * @var string
		 */
		protected static $udev_api_endpoint = 'purge';

		/**
		 * UDEV Cache Purge API services.
		 *
		 * PARAMETERS:
		 * 'cf'  => 1|0 (default 1)
		 * 'epc' => 1|0 (default 0)
		 *
		 * @var array
		 */
		public $udev_api_services = array(
			'cf'  => 1,
			'epc' => 0,
		);

		/**
		 * The hook name for scheduling a cache purge event.
		 *
		 * @var string
		 */
		public $epc_scheduled_purge_all_hook = 'epc_scheduled_purge_all';

		/**
		 * Endurance_Page_Cache constructor.
		 */
		public function __construct() {

			if ( isset( $_GET['doing_wp_cron'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
				add_action( $this->epc_scheduled_purge_all_hook, array( __CLASS__, 'scheduled_purge_all' ) );
				return;
			}

			$this->throttled = array_filter( (array) get_transient( 'epc_throttled' ) );

			$this->cache_level = $this->get_cache_level();
			$this->cache_dir   = WP_CONTENT_DIR . '/endurance-page-cache';

			$cloudflare_state = get_option( 'endurance_cloudflare_enabled', false );

			$this->cloudflare_enabled      = (bool) $cloudflare_state;
			$this->cloudflare_tier         = ( is_numeric( $cloudflare_state ) && $cloudflare_state ) ? 'basic' : $cloudflare_state;
			$this->udev_api_services['cf'] = $this->cloudflare_tier;

			$path                     = defined( 'ABSPATH' ) ? ABSPATH : __DIR__;
			$this->file_based_enabled = (bool) get_option( 'endurance_file_enabled', false === strpos( $path, 'public_html' ) );

			array_push( $this->cache_exempt, rest_get_url_prefix() );

			$this->hooks();
		}

		/**
		 * Retrieves the cache level from the database
		 *
		 * If cache level is set higher than 3, then it will reset it down to level 3
		 *
		 * @return int
		 */
		public function get_cache_level() {
			$level = absint( get_option( 'endurance_cache_level', 2 ) );

			if ( $level > 3 ) {
				$level = 3;
				update_option( 'endurance_cache_level', $level );
			}

			return $level;
		}

		/**
		 * Setup all WordPress actions and filters.
		 */
		public function hooks() {
			if ( $this->is_enabled( 'page' ) ) {
				add_action( 'init', array( $this, 'start' ) );
				add_action( 'shutdown', array( $this, 'finish' ) );
				add_action( 'shutdown', array( $this, 'shutdown' ) );
				add_action( 'generate_rewrite_rules', array( $this, 'config_nginx' ) );
			}
			add_filter( 'mod_rewrite_rules', array( $this, 'htaccess_contents_rewrites' ), 77 );
			add_filter( 'mod_rewrite_rules', array( $this, 'htaccess_contents_expirations' ), 88 );

			add_action( 'update_option_endurance_cache_level', array( $this, 'update_htaccess' ) );
			add_action( 'update_option_endurance_file_enabled', array( $this, 'update_htaccess' ) );
			add_action( 'update_option_epc_skip_404_handling', array( $this, 'update_htaccess' ) );
			add_action( 'update_option_epc_filetype_expirations', array( $this, 'update_htaccess' ) );
			add_action( 'delete_option_epc_filetype_expirations', array( $this, 'update_htaccess' ) );

			add_action( 'admin_init', array( $this, 'register_cache_settings' ) );
			add_action( 'transition_post_status', array( $this, 'save_post' ), 10, 3 );
			add_action( 'edit_terms', array( $this, 'edit_terms' ) );

			add_action( 'comment_post', array( $this, 'comment' ) );

			add_action( 'updated_option', array( $this, 'option_handler' ), 10, 3 );

			add_action( 'epc_purge', array( $this, 'purge_all' ) );
			add_action( 'epc_purge_request', array( $this, 'purge_request' ) );

			add_action( 'wp_update_nav_menu', array( $this, 'purge_all' ) );

			add_action( 'admin_bar_menu', array( $this, 'admin_toolbar' ), 99 );

			add_action( 'init', array( $this, 'do_purge' ) );

			add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'status_link' ) );

			add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'update' ) );

			add_filter( 'pre_update_option_mm_cache_settings', array( $this, 'cache_type_change' ), 10, 2 );
			add_filter( 'pre_update_option_endurance_cache_level', array( $this, 'cache_level_change' ), 10, 2 );

			add_filter( 'got_rewrite', array( $this, 'force_rewrite' ) );

			add_action( 'shutdown', array( $this, 'udev_cache_purge_via_buffer' ) );
		}

		/**
		 * Customize the WP Admin Bar.
		 *
		 * @param \WP_Admin_Bar $wp_admin_bar Instance of the admin bar.
		 */
		public function admin_toolbar( $wp_admin_bar ) {
			if ( current_user_can( 'manage_options' ) && $this->is_enabled() ) {
				$args = array(
					'id'    => 'epc_purge_menu',
					'title' => 'Caching',
				);
				$wp_admin_bar->add_node( $args );

				$args = array(
					'id'     => 'epc_purge_menu-purge_all',
					'title'  => 'Purge All',
					'parent' => 'epc_purge_menu',
					'href'   => add_query_arg( array( 'epc_purge_all' => true ) ),
				);
				$wp_admin_bar->add_node( $args );

				if ( ! is_admin() ) {
					$args = array(
						'id'     => 'epc_purge_menu-purge_single',
						'title'  => 'Purge This Page',
						'parent' => 'epc_purge_menu',
						'href'   => add_query_arg( array( 'epc_purge_single' => true ) ),
					);
					$wp_admin_bar->add_node( $args );
				}

				$args = array(
					'id'     => 'epc_purge_menu-cache_settings',
					'title'  => 'Cache Settings',
					'parent' => 'epc_purge_menu',
					'href'   => admin_url( 'options-general.php#epc_settings' ),
				);
				$wp_admin_bar->add_node( $args );
			}
		}

		/**
		 * Register fields for cache settings.
		 */
		public function register_cache_settings() {
			$section_name = 'epc_settings_section';
			add_settings_section(
				$section_name,
				'<span id="epc_settings">Endurance Cache</span>',
				'__return_false',
				'general'
			);
			add_settings_field(
				'endurance_cache_level',
				'Cache Level',
				array( $this, 'output_cache_settings' ),
				'general',
				$section_name,
				array( 'field' => 'endurance_cache_level' )
			);
			add_settings_field(
				'epc_skip_404_handling',
				'Skip WordPress 404 Handling For Static Files',
				function () {
					echo '<input type="checkbox" name="epc_skip_404_handling" value="1"' . checked( (bool) get_option( 'epc_skip_404_handling' ), true, false ) . ' />';
				},
				'general',
				$section_name,
				array( 'field' => 'epc_skip_404_handling' )
			);
			register_setting( 'general', 'endurance_cache_level' );
			register_setting( 'general', 'epc_skip_404_handling' );
		}

		/**
		 * Output the cache options.
		 *
		 * @param array $args Settings
		 */
		public function output_cache_settings( $args ) {
			$cache_level = absint( get_option( $args['field'], 2 ) );
			echo '<select name="' . esc_attr( $args['field'] ) . '">';
			$cache_levels = array(
				0 => 'Off',
				1 => 'Assets Only',
				2 => 'Normal',
				3 => 'Advanced',
			);
			foreach ( $cache_levels as $i => $label ) {
				if ( $i !== $cache_level ) {
					echo '<option value="' . absint( $i ) . '"">';
				} else {
					echo '<option value="' . absint( $i ) . '" selected="selected">';
				}

				echo esc_html( $label ) . ' (Level ' . absint( $i ) . ')';
				echo '</option>';
			}
			echo '</select>';
		}

		/**
		 * Convert a string to studly case.
		 *
		 * @param string $value String to be converted.
		 *
		 * @return string
		 */
		public function to_studly_case( $value ) {
			return str_replace( ' ', '', ucwords( str_replace( array( '-', '_' ), ' ', $value ) ) );
		}

		/**
		 * Convert a string to snake case.
		 *
		 * @param string $value String to be converted.
		 * @param string $delimiter Delimiter (can be a dash for conversion to kebab case).
		 *
		 * @return string
		 */
		public function to_snake_case( $value, $delimiter = '_' ) {
			if ( ! ctype_lower( $value ) ) {
				$value = preg_replace( '/(\s+)/u', '', ucwords( $value ) );
				$value = trim( mb_strtolower( preg_replace( '/([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)/u', '$1' . $delimiter, $value ), 'UTF-8' ), $delimiter );
			}

			return $value;
		}

		/**
		 * Checks if this environment caches requests on the current filesystem
		 *
		 * @return bool True if uses file system to cache
		 */
		public function use_file_cache() {
			return $this->file_based_enabled && $this->cache_level;
		}

		/**
		 * Whether or not to skip 404 handling for static files.
		 *
		 * Enable via WP-CLI: wp option set epc_skip_404_handling 1
		 *
		 * @return bool
		 */
		public function skip_404_handling() {
			return (bool) get_option( 'epc_skip_404_handling' );
		}

		/**
		 * Handlers that listens for changes to options and checks to see, based on the option name, if the cache should
		 * be purged.
		 *
		 * @param string $option Option name
		 * @param mixed  $old_value Old option value
		 * @param mixed  $new_value New option value
		 *
		 * @return bool
		 */
		public function option_handler( $option, $old_value, $new_value ) {

			// No need to process if nothing was updated
			if ( $old_value === $new_value ) {
				return false;
			}

			$exempt_if_equals = array(
				'active_plugins'    => true,
				'html_type'         => true,
				'fs_accounts'       => true,
				'rewrite_rules'     => true,
				'uninstall_plugins' => true,
				'wp_user_roles'     => true,
			);

			// If we have an exact match, we can just stop here.
			if ( array_key_exists( $option, $exempt_if_equals ) ) {
				return false;
			}

			$force_if_contains = array(
				'html',
				'css',
				'style',
				'query',
				'queries',
			);

			$exempt_if_contains = array(
				'_active',
				'_activated',
				'_activation',
				'_attempts',
				'_available',
				'_blacklist',
				'_cache_validator',
				'_check_',
				'_checksum',
				'_config',
				'_count',
				'_dectivated',
				'_disable',
				'_enable',
				'_errors',
				'_hash',
				'_inactive',
				'_installed',
				'_key',
				'_last_',
				'_license',
				'_log_',
				'_mode',
				'_options',
				'_pageviews',
				'_redirects',
				'_rules',
				'_schedule',
				'_session',
				'_settings',
				'_shown',
				'_stats',
				'_status',
				'_statistics',
				'_supports',
				'_sync',
				'_task',
				'_time',
				'_token',
				'_traffic',
				'_transient',
				'_url_',
				'_version',
				'_views',
				'_visits',
				'_whitelist',
				'404s',
				'cron',
				'limit_login_',
				'nonce',
				'user_roles',
			);

			$force_purge = false;

			if ( ctype_upper( str_replace( array( '-', '_' ), '', $option ) ) ) {
				$option = strtolower( $option );
			}
			$option_name = '_' . $this->to_snake_case( $this->to_studly_case( $option ) ) . '_';

			foreach ( $force_if_contains as $slug ) {
				if ( false !== strpos( $option_name, $slug ) ) {
					$force_purge = true;
					break;
				}
			}

			if ( ! $force_purge ) {
				foreach ( $exempt_if_contains as $slug ) {
					if ( false !== strpos( $option_name, $slug ) ) {
						return false;
					}
				}
			}

			$this->add_trigger( 'option_handler' );
			// Schedule a purge if not already scheduled.
			$this->schedule_purge_all();
			return true;
		}

		/**
		 * Schedules a single event for purging the cache.
		 *
		 * @return void
		 */
		public function schedule_purge_all() {
			if ( ! wp_next_scheduled( $this->epc_scheduled_purge_all_hook ) ) {
				wp_schedule_single_event( time() + 60, $this->epc_scheduled_purge_all_hook );
			}
		}

		/**
		 * Static cron job handler to execute a purge all.
		 */
		public static function scheduled_purge_all() {
			$instance = self::get_instance();
			if ( $instance ) {
				$instance->purge_all();
			}
		}

		/**
		 * Purge single post when a comment is updated.
		 *
		 * @param int $comment_id ID of the comment.
		 */
		public function comment( $comment_id ) {
			$comment = get_comment( $comment_id );
			if ( $comment && property_exists( $comment, 'comment_post_ID' ) ) {
				$post_url = get_permalink( $comment->comment_post_ID );
				$this->purge_single( $post_url );
			}
		}

		/**
		 * Purge appropriate caches when post when post is updated.
		 *
		 * @param string  $old_status The previous post status
		 * @param string  $new_status The new post status
		 * @param WP_Post $post The post object of the edited or created post
		 */
		public function save_post( $old_status, $new_status, $post ) {

			$post_type_object = get_post_type_object( $post->post_type );
			// Skip purging for non-public post types
			if ( ! $post_type_object || ! $post_type_object->public ) {
				return;
			}

			// Skip purging if the post wasn't public before and isn't now
			if ( 'publish' !== $old_status && 'publish' !== $new_status ) {
				return;
			}

			// Purge post URL when post is updated.
			$permalink = get_permalink( $post );
			if ( $permalink ) {
				$this->purge_single( $permalink );
			}

			// Purge taxonomy term URLs for related terms.
			$taxonomies = get_post_taxonomies( $post );
			foreach ( $taxonomies as $taxonomy ) {
				if ( $this->is_public_taxonomy( $taxonomy ) ) {
					$terms = get_the_terms( $post, $taxonomy );
					if ( is_array( $terms ) ) {
						foreach ( $terms as $term ) {
							$term_link = get_term_link( $term );
							$this->purge_single( $term_link );
						}
					}
				}
			}

			// Purge post type archive URL when post is updated.
			$post_type_archive = get_post_type_archive_link( $post->post_type );
			if ( $post_type_archive ) {
				$this->purge_single( $post_type_archive );
			}

			// Purge date archive URL when post is updated.
			$year_archive      = get_year_link( (int) get_the_date( 'y', $post ) );
			$year_archive_path = str_replace( get_site_url(), '', $year_archive );
			$this->purge_dir( $year_archive_path );
		}

		/**
		 * Checks if a post is public.
		 *
		 * @param int $post_id The post ID.
		 *
		 * @return boolean
		 */
		public function is_public_post( $post_id ) {
			$public = false;
			if ( false === wp_is_post_autosave( $post_id ) ) {
				$post_type = get_post_type( $post_id );
				if ( $post_type ) {
					$post_type_object = get_post_type_object( $post_type );
					if ( $post_type_object && isset( $post_type_object->public ) ) {
						$public = $post_type_object->public;
					}
				}
			}

			return $public;
		}

		/**
		 * Checks if a taxonomy is public.
		 *
		 * @param string $taxonomy Taxonomy name.
		 *
		 * @return boolean
		 */
		public function is_public_taxonomy( $taxonomy ) {
			$public          = false;
			$taxonomy_object = get_taxonomy( $taxonomy );
			if ( $taxonomy_object && isset( $taxonomy_object->public ) ) {
				$public = $taxonomy_object->public;
			}

			return $public;
		}

		/**
		 * Purge taxonomy term URL when a term is updated.
		 *
		 * @param int $term_id Term ID
		 */
		public function edit_terms( $term_id ) {
			$url = get_term_link( $term_id );
			if ( ! is_wp_error( $url ) ) {
				$this->purge_single( $url );
			}
		}

		/**
		 * Write page content to cache.
		 *
		 * @param string $page Page content to be cached.
		 *
		 * @return string
		 */
		public function write( $page ) {
			$base = wp_parse_url( trailingslashit( get_option( 'home' ) ), PHP_URL_PATH );

			if ( ! empty( $page ) ) {
				$path = WP_CONTENT_DIR . '/endurance-page-cache' . str_replace( get_option( 'home' ), '', esc_url( $_SERVER['REQUEST_URI'] ) );
				$path = str_replace( '/endurance-page-cache' . $base, '/endurance-page-cache/', $path );
				$path = str_replace( '//', '/', $path );

				if ( file_exists( $path . '_index.html' ) && filemtime( $path . '_index.html' ) > time() - HOUR_IN_SECONDS ) {
					return $page;
				}

				if ( false !== strpos( $page, '</html>' ) ) {
					$page .= "\n<!--Generated by Endurance Page Cache-->";
				}

				if ( $this->use_file_cache() ) {
					if ( ! is_dir( $path ) ) {
						mkdir( $path, 0755, true );
					}
					file_put_contents( $path . '_index.html', $page, LOCK_EX ); // phpcs:ignore WordPress.WP.AlternativeFunctions
				}
			} else {
				nocache_headers();
			}

			return $page;
		}

		/**
		 * Make a request to purge the entire Sitelock CDN
		 */
		public function purge_cdn() {

			if ( ! $this->force_purge && true === $this->should_throttle( 'sitelock_cdn', __METHOD__ ) ) {
				return;
			}

			if ( true === $this->cloudflare_enabled ) {
				return;
			}

			if ( 'BlueHost' === get_option( 'mm_brand' ) ) {
				$endpoint      = 'https://my.bluehost.com/cgi/wpapi/cdn_purge';
				$domain        = wp_parse_url( get_option( 'siteurl' ), PHP_URL_HOST );
				$query         = add_query_arg( array( 'domain' => $domain ), $endpoint );
				$refresh_token = get_option( '_mm_refresh_token' );
				if ( false === $refresh_token ) {
					return;
				}
				$path = ABSPATH;
				$path = explode( 'public_html/', $path );
				if ( 2 === count( $path ) ) {
					$path = '/public_html/' . $path[1];
				} else {
					return;
				}

				$path_hash = bin2hex( $path );
				$headers   = array(
					'x-api-refresh-token' => $refresh_token,
					'x-api-path'          => $path_hash,
				);
				$args      = array(
					'timeout'  => 1,
					'blocking' => false,
					'headers'  => $headers,
				);
				wp_remote_get( $query, $args );
			}
		}

		/**
		 * Purge CDN based on pattern.
		 *
		 * A purge pattern is any string of literal characters, and will be searched for within filenames. For example,
		 * a pattern of "ndex" will match "index.html" and "spandex.php". For more fine-grained control, it is possible
		 * to specify the standard PCRE anchor characters "^" and "$" at the beginning and/or end, respectively, of a
		 * pattern, in order to anchor to that portion of the string. For example, "html$" will match "index.html" but
		 * not "learn_html.php".
		 *
		 * @param string $pattern (Optional) Pattern used to match assets that should be purged.
		 */
		public function purge_cdn_single( $pattern = '' ) {

			if ( ! $this->force_purge && true === $this->should_throttle( $pattern, __METHOD__ ) ) {
				return;
			}

			if ( 'BlueHost' === get_option( 'mm_brand' ) ) {
				$pattern = rawurlencode( $pattern );
				$domain  = wp_parse_url( home_url(), PHP_URL_HOST );
				wp_remote_request(
					"https://my.bluehost.com/api/domains/{$domain}/caches/sitelock/{$pattern}",
					array(
						'method'   => 'PUT',
						'blocking' => false,
						'headers'  => array(
							'X-MOJO-TOKEN' => get_option( '_mm_refresh_token' ),
						),
					)
				);
			}
		}

		/**
		 * Ensure that a URI isn't purged more than once per minute.
		 *
		 * @param string $uri URI being purged
		 * @param string $type The type of throttling
		 *
		 * @return bool True if additional purges should be avoided, false otherwise.
		 */
		public function should_throttle( $uri, $type ) {

			if ( is_null( $uri ) ) {
				return true;
			}

			$should_throttle = false;

			$this->should_update_throttled_items = true;

			$hash = md5( $uri );

			if ( isset( $this->throttled[ $type ], $this->throttled[ $type ][ $hash ] ) ) {
				if ( $this->is_timestamp_valid( $this->throttled[ $type ][ $hash ] ) ) {
					$should_throttle = true;
				}
			}

			if ( ! $should_throttle ) {
				$this->throttled[ $type ][ $hash ] = time() + MINUTE_IN_SECONDS;
			}

			return $should_throttle;
		}

		/**
		 * Actions that should take place when the page is done loading.
		 */
		public function shutdown() {
			if ( $this->should_update_throttled_items ) {
				$throttled = array();
				foreach ( $this->throttled as $type => $group ) {
					$throttled[ $type ] = array_filter( $group, array( $this, 'is_timestamp_valid' ) );
				}
				set_transient( 'epc_throttled', $throttled, 60 );
			}
		}

		/**
		 * Returns true when a timestamp is in the future, or false when it is in the past (expired).
		 *
		 * @param int $timestamp Timestamp
		 *
		 * @return bool
		 */
		public function is_timestamp_valid( $timestamp ) {
			return $timestamp > time();
		}

		/**
		 * Send a cache purge request.
		 *
		 * @param string $uri URI to be purged.
		 */
		public function purge_request( $uri ) {

			global $wp_version;

			if ( ! $this->force_purge && true === $this->should_throttle( $uri, __METHOD__ ) ) {
				return;
			}

			$domain = wp_parse_url( home_url(), PHP_URL_HOST );

			if ( empty( $this->triggers ) ) {
				$this->add_trigger( current_action() );
			}

			$args = array(
				'method'     => 'PURGE',
				'timeout'    => '5',
				'blocking'   => false,
				'sslverify'  => false,
				'headers'    => array(
					'host' => $domain,
				),
				'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url() . '; EPC/v' . EPC_VERSION . '/' . $this->get_trigger(),
			);
			wp_remote_request( $this->get_purge_request_url( $uri, 'http' ), $args );
			wp_remote_request( $this->get_purge_request_url( $uri, 'https' ), $args );

			$this->udev_cache_populate_buffer( $uri );

			if ( preg_match( '/\.\*$/', $uri ) ) {
				$this->purge_cdn();
			}
		}

		/**
		 * Get URL to be used for purge requests.
		 *
		 * @param string $uri The original URI
		 * @param string $scheme The scheme to be used
		 *
		 * @return string
		 */
		public function get_purge_request_url( $uri, $scheme = 'http' ) {

			// Default scheme to http; only allow two values
			if ( 'http' !== $scheme && 'https' !== $scheme ) {
				$scheme = 'http';
			}

			$base = ( 'http' === $scheme ) ? 'http://127.0.0.1:8080' : 'https://127.0.0.1:8443';

			if ( 0 === strpos( $uri, '/' ) ) {
				return $base . $uri;
			}

			return str_replace( str_replace( wp_parse_url( home_url( '/' ), PHP_URL_PATH ), '', home_url() ), $base, $uri );
		}

		/**
		 * Purge everything in a specific directory.
		 *
		 * @param string|null $dir Directory to be purged
		 */
		public function purge_dir( $dir = null ) {

			if ( ! $this->force_purge && true === $this->should_throttle( $dir, __METHOD__ ) ) {
				return;
			}

			if ( $this->use_file_cache() ) {
				if ( is_null( $dir ) || ! is_dir( $dir ) ) {
					$dir = WP_CONTENT_DIR . '/endurance-page-cache';
				}
				$dir = str_replace( '_index.html', '', $dir );
				if ( is_dir( $dir ) ) {
					$files = scandir( $dir );
					if ( is_array( $files ) ) {
						$files = array_diff( $files, array( '.', '..' ) );
					}

					if ( is_array( $files ) ) {
						foreach ( $files as $file ) {
							if ( is_dir( $dir . '/' . $file ) ) {
								$this->purge_dir( $dir . '/' . $file );
							} elseif ( file_exists( $dir . '/' . $file ) ) {
								unlink( $dir . '/' . $file );
							}
						}
						if ( 2 === count( scandir( $dir ) ) ) {
							rmdir( $dir );
						}
					}
				}
			} else {
				$this->purge_request( get_option( 'siteurl' ) . $dir . '/.*' );
			}
		}

		/**
		 * Purge the cache for entire site
		 */
		public function purge_all() {

			if ( ! $this->force_purge && true === $this->should_throttle( 'all', __METHOD__ ) ) {
				return;
			}

			if ( $this->use_file_cache() ) {
				$this->purge_dir();
			} else {
				$this->udev_purge_buffer = array();
				$this->purge_request( get_option( 'siteurl' ) . '/.*' );
			}
		}

		/**
		 * Purge a single URI.
		 *
		 * @param string $uri URI to be purged.
		 */
		public function purge_single( $uri ) {

			if ( ! $this->force_purge && true === $this->should_throttle( $uri, __METHOD__ ) ) {
				return;
			}

			$this->purge_request( $uri );
			$this->purge_request( home_url() );
			$cache_file = $this->uri_to_cache( $uri );

			// Purge CDN
			$path = wp_parse_url( $uri, PHP_URL_PATH );
			$this->purge_cdn_single( $path . '$' );

			// Purge Image Assets from CDN
			if ( file_exists( $cache_file ) ) {
				$content = file_get_contents( $cache_file ); // phpcs:ignore WordPress.WP.AlternativeFunctions
				if ( ! empty( $content ) ) {
					$image_urls = $this->extract_image_urls( $content );
					foreach ( $image_urls as $image_url ) {
						$this->purge_cdn_single( wp_parse_url( $image_url, PHP_URL_PATH ) . '$' );
						if ( ! empty( $this->udev_purge_buffer ) ) {
							$this->udev_purge_buffer[] = wp_parse_url( $image_url, PHP_URL_PATH );
						}
					}
				}
			}

			// Purge requested file
			if ( file_exists( $cache_file ) ) {
				unlink( $cache_file );
			}

			// Purge front page file
			if ( file_exists( $this->cache_dir . '/_index.html' ) ) {
				unlink( $this->cache_dir . '/_index.html' );
			}
		}

		/**
		 * Extract image URLs from post content.
		 *
		 * @param string $content The post content
		 *
		 * @return array
		 */
		public function extract_image_urls( $content ) {
			$urls = array();
			preg_match_all( '#<img src="(.*?)"#', $content, $matches );
			if ( isset( $matches, $matches[1] ) ) {
				$urls = $matches[1];
			}

			return $urls;
		}

		/**
		 * Get the URI to cache.
		 *
		 * @param string $uri URI
		 *
		 * @return string
		 */
		public function uri_to_cache( $uri ) {
			$path = str_replace( get_site_url(), '', $uri );

			return $this->cache_dir . $path . '_index.html';
		}

		/**
		 * Check if current request is cachable.
		 *
		 * @param string $type Cache type
		 *
		 * @return bool
		 */
		public function is_cachable( $type = 'default' ) {
			global $wp_query;

			$return = true;

			if ( 'file' === $type ) {
				if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE === true ) {
					$return = false;
				} elseif ( defined( 'DOING_AJAX' ) ) {
					$return = false;
				} elseif ( 'private' === get_post_status() ) {
					$return = false;
				} elseif ( isset( $wp_query ) && is_404() ) {
					$return = false;
				} elseif ( is_admin() ) {
					$return = false;
				} elseif ( false === get_option( 'permalink_structure' ) ) {
					$return = false;
				} elseif ( function_exists( 'is_user_logged_in' ) && is_user_logged_in() ) {
					$return = false;
				} elseif ( isset( $_GET ) && ! empty( $_GET ) ) { // phpcs:ignore WordPress.Security.NonceVerification
					$return = false;
				} elseif ( isset( $_POST ) && ! empty( $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification
					$return = false;
				} elseif ( isset( $wp_query ) && is_feed() ) {
					$return = false;
				}
				$cache_exempt = array_merge( $this->cache_exempt, array( '@', '%', ':', ';', '&', '=', '.' ) );
			} else {
				if ( defined( 'DONOTCACHEPAGE' ) && DONOTCACHEPAGE === true ) {
					$return = false;
				} elseif ( defined( 'DOING_AJAX' ) ) {
					$return = false;
				} elseif ( 'private' === get_post_status() ) {
					$return = false;
				} elseif ( isset( $wp_query ) && is_404() ) {
					$return = false;
				} elseif ( is_admin() ) {
					$return = false;
				} elseif ( function_exists( 'is_user_logged_in' ) && is_user_logged_in() ) {
					$return = false;
				} elseif ( isset( $_POST ) && ! empty( $_POST ) ) { // phpcs:ignore WordPress.Security.NonceVerification
					$return = false;
				} elseif ( isset( $wp_query ) && is_feed() ) {
					$return = false;
				}
				$cache_exempt = $this->cache_exempt;
			}

			if ( empty( $_SERVER['REQUEST_URI'] ) ) {
				$return = false;
			} else {
				$cache_exempt = apply_filters( 'epc_exempt_uri_contains', $cache_exempt );
				foreach ( $cache_exempt as $exclude ) {
					if ( false !== strpos( $_SERVER['REQUEST_URI'], $exclude ) ) {
						$return = false;
					}
				}
			}

			return (bool) apply_filters( 'epc_is_cachable', $return );
		}

		/**
		 * Start output buffering for cachable requests.
		 */
		public function start() {
			if ( $this->file_based_enabled && $this->is_cachable( 'file' ) ) {
				ob_start( array( $this, 'write' ) );
			} elseif ( $this->is_cachable() === false ) {
				nocache_headers();
			}
		}

		/**
		 * End output buffering for cachable requests.
		 */
		public function finish() {
			if ( $this->is_cachable( 'file' ) && $this->file_based_enabled && ob_get_contents() ) {
				ob_end_clean();
			}
		}

		/**
		 * Update .htaccess to reflect updates.
		 */
		public function update_htaccess() {
			if ( ! function_exists( 'save_mod_rewrite_rules' ) ) {
				require_once ABSPATH . 'wp-admin/includes/misc.php';
			}

			save_mod_rewrite_rules();
		}

		/**
		 * Modify the .htaccess file with custom rewrite rules based on caching level.
		 *
		 * @param string $rules .htaccess content
		 *
		 * @return string
		 */
		public function htaccess_contents_rewrites( $rules ) {
			$base      = wp_parse_url( trailingslashit( get_option( 'home' ) ), PHP_URL_PATH );
			$cache_url = $base . str_replace( get_option( 'home' ), '', WP_CONTENT_URL . '/endurance-page-cache' );
			$cache_url = str_replace( '//', '/', $cache_url );

			$additions = 'Options -Indexes' . PHP_EOL;

			$additions .= <<<HTACCESS
<IfModule mod_headers.c>
	Header set X-Endurance-Cache-Level "{$this->cache_level}"
	Header set X-nginx-cache "WordPress"
</IfModule>
HTACCESS;

			$additions .= PHP_EOL;

			if ( $this->use_file_cache() ) {
				$additions .= <<<HTACCESS
<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteBase {$base}
	RewriteRule ^{$cache_url}/ - [L]
	RewriteCond %{REQUEST_METHOD} !POST
	RewriteCond %{QUERY_STRING} !.*=.*
	RewriteCond %{HTTP_COOKIE} !(wordpress_test_cookie|comment_author|wp\-postpass|wordpress_logged_in|wptouch_switch_toggle|wp_woocommerce_session_) [NC]
	RewriteCond %{DOCUMENT_ROOT}{$cache_url}/$1/_index.html -f
	RewriteRule ^(.*)\$ {$cache_url}/$1/_index.html [L]
</IfModule>
HTACCESS;
				$additions .= PHP_EOL;
			}

			if ( $this->skip_404_handling() ) {
				$additions .= <<<HTACCESS
<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_URI} !(robots\.txt|[a-z0-9_\-]*sitemap[a-z0-9_\.\-]*\.(xml|xsl|html)(\.gz)?)
	RewriteCond %{REQUEST_URI} \.(css|htc|less|js|js2|js3|js4|html|htm|rtf|rtx|txt|xsd|xsl|xml|asf|asx|wax|wmv|wmx|avi|avif|avifs|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|webp|json|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|webm|mpp|otf|_otf|odb|odc|odf|odg|odp|ods|odt|ogg|ogv|pdf|png|pot|pps|ppt|pptx|ra|ram|svg|svgz|swf|tar|tif|tiff|ttf|ttc|_ttf|wav|wma|wri|woff|woff2|xla|xls|xlsx|xlt|xlw|zip)$ [NC]
	RewriteRule .* - [L]
</IfModule>
HTACCESS;
				$additions .= PHP_EOL;
			}

			return $additions . $rules;
		}

		/**
		 * Modify the .htaccess file with custom expiration rules based on caching level.
		 *
		 * @param string $rules .htaccess content
		 *
		 * @return string
		 */
		public function htaccess_contents_expirations( $rules ) {

			if ( ! $this->is_enabled( 'browser' ) || $this->cache_level < 1 ) {
				return $rules;
			}

			$default_files = array(
				'image/jpg'       => '1 year',
				'image/jpeg'      => '1 year',
				'image/gif'       => '1 year',
				'image/png'       => '1 year',
				'text/css'        => '1 month',
				'application/pdf' => '1 month',
				'text/javascript' => '1 month',
				'text/html'       => '2 hours',
			);

			$file_types = wp_parse_args( get_option( 'epc_filetype_expirations', array() ), $default_files );

			$additions = "<IfModule mod_expires.c>\n\tExpiresActive On\n\t";
			foreach ( $file_types as $file_type => $expires ) {
				if ( 'default' !== $file_type ) {
					$additions .= 'ExpiresByType ' . $file_type . ' "access plus ' . $expires . '"' . "\n\t";
				}
			}

			$additions .= "ExpiresByType image/x-icon \"access plus 1 year\"\n\t";
			if ( isset( $file_types['default'] ) ) {
				$additions .= 'ExpiresDefault "access plus ' . $file_types['default'] . "\"\n";
			} else {
				$additions .= "ExpiresDefault \"access plus 6 hours\"\n";
			}
			$additions .= "</IfModule>\n";

			return $additions . $rules;
		}

		/**
		 * Check if a specific caching type is enabled.
		 *
		 * @param string $type Caching type (e.g. page or browser).
		 *
		 * @return bool
		 */
		public function is_enabled( $type = 'page' ) {

			$plugins = get_option( 'active_plugins', array() );
			if ( ! empty( $plugins ) ) {
				$plugins = implode( ' ', $plugins );
				if ( strpos( $plugins, 'cach' ) || strpos( $plugins, 'wp-rocket' ) ) {
					return false;
				}
			}

			$active_theme = array(
				'stylesheet' => get_option( 'stylesheet' ),
				'template'   => get_option( 'template' ),
			);

			$active_theme = implode( ' ', $active_theme );

			$incompatible_themes = array( 'headway', 'prophoto' );

			foreach ( $incompatible_themes as $theme ) {
				if ( false !== strpos( $active_theme, $theme ) ) {
					return false;
				}
			}

			$cache_settings = get_option( 'mm_cache_settings', array() );
			if ( 'page' === $type ) {
				if ( isset( $_GET['epc_toggle'] ) && is_admin() ) { // phpcs:ignore WordPress.Security.NonceVerification
					$valid_values = array( 'enabled', 'disabled' );
					if ( in_array( $_GET['epc_toggle'], $valid_values, true ) ) { // phpcs:ignore WordPress.Security.NonceVerification
						$cache_settings['page'] = $_GET['epc_toggle']; // phpcs:ignore WordPress.Security.NonceVerification
						update_option( 'mm_cache_settings', $cache_settings );
						header( 'Location: ' . admin_url( 'plugins.php?plugin_status=mustuse' ) );
					}
				}
				if ( isset( $cache_settings['page'] ) && 'disabled' === $cache_settings['page'] ) {
					return false;
				} else {
					return true;
				}
			}

			if ( 'browser' === $type ) {
				if ( isset( $_GET['epc_toggle'] ) && is_admin() ) { // phpcs:ignore WordPress.Security.NonceVerification
					$valid_values = array( 'enabled', 'disabled' );
					if ( in_array( $_GET['epc_toggle'], $valid_values, true ) ) { // phpcs:ignore WordPress.Security.NonceVerification
						$cache_settings['browser'] = $_GET['epc_toggle']; // phpcs:ignore WordPress.Security.NonceVerification
						update_option( 'mm_cache_settings', $cache_settings );
						header( 'Location: ' . admin_url( 'plugins.php?plugin_status=mustuse' ) );
					}
				}
				if ( isset( $cache_settings['browser'] ) && 'disabled' === $cache_settings['browser'] ) {
					return false;
				} else {
					return true;
				}
			}

			return false;
		}

		/**
		 * Add plugin action links.
		 *
		 * @param array $links Action links
		 *
		 * @return array
		 */
		public function status_link( $links ) {
			if ( $this->is_enabled() ) {
				$links[] = '<a href="' . add_query_arg( array( 'epc_toggle' => 'disabled' ) ) . '">Disable</a>';
			} else {
				$links[] = '<a href="' . add_query_arg( array( 'epc_toggle' => 'enabled' ) ) . '">Enable</a>';
			}
			$links[] = '<a href="' . add_query_arg( array( 'epc_purge_all' => 'true' ) ) . '">Purge Cache</a>';

			return $links;
		}

		/**
		 * Listens for purge actions and handles based on type.
		 */
		public function do_purge() {
			if ( ( isset( $_GET['epc_purge_all'] ) || isset( $_GET['epc_purge_single'] ) ) && is_user_logged_in() && current_user_can( 'manage_options' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
				$this->force_purge = true;
				if ( isset( $_GET['epc_purge_all'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
					$this->add_trigger( 'toolbar_manual_all' );
					$this->purge_all();
				} else {
					$this->add_trigger( 'toolbar_manual_single' );
					$this->purge_single( $this->get_current_single_purge_url() );
				}
				header( 'Location: ' . remove_query_arg( array( 'epc_purge_single', 'epc_purge_all' ) ) );
			}
		}

		/**
		 * Get the current URI for a single purge request.
		 *
		 * @return string
		 */
		public function get_current_single_purge_url() {
			$host = str_replace( wp_parse_url( home_url(), PHP_URL_PATH ), '', home_url() );
			$path = remove_query_arg( array( 'epc_purge_single', 'epc_purge_all' ) );

			return $host . $path;
		}

		/**
		 * Update the appropriate option when cache settings are changed.
		 *
		 * @param array $new_cache_settings New cache settings
		 * @param array $old_cache_settings Old Cache settings
		 *
		 * @return array
		 */
		public function cache_type_change( $new_cache_settings, $old_cache_settings ) {
			$new_page_cache_value = 0;
			if ( is_array( $new_cache_settings ) && isset( $new_cache_settings['page'] ) ) {
				$new_page_cache_value = ( 'enabled' === $new_cache_settings['page'] ) ? 1 : 0;
			}
			if ( false === get_option( 'endurance_cache_level' ) ) {
				if ( 1 === $new_page_cache_value ) {
					update_option( 'endurance_cache_level', 2 );
				} else {
					update_option( 'endurance_cache_level', 0 );
				}
			}

			return $new_cache_settings;
		}

		/**
		 * Handle cache level change.
		 *
		 * @param int $new_cache_level New cache level
		 * @param int $old_cache_level Old cache level
		 *
		 * @return int
		 */
		public function cache_level_change( $new_cache_level, $old_cache_level ) {
			$cache_settings = get_option( 'mm_cache_settings', array() );
			if ( 0 === $new_cache_level ) {
				$cache_settings['page']    = 'disabled';
				$cache_settings['browser'] = 'disabled';
			} else {
				$cache_settings['page']    = 'enabled';
				$cache_settings['browser'] = 'enabled';
			}
			remove_filter( 'pre_update_option_mm_cache_settings', array( $this, 'cache_type_change' ), 10 );
			update_option( 'mm_cache_settings', $cache_settings );
			add_filter( 'pre_update_option_mm_cache_settings', array( $this, 'cache_type_change' ), 10, 2 );
			$this->cache_level = $new_cache_level;
			$this->toggle_nginx( $new_cache_level );
			$this->update_level_expirations( $new_cache_level );

			return (int) $new_cache_level;
		}

		/**
		 * Update cache expirations rules in .htaccess based on cache level.
		 *
		 * @param int $level Cache level
		 */
		public function update_level_expirations( $level ) {
			$level = (int) $level;

			$original_expirations = get_option( 'epc_filetype_expirations', array() );
			switch ( $level ) {
				case 3:
					$new_expirations = array(
						'image/jpg'       => '1 week',
						'image/jpeg'      => '1 week',
						'image/gif'       => '1 week',
						'image/png'       => '1 week',
						'text/css'        => '1 week',
						'application/pdf' => '1 week',
						'text/javascript' => '1 month',
						'text/html'       => '8 hours',
						'default'         => '1 week',
					);
					break;

				case 2:
					$new_expirations = array(
						'image/jpg'       => '24 hours',
						'image/jpeg'      => '24 hours',
						'image/gif'       => '24 hours',
						'image/png'       => '24 hours',
						'text/css'        => '24 hours',
						'application/pdf' => '1 week',
						'text/javascript' => '24 hours',
						'text/html'       => '2 hours',
						'default'         => '24 hours',
					);
					break;

				case 1:
					$new_expirations = array(
						'image/jpg'       => '1 hour',
						'image/jpeg'      => '1 hour',
						'image/gif'       => '1 hour',
						'image/png'       => '1 hour',
						'text/css'        => '1 hour',
						'application/pdf' => '6 hours',
						'text/javascript' => '1 hour',
						'text/html'       => '0 seconds',
						'default'         => '5 minutes',
					);
					break;

				default:
					$new_expirations = array();
					break;
			}
			$expirations = wp_parse_args( $new_expirations, $original_expirations );

			if ( 0 === $level ) {
				delete_option( 'epc_filetype_expirations' );
			} else {
				update_option( 'epc_filetype_expirations', $expirations );
			}
		}

		/**
		 * Configure caching in nginx.
		 */
		public function config_nginx() {
			$this->toggle_nginx( $this->cache_level );
		}

		/**
		 * Toggle nginx caching.
		 *
		 * @param int $new_value Cache level
		 */
		public function toggle_nginx( $new_value = 0 ) {
			if ( ! $this->use_file_cache() ) {
				$domain = wp_parse_url( get_option( 'siteurl' ), PHP_URL_HOST );
				$domain = str_replace( 'www.', '', $domain );
				$path   = explode( 'public_html', __DIR__ );
				if ( 2 !== count( $path ) ) {
					return;
				}
				$user = basename( $path[0] );
				$path = $path[0];
				if ( ! is_dir( $path . '.cpanel/proxy_conf' ) ) {
					mkdir( $path . '.cpanel/proxy_conf' );
				}

				if ( true === $this->cloudflare_enabled ) {
					$new_value = '-1';
				}
				@file_put_contents( $path . '.cpanel/proxy_conf/' . $domain, 'cache_level=' . $new_value ); // phpcs:ignore WordPress.WP.AlternativeFunctions, WordPress.PHP.NoSilencedErrors
				@touch( '/etc/proxy_notify/' . $user ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
			}
		}

		/**
		 * Handle checking for plugin updates.
		 *
		 * @param \stdClass $checked_data Plugin update data.
		 *
		 * @return \stdClass
		 */
		public function update( $checked_data ) {

			$muplugins_details = get_transient( 'mojo_plugin_assets' );

			if ( ! $muplugins_details ) {
				$muplugins_details = wp_remote_get( 'https://cdn.hiive.space/bluehost/mu-plugins.json' );
				if ( ! is_wp_error( $muplugins_details ) ) {
					set_transient( 'mojo_plugin_assets', $muplugins_details, 6 * HOUR_IN_SECONDS );
				}
			}

			if ( is_wp_error( $muplugins_details ) || ! isset( $muplugins_details['body'] ) ) {
				return $checked_data;
			}

			$mu_plugin = json_decode( $muplugins_details['body'], true );

			if ( ! is_null( $mu_plugin ) ) {
				foreach ( $mu_plugin as $slug => $info ) {
					if ( isset( $info['constant'] ) && defined( $info['constant'] ) ) {
						if ( version_compare( $info['version'], constant( $info['constant'] ), '>' ) ) {
							$file = wp_remote_get( $info['source'] );
							if ( ! is_wp_error( $file ) && isset( $file['body'] ) && strpos( $file['body'], $info['constant'] ) && is_writable( WP_CONTENT_DIR . $info['destination'] ) ) {
								file_put_contents( WP_CONTENT_DIR . $info['destination'], $file['body'] ); // phpcs:ignore WordPress.WP.AlternativeFunctions
							}
						}
					}
				}
			}

			return $checked_data;
		}

		/**
		 * Filter to force got_mod_rewrite() to true
		 *
		 * On CLI requests, mod_rewrite is unavailable, so it fails to update
		 * the .htaccess file when save_mod_rewrite_rules() is called. This
		 * forces that to be true so updates from WP CLI work.
		 *
		 * @param bool $got_rewrite Value of apache_mod_loaded('mod_rewrite')
		 *
		 * @return bool true for WP CLI requests
		 */
		public function force_rewrite( $got_rewrite ) {
			if ( defined( 'WP_CLI' ) && WP_CLI ) {
				return true;
			}

			return $got_rewrite;
		}

		/**
		 * Add trigger for record keeping.
		 *
		 * @param string $trigger Typically an action but can be manually set in the event of a force purge.
		 *
		 * @return void
		 */
		protected function add_trigger( $trigger ) {
			$this->triggers[] = $trigger;
		}

		/**
		 * Retrieves the most recent trigger
		 *
		 * @return string of the most recent trigger from the collection
		 */
		protected function get_trigger() {
			return end( $this->triggers );
		}

		/**
		 * Retrieves all the triggers to send with bundled requests
		 *
		 * @param string $include_duplicates Determines if the array should be unique
		 *
		 * @return array
		 */
		protected function get_triggers( $include_duplicates = false ) {
			if ( ! $include_duplicates ) {
				return array_values( array_unique( $this->triggers ) );
			} else {
				return $this->triggers;
			}
		}

		/**
		 * Primary function for the UDEV Purge Cache API. Makes non-blocking request for current install cache purges.
		 *
		 * Calling this method with *no* parameters triggers a full cache wipe for the domain.
		 * Calling this method with relative paths to resources will purge just those resources.
		 *
		 * @param array $resources (Site paths, image assets, scripts, styles, files, etc)
		 * @param array $override_services (see defaults on self::$udev_api_services)
		 *
		 * @return void
		 */
		protected function udev_cache_purge( $resources = array(), $override_services = array() ) {
			global $wp_version;

			if ( $this->use_file_cache() || false === $this->cloudflare_enabled ) {
				return;
			}

			$throttle_key = md5( wp_json_encode( $resources ) );

			if ( ! $this->force_purge && true === $this->should_throttle( $throttle_key, __METHOD__ ) ) {
				return;
			}

			$hosts    = array( wp_parse_url( home_url(), PHP_URL_HOST ) );
			$services = ! empty( $override_services ) ? $override_services : $this->udev_api_services;

			if ( $services['cf'] && $this->cloudflare_enabled ) {
				$services['cf'] = $this->cloudflare_tier;
			}

			wp_remote_post(
				$this->udev_cache_api_uri( $services ),
				array(
					'blocking'   => false,
					'body'       => $this->udev_create_request_body( $hosts, $resources ),
					'compress'   => true,
					'headers'    => array(
						'X-EPC-PLUGIN-PURGE' => 1,
						'content-type'       => 'application/json',
					),
					'sslverify'  => false,
					'user-agent' => 'WordPress/' . $wp_version . '; ' . wp_parse_url( home_url(), PHP_URL_HOST ) . '; EPC/v' . EPC_VERSION,
				)
			);
		}

		/**
		 * Build request URL and params for UDEV Purge Cache API.
		 *
		 * @param array $services List of services
		 *
		 * @return string URI to use for the udev cache API
		 */
		protected function udev_cache_api_uri( $services ) {
			return trailingslashit( static::$udev_api_root ) . trailingslashit( static::$udev_api_version ) . static::$udev_api_endpoint . '?' . http_build_query( $services );
		}

		/**
		 * Take hosts (and perhaps specific resources) to purge and encode JSON for request body.
		 *
		 * @param array $hosts List of hosts
		 * @param array $resources List of resources
		 *
		 * @return string|false
		 */
		protected function udev_create_request_body( $hosts, $resources ) {
			$request = array( 'hosts' => $hosts );

			if ( ! empty( $resources ) ) {
				$request['assets'] = array_values( array_unique( array_filter( $resources ) ) );
			}

			$request['triggers'] = $this->triggers;

			return wp_json_encode( $request );
		}

		/**
		 * Takes full URI and adds to $this->udev_purge_buffer. Typically fires in $this->purge_request().
		 * Note that $this->purge_all() presets an empty array, which denotes a full domain purge.
		 *
		 * @param string $uri URI to add to udev purge buffer
		 *
		 * @return void
		 */
		protected function udev_cache_populate_buffer( $uri ) {
			if ( is_array( $this->udev_purge_buffer ) && ! empty( $this->udev_purge_buffer ) ) {
				$this->udev_purge_buffer[] = wp_parse_url( $uri, PHP_URL_PATH );
			} elseif ( false === $this->udev_purge_buffer ) {
				$this->udev_purge_buffer = array( wp_parse_url( $uri, PHP_URL_PATH ) );
			}
		}

		/**
		 * Takes all specified resources in $this->udev_purge_buffer (or empty array denoting full purge)
		 * and makes cache purge request to UDEV Cache API.
		 *
		 * @return void
		 */
		public function udev_cache_purge_via_buffer() {
			if ( ! empty( $this->udev_purge_buffer ) || is_array( $this->udev_purge_buffer ) ) {
				$this->udev_cache_purge( $this->udev_purge_buffer );
			}
		}

		/**
		 * Retrieve the singleton instance of the class.
		 *
		 * @return Endurance_Page_Cache
		 */
		public static function get_instance() {
			static $instance = null;

			if ( null === $instance ) {
				$instance = new self();
			}

			return $instance;
		}
	}

	$epc = new Endurance_Page_Cache();
}
Seguro Celular
Home business sonyw300 6 de febrero de 2020
SEGURO PARA CUALQUIER MOMENTO
Evita cualquier situación con nuestro seguro para celular.

Contar con un seguro para celular te brinda una protección integral contra situaciones comunes como robo, accidentes y pérdida. No solo te ahorrará dinero en reparaciones o reemplazos, sino que también te proporcionará la tranquilidad de saber que estás respaldado en caso de cualquier eventualidad. Es una inversión inteligente para salvaguardar tu dispositivo, tus datos y tu tranquilidad.

De viaje
Protegido siempre ante cualquier imprevisto
Contratar ahora!
Robo
Asegura tu equipo ante un posible robo
Contratar ahora!
Accidentes
No pases un mal momento, protege tu dispositivo
Contratar ahora!
Previous slide
Next slide
¿Porqué seguro celular es para ti?
Nos comprometemos en brindarte la mejor protección para tu dispositivo
Cobertura mundial

Sea cual sea el problema estamos aquí para proteger tu inversión y brindarte la tranquilidad que necesitas.

Proceso de reclamación fácil y rápido

Sabemos que necesitas una solución rápida en caso de cualquier incidente.

Opciones personalizadas:

Ofrecemos opciones flexibles que se adaptan a tus requisitos individuales.

Atención al cliente excepcional

Estamos disponible para responder y brindarte asistencia personalizada en todo momento.

Tu tranquilidad está a
solo un clic de distancia

Protege tu dispositivo de cualquier imprevisto
TESTIMONIOS
¿Qué dicen nuestros
valiosos clientes?
"¡Increíble servicio de seguro para celular! Rápido, eficiente y confiable. Mi reclamo fue procesado sin problemas y recibí un reemplazo de mi teléfono en tiempo récord. ¡Gracias por brindar una excelente protección para mis dispositivos!"
male1085054890319
Herman Miller
"Me encanta la tranquilidad que me brinda su servicio de seguro para celular. Sé que mi dispositivo está protegido contra cualquier daño accidental o robo. Además, el proceso de reclamación es sencillo. Super recomendado!
female1021755931884
Sofia Millan
"Me ha salvado en más de una ocasión. El personal siempre está dispuesto a ayudar y resolver cualquier problema que surja. Gracias a su servicio, puedo disfrutar de mi teléfono sin preocupaciones.
male20131085934506012
Alexander Rodriguez