Skip to content

Posts Grid frontend render can exhaust memory with unbounded post count #2971

Description

@pirate-bot

Summary

The Posts Grid block can terminate a frontend request with an out-of-memory fatal while rendering post categories.

Expected behavior: Rendering a Posts Grid block remains bounded to a safe amount of post content and completes within normal frontend memory limits.

Actual behavior: A production site running Otter Blocks 3.2.1 recorded Out of memory (allocated 87031808 bytes) (tried to allocate 32768 bytes) during category markup rendering.

Impact: The affected page request fails instead of returning rendered content.

Customer context

  • Product / area: Otter Blocks Posts Grid frontend rendering
  • Version: 3.2.1
  • Environment: WordPress 7.0.3, PHP 8.3.31
  • Integration / third party: None identified; the crash is outside the bundled Themeisle SDK.
  • Reported error / symptom: Out of memory (allocated 87031808 bytes) (tried to allocate 32768 bytes) at Posts Grid category rendering.
  • Impact: Two telemetry occurrences across one distinct production site between 2026-08-07 and 2026-08-09.

Reproduction notes

  1. Create or modify a Posts Grid block so its saved postsToShow attribute requests an unusually large result set. This is an inference from the inspected server-render path; the exact production value is unavailable.
  2. Enable post-category metadata and render the page on the frontend.
  3. On a site with enough matching posts and a constrained PHP memory limit, observe whether rendering reaches an out-of-memory fatal during category markup construction.

Production reproduction status: telemetry confirmed two frontend fatals on one site, but the exact page configuration was not captured.

Diagnosis

Conclusion

Production telemetry places the fatal at the category-markup loop in Posts_Grid_Block::get_post_fields(). The inspected render path accepts the serialized postsToShow attribute as the query's posts_per_page value without a server-side upper bound, then builds markup for every returned post. This is a definite unbounded rendering-volume path and is consistent with the memory exhaustion recorded during subsequent category-string allocation. The telemetry does not preserve the saved block attributes, so the exact value that triggered this occurrence is unknown.

Where this likely occurs

  • inc/render/class-posts-grid-block.phpPosts_Grid_Block::render() lines 37-39 retrieves the result set, and lines 63-107 constructs markup for each returned post on frontend requests.
  • inc/render/class-posts-grid-block.phpPosts_Grid_Block::get_post_fields() lines 151-155 loads a post and all of its categories; lines 221-232 append category-link markup. Telemetry identifies line 224, the separator assignment inside this loop, as the allocation point.
  • inc/render/class-posts-grid-block.phpPosts_Grid_Block::retrieve_posts() lines 343-409 sets posts_per_page directly from $attributes['postsToShow'] at lines 359-369 before creating WP_Query at line 403.
  • src/blocks/blocks/posts/block.json — Posts Grid's postsToShow attribute is numeric with a default of 6 at lines 41-44; no maximum is declared in this metadata.
  • inc/class-registration.phpRegistration::register_blocks() lines 855-870 registers Posts_Grid_Block as the dynamic renderer for posts-grid at line 863.
  • The category loop was introduced in commit e869e6ff20ca0158e40df2177d446271484262c9 (Show multiple categories) and is present in release tag v3.2.1 (059432d330bbd5ce54ad9402953ecb6189498e9e).

Engineering notes

The failure is in Otter Blocks, not the Themeisle SDK. The recorded fatal occurs in frontend rendering and line 224 is an allocation site rather than proof that category retrieval alone created the full memory footprint. The server renderer trusts serialized block attributes, while the editor UI's QueryControls is separate from this frontend execution path. Large post result sets, lengthy post fields, or high category counts can increase the retained markup and query-memory footprint on this path.

Test coverage status

tests/test-post-grid-block.php covers empty rendering, title rendering, and output sanitization. It does not cover a populated Posts Grid query with displayPostCategory, an oversized postsToShow value, or frontend memory bounds. No relevant coverage was found during inspection beyond that unit test file.

What to verify or explore next

  • May be worth reproducing with a saved Posts Grid block containing an unusually large postsToShow value and category metadata enabled.
  • Check the persisted block attributes on affected telemetry samples, if retained elsewhere, for the post count, template, and category-display settings.
  • Run the Posts Grid PHP unit suite with populated posts and category assignments while observing the rendered result count and memory usage.
  • Check whether pagination, product post types, or filters on themeisle_gutenberg_posts_block_query alter the queried result count for this path.

Unknowns / follow-up

  • The telemetry report has no structured stack trace or persisted block attributes.
  • The site memory limit, post count, category cardinality, active integrations, and page block configuration are unavailable.
  • It is unknown whether the observed input was created through the editor UI, direct block-content editing, or a query filter.

Confidence

Confidence: 82/100

Production telemetry captured the same frontend fatal twice on one site in Otter Blocks 3.2.1, and the inspected server-render path passes the saved postsToShow value directly into WP_Query without a server-side bound before constructing per-post category markup. This establishes an uncontrolled rendering-volume path consistent with the recorded memory exhaustion.

Crash telemetry

Occurrences 2
Distinct sites 1
First seen 2026-08-07 20:48 UTC
Last seen 2026-08-09 10:52 UTC
Crash location product:inc/render/class-posts-grid-block.php:224
Request context frontend
Inside Themeisle SDK no
Product versions 3.2.1
WP versions 7.0.3
PHP versions 8.3.31
SDK versions 3.3.58

Source: automated crash report — otter-blocks, fingerprint 1b2924ae1b8eca7347a8b0b3e76bbd71
Generated by bug-report-triage (ID: bug-report-triage_6a7969028cac45.01940027)

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions