Caching the Menu (wp_nav_menu) in Object Cache

The code below demonstrates how to cache the entire menu code in object cache. The cache will be flushed when the menu is updated. Caching will work for all menus.

GitHub
<?php

Pj_Cached_Nav_Menus::load();

/**
 * Caches calls to wp_nav_menu().
 */
class Pj_Cached_Nav_Menus {
	public static $ttl = 3600; // use 0 to cache forever (until nav menu update)
	public static $cache_menus = array();

	public static function load() {
		add_filter( 'pre_wp_nav_menu', array( __CLASS__, 'pre_wp_nav_menu' ), 10, 2 );
		add_filter( 'wp_nav_menu', array( __CLASS__, 'maybe_cache_nav_menu' ), 10, 2 );
		add_action( 'wp_update_nav_menu', array( __CLASS__, 'clear_caches' ) );
	}

	private static function _cache_key( $args ) {
		$_args = (array) $args;
		unset( $_args['menu'] );
		return 'pj-cached-nav-menu:' . md5( json_encode( $_args ) );
	}

	private static function _timestamp() {
		static $timestamp;
		if ( ! isset( $timestamp ) )
			$timestamp = get_option( 'pj-cached-nav-menus-timestamp', 0 );

		return $timestamp;
	}

	public static function pre_wp_nav_menu( $output, $args ) {
		if ( ! empty( $args->menu ) )
			return $output;

		$cache_key = self::_cache_key( $args );
		self::$cache_menus[] = $cache_key;

		$cache = get_transient( $cache_key );
		if ( is_array( $cache ) && $cache['timestamp'] >= self::_timestamp() ) {
			$output = $cache['html'] . '<!-- pj-cached-nav-menu -->';
		}

		return $output;
	}

	public static function maybe_cache_nav_menu( $html, $args ) {
		$cache_key = self::_cache_key( $args );

		if ( ! in_array( $cache_key, self::$cache_menus ) )
			return $html;

		$cache = array(
			'html' => $html,
			'timestamp' => time(),
		);

		set_transient( $cache_key, $cache, self::$ttl );
		return $html;
	}

	public static function clear_caches() {
		update_option( 'pj-cached-nav-menus-timestamp', time() );
	}
}

Original code: https://github.com/pressjitsu/cached-nav-menus

Composer package: https://github.com/inpsyde/menu-cache

Another similar example: https://www.bjornjohansen.com/wordpress-menu-cache

This Note embeded into: wp_nav_menu()