Discovery Cache
Foehn uses PHP reflection to discover attributes at runtime. While this provides a great developer experience, it can add overhead in production. The discovery cache stores discovery results to avoid runtime reflection.
Configuration
Enable discovery caching by passing configuration when booting the kernel:
<?php
// functions.php
use Studiometa\Foehn\Kernel;
Kernel::boot(__DIR__ . '/app', [
'discovery_cache' => 'full', // or 'partial', 'none', true, false
]);Cache Strategies
| Strategy | Description |
|---|---|
'full' | Cache all discoveries (vendor + app) - best for prod |
'partial' | Cache only vendor discoveries - good for staging |
'none' | Disable caching - use in development |
true | Alias for 'full' |
false | Alias for 'none' |
Custom Cache Path
By default, cache files are stored in wp-content/cache/foehn/discovery/. You can customize this:
Kernel::boot(__DIR__ . '/app', [
'discovery_cache' => 'full',
'discovery_cache_path' => WP_CONTENT_DIR . '/cache/my-theme/discovery',
]);CLI Commands
Warm Cache
Warm up the discovery cache by running all discoveries and caching the results. This is the recommended command for deployment as it ensures all discoveries are executed and cached, avoiding slow initial page loads:
wp tempest discovery:warmOptions:
--strategy=<strategy>- Override configured strategy (full, partial)
# Warm with specific strategy
wp tempest discovery:warm --strategy=fullThe command outputs what was discovered:
Warming discovery cache...
✓ 24 hooks discovered
✓ 3 post types discovered
✓ 2 taxonomies discovered
✓ 8 ACF blocks discovered
✓ 4 block patterns discovered
✓ 6 view composers discovered
✓ 12 template controllers discovered
✓ 5 REST routes discovered
Cache written to: /var/www/html/wp-content/cache/foehn/discovery/discoveries.php
Discovery cache warmed successfully.Generate Cache
Generate the discovery cache without running discoveries. Use discovery:warm for deployment; use this command if you only need to regenerate the cache from existing discovery data:
wp tempest discovery:generateOptions:
--strategy=<strategy>- Override configured strategy (full, partial)--clear- Clear existing cache before generating
# Generate with specific strategy
wp tempest discovery:generate --strategy=full
# Clear and regenerate
wp tempest discovery:generate --clearClear Cache
Clear the discovery cache:
wp tempest discovery:clearRun this command when:
- Adding or removing attributed classes
- Changing attribute parameters
- Deploying new code
Check Status
View the current cache status:
wp tempest discovery:statusOutput example:
Discovery Cache Status
======================
Strategy: full
Enabled: Yes
Cache path: /var/www/html/wp-content/cache/foehn/discovery
Cache exists: Yes
Cache valid: Yes
Discovery cache is active and valid.Deployment Workflow
Basic Deployment
# 1. Deploy your code
git pull origin main
# 2. Install dependencies
composer install --no-dev --optimize-autoloader
# 3. Warm discovery cache (runs all discoveries + caches)
wp tempest discovery:warmWith CI/CD
Add to your deployment script:
# GitHub Actions example
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy code
run: rsync -avz ./ user@server:/var/www/html/
- name: Warm discovery cache
run: |
ssh user@server "cd /var/www/html && wp tempest discovery:warm"With Laravel Forge
In your deploy script:
cd /home/forge/example.com
git pull origin main
composer install --no-dev --optimize-autoloader
# Warm Foehn discovery cache
php wp-cli.phar tempest discovery:warm
# Clear other caches
php wp-cli.phar cache flushEnvironment-Based Configuration
Use environment variables for different environments:
<?php
// functions.php
use Studiometa\Foehn\Kernel;
$cacheStrategy = match (wp_get_environment_type()) {
'production' => 'full',
'staging' => 'partial',
default => 'none',
};
Kernel::boot(__DIR__ . '/app', [
'discovery_cache' => $cacheStrategy,
]);Or use a constant in wp-config.php:
// wp-config.php
define('FOEHN_DISCOVERY_CACHE', 'full');// functions.php
Kernel::boot(__DIR__ . '/app', [
'discovery_cache' => defined('FOEHN_DISCOVERY_CACHE')
? FOEHN_DISCOVERY_CACHE
: 'none',
]);How It Works
Without cache: On each request, Foehn scans all PHP files in your app directory, reflecting on classes to find attributes.
With cache: Discovery results are stored as a PHP array file. On subsequent requests, this file is loaded directly (benefiting from PHP's opcode cache).
Cache invalidation: The cache stores the configured strategy. If you change strategies, the cache is automatically invalidated.
What's Cached
The cache stores serialized discovery data for:
- Hook registrations (actions/filters)
- Post types and taxonomies
- Blocks (ACF and native)
- Block patterns
- View composers
- Template controllers
- REST routes
- Shortcodes
- CLI commands
Cache Format
Cache files are stored as executable PHP for opcode caching:
<?php
declare(strict_types=1);
// Auto-generated discovery cache - do not edit
// Generated: 2024-01-15 10:30:00
return [
'Studiometa\\Foehn\\Discovery\\HookDiscovery' => [
[
'type' => 'action',
'hook' => 'init',
'className' => 'App\\Hooks\\ThemeHooks',
'methodName' => 'onInit',
'priority' => 10,
'acceptedArgs' => 1,
],
// ...
],
// ...
];Troubleshooting
Cache Not Working
Check if caching is enabled:
bashwp tempest discovery:statusEnsure the cache directory is writable:
bashchmod -R 755 wp-content/cache/foehnRegenerate the cache:
bashwp tempest discovery:generate --clear
Changes Not Reflected
If your code changes aren't taking effect:
Clear the discovery cache:
bashwp tempest discovery:clearClear PHP opcode cache:
bashwp eval "opcache_reset();"
Development Mode
Always disable caching in development to see changes immediately:
Kernel::boot(__DIR__ . '/app', [
'discovery_cache' => WP_DEBUG ? 'none' : 'full',
]);Performance Impact
| Scenario | First Request | Subsequent Requests |
|---|---|---|
| No cache (development) | ~50-100ms | ~50-100ms |
| Full cache (production) | ~50-100ms | ~5-10ms |
Times are approximate and depend on the number of discovered classes.