You've already forked wp-fedistream
fix: Complete memory leak fix with shortcode context tracking
All checks were successful
Create Release Package / build-release (push) Successful in 57s
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:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.4.2] - 2026-02-02
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Complete fix for memory leak** - v0.4.1 fix was incomplete
|
||||
- Added `$in_shortcode_context` flag to TemplateLoader to track when we're rendering shortcodes
|
||||
- All shortcode render methods now call `enter_shortcode_context()` before loading data
|
||||
- When in shortcode context, `the_content` filter is always skipped to prevent recursive shortcode processing
|
||||
- This prevents infinite recursion when post content contains FediStream shortcodes
|
||||
|
||||
## [0.4.1] - 2026-02-02
|
||||
|
||||
### Fixed
|
||||
@@ -207,7 +217,8 @@ Initial release of WP FediStream - a WordPress plugin for streaming music over A
|
||||
|
||||
---
|
||||
|
||||
[Unreleased]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.1...HEAD
|
||||
[Unreleased]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.2...HEAD
|
||||
[0.4.2]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.1...v0.4.2
|
||||
[0.4.1]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.0...v0.4.1
|
||||
[0.4.0]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.3.0...v0.4.0
|
||||
[0.3.0]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.2.0...v0.3.0
|
||||
|
||||
@@ -81,6 +81,9 @@ class Shortcodes {
|
||||
* @return string
|
||||
*/
|
||||
public function render_artist( array $atts ): string {
|
||||
// Enter shortcode context to prevent recursive shortcode processing during data loading.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
@@ -95,6 +98,7 @@ class Shortcodes {
|
||||
|
||||
$post = $this->get_post( $atts, 'fedistream_artist' );
|
||||
if ( ! $post ) {
|
||||
TemplateLoader::exit_shortcode_context();
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -119,6 +123,9 @@ class Shortcodes {
|
||||
* @return string
|
||||
*/
|
||||
public function render_album( array $atts ): string {
|
||||
// Enter shortcode context to prevent recursive shortcode processing during data loading.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
@@ -132,6 +139,7 @@ class Shortcodes {
|
||||
|
||||
$post = $this->get_post( $atts, 'fedistream_album' );
|
||||
if ( ! $post ) {
|
||||
TemplateLoader::exit_shortcode_context();
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -155,6 +163,9 @@ class Shortcodes {
|
||||
* @return string
|
||||
*/
|
||||
public function render_track( array $atts ): string {
|
||||
// Enter shortcode context to prevent recursive shortcode processing during data loading.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
@@ -168,6 +179,7 @@ class Shortcodes {
|
||||
|
||||
$post = $this->get_post( $atts, 'fedistream_track' );
|
||||
if ( ! $post ) {
|
||||
TemplateLoader::exit_shortcode_context();
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -191,6 +203,9 @@ class Shortcodes {
|
||||
* @return string
|
||||
*/
|
||||
public function render_playlist( array $atts ): string {
|
||||
// Enter shortcode context to prevent recursive shortcode processing during data loading.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => 0,
|
||||
@@ -204,6 +219,7 @@ class Shortcodes {
|
||||
|
||||
$post = $this->get_post( $atts, 'fedistream_playlist' );
|
||||
if ( ! $post ) {
|
||||
TemplateLoader::exit_shortcode_context();
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -227,6 +243,9 @@ class Shortcodes {
|
||||
* @return string
|
||||
*/
|
||||
public function render_latest_releases( array $atts ): string {
|
||||
// Enter shortcode context to prevent recursive shortcode processing during data loading.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'count' => 6,
|
||||
@@ -292,6 +311,9 @@ class Shortcodes {
|
||||
* @return string
|
||||
*/
|
||||
public function render_popular_tracks( array $atts ): string {
|
||||
// Enter shortcode context to prevent recursive shortcode processing during data loading.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'count' => 10,
|
||||
@@ -359,6 +381,9 @@ class Shortcodes {
|
||||
* @return string
|
||||
*/
|
||||
public function render_artists_grid( array $atts ): string {
|
||||
// Enter shortcode context to prevent recursive shortcode processing during data loading.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'count' => 12,
|
||||
@@ -426,6 +451,9 @@ class Shortcodes {
|
||||
* @return string
|
||||
*/
|
||||
public function render_player( array $atts ): string {
|
||||
// Enter shortcode context to prevent recursive shortcode processing during data loading.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'track' => 0,
|
||||
@@ -471,6 +499,7 @@ class Shortcodes {
|
||||
}
|
||||
|
||||
if ( empty( $tracks ) ) {
|
||||
TemplateLoader::exit_shortcode_context();
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -528,13 +557,20 @@ class Shortcodes {
|
||||
return $this->get_unlicensed_message();
|
||||
}
|
||||
|
||||
// Enter shortcode context to prevent recursive shortcode processing.
|
||||
TemplateLoader::enter_shortcode_context();
|
||||
|
||||
try {
|
||||
return $this->plugin->render( $template, $context );
|
||||
$result = $this->plugin->render( $template, $context );
|
||||
} catch ( \Exception $e ) {
|
||||
TemplateLoader::exit_shortcode_context();
|
||||
if ( WP_DEBUG ) {
|
||||
return '<p class="fedistream-error">' . esc_html( $e->getMessage() ) . '</p>';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
TemplateLoader::exit_shortcode_context();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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' ),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Plugin Name: WP FediStream
|
||||
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wp-fedistream
|
||||
* Description: Stream music over ActivityPub - Build your own music streaming platform for Musicians and Labels.
|
||||
* Version: 0.4.1
|
||||
* Version: 0.4.2
|
||||
* Requires at least: 6.4
|
||||
* Requires PHP: 8.3
|
||||
* Author: Marco Graetsch
|
||||
@@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
define( 'WP_FEDISTREAM_VERSION', '0.4.1' );
|
||||
define( 'WP_FEDISTREAM_VERSION', '0.4.2' );
|
||||
|
||||
/**
|
||||
* Plugin file path.
|
||||
|
||||
Reference in New Issue
Block a user