Codeinwp / Codeinwp/optimole-wp

4.2.12 regression: close_buffer() at shutdown PHP_INT_MIN flushes other plugins' buffers, breaks Groovy Menu

Open
#1,149 5 comments 0 reactions 1 assignee View on GitHub

@selul is already working on this.

Since Sep 15, 2026.

bug regression
Dominant language
PHP
Stars
72
Forks
14
Avg merge
2d 9h
Merged PRs (30d)
15

Description

Description

Since 4.2.12 (PR #1132, "process page HTML outside PHP's output-buffer display handler"), Groovy Menu's header menu no longer appears on the front end. Rolling back to 4.2.11 fixes it. So does adding add_filter( 'optml_capture_at_shutdown', '__return_false' ); on 4.2.12.

Cause: Groovy Menu's Divi auto-integration starts its own output buffer on init (priority 0). On shutdown (priority 0) it runs ob_get_clean() and inserts the menu HTML after <body>. In 4.2.12, Optml_Manager::close_buffer() is hooked to shutdown at PHP_INT_MIN (inc/manager.php:428) and flushes every buffer above Optimole's own:

while ( ob_get_level() > self::$ob_level ) { if ( ! @ob_end_flush() ) { break; } }

That flushes Groovy Menu's buffer before Groovy's shutdown callback runs. Groovy then gets Optimole's empty buffer, finds no <body>, and the fully generated menu HTML (~40 KB) is thrown away.

Expected: the Groovy Menu is inserted into the page, as it was on 4.2.11.
Actual: the menu markup is missing on every page. Only Groovy Menu's inline JS settings are printed.

Step-by-step reproduction instructions
  1. Install the Divi theme and Groovy Menu (premium) and enable Groovy Menu's auto-integration for Divi. Assign a menu to the "Groovy menu Primary" location.
  2. Install Optimole 4.2.12 (or 4.2.13), connect it, and leave image replacement enabled.
  3. Load any front-end page with page caching bypassed.
  4. The Groovy Menu markup (.gm-navbar, .gm-preset-id-* wrapper) is missing from the HTML.
  5. Roll back to Optimole 4.2.11, or add add_filter( 'optml_capture_at_shutdown', '__return_false' );, and reload: the menu appears.
Screenshots, screen recording, code snippet or Help Scout ticket

Buffer stack traced on an uncached render (PHP CLI, same page):

  • After the template finishes, ob_level=5:
    Optml_Manager::handle_buffer_fallback → default output handler (Groovy Menu) → SiteGround_Optimizer\Parser\Parser::run → hefo_callback → wp_finalize_template_enhancement_output_buffer
  • At shutdown priority -1, ob_level=1: only Optml_Manager::handle_buffer_fallback remains
  • Groovy's groovy_menu_final_output filter receives a string of length 0

Same render with optml_capture_at_shutdown → false: Groovy receives the full page (~188 KB) and the menu is inserted.

On a live site the menu disappeared the morning after the auto-update to 4.2.12. It came back after rolling back to 4.2.11.

Possible directions:

  • Run the flush/capture later in shutdown (after default-priority callbacks) instead of at PHP_INT_MIN.
  • If other buffers are still open above Optimole's, fall back to the pre-4.2.12 behaviour instead of force-flushing them.
  • At minimum, document optml_capture_at_shutdown as a supported compatibility switch.
Environment info

WordPress 7.1, PHP 8.2.33, Optimole 4.2.12/4.2.13 (last working: 4.2.11), Divi 4.27.7, Groovy Menu 2.6.5, WP Rocket 3.23.x, SiteGround Optimizer 7.8.x, Header and Footer 3.3.6

Is the issue you are reporting a regression

Yes, this is a regression.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.