diff --git a/includes/class-amp-theme-support.php b/includes/class-amp-theme-support.php index 445fb9d6e9f..0a3ac36cd80 100644 --- a/includes/class-amp-theme-support.php +++ b/includes/class-amp-theme-support.php @@ -77,12 +77,12 @@ class AMP_Theme_Support { public static $headers_sent = array(); /** - * Output buffering level when starting. + * Whether output buffering has started. * * @since 0.7 - * @var int + * @var bool */ - protected static $initial_ob_level = 0; + protected static $is_output_buffering = false; /** * Initialize. @@ -261,11 +261,12 @@ public static function add_hooks() { * Start output buffering at very low priority for sake of plugins and themes that use template_redirect * instead of template_include. */ - add_action( 'template_redirect', array( __CLASS__, 'start_output_buffering' ), 0 ); + $priority = defined( 'PHP_INT_MIN' ) ? PHP_INT_MIN : ~PHP_INT_MAX; // phpcs:ignore PHPCompatibility.PHP.NewConstants.php_int_minFound + add_action( 'template_redirect', array( __CLASS__, 'start_output_buffering' ), $priority ); // Add validation hooks *after* output buffering has started for the response. if ( AMP_Validation_Utils::should_validate_response() ) { - add_action( 'template_redirect', array( 'AMP_Validation_Utils', 'add_validation_hooks' ), 1 ); + AMP_Validation_Utils::add_validation_hooks(); } // Commenting hooks. @@ -978,6 +979,20 @@ public static function start_output_buffering() { } ob_start( array( __CLASS__, 'finish_output_buffering' ) ); + self::$is_output_buffering = true; + } + + /** + * Determine whether output buffering has started. + * + * @since 0.7 + * @see AMP_Theme_Support::start_output_buffering() + * @see AMP_Theme_Support::finish_output_buffering() + * + * @return bool Whether output buffering has started. + */ + public static function is_output_buffering() { + return self::$is_output_buffering; } /** @@ -990,6 +1005,7 @@ public static function start_output_buffering() { * @return string Processed Response. */ public static function finish_output_buffering( $response ) { + self::$is_output_buffering = false; return self::prepare_response( $response ); } diff --git a/includes/utils/class-amp-validation-utils.php b/includes/utils/class-amp-validation-utils.php index 57af4b989c4..36c57d6d4ad 100644 --- a/includes/utils/class-amp-validation-utils.php +++ b/includes/utils/class-amp-validation-utils.php @@ -943,6 +943,11 @@ public static function get_source( $callback ) { */ public static function can_output_buffer() { + // Output buffering for validation can only be done while overall output buffering is being done for the response. + if ( ! AMP_Theme_Support::is_output_buffering() ) { + return false; + } + // Abort when in shutdown since printing we know to be in buffering display handler, and no output allowed anyway. if ( did_action( 'shutdown' ) ) { return false; @@ -1003,7 +1008,7 @@ public static function wrapped_callback( $callback ) { } $result = call_user_func_array( $function, array_slice( $args, 0, intval( $accepted_args ) ) ); if ( $has_buffer_started ) { - @ob_end_flush(); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged + ob_end_flush(); } array_pop( self::$hook_source_stack ); diff --git a/tests/test-class-amp-theme-support.php b/tests/test-class-amp-theme-support.php index d3653a8c00f..5e0ced91953 100644 --- a/tests/test-class-amp-theme-support.php +++ b/tests/test-class-amp-theme-support.php @@ -278,7 +278,8 @@ public function test_add_hooks() { $this->assertEquals( 10, has_filter( 'customize_partial_render', array( self::TESTED_CLASS, 'filter_customize_partial_render' ) ) ); $this->assertEquals( 10, has_action( 'wp_footer', 'amp_print_analytics' ) ); $this->assertEquals( 100, has_filter( 'show_admin_bar', '__return_false' ) ); - $this->assertEquals( 0, has_action( 'template_redirect', array( self::TESTED_CLASS, 'start_output_buffering' ) ) ); + $priority = defined( 'PHP_INT_MIN' ) ? PHP_INT_MIN : ~PHP_INT_MAX; // phpcs:ignore PHPCompatibility.PHP.NewConstants.php_int_minFound + $this->assertEquals( $priority, has_action( 'template_redirect', array( self::TESTED_CLASS, 'start_output_buffering' ) ) ); $this->assertEquals( PHP_INT_MAX, has_filter( 'wp_list_comments_args', array( self::TESTED_CLASS, 'set_comments_walker' ) ) ); $this->assertEquals( 10, has_filter( 'comment_form_defaults', array( self::TESTED_CLASS, 'filter_comment_form_defaults' ) ) ); diff --git a/tests/test-class-amp-validation-utils.php b/tests/test-class-amp-validation-utils.php index 6217f7c9323..c4954fe388a 100644 --- a/tests/test-class-amp-validation-utils.php +++ b/tests/test-class-amp-validation-utils.php @@ -389,7 +389,7 @@ public function test_wrap_widget_callbacks() { ) ); $_wp_sidebars_widgets[ $sidebar_id ] = array( $widget_id ); // WPCS: global override ok. - ob_start(); + AMP_Theme_Support::start_output_buffering(); dynamic_sidebar( $sidebar_id ); $output = ob_get_clean(); @@ -440,21 +440,21 @@ public function test_callback_wrappers() { $this->assertEquals( 10, has_action( $action_one_argument, array( $this, 'output_notice' ) ) ); $this->assertEquals( 10, has_action( $action_two_arguments, array( $this, 'output_message' ) ) ); - ob_start(); + AMP_Theme_Support::start_output_buffering(); do_action( $action_function_callback ); $output = ob_get_clean(); $this->assertContains( '
', $output ); $this->assertContains( '