FasterCache

Smoother Sailing with the Faster Cache for WordPress

Architectural Focus and Code Example

Architecturally speaking, the Faster Cache focuses on the jobs that are best performed by a plugin, while steering clear of those jobs that are best handled at the server level.

What Plugins Do Best

If you’re happy with the performance penalties of using a caching plugin written in PHP to send custom headers, for example, or to gzip content, or maybe to do a spot of string manipulation just for fun, then you probably should stick with other plugins than the Faster Cache. On the other hand, if you prefer plugins to do what plugins do best, while letting servers do what servers do best, then you’ll probably appreciate that the Faster Cache focuses all its efforts on creating and intelligently maintaining a cache of final page output as produced by WordPress. But it does not mess with headers, it does not gzip content, and it does not spend comparatively slow PHP resources on string manipulations like removing whitespace from content that’s almost always going to be gzipped (by the server, that is) anyway. In the Faster Cache view of the universe, if a job can be done globally, at the server level, it usually should be done at the server level, with no involvement from PHP or a relatively massive chunk of code like WordPress.

As for retrieving cache files, that too happens directly via mod_rewrite rules without any involvement from PHP or WordPress; likewise, server-level directives configure headers and gzipping more efficiently than PHP.

Code Example: Class Constructor

To give an idea of the various nooks and crannies which Faster Cache hooks into while creating a smoothly functioning cache experience, here’s the constructor from the plugin’s class. (Since this site’s theme doesn’t provide much in the way of horizontal space to see the code easily, it may be more convenient just to select it all and paste into your own editor.)

Note that beyond the constructor shown below, the plugin only uses a little over 1000 more lines to implement full cache functionality. Admin options pages are delivered via separate code, while another couple of hundred lines of code provide analytical functions which yield the administrative dashboard performance display.

function __construct( $plugin_prefix = '', $our_name = '', $option_style = '' ) {
	/*
		Set up a few bits of housekeeping, like naming and options conventions, plus where we'll be storing the cache.
	 */
	$this->plugin_prefix = $plugin_prefix . '_';
	$this->our_name = $our_name;
	$this->set_cache_loc();
	if ( !empty( $option_style ) )
		$this->consolidate = ( 'consolidate' == $option_style ) ? true : false;
	else
		$this->consolidate = true;
	/*
		Update our cookie list
	 */
	$this->update_cookie_list();
	/*
		Extra check to ensure no caching of admin.
	 */
	add_action( 'admin_init', array( $this, 'early_admin_check' ), 1 );
	/*
		Ensure no caching of login.
	 */
	add_action( 'login_head', array( $this, 'early_admin_check' ), 1 );
	/*
		Tidy up our list of cookies to check.
	 */
	add_action( 'wp_head', array( $this, 'flesh_out_cookie_list' ), 1 );
	/*
		By the time we get to footer, we should be able to tell whether this page ought to be excluded from cache...
	 */
	add_filter( 'wp_footer', array( $this, 'should_we_cache' ), 999 );
	/*
		...but we also need a direct check on the WP status header.
	 */
	add_filter( 'status_header', array( $this, 'check_headers' ), 10, 2 );
	/*
		Expiry conditions: a post has changed...
		
		See expire_by_post_only() for details of how we work around a flaw in WP's handling of comment editing.
	 */
	add_action( 'transition_post_status', array( $this, 'detect_pub_change' ), 0, 3 );
	add_action( 'pre_post_update', array( $this, 'pre_post_update_permalink' ), 0, 1 );
	// This also runs when editing a post with a status of published.
	add_action( 'publish_post', array( $this, 'expire_by_post_only' ), 0, 1 );
	add_action( 'publish_page', array( $this, 'expire_by_post_only' ), 0, 1 );
	// And this gets called even when only comment content changes.
	add_action( 'edit_post', array( $this, 'expire_by_post_only' ), 0, 1 );
	add_action( 'publish_phone', array( $this, 'expire_by_post_only' ), 0, 1 );
	add_action( 'delete_post', array( $this, 'expire_by_post_only' ), 0, 1 );
	/*
		Expiry conditions: a comment has changed...
	 */
	add_action( 'trackback_post', array( $this, 'expire_by_comment_post' ), 999, 1 );
	add_action( 'pingback_post', array( $this, 'expire_by_comment_post' ), 999, 1 );
	// Only comment_post tells us a status.
	add_action( 'comment_post', array( $this, 'expire_by_comment_post' ), 999, 2 );
	add_action( 'edit_comment', array( $this, 'expire_by_comment_change' ), 999, 1 );
	add_action( 'transition_comment_status', array( $this, 'expire_by_comment_status' ), 999, 3 );
	/*
		Expiry conditions: an author's profile has been updated...
	 */
	add_action( 'profile_update', array( $this, 'expire_by_author_update' ), 0, 1 );
	/*
		Expiry conditions: theme switch...
	 */
	add_action( 'switch_theme', array( $this, 'expire_by_theme_change' ), 0 );
	/*
		Expiry conditions: static front page changes...
	 */
	add_action( 'update_option_show_on_front', array( $this, 'expire_by_static_front' ), 0 );
	add_action( 'update_option_page_on_front', array( $this, 'expire_by_static_front_details' ), 0, 2 );
	add_action( 'update_option_page_for_posts', array( $this, 'expire_by_static_front_details' ), 0, 2 );
	/*
		Expiry conditions: change in permalink structure...
	 */
	add_action( 'update_option_permalink_structure', array( $this, 'expire_now_no_replacement' ), 1, 0 );
	add_action( 'update_option_siteurl', array( $this, 'expire_now_no_replacement' ), 1, 0 );
	add_action( 'update_option_home', array( $this, 'expire_now_no_replacement' ), 1, 0 );
	/*
		Include our custom htaccess directives whenever htaccess is written.
		
		We set a function separately via register_deactivation_hook to deactivate them.

		Note we prepend our rules late in filtering.
	 */
	add_filter( 'mod_rewrite_rules', array( $this, 'set_htaccess' ), 999, 1 );
	/*
		Cron action for cache pruning...
	 */
	add_action( $this->plugin_prefix . 'cache_pruning', array( $this, 'cron_handler' ) );
	/*
		...and set our own cron interval.
	 */
	add_filter( 'cron_schedules', array( $this, 'cron_interval' ) );
	/*
		Cron scheduler only if we don't already have a cron schedule...
	 */
	if ( ( wp_next_scheduled( $this->plugin_prefix . 'cache_pruning' ) ) == false )
		$this->cron_scheduler();
	/*
		Thank you message.
	 */
	if ( $this->opt( 'thank_you' ) )
		add_action( 'wp_footer', array( $this, 'do_thank_you' ) );
	/*
		Also check whether only just activated, and if so, do some extra initialisation.
	 */
	add_action( 'admin_init', array( $this, 'init_extra' ), 1 );
	/*
		Catch changes in settings for updating htaccess directives, cachelife, clearing cache or performance data, etc.
		
		Would normally do this with separate add_action on 'update_option_', but not with options consolidated in one array.
	 */
	add_action( 'update_option_' . $this->plugin_prefix . 'settings', array( $this, 'option_update_watcher' ), 0, 2 );
	/*
		Third-party plugin compatibility, where we ought to expire the cache to keep some other plugins happy.
	 */
	// Nospamnx inserts hidden fields in comment form, generating new ones on activation.
	add_action( 'update_option_nospamnx', array( $this, 'expire_now' ), 0 );
	add_action( 'activate_nospamnx/nospamnx.php', array( $this, 'expire_now' ), 0 );
	add_action( 'deactivate_nospamnx/nospamnx.php', array( $this, 'expire_now' ), 0 );
	// Antispambee modifies existing comment fields in comment form, so we need to expire on both activation and deactivation.
	add_action( 'activate_antispam-bee/antispam_bee.php', array( $this, 'expire_now' ), 0 );
	add_action( 'deactivate_antispam-bee/antispam_bee.php', array( $this, 'expire_now' ), 0 );
	/*
		Externally accessible hook for other plugins which may need to expire our cache, accessible only via admin...
	 */
	add_action( $this->plugin_prefix . 'expire_cache', array( $this, 'external_expire_now' ), 0 );
	/*
		Externally accessible hook for other plugins which may need to expire specific posts by ID or URL...
	 */
	add_action( $this->plugin_prefix . 'expire_posts', array( $this, 'external_expire_posts' ), 0, 1 );
	/*
		Externally accessible hook for other plugins which may need to prevent caching of current page...
	 */
	add_action( $this->plugin_prefix . 'do_not_cache', array( $this, 'external_do_not_cache' ), 0 );
	/*
		Finished up, we're ready!
	 */
	return;
}

This site is provided for informational and entertainment purposes only. It is not intended to provide advice of any kind. Copyright © 2017, with all applicable rights reserved.

All use of this site is subject to the Terms of Use and Privacy Policy.