* The admin-specific functionality of the plugin.
* @subpackage nginx-helper/admin
* @param string $url URL.
* @param bool $feed Is feed or not.
abstract public function purge_url( $url, $feed = true );
* Purge cache for custom url.
abstract public function custom_purge_urls();
abstract public function purge_all();
* Purge cache on comment.
* @param int $comment_id Comment id.
* @param object $comment Comment data.
public function purge_post_on_comment( $comment_id, $comment ) {
$approved = $comment->comment_approved;
if ( null === $approved ) {
} elseif ( '1' === $approved ) {
} elseif ( '0' === $approved ) {
$newstatus = 'unapproved';
} elseif ( 'spam' === $approved ) {
} elseif ( 'trash' === $approved ) {
$this->purge_post_on_comment_change( $newstatus, $oldstatus, $comment );
* Purge post cache on comment change.
* @param string $newstatus New status.
* @param string $oldstatus Old status.
* @param object $comment Comment data.
public function purge_post_on_comment_change( $newstatus, $oldstatus, $comment ) {
global $nginx_helper_admin, $blog_id;
if ( ! $nginx_helper_admin->options['enable_purge'] ) {
$_post_id = $comment->comment_post_ID;
$_comment_id = $comment->comment_ID;
$this->log( '* * * * *' );
$this->log( '* Blog :: ' . addslashes( get_bloginfo( 'name' ) ) . ' ( ' . $blog_id . ' ). ' );
$this->log( '* Post :: ' . get_the_title( $_post_id ) . ' ( ' . $_post_id . ' ) ' );
$this->log( "* Comment :: $_comment_id." );
$this->log( "* Status Changed from $oldstatus to $newstatus" );
if ( 1 === (int) $nginx_helper_admin->options['purge_page_on_new_comment'] ) {
$this->log( '* Comment ( ' . $_comment_id . ' ) approved. Post ( ' . $_post_id . ' ) purging...' );
$this->log( '* * * * *' );
$this->purge_post( $_post_id );
if ( 'approved' === $oldstatus && 1 === (int) $nginx_helper_admin->options['purge_page_on_deleted_comment'] ) {
$this->log( '* Comment ( ' . $_comment_id . ' ) removed as ( ' . $newstatus . ' ). Post ( ' . $_post_id . ' ) purging...' );
$this->log( '* * * * *' );
$this->purge_post( $_post_id );
* @param int $post_id Post id.
public function purge_post( $post_id ) {
global $nginx_helper_admin, $blog_id;
if ( ! $nginx_helper_admin->options['enable_purge'] ) {
switch ( current_filter() ) {
$this->log( '* * * * *' );
$this->log( '* Blog :: ' . addslashes( get_bloginfo( 'name' ) ) . ' ( ' . $blog_id . ' ).' );
$this->log( '* Post :: ' . get_the_title( $post_id ) . ' ( ' . $post_id . ' ).' );
$this->log( '* Post ( ' . $post_id . ' ) published or edited and its status is published' );
$this->log( '* * * * *' );
$this->log( '* * * * *' );
$this->log( '* Blog :: ' . addslashes( get_bloginfo( 'name' ) ) . ' ( ' . $blog_id . ' ).' );
$this->log( '* Page :: ' . get_the_title( $post_id ) . ' ( ' . $post_id . ' ).' );
$this->log( '* Page ( ' . $post_id . ' ) published or edited and its status is published' );
$this->log( '* * * * *' );
case 'wp_set_comment_status':
$_post_type = get_post_type( $post_id );
$this->log( '* * * * *' );
$this->log( '* Blog :: ' . addslashes( get_bloginfo( 'name' ) ) . ' ( ' . $blog_id . ' ).' );
$this->log( "* Custom post type '" . $_post_type . "' :: " . get_the_title( $post_id ) . ' ( ' . $post_id . ' ).' );
$this->log( "* CPT '" . $_post_type . "' ( " . $post_id . ' ) published or edited and its status is published' );
$this->log( '* * * * *' );
$this->log( 'Function purge_post BEGIN ===' );
if ( 1 === (int) $nginx_helper_admin->options['purge_homepage_on_edit'] ) {
$this->_purge_homepage();
if ( 'comment_post' === current_filter() || 'wp_set_comment_status' === current_filter() ) {
$this->_purge_by_options(
$nginx_helper_admin->options['purge_page_on_new_comment'],
$nginx_helper_admin->options['purge_archive_on_new_comment'],
$nginx_helper_admin->options['purge_archive_on_new_comment']
$this->_purge_by_options(
$nginx_helper_admin->options['purge_page_on_mod'],
$nginx_helper_admin->options['purge_archive_on_edit'],
$nginx_helper_admin->options['purge_archive_on_edit']
$this->custom_purge_urls();
$this->log( 'Function purge_post END ^^^' );
* Purge cache by options.
* @param int $post_id Post id.
* @param int $blog_id Blog id.
* @param bool $_purge_page Purge page or not.
* @param bool $_purge_archive Purge archive or not.
* @param bool $_purge_custom_taxa Purge taxonomy or not.
private function _purge_by_options( $post_id, $blog_id, $_purge_page, $_purge_archive, $_purge_custom_taxa ) {
$_post_type = get_post_type( $post_id );
if ( 'post' === $_post_type || 'page' === $_post_type ) {
$this->log( 'Purging ' . $_post_type . ' ( id ' . $post_id . ', blog id ' . $blog_id . ' ) ' );
$this->log( "Purging custom post type '" . $_post_type . "' ( id " . $post_id . ', blog id ' . $blog_id . ' )' );
$post_status = get_post_status( $post_id );
if ( 'publish' !== $post_status ) {
if ( ! function_exists( 'get_sample_permalink' ) ) {
require_once ABSPATH . '/wp-admin/includes/post.php';
$url = get_sample_permalink( $post_id );
if ( ! empty( $url[0] ) && ! empty( $url[1] ) ) {
$url = str_replace( '%postname%', $url[1], $url[0] );
$url = get_permalink( $post_id );
if ( empty( $url ) && ! is_array( $url ) ) {
if ( 'trash' === get_post_status( $post_id ) ) {
$url = str_replace( '__trashed', '', $url );
$this->purge_url( $url );
$_post_type_archive_link = get_post_type_archive_link( $_post_type );
if ( function_exists( 'get_post_type_archive_link' ) && $_post_type_archive_link ) {
$this->log( 'Purging post type archive ( ' . $_post_type . ' )' );
$this->purge_url( $_post_type_archive_link );
if ( 'post' === $_post_type ) {
$this->log( 'Purging date' );
$day = get_the_time( 'd', $post_id );
$month = get_the_time( 'm', $post_id );
$year = get_the_time( 'Y', $post_id );
$this->purge_url( get_year_link( $year ) );
$this->purge_url( get_month_link( $year, $month ) );
$this->purge_url( get_day_link( $year, $month, $day ) );
$categories = wp_get_post_categories( $post_id );
if ( ! is_wp_error( $categories ) ) {
$this->log( 'Purging category archives' );
foreach ( $categories as $category_id ) {
$this->log( 'Purging category ' . $category_id );
$this->purge_url( get_category_link( $category_id ) );
$tags = get_the_tags( $post_id );
if ( ! is_wp_error( $tags ) && ! empty( $tags ) ) {
$this->log( 'Purging tag archives' );
foreach ( $tags as $tag ) {
$this->log( 'Purging tag ' . $tag->term_id );
$this->purge_url( get_tag_link( $tag->term_id ) );
$author_id = get_post( $post_id )->post_author;
if ( ! empty( $author_id ) ) {
$this->log( 'Purging author archive' );
$this->purge_url( get_author_posts_url( $author_id ) );
if ( $_purge_custom_taxa ) {
$custom_taxonomies = get_taxonomies(
if ( ! empty( $custom_taxonomies ) ) {
$this->log( 'Purging custom taxonomies related' );
foreach ( $custom_taxonomies as $taxon ) {
if ( ! in_array( $taxon, array( 'category', 'post_tag', 'link_category' ), true ) ) {
$terms = get_the_terms( $post_id, $taxon );
if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
foreach ( $terms as $term ) {
$this->purge_url( get_term_link( $term, $taxon ) );
$this->log( "Your built-in taxonomy '" . $taxon . "' has param '_builtin' set to false.", 'WARNING' );
* Deletes local cache files without a 3rd party nginx module.
* Does not require any other modules. Requires that the cache be stored on the same server as WordPress. You must also be using the default nginx cache options (levels=1:2) and (fastcgi_cache_key "$scheme$request_method$host$request_uri").
* Read more on how this works here:
* https://www.digitalocean.com/community/tutorials/how-to-setup-fastcgi-caching-with-nginx-on-your-vps#purging-the-cache
* @param string $url URL to purge.
protected function delete_cache_file_for( $url ) {
// Verify cache path is set.
if ( ! defined( 'RT_WP_NGINX_HELPER_CACHE_PATH' ) ) {
$this->log( 'Error purging because RT_WP_NGINX_HELPER_CACHE_PATH was not defined. URL: ' . $url, 'ERROR' );
$url_data = wp_parse_url( $url );
$this->log( 'Error purging because specified URL did not appear to be valid. URL: ' . $url, 'ERROR' );
// Build a hash of the URL.
$hash = md5( $url_data['scheme'] . 'GET' . $url_data['host'] . $url_data['path'] );
// Ensure trailing slash.
$cache_path = RT_WP_NGINX_HELPER_CACHE_PATH;
$cache_path = ( '/' === substr( $cache_path, -1 ) ) ? $cache_path : $cache_path . '/';
// Set path to cached file.
$cached_file = $cache_path . substr( $hash, -1 ) . '/' . substr( $hash, -3, 2 ) . '/' . $hash;
* Filters the cached file name.
* @param string $cached_file Cached file name.
$cached_file = apply_filters( 'rt_nginx_helper_purge_cached_file', $cached_file );
// Verify cached file exists.
if ( ! file_exists( $cached_file ) ) {
$this->log( '- - ' . $url . ' is currently not cached ( checked for file: ' . $cached_file . ' )' );
// Delete the cached file.
if ( unlink( $cached_file ) ) {
$this->log( '- - ' . $url . ' *** PURGED ***' );
* Fire an action after deleting file from cache.
* @param string $url URL to be purged.
* @param string $cached_file Cached file name.
do_action( 'rt_nginx_helper_purged_file', $url, $cached_file );
$this->log( '- - An error occurred deleting the cache file. Check the server logs for a PHP warning.', 'ERROR' );
* Remote get data from url.
* @param string $url URL to do remote request.
protected function do_remote_get( $url ) {
* Filters the URL to be purged.
* @param string $url URL to be purged.
$url = apply_filters( 'rt_nginx_helper_remote_purge_url', $url );
* Fire an action before purging URL.
* @param string $url URL to be purged.
do_action( 'rt_nginx_helper_before_remote_purge_url', $url );
$response = wp_remote_get( $url );
if ( is_wp_error( $response ) ) {
$_errors_str = implode( ' - ', $response->get_error_messages() );
$this->log( 'Error while purging URL. ' . $_errors_str, 'ERROR' );
if ( $response['response']['code'] ) {
switch ( $response['response']['code'] ) {
$this->log( '- - ' . $url . ' *** PURGED ***' );
$this->log( '- - ' . $url . ' is currently not cached' );
$this->log( '- - ' . $url . ' not found ( ' . $response['response']['code'] . ' )', 'WARNING' );
* Fire an action after remote purge request.
* @param string $url URL to be purged.
* @param array $response Array of results including HTTP headers.
do_action( 'rt_nginx_helper_after_remote_purge_url', $url, $response );