@@ -28,6 +28,11 @@ class Front_End {
28
28
*/
29
29
const PRISM_HANDLE = 'code-snippets-prism ' ;
30
30
31
+ /**
32
+ * Maximum depth for shortcode recursion.
33
+ */
34
+ const MAX_SHORTCODE_DEPTH = 5 ;
35
+
31
36
/**
32
37
* Class constructor
33
38
*/
@@ -235,7 +240,7 @@ protected function convert_boolean_attribute_flags( array $atts, array $boolean_
235
240
*
236
241
* @return string Evaluated shortcode content.
237
242
*/
238
- protected function evaluate_shortcode_content ( Snippet $ snippet , array $ atts ): string {
243
+ protected function evaluate_shortcode_content ( Snippet $ snippet , array $ atts ): string {
239
244
if ( empty ( $ atts ['php ' ] ) ) {
240
245
return $ snippet ->code ;
241
246
}
@@ -325,8 +330,25 @@ public function render_content_shortcode( array $atts ): string {
325
330
// Remove this shortcode from the list to prevent recursion.
326
331
remove_shortcode ( self ::CONTENT_SHORTCODE );
327
332
328
- // Evaluate shortcodes.
329
- $ content = do_shortcode ( $ atts ['format ' ] ? shortcode_unautop ( $ content ) : $ content );
333
+ // Recursion depth is limited to prevent infinite loops.
334
+ static $ depth = 0 ;
335
+ $ max_depth = self ::MAX_SHORTCODE_DEPTH ;
336
+
337
+ // Find the shortcode in the content and replace it with the evaluated content.
338
+ $ content = preg_replace_callback (
339
+ '/\[ ' . self ::CONTENT_SHORTCODE . '([^\]]*)\]/ ' ,
340
+ function ($ matches ) use (&$ depth , $ max_depth ) {
341
+ if ($ depth >= $ max_depth ) {
342
+ return '<!-- Max shortcode depth reached --> ' ;
343
+ }
344
+ $ depth ++;
345
+ $ atts = shortcode_parse_atts ($ matches [1 ]);
346
+ $ result = $ this ->render_content_shortcode ($ atts );
347
+ $ depth --;
348
+ return $ result ;
349
+ },
350
+ $ content
351
+ );
330
352
331
353
// Add this shortcode back to the list.
332
354
add_shortcode ( self ::CONTENT_SHORTCODE , [ $ this , 'render_content_shortcode ' ] );
0 commit comments