One of the best ways to ensure that a WordPress site–well any site really–stays performant and not broken is by leveraging caching.

WordPress by default doesn’t do much caching other than some in-memory caching of objects, and the odd database caching via the Transients API.

This site currently has three layers of caching:

This means I have three different plugins that I have to manage with these caches:

So if I am doing some development and want to purge one or more caches, I need to go dig around three different places to purge these, and that’s not fun.  To help combat this, I made myself a simple Admin Dashboard widget with quick access to purge each of these:

Here’s the code:

<?php
class Emrikol_Cache_Dashboard {
	public static function instance() {
		static $instance = false;
		if ( ! $instance ) {
			$instance = new Emrikol_Cache_Dashboard();
		}
		return $instance;
	}

	public function __construct() {
		add_action( 'init', array( $this, 'init' ) );
	}

	public function init() {
		if ( $this->is_admin() && isset( $_GET['ead_purge_object_cache'] ) && check_admin_referer( 'manual_purge' ) ) {
			$did_flush = wp_cache_flush();
			if ( $did_flush ) {
				add_action( 'admin_notices', array( $this, 'message_object_cache_purge_success' ) );
			} else {
				add_action( 'admin_notices', array( $this, 'message_object_cache_purge_failure' ) );
			}
		} elseif ( $this->is_admin() && isset( $_GET['ead_purge_wp_super_cache'] ) && check_admin_referer( 'manual_purge' ) ) {
			global $file_prefix;
			wp_cache_clean_cache( $file_prefix, true );
			add_action( 'admin_notices', array( $this, 'message_wp_super_cache_purge_success' ) );
		} elseif ( $this->is_admin() && isset( $_GET['ead_purge_OPcache'] ) && check_admin_referer( 'manual_purge' ) ) {
			// Taken from: https://wordpress.org/plugins/flush-OPcache/
			// Check if file cache is enabled and delete it if enabled.
			// phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_is_writable
			if ( ini_get( 'OPcache.file_cache' ) && is_writable( ini_get( 'OPcache.file_cache' ) ) ) {
				$files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( ini_get( 'OPcache.file_cache' ), RecursiveDirectoryIterator::SKIP_DOTS ), RecursiveIteratorIterator::CHILD_FIRST );
				foreach ( $files as $fileinfo ) {
					$todo = ( $fileinfo->isDir() ? 'rmdir' : 'unlink' );
					$todo( $fileinfo->getRealPath() );
				}
			}

			// Flush OPcache.
			$did_flush = OPcache_reset();
			if ( $did_flush ) {
				add_action( 'admin_notices', array( $this, 'message_OPcache_purge_success' ) );
			} else {
				add_action( 'admin_notices', array( $this, 'message_OPcache_purge_failure' ) );
			}
		}

		add_action( 'wp_dashboard_setup', array( $this, 'add_dashboard_widgets' ) );
	}

	public function add_dashboard_widgets() {
		if ( $this->is_admin() ) {
			wp_add_dashboard_widget( 'emrikol_admin_dashboard', 'Cache Control', array( $this, 'show_admin_dashboard' ) );
		}
	}

	public function show_admin_dashboard() {
		if ( false === get_parent_class( $GLOBALS['wp_object_cache'] ) ) {
			// Persistent Object Cache detected.
			?>
			<div class="activity-block">
				<span class="button"><a href="<?php echo esc_url( wp_nonce_url( admin_url( '?ead_purge_object_cache' ), 'manual_purge' ) ); ?>"><strong>Purge Object Cache</strong></a></span>
				<p>Force a purge of your entire site's object cache.</p>
			</div>
			<?php
		} else {
			// Transients!
			?>
			<div class="activity-block">
				<h3>Transients</h3>
				<p>Transients cannot currently be removed manually.</p>
			</div>
			<?php
		}
		if ( function_exists( 'wp_cache_clean_cache' ) ) {
			// WP Super Cache!
			?>
			<div class="activity-block">
				<span class="button"><a href="<?php echo esc_url( wp_nonce_url( admin_url( '?ead_purge_wp_super_cache' ), 'manual_purge' ) ); ?>"><strong>Purge Page Cache</strong></a></span>
				<p>Force a purge of your entire site's page cache.</p>
			</div>
			<?php
		}
		if ( function_exists( 'OPcache_reset' ) ) {
			// PHP OPcache.
			?>
			<div class="activity-block">
				<span class="button"><a href="<?php echo esc_url( wp_nonce_url( admin_url( '?ead_purge_OPcache' ), 'manual_purge' ) ); ?>"><strong>Purge PHP OPcache</strong></a></span>
				<p>Force a purge of your entire site's PHP OPcache.</p>
			</div>
			<?php
		}
	}

	public function message_wp_super_cache_purge_success() {
		echo '<div id="message" class="notice notice-success is-dismissible"><p>Page Cache purged!</p></div>';
	}

	public function message_object_cache_purge_success() {
		echo '<div id="message" class="notice notice-success is-dismissible"><p>Object Cache purged!</p></div>';
	}

	public function message_object_cache_purge_failure() {
		echo '<div id="message" class="notice notice-error is-dismissible"><p>Object Cache purge failed!</p></div>';
	}

	public function message_OPcache_purge_success() {
		echo '<div id="message" class="notice notice-success is-dismissible"><p>PHP OPcache purged!</p></div>';
	}

	public function message_OPcache_purge_failure() {
		echo '<div id="message" class="notice notice-error is-dismissible"><p>PHP OPcache purge failed!</p></div>';
	}

	private function is_admin() {
		if ( current_user_can( 'manage_options' ) ) {
			return true;
		}
		return false;
	}
}
Emrikol_Cache_Dashboard::instance();

Leave a comment

Leave a Reply

%d bloggers like this: