arraypress / wp-memoize
Fast in-memory function memoization for WordPress with TTL support and performance statistics.
dev-main
2025-07-08 14:57 UTC
Requires
- php: >=7.4
This package is auto-updated.
Last update: 2025-09-02 14:54:31 UTC
README
Fast in-memory function memoization for WordPress with TTL support and performance statistics.
Features
- 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
Why Memoization?
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.
Installation
composer require arraypress/wp-memoize
Usage
Basic Memoization
// 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
With TTL (Time-To-Live)
// 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 Cache Keys
// 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] ) ); } );
Direct Class Usage
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 ] );
Real-World Examples
WordPress Query Optimization
// 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() );
Complex Calculations
// 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 );
User Permission Checks
// 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 }
API Response Caching
// 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 );
Template Performance
// 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() );
Performance Benefits
// 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!)
Best Practices
- 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
Requirements
- PHP 7.4+
- WordPress 5.0+ (optional - works with pure PHP too)
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the GPL-2.0-or-later License.