diff --git a/bu-navigation.php b/bu-navigation.php index 2076bc7..7c632cc 100644 --- a/bu-navigation.php +++ b/bu-navigation.php @@ -5,7 +5,7 @@ * Author: Boston University (IS&T) * Author URI: http://sites.bu.edu/web/ * Description: Provides alternative navigation elements designed for blogs with large page counts - * Version: 1.3.6 + * Version: 1.3.7 * Text Domain: bu-navigation * Domain Path: /languages * License: GPL2+ @@ -94,7 +94,7 @@ class BU_Navigation_Plugin { * * @var string */ - const VERSION = '1.3.6'; + const VERSION = '1.3.7'; /** * Plugin class constructor. diff --git a/composer-includes/bu-navigation-core-widget/src/data-get-urls.php b/composer-includes/bu-navigation-core-widget/src/data-get-urls.php index 5ced43b..d8fbfdc 100644 --- a/composer-includes/bu-navigation-core-widget/src/data-get-urls.php +++ b/composer-includes/bu-navigation-core-widget/src/data-get-urls.php @@ -218,6 +218,35 @@ function get_page_uri( $page, $ancestors ) { */ function get_page_uri_ancestors( $post ) { + // Try the cache first, mirroring load_sections(). This call resolves a post's + // ancestor chain via load_sections() + the uncached get_nav_posts() query, and + // runs once per missing-ancestor chain on every front-end render. Without a + // persistent cache it re-runs the raw posts query on each request, which is the + // dominant source of wp_posts read amplification during crawls. + // + // The key is version-stamped on the core posts 'last_changed' value (bumped by + // clean_post_cache() on any post edit) and site-scoped. The 'bu-navigation' group + // is Redis-backed (persistent) in production. Freshness is fully handled by the + // last_changed stamp; the TTL is only a self-healing backstop for the rare case an + // edit bypasses clean_post_cache() (e.g. a direct $wpdb write or import). Unlike + // load_sections() (keyed on post types, so a few keys per site), this cache is keyed + // per post, so a short TTL is used to keep orphaned key generations -- one per + // last_changed bump -- from accumulating in Redis. + $last_changed = wp_cache_get( 'last_changed', 'posts' ); + if ( ! $last_changed ) { + $last_changed = microtime(); + wp_cache_set( 'last_changed', $last_changed, 'posts' ); + } + + $cache_key = 'page_uri_ancestors:' . get_current_blog_id() . ':' . md5( $post->ID . ':' . $post->post_type . ":$last_changed" ); + $cached = wp_cache_get( $cache_key, 'bu-navigation' ); + + // Use a strict check against false so that an empty-ancestors result (a top-level + // post with no ancestors) is still served from cache rather than recomputed. + if ( false !== $cached ) { + return $cached; + } + $ancestors = array(); $all_sections = load_sections( $post->post_type ); @@ -246,6 +275,8 @@ function get_page_uri_ancestors( $post ) { } } + wp_cache_set( $cache_key, $ancestors, 'bu-navigation', HOUR_IN_SECONDS ); + return $ancestors; } diff --git a/readme.md b/readme.md index f22286d..6db5697 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ **Tags:** navigation, hierarchical, post type, boston university, bu **Requires at least:** 3.1 **Tested up to:** 5.7 -**Stable tag:** 1.3.6 +**Stable tag:** 1.3.7 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -115,6 +115,16 @@ Please see this page for the details: ## Changelog +### 1.3.7 + +* Makes the per-post ancestor lookup (`get_page_uri_ancestors`) persistent, mirroring the + 1.3.6 `load_sections` change. This call resolves a post's ancestor chain when building + permalinks and ran an uncached posts query once per missing-ancestor chain on nearly every + front-end render — the dominant source of `wp_posts` read amplification during crawls. + Results are now cached in the site-scoped, version-stamped `bu-navigation` cache (invalidated + on any post edit, with a short TTL backstop), so permalinks render identically while the + underlying query is reused across requests. + ### 1.3.6 * Makes the navigation tree section cache (`load_sections`) persistent instead of diff --git a/readme.txt b/readme.txt index f75743c..c798e35 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: ntk, mgburns, gcorne, jtwiest, awbauer, inderpreet99 Tags: navigation, hierarchical, post type, boston university, bu Requires at least: 3.1 Tested up to: 5.7 -Stable tag: 1.3.6 +Stable tag: 1.3.7 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -79,6 +79,10 @@ Please see this page for the details: == Changelog == += 1.3.7 = + +* Makes the per-post ancestor lookup (`get_page_uri_ancestors`) persistent, mirroring the 1.3.6 `load_sections` change. This call resolves a post's ancestor chain when building permalinks and ran an uncached posts query once per missing-ancestor chain on nearly every front-end render — the dominant source of `wp_posts` read amplification during crawls. Results are now cached in the site-scoped, version-stamped `bu-navigation` cache (invalidated on any post edit, with a short TTL backstop), so permalinks render identically while the underlying query is reused across requests. + = 1.3.6 = * Makes the navigation tree section cache (`load_sections`) persistent instead of non-persistent, so the page-hierarchy `GROUP_CONCAT` query is reused across requests rather than re-run on nearly every front-end render. The cache key is site-scoped and version-stamped on the core posts cache, with a one-day TTL backstop; publication status, ordering, and navigation meta continue to be applied on the uncached posts query, so navigation output is unchanged.