Fast in-memory function memoization for WordPress with TTL support and performance statistics.
- In-Memory Caching - Lightning-fast RAM-based storage (no database overhead)
- TTL Support - Optional time-to-live for cache entries
- Custom Key Generation - Flexible cache key strategies
- WordPress Object Handling - Smart handling of WP objects with ID properties
- Performance Statistics - Hit/miss ratios and cache analytics
- Request-Scoped - Automatic cleanup between requests
- Exception Safe - Doesn't cache function exceptions
Memoization is perfect for expensive function calls that might be repeated within a single request:
- Complex calculations that run multiple times
- Expensive database queries called repeatedly
- API calls with identical parameters
- Heavy processing functions
Unlike WordPress object cache, memoization stores results in pure PHP memory with zero serialization overhead.
composer require arraypress/wp-memoize
// Simple function memoization
$expensive_function = wp_memoize( function( $user_id ) {
return get_user_meta( $user_id ); // Expensive DB call
});
// Multiple calls only execute once
$meta1 = $expensive_function( 123 ); // Executes function
$meta2 = $expensive_function( 123 ); // Returns cached result
// Cache results for 5 minutes
$cached_query = wp_memoize( function( $args ) {
return get_posts( $args );
}, 300 );
$posts1 = $cached_query( $args ); // Executes query
$posts2 = $cached_query( $args ); // Cached (if within 5 minutes)
// Custom key generation for complex scenarios
$smart_cache = wp_memoize(
function( $data, $options ) {
return expensive_calculation( $data, $options );
},
600, // 10 minute TTL
function( $args ) {
// Custom key based on specific data properties
return 'calc_' . md5( $args[0]['id'] . serialize( $args[1] ) );
}
);
use ArrayPress\Utils\Memoize;
// Create instance with statistics
$memoize = new Memoize( true );
// Memoize functions
$fast_query = $memoize->memoize( $expensive_function, 300 );
// Get performance stats
$stats = $memoize->get_stats();
// Returns: ['hits' => 45, 'misses' => 5, 'calls' => 50, 'hit_rate' => '90%', 'cache_size' => 23]
// Clear cache when needed
$memoize->clear();
// Invalidate specific cache entries
$memoize->invalidate( [ $specific_args ] );
// Expensive post query that might run multiple times
$get_related_posts = wp_memoize( function( $post_id, $count = 5 ) {
return get_posts([
'meta_query' => [
[
'key' => 'related_to',
'value' => $post_id,
'compare' => '='
]
],
'posts_per_page' => $count
]);
}, 300 );
// Usage in templates - only queries once even if called multiple times
$related = $get_related_posts( get_the_ID() );
// Expensive shipping calculation
$calculate_shipping = wp_memoize( function( $cart_items, $destination ) {
$total_weight = array_sum( wp_list_pluck( $cart_items, 'weight' ) );
$distance = calculate_distance( $destination );
// Complex shipping logic here...
return expensive_shipping_calculation( $total_weight, $distance );
});
// Called multiple times during checkout process
$shipping_cost = $calculate_shipping( $cart->get_items(), $address );
// Cache expensive permission calculations
$user_can_access = wp_memoize( function( $user_id, $resource_id ) {
// Complex permission logic with multiple DB queries
$user_roles = get_user_meta( $user_id, 'roles', true );
$resource_permissions = get_post_meta( $resource_id, 'permissions', true );
return complex_permission_check( $user_roles, $resource_permissions );
}, 600 );
// Fast permission checks throughout request
if ( $user_can_access( $current_user_id, $resource_id ) ) {
// Show content
}
// Cache API responses for the request duration
$get_external_data = wp_memoize( function( $endpoint, $params ) {
$response = wp_remote_get( $endpoint . '?' . http_build_query( $params ) );
if ( is_wp_error( $response ) ) {
return null;
}
return json_decode( wp_remote_retrieve_body( $response ), true );
}, 1800 ); // 30 minutes
// Multiple widgets can use same API data
$api_data = $get_external_data( 'https://api.example.com/data', $params );
// In functions.php - memoize expensive template data
function get_page_sidebar_data( $page_id ) {
static $get_sidebar_data = null;
if ( $get_sidebar_data === null ) {
$get_sidebar_data = wp_memoize( function( $page_id ) {
return [
'widgets' => get_post_meta( $page_id, 'sidebar_widgets', true ),
'menu_items' => wp_get_nav_menu_items( get_post_meta( $page_id, 'sidebar_menu', true ) ),
'recent_posts' => get_posts([ 'posts_per_page' => 5 ])
];
});
}
return $get_sidebar_data( $page_id );
}
// In template - fast even if called multiple times
$sidebar_data = get_page_sidebar_data( get_the_ID() );
// Without memoization - 3 expensive DB queries
$posts1 = get_posts( $complex_args ); // 50ms
$posts2 = get_posts( $complex_args ); // 50ms
$posts3 = get_posts( $complex_args ); // 50ms
// Total: 150ms
// With memoization - 1 DB query + 2 memory lookups
$memoized_get_posts = wp_memoize( 'get_posts' );
$posts1 = $memoized_get_posts( $complex_args ); // 50ms
$posts2 = $memoized_get_posts( $complex_args ); // 0.1ms
$posts3 = $memoized_get_posts( $complex_args ); // 0.1ms
// Total: 50.2ms (70% faster!)
- Use for repeated calls - Memoization shines when functions are called multiple times with same arguments
- Consider TTL - Set appropriate TTL for data that might change during request
- Monitor memory - Enable statistics in development to monitor cache efficiency
- WordPress objects - Library automatically handles WP objects with ID properties
- Exception handling - Exceptions are not cached, so functions will retry on next call
- PHP 7.4+
- WordPress 5.0+ (optional - works with pure PHP too)
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the GPL-2.0-or-later License.