Codeinwp / Codeinwp/optimole-wp

4.2.12 regression: re-armed capture buffer at shutdown breaks FacetWP AJAX refresh (empty template, HTML + JSON response)

Open
#1,156 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Description
Summary

Since 4.2.12, Optml_Manager::close_buffer() re-arms a fresh capture buffer after processing the page. Any plugin that captures its own output buffer later in shutdown receives that empty buffer instead of its own. FacetWP does exactly this, so every facet refresh on a FacetWP "wp" template page now returns the full HTML page followed by a JSON payload with "template":"". FacetWP's client throws a JSON error and the loading spinner never clears.

This is a second symptom of the change discussed in #1149 (Groovy Menu) and introduced by #1132. The Groovy Menu fix in #1150 does not cover this case, since the problem here is the re-arm, not the flush of foreign buffers.

Environment
  • Optimole 4.2.13 (reproduced on 4.2.12 and 4.2.13; fine before 4.2.12)
  • FacetWP 4.5 with the FacetWP Elementor add-on 1.9.4
  • Elementor 4.2.4 / Elementor Pro 4.2.3, Loop Grid with "Enable FacetWP" (FacetWP's "wp" auto-detect template mode)
  • WordPress on WP Engine, PHP output_buffering on
  • Site URL available privately on request
  1. Page with an Elementor Loop Grid using "Enable FacetWP" and any facet, so FacetWP uses its "wp" template mode and POSTs facetwp_refresh to the page URL.
  2. Optimole active with image replacement enabled.
  3. Change any facet value.
Observed

The refresh response has Content-Type: application/json but the body is the complete HTML document followed by FacetWP's JSON, with "template":"". Browser console:

SyntaxError: Unexpected non-whitespace character after JSON at position 1099

Root cause

FacetWP opens ob_start() at init and, in FacetWP_Request::inject_template() hooked to shutdown at priority 0, calls ob_get_clean() expecting its own buffer, extracts <body>…</body> into template, then wp_send_json().

Optimole's close_buffer() runs first at shutdown priority PHP_INT_MIN. It captures and processes the page, echoes the result (which lands in FacetWP's buffer), then calls start_capture_buffer() again. FacetWP's ob_get_clean() therefore returns the new empty buffer.

ob_get_status(true) captured at shutdown priority -1 during a FacetWP refresh:

level handler buffer_used
0 default output handler 0
1 WpeCommon::filter_html_output 0
2 default output handler (FacetWP, opened at init) 208422
3 Optml_Manager::handle_buffer_fallback (re-armed) 0
Workaround that resolves it
add_filter( 'optml_capture_at_shutdown', function ( $capture ) {
    if ( function_exists( 'FWP' ) && ! empty( FWP()->request->is_refresh ) ) {
        return false;
    }
    return $capture;
} );

### Step-by-step reproduction instructions

1. Page with an Elementor Loop Grid using "Enable FacetWP" and any facet, so FacetWP uses its "wp" template mode and POSTs `facetwp_refresh` to the page URL.
2. Optimole active with image replacement enabled.
3. Change any facet value.


### Screenshots, screen recording, code snippet or Help Scout ticket

_No response_

### Environment info

_No response_

### 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.

Research direction

Start by tracing Optml_Manager::close_buffer() and start_capture_buffer() at shutdown, then compare that behavior with FacetWP_Request::inject_template() and the optml_capture_at_shutdown filter. Reproduce a FacetWP refresh using the steps in the issue and verify that the response contains valid JSON without the preceding full HTML page or an empty template.

Written by the indexing model from the issue text.

Assessment

Tech stack
php, wordpress
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.