Back to Blog
Why Page Builder Content Disappeared From WordPress Search (and How Queryra Reads It Now)
guide

Why Page Builder Content Disappeared From WordPress Search (and How Queryra Reads It Now)

Elementor, Breakdance, Oxygen, and Beaver Builder all store user-authored content in postmeta rather than post_content — which is why default WordPress search misses everything you typed in the visual editor. Queryra reads each builder's postmeta directly and indexes the content for AI semantic search. Architecture explainer plus per-builder details.

RG
Rafal Gron
Founder, Queryra
May 14, 2026·9 min read

Build a page in Elementor. Add a Heading element with the words *"Italian leather handbag — handmade in Florence"*. Hit Save. Then go to the front end of your site, open the WordPress search, and type *"leather handbag"*.

The page doesn't show up.

This happens because page builders store user-authored content in postmeta — not in wp_posts.post_content. Default WordPress search (and most third-party search plugins) read post_content only. Your headings, text blocks, button labels, captions, and alt text — everything you typed into the visual editor — sit in postmeta and are invisible to search.

This post explains why that happens, which builders are affected, and how Queryra solves it through AI semantic search that reads each builder's storage format directly.

Where the content actually lives

WordPress's database schema is built around two main tables for post data:

  • wp_posts — the canonical table. post_title, post_content, post_excerpt, post_status, and a few timestamps. This is what the_content() and default search read.
  • wp_postmeta — a flat key-value table attached to each post. Plugins use it for *anything* that doesn't fit the canonical fields — SEO meta titles, internal flags, layout JSON, custom field values, page builder structures.

The original WordPress assumption was that real user-authored content goes into post_content. Plugins use postmeta for *metadata about* content. Page builders break this assumption: they treat post_content as essentially a placeholder, and put the actual page content into postmeta as a serialised structure that the builder parses at render time.

Why? Because the builders need rich structured data — nested sections, columns, widgets, styling — and post_content (a single HTML/text field) can't represent that cleanly. So they bypass it.

The price: anything that reads post_content to find text — default WordPress search, most search plugins, RSS feeds, third-party content tools — sees an empty or near-empty field for builder-authored pages.

Per-builder storage details

Each major page builder uses its own postmeta key (or set of keys). Here's the landscape:

### Elementor

  • Key: _elementor_data
  • Format: JSON tree representing every element (section, column, widget) with their settings and content
  • post_content: typically empty or a small placeholder
  • Render: Elementor hooks the_content filter to parse _elementor_data and emit HTML at request time

### Breakdance

  • Key: _breakdance_data
  • Format: JSON tree, similar conceptual structure to Elementor
  • post_content: contains only a 49-byte Gutenberg block launcher comment (<!-- wp:breakdance/block-breakdance-launcher /-->)
  • Render: Breakdance hooks the_content filter with priority PHP_INT_MIN to replace the placeholder with rendered HTML

### Oxygen (Classic)

  • Keys: _ct_builder_shortcodes (rendered HTML) + _ct_builder_json_v2 (structured tree)
  • Format: Dual storage — both the rendered HTML and the structured tree are kept; the structured tree is canonical, the HTML is a cache
  • post_content: typically empty or a small Gutenberg paragraph block
  • Render: Oxygen renders from its own template engine, bypassing the WordPress theme
  • Note: The _ct_ prefix is a legacy from Oxygen's original "Component Tester" name

### Beaver Builder

  • Key: _fl_builder_data
  • Format: Serialised PHP (not JSON) — Beaver Builder uses PHP's native serialize() for storage
  • post_content: depends on settings; sometimes contains rendered output, often empty
  • Render: Beaver Builder parses the serialised data and emits HTML

### Bricks Builder

  • Keys: _bricks_* prefix family
  • Format: JSON structured tree
  • post_content: typically empty
  • Note: Queryra doesn't currently auto-extract Bricks content. Workaround via the [queryra_indexable_meta_content](/blog/queryra-developer-filters) developer filter.

The pattern is consistent: builder content lives in postmeta, sometimes spread across multiple keys, in a format the builder understands but generic search doesn't.

What Queryra does about it

Queryra reads each builder's postmeta directly during sync — not at search time, and not through the the_content filter (which would require running every page through PHP rendering, which is expensive and side-effect-prone). The flow:

  1. Detection. On sync, the plugin checks for each builder's signature postmeta key on every post. If present, builder mode is active for that post.
  2. Extraction. For each builder:
  3. - Elementor: json_decode(_elementor_data) → recurse the tree, pull every editor, title, text, link_text field
  4. - Breakdance: same approach against _breakdance_data
  5. - Oxygen: prefer _ct_builder_json_v2 (structured); fall back to _ct_builder_shortcodes (HTML) if needed
  6. - Beaver Builder: unserialize(_fl_builder_data) → walk modules, pull text/heading/HTML fields
  7. Cleaning. Extracted text gets wp_strip_all_tags() plus a filter that drops obvious non-content (CSS class names, hex colors, URLs, ISO dates).
  8. Append. Cleaned text goes into the record's description field that's sent to the Queryra API.
  9. Embed. The Queryra backend generates an AI embedding from the full content — title, original post_content, excerpt, taxonomies, plus the extracted builder content. Search now finds the page by its real visible text, not just its title.

No configuration. No per-builder settings. The plugin auto-detects what's installed and reads accordingly.

What this fixes

Concrete failures of default WordPress search that Queryra now closes:

  • Elementor sites: Heading widgets, Text Editor widgets, button labels, image alt text — all readable. Search for a phrase that appears in your hero heading on a landing page now works.
  • Breakdance sites: Same — every text element in the builder is findable.
  • Oxygen sites: Including the *Classic* line, which has the dual-storage quirk.
  • Beaver Builder sites: Including all module types that hold text (Heading, Text Editor, Button, Callout, Posts modules with custom labels).
  • WooCommerce stores using a builder for product pages: Product descriptions authored in the builder are searchable alongside (or instead of) the short/long description fields.
  • Knowledge bases and documentation sites built with builders: Headings and body text of help articles become findable through AI semantic search — "how do I reset my password" matches a builder-built page whose heading says "Password reset instructions".

What this doesn't do

Honest framing:

  • Bricks Builder is not auto-extracted. Same architectural pattern as the others, but not on the auto-detection list yet. Workaround: hook into queryra_indexable_meta_content filter and read _bricks_* postmeta manually — see the developer filters guide.
  • Dynamic content rendered at request time is missed. If your builder content includes shortcodes that compute values at render time (e.g. [current_year], [user_specific_recommendations]), the indexed version stores the shortcode text, not the rendered value. This matches default WordPress search behaviour.
  • Theme builder templates aren't relevant. Builders use "theme builder" templates to define how *single posts* look. Those templates live in a different post type and aren't synced to Queryra — but the content they wrap (the actual post_content and postmeta of the displayed post) is.
  • Computed product fields: Some builders show WooCommerce computed values (current price, stock status). Those aren't part of the page builder structure — Queryra reads them via the WooCommerce native fields instead.
  • CSS / styling text: Class names, hex colors, font sizes — explicitly filtered out. We index visible content only.

For developers extending the integration

If you have a custom page builder or builder-like plugin that uses its own postmeta keys, the [queryra_indexable_meta_content](/blog/queryra-developer-filters) filter lets you hook in and append any text source to the indexable content. Pattern:

add_filter('queryra_indexable_meta_content', function ($content, $post_id) {
    $bricks_data = get_post_meta($post_id, '_bricks_page_content', true);
    if (is_array($bricks_data)) {
        $extracted_text = my_walk_bricks_tree($bricks_data);
        $content .= ' ' . $extracted_text;
    }
    return $content;
}, 10, 2);

Replace _bricks_page_content and my_walk_bricks_tree with your builder's actual key and a function that recurses the structure. Whatever you return is appended to what Queryra would otherwise send — your content gets indexed alongside everything else.

TL;DR

  • WordPress page builders (Elementor, Breakdance, Oxygen, Beaver Builder, Bricks) all bypass wp_posts.post_content and store user-authored content in postmeta keys (_elementor_data, _breakdance_data, _ct_builder_*, _fl_builder_data, _bricks_*).
  • Default WordPress search reads post_content only — so builder body content is invisible to default search and most third-party search plugins.
  • Queryra reads each major builder's postmeta directly during sync and extracts the visible text — headings, text blocks, buttons, captions, alt text — for the AI semantic search index. No setup needed.
  • Elementor / Breakdance / Oxygen / Beaver Builder all work out of the box. Bricks needs the queryra_indexable_meta_content developer filter (or a manual Excerpt as a fallback).
  • No plugin conflicts on the frontend search path — Queryra and page builders touch different layers (Queryra at SQL search level, builders at content-rendering level).

For extending the integration to custom postmeta sources, see Queryra Developer Filters. For the structured-taxonomies angle, see Custom Taxonomies in AI Search.