diff --git a/includes/block-override-functions.php b/includes/block-override-functions.php index a2a6b0a..2ca503f 100644 --- a/includes/block-override-functions.php +++ b/includes/block-override-functions.php @@ -3,6 +3,8 @@ * Implements common functions used in block overrides * */ +require_once __DIR__ . '/class-block-recursion-control.php'; + /** * Overrides a core block's render_callback method, if required. @@ -26,40 +28,15 @@ function fizzie_maybe_override_block( $args, $blockname, $render_callback ) { return $args; } - /** * Determines whether or not to process this content. * * @param string|integer Unique ID for the content * @return bool - true if the post has not been processed. false otherwise */ -function fizzie_process_this_content( $id ) { - global $fizzie_processed_content; - // Use this rather than context['postId'] - global $post; - $fizzie_processed = bw_array_get( $fizzie_processed_content, $id, false ); - - /* - if ( empty( $fizzie_processed_content ) ) { - $global_id = isset( $post ) ? $post->ID : null; - if ( $global_id ) { - $fizzie_processed_content[ $global_id ] = $global_id; - } - } - */ - - - if ( !$fizzie_processed ) { - $fizzie_processed_content[$id] = $id ; - } - - /** Stop when it looks highly likely we've missed something */ - if ( count( $fizzie_processed_content ) > 10 ) { - $fizzie_processed = true; - - } - bw_trace2( $fizzie_processed_content, "processed posts", true, BW_TRACE_DEBUG ); - return( !$fizzie_processed ); +function fizzie_process_this_content( $id ) { + $recursion_control = Fizzie_Block_Recursion_Control::get_instance(); + return $recursion_control->process_this_content( $id ); } /** @@ -74,15 +51,12 @@ function fizzie_process_this_content( $id ) { * - core/block - possibly * * Note: The top level is within the template, which loads the template parts and/or queries. + * + * @param string|integer $id */ function fizzie_clear_processed_content( $id=null ) { - global $fizzie_processed_content; - if ( $id ) { - array_pop( $fizzie_processed_content ); - } else { - $fizzie_processed_content = array(); - } - bw_trace2( $fizzie_processed_content, "cleared", false, BW_TRACE_DEBUG ); + $recursion_control = Fizzie_Block_Recursion_Control::get_instance(); + $recursion_control->clear_processed_content( $id ); } /** @@ -92,102 +66,11 @@ function fizzie_clear_processed_content( $id=null ) { * * @param $id string|integer recursive ID detected * @param $type string content type - * @return string + * @return string HTML reporting the error to the user */ function fizzie_report_recursion_error( $id, $type='core/post-content') { - bw_trace2(); - bw_backtrace(); - global $bad_id, $bad_fizzie_processed_content, $fizzie_processed_content; - $bad_id = $id; - $bad_fizzie_processed_content = $fizzie_processed_content; - - $content = array(); - $content[] = '
'; - switch ( $type ) { - case 'core/post-content': - $content[] = __( 'Content not available; already processed.', 'fizzie' ); - break; - case 'core/template-part': - $content[] = __( 'Template part not processed to avoid infinite recursion', 'fizzie'); - break; - case 'core/block': - $content[] = __( 'Reusable block not processed to avoid infinite recursion', 'fizzie'); - fizzie_add_filter_rest_prepare_wp_block(); - break; - default: - $content[] = __( 'Infinite recursion error prevented', 'fizzie'); - } - if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { - $content[] = ""; - $content[] = '
'; - $content[] = $id; - $content[] = '
'; - $content[] = $type; - $content[] = '
'; - global $fizzie_processed_content; - $content[] = implode( ',', $fizzie_processed_content ); - $content[] = '
'; - } - $content[] = '
'; - $content = implode( " \n", $content); - return $content; -} - -function fizzie_add_filter_rest_prepare_wp_block() { - // We only need to do this in REST API processing - // But this will only be called in REST API processing - // So no need to check - add_filter('rest_prepare_wp_block', 'fizzie_rest_prepare_wp_block', 10, 3); + $recursion_control = Fizzie_Block_Recursion_Control::get_instance(); + $html = $recursion_control->report_recursion_error($id, $type); + return $html; } -/** - * - * Fiddle with the raw content to remove the wp:block block. - * - * [raw] => -

This is reusable block 21117

- - - - * @param $response - * @param $post - * @param $request - * @return mixed# - */ -function fizzie_rest_prepare_wp_block( $response, $post, $request ) { - bw_trace2(); - bw_backtrace(); - global $bad_id; - global $bad_fizzie_processed_content; - $content = $response->data['content']['raw']; - $content = fizzie_replace_bad( $content, $bad_id ); - foreach ( $bad_fizzie_processed_content as $id ) { - $content = fizzie_replace_bad( $content, $id ); - } - // Convert any remaining to a missing block - $content = str_replace( "wp:block {", "missing {", $content ); - - $response->data['content']['raw'] = $content; - bw_trace2( $response, "response", false ); - return $response; -} - -function fizzie_replace_bad( $content, $bad_id ) { - $replacement_block = ""; - $replacement_block .= sprintf(__('Error: Recursion was detected while loading the reusable block with post ID %1$s. '), $bad_id); - $replacement_block .= fizzie_title_link($bad_id); - $replacement_block .= '
'; - $replacement_block .= "Recommendation: Please delete this block."; - $replacement_block .= ""; - $content = str_replace("", $replacement_block, $content); - return $content; -} - - -function fizzie_title_link( $id ) { - $link = sprintf( '%s', esc_url( get_permalink( $id ) ), esc_html( get_the_title( $id ) ) ); - return $link; -} - - - diff --git a/includes/block-overrides.php b/includes/block-overrides.php index 05f19ac..4d52f4d 100644 --- a/includes/block-overrides.php +++ b/includes/block-overrides.php @@ -4,13 +4,14 @@ * */ require_once __DIR__ . '/block-override-functions.php'; +require_once __DIR__ . '/class-block-recursion-control.php'; /** * Here we include the blocks we want to override. * * Either comment out the ones that aren't needed any more - when Gutenberg/core's * satisfies the requirement - * or find another way of automatically determining whether or not to include the file. + * or find another way to automatically determine whether or not to include the file. */ require_once __DIR__ . '/query-pagination.php'; require_once __DIR__ . '/query-loop.php'; @@ -27,7 +28,6 @@ */ add_filter( 'register_block_type_args', 'fizzie_register_block_type_args', 9 ); - /** * Implements overrides for core blocks which we need to improve. * diff --git a/includes/class-block-recursion-control.php b/includes/class-block-recursion-control.php new file mode 100644 index 0000000..52acf25 --- /dev/null +++ b/includes/class-block-recursion-control.php @@ -0,0 +1,223 @@ +processed_content[ $id ] ); + if ( !$processed ) { + $this->processed_content[$id] = $id ; + } + + /** Stop when it looks highly likely we've missed something */ + if ( count( $this->processed_content ) > 10 ) { + $processed = true; + + } + bw_trace2( $this->processed_content, "processed posts", true, BW_TRACE_DEBUG ); + return( !$processed ); + } + + /** + * Pops or clears the array of processed content. + * + * As we return to the previous level we can clear the processed content. + * Basically this is something we have to do while processing certain inner blocks: + * + * - core/post-content + * - core/template-part + * - core/post-excerpt - possibly + * - core/block - possibly + * + * Note: The top level is within the template, which loads the template parts and/or queries. + */ + function clear_processed_content( $id=null ) { + if ( $id ) { + array_pop( $this->processed_content ); + } else { + $this->processed_content = array(); + } + bw_trace2( $this->processed_content, "cleared", false, BW_TRACE_DEBUG ); + } + + /** + * Reports a recursion error to the user. + * + * If WP_DEBUG is true then additional information is displayed. + * + * @param $id string|integer recursive ID detected + * @param $type string content type + * @return string + */ + function report_recursion_error( $id, $type='core/post-content') { + bw_trace2(); + bw_backtrace(); + + $this->bad_id = $id; + $this->bad_processed_content = $this->processed_content; + // $content = $this->create_basic_error(); + + $content = array(); + $content[] = '
'; + switch ( $type ) { + case 'core/post-content': + $content[] = __( 'Content not available; already processed.', 'fizzie' ); + break; + case 'core/template-part': + $content[] = __( 'Template part not processed to avoid infinite recursion', 'fizzie'); + break; + case 'core/block': + $content[] = __( 'Reusable block not processed to avoid infinite recursion', 'fizzie'); + $this->add_filter_rest_prepare_wp_block(); + break; + default: + $content[] = __( 'Infinite recursion error prevented', 'fizzie'); + } + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { + $content[] = ""; + $content[] = '
'; + $content[] = $id; + $content[] = '
'; + $content[] = $type; + $content[] = '
'; + + $content[] = implode( ',', $this->processed_content ); + $content[] = '
'; + } + $content[] = '
'; + $content = implode( " \n", $content); + return $content; + } + + /** + * Adds a filter hook to alter the response for wp_block. + * + * There's no need to check if it is REST API processing. + * The hook function won't get called if it isn't. + */ + function add_filter_rest_prepare_wp_block() { + add_filter( 'rest_prepare_wp_block', [ $this, 'rest_prepare_wp_block' ], 10, 3 ); + } + + /** + * Fiddles with the raw content to remove `wp:block` blocks. + * ` + * [raw] => + *

This is reusable block 21117

+ * + * + * ` + * @param $response + * @param $post + * @param $request + * @return mixed + */ + function rest_prepare_wp_block( $response, $post, $request ) { + bw_trace2(); + bw_backtrace(); + + $content = $response->data['content']['raw']; + $content = $this->replace_bad( $content, $this->bad_id ); + foreach ( $this->processed_content as $id ) { + $content = $this->replace_bad( $content, $id ); + } + // Convert any remaining `wp:block` values to a `missing` block. + $content = str_replace( "wp:block {", "missing {", $content ); + + $response->data['content']['raw'] = $content; + bw_trace2( $response, "response", false ); + return $response; + } + + /** + * Replaces wp:block for ref:bad_id with a paragraph. + * + * @param $content + * @param $bad_id + * @return string|string[] + */ + function replace_bad( $content, $bad_id ) { + $replacement_block = ""; + $replacement_block .= sprintf(__('Error: Recursion was detected while loading the reusable block with post ID %1$s. '), $bad_id); + $replacement_block .= $this->title_link($bad_id); + $replacement_block .= '
'; + $replacement_block .= "Recommendation: Please delete this block."; + $replacement_block .= ""; + $content = str_replace("", $replacement_block, $content); + return $content; + } + + /** + * Returns a title link to the post. + * + * @param integer $id Post ID. + * @return string HTML title link. + */ + function title_link( $id ) { + $link = sprintf( '%s', esc_url( get_permalink( $id ) ), esc_html( get_the_title( $id ) ) ); + return $link; + } + +} \ No newline at end of file