From b592e45d58c87ac32202d2caad82962a81e9ee19 Mon Sep 17 00:00:00 2001 From: magdev Date: Mon, 2 Feb 2026 19:55:23 +0100 Subject: [PATCH] fix: Hard main template rendering lock - Added $rendering_main_template flag that blocks all other renders - Reduced MAX_RENDER_DEPTH from 5 to 2 - template-wrapper.php passes is_main_template=true to enable hard lock - Any render attempt during main template rendering is blocked Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 13 ++++++++++++- includes/Frontend/template-wrapper.php | 3 ++- includes/Plugin.php | 27 ++++++++++++++++++++++++-- wp-fedistream.php | 2 +- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be13b3a..03d8860 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.4.7] - 2026-02-02 + +### Fixed + +- **Hard main template rendering lock** - Added additional protection at Plugin::render() level + - Added `$rendering_main_template` flag that completely blocks any other render calls while main template is rendering + - Reduced MAX_RENDER_DEPTH from 5 to 2 (allows one level of {% include %} but prevents deeper recursion) + - template-wrapper.php now passes `is_main_template = true` to enable the hard lock + - Any render attempt during main template rendering is immediately blocked + ## [0.4.6] - 2026-02-02 ### Fixed @@ -254,7 +264,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.6...HEAD +[Unreleased]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.7...HEAD +[0.4.7]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.6...v0.4.7 [0.4.6]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.5...v0.4.6 [0.4.5]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.4...v0.4.5 [0.4.4]: https://src.bundespruefstelle.ch/magdev/wp-fedistream/compare/v0.4.3...v0.4.4 diff --git a/includes/Frontend/template-wrapper.php b/includes/Frontend/template-wrapper.php index f6bfe19..9bd04ee 100644 --- a/includes/Frontend/template-wrapper.php +++ b/includes/Frontend/template-wrapper.php @@ -60,7 +60,8 @@ get_header(); if ( $template_name ) { try { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo $plugin->render( $template_name, $context ); + // Pass true for is_main_template to set the hard rendering lock. + echo $plugin->render( $template_name, $context, true ); } catch ( \Exception $e ) { if ( WP_DEBUG ) { echo '
'; diff --git a/includes/Plugin.php b/includes/Plugin.php index 035ac31..4b95bba 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -64,10 +64,19 @@ final class Plugin { /** * Maximum allowed Twig render depth. + * Set to 2 to allow one level of nested includes but prevent deeper recursion. * * @var int */ - private const MAX_RENDER_DEPTH = 5; + private const MAX_RENDER_DEPTH = 2; + + /** + * Flag to track if we're currently rendering the main page template. + * This is a hard lock that prevents ANY other rendering. + * + * @var bool + */ + private static bool $rendering_main_template = false; /** * Post type instances. @@ -856,18 +865,32 @@ final class Plugin { * @param array $context Template context variables. * @return string Rendered template. */ - public function render( string $template, array $context = array() ): string { + public function render( string $template, array $context = array(), bool $is_main_template = false ): string { + // If we're already rendering the main template, block any other renders. + if ( self::$rendering_main_template && ! $is_main_template ) { + return ''; + } + // Prevent infinite recursion in Twig rendering. if ( self::$render_depth >= self::MAX_RENDER_DEPTH ) { return ''; } + // Set main template lock if this is the main template. + $was_main = self::$rendering_main_template; + if ( $is_main_template ) { + self::$rendering_main_template = true; + } + ++self::$render_depth; try { $result = $this->twig->render( $template . '.twig', $context ); } finally { --self::$render_depth; + if ( $is_main_template ) { + self::$rendering_main_template = $was_main; + } } return $result; diff --git a/wp-fedistream.php b/wp-fedistream.php index 72a4093..a304187 100644 --- a/wp-fedistream.php +++ b/wp-fedistream.php @@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) { * * @var string */ -define( 'WP_FEDISTREAM_VERSION', '0.4.6' ); +define( 'WP_FEDISTREAM_VERSION', '0.4.7' ); /** * Plugin file path.