arraypress/wp-memoize

Fast in-memory function memoization for WordPress with TTL support and performance statistics.

dev-main 2025-07-08 14:57 UTC

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

  1. Use for repeated calls - Memoization shines when functions are called multiple times with same arguments
  2. Consider TTL - Set appropriate TTL for data that might change during request
  3. Monitor memory - Enable statistics in development to monitor cache efficiency
  4. WordPress objects - Library automatically handles WP objects with ID properties
  5. 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.

Support