fix: Complete memory leak fix with shortcode context tracking
All checks were successful
Create Release Package / build-release (push) Successful in 57s

The v0.4.1 fix was incomplete - shortcodes called get_*_data() methods
directly, bypassing the recursion tracking in get_post_data().

Changes:
- Added $in_shortcode_context flag to TemplateLoader
- Added enter/exit_shortcode_context() methods
- All shortcode render methods now enter context before data loading
- When in shortcode context, the_content filter is always skipped

This fully prevents infinite recursion when post content contains
FediStream shortcodes that would otherwise recursively render.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-02 16:44:51 +01:00
parent eaefcff9c9
commit fedab21c2a
4 changed files with 93 additions and 7 deletions

View File

@@ -35,6 +35,43 @@ class TemplateLoader {
*/
private const MAX_RECURSION_DEPTH = 3;
/**
* Whether we're currently in a shortcode rendering context.
* When true, the_content filter is skipped to prevent recursive shortcode processing.
*
* @var bool
*/
private static bool $in_shortcode_context = false;
/**
* Enter shortcode rendering context.
* Call this before rendering shortcode content to prevent recursive shortcode processing.
*
* @return void
*/
public static function enter_shortcode_context(): void {
self::$in_shortcode_context = true;
}
/**
* Exit shortcode rendering context.
* Call this after shortcode rendering is complete.
*
* @return void
*/
public static function exit_shortcode_context(): void {
self::$in_shortcode_context = false;
}
/**
* Check if we're in a shortcode rendering context.
*
* @return bool
*/
public static function is_in_shortcode_context(): bool {
return self::$in_shortcode_context;
}
/**
* Constructor.
*/
@@ -213,13 +250,15 @@ class TemplateLoader {
// Track recursion to prevent infinite loops from shortcodes in content.
++self::$recursion_depth;
// At depth > 1, skip the_content filter to prevent shortcode recursion.
$is_nested = self::$recursion_depth > 1;
// Skip the_content filter if:
// 1. We're in a shortcode context (prevents recursive shortcode processing)
// 2. We're at depth > 1 (nested data loading)
$skip_content_filter = self::$in_shortcode_context || self::$recursion_depth > 1;
$data = array(
'id' => $post->ID,
'title' => get_the_title( $post ),
'content' => $is_nested ? wp_kses_post( $post->post_content ) : apply_filters( 'the_content', $post->post_content ),
'content' => $skip_content_filter ? wp_kses_post( $post->post_content ) : apply_filters( 'the_content', $post->post_content ),
'excerpt' => get_the_excerpt( $post ),
'permalink' => get_permalink( $post ),
'thumbnail' => get_the_post_thumbnail_url( $post->ID, 'large' ),