public static function purge_varnish_cache($post_id = null) { global $wpengine_platform_config; global $wpe_varnish_servers; global $wpdb; $wpe_all_domains = $wpengine_platform_config['all_domains']; if (!$wpe_all_domains) { $wpe_all_domains = array(); } static $purge_counter; // Globally disabled? if (defined('WPE_DISABLE_CACHE_PURGING') && WPE_DISABLE_CACHE_PURGING) { return false; } // Autosaving never updates published content. if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return false; } // If we've purged "enough" times, stop already. if (isset($purge_counter) && $purge_counter > 2) { return false; } $blog_url = home_url(); $blog_url_parts = @parse_url($blog_url); $blog_domain = $blog_url_parts['host']; // If purging everything, $paths and $abspaths are empty. $abspaths = array(); // paths to purge exactly; no prefix or suffixes. $paths = array(); // path regular expressions to purge. $purge_thing = false; if ($post_id && $post_id > 1 && !!($post = get_post($post_id))) { // Certain post types aren't cached so we shouldn't purge if ($post->post_type == 'attachment' || $post->post_type == 'revision') { return; } // If the post isn't published, we don't need to purge (draft, scheduled, deleted) if ($post->post_status != 'publish') { //error_log("purgebail: ".$post->post_status); return; } //error_log("micropurge: $post_id"); // Determine the set of paths to purge. If there's no post_id, purge all. Otherwise name the paths. $purge_domains = array($blog_domain); $blog_path = WpeCommon::get_path_trailing_slash(@$blog_url_parts['path']); if ($blog_path == '/') { $blog_path_prefix = ""; } else { $tpath = substr($blog_path, 0, -1); $blog_path_prefix = $tpath . ".*"; } // Always purge the post's own URI, along with anything similar $post_parts = parse_url(post_permalink($post_id)); $post_uri = rtrim($post_parts['path'], '/') . "(.*)"; if (!empty($post_parts['query'])) { $post_uri .= "?" . $post_parts['query']; } $paths[] = $post_uri; // Purge the categories & tags this post belongs to if (defined('WPE_PURGE_CATS_ON_PUB')) { foreach (wp_get_post_categories($post_id) as $cat_id) { $cat = get_category($cat_id); $slug = $cat->slug; $paths[] = "{$blog_path_prefix}/{$slug}/"; } foreach (wp_get_post_tags($post_id) as $tag) { $slug = $tag->slug; $paths[] = "{$blog_path_prefix}/{$slug}/"; } } // Purge main pages if we're there. Can't know for sure, so approximate by saying // if it's more than 7 days old it's either not there or has been there for so // long that it doesn't matter. if (time() - strtotime($post->post_date_gmt) < 60 * 60 * 24 * 7) { if ($post->post_type != 'shop_order') { $paths[] = "^{$blog_path}\$"; $paths[] = "/feed"; } } $purge_thing = $post_id; } else { $paths[] = ".*"; // full blog purge $purge_thing = true; $purge_domains = $wpe_all_domains; if (isset($wpdb->dmtable)) { $rows = $wpdb->get_results("SELECT domain FROM {$wpdb->dmtable}"); foreach ($rows as $row) { $purge_domains[] = strtolower($row->domain); } $purge_domains = array_unique($purge_domains); } } // add on blog domains for this blog // this will ensure we are purging in all proper locations $purge_domains = array_unique(array_merge($purge_domains, self::get_blog_domains())); if (!count($paths)) { return; // short-circuit if there's nothing to do. } // else: $paths = array_unique($paths); // allow the code above to be sloppy // At this point, we know we're going to purge, so let's bump the purge counter. This will prevent us from // over-purging on a given request. // BWD: I'm not sure this is necessary and may actually be harmful, depending on how many updates to a given // post can happen within a single request. if (!isset($purge_counter)) { $purge_counter = 1; } else { $purge_counter++; } // Purge Varnish cache. if (WPE_CLUSTER_TYPE == "pod") { $wpe_varnish_servers = array("localhost"); } else { if (!isset($wpe_varnish_servers)) { if (!defined('WPE_CLUSTER_ID') || !WPE_CLUSTER_ID) { $lbmaster = "lbmaster"; } else { if (WPE_CLUSTER_ID >= 4) { $lbmaster = "localhost"; // so the current user sees the purge } else { $lbmaster = "lbmaster-" . WPE_CLUSTER_ID; } } $wpe_varnish_servers = array($lbmaster); } } // Debugging if (false) { $msg_key = rand(); $msg = "Varnishes # {$msg_key}:\n" . var_export($wpe_varnish_servers, true) . "\nDomains:\n" . var_export($purge_domains, true) . "\nPaths:\n" . var_export($paths, true); //error_log( "PURGE: $msg" ); } if ($paths) { $paths_regex = '(' . join('|', $paths) . ')'; } if ($abspaths) { $abspaths = array_map('preg_quote', $abspaths); $abspaths_regex = '^(' . join('|', $abspaths) . ')$'; } if ($paths && $abspaths) { $path_regex = "(({$abspaths_regex})|({$paths_regex}))"; } else { if ($paths) { $path_regex = $paths_regex; } else { if ($abspaths) { $path_regex = $abspaths_regex; } else { $path_regex = '.*'; } } } // Convert the purge domains to PCRE-escaped strings and join them together in an alternation -- purging in // blocks of 100 domains. Varnish can't handle an unlimited number. Ordinarily, this will still be one chunk, // but for some massive sites, there can be more than 100 domains mapped, unfortunately. $hostname = $purge_domains[0]; $purge_domains = array_map('preg_quote', $purge_domains); $purge_domain_chunks = array_chunk($purge_domains, 100); foreach ($purge_domain_chunks as $chunk) { $purge_domain_regex = '^(' . join('|', $chunk) . ')$'; // Tell Varnish. foreach ($wpe_varnish_servers as $varnish) { $headers = array('X-Purge-Path' => $path_regex, 'X-Purge-Host' => $purge_domain_regex); $ok = WpeCommon::http_request_async('PURGE', $varnish, 9002, $hostname, '/', $headers, 0); if (!$ok) { error_log("purge_varnish_cache() failed for: ({$varnish}) #{$purge_domain_regex}# #{$path_regex}#"); } } } return true; }
public static function purge_varnish_cache($post_id = null) { global $wpe_all_domains; static $purge_counter; global $wpe_varnish_servers, $wpe_ec_servers; global $wpdb; // Globally disabled? if (WPE_DISABLE_CACHE_PURGING) { return false; } // If already done, don't keep harping on it. if (isset($purge_counter) && $purge_counter > 2) { return false; } $blog_url = home_url(); $blog_url_parts = @parse_url($blog_url); $blog_domain = $blog_url_parts['host']; $paths = array(); // will leave empty if we want a purge-all $purge_thing = false; if ($post_id && $post_id > 1 && !!($post = get_post($post_id))) { //error_log("micropurge: $post_id"); // Determine the set of paths to purge. If there's no post_id, purge all. Otherwise name the paths. $purge_domains = array($blog_domain); $blog_path = WpeCommon::get_path_trailing_slash(@$blog_url_parts['path']); if ($blog_path == '/') { $blog_path_prefix = ""; } else { $tpath = substr($blog_path, 0, -1); $blog_path_prefix = $tpath . ".*"; } // Certain post types aren't cached so we shouldn't purge if ($post->post_type == 'attachment' || $post->post_type == 'revision') { return; } // If the post isn't published, we don't need to purge (draft, scheduled, deleted) if ($post->post_status != 'publish') { //error_log("purgebail: ".$post->post_status); return; } // Always purge the post's own URI, along with anything similar $post_parts = parse_url(post_permalink($post_id)); $post_uri = rtrim($post_parts['path'], '/') . "(.*)"; if (!empty($post_parts['query'])) { $post_uri .= "?" . $post_parts['query']; } $paths[] = $post_uri; // Purge the categories & tags this post belongs to if (defined('WPE_PURGE_CATS_ON_PUB')) { foreach (wp_get_post_categories($post_id) as $cat_id) { $cat = get_category($cat_id); $slug = $cat->slug; $paths[] = "{$blog_path_prefix}/{$slug}/"; } foreach (wp_get_post_tags($post_id) as $tag) { $slug = $tag->slug; $paths[] = "{$blog_path_prefix}/{$slug}/"; } } // Purge main pages if we're there. Can't know for sure, so approximate by saying // if it's more than 7 days old it's either not there or has been there for so // long that it doesn't matter. if (time() - strtotime($post->post_date_gmt) < 60 * 60 * 24 * 7) { $paths[] = "{$blog_path}="; $paths[] = "/feed"; } $purge_thing = $post_id; } else { $paths[] = "/*"; // full blog purge $purge_thing = true; $purge_domains = $wpe_all_domains; if (isset($wpdb->dmtable)) { $rows = $wpdb->get_results("SELECT domain FROM {$wpdb->dmtable}"); foreach ($rows as $row) { $purge_domains[] = strtolower($row->domain); } $purge_domains = array_unique($purge_domains); } } if (!count($paths)) { return; } // short-circuit if there's nothing to do. $paths = array_unique($paths); // allow the code above to be sloppy // If we've already purged on this web-request, don't do it again. // DO NOT RUN THIS at the TOP of the method because it's possible the post-status changed in the middle! //error_log("micropurge: $post_id, already=$already_purged_all_varnish, ".var_export($paths)); if (!isset($purge_counter)) { $purge_counter = 1; } else { $purge_counter++; } // Determine the set of domains to purge against. // If there's a huge number of domains, only purge the current domain. if (count($wpe_all_domains) > 8) { $purge_domains = array($blog_domain); } // Purge Varnish cache. if (WPE_CLUSTER_TYPE == "pod") { $wpe_varnish_servers = array("localhost"); } else { if (!isset($wpe_varnish_servers)) { if (!defined('WPE_CLUSTER_ID') || !WPE_CLUSTER_ID) { $lbmaster = "lbmaster"; } else { if (WPE_CLUSTER_ID >= 4) { $lbmaster = "localhost"; } else { $lbmaster = "lbmaster-" . WPE_CLUSTER_ID; } } $wpe_varnish_servers = array($lbmaster); } } // Debugging if (false) { $msg_key = rand(); $msg = "Varnishes # {$msg_key}:\n" . var_export($wpe_varnish_servers, true) . "\nDomains:\n" . var_export($purge_domains, true) . "\nPaths:\n" . var_export($paths, true); //error_log( "PURGE: $msg" ); } // Tell Varnish, unless we're using EC if (!isset($wpe_ec_servers) || count($wpe_ec_servers) == 0) { foreach ($wpe_varnish_servers as $varnish) { $purge_fails = array(); foreach ($purge_domains as $hostname) { foreach ($paths as $path) { //error_log("####: $varnish: $hostname, $path"); $ok = WpeCommon::http_request_async("PURGE", $varnish, 9002, $hostname, $path, array(), 0); if (!$ok) { $purge_fails[] = "({$varnish}){$hostname}{$path}"; } } } if (count($purge_fails) > 0) { error_log("purge_varnish_cache() failed for: " . implode(", ", $purge_fails)); } } } // Tell EC, if we're using it /* if ( isset($wpe_ec_servers) ) foreach ( $wpe_ec_servers as $ec ) { WpeCommon::http_request_async( "GET", $ec, 9003, $_SERVER['HTTP_HOST'], '/', array( 'X-EC-Command' => 'purge', 'X-EC-Domains' => join('|',$purge_domains), 'X-EC-Uris' => join('|',$paths), ), 0 ); } */ return true; }